msgpack 1.6.0 → 1.6.1

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