blob: 97a7c704f095b930087114efd17db036ed5ec6f3 [file] [log] [blame]
Rob Pikeaaa3a622010-03-20 22:32:34 -07001// Go support for Protocol Buffers - Google's data interchange format
2//
3// Copyright 2010 Google Inc. All rights reserved.
4// http://code.google.com/p/goprotobuf/
5//
6// Redistribution and use in source and binary forms, with or without
7// modification, are permitted provided that the following conditions are
8// met:
9//
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
15// distribution.
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.
19//
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.
31
32package proto_test
33
34import (
35 "bytes"
David Symonds1d72f7a2011-08-19 18:28:52 +100036 "strings"
Rob Pikeaaa3a622010-03-20 22:32:34 -070037 "testing"
David Symondsaa922ff2011-07-19 14:58:06 +100038
Rob Pike3f6f2d82011-12-18 13:55:35 -080039 "code.google.com/p/goprotobuf/proto"
David Symondsaa922ff2011-07-19 14:58:06 +100040
David Symonds704096f2012-03-15 15:10:26 +110041 pb "./testdata"
Rob Pikeaaa3a622010-03-20 22:32:34 -070042)
43
David Symondsaa922ff2011-07-19 14:58:06 +100044func newTestMessage() *pb.MyMessage {
45 msg := &pb.MyMessage{
46 Count: proto.Int32(42),
47 Name: proto.String("Dave"),
48 Quote: proto.String(`"I didn't want to go."`),
Rob Pike9caa5b92010-05-11 16:04:57 -070049 Pet: []string{"bunny", "kitty", "horsey"},
David Symondsaa922ff2011-07-19 14:58:06 +100050 Inner: &pb.InnerMessage{
51 Host: proto.String("footrest.syd"),
52 Port: proto.Int32(7001),
53 Connected: proto.Bool(true),
Rob Pikeaaa3a622010-03-20 22:32:34 -070054 },
David Symondsaa922ff2011-07-19 14:58:06 +100055 Others: []*pb.OtherMessage{
David Symonds92dd6c12012-03-23 10:59:49 +110056 {
David Symondsaa922ff2011-07-19 14:58:06 +100057 Key: proto.Int64(0xdeadbeef),
Rob Pikeaaa3a622010-03-20 22:32:34 -070058 Value: []byte{1, 65, 7, 12},
59 },
David Symonds92dd6c12012-03-23 10:59:49 +110060 {
David Symondsaa922ff2011-07-19 14:58:06 +100061 Weight: proto.Float32(6.022),
62 Inner: &pb.InnerMessage{
63 Host: proto.String("lesha.mtv"),
64 Port: proto.Int32(8002),
Rob Pikeaaa3a622010-03-20 22:32:34 -070065 },
66 },
67 },
David Symondsefeca9a2012-05-08 10:36:04 +100068 Bikeshed: pb.MyMessage_BLUE.Enum(),
David Symondsaa922ff2011-07-19 14:58:06 +100069 Somegroup: &pb.MyMessage_SomeGroup{
70 GroupField: proto.Int32(8),
David Symonds9f402812011-04-28 18:08:44 +100071 },
David Symonds1d72f7a2011-08-19 18:28:52 +100072 // One normally wouldn't do this.
73 // This is an undeclared tag 13, as a varint (wire type 0) with value 4.
74 XXX_unrecognized: []byte{13<<3 | 0, 4},
Rob Pikeaaa3a622010-03-20 22:32:34 -070075 }
David Symondsaa922ff2011-07-19 14:58:06 +100076 ext := &pb.Ext{
77 Data: proto.String("Big gobs for big rats"),
David Symondse37856c2011-06-22 12:52:53 +100078 }
David Symondsaa922ff2011-07-19 14:58:06 +100079 if err := proto.SetExtension(msg, pb.E_Ext_More, ext); err != nil {
David Symondse37856c2011-06-22 12:52:53 +100080 panic(err)
81 }
David Symonds61826da2012-05-05 09:31:28 +100082 greetings := []string{"adg", "easy", "cow"}
83 if err := proto.SetExtension(msg, pb.E_Greeting, greetings); err != nil {
84 panic(err)
85 }
David Symonds1d72f7a2011-08-19 18:28:52 +100086
87 // Add an unknown extension. We marshal a pb.Ext, and fake the ID.
88 b, err := proto.Marshal(&pb.Ext{Data: proto.String("3G skiing")})
89 if err != nil {
90 panic(err)
91 }
David Symonds54531052011-12-08 12:00:31 +110092 b = append(proto.EncodeVarint(201<<3|proto.WireBytes), b...)
93 proto.SetRawExtension(msg, 201, b)
David Symonds1d72f7a2011-08-19 18:28:52 +100094
95 // Extensions can be plain fields, too, so let's test that.
David Symonds54531052011-12-08 12:00:31 +110096 b = append(proto.EncodeVarint(202<<3|proto.WireVarint), 19)
97 proto.SetRawExtension(msg, 202, b)
David Symonds1d72f7a2011-08-19 18:28:52 +100098
David Symondse37856c2011-06-22 12:52:53 +100099 return msg
Rob Pikeaaa3a622010-03-20 22:32:34 -0700100}
101
102const text = `count: 42
103name: "Dave"
104quote: "\"I didn't want to go.\""
105pet: "bunny"
106pet: "kitty"
107pet: "horsey"
108inner: <
109 host: "footrest.syd"
110 port: 7001
111 connected: true
112>
113others: <
114 key: 3735928559
David Symonds4c95bfe2011-09-13 14:43:27 +1000115 value: "\001A\007\014"
Rob Pikeaaa3a622010-03-20 22:32:34 -0700116>
117others: <
118 weight: 6.022
119 inner: <
120 host: "lesha.mtv"
121 port: 8002
122 >
123>
124bikeshed: BLUE
David Symonds9f402812011-04-28 18:08:44 +1000125SomeGroup {
126 group_field: 8
127}
David Symonds1d72f7a2011-08-19 18:28:52 +1000128/* 2 unknown bytes */
129tag13: 4
Rob Pikeb7907bf2012-02-13 14:25:20 +1100130[testdata.Ext.more]: <
David Symondse37856c2011-06-22 12:52:53 +1000131 data: "Big gobs for big rats"
132>
David Symonds61826da2012-05-05 09:31:28 +1000133[testdata.greeting]: "adg"
134[testdata.greeting]: "easy"
135[testdata.greeting]: "cow"
David Symonds1d72f7a2011-08-19 18:28:52 +1000136/* 13 unknown bytes */
David Symonds54531052011-12-08 12:00:31 +1100137tag201: "\t3G skiing"
David Symonds1d72f7a2011-08-19 18:28:52 +1000138/* 3 unknown bytes */
David Symonds54531052011-12-08 12:00:31 +1100139tag202: 19
Rob Pikeaaa3a622010-03-20 22:32:34 -0700140`
141
142func TestMarshalTextFull(t *testing.T) {
143 buf := new(bytes.Buffer)
David Symondsaa922ff2011-07-19 14:58:06 +1000144 proto.MarshalText(buf, newTestMessage())
Rob Pikeaaa3a622010-03-20 22:32:34 -0700145 s := buf.String()
146 if s != text {
147 t.Errorf("Got:\n===\n%v===\nExpected:\n===\n%v===\n", s, text)
148 }
149}
150
David Symondsdbdc4212012-11-08 08:20:35 +1100151func BenchmarkMarshalTextFull(b *testing.B) {
152 buf := new(bytes.Buffer)
153 m := newTestMessage()
154 for i := 0; i < b.N; i++ {
155 buf.Reset()
156 proto.MarshalText(buf, m)
157 }
158}
159
Rob Pikeaaa3a622010-03-20 22:32:34 -0700160func compact(src string) string {
David Symondse37856c2011-06-22 12:52:53 +1000161 // s/[ \n]+/ /g; s/ $//;
Rob Pikeaaa3a622010-03-20 22:32:34 -0700162 dst := make([]byte, len(src))
David Symonds1d72f7a2011-08-19 18:28:52 +1000163 space, comment := false, false
Rob Pikeaaa3a622010-03-20 22:32:34 -0700164 j := 0
165 for i := 0; i < len(src); i++ {
David Symonds1d72f7a2011-08-19 18:28:52 +1000166 if strings.HasPrefix(src[i:], "/*") {
167 comment = true
168 i++
169 continue
170 }
171 if comment && strings.HasPrefix(src[i:], "*/") {
172 comment = false
173 i++
174 continue
175 }
176 if comment {
177 continue
178 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700179 c := src[i]
180 if c == ' ' || c == '\n' {
181 space = true
182 continue
183 }
David Symonds9f402812011-04-28 18:08:44 +1000184 if j > 0 && (dst[j-1] == ':' || dst[j-1] == '<' || dst[j-1] == '{') {
185 space = false
186 }
187 if c == '{' {
Rob Pikeaaa3a622010-03-20 22:32:34 -0700188 space = false
189 }
190 if space {
191 dst[j] = ' '
192 j++
193 space = false
194 }
195 dst[j] = c
196 j++
197 }
198 if space {
199 dst[j] = ' '
200 j++
201 }
202 return string(dst[0:j])
203}
204
205var compactText = compact(text)
206
207func TestCompactText(t *testing.T) {
David Symondsaa922ff2011-07-19 14:58:06 +1000208 s := proto.CompactTextString(newTestMessage())
Rob Pikeaaa3a622010-03-20 22:32:34 -0700209 if s != compactText {
David Symonds4c95bfe2011-09-13 14:43:27 +1000210 t.Errorf("Got:\n===\n%v===\nExpected:\n===\n%v\n===\n", s, compactText)
211 }
212}
213
214func TestStringEscaping(t *testing.T) {
215 testCases := []struct {
216 in *pb.Strings
217 out string
218 }{
219 {
220 // Test data from C++ test (TextFormatTest.StringEscape).
221 // Single divergence: we don't escape apostrophes.
222 &pb.Strings{StringField: proto.String("\"A string with ' characters \n and \r newlines and \t tabs and \001 slashes \\ and multiple spaces")},
223 "string_field: \"\\\"A string with ' characters \\n and \\r newlines and \\t tabs and \\001 slashes \\\\ and multiple spaces\"\n",
224 },
225 {
226 // Test data from the same C++ test.
227 &pb.Strings{StringField: proto.String("\350\260\267\346\255\214")},
228 "string_field: \"\\350\\260\\267\\346\\255\\214\"\n",
229 },
David Symondsfa94a1e2012-09-24 13:21:49 +1000230 {
231 // Some UTF-8.
232 &pb.Strings{StringField: proto.String("\x00\x01\xff\x81")},
233 `string_field: "\000\001\377\201"` + "\n",
234 },
David Symonds4c95bfe2011-09-13 14:43:27 +1000235 }
236
237 for i, tc := range testCases {
238 var buf bytes.Buffer
239 proto.MarshalText(&buf, tc.in)
David Symondsfa94a1e2012-09-24 13:21:49 +1000240 s := buf.String()
241 if s != tc.out {
David Symonds4c95bfe2011-09-13 14:43:27 +1000242 t.Errorf("#%d: Got:\n%s\nExpected:\n%s\n", i, s, tc.out)
David Symondsfa94a1e2012-09-24 13:21:49 +1000243 continue
244 }
245
246 // Check round-trip.
247 pb := new(pb.Strings)
248 if err := proto.UnmarshalText(s, pb); err != nil {
249 t.Errorf("#%d: UnmarshalText: %v", i, err)
250 continue
251 }
252 if !proto.Equal(pb, tc.in) {
253 t.Errorf("#%d: Round-trip failed:\nstart: %v\n end: %v", i, tc.in, pb)
David Symonds4c95bfe2011-09-13 14:43:27 +1000254 }
Rob Pikeaaa3a622010-03-20 22:32:34 -0700255 }
256}