1
2
3
4
5 package proto_test
6
7 import (
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 var cloneTestMessage = &pb2.MyMessage{
17 Count: proto.Int32(42),
18 Name: proto.String("Dave"),
19 Pet: []string{"bunny", "kitty", "horsey"},
20 Inner: &pb2.InnerMessage{
21 Host: proto.String("niles"),
22 Port: proto.Int32(9099),
23 Connected: proto.Bool(true),
24 },
25 Others: []*pb2.OtherMessage{
26 {
27 Value: []byte("some bytes"),
28 },
29 },
30 Somegroup: &pb2.MyMessage_SomeGroup{
31 GroupField: proto.Int32(6),
32 },
33 RepBytes: [][]byte{[]byte("sham"), []byte("wow")},
34 }
35
36 func init() {
37 ext := &pb2.Ext{
38 Data: proto.String("extension"),
39 }
40 if err := proto.SetExtension(cloneTestMessage, pb2.E_Ext_More, ext); err != nil {
41 panic("SetExtension: " + err.Error())
42 }
43 if err := proto.SetExtension(cloneTestMessage, pb2.E_Ext_Text, proto.String("hello")); err != nil {
44 panic("SetExtension: " + err.Error())
45 }
46 if err := proto.SetExtension(cloneTestMessage, pb2.E_Greeting, []string{"one", "two"}); err != nil {
47 panic("SetExtension: " + err.Error())
48 }
49 }
50
51 func TestClone(t *testing.T) {
52
53 vanilla := new(pb2.MyMessage)
54 b, err := proto.Marshal(cloneTestMessage)
55 if err != nil {
56 t.Errorf("unexpected Marshal error: %v", err)
57 }
58 if err := proto.Unmarshal(b, vanilla); err != nil {
59 t.Errorf("unexpected Unarshal error: %v", err)
60 }
61
62
63 m := proto.Clone(cloneTestMessage).(*pb2.MyMessage)
64 if !proto.Equal(m, cloneTestMessage) {
65 t.Fatalf("Clone(%v) = %v", cloneTestMessage, m)
66 }
67
68
69 x1, err := proto.GetExtension(m, pb2.E_Ext_More)
70 if err != nil {
71 t.Errorf("unexpected GetExtension(%v) error: %v", pb2.E_Ext_More.Name, err)
72 }
73 x2, err := proto.GetExtension(m, pb2.E_Ext_Text)
74 if err != nil {
75 t.Errorf("unexpected GetExtension(%v) error: %v", pb2.E_Ext_Text.Name, err)
76 }
77 x3, err := proto.GetExtension(m, pb2.E_Greeting)
78 if err != nil {
79 t.Errorf("unexpected GetExtension(%v) error: %v", pb2.E_Greeting.Name, err)
80 }
81 *m.Inner.Port++
82 *(x1.(*pb2.Ext)).Data = "blah blah"
83 *(x2.(*string)) = "goodbye"
84 x3.([]string)[0] = "zero"
85 if !proto.Equal(cloneTestMessage, vanilla) {
86 t.Fatalf("mutation on original detected:\ngot %v\nwant %v", cloneTestMessage, vanilla)
87 }
88 }
89
90 func TestCloneNil(t *testing.T) {
91 var m *pb2.MyMessage
92 if c := proto.Clone(m); !proto.Equal(m, c) {
93 t.Errorf("Clone(%v) = %v", m, c)
94 }
95 }
96
97 var mergeTests = []struct {
98 src, dst, want proto.Message
99 }{
100 {
101 src: &pb2.MyMessage{
102 Count: proto.Int32(42),
103 },
104 dst: &pb2.MyMessage{
105 Name: proto.String("Dave"),
106 },
107 want: &pb2.MyMessage{
108 Count: proto.Int32(42),
109 Name: proto.String("Dave"),
110 },
111 },
112 {
113 src: &pb2.MyMessage{
114 Inner: &pb2.InnerMessage{
115 Host: proto.String("hey"),
116 Connected: proto.Bool(true),
117 },
118 Pet: []string{"horsey"},
119 Others: []*pb2.OtherMessage{
120 {
121 Value: []byte("some bytes"),
122 },
123 },
124 },
125 dst: &pb2.MyMessage{
126 Inner: &pb2.InnerMessage{
127 Host: proto.String("niles"),
128 Port: proto.Int32(9099),
129 },
130 Pet: []string{"bunny", "kitty"},
131 Others: []*pb2.OtherMessage{
132 {
133 Key: proto.Int64(31415926535),
134 },
135 {
136
137 Inner: nil,
138 },
139 },
140 },
141 want: &pb2.MyMessage{
142 Inner: &pb2.InnerMessage{
143 Host: proto.String("hey"),
144 Connected: proto.Bool(true),
145 Port: proto.Int32(9099),
146 },
147 Pet: []string{"bunny", "kitty", "horsey"},
148 Others: []*pb2.OtherMessage{
149 {
150 Key: proto.Int64(31415926535),
151 },
152 {},
153 {
154 Value: []byte("some bytes"),
155 },
156 },
157 },
158 },
159 {
160 src: &pb2.MyMessage{
161 RepBytes: [][]byte{[]byte("wow")},
162 },
163 dst: &pb2.MyMessage{
164 Somegroup: &pb2.MyMessage_SomeGroup{
165 GroupField: proto.Int32(6),
166 },
167 RepBytes: [][]byte{[]byte("sham")},
168 },
169 want: &pb2.MyMessage{
170 Somegroup: &pb2.MyMessage_SomeGroup{
171 GroupField: proto.Int32(6),
172 },
173 RepBytes: [][]byte{[]byte("sham"), []byte("wow")},
174 },
175 },
176
177 {
178 src: &pb2.OtherMessage{Value: []byte("foo")},
179 dst: &pb2.OtherMessage{Value: []byte("bar")},
180 want: &pb2.OtherMessage{Value: []byte("foo")},
181 },
182 {
183 src: &pb2.MessageWithMap{
184 NameMapping: map[int32]string{6: "Nigel"},
185 MsgMapping: map[int64]*pb2.FloatingPoint{
186 0x4001: &pb2.FloatingPoint{F: proto.Float64(2.0)},
187 0x4002: &pb2.FloatingPoint{
188 F: proto.Float64(2.0),
189 },
190 },
191 ByteMapping: map[bool][]byte{true: []byte("wowsa")},
192 },
193 dst: &pb2.MessageWithMap{
194 NameMapping: map[int32]string{
195 6: "Bruce",
196 7: "Andrew",
197 },
198 MsgMapping: map[int64]*pb2.FloatingPoint{
199 0x4002: &pb2.FloatingPoint{
200 F: proto.Float64(3.0),
201 Exact: proto.Bool(true),
202 },
203 },
204 },
205 want: &pb2.MessageWithMap{
206 NameMapping: map[int32]string{
207 6: "Nigel",
208 7: "Andrew",
209 },
210 MsgMapping: map[int64]*pb2.FloatingPoint{
211 0x4001: &pb2.FloatingPoint{F: proto.Float64(2.0)},
212 0x4002: &pb2.FloatingPoint{
213 F: proto.Float64(2.0),
214 },
215 },
216 ByteMapping: map[bool][]byte{true: []byte("wowsa")},
217 },
218 },
219
220
221 {
222 src: &pb3.Message{
223 Name: "Aaron",
224 Data: []byte(""),
225 },
226 dst: &pb3.Message{
227 HeightInCm: 176,
228 Data: []byte("texas!"),
229 },
230 want: &pb3.Message{
231 Name: "Aaron",
232 HeightInCm: 176,
233 Data: []byte("texas!"),
234 },
235 },
236 {
237 src: &pb2.Communique{Union: &pb2.Communique_Number{41}},
238 dst: &pb2.Communique{Union: &pb2.Communique_Name{"Bobby Tables"}},
239 want: &pb2.Communique{Union: &pb2.Communique_Number{41}},
240 },
241 {
242 src: &pb2.Communique{},
243 dst: &pb2.Communique{Union: &pb2.Communique_Name{"Bobby Tables"}},
244 want: &pb2.Communique{Union: &pb2.Communique_Name{"Bobby Tables"}},
245 },
246 {
247 src: &pb2.Communique{Union: &pb2.Communique_Number{1337}},
248 dst: &pb2.Communique{},
249 want: &pb2.Communique{Union: &pb2.Communique_Number{1337}},
250 },
251 {
252 src: &pb2.Communique{Union: &pb2.Communique_Col{pb2.MyMessage_RED}},
253 dst: &pb2.Communique{},
254 want: &pb2.Communique{Union: &pb2.Communique_Col{pb2.MyMessage_RED}},
255 },
256 {
257 src: &pb2.Communique{Union: &pb2.Communique_Data{[]byte("hello")}},
258 dst: &pb2.Communique{},
259 want: &pb2.Communique{Union: &pb2.Communique_Data{[]byte("hello")}},
260 },
261 {
262 src: &pb2.Communique{Union: &pb2.Communique_Msg{&pb2.Strings{BytesField: []byte{1, 2, 3}}}},
263 dst: &pb2.Communique{},
264 want: &pb2.Communique{Union: &pb2.Communique_Msg{&pb2.Strings{BytesField: []byte{1, 2, 3}}}},
265 },
266 {
267 src: &pb2.Communique{Union: &pb2.Communique_Msg{}},
268 dst: &pb2.Communique{},
269 want: &pb2.Communique{Union: &pb2.Communique_Msg{}},
270 },
271 {
272 src: &pb2.Communique{Union: &pb2.Communique_Msg{&pb2.Strings{StringField: proto.String("123")}}},
273 dst: &pb2.Communique{Union: &pb2.Communique_Msg{&pb2.Strings{BytesField: []byte{1, 2, 3}}}},
274 want: &pb2.Communique{Union: &pb2.Communique_Msg{&pb2.Strings{StringField: proto.String("123"), BytesField: []byte{1, 2, 3}}}},
275 },
276 {
277 src: &pb3.Message{
278 Terrain: map[string]*pb3.Nested{
279 "kay_a": &pb3.Nested{Cute: true},
280 "kay_b": &pb3.Nested{Bunny: "rabbit"},
281 },
282 },
283 dst: &pb3.Message{
284 Terrain: map[string]*pb3.Nested{
285 "kay_a": &pb3.Nested{Bunny: "lost"},
286 "kay_c": &pb3.Nested{Bunny: "bunny"},
287 },
288 },
289 want: &pb3.Message{
290 Terrain: map[string]*pb3.Nested{
291 "kay_a": &pb3.Nested{Cute: true},
292 "kay_b": &pb3.Nested{Bunny: "rabbit"},
293 "kay_c": &pb3.Nested{Bunny: "bunny"},
294 },
295 },
296 },
297 {
298 src: &pb2.GoTest{
299 F_BoolRepeated: []bool{},
300 F_Int32Repeated: []int32{},
301 F_Int64Repeated: []int64{},
302 F_Uint32Repeated: []uint32{},
303 F_Uint64Repeated: []uint64{},
304 F_FloatRepeated: []float32{},
305 F_DoubleRepeated: []float64{},
306 F_StringRepeated: []string{},
307 F_BytesRepeated: [][]byte{},
308 },
309 dst: &pb2.GoTest{},
310 want: &pb2.GoTest{
311 F_BoolRepeated: []bool{},
312 F_Int32Repeated: []int32{},
313 F_Int64Repeated: []int64{},
314 F_Uint32Repeated: []uint32{},
315 F_Uint64Repeated: []uint64{},
316 F_FloatRepeated: []float32{},
317 F_DoubleRepeated: []float64{},
318 F_StringRepeated: []string{},
319 F_BytesRepeated: [][]byte{},
320 },
321 },
322 {
323 src: &pb2.GoTest{},
324 dst: &pb2.GoTest{
325 F_BoolRepeated: []bool{},
326 F_Int32Repeated: []int32{},
327 F_Int64Repeated: []int64{},
328 F_Uint32Repeated: []uint32{},
329 F_Uint64Repeated: []uint64{},
330 F_FloatRepeated: []float32{},
331 F_DoubleRepeated: []float64{},
332 F_StringRepeated: []string{},
333 F_BytesRepeated: [][]byte{},
334 },
335 want: &pb2.GoTest{
336 F_BoolRepeated: []bool{},
337 F_Int32Repeated: []int32{},
338 F_Int64Repeated: []int64{},
339 F_Uint32Repeated: []uint32{},
340 F_Uint64Repeated: []uint64{},
341 F_FloatRepeated: []float32{},
342 F_DoubleRepeated: []float64{},
343 F_StringRepeated: []string{},
344 F_BytesRepeated: [][]byte{},
345 },
346 },
347 {
348 src: &pb2.GoTest{
349 F_BytesRepeated: [][]byte{nil, []byte{}, []byte{0}},
350 },
351 dst: &pb2.GoTest{},
352 want: &pb2.GoTest{
353 F_BytesRepeated: [][]byte{nil, []byte{}, []byte{0}},
354 },
355 },
356 {
357 src: &pb2.MyMessage{
358 Others: []*pb2.OtherMessage{},
359 },
360 dst: &pb2.MyMessage{},
361 want: &pb2.MyMessage{
362 Others: []*pb2.OtherMessage{},
363 },
364 },
365 }
366
367 func TestMerge(t *testing.T) {
368 for _, m := range mergeTests {
369 got := proto.Clone(m.dst)
370 if !proto.Equal(got, m.dst) {
371 t.Errorf("Clone()\ngot %v\nwant %v", got, m.dst)
372 continue
373 }
374 proto.Merge(got, m.src)
375 if !proto.Equal(got, m.want) {
376 t.Errorf("Merge(%v, %v)\ngot %v\nwant %v", m.dst, m.src, got, m.want)
377 }
378 }
379 }
380
View as plain text