xref: /aosp_15_r20/external/golang-protobuf/proto/equal_test.go (revision 1c12ee1efe575feb122dbf939ff15148a3b3e8f2)
1// Copyright 2019 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 proto_test
6
7import (
8	"math"
9	"testing"
10
11	"google.golang.org/protobuf/encoding/prototext"
12	"google.golang.org/protobuf/internal/pragma"
13	"google.golang.org/protobuf/proto"
14	"google.golang.org/protobuf/testing/protopack"
15
16	testpb "google.golang.org/protobuf/internal/testprotos/test"
17	test3pb "google.golang.org/protobuf/internal/testprotos/test3"
18)
19
20func TestEqual(t *testing.T) {
21	identicalPtrPb := &testpb.TestAllTypes{MapStringString: map[string]string{"a": "b", "c": "d"}}
22
23	type incomparableMessage struct {
24		*testpb.TestAllTypes
25		pragma.DoNotCompare
26	}
27
28	tests := []struct {
29		x, y proto.Message
30		eq   bool
31	}{
32		{
33			x:  nil,
34			y:  nil,
35			eq: true,
36		}, {
37			x:  (*testpb.TestAllTypes)(nil),
38			y:  nil,
39			eq: false,
40		}, {
41			x:  (*testpb.TestAllTypes)(nil),
42			y:  (*testpb.TestAllTypes)(nil),
43			eq: true,
44		}, {
45			x:  new(testpb.TestAllTypes),
46			y:  (*testpb.TestAllTypes)(nil),
47			eq: false,
48		}, {
49			x:  new(testpb.TestAllTypes),
50			y:  new(testpb.TestAllTypes),
51			eq: true,
52		}, {
53			x:  (*testpb.TestAllTypes)(nil),
54			y:  (*testpb.TestAllExtensions)(nil),
55			eq: false,
56		}, {
57			x:  (*testpb.TestAllTypes)(nil),
58			y:  new(testpb.TestAllExtensions),
59			eq: false,
60		}, {
61			x:  new(testpb.TestAllTypes),
62			y:  new(testpb.TestAllExtensions),
63			eq: false,
64		},
65
66		// Identical input pointers
67		{
68			x:  identicalPtrPb,
69			y:  identicalPtrPb,
70			eq: true,
71		},
72
73		// Incomparable types. The top-level types are not actually directly
74		// compared (which would panic), but rather the comparison happens on the
75		// objects returned by ProtoReflect(). These tests are here just to ensure
76		// that any short-circuit checks do not accidentally try to compare
77		// incomparable top-level types.
78		{
79			x:  incomparableMessage{TestAllTypes: identicalPtrPb},
80			y:  incomparableMessage{TestAllTypes: identicalPtrPb},
81			eq: true,
82		},
83		{
84			x:  identicalPtrPb,
85			y:  incomparableMessage{TestAllTypes: identicalPtrPb},
86			eq: true,
87		},
88		{
89			x:  identicalPtrPb,
90			y:  &incomparableMessage{TestAllTypes: identicalPtrPb},
91			eq: true,
92		},
93
94		// Proto2 scalars.
95		{
96			x: &testpb.TestAllTypes{OptionalInt32: proto.Int32(1)},
97			y: &testpb.TestAllTypes{OptionalInt32: proto.Int32(2)},
98		}, {
99			x: &testpb.TestAllTypes{OptionalInt64: proto.Int64(1)},
100			y: &testpb.TestAllTypes{OptionalInt64: proto.Int64(2)},
101		}, {
102			x: &testpb.TestAllTypes{OptionalUint32: proto.Uint32(1)},
103			y: &testpb.TestAllTypes{OptionalUint32: proto.Uint32(2)},
104		}, {
105			x: &testpb.TestAllTypes{OptionalUint64: proto.Uint64(1)},
106			y: &testpb.TestAllTypes{OptionalUint64: proto.Uint64(2)},
107		}, {
108			x: &testpb.TestAllTypes{OptionalSint32: proto.Int32(1)},
109			y: &testpb.TestAllTypes{OptionalSint32: proto.Int32(2)},
110		}, {
111			x: &testpb.TestAllTypes{OptionalSint64: proto.Int64(1)},
112			y: &testpb.TestAllTypes{OptionalSint64: proto.Int64(2)},
113		}, {
114			x: &testpb.TestAllTypes{OptionalFixed32: proto.Uint32(1)},
115			y: &testpb.TestAllTypes{OptionalFixed32: proto.Uint32(2)},
116		}, {
117			x: &testpb.TestAllTypes{OptionalFixed64: proto.Uint64(1)},
118			y: &testpb.TestAllTypes{OptionalFixed64: proto.Uint64(2)},
119		}, {
120			x: &testpb.TestAllTypes{OptionalSfixed32: proto.Int32(1)},
121			y: &testpb.TestAllTypes{OptionalSfixed32: proto.Int32(2)},
122		}, {
123			x: &testpb.TestAllTypes{OptionalSfixed64: proto.Int64(1)},
124			y: &testpb.TestAllTypes{OptionalSfixed64: proto.Int64(2)},
125		}, {
126			x: &testpb.TestAllTypes{OptionalFloat: proto.Float32(1)},
127			y: &testpb.TestAllTypes{OptionalFloat: proto.Float32(2)},
128		}, {
129			x: &testpb.TestAllTypes{OptionalDouble: proto.Float64(1)},
130			y: &testpb.TestAllTypes{OptionalDouble: proto.Float64(2)},
131		}, {
132			x: &testpb.TestAllTypes{OptionalFloat: proto.Float32(float32(math.NaN()))},
133			y: &testpb.TestAllTypes{OptionalFloat: proto.Float32(0)},
134		}, {
135			x: &testpb.TestAllTypes{OptionalDouble: proto.Float64(float64(math.NaN()))},
136			y: &testpb.TestAllTypes{OptionalDouble: proto.Float64(0)},
137		}, {
138			x: &testpb.TestAllTypes{OptionalBool: proto.Bool(true)},
139			y: &testpb.TestAllTypes{OptionalBool: proto.Bool(false)},
140		}, {
141			x: &testpb.TestAllTypes{OptionalString: proto.String("a")},
142			y: &testpb.TestAllTypes{OptionalString: proto.String("b")},
143		}, {
144			x: &testpb.TestAllTypes{OptionalBytes: []byte("a")},
145			y: &testpb.TestAllTypes{OptionalBytes: []byte("b")},
146		}, {
147			x: &testpb.TestAllTypes{OptionalNestedEnum: testpb.TestAllTypes_FOO.Enum()},
148			y: &testpb.TestAllTypes{OptionalNestedEnum: testpb.TestAllTypes_BAR.Enum()},
149		}, {
150			x:  &testpb.TestAllTypes{OptionalInt32: proto.Int32(2)},
151			y:  &testpb.TestAllTypes{OptionalInt32: proto.Int32(2)},
152			eq: true,
153		}, {
154			x:  &testpb.TestAllTypes{OptionalInt64: proto.Int64(2)},
155			y:  &testpb.TestAllTypes{OptionalInt64: proto.Int64(2)},
156			eq: true,
157		}, {
158			x:  &testpb.TestAllTypes{OptionalUint32: proto.Uint32(2)},
159			y:  &testpb.TestAllTypes{OptionalUint32: proto.Uint32(2)},
160			eq: true,
161		}, {
162			x:  &testpb.TestAllTypes{OptionalUint64: proto.Uint64(2)},
163			y:  &testpb.TestAllTypes{OptionalUint64: proto.Uint64(2)},
164			eq: true,
165		}, {
166			x:  &testpb.TestAllTypes{OptionalSint32: proto.Int32(2)},
167			y:  &testpb.TestAllTypes{OptionalSint32: proto.Int32(2)},
168			eq: true,
169		}, {
170			x:  &testpb.TestAllTypes{OptionalSint64: proto.Int64(2)},
171			y:  &testpb.TestAllTypes{OptionalSint64: proto.Int64(2)},
172			eq: true,
173		}, {
174			x:  &testpb.TestAllTypes{OptionalFixed32: proto.Uint32(2)},
175			y:  &testpb.TestAllTypes{OptionalFixed32: proto.Uint32(2)},
176			eq: true,
177		}, {
178			x:  &testpb.TestAllTypes{OptionalFixed64: proto.Uint64(2)},
179			y:  &testpb.TestAllTypes{OptionalFixed64: proto.Uint64(2)},
180			eq: true,
181		}, {
182			x:  &testpb.TestAllTypes{OptionalSfixed32: proto.Int32(2)},
183			y:  &testpb.TestAllTypes{OptionalSfixed32: proto.Int32(2)},
184			eq: true,
185		}, {
186			x:  &testpb.TestAllTypes{OptionalSfixed64: proto.Int64(2)},
187			y:  &testpb.TestAllTypes{OptionalSfixed64: proto.Int64(2)},
188			eq: true,
189		}, {
190			x:  &testpb.TestAllTypes{OptionalFloat: proto.Float32(2)},
191			y:  &testpb.TestAllTypes{OptionalFloat: proto.Float32(2)},
192			eq: true,
193		}, {
194			x:  &testpb.TestAllTypes{OptionalDouble: proto.Float64(2)},
195			y:  &testpb.TestAllTypes{OptionalDouble: proto.Float64(2)},
196			eq: true,
197		}, {
198			x:  &testpb.TestAllTypes{OptionalFloat: proto.Float32(float32(math.NaN()))},
199			y:  &testpb.TestAllTypes{OptionalFloat: proto.Float32(float32(math.NaN()))},
200			eq: true,
201		}, {
202			x:  &testpb.TestAllTypes{OptionalDouble: proto.Float64(float64(math.NaN()))},
203			y:  &testpb.TestAllTypes{OptionalDouble: proto.Float64(float64(math.NaN()))},
204			eq: true,
205		}, {
206			x:  &testpb.TestAllTypes{OptionalBool: proto.Bool(true)},
207			y:  &testpb.TestAllTypes{OptionalBool: proto.Bool(true)},
208			eq: true,
209		}, {
210			x:  &testpb.TestAllTypes{OptionalString: proto.String("abc")},
211			y:  &testpb.TestAllTypes{OptionalString: proto.String("abc")},
212			eq: true,
213		}, {
214			x:  &testpb.TestAllTypes{OptionalBytes: []byte("abc")},
215			y:  &testpb.TestAllTypes{OptionalBytes: []byte("abc")},
216			eq: true,
217		}, {
218			x:  &testpb.TestAllTypes{OptionalNestedEnum: testpb.TestAllTypes_FOO.Enum()},
219			y:  &testpb.TestAllTypes{OptionalNestedEnum: testpb.TestAllTypes_FOO.Enum()},
220			eq: true,
221		},
222
223		// Proto2 presence.
224		{
225			x: &testpb.TestAllTypes{},
226			y: &testpb.TestAllTypes{OptionalInt32: proto.Int32(0)},
227		}, {
228			x: &testpb.TestAllTypes{},
229			y: &testpb.TestAllTypes{OptionalInt64: proto.Int64(0)},
230		}, {
231			x: &testpb.TestAllTypes{},
232			y: &testpb.TestAllTypes{OptionalUint32: proto.Uint32(0)},
233		}, {
234			x: &testpb.TestAllTypes{},
235			y: &testpb.TestAllTypes{OptionalUint64: proto.Uint64(0)},
236		}, {
237			x: &testpb.TestAllTypes{},
238			y: &testpb.TestAllTypes{OptionalSint32: proto.Int32(0)},
239		}, {
240			x: &testpb.TestAllTypes{},
241			y: &testpb.TestAllTypes{OptionalSint64: proto.Int64(0)},
242		}, {
243			x: &testpb.TestAllTypes{},
244			y: &testpb.TestAllTypes{OptionalFixed32: proto.Uint32(0)},
245		}, {
246			x: &testpb.TestAllTypes{},
247			y: &testpb.TestAllTypes{OptionalFixed64: proto.Uint64(0)},
248		}, {
249			x: &testpb.TestAllTypes{},
250			y: &testpb.TestAllTypes{OptionalSfixed32: proto.Int32(0)},
251		}, {
252			x: &testpb.TestAllTypes{},
253			y: &testpb.TestAllTypes{OptionalSfixed64: proto.Int64(0)},
254		}, {
255			x: &testpb.TestAllTypes{},
256			y: &testpb.TestAllTypes{OptionalFloat: proto.Float32(0)},
257		}, {
258			x: &testpb.TestAllTypes{},
259			y: &testpb.TestAllTypes{OptionalDouble: proto.Float64(0)},
260		}, {
261			x: &testpb.TestAllTypes{},
262			y: &testpb.TestAllTypes{OptionalBool: proto.Bool(false)},
263		}, {
264			x: &testpb.TestAllTypes{},
265			y: &testpb.TestAllTypes{OptionalString: proto.String("")},
266		}, {
267			x: &testpb.TestAllTypes{},
268			y: &testpb.TestAllTypes{OptionalBytes: []byte{}},
269		}, {
270			x: &testpb.TestAllTypes{},
271			y: &testpb.TestAllTypes{OptionalNestedEnum: testpb.TestAllTypes_FOO.Enum()},
272		},
273
274		// Proto3 presence.
275		{
276			x: &test3pb.TestAllTypes{},
277			y: &test3pb.TestAllTypes{OptionalInt32: proto.Int32(0)},
278		}, {
279			x: &test3pb.TestAllTypes{},
280			y: &test3pb.TestAllTypes{OptionalInt64: proto.Int64(0)},
281		}, {
282			x: &test3pb.TestAllTypes{},
283			y: &test3pb.TestAllTypes{OptionalUint32: proto.Uint32(0)},
284		}, {
285			x: &test3pb.TestAllTypes{},
286			y: &test3pb.TestAllTypes{OptionalUint64: proto.Uint64(0)},
287		}, {
288			x: &test3pb.TestAllTypes{},
289			y: &test3pb.TestAllTypes{OptionalSint32: proto.Int32(0)},
290		}, {
291			x: &test3pb.TestAllTypes{},
292			y: &test3pb.TestAllTypes{OptionalSint64: proto.Int64(0)},
293		}, {
294			x: &test3pb.TestAllTypes{},
295			y: &test3pb.TestAllTypes{OptionalFixed32: proto.Uint32(0)},
296		}, {
297			x: &test3pb.TestAllTypes{},
298			y: &test3pb.TestAllTypes{OptionalFixed64: proto.Uint64(0)},
299		}, {
300			x: &test3pb.TestAllTypes{},
301			y: &test3pb.TestAllTypes{OptionalSfixed32: proto.Int32(0)},
302		}, {
303			x: &test3pb.TestAllTypes{},
304			y: &test3pb.TestAllTypes{OptionalSfixed64: proto.Int64(0)},
305		}, {
306			x: &test3pb.TestAllTypes{},
307			y: &test3pb.TestAllTypes{OptionalFloat: proto.Float32(0)},
308		}, {
309			x: &test3pb.TestAllTypes{},
310			y: &test3pb.TestAllTypes{OptionalDouble: proto.Float64(0)},
311		}, {
312			x: &test3pb.TestAllTypes{},
313			y: &test3pb.TestAllTypes{OptionalBool: proto.Bool(false)},
314		}, {
315			x: &test3pb.TestAllTypes{},
316			y: &test3pb.TestAllTypes{OptionalString: proto.String("")},
317		}, {
318			x: &test3pb.TestAllTypes{},
319			y: &test3pb.TestAllTypes{OptionalBytes: []byte{}},
320		}, {
321			x: &test3pb.TestAllTypes{},
322			y: &test3pb.TestAllTypes{OptionalNestedEnum: test3pb.TestAllTypes_FOO.Enum()},
323		},
324
325		// Proto2 default values are not considered by Equal, so the following are still unequal.
326		{
327			x: &testpb.TestAllTypes{DefaultInt32: proto.Int32(81)},
328			y: &testpb.TestAllTypes{},
329		}, {
330			x: &testpb.TestAllTypes{},
331			y: &testpb.TestAllTypes{DefaultInt32: proto.Int32(81)},
332		}, {
333			x: &testpb.TestAllTypes{},
334			y: &testpb.TestAllTypes{DefaultInt64: proto.Int64(82)},
335		}, {
336			x: &testpb.TestAllTypes{},
337			y: &testpb.TestAllTypes{DefaultUint32: proto.Uint32(83)},
338		}, {
339			x: &testpb.TestAllTypes{},
340			y: &testpb.TestAllTypes{DefaultUint64: proto.Uint64(84)},
341		}, {
342			x: &testpb.TestAllTypes{},
343			y: &testpb.TestAllTypes{DefaultSint32: proto.Int32(-85)},
344		}, {
345			x: &testpb.TestAllTypes{},
346			y: &testpb.TestAllTypes{DefaultSint64: proto.Int64(86)},
347		}, {
348			x: &testpb.TestAllTypes{},
349			y: &testpb.TestAllTypes{DefaultFixed32: proto.Uint32(87)},
350		}, {
351			x: &testpb.TestAllTypes{},
352			y: &testpb.TestAllTypes{DefaultFixed64: proto.Uint64(88)},
353		}, {
354			x: &testpb.TestAllTypes{},
355			y: &testpb.TestAllTypes{DefaultSfixed32: proto.Int32(89)},
356		}, {
357			x: &testpb.TestAllTypes{},
358			y: &testpb.TestAllTypes{DefaultSfixed64: proto.Int64(-90)},
359		}, {
360			x: &testpb.TestAllTypes{},
361			y: &testpb.TestAllTypes{DefaultFloat: proto.Float32(91.5)},
362		}, {
363			x: &testpb.TestAllTypes{},
364			y: &testpb.TestAllTypes{DefaultDouble: proto.Float64(92e3)},
365		}, {
366			x: &testpb.TestAllTypes{},
367			y: &testpb.TestAllTypes{DefaultBool: proto.Bool(true)},
368		}, {
369			x: &testpb.TestAllTypes{},
370			y: &testpb.TestAllTypes{DefaultString: proto.String("hello")},
371		}, {
372			x: &testpb.TestAllTypes{},
373			y: &testpb.TestAllTypes{DefaultBytes: []byte("world")},
374		}, {
375			x: &testpb.TestAllTypes{},
376			y: &testpb.TestAllTypes{DefaultNestedEnum: testpb.TestAllTypes_BAR.Enum()},
377		},
378
379		// Groups.
380		{
381			x: &testpb.TestAllTypes{Optionalgroup: &testpb.TestAllTypes_OptionalGroup{
382				A: proto.Int32(1),
383			}},
384			y: &testpb.TestAllTypes{Optionalgroup: &testpb.TestAllTypes_OptionalGroup{
385				A: proto.Int32(2),
386			}},
387		}, {
388			x: &testpb.TestAllTypes{},
389			y: &testpb.TestAllTypes{Optionalgroup: &testpb.TestAllTypes_OptionalGroup{}},
390		},
391
392		// Messages.
393		{
394			x: &testpb.TestAllTypes{OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
395				A: proto.Int32(1),
396			}},
397			y: &testpb.TestAllTypes{OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
398				A: proto.Int32(2),
399			}},
400		}, {
401			x: &testpb.TestAllTypes{},
402			y: &testpb.TestAllTypes{OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{}},
403		}, {
404			x: &test3pb.TestAllTypes{},
405			y: &test3pb.TestAllTypes{OptionalNestedMessage: &test3pb.TestAllTypes_NestedMessage{}},
406		},
407
408		// Lists.
409		{
410			x: &testpb.TestAllTypes{RepeatedInt32: []int32{1}},
411			y: &testpb.TestAllTypes{RepeatedInt32: []int32{1, 2}},
412		}, {
413			x: &testpb.TestAllTypes{RepeatedInt32: []int32{1, 2}},
414			y: &testpb.TestAllTypes{RepeatedInt32: []int32{1, 3}},
415		}, {
416			x: &testpb.TestAllTypes{RepeatedInt64: []int64{1, 2}},
417			y: &testpb.TestAllTypes{RepeatedInt64: []int64{1, 3}},
418		}, {
419			x: &testpb.TestAllTypes{RepeatedUint32: []uint32{1, 2}},
420			y: &testpb.TestAllTypes{RepeatedUint32: []uint32{1, 3}},
421		}, {
422			x: &testpb.TestAllTypes{RepeatedUint64: []uint64{1, 2}},
423			y: &testpb.TestAllTypes{RepeatedUint64: []uint64{1, 3}},
424		}, {
425			x: &testpb.TestAllTypes{RepeatedSint32: []int32{1, 2}},
426			y: &testpb.TestAllTypes{RepeatedSint32: []int32{1, 3}},
427		}, {
428			x: &testpb.TestAllTypes{RepeatedSint64: []int64{1, 2}},
429			y: &testpb.TestAllTypes{RepeatedSint64: []int64{1, 3}},
430		}, {
431			x: &testpb.TestAllTypes{RepeatedFixed32: []uint32{1, 2}},
432			y: &testpb.TestAllTypes{RepeatedFixed32: []uint32{1, 3}},
433		}, {
434			x: &testpb.TestAllTypes{RepeatedFixed64: []uint64{1, 2}},
435			y: &testpb.TestAllTypes{RepeatedFixed64: []uint64{1, 3}},
436		}, {
437			x: &testpb.TestAllTypes{RepeatedSfixed32: []int32{1, 2}},
438			y: &testpb.TestAllTypes{RepeatedSfixed32: []int32{1, 3}},
439		}, {
440			x: &testpb.TestAllTypes{RepeatedSfixed64: []int64{1, 2}},
441			y: &testpb.TestAllTypes{RepeatedSfixed64: []int64{1, 3}},
442		}, {
443			x: &testpb.TestAllTypes{RepeatedFloat: []float32{1, 2}},
444			y: &testpb.TestAllTypes{RepeatedFloat: []float32{1, 3}},
445		}, {
446			x: &testpb.TestAllTypes{RepeatedDouble: []float64{1, 2}},
447			y: &testpb.TestAllTypes{RepeatedDouble: []float64{1, 3}},
448		}, {
449			x: &testpb.TestAllTypes{RepeatedBool: []bool{true, false}},
450			y: &testpb.TestAllTypes{RepeatedBool: []bool{true, true}},
451		}, {
452			x: &testpb.TestAllTypes{RepeatedString: []string{"a", "b"}},
453			y: &testpb.TestAllTypes{RepeatedString: []string{"a", "c"}},
454		}, {
455			x: &testpb.TestAllTypes{RepeatedBytes: [][]byte{[]byte("a"), []byte("b")}},
456			y: &testpb.TestAllTypes{RepeatedBytes: [][]byte{[]byte("a"), []byte("c")}},
457		}, {
458			x: &testpb.TestAllTypes{RepeatedNestedEnum: []testpb.TestAllTypes_NestedEnum{testpb.TestAllTypes_FOO}},
459			y: &testpb.TestAllTypes{RepeatedNestedEnum: []testpb.TestAllTypes_NestedEnum{testpb.TestAllTypes_BAR}},
460		}, {
461			x: &testpb.TestAllTypes{Repeatedgroup: []*testpb.TestAllTypes_RepeatedGroup{
462				{A: proto.Int32(1)},
463				{A: proto.Int32(2)},
464			}},
465			y: &testpb.TestAllTypes{Repeatedgroup: []*testpb.TestAllTypes_RepeatedGroup{
466				{A: proto.Int32(1)},
467				{A: proto.Int32(3)},
468			}},
469		}, {
470			x: &testpb.TestAllTypes{RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{
471				{A: proto.Int32(1)},
472				{A: proto.Int32(2)},
473			}},
474			y: &testpb.TestAllTypes{RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{
475				{A: proto.Int32(1)},
476				{A: proto.Int32(3)},
477			}},
478		},
479
480		// Maps: various configurations.
481		{
482			x: &testpb.TestAllTypes{MapInt32Int32: map[int32]int32{1: 2}},
483			y: &testpb.TestAllTypes{MapInt32Int32: map[int32]int32{3: 4}},
484		}, {
485			x: &testpb.TestAllTypes{MapInt32Int32: map[int32]int32{1: 2}},
486			y: &testpb.TestAllTypes{MapInt32Int32: map[int32]int32{1: 2, 3: 4}},
487		}, {
488			x: &testpb.TestAllTypes{MapInt32Int32: map[int32]int32{1: 2, 3: 4}},
489			y: &testpb.TestAllTypes{MapInt32Int32: map[int32]int32{1: 2}},
490		},
491
492		// Maps: various types.
493		{
494			x: &testpb.TestAllTypes{MapInt32Int32: map[int32]int32{1: 2, 3: 4}},
495			y: &testpb.TestAllTypes{MapInt32Int32: map[int32]int32{1: 2, 3: 5}},
496		}, {
497			x: &testpb.TestAllTypes{MapInt64Int64: map[int64]int64{1: 2, 3: 4}},
498			y: &testpb.TestAllTypes{MapInt64Int64: map[int64]int64{1: 2, 3: 5}},
499		}, {
500			x: &testpb.TestAllTypes{MapUint32Uint32: map[uint32]uint32{1: 2, 3: 4}},
501			y: &testpb.TestAllTypes{MapUint32Uint32: map[uint32]uint32{1: 2, 3: 5}},
502		}, {
503			x: &testpb.TestAllTypes{MapUint64Uint64: map[uint64]uint64{1: 2, 3: 4}},
504			y: &testpb.TestAllTypes{MapUint64Uint64: map[uint64]uint64{1: 2, 3: 5}},
505		}, {
506			x: &testpb.TestAllTypes{MapSint32Sint32: map[int32]int32{1: 2, 3: 4}},
507			y: &testpb.TestAllTypes{MapSint32Sint32: map[int32]int32{1: 2, 3: 5}},
508		}, {
509			x: &testpb.TestAllTypes{MapSint64Sint64: map[int64]int64{1: 2, 3: 4}},
510			y: &testpb.TestAllTypes{MapSint64Sint64: map[int64]int64{1: 2, 3: 5}},
511		}, {
512			x: &testpb.TestAllTypes{MapFixed32Fixed32: map[uint32]uint32{1: 2, 3: 4}},
513			y: &testpb.TestAllTypes{MapFixed32Fixed32: map[uint32]uint32{1: 2, 3: 5}},
514		}, {
515			x: &testpb.TestAllTypes{MapFixed64Fixed64: map[uint64]uint64{1: 2, 3: 4}},
516			y: &testpb.TestAllTypes{MapFixed64Fixed64: map[uint64]uint64{1: 2, 3: 5}},
517		}, {
518			x: &testpb.TestAllTypes{MapSfixed32Sfixed32: map[int32]int32{1: 2, 3: 4}},
519			y: &testpb.TestAllTypes{MapSfixed32Sfixed32: map[int32]int32{1: 2, 3: 5}},
520		}, {
521			x: &testpb.TestAllTypes{MapSfixed64Sfixed64: map[int64]int64{1: 2, 3: 4}},
522			y: &testpb.TestAllTypes{MapSfixed64Sfixed64: map[int64]int64{1: 2, 3: 5}},
523		}, {
524			x: &testpb.TestAllTypes{MapInt32Float: map[int32]float32{1: 2, 3: 4}},
525			y: &testpb.TestAllTypes{MapInt32Float: map[int32]float32{1: 2, 3: 5}},
526		}, {
527			x: &testpb.TestAllTypes{MapInt32Double: map[int32]float64{1: 2, 3: 4}},
528			y: &testpb.TestAllTypes{MapInt32Double: map[int32]float64{1: 2, 3: 5}},
529		}, {
530			x: &testpb.TestAllTypes{MapBoolBool: map[bool]bool{true: false, false: true}},
531			y: &testpb.TestAllTypes{MapBoolBool: map[bool]bool{true: false, false: false}},
532		}, {
533			x: &testpb.TestAllTypes{MapStringString: map[string]string{"a": "b", "c": "d"}},
534			y: &testpb.TestAllTypes{MapStringString: map[string]string{"a": "b", "c": "e"}},
535		}, {
536			x: &testpb.TestAllTypes{MapStringBytes: map[string][]byte{"a": []byte("b"), "c": []byte("d")}},
537			y: &testpb.TestAllTypes{MapStringBytes: map[string][]byte{"a": []byte("b"), "c": []byte("e")}},
538		}, {
539			x: &testpb.TestAllTypes{MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{
540				"a": {A: proto.Int32(1)},
541				"b": {A: proto.Int32(2)},
542			}},
543			y: &testpb.TestAllTypes{MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{
544				"a": {A: proto.Int32(1)},
545				"b": {A: proto.Int32(3)},
546			}},
547		}, {
548			x: &testpb.TestAllTypes{MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{
549				"a": testpb.TestAllTypes_FOO,
550				"b": testpb.TestAllTypes_BAR,
551			}},
552			y: &testpb.TestAllTypes{MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{
553				"a": testpb.TestAllTypes_FOO,
554				"b": testpb.TestAllTypes_BAZ,
555			}},
556		},
557
558		// Extensions.
559		{
560			x: build(&testpb.TestAllExtensions{},
561				extend(testpb.E_OptionalInt32, int32(1)),
562			),
563			y: build(&testpb.TestAllExtensions{},
564				extend(testpb.E_OptionalInt32, int32(2)),
565			),
566		}, {
567			x: &testpb.TestAllExtensions{},
568			y: build(&testpb.TestAllExtensions{},
569				extend(testpb.E_OptionalInt32, int32(2)),
570			),
571		},
572
573		// Unknown fields.
574		{
575			x: build(&testpb.TestAllTypes{}, unknown(protopack.Message{
576				protopack.Tag{100000, protopack.VarintType}, protopack.Varint(1),
577			}.Marshal())),
578			y: build(&testpb.TestAllTypes{}, unknown(protopack.Message{
579				protopack.Tag{100000, protopack.VarintType}, protopack.Varint(2),
580			}.Marshal())),
581		}, {
582			x: build(&testpb.TestAllTypes{}, unknown(protopack.Message{
583				protopack.Tag{100000, protopack.VarintType}, protopack.Varint(1),
584			}.Marshal())),
585			y: &testpb.TestAllTypes{},
586		},
587	}
588
589	for _, tt := range tests {
590		if !tt.eq && !proto.Equal(tt.x, tt.x) {
591			t.Errorf("Equal(x, x) = false, want true\n==== x ====\n%v", prototext.Format(tt.x))
592		}
593		if !tt.eq && !proto.Equal(tt.y, tt.y) {
594			t.Errorf("Equal(y, y) = false, want true\n==== y ====\n%v", prototext.Format(tt.y))
595		}
596		if eq := proto.Equal(tt.x, tt.y); eq != tt.eq {
597			t.Errorf("Equal(x, y) = %v, want %v\n==== x ====\n%v==== y ====\n%v", eq, tt.eq, prototext.Format(tt.x), prototext.Format(tt.y))
598		}
599	}
600}
601
602func BenchmarkEqualWithSmallEmpty(b *testing.B) {
603	x := &testpb.ForeignMessage{}
604	y := &testpb.ForeignMessage{}
605
606	b.ResetTimer()
607	for i := 0; i < b.N; i++ {
608		proto.Equal(x, y)
609	}
610}
611
612func BenchmarkEqualWithIdenticalPtrEmpty(b *testing.B) {
613	x := &testpb.ForeignMessage{}
614
615	b.ResetTimer()
616	for i := 0; i < b.N; i++ {
617		proto.Equal(x, x)
618	}
619}
620
621func BenchmarkEqualWithLargeEmpty(b *testing.B) {
622	x := &testpb.TestAllTypes{}
623	y := &testpb.TestAllTypes{}
624
625	b.ResetTimer()
626	for i := 0; i < b.N; i++ {
627		proto.Equal(x, y)
628	}
629}
630
631func makeNested(depth int) *testpb.TestAllTypes {
632	if depth <= 0 {
633		return nil
634	}
635	return &testpb.TestAllTypes{
636		OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
637			Corecursive: makeNested(depth - 1),
638		},
639	}
640}
641
642func BenchmarkEqualWithDeeplyNestedEqual(b *testing.B) {
643	x := makeNested(20)
644	y := makeNested(20)
645
646	b.ResetTimer()
647	for i := 0; i < b.N; i++ {
648		proto.Equal(x, y)
649	}
650}
651
652func BenchmarkEqualWithDeeplyNestedDifferent(b *testing.B) {
653	x := makeNested(20)
654	y := makeNested(21)
655
656	b.ResetTimer()
657	for i := 0; i < b.N; i++ {
658		proto.Equal(x, y)
659	}
660}
661
662func BenchmarkEqualWithDeeplyNestedIdenticalPtr(b *testing.B) {
663	x := makeNested(20)
664
665	b.ResetTimer()
666	for i := 0; i < b.N; i++ {
667		proto.Equal(x, x)
668	}
669}
670