msgpack 1.3.3 → 1.6.0
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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yaml +57 -0
- data/.rubocop.yml +2 -2
- data/ChangeLog +74 -0
- data/Gemfile +1 -1
- data/README.md +266 -0
- data/Rakefile +1 -9
- data/bench/bench.rb +78 -0
- data/bin/console +8 -0
- data/doclib/msgpack/factory.rb +47 -3
- data/doclib/msgpack/packer.rb +5 -4
- data/doclib/msgpack/unpacker.rb +2 -2
- data/ext/java/org/msgpack/jruby/Buffer.java +23 -16
- data/ext/java/org/msgpack/jruby/Decoder.java +46 -23
- data/ext/java/org/msgpack/jruby/Encoder.java +68 -30
- data/ext/java/org/msgpack/jruby/ExtensionRegistry.java +37 -49
- data/ext/java/org/msgpack/jruby/ExtensionValue.java +5 -8
- data/ext/java/org/msgpack/jruby/Factory.java +47 -7
- data/ext/java/org/msgpack/jruby/Packer.java +29 -17
- data/ext/java/org/msgpack/jruby/Unpacker.java +72 -37
- data/ext/msgpack/buffer.c +42 -68
- data/ext/msgpack/buffer.h +59 -14
- data/ext/msgpack/buffer_class.c +90 -52
- data/ext/msgpack/compat.h +1 -111
- data/ext/msgpack/extconf.rb +45 -19
- data/ext/msgpack/factory_class.c +133 -43
- data/ext/msgpack/packer.c +60 -36
- data/ext/msgpack/packer.h +27 -25
- data/ext/msgpack/packer_class.c +84 -77
- data/ext/msgpack/packer_class.h +11 -0
- data/ext/msgpack/packer_ext_registry.c +24 -32
- data/ext/msgpack/packer_ext_registry.h +40 -33
- data/ext/msgpack/sysdep.h +5 -2
- data/ext/msgpack/unpacker.c +132 -115
- data/ext/msgpack/unpacker.h +23 -10
- data/ext/msgpack/unpacker_class.c +83 -78
- data/ext/msgpack/unpacker_class.h +11 -0
- data/ext/msgpack/unpacker_ext_registry.c +42 -18
- data/ext/msgpack/unpacker_ext_registry.h +23 -16
- data/lib/msgpack/bigint.rb +69 -0
- data/lib/msgpack/factory.rb +103 -0
- data/lib/msgpack/symbol.rb +21 -4
- data/lib/msgpack/time.rb +1 -1
- data/lib/msgpack/version.rb +4 -8
- data/lib/msgpack.rb +6 -12
- data/msgpack.gemspec +4 -6
- data/spec/bigint_spec.rb +26 -0
- data/spec/cruby/buffer_spec.rb +17 -0
- data/spec/factory_spec.rb +351 -12
- data/spec/msgpack_spec.rb +1 -1
- data/spec/packer_spec.rb +18 -0
- data/spec/spec_helper.rb +37 -3
- data/spec/timestamp_spec.rb +38 -0
- data/spec/unpacker_spec.rb +157 -4
- metadata +31 -61
- data/.travis.yml +0 -43
- data/README.rdoc +0 -225
- data/bench/pack.rb +0 -23
- data/bench/pack_log.rb +0 -33
- data/bench/pack_log_long.rb +0 -65
- data/bench/pack_symbols.rb +0 -28
- data/bench/run.sh +0 -14
- data/bench/run_long.sh +0 -35
- data/bench/run_symbols.sh +0 -26
- data/bench/unpack.rb +0 -21
- data/bench/unpack_log.rb +0 -34
- data/bench/unpack_log_long.rb +0 -67
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,34 +269,231 @@ 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
|
+
|
426
|
+
expect(factory.load(payload)).to be == [
|
427
|
+
1,
|
428
|
+
Point.new(1, 2, 3),
|
429
|
+
3,
|
430
|
+
]
|
431
|
+
end
|
432
|
+
|
433
|
+
it 'can be nested' do
|
434
|
+
factory = MessagePack::Factory.new
|
435
|
+
factory.register_type(
|
436
|
+
0x02,
|
437
|
+
Set,
|
438
|
+
packer: ->(set, packer) do
|
439
|
+
packer.write(set.to_a)
|
440
|
+
nil
|
441
|
+
end,
|
442
|
+
unpacker: ->(unpacker) do
|
443
|
+
unpacker.read.to_set
|
444
|
+
end,
|
445
|
+
recursive: true,
|
446
|
+
)
|
447
|
+
|
448
|
+
expected = Set[1, Set[2, Set[3]]]
|
449
|
+
payload = factory.dump(expected)
|
450
|
+
expect(payload).to be == "\xC7\v\x02\x92\x01\xC7\x06\x02\x92\x02\xD5\x02\x91\x03".b
|
451
|
+
expect(factory.load(factory.dump(expected))).to be == expected
|
452
|
+
end
|
453
|
+
end
|
272
454
|
end
|
273
455
|
|
274
456
|
describe 'the special treatment of symbols with ext type' do
|
275
|
-
|
276
|
-
|
457
|
+
def roundtrip(object, options = nil)
|
458
|
+
subject.load(subject.dump(object), options)
|
459
|
+
end
|
277
460
|
|
278
|
-
|
279
|
-
|
280
|
-
|
461
|
+
context 'using the optimized symbol unpacker' do
|
462
|
+
before do
|
463
|
+
skip if IS_JRUBY # JRuby implementation doesn't support the optimized symbols unpacker for now
|
464
|
+
subject.register_type(
|
465
|
+
0x00,
|
466
|
+
::Symbol,
|
467
|
+
packer: :to_msgpack_ext,
|
468
|
+
unpacker: :from_msgpack_ext,
|
469
|
+
optimized_symbols_parsing: true,
|
470
|
+
)
|
471
|
+
end
|
472
|
+
|
473
|
+
it 'lets symbols survive a roundtrip' do
|
474
|
+
expect(roundtrip(:symbol)).to be :symbol
|
475
|
+
end
|
476
|
+
|
477
|
+
it 'works with empty symbol' do
|
478
|
+
expect(roundtrip(:"")).to be :""
|
479
|
+
end
|
480
|
+
|
481
|
+
it 'preserves encoding for ASCII symbols' do
|
482
|
+
expect(:symbol.encoding).to be Encoding::US_ASCII
|
483
|
+
expect(roundtrip(:symbol)).to be :symbol
|
484
|
+
expect(roundtrip(:symbol).encoding).to be Encoding::US_ASCII
|
485
|
+
end
|
486
|
+
|
487
|
+
it 'preserves encoding for UTF-8 symbols' do
|
488
|
+
expect(:"fée".encoding).to be Encoding::UTF_8
|
489
|
+
expect(roundtrip(:"fée").encoding).to be Encoding::UTF_8
|
490
|
+
expect(roundtrip(:"fée")).to be :"fée"
|
491
|
+
end
|
281
492
|
end
|
282
493
|
|
283
494
|
context 'if no ext type is registered for symbols' do
|
284
495
|
it 'converts symbols to string' do
|
285
|
-
expect(
|
496
|
+
expect(roundtrip(:symbol)).to eq 'symbol'
|
286
497
|
end
|
287
498
|
end
|
288
499
|
|
@@ -291,7 +502,41 @@ describe MessagePack::Factory do
|
|
291
502
|
before { subject.register_type(0x00, ::Symbol) }
|
292
503
|
|
293
504
|
it 'lets symbols survive a roundtrip' do
|
294
|
-
expect(
|
505
|
+
expect(roundtrip(:symbol)).to be :symbol
|
506
|
+
end
|
507
|
+
|
508
|
+
it 'works with hash keys' do
|
509
|
+
expect(roundtrip(symbol: 1)).to be == { symbol: 1 }
|
510
|
+
end
|
511
|
+
|
512
|
+
it 'works with frozen: true option' do
|
513
|
+
expect(roundtrip(:symbol, freeze: true)).to be :symbol
|
514
|
+
end
|
515
|
+
|
516
|
+
it 'preserves encoding for ASCII symbols' do
|
517
|
+
expect(:symbol.encoding).to be Encoding::US_ASCII
|
518
|
+
expect(roundtrip(:symbol)).to be :symbol
|
519
|
+
expect(roundtrip(:symbol).encoding).to be Encoding::US_ASCII
|
520
|
+
end
|
521
|
+
|
522
|
+
it 'preserves encoding for UTF-8 symbols' do
|
523
|
+
expect(:"fée".encoding).to be Encoding::UTF_8
|
524
|
+
expect(roundtrip(:"fée")).to be :"fée"
|
525
|
+
expect(roundtrip(:"fée").encoding).to be Encoding::UTF_8
|
526
|
+
end
|
527
|
+
|
528
|
+
it 'does not handle symbols in other encodings' do
|
529
|
+
symbol = "fàe".encode(Encoding::ISO_8859_1).to_sym
|
530
|
+
expect(symbol.encoding).to be Encoding::ISO_8859_1
|
531
|
+
|
532
|
+
if IS_JRUBY
|
533
|
+
# JRuby doesn't quite behave like MRI here.
|
534
|
+
# "fàe".force_encoding(Encoding::BINARY).to_sym is able to lookup the existing ISO-8859-1 symbol
|
535
|
+
# It likely is a JRuby bug.
|
536
|
+
expect(roundtrip(symbol).encoding).to be Encoding::ISO_8859_1
|
537
|
+
else
|
538
|
+
expect(roundtrip(symbol).encoding).to be Encoding::BINARY
|
539
|
+
end
|
295
540
|
end
|
296
541
|
end
|
297
542
|
|
@@ -315,7 +560,7 @@ describe MessagePack::Factory do
|
|
315
560
|
before { subject.register_type(0x00, ::Symbol) }
|
316
561
|
|
317
562
|
it 'lets symbols survive a roundtrip' do
|
318
|
-
expect(
|
563
|
+
expect(roundtrip(:symbol)).to be :symbol
|
319
564
|
end
|
320
565
|
|
321
566
|
after do
|
@@ -342,6 +587,48 @@ describe MessagePack::Factory do
|
|
342
587
|
GC.stress = false
|
343
588
|
end
|
344
589
|
end
|
590
|
+
|
591
|
+
it 'does not crash in recursive extensions' do
|
592
|
+
my_hash_type = Class.new(Hash)
|
593
|
+
factory = MessagePack::Factory.new
|
594
|
+
factory.register_type(7,
|
595
|
+
my_hash_type,
|
596
|
+
packer: ->(value, packer) do
|
597
|
+
packer.write(value.to_h)
|
598
|
+
end,
|
599
|
+
unpacker: ->(unpacker) { my_hash_type.new(unpacker.read) },
|
600
|
+
recursive: true,
|
601
|
+
)
|
602
|
+
|
603
|
+
payload = factory.dump(
|
604
|
+
[my_hash_type.new]
|
605
|
+
)
|
606
|
+
|
607
|
+
begin
|
608
|
+
GC.stress = true
|
609
|
+
factory.load(payload)
|
610
|
+
ensure
|
611
|
+
GC.stress = false
|
612
|
+
end
|
613
|
+
end
|
614
|
+
end
|
615
|
+
|
616
|
+
describe 'memsize' do
|
617
|
+
it 'works on a fresh factory' do
|
618
|
+
skip "JRuby doesn't support ObjectSpace.memsize_of" if IS_JRUBY
|
619
|
+
|
620
|
+
f = MessagePack::Factory.new
|
621
|
+
expect(ObjectSpace.memsize_of(f)).to be_an(Integer)
|
622
|
+
end
|
623
|
+
|
624
|
+
it 'works on a factory with registered types' do
|
625
|
+
skip "JRuby doesn't support ObjectSpace.memsize_of" if IS_JRUBY
|
626
|
+
|
627
|
+
f = MessagePack::Factory.new
|
628
|
+
base_size = ObjectSpace.memsize_of(f)
|
629
|
+
f.register_type(0x0a, Symbol)
|
630
|
+
expect(ObjectSpace.memsize_of(f)).to be > base_size
|
631
|
+
end
|
345
632
|
end
|
346
633
|
|
347
634
|
describe 'DefaultFactory' do
|
@@ -364,4 +651,56 @@ describe MessagePack::Factory do
|
|
364
651
|
expect(MessagePack.unpack(MessagePack.pack(dm2))).to eq(dm2)
|
365
652
|
end
|
366
653
|
end
|
654
|
+
|
655
|
+
describe '#pool' do
|
656
|
+
let(:factory) { described_class.new }
|
657
|
+
|
658
|
+
it 'responds to serializers interface' do
|
659
|
+
pool = factory.pool(1)
|
660
|
+
expect(pool.load(pool.dump(42))).to be == 42
|
661
|
+
end
|
662
|
+
|
663
|
+
it 'types can be registered before the pool is created' do
|
664
|
+
factory.register_type(0x00, Symbol)
|
665
|
+
pool = factory.pool(1)
|
666
|
+
expect(pool.load(pool.dump(:foo))).to be == :foo
|
667
|
+
end
|
668
|
+
|
669
|
+
it 'types cannot be registered after the pool is created' do
|
670
|
+
pool = factory.pool(1)
|
671
|
+
factory.register_type(0x20, ::MyType)
|
672
|
+
|
673
|
+
expect do
|
674
|
+
pool.dump(MyType.new(1, 2))
|
675
|
+
end.to raise_error NoMethodError
|
676
|
+
|
677
|
+
payload = factory.dump(MyType.new(1, 2))
|
678
|
+
expect do
|
679
|
+
pool.load(payload)
|
680
|
+
end.to raise_error MessagePack::UnknownExtTypeError
|
681
|
+
end
|
682
|
+
|
683
|
+
it 'support symbolize_keys: true' do
|
684
|
+
pool = factory.pool(1, symbolize_keys: true)
|
685
|
+
expect(pool.load(pool.dump('foo' => 1))).to be == { foo: 1 }
|
686
|
+
end
|
687
|
+
|
688
|
+
it 'support freeze: true' do
|
689
|
+
pool = factory.pool(1, freeze: true)
|
690
|
+
expect(pool.load(pool.dump('foo'))).to be_frozen
|
691
|
+
end
|
692
|
+
|
693
|
+
it 'is thread safe' do
|
694
|
+
pool = factory.pool(1)
|
695
|
+
|
696
|
+
threads = 10.times.map do
|
697
|
+
Thread.new do
|
698
|
+
1_000.times do |i|
|
699
|
+
expect(pool.load(pool.dump(i))).to be == i
|
700
|
+
end
|
701
|
+
end
|
702
|
+
end
|
703
|
+
threads.each(&:join)
|
704
|
+
end
|
705
|
+
end
|
367
706
|
end
|
data/spec/msgpack_spec.rb
CHANGED
@@ -115,7 +115,7 @@ describe MessagePack do
|
|
115
115
|
expect { MessagePack.pack(self) }.to raise_error(NoMethodError, /^undefined method `to_msgpack'/)
|
116
116
|
end
|
117
117
|
|
118
|
-
it '
|
118
|
+
it 'raises an error on #unpack with garbage' do
|
119
119
|
skip "but nothing was raised. why?"
|
120
120
|
expect { MessagePack.unpack('asdka;sd') }.to raise_error(MessagePack::UnpackError)
|
121
121
|
end
|
data/spec/packer_spec.rb
CHANGED
@@ -488,6 +488,24 @@ describe MessagePack::Packer do
|
|
488
488
|
it { is_expected.to eq "\xC7\x0F\x01value_msgpacked" }
|
489
489
|
end
|
490
490
|
|
491
|
+
shared_examples_for 'extension subclasses core type' do |klass|
|
492
|
+
before { stub_const('Value', Class.new(klass)) }
|
493
|
+
let(:object) { Value.new }
|
494
|
+
subject { packer.pack(object).to_s }
|
495
|
+
|
496
|
+
it "defaults to #{klass.name} packer if no extension is present" do
|
497
|
+
expect(subject).to eq(MessagePack.dump(klass.new))
|
498
|
+
end
|
499
|
+
|
500
|
+
it "uses core type extension for #{klass.name}" do
|
501
|
+
packer.register_type(0x01, Value, ->(_) { 'value_msgpacked' })
|
502
|
+
expect(subject).to eq("\xC7\x0F\x01value_msgpacked")
|
503
|
+
end
|
504
|
+
end
|
505
|
+
it_behaves_like 'extension subclasses core type', Hash
|
506
|
+
it_behaves_like 'extension subclasses core type', Array
|
507
|
+
it_behaves_like 'extension subclasses core type', String
|
508
|
+
|
491
509
|
context 'when registering a type for symbols' do
|
492
510
|
before { packer.register_type(0x00, ::Symbol, :to_msgpack_ext) }
|
493
511
|
|
data/spec/spec_helper.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require "set"
|
2
|
+
require "objspace"
|
1
3
|
|
2
4
|
if ENV['SIMPLE_COV']
|
3
5
|
require 'simplecov'
|
@@ -14,12 +16,44 @@ if ENV['GC_STRESS']
|
|
14
16
|
end
|
15
17
|
|
16
18
|
require 'msgpack'
|
19
|
+
require "msgpack/bigint"
|
17
20
|
|
18
|
-
|
19
|
-
|
21
|
+
if GC.respond_to?(:verify_compaction_references)
|
22
|
+
# This method was added in Ruby 3.0.0. Calling it this way asks the GC to
|
23
|
+
# move objects around, helping to find object movement bugs.
|
24
|
+
begin
|
25
|
+
GC.verify_compaction_references(double_heap: true, toward: :empty)
|
26
|
+
rescue NotImplementedError
|
27
|
+
# Some platforms don't support compaction
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
if GC.respond_to?(:auto_compact=)
|
32
|
+
GC.auto_compact = true
|
33
|
+
end
|
34
|
+
|
35
|
+
IS_JRUBY = RUBY_ENGINE == 'jruby'
|
36
|
+
|
37
|
+
IS_TRUFFLERUBY = RUBY_ENGINE == 'truffleruby'
|
38
|
+
|
39
|
+
# checking if Hash#[]= (rb_hash_aset) dedupes string keys
|
40
|
+
def automatic_string_keys_deduplication?
|
41
|
+
h = {}
|
42
|
+
x = {}
|
43
|
+
r = rand.to_s
|
44
|
+
h[%W(#{r}).join('')] = :foo
|
45
|
+
x[%W(#{r}).join('')] = :foo
|
46
|
+
|
47
|
+
x.keys[0].equal?(h.keys[0])
|
48
|
+
end
|
49
|
+
|
50
|
+
def string_deduplication?
|
51
|
+
r1 = rand.to_s
|
52
|
+
r2 = r1.dup
|
53
|
+
(-r1).equal?(-r2)
|
20
54
|
end
|
21
55
|
|
22
|
-
if
|
56
|
+
if IS_JRUBY
|
23
57
|
RSpec.configure do |c|
|
24
58
|
c.treat_symbols_as_metadata_keys_with_true_values = true
|
25
59
|
c.filter_run_excluding :encodings => !(defined? Encoding)
|
data/spec/timestamp_spec.rb
CHANGED
@@ -60,6 +60,44 @@ describe MessagePack::Timestamp do
|
|
60
60
|
it 'runs correctly (regression)' do
|
61
61
|
expect(factory.unpack(factory.pack(Time.utc(2200)))).to eq(Time.utc(2200))
|
62
62
|
end
|
63
|
+
|
64
|
+
let(:time32_max) { Time.new(2106, 2, 7, 6, 28, 15, "+00:00") }
|
65
|
+
it 'is serialized into timestamp32' do
|
66
|
+
expect(factory.pack(time32_max).size).to be 6
|
67
|
+
expect(factory.unpack(factory.pack(time32_max)).utc).to eq(time32_max)
|
68
|
+
end
|
69
|
+
|
70
|
+
let(:time64_min) { Time.new(2106, 2, 7, 6, 28, 16, "+00:00") }
|
71
|
+
it 'is serialized into timestamp64' do
|
72
|
+
expect(factory.pack(time64_min).size).to be 10
|
73
|
+
expect(factory.unpack(factory.pack(time64_min)).utc).to eq(time64_min)
|
74
|
+
end
|
75
|
+
|
76
|
+
let(:time64_max) { Time.at(Time.new(2514, 5, 30, 1, 53, 3, "+00:00").to_i, 999999999 / 1000.0r).utc } # TODO: use Time.at(sec, nsec, :nsec) when removing Ruby 2.4 from the list
|
77
|
+
it 'is serialized into timestamp64' do
|
78
|
+
expect(factory.pack(time64_max).size).to be 10
|
79
|
+
expect(factory.unpack(factory.pack(time64_max)).utc).to eq(time64_max)
|
80
|
+
end
|
81
|
+
|
82
|
+
let(:time96_positive_min) { Time.new(2514, 5, 30, 1, 53, 4, "+00:00") }
|
83
|
+
it 'is serialized into timestamp96' do
|
84
|
+
expect(factory.pack(time96_positive_min).size).to be 15
|
85
|
+
expect(factory.unpack(factory.pack(time96_positive_min)).utc).to eq(time96_positive_min)
|
86
|
+
end
|
87
|
+
|
88
|
+
let(:time96_min) { Time.at(-2**63).utc }
|
89
|
+
it 'is serialized into timestamp96' do
|
90
|
+
skip if IS_JRUBY || IS_TRUFFLERUBY # JRuby and TruffleRuby both use underlying Java time classes that do not support |year| >= 1 billion
|
91
|
+
expect(factory.pack(time96_min).size).to be 15
|
92
|
+
expect(factory.unpack(factory.pack(time96_min)).utc).to eq(time96_min)
|
93
|
+
end
|
94
|
+
|
95
|
+
let(:time96_max) { Time.at(2**63 - 1).utc }
|
96
|
+
it 'is serialized into timestamp96' do
|
97
|
+
skip if IS_JRUBY || IS_TRUFFLERUBY # JRuby and TruffleRuby both use underlying Java time classes that do not support |year| >= 1 billion
|
98
|
+
expect(factory.pack(time96_max).size).to be 15
|
99
|
+
expect(factory.unpack(factory.pack(time96_max)).utc).to eq(time96_max)
|
100
|
+
end
|
63
101
|
end
|
64
102
|
|
65
103
|
describe 'register_type with MessagePack::Timestamp' do
|