chrisk-protopuffs 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,98 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class MessageBaseTest < Test::Unit::TestCase
4
+
5
+ context ".define_message_class using 'Person' and two fields" do
6
+ should "create a Message::Person class" do
7
+ fields = [Protopuffs::MessageField.new("optional", "string", "name", 1),
8
+ Protopuffs::MessageField.new("optional", "string", "address", 2)]
9
+ Protopuffs::Message::Base.define_message_class("Person", fields)
10
+ Protopuffs::Message::Person
11
+ end
12
+
13
+ should "create a class with accessors for each field" do
14
+ fields = [Protopuffs::MessageField.new("optional", "string", "name", 1),
15
+ Protopuffs::MessageField.new("optional", "string", "address", 2)]
16
+ Protopuffs::Message::Base.define_message_class("Person", fields)
17
+ person = Protopuffs::Message::Person.new
18
+ person.name = "Chris"
19
+ person.address = "61 Carmelita St."
20
+ assert_equal person.name, "Chris"
21
+ assert_equal person.address, "61 Carmelita St."
22
+ end
23
+ end
24
+
25
+
26
+ context ".define_message_class with fields that have duplicate tags" do
27
+ should "raise a Protopuffs::ParseError" do
28
+ fields = [Protopuffs::MessageField.new("optional", "int32", "name", 1),
29
+ Protopuffs::MessageField.new("optional", "string", "address", 1)]
30
+ assert_raises Protopuffs::ParseError do
31
+ Protopuffs::Message::Base.define_message_class("Person", fields)
32
+ end
33
+ end
34
+ end
35
+
36
+
37
+ context ".define_message_class with fields that have invalid tags" do
38
+ should "raise a Protopuffs::ParseError when a tag is too large" do
39
+ fields = [Protopuffs::MessageField.new("optional", "int32", "name", 1),
40
+ Protopuffs::MessageField.new("optional", "string", "address", 536_870_912)]
41
+ assert_raises Protopuffs::ParseError do
42
+ Protopuffs::Message::Base.define_message_class("Person", fields)
43
+ end
44
+ end
45
+
46
+ should "raise a Protopuffs::ParseError when a tag is too small" do
47
+ fields = [Protopuffs::MessageField.new("optional", "int32", "name", 0),
48
+ Protopuffs::MessageField.new("optional", "string", "address", 1)]
49
+ assert_raises Protopuffs::ParseError do
50
+ Protopuffs::Message::Base.define_message_class("Person", fields)
51
+ end
52
+ end
53
+
54
+ should "raise a Protopuffs::ParseError when a tag is reserved" do
55
+ fields = [Protopuffs::MessageField.new("optional", "string", "name", 19050)]
56
+ assert_raises Protopuffs::ParseError do
57
+ Protopuffs::Message::Base.define_message_class("Person", fields)
58
+ end
59
+ end
60
+ end
61
+
62
+
63
+ should "not allow you to instantiate Message::Base directly" do
64
+ assert_raises RuntimeError do
65
+ Protopuffs::Message::Base.new
66
+ end
67
+ end
68
+
69
+
70
+ context "comparing messages with #==" do
71
+ should "return false when the messages have different types" do
72
+ Protopuffs::Message::Base.define_message_class("Dog", [])
73
+ Protopuffs::Message::Base.define_message_class("Cat", [])
74
+ assert_not_equal Protopuffs::Message::Dog.new, Protopuffs::Message::Cat.new
75
+ end
76
+
77
+ should "return false when the messages' fields have different values" do
78
+ fields = [Protopuffs::MessageField.new("optional", "string", "name", 1)]
79
+ Protopuffs::Message::Base.define_message_class("Person", fields)
80
+ alice = Protopuffs::Message::Person.new
81
+ alice.name = "Alice"
82
+ bob = Protopuffs::Message::Person.new
83
+ bob.name = "Bob"
84
+ assert_not_equal alice, bob
85
+ end
86
+
87
+ should "return true when messages of the same type have the same field values" do
88
+ fields = [Protopuffs::MessageField.new("optional", "string", "name", 1)]
89
+ Protopuffs::Message::Base.define_message_class("Sheep", fields)
90
+ sheep = Protopuffs::Message::Sheep.new
91
+ sheep.name = "Dolly"
92
+ sheep2 = Protopuffs::Message::Sheep.new
93
+ sheep2.name = "Dolly"
94
+ assert_equal sheep, sheep2
95
+ end
96
+ end
97
+
98
+ end
@@ -0,0 +1,34 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class MessageFieldTest < Test::Unit::TestCase
4
+
5
+ context "creating a MessageField" do
6
+ should "set a string's default to '' when a default isn't specified" do
7
+ field = Protopuffs::MessageField.new("optional", "string", "name", 1)
8
+ assert_equal "", field.default
9
+ end
10
+
11
+ should "set a numeric's default to 0 when a default isn't specified" do
12
+ numeric_types = %w(double float int32 int64 uint32 unit64 sint32 sint64
13
+ fixed32 fixed64 sfixed32 sfixed64)
14
+ numeric_types.each do |type|
15
+ assert_equal 0, Protopuffs::MessageField.new("optional", type, "number", 1).default
16
+ end
17
+ end
18
+
19
+ should "set a bool's default to false when a default isn't specified" do
20
+ field = Protopuffs::MessageField.new("optional", "bool", "opt_in", 1)
21
+ assert_same false, field.default
22
+ end
23
+
24
+ should "set the default to 'Matz' when that default is specified" do
25
+ field = Protopuffs::MessageField.new("optional", "string", "name", 1, "Matz")
26
+ assert_equal "Matz", field.default
27
+ end
28
+ end
29
+
30
+ should_return_wire_type_for_fields_typed 0 => %w(int32 int64 uint32 uint64 bool),
31
+ 1 => %w(double fixed64),
32
+ 2 => %w(bytes string TestMessage),
33
+ 5 => %w(float fixed32)
34
+ end
@@ -0,0 +1,206 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class ParseTreeTest < Test::Unit::TestCase
4
+
5
+ context "a protocol buffer descriptor" do
6
+ setup do
7
+ @parser = Protopuffs::Parser::ProtocolBufferDescriptor.new
8
+ end
9
+
10
+ context "with an empty Person message" do
11
+ setup do
12
+ @proto = @parser.parse("message Person {}")
13
+ end
14
+
15
+ should "have one message" do
16
+ assert_equal 1, @proto.messages.size
17
+ end
18
+
19
+ should "have a message named Person" do
20
+ assert_equal "Person", @proto.messages.first.name
21
+ end
22
+
23
+ should "have an empty body" do
24
+ assert @proto.messages.first.body.empty?
25
+ end
26
+ end
27
+
28
+ context "with two empty messages Apple and Orange" do
29
+ setup do
30
+ @descriptor = <<-proto
31
+ message Apple {}
32
+ message Orange {}
33
+ proto
34
+ end
35
+
36
+ should "have two messages" do
37
+ proto = @parser.parse(@descriptor)
38
+ assert_equal 2, proto.messages.size
39
+ end
40
+
41
+ should "have messages named Apple and Orange" do
42
+ proto = @parser.parse(@descriptor)
43
+ assert_equal %w(Apple Orange), proto.messages.map { |m| m.name }.sort
44
+ end
45
+
46
+ should "have messages with empty bodes" do
47
+ proto = @parser.parse(@descriptor)
48
+ assert proto.messages.all? { |m| m.body.empty? }
49
+ end
50
+ end
51
+
52
+ context "a proto with a Person message including a name field" do
53
+ setup do
54
+ @descriptor = <<-proto
55
+ message Person {
56
+ required string name = 1;
57
+ }
58
+ proto
59
+ end
60
+
61
+ should "have one message named person" do
62
+ proto = @parser.parse(@descriptor)
63
+ assert_equal 1, proto.messages.size
64
+ assert_equal "Person", proto.messages.first.name
65
+ end
66
+
67
+ should "have one required string field called name with tag 1" do
68
+ proto = @parser.parse(@descriptor)
69
+ fields = proto.messages.first.body.fields
70
+ assert_equal 1, fields.size
71
+ assert_equal "required", fields.first.modifier.text_value
72
+ assert_equal "string", fields.first.type.text_value
73
+ assert_equal "name", fields.first.identifier.text_value
74
+ assert_equal "1", fields.first.integer.text_value
75
+ end
76
+ end
77
+
78
+ context "with a Person message including three fields" do
79
+ setup do
80
+ @descriptor = <<-proto
81
+ message Person {
82
+ required string name = 1;
83
+ required int32 id = 2;
84
+ optional string email = 3;
85
+ }
86
+ proto
87
+ end
88
+
89
+ should "have one message named person" do
90
+ proto = @parser.parse(@descriptor)
91
+ assert_equal 1, proto.messages.size
92
+ assert_equal "Person", proto.messages.first.name
93
+ end
94
+
95
+ should "have three fields with correct components" do
96
+ proto = @parser.parse(@descriptor)
97
+ fields = proto.messages.first.body.fields
98
+ assert_equal 3, fields.size
99
+ actual = fields.map { |f| [f.modifier, f.type, f.identifier, f.integer].map { |el| el.text_value } }
100
+ expected = [ %w(required string name 1),
101
+ %w(required int32 id 2),
102
+ %w(optional string email 3) ]
103
+ assert_equal expected, actual
104
+ end
105
+ end
106
+
107
+ context "with a Person message including two fields with defaults and one without" do
108
+ setup do
109
+ @proto = @parser.parse(<<-proto)
110
+ message Person {
111
+ required string name = 1;
112
+ optional string language = 2 [default = "en"];
113
+ optional int32 account_code = 3 [default = 0];
114
+ }
115
+ proto
116
+ end
117
+
118
+ should "have one message named person" do
119
+ assert_equal 1, @proto.messages.size
120
+ assert_equal "Person", @proto.messages.first.name
121
+ end
122
+
123
+ should "have three fields with correct components" do
124
+ fields = @proto.messages.first.body.fields
125
+ assert_equal 3, fields.size
126
+ actual = fields.map { |f| [f.modifier, f.type, f.identifier, f.integer, f.default] }
127
+ actual.map! { |f| f.map! { |el| el.respond_to?(:text_value) ? el.text_value : el } }
128
+ expected = [ ["required", "string", "name", "1", nil],
129
+ ["optional", "string", "language", "2", "en"],
130
+ ["optional", "int32", "account_code", "3", 0] ]
131
+ assert_equal expected, actual
132
+ end
133
+ end
134
+
135
+ context "with a message including lots of comments" do
136
+ setup do
137
+ @proto = @parser.parse(<<-proto)
138
+ // test
139
+ //test
140
+ message Person { //test // test
141
+ // test
142
+ required string name = 1; // test
143
+ // optional string language = 2 [default = "en"];
144
+ optional int32 account_code = 3 [default = 0]; // test
145
+ // test
146
+ } // test
147
+ // test
148
+ //test
149
+ proto
150
+ end
151
+
152
+ should "parse" do
153
+ assert_not_nil @proto
154
+ end
155
+
156
+ should "have uncommented fields with correct components" do
157
+ fields = @proto.messages.first.body.fields
158
+ assert_equal 2, fields.size
159
+ actual = fields.map { |f| [f.modifier, f.type, f.identifier, f.integer, f.default] }
160
+ actual.map! { |f| f.map! { |el| el.respond_to?(:text_value) ? el.text_value : el } }
161
+ expected = [ ["required", "string", "name", "1", nil],
162
+ ["optional", "int32", "account_code", "3", 0] ]
163
+ assert_equal expected, actual
164
+ end
165
+ end
166
+
167
+
168
+ context "with a message including a user-typed field" do
169
+ setup do
170
+ @proto = @parser.parse(<<-proto)
171
+ message Person {
172
+ required string name = 1;
173
+ repeated Address addresses = 2;
174
+ }
175
+ proto
176
+ end
177
+
178
+ should "parse" do
179
+ assert_not_nil @proto
180
+ end
181
+
182
+ should "have two fields with correct components" do
183
+ fields = @proto.messages.first.body.fields
184
+ assert_equal 2, fields.size
185
+ actual = fields.map { |f| [f.modifier, f.type, f.identifier, f.integer] }
186
+ actual.map! { |f| f.map! { |el| el.respond_to?(:text_value) ? el.text_value : el } }
187
+ expected = [ ["required", "string", "name", "1"],
188
+ ["repeated", "Address", "addresses", "2"] ]
189
+ assert_equal expected, actual
190
+ end
191
+ end
192
+
193
+
194
+ should "raise a ParseError when parsing a message with a syntax error" do
195
+ assert_raises Protopuffs::ParseError do
196
+ @parser.parse(<<-proto)
197
+ message Person {
198
+ required name = 1
199
+ }
200
+ proto
201
+ end
202
+ end
203
+
204
+ end
205
+
206
+ end
@@ -0,0 +1,36 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class ProtopuffsTest < Test::Unit::TestCase
4
+
5
+ context ".proto_load_path accessors" do
6
+ setup { Protopuffs.proto_load_path = [] }
7
+
8
+ should "have an accessor for an array of load paths for .proto files" do
9
+ Protopuffs.proto_load_path << "proto_files" << "other_proto_files"
10
+ assert_equal ["proto_files", "other_proto_files"], Protopuffs.proto_load_path
11
+ end
12
+
13
+ should "have a mutator for directly assigning the load paths" do
14
+ Protopuffs.proto_load_path = ["my_proto_files"]
15
+ assert_equal ["my_proto_files"], Protopuffs.proto_load_path
16
+ end
17
+ end
18
+
19
+ should "have a ParseError class" do
20
+ Protopuffs::ParseError
21
+ end
22
+
23
+
24
+ context ".load_message_classes when a descriptor is in the load path with a Person message" do
25
+ setup { Protopuffs.proto_load_path = ["#{File.dirname(__FILE__)}/fixtures/proto"] }
26
+
27
+ should "create a Person message class with correct accessors" do
28
+ Protopuffs.load_message_classes
29
+ p = Protopuffs::Message::Person.new
30
+ p.name = "Chris"
31
+ p.id = 42
32
+ p.email = "chris@kampers.net"
33
+ assert_equal ["Chris", 42, "chris@kampers.net"], [p.name, p.id, p.email]
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,71 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+ require 'mocha'
5
+ require 'treetop'
6
+
7
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
8
+ require 'protopuffs'
9
+
10
+ class Test::Unit::TestCase
11
+
12
+ # helper for debugging
13
+ def print_bytes(string)
14
+ puts
15
+ string.each_byte do |byte|
16
+ printf("%1$08b (%1$02X)\n", byte)
17
+ end
18
+ end
19
+
20
+ # helper for generating test names
21
+ def self.inspect_bytes(bytes_array)
22
+ "[#{bytes_array.map { |b| sprintf("%02X", b) }.join(' ')}]"
23
+ end
24
+
25
+
26
+ def self.should_encode_wire_format_from_fields(expected_bytes, actual_fields)
27
+ should "encode the fields #{actual_fields.inspect} to the byte string #{inspect_bytes(expected_bytes)}" do
28
+ actual_fields.each_pair do |name, value|
29
+ value = value.call if value.respond_to?(:call)
30
+ @message.send("#{name}=", value)
31
+ end
32
+ actual_bytes = @message.to_wire_format.unpack('C*')
33
+ assert_equal expected_bytes, actual_bytes
34
+ end
35
+ end
36
+
37
+ def self.should_decode_wire_format_to_fields(actual_bytes, expected_fields)
38
+ should "decode the byte string #{inspect_bytes(actual_bytes)} to the fields #{expected_fields.inspect}" do
39
+ buffer = StringIO.new(actual_bytes.pack('C*'))
40
+ @message.from_wire_format(buffer)
41
+ actual_fields = @message.class.fields.inject({}) { |hash, field|
42
+ hash[field.identifier.to_sym] = @message.send(field.identifier)
43
+ hash
44
+ }
45
+
46
+ expected_fields.each_pair do |key, expected_value|
47
+ expected_value = expected_value.call if expected_value.respond_to?(:call)
48
+ if expected_value.is_a?(Float)
49
+ assert_in_delta(expected_value, actual_fields[key], Float::EPSILON)
50
+ else
51
+ assert_equal expected_value, actual_fields[key]
52
+ end
53
+ end
54
+
55
+ assert_equal expected_fields.size, actual_fields.size
56
+ end
57
+ end
58
+
59
+
60
+ def self.should_return_wire_type_for_fields_typed(wire_types)
61
+ wire_types.each_pair do |wire_type, names|
62
+ names.each do |name|
63
+ should "return wire type #{wire_type} for a field with type #{name}" do
64
+ assert_equal wire_type, Protopuffs::MessageField.new("required", name, "a", 1).wire_type
65
+ end
66
+ end
67
+ end
68
+ end
69
+
70
+ end
71
+
@@ -0,0 +1,231 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class WireFormatTest < Test::Unit::TestCase
4
+
5
+ context "a message with one int32 field tagged #1" do
6
+ # from http://code.google.com/apis/protocolbuffers/docs/encoding.html#simple
7
+ setup do
8
+ fields = [Protopuffs::MessageField.new("required", "int32", "a", 1)]
9
+ Protopuffs::Message::Base.define_message_class("Test1", fields)
10
+ @message = Protopuffs::Message::Test1.new
11
+ end
12
+
13
+ should_encode_wire_format_from_fields [0x08, 0x96, 0x01], :a => 150
14
+ should_decode_wire_format_to_fields [0x08, 0x96, 0x01], :a => 150
15
+
16
+ # should ignore unknown fields: this message also has an int32 tagged #2 with value 157,372
17
+ should_decode_wire_format_to_fields [0x08, 0x96, 0x01, 0x10, 0xBC, 0xCD, 0x09], :a => 150
18
+ end
19
+
20
+
21
+ context "a message with two int32 fields tagged #1 and #2" do
22
+ setup do
23
+ fields = [Protopuffs::MessageField.new("required", "int32", "a", 1),
24
+ Protopuffs::MessageField.new("required", "int32", "b", 2)]
25
+ Protopuffs::Message::Base.define_message_class("Test1", fields)
26
+ @message = Protopuffs::Message::Test1.new
27
+ end
28
+
29
+ should_encode_wire_format_from_fields [0x08, 0x96, 0x01, 0x10, 0xBC, 0xCD, 0x09],
30
+ :a => 150, :b => 157_372
31
+ should_decode_wire_format_to_fields [0x08, 0x96, 0x01, 0x10, 0xBC, 0xCD, 0x09],
32
+ :a => 150, :b => 157_372
33
+ end
34
+
35
+
36
+ context "a message with one int64 field tagged #1" do
37
+ setup do
38
+ fields = [Protopuffs::MessageField.new("required", "int64", "a", 1)]
39
+ Protopuffs::Message::Base.define_message_class("Test1", fields)
40
+ @message = Protopuffs::Message::Test1.new
41
+ end
42
+
43
+ should_encode_wire_format_from_fields [0x08, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x02],
44
+ :a => 2**50
45
+ should_decode_wire_format_to_fields [0x08, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x02],
46
+ :a => 2**50
47
+ end
48
+
49
+
50
+ context "a message with one uint32 field tagged #1 and one uint64 field tagged #2" do
51
+ setup do
52
+ fields = [Protopuffs::MessageField.new("required", "uint32", "a", 1),
53
+ Protopuffs::MessageField.new("required", "uint64", "b", 2)]
54
+ Protopuffs::Message::Base.define_message_class("Test1", fields)
55
+ @message = Protopuffs::Message::Test1.new
56
+ end
57
+
58
+ should_encode_wire_format_from_fields [0x08, 0x90, 0x07, 0x10, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x20],
59
+ :a => 912, :b => 2**54
60
+ should_decode_wire_format_to_fields [0x08, 0x90, 0x07, 0x10, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x20],
61
+ :a => 912, :b => 2**54
62
+ end
63
+
64
+
65
+ context "a message with two bool fields tagged #1 and #2" do
66
+ setup do
67
+ fields = [Protopuffs::MessageField.new("required", "bool", "a", 1),
68
+ Protopuffs::MessageField.new("required", "bool", "b", 2)]
69
+ Protopuffs::Message::Base.define_message_class("Test1", fields)
70
+ @message = Protopuffs::Message::Test1.new
71
+ end
72
+
73
+ should_encode_wire_format_from_fields [0x08, 0x00, 0x10, 0x01],
74
+ :a => false, :b => true
75
+ should_decode_wire_format_to_fields [0x08, 0x00, 0x10, 0x01],
76
+ :a => false, :b => true
77
+ end
78
+
79
+
80
+ context "a message with one string field tagged #2" do
81
+ setup do
82
+ # from http://code.google.com/apis/protocolbuffers/docs/encoding.html#types
83
+ fields = [Protopuffs::MessageField.new("required", "string", "b", 2)]
84
+ Protopuffs::Message::Base.define_message_class("Test2", fields)
85
+ @message = Protopuffs::Message::Test2.new
86
+ end
87
+
88
+ should_encode_wire_format_from_fields [0x12, 0x07, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6E, 0x67],
89
+ :b => "testing"
90
+ should_decode_wire_format_to_fields [0x12, 0x07, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6E, 0x67],
91
+ :b => "testing"
92
+ end
93
+
94
+
95
+ context "a message with a bytes field tagged #1" do
96
+ setup do
97
+ fields = [Protopuffs::MessageField.new("required", "bytes", "a", 1)]
98
+ Protopuffs::Message::Base.define_message_class("Test1", fields)
99
+ @message = Protopuffs::Message::Test1.new
100
+ end
101
+
102
+ should_encode_wire_format_from_fields [0x0A, 0x04, 0xDE, 0xCA, 0xFB, 0xAD],
103
+ :a => [0xDE, 0xCA, 0xFB, 0xAD].pack('C*')
104
+ should_decode_wire_format_to_fields [0x0A, 0x04, 0xDE, 0xCA, 0xFB, 0xAD],
105
+ :a => [0xDE, 0xCA, 0xFB, 0xAD].pack('C*')
106
+ end
107
+
108
+
109
+ context "a message with one float field tagged #1" do
110
+ setup do
111
+ fields = [Protopuffs::MessageField.new("required", "float", "a", 1)]
112
+ Protopuffs::Message::Base.define_message_class("Test1", fields)
113
+ @message = Protopuffs::Message::Test1.new
114
+ end
115
+
116
+ # 1.61803 gives you repeating binary digits when encoded, so the number
117
+ # you get from decoding is different (within Float::EPSILON)
118
+ should_encode_wire_format_from_fields [0x0D, 0x9B, 0x1B, 0xCF, 0x3F],
119
+ :a => 1.61803
120
+ should_decode_wire_format_to_fields [0x0D, 0x9B, 0x1B, 0xCF, 0x3F],
121
+ :a => 1.6180299520492554
122
+ end
123
+
124
+
125
+ context "a message with one double field tagged #1" do
126
+ setup do
127
+ fields = [Protopuffs::MessageField.new("required", "double", "a", 1)]
128
+ Protopuffs::Message::Base.define_message_class("Test1", fields)
129
+ @message = Protopuffs::Message::Test1.new
130
+ end
131
+
132
+ # 64-bit doubles have enough precision to encode/decode 1.61803,
133
+ # unlike the 32-bit floats above
134
+ should_encode_wire_format_from_fields [0x09, 0x6C, 0x26, 0xDF, 0x6C, 0x73, 0xE3, 0xF9, 0x3F],
135
+ :a => 1.61803
136
+ should_decode_wire_format_to_fields [0x09, 0x6C, 0x26, 0xDF, 0x6C, 0x73, 0xE3, 0xF9, 0x3F],
137
+ :a => 1.61803
138
+ end
139
+
140
+
141
+ context "a message with one fixed64 field tagged #1" do
142
+ setup do
143
+ fields = [Protopuffs::MessageField.new("required", "fixed64", "a", 1)]
144
+ Protopuffs::Message::Base.define_message_class("Test1", fields)
145
+ @message = Protopuffs::Message::Test1.new
146
+ end
147
+
148
+ should_encode_wire_format_from_fields [0x09, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F],
149
+ :a => 2**62 - 15
150
+ should_decode_wire_format_to_fields [0x09, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F],
151
+ :a => 2**62 - 15
152
+
153
+ end
154
+
155
+
156
+ context "a message with one fixed32 field tagged #1" do
157
+ setup do
158
+ fields = [Protopuffs::MessageField.new("required", "fixed32", "a", 1)]
159
+ Protopuffs::Message::Base.define_message_class("Test1", fields)
160
+ @message = Protopuffs::Message::Test1.new
161
+ end
162
+
163
+ should_encode_wire_format_from_fields [0x0D, 0xFE, 0xFF, 0xFF, 0xFF],
164
+ :a => 2**32 - 2
165
+ should_decode_wire_format_to_fields [0x0D, 0xFE, 0xFF, 0xFF, 0xFF],
166
+ :a => 2**32 - 2
167
+ end
168
+
169
+
170
+ context "a message with one repeating int32 field tagged #1" do
171
+ setup do
172
+ fields = [Protopuffs::MessageField.new("repeated", "int32", "a", 1)]
173
+ Protopuffs::Message::Base.define_message_class("Test1", fields)
174
+ @message = Protopuffs::Message::Test1.new
175
+ end
176
+
177
+ should_encode_wire_format_from_fields [0x08, 0x96, 0x01, 0x08, 0xBC, 0xCD, 0x09, 0x08, 0x3D],
178
+ :a => [150, 157_372, 61]
179
+ should_decode_wire_format_to_fields [0x08, 0x96, 0x01, 0x08, 0xBC, 0xCD, 0x09, 0x08, 0x3D],
180
+ :a => [150, 157_372, 61]
181
+ end
182
+
183
+
184
+ context "a message with one embedded-message field Test1 tagged #3 (where Test1 has an int32 field tagged #1)" do
185
+ # from http://code.google.com/apis/protocolbuffers/docs/encoding.html#embedded
186
+ setup do
187
+ test1_fields = [Protopuffs::MessageField.new("required", "int32", "a", 1)]
188
+ Protopuffs::Message::Base.define_message_class("Test1", test1_fields)
189
+
190
+ test3_fields = [Protopuffs::MessageField.new("required", "Test1", "c", 3)]
191
+ Protopuffs::Message::Base.define_message_class("Test3", test3_fields)
192
+ @message = Protopuffs::Message::Test3.new
193
+ end
194
+
195
+ should_encode_wire_format_from_fields [0x1A, 0x03, 0x08, 0x96, 0x01],
196
+ :c => lambda { msg = Protopuffs::Message::Test1.new; msg.a = 150; msg }
197
+ should_decode_wire_format_to_fields [0x1A, 0x03, 0x08, 0x96, 0x01],
198
+ :c => lambda { msg = Protopuffs::Message::Test1.new; msg.a = 150; msg }
199
+ end
200
+
201
+
202
+ context "a message with two int32 fields tagged #1 (optional, default=150) and #2 (required)" do
203
+ setup do
204
+ fields = [Protopuffs::MessageField.new("optional", "int32", "a", 1, 150),
205
+ Protopuffs::MessageField.new("required", "int32", "b", 2)]
206
+ Protopuffs::Message::Base.define_message_class("Test1", fields)
207
+ @message = Protopuffs::Message::Test1.new
208
+ end
209
+
210
+ should_encode_wire_format_from_fields [0x10, 0xBC, 0xCD, 0x09],
211
+ :b => 157_372
212
+ should_decode_wire_format_to_fields [0x10, 0xBC, 0xCD, 0x09],
213
+ :a => 150, :b => 157_372
214
+ end
215
+
216
+
217
+ context "a message with two int32 fields tagged #1 (optional, no default) and #2 (required)" do
218
+ setup do
219
+ fields = [Protopuffs::MessageField.new("optional", "int32", "a", 1),
220
+ Protopuffs::MessageField.new("required", "int32", "b", 2)]
221
+ Protopuffs::Message::Base.define_message_class("Test1", fields)
222
+ @message = Protopuffs::Message::Test1.new
223
+ end
224
+
225
+ should_encode_wire_format_from_fields [0x10, 0xBC, 0xCD, 0x09],
226
+ :b => 157_372
227
+ should_decode_wire_format_to_fields [0x10, 0xBC, 0xCD, 0x09],
228
+ :a => 0, :b => 157_372
229
+ end
230
+
231
+ end