1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 package proto_test
33
34 import (
35 "strings"
36 "testing"
37
38 "github.com/gogo/protobuf/proto"
39
40 pb "github.com/gogo/protobuf/proto/proto3_proto"
41 testpb "github.com/gogo/protobuf/proto/test_proto"
42 "github.com/gogo/protobuf/types"
43 )
44
45 var (
46 expandedMarshaler = proto.TextMarshaler{ExpandAny: true}
47 expandedCompactMarshaler = proto.TextMarshaler{Compact: true, ExpandAny: true}
48 )
49
50
51
52
53
54
55 func anyEqual(got, want proto.Message) bool {
56
57 if proto.Equal(got, want) {
58 return true
59 }
60 g := expandedMarshaler.Text(got)
61 w := expandedMarshaler.Text(want)
62 return g == w
63 }
64
65 type golden struct {
66 m proto.Message
67 t, c string
68 }
69
70 var goldenMessages = makeGolden()
71
72 func makeGolden() []golden {
73 nested := &pb.Nested{Bunny: "Monty"}
74 nb, err := proto.Marshal(nested)
75 if err != nil {
76 panic(err)
77 }
78 m1 := &pb.Message{
79 Name: "David",
80 ResultCount: 47,
81 Anything: &types.Any{TypeUrl: "type.googleapis.com/" + proto.MessageName(nested), Value: nb},
82 }
83 m2 := &pb.Message{
84 Name: "David",
85 ResultCount: 47,
86 Anything: &types.Any{TypeUrl: "http://[::1]/type.googleapis.com/" + proto.MessageName(nested), Value: nb},
87 }
88 m3 := &pb.Message{
89 Name: "David",
90 ResultCount: 47,
91 Anything: &types.Any{TypeUrl: `type.googleapis.com/"/` + proto.MessageName(nested), Value: nb},
92 }
93 m4 := &pb.Message{
94 Name: "David",
95 ResultCount: 47,
96 Anything: &types.Any{TypeUrl: "type.googleapis.com/a/path/" + proto.MessageName(nested), Value: nb},
97 }
98 m5 := &types.Any{TypeUrl: "type.googleapis.com/" + proto.MessageName(nested), Value: nb}
99
100 any1 := &testpb.MyMessage{Count: proto.Int32(47), Name: proto.String("David")}
101 proto.SetExtension(any1, testpb.E_Ext_More, &testpb.Ext{Data: proto.String("foo")})
102 proto.SetExtension(any1, testpb.E_Ext_Text, proto.String("bar"))
103 any1b, err := proto.Marshal(any1)
104 if err != nil {
105 panic(err)
106 }
107 any2 := &testpb.MyMessage{Count: proto.Int32(42), Bikeshed: testpb.MyMessage_GREEN.Enum(), RepBytes: [][]byte{[]byte("roboto")}}
108 proto.SetExtension(any2, testpb.E_Ext_More, &testpb.Ext{Data: proto.String("baz")})
109 any2b, err := proto.Marshal(any2)
110 if err != nil {
111 panic(err)
112 }
113 m6 := &pb.Message{
114 Name: "David",
115 ResultCount: 47,
116 Anything: &types.Any{TypeUrl: "type.googleapis.com/" + proto.MessageName(any1), Value: any1b},
117 ManyThings: []*types.Any{
118 {TypeUrl: "type.googleapis.com/" + proto.MessageName(any2), Value: any2b},
119 {TypeUrl: "type.googleapis.com/" + proto.MessageName(any1), Value: any1b},
120 },
121 }
122
123 const (
124 m1Golden = `
125 name: "David"
126 result_count: 47
127 anything: <
128 [type.googleapis.com/proto3_proto.Nested]: <
129 bunny: "Monty"
130 >
131 >
132 `
133 m2Golden = `
134 name: "David"
135 result_count: 47
136 anything: <
137 ["http://[::1]/type.googleapis.com/proto3_proto.Nested"]: <
138 bunny: "Monty"
139 >
140 >
141 `
142 m3Golden = `
143 name: "David"
144 result_count: 47
145 anything: <
146 ["type.googleapis.com/\"/proto3_proto.Nested"]: <
147 bunny: "Monty"
148 >
149 >
150 `
151 m4Golden = `
152 name: "David"
153 result_count: 47
154 anything: <
155 [type.googleapis.com/a/path/proto3_proto.Nested]: <
156 bunny: "Monty"
157 >
158 >
159 `
160 m5Golden = `
161 [type.googleapis.com/proto3_proto.Nested]: <
162 bunny: "Monty"
163 >
164 `
165 m6Golden = `
166 name: "David"
167 result_count: 47
168 anything: <
169 [type.googleapis.com/test_proto.MyMessage]: <
170 count: 47
171 name: "David"
172 [test_proto.Ext.more]: <
173 data: "foo"
174 >
175 [test_proto.Ext.text]: "bar"
176 >
177 >
178 many_things: <
179 [type.googleapis.com/test_proto.MyMessage]: <
180 count: 42
181 bikeshed: GREEN
182 rep_bytes: "roboto"
183 [test_proto.Ext.more]: <
184 data: "baz"
185 >
186 >
187 >
188 many_things: <
189 [type.googleapis.com/test_proto.MyMessage]: <
190 count: 47
191 name: "David"
192 [test_proto.Ext.more]: <
193 data: "foo"
194 >
195 [test_proto.Ext.text]: "bar"
196 >
197 >
198 `
199 )
200 return []golden{
201 {m1, strings.TrimSpace(m1Golden) + "\n", strings.TrimSpace(compact(m1Golden)) + " "},
202 {m2, strings.TrimSpace(m2Golden) + "\n", strings.TrimSpace(compact(m2Golden)) + " "},
203 {m3, strings.TrimSpace(m3Golden) + "\n", strings.TrimSpace(compact(m3Golden)) + " "},
204 {m4, strings.TrimSpace(m4Golden) + "\n", strings.TrimSpace(compact(m4Golden)) + " "},
205 {m5, strings.TrimSpace(m5Golden) + "\n", strings.TrimSpace(compact(m5Golden)) + " "},
206 {m6, strings.TrimSpace(m6Golden) + "\n", strings.TrimSpace(compact(m6Golden)) + " "},
207 }
208 }
209
210 func TestMarshalGolden(t *testing.T) {
211 for _, tt := range goldenMessages {
212 if got, want := expandedMarshaler.Text(tt.m), tt.t; got != want {
213 t.Errorf("message %v: got:\n%s\nwant:\n%s", tt.m, got, want)
214 }
215 if got, want := expandedCompactMarshaler.Text(tt.m), tt.c; got != want {
216 t.Errorf("message %v: got:\n`%s`\nwant:\n`%s`", tt.m, got, want)
217 }
218 }
219 }
220
221 func TestUnmarshalGolden(t *testing.T) {
222 for _, tt := range goldenMessages {
223 want := tt.m
224 got := proto.Clone(tt.m)
225 got.Reset()
226 if err := proto.UnmarshalText(tt.t, got); err != nil {
227 t.Errorf("failed to unmarshal\n%s\nerror: %v", tt.t, err)
228 }
229 if !anyEqual(got, want) {
230 t.Errorf("message:\n%s\ngot:\n%s\nwant:\n%s", tt.t, got, want)
231 }
232 got.Reset()
233 if err := proto.UnmarshalText(tt.c, got); err != nil {
234 t.Errorf("failed to unmarshal\n%s\nerror: %v", tt.c, err)
235 }
236 if !anyEqual(got, want) {
237 t.Errorf("message:\n%s\ngot:\n%s\nwant:\n%s", tt.c, got, want)
238 }
239 }
240 }
241
242 func TestMarshalUnknownAny(t *testing.T) {
243 m := &pb.Message{
244 Anything: &types.Any{
245 TypeUrl: "foo",
246 Value: []byte("bar"),
247 },
248 }
249 want := `anything: <
250 type_url: "foo"
251 value: "bar"
252 >
253 `
254 got := expandedMarshaler.Text(m)
255 if got != want {
256 t.Errorf("got\n`%s`\nwant\n`%s`", got, want)
257 }
258 }
259
260 func TestAmbiguousAny(t *testing.T) {
261 pb := &types.Any{}
262 err := proto.UnmarshalText(`
263 type_url: "ttt/proto3_proto.Nested"
264 value: "\n\x05Monty"
265 `, pb)
266 t.Logf("result: %v (error: %v)", expandedMarshaler.Text(pb), err)
267 if err != nil {
268 t.Errorf("failed to parse ambiguous Any message: %v", err)
269 }
270 }
271
272 func TestUnmarshalOverwriteAny(t *testing.T) {
273 pb := &types.Any{}
274 err := proto.UnmarshalText(`
275 [type.googleapis.com/a/path/proto3_proto.Nested]: <
276 bunny: "Monty"
277 >
278 [type.googleapis.com/a/path/proto3_proto.Nested]: <
279 bunny: "Rabbit of Caerbannog"
280 >
281 `, pb)
282 want := `line 7: Any message unpacked multiple times, or "type_url" already set`
283 if err.Error() != want {
284 t.Errorf("incorrect error.\nHave: %v\nWant: %v", err.Error(), want)
285 }
286 }
287
288 func TestUnmarshalAnyMixAndMatch(t *testing.T) {
289 pb := &types.Any{}
290 err := proto.UnmarshalText(`
291 value: "\n\x05Monty"
292 [type.googleapis.com/a/path/proto3_proto.Nested]: <
293 bunny: "Rabbit of Caerbannog"
294 >
295 `, pb)
296 want := `line 5: Any message unpacked multiple times, or "value" already set`
297 if err.Error() != want {
298 t.Errorf("incorrect error.\nHave: %v\nWant: %v", err.Error(), want)
299 }
300 }
301
View as plain text