1
2
3
4
5 package protocmp
6
7 import (
8 "strings"
9 "testing"
10
11 "github.com/google/go-cmp/cmp"
12
13 "google.golang.org/protobuf/internal/detrand"
14 "google.golang.org/protobuf/proto"
15 "google.golang.org/protobuf/reflect/protoreflect"
16 "google.golang.org/protobuf/reflect/protoregistry"
17 "google.golang.org/protobuf/testing/protopack"
18 "google.golang.org/protobuf/types/known/anypb"
19
20 testpb "google.golang.org/protobuf/internal/testprotos/test"
21 )
22
23 func init() {
24 detrand.Disable()
25 }
26
27 func TestTransform(t *testing.T) {
28 tests := []struct {
29 in proto.Message
30 want Message
31 }{{
32 in: &testpb.TestAllTypes{
33 OptionalBool: proto.Bool(false),
34 OptionalInt32: proto.Int32(-32),
35 OptionalInt64: proto.Int64(-64),
36 OptionalUint32: proto.Uint32(32),
37 OptionalUint64: proto.Uint64(64),
38 OptionalFloat: proto.Float32(32.32),
39 OptionalDouble: proto.Float64(64.64),
40 OptionalString: proto.String("string"),
41 OptionalBytes: []byte("bytes"),
42 OptionalNestedEnum: testpb.TestAllTypes_NEG.Enum(),
43 OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{A: proto.Int32(5)},
44 },
45 want: Message{
46 messageTypeKey: messageMetaOf(&testpb.TestAllTypes{}),
47 "optional_bool": bool(false),
48 "optional_int32": int32(-32),
49 "optional_int64": int64(-64),
50 "optional_uint32": uint32(32),
51 "optional_uint64": uint64(64),
52 "optional_float": float32(32.32),
53 "optional_double": float64(64.64),
54 "optional_string": string("string"),
55 "optional_bytes": []byte("bytes"),
56 "optional_nested_enum": enumOf(testpb.TestAllTypes_NEG),
57 "optional_nested_message": Message{messageTypeKey: messageMetaOf(&testpb.TestAllTypes_NestedMessage{}), "a": int32(5)},
58 },
59 }, {
60 in: &testpb.TestAllTypes{
61 RepeatedBool: []bool{false, true},
62 RepeatedInt32: []int32{32, -32},
63 RepeatedInt64: []int64{64, -64},
64 RepeatedUint32: []uint32{0, 32},
65 RepeatedUint64: []uint64{0, 64},
66 RepeatedFloat: []float32{0, 32.32},
67 RepeatedDouble: []float64{0, 64.64},
68 RepeatedString: []string{"s1", "s2"},
69 RepeatedBytes: [][]byte{{1}, {2}},
70 RepeatedNestedEnum: []testpb.TestAllTypes_NestedEnum{
71 testpb.TestAllTypes_FOO,
72 testpb.TestAllTypes_BAR,
73 },
74 RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{
75 {A: proto.Int32(5)},
76 {A: proto.Int32(-5)},
77 },
78 },
79 want: Message{
80 messageTypeKey: messageMetaOf(&testpb.TestAllTypes{}),
81 "repeated_bool": []bool{false, true},
82 "repeated_int32": []int32{32, -32},
83 "repeated_int64": []int64{64, -64},
84 "repeated_uint32": []uint32{0, 32},
85 "repeated_uint64": []uint64{0, 64},
86 "repeated_float": []float32{0, 32.32},
87 "repeated_double": []float64{0, 64.64},
88 "repeated_string": []string{"s1", "s2"},
89 "repeated_bytes": [][]byte{{1}, {2}},
90 "repeated_nested_enum": []Enum{
91 enumOf(testpb.TestAllTypes_FOO),
92 enumOf(testpb.TestAllTypes_BAR),
93 },
94 "repeated_nested_message": []Message{
95 {messageTypeKey: messageMetaOf(&testpb.TestAllTypes_NestedMessage{}), "a": int32(5)},
96 {messageTypeKey: messageMetaOf(&testpb.TestAllTypes_NestedMessage{}), "a": int32(-5)},
97 },
98 },
99 }, {
100 in: &testpb.TestAllTypes{
101 MapBoolBool: map[bool]bool{true: false},
102 MapInt32Int32: map[int32]int32{-32: 32},
103 MapInt64Int64: map[int64]int64{-64: 64},
104 MapUint32Uint32: map[uint32]uint32{0: 32},
105 MapUint64Uint64: map[uint64]uint64{0: 64},
106 MapInt32Float: map[int32]float32{32: 32.32},
107 MapInt32Double: map[int32]float64{64: 64.64},
108 MapStringString: map[string]string{"k": "v", "empty": ""},
109 MapStringBytes: map[string][]byte{"k": []byte("v"), "empty": nil},
110 MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{
111 "k": testpb.TestAllTypes_FOO,
112 },
113 MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{
114 "k": {A: proto.Int32(5)},
115 },
116 },
117 want: Message{
118 messageTypeKey: messageMetaOf(&testpb.TestAllTypes{}),
119 "map_bool_bool": map[bool]bool{true: false},
120 "map_int32_int32": map[int32]int32{-32: 32},
121 "map_int64_int64": map[int64]int64{-64: 64},
122 "map_uint32_uint32": map[uint32]uint32{0: 32},
123 "map_uint64_uint64": map[uint64]uint64{0: 64},
124 "map_int32_float": map[int32]float32{32: 32.32},
125 "map_int32_double": map[int32]float64{64: 64.64},
126 "map_string_string": map[string]string{"k": "v", "empty": ""},
127 "map_string_bytes": map[string][]byte{"k": []byte("v"), "empty": []byte{}},
128 "map_string_nested_enum": map[string]Enum{
129 "k": enumOf(testpb.TestAllTypes_FOO),
130 },
131 "map_string_nested_message": map[string]Message{
132 "k": {messageTypeKey: messageMetaOf(&testpb.TestAllTypes_NestedMessage{}), "a": int32(5)},
133 },
134 },
135 }, {
136 in: func() proto.Message {
137 m := &testpb.TestAllExtensions{}
138 proto.SetExtension(m, testpb.E_OptionalBool, bool(false))
139 proto.SetExtension(m, testpb.E_OptionalInt32, int32(-32))
140 proto.SetExtension(m, testpb.E_OptionalInt64, int64(-64))
141 proto.SetExtension(m, testpb.E_OptionalUint32, uint32(32))
142 proto.SetExtension(m, testpb.E_OptionalUint64, uint64(64))
143 proto.SetExtension(m, testpb.E_OptionalFloat, float32(32.32))
144 proto.SetExtension(m, testpb.E_OptionalDouble, float64(64.64))
145 proto.SetExtension(m, testpb.E_OptionalString, string("string"))
146 proto.SetExtension(m, testpb.E_OptionalBytes, []byte("bytes"))
147 proto.SetExtension(m, testpb.E_OptionalNestedEnum, testpb.TestAllTypes_NEG)
148 proto.SetExtension(m, testpb.E_OptionalNestedMessage, &testpb.TestAllExtensions_NestedMessage{A: proto.Int32(5)})
149 return m
150 }(),
151 want: Message{
152 messageTypeKey: messageMetaOf(&testpb.TestAllExtensions{}),
153 "[goproto.proto.test.optional_bool]": bool(false),
154 "[goproto.proto.test.optional_int32]": int32(-32),
155 "[goproto.proto.test.optional_int64]": int64(-64),
156 "[goproto.proto.test.optional_uint32]": uint32(32),
157 "[goproto.proto.test.optional_uint64]": uint64(64),
158 "[goproto.proto.test.optional_float]": float32(32.32),
159 "[goproto.proto.test.optional_double]": float64(64.64),
160 "[goproto.proto.test.optional_string]": string("string"),
161 "[goproto.proto.test.optional_bytes]": []byte("bytes"),
162 "[goproto.proto.test.optional_nested_enum]": enumOf(testpb.TestAllTypes_NEG),
163 "[goproto.proto.test.optional_nested_message]": Message{messageTypeKey: messageMetaOf(&testpb.TestAllExtensions_NestedMessage{}), "a": int32(5)},
164 },
165 }, {
166 in: func() proto.Message {
167 m := &testpb.TestAllExtensions{}
168 proto.SetExtension(m, testpb.E_RepeatedBool, []bool{false, true})
169 proto.SetExtension(m, testpb.E_RepeatedInt32, []int32{32, -32})
170 proto.SetExtension(m, testpb.E_RepeatedInt64, []int64{64, -64})
171 proto.SetExtension(m, testpb.E_RepeatedUint32, []uint32{0, 32})
172 proto.SetExtension(m, testpb.E_RepeatedUint64, []uint64{0, 64})
173 proto.SetExtension(m, testpb.E_RepeatedFloat, []float32{0, 32.32})
174 proto.SetExtension(m, testpb.E_RepeatedDouble, []float64{0, 64.64})
175 proto.SetExtension(m, testpb.E_RepeatedString, []string{"s1", "s2"})
176 proto.SetExtension(m, testpb.E_RepeatedBytes, [][]byte{{1}, {2}})
177 proto.SetExtension(m, testpb.E_RepeatedNestedEnum, []testpb.TestAllTypes_NestedEnum{
178 testpb.TestAllTypes_FOO,
179 testpb.TestAllTypes_BAR,
180 })
181 proto.SetExtension(m, testpb.E_RepeatedNestedMessage, []*testpb.TestAllExtensions_NestedMessage{
182 {A: proto.Int32(5)},
183 {A: proto.Int32(-5)},
184 })
185 return m
186 }(),
187 want: Message{
188 messageTypeKey: messageMetaOf(&testpb.TestAllExtensions{}),
189 "[goproto.proto.test.repeated_bool]": []bool{false, true},
190 "[goproto.proto.test.repeated_int32]": []int32{32, -32},
191 "[goproto.proto.test.repeated_int64]": []int64{64, -64},
192 "[goproto.proto.test.repeated_uint32]": []uint32{0, 32},
193 "[goproto.proto.test.repeated_uint64]": []uint64{0, 64},
194 "[goproto.proto.test.repeated_float]": []float32{0, 32.32},
195 "[goproto.proto.test.repeated_double]": []float64{0, 64.64},
196 "[goproto.proto.test.repeated_string]": []string{"s1", "s2"},
197 "[goproto.proto.test.repeated_bytes]": [][]byte{{1}, {2}},
198 "[goproto.proto.test.repeated_nested_enum]": []Enum{
199 enumOf(testpb.TestAllTypes_FOO),
200 enumOf(testpb.TestAllTypes_BAR),
201 },
202 "[goproto.proto.test.repeated_nested_message]": []Message{
203 {messageTypeKey: messageMetaOf(&testpb.TestAllExtensions_NestedMessage{}), "a": int32(5)},
204 {messageTypeKey: messageMetaOf(&testpb.TestAllExtensions_NestedMessage{}), "a": int32(-5)},
205 },
206 },
207 }, {
208 in: func() proto.Message {
209 m := &testpb.TestAllTypes{}
210 m.ProtoReflect().SetUnknown(protopack.Message{
211 protopack.Tag{Number: 50000, Type: protopack.VarintType}, protopack.Uvarint(100),
212 protopack.Tag{Number: 50001, Type: protopack.Fixed32Type}, protopack.Uint32(200),
213 protopack.Tag{Number: 50002, Type: protopack.Fixed64Type}, protopack.Uint64(300),
214 protopack.Tag{Number: 50003, Type: protopack.BytesType}, protopack.String("hello"),
215 protopack.Message{
216 protopack.Tag{Number: 50004, Type: protopack.StartGroupType},
217 protopack.Tag{Number: 1, Type: protopack.VarintType}, protopack.Uvarint(100),
218 protopack.Tag{Number: 1, Type: protopack.Fixed32Type}, protopack.Uint32(200),
219 protopack.Tag{Number: 1, Type: protopack.Fixed64Type}, protopack.Uint64(300),
220 protopack.Tag{Number: 1, Type: protopack.BytesType}, protopack.String("hello"),
221 protopack.Message{
222 protopack.Tag{Number: 1, Type: protopack.StartGroupType},
223 protopack.Tag{Number: 1, Type: protopack.VarintType}, protopack.Uvarint(100),
224 protopack.Tag{Number: 1, Type: protopack.Fixed32Type}, protopack.Uint32(200),
225 protopack.Tag{Number: 1, Type: protopack.Fixed64Type}, protopack.Uint64(300),
226 protopack.Tag{Number: 1, Type: protopack.BytesType}, protopack.String("hello"),
227 protopack.Tag{Number: 1, Type: protopack.EndGroupType},
228 },
229 protopack.Tag{Number: 50004, Type: protopack.EndGroupType},
230 },
231 }.Marshal())
232 return m
233 }(),
234 want: Message{
235 messageTypeKey: messageMetaOf(&testpb.TestAllTypes{}),
236 "50000": protoreflect.RawFields(protopack.Message{protopack.Tag{Number: 50000, Type: protopack.VarintType}, protopack.Uvarint(100)}.Marshal()),
237 "50001": protoreflect.RawFields(protopack.Message{protopack.Tag{Number: 50001, Type: protopack.Fixed32Type}, protopack.Uint32(200)}.Marshal()),
238 "50002": protoreflect.RawFields(protopack.Message{protopack.Tag{Number: 50002, Type: protopack.Fixed64Type}, protopack.Uint64(300)}.Marshal()),
239 "50003": protoreflect.RawFields(protopack.Message{protopack.Tag{Number: 50003, Type: protopack.BytesType}, protopack.String("hello")}.Marshal()),
240 "50004": protoreflect.RawFields(protopack.Message{
241 protopack.Tag{Number: 50004, Type: protopack.StartGroupType},
242 protopack.Tag{Number: 1, Type: protopack.VarintType}, protopack.Uvarint(100),
243 protopack.Tag{Number: 1, Type: protopack.Fixed32Type}, protopack.Uint32(200),
244 protopack.Tag{Number: 1, Type: protopack.Fixed64Type}, protopack.Uint64(300),
245 protopack.Tag{Number: 1, Type: protopack.BytesType}, protopack.String("hello"),
246 protopack.Message{
247 protopack.Tag{Number: 1, Type: protopack.StartGroupType},
248 protopack.Tag{Number: 1, Type: protopack.VarintType}, protopack.Uvarint(100),
249 protopack.Tag{Number: 1, Type: protopack.Fixed32Type}, protopack.Uint32(200),
250 protopack.Tag{Number: 1, Type: protopack.Fixed64Type}, protopack.Uint64(300),
251 protopack.Tag{Number: 1, Type: protopack.BytesType}, protopack.String("hello"),
252 protopack.Tag{Number: 1, Type: protopack.EndGroupType},
253 },
254 protopack.Tag{Number: 50004, Type: protopack.EndGroupType},
255 }.Marshal()),
256 },
257 }}
258 for _, tt := range tests {
259 t.Run("", func(t *testing.T) {
260 got := newTransformer().transformMessage(tt.in.ProtoReflect())
261 if diff := cmp.Diff(tt.want, got); diff != "" {
262 t.Errorf("Transform() mismatch (-want +got):\n%v", diff)
263 }
264 if got.Unwrap() != tt.in {
265 t.Errorf("got.Unwrap() = %p, want %p", got.Unwrap(), tt.in)
266 }
267 })
268 }
269
270 t.Run("messageTypeResolver", func(t *testing.T) {
271 r := unaryMessageTypeResolver{
272 Type: (&testpb.TestAllTypes{}).ProtoReflect().Type(),
273 }
274 m := &testpb.TestAllTypes{OptionalBool: proto.Bool(true)}
275 in, err := anypb.New(m)
276 if err != nil {
277 t.Fatalf("anypb.New() failed: %v", err)
278 }
279 in.TypeUrl = "type.googleapis.com/MagicTestMessage"
280
281 got := newTransformer(MessageTypeResolver(r)).transformMessage(in.ProtoReflect())
282 want := Message{
283 messageTypeKey: messageMetaOf(&anypb.Any{}),
284 "type_url": "type.googleapis.com/MagicTestMessage",
285 "value": Message{
286 messageTypeKey: messageMetaOf(m),
287 "optional_bool": true,
288 },
289 }
290 if diff := cmp.Diff(want, got); diff != "" {
291 t.Errorf("Transform() mismatch (-want +got):\n%v", diff)
292 }
293 if got.Unwrap() != in {
294 t.Errorf("got.Unwrap() = %p, want %p", got.Unwrap(), in)
295 }
296 })
297 }
298
299 func enumOf(e protoreflect.Enum) Enum {
300 return Enum{e.Number(), e.Descriptor()}
301 }
302
303 func messageMetaOf(m protoreflect.ProtoMessage) messageMeta {
304 return messageMeta{m: m, md: m.ProtoReflect().Descriptor()}
305 }
306
307
308
309 type unaryMessageTypeResolver struct {
310 Type protoreflect.MessageType
311 }
312
313 func (r unaryMessageTypeResolver) FindMessageByName(message protoreflect.FullName) (protoreflect.MessageType, error) {
314 if message != "MagicTestMessage" {
315 return nil, protoregistry.NotFound
316 }
317 return r.Type, nil
318 }
319
320 func (r unaryMessageTypeResolver) FindMessageByURL(url string) (protoreflect.MessageType, error) {
321 const prefix = "type.googleapis.com/"
322
323 if !strings.HasPrefix(url, prefix) {
324 return nil, protoregistry.NotFound
325 }
326 return r.FindMessageByName(protoreflect.FullName(strings.TrimPrefix(url, prefix)))
327 }
328
View as plain text