Skip to content

Commit

Permalink
feat: added Proto conversion util (#56)
Browse files Browse the repository at this point in the history
* added proto util

* added proto conversion

* fixed lint

* added failure case
  • Loading branch information
capri-xiyue authored and sethvargo committed Jan 24, 2023
1 parent 332010b commit 83a2a87
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 1 deletion.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ require (
go.uber.org/zap v1.23.0
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
google.golang.org/grpc v1.49.0
google.golang.org/protobuf v1.28.1
gopkg.in/yaml.v2 v2.4.0
)

Expand Down Expand Up @@ -54,5 +55,4 @@ require (
golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 // indirect
golang.org/x/text v0.3.7 // indirect
google.golang.org/genproto v0.0.0-20220921223823-23cae91e6737 // indirect
google.golang.org/protobuf v1.28.1 // indirect
)
36 changes: 36 additions & 0 deletions protoutil/conversion.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2023 The Authors (see AUTHORS file)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package protoutil provides mechanisms for interacting with proto.
package protoutil

import (
"encoding/json"
"fmt"

"google.golang.org/protobuf/types/known/structpb"
)

// ToProtoStruct converts v, which must marshal into a JSON object, into a proto struct.
func ToProtoStruct(v any) (*structpb.Struct, error) {
jb, err := json.Marshal(v)
if err != nil {
return nil, fmt.Errorf("json.Marshal: %w", err)
}
x := &structpb.Struct{}
if err := x.UnmarshalJSON(jb); err != nil {
return nil, fmt.Errorf("structpb.Struct.UnmarshalJSON: %w", err)
}
return x, nil
}
84 changes: 84 additions & 0 deletions protoutil/conversion_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Copyright 2023 The Authors (see AUTHORS file)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package protoutil provides mechanisms for interacting with proto.
package protoutil

import (
"testing"

"github.com/abcxyz/pkg/testutil"
"github.com/google/go-cmp/cmp"
"google.golang.org/protobuf/testing/protocmp"
"google.golang.org/protobuf/types/known/structpb"
)

func TestParseProject(t *testing.T) {
t.Parallel()

cases := []struct {
name string
input any
want *structpb.Struct
wantErrSubstr string
}{
{
name: "success",
input: map[string]any{
"FieldA": "A",
"FieldB": []string{"B1", "B2"},
"FieldC": map[string]string{
"keyC": "ValueC",
},
},
want: &structpb.Struct{Fields: map[string]*structpb.Value{
"FieldA": structpb.NewStringValue("A"),
"FieldB": structpb.NewListValue(&structpb.ListValue{Values: []*structpb.Value{structpb.NewStringValue("B1"), structpb.NewStringValue("B2")}}),
"FieldC": structpb.NewStructValue(&structpb.Struct{
Fields: map[string]*structpb.Value{
"keyC": structpb.NewStringValue("ValueC"),
},
}),
}},
},
{
name: "failure_with_json_marshal",
input: map[string]any{
"FieldA": make(chan int),
},
wantErrSubstr: "json.Marshal: json: unsupported type: chan int",
},
{
name: "failure_with_structpb_unmarshal",
input: nil,
wantErrSubstr: "structpb.Struct.UnmarshalJSON: proto:",
},
}

for _, tc := range cases {
tc := tc

t.Run(tc.name, func(t *testing.T) {
t.Parallel()

got, gotErr := ToProtoStruct(tc.input)
if diff := testutil.DiffErrString(gotErr, tc.wantErrSubstr); diff != "" {
t.Errorf("Process(%+v) got unexpected error substring: %v", tc.name, diff)
}
if diff := cmp.Diff(tc.want, got, protocmp.Transform()); diff != "" {
t.Errorf("ToProtoStruct(%+v) got diff (-want, +got): %v", tc.name, diff)
}
})
}
}

0 comments on commit 83a2a87

Please sign in to comment.