diff options
Diffstat (limited to 'spec/ruby/core/string/unpack/shared')
| -rw-r--r-- | spec/ruby/core/string/unpack/shared/basic.rb | 37 | ||||
| -rw-r--r-- | spec/ruby/core/string/unpack/shared/float.rb | 319 | ||||
| -rw-r--r-- | spec/ruby/core/string/unpack/shared/integer.rb | 411 | ||||
| -rw-r--r-- | spec/ruby/core/string/unpack/shared/string.rb | 51 | ||||
| -rw-r--r-- | spec/ruby/core/string/unpack/shared/taint.rb | 2 | ||||
| -rw-r--r-- | spec/ruby/core/string/unpack/shared/unicode.rb | 72 |
6 files changed, 892 insertions, 0 deletions
diff --git a/spec/ruby/core/string/unpack/shared/basic.rb b/spec/ruby/core/string/unpack/shared/basic.rb new file mode 100644 index 0000000000..734630bda0 --- /dev/null +++ b/spec/ruby/core/string/unpack/shared/basic.rb @@ -0,0 +1,37 @@ +describe :string_unpack_basic, shared: true do + it "ignores whitespace in the format string" do + "abc".unpack("a \t\n\v\f\r"+unpack_format).should be_an_instance_of(Array) + end + + it "calls #to_str to coerce the directives string" do + d = mock("unpack directive") + d.should_receive(:to_str).and_return("a"+unpack_format) + "abc".unpack(d).should be_an_instance_of(Array) + end + + ruby_version_is ""..."3.3" do + it "warns about using an unknown directive" do + -> { "abcdefgh".unpack("a R" + unpack_format) }.should complain(/unknown unpack directive 'R' in 'a R#{unpack_format}'/) + -> { "abcdefgh".unpack("a 0" + unpack_format) }.should complain(/unknown unpack directive '0' in 'a 0#{unpack_format}'/) + -> { "abcdefgh".unpack("a :" + unpack_format) }.should complain(/unknown unpack directive ':' in 'a :#{unpack_format}'/) + end + end + + ruby_version_is "3.3" do + it "raises ArgumentError when a directive is unknown" do + -> { "abcdefgh".unpack("a K" + unpack_format) }.should raise_error(ArgumentError, "unknown unpack directive 'K' in 'a K#{unpack_format}'") + -> { "abcdefgh".unpack("a 0" + unpack_format) }.should raise_error(ArgumentError, "unknown unpack directive '0' in 'a 0#{unpack_format}'") + -> { "abcdefgh".unpack("a :" + unpack_format) }.should raise_error(ArgumentError, "unknown unpack directive ':' in 'a :#{unpack_format}'") + end + end +end + +describe :string_unpack_no_platform, shared: true do + it "raises an ArgumentError when the format modifier is '_'" do + -> { "abcdefgh".unpack(unpack_format("_")) }.should raise_error(ArgumentError) + end + + it "raises an ArgumentError when the format modifier is '!'" do + -> { "abcdefgh".unpack(unpack_format("!")) }.should raise_error(ArgumentError) + end +end diff --git a/spec/ruby/core/string/unpack/shared/float.rb b/spec/ruby/core/string/unpack/shared/float.rb new file mode 100644 index 0000000000..b31c2c8bdc --- /dev/null +++ b/spec/ruby/core/string/unpack/shared/float.rb @@ -0,0 +1,319 @@ +# encoding: binary + +describe :string_unpack_float_le, shared: true do + it "decodes one float for a single format character" do + "\x8f\xc2\xb5?".unpack(unpack_format).should == [1.4199999570846558] + end + + it "decodes a negative float" do + "\xcd\xcc\x08\xc2".unpack(unpack_format).should == [-34.200000762939453] + end + + it "decodes two floats for two format characters" do + array = "\x9a\x999@33\xb3?".unpack(unpack_format(nil, 2)) + array.should == [2.9000000953674316, 1.399999976158142] + end + + it "decodes the number of floats requested by the count modifier" do + array = "\x9a\x999@33\xb3?33\x03A".unpack(unpack_format(3)) + array.should == [2.9000000953674316, 1.399999976158142, 8.199999809265137] + end + + it "decodes the remaining floats when passed the '*' modifier" do + array = "\x9a\x999@33\xb3?33\x03A".unpack(unpack_format("*")) + array.should == [2.9000000953674316, 1.399999976158142, 8.199999809265137] + end + + it "decodes the remaining floats when passed the '*' modifier after another directive" do + array = "\x9a\x99\xa9@33\x13A".unpack(unpack_format()+unpack_format('*')) + array.should == [5.300000190734863, 9.199999809265137] + end + + it "does not decode a float when fewer bytes than a float remain and the '*' modifier is passed" do + [ ["\xff", []], + ["\xff\x00", []], + ["\xff\x00\xff", []] + ].should be_computed_by(:unpack, unpack_format("*")) + end + + it "adds nil for each element requested beyond the end of the String" do + [ ["abc", [nil, nil, nil]], + ["\x8f\xc2\xb5?abc", [1.4199999570846558, nil, nil]], + ["\x9a\x999@33\xb3?abc", [2.9000000953674316, 1.399999976158142, nil]] + ].should be_computed_by(:unpack, unpack_format(3)) + end + + it "decodes positive Infinity" do + "\x00\x00\x80\x7f".unpack(unpack_format).should == [infinity_value] + end + + it "decodes negative Infinity" do + "\x00\x00\x80\xff".unpack(unpack_format).should == [-infinity_value] + end + + it "decodes NaN" do + # mumble mumble NaN mumble https://bugs.ruby-lang.org/issues/5884 + [nan_value].pack(unpack_format).unpack(unpack_format).first.nan?.should be_true + end + + ruby_version_is ""..."3.3" do + it "ignores NULL bytes between directives" do + suppress_warning do + array = "\x9a\x999@33\xb3?".unpack(unpack_format("\000", 2)) + array.should == [2.9000000953674316, 1.399999976158142] + end + end + end + + ruby_version_is "3.3" do + it "raise ArgumentError for NULL bytes between directives" do + -> { + "\x9a\x999@33\xb3?".unpack(unpack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown unpack directive/) + end + end + + it "ignores spaces between directives" do + array = "\x9a\x999@33\xb3?".unpack(unpack_format(' ', 2)) + array.should == [2.9000000953674316, 1.399999976158142] + end +end + +describe :string_unpack_float_be, shared: true do + it "decodes one float for a single format character" do + "?\xb5\xc2\x8f".unpack(unpack_format).should == [1.4199999570846558] + end + + it "decodes a negative float" do + "\xc2\x08\xcc\xcd".unpack(unpack_format).should == [-34.200000762939453] + end + + it "decodes two floats for two format characters" do + array = "@9\x99\x9a?\xb333".unpack(unpack_format(nil, 2)) + array.should == [2.9000000953674316, 1.399999976158142] + end + + it "decodes the number of floats requested by the count modifier" do + array = "@9\x99\x9a?\xb333A\x0333".unpack(unpack_format(3)) + array.should == [2.9000000953674316, 1.399999976158142, 8.199999809265137] + end + + it "decodes the remaining floats when passed the '*' modifier" do + array = "@9\x99\x9a?\xb333A\x0333".unpack(unpack_format("*")) + array.should == [2.9000000953674316, 1.399999976158142, 8.199999809265137] + end + + it "decodes the remaining floats when passed the '*' modifier after another directive" do + array = "@\xa9\x99\x9aA\x1333".unpack(unpack_format()+unpack_format('*')) + array.should == [5.300000190734863, 9.199999809265137] + end + + it "does not decode a float when fewer bytes than a float remain and the '*' modifier is passed" do + [ ["\xff", []], + ["\xff\x00", []], + ["\xff\x00\xff", []] + ].should be_computed_by(:unpack, unpack_format("*")) + end + + it "adds nil for each element requested beyond the end of the String" do + [ ["abc", [nil, nil, nil]], + ["?\xb5\xc2\x8fabc", [1.4199999570846558, nil, nil]], + ["@9\x99\x9a?\xb333abc", [2.9000000953674316, 1.399999976158142, nil]] + ].should be_computed_by(:unpack, unpack_format(3)) + end + + it "decodes positive Infinity" do + "\x7f\x80\x00\x00".unpack(unpack_format).should == [infinity_value] + end + + it "decodes negative Infinity" do + "\xff\x80\x00\x00".unpack(unpack_format).should == [-infinity_value] + end + + it "decodes NaN" do + # mumble mumble NaN mumble https://bugs.ruby-lang.org/issues/5884 + [nan_value].pack(unpack_format).unpack(unpack_format).first.nan?.should be_true + end + + ruby_version_is ""..."3.3" do + it "ignores NULL bytes between directives" do + suppress_warning do + array = "@9\x99\x9a?\xb333".unpack(unpack_format("\000", 2)) + array.should == [2.9000000953674316, 1.399999976158142] + end + end + end + + ruby_version_is "3.3" do + it "raise ArgumentError for NULL bytes between directives" do + -> { + "@9\x99\x9a?\xb333".unpack(unpack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown unpack directive/) + end + end + + it "ignores spaces between directives" do + array = "@9\x99\x9a?\xb333".unpack(unpack_format(' ', 2)) + array.should == [2.9000000953674316, 1.399999976158142] + end +end + +describe :string_unpack_double_le, shared: true do + it "decodes one double for a single format character" do + "\xb8\x1e\x85\xebQ\xb8\xf6?".unpack(unpack_format).should == [1.42] + end + + it "decodes a negative double" do + "\x9a\x99\x99\x99\x99\x19A\xc0".unpack(unpack_format).should == [-34.2] + end + + it "decodes two doubles for two format characters" do + "333333\x07@ffffff\xf6?".unpack(unpack_format(nil, 2)).should == [2.9, 1.4] + end + + it "decodes the number of doubles requested by the count modifier" do + array = "333333\x07@ffffff\xf6?ffffff\x20@".unpack(unpack_format(3)) + array.should == [2.9, 1.4, 8.2] + end + + it "decodes the remaining doubles when passed the '*' modifier" do + array = "333333\x07@ffffff\xf6?ffffff\x20@".unpack(unpack_format("*")) + array.should == [2.9, 1.4, 8.2] + end + + it "decodes the remaining doubles when passed the '*' modifier after another directive" do + array = "333333\x15@ffffff\x22@".unpack(unpack_format()+unpack_format('*')) + array.should == [5.3, 9.2] + end + + it "does not decode a double when fewer bytes than a double remain and the '*' modifier is passed" do + [ ["\xff", []], + ["\xff\x00", []], + ["\xff\x00\xff", []], + ["\xff\x00\xff\x00", []], + ["\xff\x00\xff\x00\xff", []], + ["\xff\x00\xff\x00\xff\x00", []], + ["\xff\x00\xff\x00\xff\x00\xff", []] + ].should be_computed_by(:unpack, unpack_format("*")) + end + + it "adds nil for each element requested beyond the end of the String" do + [ ["\xff\x00\xff\x00\xff\x00\xff", [nil, nil, nil]], + ["\xb8\x1e\x85\xebQ\xb8\xf6?abc", [1.42, nil, nil]], + ["333333\x07@ffffff\xf6?abcd", [2.9, 1.4, nil]] + ].should be_computed_by(:unpack, unpack_format(3)) + end + + it "decodes positive Infinity" do + "\x00\x00\x00\x00\x00\x00\xf0\x7f".unpack(unpack_format).should == [infinity_value] + end + + it "decodes negative Infinity" do + "\x00\x00\x00\x00\x00\x00\xf0\xff".unpack(unpack_format).should == [-infinity_value] + end + + it "decodes NaN" do + # mumble mumble NaN mumble https://bugs.ruby-lang.org/issues/5884 + [nan_value].pack(unpack_format).unpack(unpack_format).first.nan?.should be_true + end + + ruby_version_is ""..."3.3" do + it "ignores NULL bytes between directives" do + suppress_warning do + "333333\x07@ffffff\xf6?".unpack(unpack_format("\000", 2)).should == [2.9, 1.4] + end + end + end + + ruby_version_is "3.3" do + it "raise ArgumentError for NULL bytes between directives" do + -> { + "333333\x07@ffffff\xf6?".unpack(unpack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown unpack directive/) + end + end + + it "ignores spaces between directives" do + "333333\x07@ffffff\xf6?".unpack(unpack_format(' ', 2)).should == [2.9, 1.4] + end +end + +describe :string_unpack_double_be, shared: true do + it "decodes one double for a single format character" do + "?\xf6\xb8Q\xeb\x85\x1e\xb8".unpack(unpack_format).should == [1.42] + end + + it "decodes a negative double" do + "\xc0A\x19\x99\x99\x99\x99\x9a".unpack(unpack_format).should == [-34.2] + end + + it "decodes two doubles for two format characters" do + "@\x07333333?\xf6ffffff".unpack(unpack_format(nil, 2)).should == [2.9, 1.4] + end + + it "decodes the number of doubles requested by the count modifier" do + array = "@\x07333333?\xf6ffffff@\x20ffffff".unpack(unpack_format(3)) + array.should == [2.9, 1.4, 8.2] + end + + it "decodes the remaining doubles when passed the '*' modifier" do + array = "@\x07333333?\xf6ffffff@\x20ffffff".unpack(unpack_format("*")) + array.should == [2.9, 1.4, 8.2] + end + + it "decodes the remaining doubles when passed the '*' modifier after another directive" do + array = "@\x15333333@\x22ffffff".unpack(unpack_format()+unpack_format('*')) + array.should == [5.3, 9.2] + end + + it "does not decode a double when fewer bytes than a double remain and the '*' modifier is passed" do + [ ["\xff", []], + ["\xff\x00", []], + ["\xff\x00\xff", []], + ["\xff\x00\xff\x00", []], + ["\xff\x00\xff\x00\xff", []], + ["\xff\x00\xff\x00\xff\x00", []], + ["\xff\x00\xff\x00\xff\x00\xff", []] + ].should be_computed_by(:unpack, unpack_format("*")) + end + + it "adds nil for each element requested beyond the end of the String" do + [ ["abcdefg", [nil, nil, nil]], + ["?\xf6\xb8Q\xeb\x85\x1e\xb8abc", [1.42, nil, nil]], + ["@\x07333333?\xf6ffffffabcd", [2.9, 1.4, nil]] + ].should be_computed_by(:unpack, unpack_format(3)) + end + + it "decodes positive Infinity" do + "\x7f\xf0\x00\x00\x00\x00\x00\x00".unpack(unpack_format).should == [infinity_value] + end + + it "decodes negative Infinity" do + "\xff\xf0\x00\x00\x00\x00\x00\x00".unpack(unpack_format).should == [-infinity_value] + end + + it "decodes NaN" do + # mumble mumble NaN mumble https://bugs.ruby-lang.org/issues/5884 + [nan_value].pack(unpack_format).unpack(unpack_format).first.nan?.should be_true + end + + ruby_version_is ""..."3.3" do + it "ignores NULL bytes between directives" do + suppress_warning do + "@\x07333333?\xf6ffffff".unpack(unpack_format("\000", 2)).should == [2.9, 1.4] + end + end + end + + ruby_version_is "3.3" do + it "raise ArgumentError for NULL bytes between directives" do + -> { + "@\x07333333?\xf6ffffff".unpack(unpack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown unpack directive/) + end + end + + it "ignores spaces between directives" do + "@\x07333333?\xf6ffffff".unpack(unpack_format(' ', 2)).should == [2.9, 1.4] + end +end diff --git a/spec/ruby/core/string/unpack/shared/integer.rb b/spec/ruby/core/string/unpack/shared/integer.rb new file mode 100644 index 0000000000..d3934753ba --- /dev/null +++ b/spec/ruby/core/string/unpack/shared/integer.rb @@ -0,0 +1,411 @@ +# encoding: binary + +describe :string_unpack_16bit_le, shared: true do + it "decodes one short for a single format character" do + "ab".unpack(unpack_format).should == [25185] + end + + it "decodes two shorts for two format characters" do + "abcd".unpack(unpack_format(nil, 2)).should == [25185, 25699] + end + + it "decodes the number of shorts requested by the count modifier" do + "abcdef".unpack(unpack_format(3)).should == [25185, 25699, 26213] + end + + it "decodes the remaining shorts when passed the '*' modifier" do + "abcd".unpack(unpack_format('*')).should == [25185, 25699] + end + + it "decodes the remaining shorts when passed the '*' modifier after another directive" do + "abcd".unpack(unpack_format()+unpack_format('*')).should == [25185, 25699] + end + + it "does not decode a short when fewer bytes than a short remain and the '*' modifier is passed" do + "\xff".unpack(unpack_format('*')).should == [] + end + + it "adds nil for each element requested beyond the end of the String" do + [ ["", [nil, nil, nil]], + ["abc", [25185, nil, nil]], + ["abcd", [25185, 25699, nil]] + ].should be_computed_by(:unpack, unpack_format(3)) + end + + ruby_version_is ""..."3.3" do + it "ignores NULL bytes between directives" do + suppress_warning do + "abcd".unpack(unpack_format("\000", 2)).should == [25185, 25699] + end + end + end + + ruby_version_is "3.3" do + it "raise ArgumentError for NULL bytes between directives" do + -> { + "abcd".unpack(unpack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown unpack directive/) + end + end + + it "ignores spaces between directives" do + "abcd".unpack(unpack_format(' ', 2)).should == [25185, 25699] + end +end + +describe :string_unpack_16bit_le_signed, shared: true do + it "decodes a short with most significant bit set as a negative number" do + "\x00\xff".unpack(unpack_format()).should == [-256] + end +end + +describe :string_unpack_16bit_le_unsigned, shared: true do + it "decodes a short with most significant bit set as a positive number" do + "\x00\xff".unpack(unpack_format()).should == [65280] + end +end + +describe :string_unpack_16bit_be, shared: true do + it "decodes one short for a single format character" do + "ba".unpack(unpack_format).should == [25185] + end + + it "decodes two shorts for two format characters" do + "badc".unpack(unpack_format(nil, 2)).should == [25185, 25699] + end + + it "decodes the number of shorts requested by the count modifier" do + "badcfe".unpack(unpack_format(3)).should == [25185, 25699, 26213] + end + + it "decodes the remaining shorts when passed the '*' modifier" do + "badc".unpack(unpack_format('*')).should == [25185, 25699] + end + + it "decodes the remaining shorts when passed the '*' modifier after another directive" do + "badc".unpack(unpack_format()+unpack_format('*')).should == [25185, 25699] + end + + it "does not decode a short when fewer bytes than a short remain and the '*' modifier is passed" do + "\xff".unpack(unpack_format('*')).should == [] + end + + it "adds nil for each element requested beyond the end of the String" do + [ ["", [nil, nil, nil]], + ["bac", [25185, nil, nil]], + ["badc", [25185, 25699, nil]] + ].should be_computed_by(:unpack, unpack_format(3)) + end + + ruby_version_is ""..."3.3" do + it "ignores NULL bytes between directives" do + suppress_warning do + "badc".unpack(unpack_format("\000", 2)).should == [25185, 25699] + end + end + end + + ruby_version_is "3.3" do + it "raise ArgumentError for NULL bytes between directives" do + -> { + "badc".unpack(unpack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown unpack directive/) + end + end + + it "ignores spaces between directives" do + "badc".unpack(unpack_format(' ', 2)).should == [25185, 25699] + end +end + +describe :string_unpack_16bit_be_signed, shared: true do + it "decodes a short with most significant bit set as a negative number" do + "\xff\x00".unpack(unpack_format()).should == [-256] + end +end + +describe :string_unpack_16bit_be_unsigned, shared: true do + it "decodes a short with most significant bit set as a positive number" do + "\xff\x00".unpack(unpack_format()).should == [65280] + end +end + +describe :string_unpack_32bit_le, shared: true do + it "decodes one int for a single format character" do + "abcd".unpack(unpack_format).should == [1684234849] + end + + it "decodes two ints for two format characters" do + "abghefcd".unpack(unpack_format(nil, 2)).should == [1751605857, 1684235877] + end + + it "decodes the number of ints requested by the count modifier" do + "abcedfgh".unpack(unpack_format(2)).should == [1701012065, 1751606884] + end + + it "decodes the remaining ints when passed the '*' modifier" do + "acbdegfh".unpack(unpack_format('*')).should == [1684169569, 1751541605] + end + + it "decodes the remaining ints when passed the '*' modifier after another directive" do + "abcdefgh".unpack(unpack_format()+unpack_format('*')).should == [1684234849, 1751606885] + end + + it "does not decode an int when fewer bytes than an int remain and the '*' modifier is passed" do + "abc".unpack(unpack_format('*')).should == [] + end + + it "adds nil for each element requested beyond the end of the String" do + [ ["", [nil, nil, nil]], + ["abcde", [1684234849, nil, nil]], + ["abcdefg", [1684234849, nil, nil]], + ["abcdefgh", [1684234849, 1751606885, nil]] + ].should be_computed_by(:unpack, unpack_format(3)) + end + + ruby_version_is ""..."3.3" do + it "ignores NULL bytes between directives" do + suppress_warning do + "abcdefgh".unpack(unpack_format("\000", 2)).should == [1684234849, 1751606885] + end + end + end + + ruby_version_is "3.3" do + it "raise ArgumentError for NULL bytes between directives" do + -> { + "abcdefgh".unpack(unpack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown unpack directive/) + end + end + + it "ignores spaces between directives" do + "abcdefgh".unpack(unpack_format(' ', 2)).should == [1684234849, 1751606885] + end +end + +describe :string_unpack_32bit_le_signed, shared: true do + it "decodes an int with most significant bit set as a negative number" do + "\x00\xaa\x00\xff".unpack(unpack_format()).should == [-16733696] + end +end + +describe :string_unpack_32bit_le_unsigned, shared: true do + it "decodes an int with most significant bit set as a positive number" do + "\x00\xaa\x00\xff".unpack(unpack_format()).should == [4278233600] + end +end + +describe :string_unpack_32bit_be, shared: true do + it "decodes one int for a single format character" do + "dcba".unpack(unpack_format).should == [1684234849] + end + + it "decodes two ints for two format characters" do + "hgbadcfe".unpack(unpack_format(nil, 2)).should == [1751605857, 1684235877] + end + + it "decodes the number of ints requested by the count modifier" do + "ecbahgfd".unpack(unpack_format(2)).should == [1701012065, 1751606884] + end + + it "decodes the remaining ints when passed the '*' modifier" do + "dbcahfge".unpack(unpack_format('*')).should == [1684169569, 1751541605] + end + + it "decodes the remaining ints when passed the '*' modifier after another directive" do + "dcbahgfe".unpack(unpack_format()+unpack_format('*')).should == [1684234849, 1751606885] + end + + it "does not decode an int when fewer bytes than an int remain and the '*' modifier is passed" do + "abc".unpack(unpack_format('*')).should == [] + end + + it "adds nil for each element requested beyond the end of the String" do + [ ["", [nil, nil, nil]], + ["dcbae", [1684234849, nil, nil]], + ["dcbaefg", [1684234849, nil, nil]], + ["dcbahgfe", [1684234849, 1751606885, nil]] + ].should be_computed_by(:unpack, unpack_format(3)) + end + + ruby_version_is ""..."3.3" do + it "ignores NULL bytes between directives" do + suppress_warning do + "dcbahgfe".unpack(unpack_format("\000", 2)).should == [1684234849, 1751606885] + end + end + end + + ruby_version_is "3.3" do + it "raise ArgumentError for NULL bytes between directives" do + -> { + "dcbahgfe".unpack(unpack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown unpack directive/) + end + end + + it "ignores spaces between directives" do + "dcbahgfe".unpack(unpack_format(' ', 2)).should == [1684234849, 1751606885] + end +end + +describe :string_unpack_32bit_be_signed, shared: true do + it "decodes an int with most significant bit set as a negative number" do + "\xff\x00\xaa\x00".unpack(unpack_format()).should == [-16733696] + end +end + +describe :string_unpack_32bit_be_unsigned, shared: true do + it "decodes an int with most significant bit set as a positive number" do + "\xff\x00\xaa\x00".unpack(unpack_format()).should == [4278233600] + end +end + +describe :string_unpack_64bit_le, shared: true do + it "decodes one long for a single format character" do + "abcdefgh".unpack(unpack_format).should == [7523094288207667809] + end + + it "decodes two longs for two format characters" do + array = "abghefcdghefabcd".unpack(unpack_format(nil, 2)) + array.should == [7233738012216484449, 7233733596956420199] + end + + it "decodes the number of longs requested by the count modifier" do + array = "abcedfghefcdghef".unpack(unpack_format(2)) + array.should == [7523094283929477729, 7378418357791581797] + end + + it "decodes the remaining longs when passed the '*' modifier" do + array = "acbdegfhdegfhacb".unpack(unpack_format('*')) + array.should == [7522813912742519649, 7089617339433837924] + end + + it "decodes the remaining longs when passed the '*' modifier after another directive" do + array = "bcahfgedhfgedbca".unpack(unpack_format()+unpack_format('*')) + array.should == [7234302065976107874, 7017560827710891624] + end + + it "does not decode a long when fewer bytes than a long remain and the '*' modifier is passed" do + "abc".unpack(unpack_format('*')).should == [] + end + + ruby_version_is ""..."3.3" do + it "ignores NULL bytes between directives" do + suppress_warning do + array = "abcdefghabghefcd".unpack(unpack_format("\000", 2)) + array.should == [7523094288207667809, 7233738012216484449] + end + end + end + + ruby_version_is "3.3" do + it "raise ArgumentError for NULL bytes between directives" do + -> { + "badc".unpack(unpack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown unpack directive/) + end + end + + it "ignores spaces between directives" do + array = "abcdefghabghefcd".unpack(unpack_format(' ', 2)) + array.should == [7523094288207667809, 7233738012216484449] + end +end + +describe :string_unpack_64bit_le_extra, shared: true do + it "adds nil for each element requested beyond the end of the String" do + [ ["", [nil, nil, nil]], + ["abcdefgh", [7523094288207667809, nil, nil]], + ["abcdefghcdefab", [7523094288207667809, nil, nil]], + ["abcdefghcdefabde", [7523094288207667809, 7306072665971057763, nil]] + ].should be_computed_by(:unpack, unpack_format(3)) + end +end + +describe :string_unpack_64bit_le_signed, shared: true do + it "decodes a long with most significant bit set as a negative number" do + "\x00\xcc\x00\xbb\x00\xaa\x00\xff".unpack(unpack_format()).should == [-71870673923814400] + end +end + +describe :string_unpack_64bit_le_unsigned, shared: true do + it "decodes a long with most significant bit set as a positive number" do + "\x00\xcc\x00\xbb\x00\xaa\x00\xff".unpack(unpack_format()).should == [18374873399785737216] + end +end + +describe :string_unpack_64bit_be, shared: true do + it "decodes one long for a single format character" do + "hgfedcba".unpack(unpack_format).should == [7523094288207667809] + end + + it "decodes two longs for two format characters" do + array = "dcfehgbadcbafehg".unpack(unpack_format(nil, 2)) + array.should == [7233738012216484449, 7233733596956420199] + end + + it "decodes the number of longs requested by the count modifier" do + array = "hgfdecbafehgdcfe".unpack(unpack_format(2)) + array.should == [7523094283929477729, 7378418357791581797] + end + + it "decodes the remaining longs when passed the '*' modifier" do + array = "hfgedbcabcahfged".unpack(unpack_format('*')) + array.should == [7522813912742519649, 7089617339433837924] + end + + it "decodes the remaining longs when passed the '*' modifier after another directive" do + array = "degfhacbacbdegfh".unpack(unpack_format()+unpack_format('*')) + array.should == [7234302065976107874, 7017560827710891624] + end + + it "does not decode a long when fewer bytes than a long remain and the '*' modifier is passed" do + "abc".unpack(unpack_format('*')).should == [] + end + + ruby_version_is ""..."3.3" do + it "ignores NULL bytes between directives" do + suppress_warning do + array = "hgfedcbadcfehgba".unpack(unpack_format("\000", 2)) + array.should == [7523094288207667809, 7233738012216484449] + end + end + end + + ruby_version_is "3.3" do + it "raise ArgumentError for NULL bytes between directives" do + -> { + "hgfedcbadcfehgba".unpack(unpack_format("\000", 2)) + }.should raise_error(ArgumentError, /unknown unpack directive/) + end + end + + it "ignores spaces between directives" do + array = "hgfedcbadcfehgba".unpack(unpack_format(' ', 2)) + array.should == [7523094288207667809, 7233738012216484449] + end +end + +describe :string_unpack_64bit_be_extra, shared: true do + it "adds nil for each element requested beyond the end of the String" do + [ ["", [nil, nil, nil]], + ["hgfedcba", [7523094288207667809, nil, nil]], + ["hgfedcbacdefab", [7523094288207667809, nil, nil]], + ["hgfedcbaedbafedc", [7523094288207667809, 7306072665971057763, nil]] + ].should be_computed_by(:unpack, unpack_format(3)) + end +end + +describe :string_unpack_64bit_be_signed, shared: true do + it "decodes a long with most significant bit set as a negative number" do + "\xff\x00\xaa\x00\xbb\x00\xcc\x00".unpack(unpack_format()).should == [-71870673923814400] + end +end + +describe :string_unpack_64bit_be_unsigned, shared: true do + it "decodes a long with most significant bit set as a positive number" do + "\xff\x00\xaa\x00\xbb\x00\xcc\x00".unpack(unpack_format()).should == [18374873399785737216] + end +end diff --git a/spec/ruby/core/string/unpack/shared/string.rb b/spec/ruby/core/string/unpack/shared/string.rb new file mode 100644 index 0000000000..9d85eedf26 --- /dev/null +++ b/spec/ruby/core/string/unpack/shared/string.rb @@ -0,0 +1,51 @@ +describe :string_unpack_string, shared: true do + it "returns an empty string if the input is empty" do + "".unpack(unpack_format).should == [""] + end + + it "returns empty strings for repeated formats if the input is empty" do + "".unpack(unpack_format(nil, 3)).should == ["", "", ""] + end + + it "returns an empty string and does not decode any bytes when the count modifier is zero" do + "abc".unpack(unpack_format(0)+unpack_format).should == ["", "a"] + end + + it "implicitly has a count of one when no count is specified" do + "abc".unpack(unpack_format).should == ["a"] + end + + it "decodes the number of bytes specified by the count modifier" do + "abc".unpack(unpack_format(3)).should == ["abc"] + end + + it "decodes the number of bytes specified by the count modifier including whitespace bytes" do + [ ["a bc", ["a b", "c"]], + ["a\fbc", ["a\fb", "c"]], + ["a\nbc", ["a\nb", "c"]], + ["a\rbc", ["a\rb", "c"]], + ["a\tbc", ["a\tb", "c"]], + ["a\vbc", ["a\vb", "c"]] + ].should be_computed_by(:unpack, unpack_format(3)+unpack_format) + end + + it "decodes past whitespace bytes when passed the '*' modifier" do + [ ["a b c", ["a b c"]], + ["a\fb c", ["a\fb c"]], + ["a\nb c", ["a\nb c"]], + ["a\rb c", ["a\rb c"]], + ["a\tb c", ["a\tb c"]], + ["a\vb c", ["a\vb c"]], + ].should be_computed_by(:unpack, unpack_format("*")) + end +end + +describe :string_unpack_Aa, shared: true do + it "decodes the number of bytes specified by the count modifier including NULL bytes" do + "a\x00bc".unpack(unpack_format(3)+unpack_format).should == ["a\x00b", "c"] + end + + it "decodes past NULL bytes when passed the '*' modifier" do + "a\x00b c".unpack(unpack_format("*")).should == ["a\x00b c"] + end +end diff --git a/spec/ruby/core/string/unpack/shared/taint.rb b/spec/ruby/core/string/unpack/shared/taint.rb new file mode 100644 index 0000000000..79c7251f01 --- /dev/null +++ b/spec/ruby/core/string/unpack/shared/taint.rb @@ -0,0 +1,2 @@ +describe :string_unpack_taint, shared: true do +end diff --git a/spec/ruby/core/string/unpack/shared/unicode.rb b/spec/ruby/core/string/unpack/shared/unicode.rb new file mode 100644 index 0000000000..9fe07f53ae --- /dev/null +++ b/spec/ruby/core/string/unpack/shared/unicode.rb @@ -0,0 +1,72 @@ +# -*- encoding: utf-8 -*- + +describe :string_unpack_unicode, shared: true do + it "decodes Unicode codepoints as ASCII values" do + [ ["\x00", [0]], + ["\x01", [1]], + ["\x08", [8]], + ["\x0f", [15]], + ["\x18", [24]], + ["\x1f", [31]], + ["\x7f", [127]], + ["\xc2\x80", [128]], + ["\xc2\x81", [129]], + ["\xc3\xbf", [255]] + ].should be_computed_by(:unpack, "U") + end + + it "decodes the number of characters specified by the count modifier" do + [ ["\xc2\x80\xc2\x81\xc2\x82\xc2\x83", "U1", [0x80]], + ["\xc2\x80\xc2\x81\xc2\x82\xc2\x83", "U2", [0x80, 0x81]], + ["\xc2\x80\xc2\x81\xc2\x82\xc2\x83", "U3", [0x80, 0x81, 0x82]] + ].should be_computed_by(:unpack) + end + + it "implicitly has a count of one when no count modifier is passed" do + "\xc2\x80\xc2\x81\xc2\x82\xc2\x83".unpack("U1").should == [0x80] + end + + it "decodes all remaining characters when passed the '*' modifier" do + "\xc2\x80\xc2\x81\xc2\x82\xc2\x83".unpack("U*").should == [0x80, 0x81, 0x82, 0x83] + end + + it "decodes UTF-8 BMP codepoints" do + [ ["\xc2\x80", [0x80]], + ["\xdf\xbf", [0x7ff]], + ["\xe0\xa0\x80", [0x800]], + ["\xef\xbf\xbf", [0xffff]] + ].should be_computed_by(:unpack, "U") + end + + it "decodes UTF-8 max codepoints" do + [ ["\xf0\x90\x80\x80", [0x10000]], + ["\xf3\xbf\xbf\xbf", [0xfffff]], + ["\xf4\x80\x80\x80", [0x100000]], + ["\xf4\x8f\xbf\xbf", [0x10ffff]] + ].should be_computed_by(:unpack, "U") + end + + it "does not decode any items for directives exceeding the input string size" do + "\xc2\x80".unpack("UUUU").should == [0x80] + end + + ruby_version_is ""..."3.3" do + it "ignores NULL bytes between directives" do + suppress_warning do + "\x01\x02".unpack("U\x00U").should == [1, 2] + end + end + end + + ruby_version_is "3.3" do + it "raise ArgumentError for NULL bytes between directives" do + -> { + "\x01\x02".unpack("U\x00U") + }.should raise_error(ArgumentError, /unknown unpack directive/) + end + end + + it "ignores spaces between directives" do + "\x01\x02".unpack("U U").should == [1, 2] + end +end |
