aboutsummaryrefslogtreecommitdiff
path: root/proto/equal_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'proto/equal_test.go')
-rw-r--r--proto/equal_test.go105
1 files changed, 105 insertions, 0 deletions
diff --git a/proto/equal_test.go b/proto/equal_test.go
index 2def30f1..db7ac6fe 100644
--- a/proto/equal_test.go
+++ b/proto/equal_test.go
@@ -9,6 +9,7 @@ import (
"testing"
"google.golang.org/protobuf/encoding/prototext"
+ "google.golang.org/protobuf/internal/pragma"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/testing/protopack"
@@ -17,6 +18,13 @@ import (
)
func TestEqual(t *testing.T) {
+ identicalPtrPb := &testpb.TestAllTypes{MapStringString: map[string]string{"a": "b", "c": "d"}}
+
+ type incomparableMessage struct {
+ *testpb.TestAllTypes
+ pragma.DoNotCompare
+ }
+
tests := []struct {
x, y proto.Message
eq bool
@@ -55,6 +63,34 @@ func TestEqual(t *testing.T) {
eq: false,
},
+ // Identical input pointers
+ {
+ x: identicalPtrPb,
+ y: identicalPtrPb,
+ eq: true,
+ },
+
+ // Incomparable types. The top-level types are not actually directly
+ // compared (which would panic), but rather the comparison happens on the
+ // objects returned by ProtoReflect(). These tests are here just to ensure
+ // that any short-circuit checks do not accidentally try to compare
+ // incomparable top-level types.
+ {
+ x: incomparableMessage{TestAllTypes: identicalPtrPb},
+ y: incomparableMessage{TestAllTypes: identicalPtrPb},
+ eq: true,
+ },
+ {
+ x: identicalPtrPb,
+ y: incomparableMessage{TestAllTypes: identicalPtrPb},
+ eq: true,
+ },
+ {
+ x: identicalPtrPb,
+ y: &incomparableMessage{TestAllTypes: identicalPtrPb},
+ eq: true,
+ },
+
// Proto2 scalars.
{
x: &testpb.TestAllTypes{OptionalInt32: proto.Int32(1)},
@@ -562,3 +598,72 @@ func TestEqual(t *testing.T) {
}
}
}
+
+func BenchmarkEqualWithSmallEmpty(b *testing.B) {
+ x := &testpb.ForeignMessage{}
+ y := &testpb.ForeignMessage{}
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ proto.Equal(x, y)
+ }
+}
+
+func BenchmarkEqualWithIdenticalPtrEmpty(b *testing.B) {
+ x := &testpb.ForeignMessage{}
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ proto.Equal(x, x)
+ }
+}
+
+func BenchmarkEqualWithLargeEmpty(b *testing.B) {
+ x := &testpb.TestAllTypes{}
+ y := &testpb.TestAllTypes{}
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ proto.Equal(x, y)
+ }
+}
+
+func makeNested(depth int) *testpb.TestAllTypes {
+ if depth <= 0 {
+ return nil
+ }
+ return &testpb.TestAllTypes{
+ OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
+ Corecursive: makeNested(depth - 1),
+ },
+ }
+}
+
+func BenchmarkEqualWithDeeplyNestedEqual(b *testing.B) {
+ x := makeNested(20)
+ y := makeNested(20)
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ proto.Equal(x, y)
+ }
+}
+
+func BenchmarkEqualWithDeeplyNestedDifferent(b *testing.B) {
+ x := makeNested(20)
+ y := makeNested(21)
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ proto.Equal(x, y)
+ }
+}
+
+func BenchmarkEqualWithDeeplyNestedIdenticalPtr(b *testing.B) {
+ x := makeNested(20)
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ proto.Equal(x, x)
+ }
+}