blob: 18243cc473039b572a363eaa1c579fb12ca803de [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) {
Joe Tsai2fc306a2019-06-20 03:01:22 -070018
Joe Tsaice496b52020-01-02 15:47:15 -080019 t.Run("Deep", func(t *testing.T) { testMerge(t, false) })
20 t.Run("Shallow", func(t *testing.T) { testMerge(t, true) })
21}
Joe Tsai2fc306a2019-06-20 03:01:22 -070022
Joe Tsaice496b52020-01-02 15:47:15 -080023func testMerge(t *testing.T, shallow bool) {
Joe Tsai2fc306a2019-06-20 03:01:22 -070024 tests := []struct {
Joe Tsaice496b52020-01-02 15:47:15 -080025 desc string
26 dst proto.Message
27 src proto.Message
28 want proto.Message
29
30 // If provided, mutator is run on src after merging.
31 // It reports whether a mutation is expected to be observable in dst
32 // if Shallow is enabled.
33 mutator func(proto.Message) bool
Joe Tsai2fc306a2019-06-20 03:01:22 -070034 }{{
35 desc: "merge from nil message",
36 dst: new(testpb.TestAllTypes),
37 src: (*testpb.TestAllTypes)(nil),
38 want: new(testpb.TestAllTypes),
39 }, {
40 desc: "clone a large message",
41 dst: new(testpb.TestAllTypes),
42 src: &testpb.TestAllTypes{
Damien Neila8a2cea2019-07-10 16:17:16 -070043 OptionalInt64: proto.Int64(0),
Joe Tsai2fc306a2019-06-20 03:01:22 -070044 OptionalNestedEnum: testpb.TestAllTypes_NestedEnum(1).Enum(),
45 OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -070046 A: proto.Int32(100),
Joe Tsai2fc306a2019-06-20 03:01:22 -070047 },
48 RepeatedSfixed32: []int32{1, 2, 3},
49 RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -070050 {A: proto.Int32(200)},
51 {A: proto.Int32(300)},
Joe Tsai2fc306a2019-06-20 03:01:22 -070052 },
53 MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{
54 "fizz": 400,
55 "buzz": 500,
56 },
57 MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -070058 "foo": {A: proto.Int32(600)},
59 "bar": {A: proto.Int32(700)},
Joe Tsai2fc306a2019-06-20 03:01:22 -070060 },
61 OneofField: &testpb.TestAllTypes_OneofNestedMessage{
62 &testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -070063 A: proto.Int32(800),
Joe Tsai2fc306a2019-06-20 03:01:22 -070064 },
65 },
66 },
67 want: &testpb.TestAllTypes{
Damien Neila8a2cea2019-07-10 16:17:16 -070068 OptionalInt64: proto.Int64(0),
Joe Tsai2fc306a2019-06-20 03:01:22 -070069 OptionalNestedEnum: testpb.TestAllTypes_NestedEnum(1).Enum(),
70 OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -070071 A: proto.Int32(100),
Joe Tsai2fc306a2019-06-20 03:01:22 -070072 },
73 RepeatedSfixed32: []int32{1, 2, 3},
74 RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -070075 {A: proto.Int32(200)},
76 {A: proto.Int32(300)},
Joe Tsai2fc306a2019-06-20 03:01:22 -070077 },
78 MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{
79 "fizz": 400,
80 "buzz": 500,
81 },
82 MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -070083 "foo": {A: proto.Int32(600)},
84 "bar": {A: proto.Int32(700)},
Joe Tsai2fc306a2019-06-20 03:01:22 -070085 },
86 OneofField: &testpb.TestAllTypes_OneofNestedMessage{
87 &testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -070088 A: proto.Int32(800),
Joe Tsai2fc306a2019-06-20 03:01:22 -070089 },
90 },
91 },
Joe Tsaice496b52020-01-02 15:47:15 -080092 mutator: func(mi proto.Message) bool {
Joe Tsai2fc306a2019-06-20 03:01:22 -070093 m := mi.(*testpb.TestAllTypes)
94 *m.OptionalInt64++
95 *m.OptionalNestedEnum++
96 *m.OptionalNestedMessage.A++
97 m.RepeatedSfixed32[0]++
98 *m.RepeatedNestedMessage[0].A++
99 delete(m.MapStringNestedEnum, "fizz")
100 *m.MapStringNestedMessage["foo"].A++
101 *m.OneofField.(*testpb.TestAllTypes_OneofNestedMessage).OneofNestedMessage.A++
Joe Tsaice496b52020-01-02 15:47:15 -0800102 return true
Joe Tsai2fc306a2019-06-20 03:01:22 -0700103 },
104 }, {
105 desc: "merge bytes",
106 dst: &testpb.TestAllTypes{
107 OptionalBytes: []byte{1, 2, 3},
108 RepeatedBytes: [][]byte{{1, 2}, {3, 4}},
109 MapStringBytes: map[string][]byte{"alpha": {1, 2, 3}},
110 },
111 src: &testpb.TestAllTypes{
112 OptionalBytes: []byte{4, 5, 6},
113 RepeatedBytes: [][]byte{{5, 6}, {7, 8}},
114 MapStringBytes: map[string][]byte{"alpha": {4, 5, 6}, "bravo": {1, 2, 3}},
115 },
116 want: &testpb.TestAllTypes{
117 OptionalBytes: []byte{4, 5, 6},
118 RepeatedBytes: [][]byte{{1, 2}, {3, 4}, {5, 6}, {7, 8}},
119 MapStringBytes: map[string][]byte{"alpha": {4, 5, 6}, "bravo": {1, 2, 3}},
120 },
Joe Tsaice496b52020-01-02 15:47:15 -0800121 mutator: func(mi proto.Message) bool {
Joe Tsai2fc306a2019-06-20 03:01:22 -0700122 m := mi.(*testpb.TestAllTypes)
123 m.OptionalBytes[0]++
124 m.RepeatedBytes[0][0]++
125 m.MapStringBytes["alpha"][0]++
Joe Tsaice496b52020-01-02 15:47:15 -0800126 return true
Joe Tsai2fc306a2019-06-20 03:01:22 -0700127 },
128 }, {
129 desc: "merge singular fields",
130 dst: &testpb.TestAllTypes{
Damien Neila8a2cea2019-07-10 16:17:16 -0700131 OptionalInt32: proto.Int32(1),
132 OptionalInt64: proto.Int64(1),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700133 OptionalNestedEnum: testpb.TestAllTypes_NestedEnum(10).Enum(),
134 OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700135 A: proto.Int32(100),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700136 Corecursive: &testpb.TestAllTypes{
Damien Neila8a2cea2019-07-10 16:17:16 -0700137 OptionalInt64: proto.Int64(1000),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700138 },
139 },
140 },
141 src: &testpb.TestAllTypes{
Damien Neila8a2cea2019-07-10 16:17:16 -0700142 OptionalInt64: proto.Int64(2),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700143 OptionalNestedEnum: testpb.TestAllTypes_NestedEnum(20).Enum(),
144 OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700145 A: proto.Int32(200),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700146 },
147 },
148 want: &testpb.TestAllTypes{
Damien Neila8a2cea2019-07-10 16:17:16 -0700149 OptionalInt32: proto.Int32(1),
150 OptionalInt64: proto.Int64(2),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700151 OptionalNestedEnum: testpb.TestAllTypes_NestedEnum(20).Enum(),
152 OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700153 A: proto.Int32(200),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700154 Corecursive: &testpb.TestAllTypes{
Damien Neila8a2cea2019-07-10 16:17:16 -0700155 OptionalInt64: proto.Int64(1000),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700156 },
157 },
158 },
Joe Tsaice496b52020-01-02 15:47:15 -0800159 mutator: func(mi proto.Message) bool {
Joe Tsai2fc306a2019-06-20 03:01:22 -0700160 m := mi.(*testpb.TestAllTypes)
161 *m.OptionalInt64++
162 *m.OptionalNestedEnum++
163 *m.OptionalNestedMessage.A++
Joe Tsaice496b52020-01-02 15:47:15 -0800164 return false // scalar mutations are not observable in shallow copy
Joe Tsai2fc306a2019-06-20 03:01:22 -0700165 },
166 }, {
167 desc: "merge list fields",
168 dst: &testpb.TestAllTypes{
169 RepeatedSfixed32: []int32{1, 2, 3},
170 RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700171 {A: proto.Int32(100)},
172 {A: proto.Int32(200)},
Joe Tsai2fc306a2019-06-20 03:01:22 -0700173 },
174 },
175 src: &testpb.TestAllTypes{
176 RepeatedSfixed32: []int32{4, 5, 6},
177 RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700178 {A: proto.Int32(300)},
179 {A: proto.Int32(400)},
Joe Tsai2fc306a2019-06-20 03:01:22 -0700180 },
181 },
182 want: &testpb.TestAllTypes{
183 RepeatedSfixed32: []int32{1, 2, 3, 4, 5, 6},
184 RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700185 {A: proto.Int32(100)},
186 {A: proto.Int32(200)},
187 {A: proto.Int32(300)},
188 {A: proto.Int32(400)},
Joe Tsai2fc306a2019-06-20 03:01:22 -0700189 },
190 },
Joe Tsaice496b52020-01-02 15:47:15 -0800191 mutator: func(mi proto.Message) bool {
Joe Tsai2fc306a2019-06-20 03:01:22 -0700192 m := mi.(*testpb.TestAllTypes)
193 m.RepeatedSfixed32[0]++
194 *m.RepeatedNestedMessage[0].A++
Joe Tsaice496b52020-01-02 15:47:15 -0800195 return true
Joe Tsai2fc306a2019-06-20 03:01:22 -0700196 },
197 }, {
198 desc: "merge map fields",
199 dst: &testpb.TestAllTypes{
200 MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{
201 "fizz": 100,
202 "buzz": 200,
203 "guzz": 300,
204 },
205 MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700206 "foo": {A: proto.Int32(400)},
Joe Tsai2fc306a2019-06-20 03:01:22 -0700207 },
208 },
209 src: &testpb.TestAllTypes{
210 MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{
211 "fizz": 1000,
212 "buzz": 2000,
213 },
214 MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700215 "foo": {A: proto.Int32(3000)},
Joe Tsai2fc306a2019-06-20 03:01:22 -0700216 "bar": {},
217 },
218 },
219 want: &testpb.TestAllTypes{
220 MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{
221 "fizz": 1000,
222 "buzz": 2000,
223 "guzz": 300,
224 },
225 MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700226 "foo": {A: proto.Int32(3000)},
Joe Tsai2fc306a2019-06-20 03:01:22 -0700227 "bar": {},
228 },
229 },
Joe Tsaice496b52020-01-02 15:47:15 -0800230 mutator: func(mi proto.Message) bool {
Joe Tsai2fc306a2019-06-20 03:01:22 -0700231 m := mi.(*testpb.TestAllTypes)
232 delete(m.MapStringNestedEnum, "fizz")
Damien Neila8a2cea2019-07-10 16:17:16 -0700233 m.MapStringNestedMessage["bar"].A = proto.Int32(1)
Joe Tsaice496b52020-01-02 15:47:15 -0800234 return true
Joe Tsai2fc306a2019-06-20 03:01:22 -0700235 },
236 }, {
237 desc: "merge oneof message fields",
238 dst: &testpb.TestAllTypes{
239 OneofField: &testpb.TestAllTypes_OneofNestedMessage{
240 &testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700241 A: proto.Int32(100),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700242 },
243 },
244 },
245 src: &testpb.TestAllTypes{
246 OneofField: &testpb.TestAllTypes_OneofNestedMessage{
247 &testpb.TestAllTypes_NestedMessage{
248 Corecursive: &testpb.TestAllTypes{
Damien Neila8a2cea2019-07-10 16:17:16 -0700249 OptionalInt64: proto.Int64(1000),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700250 },
251 },
252 },
253 },
254 want: &testpb.TestAllTypes{
255 OneofField: &testpb.TestAllTypes_OneofNestedMessage{
256 &testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700257 A: proto.Int32(100),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700258 Corecursive: &testpb.TestAllTypes{
Damien Neila8a2cea2019-07-10 16:17:16 -0700259 OptionalInt64: proto.Int64(1000),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700260 },
261 },
262 },
263 },
Joe Tsaice496b52020-01-02 15:47:15 -0800264 mutator: func(mi proto.Message) bool {
Joe Tsai2fc306a2019-06-20 03:01:22 -0700265 m := mi.(*testpb.TestAllTypes)
266 *m.OneofField.(*testpb.TestAllTypes_OneofNestedMessage).OneofNestedMessage.Corecursive.OptionalInt64++
Joe Tsaice496b52020-01-02 15:47:15 -0800267 return true
Joe Tsai2fc306a2019-06-20 03:01:22 -0700268 },
Joe Tsai2fc306a2019-06-20 03:01:22 -0700269 }, {
270 desc: "merge oneof scalar fields",
271 dst: &testpb.TestAllTypes{
272 OneofField: &testpb.TestAllTypes_OneofUint32{100},
273 },
274 src: &testpb.TestAllTypes{
275 OneofField: &testpb.TestAllTypes_OneofFloat{3.14152},
276 },
277 want: &testpb.TestAllTypes{
278 OneofField: &testpb.TestAllTypes_OneofFloat{3.14152},
279 },
Joe Tsaice496b52020-01-02 15:47:15 -0800280 mutator: func(mi proto.Message) bool {
Joe Tsai2fc306a2019-06-20 03:01:22 -0700281 m := mi.(*testpb.TestAllTypes)
282 m.OneofField.(*testpb.TestAllTypes_OneofFloat).OneofFloat++
Joe Tsaice496b52020-01-02 15:47:15 -0800283 return false // scalar mutations are not observable in shallow copy
Joe Tsai2fc306a2019-06-20 03:01:22 -0700284 },
285 }, {
286 desc: "merge extension fields",
287 dst: func() proto.Message {
288 m := new(testpb.TestAllExtensions)
Damien Neilf1e905b2019-08-08 15:45:59 -0700289 proto.SetExtension(m, testpb.E_OptionalInt32Extension, int32(32))
290 proto.SetExtension(m, testpb.E_OptionalNestedMessageExtension,
Damien Neil92f76182019-08-02 16:58:08 -0700291 &testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700292 A: proto.Int32(50),
Damien Neil92f76182019-08-02 16:58:08 -0700293 },
Joe Tsai2fc306a2019-06-20 03:01:22 -0700294 )
Damien Neil293dc762019-08-29 11:42:57 -0700295 proto.SetExtension(m, testpb.E_RepeatedFixed32Extension, []uint32{1, 2, 3})
Joe Tsai2fc306a2019-06-20 03:01:22 -0700296 return m
297 }(),
298 src: func() proto.Message {
299 m := new(testpb.TestAllExtensions)
Damien Neilf1e905b2019-08-08 15:45:59 -0700300 proto.SetExtension(m, testpb.E_OptionalInt64Extension, int64(64))
301 proto.SetExtension(m, testpb.E_OptionalNestedMessageExtension,
Damien Neil92f76182019-08-02 16:58:08 -0700302 &testpb.TestAllTypes_NestedMessage{
Joe Tsai2fc306a2019-06-20 03:01:22 -0700303 Corecursive: &testpb.TestAllTypes{
Damien Neila8a2cea2019-07-10 16:17:16 -0700304 OptionalInt64: proto.Int64(1000),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700305 },
Damien Neil92f76182019-08-02 16:58:08 -0700306 },
Joe Tsai2fc306a2019-06-20 03:01:22 -0700307 )
Damien Neil293dc762019-08-29 11:42:57 -0700308 proto.SetExtension(m, testpb.E_RepeatedFixed32Extension, []uint32{4, 5, 6})
Joe Tsai2fc306a2019-06-20 03:01:22 -0700309 return m
310 }(),
311 want: func() proto.Message {
312 m := new(testpb.TestAllExtensions)
Damien Neilf1e905b2019-08-08 15:45:59 -0700313 proto.SetExtension(m, testpb.E_OptionalInt32Extension, int32(32))
314 proto.SetExtension(m, testpb.E_OptionalInt64Extension, int64(64))
315 proto.SetExtension(m, testpb.E_OptionalNestedMessageExtension,
Damien Neil92f76182019-08-02 16:58:08 -0700316 &testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700317 A: proto.Int32(50),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700318 Corecursive: &testpb.TestAllTypes{
Damien Neila8a2cea2019-07-10 16:17:16 -0700319 OptionalInt64: proto.Int64(1000),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700320 },
Damien Neil92f76182019-08-02 16:58:08 -0700321 },
Joe Tsai2fc306a2019-06-20 03:01:22 -0700322 )
Damien Neil293dc762019-08-29 11:42:57 -0700323 proto.SetExtension(m, testpb.E_RepeatedFixed32Extension, []uint32{1, 2, 3, 4, 5, 6})
Joe Tsai2fc306a2019-06-20 03:01:22 -0700324 return m
325 }(),
326 }, {
327 desc: "merge unknown fields",
328 dst: func() proto.Message {
329 m := new(testpb.TestAllTypes)
330 m.ProtoReflect().SetUnknown(pack.Message{
331 pack.Tag{Number: 50000, Type: pack.VarintType}, pack.Svarint(-5),
332 }.Marshal())
333 return m
334 }(),
335 src: func() proto.Message {
336 m := new(testpb.TestAllTypes)
337 m.ProtoReflect().SetUnknown(pack.Message{
338 pack.Tag{Number: 500000, Type: pack.VarintType}, pack.Svarint(-50),
339 }.Marshal())
340 return m
341 }(),
342 want: func() proto.Message {
343 m := new(testpb.TestAllTypes)
344 m.ProtoReflect().SetUnknown(pack.Message{
345 pack.Tag{Number: 50000, Type: pack.VarintType}, pack.Svarint(-5),
346 pack.Tag{Number: 500000, Type: pack.VarintType}, pack.Svarint(-50),
347 }.Marshal())
348 return m
349 }(),
350 }}
351
352 for _, tt := range tests {
353 t.Run(tt.desc, func(t *testing.T) {
354 // Merge should be semantically equivalent to unmarshaling the
355 // encoded form of src into the current dst.
356 b1, err := proto.MarshalOptions{AllowPartial: true}.Marshal(tt.dst)
357 if err != nil {
358 t.Fatalf("Marshal(dst) error: %v", err)
359 }
360 b2, err := proto.MarshalOptions{AllowPartial: true}.Marshal(tt.src)
361 if err != nil {
362 t.Fatalf("Marshal(src) error: %v", err)
363 }
364 dst := tt.dst.ProtoReflect().New().Interface()
365 err = proto.UnmarshalOptions{AllowPartial: true}.Unmarshal(append(b1, b2...), dst)
366 if err != nil {
367 t.Fatalf("Unmarshal() error: %v", err)
368 }
Joe Tsai6c286742019-07-11 23:15:05 -0700369 if !proto.Equal(dst, tt.want) {
Joe Tsai2fc306a2019-06-20 03:01:22 -0700370 t.Fatalf("Unmarshal(Marshal(dst)+Marshal(src)) mismatch: got %v, want %v", dst, tt.want)
371 }
372
Joe Tsaice496b52020-01-02 15:47:15 -0800373 proto.MergeOptions{Shallow: shallow}.Merge(tt.dst, tt.src)
Joe Tsai2fc306a2019-06-20 03:01:22 -0700374 if !proto.Equal(tt.dst, tt.want) {
Damien Neil293dc762019-08-29 11:42:57 -0700375 t.Fatalf("Merge() mismatch:\n got %v\nwant %v", tt.dst, tt.want)
Joe Tsai2fc306a2019-06-20 03:01:22 -0700376 }
Joe Tsaice496b52020-01-02 15:47:15 -0800377 if tt.mutator != nil {
378 wantObservable := tt.mutator(tt.src) && shallow
379 gotObservable := !proto.Equal(tt.dst, tt.want)
380 if gotObservable != wantObservable {
381 t.Fatalf("mutation observed:\n got %v\nwant %v", gotObservable, wantObservable)
382 }
383 }
Joe Tsai2fc306a2019-06-20 03:01:22 -0700384 })
385 }
386}
Joe Tsaic9081442019-09-20 12:18:55 -0700387
388func TestMergeRace(t *testing.T) {
389 dst := new(testpb.TestAllTypes)
390 srcs := []*testpb.TestAllTypes{
391 {OptionalInt32: proto.Int32(1)},
392 {OptionalString: proto.String("hello")},
393 {RepeatedInt32: []int32{2, 3, 4}},
394 {RepeatedString: []string{"goodbye"}},
395 {MapStringString: map[string]string{"key": "value"}},
396 {OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
397 A: proto.Int32(5),
398 }},
399 func() *testpb.TestAllTypes {
400 m := new(testpb.TestAllTypes)
401 m.ProtoReflect().SetUnknown(pack.Message{
402 pack.Tag{Number: 50000, Type: pack.VarintType}, pack.Svarint(-5),
403 }.Marshal())
404 return m
405 }(),
406 }
407
408 // It should be safe to concurrently merge non-overlapping fields.
409 var wg sync.WaitGroup
410 defer wg.Wait()
411 for _, src := range srcs {
412 wg.Add(1)
413 go func(src proto.Message) {
414 defer wg.Done()
415 proto.Merge(dst, src)
416 }(src)
417 }
418}
Joe Tsai641611d2019-09-21 21:50:50 -0700419
420func TestMergeSelf(t *testing.T) {
421 got := &testpb.TestAllTypes{
422 OptionalInt32: proto.Int32(1),
423 OptionalString: proto.String("hello"),
424 RepeatedInt32: []int32{2, 3, 4},
425 RepeatedString: []string{"goodbye"},
426 MapStringString: map[string]string{"key": "value"},
427 OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
428 A: proto.Int32(5),
429 },
430 }
431 got.ProtoReflect().SetUnknown(pack.Message{
432 pack.Tag{Number: 50000, Type: pack.VarintType}, pack.Svarint(-5),
433 }.Marshal())
434 proto.Merge(got, got)
435
436 // The main impact of merging to self is that repeated fields and
437 // unknown fields are doubled.
438 want := &testpb.TestAllTypes{
439 OptionalInt32: proto.Int32(1),
440 OptionalString: proto.String("hello"),
441 RepeatedInt32: []int32{2, 3, 4, 2, 3, 4},
442 RepeatedString: []string{"goodbye", "goodbye"},
443 MapStringString: map[string]string{"key": "value"},
444 OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
445 A: proto.Int32(5),
446 },
447 }
448 want.ProtoReflect().SetUnknown(pack.Message{
449 pack.Tag{Number: 50000, Type: pack.VarintType}, pack.Svarint(-5),
450 pack.Tag{Number: 50000, Type: pack.VarintType}, pack.Svarint(-5),
451 }.Marshal())
452
453 if !proto.Equal(got, want) {
454 t.Errorf("Equal mismatch:\ngot %v\nwant %v", got, want)
455 }
456}