msgpack 0.6.0-x86-mswin32-60

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +20 -0
  3. data/.travis.yml +26 -0
  4. data/ChangeLog +129 -0
  5. data/Dockerfile +62 -0
  6. data/LICENSE +177 -0
  7. data/README.rdoc +141 -0
  8. data/Rakefile +68 -0
  9. data/bench/pack.rb +23 -0
  10. data/bench/pack_log.rb +33 -0
  11. data/bench/pack_log_long.rb +65 -0
  12. data/bench/run.sh +14 -0
  13. data/bench/run_long.sh +35 -0
  14. data/bench/unpack.rb +21 -0
  15. data/bench/unpack_log.rb +34 -0
  16. data/bench/unpack_log_long.rb +67 -0
  17. data/doclib/msgpack.rb +77 -0
  18. data/doclib/msgpack/buffer.rb +193 -0
  19. data/doclib/msgpack/core_ext.rb +101 -0
  20. data/doclib/msgpack/error.rb +14 -0
  21. data/doclib/msgpack/packer.rb +134 -0
  22. data/doclib/msgpack/unpacker.rb +146 -0
  23. data/ext/java/org/msgpack/jruby/Buffer.java +221 -0
  24. data/ext/java/org/msgpack/jruby/Decoder.java +201 -0
  25. data/ext/java/org/msgpack/jruby/Encoder.java +308 -0
  26. data/ext/java/org/msgpack/jruby/ExtensionValue.java +136 -0
  27. data/ext/java/org/msgpack/jruby/MessagePackLibrary.java +107 -0
  28. data/ext/java/org/msgpack/jruby/Packer.java +78 -0
  29. data/ext/java/org/msgpack/jruby/Types.java +37 -0
  30. data/ext/java/org/msgpack/jruby/Unpacker.java +170 -0
  31. data/ext/msgpack/buffer.c +695 -0
  32. data/ext/msgpack/buffer.h +447 -0
  33. data/ext/msgpack/buffer_class.c +507 -0
  34. data/ext/msgpack/buffer_class.h +32 -0
  35. data/ext/msgpack/compat.h +114 -0
  36. data/ext/msgpack/core_ext.c +129 -0
  37. data/ext/msgpack/core_ext.h +26 -0
  38. data/ext/msgpack/extconf.rb +30 -0
  39. data/ext/msgpack/packer.c +168 -0
  40. data/ext/msgpack/packer.h +441 -0
  41. data/ext/msgpack/packer_class.c +302 -0
  42. data/ext/msgpack/packer_class.h +30 -0
  43. data/ext/msgpack/rbinit.c +33 -0
  44. data/ext/msgpack/rmem.c +94 -0
  45. data/ext/msgpack/rmem.h +109 -0
  46. data/ext/msgpack/sysdep.h +115 -0
  47. data/ext/msgpack/sysdep_endian.h +50 -0
  48. data/ext/msgpack/sysdep_types.h +46 -0
  49. data/ext/msgpack/unpacker.c +771 -0
  50. data/ext/msgpack/unpacker.h +122 -0
  51. data/ext/msgpack/unpacker_class.c +405 -0
  52. data/ext/msgpack/unpacker_class.h +32 -0
  53. data/lib/msgpack.rb +13 -0
  54. data/lib/msgpack/version.rb +3 -0
  55. data/msgpack.gemspec +31 -0
  56. data/msgpack.org.md +46 -0
  57. data/spec/cases.json +1 -0
  58. data/spec/cases.msg +0 -0
  59. data/spec/cases_compact.msg +0 -0
  60. data/spec/cases_spec.rb +39 -0
  61. data/spec/cruby/buffer_io_spec.rb +256 -0
  62. data/spec/cruby/buffer_packer.rb +29 -0
  63. data/spec/cruby/buffer_spec.rb +572 -0
  64. data/spec/cruby/buffer_unpacker.rb +19 -0
  65. data/spec/cruby/packer_spec.rb +120 -0
  66. data/spec/cruby/unpacker_spec.rb +305 -0
  67. data/spec/format_spec.rb +282 -0
  68. data/spec/jruby/benchmarks/shootout_bm.rb +73 -0
  69. data/spec/jruby/benchmarks/symbolize_keys_bm.rb +25 -0
  70. data/spec/jruby/msgpack/unpacker_spec.rb +290 -0
  71. data/spec/jruby/msgpack_spec.rb +142 -0
  72. data/spec/pack_spec.rb +67 -0
  73. data/spec/random_compat.rb +24 -0
  74. data/spec/spec_helper.rb +27 -0
  75. data/spec/unpack_spec.rb +60 -0
  76. metadata +208 -0
@@ -0,0 +1,73 @@
1
+ # encoding: utf-8
2
+
3
+ if RUBY_PLATFORM.include?('java')
4
+ # JRuby should use this library, MRI should use the standard gem
5
+ $: << File.expand_path('../../../lib', __FILE__)
6
+ end
7
+
8
+ require 'viiite'
9
+ require 'msgpack'
10
+ require 'json'
11
+ require 'bson'
12
+
13
+ if RUBY_PLATFORM.include?('java')
14
+ BSON_IMPL = BSON::BSON_JAVA
15
+ else
16
+ BSON_IMPL = BSON::BSON_C
17
+ end
18
+
19
+ OBJECT_STRUCTURE = {'x' => ['y', 34, 2**30 + 3, 2.1223423423356, {'hello' => 'world', '5' => [63, 'asjdl']}]}
20
+ ENCODED_MSGPACK = "\x81\xA1x\x95\xA1y\"\xCE@\x00\x00\x03\xCB@\x00\xFA\x8E\x9F9\xFA\xC1\x82\xA5hello\xA5world\xA15\x92?\xA5asjdl"
21
+ ENCODED_BSON = "d\x00\x00\x00\x04x\x00\\\x00\x00\x00\x020\x00\x02\x00\x00\x00y\x00\x101\x00\"\x00\x00\x00\x102\x00\x03\x00\x00@\x013\x00\xC1\xFA9\x9F\x8E\xFA\x00@\x034\x002\x00\x00\x00\x02hello\x00\x06\x00\x00\x00world\x00\x045\x00\x19\x00\x00\x00\x100\x00?\x00\x00\x00\x021\x00\x06\x00\x00\x00asjdl\x00\x00\x00\x00\x00"
22
+ ENCODED_JSON = '{"x":["y",34,1073741827,2.1223423423356,{"hello":"world","5":[63,"asjdl"]}]}'
23
+ ITERATIONS = 1_00_000
24
+ IMPLEMENTATIONS = ENV.fetch('IMPLEMENTATIONS', 'json,bson,msgpack').split(',').map(&:to_sym)
25
+
26
+ Viiite.bm do |b|
27
+ b.variation_point :ruby, Viiite.which_ruby
28
+
29
+ IMPLEMENTATIONS.each do |lib|
30
+ b.variation_point :lib, lib
31
+
32
+
33
+ b.report(:pack) do
34
+ ITERATIONS.times do
35
+ case lib
36
+ when :msgpack then MessagePack.pack(OBJECT_STRUCTURE)
37
+ when :bson then BSON_IMPL.serialize(OBJECT_STRUCTURE).to_s
38
+ when :json then OBJECT_STRUCTURE.to_json
39
+ end
40
+ end
41
+ end
42
+
43
+ b.report(:unpack) do
44
+ ITERATIONS.times do
45
+ case lib
46
+ when :msgpack then MessagePack.unpack(ENCODED_MSGPACK)
47
+ when :bson then BSON_IMPL.deserialize(ENCODED_BSON)
48
+ when :json then JSON.parse(ENCODED_JSON)
49
+ end
50
+ end
51
+ end
52
+
53
+ b.report(:pack_unpack) do
54
+ ITERATIONS.times do
55
+ case lib
56
+ when :msgpack then MessagePack.unpack(MessagePack.pack(OBJECT_STRUCTURE))
57
+ when :bson then BSON_IMPL.deserialize(BSON_IMPL.serialize(OBJECT_STRUCTURE).to_s)
58
+ when :json then JSON.parse(OBJECT_STRUCTURE.to_json)
59
+ end
60
+ end
61
+ end
62
+
63
+ b.report(:unpack_pack) do
64
+ ITERATIONS.times do
65
+ case lib
66
+ when :msgpack then MessagePack.pack(MessagePack.unpack(ENCODED_MSGPACK))
67
+ when :bson then BSON_IMPL.serialize(BSON_IMPL.deserialize(ENCODED_BSON)).to_s
68
+ when :json then OBJECT_STRUCTURE.to_json(JSON.parse(ENCODED_JSON))
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,25 @@
1
+ # encoding: utf-8
2
+
3
+ $: << File.expand_path('../../../lib', __FILE__)
4
+
5
+ require 'viiite'
6
+ require 'msgpack'
7
+
8
+
9
+ iterations = 10_000
10
+ data = MessagePack.pack(:hello => 'world', :nested => ['structure', {:value => 42}])
11
+
12
+ Viiite.bm do |b|
13
+ b.report(:strings) do
14
+ iterations.times do
15
+ MessagePack.unpack(data)
16
+ end
17
+ end
18
+
19
+ b.report(:symbols) do
20
+ options = {:symbolize_keys => true}
21
+ iterations.times do
22
+ MessagePack.unpack(data, options)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,290 @@
1
+ # encoding: ascii-8bit
2
+
3
+ require 'stringio'
4
+ require 'tempfile'
5
+ require 'spec_helper'
6
+
7
+
8
+ describe ::MessagePack::Unpacker do
9
+ def flatten(struct, results = [])
10
+ case struct
11
+ when Array
12
+ struct.each { |v| flatten(v, results) }
13
+ when Hash
14
+ struct.each { |k, v| flatten(v, flatten(k, results)) }
15
+ else
16
+ results << struct
17
+ end
18
+ results
19
+ end
20
+
21
+ subject do
22
+ described_class.new
23
+ end
24
+
25
+ let :buffer1 do
26
+ MessagePack.pack(:foo => 'bar')
27
+ end
28
+
29
+ let :buffer2 do
30
+ MessagePack.pack(:hello => {:world => [1, 2, 3]})
31
+ end
32
+
33
+ let :buffer3 do
34
+ MessagePack.pack(:x => 'y')
35
+ end
36
+
37
+ describe '#execute/#execute_limit/#finished?' do
38
+ let :buffer do
39
+ buffer1 + buffer2 + buffer3
40
+ end
41
+
42
+ it 'extracts an object from the buffer' do
43
+ subject.execute(buffer, 0)
44
+ subject.data.should == {'foo' => 'bar'}
45
+ end
46
+
47
+ it 'extracts an object from the buffer, starting at an offset' do
48
+ subject.execute(buffer, buffer1.length)
49
+ subject.data.should == {'hello' => {'world' => [1, 2, 3]}}
50
+ end
51
+
52
+ it 'extracts an object from the buffer, starting at an offset reading bytes up to a limit' do
53
+ subject.execute_limit(buffer, buffer1.length, buffer2.length)
54
+ subject.data.should == {'hello' => {'world' => [1, 2, 3]}}
55
+ end
56
+
57
+ it 'extracts nothing if the limit cuts an object in half' do
58
+ subject.execute_limit(buffer, buffer1.length, 3)
59
+ subject.data.should be_nil
60
+ end
61
+
62
+ it 'returns the offset where the object ended' do
63
+ subject.execute(buffer, 0).should == buffer1.length
64
+ subject.execute(buffer, buffer1.length).should == buffer1.length + buffer2.length
65
+ end
66
+
67
+ it 'is finished if #data returns an object' do
68
+ subject.execute_limit(buffer, buffer1.length, buffer2.length)
69
+ subject.should be_finished
70
+
71
+ subject.execute_limit(buffer, buffer1.length, 3)
72
+ subject.should_not be_finished
73
+ end
74
+ end
75
+
76
+ describe '#each' do
77
+ context 'with a buffer' do
78
+ it 'yields each object in the buffer' do
79
+ objects = []
80
+ subject.feed(buffer1)
81
+ subject.feed(buffer2)
82
+ subject.feed(buffer3)
83
+ subject.each do |obj|
84
+ objects << obj
85
+ end
86
+ objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}]
87
+ end
88
+
89
+ it 'returns an enumerator when no block is given' do
90
+ subject.feed(buffer1)
91
+ subject.feed(buffer2)
92
+ subject.feed(buffer3)
93
+ enum = subject.each
94
+ enum.map { |obj| obj.keys.first }.should == %w[foo hello x]
95
+ end
96
+ end
97
+
98
+ context 'with a StringIO stream' do
99
+ it 'yields each object in the stream' do
100
+ objects = []
101
+ subject.stream = StringIO.new(buffer1 + buffer2 + buffer3)
102
+ subject.each do |obj|
103
+ objects << obj
104
+ end
105
+ objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}]
106
+ end
107
+ end
108
+
109
+ context 'with a File stream' do
110
+ it 'yields each object in the stream' do
111
+ objects = []
112
+ file = Tempfile.new('msgpack')
113
+ file.write(buffer1)
114
+ file.write(buffer2)
115
+ file.write(buffer3)
116
+ file.open
117
+ subject.stream = file
118
+ subject.each do |obj|
119
+ objects << obj
120
+ end
121
+ objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}]
122
+ end
123
+ end
124
+
125
+ context 'with a stream passed to the constructor' do
126
+ it 'yields each object in the stream' do
127
+ objects = []
128
+ unpacker = described_class.new(StringIO.new(buffer1 + buffer2 + buffer3))
129
+ unpacker.each do |obj|
130
+ objects << obj
131
+ end
132
+ objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}]
133
+ end
134
+ end
135
+ end
136
+
137
+ describe '#feed_each' do
138
+ it 'feeds the buffer then runs #each' do
139
+ objects = []
140
+ subject.feed_each(buffer1 + buffer2 + buffer3) do |obj|
141
+ objects << obj
142
+ end
143
+ objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}]
144
+ end
145
+
146
+ it 'handles chunked data' do
147
+ objects = []
148
+ buffer = buffer1 + buffer2 + buffer3
149
+ buffer.chars.each do |ch|
150
+ subject.feed_each(ch) do |obj|
151
+ objects << obj
152
+ end
153
+ end
154
+ objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}]
155
+ end
156
+ end
157
+
158
+ describe '#fill' do
159
+ it 'is a no-op' do
160
+ subject.stream = StringIO.new(buffer1 + buffer2 + buffer3)
161
+ subject.fill
162
+ subject.each { |obj| }
163
+ end
164
+ end
165
+
166
+ describe '#reset' do
167
+ context 'with a buffer' do
168
+ it 'is unclear what it is supposed to do'
169
+ end
170
+
171
+ context 'with a stream' do
172
+ it 'is unclear what it is supposed to do'
173
+ end
174
+ end
175
+
176
+ context 'regressions' do
177
+ it 'handles massive arrays (issue #2)' do
178
+ array = ['foo'] * 10_000
179
+ MessagePack.unpack(MessagePack.pack(array)).should have(10_000).items
180
+ end
181
+ end
182
+
183
+ context 'encoding', :encodings do
184
+ before :all do
185
+ @default_internal = Encoding.default_internal
186
+ @default_external = Encoding.default_external
187
+ end
188
+
189
+ after :all do
190
+ Encoding.default_internal = @default_internal
191
+ Encoding.default_external = @default_external
192
+ end
193
+
194
+ let :buffer do
195
+ MessagePack.pack({'hello' => 'world', 'nested' => ['object', {"sk\xC3\xA5l".force_encoding('utf-8') => true}]})
196
+ end
197
+
198
+ let :unpacker do
199
+ described_class.new
200
+ end
201
+
202
+ before do
203
+ Encoding.default_internal = Encoding::UTF_8
204
+ Encoding.default_external = Encoding::ISO_8859_1
205
+ end
206
+
207
+ it 'produces results with default internal encoding' do
208
+ unpacker.execute(buffer, 0)
209
+ strings = flatten(unpacker.data).grep(String)
210
+ strings.map(&:encoding).uniq.should == [Encoding.default_internal]
211
+ end
212
+
213
+ it 'recodes to internal encoding' do
214
+ unpacker.execute(buffer, 0)
215
+ unpacker.data['nested'][1].keys.should == ["sk\xC3\xA5l".force_encoding(Encoding.default_internal)]
216
+ end
217
+ end
218
+
219
+ context 'extensions' do
220
+ context 'symbolized keys' do
221
+ let :buffer do
222
+ MessagePack.pack({'hello' => 'world', 'nested' => ['object', {'structure' => true}]})
223
+ end
224
+
225
+ let :unpacker do
226
+ described_class.new(:symbolize_keys => true)
227
+ end
228
+
229
+ it 'can symbolize keys when using #execute' do
230
+ unpacker.execute(buffer, 0)
231
+ unpacker.data.should == {:hello => 'world', :nested => ['object', {:structure => true}]}
232
+ end
233
+
234
+ it 'can symbolize keys when using #each' do
235
+ objs = []
236
+ unpacker.feed(buffer)
237
+ unpacker.each do |obj|
238
+ objs << obj
239
+ end
240
+ objs.should == [{:hello => 'world', :nested => ['object', {:structure => true}]}]
241
+ end
242
+
243
+ it 'can symbolize keys when using #feed_each' do
244
+ objs = []
245
+ unpacker.feed_each(buffer) do |obj|
246
+ objs << obj
247
+ end
248
+ objs.should == [{:hello => 'world', :nested => ['object', {:structure => true}]}]
249
+ end
250
+ end
251
+
252
+ context 'encoding', :encodings do
253
+ let :buffer do
254
+ MessagePack.pack({'hello' => 'world', 'nested' => ['object', {'structure' => true}]})
255
+ end
256
+
257
+ let :unpacker do
258
+ described_class.new(:encoding => 'UTF-8')
259
+ end
260
+
261
+ it 'can hardcode encoding when using #execute' do
262
+ unpacker.execute(buffer, 0)
263
+ strings = flatten(unpacker.data).grep(String)
264
+ strings.should == %w[hello world nested object structure]
265
+ strings.map(&:encoding).uniq.should == [Encoding::UTF_8]
266
+ end
267
+
268
+ it 'can hardcode encoding when using #each' do
269
+ objs = []
270
+ unpacker.feed(buffer)
271
+ unpacker.each do |obj|
272
+ objs << obj
273
+ end
274
+ strings = flatten(objs).grep(String)
275
+ strings.should == %w[hello world nested object structure]
276
+ strings.map(&:encoding).uniq.should == [Encoding::UTF_8]
277
+ end
278
+
279
+ it 'can hardcode encoding when using #feed_each' do
280
+ objs = []
281
+ unpacker.feed_each(buffer) do |obj|
282
+ objs << obj
283
+ end
284
+ strings = flatten(objs).grep(String)
285
+ strings.should == %w[hello world nested object structure]
286
+ strings.map(&:encoding).uniq.should == [Encoding::UTF_8]
287
+ end
288
+ end
289
+ end
290
+ end
@@ -0,0 +1,142 @@
1
+ # encoding: ascii-8bit
2
+
3
+ require 'spec_helper'
4
+
5
+ def utf8enc(str)
6
+ str.encode('UTF-8')
7
+ end
8
+
9
+ def asciienc(str)
10
+ str.encode('ASCII-8BIT')
11
+ end
12
+
13
+ describe MessagePack do
14
+ tests = {
15
+ 'constant values' => [
16
+ ['true', true, "\xC3"],
17
+ ['false', false, "\xC2"],
18
+ ['nil', nil, "\xC0"]
19
+ ],
20
+ 'numbers' => [
21
+ ['zero', 0, "\x00"],
22
+ ['127', 127, "\x7F"],
23
+ ['128', 128, "\xCC\x80"],
24
+ ['256', 256, "\xCD\x01\x00"],
25
+ ['-1', -1, "\xFF"],
26
+ ['-33', -33, "\xD0\xDF"],
27
+ ['-129', -129, "\xD1\xFF\x7F"],
28
+ ['small integers', 42, "*"],
29
+ ['medium integers', 333, "\xCD\x01M"],
30
+ ['large integers', 2**31 - 1, "\xCE\x7F\xFF\xFF\xFF"],
31
+ ['huge integers', 2**64 - 1, "\xCF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"],
32
+ ['negative integers', -1, "\xFF"],
33
+ ['1.0', 1.0, "\xcb\x3f\xf0\x00\x00\x00\x00\x00\x00"],
34
+ ['small floats', 3.14, "\xCB@\t\x1E\xB8Q\xEB\x85\x1F"],
35
+ ['big floats', Math::PI * 1_000_000_000_000_000_000, "\xCBC\xC5\xCC\x96\xEF\xD1\x19%"],
36
+ ['negative floats', -2.1, "\xCB\xC0\x00\xCC\xCC\xCC\xCC\xCC\xCD"]
37
+ ],
38
+ 'strings' => [
39
+ ['strings', utf8enc('hello world'), "\xABhello world"],
40
+ ['empty strings', utf8enc(''), "\xA0"]
41
+ ],
42
+ 'arrays' => [
43
+ ['empty arrays', [], "\x90"],
44
+ ['arrays with strings', [utf8enc("hello"), utf8enc("world")], "\x92\xA5hello\xA5world"],
45
+ ['arrays with mixed values', [utf8enc("hello"), utf8enc("world"), 42], "\x93\xA5hello\xA5world*"],
46
+ ['arrays of arrays', [[[[1, 2], 3], 4]], "\x91\x92\x92\x92\x01\x02\x03\x04"],
47
+ ['empty arrays', [], "\x90"]
48
+ ],
49
+ 'hashes' => [
50
+ ['empty hashes', {}, "\x80"],
51
+ ['hashes', {utf8enc('foo') => utf8enc('bar')}, "\x81\xA3foo\xA3bar"],
52
+ ['hashes with mixed keys and values', {utf8enc('foo') => utf8enc('bar'), 3 => utf8enc('three'), utf8enc('four') => 4, utf8enc('x') => [utf8enc('y')], utf8enc('a') => utf8enc('b')}, "\x85\xA3foo\xA3bar\x03\xA5three\xA4four\x04\xA1x\x91\xA1y\xA1a\xA1b"],
53
+ ['hashes of hashes', {{utf8enc('x') => {utf8enc('y') => utf8enc('z')}} => utf8enc('s')}, "\x81\x81\xA1x\x81\xA1y\xA1z\xA1s"],
54
+ ['hashes with nils', {utf8enc('foo') => nil}, "\x81\xA3foo\xC0"]
55
+ ]
56
+ }
57
+
58
+ tests.each do |ctx, its|
59
+ context("with #{ctx}") do
60
+ its.each do |desc, unpacked, packed|
61
+ it("encodes #{desc}") do
62
+ MessagePack.pack(unpacked).should == packed
63
+ end
64
+
65
+ it "decodes #{desc}" do
66
+ MessagePack.unpack(packed).should == unpacked
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ context 'using other names for .pack and .unpack' do
73
+ it 'can unpack with .load' do
74
+ MessagePack.load("\xABhello world").should == 'hello world'
75
+ end
76
+
77
+ it 'can pack with .dump' do
78
+ MessagePack.dump(utf8enc('hello world')).should == "\xABhello world"
79
+ end
80
+ end
81
+
82
+ context 'with symbols' do
83
+ it 'encodes symbols as strings' do
84
+ MessagePack.pack(:symbol).should == "\xA6symbol"
85
+ end
86
+ end
87
+
88
+ context 'with different external encoding', :encodings do
89
+ before do
90
+ @default_external = Encoding.default_external
91
+ @default_internal = Encoding.default_internal
92
+ Encoding.default_external = Encoding::UTF_8
93
+ Encoding.default_internal = Encoding::ISO_8859_1
94
+ end
95
+
96
+ after do
97
+ Encoding.default_external = @default_external
98
+ Encoding.default_internal = @default_internal
99
+ end
100
+
101
+ it 'transcodes strings when encoding' do
102
+ input = "sk\xE5l".force_encoding(Encoding::ISO_8859_1)
103
+ MessagePack.pack(input).should == "\xA5sk\xC3\xA5l"
104
+ end
105
+ end
106
+
107
+ context 'with other things' do
108
+ it 'raises an error on #pack with an unsupported type' do
109
+ expect { MessagePack.pack(self) }.to raise_error(ArgumentError, /^Cannot pack type:/)
110
+ end
111
+
112
+ it 'rasies an error on #unpack with garbage' do
113
+ skip "???"
114
+ expect { MessagePack.unpack('asdka;sd') }.to raise_error(MessagePack::UnpackError)
115
+ end
116
+ end
117
+
118
+ context 'extensions' do
119
+ it 'can unpack hashes with symbolized keys' do
120
+ packed = MessagePack.pack({'hello' => 'world', 'nested' => ['object', {'structure' => true}]})
121
+ unpacked = MessagePack.unpack(packed, :symbolize_keys => true)
122
+ unpacked.should == {:hello => 'world', :nested => ['object', {:structure => true}]}
123
+ end
124
+
125
+ it 'does not symbolize keys even if other options are present' do
126
+ packed = MessagePack.pack({'hello' => 'world', 'nested' => ['object', {'structure' => true}]})
127
+ unpacked = MessagePack.unpack(packed, :other_option => false)
128
+ unpacked.should == {'hello' => 'world', 'nested' => ['object', {'structure' => true}]}
129
+ end
130
+
131
+ it 'can unpack strings with a specified encoding', :encodings do
132
+ packed = MessagePack.pack({utf8enc('hello') => utf8enc('world')})
133
+ unpacked = MessagePack.unpack(packed)
134
+ unpacked['hello'].encoding.should == Encoding::UTF_8
135
+ end
136
+
137
+ it 'can pack strings with a specified encoding', :encodings do
138
+ packed = MessagePack.pack({'hello' => "w\xE5rld".force_encoding(Encoding::ISO_8859_1)})
139
+ packed.index("w\xC3\xA5rld").should_not be_nil
140
+ end
141
+ end
142
+ end