msgpack 1.4.4 → 1.5.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.
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