msgpack 1.4.2 → 1.7.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog +85 -0
  3. data/README.md +52 -1
  4. data/ext/java/org/msgpack/jruby/Buffer.java +26 -19
  5. data/ext/java/org/msgpack/jruby/Decoder.java +29 -21
  6. data/ext/java/org/msgpack/jruby/Encoder.java +68 -30
  7. data/ext/java/org/msgpack/jruby/ExtensionRegistry.java +43 -64
  8. data/ext/java/org/msgpack/jruby/ExtensionValue.java +6 -9
  9. data/ext/java/org/msgpack/jruby/Factory.java +43 -42
  10. data/ext/java/org/msgpack/jruby/Packer.java +37 -40
  11. data/ext/java/org/msgpack/jruby/Unpacker.java +80 -73
  12. data/ext/msgpack/buffer.c +54 -74
  13. data/ext/msgpack/buffer.h +21 -18
  14. data/ext/msgpack/buffer_class.c +161 -52
  15. data/ext/msgpack/buffer_class.h +1 -0
  16. data/ext/msgpack/compat.h +0 -99
  17. data/ext/msgpack/extconf.rb +25 -46
  18. data/ext/msgpack/factory_class.c +143 -87
  19. data/ext/msgpack/packer.c +66 -43
  20. data/ext/msgpack/packer.h +25 -20
  21. data/ext/msgpack/packer_class.c +102 -130
  22. data/ext/msgpack/packer_class.h +11 -0
  23. data/ext/msgpack/packer_ext_registry.c +35 -40
  24. data/ext/msgpack/packer_ext_registry.h +41 -38
  25. data/ext/msgpack/rbinit.c +1 -1
  26. data/ext/msgpack/rmem.c +3 -4
  27. data/ext/msgpack/sysdep.h +5 -2
  28. data/ext/msgpack/unpacker.c +126 -108
  29. data/ext/msgpack/unpacker.h +16 -13
  30. data/ext/msgpack/unpacker_class.c +86 -126
  31. data/ext/msgpack/unpacker_class.h +11 -0
  32. data/ext/msgpack/unpacker_ext_registry.c +40 -28
  33. data/ext/msgpack/unpacker_ext_registry.h +21 -18
  34. data/lib/msgpack/bigint.rb +69 -0
  35. data/lib/msgpack/buffer.rb +9 -0
  36. data/lib/msgpack/factory.rb +140 -10
  37. data/lib/msgpack/packer.rb +10 -1
  38. data/lib/msgpack/symbol.rb +21 -4
  39. data/lib/msgpack/time.rb +1 -1
  40. data/lib/msgpack/unpacker.rb +14 -1
  41. data/lib/msgpack/version.rb +1 -1
  42. data/lib/msgpack.rb +6 -7
  43. data/msgpack.gemspec +8 -5
  44. metadata +37 -82
  45. data/.gitignore +0 -23
  46. data/.rubocop.yml +0 -36
  47. data/.travis.yml +0 -39
  48. data/Gemfile +0 -9
  49. data/Rakefile +0 -71
  50. data/appveyor.yml +0 -18
  51. data/bench/pack.rb +0 -23
  52. data/bench/pack_log.rb +0 -33
  53. data/bench/pack_log_long.rb +0 -65
  54. data/bench/pack_symbols.rb +0 -28
  55. data/bench/run.sh +0 -14
  56. data/bench/run_long.sh +0 -35
  57. data/bench/run_symbols.sh +0 -26
  58. data/bench/unpack.rb +0 -21
  59. data/bench/unpack_log.rb +0 -34
  60. data/bench/unpack_log_long.rb +0 -67
  61. data/doclib/msgpack/buffer.rb +0 -193
  62. data/doclib/msgpack/core_ext.rb +0 -101
  63. data/doclib/msgpack/error.rb +0 -19
  64. data/doclib/msgpack/extension_value.rb +0 -9
  65. data/doclib/msgpack/factory.rb +0 -101
  66. data/doclib/msgpack/packer.rb +0 -208
  67. data/doclib/msgpack/time.rb +0 -22
  68. data/doclib/msgpack/timestamp.rb +0 -44
  69. data/doclib/msgpack/unpacker.rb +0 -183
  70. data/doclib/msgpack.rb +0 -87
  71. data/msgpack.org.md +0 -46
  72. data/spec/cases.json +0 -1
  73. data/spec/cases.msg +0 -0
  74. data/spec/cases_compact.msg +0 -0
  75. data/spec/cases_spec.rb +0 -39
  76. data/spec/cruby/buffer_io_spec.rb +0 -255
  77. data/spec/cruby/buffer_packer.rb +0 -29
  78. data/spec/cruby/buffer_spec.rb +0 -575
  79. data/spec/cruby/buffer_unpacker.rb +0 -19
  80. data/spec/cruby/unpacker_spec.rb +0 -70
  81. data/spec/ext_value_spec.rb +0 -99
  82. data/spec/exttypes.rb +0 -51
  83. data/spec/factory_spec.rb +0 -367
  84. data/spec/format_spec.rb +0 -301
  85. data/spec/jruby/benchmarks/shootout_bm.rb +0 -73
  86. data/spec/jruby/benchmarks/symbolize_keys_bm.rb +0 -25
  87. data/spec/jruby/unpacker_spec.rb +0 -186
  88. data/spec/msgpack_spec.rb +0 -214
  89. data/spec/pack_spec.rb +0 -61
  90. data/spec/packer_spec.rb +0 -557
  91. data/spec/random_compat.rb +0 -24
  92. data/spec/spec_helper.rb +0 -55
  93. data/spec/timestamp_spec.rb +0 -121
  94. data/spec/unpack_spec.rb +0 -57
  95. data/spec/unpacker_spec.rb +0 -819
@@ -1,819 +0,0 @@
1
- # encoding: ascii-8bit
2
-
3
- require 'stringio'
4
- require 'tempfile'
5
- require 'zlib'
6
-
7
- require 'spec_helper'
8
-
9
- describe MessagePack::Unpacker do
10
- let :unpacker do
11
- MessagePack::Unpacker.new
12
- end
13
-
14
- let :packer do
15
- MessagePack::Packer.new
16
- end
17
-
18
- it 'gets options to specify how to unpack values' do
19
- u1 = MessagePack::Unpacker.new
20
- u1.symbolize_keys?.should == false
21
- u1.freeze?.should == false
22
- u1.allow_unknown_ext?.should == false
23
-
24
- u2 = MessagePack::Unpacker.new(symbolize_keys: true, freeze: true, allow_unknown_ext: true)
25
- u2.symbolize_keys?.should == true
26
- u2.freeze?.should == true
27
- u2.allow_unknown_ext?.should == true
28
- end
29
-
30
- if automatic_string_keys_deduplication?
31
- it 'ensure string hash keys are deduplicated' do
32
- sample_data = [{"foo" => 1}, {"foo" => 2}]
33
- sample_packed = MessagePack.pack(sample_data).force_encoding('ASCII-8BIT')
34
- unpacker.feed(sample_packed)
35
- hashes = nil
36
- unpacker.each { |obj| hashes = obj }
37
- expect(hashes[0].keys.first).to equal(hashes[1].keys.first)
38
- end
39
- end
40
-
41
- it 'gets IO or object which has #read to read data from it' do
42
- sample_data = {"message" => "morning!", "num" => 1}
43
- sample_packed = MessagePack.pack(sample_data).force_encoding('ASCII-8BIT')
44
-
45
- Tempfile.open("for_io") do |file|
46
- file.sync = true
47
- file.write sample_packed
48
- file.rewind
49
-
50
- u1 = MessagePack::Unpacker.new(file)
51
- u1.each do |obj|
52
- expect(obj).to eql(sample_data)
53
- end
54
- file.unlink
55
- end
56
-
57
- sio = StringIO.new(sample_packed)
58
- u2 = MessagePack::Unpacker.new(sio)
59
- u2.each do |obj|
60
- expect(obj).to eql(sample_data)
61
- end
62
-
63
- dio = StringIO.new
64
- Zlib::GzipWriter.wrap(dio){|gz| gz.write sample_packed }
65
- reader = Zlib::GzipReader.new(StringIO.new(dio.string))
66
- u3 = MessagePack::Unpacker.new(reader)
67
- u3.each do |obj|
68
- expect(obj).to eql(sample_data)
69
- end
70
-
71
- class DummyIO
72
- def initialize
73
- @buf = "".force_encoding('ASCII-8BIT')
74
- @pos = 0
75
- end
76
- def write(val)
77
- @buf << val.to_s
78
- end
79
- def read(length=nil,outbuf="")
80
- if @pos == @buf.size
81
- nil
82
- elsif length.nil?
83
- val = @buf[@pos..(@buf.size)]
84
- @pos = @buf.size
85
- outbuf << val
86
- outbuf
87
- else
88
- val = @buf[@pos..(@pos + length)]
89
- @pos += val.size
90
- @pos = @buf.size if @pos > @buf.size
91
- outbuf << val
92
- outbuf
93
- end
94
- end
95
- def flush
96
- # nop
97
- end
98
- end
99
-
100
- dio = DummyIO.new
101
- dio.write sample_packed
102
- u4 = MessagePack::Unpacker.new(dio)
103
- u4.each do |obj|
104
- expect(obj).to eql(sample_data)
105
- end
106
- end
107
-
108
- it 'read_array_header succeeds' do
109
- unpacker.feed("\x91")
110
- unpacker.read_array_header.should == 1
111
- end
112
-
113
- it 'read_array_header fails' do
114
- unpacker.feed("\x81")
115
- lambda {
116
- unpacker.read_array_header
117
- }.should raise_error(MessagePack::TypeError) # TypeError is included in UnexpectedTypeError
118
- lambda {
119
- unpacker.read_array_header
120
- }.should raise_error(MessagePack::UnexpectedTypeError)
121
- end
122
-
123
- it 'read_map_header converts an map to key-value sequence' do
124
- packer.write_array_header(2)
125
- packer.write("e")
126
- packer.write(1)
127
- unpacker = MessagePack::Unpacker.new
128
- unpacker.feed(packer.to_s)
129
- unpacker.read_array_header.should == 2
130
- unpacker.read.should == "e"
131
- unpacker.read.should == 1
132
- end
133
-
134
- it 'read_map_header succeeds' do
135
- unpacker.feed("\x81")
136
- unpacker.read_map_header.should == 1
137
- end
138
-
139
- it 'read_map_header converts an map to key-value sequence' do
140
- packer.write_map_header(1)
141
- packer.write("k")
142
- packer.write("v")
143
- unpacker = MessagePack::Unpacker.new
144
- unpacker.feed(packer.to_s)
145
- unpacker.read_map_header.should == 1
146
- unpacker.read.should == "k"
147
- unpacker.read.should == "v"
148
- end
149
-
150
- it 'read_map_header fails' do
151
- unpacker.feed("\x91")
152
- lambda {
153
- unpacker.read_map_header
154
- }.should raise_error(MessagePack::TypeError) # TypeError is included in UnexpectedTypeError
155
- lambda {
156
- unpacker.read_map_header
157
- }.should raise_error(MessagePack::UnexpectedTypeError)
158
- end
159
-
160
- it 'read raises EOFError before feeding' do
161
- lambda {
162
- unpacker.read
163
- }.should raise_error(EOFError)
164
- end
165
-
166
- let :sample_object do
167
- [1024, {["a","b"]=>["c","d"]}, ["e","f"], "d", 70000, 4.12, 1.5, 1.5, 1.5]
168
- end
169
-
170
- it 'feed and each continue internal state' do
171
- raw = sample_object.to_msgpack.to_s * 4
172
- objects = []
173
-
174
- raw.split(//).each do |b|
175
- unpacker.feed(b)
176
- unpacker.each {|c|
177
- objects << c
178
- }
179
- end
180
-
181
- objects.should == [sample_object] * 4
182
- end
183
-
184
- it 'feed_each continues internal state' do
185
- raw = sample_object.to_msgpack.to_s * 4
186
- objects = []
187
-
188
- raw.split(//).each do |b|
189
- unpacker.feed_each(b) {|c|
190
- objects << c
191
- }
192
- end
193
-
194
- objects.should == [sample_object] * 4
195
- end
196
-
197
- it 'feed_each enumerator' do
198
- raw = sample_object.to_msgpack.to_s * 4
199
-
200
- enum = unpacker.feed_each(raw)
201
- enum.should be_instance_of(Enumerator)
202
- enum.to_a.should == [sample_object] * 4
203
- end
204
-
205
- it 'reset clears internal buffer' do
206
- # 1-element array
207
- unpacker.feed("\x91")
208
- unpacker.reset
209
- unpacker.feed("\x01")
210
-
211
- unpacker.each.map {|x| x }.should == [1]
212
- end
213
-
214
- it 'reset clears internal state' do
215
- # 1-element array
216
- unpacker.feed("\x91")
217
- unpacker.each.map {|x| x }.should == []
218
-
219
- unpacker.reset
220
-
221
- unpacker.feed("\x01")
222
- unpacker.each.map {|x| x }.should == [1]
223
- end
224
-
225
- it 'frozen short strings' do
226
- raw = sample_object.to_msgpack.to_s.force_encoding('UTF-8')
227
- lambda {
228
- unpacker.feed_each(raw.freeze) { }
229
- }.should_not raise_error
230
- end
231
-
232
- it 'frozen long strings' do
233
- raw = (sample_object.to_msgpack.to_s * 10240).force_encoding('UTF-8')
234
- lambda {
235
- unpacker.feed_each(raw.freeze) { }
236
- }.should_not raise_error
237
- end
238
-
239
- it 'read raises invalid byte error' do
240
- unpacker.feed("\xc1")
241
- lambda {
242
- unpacker.read
243
- }.should raise_error(MessagePack::MalformedFormatError)
244
- end
245
-
246
- it "gc mark" do
247
- raw = sample_object.to_msgpack.to_s * 4
248
-
249
- n = 0
250
- raw.split(//).each do |b|
251
- GC.start
252
- unpacker.feed_each(b) {|o|
253
- GC.start
254
- o.should == sample_object
255
- n += 1
256
- }
257
- GC.start
258
- end
259
-
260
- n.should == 4
261
- end
262
-
263
- it "buffer" do
264
- orig = "a"*32*1024*4
265
- raw = orig.to_msgpack.to_s
266
-
267
- n = 655
268
- times = raw.size / n
269
- times += 1 unless raw.size % n == 0
270
-
271
- off = 0
272
- parsed = false
273
-
274
- times.times do
275
- parsed.should == false
276
-
277
- seg = raw[off, n]
278
- off += seg.length
279
-
280
- unpacker.feed_each(seg) {|obj|
281
- parsed.should == false
282
- obj.should == orig
283
- parsed = true
284
- }
285
- end
286
-
287
- parsed.should == true
288
- end
289
-
290
- it 'MessagePack.unpack symbolize_keys' do
291
- symbolized_hash = {:a => 'b', :c => 'd'}
292
- MessagePack.load(MessagePack.pack(symbolized_hash), :symbolize_keys => true).should == symbolized_hash
293
- MessagePack.unpack(MessagePack.pack(symbolized_hash), :symbolize_keys => true).should == symbolized_hash
294
- end
295
-
296
- it 'Unpacker#unpack symbolize_keys' do
297
- unpacker = MessagePack::Unpacker.new(:symbolize_keys => true)
298
- symbolized_hash = {:a => 'b', :c => 'd'}
299
- unpacker.feed(MessagePack.pack(symbolized_hash)).read.should == symbolized_hash
300
- end
301
-
302
- it "msgpack str 8 type" do
303
- MessagePack.unpack([0xd9, 0x00].pack('C*')).should == ""
304
- MessagePack.unpack([0xd9, 0x00].pack('C*')).encoding.should == Encoding::UTF_8
305
- MessagePack.unpack([0xd9, 0x01].pack('C*') + 'a').should == "a"
306
- MessagePack.unpack([0xd9, 0x02].pack('C*') + 'aa').should == "aa"
307
- end
308
-
309
- it "msgpack str 16 type" do
310
- MessagePack.unpack([0xda, 0x00, 0x00].pack('C*')).should == ""
311
- MessagePack.unpack([0xda, 0x00, 0x00].pack('C*')).encoding.should == Encoding::UTF_8
312
- MessagePack.unpack([0xda, 0x00, 0x01].pack('C*') + 'a').should == "a"
313
- MessagePack.unpack([0xda, 0x00, 0x02].pack('C*') + 'aa').should == "aa"
314
- end
315
-
316
- it "msgpack str 32 type" do
317
- MessagePack.unpack([0xdb, 0x00, 0x00, 0x00, 0x00].pack('C*')).should == ""
318
- MessagePack.unpack([0xdb, 0x00, 0x00, 0x00, 0x00].pack('C*')).encoding.should == Encoding::UTF_8
319
- MessagePack.unpack([0xdb, 0x00, 0x00, 0x00, 0x01].pack('C*') + 'a').should == "a"
320
- MessagePack.unpack([0xdb, 0x00, 0x00, 0x00, 0x02].pack('C*') + 'aa').should == "aa"
321
- end
322
-
323
- it "msgpack bin 8 type" do
324
- MessagePack.unpack([0xc4, 0x00].pack('C*')).should == ""
325
- MessagePack.unpack([0xc4, 0x00].pack('C*')).encoding.should == Encoding::ASCII_8BIT
326
- MessagePack.unpack([0xc4, 0x01].pack('C*') + 'a').should == "a"
327
- MessagePack.unpack([0xc4, 0x02].pack('C*') + 'aa').should == "aa"
328
- end
329
-
330
- it "msgpack bin 16 type" do
331
- MessagePack.unpack([0xc5, 0x00, 0x00].pack('C*')).should == ""
332
- MessagePack.unpack([0xc5, 0x00, 0x00].pack('C*')).encoding.should == Encoding::ASCII_8BIT
333
- MessagePack.unpack([0xc5, 0x00, 0x01].pack('C*') + 'a').should == "a"
334
- MessagePack.unpack([0xc5, 0x00, 0x02].pack('C*') + 'aa').should == "aa"
335
- end
336
-
337
- it "msgpack bin 32 type" do
338
- MessagePack.unpack([0xc6, 0x00, 0x00, 0x00, 0x00].pack('C*')).should == ""
339
- MessagePack.unpack([0xc6, 0x0, 0x00, 0x00, 0x000].pack('C*')).encoding.should == Encoding::ASCII_8BIT
340
- MessagePack.unpack([0xc6, 0x00, 0x00, 0x00, 0x01].pack('C*') + 'a').should == "a"
341
- MessagePack.unpack([0xc6, 0x00, 0x00, 0x00, 0x02].pack('C*') + 'aa').should == "aa"
342
- end
343
-
344
- describe "ext formats" do
345
- let(:unpacker) { MessagePack::Unpacker.new(allow_unknown_ext: true) }
346
-
347
- [1, 2, 4, 8, 16].zip([0xd4, 0xd5, 0xd6, 0xd7, 0xd8]).each do |n,b|
348
- it "msgpack fixext #{n} format" do
349
- unpacker.feed([b, 1].pack('CC') + "a"*n).unpack.should == MessagePack::ExtensionValue.new(1, "a"*n)
350
- unpacker.feed([b, -1].pack('CC') + "a"*n).unpack.should == MessagePack::ExtensionValue.new(-1, "a"*n)
351
- end
352
- end
353
-
354
- it "msgpack ext 8 format" do
355
- unpacker.feed([0xc7, 0, 1].pack('CCC')).unpack.should == MessagePack::ExtensionValue.new(1, "")
356
- unpacker.feed([0xc7, 255, -1].pack('CCC') + "a"*255).unpack.should == MessagePack::ExtensionValue.new(-1, "a"*255)
357
- end
358
-
359
- it "msgpack ext 16 format" do
360
- unpacker.feed([0xc8, 0, 1].pack('CnC')).unpack.should == MessagePack::ExtensionValue.new(1, "")
361
- unpacker.feed([0xc8, 256, -1].pack('CnC') + "a"*256).unpack.should == MessagePack::ExtensionValue.new(-1, "a"*256)
362
- end
363
-
364
- it "msgpack ext 32 format" do
365
- unpacker.feed([0xc9, 0, 1].pack('CNC')).unpack.should == MessagePack::ExtensionValue.new(1, "")
366
- unpacker.feed([0xc9, 256, -1].pack('CNC') + "a"*256).unpack.should == MessagePack::ExtensionValue.new(-1, "a"*256)
367
- unpacker.feed([0xc9, 65536, -1].pack('CNC') + "a"*65536).unpack.should == MessagePack::ExtensionValue.new(-1, "a"*65536)
368
- end
369
- end
370
-
371
- class ValueOne
372
- attr_reader :num
373
- def initialize(num)
374
- @num = num
375
- end
376
- def ==(obj)
377
- self.num == obj.num
378
- end
379
- def num
380
- @num
381
- end
382
- def to_msgpack_ext
383
- @num.to_msgpack
384
- end
385
- def self.from_msgpack_ext(data)
386
- self.new(MessagePack.unpack(data))
387
- end
388
- end
389
-
390
- class ValueTwo
391
- attr_reader :num_s
392
- def initialize(num)
393
- @num_s = num.to_s
394
- end
395
- def ==(obj)
396
- self.num_s == obj.num_s
397
- end
398
- def num
399
- @num_s.to_i
400
- end
401
- def to_msgpack_ext
402
- @num_s.to_msgpack
403
- end
404
- def self.from_msgpack_ext(data)
405
- self.new(MessagePack.unpack(data))
406
- end
407
- end
408
-
409
- describe '#type_registered?' do
410
- it 'receive Class or Integer, and return bool' do
411
- expect(subject.type_registered?(0x00)).to be_falsy
412
- expect(subject.type_registered?(0x01)).to be_falsy
413
- expect(subject.type_registered?(::ValueOne)).to be_falsy
414
- end
415
-
416
- it 'returns true if specified type or class is already registered' do
417
- subject.register_type(0x30, ::ValueOne, :from_msgpack_ext)
418
- subject.register_type(0x31, ::ValueTwo, :from_msgpack_ext)
419
-
420
- expect(subject.type_registered?(0x00)).to be_falsy
421
- expect(subject.type_registered?(0x01)).to be_falsy
422
-
423
- expect(subject.type_registered?(0x30)).to be_truthy
424
- expect(subject.type_registered?(0x31)).to be_truthy
425
- expect(subject.type_registered?(::ValueOne)).to be_truthy
426
- expect(subject.type_registered?(::ValueTwo)).to be_truthy
427
- end
428
-
429
- it 'cannot detect unpack rule with block, not method' do
430
- subject.register_type(0x40){|data| ValueOne.from_msgpack_ext(data) }
431
-
432
- expect(subject.type_registered?(0x40)).to be_truthy
433
- expect(subject.type_registered?(ValueOne)).to be_falsy
434
- end
435
- end
436
-
437
- context 'with ext definitions' do
438
- it 'get type and class mapping for packing' do
439
- unpacker = MessagePack::Unpacker.new
440
- unpacker.register_type(0x01){|data| ValueOne.from_msgpack_ext }
441
- unpacker.register_type(0x02){|data| ValueTwo.from_msgpack_ext(data) }
442
-
443
- unpacker = MessagePack::Unpacker.new
444
- unpacker.register_type(0x01, ValueOne, :from_msgpack_ext)
445
- unpacker.register_type(0x02, ValueTwo, :from_msgpack_ext)
446
- end
447
-
448
- it 'returns a Array of Hash which contains :type, :class and :unpacker' do
449
- unpacker = MessagePack::Unpacker.new
450
- unpacker.register_type(0x02, ValueTwo, :from_msgpack_ext)
451
- unpacker.register_type(0x01, ValueOne, :from_msgpack_ext)
452
-
453
- list = unpacker.registered_types
454
-
455
- expect(list).to be_a(Array)
456
- expect(list.size).to eq(2)
457
-
458
- one = list[0]
459
- expect(one.keys.sort).to eq([:type, :class, :unpacker].sort)
460
- expect(one[:type]).to eq(0x01)
461
- expect(one[:class]).to eq(ValueOne)
462
- expect(one[:unpacker]).to eq(:from_msgpack_ext)
463
-
464
- two = list[1]
465
- expect(two.keys.sort).to eq([:type, :class, :unpacker].sort)
466
- expect(two[:type]).to eq(0x02)
467
- expect(two[:class]).to eq(ValueTwo)
468
- expect(two[:unpacker]).to eq(:from_msgpack_ext)
469
- end
470
-
471
- it 'returns a Array of Hash, which contains nil for class if block unpacker specified' do
472
- unpacker = MessagePack::Unpacker.new
473
- unpacker.register_type(0x01){|data| ValueOne.from_msgpack_ext }
474
- unpacker.register_type(0x02, &ValueTwo.method(:from_msgpack_ext))
475
-
476
- list = unpacker.registered_types
477
-
478
- expect(list).to be_a(Array)
479
- expect(list.size).to eq(2)
480
-
481
- one = list[0]
482
- expect(one.keys.sort).to eq([:type, :class, :unpacker].sort)
483
- expect(one[:type]).to eq(0x01)
484
- expect(one[:class]).to be_nil
485
- expect(one[:unpacker]).to be_instance_of(Proc)
486
-
487
- two = list[1]
488
- expect(two.keys.sort).to eq([:type, :class, :unpacker].sort)
489
- expect(two[:type]).to eq(0x02)
490
- expect(two[:class]).to be_nil
491
- expect(two[:unpacker]).to be_instance_of(Proc)
492
- end
493
-
494
- describe "registering an ext type for a module" do
495
- subject { unpacker.feed("\xc7\x06\x00module").unpack }
496
-
497
- let(:unpacker) { MessagePack::Unpacker.new }
498
-
499
- before do
500
- mod = Module.new do
501
- def self.from_msgpack_ext(data)
502
- "unpacked #{data}"
503
- end
504
- end
505
- stub_const('Mod', mod)
506
- end
507
-
508
- before { unpacker.register_type(0x00, Mod, :from_msgpack_ext) }
509
- it { is_expected.to eq "unpacked module" }
510
- end
511
- end
512
-
513
- def flatten(struct, results = [])
514
- case struct
515
- when Array
516
- struct.each { |v| flatten(v, results) }
517
- when Hash
518
- struct.each { |k, v| flatten(v, flatten(k, results)) }
519
- else
520
- results << struct
521
- end
522
- results
523
- end
524
-
525
- subject do
526
- described_class.new
527
- end
528
-
529
- let :buffer1 do
530
- MessagePack.pack(:foo => 'bar')
531
- end
532
-
533
- let :buffer2 do
534
- MessagePack.pack(:hello => {:world => [1, 2, 3]})
535
- end
536
-
537
- let :buffer3 do
538
- MessagePack.pack(:x => 'y')
539
- end
540
-
541
- describe '#read' do
542
- context 'with a buffer' do
543
- it 'reads objects' do
544
- objects = []
545
- subject.feed(buffer1)
546
- subject.feed(buffer2)
547
- subject.feed(buffer3)
548
- objects << subject.read
549
- objects << subject.read
550
- objects << subject.read
551
- objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}]
552
- end
553
-
554
- it 'reads map header' do
555
- subject.feed({}.to_msgpack)
556
- subject.read_map_header.should == 0
557
- end
558
-
559
- it 'reads array header' do
560
- subject.feed([].to_msgpack)
561
- subject.read_array_header.should == 0
562
- end
563
- end
564
- end
565
-
566
- describe '#each' do
567
- context 'with a buffer' do
568
- it 'yields each object in the buffer' do
569
- objects = []
570
- subject.feed(buffer1)
571
- subject.feed(buffer2)
572
- subject.feed(buffer3)
573
- subject.each do |obj|
574
- objects << obj
575
- end
576
- objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}]
577
- end
578
-
579
- it 'returns an enumerator when no block is given' do
580
- subject.feed(buffer1)
581
- subject.feed(buffer2)
582
- subject.feed(buffer3)
583
- enum = subject.each
584
- enum.map { |obj| obj.keys.first }.should == %w[foo hello x]
585
- end
586
- end
587
-
588
- context 'with a stream passed to the constructor' do
589
- it 'yields each object in the stream' do
590
- objects = []
591
- unpacker = described_class.new(StringIO.new(buffer1 + buffer2 + buffer3))
592
- unpacker.each do |obj|
593
- objects << obj
594
- end
595
- objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}]
596
- end
597
- end
598
-
599
- context 'with a stream and symbolize_keys passed to the constructor' do
600
- it 'yields each object in the stream, with symbolized keys' do
601
- objects = []
602
- unpacker = described_class.new(StringIO.new(buffer1 + buffer2 + buffer3), symbolize_keys: true)
603
- unpacker.each do |obj|
604
- objects << obj
605
- end
606
- objects.should == [{:foo => 'bar'}, {:hello => {:world => [1, 2, 3]}}, {:x => 'y'}]
607
- end
608
- end
609
- end
610
-
611
- describe '#feed_each' do
612
- it 'feeds the buffer then runs #each' do
613
- objects = []
614
- subject.feed_each(buffer1 + buffer2 + buffer3) do |obj|
615
- objects << obj
616
- end
617
- objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}]
618
- end
619
-
620
- it 'handles chunked data' do
621
- objects = []
622
- buffer = buffer1 + buffer2 + buffer3
623
- buffer.chars.each do |ch|
624
- subject.feed_each(ch) do |obj|
625
- objects << obj
626
- end
627
- end
628
- objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}]
629
- end
630
- end
631
-
632
- context 'regressions' do
633
- it 'handles massive arrays (issue #2)' do
634
- array = ['foo'] * 10_000
635
- MessagePack.unpack(MessagePack.pack(array)).size.should == 10_000
636
- end
637
-
638
- it 'preserve string encoding (issue #200)' do
639
- string = 'a'.force_encoding(Encoding::UTF_8)
640
- MessagePack.unpack(MessagePack.pack(string)).encoding.should == string.encoding
641
-
642
- string *= 256
643
- MessagePack.unpack(MessagePack.pack(string)).encoding.should == string.encoding
644
- end
645
- end
646
-
647
- context 'extensions' do
648
- context 'symbolized keys' do
649
- let :buffer do
650
- MessagePack.pack({'hello' => 'world', 'nested' => ['object', {'structure' => true}]})
651
- end
652
-
653
- let :unpacker do
654
- described_class.new(:symbolize_keys => true)
655
- end
656
-
657
- it 'can symbolize keys when using #each' do
658
- objs = []
659
- unpacker.feed(buffer)
660
- unpacker.each do |obj|
661
- objs << obj
662
- end
663
- objs.should == [{:hello => 'world', :nested => ['object', {:structure => true}]}]
664
- end
665
-
666
- it 'can symbolize keys when using #feed_each' do
667
- objs = []
668
- unpacker.feed_each(buffer) do |obj|
669
- objs << obj
670
- end
671
- objs.should == [{:hello => 'world', :nested => ['object', {:structure => true}]}]
672
- end
673
- end
674
-
675
- context 'freeze' do
676
- let :struct do
677
- {'hello' => 'world', 'nested' => ['object', {'structure' => true}]}
678
- end
679
-
680
- let :buffer do
681
- MessagePack.pack(struct)
682
- end
683
-
684
- let :unpacker do
685
- described_class.new(:freeze => true)
686
- end
687
-
688
- it 'can freeze objects when using .unpack' do
689
- parsed_struct = MessagePack.unpack(buffer, freeze: true)
690
- parsed_struct.should == struct
691
-
692
- parsed_struct.should be_frozen
693
- parsed_struct['hello'].should be_frozen
694
- parsed_struct['nested'].should be_frozen
695
- parsed_struct['nested'][0].should be_frozen
696
- parsed_struct['nested'][1].should be_frozen
697
-
698
- if string_deduplication?
699
- parsed_struct.keys[0].should be_equal('hello'.freeze)
700
- parsed_struct.keys[1].should be_equal('nested'.freeze)
701
- parsed_struct.values[0].should be_equal('world'.freeze)
702
- parsed_struct.values[1][0].should be_equal('object'.freeze)
703
- parsed_struct.values[1][1].keys[0].should be_equal('structure'.freeze)
704
- end
705
- end
706
-
707
- it 'can freeze objects when using #each' do
708
- objs = []
709
- unpacker.feed(buffer)
710
- unpacker.each do |obj|
711
- objs << obj
712
- end
713
-
714
- parsed_struct = objs.first
715
- parsed_struct.should == struct
716
-
717
- parsed_struct.should be_frozen
718
- parsed_struct['hello'].should be_frozen
719
- parsed_struct['nested'].should be_frozen
720
- parsed_struct['nested'][0].should be_frozen
721
- parsed_struct['nested'][1].should be_frozen
722
-
723
- if string_deduplication?
724
- parsed_struct.keys[0].should be_equal('hello'.freeze)
725
- parsed_struct.keys[1].should be_equal('nested'.freeze)
726
- parsed_struct.values[0].should be_equal('world'.freeze)
727
- parsed_struct.values[1][0].should be_equal('object'.freeze)
728
- parsed_struct.values[1][1].keys[0].should be_equal('structure'.freeze)
729
- end
730
- end
731
-
732
- it 'can freeze objects when using #feed_each' do
733
- objs = []
734
- unpacker.feed_each(buffer) do |obj|
735
- objs << obj
736
- end
737
-
738
- parsed_struct = objs.first
739
- parsed_struct.should == struct
740
-
741
- parsed_struct.should be_frozen
742
- parsed_struct['hello'].should be_frozen
743
- parsed_struct['nested'].should be_frozen
744
- parsed_struct['nested'][0].should be_frozen
745
- parsed_struct['nested'][1].should be_frozen
746
-
747
- if string_deduplication?
748
- parsed_struct.keys[0].should be_equal('hello'.freeze)
749
- parsed_struct.keys[1].should be_equal('nested'.freeze)
750
- parsed_struct.values[0].should be_equal('world'.freeze)
751
- parsed_struct.values[1][0].should be_equal('object'.freeze)
752
- parsed_struct.values[1][1].keys[0].should be_equal('structure'.freeze)
753
- end
754
- end
755
- end
756
-
757
- context 'binary encoding', :encodings do
758
- let :buffer do
759
- MessagePack.pack({'hello' => 'world', 'nested' => ['object', {'structure' => true}]})
760
- end
761
-
762
- let :unpacker do
763
- described_class.new()
764
- end
765
-
766
- it 'decodes binary as ascii-8bit when using #feed' do
767
- objs = []
768
- unpacker.feed(buffer)
769
- unpacker.each do |obj|
770
- objs << obj
771
- end
772
- strings = flatten(objs).grep(String)
773
- strings.should == %w[hello world nested object structure]
774
- strings.map(&:encoding).uniq.should == [Encoding::ASCII_8BIT]
775
- end
776
-
777
- it 'decodes binary as ascii-8bit when using #feed_each' do
778
- objs = []
779
- unpacker.feed_each(buffer) do |obj|
780
- objs << obj
781
- end
782
- strings = flatten(objs).grep(String)
783
- strings.should == %w[hello world nested object structure]
784
- strings.map(&:encoding).uniq.should == [Encoding::ASCII_8BIT]
785
- end
786
- end
787
-
788
- context 'string encoding', :encodings do
789
- let :buffer do
790
- MessagePack.pack({'hello'.force_encoding(Encoding::UTF_8) => 'world'.force_encoding(Encoding::UTF_8), 'nested'.force_encoding(Encoding::UTF_8) => ['object'.force_encoding(Encoding::UTF_8), {'structure'.force_encoding(Encoding::UTF_8) => true}]})
791
- end
792
-
793
- let :unpacker do
794
- described_class.new()
795
- end
796
-
797
- it 'decodes string as utf-8 when using #feed' do
798
- objs = []
799
- unpacker.feed(buffer)
800
- unpacker.each do |obj|
801
- objs << obj
802
- end
803
- strings = flatten(objs).grep(String)
804
- strings.should == %w[hello world nested object structure]
805
- strings.map(&:encoding).uniq.should == [Encoding::UTF_8]
806
- end
807
-
808
- it 'decodes binary as ascii-8bit when using #feed_each' do
809
- objs = []
810
- unpacker.feed_each(buffer) do |obj|
811
- objs << obj
812
- end
813
- strings = flatten(objs).grep(String)
814
- strings.should == %w[hello world nested object structure]
815
- strings.map(&:encoding).uniq.should == [Encoding::UTF_8]
816
- end
817
- end
818
- end
819
- end