msgpack 1.6.0 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog +14 -0
  3. data/README.md +27 -0
  4. data/ext/java/org/msgpack/jruby/ExtensionRegistry.java +4 -9
  5. data/ext/java/org/msgpack/jruby/Factory.java +1 -1
  6. data/ext/java/org/msgpack/jruby/Packer.java +3 -0
  7. data/ext/java/org/msgpack/jruby/Unpacker.java +3 -0
  8. data/ext/msgpack/buffer.c +9 -12
  9. data/ext/msgpack/buffer.h +2 -10
  10. data/ext/msgpack/buffer_class.c +4 -4
  11. data/ext/msgpack/extconf.rb +3 -15
  12. data/ext/msgpack/factory_class.c +1 -1
  13. data/ext/msgpack/packer.c +1 -0
  14. data/ext/msgpack/packer_class.c +9 -19
  15. data/ext/msgpack/rbinit.c +1 -1
  16. data/ext/msgpack/rmem.c +3 -4
  17. data/ext/msgpack/unpacker.c +8 -20
  18. data/ext/msgpack/unpacker.h +0 -4
  19. data/ext/msgpack/unpacker_class.c +11 -21
  20. data/lib/msgpack/buffer.rb +9 -0
  21. data/lib/msgpack/factory.rb +41 -53
  22. data/lib/msgpack/packer.rb +4 -0
  23. data/lib/msgpack/unpacker.rb +4 -0
  24. data/lib/msgpack/version.rb +1 -1
  25. data/lib/msgpack.rb +1 -0
  26. data/msgpack.gemspec +6 -3
  27. metadata +19 -48
  28. data/.github/workflows/ci.yaml +0 -57
  29. data/.gitignore +0 -23
  30. data/.rubocop.yml +0 -36
  31. data/Gemfile +0 -9
  32. data/Rakefile +0 -70
  33. data/appveyor.yml +0 -18
  34. data/bench/bench.rb +0 -78
  35. data/bin/console +0 -8
  36. data/doclib/msgpack/buffer.rb +0 -193
  37. data/doclib/msgpack/core_ext.rb +0 -101
  38. data/doclib/msgpack/error.rb +0 -19
  39. data/doclib/msgpack/extension_value.rb +0 -9
  40. data/doclib/msgpack/factory.rb +0 -145
  41. data/doclib/msgpack/packer.rb +0 -209
  42. data/doclib/msgpack/time.rb +0 -22
  43. data/doclib/msgpack/timestamp.rb +0 -44
  44. data/doclib/msgpack/unpacker.rb +0 -183
  45. data/doclib/msgpack.rb +0 -87
  46. data/msgpack.org.md +0 -46
  47. data/spec/bigint_spec.rb +0 -26
  48. data/spec/cases.json +0 -1
  49. data/spec/cases.msg +0 -0
  50. data/spec/cases_compact.msg +0 -0
  51. data/spec/cases_spec.rb +0 -39
  52. data/spec/cruby/buffer_io_spec.rb +0 -255
  53. data/spec/cruby/buffer_packer.rb +0 -29
  54. data/spec/cruby/buffer_spec.rb +0 -592
  55. data/spec/cruby/buffer_unpacker.rb +0 -19
  56. data/spec/cruby/unpacker_spec.rb +0 -70
  57. data/spec/ext_value_spec.rb +0 -99
  58. data/spec/exttypes.rb +0 -51
  59. data/spec/factory_spec.rb +0 -706
  60. data/spec/format_spec.rb +0 -301
  61. data/spec/jruby/benchmarks/shootout_bm.rb +0 -73
  62. data/spec/jruby/benchmarks/symbolize_keys_bm.rb +0 -25
  63. data/spec/jruby/unpacker_spec.rb +0 -186
  64. data/spec/msgpack_spec.rb +0 -214
  65. data/spec/pack_spec.rb +0 -61
  66. data/spec/packer_spec.rb +0 -575
  67. data/spec/random_compat.rb +0 -24
  68. data/spec/spec_helper.rb +0 -72
  69. data/spec/timestamp_spec.rb +0 -159
  70. data/spec/unpack_spec.rb +0 -57
  71. 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