1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
|
# encoding: ascii-8bit
require 'stringio'
require 'tempfile'
require 'spec_helper'
describe MessagePack::Unpacker do
let :unpacker do
MessagePack::Unpacker.new
end
let :packer do
MessagePack::Packer.new
end
let :buffer1 do
MessagePack.pack(:foo => 'bar')
end
let :buffer2 do
MessagePack.pack(:hello => {:world => [1, 2, 3]})
end
let :buffer3 do
MessagePack.pack(:x => 'y')
end
describe '#execute/#execute_limit/#finished?' do
let :buffer do
buffer1 + buffer2 + buffer3
end
it 'extracts an object from the buffer' do
subject.execute(buffer, 0)
subject.data.should == {'foo' => 'bar'}
end
it 'extracts an object from the buffer, starting at an offset' do
subject.execute(buffer, buffer1.length)
subject.data.should == {'hello' => {'world' => [1, 2, 3]}}
end
it 'extracts an object from the buffer, starting at an offset reading bytes up to a limit' do
subject.execute_limit(buffer, buffer1.length, buffer2.length)
subject.data.should == {'hello' => {'world' => [1, 2, 3]}}
end
it 'extracts nothing if the limit cuts an object in half' do
subject.execute_limit(buffer, buffer1.length, 3)
subject.data.should be_nil
end
it 'returns the offset where the object ended' do
subject.execute(buffer, 0).should == buffer1.length
subject.execute(buffer, buffer1.length).should == buffer1.length + buffer2.length
end
it 'is finished if #data returns an object' do
subject.execute_limit(buffer, buffer1.length, buffer2.length)
subject.should be_finished
subject.execute_limit(buffer, buffer1.length, 3)
subject.should_not be_finished
end
end
describe '#each' do
context 'with a StringIO stream' do
it 'yields each object in the stream' do
objects = []
subject.stream = StringIO.new(buffer1 + buffer2 + buffer3)
subject.each do |obj|
objects << obj
end
objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}]
end
end
context 'with a File stream' do
it 'yields each object in the stream' do
objects = []
file = Tempfile.new('msgpack')
file.write(buffer1)
file.write(buffer2)
file.write(buffer3)
file.open
subject.stream = file
subject.each do |obj|
objects << obj
end
objects.should == [{'foo' => 'bar'}, {'hello' => {'world' => [1, 2, 3]}}, {'x' => 'y'}]
end
end
end
describe '#fill' do
it 'is a no-op' do
subject.stream = StringIO.new(buffer1 + buffer2 + buffer3)
subject.fill
subject.each { |obj| }
end
end
def flatten(struct, results = [])
case struct
when Array
struct.each { |v| flatten(v, results) }
when Hash
struct.each { |k, v| flatten(v, flatten(k, results)) }
else
results << struct
end
results
end
context 'encoding', :encodings do
before :all do
@default_internal = Encoding.default_internal
@default_external = Encoding.default_external
end
after :all do
Encoding.default_internal = @default_internal
Encoding.default_external = @default_external
end
let :buffer do
MessagePack.pack({'hello' => 'world', 'nested' => ['object', {"sk\xC3\xA5l".force_encoding('utf-8') => true}]})
end
let :unpacker do
described_class.new
end
before do
Encoding.default_internal = Encoding::UTF_8
Encoding.default_external = Encoding::ISO_8859_1
end
it 'produces results with encoding as binary or string(utf8)' do
unpacker.execute(buffer, 0)
strings = flatten(unpacker.data).grep(String)
strings.map(&:encoding).uniq.sort{|a,b| a.to_s <=> b.to_s}.should == [Encoding::ASCII_8BIT, Encoding::UTF_8]
end
it 'recodes to internal encoding' do
unpacker.execute(buffer, 0)
unpacker.data['nested'][1].keys.should == ["sk\xC3\xA5l".force_encoding(Encoding::UTF_8)]
end
end
context 'extensions' do
context 'symbolized keys' do
let :buffer do
MessagePack.pack({'hello' => 'world', 'nested' => ['object', {'structure' => true}]})
end
let :unpacker do
described_class.new(:symbolize_keys => true)
end
it 'can symbolize keys when using #execute' do
unpacker.execute(buffer, 0)
unpacker.data.should == {:hello => 'world', :nested => ['object', {:structure => true}]}
end
end
context 'encoding', :encodings do
let :buffer do
MessagePack.pack({'hello' => 'world', 'nested' => ['object', {'structure' => true}]})
end
let :unpacker do
described_class.new()
end
it 'decode binary as ascii-8bit string when using #execute' do
unpacker.execute(buffer, 0)
strings = flatten(unpacker.data).grep(String)
strings.should == %w[hello world nested object structure]
strings.map(&:encoding).uniq.should == [Encoding::ASCII_8BIT]
end
end
end
end
|