Skip to content

Commit

Permalink
Amending specs for Array#pack('U')
Browse files Browse the repository at this point in the history
* rbx is now passing most specs
* failing specs are due to String#unpack.

Signed-off-by: Brian Ford <bford@engineyard.com>
  • Loading branch information
ashelly authored and Brian Ford committed Feb 27, 2008
1 parent 328c40e commit b239a3b
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 10 deletions.
44 changes: 44 additions & 0 deletions kernel/core/array.rb
Expand Up @@ -906,6 +906,7 @@ def self.after_loaded
BASE_64_ALPHA[63] = ?/
end


# TODO fill out pack.
def pack(schema)
# The schema is an array of arrays like [["A", "6"], ["u", "*"], ["X", ""]]. It represents the parsed
Expand Down Expand Up @@ -1169,6 +1170,47 @@ def pack(schema)

arr_idx += 1
ret << str

elsif kind == 'U'
#converts the number passed, or all for * or 1 if missing
count = !t ? 1 : (t == "*" ? self.size-arr_idx : t.to_i)
raise ArgumentError, "too few array elements" if arr_idx + count > self.length

count.times do
item = Type.coerce_to(self[arr_idx], Integer, :to_i)
raise RangeError, "pack(U): value out of range" if item < 0
#handle the simple case and move on
if item < 0x80
ret << item
i=0
#else count the bytes needed
elsif item < 0x800
i = bytes = 2
elsif item < 0x10000
i = bytes = 3
elsif item < 0x200000
i = bytes = 4
elsif item < 0x4000000
i = bytes = 5
elsif item <= 0x7FFFFFFF
i = bytes = 6
else
raise RangeError, "pack(U): value out of range"
end
if i>0
#make room
ret<<' '*bytes
#fill backwards: put the least significant bits at the end
# shift the next set down, and repeat
while 0 < i-=1
ret[i-bytes] = (item | 0x80) & 0xBF
item >>= 6
end
#catch the highest bits - the mask depends on the byte count
ret[-bytes] = (item | ((0x3F00>>bytes)) & 0xFC)
end
arr_idx += 1
end
else
raise ArgumentError, "Unknown kind #{kind}"
end
Expand Down Expand Up @@ -1907,3 +1949,5 @@ def isort_block!(left, right, block)
private :qsort_block
private :isort_block
end
35 changes: 25 additions & 10 deletions spec/ruby/1.8/core/array/pack_spec.rb
Expand Up @@ -600,20 +600,35 @@ class X; def to_s; "unnamed object"; end; end
end

it "converts integers into UTF-8 encoded byte sequences with ('U')" do
numbers = [0, 1, 15, 16, 127,
128, 255, 256, 1024]
numbers.each do |n|
[n].pack('U').unpack('U').should == [n]
end
[0x7F, 0x7F].pack('U*').should == "\x7F\x7F"
[262193, 4736, 191, 12, 107].pack('U*').should == "\xF1\x80\x80\xB1\xE1\x8A\x80\xC2\xBF\x0C\x6B"
[2**16+1, 2**30].pack('U2').should == "\360\220\200\201\375\200\200\200\200\200"

lambda { [].pack('U') }.should raise_error(ArgumentError)
lambda { [1].pack('UU') }.should raise_error(ArgumentError)
lambda { [2**32].pack('U') }.should raise_error(RangeError)
lambda { [-1].pack('U') }.should raise_error(RangeError)
lambda { [-5].pack('U') }.should raise_error(RangeError)
lambda { [-2**32].pack('U') }.should raise_error(RangeError)
end

it "only takes as many elements as specified after ('U')" do
[?a,?b,?c].pack('U2').should == "ab"
end

it "converts big integers into UTF-8 encoded byte sequences with ('U')" do
#these are actually failing on String#unpack
# they are not passing the 'utf8_regex_strict' test
compliant_on :ruby, :jruby do
numbers = [0, 1, 15, 16, 127,
128, 255, 256, 1024, 2048, 4096, 2**16 -1, 2**16, 2**16 + 1, 2**30]
numbers = [ 2048, 4096, 2**16 -1, 2**16, 2**16 + 1, 2**30]
numbers.each do |n|
[n].pack('U').unpack('U').should == [n]
end
[0x7F, 0x7F].pack('U*').should == "\x7F\x7F"
[262193, 4736, 191, 12, 107].pack('U*').should == "\xF1\x80\x80\xB1\xE1\x8A\x80\xC2\xBF\x0C\x6B"
lambda { [].pack('U') }.should raise_error(ArgumentError)
lambda { [1].pack('UU') }.should raise_error(ArgumentError)
lambda { [2**32].pack('U') }.should raise_error(RangeError)
lambda { [-1].pack('U') }.should raise_error(RangeError)
lambda { [-5].pack('U') }.should raise_error(RangeError)
lambda { [-2**32].pack('U') }.should raise_error(RangeError)
end
end

Expand Down

0 comments on commit b239a3b

Please sign in to comment.