forked from mozy/ruby-protocol-buffers
-
Notifications
You must be signed in to change notification settings - Fork 20
/
runtime_spec.rb
421 lines (352 loc) · 10.8 KB
/
runtime_spec.rb
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
require 'stringio'
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
require 'protocol_buffers'
require 'protocol_buffers/compiler'
ProtocolBuffers::Compiler.compile_and_load(
File.join(File.dirname(__FILE__), "proto_files", "simple.proto"))
ProtocolBuffers::Compiler.compile_and_load(
File.join(File.dirname(__FILE__), "proto_files", "featureful.proto"))
describe ProtocolBuffers, "runtime" do
it "can handle basic operations" do
msg1 = Simple::Test1.new
msg1.test_field.should == ""
msg1.test_field = "zomgkittenz"
ser = StringIO.new(msg1.to_s)
msg2 = Simple::Test1.parse(ser)
msg2.test_field.should == "zomgkittenz"
msg2.should == msg1
end
it "doesn't serialize unset fields" do
msg1 = Simple::Test1.new
msg1.test_field.should == ""
msg1.to_s.should == ""
msg1.test_field = "zomgkittenz"
msg1.to_s.should_not == ""
end
it "flags values that have been set" do
a1 = Featureful::A.new
a1.has_i2?.should == false
a1.i2 = 5
a1.has_i2?.should == true
end
it "flags sub-messages that have been set" do
a1 = Featureful::A.new
a1.value_for_tag?(a1.class.field_for_name(:sub1).tag).should == true
a1.value_for_tag?(a1.class.field_for_name(:sub2).tag).should == false
a1.value_for_tag?(a1.class.field_for_name(:sub3).tag).should == false
a1.has_sub1?.should == true
a1.has_sub2?.should == false
a1.has_sub3?.should == false
a1.sub2 = Featureful::A::Sub.new(:payload => "ohai")
a1.has_sub2?.should == true
end
it "detects changes to a sub-message and flags it as set if it wasn't" do
a1 = Featureful::A.new
a1.has_sub2?.should == false
a1.sub2.payload = "ohai"
a1.has_sub2?.should == true
end
it "detects changes to a sub-sub-message and flags up the chain" do
a1 = Featureful::A.new
a1.sub2.has_subsub1?.should == false
a1.has_sub2?.should == false
a1.sub2.subsub1.subsub_payload = "ohai"
a1.has_sub2?.should == true
a1.sub2.has_subsub1?.should == true
end
it "pretends that repeated fields are arrays" do
# make sure our RepeatedField class acts like a normal Array
ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
package foo;
message Foo {
repeated int32 nums = 1;
}
EOS
foo = Foo::Foo.new
foo2 = Foo::Foo.new(:nums => [1,2,3])
proc do
foo.nums << 1
foo.nums.class.should == ProtocolBuffers::RepeatedField
foo.nums.to_a.class.should == Array
(foo.nums & foo2.nums).should == [1]
(foo.nums + foo2.nums).should == [1,1,2,3]
foo2.nums.map! { |i| i + 1 }
foo2.nums.to_a.should == [2,3,4]
foo2.nums.class.should == ProtocolBuffers::RepeatedField
end.should_not raise_error
end
it "does type checking of repeated fields" do
a1 = Featureful::A.new
proc do
a1.sub1 << Featureful::A::Sub.new
end.should_not raise_error(TypeError)
a1 = Featureful::A.new
proc do
a1.sub1 << Featureful::A::Sub.new << "dummy string"
end.should raise_error(TypeError)
a1.sub1.should == [Featureful::A::Sub.new]
a1 = Featureful::A.new
proc do
a1.sub1 = [Featureful::A::Sub.new, Featureful::A::Sub.new, 5, Featureful::A::Sub.new]
end.should raise_error(TypeError)
end
it "does value checking of repeated fields" do
ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
package foo;
message Foo {
repeated int32 nums = 1;
}
EOS
foo = Foo::Foo.new
proc do
foo.nums << 5 << 3 << (1 << 32) # value too large for int32
end.should raise_error(ArgumentError)
end
# sort of redundant test, but let's check the example in the docs for
# correctness
it "handles singular message fields exactly as in the documentation" do
ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
package foo;
message Foo {
optional Bar bar = 1;
}
message Bar {
optional int32 i = 1;
}
EOS
foo = Foo::Foo.new
foo.has_bar?.should == false
foo.bar = Foo::Bar.new
foo.has_bar?.should == true
foo = Foo::Foo.new
foo.has_bar?.should == false
foo.bar.i = 1
foo.has_bar?.should == true
foo = Foo::Foo.new
foo.has_bar?.should == false
local_i = foo.bar.i
foo.has_bar?.should == false
end
# another example from the docs
it "handles repeated field logic" do
ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
package foo;
message Foo {
repeated int32 nums = 1;
}
EOS
foo = Foo::Foo.new
foo.has_nums?.should == true
foo.nums << 15
foo.has_nums?.should == true
foo.nums.push(32)
foo.nums.length.should == 2
foo.nums[0].should == 15
foo.nums[1].should == 32
foo.nums[1] = 56
foo.nums[1].should == 56
foo = Foo::Foo.new
foo.nums << 15
foo.nums.push(32)
foo.nums.length.should == 2
foo.nums.clear
foo.nums.length.should == 0
foo.nums << 15
foo.nums.length.should == 1
foo.nums = nil
foo.nums.length.should == 0
foo = Foo::Foo.new
foo.nums << 15
foo.nums = [1, 3, 5]
foo.nums.length.should == 3
foo.nums.to_a.should == [1,3,5]
end
it "can assign any object with an each method to a repeated field" do
ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
package foo;
message Foo {
repeated Bar nums = 1;
}
message Bar {
optional int32 i = 1;
}
EOS
class Blah
def each
yield Foo::Bar.new(:i => 1)
yield Foo::Bar.new(:i => 3)
end
end
foo = Foo::Foo.new
foo.nums = Blah.new
foo.nums.to_a.should == [Foo::Bar.new(:i => 1), Foo::Bar.new(:i => 3)]
end
it "shouldn't modify the default Message instance like this" do
a1 = Featureful::A.new
a1.sub2.payload = "ohai"
a2 = Featureful::A.new
a2.sub2.payload.should == ""
sub = Featureful::A::Sub.new
sub.payload.should == ""
end
it "doesn't allow defining fields after gen_methods is called" do
proc do
A.define_field(:optional, :string, "newfield", 15)
end.should raise_error()
end
def filled_in_bit
bit = Featureful::ABitOfEverything.new
bit.double_field = 1.0
bit.float_field = 2.0
bit.int32_field = 3
bit.int64_field = 4
bit.uint32_field = 5
bit.uint64_field = 6
bit.sint32_field = 7
bit.sint64_field = 8
bit.fixed32_field = 9
bit.fixed64_field = 10
bit.sfixed32_field = 11
bit.sfixed64_field = 12
bit.bool_field = true
bit.string_field = "14"
bit.bytes_field = "15"
bit
end
it "can serialize and de-serialize all basic field types" do
bit = filled_in_bit
bit2 = Featureful::ABitOfEverything.parse(bit.to_s)
bit.should == bit2
bit.fields.each do |tag, field|
bit.value_for_tag(tag).should == bit2.value_for_tag(tag)
end
end
it "does type checking" do
bit = filled_in_bit
proc do
bit.fixed32_field = 1.0
end.should raise_error(TypeError)
proc do
bit.double_field = 15
end.should_not raise_error()
bit2 = Featureful::ABitOfEverything.parse(bit.to_s)
bit2.double_field.should == 15
bit2.double_field.should == 15.0
bit2.double_field.is_a?(Float).should == true
proc do
bit.bool_field = 1.0
end.should raise_error(TypeError)
proc do
bit.string_field = 1.0
end.should raise_error(TypeError)
a1 = Featureful::A.new
proc do
a1.sub2 = "zomgkittenz"
end.should raise_error(TypeError)
end
it "doesn't allow invalid enum values" do
sub = Featureful::A::Sub.new
proc do
sub.payload_type.should == 0
sub.payload_type = Featureful::A::Sub::Payloads::P2
sub.payload_type.should == 1
end.should_not raise_error()
proc do
sub.payload_type = 2
end.should raise_error(ArgumentError)
end
it "enforces required fields on serialization" do
ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
package tehUnknown;
message MyResult {
required string field_1 = 1;
optional string field_2 = 2;
}
EOS
res1 = TehUnknown::MyResult.new(:field_2 => 'b')
proc { res1.to_s }.should raise_error(ProtocolBuffers::EncodeError)
end
it "enforces required fields on deserialization" do
ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
package tehUnknown;
message MyResult {
optional string field_1 = 1;
optional string field_2 = 2;
}
EOS
res1 = TehUnknown::MyResult.new(:field_2 => 'b')
buf = res1.to_s
# now make field_1 required
ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
package tehUnknown;
message MyResult {
required string field_1 = 1;
optional string field_2 = 2;
}
EOS
proc { TehUnknown::MyResult.parse(buf) }.should raise_error(ProtocolBuffers::DecodeError)
end
it "enforces valid values on deserialization" do
ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
package tehUnknown;
message MyResult {
optional int32 field_1 = 1;
}
EOS
res1 = TehUnknown::MyResult.new(:field_1 => 5)
buf = res1.to_s
ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
package tehUnknown;
message MyResult {
enum E { A = 1; }
optional E field_1 = 1;
}
EOS
proc { TehUnknown::MyResult.parse(buf) }.should raise_error(ProtocolBuffers::DecodeError)
end
it "ignores and passes on unknown fields" do
ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
package tehUnknown;
message MyResult {
optional int32 field_1 = 1;
optional int32 field_2 = 2;
optional int32 field_3 = 3;
}
EOS
res1 = TehUnknown::MyResult.new(:field_1 => 0xffff, :field_2 => 0xfffe,
:field_3 => 0xfffd)
serialized = res1.to_s
# remove field_2 to pretend we never knew about it
ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
package tehUnknown;
message MyResult {
optional int32 field_1 = 1;
optional int32 field_3 = 3;
}
EOS
res2 = nil
proc do
res2 = TehUnknown::MyResult.parse(serialized)
end.should_not raise_error()
res2.field_1.should == 0xffff
res2.field_3.should == 0xfffd
proc do
res2.field_2.should == 0xfffe
end.should raise_error(NoMethodError)
serialized2 = res2.to_s
# now we know about field_2 again
ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
package tehUnknown;
message MyResult {
optional int32 field_1 = 1;
optional int32 field_2 = 2;
}
EOS
res3 = TehUnknown::MyResult.parse(serialized2)
res3.field_1.should == 0xffff
pending("pass on unknown fields") do
res3.field_2.should == 0xfffe
end
end
end