1// Copyright 2011 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 "testing" 9 10 "github.com/golang/protobuf/proto" 11 12 pb2 "github.com/golang/protobuf/internal/testprotos/proto2_proto" 13 pb3 "github.com/golang/protobuf/internal/testprotos/proto3_proto" 14) 15 16// Four identical base messages. 17// The init function adds extensions to some of them. 18var messageWithoutExtension = &pb2.MyMessage{Count: proto.Int32(7)} 19var messageWithExtension1a = &pb2.MyMessage{Count: proto.Int32(7)} 20var messageWithExtension1b = &pb2.MyMessage{Count: proto.Int32(7)} 21var messageWithExtension2 = &pb2.MyMessage{Count: proto.Int32(7)} 22var messageWithExtension3a = &pb2.MyMessage{Count: proto.Int32(7)} 23var messageWithExtension3b = &pb2.MyMessage{Count: proto.Int32(7)} 24var messageWithExtension3c = &pb2.MyMessage{Count: proto.Int32(7)} 25 26// Two messages with non-message extensions. 27var messageWithInt32Extension1 = &pb2.MyMessage{Count: proto.Int32(8)} 28var messageWithInt32Extension2 = &pb2.MyMessage{Count: proto.Int32(8)} 29 30func init() { 31 ext1 := &pb2.Ext{Data: proto.String("Kirk")} 32 ext2 := &pb2.Ext{Data: proto.String("Picard")} 33 34 // messageWithExtension1a has ext1, but never marshals it. 35 if err := proto.SetExtension(messageWithExtension1a, pb2.E_Ext_More, ext1); err != nil { 36 panic("proto.SetExtension on 1a failed: " + err.Error()) 37 } 38 39 // messageWithExtension1b is the unmarshaled form of messageWithExtension1a. 40 if err := proto.SetExtension(messageWithExtension1b, pb2.E_Ext_More, ext1); err != nil { 41 panic("proto.SetExtension on 1b failed: " + err.Error()) 42 } 43 buf, err := proto.Marshal(messageWithExtension1b) 44 if err != nil { 45 panic("proto.Marshal of 1b failed: " + err.Error()) 46 } 47 messageWithExtension1b.Reset() 48 if err := proto.Unmarshal(buf, messageWithExtension1b); err != nil { 49 panic("proto.Unmarshal of 1b failed: " + err.Error()) 50 } 51 52 // messageWithExtension2 has ext2. 53 if err := proto.SetExtension(messageWithExtension2, pb2.E_Ext_More, ext2); err != nil { 54 panic("proto.SetExtension on 2 failed: " + err.Error()) 55 } 56 57 if err := proto.SetExtension(messageWithInt32Extension1, pb2.E_Ext_Number, proto.Int32(23)); err != nil { 58 panic("proto.SetExtension on Int32-1 failed: " + err.Error()) 59 } 60 if err := proto.SetExtension(messageWithInt32Extension1, pb2.E_Ext_Number, proto.Int32(24)); err != nil { 61 panic("proto.SetExtension on Int32-2 failed: " + err.Error()) 62 } 63 64 // messageWithExtension3{a,b,c} has unregistered extension. 65 if proto.RegisteredExtensions(messageWithExtension3a)[200] != nil { 66 panic("expect extension 200 unregistered") 67 } 68 bytes := []byte{ 69 0xc0, 0x0c, 0x01, // id=200, wiretype=0 (varint), data=1 70 } 71 bytes2 := []byte{ 72 0xc0, 0x0c, 0x02, // id=200, wiretype=0 (varint), data=2 73 } 74 proto.SetRawExtension(messageWithExtension3a, 200, bytes) 75 proto.SetRawExtension(messageWithExtension3b, 200, bytes) 76 proto.SetRawExtension(messageWithExtension3c, 200, bytes2) 77} 78 79var EqualTests = []struct { 80 desc string 81 a, b proto.Message 82 exp bool 83}{ 84 {"different types", &pb2.GoEnum{}, &pb2.GoTestField{}, false}, 85 {"equal empty", &pb2.GoEnum{}, &pb2.GoEnum{}, true}, 86 {"nil vs nil", nil, nil, true}, 87 {"typed nil vs typed nil", (*pb2.GoEnum)(nil), (*pb2.GoEnum)(nil), true}, 88 {"typed nil vs empty", (*pb2.GoEnum)(nil), &pb2.GoEnum{}, false}, 89 {"different typed nil", (*pb2.GoEnum)(nil), (*pb2.GoTestField)(nil), false}, 90 91 {"one set field, one unset field", &pb2.GoTestField{Label: proto.String("foo")}, &pb2.GoTestField{}, false}, 92 {"one set field zero, one unset field", &pb2.GoTest{Param: proto.Int32(0)}, &pb2.GoTest{}, false}, 93 {"different set fields", &pb2.GoTestField{Label: proto.String("foo")}, &pb2.GoTestField{Label: proto.String("bar")}, false}, 94 {"equal set", &pb2.GoTestField{Label: proto.String("foo")}, &pb2.GoTestField{Label: proto.String("foo")}, true}, 95 96 {"repeated, one set", &pb2.GoTest{F_Int32Repeated: []int32{2, 3}}, &pb2.GoTest{}, false}, 97 {"repeated, different length", &pb2.GoTest{F_Int32Repeated: []int32{2, 3}}, &pb2.GoTest{F_Int32Repeated: []int32{2}}, false}, 98 {"repeated, different value", &pb2.GoTest{F_Int32Repeated: []int32{2}}, &pb2.GoTest{F_Int32Repeated: []int32{3}}, false}, 99 {"repeated, equal", &pb2.GoTest{F_Int32Repeated: []int32{2, 4}}, &pb2.GoTest{F_Int32Repeated: []int32{2, 4}}, true}, 100 {"repeated, nil equal nil", &pb2.GoTest{F_Int32Repeated: nil}, &pb2.GoTest{F_Int32Repeated: nil}, true}, 101 {"repeated, nil equal empty", &pb2.GoTest{F_Int32Repeated: nil}, &pb2.GoTest{F_Int32Repeated: []int32{}}, true}, 102 {"repeated, empty equal nil", &pb2.GoTest{F_Int32Repeated: []int32{}}, &pb2.GoTest{F_Int32Repeated: nil}, true}, 103 104 { 105 "nested, different", 106 &pb2.GoTest{RequiredField: &pb2.GoTestField{Label: proto.String("foo")}}, 107 &pb2.GoTest{RequiredField: &pb2.GoTestField{Label: proto.String("bar")}}, 108 false, 109 }, 110 { 111 "nested, equal", 112 &pb2.GoTest{RequiredField: &pb2.GoTestField{Label: proto.String("wow")}}, 113 &pb2.GoTest{RequiredField: &pb2.GoTestField{Label: proto.String("wow")}}, 114 true, 115 }, 116 117 {"bytes", &pb2.OtherMessage{Value: []byte("foo")}, &pb2.OtherMessage{Value: []byte("foo")}, true}, 118 {"bytes, empty", &pb2.OtherMessage{Value: []byte{}}, &pb2.OtherMessage{Value: []byte{}}, true}, 119 {"bytes, empty vs nil", &pb2.OtherMessage{Value: []byte{}}, &pb2.OtherMessage{Value: nil}, false}, 120 { 121 "repeated bytes", 122 &pb2.MyMessage{RepBytes: [][]byte{[]byte("sham"), []byte("wow")}}, 123 &pb2.MyMessage{RepBytes: [][]byte{[]byte("sham"), []byte("wow")}}, 124 true, 125 }, 126 // In proto3, []byte{} and []byte(nil) are equal. 127 {"proto3 bytes, empty vs nil", &pb3.Message{Data: []byte{}}, &pb3.Message{Data: nil}, true}, 128 129 {"extension vs. no extension", messageWithoutExtension, messageWithExtension1a, false}, 130 {"extension vs. same extension", messageWithExtension1a, messageWithExtension1b, true}, 131 {"extension vs. different extension", messageWithExtension1a, messageWithExtension2, false}, 132 133 {"int32 extension vs. itself", messageWithInt32Extension1, messageWithInt32Extension1, true}, 134 {"int32 extension vs. a different int32", messageWithInt32Extension1, messageWithInt32Extension2, false}, 135 136 {"unregistered extension same", messageWithExtension3a, messageWithExtension3b, true}, 137 {"unregistered extension different", messageWithExtension3a, messageWithExtension3c, false}, 138 139 { 140 "message with group", 141 &pb2.MyMessage{ 142 Count: proto.Int32(1), 143 Somegroup: &pb2.MyMessage_SomeGroup{ 144 GroupField: proto.Int32(5), 145 }, 146 }, 147 &pb2.MyMessage{ 148 Count: proto.Int32(1), 149 Somegroup: &pb2.MyMessage_SomeGroup{ 150 GroupField: proto.Int32(5), 151 }, 152 }, 153 true, 154 }, 155 156 { 157 "map same", 158 &pb2.MessageWithMap{NameMapping: map[int32]string{1: "Ken"}}, 159 &pb2.MessageWithMap{NameMapping: map[int32]string{1: "Ken"}}, 160 true, 161 }, 162 { 163 "map different entry", 164 &pb2.MessageWithMap{NameMapping: map[int32]string{1: "Ken"}}, 165 &pb2.MessageWithMap{NameMapping: map[int32]string{2: "Rob"}}, 166 false, 167 }, 168 { 169 "map different key only", 170 &pb2.MessageWithMap{NameMapping: map[int32]string{1: "Ken"}}, 171 &pb2.MessageWithMap{NameMapping: map[int32]string{2: "Ken"}}, 172 false, 173 }, 174 { 175 "map different value only", 176 &pb2.MessageWithMap{NameMapping: map[int32]string{1: "Ken"}}, 177 &pb2.MessageWithMap{NameMapping: map[int32]string{1: "Rob"}}, 178 false, 179 }, 180 { 181 "zero-length maps same", 182 &pb2.MessageWithMap{NameMapping: map[int32]string{}}, 183 &pb2.MessageWithMap{NameMapping: nil}, 184 true, 185 }, 186 { 187 "orders in map don't matter", 188 &pb2.MessageWithMap{NameMapping: map[int32]string{1: "Ken", 2: "Rob"}}, 189 &pb2.MessageWithMap{NameMapping: map[int32]string{2: "Rob", 1: "Ken"}}, 190 true, 191 }, 192 { 193 "oneof same", 194 &pb2.Communique{Union: &pb2.Communique_Number{41}}, 195 &pb2.Communique{Union: &pb2.Communique_Number{41}}, 196 true, 197 }, 198 { 199 "oneof one nil", 200 &pb2.Communique{Union: &pb2.Communique_Number{41}}, 201 &pb2.Communique{}, 202 false, 203 }, 204 { 205 "oneof different", 206 &pb2.Communique{Union: &pb2.Communique_Number{41}}, 207 &pb2.Communique{Union: &pb2.Communique_Name{"Bobby Tables"}}, 208 false, 209 }, 210} 211 212func TestEqual(t *testing.T) { 213 for _, tc := range EqualTests { 214 if res := proto.Equal(tc.a, tc.b); res != tc.exp { 215 t.Errorf("%v: Equal(%v, %v) = %v, want %v", tc.desc, tc.a, tc.b, res, tc.exp) 216 } 217 } 218} 219