msgpack 0.5.10-java

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,73 @@
1
+ # encoding: utf-8
2
+
3
+ if RUBY_PLATFORM.include?('java')
4
+ # JRuby should use this library, MRI should use the standard gem
5
+ $: << File.expand_path('../../../lib', __FILE__)
6
+ end
7
+
8
+ require 'viiite'
9
+ require 'msgpack'
10
+ require 'json'
11
+ require 'bson'
12
+
13
+ if RUBY_PLATFORM.include?('java')
14
+ BSON_IMPL = BSON::BSON_JAVA
15
+ else
16
+ BSON_IMPL = BSON::BSON_C
17
+ end
18
+
19
+ OBJECT_STRUCTURE = {'x' => ['y', 34, 2**30 + 3, 2.1223423423356, {'hello' => 'world', '5' => [63, 'asjdl']}]}
20
+ ENCODED_MSGPACK = "\x81\xA1x\x95\xA1y\"\xCE@\x00\x00\x03\xCB@\x00\xFA\x8E\x9F9\xFA\xC1\x82\xA5hello\xA5world\xA15\x92?\xA5asjdl"
21
+ ENCODED_BSON = "d\x00\x00\x00\x04x\x00\\\x00\x00\x00\x020\x00\x02\x00\x00\x00y\x00\x101\x00\"\x00\x00\x00\x102\x00\x03\x00\x00@\x013\x00\xC1\xFA9\x9F\x8E\xFA\x00@\x034\x002\x00\x00\x00\x02hello\x00\x06\x00\x00\x00world\x00\x045\x00\x19\x00\x00\x00\x100\x00?\x00\x00\x00\x021\x00\x06\x00\x00\x00asjdl\x00\x00\x00\x00\x00"
22
+ ENCODED_JSON = '{"x":["y",34,1073741827,2.1223423423356,{"hello":"world","5":[63,"asjdl"]}]}'
23
+ ITERATIONS = 1_00_000
24
+ IMPLEMENTATIONS = ENV.fetch('IMPLEMENTATIONS', 'json,bson,msgpack').split(',').map(&:to_sym)
25
+
26
+ Viiite.bm do |b|
27
+ b.variation_point :ruby, Viiite.which_ruby
28
+
29
+ IMPLEMENTATIONS.each do |lib|
30
+ b.variation_point :lib, lib
31
+
32
+
33
+ b.report(:pack) do
34
+ ITERATIONS.times do
35
+ case lib
36
+ when :msgpack then MessagePack.pack(OBJECT_STRUCTURE)
37
+ when :bson then BSON_IMPL.serialize(OBJECT_STRUCTURE).to_s
38
+ when :json then OBJECT_STRUCTURE.to_json
39
+ end
40
+ end
41
+ end
42
+
43
+ b.report(:unpack) do
44
+ ITERATIONS.times do
45
+ case lib
46
+ when :msgpack then MessagePack.unpack(ENCODED_MSGPACK)
47
+ when :bson then BSON_IMPL.deserialize(ENCODED_BSON)
48
+ when :json then JSON.parse(ENCODED_JSON)
49
+ end
50
+ end
51
+ end
52
+
53
+ b.report(:pack_unpack) do
54
+ ITERATIONS.times do
55
+ case lib
56
+ when :msgpack then MessagePack.unpack(MessagePack.pack(OBJECT_STRUCTURE))
57
+ when :bson then BSON_IMPL.deserialize(BSON_IMPL.serialize(OBJECT_STRUCTURE).to_s)
58
+ when :json then JSON.parse(OBJECT_STRUCTURE.to_json)
59
+ end
60
+ end
61
+ end
62
+
63
+ b.report(:unpack_pack) do
64
+ ITERATIONS.times do
65
+ case lib
66
+ when :msgpack then MessagePack.pack(MessagePack.unpack(ENCODED_MSGPACK))
67
+ when :bson then BSON_IMPL.serialize(BSON_IMPL.deserialize(ENCODED_BSON)).to_s
68
+ when :json then OBJECT_STRUCTURE.to_json(JSON.parse(ENCODED_JSON))
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,25 @@
1
+ # encoding: utf-8
2
+
3
+ $: << File.expand_path('../../../lib', __FILE__)
4
+
5
+ require 'viiite'
6
+ require 'msgpack'
7
+
8
+
9
+ iterations = 10_000
10
+ data = MessagePack.pack(:hello => 'world', :nested => ['structure', {:value => 42}])
11
+
12
+ Viiite.bm do |b|
13
+ b.report(:strings) do
14
+ iterations.times do
15
+ MessagePack.unpack(data)
16
+ end
17
+ end
18
+
19
+ b.report(:symbols) do
20
+ options = {:symbolize_keys => true}
21
+ iterations.times do
22
+ MessagePack.unpack(data, options)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,290 @@
1
+ # encoding: ascii-8bit
2
+
3
+ require 'stringio'
4
+ require 'tempfile'
5
+ require 'spec_helper'
6
+
7
+
8
+ describe ::MessagePack::Unpacker do
9
+ def flatten(struct, results = [])
10
+ case struct
11
+ when Array
12
+ struct.each { |v| flatten(v, results) }
13
+ when Hash
14
+ struct.each { |k, v| flatten(v, flatten(k, results)) }
15
+ else
16
+ results << struct
17
+ end
18
+ results
19
+ end
20
+
21
+ subject do
22
+ described_class.new
23
+ end
24
+
25
+ let :buffer1 do
26
+ MessagePack.pack(:foo => 'bar')
27
+ end
28
+
29
+ let :buffer2 do
30
+ MessagePack.pack(:hello => {:world => [1, 2, 3]})
31
+ end
32
+
33
+ let :buffer3 do
34
+ MessagePack.pack(:x => 'y')
35
+ end
36
+
37
+ describe '#execute/#execute_limit/#finished?' do
38
+ let :buffer do
39
+ buffer1 + buffer2 + buffer3
40
+ end
41
+
42
+ it 'extracts an object from the buffer' do
43
+ subject.execute(buffer, 0)
44
+ subject.data.should == {'foo' => 'bar'}
45
+ end
46
+
47
+ it 'extracts an object from the buffer, starting at an offset' do
48
+ subject.execute(buffer, buffer1.length)
49
+ subject.data.should == {'hello' => {'world' => [1, 2, 3]}}
50
+ end
51
+
52
+ it 'extracts an object from the buffer, starting at an offset reading bytes up to a limit' do
53
+ subject.execute_limit(buffer, buffer1.length, buffer2.length)
54
+ subject.data.should == {'hello' => {'world' => [1, 2, 3]}}
55
+ end
56
+
57
+ it 'extracts nothing if the limit cuts an object in half' do
58
+ subject.execute_limit(buffer, buffer1.length, 3)
59
+ subject.data.should be_nil
60
+ end
61
+
62
+ it 'returns the offset where the object ended' do
63
+ subject.execute(buffer, 0).should == buffer1.length
64
+ subject.execute(buffer, buffer1.length).should == buffer1.length + buffer2.length
65
+ end
66
+
67
+ it 'is finished if #data returns an object' do
68
+ subject.execute_limit(buffer, buffer1.length, buffer2.length)
69
+ subject.should be_finished
70
+
71
+ subject.execute_limit(buffer, buffer1.length, 3)
72
+ subject.should_not be_finished
73
+ end
74
+ end
75
+
76
+ describe '#each' do
77
+ context 'with a buffer' do
78
+ it 'yields each object in the buffer' do
79
+ objects = []
80
+ subject.feed(buffer1)
81
+ subject.feed(buffer2)
82
+ subject.feed(buffer3)
83
+ subject.each do |obj|
84
+ objects << obj
85
+ end
86
+ objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}]
87
+ end
88
+
89
+ it 'returns an enumerator when no block is given' do
90
+ subject.feed(buffer1)
91
+ subject.feed(buffer2)
92
+ subject.feed(buffer3)
93
+ enum = subject.each
94
+ enum.map { |obj| obj.keys.first }.should == %w[foo hello x]
95
+ end
96
+ end
97
+
98
+ context 'with a StringIO stream' do
99
+ it 'yields each object in the stream' do
100
+ objects = []
101
+ subject.stream = StringIO.new(buffer1 + buffer2 + buffer3)
102
+ subject.each do |obj|
103
+ objects << obj
104
+ end
105
+ objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}]
106
+ end
107
+ end
108
+
109
+ context 'with a File stream' do
110
+ it 'yields each object in the stream' do
111
+ objects = []
112
+ file = Tempfile.new('msgpack')
113
+ file.write(buffer1)
114
+ file.write(buffer2)
115
+ file.write(buffer3)
116
+ file.open
117
+ subject.stream = file
118
+ subject.each do |obj|
119
+ objects << obj
120
+ end
121
+ objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}]
122
+ end
123
+ end
124
+
125
+ context 'with a stream passed to the constructor' do
126
+ it 'yields each object in the stream' do
127
+ objects = []
128
+ unpacker = described_class.new(StringIO.new(buffer1 + buffer2 + buffer3))
129
+ unpacker.each do |obj|
130
+ objects << obj
131
+ end
132
+ objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}]
133
+ end
134
+ end
135
+ end
136
+
137
+ describe '#feed_each' do
138
+ it 'feeds the buffer then runs #each' do
139
+ objects = []
140
+ subject.feed_each(buffer1 + buffer2 + buffer3) do |obj|
141
+ objects << obj
142
+ end
143
+ objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}]
144
+ end
145
+
146
+ it 'handles chunked data' do
147
+ objects = []
148
+ buffer = buffer1 + buffer2 + buffer3
149
+ buffer.chars.each do |ch|
150
+ subject.feed_each(ch) do |obj|
151
+ objects << obj
152
+ end
153
+ end
154
+ objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}]
155
+ end
156
+ end
157
+
158
+ describe '#fill' do
159
+ it 'is a no-op' do
160
+ subject.stream = StringIO.new(buffer1 + buffer2 + buffer3)
161
+ subject.fill
162
+ subject.each { |obj| }
163
+ end
164
+ end
165
+
166
+ describe '#reset' do
167
+ context 'with a buffer' do
168
+ it 'is unclear what it is supposed to do'
169
+ end
170
+
171
+ context 'with a stream' do
172
+ it 'is unclear what it is supposed to do'
173
+ end
174
+ end
175
+
176
+ context 'regressions' do
177
+ it 'handles massive arrays (issue #2)' do
178
+ array = ['foo'] * 10_000
179
+ MessagePack.unpack(MessagePack.pack(array)).should have(10_000).items
180
+ end
181
+ end
182
+
183
+ context 'encoding', :encodings do
184
+ before :all do
185
+ @default_internal = Encoding.default_internal
186
+ @default_external = Encoding.default_external
187
+ end
188
+
189
+ after :all do
190
+ Encoding.default_internal = @default_internal
191
+ Encoding.default_external = @default_external
192
+ end
193
+
194
+ let :buffer do
195
+ MessagePack.pack({'hello' => 'world', 'nested' => ['object', {"sk\xC3\xA5l".force_encoding('utf-8') => true}]})
196
+ end
197
+
198
+ let :unpacker do
199
+ described_class.new
200
+ end
201
+
202
+ before do
203
+ Encoding.default_internal = Encoding::UTF_8
204
+ Encoding.default_external = Encoding::ISO_8859_1
205
+ end
206
+
207
+ it 'produces results with default internal encoding' do
208
+ unpacker.execute(buffer, 0)
209
+ strings = flatten(unpacker.data).grep(String)
210
+ strings.map(&:encoding).uniq.should == [Encoding.default_internal]
211
+ end
212
+
213
+ it 'recodes to internal encoding' do
214
+ unpacker.execute(buffer, 0)
215
+ unpacker.data['nested'][1].keys.should == ["sk\xC3\xA5l".force_encoding(Encoding.default_internal)]
216
+ end
217
+ end
218
+
219
+ context 'extensions' do
220
+ context 'symbolized keys' do
221
+ let :buffer do
222
+ MessagePack.pack({'hello' => 'world', 'nested' => ['object', {'structure' => true}]})
223
+ end
224
+
225
+ let :unpacker do
226
+ described_class.new(:symbolize_keys => true)
227
+ end
228
+
229
+ it 'can symbolize keys when using #execute' do
230
+ unpacker.execute(buffer, 0)
231
+ unpacker.data.should == {:hello => 'world', :nested => ['object', {:structure => true}]}
232
+ end
233
+
234
+ it 'can symbolize keys when using #each' do
235
+ objs = []
236
+ unpacker.feed(buffer)
237
+ unpacker.each do |obj|
238
+ objs << obj
239
+ end
240
+ objs.should == [{:hello => 'world', :nested => ['object', {:structure => true}]}]
241
+ end
242
+
243
+ it 'can symbolize keys when using #feed_each' do
244
+ objs = []
245
+ unpacker.feed_each(buffer) do |obj|
246
+ objs << obj
247
+ end
248
+ objs.should == [{:hello => 'world', :nested => ['object', {:structure => true}]}]
249
+ end
250
+ end
251
+
252
+ context 'encoding', :encodings do
253
+ let :buffer do
254
+ MessagePack.pack({'hello' => 'world', 'nested' => ['object', {'structure' => true}]})
255
+ end
256
+
257
+ let :unpacker do
258
+ described_class.new(:encoding => 'UTF-8')
259
+ end
260
+
261
+ it 'can hardcode encoding when using #execute' do
262
+ unpacker.execute(buffer, 0)
263
+ strings = flatten(unpacker.data).grep(String)
264
+ strings.should == %w[hello world nested object structure]
265
+ strings.map(&:encoding).uniq.should == [Encoding::UTF_8]
266
+ end
267
+
268
+ it 'can hardcode encoding when using #each' do
269
+ objs = []
270
+ unpacker.feed(buffer)
271
+ unpacker.each do |obj|
272
+ objs << obj
273
+ end
274
+ strings = flatten(objs).grep(String)
275
+ strings.should == %w[hello world nested object structure]
276
+ strings.map(&:encoding).uniq.should == [Encoding::UTF_8]
277
+ end
278
+
279
+ it 'can hardcode encoding when using #feed_each' do
280
+ objs = []
281
+ unpacker.feed_each(buffer) do |obj|
282
+ objs << obj
283
+ end
284
+ strings = flatten(objs).grep(String)
285
+ strings.should == %w[hello world nested object structure]
286
+ strings.map(&:encoding).uniq.should == [Encoding::UTF_8]
287
+ end
288
+ end
289
+ end
290
+ end
@@ -0,0 +1,136 @@
1
+ # encoding: ascii-8bit
2
+
3
+ require 'spec_helper'
4
+
5
+ def utf8enc(str)
6
+ str.encode('UTF-8')
7
+ end
8
+
9
+ def asciienc(str)
10
+ str.encode('ASCII-8BIT')
11
+ end
12
+
13
+ describe MessagePack do
14
+ tests = {
15
+ 'constant values' => [
16
+ ['true', true, "\xC3"],
17
+ ['false', false, "\xC2"],
18
+ ['nil', nil, "\xC0"]
19
+ ],
20
+ 'numbers' => [
21
+ ['zero', 0, "\x00"],
22
+ ['127', 127, "\x7F"],
23
+ ['128', 128, "\xCC\x80"],
24
+ ['256', 256, "\xCD\x01\x00"],
25
+ ['-1', -1, "\xFF"],
26
+ ['-33', -33, "\xD0\xDF"],
27
+ ['-129', -129, "\xD1\xFF\x7F"],
28
+ ['small integers', 42, "*"],
29
+ ['medium integers', 333, "\xCD\x01M"],
30
+ ['large integers', 2**31 - 1, "\xCE\x7F\xFF\xFF\xFF"],
31
+ ['huge integers', 2**64 - 1, "\xCF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"],
32
+ ['negative integers', -1, "\xFF"],
33
+ ['1.0', 1.0, "\xcb\x3f\xf0\x00\x00\x00\x00\x00\x00"],
34
+ ['small floats', 3.14, "\xCB@\t\x1E\xB8Q\xEB\x85\x1F"],
35
+ ['big floats', Math::PI * 1_000_000_000_000_000_000, "\xCBC\xC5\xCC\x96\xEF\xD1\x19%"],
36
+ ['negative floats', -2.1, "\xCB\xC0\x00\xCC\xCC\xCC\xCC\xCC\xCD"]
37
+ ],
38
+ 'strings' => [
39
+ ['strings', utf8enc('hello world'), "\xABhello world"],
40
+ ['empty strings', utf8enc(''), "\xA0"]
41
+ ],
42
+ 'arrays' => [
43
+ ['empty arrays', [], "\x90"],
44
+ ['arrays with strings', [utf8enc("hello"), utf8enc("world")], "\x92\xA5hello\xA5world"],
45
+ ['arrays with mixed values', [utf8enc("hello"), utf8enc("world"), 42], "\x93\xA5hello\xA5world*"],
46
+ ['arrays of arrays', [[[[1, 2], 3], 4]], "\x91\x92\x92\x92\x01\x02\x03\x04"],
47
+ ['empty arrays', [], "\x90"]
48
+ ],
49
+ 'hashes' => [
50
+ ['empty hashes', {}, "\x80"],
51
+ ['hashes', {utf8enc('foo') => utf8enc('bar')}, "\x81\xA3foo\xA3bar"],
52
+ ['hashes with mixed keys and values', {utf8enc('foo') => utf8enc('bar'), 3 => utf8enc('three'), utf8enc('four') => 4, utf8enc('x') => [utf8enc('y')], utf8enc('a') => utf8enc('b')}, "\x85\xA3foo\xA3bar\x03\xA5three\xA4four\x04\xA1x\x91\xA1y\xA1a\xA1b"],
53
+ ['hashes of hashes', {{utf8enc('x') => {utf8enc('y') => utf8enc('z')}} => utf8enc('s')}, "\x81\x81\xA1x\x81\xA1y\xA1z\xA1s"],
54
+ ['hashes with nils', {utf8enc('foo') => nil}, "\x81\xA3foo\xC0"]
55
+ ]
56
+ }
57
+
58
+ tests.each do |ctx, its|
59
+ context("with #{ctx}") do
60
+ its.each do |desc, unpacked, packed|
61
+ it("encodes #{desc}") do
62
+ MessagePack.pack(unpacked).should == packed
63
+ end
64
+
65
+ it "decodes #{desc}" do
66
+ MessagePack.unpack(packed).should == unpacked
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ context 'using other names for .pack and .unpack' do
73
+ it 'can unpack with .load' do
74
+ MessagePack.load("\xABhello world").should == 'hello world'
75
+ end
76
+
77
+ it 'can pack with .dump' do
78
+ MessagePack.dump(utf8enc('hello world')).should == "\xABhello world"
79
+ end
80
+ end
81
+
82
+ context 'with symbols' do
83
+ it 'encodes symbols as strings' do
84
+ MessagePack.pack(:symbol).should == "\xA6symbol"
85
+ end
86
+ end
87
+
88
+ context 'with different external encoding', :encodings do
89
+ before do
90
+ @default_external = Encoding.default_external
91
+ @default_internal = Encoding.default_internal
92
+ Encoding.default_external = Encoding::UTF_8
93
+ Encoding.default_internal = Encoding::ISO_8859_1
94
+ end
95
+
96
+ after do
97
+ Encoding.default_external = @default_external
98
+ Encoding.default_internal = @default_internal
99
+ end
100
+
101
+ it 'transcodes strings when encoding' do
102
+ input = "sk\xE5l".force_encoding(Encoding::ISO_8859_1)
103
+ MessagePack.pack(input).should == "\xA5sk\xC3\xA5l"
104
+ end
105
+ end
106
+
107
+ context 'with other things' do
108
+ it 'raises an error on #pack with an unsupported type' do
109
+ expect { MessagePack.pack(self) }.to raise_error(ArgumentError, /^Cannot pack type:/)
110
+ end
111
+
112
+ it 'rasies an error on #unpack with garbage' do
113
+ skip "???"
114
+ expect { MessagePack.unpack('asdka;sd') }.to raise_error(MessagePack::UnpackError)
115
+ end
116
+ end
117
+
118
+ context 'extensions' do
119
+ it 'can unpack hashes with symbolized keys' do
120
+ packed = MessagePack.pack({'hello' => 'world', 'nested' => ['object', {'structure' => true}]})
121
+ unpacked = MessagePack.unpack(packed, :symbolize_keys => true)
122
+ unpacked.should == {:hello => 'world', :nested => ['object', {:structure => true}]}
123
+ end
124
+
125
+ it 'can unpack strings with a specified encoding', :encodings do
126
+ packed = MessagePack.pack({utf8enc('hello') => utf8enc('world')})
127
+ unpacked = MessagePack.unpack(packed)
128
+ unpacked['hello'].encoding.should == Encoding::UTF_8
129
+ end
130
+
131
+ it 'can pack strings with a specified encoding', :encodings do
132
+ packed = MessagePack.pack({'hello' => "w\xE5rld".force_encoding(Encoding::ISO_8859_1)})
133
+ packed.index("w\xC3\xA5rld").should_not be_nil
134
+ end
135
+ end
136
+ end