blob: a0ec571278745c49f6eda49f1277c41687b56a77 [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)
Damien Neil92f76182019-08-02 16:58:08 -0700277 proto.SetExtension(m, testpb.E_OptionalInt32Extension.Type, int32(32))
278 proto.SetExtension(m, testpb.E_OptionalNestedMessageExtension.Type,
279 &testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700280 A: proto.Int32(50),
Damien Neil92f76182019-08-02 16:58:08 -0700281 },
Joe Tsai2fc306a2019-06-20 03:01:22 -0700282 )
Damien Neil92f76182019-08-02 16:58:08 -0700283 proto.SetExtension(m, testpb.E_RepeatedFixed32Extension.Type, &[]uint32{1, 2, 3})
Joe Tsai2fc306a2019-06-20 03:01:22 -0700284 return m
285 }(),
286 src: func() proto.Message {
287 m := new(testpb.TestAllExtensions)
Damien Neil92f76182019-08-02 16:58:08 -0700288 proto.SetExtension(m, testpb.E_OptionalInt64Extension.Type, int64(64))
289 proto.SetExtension(m, testpb.E_OptionalNestedMessageExtension.Type,
290 &testpb.TestAllTypes_NestedMessage{
Joe Tsai2fc306a2019-06-20 03:01:22 -0700291 Corecursive: &testpb.TestAllTypes{
Damien Neila8a2cea2019-07-10 16:17:16 -0700292 OptionalInt64: proto.Int64(1000),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700293 },
Damien Neil92f76182019-08-02 16:58:08 -0700294 },
Joe Tsai2fc306a2019-06-20 03:01:22 -0700295 )
Damien Neil92f76182019-08-02 16:58:08 -0700296 proto.SetExtension(m, testpb.E_RepeatedFixed32Extension.Type, &[]uint32{4, 5, 6})
Joe Tsai2fc306a2019-06-20 03:01:22 -0700297 return m
298 }(),
299 want: func() proto.Message {
300 m := new(testpb.TestAllExtensions)
Damien Neil92f76182019-08-02 16:58:08 -0700301 proto.SetExtension(m, testpb.E_OptionalInt32Extension.Type, int32(32))
302 proto.SetExtension(m, testpb.E_OptionalInt64Extension.Type, int64(64))
303 proto.SetExtension(m, testpb.E_OptionalNestedMessageExtension.Type,
304 &testpb.TestAllTypes_NestedMessage{
Damien Neila8a2cea2019-07-10 16:17:16 -0700305 A: proto.Int32(50),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700306 Corecursive: &testpb.TestAllTypes{
Damien Neila8a2cea2019-07-10 16:17:16 -0700307 OptionalInt64: proto.Int64(1000),
Joe Tsai2fc306a2019-06-20 03:01:22 -0700308 },
Damien Neil92f76182019-08-02 16:58:08 -0700309 },
Joe Tsai2fc306a2019-06-20 03:01:22 -0700310 )
Damien Neil92f76182019-08-02 16:58:08 -0700311 proto.SetExtension(m, testpb.E_RepeatedFixed32Extension.Type, &[]uint32{1, 2, 3, 4, 5, 6})
Joe Tsai2fc306a2019-06-20 03:01:22 -0700312 return m
313 }(),
314 }, {
315 desc: "merge unknown fields",
316 dst: func() proto.Message {
317 m := new(testpb.TestAllTypes)
318 m.ProtoReflect().SetUnknown(pack.Message{
319 pack.Tag{Number: 50000, Type: pack.VarintType}, pack.Svarint(-5),
320 }.Marshal())
321 return m
322 }(),
323 src: func() proto.Message {
324 m := new(testpb.TestAllTypes)
325 m.ProtoReflect().SetUnknown(pack.Message{
326 pack.Tag{Number: 500000, Type: pack.VarintType}, pack.Svarint(-50),
327 }.Marshal())
328 return m
329 }(),
330 want: func() proto.Message {
331 m := new(testpb.TestAllTypes)
332 m.ProtoReflect().SetUnknown(pack.Message{
333 pack.Tag{Number: 50000, Type: pack.VarintType}, pack.Svarint(-5),
334 pack.Tag{Number: 500000, Type: pack.VarintType}, pack.Svarint(-50),
335 }.Marshal())
336 return m
337 }(),
338 }}
339
340 for _, tt := range tests {
341 t.Run(tt.desc, func(t *testing.T) {
342 // Merge should be semantically equivalent to unmarshaling the
343 // encoded form of src into the current dst.
344 b1, err := proto.MarshalOptions{AllowPartial: true}.Marshal(tt.dst)
345 if err != nil {
346 t.Fatalf("Marshal(dst) error: %v", err)
347 }
348 b2, err := proto.MarshalOptions{AllowPartial: true}.Marshal(tt.src)
349 if err != nil {
350 t.Fatalf("Marshal(src) error: %v", err)
351 }
352 dst := tt.dst.ProtoReflect().New().Interface()
353 err = proto.UnmarshalOptions{AllowPartial: true}.Unmarshal(append(b1, b2...), dst)
354 if err != nil {
355 t.Fatalf("Unmarshal() error: %v", err)
356 }
Joe Tsai6c286742019-07-11 23:15:05 -0700357 if !proto.Equal(dst, tt.want) {
Joe Tsai2fc306a2019-06-20 03:01:22 -0700358 t.Fatalf("Unmarshal(Marshal(dst)+Marshal(src)) mismatch: got %v, want %v", dst, tt.want)
359 }
360
361 proto.Merge(tt.dst, tt.src)
362 if tt.mutator != nil {
363 tt.mutator(tt.src) // should not be observable by dst
364 }
365 if !proto.Equal(tt.dst, tt.want) {
366 t.Fatalf("Merge() mismatch: got %v, want %v", tt.dst, tt.want)
367 }
368 })
369 }
370}