2019-06-20 03:01:22 -07:00
|
|
|
// Copyright 2019 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package proto_test
|
|
|
|
|
|
|
|
import (
|
2019-09-20 17:57:39 -07:00
|
|
|
"reflect"
|
2019-09-20 12:18:55 -07:00
|
|
|
"sync"
|
2019-06-20 03:01:22 -07:00
|
|
|
"testing"
|
|
|
|
|
|
|
|
"google.golang.org/protobuf/internal/encoding/pack"
|
|
|
|
"google.golang.org/protobuf/proto"
|
|
|
|
|
|
|
|
testpb "google.golang.org/protobuf/internal/testprotos/test"
|
2019-09-20 17:57:39 -07:00
|
|
|
test3pb "google.golang.org/protobuf/internal/testprotos/test3"
|
2019-06-20 03:01:22 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestMerge(t *testing.T) {
|
|
|
|
tests := []struct {
|
2020-01-02 15:47:15 -08:00
|
|
|
desc string
|
|
|
|
dst proto.Message
|
|
|
|
src proto.Message
|
|
|
|
want proto.Message
|
|
|
|
|
|
|
|
// If provided, mutator is run on src after merging.
|
|
|
|
// It reports whether a mutation is expected to be observable in dst
|
|
|
|
// if Shallow is enabled.
|
|
|
|
mutator func(proto.Message) bool
|
2019-06-20 03:01:22 -07:00
|
|
|
}{{
|
|
|
|
desc: "merge from nil message",
|
|
|
|
dst: new(testpb.TestAllTypes),
|
|
|
|
src: (*testpb.TestAllTypes)(nil),
|
|
|
|
want: new(testpb.TestAllTypes),
|
|
|
|
}, {
|
|
|
|
desc: "clone a large message",
|
|
|
|
dst: new(testpb.TestAllTypes),
|
|
|
|
src: &testpb.TestAllTypes{
|
2019-07-10 16:17:16 -07:00
|
|
|
OptionalInt64: proto.Int64(0),
|
2019-06-20 03:01:22 -07:00
|
|
|
OptionalNestedEnum: testpb.TestAllTypes_NestedEnum(1).Enum(),
|
|
|
|
OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
|
2019-07-10 16:17:16 -07:00
|
|
|
A: proto.Int32(100),
|
2019-06-20 03:01:22 -07:00
|
|
|
},
|
|
|
|
RepeatedSfixed32: []int32{1, 2, 3},
|
|
|
|
RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{
|
2019-07-10 16:17:16 -07:00
|
|
|
{A: proto.Int32(200)},
|
|
|
|
{A: proto.Int32(300)},
|
2019-06-20 03:01:22 -07:00
|
|
|
},
|
|
|
|
MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{
|
|
|
|
"fizz": 400,
|
|
|
|
"buzz": 500,
|
|
|
|
},
|
|
|
|
MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{
|
2019-07-10 16:17:16 -07:00
|
|
|
"foo": {A: proto.Int32(600)},
|
|
|
|
"bar": {A: proto.Int32(700)},
|
2019-06-20 03:01:22 -07:00
|
|
|
},
|
|
|
|
OneofField: &testpb.TestAllTypes_OneofNestedMessage{
|
|
|
|
&testpb.TestAllTypes_NestedMessage{
|
2019-07-10 16:17:16 -07:00
|
|
|
A: proto.Int32(800),
|
2019-06-20 03:01:22 -07:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
want: &testpb.TestAllTypes{
|
2019-07-10 16:17:16 -07:00
|
|
|
OptionalInt64: proto.Int64(0),
|
2019-06-20 03:01:22 -07:00
|
|
|
OptionalNestedEnum: testpb.TestAllTypes_NestedEnum(1).Enum(),
|
|
|
|
OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
|
2019-07-10 16:17:16 -07:00
|
|
|
A: proto.Int32(100),
|
2019-06-20 03:01:22 -07:00
|
|
|
},
|
|
|
|
RepeatedSfixed32: []int32{1, 2, 3},
|
|
|
|
RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{
|
2019-07-10 16:17:16 -07:00
|
|
|
{A: proto.Int32(200)},
|
|
|
|
{A: proto.Int32(300)},
|
2019-06-20 03:01:22 -07:00
|
|
|
},
|
|
|
|
MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{
|
|
|
|
"fizz": 400,
|
|
|
|
"buzz": 500,
|
|
|
|
},
|
|
|
|
MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{
|
2019-07-10 16:17:16 -07:00
|
|
|
"foo": {A: proto.Int32(600)},
|
|
|
|
"bar": {A: proto.Int32(700)},
|
2019-06-20 03:01:22 -07:00
|
|
|
},
|
|
|
|
OneofField: &testpb.TestAllTypes_OneofNestedMessage{
|
|
|
|
&testpb.TestAllTypes_NestedMessage{
|
2019-07-10 16:17:16 -07:00
|
|
|
A: proto.Int32(800),
|
2019-06-20 03:01:22 -07:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2020-01-02 15:47:15 -08:00
|
|
|
mutator: func(mi proto.Message) bool {
|
2019-06-20 03:01:22 -07:00
|
|
|
m := mi.(*testpb.TestAllTypes)
|
|
|
|
*m.OptionalInt64++
|
|
|
|
*m.OptionalNestedEnum++
|
|
|
|
*m.OptionalNestedMessage.A++
|
|
|
|
m.RepeatedSfixed32[0]++
|
|
|
|
*m.RepeatedNestedMessage[0].A++
|
|
|
|
delete(m.MapStringNestedEnum, "fizz")
|
|
|
|
*m.MapStringNestedMessage["foo"].A++
|
|
|
|
*m.OneofField.(*testpb.TestAllTypes_OneofNestedMessage).OneofNestedMessage.A++
|
2020-01-02 15:47:15 -08:00
|
|
|
return true
|
2019-06-20 03:01:22 -07:00
|
|
|
},
|
|
|
|
}, {
|
|
|
|
desc: "merge bytes",
|
|
|
|
dst: &testpb.TestAllTypes{
|
|
|
|
OptionalBytes: []byte{1, 2, 3},
|
|
|
|
RepeatedBytes: [][]byte{{1, 2}, {3, 4}},
|
|
|
|
MapStringBytes: map[string][]byte{"alpha": {1, 2, 3}},
|
|
|
|
},
|
|
|
|
src: &testpb.TestAllTypes{
|
|
|
|
OptionalBytes: []byte{4, 5, 6},
|
|
|
|
RepeatedBytes: [][]byte{{5, 6}, {7, 8}},
|
|
|
|
MapStringBytes: map[string][]byte{"alpha": {4, 5, 6}, "bravo": {1, 2, 3}},
|
|
|
|
},
|
|
|
|
want: &testpb.TestAllTypes{
|
|
|
|
OptionalBytes: []byte{4, 5, 6},
|
|
|
|
RepeatedBytes: [][]byte{{1, 2}, {3, 4}, {5, 6}, {7, 8}},
|
|
|
|
MapStringBytes: map[string][]byte{"alpha": {4, 5, 6}, "bravo": {1, 2, 3}},
|
|
|
|
},
|
2020-01-02 15:47:15 -08:00
|
|
|
mutator: func(mi proto.Message) bool {
|
2019-06-20 03:01:22 -07:00
|
|
|
m := mi.(*testpb.TestAllTypes)
|
|
|
|
m.OptionalBytes[0]++
|
|
|
|
m.RepeatedBytes[0][0]++
|
|
|
|
m.MapStringBytes["alpha"][0]++
|
2020-01-02 15:47:15 -08:00
|
|
|
return true
|
2019-06-20 03:01:22 -07:00
|
|
|
},
|
|
|
|
}, {
|
|
|
|
desc: "merge singular fields",
|
|
|
|
dst: &testpb.TestAllTypes{
|
2019-07-10 16:17:16 -07:00
|
|
|
OptionalInt32: proto.Int32(1),
|
|
|
|
OptionalInt64: proto.Int64(1),
|
2019-06-20 03:01:22 -07:00
|
|
|
OptionalNestedEnum: testpb.TestAllTypes_NestedEnum(10).Enum(),
|
|
|
|
OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
|
2019-07-10 16:17:16 -07:00
|
|
|
A: proto.Int32(100),
|
2019-06-20 03:01:22 -07:00
|
|
|
Corecursive: &testpb.TestAllTypes{
|
2019-07-10 16:17:16 -07:00
|
|
|
OptionalInt64: proto.Int64(1000),
|
2019-06-20 03:01:22 -07:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
src: &testpb.TestAllTypes{
|
2019-07-10 16:17:16 -07:00
|
|
|
OptionalInt64: proto.Int64(2),
|
2019-06-20 03:01:22 -07:00
|
|
|
OptionalNestedEnum: testpb.TestAllTypes_NestedEnum(20).Enum(),
|
|
|
|
OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
|
2019-07-10 16:17:16 -07:00
|
|
|
A: proto.Int32(200),
|
2019-06-20 03:01:22 -07:00
|
|
|
},
|
|
|
|
},
|
|
|
|
want: &testpb.TestAllTypes{
|
2019-07-10 16:17:16 -07:00
|
|
|
OptionalInt32: proto.Int32(1),
|
|
|
|
OptionalInt64: proto.Int64(2),
|
2019-06-20 03:01:22 -07:00
|
|
|
OptionalNestedEnum: testpb.TestAllTypes_NestedEnum(20).Enum(),
|
|
|
|
OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
|
2019-07-10 16:17:16 -07:00
|
|
|
A: proto.Int32(200),
|
2019-06-20 03:01:22 -07:00
|
|
|
Corecursive: &testpb.TestAllTypes{
|
2019-07-10 16:17:16 -07:00
|
|
|
OptionalInt64: proto.Int64(1000),
|
2019-06-20 03:01:22 -07:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2020-01-02 15:47:15 -08:00
|
|
|
mutator: func(mi proto.Message) bool {
|
2019-06-20 03:01:22 -07:00
|
|
|
m := mi.(*testpb.TestAllTypes)
|
|
|
|
*m.OptionalInt64++
|
|
|
|
*m.OptionalNestedEnum++
|
|
|
|
*m.OptionalNestedMessage.A++
|
2020-01-02 15:47:15 -08:00
|
|
|
return false // scalar mutations are not observable in shallow copy
|
2019-06-20 03:01:22 -07:00
|
|
|
},
|
|
|
|
}, {
|
|
|
|
desc: "merge list fields",
|
|
|
|
dst: &testpb.TestAllTypes{
|
|
|
|
RepeatedSfixed32: []int32{1, 2, 3},
|
|
|
|
RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{
|
2019-07-10 16:17:16 -07:00
|
|
|
{A: proto.Int32(100)},
|
|
|
|
{A: proto.Int32(200)},
|
2019-06-20 03:01:22 -07:00
|
|
|
},
|
|
|
|
},
|
|
|
|
src: &testpb.TestAllTypes{
|
|
|
|
RepeatedSfixed32: []int32{4, 5, 6},
|
|
|
|
RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{
|
2019-07-10 16:17:16 -07:00
|
|
|
{A: proto.Int32(300)},
|
|
|
|
{A: proto.Int32(400)},
|
2019-06-20 03:01:22 -07:00
|
|
|
},
|
|
|
|
},
|
|
|
|
want: &testpb.TestAllTypes{
|
|
|
|
RepeatedSfixed32: []int32{1, 2, 3, 4, 5, 6},
|
|
|
|
RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{
|
2019-07-10 16:17:16 -07:00
|
|
|
{A: proto.Int32(100)},
|
|
|
|
{A: proto.Int32(200)},
|
|
|
|
{A: proto.Int32(300)},
|
|
|
|
{A: proto.Int32(400)},
|
2019-06-20 03:01:22 -07:00
|
|
|
},
|
|
|
|
},
|
2020-01-02 15:47:15 -08:00
|
|
|
mutator: func(mi proto.Message) bool {
|
2019-06-20 03:01:22 -07:00
|
|
|
m := mi.(*testpb.TestAllTypes)
|
|
|
|
m.RepeatedSfixed32[0]++
|
|
|
|
*m.RepeatedNestedMessage[0].A++
|
2020-01-02 15:47:15 -08:00
|
|
|
return true
|
2019-06-20 03:01:22 -07:00
|
|
|
},
|
|
|
|
}, {
|
|
|
|
desc: "merge map fields",
|
|
|
|
dst: &testpb.TestAllTypes{
|
|
|
|
MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{
|
|
|
|
"fizz": 100,
|
|
|
|
"buzz": 200,
|
|
|
|
"guzz": 300,
|
|
|
|
},
|
|
|
|
MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{
|
2019-07-10 16:17:16 -07:00
|
|
|
"foo": {A: proto.Int32(400)},
|
2019-06-20 03:01:22 -07:00
|
|
|
},
|
|
|
|
},
|
|
|
|
src: &testpb.TestAllTypes{
|
|
|
|
MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{
|
|
|
|
"fizz": 1000,
|
|
|
|
"buzz": 2000,
|
|
|
|
},
|
|
|
|
MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{
|
2019-07-10 16:17:16 -07:00
|
|
|
"foo": {A: proto.Int32(3000)},
|
2019-06-20 03:01:22 -07:00
|
|
|
"bar": {},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
want: &testpb.TestAllTypes{
|
|
|
|
MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{
|
|
|
|
"fizz": 1000,
|
|
|
|
"buzz": 2000,
|
|
|
|
"guzz": 300,
|
|
|
|
},
|
|
|
|
MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{
|
2019-07-10 16:17:16 -07:00
|
|
|
"foo": {A: proto.Int32(3000)},
|
2019-06-20 03:01:22 -07:00
|
|
|
"bar": {},
|
|
|
|
},
|
|
|
|
},
|
2020-01-02 15:47:15 -08:00
|
|
|
mutator: func(mi proto.Message) bool {
|
2019-06-20 03:01:22 -07:00
|
|
|
m := mi.(*testpb.TestAllTypes)
|
|
|
|
delete(m.MapStringNestedEnum, "fizz")
|
2019-07-10 16:17:16 -07:00
|
|
|
m.MapStringNestedMessage["bar"].A = proto.Int32(1)
|
2020-01-02 15:47:15 -08:00
|
|
|
return true
|
2019-06-20 03:01:22 -07:00
|
|
|
},
|
|
|
|
}, {
|
|
|
|
desc: "merge oneof message fields",
|
|
|
|
dst: &testpb.TestAllTypes{
|
|
|
|
OneofField: &testpb.TestAllTypes_OneofNestedMessage{
|
|
|
|
&testpb.TestAllTypes_NestedMessage{
|
2019-07-10 16:17:16 -07:00
|
|
|
A: proto.Int32(100),
|
2019-06-20 03:01:22 -07:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
src: &testpb.TestAllTypes{
|
|
|
|
OneofField: &testpb.TestAllTypes_OneofNestedMessage{
|
|
|
|
&testpb.TestAllTypes_NestedMessage{
|
|
|
|
Corecursive: &testpb.TestAllTypes{
|
2019-07-10 16:17:16 -07:00
|
|
|
OptionalInt64: proto.Int64(1000),
|
2019-06-20 03:01:22 -07:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
want: &testpb.TestAllTypes{
|
|
|
|
OneofField: &testpb.TestAllTypes_OneofNestedMessage{
|
|
|
|
&testpb.TestAllTypes_NestedMessage{
|
2019-07-10 16:17:16 -07:00
|
|
|
A: proto.Int32(100),
|
2019-06-20 03:01:22 -07:00
|
|
|
Corecursive: &testpb.TestAllTypes{
|
2019-07-10 16:17:16 -07:00
|
|
|
OptionalInt64: proto.Int64(1000),
|
2019-06-20 03:01:22 -07:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2020-01-02 15:47:15 -08:00
|
|
|
mutator: func(mi proto.Message) bool {
|
2019-06-20 03:01:22 -07:00
|
|
|
m := mi.(*testpb.TestAllTypes)
|
|
|
|
*m.OneofField.(*testpb.TestAllTypes_OneofNestedMessage).OneofNestedMessage.Corecursive.OptionalInt64++
|
2020-01-02 15:47:15 -08:00
|
|
|
return true
|
2019-06-20 03:01:22 -07:00
|
|
|
},
|
|
|
|
}, {
|
|
|
|
desc: "merge oneof scalar fields",
|
|
|
|
dst: &testpb.TestAllTypes{
|
|
|
|
OneofField: &testpb.TestAllTypes_OneofUint32{100},
|
|
|
|
},
|
|
|
|
src: &testpb.TestAllTypes{
|
|
|
|
OneofField: &testpb.TestAllTypes_OneofFloat{3.14152},
|
|
|
|
},
|
|
|
|
want: &testpb.TestAllTypes{
|
|
|
|
OneofField: &testpb.TestAllTypes_OneofFloat{3.14152},
|
|
|
|
},
|
2020-01-02 15:47:15 -08:00
|
|
|
mutator: func(mi proto.Message) bool {
|
2019-06-20 03:01:22 -07:00
|
|
|
m := mi.(*testpb.TestAllTypes)
|
|
|
|
m.OneofField.(*testpb.TestAllTypes_OneofFloat).OneofFloat++
|
2020-01-02 15:47:15 -08:00
|
|
|
return false // scalar mutations are not observable in shallow copy
|
2019-06-20 03:01:22 -07:00
|
|
|
},
|
|
|
|
}, {
|
|
|
|
desc: "merge extension fields",
|
|
|
|
dst: func() proto.Message {
|
|
|
|
m := new(testpb.TestAllExtensions)
|
2020-02-02 00:53:34 -08:00
|
|
|
proto.SetExtension(m, testpb.E_OptionalInt32, int32(32))
|
|
|
|
proto.SetExtension(m, testpb.E_OptionalNestedMessage,
|
2020-01-28 13:11:20 -08:00
|
|
|
&testpb.TestAllExtensions_NestedMessage{
|
2019-07-10 16:17:16 -07:00
|
|
|
A: proto.Int32(50),
|
2019-08-02 16:58:08 -07:00
|
|
|
},
|
2019-06-20 03:01:22 -07:00
|
|
|
)
|
2020-02-02 00:53:34 -08:00
|
|
|
proto.SetExtension(m, testpb.E_RepeatedFixed32, []uint32{1, 2, 3})
|
2019-06-20 03:01:22 -07:00
|
|
|
return m
|
|
|
|
}(),
|
|
|
|
src: func() proto.Message {
|
2020-01-28 13:11:20 -08:00
|
|
|
m2 := new(testpb.TestAllExtensions)
|
2020-02-02 00:53:34 -08:00
|
|
|
proto.SetExtension(m2, testpb.E_OptionalInt64, int64(1000))
|
2019-06-20 03:01:22 -07:00
|
|
|
m := new(testpb.TestAllExtensions)
|
2020-02-02 00:53:34 -08:00
|
|
|
proto.SetExtension(m, testpb.E_OptionalInt64, int64(64))
|
|
|
|
proto.SetExtension(m, testpb.E_OptionalNestedMessage,
|
2020-01-28 13:11:20 -08:00
|
|
|
&testpb.TestAllExtensions_NestedMessage{
|
|
|
|
Corecursive: m2,
|
2019-08-02 16:58:08 -07:00
|
|
|
},
|
2019-06-20 03:01:22 -07:00
|
|
|
)
|
2020-02-02 00:53:34 -08:00
|
|
|
proto.SetExtension(m, testpb.E_RepeatedFixed32, []uint32{4, 5, 6})
|
2019-06-20 03:01:22 -07:00
|
|
|
return m
|
|
|
|
}(),
|
|
|
|
want: func() proto.Message {
|
2020-01-28 13:11:20 -08:00
|
|
|
m2 := new(testpb.TestAllExtensions)
|
2020-02-02 00:53:34 -08:00
|
|
|
proto.SetExtension(m2, testpb.E_OptionalInt64, int64(1000))
|
2019-06-20 03:01:22 -07:00
|
|
|
m := new(testpb.TestAllExtensions)
|
2020-02-02 00:53:34 -08:00
|
|
|
proto.SetExtension(m, testpb.E_OptionalInt32, int32(32))
|
|
|
|
proto.SetExtension(m, testpb.E_OptionalInt64, int64(64))
|
|
|
|
proto.SetExtension(m, testpb.E_OptionalNestedMessage,
|
2020-01-28 13:11:20 -08:00
|
|
|
&testpb.TestAllExtensions_NestedMessage{
|
|
|
|
A: proto.Int32(50),
|
|
|
|
Corecursive: m2,
|
2019-08-02 16:58:08 -07:00
|
|
|
},
|
2019-06-20 03:01:22 -07:00
|
|
|
)
|
2020-02-02 00:53:34 -08:00
|
|
|
proto.SetExtension(m, testpb.E_RepeatedFixed32, []uint32{1, 2, 3, 4, 5, 6})
|
2019-06-20 03:01:22 -07:00
|
|
|
return m
|
|
|
|
}(),
|
|
|
|
}, {
|
|
|
|
desc: "merge unknown fields",
|
|
|
|
dst: func() proto.Message {
|
|
|
|
m := new(testpb.TestAllTypes)
|
|
|
|
m.ProtoReflect().SetUnknown(pack.Message{
|
|
|
|
pack.Tag{Number: 50000, Type: pack.VarintType}, pack.Svarint(-5),
|
|
|
|
}.Marshal())
|
|
|
|
return m
|
|
|
|
}(),
|
|
|
|
src: func() proto.Message {
|
|
|
|
m := new(testpb.TestAllTypes)
|
|
|
|
m.ProtoReflect().SetUnknown(pack.Message{
|
|
|
|
pack.Tag{Number: 500000, Type: pack.VarintType}, pack.Svarint(-50),
|
|
|
|
}.Marshal())
|
|
|
|
return m
|
|
|
|
}(),
|
|
|
|
want: func() proto.Message {
|
|
|
|
m := new(testpb.TestAllTypes)
|
|
|
|
m.ProtoReflect().SetUnknown(pack.Message{
|
|
|
|
pack.Tag{Number: 50000, Type: pack.VarintType}, pack.Svarint(-5),
|
|
|
|
pack.Tag{Number: 500000, Type: pack.VarintType}, pack.Svarint(-50),
|
|
|
|
}.Marshal())
|
|
|
|
return m
|
|
|
|
}(),
|
|
|
|
}}
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.desc, func(t *testing.T) {
|
|
|
|
// Merge should be semantically equivalent to unmarshaling the
|
|
|
|
// encoded form of src into the current dst.
|
|
|
|
b1, err := proto.MarshalOptions{AllowPartial: true}.Marshal(tt.dst)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Marshal(dst) error: %v", err)
|
|
|
|
}
|
|
|
|
b2, err := proto.MarshalOptions{AllowPartial: true}.Marshal(tt.src)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Marshal(src) error: %v", err)
|
|
|
|
}
|
|
|
|
dst := tt.dst.ProtoReflect().New().Interface()
|
|
|
|
err = proto.UnmarshalOptions{AllowPartial: true}.Unmarshal(append(b1, b2...), dst)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Unmarshal() error: %v", err)
|
|
|
|
}
|
2019-07-11 23:15:05 -07:00
|
|
|
if !proto.Equal(dst, tt.want) {
|
2019-06-20 03:01:22 -07:00
|
|
|
t.Fatalf("Unmarshal(Marshal(dst)+Marshal(src)) mismatch: got %v, want %v", dst, tt.want)
|
|
|
|
}
|
|
|
|
|
2020-02-12 10:26:17 -08:00
|
|
|
proto.Merge(tt.dst, tt.src)
|
2019-06-20 03:01:22 -07:00
|
|
|
if !proto.Equal(tt.dst, tt.want) {
|
2019-08-29 11:42:57 -07:00
|
|
|
t.Fatalf("Merge() mismatch:\n got %v\nwant %v", tt.dst, tt.want)
|
2019-06-20 03:01:22 -07:00
|
|
|
}
|
2020-01-02 15:47:15 -08:00
|
|
|
if tt.mutator != nil {
|
2020-02-12 10:26:17 -08:00
|
|
|
if !proto.Equal(tt.dst, tt.want) {
|
|
|
|
t.Fatalf("mutation observed in dest after modifying merge source:\n got %v\nwant %v", tt.dst, tt.want)
|
2020-01-02 15:47:15 -08:00
|
|
|
}
|
|
|
|
}
|
2019-06-20 03:01:22 -07:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2019-09-20 12:18:55 -07:00
|
|
|
|
2019-09-20 17:57:39 -07:00
|
|
|
// TestMergeAberrant tests inputs that are beyond the protobuf data model.
|
|
|
|
// Just because there is a test for the current behavior does not mean that
|
|
|
|
// this will behave the same way in the future.
|
|
|
|
func TestMergeAberrant(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
|
|
label string
|
|
|
|
dst proto.Message
|
|
|
|
src proto.Message
|
|
|
|
check func(proto.Message) bool
|
|
|
|
}{{
|
|
|
|
label: "Proto2EmptyBytes",
|
|
|
|
dst: &testpb.TestAllTypes{OptionalBytes: nil},
|
|
|
|
src: &testpb.TestAllTypes{OptionalBytes: []byte{}},
|
|
|
|
check: func(m proto.Message) bool {
|
|
|
|
return m.(*testpb.TestAllTypes).OptionalBytes != nil
|
|
|
|
},
|
|
|
|
}, {
|
|
|
|
label: "Proto3EmptyBytes",
|
|
|
|
dst: &test3pb.TestAllTypes{OptionalBytes: nil},
|
|
|
|
src: &test3pb.TestAllTypes{OptionalBytes: []byte{}},
|
|
|
|
check: func(m proto.Message) bool {
|
|
|
|
return m.(*test3pb.TestAllTypes).OptionalBytes == nil
|
|
|
|
},
|
|
|
|
}, {
|
|
|
|
label: "EmptyList",
|
|
|
|
dst: &testpb.TestAllTypes{RepeatedInt32: nil},
|
|
|
|
src: &testpb.TestAllTypes{RepeatedInt32: []int32{}},
|
|
|
|
check: func(m proto.Message) bool {
|
|
|
|
return m.(*testpb.TestAllTypes).RepeatedInt32 == nil
|
|
|
|
},
|
|
|
|
}, {
|
|
|
|
label: "ListWithNilBytes",
|
|
|
|
dst: &testpb.TestAllTypes{RepeatedBytes: nil},
|
|
|
|
src: &testpb.TestAllTypes{RepeatedBytes: [][]byte{nil}},
|
|
|
|
check: func(m proto.Message) bool {
|
|
|
|
return reflect.DeepEqual(m.(*testpb.TestAllTypes).RepeatedBytes, [][]byte{{}})
|
|
|
|
},
|
|
|
|
}, {
|
|
|
|
label: "ListWithEmptyBytes",
|
|
|
|
dst: &testpb.TestAllTypes{RepeatedBytes: nil},
|
|
|
|
src: &testpb.TestAllTypes{RepeatedBytes: [][]byte{{}}},
|
|
|
|
check: func(m proto.Message) bool {
|
|
|
|
return reflect.DeepEqual(m.(*testpb.TestAllTypes).RepeatedBytes, [][]byte{{}})
|
|
|
|
},
|
|
|
|
}, {
|
|
|
|
label: "ListWithNilMessage",
|
|
|
|
dst: &testpb.TestAllTypes{RepeatedNestedMessage: nil},
|
|
|
|
src: &testpb.TestAllTypes{RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{nil}},
|
|
|
|
check: func(m proto.Message) bool {
|
|
|
|
return m.(*testpb.TestAllTypes).RepeatedNestedMessage[0] != nil
|
|
|
|
},
|
|
|
|
}, {
|
|
|
|
label: "EmptyMap",
|
|
|
|
dst: &testpb.TestAllTypes{MapStringString: nil},
|
|
|
|
src: &testpb.TestAllTypes{MapStringString: map[string]string{}},
|
|
|
|
check: func(m proto.Message) bool {
|
|
|
|
return m.(*testpb.TestAllTypes).MapStringString == nil
|
|
|
|
},
|
|
|
|
}, {
|
|
|
|
label: "MapWithNilBytes",
|
|
|
|
dst: &testpb.TestAllTypes{MapStringBytes: nil},
|
|
|
|
src: &testpb.TestAllTypes{MapStringBytes: map[string][]byte{"k": nil}},
|
|
|
|
check: func(m proto.Message) bool {
|
|
|
|
return reflect.DeepEqual(m.(*testpb.TestAllTypes).MapStringBytes, map[string][]byte{"k": {}})
|
|
|
|
},
|
|
|
|
}, {
|
|
|
|
label: "MapWithEmptyBytes",
|
|
|
|
dst: &testpb.TestAllTypes{MapStringBytes: nil},
|
|
|
|
src: &testpb.TestAllTypes{MapStringBytes: map[string][]byte{"k": {}}},
|
|
|
|
check: func(m proto.Message) bool {
|
|
|
|
return reflect.DeepEqual(m.(*testpb.TestAllTypes).MapStringBytes, map[string][]byte{"k": {}})
|
|
|
|
},
|
|
|
|
}, {
|
|
|
|
label: "MapWithNilMessage",
|
|
|
|
dst: &testpb.TestAllTypes{MapStringNestedMessage: nil},
|
|
|
|
src: &testpb.TestAllTypes{MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{"k": nil}},
|
|
|
|
check: func(m proto.Message) bool {
|
|
|
|
return m.(*testpb.TestAllTypes).MapStringNestedMessage["k"] != nil
|
|
|
|
},
|
|
|
|
}, {
|
|
|
|
label: "OneofWithTypedNilWrapper",
|
|
|
|
dst: &testpb.TestAllTypes{OneofField: nil},
|
|
|
|
src: &testpb.TestAllTypes{OneofField: (*testpb.TestAllTypes_OneofNestedMessage)(nil)},
|
|
|
|
check: func(m proto.Message) bool {
|
|
|
|
return m.(*testpb.TestAllTypes).OneofField == nil
|
|
|
|
},
|
|
|
|
}, {
|
|
|
|
label: "OneofWithNilMessage",
|
|
|
|
dst: &testpb.TestAllTypes{OneofField: nil},
|
|
|
|
src: &testpb.TestAllTypes{OneofField: &testpb.TestAllTypes_OneofNestedMessage{OneofNestedMessage: nil}},
|
|
|
|
check: func(m proto.Message) bool {
|
|
|
|
return m.(*testpb.TestAllTypes).OneofField.(*testpb.TestAllTypes_OneofNestedMessage).OneofNestedMessage != nil
|
|
|
|
},
|
|
|
|
// TODO: extension, nil message
|
|
|
|
// TODO: repeated extension, nil
|
|
|
|
// TODO: extension bytes
|
|
|
|
// TODO: repeated extension, nil message
|
|
|
|
}}
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.label, func(t *testing.T) {
|
|
|
|
var pass bool
|
|
|
|
func() {
|
|
|
|
defer func() { recover() }()
|
|
|
|
proto.Merge(tt.dst, tt.src)
|
|
|
|
pass = tt.check(tt.dst)
|
|
|
|
}()
|
|
|
|
if !pass {
|
|
|
|
t.Error("check failed")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-20 12:18:55 -07:00
|
|
|
func TestMergeRace(t *testing.T) {
|
|
|
|
dst := new(testpb.TestAllTypes)
|
|
|
|
srcs := []*testpb.TestAllTypes{
|
|
|
|
{OptionalInt32: proto.Int32(1)},
|
|
|
|
{OptionalString: proto.String("hello")},
|
|
|
|
{RepeatedInt32: []int32{2, 3, 4}},
|
|
|
|
{RepeatedString: []string{"goodbye"}},
|
|
|
|
{MapStringString: map[string]string{"key": "value"}},
|
|
|
|
{OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
|
|
|
|
A: proto.Int32(5),
|
|
|
|
}},
|
|
|
|
func() *testpb.TestAllTypes {
|
|
|
|
m := new(testpb.TestAllTypes)
|
|
|
|
m.ProtoReflect().SetUnknown(pack.Message{
|
|
|
|
pack.Tag{Number: 50000, Type: pack.VarintType}, pack.Svarint(-5),
|
|
|
|
}.Marshal())
|
|
|
|
return m
|
|
|
|
}(),
|
|
|
|
}
|
|
|
|
|
|
|
|
// It should be safe to concurrently merge non-overlapping fields.
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
defer wg.Wait()
|
|
|
|
for _, src := range srcs {
|
|
|
|
wg.Add(1)
|
|
|
|
go func(src proto.Message) {
|
|
|
|
defer wg.Done()
|
|
|
|
proto.Merge(dst, src)
|
|
|
|
}(src)
|
|
|
|
}
|
|
|
|
}
|
2019-09-21 21:50:50 -07:00
|
|
|
|
|
|
|
func TestMergeSelf(t *testing.T) {
|
|
|
|
got := &testpb.TestAllTypes{
|
|
|
|
OptionalInt32: proto.Int32(1),
|
|
|
|
OptionalString: proto.String("hello"),
|
|
|
|
RepeatedInt32: []int32{2, 3, 4},
|
|
|
|
RepeatedString: []string{"goodbye"},
|
|
|
|
MapStringString: map[string]string{"key": "value"},
|
|
|
|
OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
|
|
|
|
A: proto.Int32(5),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
got.ProtoReflect().SetUnknown(pack.Message{
|
|
|
|
pack.Tag{Number: 50000, Type: pack.VarintType}, pack.Svarint(-5),
|
|
|
|
}.Marshal())
|
|
|
|
proto.Merge(got, got)
|
|
|
|
|
|
|
|
// The main impact of merging to self is that repeated fields and
|
|
|
|
// unknown fields are doubled.
|
|
|
|
want := &testpb.TestAllTypes{
|
|
|
|
OptionalInt32: proto.Int32(1),
|
|
|
|
OptionalString: proto.String("hello"),
|
|
|
|
RepeatedInt32: []int32{2, 3, 4, 2, 3, 4},
|
|
|
|
RepeatedString: []string{"goodbye", "goodbye"},
|
|
|
|
MapStringString: map[string]string{"key": "value"},
|
|
|
|
OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
|
|
|
|
A: proto.Int32(5),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
want.ProtoReflect().SetUnknown(pack.Message{
|
|
|
|
pack.Tag{Number: 50000, Type: pack.VarintType}, pack.Svarint(-5),
|
|
|
|
pack.Tag{Number: 50000, Type: pack.VarintType}, pack.Svarint(-5),
|
|
|
|
}.Marshal())
|
|
|
|
|
|
|
|
if !proto.Equal(got, want) {
|
|
|
|
t.Errorf("Equal mismatch:\ngot %v\nwant %v", got, want)
|
|
|
|
}
|
|
|
|
}
|