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.
- checksums.yaml +7 -0
- data/lib/msgpack.rb +13 -0
- data/lib/msgpack/msgpack.jar +0 -0
- data/lib/msgpack/version.rb +3 -0
- data/spec/cases.json +1 -0
- data/spec/cases.msg +0 -0
- data/spec/cases_compact.msg +0 -0
- data/spec/cases_spec.rb +39 -0
- data/spec/cruby/buffer_io_spec.rb +256 -0
- data/spec/cruby/buffer_packer.rb +29 -0
- data/spec/cruby/buffer_spec.rb +572 -0
- data/spec/cruby/buffer_unpacker.rb +19 -0
- data/spec/cruby/packer_spec.rb +120 -0
- data/spec/cruby/unpacker_spec.rb +299 -0
- data/spec/format_spec.rb +227 -0
- data/spec/jruby/benchmarks/shootout_bm.rb +73 -0
- data/spec/jruby/benchmarks/symbolize_keys_bm.rb +25 -0
- data/spec/jruby/msgpack/unpacker_spec.rb +290 -0
- data/spec/jruby/msgpack_spec.rb +136 -0
- data/spec/pack_spec.rb +67 -0
- data/spec/random_compat.rb +24 -0
- data/spec/spec_helper.rb +27 -0
- data/spec/unpack_spec.rb +72 -0
- metadata +172 -0
@@ -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
|