diff options
Diffstat (limited to 'spec/rubyspec/core/array/pack/shared')
-rw-r--r-- | spec/rubyspec/core/array/pack/shared/basic.rb | 65 | ||||
-rw-r--r-- | spec/rubyspec/core/array/pack/shared/encodings.rb | 16 | ||||
-rw-r--r-- | spec/rubyspec/core/array/pack/shared/float.rb | 249 | ||||
-rw-r--r-- | spec/rubyspec/core/array/pack/shared/integer.rb | 381 | ||||
-rw-r--r-- | spec/rubyspec/core/array/pack/shared/numeric_basic.rb | 44 | ||||
-rw-r--r-- | spec/rubyspec/core/array/pack/shared/string.rb | 80 | ||||
-rw-r--r-- | spec/rubyspec/core/array/pack/shared/unicode.rb | 94 |
7 files changed, 929 insertions, 0 deletions
diff --git a/spec/rubyspec/core/array/pack/shared/basic.rb b/spec/rubyspec/core/array/pack/shared/basic.rb new file mode 100644 index 0000000000..39ab15308d --- /dev/null +++ b/spec/rubyspec/core/array/pack/shared/basic.rb @@ -0,0 +1,65 @@ +describe :array_pack_arguments, shared: true do + it "raises an ArgumentError if there are fewer elements than the format requires" do + lambda { [].pack(pack_format(1)) }.should raise_error(ArgumentError) + end +end + +describe :array_pack_basic, shared: true do + before :each do + @obj = ArraySpecs.universal_pack_object + end + + it "raises a TypeError when passed nil" do + lambda { [@obj].pack(nil) }.should raise_error(TypeError) + end + + it "raises a TypeError when passed an Integer" do + lambda { [@obj].pack(1) }.should raise_error(TypeError) + end +end + +describe :array_pack_basic_non_float, shared: true do + before :each do + @obj = ArraySpecs.universal_pack_object + end + + it "ignores whitespace in the format string" do + [@obj, @obj].pack("a \t\n\v\f\r"+pack_format).should be_an_instance_of(String) + end + + it "calls #to_str to coerce the directives string" do + d = mock("pack directive") + d.should_receive(:to_str).and_return("x"+pack_format) + [@obj, @obj].pack(d).should be_an_instance_of(String) + end + + it "taints the output string if the format string is tainted" do + [@obj, @obj].pack("x"+pack_format.taint).tainted?.should be_true + end +end + +describe :array_pack_basic_float, shared: true do + it "ignores whitespace in the format string" do + [9.3, 4.7].pack(" \t\n\v\f\r"+pack_format).should be_an_instance_of(String) + end + + it "calls #to_str to coerce the directives string" do + d = mock("pack directive") + d.should_receive(:to_str).and_return("x"+pack_format) + [1.2, 4.7].pack(d).should be_an_instance_of(String) + end + + it "taints the output string if the format string is tainted" do + [3.2, 2.8].pack("x"+pack_format.taint).tainted?.should be_true + end +end + +describe :array_pack_no_platform, shared: true do + it "raises ArgumentError when the format modifier is '_'" do + lambda{ [1].pack(pack_format("_")) }.should raise_error(ArgumentError) + end + + it "raises ArgumentError when the format modifier is '!'" do + lambda{ [1].pack(pack_format("!")) }.should raise_error(ArgumentError) + end +end diff --git a/spec/rubyspec/core/array/pack/shared/encodings.rb b/spec/rubyspec/core/array/pack/shared/encodings.rb new file mode 100644 index 0000000000..3724a5d859 --- /dev/null +++ b/spec/rubyspec/core/array/pack/shared/encodings.rb @@ -0,0 +1,16 @@ +describe :array_pack_hex, shared: true do + it "encodes no bytes when passed zero as the count modifier" do + ["abc"].pack(pack_format(0)).should == "" + end + + it "raises a TypeError if the object does not respond to #to_str" do + obj = mock("pack hex non-string") + lambda { [obj].pack(pack_format) }.should raise_error(TypeError) + end + + it "raises a TypeError if #to_str does not return a String" do + obj = mock("pack hex non-string") + obj.should_receive(:to_str).and_return(1) + lambda { [obj].pack(pack_format) }.should raise_error(TypeError) + end +end diff --git a/spec/rubyspec/core/array/pack/shared/float.rb b/spec/rubyspec/core/array/pack/shared/float.rb new file mode 100644 index 0000000000..082de27acd --- /dev/null +++ b/spec/rubyspec/core/array/pack/shared/float.rb @@ -0,0 +1,249 @@ +# -*- encoding: ascii-8bit -*- + +describe :array_pack_float_le, shared: true do + it "encodes a positive Float" do + [1.42].pack(pack_format).should == "\x8f\xc2\xb5?" + end + + it "encodes a negative Float" do + [-34.2].pack(pack_format).should == "\xcd\xcc\x08\xc2" + end + + it "converts an Integer to a Float" do + [8].pack(pack_format).should == "\x00\x00\x00A" + end + + it "raises a TypeError if passed a String representation of a floating point number" do + lambda { ["13"].pack(pack_format) }.should raise_error(TypeError) + end + + it "encodes the number of array elements specified by the count modifier" do + [2.9, 1.4, 8.2].pack(pack_format(nil, 2)).should == "\x9a\x999@33\xb3?" + end + + it "encodes all remaining elements when passed the '*' modifier" do + [2.9, 1.4, 8.2].pack(pack_format("*")).should == "\x9a\x999@33\xb3?33\x03A" + end + + it "ignores NULL bytes between directives" do + [5.3, 9.2].pack(pack_format("\000", 2)).should == "\x9a\x99\xa9@33\x13A" + end + + it "ignores spaces between directives" do + [5.3, 9.2].pack(pack_format(" ", 2)).should == "\x9a\x99\xa9@33\x13A" + end + + it "encodes positive Infinity" do + [infinity_value].pack(pack_format).should == "\x00\x00\x80\x7f" + end + + it "encodes negative Infinity" do + [-infinity_value].pack(pack_format).should == "\x00\x00\x80\xff" + end + + platform_is "86" do # x86 / x86_64 + it "encodes NaN" do + [nan_value].pack(pack_format).should == "\x00\x00\xc0\xff" + end + end + + platform_is "powerpc64" do + it "encodes NaN" do + [nan_value].pack(pack_format).should == "\x00\x00\xc0\x7f" + end + end + + it "encodes a positive Float outside the range of a single precision float" do + [1e150].pack(pack_format).should == "\x00\x00\x80\x7f" + end + + it "encodes a negative Float outside the range of a single precision float" do + [-1e150].pack(pack_format).should == "\x00\x00\x80\xff" + end +end + +describe :array_pack_float_be, shared: true do + it "encodes a positive Float" do + [1.42].pack(pack_format).should == "?\xb5\xc2\x8f" + end + + it "encodes a negative Float" do + [-34.2].pack(pack_format).should == "\xc2\x08\xcc\xcd" + end + + it "converts an Integer to a Float" do + [8].pack(pack_format).should == "A\x00\x00\x00" + end + + it "raises a TypeError if passed a String representation of a floating point number" do + lambda { ["13"].pack(pack_format) }.should raise_error(TypeError) + end + + it "encodes the number of array elements specified by the count modifier" do + [2.9, 1.4, 8.2].pack(pack_format(nil, 2)).should == "@9\x99\x9a?\xb333" + end + + it "encodes all remaining elements when passed the '*' modifier" do + [2.9, 1.4, 8.2].pack(pack_format("*")).should == "@9\x99\x9a?\xb333A\x0333" + end + + it "ignores NULL bytes between directives" do + [5.3, 9.2].pack(pack_format("\000", 2)).should == "@\xa9\x99\x9aA\x1333" + end + + it "ignores spaces between directives" do + [5.3, 9.2].pack(pack_format(" ", 2)).should == "@\xa9\x99\x9aA\x1333" + end + + it "encodes positive Infinity" do + [infinity_value].pack(pack_format).should == "\x7f\x80\x00\x00" + end + + it "encodes negative Infinity" do + [-infinity_value].pack(pack_format).should == "\xff\x80\x00\x00" + end + + platform_is "86" do # x86 / x86_64 + it "encodes NaN" do + [nan_value].pack(pack_format).should == "\xff\xc0\x00\x00" + end + end + + platform_is "powerpc64" do + it "encodes NaN" do + [nan_value].pack(pack_format).should == "\x7f\xc0\x00\x00" + end + end + + it "encodes a positive Float outside the range of a single precision float" do + [1e150].pack(pack_format).should == "\x7f\x80\x00\x00" + end + + it "encodes a negative Float outside the range of a single precision float" do + [-1e150].pack(pack_format).should == "\xff\x80\x00\x00" + end +end + +describe :array_pack_double_le, shared: true do + it "encodes a positive Float" do + [1.42].pack(pack_format).should == "\xb8\x1e\x85\xebQ\xb8\xf6?" + end + + it "encodes a negative Float" do + [-34.2].pack(pack_format).should == "\x9a\x99\x99\x99\x99\x19A\xc0" + end + + it "converts an Integer to a Float" do + [8].pack(pack_format).should == "\x00\x00\x00\x00\x00\x00\x20@" + end + + it "raises a TypeError if passed a String representation of a floating point number" do + lambda { ["13"].pack(pack_format) }.should raise_error(TypeError) + end + + it "encodes the number of array elements specified by the count modifier" do + [2.9, 1.4, 8.2].pack(pack_format(nil, 2)).should == "333333\x07@ffffff\xf6?" + end + + it "encodes all remaining elements when passed the '*' modifier" do + [2.9, 1.4, 8.2].pack(pack_format("*")).should == "333333\x07@ffffff\xf6?ffffff\x20@" + end + + it "ignores NULL bytes between directives" do + [5.3, 9.2].pack(pack_format("\000", 2)).should == "333333\x15@ffffff\x22@" + end + + it "ignores spaces between directives" do + [5.3, 9.2].pack(pack_format(" ", 2)).should == "333333\x15@ffffff\x22@" + end + + it "encodes positive Infinity" do + [infinity_value].pack(pack_format).should == "\x00\x00\x00\x00\x00\x00\xf0\x7f" + end + + it "encodes negative Infinity" do + [-infinity_value].pack(pack_format).should == "\x00\x00\x00\x00\x00\x00\xf0\xff" + end + + platform_is "86" do # x86 / x86_64 + it "encodes NaN" do + [nan_value].pack(pack_format).should == "\x00\x00\x00\x00\x00\x00\xf8\xff" + end + end + + platform_is "powerpc64" do + it "encodes NaN" do + [nan_value].pack(pack_format).should == "\x00\x00\x00\x00\x00\x00\xf8\x7f" + end + end + + it "encodes a positive Float outside the range of a single precision float" do + [1e150].pack(pack_format).should == "\xaf\x96P\x2e5\x8d\x13_" + end + + it "encodes a negative Float outside the range of a single precision float" do + [-1e150].pack(pack_format).should == "\xaf\x96P\x2e5\x8d\x13\xdf" + end +end + +describe :array_pack_double_be, shared: true do + it "encodes a positive Float" do + [1.42].pack(pack_format).should == "?\xf6\xb8Q\xeb\x85\x1e\xb8" + end + + it "encodes a negative Float" do + [-34.2].pack(pack_format).should == "\xc0A\x19\x99\x99\x99\x99\x9a" + end + + it "converts an Integer to a Float" do + [8].pack(pack_format).should == "@\x20\x00\x00\x00\x00\x00\x00" + end + + it "raises a TypeError if passed a String representation of a floating point number" do + lambda { ["13"].pack(pack_format) }.should raise_error(TypeError) + end + + it "encodes the number of array elements specified by the count modifier" do + [2.9, 1.4, 8.2].pack(pack_format(nil, 2)).should == "@\x07333333?\xf6ffffff" + end + + it "encodes all remaining elements when passed the '*' modifier" do + [2.9, 1.4, 8.2].pack(pack_format("*")).should == "@\x07333333?\xf6ffffff@\x20ffffff" + end + + it "ignores NULL bytes between directives" do + [5.3, 9.2].pack(pack_format("\000", 2)).should == "@\x15333333@\x22ffffff" + end + + it "ignores spaces between directives" do + [5.3, 9.2].pack(pack_format(" ", 2)).should == "@\x15333333@\x22ffffff" + end + + it "encodes positive Infinity" do + [infinity_value].pack(pack_format).should == "\x7f\xf0\x00\x00\x00\x00\x00\x00" + end + + it "encodes negative Infinity" do + [-infinity_value].pack(pack_format).should == "\xff\xf0\x00\x00\x00\x00\x00\x00" + end + + platform_is "86" do # x86 / x86_64 + it "encodes NaN" do + [nan_value].pack(pack_format).should == "\xff\xf8\x00\x00\x00\x00\x00\x00" + end + end + + platform_is "powerpc64" do + it "encodes NaN" do + [nan_value].pack(pack_format).should == "\x7f\xf8\x00\x00\x00\x00\x00\x00" + end + end + + it "encodes a positive Float outside the range of a single precision float" do + [1e150].pack(pack_format).should == "_\x13\x8d5\x2eP\x96\xaf" + end + + it "encodes a negative Float outside the range of a single precision float" do + [-1e150].pack(pack_format).should == "\xdf\x13\x8d5\x2eP\x96\xaf" + end +end diff --git a/spec/rubyspec/core/array/pack/shared/integer.rb b/spec/rubyspec/core/array/pack/shared/integer.rb new file mode 100644 index 0000000000..0df03bbfd1 --- /dev/null +++ b/spec/rubyspec/core/array/pack/shared/integer.rb @@ -0,0 +1,381 @@ +# -*- encoding: ascii-8bit -*- + +describe :array_pack_16bit_le, shared: true do + it "encodes the least significant 16 bits of a positive number" do + [ [[0x0000_0021], "\x21\x00"], + [[0x0000_4321], "\x21\x43"], + [[0x0065_4321], "\x21\x43"], + [[0x7865_4321], "\x21\x43"] + ].should be_computed_by(:pack, pack_format()) + end + + it "encodes the least significant 16 bits of a negative number" do + [ [[-0x0000_0021], "\xdf\xff"], + [[-0x0000_4321], "\xdf\xbc"], + [[-0x0065_4321], "\xdf\xbc"], + [[-0x7865_4321], "\xdf\xbc"] + ].should be_computed_by(:pack, pack_format()) + end + + it "encodes a Float truncated as an Integer" do + [ [[2019902241.2], "\x21\x43"], + [[2019902241.8], "\x21\x43"], + [[-2019902241.2], "\xdf\xbc"], + [[-2019902241.8], "\xdf\xbc"] + ].should be_computed_by(:pack, pack_format()) + end + + it "calls #to_int to convert the pack argument to an Integer" do + obj = mock('to_int') + obj.should_receive(:to_int).and_return(0x1234_5678) + [obj].pack(pack_format()).should == "\x78\x56" + end + + it "encodes the number of array elements specified by the count modifier" do + str = [0x1243_6578, 0xdef0_abcd, 0x7865_4321].pack(pack_format(2)) + str.should == "\x78\x65\xcd\xab" + end + + it "encodes all remaining elements when passed the '*' modifier" do + str = [0x1243_6578, 0xdef0_abcd, 0x7865_4321].pack(pack_format('*')) + str.should == "\x78\x65\xcd\xab\x21\x43" + end + + it "ignores NULL bytes between directives" do + str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) + str.should == "\x78\x65\xcd\xab" + end + + it "ignores spaces between directives" do + str = [0x1243_6578, 0xdef0_abcd].pack(pack_format(' ', 2)) + str.should == "\x78\x65\xcd\xab" + end +end + +describe :array_pack_16bit_be, shared: true do + it "encodes the least significant 16 bits of a positive number" do + [ [[0x0000_0021], "\x00\x21"], + [[0x0000_4321], "\x43\x21"], + [[0x0065_4321], "\x43\x21"], + [[0x7865_4321], "\x43\x21"] + ].should be_computed_by(:pack, pack_format()) + end + + it "encodes the least significant 16 bits of a negative number" do + [ [[-0x0000_0021], "\xff\xdf"], + [[-0x0000_4321], "\xbc\xdf"], + [[-0x0065_4321], "\xbc\xdf"], + [[-0x7865_4321], "\xbc\xdf"] + ].should be_computed_by(:pack, pack_format()) + end + + it "encodes a Float truncated as an Integer" do + [ [[2019902241.2], "\x43\x21"], + [[2019902241.8], "\x43\x21"], + [[-2019902241.2], "\xbc\xdf"], + [[-2019902241.8], "\xbc\xdf"] + ].should be_computed_by(:pack, pack_format()) + end + + it "calls #to_int to convert the pack argument to an Integer" do + obj = mock('to_int') + obj.should_receive(:to_int).and_return(0x1234_5678) + [obj].pack(pack_format()).should == "\x56\x78" + end + + it "encodes the number of array elements specified by the count modifier" do + str = [0x1243_6578, 0xdef0_abcd, 0x7865_4321].pack(pack_format(2)) + str.should == "\x65\x78\xab\xcd" + end + + it "encodes all remaining elements when passed the '*' modifier" do + str = [0x1243_6578, 0xdef0_abcd, 0x7865_4321].pack(pack_format('*')) + str.should == "\x65\x78\xab\xcd\x43\x21" + end + + it "ignores NULL bytes between directives" do + str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) + str.should == "\x65\x78\xab\xcd" + end + + it "ignores spaces between directives" do + str = [0x1243_6578, 0xdef0_abcd].pack(pack_format(' ', 2)) + str.should == "\x65\x78\xab\xcd" + end +end + +describe :array_pack_32bit_le, shared: true do + it "encodes the least significant 32 bits of a positive number" do + [ [[0x0000_0021], "\x21\x00\x00\x00"], + [[0x0000_4321], "\x21\x43\x00\x00"], + [[0x0065_4321], "\x21\x43\x65\x00"], + [[0x7865_4321], "\x21\x43\x65\x78"] + ].should be_computed_by(:pack, pack_format()) + end + + it "encodes the least significant 32 bits of a negative number" do + [ [[-0x0000_0021], "\xdf\xff\xff\xff"], + [[-0x0000_4321], "\xdf\xbc\xff\xff"], + [[-0x0065_4321], "\xdf\xbc\x9a\xff"], + [[-0x7865_4321], "\xdf\xbc\x9a\x87"] + ].should be_computed_by(:pack, pack_format()) + end + + it "encodes a Float truncated as an Integer" do + [ [[2019902241.2], "\x21\x43\x65\x78"], + [[2019902241.8], "\x21\x43\x65\x78"], + [[-2019902241.2], "\xdf\xbc\x9a\x87"], + [[-2019902241.8], "\xdf\xbc\x9a\x87"] + ].should be_computed_by(:pack, pack_format()) + end + + it "calls #to_int to convert the pack argument to an Integer" do + obj = mock('to_int') + obj.should_receive(:to_int).and_return(0x1234_5678) + [obj].pack(pack_format()).should == "\x78\x56\x34\x12" + end + + it "encodes the number of array elements specified by the count modifier" do + str = [0x1243_6578, 0xdef0_abcd, 0x7865_4321].pack(pack_format(2)) + str.should == "\x78\x65\x43\x12\xcd\xab\xf0\xde" + end + + it "encodes all remaining elements when passed the '*' modifier" do + str = [0x1243_6578, 0xdef0_abcd, 0x7865_4321].pack(pack_format('*')) + str.should == "\x78\x65\x43\x12\xcd\xab\xf0\xde\x21\x43\x65\x78" + end + + it "ignores NULL bytes between directives" do + str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) + str.should == "\x78\x65\x43\x12\xcd\xab\xf0\xde" + end + + it "ignores spaces between directives" do + str = [0x1243_6578, 0xdef0_abcd].pack(pack_format(' ', 2)) + str.should == "\x78\x65\x43\x12\xcd\xab\xf0\xde" + end +end + +describe :array_pack_32bit_be, shared: true do + it "encodes the least significant 32 bits of a positive number" do + [ [[0x0000_0021], "\x00\x00\x00\x21"], + [[0x0000_4321], "\x00\x00\x43\x21"], + [[0x0065_4321], "\x00\x65\x43\x21"], + [[0x7865_4321], "\x78\x65\x43\x21"] + ].should be_computed_by(:pack, pack_format()) + end + + it "encodes the least significant 32 bits of a negative number" do + [ [[-0x0000_0021], "\xff\xff\xff\xdf"], + [[-0x0000_4321], "\xff\xff\xbc\xdf"], + [[-0x0065_4321], "\xff\x9a\xbc\xdf"], + [[-0x7865_4321], "\x87\x9a\xbc\xdf"] + ].should be_computed_by(:pack, pack_format()) + end + + it "encodes a Float truncated as an Integer" do + [ [[2019902241.2], "\x78\x65\x43\x21"], + [[2019902241.8], "\x78\x65\x43\x21"], + [[-2019902241.2], "\x87\x9a\xbc\xdf"], + [[-2019902241.8], "\x87\x9a\xbc\xdf"] + ].should be_computed_by(:pack, pack_format()) + end + + it "calls #to_int to convert the pack argument to an Integer" do + obj = mock('to_int') + obj.should_receive(:to_int).and_return(0x1234_5678) + [obj].pack(pack_format()).should == "\x12\x34\x56\x78" + end + + it "encodes the number of array elements specified by the count modifier" do + str = [0x1243_6578, 0xdef0_abcd, 0x7865_4321].pack(pack_format(2)) + str.should == "\x12\x43\x65\x78\xde\xf0\xab\xcd" + end + + it "encodes all remaining elements when passed the '*' modifier" do + str = [0x1243_6578, 0xdef0_abcd, 0x7865_4321].pack(pack_format('*')) + str.should == "\x12\x43\x65\x78\xde\xf0\xab\xcd\x78\x65\x43\x21" + end + + it "ignores NULL bytes between directives" do + str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) + str.should == "\x12\x43\x65\x78\xde\xf0\xab\xcd" + end + + it "ignores spaces between directives" do + str = [0x1243_6578, 0xdef0_abcd].pack(pack_format(' ', 2)) + str.should == "\x12\x43\x65\x78\xde\xf0\xab\xcd" + end +end + +describe :array_pack_32bit_le_platform, shared: true do + it "encodes the least significant 32 bits of a number" do + [ [[0x7865_4321], "\x21\x43\x65\x78"], + [[-0x7865_4321], "\xdf\xbc\x9a\x87"] + ].should be_computed_by(:pack, pack_format()) + end + + it "encodes the number of array elements specified by the count modifier" do + str = [0x1243_6578, 0xdef0_abcd, 0x7865_4321].pack(pack_format(2)) + str.should == "\x78\x65\x43\x12\xcd\xab\xf0\xde" + end + + it "encodes all remaining elements when passed the '*' modifier" do + str = [0x1243_6578, 0xdef0_abcd, 0x7865_4321].pack(pack_format('*')) + str.should == "\x78\x65\x43\x12\xcd\xab\xf0\xde\x21\x43\x65\x78" + end + + platform_is wordsize: 64 do + it "encodes the least significant 32 bits of a number that is greater than 32 bits" do + [ [[0xff_7865_4321], "\x21\x43\x65\x78"], + [[-0xff_7865_4321], "\xdf\xbc\x9a\x87"] + ].should be_computed_by(:pack, pack_format()) + end + end +end + +describe :array_pack_32bit_be_platform, shared: true do + it "encodes the least significant 32 bits of a number" do + [ [[0x7865_4321], "\x78\x65\x43\x21"], + [[-0x7865_4321], "\x87\x9a\xbc\xdf"] + ].should be_computed_by(:pack, pack_format()) + end + + it "encodes the number of array elements specified by the count modifier" do + str = [0x1243_6578, 0xdef0_abcd, 0x7865_4321].pack(pack_format(2)) + str.should == "\x12\x43\x65\x78\xde\xf0\xab\xcd" + end + + it "encodes all remaining elements when passed the '*' modifier" do + str = [0x1243_6578, 0xdef0_abcd, 0x7865_4321].pack(pack_format('*')) + str.should == "\x12\x43\x65\x78\xde\xf0\xab\xcd\x78\x65\x43\x21" + end + + platform_is wordsize: 64 do + it "encodes the least significant 32 bits of a number that is greater than 32 bits" do + [ [[0xff_7865_4321], "\x78\x65\x43\x21"], + [[-0xff_7865_4321], "\x87\x9a\xbc\xdf"] + ].should be_computed_by(:pack, pack_format()) + end + end +end + +describe :array_pack_64bit_le, shared: true do + it "encodes the least significant 64 bits of a positive number" do + [ [[0x0000_0000_0000_0021], "\x21\x00\x00\x00\x00\x00\x00\x00"], + [[0x0000_0000_0000_4321], "\x21\x43\x00\x00\x00\x00\x00\x00"], + [[0x0000_0000_0065_4321], "\x21\x43\x65\x00\x00\x00\x00\x00"], + [[0x0000_0000_7865_4321], "\x21\x43\x65\x78\x00\x00\x00\x00"], + [[0x0000_0090_7865_4321], "\x21\x43\x65\x78\x90\x00\x00\x00"], + [[0x0000_ba90_7865_4321], "\x21\x43\x65\x78\x90\xba\x00\x00"], + [[0x00dc_ba90_7865_4321], "\x21\x43\x65\x78\x90\xba\xdc\x00"], + [[0x7edc_ba90_7865_4321], "\x21\x43\x65\x78\x90\xba\xdc\x7e"] + ].should be_computed_by(:pack, pack_format()) + end + + it "encodes the least significant 64 bits of a negative number" do + [ [[-0x0000_0000_0000_0021], "\xdf\xff\xff\xff\xff\xff\xff\xff"], + [[-0x0000_0000_0000_4321], "\xdf\xbc\xff\xff\xff\xff\xff\xff"], + [[-0x0000_0000_0065_4321], "\xdf\xbc\x9a\xff\xff\xff\xff\xff"], + [[-0x0000_0000_7865_4321], "\xdf\xbc\x9a\x87\xff\xff\xff\xff"], + [[-0x0000_0090_7865_4321], "\xdf\xbc\x9a\x87\x6f\xff\xff\xff"], + [[-0x0000_ba90_7865_4321], "\xdf\xbc\x9a\x87\x6f\x45\xff\xff"], + [[-0x00dc_ba90_7865_4321], "\xdf\xbc\x9a\x87\x6f\x45\x23\xff"], + [[-0x7edc_ba90_7865_4321], "\xdf\xbc\x9a\x87\x6f\x45\x23\x81"] + ].should be_computed_by(:pack, pack_format()) + end + + it "encodes a Float truncated as an Integer" do + [ [[9.14138647331322368e+18], "\x00\x44\x65\x78\x90\xba\xdc\x7e"], + [[-9.14138647331322368e+18], "\x00\xbc\x9a\x87\x6f\x45\x23\x81"] + ].should be_computed_by(:pack, pack_format()) + end + + it "calls #to_int to convert the pack argument to an Integer" do + obj = mock('to_int') + obj.should_receive(:to_int).and_return(0x1234_5678_90ab_cdef) + [obj].pack(pack_format()).should == "\xef\xcd\xab\x90\x78\x56\x34\x12" + end + + it "encodes the number of array elements specified by the count modifier" do + str = [0x1234_5678_90ab_cdef, + 0xdef0_abcd_3412_7856, + 0x7865_4321_dcba_def0].pack(pack_format(2)) + str.should == "\xef\xcd\xab\x90\x78\x56\x34\x12\x56\x78\x12\x34\xcd\xab\xf0\xde" + end + + it "encodes all remaining elements when passed the '*' modifier" do + str = [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format('*')) + str.should == "\x56\x78\x12\x34\xcd\xab\xf0\xde\xf0\xde\xba\xdc\x21\x43\x65\x78" + end + + it "ignores NULL bytes between directives" do + str = [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2)) + str.should == "\x56\x78\x12\x34\xcd\xab\xf0\xde\xf0\xde\xba\xdc\x21\x43\x65\x78" + end + + it "ignores spaces between directives" do + str = [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format(' ', 2)) + str.should == "\x56\x78\x12\x34\xcd\xab\xf0\xde\xf0\xde\xba\xdc\x21\x43\x65\x78" + end +end + +describe :array_pack_64bit_be, shared: true do + it "encodes the least significant 64 bits of a positive number" do + [ [[0x0000_0000_0000_0021], "\x00\x00\x00\x00\x00\x00\x00\x21"], + [[0x0000_0000_0000_4321], "\x00\x00\x00\x00\x00\x00\x43\x21"], + [[0x0000_0000_0065_4321], "\x00\x00\x00\x00\x00\x65\x43\x21"], + [[0x0000_0000_7865_4321], "\x00\x00\x00\x00\x78\x65\x43\x21"], + [[0x0000_0090_7865_4321], "\x00\x00\x00\x90\x78\x65\x43\x21"], + [[0x0000_ba90_7865_4321], "\x00\x00\xba\x90\x78\x65\x43\x21"], + [[0x00dc_ba90_7865_4321], "\x00\xdc\xba\x90\x78\x65\x43\x21"], + [[0x7edc_ba90_7865_4321], "\x7e\xdc\xba\x90\x78\x65\x43\x21"] + ].should be_computed_by(:pack, pack_format()) + end + + it "encodes the least significant 64 bits of a negative number" do + [ [[-0x0000_0000_0000_0021], "\xff\xff\xff\xff\xff\xff\xff\xdf"], + [[-0x0000_0000_0000_4321], "\xff\xff\xff\xff\xff\xff\xbc\xdf"], + [[-0x0000_0000_0065_4321], "\xff\xff\xff\xff\xff\x9a\xbc\xdf"], + [[-0x0000_0000_7865_4321], "\xff\xff\xff\xff\x87\x9a\xbc\xdf"], + [[-0x0000_0090_7865_4321], "\xff\xff\xff\x6f\x87\x9a\xbc\xdf"], + [[-0x0000_ba90_7865_4321], "\xff\xff\x45\x6f\x87\x9a\xbc\xdf"], + [[-0x00dc_ba90_7865_4321], "\xff\x23\x45\x6f\x87\x9a\xbc\xdf"], + [[-0x7edc_ba90_7865_4321], "\x81\x23\x45\x6f\x87\x9a\xbc\xdf"] + ].should be_computed_by(:pack, pack_format()) + end + + it "encodes a Float truncated as an Integer" do + [ [[9.14138647331322368e+18], "\x7e\xdc\xba\x90\x78\x65\x44\x00"], + [[-9.14138647331322368e+18], "\x81\x23\x45\x6f\x87\x9a\xbc\x00"] + ].should be_computed_by(:pack, pack_format()) + end + + it "calls #to_int to convert the pack argument to an Integer" do + obj = mock('to_int') + obj.should_receive(:to_int).and_return(0x1234_5678_90ab_cdef) + [obj].pack(pack_format()).should == "\x12\x34\x56\x78\x90\xab\xcd\xef" + end + + it "encodes the number of array elements specified by the count modifier" do + str = [0x1234_5678_90ab_cdef, + 0xdef0_abcd_3412_7856, + 0x7865_4321_dcba_def0].pack(pack_format(2)) + str.should == "\x12\x34\x56\x78\x90\xab\xcd\xef\xde\xf0\xab\xcd\x34\x12\x78\x56" + end + + it "encodes all remaining elements when passed the '*' modifier" do + str = [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format('*')) + str.should == "\xde\xf0\xab\xcd\x34\x12\x78\x56\x78\x65\x43\x21\xdc\xba\xde\xf0" + end + + it "ignores NULL bytes between directives" do + str = [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2)) + str.should == "\xde\xf0\xab\xcd\x34\x12\x78\x56\x78\x65\x43\x21\xdc\xba\xde\xf0" + end + + it "ignores spaces between directives" do + str = [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format(' ', 2)) + str.should == "\xde\xf0\xab\xcd\x34\x12\x78\x56\x78\x65\x43\x21\xdc\xba\xde\xf0" + end +end diff --git a/spec/rubyspec/core/array/pack/shared/numeric_basic.rb b/spec/rubyspec/core/array/pack/shared/numeric_basic.rb new file mode 100644 index 0000000000..9224d6080e --- /dev/null +++ b/spec/rubyspec/core/array/pack/shared/numeric_basic.rb @@ -0,0 +1,44 @@ +describe :array_pack_numeric_basic, shared: true do + it "returns an empty String if count is zero" do + [1].pack(pack_format(0)).should == "" + end + + it "raises a TypeError when passed nil" do + lambda { [nil].pack(pack_format) }.should raise_error(TypeError) + end + + it "raises a TypeError when passed true" do + lambda { [true].pack(pack_format) }.should raise_error(TypeError) + end + + it "raises a TypeError when passed false" do + lambda { [false].pack(pack_format) }.should raise_error(TypeError) + end + + it "returns an ASCII-8BIT string" do + [0xFF].pack(pack_format).encoding.should == Encoding::ASCII_8BIT + [0xE3, 0x81, 0x82].pack(pack_format(3)).encoding.should == Encoding::ASCII_8BIT + end +end + +describe :array_pack_integer, shared: true do + it "raises a TypeError when the object does not respond to #to_int" do + obj = mock('not an integer') + lambda { [obj].pack(pack_format) }.should raise_error(TypeError) + end + + it "raises a TypeError when passed a String" do + lambda { ["5"].pack(pack_format) }.should raise_error(TypeError) + end +end + +describe :array_pack_float, shared: true do + it "raises a TypeError if a String does not represent a floating point number" do + lambda { ["a"].pack(pack_format) }.should raise_error(TypeError) + end + + it "raises a TypeError when the object does not respond to #to_f" do + obj = mock('not an float') + lambda { [obj].pack(pack_format) }.should raise_error(TypeError) + end +end diff --git a/spec/rubyspec/core/array/pack/shared/string.rb b/spec/rubyspec/core/array/pack/shared/string.rb new file mode 100644 index 0000000000..cedb0886e2 --- /dev/null +++ b/spec/rubyspec/core/array/pack/shared/string.rb @@ -0,0 +1,80 @@ +# -*- encoding: binary -*- +describe :array_pack_string, shared: true do + it "adds count bytes of a String to the output" do + ["abc"].pack(pack_format(2)).should == "ab" + end + + it "implicitly has a count of one when no count is specified" do + ["abc"].pack(pack_format).should == "a" + end + + it "does not add any bytes when the count is zero" do + ["abc"].pack(pack_format(0)).should == "" + end + + it "is not affected by a previous count modifier" do + ["abcde", "defg"].pack(pack_format(3)+pack_format).should == "abcd" + end + + it "raises an ArgumentError when the Array is empty" do + lambda { [].pack(pack_format) }.should raise_error(ArgumentError) + end + + it "raises an ArgumentError when the Array has too few elements" do + lambda { ["a"].pack(pack_format(nil, 2)) }.should raise_error(ArgumentError) + end + + it "calls #to_str to convert the element to a String" do + obj = mock('pack string') + obj.should_receive(:to_str).and_return("abc") + + [obj].pack(pack_format).should == "a" + end + + it "raises a TypeError when the object does not respond to #to_str" do + obj = mock("not a string") + lambda { [obj].pack(pack_format) }.should raise_error(TypeError) + end + + it "returns a tainted string when a pack argument is tainted" do + ["abcd".taint, 0x20].pack(pack_format("3C")).tainted?.should be_true + end + + it "does not return a tainted string when the array is tainted" do + ["abcd", 0x20].taint.pack(pack_format("3C")).tainted?.should be_false + end + + it "returns a tainted string when the format is tainted" do + ["abcd", 0x20].pack(pack_format("3C").taint).tainted?.should be_true + end + + it "returns a tainted string when an empty format is tainted" do + ["abcd", 0x20].pack("".taint).tainted?.should be_true + end + + it "returns a untrusted string when the format is untrusted" do + ["abcd", 0x20].pack(pack_format("3C").untrust).untrusted?.should be_true + end + + it "returns a untrusted string when the empty format is untrusted" do + ["abcd", 0x20].pack("".untrust).untrusted?.should be_true + end + + it "returns a untrusted string when a pack argument is untrusted" do + ["abcd".untrust, 0x20].pack(pack_format("3C")).untrusted?.should be_true + end + + it "returns a trusted string when the array is untrusted" do + ["abcd", 0x20].untrust.pack(pack_format("3C")).untrusted?.should be_false + end + + it "returns a string in encoding of common to the concatenated results" do + f = pack_format("*") + [ [["\u{3042 3044 3046 3048}", 0x2000B].pack(f+"U"), Encoding::ASCII_8BIT], + [["abcde\xd1", "\xFF\xFe\x81\x82"].pack(f+"u"), Encoding::ASCII_8BIT], + [["a".force_encoding("ascii"), "\xFF\xFe\x81\x82"].pack(f+"u"), Encoding::ASCII_8BIT], + # under discussion [ruby-dev:37294] + [["\u{3042 3044 3046 3048}", 1].pack(f+"N"), Encoding::ASCII_8BIT] + ].should be_computed_by(:encoding) + end +end diff --git a/spec/rubyspec/core/array/pack/shared/unicode.rb b/spec/rubyspec/core/array/pack/shared/unicode.rb new file mode 100644 index 0000000000..e16110c491 --- /dev/null +++ b/spec/rubyspec/core/array/pack/shared/unicode.rb @@ -0,0 +1,94 @@ +# -*- encoding: utf-8 -*- + +describe :array_pack_unicode, shared: true do + it "encodes ASCII values as a Unicode codepoint" do + [ [[0], "\x00"], + [[1], "\x01"], + [[8], "\x08"], + [[15], "\x0f"], + [[24], "\x18"], + [[31], "\x1f"], + [[127], "\x7f"], + [[128], "\xc2\x80"], + [[129], "\xc2\x81"], + [[255], "\xc3\xbf"] + ].should be_computed_by(:pack, "U") + end + + it "encodes UTF-8 BMP codepoints" do + [ [[0x80], "\xc2\x80"], + [[0x7ff], "\xdf\xbf"], + [[0x800], "\xe0\xa0\x80"], + [[0xffff], "\xef\xbf\xbf"] + ].should be_computed_by(:pack, "U") + end + + it "constructs strings with valid encodings" do + str = [0x85].pack("U*") + str.should == "\xc2\x85" + str.valid_encoding?.should be_true + end + + it "encodes values larger than UTF-8 max codepoints" do + [ + [[0x00110000], [244, 144, 128, 128].pack('C*').force_encoding('utf-8')], + [[0x04000000], [252, 132, 128, 128, 128, 128].pack('C*').force_encoding('utf-8')], + [[0x7FFFFFFF], [253, 191, 191, 191, 191, 191].pack('C*').force_encoding('utf-8')] + ].should be_computed_by(:pack, "U") + end + + it "encodes UTF-8 max codepoints" do + [ [[0x10000], "\xf0\x90\x80\x80"], + [[0xfffff], "\xf3\xbf\xbf\xbf"], + [[0x100000], "\xf4\x80\x80\x80"], + [[0x10ffff], "\xf4\x8f\xbf\xbf"] + ].should be_computed_by(:pack, "U") + end + + it "encodes the number of array elements specified by the count modifier" do + [ [[0x41, 0x42, 0x43, 0x44], "U2", "\x41\x42"], + [[0x41, 0x42, 0x43, 0x44], "U2U", "\x41\x42\x43"] + ].should be_computed_by(:pack) + end + + it "encodes all remaining elements when passed the '*' modifier" do + [0x41, 0x42, 0x43, 0x44].pack("U*").should == "\x41\x42\x43\x44" + end + + it "calls #to_int to convert the pack argument to an Integer" do + obj = mock('to_int') + obj.should_receive(:to_int).and_return(5) + [obj].pack("U").should == "\x05" + end + + it "raises a TypeError if #to_int does not return an Integer" do + obj = mock('to_int') + obj.should_receive(:to_int).and_return("5") + lambda { [obj].pack("U") }.should raise_error(TypeError) + end + + it "ignores NULL bytes between directives" do + [1, 2, 3].pack("U\x00U").should == "\x01\x02" + end + + it "ignores spaces between directives" do + [1, 2, 3].pack("U U").should == "\x01\x02" + end + + it "raises a RangeError if passed a negative number" do + lambda { [-1].pack("U") }.should raise_error(RangeError) + end + + it "raises a RangeError if passed a number larger than an unsigned 32-bit integer" do + lambda { [2**32].pack("U") }.should raise_error(RangeError) + end + + it "sets the output string to UTF-8 encoding" do + [ [[0x00].pack("U"), Encoding::UTF_8], + [[0x41].pack("U"), Encoding::UTF_8], + [[0x7F].pack("U"), Encoding::UTF_8], + [[0x80].pack("U"), Encoding::UTF_8], + [[0x10FFFF].pack("U"), Encoding::UTF_8] + ].should be_computed_by(:encoding) + end +end |