ruby-protocol-buffers 0.8.4
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.
- data/.document +3 -0
- data/.gitignore +11 -0
- data/LICENSE +22 -0
- data/README +82 -0
- data/Rakefile +56 -0
- data/VERSION +1 -0
- data/bin/ruby-protoc +55 -0
- data/debian/changelog +105 -0
- data/debian/compatability +1 -0
- data/debian/control +12 -0
- data/debian/libprotobuf-ruby1.8.install +7 -0
- data/debian/protocol_buffers.rb +3 -0
- data/debian/rules +13 -0
- data/examples/json_protobuf.rb +90 -0
- data/ext/extconf.disabled.rb +3 -0
- data/ext/varint.c +65 -0
- data/lib/protocol_buffers.rb +5 -0
- data/lib/protocol_buffers/compiler.rb +48 -0
- data/lib/protocol_buffers/compiler/descriptor.pb.rb +236 -0
- data/lib/protocol_buffers/compiler/descriptor.proto +393 -0
- data/lib/protocol_buffers/compiler/file_descriptor_to_d.rb +195 -0
- data/lib/protocol_buffers/compiler/file_descriptor_to_ruby.rb +173 -0
- data/lib/protocol_buffers/limited_io.rb +33 -0
- data/lib/protocol_buffers/runtime/decoder.rb +65 -0
- data/lib/protocol_buffers/runtime/encoder.rb +53 -0
- data/lib/protocol_buffers/runtime/enum.rb +4 -0
- data/lib/protocol_buffers/runtime/extend.rb +1 -0
- data/lib/protocol_buffers/runtime/field.rb +550 -0
- data/lib/protocol_buffers/runtime/message.rb +494 -0
- data/lib/protocol_buffers/runtime/service.rb +1 -0
- data/lib/protocol_buffers/runtime/varint.rb +62 -0
- data/spec/compiler_spec.rb +19 -0
- data/spec/fields_spec.rb +49 -0
- data/spec/proto_files/depends.proto +5 -0
- data/spec/proto_files/featureful.proto +54 -0
- data/spec/proto_files/no_package.proto +10 -0
- data/spec/proto_files/simple.proto +5 -0
- data/spec/runtime_spec.rb +430 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +8 -0
- metadata +128 -0
@@ -0,0 +1 @@
|
|
1
|
+
# TODO
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module ProtocolBuffers
|
2
|
+
|
3
|
+
module Varint # :nodoc:
|
4
|
+
# encode/decode methods defined in ext/varint.c
|
5
|
+
|
6
|
+
unless self.respond_to?(:encode)
|
7
|
+
def self.encode(io, int_val)
|
8
|
+
if int_val < 0
|
9
|
+
# negative varints are always encoded with the full 10 bytes
|
10
|
+
int_val = int_val & 0xffffffff_ffffffff
|
11
|
+
end
|
12
|
+
loop do
|
13
|
+
byte = int_val & 0b0111_1111
|
14
|
+
int_val >>= 7
|
15
|
+
if int_val == 0
|
16
|
+
io << byte.chr
|
17
|
+
break
|
18
|
+
else
|
19
|
+
io << (byte | 0b1000_0000).chr
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
unless self.respond_to?(:decode)
|
26
|
+
def self.decode(io)
|
27
|
+
int_val = 0
|
28
|
+
shift = 0
|
29
|
+
loop do
|
30
|
+
raise(DecodeError, "too many bytes when decoding varint") if shift >= 64
|
31
|
+
byte = io.getc.ord
|
32
|
+
int_val |= (byte & 0b0111_1111) << shift
|
33
|
+
shift += 7
|
34
|
+
return int_val if (byte & 0b1000_0000) == 0
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.encodeZigZag32(int_val)
|
40
|
+
(int_val << 1) ^ (int_val >> 31)
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.encodeZigZag64(int_val)
|
44
|
+
(int_val << 1) ^ (int_val >> 63)
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.decodeZigZag32(int_val)
|
48
|
+
(int_val >> 1) ^ -(int_val & 1)
|
49
|
+
end
|
50
|
+
class << self; alias_method :decodeZigZag64, :decodeZigZag32 end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
# fix for 1.8 <-> 1.9 compat
|
57
|
+
unless 'a'.respond_to?(:ord)
|
58
|
+
class String; def ord; self[0]; end; end
|
59
|
+
end
|
60
|
+
unless (1).respond_to?(:ord)
|
61
|
+
class Fixnum; def ord; self; end; end
|
62
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
|
4
|
+
require 'protocol_buffers'
|
5
|
+
require 'protocol_buffers/compiler'
|
6
|
+
|
7
|
+
describe ProtocolBuffers, "compiler" do
|
8
|
+
|
9
|
+
test_files = Dir[File.join(File.dirname(__FILE__), "proto_files", "*.proto")]
|
10
|
+
|
11
|
+
test_files.each do |file|
|
12
|
+
it "can compile #{File.basename(file)}" do
|
13
|
+
proc do
|
14
|
+
ProtocolBuffers::Compiler.compile_and_load(file)
|
15
|
+
end.should_not raise_error()
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
data/spec/fields_spec.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
require 'stringio'
|
4
|
+
|
5
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
|
6
|
+
require 'protocol_buffers/runtime/field'
|
7
|
+
|
8
|
+
describe ProtocolBuffers, "fields" do
|
9
|
+
|
10
|
+
def mkfield(ftype)
|
11
|
+
ProtocolBuffers::Field.const_get(ftype).new(:optional, "test", 1)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "checks bounds on varint field types" do
|
15
|
+
u32 = mkfield(:Uint32Field)
|
16
|
+
proc { u32.check_valid(0xFFFFFFFF) }.should_not raise_error()
|
17
|
+
proc { u32.check_valid(0x100000000) }.should raise_error(ArgumentError)
|
18
|
+
proc { u32.check_valid(-1) }.should raise_error(ArgumentError)
|
19
|
+
|
20
|
+
u64 = mkfield(:Uint64Field)
|
21
|
+
proc { u64.check_valid(0xFFFFFFFF_FFFFFFFF) }.should_not raise_error()
|
22
|
+
proc { u64.check_valid(0x100000000_00000000) }.should raise_error(ArgumentError)
|
23
|
+
proc { u64.check_valid(-1) }.should raise_error(ArgumentError)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "properly encodes and decodes negative varints" do
|
27
|
+
val = -2082844800000000
|
28
|
+
str = "\200\300\313\274\236\265\246\374\377\001"
|
29
|
+
sio = StringIO.new
|
30
|
+
ProtocolBuffers::Varint.encode(sio, val)
|
31
|
+
sio.string.should == str
|
32
|
+
sio.rewind
|
33
|
+
val2 = ProtocolBuffers::Varint.decode(sio)
|
34
|
+
int64 = mkfield(:Int64Field)
|
35
|
+
int64.deserialize(val2).should == val
|
36
|
+
proc { int64.check_value(int64.deserialize(val2)) }.should_not raise_error
|
37
|
+
end
|
38
|
+
|
39
|
+
it "verifies UTF-8 for string fields" do
|
40
|
+
pending("do UTF-8 validation") do
|
41
|
+
s1 = mkfield(:StringField)
|
42
|
+
proc { s1.check_valid("hello") }.should_not raise_error()
|
43
|
+
proc { s1.check_valid("\xff\xff") }.should raise_error(ArgumentError)
|
44
|
+
b1 = mkfield(:BytesField)
|
45
|
+
proc { b1.check_valid("\xff\xff") }.should_not raise_error()
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
package featureful;
|
2
|
+
|
3
|
+
message A {
|
4
|
+
message Sub {
|
5
|
+
enum Payloads {
|
6
|
+
P1 = 0;
|
7
|
+
P2 = 1;
|
8
|
+
};
|
9
|
+
|
10
|
+
optional string payload = 1;
|
11
|
+
required Payloads payload_type = 2 [default = P1];
|
12
|
+
|
13
|
+
message SubSub {
|
14
|
+
optional string subsub_payload = 1;
|
15
|
+
};
|
16
|
+
optional SubSub subsub1 = 3;
|
17
|
+
};
|
18
|
+
|
19
|
+
repeated int32 i1 = 1;
|
20
|
+
optional int32 i2 = 2;
|
21
|
+
required int32 i3 = 3;
|
22
|
+
|
23
|
+
repeated Sub sub1 = 4;
|
24
|
+
optional Sub sub2 = 5;
|
25
|
+
required Sub sub3 = 6;
|
26
|
+
};
|
27
|
+
|
28
|
+
message B {
|
29
|
+
repeated A a = 1;
|
30
|
+
};
|
31
|
+
|
32
|
+
enum MainPayloads {
|
33
|
+
P1 = 2;
|
34
|
+
P2 = 3;
|
35
|
+
P3 = 4;
|
36
|
+
};
|
37
|
+
|
38
|
+
message ABitOfEverything {
|
39
|
+
optional double double_field = 1;
|
40
|
+
optional float float_field = 2;
|
41
|
+
optional int32 int32_field = 3;
|
42
|
+
optional int64 int64_field = 4 [default = 15];
|
43
|
+
optional uint32 uint32_field = 5;
|
44
|
+
optional uint64 uint64_field = 6;
|
45
|
+
optional sint32 sint32_field = 7;
|
46
|
+
optional sint64 sint64_field = 8;
|
47
|
+
optional fixed32 fixed32_field = 9;
|
48
|
+
optional fixed64 fixed64_field = 10;
|
49
|
+
optional sfixed32 sfixed32_field = 11;
|
50
|
+
optional sfixed64 sfixed64_field = 12;
|
51
|
+
optional bool bool_field = 13 [default = false];
|
52
|
+
optional string string_field = 14 [default = "zomgkittenz"];
|
53
|
+
optional bytes bytes_field = 15;
|
54
|
+
};
|
@@ -0,0 +1,430 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
require 'stringio'
|
4
|
+
|
5
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
|
6
|
+
require 'protocol_buffers'
|
7
|
+
require 'protocol_buffers/compiler'
|
8
|
+
|
9
|
+
ProtocolBuffers::Compiler.compile_and_load(
|
10
|
+
File.join(File.dirname(__FILE__), "proto_files", "simple.proto"))
|
11
|
+
ProtocolBuffers::Compiler.compile_and_load(
|
12
|
+
File.join(File.dirname(__FILE__), "proto_files", "featureful.proto"))
|
13
|
+
|
14
|
+
describe ProtocolBuffers, "runtime" do
|
15
|
+
|
16
|
+
it "can handle basic operations" do
|
17
|
+
|
18
|
+
msg1 = Simple::Test1.new
|
19
|
+
msg1.test_field.should == ""
|
20
|
+
|
21
|
+
msg1.test_field = "zomgkittenz"
|
22
|
+
|
23
|
+
ser = StringIO.new(msg1.to_s)
|
24
|
+
msg2 = Simple::Test1.parse(ser)
|
25
|
+
msg2.test_field.should == "zomgkittenz"
|
26
|
+
msg2.should == msg1
|
27
|
+
end
|
28
|
+
|
29
|
+
it "doesn't serialize unset fields" do
|
30
|
+
msg1 = Simple::Test1.new
|
31
|
+
msg1.test_field.should == ""
|
32
|
+
msg1.to_s.should == ""
|
33
|
+
|
34
|
+
msg1.test_field = "zomgkittenz"
|
35
|
+
msg1.to_s.should_not == ""
|
36
|
+
end
|
37
|
+
|
38
|
+
it "flags values that have been set" do
|
39
|
+
a1 = Featureful::A.new
|
40
|
+
a1.has_i2?.should == false
|
41
|
+
a1.i2 = 5
|
42
|
+
a1.has_i2?.should == true
|
43
|
+
end
|
44
|
+
|
45
|
+
it "flags sub-messages that have been set" do
|
46
|
+
a1 = Featureful::A.new
|
47
|
+
a1.value_for_tag?(a1.class.field_for_name(:sub1).tag).should == true
|
48
|
+
a1.value_for_tag?(a1.class.field_for_name(:sub2).tag).should == false
|
49
|
+
a1.value_for_tag?(a1.class.field_for_name(:sub3).tag).should == false
|
50
|
+
|
51
|
+
a1.has_sub1?.should == true
|
52
|
+
a1.has_sub2?.should == false
|
53
|
+
a1.has_sub3?.should == false
|
54
|
+
|
55
|
+
a1.sub2 = Featureful::A::Sub.new(:payload => "ohai")
|
56
|
+
a1.has_sub2?.should == true
|
57
|
+
end
|
58
|
+
|
59
|
+
it "detects changes to a sub-message and flags it as set if it wasn't" do
|
60
|
+
a1 = Featureful::A.new
|
61
|
+
a1.has_sub2?.should == false
|
62
|
+
a1.sub2.payload = "ohai"
|
63
|
+
a1.has_sub2?.should == true
|
64
|
+
end
|
65
|
+
|
66
|
+
it "detects changes to a sub-sub-message and flags up the chain" do
|
67
|
+
a1 = Featureful::A.new
|
68
|
+
a1.sub2.has_subsub1?.should == false
|
69
|
+
a1.has_sub2?.should == false
|
70
|
+
a1.sub2.subsub1.subsub_payload = "ohai"
|
71
|
+
a1.has_sub2?.should == true
|
72
|
+
a1.sub2.has_subsub1?.should == true
|
73
|
+
end
|
74
|
+
|
75
|
+
it "pretends that repeated fields are arrays" do
|
76
|
+
# make sure our RepeatedField class acts like a normal Array
|
77
|
+
ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
|
78
|
+
package foo;
|
79
|
+
message Foo {
|
80
|
+
repeated int32 nums = 1;
|
81
|
+
}
|
82
|
+
EOS
|
83
|
+
|
84
|
+
foo = Foo::Foo.new
|
85
|
+
foo2 = Foo::Foo.new(:nums => [1,2,3])
|
86
|
+
proc do
|
87
|
+
foo.nums << 1
|
88
|
+
foo.nums.class.should == ProtocolBuffers::RepeatedField
|
89
|
+
foo.nums.to_a.class.should == Array
|
90
|
+
(foo.nums & foo2.nums).should == [1]
|
91
|
+
(foo.nums + foo2.nums).should == [1,1,2,3]
|
92
|
+
foo2.nums.map! { |i| i + 1 }
|
93
|
+
foo2.nums.to_a.should == [2,3,4]
|
94
|
+
foo2.nums.class.should == ProtocolBuffers::RepeatedField
|
95
|
+
end.should_not raise_error
|
96
|
+
end
|
97
|
+
|
98
|
+
it "does type checking of repeated fields" do
|
99
|
+
a1 = Featureful::A.new
|
100
|
+
proc do
|
101
|
+
a1.sub1 << Featureful::A::Sub.new
|
102
|
+
end.should_not raise_error(TypeError)
|
103
|
+
|
104
|
+
a1 = Featureful::A.new
|
105
|
+
proc do
|
106
|
+
a1.sub1 << Featureful::A::Sub.new << "dummy string"
|
107
|
+
end.should raise_error(TypeError)
|
108
|
+
a1.sub1.should == [Featureful::A::Sub.new]
|
109
|
+
|
110
|
+
a1 = Featureful::A.new
|
111
|
+
proc do
|
112
|
+
a1.sub1 = [Featureful::A::Sub.new, Featureful::A::Sub.new, 5, Featureful::A::Sub.new]
|
113
|
+
end.should raise_error(TypeError)
|
114
|
+
end
|
115
|
+
|
116
|
+
it "does value checking of repeated fields" do
|
117
|
+
ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
|
118
|
+
package foo;
|
119
|
+
message Foo {
|
120
|
+
repeated int32 nums = 1;
|
121
|
+
}
|
122
|
+
EOS
|
123
|
+
|
124
|
+
foo = Foo::Foo.new
|
125
|
+
proc do
|
126
|
+
foo.nums << 5 << 3 << (1 << 32) # value too large for int32
|
127
|
+
end.should raise_error(ArgumentError)
|
128
|
+
end
|
129
|
+
|
130
|
+
# sort of redundant test, but let's check the example in the docs for
|
131
|
+
# correctness
|
132
|
+
it "handles singular message fields exactly as in the documentation" do
|
133
|
+
ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
|
134
|
+
package foo;
|
135
|
+
message Foo {
|
136
|
+
optional Bar bar = 1;
|
137
|
+
}
|
138
|
+
message Bar {
|
139
|
+
optional int32 i = 1;
|
140
|
+
}
|
141
|
+
EOS
|
142
|
+
|
143
|
+
foo = Foo::Foo.new
|
144
|
+
foo.has_bar?.should == false
|
145
|
+
foo.bar = Foo::Bar.new
|
146
|
+
foo.has_bar?.should == true
|
147
|
+
|
148
|
+
foo = Foo::Foo.new
|
149
|
+
foo.has_bar?.should == false
|
150
|
+
foo.bar.i = 1
|
151
|
+
foo.has_bar?.should == true
|
152
|
+
|
153
|
+
foo = Foo::Foo.new
|
154
|
+
foo.has_bar?.should == false
|
155
|
+
local_i = foo.bar.i
|
156
|
+
foo.has_bar?.should == false
|
157
|
+
end
|
158
|
+
|
159
|
+
# another example from the docs
|
160
|
+
it "handles repeated field logic" do
|
161
|
+
ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
|
162
|
+
package foo;
|
163
|
+
message Foo {
|
164
|
+
repeated int32 nums = 1;
|
165
|
+
}
|
166
|
+
EOS
|
167
|
+
|
168
|
+
foo = Foo::Foo.new
|
169
|
+
foo.has_nums?.should == true
|
170
|
+
foo.nums << 15
|
171
|
+
foo.has_nums?.should == true
|
172
|
+
foo.nums.push(32)
|
173
|
+
foo.nums.length.should == 2
|
174
|
+
foo.nums[0].should == 15
|
175
|
+
foo.nums[1].should == 32
|
176
|
+
foo.nums[1] = 56
|
177
|
+
foo.nums[1].should == 56
|
178
|
+
|
179
|
+
foo = Foo::Foo.new
|
180
|
+
foo.nums << 15
|
181
|
+
foo.nums.push(32)
|
182
|
+
foo.nums.length.should == 2
|
183
|
+
foo.nums.clear
|
184
|
+
foo.nums.length.should == 0
|
185
|
+
foo.nums << 15
|
186
|
+
foo.nums.length.should == 1
|
187
|
+
foo.nums = nil
|
188
|
+
foo.nums.length.should == 0
|
189
|
+
|
190
|
+
foo = Foo::Foo.new
|
191
|
+
foo.nums << 15
|
192
|
+
foo.nums = [1, 3, 5]
|
193
|
+
foo.nums.length.should == 3
|
194
|
+
foo.nums.to_a.should == [1,3,5]
|
195
|
+
|
196
|
+
foo.merge_from_string(foo.to_s)
|
197
|
+
foo.nums.length.should == 6
|
198
|
+
foo.nums.to_a.should == [1,3,5,1,3,5]
|
199
|
+
end
|
200
|
+
|
201
|
+
it "can assign any object with an each method to a repeated field" do
|
202
|
+
ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
|
203
|
+
package foo;
|
204
|
+
message Foo {
|
205
|
+
repeated Bar nums = 1;
|
206
|
+
}
|
207
|
+
message Bar {
|
208
|
+
optional int32 i = 1;
|
209
|
+
}
|
210
|
+
EOS
|
211
|
+
|
212
|
+
class Blah
|
213
|
+
def each
|
214
|
+
yield Foo::Bar.new(:i => 1)
|
215
|
+
yield Foo::Bar.new(:i => 3)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
foo = Foo::Foo.new
|
220
|
+
foo.nums = Blah.new
|
221
|
+
foo.nums.to_a.should == [Foo::Bar.new(:i => 1), Foo::Bar.new(:i => 3)]
|
222
|
+
end
|
223
|
+
|
224
|
+
it "shouldn't modify the default Message instance like this" do
|
225
|
+
a1 = Featureful::A.new
|
226
|
+
a1.sub2.payload = "ohai"
|
227
|
+
a2 = Featureful::A.new
|
228
|
+
a2.sub2.payload.should == ""
|
229
|
+
sub = Featureful::A::Sub.new
|
230
|
+
sub.payload.should == ""
|
231
|
+
end
|
232
|
+
|
233
|
+
it "doesn't allow defining fields after gen_methods is called" do
|
234
|
+
proc do
|
235
|
+
A.define_field(:optional, :string, "newfield", 15)
|
236
|
+
end.should raise_error()
|
237
|
+
end
|
238
|
+
|
239
|
+
def filled_in_bit
|
240
|
+
bit = Featureful::ABitOfEverything.new
|
241
|
+
bit.int64_field.should == 15
|
242
|
+
bit.bool_field.should == false
|
243
|
+
bit.string_field.should == "zomgkittenz"
|
244
|
+
bit.double_field = 1.0
|
245
|
+
bit.float_field = 2.0
|
246
|
+
bit.int32_field = 3
|
247
|
+
bit.int64_field = 4
|
248
|
+
bit.uint32_field = 5
|
249
|
+
bit.uint64_field = 6
|
250
|
+
bit.sint32_field = 7
|
251
|
+
bit.sint64_field = 8
|
252
|
+
bit.fixed32_field = 9
|
253
|
+
bit.fixed64_field = 10
|
254
|
+
bit.sfixed32_field = 11
|
255
|
+
bit.sfixed64_field = 12
|
256
|
+
bit.bool_field = true
|
257
|
+
bit.string_field = "14"
|
258
|
+
bit.bytes_field = "15"
|
259
|
+
bit
|
260
|
+
end
|
261
|
+
|
262
|
+
it "can serialize and de-serialize all basic field types" do
|
263
|
+
bit = filled_in_bit
|
264
|
+
|
265
|
+
bit2 = Featureful::ABitOfEverything.parse(bit.to_s)
|
266
|
+
bit.should == bit2
|
267
|
+
bit.fields.each do |tag, field|
|
268
|
+
bit.value_for_tag(tag).should == bit2.value_for_tag(tag)
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
it "does type checking" do
|
273
|
+
bit = filled_in_bit
|
274
|
+
|
275
|
+
proc do
|
276
|
+
bit.fixed32_field = 1.0
|
277
|
+
end.should raise_error(TypeError)
|
278
|
+
|
279
|
+
proc do
|
280
|
+
bit.double_field = 15
|
281
|
+
end.should_not raise_error()
|
282
|
+
bit2 = Featureful::ABitOfEverything.parse(bit.to_s)
|
283
|
+
bit2.double_field.should == 15
|
284
|
+
bit2.double_field.should == 15.0
|
285
|
+
bit2.double_field.is_a?(Float).should == true
|
286
|
+
|
287
|
+
proc do
|
288
|
+
bit.bool_field = 1.0
|
289
|
+
end.should raise_error(TypeError)
|
290
|
+
|
291
|
+
proc do
|
292
|
+
bit.string_field = 1.0
|
293
|
+
end.should raise_error(TypeError)
|
294
|
+
|
295
|
+
a1 = Featureful::A.new
|
296
|
+
proc do
|
297
|
+
a1.sub2 = "zomgkittenz"
|
298
|
+
end.should raise_error(TypeError)
|
299
|
+
end
|
300
|
+
|
301
|
+
it "doesn't allow invalid enum values" do
|
302
|
+
sub = Featureful::A::Sub.new
|
303
|
+
|
304
|
+
proc do
|
305
|
+
sub.payload_type.should == 0
|
306
|
+
sub.payload_type = Featureful::A::Sub::Payloads::P2
|
307
|
+
sub.payload_type.should == 1
|
308
|
+
end.should_not raise_error()
|
309
|
+
|
310
|
+
proc do
|
311
|
+
sub.payload_type = 2
|
312
|
+
end.should raise_error(ArgumentError)
|
313
|
+
end
|
314
|
+
|
315
|
+
it "enforces required fields on serialization" do
|
316
|
+
ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
|
317
|
+
package tehUnknown;
|
318
|
+
message MyResult {
|
319
|
+
required string field_1 = 1;
|
320
|
+
optional string field_2 = 2;
|
321
|
+
}
|
322
|
+
EOS
|
323
|
+
|
324
|
+
res1 = TehUnknown::MyResult.new(:field_2 => 'b')
|
325
|
+
|
326
|
+
proc { res1.to_s }.should raise_error(ProtocolBuffers::EncodeError)
|
327
|
+
end
|
328
|
+
|
329
|
+
it "enforces required fields on deserialization" do
|
330
|
+
ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
|
331
|
+
package tehUnknown;
|
332
|
+
message MyResult {
|
333
|
+
optional string field_1 = 1;
|
334
|
+
optional string field_2 = 2;
|
335
|
+
}
|
336
|
+
EOS
|
337
|
+
|
338
|
+
res1 = TehUnknown::MyResult.new(:field_2 => 'b')
|
339
|
+
buf = res1.to_s
|
340
|
+
|
341
|
+
# now make field_1 required
|
342
|
+
ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
|
343
|
+
package tehUnknown;
|
344
|
+
message MyResult {
|
345
|
+
required string field_1 = 1;
|
346
|
+
optional string field_2 = 2;
|
347
|
+
}
|
348
|
+
EOS
|
349
|
+
|
350
|
+
proc { TehUnknown::MyResult.parse(buf) }.should raise_error(ProtocolBuffers::DecodeError)
|
351
|
+
end
|
352
|
+
|
353
|
+
it "enforces valid values on deserialization" do
|
354
|
+
ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
|
355
|
+
package tehUnknown;
|
356
|
+
message MyResult {
|
357
|
+
optional int32 field_1 = 1;
|
358
|
+
}
|
359
|
+
EOS
|
360
|
+
|
361
|
+
res1 = TehUnknown::MyResult.new(:field_1 => 5)
|
362
|
+
buf = res1.to_s
|
363
|
+
|
364
|
+
ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
|
365
|
+
package tehUnknown;
|
366
|
+
message MyResult {
|
367
|
+
enum E { A = 1; }
|
368
|
+
optional E field_1 = 1;
|
369
|
+
}
|
370
|
+
EOS
|
371
|
+
|
372
|
+
proc { TehUnknown::MyResult.parse(buf) }.should raise_error(ProtocolBuffers::DecodeError)
|
373
|
+
end
|
374
|
+
|
375
|
+
it "ignores and passes on unknown fields" do
|
376
|
+
ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
|
377
|
+
package tehUnknown;
|
378
|
+
message MyResult {
|
379
|
+
optional int32 field_1 = 1;
|
380
|
+
optional int32 field_2 = 2;
|
381
|
+
optional int32 field_3 = 3;
|
382
|
+
optional int32 field_4 = 4;
|
383
|
+
}
|
384
|
+
EOS
|
385
|
+
|
386
|
+
res1 = TehUnknown::MyResult.new(:field_1 => 0xffff, :field_2 => 0xfffe,
|
387
|
+
:field_3 => 0xfffd, :field_4 => 0xfffc)
|
388
|
+
serialized = res1.to_s
|
389
|
+
|
390
|
+
# remove field_2 to pretend we never knew about it
|
391
|
+
ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
|
392
|
+
package tehUnknown;
|
393
|
+
message MyResult {
|
394
|
+
optional int32 field_1 = 1;
|
395
|
+
optional int32 field_3 = 3;
|
396
|
+
}
|
397
|
+
EOS
|
398
|
+
|
399
|
+
res2 = nil
|
400
|
+
proc do
|
401
|
+
res2 = TehUnknown::MyResult.parse(serialized)
|
402
|
+
end.should_not raise_error()
|
403
|
+
|
404
|
+
res2.field_1.should == 0xffff
|
405
|
+
res2.field_3.should == 0xfffd
|
406
|
+
|
407
|
+
proc do
|
408
|
+
res2.field_2.should == 0xfffe
|
409
|
+
end.should raise_error(NoMethodError)
|
410
|
+
|
411
|
+
serialized2 = res2.to_s
|
412
|
+
|
413
|
+
# now we know about field_2 again
|
414
|
+
ProtocolBuffers::Compiler.compile_and_load_string <<-EOS
|
415
|
+
package tehUnknown;
|
416
|
+
message MyResult {
|
417
|
+
optional int32 field_1 = 1;
|
418
|
+
optional int32 field_2 = 2;
|
419
|
+
optional int32 field_4 = 4;
|
420
|
+
}
|
421
|
+
EOS
|
422
|
+
|
423
|
+
res3 = TehUnknown::MyResult.parse(serialized2)
|
424
|
+
res3.field_1.should == 0xffff
|
425
|
+
|
426
|
+
res3.field_2.should == 0xfffe
|
427
|
+
res3.field_4.should == 0xfffc
|
428
|
+
end
|
429
|
+
|
430
|
+
end
|