msgpack 1.4.4 → 1.5.1

Sign up to get free protection for your applications and to get access to all the features.
data/spec/factory_spec.rb CHANGED
@@ -1,4 +1,3 @@
1
- # encoding: ascii-8bit
2
1
  require 'spec_helper'
3
2
 
4
3
  describe MessagePack::Factory do
@@ -42,6 +41,21 @@ describe MessagePack::Factory do
42
41
  unpacker.feed(MessagePack::ExtensionValue.new(1, 'a').to_msgpack)
43
42
  expect{ unpacker.read }.to raise_error(MessagePack::UnknownExtTypeError)
44
43
  end
44
+
45
+ it 'does not share the extension registry with unpackers' do
46
+ subject.register_type(0x00, Symbol)
47
+ expect do
48
+ unpacker = subject.unpacker
49
+ expect do
50
+ unpacker.register_type(0x01) {}
51
+ end.to change { unpacker.registered_types }
52
+
53
+ second_unpacker = subject.unpacker
54
+ expect do
55
+ second_unpacker.register_type(0x01) {}
56
+ end.to_not change { unpacker.registered_types }
57
+ end.to_not change { subject.registered_types }
58
+ end
45
59
  end
46
60
 
47
61
  describe '#dump and #load' do
@@ -255,29 +269,187 @@ describe MessagePack::Factory do
255
269
  subject { factory.packer.pack(value).to_s }
256
270
  before { stub_const('Value', Class.new{ include Mod }) }
257
271
  let(:value) { Value.new }
258
- it { is_expected.to eq "\xC7\x0F\x01value_msgpacked" }
272
+ it { is_expected.to eq "\xC7\x0F\x01value_msgpacked".force_encoding(Encoding::BINARY) }
259
273
  end
260
274
 
261
275
  describe "packing an object which has been extended by the module" do
262
276
  subject { factory.packer.pack(object).to_s }
263
277
  let(:object) { Object.new.extend Mod }
264
- it { is_expected.to eq "\xC7\x0F\x01value_msgpacked" }
278
+ it { is_expected.to eq "\xC7\x0F\x01value_msgpacked".force_encoding(Encoding::BINARY) }
265
279
  end
266
280
 
267
281
  describe "unpacking with the module" do
268
- subject { factory.unpacker.feed("\xC7\x06\x01module").unpack }
282
+ subject { factory.unpacker.feed("\xC7\x06\x01module".force_encoding(Encoding::BINARY)).unpack }
269
283
  it { is_expected.to eq "unpacked module" }
270
284
  end
271
285
  end
286
+
287
+ describe "registering an ext type for Integer" do
288
+ let(:factory) { described_class.new }
289
+ let(:bigint) { 10**150 }
290
+
291
+ it 'does not work by default without passing `oversized_integer_extension: true`' do
292
+ factory.register_type(0x01, Integer, packer: :to_s, unpacker: method(:Integer))
293
+
294
+ expect do
295
+ factory.dump(bigint)
296
+ end.to raise_error RangeError
297
+ end
298
+
299
+ it 'raises ArgumentError if the type is not Integer' do
300
+ expect do
301
+ factory.register_type(0x01, MyType, packer: :to_s, unpacker: method(:Integer), oversized_integer_extension: true)
302
+ end.to raise_error(ArgumentError)
303
+ end
304
+
305
+ it 'invokes the packer if registered with `oversized_integer_extension: true`' do
306
+ factory.register_type(0x01, Integer, packer: :to_s, unpacker: method(:Integer), oversized_integer_extension: true)
307
+
308
+ expect(factory.load(factory.dump(bigint))).to be == bigint
309
+ end
310
+
311
+ it 'does not use the oversized_integer_extension packer for integers fitting in native types' do
312
+ factory.register_type(
313
+ 0x01,
314
+ Integer,
315
+ packer: ->(int) { raise NotImplementedError },
316
+ unpacker: ->(payload) { raise NotImplementedError },
317
+ oversized_integer_extension: true
318
+ )
319
+
320
+ expect(factory.dump(42)).to eq(MessagePack.dump(42))
321
+ end
322
+ end
323
+
324
+ describe "registering ext type with recursive serialization" do
325
+ before do
326
+ stub_const("Point", Struct.new(:x, :y, :z))
327
+ end
328
+
329
+ it 'can receive the packer as argument (proc)' do
330
+ factory = MessagePack::Factory.new
331
+ factory.register_type(0x00, Symbol)
332
+ factory.register_type(
333
+ 0x01,
334
+ Point,
335
+ packer: ->(point, packer) do
336
+ packer.write(point.to_h)
337
+ nil
338
+ end,
339
+ unpacker: ->(unpacker) do
340
+ attrs = unpacker.read
341
+ Point.new(attrs.fetch(:x), attrs.fetch(:y), attrs.fetch(:z))
342
+ end,
343
+ recursive: true,
344
+ )
345
+
346
+ point = Point.new(1, 2, 3)
347
+ payload = factory.dump(point)
348
+ expect(factory.load(payload)).to be == point
349
+ end
350
+
351
+ it 'can receive the packer as argument (Method)' do
352
+ mod = Module.new
353
+ mod.define_singleton_method(:packer) do |point, packer|
354
+ packer.write(point.to_h)
355
+ nil
356
+ end
357
+
358
+ mod.define_singleton_method(:unpacker) do |unpacker|
359
+ attrs = unpacker.read
360
+ Point.new(attrs.fetch(:x), attrs.fetch(:y), attrs.fetch(:z))
361
+ end
362
+
363
+ factory = MessagePack::Factory.new
364
+ factory.register_type(0x00, Symbol)
365
+ factory.register_type(
366
+ 0x01,
367
+ Point,
368
+ packer: mod.method(:packer),
369
+ unpacker: mod.method(:unpacker),
370
+ recursive: true,
371
+ )
372
+
373
+ point = Point.new(1, 2, 3)
374
+ payload = factory.dump(point)
375
+ expect(factory.load(payload)).to be == point
376
+ end
377
+
378
+ it 'respect message pack format' do
379
+ factory = MessagePack::Factory.new
380
+ factory.register_type(0x00, Symbol)
381
+ factory.register_type(
382
+ 0x01,
383
+ Point,
384
+ packer: ->(point, packer) do
385
+ packer.write(point.to_a)
386
+ nil
387
+ end,
388
+ unpacker: ->(unpacker) do
389
+ attrs = unpacker.read
390
+ Point.new(*attrs)
391
+ end,
392
+ recursive: true,
393
+ )
394
+
395
+ point = Point.new(1, 2, 3)
396
+ expect(factory.dump(point)).to be == "\xD6\x01".b + MessagePack.dump([1, 2, 3])
397
+ end
398
+
399
+ it 'sets the correct length' do
400
+ factory = MessagePack::Factory.new
401
+ factory.register_type(0x00, Symbol)
402
+ factory.register_type(
403
+ 0x01,
404
+ Point,
405
+ packer: ->(point, packer) do
406
+ packer.write(point.to_h)
407
+ nil
408
+ end,
409
+ unpacker: ->(unpacker) do
410
+ attrs = unpacker.read
411
+ Point.new(attrs.fetch(:x), attrs.fetch(:y), attrs.fetch(:z))
412
+ end,
413
+ recursive: true,
414
+ )
415
+
416
+ point = Point.new(1, 2, 3)
417
+ payload = factory.dump([1, point, 3])
418
+
419
+ obj = MessagePack::Factory.new.load(payload, allow_unknown_ext: true)
420
+ expect(obj).to be == [
421
+ 1,
422
+ MessagePack::ExtensionValue.new(1, factory.dump(x: 1, y: 2, z: 3)),
423
+ 3,
424
+ ]
425
+ end
426
+
427
+ it 'can be nested' do
428
+ factory = MessagePack::Factory.new
429
+ factory.register_type(
430
+ 0x02,
431
+ Set,
432
+ packer: ->(set, packer) do
433
+ packer.write(set.to_a)
434
+ nil
435
+ end,
436
+ unpacker: ->(unpacker) do
437
+ unpacker.read.to_set
438
+ end,
439
+ recursive: true,
440
+ )
441
+
442
+ expected = Set[1, Set[2, Set[3]]]
443
+ payload = factory.dump(expected)
444
+ expect(payload).to be == "\xC7\v\x02\x92\x01\xC7\x06\x02\x92\x02\xD5\x02\x91\x03".b
445
+ expect(factory.load(factory.dump(expected))).to be == expected
446
+ end
447
+ end
272
448
  end
273
449
 
274
450
  describe 'the special treatment of symbols with ext type' do
275
- let(:packer) { subject.packer }
276
- let(:unpacker) { subject.unpacker }
277
-
278
- def symbol_after_roundtrip
279
- packed_symbol = packer.pack(:symbol).to_s
280
- unpacker.feed(packed_symbol).unpack
451
+ def roundtrip(object, options = nil)
452
+ subject.load(subject.dump(object), options)
281
453
  end
282
454
 
283
455
  context 'using the optimized symbol unpacker' do
@@ -293,13 +465,25 @@ describe MessagePack::Factory do
293
465
  end
294
466
 
295
467
  it 'lets symbols survive a roundtrip' do
296
- expect(symbol_after_roundtrip).to be :symbol
468
+ expect(roundtrip(:symbol)).to be :symbol
469
+ end
470
+
471
+ it 'preserves encoding for ASCII symbols' do
472
+ expect(:symbol.encoding).to be Encoding::US_ASCII
473
+ expect(roundtrip(:symbol)).to be :symbol
474
+ expect(roundtrip(:symbol).encoding).to be Encoding::US_ASCII
475
+ end
476
+
477
+ it 'preserves encoding for UTF-8 symbols' do
478
+ expect(:"fée".encoding).to be Encoding::UTF_8
479
+ expect(roundtrip(:"fée").encoding).to be Encoding::UTF_8
480
+ expect(roundtrip(:"fée")).to be :"fée"
297
481
  end
298
482
  end
299
483
 
300
484
  context 'if no ext type is registered for symbols' do
301
485
  it 'converts symbols to string' do
302
- expect(symbol_after_roundtrip).to eq 'symbol'
486
+ expect(roundtrip(:symbol)).to eq 'symbol'
303
487
  end
304
488
  end
305
489
 
@@ -308,7 +492,41 @@ describe MessagePack::Factory do
308
492
  before { subject.register_type(0x00, ::Symbol) }
309
493
 
310
494
  it 'lets symbols survive a roundtrip' do
311
- expect(symbol_after_roundtrip).to be :symbol
495
+ expect(roundtrip(:symbol)).to be :symbol
496
+ end
497
+
498
+ it 'works with hash keys' do
499
+ expect(roundtrip(symbol: 1)).to be == { symbol: 1 }
500
+ end
501
+
502
+ it 'works with frozen: true option' do
503
+ expect(roundtrip(:symbol, freeze: true)).to be :symbol
504
+ end
505
+
506
+ it 'preserves encoding for ASCII symbols' do
507
+ expect(:symbol.encoding).to be Encoding::US_ASCII
508
+ expect(roundtrip(:symbol)).to be :symbol
509
+ expect(roundtrip(:symbol).encoding).to be Encoding::US_ASCII
510
+ end
511
+
512
+ it 'preserves encoding for UTF-8 symbols' do
513
+ expect(:"fée".encoding).to be Encoding::UTF_8
514
+ expect(roundtrip(:"fée")).to be :"fée"
515
+ expect(roundtrip(:"fée").encoding).to be Encoding::UTF_8
516
+ end
517
+
518
+ it 'does not handle symbols in other encodings' do
519
+ symbol = "fàe".encode(Encoding::ISO_8859_1).to_sym
520
+ expect(symbol.encoding).to be Encoding::ISO_8859_1
521
+
522
+ if IS_JRUBY
523
+ # JRuby doesn't quite behave like MRI here.
524
+ # "fàe".force_encoding(Encoding::BINARY).to_sym is able to lookup the existing ISO-8859-1 symbol
525
+ # It likely is a JRuby bug.
526
+ expect(roundtrip(symbol).encoding).to be Encoding::ISO_8859_1
527
+ else
528
+ expect(roundtrip(symbol).encoding).to be Encoding::BINARY
529
+ end
312
530
  end
313
531
  end
314
532
 
@@ -332,7 +550,7 @@ describe MessagePack::Factory do
332
550
  before { subject.register_type(0x00, ::Symbol) }
333
551
 
334
552
  it 'lets symbols survive a roundtrip' do
335
- expect(symbol_after_roundtrip).to be :symbol
553
+ expect(roundtrip(:symbol)).to be :symbol
336
554
  end
337
555
 
338
556
  after do
@@ -381,4 +599,56 @@ describe MessagePack::Factory do
381
599
  expect(MessagePack.unpack(MessagePack.pack(dm2))).to eq(dm2)
382
600
  end
383
601
  end
602
+
603
+ describe '#pool' do
604
+ let(:factory) { described_class.new }
605
+
606
+ it 'responds to serializers interface' do
607
+ pool = factory.pool(1)
608
+ expect(pool.load(pool.dump(42))).to be == 42
609
+ end
610
+
611
+ it 'types can be registered before the pool is created' do
612
+ factory.register_type(0x00, Symbol)
613
+ pool = factory.pool(1)
614
+ expect(pool.load(pool.dump(:foo))).to be == :foo
615
+ end
616
+
617
+ it 'types cannot be registered after the pool is created' do
618
+ pool = factory.pool(1)
619
+ factory.register_type(0x20, ::MyType)
620
+
621
+ expect do
622
+ pool.dump(MyType.new(1, 2))
623
+ end.to raise_error NoMethodError
624
+
625
+ payload = factory.dump(MyType.new(1, 2))
626
+ expect do
627
+ pool.load(payload)
628
+ end.to raise_error MessagePack::UnknownExtTypeError
629
+ end
630
+
631
+ it 'support symbolize_keys: true' do
632
+ pool = factory.pool(1, symbolize_keys: true)
633
+ expect(pool.load(pool.dump('foo' => 1))).to be == { foo: 1 }
634
+ end
635
+
636
+ it 'support freeze: true' do
637
+ pool = factory.pool(1, freeze: true)
638
+ expect(pool.load(pool.dump('foo'))).to be_frozen
639
+ end
640
+
641
+ it 'is thread safe' do
642
+ pool = factory.pool(1)
643
+
644
+ threads = 10.times.map do
645
+ Thread.new do
646
+ 1_000.times do |i|
647
+ expect(pool.load(pool.dump(i))).to be == i
648
+ end
649
+ end
650
+ end
651
+ threads.each(&:join)
652
+ end
653
+ end
384
654
  end
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require "set"
1
2
 
2
3
  if ENV['SIMPLE_COV']
3
4
  require 'simplecov'
@@ -14,6 +15,7 @@ if ENV['GC_STRESS']
14
15
  end
15
16
 
16
17
  require 'msgpack'
18
+ require "msgpack/bigint"
17
19
 
18
20
  if GC.respond_to?(:verify_compaction_references)
19
21
  # This method was added in Ruby 3.0.0. Calling it this way asks the GC to
@@ -25,9 +27,7 @@ if GC.respond_to?(:auto_compact=)
25
27
  GC.auto_compact = true
26
28
  end
27
29
 
28
- def java?
29
- /java/ =~ RUBY_PLATFORM
30
- end
30
+ IS_JRUBY = RUBY_ENGINE == 'jruby'
31
31
 
32
32
  # checking if Hash#[]= (rb_hash_aset) dedupes string keys
33
33
  def automatic_string_keys_deduplication?
@@ -46,7 +46,7 @@ def string_deduplication?
46
46
  (-r1).equal?(-r2)
47
47
  end
48
48
 
49
- if java?
49
+ if IS_JRUBY
50
50
  RSpec.configure do |c|
51
51
  c.treat_symbols_as_metadata_keys_with_true_values = true
52
52
  c.filter_run_excluding :encodings => !(defined? Encoding)
@@ -2,8 +2,6 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- IS_JRUBY = Kernel.const_defined?(:JRUBY_VERSION)
6
-
7
5
  describe MessagePack::Timestamp do
8
6
  describe 'malformed format' do
9
7
  it do
@@ -1,5 +1,3 @@
1
- # encoding: ascii-8bit
2
-
3
1
  require 'stringio'
4
2
  require 'tempfile'
5
3
  require 'zlib'
@@ -302,6 +300,21 @@ describe MessagePack::Unpacker do
302
300
  MessagePack.unpack(MessagePack.pack(symbolized_hash), :symbolize_keys => true).should == symbolized_hash
303
301
  end
304
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
+
305
318
  it 'Unpacker#unpack symbolize_keys' do
306
319
  unpacker = MessagePack::Unpacker.new(:symbolize_keys => true)
307
320
  symbolized_hash = {:a => 'b', :c => 'd'}
@@ -765,7 +778,13 @@ describe MessagePack::Unpacker do
765
778
 
766
779
  context 'binary encoding', :encodings do
767
780
  let :buffer do
768
- MessagePack.pack({'hello' => 'world', 'nested' => ['object', {'structure' => true}]})
781
+ MessagePack.pack({
782
+ 'hello'.b => 'world'.b,
783
+ 'nested'.b => [
784
+ 'object'.b,
785
+ {'structure'.b => true},
786
+ ]
787
+ })
769
788
  end
770
789
 
771
790
  let :unpacker do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: msgpack
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.4
4
+ version: 1.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sadayuki Furuhashi
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2022-01-22 00:00:00.000000000 Z
13
+ date: 2022-04-07 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: bundler
@@ -176,6 +176,7 @@ files:
176
176
  - ext/msgpack/unpacker_ext_registry.c
177
177
  - ext/msgpack/unpacker_ext_registry.h
178
178
  - lib/msgpack.rb
179
+ - lib/msgpack/bigint.rb
179
180
  - lib/msgpack/core_ext.rb
180
181
  - lib/msgpack/factory.rb
181
182
  - lib/msgpack/packer.rb
@@ -186,6 +187,7 @@ files:
186
187
  - lib/msgpack/version.rb
187
188
  - msgpack.gemspec
188
189
  - msgpack.org.md
190
+ - spec/bigint_spec.rb
189
191
  - spec/cases.json
190
192
  - spec/cases.msg
191
193
  - spec/cases_compact.msg