1// Copyright 2020 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 protocmp
6
7import (
8	"testing"
9
10	"github.com/google/go-cmp/cmp"
11
12	"google.golang.org/protobuf/proto"
13
14	testpb "google.golang.org/protobuf/internal/testprotos/test"
15	textpb "google.golang.org/protobuf/internal/testprotos/textpb2"
16	anypb "google.golang.org/protobuf/types/known/anypb"
17	wrapperspb "google.golang.org/protobuf/types/known/wrapperspb"
18)
19
20func TestReflect(t *testing.T) {
21	optMsg := &testpb.TestAllTypes{
22		OptionalInt32:         proto.Int32(-32),
23		OptionalInt64:         proto.Int64(-64),
24		OptionalUint32:        proto.Uint32(32),
25		OptionalUint64:        proto.Uint64(64),
26		OptionalFloat:         proto.Float32(32.32),
27		OptionalDouble:        proto.Float64(64.64),
28		OptionalBool:          proto.Bool(true),
29		OptionalString:        proto.String("string"),
30		OptionalBytes:         []byte("bytes"),
31		OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{A: proto.Int32(-32)},
32		OptionalNestedEnum:    testpb.TestAllTypes_NEG.Enum(),
33	}
34	repMsg := &testpb.TestAllTypes{
35		RepeatedInt32:         []int32{-32, +32},
36		RepeatedInt64:         []int64{-64, +64},
37		RepeatedUint32:        []uint32{0, 32},
38		RepeatedUint64:        []uint64{0, 64},
39		RepeatedFloat:         []float32{-32.32, +32.32},
40		RepeatedDouble:        []float64{-64.64, +64.64},
41		RepeatedBool:          []bool{false, true},
42		RepeatedString:        []string{"hello", "goodbye"},
43		RepeatedBytes:         [][]byte{[]byte("hello"), []byte("goodbye")},
44		RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{{A: proto.Int32(-32)}, {A: proto.Int32(+32)}},
45		RepeatedNestedEnum:    []testpb.TestAllTypes_NestedEnum{testpb.TestAllTypes_FOO, testpb.TestAllTypes_NEG},
46	}
47	mapMsg := &testpb.TestAllTypes{
48		MapInt32Int32:          map[int32]int32{-1: -32, +1: +32},
49		MapInt64Int64:          map[int64]int64{-1: -32, +1: +64},
50		MapUint32Uint32:        map[uint32]uint32{0: 0, 1: 32},
51		MapUint64Uint64:        map[uint64]uint64{0: 0, 1: 64},
52		MapInt32Float:          map[int32]float32{-1: -32.32, +1: +32.32},
53		MapInt32Double:         map[int32]float64{-1: -64.64, +1: +64.64},
54		MapBoolBool:            map[bool]bool{false: true, true: false},
55		MapStringString:        map[string]string{"k1": "v1", "k2": "v2"},
56		MapStringBytes:         map[string][]byte{"k1": []byte("v1"), "k2": []byte("v2")},
57		MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{"k1": {A: proto.Int32(-32)}, "k2": {A: proto.Int32(+32)}},
58		MapStringNestedEnum:    map[string]testpb.TestAllTypes_NestedEnum{"k1": testpb.TestAllTypes_FOO, "k2": testpb.TestAllTypes_NEG},
59	}
60
61	tests := []proto.Message{
62		optMsg,
63		repMsg,
64		mapMsg,
65		&testpb.TestAllTypes{
66			OneofField: &testpb.TestAllTypes_OneofUint32{32},
67		},
68		&testpb.TestAllTypes{
69			OneofField: &testpb.TestAllTypes_OneofUint64{64},
70		},
71		&testpb.TestAllTypes{
72			OneofField: &testpb.TestAllTypes_OneofFloat{32.32},
73		},
74		&testpb.TestAllTypes{
75			OneofField: &testpb.TestAllTypes_OneofDouble{64.64},
76		},
77		&testpb.TestAllTypes{
78			OneofField: &testpb.TestAllTypes_OneofBool{true},
79		},
80		&testpb.TestAllTypes{
81			OneofField: &testpb.TestAllTypes_OneofString{"string"},
82		},
83		&testpb.TestAllTypes{
84			OneofField: &testpb.TestAllTypes_OneofBytes{[]byte("bytes")},
85		},
86		&testpb.TestAllTypes{
87			OneofField: &testpb.TestAllTypes_OneofNestedMessage{&testpb.TestAllTypes_NestedMessage{A: proto.Int32(-32)}},
88		},
89		&testpb.TestAllTypes{
90			OneofField: &testpb.TestAllTypes_OneofEnum{testpb.TestAllTypes_NEG},
91		},
92		func() proto.Message {
93			m := new(testpb.TestAllExtensions)
94			proto.SetExtension(m, testpb.E_OptionalInt32, int32(-32))
95			proto.SetExtension(m, testpb.E_OptionalInt64, int64(-64))
96			proto.SetExtension(m, testpb.E_OptionalUint32, uint32(32))
97			proto.SetExtension(m, testpb.E_OptionalUint64, uint64(64))
98			proto.SetExtension(m, testpb.E_OptionalFloat, float32(32.32))
99			proto.SetExtension(m, testpb.E_OptionalDouble, float64(64.64))
100			proto.SetExtension(m, testpb.E_OptionalBool, bool(true))
101			proto.SetExtension(m, testpb.E_OptionalString, string("string"))
102			proto.SetExtension(m, testpb.E_OptionalBytes, []byte("bytes"))
103			proto.SetExtension(m, testpb.E_OptionalNestedMessage, &testpb.TestAllExtensions_NestedMessage{A: proto.Int32(-32)})
104			proto.SetExtension(m, testpb.E_OptionalNestedEnum, testpb.TestAllTypes_NEG)
105			return m
106		}(),
107		func() proto.Message {
108			m := new(testpb.TestAllExtensions)
109			proto.SetExtension(m, testpb.E_RepeatedInt32, []int32{-32, +32})
110			proto.SetExtension(m, testpb.E_RepeatedInt64, []int64{-64, +64})
111			proto.SetExtension(m, testpb.E_RepeatedUint32, []uint32{0, 32})
112			proto.SetExtension(m, testpb.E_RepeatedUint64, []uint64{0, 64})
113			proto.SetExtension(m, testpb.E_RepeatedFloat, []float32{-32.32, +32.32})
114			proto.SetExtension(m, testpb.E_RepeatedDouble, []float64{-64.64, +64.64})
115			proto.SetExtension(m, testpb.E_RepeatedBool, []bool{false, true})
116			proto.SetExtension(m, testpb.E_RepeatedString, []string{"hello", "goodbye"})
117			proto.SetExtension(m, testpb.E_RepeatedBytes, [][]byte{[]byte("hello"), []byte("goodbye")})
118			proto.SetExtension(m, testpb.E_RepeatedNestedMessage, []*testpb.TestAllExtensions_NestedMessage{{A: proto.Int32(-32)}, {A: proto.Int32(+32)}})
119			proto.SetExtension(m, testpb.E_RepeatedNestedEnum, []testpb.TestAllTypes_NestedEnum{testpb.TestAllTypes_FOO, testpb.TestAllTypes_NEG})
120			return m
121		}(),
122		&textpb.KnownTypes{
123			OptBool:   &wrapperspb.BoolValue{Value: true},
124			OptInt32:  &wrapperspb.Int32Value{Value: -32},
125			OptInt64:  &wrapperspb.Int64Value{Value: -64},
126			OptUint32: &wrapperspb.UInt32Value{Value: +32},
127			OptUint64: &wrapperspb.UInt64Value{Value: +64},
128			OptFloat:  &wrapperspb.FloatValue{Value: 32.32},
129			OptDouble: &wrapperspb.DoubleValue{Value: 64.64},
130			OptString: &wrapperspb.StringValue{Value: "string"},
131			OptBytes:  &wrapperspb.BytesValue{Value: []byte("bytes")},
132		},
133		&textpb.KnownTypes{
134			OptAny: &anypb.Any{
135				TypeUrl: "google.golang.org/goproto.proto.test.TestAllTypes",
136				Value: func() []byte {
137					b1, _ := proto.MarshalOptions{Deterministic: true}.Marshal(optMsg)
138					b2, _ := proto.MarshalOptions{Deterministic: true}.Marshal(repMsg)
139					b3, _ := proto.MarshalOptions{Deterministic: true}.Marshal(mapMsg)
140					return append(append(append([]byte(nil), b1...), b2...), b3...)
141				}(),
142			},
143		},
144		&textpb.KnownTypes{
145			OptAny: &anypb.Any{
146				TypeUrl: "unknown_type",
147				Value:   []byte("invalid_value"),
148			},
149		},
150	}
151
152	for _, src := range tests {
153		dst := src.ProtoReflect().Type().New().Interface()
154		proto.Merge(dst, transformMessage(src.ProtoReflect()))
155		if diff := cmp.Diff(src, dst, Transform()); diff != "" {
156			t.Errorf("Merge mismatch (-want +got):\n%s", diff)
157		}
158	}
159}
160