msgpack 1.3.3 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|