1 // Go support for Protocol Buffers - Google's data interchange format
3 // Copyright 2016 The Go Authors. All rights reserved.
4 // https://github.com/golang/protobuf
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are
10 // * Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
12 // * Redistributions in binary form must reproduce the above
13 // copyright notice, this list of conditions and the following disclaimer
14 // in the documentation and/or other materials provided with the
16 // * Neither the name of Google Inc. nor the names of its
17 // contributors may be used to endorse or promote products derived from
18 // this software without specific prior written permission.
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 "github.com/golang/protobuf/proto"
40 pb "github.com/golang/protobuf/proto/proto3_proto"
41 testpb "github.com/golang/protobuf/proto/testdata"
42 anypb "github.com/golang/protobuf/ptypes/any"
46 expandedMarshaler = proto.TextMarshaler{ExpandAny: true}
47 expandedCompactMarshaler = proto.TextMarshaler{Compact: true, ExpandAny: true}
50 // anyEqual reports whether two messages which may be google.protobuf.Any or may
51 // contain google.protobuf.Any fields are equal. We can't use proto.Equal for
52 // comparison, because semantically equivalent messages may be marshaled to
53 // binary in different tag order. Instead, trust that TextMarshaler with
54 // ExpandAny option works and compare the text marshaling results.
55 func anyEqual(got, want proto.Message) bool {
56 // if messages are proto.Equal, no need to marshal.
57 if proto.Equal(got, want) {
60 g := expandedMarshaler.Text(got)
61 w := expandedMarshaler.Text(want)
70 var goldenMessages = makeGolden()
72 func makeGolden() []golden {
73 nested := &pb.Nested{Bunny: "Monty"}
74 nb, err := proto.Marshal(nested)
81 Anything: &anypb.Any{TypeUrl: "type.googleapis.com/" + proto.MessageName(nested), Value: nb},
86 Anything: &anypb.Any{TypeUrl: "http://[::1]/type.googleapis.com/" + proto.MessageName(nested), Value: nb},
91 Anything: &anypb.Any{TypeUrl: `type.googleapis.com/"/` + proto.MessageName(nested), Value: nb},
96 Anything: &anypb.Any{TypeUrl: "type.googleapis.com/a/path/" + proto.MessageName(nested), Value: nb},
98 m5 := &anypb.Any{TypeUrl: "type.googleapis.com/" + proto.MessageName(nested), Value: nb}
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)
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)
116 Anything: &anypb.Any{TypeUrl: "type.googleapis.com/" + proto.MessageName(any1), Value: any1b},
117 ManyThings: []*anypb.Any{
118 &anypb.Any{TypeUrl: "type.googleapis.com/" + proto.MessageName(any2), Value: any2b},
119 &anypb.Any{TypeUrl: "type.googleapis.com/" + proto.MessageName(any1), Value: any1b},
128 [type.googleapis.com/proto3_proto.Nested]: <
137 ["http://[::1]/type.googleapis.com/proto3_proto.Nested"]: <
146 ["type.googleapis.com/\"/proto3_proto.Nested"]: <
155 [type.googleapis.com/a/path/proto3_proto.Nested]: <
161 [type.googleapis.com/proto3_proto.Nested]: <
169 [type.googleapis.com/testdata.MyMessage]: <
172 [testdata.Ext.more]: <
175 [testdata.Ext.text]: "bar"
179 [type.googleapis.com/testdata.MyMessage]: <
183 [testdata.Ext.more]: <
189 [type.googleapis.com/testdata.MyMessage]: <
192 [testdata.Ext.more]: <
195 [testdata.Ext.text]: "bar"
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)) + " "},
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)
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)
221 func TestUnmarshalGolden(t *testing.T) {
222 for _, tt := range goldenMessages {
224 got := proto.Clone(tt.m)
226 if err := proto.UnmarshalText(tt.t, got); err != nil {
227 t.Errorf("failed to unmarshal\n%s\nerror: %v", tt.t, err)
229 if !anyEqual(got, want) {
230 t.Errorf("message:\n%s\ngot:\n%s\nwant:\n%s", tt.t, got, want)
233 if err := proto.UnmarshalText(tt.c, got); err != nil {
234 t.Errorf("failed to unmarshal\n%s\nerror: %v", tt.c, err)
236 if !anyEqual(got, want) {
237 t.Errorf("message:\n%s\ngot:\n%s\nwant:\n%s", tt.c, got, want)
242 func TestMarshalUnknownAny(t *testing.T) {
244 Anything: &anypb.Any{
246 Value: []byte("bar"),
254 got := expandedMarshaler.Text(m)
256 t.Errorf("got\n`%s`\nwant\n`%s`", got, want)
260 func TestAmbiguousAny(t *testing.T) {
262 err := proto.UnmarshalText(`
263 type_url: "ttt/proto3_proto.Nested"
266 t.Logf("result: %v (error: %v)", expandedMarshaler.Text(pb), err)
268 t.Errorf("failed to parse ambiguous Any message: %v", err)
272 func TestUnmarshalOverwriteAny(t *testing.T) {
274 err := proto.UnmarshalText(`
275 [type.googleapis.com/a/path/proto3_proto.Nested]: <
278 [type.googleapis.com/a/path/proto3_proto.Nested]: <
279 bunny: "Rabbit of Caerbannog"
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)
288 func TestUnmarshalAnyMixAndMatch(t *testing.T) {
290 err := proto.UnmarshalText(`
292 [type.googleapis.com/a/path/proto3_proto.Nested]: <
293 bunny: "Rabbit of Caerbannog"
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)