...

Source file src/google.golang.org/protobuf/proto/merge_test.go

Documentation: google.golang.org/protobuf/proto

     1  // 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  
     5  package proto_test
     6  
     7  import (
     8  	"fmt"
     9  	"reflect"
    10  	"sync"
    11  	"testing"
    12  
    13  	"github.com/google/go-cmp/cmp"
    14  
    15  	"google.golang.org/protobuf/encoding/prototext"
    16  	"google.golang.org/protobuf/internal/protobuild"
    17  	"google.golang.org/protobuf/proto"
    18  	"google.golang.org/protobuf/reflect/protoreflect"
    19  	"google.golang.org/protobuf/testing/protocmp"
    20  	"google.golang.org/protobuf/testing/protopack"
    21  	"google.golang.org/protobuf/types/dynamicpb"
    22  
    23  	legacypb "google.golang.org/protobuf/internal/testprotos/legacy"
    24  	testpb "google.golang.org/protobuf/internal/testprotos/test"
    25  	test3pb "google.golang.org/protobuf/internal/testprotos/test3"
    26  )
    27  
    28  type testMerge struct {
    29  	desc  string
    30  	dst   protobuild.Message
    31  	src   protobuild.Message
    32  	want  protobuild.Message // if dst and want are nil, want = src
    33  	types []proto.Message
    34  }
    35  
    36  var testMerges = []testMerge{{
    37  	desc: "clone a large message",
    38  	src: protobuild.Message{
    39  		"optional_int32":       1001,
    40  		"optional_int64":       1002,
    41  		"optional_uint32":      1003,
    42  		"optional_uint64":      1004,
    43  		"optional_sint32":      1005,
    44  		"optional_sint64":      1006,
    45  		"optional_fixed32":     1007,
    46  		"optional_fixed64":     1008,
    47  		"optional_sfixed32":    1009,
    48  		"optional_sfixed64":    1010,
    49  		"optional_float":       1011.5,
    50  		"optional_double":      1012.5,
    51  		"optional_bool":        true,
    52  		"optional_string":      "string",
    53  		"optional_bytes":       []byte("bytes"),
    54  		"optional_nested_enum": 1,
    55  		"optional_nested_message": protobuild.Message{
    56  			"a": 100,
    57  		},
    58  		"repeated_int32":       []int32{1001, 2001},
    59  		"repeated_int64":       []int64{1002, 2002},
    60  		"repeated_uint32":      []uint32{1003, 2003},
    61  		"repeated_uint64":      []uint64{1004, 2004},
    62  		"repeated_sint32":      []int32{1005, 2005},
    63  		"repeated_sint64":      []int64{1006, 2006},
    64  		"repeated_fixed32":     []uint32{1007, 2007},
    65  		"repeated_fixed64":     []uint64{1008, 2008},
    66  		"repeated_sfixed32":    []int32{1009, 2009},
    67  		"repeated_sfixed64":    []int64{1010, 2010},
    68  		"repeated_float":       []float32{1011.5, 2011.5},
    69  		"repeated_double":      []float64{1012.5, 2012.5},
    70  		"repeated_bool":        []bool{true, false},
    71  		"repeated_string":      []string{"foo", "bar"},
    72  		"repeated_bytes":       []string{"FOO", "BAR"},
    73  		"repeated_nested_enum": []string{"FOO", "BAR"},
    74  		"repeated_nested_message": []protobuild.Message{
    75  			{"a": 200},
    76  			{"a": 300},
    77  		},
    78  	},
    79  }, {
    80  	desc: "clone maps",
    81  	src: protobuild.Message{
    82  		"map_int32_int32":       map[int32]int32{1056: 1156, 2056: 2156},
    83  		"map_int64_int64":       map[int64]int64{1057: 1157, 2057: 2157},
    84  		"map_uint32_uint32":     map[uint32]uint32{1058: 1158, 2058: 2158},
    85  		"map_uint64_uint64":     map[uint64]uint64{1059: 1159, 2059: 2159},
    86  		"map_sint32_sint32":     map[int32]int32{1060: 1160, 2060: 2160},
    87  		"map_sint64_sint64":     map[int64]int64{1061: 1161, 2061: 2161},
    88  		"map_fixed32_fixed32":   map[uint32]uint32{1062: 1162, 2062: 2162},
    89  		"map_fixed64_fixed64":   map[uint64]uint64{1063: 1163, 2063: 2163},
    90  		"map_sfixed32_sfixed32": map[int32]int32{1064: 1164, 2064: 2164},
    91  		"map_sfixed64_sfixed64": map[int64]int64{1065: 1165, 2065: 2165},
    92  		"map_int32_float":       map[int32]float32{1066: 1166.5, 2066: 2166.5},
    93  		"map_int32_double":      map[int32]float64{1067: 1167.5, 2067: 2167.5},
    94  		"map_bool_bool":         map[bool]bool{true: false, false: true},
    95  		"map_string_string":     map[string]string{"69.1.key": "69.1.val", "69.2.key": "69.2.val"},
    96  		"map_string_bytes":      map[string][]byte{"70.1.key": []byte("70.1.val"), "70.2.key": []byte("70.2.val")},
    97  		"map_string_nested_message": map[string]protobuild.Message{
    98  			"71.1.key": {"a": 1171},
    99  			"71.2.key": {"a": 2171},
   100  		},
   101  		"map_string_nested_enum": map[string]string{"73.1.key": "FOO", "73.2.key": "BAR"},
   102  	},
   103  	types: []proto.Message{&testpb.TestAllTypes{}, &test3pb.TestAllTypes{}},
   104  }, {
   105  	desc: "clone oneof uint32",
   106  	src: protobuild.Message{
   107  		"oneof_uint32": 1111,
   108  	},
   109  	types: []proto.Message{&testpb.TestAllTypes{}, &test3pb.TestAllTypes{}},
   110  }, {
   111  	desc: "clone oneof string",
   112  	src: protobuild.Message{
   113  		"oneof_string": "string",
   114  	},
   115  	types: []proto.Message{&testpb.TestAllTypes{}, &test3pb.TestAllTypes{}},
   116  }, {
   117  	desc: "clone oneof bytes",
   118  	src: protobuild.Message{
   119  		"oneof_bytes": "bytes",
   120  	},
   121  	types: []proto.Message{&testpb.TestAllTypes{}, &test3pb.TestAllTypes{}},
   122  }, {
   123  	desc: "clone oneof bool",
   124  	src: protobuild.Message{
   125  		"oneof_bool": true,
   126  	},
   127  	types: []proto.Message{&testpb.TestAllTypes{}, &test3pb.TestAllTypes{}},
   128  }, {
   129  	desc: "clone oneof uint64",
   130  	src: protobuild.Message{
   131  		"oneof_uint64": 100,
   132  	},
   133  	types: []proto.Message{&testpb.TestAllTypes{}, &test3pb.TestAllTypes{}},
   134  }, {
   135  	desc: "clone oneof float",
   136  	src: protobuild.Message{
   137  		"oneof_float": 100,
   138  	},
   139  	types: []proto.Message{&testpb.TestAllTypes{}, &test3pb.TestAllTypes{}},
   140  }, {
   141  	desc: "clone oneof double",
   142  	src: protobuild.Message{
   143  		"oneof_double": 1111,
   144  	},
   145  	types: []proto.Message{&testpb.TestAllTypes{}, &test3pb.TestAllTypes{}},
   146  }, {
   147  	desc: "clone oneof enum",
   148  	src: protobuild.Message{
   149  		"oneof_enum": 1,
   150  	},
   151  	types: []proto.Message{&testpb.TestAllTypes{}, &test3pb.TestAllTypes{}},
   152  }, {
   153  	desc: "clone oneof message",
   154  	src: protobuild.Message{
   155  		"oneof_nested_message": protobuild.Message{
   156  			"a": 1,
   157  		},
   158  	},
   159  	types: []proto.Message{&testpb.TestAllTypes{}, &test3pb.TestAllTypes{}},
   160  }, {
   161  	desc: "clone oneof group",
   162  	src: protobuild.Message{
   163  		"oneofgroup": protobuild.Message{
   164  			"a": 1,
   165  		},
   166  	},
   167  	types: []proto.Message{&testpb.TestAllTypes{}},
   168  }, {
   169  	desc: "merge bytes",
   170  	dst: protobuild.Message{
   171  		"optional_bytes":   []byte{1, 2, 3},
   172  		"repeated_bytes":   [][]byte{{1, 2}, {3, 4}},
   173  		"map_string_bytes": map[string][]byte{"alpha": {1, 2, 3}},
   174  	},
   175  	src: protobuild.Message{
   176  		"optional_bytes":   []byte{4, 5, 6},
   177  		"repeated_bytes":   [][]byte{{5, 6}, {7, 8}},
   178  		"map_string_bytes": map[string][]byte{"alpha": {4, 5, 6}, "bravo": {1, 2, 3}},
   179  	},
   180  	want: protobuild.Message{
   181  		"optional_bytes":   []byte{4, 5, 6},
   182  		"repeated_bytes":   [][]byte{{1, 2}, {3, 4}, {5, 6}, {7, 8}},
   183  		"map_string_bytes": map[string][]byte{"alpha": {4, 5, 6}, "bravo": {1, 2, 3}},
   184  	},
   185  	types: []proto.Message{&testpb.TestAllTypes{}, &test3pb.TestAllTypes{}},
   186  }, {
   187  	desc: "merge singular fields",
   188  	dst: protobuild.Message{
   189  		"optional_int32":       1,
   190  		"optional_int64":       1,
   191  		"optional_uint32":      1,
   192  		"optional_uint64":      1,
   193  		"optional_sint32":      1,
   194  		"optional_sint64":      1,
   195  		"optional_fixed32":     1,
   196  		"optional_fixed64":     1,
   197  		"optional_sfixed32":    1,
   198  		"optional_sfixed64":    1,
   199  		"optional_float":       1,
   200  		"optional_double":      1,
   201  		"optional_bool":        false,
   202  		"optional_string":      "1",
   203  		"optional_bytes":       "1",
   204  		"optional_nested_enum": 1,
   205  		"optional_nested_message": protobuild.Message{
   206  			"a": 1,
   207  			"corecursive": protobuild.Message{
   208  				"optional_int64": 1,
   209  			},
   210  		},
   211  	},
   212  	src: protobuild.Message{
   213  		"optional_int32":       2,
   214  		"optional_int64":       2,
   215  		"optional_uint32":      2,
   216  		"optional_uint64":      2,
   217  		"optional_sint32":      2,
   218  		"optional_sint64":      2,
   219  		"optional_fixed32":     2,
   220  		"optional_fixed64":     2,
   221  		"optional_sfixed32":    2,
   222  		"optional_sfixed64":    2,
   223  		"optional_float":       2,
   224  		"optional_double":      2,
   225  		"optional_bool":        true,
   226  		"optional_string":      "2",
   227  		"optional_bytes":       "2",
   228  		"optional_nested_enum": 2,
   229  		"optional_nested_message": protobuild.Message{
   230  			"a": 2,
   231  			"corecursive": protobuild.Message{
   232  				"optional_int64": 2,
   233  			},
   234  		},
   235  	},
   236  	want: protobuild.Message{
   237  		"optional_int32":       2,
   238  		"optional_int64":       2,
   239  		"optional_uint32":      2,
   240  		"optional_uint64":      2,
   241  		"optional_sint32":      2,
   242  		"optional_sint64":      2,
   243  		"optional_fixed32":     2,
   244  		"optional_fixed64":     2,
   245  		"optional_sfixed32":    2,
   246  		"optional_sfixed64":    2,
   247  		"optional_float":       2,
   248  		"optional_double":      2,
   249  		"optional_bool":        true,
   250  		"optional_string":      "2",
   251  		"optional_bytes":       "2",
   252  		"optional_nested_enum": 2,
   253  		"optional_nested_message": protobuild.Message{
   254  			"a": 2,
   255  			"corecursive": protobuild.Message{
   256  				"optional_int64": 2,
   257  			},
   258  		},
   259  	},
   260  }, {
   261  	desc: "no merge of empty singular fields",
   262  	dst: protobuild.Message{
   263  		"optional_int32":       1,
   264  		"optional_int64":       1,
   265  		"optional_uint32":      1,
   266  		"optional_uint64":      1,
   267  		"optional_sint32":      1,
   268  		"optional_sint64":      1,
   269  		"optional_fixed32":     1,
   270  		"optional_fixed64":     1,
   271  		"optional_sfixed32":    1,
   272  		"optional_sfixed64":    1,
   273  		"optional_float":       1,
   274  		"optional_double":      1,
   275  		"optional_bool":        false,
   276  		"optional_string":      "1",
   277  		"optional_bytes":       "1",
   278  		"optional_nested_enum": 1,
   279  		"optional_nested_message": protobuild.Message{
   280  			"a": 1,
   281  			"corecursive": protobuild.Message{
   282  				"optional_int64": 1,
   283  			},
   284  		},
   285  	},
   286  	src: protobuild.Message{
   287  		"optional_nested_message": protobuild.Message{
   288  			"a": 1,
   289  			"corecursive": protobuild.Message{
   290  				"optional_int32": 2,
   291  			},
   292  		},
   293  	},
   294  	want: protobuild.Message{
   295  		"optional_int32":       1,
   296  		"optional_int64":       1,
   297  		"optional_uint32":      1,
   298  		"optional_uint64":      1,
   299  		"optional_sint32":      1,
   300  		"optional_sint64":      1,
   301  		"optional_fixed32":     1,
   302  		"optional_fixed64":     1,
   303  		"optional_sfixed32":    1,
   304  		"optional_sfixed64":    1,
   305  		"optional_float":       1,
   306  		"optional_double":      1,
   307  		"optional_bool":        false,
   308  		"optional_string":      "1",
   309  		"optional_bytes":       "1",
   310  		"optional_nested_enum": 1,
   311  		"optional_nested_message": protobuild.Message{
   312  			"a": 1,
   313  			"corecursive": protobuild.Message{
   314  				"optional_int32": 2,
   315  				"optional_int64": 1,
   316  			},
   317  		},
   318  	},
   319  }, {
   320  	desc: "merge list fields",
   321  	dst: protobuild.Message{
   322  		"repeated_int32":       []int32{1, 2, 3},
   323  		"repeated_int64":       []int64{1, 2, 3},
   324  		"repeated_uint32":      []uint32{1, 2, 3},
   325  		"repeated_uint64":      []uint64{1, 2, 3},
   326  		"repeated_sint32":      []int32{1, 2, 3},
   327  		"repeated_sint64":      []int64{1, 2, 3},
   328  		"repeated_fixed32":     []uint32{1, 2, 3},
   329  		"repeated_fixed64":     []uint64{1, 2, 3},
   330  		"repeated_sfixed32":    []int32{1, 2, 3},
   331  		"repeated_sfixed64":    []int64{1, 2, 3},
   332  		"repeated_float":       []float32{1, 2, 3},
   333  		"repeated_double":      []float64{1, 2, 3},
   334  		"repeated_bool":        []bool{true},
   335  		"repeated_string":      []string{"a", "b", "c"},
   336  		"repeated_bytes":       []string{"a", "b", "c"},
   337  		"repeated_nested_enum": []int{1, 2, 3},
   338  		"repeated_nested_message": []protobuild.Message{
   339  			{"a": 100},
   340  			{"a": 200},
   341  		},
   342  	},
   343  	src: protobuild.Message{
   344  		"repeated_int32":       []int32{4, 5, 6},
   345  		"repeated_int64":       []int64{4, 5, 6},
   346  		"repeated_uint32":      []uint32{4, 5, 6},
   347  		"repeated_uint64":      []uint64{4, 5, 6},
   348  		"repeated_sint32":      []int32{4, 5, 6},
   349  		"repeated_sint64":      []int64{4, 5, 6},
   350  		"repeated_fixed32":     []uint32{4, 5, 6},
   351  		"repeated_fixed64":     []uint64{4, 5, 6},
   352  		"repeated_sfixed32":    []int32{4, 5, 6},
   353  		"repeated_sfixed64":    []int64{4, 5, 6},
   354  		"repeated_float":       []float32{4, 5, 6},
   355  		"repeated_double":      []float64{4, 5, 6},
   356  		"repeated_bool":        []bool{false},
   357  		"repeated_string":      []string{"d", "e", "f"},
   358  		"repeated_bytes":       []string{"d", "e", "f"},
   359  		"repeated_nested_enum": []int{4, 5, 6},
   360  		"repeated_nested_message": []protobuild.Message{
   361  			{"a": 300},
   362  			{"a": 400},
   363  		},
   364  	},
   365  	want: protobuild.Message{
   366  		"repeated_int32":       []int32{1, 2, 3, 4, 5, 6},
   367  		"repeated_int64":       []int64{1, 2, 3, 4, 5, 6},
   368  		"repeated_uint32":      []uint32{1, 2, 3, 4, 5, 6},
   369  		"repeated_uint64":      []uint64{1, 2, 3, 4, 5, 6},
   370  		"repeated_sint32":      []int32{1, 2, 3, 4, 5, 6},
   371  		"repeated_sint64":      []int64{1, 2, 3, 4, 5, 6},
   372  		"repeated_fixed32":     []uint32{1, 2, 3, 4, 5, 6},
   373  		"repeated_fixed64":     []uint64{1, 2, 3, 4, 5, 6},
   374  		"repeated_sfixed32":    []int32{1, 2, 3, 4, 5, 6},
   375  		"repeated_sfixed64":    []int64{1, 2, 3, 4, 5, 6},
   376  		"repeated_float":       []float32{1, 2, 3, 4, 5, 6},
   377  		"repeated_double":      []float64{1, 2, 3, 4, 5, 6},
   378  		"repeated_bool":        []bool{true, false},
   379  		"repeated_string":      []string{"a", "b", "c", "d", "e", "f"},
   380  		"repeated_bytes":       []string{"a", "b", "c", "d", "e", "f"},
   381  		"repeated_nested_enum": []int{1, 2, 3, 4, 5, 6},
   382  		"repeated_nested_message": []protobuild.Message{
   383  			{"a": 100},
   384  			{"a": 200},
   385  			{"a": 300},
   386  			{"a": 400},
   387  		},
   388  	},
   389  }, {
   390  	desc: "merge map fields",
   391  	dst: protobuild.Message{
   392  		"map_int32_int32":       map[int]int{1: 1, 3: 1},
   393  		"map_int64_int64":       map[int]int{1: 1, 3: 1},
   394  		"map_uint32_uint32":     map[int]int{1: 1, 3: 1},
   395  		"map_uint64_uint64":     map[int]int{1: 1, 3: 1},
   396  		"map_sint32_sint32":     map[int]int{1: 1, 3: 1},
   397  		"map_sint64_sint64":     map[int]int{1: 1, 3: 1},
   398  		"map_fixed32_fixed32":   map[int]int{1: 1, 3: 1},
   399  		"map_fixed64_fixed64":   map[int]int{1: 1, 3: 1},
   400  		"map_sfixed32_sfixed32": map[int]int{1: 1, 3: 1},
   401  		"map_sfixed64_sfixed64": map[int]int{1: 1, 3: 1},
   402  		"map_int32_float":       map[int]int{1: 1, 3: 1},
   403  		"map_int32_double":      map[int]int{1: 1, 3: 1},
   404  		"map_bool_bool":         map[bool]bool{true: true},
   405  		"map_string_string":     map[string]string{"a": "1", "ab": "1"},
   406  		"map_string_bytes":      map[string]string{"a": "1", "ab": "1"},
   407  		"map_string_nested_message": map[string]protobuild.Message{
   408  			"a": {"a": 1},
   409  			"ab": {
   410  				"a": 1,
   411  				"corecursive": protobuild.Message{
   412  					"map_int32_int32": map[int]int{1: 1, 3: 1},
   413  				},
   414  			},
   415  		},
   416  		"map_string_nested_enum": map[string]int{"a": 1, "ab": 1},
   417  	},
   418  	src: protobuild.Message{
   419  		"map_int32_int32":       map[int]int{2: 2, 3: 2},
   420  		"map_int64_int64":       map[int]int{2: 2, 3: 2},
   421  		"map_uint32_uint32":     map[int]int{2: 2, 3: 2},
   422  		"map_uint64_uint64":     map[int]int{2: 2, 3: 2},
   423  		"map_sint32_sint32":     map[int]int{2: 2, 3: 2},
   424  		"map_sint64_sint64":     map[int]int{2: 2, 3: 2},
   425  		"map_fixed32_fixed32":   map[int]int{2: 2, 3: 2},
   426  		"map_fixed64_fixed64":   map[int]int{2: 2, 3: 2},
   427  		"map_sfixed32_sfixed32": map[int]int{2: 2, 3: 2},
   428  		"map_sfixed64_sfixed64": map[int]int{2: 2, 3: 2},
   429  		"map_int32_float":       map[int]int{2: 2, 3: 2},
   430  		"map_int32_double":      map[int]int{2: 2, 3: 2},
   431  		"map_bool_bool":         map[bool]bool{false: false},
   432  		"map_string_string":     map[string]string{"b": "2", "ab": "2"},
   433  		"map_string_bytes":      map[string]string{"b": "2", "ab": "2"},
   434  		"map_string_nested_message": map[string]protobuild.Message{
   435  			"b": {"a": 2},
   436  			"ab": {
   437  				"a": 2,
   438  				"corecursive": protobuild.Message{
   439  					"map_int32_int32": map[int]int{2: 2, 3: 2},
   440  				},
   441  			},
   442  		},
   443  		"map_string_nested_enum": map[string]int{"b": 2, "ab": 2},
   444  	},
   445  	want: protobuild.Message{
   446  		"map_int32_int32":       map[int]int{1: 1, 2: 2, 3: 2},
   447  		"map_int64_int64":       map[int]int{1: 1, 2: 2, 3: 2},
   448  		"map_uint32_uint32":     map[int]int{1: 1, 2: 2, 3: 2},
   449  		"map_uint64_uint64":     map[int]int{1: 1, 2: 2, 3: 2},
   450  		"map_sint32_sint32":     map[int]int{1: 1, 2: 2, 3: 2},
   451  		"map_sint64_sint64":     map[int]int{1: 1, 2: 2, 3: 2},
   452  		"map_fixed32_fixed32":   map[int]int{1: 1, 2: 2, 3: 2},
   453  		"map_fixed64_fixed64":   map[int]int{1: 1, 2: 2, 3: 2},
   454  		"map_sfixed32_sfixed32": map[int]int{1: 1, 2: 2, 3: 2},
   455  		"map_sfixed64_sfixed64": map[int]int{1: 1, 2: 2, 3: 2},
   456  		"map_int32_float":       map[int]int{1: 1, 2: 2, 3: 2},
   457  		"map_int32_double":      map[int]int{1: 1, 2: 2, 3: 2},
   458  		"map_bool_bool":         map[bool]bool{true: true, false: false},
   459  		"map_string_string":     map[string]string{"a": "1", "b": "2", "ab": "2"},
   460  		"map_string_bytes":      map[string]string{"a": "1", "b": "2", "ab": "2"},
   461  		"map_string_nested_message": map[string]protobuild.Message{
   462  			"a": {"a": 1},
   463  			"b": {"a": 2},
   464  			"ab": {
   465  				"a": 2,
   466  				"corecursive": protobuild.Message{
   467  					// The map item "ab" was entirely replaced, so
   468  					// this does not contain 1:1 from dst.
   469  					"map_int32_int32": map[int]int{2: 2, 3: 2},
   470  				},
   471  			},
   472  		},
   473  		"map_string_nested_enum": map[string]int{"a": 1, "b": 2, "ab": 2},
   474  	},
   475  	types: []proto.Message{&testpb.TestAllTypes{}, &test3pb.TestAllTypes{}},
   476  }, {
   477  	desc: "merge oneof message fields",
   478  	dst: protobuild.Message{
   479  		"oneof_nested_message": protobuild.Message{
   480  			"a": 100,
   481  		},
   482  	},
   483  	src: protobuild.Message{
   484  		"oneof_nested_message": protobuild.Message{
   485  			"corecursive": protobuild.Message{
   486  				"optional_int64": 1000,
   487  			},
   488  		},
   489  	},
   490  	want: protobuild.Message{
   491  		"oneof_nested_message": protobuild.Message{
   492  			"a": 100,
   493  			"corecursive": protobuild.Message{
   494  				"optional_int64": 1000,
   495  			},
   496  		},
   497  	},
   498  	types: []proto.Message{&testpb.TestAllTypes{}, &test3pb.TestAllTypes{}},
   499  }, {
   500  	desc: "merge oneof scalar fields",
   501  	dst: protobuild.Message{
   502  		"oneof_uint32": 100,
   503  	},
   504  	src: protobuild.Message{
   505  		"oneof_float": 3.14152,
   506  	},
   507  	want: protobuild.Message{
   508  		"oneof_float": 3.14152,
   509  	},
   510  	types: []proto.Message{&testpb.TestAllTypes{}, &test3pb.TestAllTypes{}},
   511  }, {
   512  	desc: "merge unknown fields",
   513  	dst: protobuild.Message{
   514  		protobuild.Unknown: protopack.Message{
   515  			protopack.Tag{Number: 50000, Type: protopack.VarintType}, protopack.Svarint(-5),
   516  		}.Marshal(),
   517  	},
   518  	src: protobuild.Message{
   519  		protobuild.Unknown: protopack.Message{
   520  			protopack.Tag{Number: 500000, Type: protopack.VarintType}, protopack.Svarint(-50),
   521  		}.Marshal(),
   522  	},
   523  	want: protobuild.Message{
   524  		protobuild.Unknown: protopack.Message{
   525  			protopack.Tag{Number: 50000, Type: protopack.VarintType}, protopack.Svarint(-5),
   526  			protopack.Tag{Number: 500000, Type: protopack.VarintType}, protopack.Svarint(-50),
   527  		}.Marshal(),
   528  	},
   529  }, {
   530  	desc: "clone legacy message",
   531  	src: protobuild.Message{"f1": protobuild.Message{
   532  		"optional_int32":        1,
   533  		"optional_int64":        1,
   534  		"optional_uint32":       1,
   535  		"optional_uint64":       1,
   536  		"optional_sint32":       1,
   537  		"optional_sint64":       1,
   538  		"optional_fixed32":      1,
   539  		"optional_fixed64":      1,
   540  		"optional_sfixed32":     1,
   541  		"optional_sfixed64":     1,
   542  		"optional_float":        1,
   543  		"optional_double":       1,
   544  		"optional_bool":         true,
   545  		"optional_string":       "string",
   546  		"optional_bytes":        "bytes",
   547  		"optional_sibling_enum": 1,
   548  		"optional_sibling_message": protobuild.Message{
   549  			"f1": "value",
   550  		},
   551  		"repeated_int32":        []int32{1},
   552  		"repeated_int64":        []int64{1},
   553  		"repeated_uint32":       []uint32{1},
   554  		"repeated_uint64":       []uint64{1},
   555  		"repeated_sint32":       []int32{1},
   556  		"repeated_sint64":       []int64{1},
   557  		"repeated_fixed32":      []uint32{1},
   558  		"repeated_fixed64":      []uint64{1},
   559  		"repeated_sfixed32":     []int32{1},
   560  		"repeated_sfixed64":     []int64{1},
   561  		"repeated_float":        []float32{1},
   562  		"repeated_double":       []float64{1},
   563  		"repeated_bool":         []bool{true},
   564  		"repeated_string":       []string{"string"},
   565  		"repeated_bytes":        []string{"bytes"},
   566  		"repeated_sibling_enum": []int{1},
   567  		"repeated_sibling_message": []protobuild.Message{
   568  			{"f1": "1"},
   569  		},
   570  		"map_bool_int32":    map[bool]int{true: 1},
   571  		"map_bool_int64":    map[bool]int{true: 1},
   572  		"map_bool_uint32":   map[bool]int{true: 1},
   573  		"map_bool_uint64":   map[bool]int{true: 1},
   574  		"map_bool_sint32":   map[bool]int{true: 1},
   575  		"map_bool_sint64":   map[bool]int{true: 1},
   576  		"map_bool_fixed32":  map[bool]int{true: 1},
   577  		"map_bool_fixed64":  map[bool]int{true: 1},
   578  		"map_bool_sfixed32": map[bool]int{true: 1},
   579  		"map_bool_sfixed64": map[bool]int{true: 1},
   580  		"map_bool_float":    map[bool]int{true: 1},
   581  		"map_bool_double":   map[bool]int{true: 1},
   582  		"map_bool_bool":     map[bool]bool{true: false},
   583  		"map_bool_string":   map[bool]string{true: "1"},
   584  		"map_bool_bytes":    map[bool]string{true: "1"},
   585  		"map_bool_sibling_message": map[bool]protobuild.Message{
   586  			true: {"f1": "1"},
   587  		},
   588  		"map_bool_sibling_enum": map[bool]int{true: 1},
   589  		"oneof_sibling_message": protobuild.Message{
   590  			"f1": "1",
   591  		},
   592  	}},
   593  	types: []proto.Message{&legacypb.Legacy{}},
   594  }}
   595  
   596  func TestMerge(t *testing.T) {
   597  	for _, tt := range testMerges {
   598  		for _, mt := range templateMessages(tt.types...) {
   599  			t.Run(fmt.Sprintf("%s (%v)", tt.desc, mt.Descriptor().FullName()), func(t *testing.T) {
   600  				dst := mt.New().Interface()
   601  				tt.dst.Build(dst.ProtoReflect())
   602  
   603  				src := mt.New().Interface()
   604  				tt.src.Build(src.ProtoReflect())
   605  
   606  				want := mt.New().Interface()
   607  				if tt.dst == nil && tt.want == nil {
   608  					tt.src.Build(want.ProtoReflect())
   609  				} else {
   610  					tt.want.Build(want.ProtoReflect())
   611  				}
   612  
   613  				// Merge should be semantically equivalent to unmarshaling the
   614  				// encoded form of src into the current dst.
   615  				b1, err := proto.MarshalOptions{AllowPartial: true}.Marshal(dst)
   616  				if err != nil {
   617  					t.Fatalf("Marshal(dst) error: %v", err)
   618  				}
   619  				b2, err := proto.MarshalOptions{AllowPartial: true}.Marshal(src)
   620  				if err != nil {
   621  					t.Fatalf("Marshal(src) error: %v", err)
   622  				}
   623  				unmarshaled := dst.ProtoReflect().New().Interface()
   624  				err = proto.UnmarshalOptions{AllowPartial: true}.Unmarshal(append(b1, b2...), unmarshaled)
   625  				if err != nil {
   626  					t.Fatalf("Unmarshal() error: %v", err)
   627  				}
   628  				if !proto.Equal(unmarshaled, want) {
   629  					t.Fatalf("Unmarshal(Marshal(dst)+Marshal(src)) mismatch:\n got %v\nwant %v\ndiff (-want,+got):\n%v", unmarshaled, want, cmp.Diff(want, unmarshaled, protocmp.Transform()))
   630  				}
   631  
   632  				// Test heterogeneous MessageTypes by merging into a
   633  				// dynamic message.
   634  				ddst := dynamicpb.NewMessage(mt.Descriptor())
   635  				tt.dst.Build(ddst.ProtoReflect())
   636  				proto.Merge(ddst, src)
   637  				if !proto.Equal(ddst, want) {
   638  					t.Fatalf("Merge() into dynamic message mismatch:\n got %v\nwant %v\ndiff (-want,+got):\n%v", ddst, want, cmp.Diff(want, ddst, protocmp.Transform()))
   639  				}
   640  
   641  				proto.Merge(dst, src)
   642  				if !proto.Equal(dst, want) {
   643  					t.Fatalf("Merge() mismatch:\n got %v\nwant %v\ndiff (-want,+got):\n%v", dst, want, cmp.Diff(want, dst, protocmp.Transform()))
   644  				}
   645  				mutateValue(protoreflect.ValueOfMessage(src.ProtoReflect()))
   646  				if !proto.Equal(dst, want) {
   647  					t.Fatalf("mutation observed after modifying source:\n got %v\nwant %v\ndiff (-want,+got):\n%v", dst, want, cmp.Diff(want, dst, protocmp.Transform()))
   648  				}
   649  			})
   650  		}
   651  	}
   652  }
   653  
   654  func TestMergeFromNil(t *testing.T) {
   655  	dst := &testpb.TestAllTypes{}
   656  	proto.Merge(dst, (*testpb.TestAllTypes)(nil))
   657  	if !proto.Equal(dst, &testpb.TestAllTypes{}) {
   658  		t.Errorf("destination should be empty after merging from nil message; got:\n%v", prototext.Format(dst))
   659  	}
   660  }
   661  
   662  // TestMergeAberrant tests inputs that are beyond the protobuf data model.
   663  // Just because there is a test for the current behavior does not mean that
   664  // this will behave the same way in the future.
   665  func TestMergeAberrant(t *testing.T) {
   666  	tests := []struct {
   667  		label string
   668  		dst   proto.Message
   669  		src   proto.Message
   670  		check func(proto.Message) bool
   671  	}{{
   672  		label: "Proto2EmptyBytes",
   673  		dst:   &testpb.TestAllTypes{OptionalBytes: nil},
   674  		src:   &testpb.TestAllTypes{OptionalBytes: []byte{}},
   675  		check: func(m proto.Message) bool {
   676  			return m.(*testpb.TestAllTypes).OptionalBytes != nil
   677  		},
   678  	}, {
   679  		label: "Proto3EmptyBytes",
   680  		dst:   &test3pb.TestAllTypes{SingularBytes: nil},
   681  		src:   &test3pb.TestAllTypes{SingularBytes: []byte{}},
   682  		check: func(m proto.Message) bool {
   683  			return m.(*test3pb.TestAllTypes).SingularBytes == nil
   684  		},
   685  	}, {
   686  		label: "EmptyList",
   687  		dst:   &testpb.TestAllTypes{RepeatedInt32: nil},
   688  		src:   &testpb.TestAllTypes{RepeatedInt32: []int32{}},
   689  		check: func(m proto.Message) bool {
   690  			return m.(*testpb.TestAllTypes).RepeatedInt32 == nil
   691  		},
   692  	}, {
   693  		label: "ListWithNilBytes",
   694  		dst:   &testpb.TestAllTypes{RepeatedBytes: nil},
   695  		src:   &testpb.TestAllTypes{RepeatedBytes: [][]byte{nil}},
   696  		check: func(m proto.Message) bool {
   697  			return reflect.DeepEqual(m.(*testpb.TestAllTypes).RepeatedBytes, [][]byte{{}})
   698  		},
   699  	}, {
   700  		label: "ListWithEmptyBytes",
   701  		dst:   &testpb.TestAllTypes{RepeatedBytes: nil},
   702  		src:   &testpb.TestAllTypes{RepeatedBytes: [][]byte{{}}},
   703  		check: func(m proto.Message) bool {
   704  			return reflect.DeepEqual(m.(*testpb.TestAllTypes).RepeatedBytes, [][]byte{{}})
   705  		},
   706  	}, {
   707  		label: "ListWithNilMessage",
   708  		dst:   &testpb.TestAllTypes{RepeatedNestedMessage: nil},
   709  		src:   &testpb.TestAllTypes{RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{nil}},
   710  		check: func(m proto.Message) bool {
   711  			return m.(*testpb.TestAllTypes).RepeatedNestedMessage[0] != nil
   712  		},
   713  	}, {
   714  		label: "EmptyMap",
   715  		dst:   &testpb.TestAllTypes{MapStringString: nil},
   716  		src:   &testpb.TestAllTypes{MapStringString: map[string]string{}},
   717  		check: func(m proto.Message) bool {
   718  			return m.(*testpb.TestAllTypes).MapStringString == nil
   719  		},
   720  	}, {
   721  		label: "MapWithNilBytes",
   722  		dst:   &testpb.TestAllTypes{MapStringBytes: nil},
   723  		src:   &testpb.TestAllTypes{MapStringBytes: map[string][]byte{"k": nil}},
   724  		check: func(m proto.Message) bool {
   725  			return reflect.DeepEqual(m.(*testpb.TestAllTypes).MapStringBytes, map[string][]byte{"k": {}})
   726  		},
   727  	}, {
   728  		label: "MapWithEmptyBytes",
   729  		dst:   &testpb.TestAllTypes{MapStringBytes: nil},
   730  		src:   &testpb.TestAllTypes{MapStringBytes: map[string][]byte{"k": {}}},
   731  		check: func(m proto.Message) bool {
   732  			return reflect.DeepEqual(m.(*testpb.TestAllTypes).MapStringBytes, map[string][]byte{"k": {}})
   733  		},
   734  	}, {
   735  		label: "MapWithNilMessage",
   736  		dst:   &testpb.TestAllTypes{MapStringNestedMessage: nil},
   737  		src:   &testpb.TestAllTypes{MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{"k": nil}},
   738  		check: func(m proto.Message) bool {
   739  			return m.(*testpb.TestAllTypes).MapStringNestedMessage["k"] != nil
   740  		},
   741  	}, {
   742  		label: "OneofWithTypedNilWrapper",
   743  		dst:   &testpb.TestAllTypes{OneofField: nil},
   744  		src:   &testpb.TestAllTypes{OneofField: (*testpb.TestAllTypes_OneofNestedMessage)(nil)},
   745  		check: func(m proto.Message) bool {
   746  			return m.(*testpb.TestAllTypes).OneofField == nil
   747  		},
   748  	}, {
   749  		label: "OneofWithNilMessage",
   750  		dst:   &testpb.TestAllTypes{OneofField: nil},
   751  		src:   &testpb.TestAllTypes{OneofField: &testpb.TestAllTypes_OneofNestedMessage{OneofNestedMessage: nil}},
   752  		check: func(m proto.Message) bool {
   753  			return m.(*testpb.TestAllTypes).OneofField.(*testpb.TestAllTypes_OneofNestedMessage).OneofNestedMessage != nil
   754  		},
   755  		// TODO: extension, nil message
   756  		// TODO: repeated extension, nil
   757  		// TODO: extension bytes
   758  		// TODO: repeated extension, nil message
   759  	}}
   760  
   761  	for _, tt := range tests {
   762  		t.Run(tt.label, func(t *testing.T) {
   763  			var pass bool
   764  			func() {
   765  				defer func() { recover() }()
   766  				proto.Merge(tt.dst, tt.src)
   767  				pass = tt.check(tt.dst)
   768  			}()
   769  			if !pass {
   770  				t.Error("check failed")
   771  			}
   772  		})
   773  	}
   774  }
   775  
   776  func TestMergeRace(t *testing.T) {
   777  	dst := new(testpb.TestAllTypes)
   778  	srcs := []*testpb.TestAllTypes{
   779  		{OptionalInt32: proto.Int32(1)},
   780  		{OptionalString: proto.String("hello")},
   781  		{RepeatedInt32: []int32{2, 3, 4}},
   782  		{RepeatedString: []string{"goodbye"}},
   783  		{MapStringString: map[string]string{"key": "value"}},
   784  		{OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
   785  			A: proto.Int32(5),
   786  		}},
   787  		func() *testpb.TestAllTypes {
   788  			m := new(testpb.TestAllTypes)
   789  			m.ProtoReflect().SetUnknown(protopack.Message{
   790  				protopack.Tag{Number: 50000, Type: protopack.VarintType}, protopack.Svarint(-5),
   791  			}.Marshal())
   792  			return m
   793  		}(),
   794  	}
   795  
   796  	// It should be safe to concurrently merge non-overlapping fields.
   797  	var wg sync.WaitGroup
   798  	defer wg.Wait()
   799  	for _, src := range srcs {
   800  		wg.Add(1)
   801  		go func(src proto.Message) {
   802  			defer wg.Done()
   803  			proto.Merge(dst, src)
   804  		}(src)
   805  	}
   806  }
   807  
   808  func TestMergeSelf(t *testing.T) {
   809  	got := &testpb.TestAllTypes{
   810  		OptionalInt32:   proto.Int32(1),
   811  		OptionalString:  proto.String("hello"),
   812  		RepeatedInt32:   []int32{2, 3, 4},
   813  		RepeatedString:  []string{"goodbye"},
   814  		MapStringString: map[string]string{"key": "value"},
   815  		OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
   816  			A: proto.Int32(5),
   817  		},
   818  	}
   819  	got.ProtoReflect().SetUnknown(protopack.Message{
   820  		protopack.Tag{Number: 50000, Type: protopack.VarintType}, protopack.Svarint(-5),
   821  	}.Marshal())
   822  	proto.Merge(got, got)
   823  
   824  	// The main impact of merging to self is that repeated fields and
   825  	// unknown fields are doubled.
   826  	want := &testpb.TestAllTypes{
   827  		OptionalInt32:   proto.Int32(1),
   828  		OptionalString:  proto.String("hello"),
   829  		RepeatedInt32:   []int32{2, 3, 4, 2, 3, 4},
   830  		RepeatedString:  []string{"goodbye", "goodbye"},
   831  		MapStringString: map[string]string{"key": "value"},
   832  		OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{
   833  			A: proto.Int32(5),
   834  		},
   835  	}
   836  	want.ProtoReflect().SetUnknown(protopack.Message{
   837  		protopack.Tag{Number: 50000, Type: protopack.VarintType}, protopack.Svarint(-5),
   838  		protopack.Tag{Number: 50000, Type: protopack.VarintType}, protopack.Svarint(-5),
   839  	}.Marshal())
   840  
   841  	if !proto.Equal(got, want) {
   842  		t.Errorf("Equal mismatch:\ngot  %v\nwant %v", got, want)
   843  	}
   844  }
   845  
   846  func TestClone(t *testing.T) {
   847  	want := &testpb.TestAllTypes{
   848  		OptionalInt32: proto.Int32(1),
   849  	}
   850  	got := proto.Clone(want).(*testpb.TestAllTypes)
   851  	if !proto.Equal(got, want) {
   852  		t.Errorf("Clone(src) != src:\n got %v\nwant %v", got, want)
   853  	}
   854  }
   855  
   856  // mutateValue changes a Value, returning a new value.
   857  //
   858  // For scalar values, it returns a value different from the input.
   859  // For Message, List, and Map values, it mutates the input and returns it.
   860  func mutateValue(v protoreflect.Value) protoreflect.Value {
   861  	switch v := v.Interface().(type) {
   862  	case bool:
   863  		return protoreflect.ValueOfBool(!v)
   864  	case protoreflect.EnumNumber:
   865  		return protoreflect.ValueOfEnum(v + 1)
   866  	case int32:
   867  		return protoreflect.ValueOfInt32(v + 1)
   868  	case int64:
   869  		return protoreflect.ValueOfInt64(v + 1)
   870  	case uint32:
   871  		return protoreflect.ValueOfUint32(v + 1)
   872  	case uint64:
   873  		return protoreflect.ValueOfUint64(v + 1)
   874  	case float32:
   875  		return protoreflect.ValueOfFloat32(v + 1)
   876  	case float64:
   877  		return protoreflect.ValueOfFloat64(v + 1)
   878  	case []byte:
   879  		for i := range v {
   880  			v[i]++
   881  		}
   882  		return protoreflect.ValueOfBytes(v)
   883  	case string:
   884  		return protoreflect.ValueOfString("_" + v)
   885  	case protoreflect.Message:
   886  		v.Range(func(fd protoreflect.FieldDescriptor, val protoreflect.Value) bool {
   887  			v.Set(fd, mutateValue(val))
   888  			return true
   889  		})
   890  		return protoreflect.ValueOfMessage(v)
   891  	case protoreflect.List:
   892  		for i := 0; i < v.Len(); i++ {
   893  			v.Set(i, mutateValue(v.Get(i)))
   894  		}
   895  		return protoreflect.ValueOfList(v)
   896  	case protoreflect.Map:
   897  		v.Range(func(mk protoreflect.MapKey, mv protoreflect.Value) bool {
   898  			v.Set(mk, mutateValue(mv))
   899  			return true
   900  		})
   901  		return protoreflect.ValueOfMap(v)
   902  	default:
   903  		panic(fmt.Sprintf("unknown value type %T", v))
   904  	}
   905  }
   906  

View as plain text