blob: 19756c509a89f52ef7eba1adaa0bcc1df8e7e11d [file] [log] [blame]
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fieldmaskpb_test
import (
"testing"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"google.golang.org/protobuf/proto"
testpb "google.golang.org/protobuf/internal/testprotos/test"
fmpb "google.golang.org/protobuf/types/known/fieldmaskpb"
)
func TestAppend(t *testing.T) {
tests := []struct {
inMessage proto.Message
inPaths []string
wantPaths []string
wantError error
}{{
inMessage: (*fmpb.FieldMask)(nil),
inPaths: []string{},
wantPaths: []string{},
}, {
inMessage: (*fmpb.FieldMask)(nil),
inPaths: []string{"paths", "paths"},
wantPaths: []string{"paths", "paths"},
}, {
inMessage: (*fmpb.FieldMask)(nil),
inPaths: []string{"paths", "<INVALID>", "paths"},
wantPaths: []string{"paths"},
wantError: cmpopts.AnyError,
}, {
inMessage: (*testpb.TestAllTypes)(nil),
inPaths: []string{"optional_int32", "OptionalGroup.optional_nested_message", "map_uint32_uint32", "map_string_nested_message.corecursive", "oneof_bool"},
wantPaths: []string{"optional_int32", "OptionalGroup.optional_nested_message", "map_uint32_uint32"},
wantError: cmpopts.AnyError,
}, {
inMessage: (*testpb.TestAllTypes)(nil),
inPaths: []string{"optional_nested_message", "optional_nested_message.corecursive", "optional_nested_message.corecursive.optional_nested_message", "optional_nested_message.corecursive.optional_nested_message.corecursive"},
wantPaths: []string{"optional_nested_message", "optional_nested_message.corecursive", "optional_nested_message.corecursive.optional_nested_message", "optional_nested_message.corecursive.optional_nested_message.corecursive"},
}, {
inMessage: (*testpb.TestAllTypes)(nil),
inPaths: []string{"optional_int32", "optional_nested_message.corecursive.optional_int64", "optional_nested_message.corecursive.<INVALID>", "optional_int64"},
wantPaths: []string{"optional_int32", "optional_nested_message.corecursive.optional_int64"},
wantError: cmpopts.AnyError,
}, {
inMessage: (*testpb.TestAllTypes)(nil),
inPaths: []string{"optional_int32", "optional_nested_message.corecursive.oneof_uint32", "optional_nested_message.oneof_field", "optional_int64"},
wantPaths: []string{"optional_int32", "optional_nested_message.corecursive.oneof_uint32"},
wantError: cmpopts.AnyError,
}}
for _, tt := range tests {
t.Run("", func(t *testing.T) {
var mask fmpb.FieldMask
gotError := mask.Append(tt.inMessage, tt.inPaths...)
gotPaths := mask.GetPaths()
if diff := cmp.Diff(tt.wantPaths, gotPaths, cmpopts.EquateEmpty()); diff != "" {
t.Errorf("Append() paths mismatch (-want +got):\n%s", diff)
}
if diff := cmp.Diff(tt.wantError, gotError, cmpopts.EquateErrors()); diff != "" {
t.Errorf("Append() error mismatch (-want +got):\n%s", diff)
}
})
}
}
func TestCombine(t *testing.T) {
tests := []struct {
in [][]string
wantUnion []string
wantIntersect []string
}{{
in: [][]string{
{},
{},
},
wantUnion: []string{},
wantIntersect: []string{},
}, {
in: [][]string{
{"a"},
{},
},
wantUnion: []string{"a"},
wantIntersect: []string{},
}, {
in: [][]string{
{"a"},
{"a"},
},
wantUnion: []string{"a"},
wantIntersect: []string{"a"},
}, {
in: [][]string{
{"a"},
{"b"},
{"c"},
},
wantUnion: []string{"a", "b", "c"},
wantIntersect: []string{},
}, {
in: [][]string{
{"a", "b"},
{"b.b"},
{"b"},
{"b", "a.A"},
{"b", "c", "c.a", "c.b"},
},
wantUnion: []string{"a", "b", "c"},
wantIntersect: []string{"b.b"},
}, {
in: [][]string{
{"a.b", "a.c.d"},
{"a"},
},
wantUnion: []string{"a"},
wantIntersect: []string{"a.b", "a.c.d"},
}, {
in: [][]string{
{},
{"a.b", "a.c", "d"},
},
wantUnion: []string{"a.b", "a.c", "d"},
wantIntersect: []string{},
}}
for _, tt := range tests {
t.Run("", func(t *testing.T) {
var masks []*fmpb.FieldMask
for _, paths := range tt.in {
masks = append(masks, &fmpb.FieldMask{Paths: paths})
}
union := fmpb.Union(masks[0], masks[1], masks[2:]...)
gotUnion := union.GetPaths()
if diff := cmp.Diff(tt.wantUnion, gotUnion, cmpopts.EquateEmpty()); diff != "" {
t.Errorf("Union() mismatch (-want +got):\n%s", diff)
}
intersect := fmpb.Intersect(masks[0], masks[1], masks[2:]...)
gotIntersect := intersect.GetPaths()
if diff := cmp.Diff(tt.wantIntersect, gotIntersect, cmpopts.EquateEmpty()); diff != "" {
t.Errorf("Intersect() mismatch (-want +got):\n%s", diff)
}
})
}
}
func TestNormalize(t *testing.T) {
tests := []struct {
in []string
want []string
}{{
in: []string{},
want: []string{},
}, {
in: []string{"a"},
want: []string{"a"},
}, {
in: []string{"foo", "foo.bar", "foo.baz"},
want: []string{"foo"},
}, {
in: []string{"foo.bar", "foo.baz"},
want: []string{"foo.bar", "foo.baz"},
}, {
in: []string{"", "a.", ".b", "a.b", ".", "", "a.", ".b", "a.b", "."},
want: []string{"", "a.", "a.b"},
}, {
in: []string{"e.a", "e.b", "e.c", "e.d", "e.f", "e.g", "e.b.a", "e$c", "e.b.c"},
want: []string{"e.a", "e.b", "e.c", "e.d", "e.f", "e.g", "e$c"},
}, {
in: []string{"a", "aa", "aaa", "a$", "AAA", "aA.a", "a.a", "a", "aa", "aaa", "a$", "AAA", "aA.a"},
want: []string{"AAA", "a", "aA.a", "aa", "aaa", "a$"},
}, {
in: []string{"a.b", "aa.bb.cc", ".", "a$b", "aa", "a.", "a", "b.c.d", ".a", "", "a$", "a$", "a.b", "a", "a.bb", ""},
want: []string{"", "a", "aa", "a$", "a$b", "b.c.d"},
}}
for _, tt := range tests {
t.Run("", func(t *testing.T) {
mask := &fmpb.FieldMask{
Paths: append([]string(nil), tt.in...),
}
mask.Normalize()
got := mask.GetPaths()
if diff := cmp.Diff(tt.want, got, cmpopts.EquateEmpty()); diff != "" {
t.Errorf("Normalize() mismatch (-want +got):\n%s", diff)
}
})
}
}
func TestIsValid(t *testing.T) {
tests := []struct {
message proto.Message
paths []string
want bool
}{{
message: (*testpb.TestAllTypes)(nil),
paths: []string{"no_such_field"},
want: false,
}, {
message: (*testpb.TestAllTypes)(nil),
paths: []string{""},
want: false,
}, {
message: (*testpb.TestAllTypes)(nil),
paths: []string{
"optional_int32",
"optional_int32",
"optional_int64",
"optional_uint32",
"optional_uint64",
"optional_sint32",
"optional_sint64",
"optional_fixed32",
"optional_fixed64",
"optional_sfixed32",
"optional_sfixed64",
"optional_float",
"optional_double",
"optional_bool",
"optional_string",
"optional_bytes",
"OptionalGroup",
"optional_nested_message",
"optional_foreign_message",
"optional_import_message",
"optional_nested_enum",
"optional_foreign_enum",
"optional_import_enum",
"repeated_int32",
"repeated_int64",
"repeated_uint32",
"repeated_uint64",
"repeated_sint32",
"repeated_sint64",
"repeated_fixed32",
"repeated_fixed64",
"repeated_sfixed32",
"repeated_sfixed64",
"repeated_float",
"repeated_double",
"repeated_bool",
"repeated_string",
"repeated_bytes",
"RepeatedGroup",
"repeated_nested_message",
"repeated_foreign_message",
"repeated_importmessage",
"repeated_nested_enum",
"repeated_foreign_enum",
"repeated_importenum",
"map_int32_int32",
"map_int64_int64",
"map_uint32_uint32",
"map_uint64_uint64",
"map_sint32_sint32",
"map_sint64_sint64",
"map_fixed32_fixed32",
"map_fixed64_fixed64",
"map_sfixed32_sfixed32",
"map_sfixed64_sfixed64",
"map_int32_float",
"map_int32_double",
"map_bool_bool",
"map_string_string",
"map_string_bytes",
"map_string_nested_message",
"map_string_nested_enum",
"oneof_uint32",
"oneof_nested_message",
"oneof_string",
"oneof_bytes",
"oneof_bool",
"oneof_uint64",
"oneof_float",
"oneof_double",
"oneof_enum",
"OneofGroup",
},
want: true,
}, {
message: (*testpb.TestAllTypes)(nil),
paths: []string{
"optional_nested_message.a",
"optional_nested_message.corecursive",
"optional_nested_message.corecursive.optional_int32",
"optional_nested_message.corecursive.optional_nested_message.corecursive.optional_nested_message.a",
"OptionalGroup.a",
"OptionalGroup.optional_nested_message",
"OptionalGroup.optional_nested_message.corecursive",
"oneof_nested_message.a",
"oneof_nested_message.corecursive",
},
want: true,
}, {
message: (*testpb.TestAllTypes)(nil),
paths: []string{"repeated_nested_message.a"},
want: false,
}, {
message: (*testpb.TestAllTypes)(nil),
paths: []string{"repeated_nested_message[0]"},
want: false,
}, {
message: (*testpb.TestAllTypes)(nil),
paths: []string{"repeated_nested_message[0].a"},
want: false,
}, {
message: (*testpb.TestAllTypes)(nil),
paths: []string{"map_string_nested_message.a"},
want: false,
}, {
message: (*testpb.TestAllTypes)(nil),
paths: []string{`map_string_nested_message["key"]`},
want: false,
}, {
message: (*testpb.TestAllExtensions)(nil),
paths: []string{"nested_string_extension"},
want: false,
}}
for _, tt := range tests {
t.Run("", func(t *testing.T) {
mask := &fmpb.FieldMask{Paths: tt.paths}
got := mask.IsValid(tt.message)
if got != tt.want {
t.Errorf("IsValid() returns %v want %v", got, tt.want)
}
})
}
}