ruby-protocol-buffers 1.5.1 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/.travis.yml +4 -8
- data/CHANGELOG.md +80 -0
- data/Changelog.md +73 -9
- data/README.md +31 -32
- data/Rakefile +8 -0
- data/bin/protoc-gen-ruby +2 -1
- data/lib/protocol_buffers.rb +14 -3
- data/lib/protocol_buffers/runtime/encoder.rb +1 -1
- data/lib/protocol_buffers/runtime/field.rb +44 -0
- data/lib/protocol_buffers/runtime/message.rb +63 -0
- data/lib/protocol_buffers/runtime/text_formatter.rb +116 -0
- data/lib/protocol_buffers/runtime/text_parser.ry +136 -0
- data/lib/protocol_buffers/runtime/text_scanner.rb +94 -0
- data/lib/protocol_buffers/version.rb +1 -1
- data/ruby-protocol-buffers.gemspec +2 -1
- data/spec/message_spec.rb +22 -0
- data/spec/negative_int32_spec.rb +10 -10
- data/spec/nil_bugs_spec.rb +1 -1
- data/spec/runtime_spec.rb +2 -2
- data/spec/text_format_spec.rb +679 -0
- data/spec/unicode_string_spec.rb +2 -2
- metadata +46 -48
data/spec/message_spec.rb
CHANGED
@@ -116,4 +116,26 @@ describe ProtocolBuffers, "message" do
|
|
116
116
|
|
117
117
|
c.value_for_tag?(1).should == true
|
118
118
|
end
|
119
|
+
|
120
|
+
it "correctly handles get" do
|
121
|
+
f = Featureful::A.new
|
122
|
+
f.i3 = 4
|
123
|
+
f.sub3.subsub1.subsub_payload = "sub3subsubpayload"
|
124
|
+
|
125
|
+
f.get(:sub3, :subsub1, :subsub_payload).should == "sub3subsubpayload"
|
126
|
+
f.get(:i3).should == 4
|
127
|
+
f.get(:i2).should == nil
|
128
|
+
f.get(:sub2).should == nil
|
129
|
+
end
|
130
|
+
|
131
|
+
it "correctly handles get!" do
|
132
|
+
f = Featureful::A.new
|
133
|
+
f.i3 = 4
|
134
|
+
f.sub3.subsub1.subsub_payload = "sub3subsubpayload"
|
135
|
+
|
136
|
+
f.get!(:sub3, :subsub1, :subsub_payload).should == "sub3subsubpayload"
|
137
|
+
f.get!(:i3).should == 4
|
138
|
+
proc { f.get!(:i2) }.should raise_error(ArgumentError)
|
139
|
+
proc { f.get!(:sub2) }.should raise_error(ArgumentError)
|
140
|
+
end
|
119
141
|
end
|
data/spec/negative_int32_spec.rb
CHANGED
@@ -9,25 +9,25 @@ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
|
|
9
9
|
require 'protocol_buffers'
|
10
10
|
|
11
11
|
describe "Testing for decode errors for negative int32 fields" do
|
12
|
-
# These should fail without the int32 negative handling fix
|
12
|
+
# These should fail without the int32 negative handling fix
|
13
13
|
it "should return -1 given -1" do
|
14
|
-
(validate_pbr(SignedIntTest, -1, true)).should
|
14
|
+
(validate_pbr(SignedIntTest, -1, true)).should be true
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
it "should return -1111 given -1111" do
|
18
|
-
(validate_pbr(SignedIntTest, -1111, true)).should
|
18
|
+
(validate_pbr(SignedIntTest, -1111, true)).should be true
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
# These should pass with or without the negative handling fix
|
22
22
|
it "should return 1 given 1" do
|
23
|
-
(validate_pbr(SignedIntTest, 1, true)).should
|
23
|
+
(validate_pbr(SignedIntTest, 1, true)).should be true
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
it "should return 0 given 0" do
|
27
|
-
(validate_pbr(SignedIntTest, 0, true)).should
|
27
|
+
(validate_pbr(SignedIntTest, 0, true)).should be true
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
it "should return 100000 given 100000" do
|
31
|
-
(validate_pbr(SignedIntTest, 100000, true)).should
|
31
|
+
(validate_pbr(SignedIntTest, 100000, true)).should be true
|
32
32
|
end
|
33
33
|
end
|
data/spec/nil_bugs_spec.rb
CHANGED
data/spec/runtime_spec.rb
CHANGED
@@ -278,7 +278,7 @@ describe ProtocolBuffers, "runtime" do
|
|
278
278
|
a1 = Featureful::A.new
|
279
279
|
proc do
|
280
280
|
a1.sub1 << Featureful::A::Sub.new
|
281
|
-
end.should_not raise_error
|
281
|
+
end.should_not raise_error
|
282
282
|
|
283
283
|
a1 = Featureful::A.new
|
284
284
|
proc do
|
@@ -633,7 +633,7 @@ describe ProtocolBuffers, "runtime" do
|
|
633
633
|
res2 = TehUnknown2::MyResult.parse(serialized)
|
634
634
|
end.should_not raise_error()
|
635
635
|
|
636
|
-
res2.value_for_tag?(1).should
|
636
|
+
res2.value_for_tag?(1).should be false
|
637
637
|
res2.unknown_field_count.should == 1
|
638
638
|
|
639
639
|
serialized2 = res2.to_s
|
@@ -0,0 +1,679 @@
|
|
1
|
+
# -*- coding: UTF-8 -*-
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
3
|
+
|
4
|
+
describe ProtocolBuffers::TextScanner do
|
5
|
+
def scanned_list(text)
|
6
|
+
s = ProtocolBuffers::TextScanner.new(text)
|
7
|
+
s.enum_for(:scan).to_a
|
8
|
+
end
|
9
|
+
|
10
|
+
it "returns [false, nil] on the end" do
|
11
|
+
expect(scanned_list("")).to eq [[false, nil]]
|
12
|
+
end
|
13
|
+
|
14
|
+
it "returns [:bool, true] for 'true'" do
|
15
|
+
expect(scanned_list("true")).to eq [[:bool, true], [false, nil]]
|
16
|
+
end
|
17
|
+
|
18
|
+
it "returns [:bool, false] for 'false'" do
|
19
|
+
expect(scanned_list("false")).to eq [[:bool, false], [false, nil]]
|
20
|
+
end
|
21
|
+
|
22
|
+
%w( . : [ ] < > { } ).each do |c|
|
23
|
+
it "returns a single character token for #{c}" do
|
24
|
+
expect(scanned_list(c)).to eq [[c, c], [false, nil]]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'returns [:string, str] for a simple single quoted text' do
|
29
|
+
expect(scanned_list(%q['str'])).to eq [[:string, 'str'], [false, nil]]
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'returns [:string, str] for a simple doubl quoted text' do
|
33
|
+
expect(scanned_list(%q["str"])).to eq [[:string, 'str'], [false, nil]]
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'raises Racc::ParseError on unterminated quotation' do
|
37
|
+
expect {
|
38
|
+
scanned_list(%q['str])
|
39
|
+
}.to raise_error(Racc::ParseError, /unterminated string from line 1/)
|
40
|
+
|
41
|
+
expect {
|
42
|
+
scanned_list(%Q['str '\n'str])
|
43
|
+
}.to raise_error(Racc::ParseError, /unterminated string from line 2/)
|
44
|
+
|
45
|
+
expect {
|
46
|
+
scanned_list(%Q['str" 'str'])
|
47
|
+
}.to raise_error(Racc::ParseError, /unterminated string from line 1/)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'raises Racc::ParseError on multiline string' do
|
51
|
+
expect {
|
52
|
+
scanned_list(%Q['str\n'])
|
53
|
+
}.to raise_error(Racc::ParseError, /unterminated string from line 1/)
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'understands hex escaped string' do
|
57
|
+
expect(scanned_list(%q["\\x12"])).to eq [[:string, "\x12"], [false, nil]]
|
58
|
+
expect(scanned_list(%q["\\X12"])).to eq [[:string, "\x12"], [false, nil]]
|
59
|
+
|
60
|
+
expect(scanned_list(%q['\\x12'])).to eq [[:string, "\x12"], [false, nil]]
|
61
|
+
|
62
|
+
expect(scanned_list(%q['\\xfghijk'])).to eq [[:string, "\x0f" + "ghijk"], [false, nil]]
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'understands octal escaped string' do
|
66
|
+
expect(scanned_list(%q["\\012"])).to eq [[:string, "\012"], [false, nil]]
|
67
|
+
expect(scanned_list(%q['\\12'])).to eq [[:string, "\012"], [false, nil]]
|
68
|
+
|
69
|
+
expect(scanned_list(%q['\\0'])).to eq [[:string, "\0"], [false, nil]]
|
70
|
+
|
71
|
+
expect(scanned_list(%q['\\0012'])).to eq [[:string, "\001" + "2"], [false, nil]]
|
72
|
+
expect(scanned_list(%q['\\6789'])).to eq [[:string, "\067" + "89"], [false, nil]]
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'understands named escaped string' do
|
76
|
+
input = %q[
|
77
|
+
"
|
78
|
+
\\a
|
79
|
+
\\b
|
80
|
+
\\f
|
81
|
+
\\n
|
82
|
+
\\r
|
83
|
+
\\t
|
84
|
+
\\v
|
85
|
+
\\\\
|
86
|
+
\\"
|
87
|
+
\\'
|
88
|
+
"
|
89
|
+
].gsub(/\s/, '')
|
90
|
+
expect(scanned_list(input)).to eq [
|
91
|
+
[:string, "\a\b\f\n\r\t\v\\\"'"],
|
92
|
+
[false, nil]
|
93
|
+
]
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'accepts quoted punctuations' do
|
97
|
+
expect(scanned_list(%q[".:[]<>{}"])).to eq [[:string, ".:[]<>{}"], [false, nil]]
|
98
|
+
expect(scanned_list(%q["'"])).to eq [[:string, "'"], [false, nil]]
|
99
|
+
expect(scanned_list(%q['"'])).to eq [[:string, '"'], [false, nil]]
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'leaves uninterpretable escape as is' do
|
103
|
+
expect(scanned_list(%q["\\c"])).to eq [[:string, "\\c"], [false, nil]]
|
104
|
+
expect(scanned_list(%q["\\u0030"])).to eq [[:string, "\\u0030"], [false, nil]]
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'returns [:integer, value] for binary integer literal' do
|
108
|
+
expect(scanned_list('0b0101')).to eq [[:integer, 0b0101], [false, nil]]
|
109
|
+
expect(scanned_list('0B0101')).to eq [[:integer, 0b0101], [false, nil]]
|
110
|
+
expect(scanned_list('+0B0101')).to eq [[:integer, +0b0101], [false, nil]]
|
111
|
+
expect(scanned_list('-0B0101')).to eq [[:integer, -0b0101], [false, nil]]
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'returns [:integer, value] for octal integer literal' do
|
115
|
+
expect(scanned_list('0123')).to eq [[:integer, 0123], [false, nil]]
|
116
|
+
expect(scanned_list('0o123')).to eq [[:integer, 0123], [false, nil]]
|
117
|
+
expect(scanned_list('0O123')).to eq [[:integer, 0123], [false, nil]]
|
118
|
+
expect(scanned_list('+0123')).to eq [[:integer, 0123], [false, nil]]
|
119
|
+
expect(scanned_list('+0o123')).to eq [[:integer, 0123], [false, nil]]
|
120
|
+
expect(scanned_list('-0123')).to eq [[:integer, -0123], [false, nil]]
|
121
|
+
expect(scanned_list('-0o123')).to eq [[:integer, -0123], [false, nil]]
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'returns [:integer, value] for decimal integer literal' do
|
125
|
+
expect(scanned_list('12345')).to eq [[:integer, 12345], [false, nil]]
|
126
|
+
expect(scanned_list('0d12345')).to eq [[:integer, 12345], [false, nil]]
|
127
|
+
expect(scanned_list('0D12345')).to eq [[:integer, 12345], [false, nil]]
|
128
|
+
expect(scanned_list('+12345')).to eq [[:integer, 12345], [false, nil]]
|
129
|
+
expect(scanned_list('+0d12345')).to eq [[:integer, 12345], [false, nil]]
|
130
|
+
expect(scanned_list('-12345')).to eq [[:integer, -12345], [false, nil]]
|
131
|
+
expect(scanned_list('-0d12345')).to eq [[:integer, -12345], [false, nil]]
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'returns [:integer, value] for hex integer literal' do
|
135
|
+
expect(scanned_list('0xABC12')).to eq [[:integer, 0xABC12], [false, nil]]
|
136
|
+
expect(scanned_list('0XABC12')).to eq [[:integer, 0xABC12], [false, nil]]
|
137
|
+
expect(scanned_list('+0xABC12')).to eq [[:integer, 0xABC12], [false, nil]]
|
138
|
+
expect(scanned_list('-0xABC12')).to eq [[:integer, -0xABC12], [false, nil]]
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'returns [:integer, 0] for "0"' do
|
142
|
+
expect(scanned_list('0')).to eq [[:integer, 0], [false, nil]]
|
143
|
+
expect(scanned_list('+0')).to eq [[:integer, 0], [false, nil]]
|
144
|
+
expect(scanned_list('-0')).to eq [[:integer, 0], [false, nil]]
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'returns [:float, value] for decimal float literal' do
|
148
|
+
expect(scanned_list('0.123')).to eq [[:float, 0.123], [false, nil]]
|
149
|
+
expect(scanned_list('12.34')).to eq [[:float, 12.34], [false, nil]]
|
150
|
+
expect(scanned_list('+0.123')).to eq [[:float, 0.123], [false, nil]]
|
151
|
+
expect(scanned_list('+12.34')).to eq [[:float, 12.34], [false, nil]]
|
152
|
+
expect(scanned_list('-0.123')).to eq [[:float, -0.123], [false, nil]]
|
153
|
+
expect(scanned_list('-12.34')).to eq [[:float, -12.34], [false, nil]]
|
154
|
+
expect(scanned_list('0.0')).to eq [[:float, 0.0], [false, nil]]
|
155
|
+
expect(scanned_list('+0.0')).to eq [[:float, 0.0], [false, nil]]
|
156
|
+
expect(scanned_list('-0.0')).to eq [[:float, -0.0], [false, nil]]
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'returns [:float, value] for scientific float literal' do
|
160
|
+
expect(scanned_list('1.1e5')).to eq [[:float, 1.1e5], [false, nil]]
|
161
|
+
expect(scanned_list('1.1E5')).to eq [[:float, 1.1e5], [false, nil]]
|
162
|
+
expect(scanned_list('1.1e+5')).to eq [[:float, 1.1e5], [false, nil]]
|
163
|
+
expect(scanned_list('1.1e-5')).to eq [[:float, 1.1e-5], [false, nil]]
|
164
|
+
expect(scanned_list('1.1e0')).to eq [[:float, 1.1], [false, nil]]
|
165
|
+
expect(scanned_list('1.1e+0')).to eq [[:float, 1.1], [false, nil]]
|
166
|
+
expect(scanned_list('1.1e-0')).to eq [[:float, 1.1], [false, nil]]
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'returns [:identifier, str] for identifiers' do
|
170
|
+
%w! abc ab_c _abc abc_ ABC AB_C _ABC ABC_ Abc AbC aBc !.each do |name|
|
171
|
+
expect(scanned_list(name)).to eq [[:identifier, name], [false, nil]]
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
it 'ignores spaces between tokens' do
|
176
|
+
expect(scanned_list("abc\n: def . ghi jk :\t'l : m' n\r: 012")).to eq [
|
177
|
+
[:identifier, 'abc'],
|
178
|
+
[':', ':'],
|
179
|
+
[:identifier, 'def'],
|
180
|
+
['.', '.'],
|
181
|
+
[:identifier, 'ghi'],
|
182
|
+
[:identifier, 'jk'],
|
183
|
+
[':', ':'],
|
184
|
+
[:string, 'l : m'],
|
185
|
+
[:identifier, 'n'],
|
186
|
+
[':', ':'],
|
187
|
+
[:integer, 012],
|
188
|
+
[false, nil]
|
189
|
+
]
|
190
|
+
end
|
191
|
+
|
192
|
+
it 'splits tokens without spaces' do
|
193
|
+
expect(scanned_list("abc:def.ghi jk:'l : m'n:012")).to eq [
|
194
|
+
[:identifier, 'abc'],
|
195
|
+
[':', ':'],
|
196
|
+
[:identifier, 'def'],
|
197
|
+
['.', '.'],
|
198
|
+
[:identifier, 'ghi'],
|
199
|
+
[:identifier, 'jk'],
|
200
|
+
[':', ':'],
|
201
|
+
[:string, 'l : m'],
|
202
|
+
[:identifier, 'n'],
|
203
|
+
[':', ':'],
|
204
|
+
[:integer, 012],
|
205
|
+
[false, nil]
|
206
|
+
]
|
207
|
+
end
|
208
|
+
|
209
|
+
it 'ignores comments' do
|
210
|
+
expect(scanned_list("#")).to eq [[false, nil]]
|
211
|
+
expect(scanned_list("#\n")).to eq [[false, nil]]
|
212
|
+
expect(scanned_list("# abc\n")).to eq [[false, nil]]
|
213
|
+
expect(scanned_list("abc #\n")).to eq [[:identifier, 'abc'], [false, nil]]
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
describe ProtocolBuffers::TextParser do
|
218
|
+
before(:each) do
|
219
|
+
@parser = ProtocolBuffers::TextParser.new
|
220
|
+
load File.join(File.dirname(__FILE__), "proto_files", "simple.pb.rb")
|
221
|
+
load File.join(File.dirname(__FILE__), "proto_files", "featureful.pb.rb")
|
222
|
+
end
|
223
|
+
|
224
|
+
it 'returns parsed message' do
|
225
|
+
m = ::Simple::Foo.new
|
226
|
+
tokens = [[false, nil]]
|
227
|
+
expect(@parser.parse_from_scanner(tokens, m)).to be_equal(m)
|
228
|
+
end
|
229
|
+
|
230
|
+
it 'accepts simple field' do
|
231
|
+
m = ::Simple::Test1.new
|
232
|
+
tokens = [
|
233
|
+
[:identifier, 'test_field'],
|
234
|
+
[':', ':'],
|
235
|
+
[:string, 'str'],
|
236
|
+
[false, nil]
|
237
|
+
]
|
238
|
+
expect(@parser.parse_from_scanner(tokens, m)).to be_equal(m)
|
239
|
+
expect(m.test_field).to eq 'str'
|
240
|
+
end
|
241
|
+
|
242
|
+
it 'rejects unknown field name' do
|
243
|
+
m = ::Simple::Test1.new
|
244
|
+
tokens = [
|
245
|
+
[:identifier, 'no_such_field'],
|
246
|
+
[':', ':'],
|
247
|
+
[:string, 'str'],
|
248
|
+
[false, nil]
|
249
|
+
]
|
250
|
+
expect {
|
251
|
+
@parser.parse_from_scanner(tokens, m)
|
252
|
+
}.to raise_error(Racc::ParseError, /no such field/)
|
253
|
+
end
|
254
|
+
|
255
|
+
it 'accepts nested field' do
|
256
|
+
m = ::Simple::Bar.new
|
257
|
+
tokens = [
|
258
|
+
[:identifier, 'foo'],
|
259
|
+
['<', '<'],
|
260
|
+
['>', '>'],
|
261
|
+
[false, nil]
|
262
|
+
]
|
263
|
+
expect(@parser.parse_from_scanner(tokens, m)).to be_equal(m)
|
264
|
+
expect(m).to have_foo
|
265
|
+
end
|
266
|
+
|
267
|
+
it 'accepts nested field with colon' do
|
268
|
+
m = ::Simple::Bar.new
|
269
|
+
tokens = [
|
270
|
+
[:identifier, 'foo'],
|
271
|
+
[':', ':'],
|
272
|
+
['<', '<'],
|
273
|
+
['>', '>'],
|
274
|
+
[false, nil]
|
275
|
+
]
|
276
|
+
expect(@parser.parse_from_scanner(tokens, m)).to be_equal(m)
|
277
|
+
expect(m).to have_foo
|
278
|
+
end
|
279
|
+
|
280
|
+
|
281
|
+
it 'accepts deeply nested field' do
|
282
|
+
m = ::Featureful::C.new
|
283
|
+
tokens = [
|
284
|
+
[:identifier, 'e'],
|
285
|
+
['<', '<'],
|
286
|
+
[:identifier, 'd'],
|
287
|
+
['<', '<'],
|
288
|
+
[:identifier, 'f'],
|
289
|
+
['<', '<'],
|
290
|
+
[:identifier, 's'],
|
291
|
+
[':', ':'],
|
292
|
+
[:string, 'str'],
|
293
|
+
['>', '>'],
|
294
|
+
['>', '>'],
|
295
|
+
['>', '>'],
|
296
|
+
[false, nil]
|
297
|
+
]
|
298
|
+
expect(@parser.parse_from_scanner(tokens, m)).to be_equal(m)
|
299
|
+
|
300
|
+
expect(m).not_to have_d
|
301
|
+
expect(m).to have(1).e
|
302
|
+
|
303
|
+
expect(m.e[0]).to have_d
|
304
|
+
expect(m.e[0].d).to have(1).f
|
305
|
+
|
306
|
+
expect(m.e[0].d.f[0]).to have_s
|
307
|
+
expect(m.e[0].d.f[0].s).to eq 'str'
|
308
|
+
end
|
309
|
+
|
310
|
+
it 'accepts group field' do
|
311
|
+
m = ::Featureful::A::Group1.new
|
312
|
+
tokens = [
|
313
|
+
[:identifier, 'i1'],
|
314
|
+
[':', ':'],
|
315
|
+
[:integer, 1],
|
316
|
+
[:identifier, 'Subgroup'],
|
317
|
+
['{', '{'],
|
318
|
+
[:identifier, 'i1'],
|
319
|
+
[':', ':'],
|
320
|
+
[:integer, 1],
|
321
|
+
['}', '}'],
|
322
|
+
[false, nil]
|
323
|
+
]
|
324
|
+
expect(@parser.parse_from_scanner(tokens, m)).to be_equal(m)
|
325
|
+
|
326
|
+
expect(m.i1).to eq(1)
|
327
|
+
expect(m).to have(1).subgroup
|
328
|
+
expect(m.subgroup[0].i1).to eq(1)
|
329
|
+
end
|
330
|
+
|
331
|
+
it 'accepts multiple values for repeated field' do
|
332
|
+
m = ::Featureful::D.new
|
333
|
+
tokens = [
|
334
|
+
[:identifier, 'f'],
|
335
|
+
['<', '<'],
|
336
|
+
[:identifier, 's'],
|
337
|
+
[':', ':'],
|
338
|
+
[:string, 'str'],
|
339
|
+
['>', '>'],
|
340
|
+
[:identifier, 'f'],
|
341
|
+
['{', '{'],
|
342
|
+
[:identifier, 's'],
|
343
|
+
[':', ':'],
|
344
|
+
[:string, 'str2'],
|
345
|
+
['}', '}'],
|
346
|
+
[:identifier, 'f'],
|
347
|
+
['<', '<'],
|
348
|
+
['>', '>'],
|
349
|
+
[false, nil]
|
350
|
+
]
|
351
|
+
expect(@parser.parse_from_scanner(tokens, m)).to be_equal(m)
|
352
|
+
|
353
|
+
expect(m).to have(3).f
|
354
|
+
expect(m.f[0]).to have_s
|
355
|
+
expect(m.f[0].s).to eq 'str'
|
356
|
+
expect(m.f[1]).to have_s
|
357
|
+
expect(m.f[1].s).to eq 'str2'
|
358
|
+
expect(m.f[2]).not_to have_s
|
359
|
+
end
|
360
|
+
|
361
|
+
it 'rejects unterminated field' do
|
362
|
+
m = ::Simple::Test1.new
|
363
|
+
tokens = [
|
364
|
+
[:identifier, 'test_field'],
|
365
|
+
[':', ':'],
|
366
|
+
[false, nil]
|
367
|
+
]
|
368
|
+
expect {
|
369
|
+
@parser.parse_from_scanner(tokens, m)
|
370
|
+
}.to raise_error(Racc::ParseError)
|
371
|
+
|
372
|
+
m = ::Simple::Test1.new
|
373
|
+
tokens = [
|
374
|
+
[:identifier, 'test_field'],
|
375
|
+
[false, nil]
|
376
|
+
]
|
377
|
+
expect {
|
378
|
+
@parser.parse_from_scanner(tokens, m)
|
379
|
+
}.to raise_error(Racc::ParseError)
|
380
|
+
end
|
381
|
+
|
382
|
+
it 'accepts string field' do
|
383
|
+
m = ::Featureful::ABitOfEverything.new
|
384
|
+
tokens = [
|
385
|
+
[:identifier, 'string_field'],
|
386
|
+
[':', ':'],
|
387
|
+
[:string, 'str'],
|
388
|
+
[false, nil]
|
389
|
+
]
|
390
|
+
expect(@parser.parse_from_scanner(tokens, m)).to be_equal(m)
|
391
|
+
expect(m.string_field).to eq 'str'
|
392
|
+
expect(m.string_field.encoding).to eq Encoding::UTF_8
|
393
|
+
end
|
394
|
+
|
395
|
+
it 'accepts bytes field' do
|
396
|
+
m = ::Featureful::ABitOfEverything.new
|
397
|
+
tokens = [
|
398
|
+
[:identifier, 'bytes_field'],
|
399
|
+
[':', ':'],
|
400
|
+
[:string, "bytes\x00\x01\x02\x03"],
|
401
|
+
[false, nil]
|
402
|
+
]
|
403
|
+
expect(@parser.parse_from_scanner(tokens, m)).to be_equal(m)
|
404
|
+
expect(m.bytes_field).to eq "bytes\x00\x01\x02\x03"
|
405
|
+
end
|
406
|
+
|
407
|
+
it 'accepts float field' do
|
408
|
+
m = ::Featureful::ABitOfEverything.new
|
409
|
+
tokens = [
|
410
|
+
[:identifier, 'float_field'],
|
411
|
+
[':', ':'],
|
412
|
+
[:float, 1.1],
|
413
|
+
[:identifier, 'double_field'],
|
414
|
+
[':', ':'],
|
415
|
+
[:float, 1.1],
|
416
|
+
[false, nil]
|
417
|
+
]
|
418
|
+
expect(@parser.parse_from_scanner(tokens, m)).to be_equal(m)
|
419
|
+
expect(m.float_field).to eq 1.1
|
420
|
+
expect(m.double_field).to eq 1.1
|
421
|
+
end
|
422
|
+
|
423
|
+
it 'accepts int field' do
|
424
|
+
m = ::Featureful::ABitOfEverything.new
|
425
|
+
tokens = [
|
426
|
+
[:identifier, 'int32_field'],
|
427
|
+
[':', ':'],
|
428
|
+
[:integer, 1],
|
429
|
+
[false, nil]
|
430
|
+
]
|
431
|
+
expect(@parser.parse_from_scanner(tokens, m)).to be_equal(m)
|
432
|
+
expect(m.int32_field).to eq 1
|
433
|
+
end
|
434
|
+
|
435
|
+
it 'accepts bool field' do
|
436
|
+
m = ::Featureful::ABitOfEverything.new
|
437
|
+
tokens = [
|
438
|
+
[:identifier, 'bool_field'],
|
439
|
+
[':', ':'],
|
440
|
+
[:bool, true],
|
441
|
+
[false, nil]
|
442
|
+
]
|
443
|
+
expect(@parser.parse_from_scanner(tokens, m)).to be_equal(m)
|
444
|
+
expect(m.bool_field).to be_true
|
445
|
+
end
|
446
|
+
|
447
|
+
it 'accepts integer as a enum field' do
|
448
|
+
m = ::Featureful::A::Sub.new
|
449
|
+
tokens = [
|
450
|
+
[:identifier, 'payload_type'],
|
451
|
+
[':', ':'],
|
452
|
+
[:integer, 1],
|
453
|
+
[false, nil]
|
454
|
+
]
|
455
|
+
expect(@parser.parse_from_scanner(tokens, m)).to be_equal(m)
|
456
|
+
expect(m).to have_payload_type
|
457
|
+
expect(m.payload_type).to eq ::Featureful::A::Sub::Payloads::P2
|
458
|
+
end
|
459
|
+
|
460
|
+
it 'accepts enum name as a enum field' do
|
461
|
+
m = ::Featureful::A::Sub.new
|
462
|
+
tokens = [
|
463
|
+
[:identifier, 'payload_type'],
|
464
|
+
[':', ':'],
|
465
|
+
[:identifier, 'P2'],
|
466
|
+
[false, nil]
|
467
|
+
]
|
468
|
+
expect(@parser.parse_from_scanner(tokens, m)).to be_equal(m)
|
469
|
+
expect(m).to have_payload_type
|
470
|
+
expect(m.payload_type).to eq ::Featureful::A::Sub::Payloads::P2
|
471
|
+
end
|
472
|
+
|
473
|
+
it 'concatenates strings' do
|
474
|
+
m = ::Simple::Test1.new
|
475
|
+
tokens = [
|
476
|
+
[:identifier, 'test_field'],
|
477
|
+
[':', ':'],
|
478
|
+
[:string, 'str'],
|
479
|
+
[:string, 'another str'],
|
480
|
+
[false, nil]
|
481
|
+
]
|
482
|
+
expect(@parser.parse_from_scanner(tokens, m)).to be_equal(m)
|
483
|
+
expect(m.test_field).to eq 'stranother str'
|
484
|
+
end
|
485
|
+
|
486
|
+
it 'rejects unknown field' do
|
487
|
+
# The text format for unknown field is designed only for displaying a
|
488
|
+
# message to human.
|
489
|
+
# Since wire_types in it are ambigous, we cannot parse the notation.
|
490
|
+
m = ::Simple::Test1.new
|
491
|
+
tokens = [
|
492
|
+
[:integer, 1],
|
493
|
+
[':', ':'],
|
494
|
+
[:string, 'str'],
|
495
|
+
[false, nil]
|
496
|
+
]
|
497
|
+
expect {
|
498
|
+
@parser.parse_from_scanner(tokens, m)
|
499
|
+
}.to raise_error(Racc::ParseError)
|
500
|
+
end
|
501
|
+
end
|
502
|
+
|
503
|
+
describe ProtocolBuffers::TextFormatter do
|
504
|
+
def formatter(options = nil)
|
505
|
+
ProtocolBuffers::TextFormatter.new(options)
|
506
|
+
end
|
507
|
+
|
508
|
+
# Returns a dummy instance of Featureful::A
|
509
|
+
def dummy_a
|
510
|
+
m = Featureful::A.new
|
511
|
+
m.i1 = [1, 2, 3]
|
512
|
+
m.i3 = 4
|
513
|
+
|
514
|
+
subsub = Featureful::A::Sub::SubSub.new(:subsub_payload => "foo")
|
515
|
+
m.sub1 = [
|
516
|
+
Featureful::A::Sub.new(:payload => "bar",
|
517
|
+
:payload_type => Featureful::A::Sub::Payloads::P1,
|
518
|
+
:subsub1 => subsub),
|
519
|
+
Featureful::A::Sub.new(:payload => "baz",
|
520
|
+
:payload_type => Featureful::A::Sub::Payloads::P2),
|
521
|
+
]
|
522
|
+
m.sub3.payload = "qux"
|
523
|
+
m.sub3.payload_type = Featureful::A::Sub::Payloads::P1
|
524
|
+
m.sub3.subsub1.subsub_payload = "quux"
|
525
|
+
|
526
|
+
sg = Featureful::A::Group1::Subgroup.new(:i1 => 1)
|
527
|
+
m.group1 = [
|
528
|
+
Featureful::A::Group1.new(:i1 => 1, :subgroup => [sg]),
|
529
|
+
Featureful::A::Group1.new(:i1 => 2),
|
530
|
+
]
|
531
|
+
m.group3.i1 = 5
|
532
|
+
m.group3.subgroup << Featureful::A::Group3::Subgroup.new(:i1 => 1)
|
533
|
+
|
534
|
+
m
|
535
|
+
end
|
536
|
+
|
537
|
+
before(:each) do
|
538
|
+
@parser = ProtocolBuffers::TextParser.new
|
539
|
+
load File.join(File.dirname(__FILE__), "proto_files", "simple.pb.rb")
|
540
|
+
load File.join(File.dirname(__FILE__), "proto_files", "featureful.pb.rb")
|
541
|
+
end
|
542
|
+
|
543
|
+
it "formats integer field in decimal" do
|
544
|
+
m = Featureful::ABitOfEverything.new
|
545
|
+
m.int32_field = 123
|
546
|
+
expect(m.text_format_to_string).to eq "int32_field: 123\n"
|
547
|
+
end
|
548
|
+
|
549
|
+
it "formats float field in decimal" do
|
550
|
+
m = Featureful::ABitOfEverything.new
|
551
|
+
m.float_field = 0.123
|
552
|
+
expect(m.text_format_to_string).to eq "float_field: 0.123\n"
|
553
|
+
end
|
554
|
+
|
555
|
+
it "formats string field with quotation" do
|
556
|
+
m = Featureful::ABitOfEverything.new
|
557
|
+
m.string_field = "str"
|
558
|
+
expect(m.text_format_to_string).to eq "string_field: \"str\"\n"
|
559
|
+
end
|
560
|
+
|
561
|
+
it "escapes non ascii printable characters in string field" do
|
562
|
+
str = "\xe3\x81\x82\0\n"
|
563
|
+
str.force_encoding(Encoding::UTF_8) if str.respond_to?(:force_encoding)
|
564
|
+
m = Featureful::ABitOfEverything.new
|
565
|
+
m.string_field = str
|
566
|
+
|
567
|
+
formatted = m.text_format_to_string
|
568
|
+
expect(formatted).to match(/\Astring_field: "(.*?)"\n/)
|
569
|
+
|
570
|
+
escaped = formatted[/string_field: (".*?")/, 1]
|
571
|
+
expect(escaped).to match(/\A[[:ascii:]&&[:print:]]+\z/)
|
572
|
+
expect(eval(escaped)).to eq str
|
573
|
+
end
|
574
|
+
|
575
|
+
it "escapes bytes in bytes field" do
|
576
|
+
m = Featureful::ABitOfEverything.new
|
577
|
+
m.bytes_field = "bytes"
|
578
|
+
expect(m.text_format_to_string).to eq "bytes_field: \"\\x62\\x79\\x74\\x65\\x73\"\n"
|
579
|
+
end
|
580
|
+
|
581
|
+
it "formats message field with indent" do
|
582
|
+
m = Featureful::E.new
|
583
|
+
m.d.f2.s = "str"
|
584
|
+
expect(m.text_format_to_string).to eq <<-EOS
|
585
|
+
d {
|
586
|
+
f2 {
|
587
|
+
s: "str"
|
588
|
+
}
|
589
|
+
}
|
590
|
+
EOS
|
591
|
+
end
|
592
|
+
|
593
|
+
it "formats group field with indent" do
|
594
|
+
m = Featureful::A::Group1.new
|
595
|
+
m.i1 = 1
|
596
|
+
m.subgroup << Featureful::A::Group1::Subgroup.new(:i1 => 1)
|
597
|
+
expect(m.text_format_to_string).to eq <<-EOS
|
598
|
+
i1: 1
|
599
|
+
Subgroup {
|
600
|
+
i1: 1
|
601
|
+
}
|
602
|
+
EOS
|
603
|
+
end
|
604
|
+
|
605
|
+
it "rejects invalid message" do
|
606
|
+
m = Featureful::A.new
|
607
|
+
expect {
|
608
|
+
m.text_format_to_string
|
609
|
+
}.to raise_error(ProtocolBuffers::EncodeError)
|
610
|
+
end
|
611
|
+
|
612
|
+
it "formats unknown field with tag number" do
|
613
|
+
m = ::Simple::Foo.new
|
614
|
+
m.remember_unknown_field(100 << 3 | ProtocolBuffers::WireTypes::VARINT, 1)
|
615
|
+
m.remember_unknown_field(101 << 3 | ProtocolBuffers::WireTypes::FIXED32, "\x01\x02\x03\x04")
|
616
|
+
m.remember_unknown_field(102 << 3 | ProtocolBuffers::WireTypes::FIXED64, "\x01\x02\x03\x04\x05\x06\x07\x08")
|
617
|
+
m.remember_unknown_field(103 << 3 | ProtocolBuffers::WireTypes::LENGTH_DELIMITED, "str")
|
618
|
+
|
619
|
+
group = ProtocolBuffers::Message.new
|
620
|
+
group.remember_unknown_field(1 << 3 | ProtocolBuffers::WireTypes::VARINT, 1)
|
621
|
+
subgroup = ProtocolBuffers::Message.new
|
622
|
+
subgroup.remember_unknown_field(1 << 3 | ProtocolBuffers::WireTypes::VARINT, 1)
|
623
|
+
group.remember_unknown_field(2 << 3 | ProtocolBuffers::WireTypes::START_GROUP, subgroup)
|
624
|
+
m.remember_unknown_field(104 << 3 | ProtocolBuffers::WireTypes::START_GROUP, group)
|
625
|
+
|
626
|
+
expect(m.text_format_to_string).to eq <<-EOS
|
627
|
+
100: 1
|
628
|
+
101: 0x04030201
|
629
|
+
102: 0x0807060504030201
|
630
|
+
103: "\\x73\\x74\\x72"
|
631
|
+
104 {
|
632
|
+
1: 1
|
633
|
+
2 {
|
634
|
+
1: 1
|
635
|
+
}
|
636
|
+
}
|
637
|
+
EOS
|
638
|
+
end
|
639
|
+
|
640
|
+
it "roundtrips with TextParser" do
|
641
|
+
m = dummy_a
|
642
|
+
parser = ProtocolBuffers::TextParser.new
|
643
|
+
parsed = Featureful::A.new
|
644
|
+
parser.parse_text(m.text_format_to_string, parsed)
|
645
|
+
|
646
|
+
expect(parsed).to eq(m)
|
647
|
+
end
|
648
|
+
|
649
|
+
context "if option[:short] is specified" do
|
650
|
+
it "doesn't emit newline" do
|
651
|
+
m = Featureful::ABitOfEverything.new
|
652
|
+
m.int32_field = 123
|
653
|
+
expect(m.text_format_to_string(:short => true)).to eq "int32_field: 123"
|
654
|
+
end
|
655
|
+
|
656
|
+
it "separates fields with space" do
|
657
|
+
m = Featureful::ABitOfEverything.new
|
658
|
+
m.int32_field = 123
|
659
|
+
m.string_field = "str"
|
660
|
+
expect(m.text_format_to_string(:short => true)).to eq "int32_field: 123 string_field: \"str\""
|
661
|
+
end
|
662
|
+
|
663
|
+
it "formats message field with spaces" do
|
664
|
+
m = Featureful::E.new
|
665
|
+
m.d.f2.s = "str"
|
666
|
+
expect(m.text_format_to_string(:short => true)).to eq "d { f2 { s: \"str\" } }"
|
667
|
+
end
|
668
|
+
|
669
|
+
it "roundtrips with TextParser" do
|
670
|
+
m = dummy_a
|
671
|
+
|
672
|
+
parser = ProtocolBuffers::TextParser.new
|
673
|
+
parsed = Featureful::A.new
|
674
|
+
parser.parse_text(m.text_format_to_string(:short => true), parsed)
|
675
|
+
|
676
|
+
expect(parsed).to eq(m)
|
677
|
+
end
|
678
|
+
end
|
679
|
+
end
|