xref: /aosp_15_r20/external/golang-protobuf/types/known/fieldmaskpb/field_mask_test.go (revision 1c12ee1efe575feb122dbf939ff15148a3b3e8f2)
1// Copyright 2020 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package fieldmaskpb_test
6
7import (
8	"testing"
9
10	"github.com/google/go-cmp/cmp"
11	"github.com/google/go-cmp/cmp/cmpopts"
12	"google.golang.org/protobuf/proto"
13
14	testpb "google.golang.org/protobuf/internal/testprotos/test"
15	fmpb "google.golang.org/protobuf/types/known/fieldmaskpb"
16)
17
18func TestAppend(t *testing.T) {
19	tests := []struct {
20		inMessage proto.Message
21		inPaths   []string
22		wantPaths []string
23		wantError error
24	}{{
25		inMessage: (*fmpb.FieldMask)(nil),
26		inPaths:   []string{},
27		wantPaths: []string{},
28	}, {
29		inMessage: (*fmpb.FieldMask)(nil),
30		inPaths:   []string{"paths", "paths"},
31		wantPaths: []string{"paths", "paths"},
32	}, {
33		inMessage: (*fmpb.FieldMask)(nil),
34		inPaths:   []string{"paths", "<INVALID>", "paths"},
35		wantPaths: []string{"paths"},
36		wantError: cmpopts.AnyError,
37	}, {
38		inMessage: (*testpb.TestAllTypes)(nil),
39		inPaths:   []string{"optional_int32", "OptionalGroup.optional_nested_message", "map_uint32_uint32", "map_string_nested_message.corecursive", "oneof_bool"},
40		wantPaths: []string{"optional_int32", "OptionalGroup.optional_nested_message", "map_uint32_uint32"},
41		wantError: cmpopts.AnyError,
42	}, {
43		inMessage: (*testpb.TestAllTypes)(nil),
44		inPaths:   []string{"optional_nested_message", "optional_nested_message.corecursive", "optional_nested_message.corecursive.optional_nested_message", "optional_nested_message.corecursive.optional_nested_message.corecursive"},
45		wantPaths: []string{"optional_nested_message", "optional_nested_message.corecursive", "optional_nested_message.corecursive.optional_nested_message", "optional_nested_message.corecursive.optional_nested_message.corecursive"},
46	}, {
47		inMessage: (*testpb.TestAllTypes)(nil),
48		inPaths:   []string{"optional_int32", "optional_nested_message.corecursive.optional_int64", "optional_nested_message.corecursive.<INVALID>", "optional_int64"},
49		wantPaths: []string{"optional_int32", "optional_nested_message.corecursive.optional_int64"},
50		wantError: cmpopts.AnyError,
51	}, {
52		inMessage: (*testpb.TestAllTypes)(nil),
53		inPaths:   []string{"optional_int32", "optional_nested_message.corecursive.oneof_uint32", "optional_nested_message.oneof_field", "optional_int64"},
54		wantPaths: []string{"optional_int32", "optional_nested_message.corecursive.oneof_uint32"},
55		wantError: cmpopts.AnyError,
56	}}
57
58	for _, tt := range tests {
59		t.Run("", func(t *testing.T) {
60			var mask fmpb.FieldMask
61			gotError := mask.Append(tt.inMessage, tt.inPaths...)
62			gotPaths := mask.GetPaths()
63			if diff := cmp.Diff(tt.wantPaths, gotPaths, cmpopts.EquateEmpty()); diff != "" {
64				t.Errorf("Append() paths mismatch (-want +got):\n%s", diff)
65			}
66			if diff := cmp.Diff(tt.wantError, gotError, cmpopts.EquateErrors()); diff != "" {
67				t.Errorf("Append() error mismatch (-want +got):\n%s", diff)
68			}
69		})
70	}
71}
72
73func TestCombine(t *testing.T) {
74	tests := []struct {
75		in            [][]string
76		wantUnion     []string
77		wantIntersect []string
78	}{{
79		in: [][]string{
80			{},
81			{},
82		},
83		wantUnion:     []string{},
84		wantIntersect: []string{},
85	}, {
86		in: [][]string{
87			{"a"},
88			{},
89		},
90		wantUnion:     []string{"a"},
91		wantIntersect: []string{},
92	}, {
93		in: [][]string{
94			{"a"},
95			{"a"},
96		},
97		wantUnion:     []string{"a"},
98		wantIntersect: []string{"a"},
99	}, {
100		in: [][]string{
101			{"a"},
102			{"b"},
103			{"c"},
104		},
105		wantUnion:     []string{"a", "b", "c"},
106		wantIntersect: []string{},
107	}, {
108		in: [][]string{
109			{"a", "b"},
110			{"b.b"},
111			{"b"},
112			{"b", "a.A"},
113			{"b", "c", "c.a", "c.b"},
114		},
115		wantUnion:     []string{"a", "b", "c"},
116		wantIntersect: []string{"b.b"},
117	}, {
118		in: [][]string{
119			{"a.b", "a.c.d"},
120			{"a"},
121		},
122		wantUnion:     []string{"a"},
123		wantIntersect: []string{"a.b", "a.c.d"},
124	}, {
125		in: [][]string{
126			{},
127			{"a.b", "a.c", "d"},
128		},
129		wantUnion:     []string{"a.b", "a.c", "d"},
130		wantIntersect: []string{},
131	}}
132
133	for _, tt := range tests {
134		t.Run("", func(t *testing.T) {
135			var masks []*fmpb.FieldMask
136			for _, paths := range tt.in {
137				masks = append(masks, &fmpb.FieldMask{Paths: paths})
138			}
139
140			union := fmpb.Union(masks[0], masks[1], masks[2:]...)
141			gotUnion := union.GetPaths()
142			if diff := cmp.Diff(tt.wantUnion, gotUnion, cmpopts.EquateEmpty()); diff != "" {
143				t.Errorf("Union() mismatch (-want +got):\n%s", diff)
144			}
145
146			intersect := fmpb.Intersect(masks[0], masks[1], masks[2:]...)
147			gotIntersect := intersect.GetPaths()
148			if diff := cmp.Diff(tt.wantIntersect, gotIntersect, cmpopts.EquateEmpty()); diff != "" {
149				t.Errorf("Intersect() mismatch (-want +got):\n%s", diff)
150			}
151		})
152	}
153}
154
155func TestNormalize(t *testing.T) {
156	tests := []struct {
157		in   []string
158		want []string
159	}{{
160		in:   []string{},
161		want: []string{},
162	}, {
163		in:   []string{"a"},
164		want: []string{"a"},
165	}, {
166		in:   []string{"foo", "foo.bar", "foo.baz"},
167		want: []string{"foo"},
168	}, {
169		in:   []string{"foo.bar", "foo.baz"},
170		want: []string{"foo.bar", "foo.baz"},
171	}, {
172		in:   []string{"", "a.", ".b", "a.b", ".", "", "a.", ".b", "a.b", "."},
173		want: []string{"", "a.", "a.b"},
174	}, {
175		in:   []string{"e.a", "e.b", "e.c", "e.d", "e.f", "e.g", "e.b.a", "e$c", "e.b.c"},
176		want: []string{"e.a", "e.b", "e.c", "e.d", "e.f", "e.g", "e$c"},
177	}, {
178		in:   []string{"a", "aa", "aaa", "a$", "AAA", "aA.a", "a.a", "a", "aa", "aaa", "a$", "AAA", "aA.a"},
179		want: []string{"AAA", "a", "aA.a", "aa", "aaa", "a$"},
180	}, {
181		in:   []string{"a.b", "aa.bb.cc", ".", "a$b", "aa", "a.", "a", "b.c.d", ".a", "", "a$", "a$", "a.b", "a", "a.bb", ""},
182		want: []string{"", "a", "aa", "a$", "a$b", "b.c.d"},
183	}}
184
185	for _, tt := range tests {
186		t.Run("", func(t *testing.T) {
187			mask := &fmpb.FieldMask{
188				Paths: append([]string(nil), tt.in...),
189			}
190			mask.Normalize()
191			got := mask.GetPaths()
192			if diff := cmp.Diff(tt.want, got, cmpopts.EquateEmpty()); diff != "" {
193				t.Errorf("Normalize() mismatch (-want +got):\n%s", diff)
194			}
195		})
196	}
197}
198
199func TestIsValid(t *testing.T) {
200	tests := []struct {
201		message proto.Message
202		paths   []string
203		want    bool
204	}{{
205		message: (*testpb.TestAllTypes)(nil),
206		paths:   []string{"no_such_field"},
207		want:    false,
208	}, {
209		message: (*testpb.TestAllTypes)(nil),
210		paths:   []string{""},
211		want:    false,
212	}, {
213		message: (*testpb.TestAllTypes)(nil),
214		paths: []string{
215			"optional_int32",
216			"optional_int32",
217			"optional_int64",
218			"optional_uint32",
219			"optional_uint64",
220			"optional_sint32",
221			"optional_sint64",
222			"optional_fixed32",
223			"optional_fixed64",
224			"optional_sfixed32",
225			"optional_sfixed64",
226			"optional_float",
227			"optional_double",
228			"optional_bool",
229			"optional_string",
230			"optional_bytes",
231			"OptionalGroup",
232			"optional_nested_message",
233			"optional_foreign_message",
234			"optional_import_message",
235			"optional_nested_enum",
236			"optional_foreign_enum",
237			"optional_import_enum",
238			"repeated_int32",
239			"repeated_int64",
240			"repeated_uint32",
241			"repeated_uint64",
242			"repeated_sint32",
243			"repeated_sint64",
244			"repeated_fixed32",
245			"repeated_fixed64",
246			"repeated_sfixed32",
247			"repeated_sfixed64",
248			"repeated_float",
249			"repeated_double",
250			"repeated_bool",
251			"repeated_string",
252			"repeated_bytes",
253			"RepeatedGroup",
254			"repeated_nested_message",
255			"repeated_foreign_message",
256			"repeated_importmessage",
257			"repeated_nested_enum",
258			"repeated_foreign_enum",
259			"repeated_importenum",
260			"map_int32_int32",
261			"map_int64_int64",
262			"map_uint32_uint32",
263			"map_uint64_uint64",
264			"map_sint32_sint32",
265			"map_sint64_sint64",
266			"map_fixed32_fixed32",
267			"map_fixed64_fixed64",
268			"map_sfixed32_sfixed32",
269			"map_sfixed64_sfixed64",
270			"map_int32_float",
271			"map_int32_double",
272			"map_bool_bool",
273			"map_string_string",
274			"map_string_bytes",
275			"map_string_nested_message",
276			"map_string_nested_enum",
277			"oneof_uint32",
278			"oneof_nested_message",
279			"oneof_string",
280			"oneof_bytes",
281			"oneof_bool",
282			"oneof_uint64",
283			"oneof_float",
284			"oneof_double",
285			"oneof_enum",
286			"OneofGroup",
287		},
288		want: true,
289	}, {
290		message: (*testpb.TestAllTypes)(nil),
291		paths: []string{
292			"optional_nested_message.a",
293			"optional_nested_message.corecursive",
294			"optional_nested_message.corecursive.optional_int32",
295			"optional_nested_message.corecursive.optional_nested_message.corecursive.optional_nested_message.a",
296			"OptionalGroup.a",
297			"OptionalGroup.optional_nested_message",
298			"OptionalGroup.optional_nested_message.corecursive",
299			"oneof_nested_message.a",
300			"oneof_nested_message.corecursive",
301		},
302		want: true,
303	}, {
304		message: (*testpb.TestAllTypes)(nil),
305		paths:   []string{"repeated_nested_message.a"},
306		want:    false,
307	}, {
308		message: (*testpb.TestAllTypes)(nil),
309		paths:   []string{"repeated_nested_message[0]"},
310		want:    false,
311	}, {
312		message: (*testpb.TestAllTypes)(nil),
313		paths:   []string{"repeated_nested_message[0].a"},
314		want:    false,
315	}, {
316		message: (*testpb.TestAllTypes)(nil),
317		paths:   []string{"map_string_nested_message.a"},
318		want:    false,
319	}, {
320		message: (*testpb.TestAllTypes)(nil),
321		paths:   []string{`map_string_nested_message["key"]`},
322		want:    false,
323	}, {
324		message: (*testpb.TestAllExtensions)(nil),
325		paths:   []string{"nested_string_extension"},
326		want:    false,
327	}}
328
329	for _, tt := range tests {
330		t.Run("", func(t *testing.T) {
331			mask := &fmpb.FieldMask{Paths: tt.paths}
332			got := mask.IsValid(tt.message)
333			if got != tt.want {
334				t.Errorf("IsValid() returns %v want %v", got, tt.want)
335			}
336		})
337	}
338}
339