Skip to content

Commit

Permalink
feat: add UnmarshalYAML to protoutil (#61)
Browse files Browse the repository at this point in the history
  • Loading branch information
yolocs authored Feb 10, 2023
1 parent c0c719a commit ffe3fe7
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 2 deletions.
23 changes: 22 additions & 1 deletion protoutil/conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,14 @@ import (
"encoding/json"
"fmt"

"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/structpb"
"gopkg.in/yaml.v2"
)

// ToProtoStruct converts v, which must marshal into a JSON object, into a proto struct.
// 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 {
Expand All @@ -34,3 +38,20 @@ func ToProtoStruct(v any) (*structpb.Struct, error) {
}
return x, nil
}

// UnmarshalYAML unmarshals the give YAML bytes to the given proto message.
func UnmarshalYAML(b []byte, msg proto.Message) error {
tmp := map[string]any{}
if err := yaml.Unmarshal(b, tmp); err != nil {
return fmt.Errorf("failed to unmarshal yaml: %w", err)
}
jb, err := json.Marshal(tmp)
if err != nil {
return fmt.Errorf("failed to marshal json: %w", err)
}

if err := protojson.Unmarshal(jb, msg); err != nil {
return fmt.Errorf("failed to unmarshal proto: %w", err)
}
return nil
}
60 changes: 59 additions & 1 deletion protoutil/conversion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (
"google.golang.org/protobuf/types/known/structpb"
)

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

cases := []struct {
Expand Down Expand Up @@ -82,3 +82,61 @@ func TestParseProject(t *testing.T) {
})
}
}

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

cases := []struct {
name string
b []byte
want *structpb.Struct
wantErrSubstr string
}{
{
name: "success",
b: []byte(`foo: bar
slice:
- abc
- xyz
num: 1
bool: true
`),
want: &structpb.Struct{
Fields: map[string]*structpb.Value{
"foo": structpb.NewStringValue("bar"),
"slice": structpb.NewListValue(&structpb.ListValue{
Values: []*structpb.Value{
structpb.NewStringValue("abc"),
structpb.NewStringValue("xyz"),
},
}),
"num": structpb.NewNumberValue(1),
"bool": structpb.NewBoolValue(true),
},
},
},
{
name: "invalid_yaml_error",
b: []byte("foobar: {}{}"),
want: &structpb.Struct{},
wantErrSubstr: "failed to unmarshal yaml",
},
}

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

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

var msg structpb.Struct
err := UnmarshalYAML(tc.b, &msg)
if diff := testutil.DiffErrString(err, tc.wantErrSubstr); diff != "" {
t.Errorf("unexpected error: %s", diff)
}
if diff := cmp.Diff(tc.want, &msg, protocmp.Transform()); diff != "" {
t.Errorf("UnmarshalYAML (-want,+got):\n%s", diff)
}
})
}
}

0 comments on commit ffe3fe7

Please sign in to comment.