blob: 9b6ee0f5ad4647316b28d5971b2b8698b1679498 [file] [log] [blame]
Joe Tsai2fc306a2019-06-20 03:01:22 -07001// 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 (
Joe Tsaic9081442019-09-20 12:18:55 -07008 "sync"
Joe Tsai2fc306a2019-06-20 03:01:22 -07009 "testing"
10
11 "google.golang.org/protobuf/internal/encoding/pack"
Joe Tsai2fc306a2019-06-20 03:01:22 -070012 "google.golang.org/protobuf/proto"
13
14 testpb "google.golang.org/protobuf/internal/testprotos/test"
15)
16
17func TestMerge(t *testing.T) {
18 dst := new(testpb.TestAllTypes)
19 src := (*testpb.TestAllTypes)(nil)
20 proto.Merge(dst, src)
21
22 // Mutating the source should not affect dst.
23
24 tests := []struct {
25 desc string
26 dst proto.Message
27 src proto.Message
28 want proto.Message
29 mutator func(proto.Message) // if provided, is run on src after merging
Joe Tsai2fc306a2019-06-20 03:01:22 -070030 }{{
31 desc: "merge from nil message",
32 dst: new(testpb.TestAllTypes),
33 src: (*testpb.TestAllTypes)(nil),
34 want: new(testpb.TestAllTypes),
35 }, {
36 desc: "clone a large message",
37 dst: new(testpb.TestAllTypes),
38 src: &testpb.TestAllTypes{
Damien Neila8a2cea2019-07-10 16:17:16 -070039 OptionalInt64: proto.Int64(0),
Joe Tsai2fc306a2019-06-20 03:01:22 -070040 OptionalNestedEnum: testpb.TestAllTypes_NestedEnum(1).Enum(),
41 OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -070042 A: proto.Int32(100),
Joe Tsai2fc306a2019-06-20 03:01:22 -070043 },
44 RepeatedSfixed32: []int32{1, 2, 3},
45 RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -070046 {A: proto.Int32(200)},
47 {A: proto.Int32(300)},
Joe Tsai2fc306a2019-06-20 03:01:22 -070048 },
49 MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{
50 "fizz": 400,
51 "buzz": 500,
52 },
53 MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -070054 "foo": {A: proto.Int32(600)},
55 "bar": {A: proto.Int32(700)},
Joe Tsai2fc306a2019-06-20 03:01:22 -070056 },
57 OneofField: &testpb.TestAllTypes_OneofNestedMessage{
58 &testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -070059 A: proto.Int32(800),
Joe Tsai2fc306a2019-06-20 03:01:22 -070060 },
61 },
62 },
63 want: &testpb.TestAllTypes{
Damien Neila8a2cea2019-07-10 16:17:16 -070064 OptionalInt64: proto.Int64(0),
Joe Tsai2fc306a2019-06-20 03:01:22 -070065 OptionalNestedEnum: testpb.TestAllTypes_NestedEnum(1).Enum(),
66 OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -070067 A: proto.Int32(100),
Joe Tsai2fc306a2019-06-20 03:01:22 -070068 },
69 RepeatedSfixed32: []int32{1, 2, 3},
70 RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -070071 {A: proto.Int32(200)},
72 {A: proto.Int32(300)},
Joe Tsai2fc306a2019-06-20 03:01:22 -070073 },
74 MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{
75 "fizz": 400,
76 "buzz": 500,
77 },
78 MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -070079 "foo": {A: proto.Int32(600)},
80 "bar": {A: proto.Int32(700)},
Joe Tsai2fc306a2019-06-20 03:01:22 -070081 },
82 OneofField: &testpb.TestAllTypes_OneofNestedMessage{
83 &testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -070084 A: proto.Int32(800),
Joe Tsai2fc306a2019-06-20 03:01:22 -070085 },
86 },
87 },
88 mutator: func(mi proto.Message) {
89 m := mi.(*testpb.TestAllTypes)
90 *m.OptionalInt64++
91 *m.OptionalNestedEnum++
92 *m.OptionalNestedMessage.A++
93 m.RepeatedSfixed32[0]++
94 *m.RepeatedNestedMessage[0].A++
95 delete(m.MapStringNestedEnum, "fizz")
96 *m.MapStringNestedMessage["foo"].A++
97 *m.OneofField.(*testpb.TestAllTypes_OneofNestedMessage).OneofNestedMessage.A++
98 },
99 }, {
100 desc: "merge bytes",
101 dst: &testpb.TestAllTypes{
102 OptionalBytes: []byte{1, 2, 3},
103 RepeatedBytes: [][]byte{{1, 2}, {3, 4}},
104 MapStringBytes: map[string][]byte{"alpha": {1, 2, 3}},
105 },
106 src: &testpb.TestAllTypes{
107 OptionalBytes: []byte{4, 5, 6},
108 RepeatedBytes: [][]byte{{5, 6}, {7, 8}},
109 MapStringBytes: map[string][]byte{"alpha": {4, 5, 6}, "bravo": {1, 2, 3}},
110 },
111 want: &testpb.TestAllTypes{
112 OptionalBytes: []byte{4, 5, 6},
113 RepeatedBytes: [][]byte{{1, 2}, {3, 4}, {5, 6}, {7, 8}},
114 MapStringBytes: map[string][]byte{"alpha": {4, 5, 6}, "bravo": {1, 2, 3}},
115 },
116 mutator: func(mi proto.Message) {
117 m := mi.(*testpb.TestAllTypes)
118 m.OptionalBytes[0]++
119 m.RepeatedBytes[0][0]++
120 m.MapStringBytes["alpha"][0]++
121 },
122 }, {
123 desc: "merge singular fields",
124 dst: &testpb.TestAllTypes{
Damien Neila8a2cea2019-07-10 16:17:16 -0700125 OptionalInt32: proto.Int32(1),
126 OptionalInt64: proto.Int64(1),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700127 OptionalNestedEnum: testpb.TestAllTypes_NestedEnum(10).Enum(),
128 OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700129 A: proto.Int32(100),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700130 Corecursive: &testpb.TestAllTypes{
Damien Neila8a2cea2019-07-10 16:17:16 -0700131 OptionalInt64: proto.Int64(1000),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700132 },
133 },
134 },
135 src: &testpb.TestAllTypes{
Damien Neila8a2cea2019-07-10 16:17:16 -0700136 OptionalInt64: proto.Int64(2),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700137 OptionalNestedEnum: testpb.TestAllTypes_NestedEnum(20).Enum(),
138 OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700139 A: proto.Int32(200),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700140 },
141 },
142 want: &testpb.TestAllTypes{
Damien Neila8a2cea2019-07-10 16:17:16 -0700143 OptionalInt32: proto.Int32(1),
144 OptionalInt64: proto.Int64(2),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700145 OptionalNestedEnum: testpb.TestAllTypes_NestedEnum(20).Enum(),
146 OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700147 A: proto.Int32(200),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700148 Corecursive: &testpb.TestAllTypes{
Damien Neila8a2cea2019-07-10 16:17:16 -0700149 OptionalInt64: proto.Int64(1000),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700150 },
151 },
152 },
153 mutator: func(mi proto.Message) {
154 m := mi.(*testpb.TestAllTypes)
155 *m.OptionalInt64++
156 *m.OptionalNestedEnum++
157 *m.OptionalNestedMessage.A++
158 },
159 }, {
160 desc: "merge list fields",
161 dst: &testpb.TestAllTypes{
162 RepeatedSfixed32: []int32{1, 2, 3},
163 RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700164 {A: proto.Int32(100)},
165 {A: proto.Int32(200)},
Joe Tsai2fc306a2019-06-20 03:01:22 -0700166 },
167 },
168 src: &testpb.TestAllTypes{
169 RepeatedSfixed32: []int32{4, 5, 6},
170 RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700171 {A: proto.Int32(300)},
172 {A: proto.Int32(400)},
Joe Tsai2fc306a2019-06-20 03:01:22 -0700173 },
174 },
175 want: &testpb.TestAllTypes{
176 RepeatedSfixed32: []int32{1, 2, 3, 4, 5, 6},
177 RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700178 {A: proto.Int32(100)},
179 {A: proto.Int32(200)},
180 {A: proto.Int32(300)},
181 {A: proto.Int32(400)},
Joe Tsai2fc306a2019-06-20 03:01:22 -0700182 },
183 },
184 mutator: func(mi proto.Message) {
185 m := mi.(*testpb.TestAllTypes)
186 m.RepeatedSfixed32[0]++
187 *m.RepeatedNestedMessage[0].A++
188 },
189 }, {
190 desc: "merge map fields",
191 dst: &testpb.TestAllTypes{
192 MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{
193 "fizz": 100,
194 "buzz": 200,
195 "guzz": 300,
196 },
197 MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700198 "foo": {A: proto.Int32(400)},
Joe Tsai2fc306a2019-06-20 03:01:22 -0700199 },
200 },
201 src: &testpb.TestAllTypes{
202 MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{
203 "fizz": 1000,
204 "buzz": 2000,
205 },
206 MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700207 "foo": {A: proto.Int32(3000)},
Joe Tsai2fc306a2019-06-20 03:01:22 -0700208 "bar": {},
209 },
210 },
211 want: &testpb.TestAllTypes{
212 MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{
213 "fizz": 1000,
214 "buzz": 2000,
215 "guzz": 300,
216 },
217 MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700218 "foo": {A: proto.Int32(3000)},
Joe Tsai2fc306a2019-06-20 03:01:22 -0700219 "bar": {},
220 },
221 },
222 mutator: func(mi proto.Message) {
223 m := mi.(*testpb.TestAllTypes)
224 delete(m.MapStringNestedEnum, "fizz")
Damien Neila8a2cea2019-07-10 16:17:16 -0700225 m.MapStringNestedMessage["bar"].A = proto.Int32(1)
Joe Tsai2fc306a2019-06-20 03:01:22 -0700226 },
227 }, {
228 desc: "merge oneof message fields",
229 dst: &testpb.TestAllTypes{
230 OneofField: &testpb.TestAllTypes_OneofNestedMessage{
231 &testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700232 A: proto.Int32(100),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700233 },
234 },
235 },
236 src: &testpb.TestAllTypes{
237 OneofField: &testpb.TestAllTypes_OneofNestedMessage{
238 &testpb.TestAllTypes_NestedMessage{
239 Corecursive: &testpb.TestAllTypes{
Damien Neila8a2cea2019-07-10 16:17:16 -0700240 OptionalInt64: proto.Int64(1000),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700241 },
242 },
243 },
244 },
245 want: &testpb.TestAllTypes{
246 OneofField: &testpb.TestAllTypes_OneofNestedMessage{
247 &testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700248 A: proto.Int32(100),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700249 Corecursive: &testpb.TestAllTypes{
Damien Neila8a2cea2019-07-10 16:17:16 -0700250 OptionalInt64: proto.Int64(1000),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700251 },
252 },
253 },
254 },
255 mutator: func(mi proto.Message) {
256 m := mi.(*testpb.TestAllTypes)
257 *m.OneofField.(*testpb.TestAllTypes_OneofNestedMessage).OneofNestedMessage.Corecursive.OptionalInt64++
258 },
Joe Tsai2fc306a2019-06-20 03:01:22 -0700259 }, {
260 desc: "merge oneof scalar fields",
261 dst: &testpb.TestAllTypes{
262 OneofField: &testpb.TestAllTypes_OneofUint32{100},
263 },
264 src: &testpb.TestAllTypes{
265 OneofField: &testpb.TestAllTypes_OneofFloat{3.14152},
266 },
267 want: &testpb.TestAllTypes{
268 OneofField: &testpb.TestAllTypes_OneofFloat{3.14152},
269 },
270 mutator: func(mi proto.Message) {
271 m := mi.(*testpb.TestAllTypes)
272 m.OneofField.(*testpb.TestAllTypes_OneofFloat).OneofFloat++
273 },
274 }, {
275 desc: "merge extension fields",
276 dst: func() proto.Message {
277 m := new(testpb.TestAllExtensions)
Damien Neilf1e905b2019-08-08 15:45:59 -0700278 proto.SetExtension(m, testpb.E_OptionalInt32Extension, int32(32))
279 proto.SetExtension(m, testpb.E_OptionalNestedMessageExtension,
Damien Neil92f76182019-08-02 16:58:08 -0700280 &testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700281 A: proto.Int32(50),
Damien Neil92f76182019-08-02 16:58:08 -0700282 },
Joe Tsai2fc306a2019-06-20 03:01:22 -0700283 )
Damien Neil293dc762019-08-29 11:42:57 -0700284 proto.SetExtension(m, testpb.E_RepeatedFixed32Extension, []uint32{1, 2, 3})
Joe Tsai2fc306a2019-06-20 03:01:22 -0700285 return m
286 }(),
287 src: func() proto.Message {
288 m := new(testpb.TestAllExtensions)
Damien Neilf1e905b2019-08-08 15:45:59 -0700289 proto.SetExtension(m, testpb.E_OptionalInt64Extension, int64(64))
290 proto.SetExtension(m, testpb.E_OptionalNestedMessageExtension,
Damien Neil92f76182019-08-02 16:58:08 -0700291 &testpb.TestAllTypes_NestedMessage{
Joe Tsai2fc306a2019-06-20 03:01:22 -0700292 Corecursive: &testpb.TestAllTypes{
Damien Neila8a2cea2019-07-10 16:17:16 -0700293 OptionalInt64: proto.Int64(1000),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700294 },
Damien Neil92f76182019-08-02 16:58:08 -0700295 },
Joe Tsai2fc306a2019-06-20 03:01:22 -0700296 )
Damien Neil293dc762019-08-29 11:42:57 -0700297 proto.SetExtension(m, testpb.E_RepeatedFixed32Extension, []uint32{4, 5, 6})
Joe Tsai2fc306a2019-06-20 03:01:22 -0700298 return m
299 }(),
300 want: func() proto.Message {
301 m := new(testpb.TestAllExtensions)
Damien Neilf1e905b2019-08-08 15:45:59 -0700302 proto.SetExtension(m, testpb.E_OptionalInt32Extension, int32(32))
303 proto.SetExtension(m, testpb.E_OptionalInt64Extension, int64(64))
304 proto.SetExtension(m, testpb.E_OptionalNestedMessageExtension,
Damien Neil92f76182019-08-02 16:58:08 -0700305 &testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700306 A: proto.Int32(50),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700307 Corecursive: &testpb.TestAllTypes{
Damien Neila8a2cea2019-07-10 16:17:16 -0700308 OptionalInt64: proto.Int64(1000),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700309 },
Damien Neil92f76182019-08-02 16:58:08 -0700310 },
Joe Tsai2fc306a2019-06-20 03:01:22 -0700311 )
Damien Neil293dc762019-08-29 11:42:57 -0700312 proto.SetExtension(m, testpb.E_RepeatedFixed32Extension, []uint32{1, 2, 3, 4, 5, 6})
Joe Tsai2fc306a2019-06-20 03:01:22 -0700313 return m
314 }(),
315 }, {
316 desc: "merge unknown fields",
317 dst: func() proto.Message {
318 m := new(testpb.TestAllTypes)
319 m.ProtoReflect().SetUnknown(pack.Message{
320 pack.Tag{Number: 50000, Type: pack.VarintType}, pack.Svarint(-5),
321 }.Marshal())
322 return m
323 }(),
324 src: func() proto.Message {
325 m := new(testpb.TestAllTypes)
326 m.ProtoReflect().SetUnknown(pack.Message{
327 pack.Tag{Number: 500000, Type: pack.VarintType}, pack.Svarint(-50),
328 }.Marshal())
329 return m
330 }(),
331 want: func() proto.Message {
332 m := new(testpb.TestAllTypes)
333 m.ProtoReflect().SetUnknown(pack.Message{
334 pack.Tag{Number: 50000, Type: pack.VarintType}, pack.Svarint(-5),
335 pack.Tag{Number: 500000, Type: pack.VarintType}, pack.Svarint(-50),
336 }.Marshal())
337 return m
338 }(),
339 }}
340
341 for _, tt := range tests {
342 t.Run(tt.desc, func(t *testing.T) {
343 // Merge should be semantically equivalent to unmarshaling the
344 // encoded form of src into the current dst.
345 b1, err := proto.MarshalOptions{AllowPartial: true}.Marshal(tt.dst)
346 if err != nil {
347 t.Fatalf("Marshal(dst) error: %v", err)
348 }
349 b2, err := proto.MarshalOptions{AllowPartial: true}.Marshal(tt.src)
350 if err != nil {
351 t.Fatalf("Marshal(src) error: %v", err)
352 }
353 dst := tt.dst.ProtoReflect().New().Interface()
354 err = proto.UnmarshalOptions{AllowPartial: true}.Unmarshal(append(b1, b2...), dst)
355 if err != nil {
356 t.Fatalf("Unmarshal() error: %v", err)
357 }
Joe Tsai6c286742019-07-11 23:15:05 -0700358 if !proto.Equal(dst, tt.want) {
Joe Tsai2fc306a2019-06-20 03:01:22 -0700359 t.Fatalf("Unmarshal(Marshal(dst)+Marshal(src)) mismatch: got %v, want %v", dst, tt.want)
360 }
361
362 proto.Merge(tt.dst, tt.src)
363 if tt.mutator != nil {
364 tt.mutator(tt.src) // should not be observable by dst
365 }
366 if !proto.Equal(tt.dst, tt.want) {
Damien Neil293dc762019-08-29 11:42:57 -0700367 t.Fatalf("Merge() mismatch:\n got %v\nwant %v", tt.dst, tt.want)
Joe Tsai2fc306a2019-06-20 03:01:22 -0700368 }
369 })
370 }
371}
Joe Tsaic9081442019-09-20 12:18:55 -0700372
373func TestMergeRace(t *testing.T) {
374 dst := new(testpb.TestAllTypes)
375 srcs := []*testpb.TestAllTypes{
376 {OptionalInt32: proto.Int32(1)},
377 {OptionalString: proto.String("hello")},
378 {RepeatedInt32: []int32{2, 3, 4}},
379 {RepeatedString: []string{"goodbye"}},
380 {MapStringString: map[string]string{"key": "value"}},
381 {OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
382 A: proto.Int32(5),
383 }},
384 func() *testpb.TestAllTypes {
385 m := new(testpb.TestAllTypes)
386 m.ProtoReflect().SetUnknown(pack.Message{
387 pack.Tag{Number: 50000, Type: pack.VarintType}, pack.Svarint(-5),
388 }.Marshal())
389 return m
390 }(),
391 }
392
393 // It should be safe to concurrently merge non-overlapping fields.
394 var wg sync.WaitGroup
395 defer wg.Wait()
396 for _, src := range srcs {
397 wg.Add(1)
398 go func(src proto.Message) {
399 defer wg.Done()
400 proto.Merge(dst, src)
401 }(src)
402 }
403}
Joe Tsai641611d2019-09-21 21:50:50 -0700404
405func TestMergeSelf(t *testing.T) {
406 got := &testpb.TestAllTypes{
407 OptionalInt32: proto.Int32(1),
408 OptionalString: proto.String("hello"),
409 RepeatedInt32: []int32{2, 3, 4},
410 RepeatedString: []string{"goodbye"},
411 MapStringString: map[string]string{"key": "value"},
412 OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
413 A: proto.Int32(5),
414 },
415 }
416 got.ProtoReflect().SetUnknown(pack.Message{
417 pack.Tag{Number: 50000, Type: pack.VarintType}, pack.Svarint(-5),
418 }.Marshal())
419 proto.Merge(got, got)
420
421 // The main impact of merging to self is that repeated fields and
422 // unknown fields are doubled.
423 want := &testpb.TestAllTypes{
424 OptionalInt32: proto.Int32(1),
425 OptionalString: proto.String("hello"),
426 RepeatedInt32: []int32{2, 3, 4, 2, 3, 4},
427 RepeatedString: []string{"goodbye", "goodbye"},
428 MapStringString: map[string]string{"key": "value"},
429 OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
430 A: proto.Int32(5),
431 },
432 }
433 want.ProtoReflect().SetUnknown(pack.Message{
434 pack.Tag{Number: 50000, Type: pack.VarintType}, pack.Svarint(-5),
435 pack.Tag{Number: 50000, Type: pack.VarintType}, pack.Svarint(-5),
436 }.Marshal())
437
438 if !proto.Equal(got, want) {
439 t.Errorf("Equal mismatch:\ngot %v\nwant %v", got, want)
440 }
441}