msgpack 1.4.2 → 1.7.3

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 (95) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog +89 -0
  3. data/README.md +73 -13
  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 +136 -111
  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