chrisk-protopuffs 0.2.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.
@@ -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