blob: 4fa161ef20654ea9fa1fc0c4311e982646ce0ec5 [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 (
8 "testing"
9
10 "google.golang.org/protobuf/internal/encoding/pack"
Joe Tsai2fc306a2019-06-20 03:01:22 -070011 "google.golang.org/protobuf/proto"
12
13 testpb "google.golang.org/protobuf/internal/testprotos/test"
14)
15
16func TestMerge(t *testing.T) {
17 dst := new(testpb.TestAllTypes)
18 src := (*testpb.TestAllTypes)(nil)
19 proto.Merge(dst, src)
20
21 // Mutating the source should not affect dst.
22
23 tests := []struct {
24 desc string
25 dst proto.Message
26 src proto.Message
27 want proto.Message
28 mutator func(proto.Message) // if provided, is run on src after merging
Joe Tsai2fc306a2019-06-20 03:01:22 -070029 }{{
30 desc: "merge from nil message",
31 dst: new(testpb.TestAllTypes),
32 src: (*testpb.TestAllTypes)(nil),
33 want: new(testpb.TestAllTypes),
34 }, {
35 desc: "clone a large message",
36 dst: new(testpb.TestAllTypes),
37 src: &testpb.TestAllTypes{
Damien Neila8a2cea2019-07-10 16:17:16 -070038 OptionalInt64: proto.Int64(0),
Joe Tsai2fc306a2019-06-20 03:01:22 -070039 OptionalNestedEnum: testpb.TestAllTypes_NestedEnum(1).Enum(),
40 OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -070041 A: proto.Int32(100),
Joe Tsai2fc306a2019-06-20 03:01:22 -070042 },
43 RepeatedSfixed32: []int32{1, 2, 3},
44 RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -070045 {A: proto.Int32(200)},
46 {A: proto.Int32(300)},
Joe Tsai2fc306a2019-06-20 03:01:22 -070047 },
48 MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{
49 "fizz": 400,
50 "buzz": 500,
51 },
52 MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -070053 "foo": {A: proto.Int32(600)},
54 "bar": {A: proto.Int32(700)},
Joe Tsai2fc306a2019-06-20 03:01:22 -070055 },
56 OneofField: &testpb.TestAllTypes_OneofNestedMessage{
57 &testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -070058 A: proto.Int32(800),
Joe Tsai2fc306a2019-06-20 03:01:22 -070059 },
60 },
61 },
62 want: &testpb.TestAllTypes{
Damien Neila8a2cea2019-07-10 16:17:16 -070063 OptionalInt64: proto.Int64(0),
Joe Tsai2fc306a2019-06-20 03:01:22 -070064 OptionalNestedEnum: testpb.TestAllTypes_NestedEnum(1).Enum(),
65 OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -070066 A: proto.Int32(100),
Joe Tsai2fc306a2019-06-20 03:01:22 -070067 },
68 RepeatedSfixed32: []int32{1, 2, 3},
69 RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -070070 {A: proto.Int32(200)},
71 {A: proto.Int32(300)},
Joe Tsai2fc306a2019-06-20 03:01:22 -070072 },
73 MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{
74 "fizz": 400,
75 "buzz": 500,
76 },
77 MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -070078 "foo": {A: proto.Int32(600)},
79 "bar": {A: proto.Int32(700)},
Joe Tsai2fc306a2019-06-20 03:01:22 -070080 },
81 OneofField: &testpb.TestAllTypes_OneofNestedMessage{
82 &testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -070083 A: proto.Int32(800),
Joe Tsai2fc306a2019-06-20 03:01:22 -070084 },
85 },
86 },
87 mutator: func(mi proto.Message) {
88 m := mi.(*testpb.TestAllTypes)
89 *m.OptionalInt64++
90 *m.OptionalNestedEnum++
91 *m.OptionalNestedMessage.A++
92 m.RepeatedSfixed32[0]++
93 *m.RepeatedNestedMessage[0].A++
94 delete(m.MapStringNestedEnum, "fizz")
95 *m.MapStringNestedMessage["foo"].A++
96 *m.OneofField.(*testpb.TestAllTypes_OneofNestedMessage).OneofNestedMessage.A++
97 },
98 }, {
99 desc: "merge bytes",
100 dst: &testpb.TestAllTypes{
101 OptionalBytes: []byte{1, 2, 3},
102 RepeatedBytes: [][]byte{{1, 2}, {3, 4}},
103 MapStringBytes: map[string][]byte{"alpha": {1, 2, 3}},
104 },
105 src: &testpb.TestAllTypes{
106 OptionalBytes: []byte{4, 5, 6},
107 RepeatedBytes: [][]byte{{5, 6}, {7, 8}},
108 MapStringBytes: map[string][]byte{"alpha": {4, 5, 6}, "bravo": {1, 2, 3}},
109 },
110 want: &testpb.TestAllTypes{
111 OptionalBytes: []byte{4, 5, 6},
112 RepeatedBytes: [][]byte{{1, 2}, {3, 4}, {5, 6}, {7, 8}},
113 MapStringBytes: map[string][]byte{"alpha": {4, 5, 6}, "bravo": {1, 2, 3}},
114 },
115 mutator: func(mi proto.Message) {
116 m := mi.(*testpb.TestAllTypes)
117 m.OptionalBytes[0]++
118 m.RepeatedBytes[0][0]++
119 m.MapStringBytes["alpha"][0]++
120 },
121 }, {
122 desc: "merge singular fields",
123 dst: &testpb.TestAllTypes{
Damien Neila8a2cea2019-07-10 16:17:16 -0700124 OptionalInt32: proto.Int32(1),
125 OptionalInt64: proto.Int64(1),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700126 OptionalNestedEnum: testpb.TestAllTypes_NestedEnum(10).Enum(),
127 OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700128 A: proto.Int32(100),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700129 Corecursive: &testpb.TestAllTypes{
Damien Neila8a2cea2019-07-10 16:17:16 -0700130 OptionalInt64: proto.Int64(1000),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700131 },
132 },
133 },
134 src: &testpb.TestAllTypes{
Damien Neila8a2cea2019-07-10 16:17:16 -0700135 OptionalInt64: proto.Int64(2),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700136 OptionalNestedEnum: testpb.TestAllTypes_NestedEnum(20).Enum(),
137 OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700138 A: proto.Int32(200),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700139 },
140 },
141 want: &testpb.TestAllTypes{
Damien Neila8a2cea2019-07-10 16:17:16 -0700142 OptionalInt32: proto.Int32(1),
143 OptionalInt64: proto.Int64(2),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700144 OptionalNestedEnum: testpb.TestAllTypes_NestedEnum(20).Enum(),
145 OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700146 A: proto.Int32(200),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700147 Corecursive: &testpb.TestAllTypes{
Damien Neila8a2cea2019-07-10 16:17:16 -0700148 OptionalInt64: proto.Int64(1000),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700149 },
150 },
151 },
152 mutator: func(mi proto.Message) {
153 m := mi.(*testpb.TestAllTypes)
154 *m.OptionalInt64++
155 *m.OptionalNestedEnum++
156 *m.OptionalNestedMessage.A++
157 },
158 }, {
159 desc: "merge list fields",
160 dst: &testpb.TestAllTypes{
161 RepeatedSfixed32: []int32{1, 2, 3},
162 RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700163 {A: proto.Int32(100)},
164 {A: proto.Int32(200)},
Joe Tsai2fc306a2019-06-20 03:01:22 -0700165 },
166 },
167 src: &testpb.TestAllTypes{
168 RepeatedSfixed32: []int32{4, 5, 6},
169 RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700170 {A: proto.Int32(300)},
171 {A: proto.Int32(400)},
Joe Tsai2fc306a2019-06-20 03:01:22 -0700172 },
173 },
174 want: &testpb.TestAllTypes{
175 RepeatedSfixed32: []int32{1, 2, 3, 4, 5, 6},
176 RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700177 {A: proto.Int32(100)},
178 {A: proto.Int32(200)},
179 {A: proto.Int32(300)},
180 {A: proto.Int32(400)},
Joe Tsai2fc306a2019-06-20 03:01:22 -0700181 },
182 },
183 mutator: func(mi proto.Message) {
184 m := mi.(*testpb.TestAllTypes)
185 m.RepeatedSfixed32[0]++
186 *m.RepeatedNestedMessage[0].A++
187 },
188 }, {
189 desc: "merge map fields",
190 dst: &testpb.TestAllTypes{
191 MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{
192 "fizz": 100,
193 "buzz": 200,
194 "guzz": 300,
195 },
196 MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700197 "foo": {A: proto.Int32(400)},
Joe Tsai2fc306a2019-06-20 03:01:22 -0700198 },
199 },
200 src: &testpb.TestAllTypes{
201 MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{
202 "fizz": 1000,
203 "buzz": 2000,
204 },
205 MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700206 "foo": {A: proto.Int32(3000)},
Joe Tsai2fc306a2019-06-20 03:01:22 -0700207 "bar": {},
208 },
209 },
210 want: &testpb.TestAllTypes{
211 MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{
212 "fizz": 1000,
213 "buzz": 2000,
214 "guzz": 300,
215 },
216 MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700217 "foo": {A: proto.Int32(3000)},
Joe Tsai2fc306a2019-06-20 03:01:22 -0700218 "bar": {},
219 },
220 },
221 mutator: func(mi proto.Message) {
222 m := mi.(*testpb.TestAllTypes)
223 delete(m.MapStringNestedEnum, "fizz")
Damien Neila8a2cea2019-07-10 16:17:16 -0700224 m.MapStringNestedMessage["bar"].A = proto.Int32(1)
Joe Tsai2fc306a2019-06-20 03:01:22 -0700225 },
226 }, {
227 desc: "merge oneof message fields",
228 dst: &testpb.TestAllTypes{
229 OneofField: &testpb.TestAllTypes_OneofNestedMessage{
230 &testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700231 A: proto.Int32(100),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700232 },
233 },
234 },
235 src: &testpb.TestAllTypes{
236 OneofField: &testpb.TestAllTypes_OneofNestedMessage{
237 &testpb.TestAllTypes_NestedMessage{
238 Corecursive: &testpb.TestAllTypes{
Damien Neila8a2cea2019-07-10 16:17:16 -0700239 OptionalInt64: proto.Int64(1000),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700240 },
241 },
242 },
243 },
244 want: &testpb.TestAllTypes{
245 OneofField: &testpb.TestAllTypes_OneofNestedMessage{
246 &testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700247 A: proto.Int32(100),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700248 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 mutator: func(mi proto.Message) {
255 m := mi.(*testpb.TestAllTypes)
256 *m.OneofField.(*testpb.TestAllTypes_OneofNestedMessage).OneofNestedMessage.Corecursive.OptionalInt64++
257 },
Joe Tsai2fc306a2019-06-20 03:01:22 -0700258 }, {
259 desc: "merge oneof scalar fields",
260 dst: &testpb.TestAllTypes{
261 OneofField: &testpb.TestAllTypes_OneofUint32{100},
262 },
263 src: &testpb.TestAllTypes{
264 OneofField: &testpb.TestAllTypes_OneofFloat{3.14152},
265 },
266 want: &testpb.TestAllTypes{
267 OneofField: &testpb.TestAllTypes_OneofFloat{3.14152},
268 },
269 mutator: func(mi proto.Message) {
270 m := mi.(*testpb.TestAllTypes)
271 m.OneofField.(*testpb.TestAllTypes_OneofFloat).OneofFloat++
272 },
273 }, {
274 desc: "merge extension fields",
275 dst: func() proto.Message {
276 m := new(testpb.TestAllExtensions)
277 m.ProtoReflect().Set(
278 testpb.E_OptionalInt32Extension.Type,
279 testpb.E_OptionalInt32Extension.Type.ValueOf(int32(32)),
280 )
281 m.ProtoReflect().Set(
282 testpb.E_OptionalNestedMessageExtension.Type,
283 testpb.E_OptionalNestedMessageExtension.Type.ValueOf(&testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700284 A: proto.Int32(50),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700285 }),
286 )
287 m.ProtoReflect().Set(
288 testpb.E_RepeatedFixed32Extension.Type,
289 testpb.E_RepeatedFixed32Extension.Type.ValueOf(&[]uint32{1, 2, 3}),
290 )
291 return m
292 }(),
293 src: func() proto.Message {
294 m := new(testpb.TestAllExtensions)
295 m.ProtoReflect().Set(
296 testpb.E_OptionalInt64Extension.Type,
297 testpb.E_OptionalInt64Extension.Type.ValueOf(int64(64)),
298 )
299 m.ProtoReflect().Set(
300 testpb.E_OptionalNestedMessageExtension.Type,
301 testpb.E_OptionalNestedMessageExtension.Type.ValueOf(&testpb.TestAllTypes_NestedMessage{
302 Corecursive: &testpb.TestAllTypes{
Damien Neila8a2cea2019-07-10 16:17:16 -0700303 OptionalInt64: proto.Int64(1000),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700304 },
305 }),
306 )
307 m.ProtoReflect().Set(
308 testpb.E_RepeatedFixed32Extension.Type,
309 testpb.E_RepeatedFixed32Extension.Type.ValueOf(&[]uint32{4, 5, 6}),
310 )
311 return m
312 }(),
313 want: func() proto.Message {
314 m := new(testpb.TestAllExtensions)
315 m.ProtoReflect().Set(
316 testpb.E_OptionalInt32Extension.Type,
317 testpb.E_OptionalInt32Extension.Type.ValueOf(int32(32)),
318 )
319 m.ProtoReflect().Set(
320 testpb.E_OptionalInt64Extension.Type,
321 testpb.E_OptionalInt64Extension.Type.ValueOf(int64(64)),
322 )
323 m.ProtoReflect().Set(
324 testpb.E_OptionalNestedMessageExtension.Type,
325 testpb.E_OptionalNestedMessageExtension.Type.ValueOf(&testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700326 A: proto.Int32(50),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700327 Corecursive: &testpb.TestAllTypes{
Damien Neila8a2cea2019-07-10 16:17:16 -0700328 OptionalInt64: proto.Int64(1000),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700329 },
330 }),
331 )
332 m.ProtoReflect().Set(
333 testpb.E_RepeatedFixed32Extension.Type,
334 testpb.E_RepeatedFixed32Extension.Type.ValueOf(&[]uint32{1, 2, 3, 4, 5, 6}),
335 )
336 return m
337 }(),
338 }, {
339 desc: "merge unknown fields",
340 dst: func() proto.Message {
341 m := new(testpb.TestAllTypes)
342 m.ProtoReflect().SetUnknown(pack.Message{
343 pack.Tag{Number: 50000, Type: pack.VarintType}, pack.Svarint(-5),
344 }.Marshal())
345 return m
346 }(),
347 src: func() proto.Message {
348 m := new(testpb.TestAllTypes)
349 m.ProtoReflect().SetUnknown(pack.Message{
350 pack.Tag{Number: 500000, Type: pack.VarintType}, pack.Svarint(-50),
351 }.Marshal())
352 return m
353 }(),
354 want: func() proto.Message {
355 m := new(testpb.TestAllTypes)
356 m.ProtoReflect().SetUnknown(pack.Message{
357 pack.Tag{Number: 50000, Type: pack.VarintType}, pack.Svarint(-5),
358 pack.Tag{Number: 500000, Type: pack.VarintType}, pack.Svarint(-50),
359 }.Marshal())
360 return m
361 }(),
362 }}
363
364 for _, tt := range tests {
365 t.Run(tt.desc, func(t *testing.T) {
366 // Merge should be semantically equivalent to unmarshaling the
367 // encoded form of src into the current dst.
368 b1, err := proto.MarshalOptions{AllowPartial: true}.Marshal(tt.dst)
369 if err != nil {
370 t.Fatalf("Marshal(dst) error: %v", err)
371 }
372 b2, err := proto.MarshalOptions{AllowPartial: true}.Marshal(tt.src)
373 if err != nil {
374 t.Fatalf("Marshal(src) error: %v", err)
375 }
376 dst := tt.dst.ProtoReflect().New().Interface()
377 err = proto.UnmarshalOptions{AllowPartial: true}.Unmarshal(append(b1, b2...), dst)
378 if err != nil {
379 t.Fatalf("Unmarshal() error: %v", err)
380 }
Joe Tsai6c286742019-07-11 23:15:05 -0700381 if !proto.Equal(dst, tt.want) {
Joe Tsai2fc306a2019-06-20 03:01:22 -0700382 t.Fatalf("Unmarshal(Marshal(dst)+Marshal(src)) mismatch: got %v, want %v", dst, tt.want)
383 }
384
385 proto.Merge(tt.dst, tt.src)
386 if tt.mutator != nil {
387 tt.mutator(tt.src) // should not be observable by dst
388 }
389 if !proto.Equal(tt.dst, tt.want) {
390 t.Fatalf("Merge() mismatch: got %v, want %v", tt.dst, tt.want)
391 }
392 })
393 }
394}