msgpack 1.5.6 → 1.8.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/ChangeLog +50 -0
- data/README.md +48 -12
- data/ext/java/org/msgpack/jruby/Buffer.java +3 -3
- data/ext/java/org/msgpack/jruby/ExtensionRegistry.java +11 -20
- data/ext/java/org/msgpack/jruby/ExtensionValue.java +1 -1
- data/ext/java/org/msgpack/jruby/Factory.java +11 -50
- data/ext/java/org/msgpack/jruby/Packer.java +9 -24
- data/ext/java/org/msgpack/jruby/Unpacker.java +15 -32
- data/ext/msgpack/buffer.c +69 -56
- data/ext/msgpack/buffer.h +138 -44
- data/ext/msgpack/buffer_class.c +132 -31
- data/ext/msgpack/buffer_class.h +1 -0
- data/ext/msgpack/extconf.rb +20 -30
- data/ext/msgpack/factory_class.c +75 -86
- data/ext/msgpack/packer.c +13 -16
- data/ext/msgpack/packer.h +24 -21
- data/ext/msgpack/packer_class.c +72 -98
- data/ext/msgpack/packer_class.h +11 -0
- data/ext/msgpack/packer_ext_registry.c +31 -28
- data/ext/msgpack/packer_ext_registry.h +10 -14
- data/ext/msgpack/rbinit.c +1 -1
- data/ext/msgpack/rmem.c +3 -4
- data/ext/msgpack/sysdep.h +5 -2
- data/ext/msgpack/unpacker.c +201 -113
- data/ext/msgpack/unpacker.h +22 -15
- data/ext/msgpack/unpacker_class.c +87 -92
- data/ext/msgpack/unpacker_class.h +11 -0
- data/ext/msgpack/unpacker_ext_registry.c +4 -16
- data/ext/msgpack/unpacker_ext_registry.h +3 -7
- data/lib/msgpack/buffer.rb +9 -0
- data/lib/msgpack/factory.rb +90 -63
- data/lib/msgpack/packer.rb +10 -1
- data/lib/msgpack/unpacker.rb +14 -1
- data/lib/msgpack/version.rb +1 -1
- data/lib/msgpack.rb +1 -0
- data/msgpack.gemspec +8 -3
- metadata +21 -51
- data/.github/workflows/ci.yaml +0 -57
- data/.gitignore +0 -23
- data/.rubocop.yml +0 -36
- data/Gemfile +0 -9
- data/Rakefile +0 -70
- data/appveyor.yml +0 -18
- data/bench/bench.rb +0 -78
- data/doclib/msgpack/buffer.rb +0 -193
- data/doclib/msgpack/core_ext.rb +0 -101
- data/doclib/msgpack/error.rb +0 -19
- data/doclib/msgpack/extension_value.rb +0 -9
- data/doclib/msgpack/factory.rb +0 -145
- data/doclib/msgpack/packer.rb +0 -209
- data/doclib/msgpack/time.rb +0 -22
- data/doclib/msgpack/timestamp.rb +0 -44
- data/doclib/msgpack/unpacker.rb +0 -183
- data/doclib/msgpack.rb +0 -87
- data/msgpack.org.md +0 -46
- data/spec/bigint_spec.rb +0 -26
- data/spec/cases.json +0 -1
- data/spec/cases.msg +0 -0
- data/spec/cases_compact.msg +0 -0
- data/spec/cases_spec.rb +0 -39
- data/spec/cruby/buffer_io_spec.rb +0 -255
- data/spec/cruby/buffer_packer.rb +0 -29
- data/spec/cruby/buffer_spec.rb +0 -575
- data/spec/cruby/buffer_unpacker.rb +0 -19
- data/spec/cruby/unpacker_spec.rb +0 -70
- data/spec/ext_value_spec.rb +0 -99
- data/spec/exttypes.rb +0 -51
- data/spec/factory_spec.rb +0 -688
- data/spec/format_spec.rb +0 -301
- data/spec/jruby/benchmarks/shootout_bm.rb +0 -73
- data/spec/jruby/benchmarks/symbolize_keys_bm.rb +0 -25
- data/spec/jruby/unpacker_spec.rb +0 -186
- data/spec/msgpack_spec.rb +0 -214
- data/spec/pack_spec.rb +0 -61
- data/spec/packer_spec.rb +0 -575
- data/spec/random_compat.rb +0 -24
- data/spec/spec_helper.rb +0 -71
- data/spec/timestamp_spec.rb +0 -159
- data/spec/unpack_spec.rb +0 -57
- data/spec/unpacker_spec.rb +0 -859
data/spec/factory_spec.rb
DELETED
@@ -1,688 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe MessagePack::Factory do
|
4
|
-
subject do
|
5
|
-
described_class.new
|
6
|
-
end
|
7
|
-
|
8
|
-
describe '#packer' do
|
9
|
-
it 'creates a Packer instance' do
|
10
|
-
subject.packer.should be_kind_of(MessagePack::Packer)
|
11
|
-
end
|
12
|
-
|
13
|
-
it 'creates new instance' do
|
14
|
-
subject.packer.object_id.should_not == subject.packer.object_id
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
describe '#unpacker' do
|
19
|
-
it 'creates a Unpacker instance' do
|
20
|
-
subject.unpacker.should be_kind_of(MessagePack::Unpacker)
|
21
|
-
end
|
22
|
-
|
23
|
-
it 'creates new instance' do
|
24
|
-
subject.unpacker.object_id.should_not == subject.unpacker.object_id
|
25
|
-
end
|
26
|
-
|
27
|
-
it 'creates unpacker with symbolize_keys option' do
|
28
|
-
unpacker = subject.unpacker(symbolize_keys: true)
|
29
|
-
unpacker.feed(MessagePack.pack({'k'=>'v'}))
|
30
|
-
unpacker.read.should == {:k => 'v'}
|
31
|
-
end
|
32
|
-
|
33
|
-
it 'creates unpacker with allow_unknown_ext option' do
|
34
|
-
unpacker = subject.unpacker(allow_unknown_ext: true)
|
35
|
-
unpacker.feed(MessagePack::ExtensionValue.new(1, 'a').to_msgpack)
|
36
|
-
unpacker.read.should == MessagePack::ExtensionValue.new(1, 'a')
|
37
|
-
end
|
38
|
-
|
39
|
-
it 'creates unpacker without allow_unknown_ext option' do
|
40
|
-
unpacker = subject.unpacker
|
41
|
-
unpacker.feed(MessagePack::ExtensionValue.new(1, 'a').to_msgpack)
|
42
|
-
expect{ unpacker.read }.to raise_error(MessagePack::UnknownExtTypeError)
|
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
|
59
|
-
end
|
60
|
-
|
61
|
-
describe '#dump and #load' do
|
62
|
-
it 'can be used like a standard coder' do
|
63
|
-
subject.register_type(0x00, Symbol)
|
64
|
-
expect(subject.load(subject.dump(:symbol))).to be == :symbol
|
65
|
-
end
|
66
|
-
|
67
|
-
it 'is alias as pack and unpack' do
|
68
|
-
subject.register_type(0x00, Symbol)
|
69
|
-
expect(subject.unpack(subject.pack(:symbol))).to be == :symbol
|
70
|
-
end
|
71
|
-
|
72
|
-
it 'accept options' do
|
73
|
-
hash = subject.unpack(MessagePack.pack('k' => 'v'), symbolize_keys: true)
|
74
|
-
expect(hash).to be == { k: 'v' }
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
describe '#freeze' do
|
79
|
-
it 'can freeze factory instance to deny new registrations anymore' do
|
80
|
-
subject.register_type(0x00, Symbol)
|
81
|
-
subject.freeze
|
82
|
-
expect(subject.frozen?).to be_truthy
|
83
|
-
expect{ subject.register_type(0x01, Array) }.to raise_error(RuntimeError, "can't modify frozen Factory")
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
class MyType
|
88
|
-
def initialize(a, b)
|
89
|
-
@a = a
|
90
|
-
@b = b
|
91
|
-
end
|
92
|
-
|
93
|
-
attr_reader :a, :b
|
94
|
-
|
95
|
-
def to_msgpack_ext
|
96
|
-
[a, b].pack('CC')
|
97
|
-
end
|
98
|
-
|
99
|
-
def self.from_msgpack_ext(data)
|
100
|
-
new(*data.unpack('CC'))
|
101
|
-
end
|
102
|
-
|
103
|
-
def to_msgpack_ext_only_a
|
104
|
-
[a, 0].pack('CC')
|
105
|
-
end
|
106
|
-
|
107
|
-
def self.from_msgpack_ext_only_b(data)
|
108
|
-
a, b = *data.unpack('CC')
|
109
|
-
new(0, b)
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
class MyType2 < MyType
|
114
|
-
end
|
115
|
-
|
116
|
-
describe '#registered_types' do
|
117
|
-
it 'returns Array' do
|
118
|
-
expect(subject.registered_types).to be_instance_of(Array)
|
119
|
-
end
|
120
|
-
|
121
|
-
it 'returns Array of Hash contains :type, :class, :packer, :unpacker' do
|
122
|
-
subject.register_type(0x20, ::MyType)
|
123
|
-
subject.register_type(0x21, ::MyType2)
|
124
|
-
|
125
|
-
list = subject.registered_types
|
126
|
-
|
127
|
-
expect(list.size).to eq(2)
|
128
|
-
expect(list[0]).to be_instance_of(Hash)
|
129
|
-
expect(list[1]).to be_instance_of(Hash)
|
130
|
-
expect(list[0].keys.sort).to eq([:type, :class, :packer, :unpacker].sort)
|
131
|
-
expect(list[1].keys.sort).to eq([:type, :class, :packer, :unpacker].sort)
|
132
|
-
|
133
|
-
expect(list[0][:type]).to eq(0x20)
|
134
|
-
expect(list[0][:class]).to eq(::MyType)
|
135
|
-
expect(list[0][:packer]).to eq(:to_msgpack_ext)
|
136
|
-
expect(list[0][:unpacker]).to eq(:from_msgpack_ext)
|
137
|
-
|
138
|
-
expect(list[1][:type]).to eq(0x21)
|
139
|
-
expect(list[1][:class]).to eq(::MyType2)
|
140
|
-
expect(list[1][:packer]).to eq(:to_msgpack_ext)
|
141
|
-
expect(list[1][:unpacker]).to eq(:from_msgpack_ext)
|
142
|
-
end
|
143
|
-
|
144
|
-
it 'returns Array of Hash which has nil for unregistered feature' do
|
145
|
-
subject.register_type(0x21, ::MyType2, unpacker: :from_msgpack_ext)
|
146
|
-
subject.register_type(0x20, ::MyType, packer: :to_msgpack_ext)
|
147
|
-
|
148
|
-
list = subject.registered_types
|
149
|
-
|
150
|
-
expect(list.size).to eq(2)
|
151
|
-
expect(list[0]).to be_instance_of(Hash)
|
152
|
-
expect(list[1]).to be_instance_of(Hash)
|
153
|
-
expect(list[0].keys.sort).to eq([:type, :class, :packer, :unpacker].sort)
|
154
|
-
expect(list[1].keys.sort).to eq([:type, :class, :packer, :unpacker].sort)
|
155
|
-
|
156
|
-
expect(list[0][:type]).to eq(0x20)
|
157
|
-
expect(list[0][:class]).to eq(::MyType)
|
158
|
-
expect(list[0][:packer]).to eq(:to_msgpack_ext)
|
159
|
-
expect(list[0][:unpacker]).to be_nil
|
160
|
-
|
161
|
-
expect(list[1][:type]).to eq(0x21)
|
162
|
-
expect(list[1][:class]).to eq(::MyType2)
|
163
|
-
expect(list[1][:packer]).to be_nil
|
164
|
-
expect(list[1][:unpacker]).to eq(:from_msgpack_ext)
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
|
-
describe '#type_registered?' do
|
169
|
-
it 'receive Class or Integer, and return bool' do
|
170
|
-
expect(subject.type_registered?(0x00)).to be_falsy
|
171
|
-
expect(subject.type_registered?(0x01)).to be_falsy
|
172
|
-
expect(subject.type_registered?(::MyType)).to be_falsy
|
173
|
-
end
|
174
|
-
|
175
|
-
it 'has option to specify what types are registered for' do
|
176
|
-
expect(subject.type_registered?(0x00, :both)).to be_falsy
|
177
|
-
expect(subject.type_registered?(0x00, :packer)).to be_falsy
|
178
|
-
expect(subject.type_registered?(0x00, :unpacker)).to be_falsy
|
179
|
-
expect{ subject.type_registered?(0x00, :something) }.to raise_error(ArgumentError)
|
180
|
-
end
|
181
|
-
|
182
|
-
it 'returns true if specified type or class is already registered' do
|
183
|
-
subject.register_type(0x20, ::MyType)
|
184
|
-
subject.register_type(0x21, ::MyType2)
|
185
|
-
|
186
|
-
expect(subject.type_registered?(0x00)).to be_falsy
|
187
|
-
expect(subject.type_registered?(0x01)).to be_falsy
|
188
|
-
|
189
|
-
expect(subject.type_registered?(0x20)).to be_truthy
|
190
|
-
expect(subject.type_registered?(0x21)).to be_truthy
|
191
|
-
expect(subject.type_registered?(::MyType)).to be_truthy
|
192
|
-
expect(subject.type_registered?(::MyType2)).to be_truthy
|
193
|
-
end
|
194
|
-
end
|
195
|
-
|
196
|
-
describe '#register_type' do
|
197
|
-
let :src do
|
198
|
-
::MyType.new(1, 2)
|
199
|
-
end
|
200
|
-
|
201
|
-
it 'registers #to_msgpack_ext and .from_msgpack_ext by default' do
|
202
|
-
subject.register_type(0x7f, ::MyType)
|
203
|
-
|
204
|
-
data = subject.packer.write(src).to_s
|
205
|
-
my = subject.unpacker.feed(data).read
|
206
|
-
my.a.should == 1
|
207
|
-
my.b.should == 2
|
208
|
-
end
|
209
|
-
|
210
|
-
it 'registers custom packer method name' do
|
211
|
-
subject.register_type(0x7f, ::MyType, packer: :to_msgpack_ext_only_a, unpacker: :from_msgpack_ext)
|
212
|
-
|
213
|
-
data = subject.packer.write(src).to_s
|
214
|
-
my = subject.unpacker.feed(data).read
|
215
|
-
my.a.should == 1
|
216
|
-
my.b.should == 0
|
217
|
-
end
|
218
|
-
|
219
|
-
it 'registers custom unpacker method name' do
|
220
|
-
subject.register_type(0x7f, ::MyType, packer: :to_msgpack_ext, unpacker: 'from_msgpack_ext_only_b')
|
221
|
-
|
222
|
-
data = subject.packer.write(src).to_s
|
223
|
-
my = subject.unpacker.feed(data).read
|
224
|
-
my.a.should == 0
|
225
|
-
my.b.should == 2
|
226
|
-
end
|
227
|
-
|
228
|
-
it 'registers custom proc objects' do
|
229
|
-
pk = lambda {|obj| [obj.a + obj.b].pack('C') }
|
230
|
-
uk = lambda {|data| ::MyType.new(data.unpack('C').first, -1) }
|
231
|
-
subject.register_type(0x7f, ::MyType, packer: pk, unpacker: uk)
|
232
|
-
|
233
|
-
data = subject.packer.write(src).to_s
|
234
|
-
my = subject.unpacker.feed(data).read
|
235
|
-
my.a.should == 3
|
236
|
-
my.b.should == -1
|
237
|
-
end
|
238
|
-
|
239
|
-
it 'does not affect existent packer and unpackers' do
|
240
|
-
subject.register_type(0x7f, ::MyType)
|
241
|
-
packer = subject.packer
|
242
|
-
unpacker = subject.unpacker
|
243
|
-
|
244
|
-
subject.register_type(0x7f, ::MyType, packer: :to_msgpack_ext_only_a, unpacker: :from_msgpack_ext_only_b)
|
245
|
-
|
246
|
-
data = packer.write(src).to_s
|
247
|
-
my = unpacker.feed(data).read
|
248
|
-
my.a.should == 1
|
249
|
-
my.b.should == 2
|
250
|
-
end
|
251
|
-
|
252
|
-
describe "registering an ext type for a module" do
|
253
|
-
before do
|
254
|
-
mod = Module.new do
|
255
|
-
def self.from_msgpack_ext(data)
|
256
|
-
"unpacked #{data}"
|
257
|
-
end
|
258
|
-
|
259
|
-
def to_msgpack_ext
|
260
|
-
'value_msgpacked'
|
261
|
-
end
|
262
|
-
end
|
263
|
-
stub_const('Mod', mod)
|
264
|
-
end
|
265
|
-
let(:factory) { described_class.new }
|
266
|
-
before { factory.register_type(0x01, Mod) }
|
267
|
-
|
268
|
-
describe "packing an object whose class included the module" do
|
269
|
-
subject { factory.packer.pack(value).to_s }
|
270
|
-
before { stub_const('Value', Class.new{ include Mod }) }
|
271
|
-
let(:value) { Value.new }
|
272
|
-
it { is_expected.to eq "\xC7\x0F\x01value_msgpacked".force_encoding(Encoding::BINARY) }
|
273
|
-
end
|
274
|
-
|
275
|
-
describe "packing an object which has been extended by the module" do
|
276
|
-
subject { factory.packer.pack(object).to_s }
|
277
|
-
let(:object) { Object.new.extend Mod }
|
278
|
-
it { is_expected.to eq "\xC7\x0F\x01value_msgpacked".force_encoding(Encoding::BINARY) }
|
279
|
-
end
|
280
|
-
|
281
|
-
describe "unpacking with the module" do
|
282
|
-
subject { factory.unpacker.feed("\xC7\x06\x01module".force_encoding(Encoding::BINARY)).unpack }
|
283
|
-
it { is_expected.to eq "unpacked module" }
|
284
|
-
end
|
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
|
454
|
-
end
|
455
|
-
|
456
|
-
describe 'the special treatment of symbols with ext type' do
|
457
|
-
def roundtrip(object, options = nil)
|
458
|
-
subject.load(subject.dump(object), options)
|
459
|
-
end
|
460
|
-
|
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
|
492
|
-
end
|
493
|
-
|
494
|
-
context 'if no ext type is registered for symbols' do
|
495
|
-
it 'converts symbols to string' do
|
496
|
-
expect(roundtrip(:symbol)).to eq 'symbol'
|
497
|
-
end
|
498
|
-
end
|
499
|
-
|
500
|
-
context 'if an ext type is registered for symbols' do
|
501
|
-
context 'if using the default serializer' do
|
502
|
-
before { subject.register_type(0x00, ::Symbol) }
|
503
|
-
|
504
|
-
it 'lets symbols survive a roundtrip' do
|
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
|
540
|
-
end
|
541
|
-
end
|
542
|
-
|
543
|
-
context 'if using a custom serializer' do
|
544
|
-
before do
|
545
|
-
class Symbol
|
546
|
-
alias_method :to_msgpack_ext_orig, :to_msgpack_ext
|
547
|
-
def to_msgpack_ext
|
548
|
-
self.to_s.codepoints.to_a.pack('n*')
|
549
|
-
end
|
550
|
-
end
|
551
|
-
|
552
|
-
class << Symbol
|
553
|
-
alias_method :from_msgpack_ext_orig, :from_msgpack_ext
|
554
|
-
def from_msgpack_ext(data)
|
555
|
-
data.unpack('n*').map(&:chr).join.to_sym
|
556
|
-
end
|
557
|
-
end
|
558
|
-
end
|
559
|
-
|
560
|
-
before { subject.register_type(0x00, ::Symbol) }
|
561
|
-
|
562
|
-
it 'lets symbols survive a roundtrip' do
|
563
|
-
expect(roundtrip(:symbol)).to be :symbol
|
564
|
-
end
|
565
|
-
|
566
|
-
after do
|
567
|
-
class Symbol
|
568
|
-
alias_method :to_msgpack_ext, :to_msgpack_ext_orig
|
569
|
-
end
|
570
|
-
|
571
|
-
class << Symbol
|
572
|
-
alias_method :from_msgpack_ext, :from_msgpack_ext_orig
|
573
|
-
end
|
574
|
-
end
|
575
|
-
end
|
576
|
-
end
|
577
|
-
end
|
578
|
-
|
579
|
-
describe 'under stressful GC' do
|
580
|
-
it 'works well' do
|
581
|
-
begin
|
582
|
-
GC.stress = true
|
583
|
-
|
584
|
-
f = MessagePack::Factory.new
|
585
|
-
f.register_type(0x0a, Symbol)
|
586
|
-
ensure
|
587
|
-
GC.stress = false
|
588
|
-
end
|
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 'DefaultFactory' do
|
617
|
-
it 'is a factory' do
|
618
|
-
MessagePack::DefaultFactory.should be_kind_of(MessagePack::Factory)
|
619
|
-
end
|
620
|
-
|
621
|
-
require_relative 'exttypes'
|
622
|
-
|
623
|
-
it 'should be referred by MessagePack.pack and MessagePack.unpack' do
|
624
|
-
MessagePack::DefaultFactory.register_type(DummyTimeStamp1::TYPE, DummyTimeStamp1)
|
625
|
-
MessagePack::DefaultFactory.register_type(DummyTimeStamp2::TYPE, DummyTimeStamp2, packer: :serialize, unpacker: :deserialize)
|
626
|
-
|
627
|
-
t = Time.now
|
628
|
-
|
629
|
-
dm1 = DummyTimeStamp1.new(t.to_i, t.usec)
|
630
|
-
expect(MessagePack.unpack(MessagePack.pack(dm1))).to eq(dm1)
|
631
|
-
|
632
|
-
dm2 = DummyTimeStamp1.new(t.to_i, t.usec)
|
633
|
-
expect(MessagePack.unpack(MessagePack.pack(dm2))).to eq(dm2)
|
634
|
-
end
|
635
|
-
end
|
636
|
-
|
637
|
-
describe '#pool' do
|
638
|
-
let(:factory) { described_class.new }
|
639
|
-
|
640
|
-
it 'responds to serializers interface' do
|
641
|
-
pool = factory.pool(1)
|
642
|
-
expect(pool.load(pool.dump(42))).to be == 42
|
643
|
-
end
|
644
|
-
|
645
|
-
it 'types can be registered before the pool is created' do
|
646
|
-
factory.register_type(0x00, Symbol)
|
647
|
-
pool = factory.pool(1)
|
648
|
-
expect(pool.load(pool.dump(:foo))).to be == :foo
|
649
|
-
end
|
650
|
-
|
651
|
-
it 'types cannot be registered after the pool is created' do
|
652
|
-
pool = factory.pool(1)
|
653
|
-
factory.register_type(0x20, ::MyType)
|
654
|
-
|
655
|
-
expect do
|
656
|
-
pool.dump(MyType.new(1, 2))
|
657
|
-
end.to raise_error NoMethodError
|
658
|
-
|
659
|
-
payload = factory.dump(MyType.new(1, 2))
|
660
|
-
expect do
|
661
|
-
pool.load(payload)
|
662
|
-
end.to raise_error MessagePack::UnknownExtTypeError
|
663
|
-
end
|
664
|
-
|
665
|
-
it 'support symbolize_keys: true' do
|
666
|
-
pool = factory.pool(1, symbolize_keys: true)
|
667
|
-
expect(pool.load(pool.dump('foo' => 1))).to be == { foo: 1 }
|
668
|
-
end
|
669
|
-
|
670
|
-
it 'support freeze: true' do
|
671
|
-
pool = factory.pool(1, freeze: true)
|
672
|
-
expect(pool.load(pool.dump('foo'))).to be_frozen
|
673
|
-
end
|
674
|
-
|
675
|
-
it 'is thread safe' do
|
676
|
-
pool = factory.pool(1)
|
677
|
-
|
678
|
-
threads = 10.times.map do
|
679
|
-
Thread.new do
|
680
|
-
1_000.times do |i|
|
681
|
-
expect(pool.load(pool.dump(i))).to be == i
|
682
|
-
end
|
683
|
-
end
|
684
|
-
end
|
685
|
-
threads.each(&:join)
|
686
|
-
end
|
687
|
-
end
|
688
|
-
end
|