aboutsummaryrefslogtreecommitdiffstats
path: root/spec/rubyspec/core/string/unpack
diff options
context:
space:
mode:
Diffstat (limited to 'spec/rubyspec/core/string/unpack')
-rw-r--r--spec/rubyspec/core/string/unpack/a_spec.rb63
-rw-r--r--spec/rubyspec/core/string/unpack/at_spec.rb29
-rw-r--r--spec/rubyspec/core/string/unpack/b_spec.rb190
-rw-r--r--spec/rubyspec/core/string/unpack/c_spec.rb63
-rw-r--r--spec/rubyspec/core/string/unpack/comment_spec.rb25
-rw-r--r--spec/rubyspec/core/string/unpack/d_spec.rb28
-rw-r--r--spec/rubyspec/core/string/unpack/e_spec.rb14
-rw-r--r--spec/rubyspec/core/string/unpack/f_spec.rb28
-rw-r--r--spec/rubyspec/core/string/unpack/g_spec.rb14
-rw-r--r--spec/rubyspec/core/string/unpack/h_spec.rb124
-rw-r--r--spec/rubyspec/core/string/unpack/i_spec.rb152
-rw-r--r--spec/rubyspec/core/string/unpack/j_spec.rb277
-rw-r--r--spec/rubyspec/core/string/unpack/l_spec.rb376
-rw-r--r--spec/rubyspec/core/string/unpack/m_spec.rb170
-rw-r--r--spec/rubyspec/core/string/unpack/n_spec.rb18
-rw-r--r--spec/rubyspec/core/string/unpack/p_spec.rb21
-rw-r--r--spec/rubyspec/core/string/unpack/percent_spec.rb7
-rw-r--r--spec/rubyspec/core/string/unpack/q_spec.rb64
-rw-r--r--spec/rubyspec/core/string/unpack/s_spec.rb152
-rw-r--r--spec/rubyspec/core/string/unpack/shared/basic.rb29
-rw-r--r--spec/rubyspec/core/string/unpack/shared/float.rb271
-rw-r--r--spec/rubyspec/core/string/unpack/shared/integer.rb339
-rw-r--r--spec/rubyspec/core/string/unpack/shared/string.rb51
-rw-r--r--spec/rubyspec/core/string/unpack/shared/unicode.rb60
-rw-r--r--spec/rubyspec/core/string/unpack/u_spec.rb94
-rw-r--r--spec/rubyspec/core/string/unpack/v_spec.rb18
-rw-r--r--spec/rubyspec/core/string/unpack/w_spec.rb25
-rw-r--r--spec/rubyspec/core/string/unpack/x_spec.rb62
-rw-r--r--spec/rubyspec/core/string/unpack/z_spec.rb21
29 files changed, 2785 insertions, 0 deletions
diff --git a/spec/rubyspec/core/string/unpack/a_spec.rb b/spec/rubyspec/core/string/unpack/a_spec.rb
new file mode 100644
index 0000000000..18882c91a6
--- /dev/null
+++ b/spec/rubyspec/core/string/unpack/a_spec.rb
@@ -0,0 +1,63 @@
+# -*- encoding: ascii-8bit -*-
+require File.expand_path('../../../../spec_helper', __FILE__)
+require File.expand_path('../../fixtures/classes', __FILE__)
+require File.expand_path('../shared/basic', __FILE__)
+require File.expand_path('../shared/string', __FILE__)
+
+describe "String#unpack with format 'A'" do
+ it_behaves_like :string_unpack_basic, 'A'
+ it_behaves_like :string_unpack_no_platform, 'A'
+ it_behaves_like :string_unpack_string, 'A'
+ it_behaves_like :string_unpack_Aa, 'A'
+
+ it "removes trailing space and NULL bytes from the decoded string" do
+ [ ["a\x00 b \x00", ["a\x00 b", ""]],
+ ["a\x00 b \x00 ", ["a\x00 b", ""]],
+ ["a\x00 b\x00 ", ["a\x00 b", ""]],
+ ["a\x00 b\x00", ["a\x00 b", ""]],
+ ["a\x00 b ", ["a\x00 b", ""]]
+ ].should be_computed_by(:unpack, "A*A")
+ end
+
+ it "does not remove whitespace other than space" do
+ [ ["a\x00 b\x00\f", ["a\x00 b\x00\f"]],
+ ["a\x00 b\x00\n", ["a\x00 b\x00\n"]],
+ ["a\x00 b\x00\r", ["a\x00 b\x00\r"]],
+ ["a\x00 b\x00\t", ["a\x00 b\x00\t"]],
+ ["a\x00 b\x00\v", ["a\x00 b\x00\v"]],
+ ].should be_computed_by(:unpack, "A*")
+ end
+
+ it "decodes into raw (ascii) string values" do
+ str = "str".force_encoding('UTF-8').unpack("A*")[0]
+ str.encoding.name.should == 'ASCII-8BIT'
+ end
+
+end
+
+describe "String#unpack with format 'a'" do
+ it_behaves_like :string_unpack_basic, 'a'
+ it_behaves_like :string_unpack_no_platform, 'a'
+ it_behaves_like :string_unpack_string, 'a'
+ it_behaves_like :string_unpack_Aa, 'a'
+
+ it "does not remove trailing whitespace or NULL bytes from the decoded string" do
+ [ ["a\x00 b \x00", ["a\x00 b \x00"]],
+ ["a\x00 b \x00 ", ["a\x00 b \x00 "]],
+ ["a\x00 b\x00 ", ["a\x00 b\x00 "]],
+ ["a\x00 b\x00", ["a\x00 b\x00"]],
+ ["a\x00 b ", ["a\x00 b "]],
+ ["a\x00 b\f", ["a\x00 b\f"]],
+ ["a\x00 b\n", ["a\x00 b\n"]],
+ ["a\x00 b\r", ["a\x00 b\r"]],
+ ["a\x00 b\t", ["a\x00 b\t"]],
+ ["a\x00 b\v", ["a\x00 b\v"]]
+ ].should be_computed_by(:unpack, "a*")
+ end
+
+ it "decodes into raw (ascii) string values" do
+ str = "".unpack("a*")[0]
+ str.encoding.name.should == 'ASCII-8BIT'
+ end
+
+end
diff --git a/spec/rubyspec/core/string/unpack/at_spec.rb b/spec/rubyspec/core/string/unpack/at_spec.rb
new file mode 100644
index 0000000000..70cbebd2ba
--- /dev/null
+++ b/spec/rubyspec/core/string/unpack/at_spec.rb
@@ -0,0 +1,29 @@
+# -*- encoding: ascii-8bit -*-
+require File.expand_path('../../../../spec_helper', __FILE__)
+require File.expand_path('../../fixtures/classes', __FILE__)
+require File.expand_path('../shared/basic', __FILE__)
+
+describe "String#unpack with format '@'" do
+ it_behaves_like :string_unpack_basic, '@'
+ it_behaves_like :string_unpack_no_platform, '@'
+
+ it "moves the read index to the byte specified by the count" do
+ "\x01\x02\x03\x04".unpack("C3@2C").should == [1, 2, 3, 3]
+ end
+
+ it "implicitly has a count of zero when count is not specified" do
+ "\x01\x02\x03\x04".unpack("C2@C").should == [1, 2, 1]
+ end
+
+ it "has no effect when passed the '*' modifier" do
+ "\x01\x02\x03\x04".unpack("C2@*C").should == [1, 2, 3]
+ end
+
+ it "positions the read index one beyond the last readable byte in the String" do
+ "\x01\x02\x03\x04".unpack("C2@4C").should == [1, 2, nil]
+ end
+
+ it "raises an ArgumentError if the count exceeds the size of the String" do
+ lambda { "\x01\x02\x03\x04".unpack("C2@5C") }.should raise_error(ArgumentError)
+ end
+end
diff --git a/spec/rubyspec/core/string/unpack/b_spec.rb b/spec/rubyspec/core/string/unpack/b_spec.rb
new file mode 100644
index 0000000000..fa632e6526
--- /dev/null
+++ b/spec/rubyspec/core/string/unpack/b_spec.rb
@@ -0,0 +1,190 @@
+# -*- encoding: ascii-8bit -*-
+require File.expand_path('../../../../spec_helper', __FILE__)
+require File.expand_path('../../fixtures/classes', __FILE__)
+require File.expand_path('../shared/basic', __FILE__)
+
+describe "String#unpack with format 'B'" do
+ it_behaves_like :string_unpack_basic, 'B'
+ it_behaves_like :string_unpack_no_platform, 'B'
+
+ it "decodes one bit from each byte for each format character starting with the most significant bit" do
+ [ ["\x00", "B", ["0"]],
+ ["\x80", "B", ["1"]],
+ ["\x0f", "B", ["0"]],
+ ["\x8f", "B", ["1"]],
+ ["\x7f", "B", ["0"]],
+ ["\xff", "B", ["1"]],
+ ["\x80\x00", "BB", ["1", "0"]],
+ ["\x8f\x00", "BB", ["1", "0"]],
+ ["\x80\x0f", "BB", ["1", "0"]],
+ ["\x80\x8f", "BB", ["1", "1"]],
+ ["\x80\x80", "BB", ["1", "1"]],
+ ["\x0f\x80", "BB", ["0", "1"]]
+ ].should be_computed_by(:unpack)
+ end
+
+ it "decodes only the number of bits in the string when passed a count" do
+ "\x83".unpack("B25").should == ["10000011"]
+ end
+
+ it "decodes multiple differing bit counts from a single string" do
+ str = "\xaa\xaa\xaa\xaa\x55\xaa\xd4\xc3\x6b\xd7\xaa\xd7\xc3\xd4\xaa\x6b\xd7\xaa"
+ array = str.unpack("B5B6B7B8B9B10B13B14B16B17")
+ array.should == ["10101", "101010", "1010101", "10101010", "010101011",
+ "1101010011", "0110101111010", "10101010110101",
+ "1100001111010100", "10101010011010111"]
+ end
+
+ it "decodes a directive with a '*' modifier after a directive with a count modifier" do
+ "\xd4\xc3\x6b\xd7".unpack("B5B*").should == ["11010", "110000110110101111010111"]
+ end
+
+ it "decodes a directive with a count modifier after a directive with a '*' modifier" do
+ "\xd4\xc3\x6b\xd7".unpack("B*B5").should == ["11010100110000110110101111010111", ""]
+ end
+
+ it "decodes the number of bits specified by the count modifier" do
+ [ ["\x00", "B0", [""]],
+ ["\x80", "B1", ["1"]],
+ ["\x7f", "B2", ["01"]],
+ ["\x8f", "B3", ["100"]],
+ ["\x7f", "B4", ["0111"]],
+ ["\xff", "B5", ["11111"]],
+ ["\xf8", "B6", ["111110"]],
+ ["\x9c", "B7", ["1001110"]],
+ ["\xbd", "B8", ["10111101"]],
+ ["\x80\x80", "B9", ["100000001"]],
+ ["\x80\x70", "B10", ["1000000001"]],
+ ["\x80\x20", "B11", ["10000000001"]],
+ ["\x8f\x10", "B12", ["100011110001"]],
+ ["\x8f\x0f", "B13", ["1000111100001"]],
+ ["\x80\x0f", "B14", ["10000000000011"]],
+ ["\x80\x8f", "B15", ["100000001000111"]],
+ ["\x0f\x81", "B16", ["0000111110000001"]]
+ ].should be_computed_by(:unpack)
+ end
+
+ it "decodes all the bits when passed the '*' modifier" do
+ [ ["", [""]],
+ ["\x00", ["00000000"]],
+ ["\x80", ["10000000"]],
+ ["\x7f", ["01111111"]],
+ ["\x81", ["10000001"]],
+ ["\x0f", ["00001111"]],
+ ["\x80\x80", ["1000000010000000"]],
+ ["\x8f\x10", ["1000111100010000"]],
+ ["\x00\x10", ["0000000000010000"]]
+ ].should be_computed_by(:unpack, "B*")
+ end
+
+ it "adds an empty string for each element requested beyond the end of the String" do
+ [ ["", ["", "", ""]],
+ ["\x80", ["1", "", ""]],
+ ["\x80\x08", ["1", "0", ""]]
+ ].should be_computed_by(:unpack, "BBB")
+ end
+
+ it "ignores NULL bytes between directives" do
+ "\x80\x00".unpack("B\x00B").should == ["1", "0"]
+ end
+
+ it "ignores spaces between directives" do
+ "\x80\x00".unpack("B B").should == ["1", "0"]
+ end
+end
+
+describe "String#unpack with format 'b'" do
+ it_behaves_like :string_unpack_basic, 'b'
+ it_behaves_like :string_unpack_no_platform, 'b'
+
+ it "decodes one bit from each byte for each format character starting with the least significant bit" do
+ [ ["\x00", "b", ["0"]],
+ ["\x01", "b", ["1"]],
+ ["\xf0", "b", ["0"]],
+ ["\xf1", "b", ["1"]],
+ ["\xfe", "b", ["0"]],
+ ["\xff", "b", ["1"]],
+ ["\x01\x00", "bb", ["1", "0"]],
+ ["\xf1\x00", "bb", ["1", "0"]],
+ ["\x01\xf0", "bb", ["1", "0"]],
+ ["\x01\xf1", "bb", ["1", "1"]],
+ ["\x01\x01", "bb", ["1", "1"]],
+ ["\xf0\x01", "bb", ["0", "1"]]
+ ].should be_computed_by(:unpack)
+ end
+
+ it "decodes only the number of bits in the string when passed a count" do
+ "\x83".unpack("b25").should == ["11000001"]
+ end
+
+ it "decodes multiple differing bit counts from a single string" do
+ str = "\xaa\xaa\xaa\xaa\x55\xaa\xd4\xc3\x6b\xd7\xaa\xd7\xc3\xd4\xaa\x6b\xd7\xaa"
+ array = str.unpack("b5b6b7b8b9b10b13b14b16b17")
+ array.should == ["01010", "010101", "0101010", "01010101", "101010100",
+ "0010101111", "1101011011101", "01010101111010",
+ "1100001100101011", "01010101110101101"]
+ end
+
+ it "decodes a directive with a '*' modifier after a directive with a count modifier" do
+ "\xd4\xc3\x6b\xd7".unpack("b5b*").should == ["00101", "110000111101011011101011"]
+ end
+
+ it "decodes a directive with a count modifier after a directive with a '*' modifier" do
+ "\xd4\xc3\x6b\xd7".unpack("b*b5").should == ["00101011110000111101011011101011", ""]
+ end
+
+ it "decodes the number of bits specified by the count modifier" do
+ [ ["\x00", "b0", [""]],
+ ["\x01", "b1", ["1"]],
+ ["\xfe", "b2", ["01"]],
+ ["\xfc", "b3", ["001"]],
+ ["\xf7", "b4", ["1110"]],
+ ["\xff", "b5", ["11111"]],
+ ["\xfe", "b6", ["011111"]],
+ ["\xce", "b7", ["0111001"]],
+ ["\xbd", "b8", ["10111101"]],
+ ["\x01\xff", "b9", ["100000001"]],
+ ["\x01\xfe", "b10", ["1000000001"]],
+ ["\x01\xfc", "b11", ["10000000001"]],
+ ["\xf1\xf8", "b12", ["100011110001"]],
+ ["\xe1\xf1", "b13", ["1000011110001"]],
+ ["\x03\xe0", "b14", ["11000000000001"]],
+ ["\x47\xc0", "b15", ["111000100000001"]],
+ ["\x81\x0f", "b16", ["1000000111110000"]]
+ ].should be_computed_by(:unpack)
+ end
+
+ it "decodes all the bits when passed the '*' modifier" do
+ [ ["", [""]],
+ ["\x00", ["00000000"]],
+ ["\x80", ["00000001"]],
+ ["\x7f", ["11111110"]],
+ ["\x81", ["10000001"]],
+ ["\x0f", ["11110000"]],
+ ["\x80\x80", ["0000000100000001"]],
+ ["\x8f\x10", ["1111000100001000"]],
+ ["\x00\x10", ["0000000000001000"]]
+ ].should be_computed_by(:unpack, "b*")
+ end
+
+ it "adds an empty string for each element requested beyond the end of the String" do
+ [ ["", ["", "", ""]],
+ ["\x01", ["1", "", ""]],
+ ["\x01\x80", ["1", "0", ""]]
+ ].should be_computed_by(:unpack, "bbb")
+ end
+
+ it "ignores NULL bytes between directives" do
+ "\x01\x00".unpack("b\x00b").should == ["1", "0"]
+ end
+
+ it "ignores spaces between directives" do
+ "\x01\x00".unpack("b b").should == ["1", "0"]
+ end
+
+ it "decodes into US-ASCII string values" do
+ str = "s".force_encoding('UTF-8').unpack("b*")[0]
+ str.encoding.name.should == 'US-ASCII'
+ end
+
+end
diff --git a/spec/rubyspec/core/string/unpack/c_spec.rb b/spec/rubyspec/core/string/unpack/c_spec.rb
new file mode 100644
index 0000000000..36de462cac
--- /dev/null
+++ b/spec/rubyspec/core/string/unpack/c_spec.rb
@@ -0,0 +1,63 @@
+# -*- encoding: ascii-8bit -*-
+require File.expand_path('../../../../spec_helper', __FILE__)
+require File.expand_path('../../fixtures/classes', __FILE__)
+require File.expand_path('../shared/basic', __FILE__)
+
+describe :string_unpack_8bit, shared: true do
+ it "decodes one byte for a single format character" do
+ "abc".unpack(unpack_format()).should == [97]
+ end
+
+ it "decodes two bytes for two format characters" do
+ "abc".unpack(unpack_format(nil, 2)).should == [97, 98]
+ end
+
+ it "decodes the number of bytes requested by the count modifier" do
+ "abc".unpack(unpack_format(2)).should == [97, 98]
+ end
+
+ it "decodes the remaining bytes when passed the '*' modifier" do
+ "abc".unpack(unpack_format('*')).should == [97, 98, 99]
+ end
+
+ it "decodes the remaining bytes when passed the '*' modifer after another directive" do
+ "abc".unpack(unpack_format()+unpack_format('*')).should == [97, 98, 99]
+ end
+
+ it "decodes zero bytes when no bytes remain and the '*' modifier is passed" do
+ "abc".unpack(unpack_format('*', 2)).should == [97, 98, 99]
+ end
+
+ it "adds nil for each element requested beyond the end of the String" do
+ [ ["", [nil, nil, nil]],
+ ["a", [97, nil, nil]],
+ ["ab", [97, 98, nil]]
+ ].should be_computed_by(:unpack, unpack_format(3))
+ end
+
+ it "ignores NULL bytes between directives" do
+ "abc".unpack(unpack_format("\000", 2)).should == [97, 98]
+ end
+
+ it "ignores spaces between directives" do
+ "abc".unpack(unpack_format(' ', 2)).should == [97, 98]
+ end
+end
+
+describe "String#unpack with format 'C'" do
+ it_behaves_like :string_unpack_basic, 'C'
+ it_behaves_like :string_unpack_8bit, 'C'
+
+ it "decodes a byte with most significant bit set as a positive number" do
+ "\xff\x80\x82".unpack('C*').should == [255, 128, 130]
+ end
+end
+
+describe "String#unpack with format 'c'" do
+ it_behaves_like :string_unpack_basic, 'c'
+ it_behaves_like :string_unpack_8bit, 'c'
+
+ it "decodes a byte with most significant bit set as a negative number" do
+ "\xff\x80\x82".unpack('c*').should == [-1, -128, -126]
+ end
+end
diff --git a/spec/rubyspec/core/string/unpack/comment_spec.rb b/spec/rubyspec/core/string/unpack/comment_spec.rb
new file mode 100644
index 0000000000..884960b337
--- /dev/null
+++ b/spec/rubyspec/core/string/unpack/comment_spec.rb
@@ -0,0 +1,25 @@
+# -*- encoding: ascii-8bit -*-
+require File.expand_path('../../../../spec_helper', __FILE__)
+require File.expand_path('../../fixtures/classes', __FILE__)
+
+describe "String#unpack" do
+ it "ignores directives text from '#' to the first newline" do
+ "\x01\x02\x03".unpack("c#this is a comment\nc").should == [1, 2]
+ end
+
+ it "ignores directives text from '#' to the end if no newline is present" do
+ "\x01\x02\x03".unpack("c#this is a comment c").should == [1]
+ end
+
+ it "ignores comments at the start of the directives string" do
+ "\x01\x02\x03".unpack("#this is a comment\nc").should == [1]
+ end
+
+ it "ignores the entire directive string if it is a comment" do
+ "\x01\x02\x03".unpack("#this is a comment c").should == []
+ end
+
+ it "ignores multiple comments" do
+ "\x01\x02\x03".unpack("c#comment\nc#comment\nc#c").should == [1, 2, 3]
+ end
+end
diff --git a/spec/rubyspec/core/string/unpack/d_spec.rb b/spec/rubyspec/core/string/unpack/d_spec.rb
new file mode 100644
index 0000000000..db4638f8ef
--- /dev/null
+++ b/spec/rubyspec/core/string/unpack/d_spec.rb
@@ -0,0 +1,28 @@
+require File.expand_path('../../../../spec_helper', __FILE__)
+require File.expand_path('../../fixtures/classes', __FILE__)
+require File.expand_path('../shared/basic', __FILE__)
+require File.expand_path('../shared/float', __FILE__)
+
+little_endian do
+ describe "String#unpack with format 'D'" do
+ it_behaves_like :string_unpack_basic, 'D'
+ it_behaves_like :string_unpack_double_le, 'D'
+ end
+
+ describe "String#unpack with format 'd'" do
+ it_behaves_like :string_unpack_basic, 'd'
+ it_behaves_like :string_unpack_double_le, 'd'
+ end
+end
+
+big_endian do
+ describe "String#unpack with format 'D'" do
+ it_behaves_like :string_unpack_basic, 'D'
+ it_behaves_like :string_unpack_double_be, 'D'
+ end
+
+ describe "String#unpack with format 'd'" do
+ it_behaves_like :string_unpack_basic, 'd'
+ it_behaves_like :string_unpack_double_be, 'd'
+ end
+end
diff --git a/spec/rubyspec/core/string/unpack/e_spec.rb b/spec/rubyspec/core/string/unpack/e_spec.rb
new file mode 100644
index 0000000000..cb74c00206
--- /dev/null
+++ b/spec/rubyspec/core/string/unpack/e_spec.rb
@@ -0,0 +1,14 @@
+require File.expand_path('../../../../spec_helper', __FILE__)
+require File.expand_path('../../fixtures/classes', __FILE__)
+require File.expand_path('../shared/basic', __FILE__)
+require File.expand_path('../shared/float', __FILE__)
+
+describe "String#unpack with format 'E'" do
+ it_behaves_like :string_unpack_basic, 'E'
+ it_behaves_like :string_unpack_double_le, 'E'
+end
+
+describe "String#unpack with format 'e'" do
+ it_behaves_like :string_unpack_basic, 'e'
+ it_behaves_like :string_unpack_float_le, 'e'
+end
diff --git a/spec/rubyspec/core/string/unpack/f_spec.rb b/spec/rubyspec/core/string/unpack/f_spec.rb
new file mode 100644
index 0000000000..60dad46703
--- /dev/null
+++ b/spec/rubyspec/core/string/unpack/f_spec.rb
@@ -0,0 +1,28 @@
+require File.expand_path('../../../../spec_helper', __FILE__)
+require File.expand_path('../../fixtures/classes', __FILE__)
+require File.expand_path('../shared/basic', __FILE__)
+require File.expand_path('../shared/float', __FILE__)
+
+little_endian do
+ describe "String#unpack with format 'F'" do
+ it_behaves_like :string_unpack_basic, 'F'
+ it_behaves_like :string_unpack_float_le, 'F'
+ end
+
+ describe "String#unpack with format 'f'" do
+ it_behaves_like :string_unpack_basic, 'f'
+ it_behaves_like :string_unpack_float_le, 'f'
+ end
+end
+
+big_endian do
+ describe "String#unpack with format 'F'" do
+ it_behaves_like :string_unpack_basic, 'F'
+ it_behaves_like :string_unpack_float_be, 'F'
+ end
+
+ describe "String#unpack with format 'f'" do
+ it_behaves_like :string_unpack_basic, 'f'
+ it_behaves_like :string_unpack_float_be, 'f'
+ end
+end
diff --git a/spec/rubyspec/core/string/unpack/g_spec.rb b/spec/rubyspec/core/string/unpack/g_spec.rb
new file mode 100644
index 0000000000..f5bec1534e
--- /dev/null
+++ b/spec/rubyspec/core/string/unpack/g_spec.rb
@@ -0,0 +1,14 @@
+require File.expand_path('../../../../spec_helper', __FILE__)
+require File.expand_path('../../fixtures/classes', __FILE__)
+require File.expand_path('../shared/basic', __FILE__)
+require File.expand_path('../shared/float', __FILE__)
+
+describe "String#unpack with format 'G'" do
+ it_behaves_like :string_unpack_basic, 'G'
+ it_behaves_like :string_unpack_double_be, 'G'
+end
+
+describe "String#unpack with format 'g'" do
+ it_behaves_like :string_unpack_basic, 'g'
+ it_behaves_like :string_unpack_float_be, 'g'
+end
diff --git a/spec/rubyspec/core/string/unpack/h_spec.rb b/spec/rubyspec/core/string/unpack/h_spec.rb
new file mode 100644
index 0000000000..00d6d68eee
--- /dev/null
+++ b/spec/rubyspec/core/string/unpack/h_spec.rb
@@ -0,0 +1,124 @@
+# -*- encoding: ascii-8bit -*-
+require File.expand_path('../../../../spec_helper', __FILE__)
+require File.expand_path('../../fixtures/classes', __FILE__)
+require File.expand_path('../shared/basic', __FILE__)
+
+describe "String#unpack with format 'H'" do
+ it_behaves_like :string_unpack_basic, 'H'
+ it_behaves_like :string_unpack_no_platform, 'H'
+
+ it "decodes one nibble from each byte for each format character starting with the most significant bit" do
+ [ ["\x8f", "H", ["8"]],
+ ["\xf8\x0f", "HH", ["f", "0"]]
+ ].should be_computed_by(:unpack)
+ end
+
+ it "decodes only the number of nibbles in the string when passed a count" do
+ "\xca\xfe".unpack("H5").should == ["cafe"]
+ end
+
+ it "decodes multiple differing nibble counts from a single string" do
+ array = "\xaa\x55\xaa\xd4\xc3\x6b\xd7\xaa\xd7".unpack("HH2H3H4H5")
+ array.should == ["a", "55", "aad", "c36b", "d7aad"]
+ end
+
+ it "decodes a directive with a '*' modifier after a directive with a count modifier" do
+ "\xaa\x55\xaa\xd4\xc3\x6b".unpack("H3H*").should == ["aa5", "aad4c36b"]
+ end
+
+ it "decodes a directive with a count modifier after a directive with a '*' modifier" do
+ "\xaa\x55\xaa\xd4\xc3\x6b".unpack("H*H3").should == ["aa55aad4c36b", ""]
+ end
+
+ it "decodes the number of nibbles specified by the count modifier" do
+ [ ["\xab", "H0", [""]],
+ ["\x00", "H1", ["0"]],
+ ["\x01", "H2", ["01"]],
+ ["\x01\x23", "H3", ["012"]],
+ ["\x01\x23", "H4", ["0123"]],
+ ["\x01\x23\x45", "H5", ["01234"]]
+ ].should be_computed_by(:unpack)
+ end
+
+ it "decodes all the nibbles when passed the '*' modifier" do
+ [ ["", [""]],
+ ["\xab", ["ab"]],
+ ["\xca\xfe", ["cafe"]],
+ ].should be_computed_by(:unpack, "H*")
+ end
+
+ it "adds an empty string for each element requested beyond the end of the String" do
+ [ ["", ["", "", ""]],
+ ["\x01", ["0", "", ""]],
+ ["\x01\x80", ["0", "8", ""]]
+ ].should be_computed_by(:unpack, "HHH")
+ end
+
+ it "ignores NULL bytes between directives" do
+ "\x01\x10".unpack("H\x00H").should == ["0", "1"]
+ end
+
+ it "ignores spaces between directives" do
+ "\x01\x10".unpack("H H").should == ["0", "1"]
+ end
+end
+
+describe "String#unpack with format 'h'" do
+ it_behaves_like :string_unpack_basic, 'h'
+ it_behaves_like :string_unpack_no_platform, 'h'
+
+ it "decodes one nibble from each byte for each format character starting with the least significant bit" do
+ [ ["\x8f", "h", ["f"]],
+ ["\xf8\x0f", "hh", ["8", "f"]]
+ ].should be_computed_by(:unpack)
+ end
+
+ it "decodes only the number of nibbles in the string when passed a count" do
+ "\xac\xef".unpack("h5").should == ["cafe"]
+ end
+
+ it "decodes multiple differing nibble counts from a single string" do
+ array = "\xaa\x55\xaa\xd4\xc3\x6b\xd7\xaa\xd7".unpack("hh2h3h4h5")
+ array.should == ["a", "55", "aa4", "3cb6", "7daa7"]
+ end
+
+ it "decodes a directive with a '*' modifier after a directive with a count modifier" do
+ "\xba\x55\xaa\xd4\xc3\x6b".unpack("h3h*").should == ["ab5", "aa4d3cb6"]
+ end
+
+ it "decodes a directive with a count modifier after a directive with a '*' modifier" do
+ "\xba\x55\xaa\xd4\xc3\x6b".unpack("h*h3").should == ["ab55aa4d3cb6", ""]
+ end
+
+ it "decodes the number of nibbles specified by the count modifier" do
+ [ ["\xab", "h0", [""]],
+ ["\x00", "h1", ["0"]],
+ ["\x01", "h2", ["10"]],
+ ["\x01\x23", "h3", ["103"]],
+ ["\x01\x23", "h4", ["1032"]],
+ ["\x01\x23\x45", "h5", ["10325"]]
+ ].should be_computed_by(:unpack)
+ end
+
+ it "decodes all the nibbles when passed the '*' modifier" do
+ [ ["", [""]],
+ ["\xab", ["ba"]],
+ ["\xac\xef", ["cafe"]],
+ ].should be_computed_by(:unpack, "h*")
+ end
+
+ it "adds an empty string for each element requested beyond the end of the String" do
+ [ ["", ["", "", ""]],
+ ["\x01", ["1", "", ""]],
+ ["\x01\x80", ["1", "0", ""]]
+ ].should be_computed_by(:unpack, "hhh")
+ end
+
+ it "ignores NULL bytes between directives" do
+ "\x01\x10".unpack("h\x00h").should == ["1", "0"]
+ end
+
+ it "ignores spaces between directives" do
+ "\x01\x10".unpack("h h").should == ["1", "0"]
+ end
+end
diff --git a/spec/rubyspec/core/string/unpack/i_spec.rb b/spec/rubyspec/core/string/unpack/i_spec.rb
new file mode 100644
index 0000000000..f3183afe99
--- /dev/null
+++ b/spec/rubyspec/core/string/unpack/i_spec.rb
@@ -0,0 +1,152 @@
+require File.expand_path('../../../../spec_helper', __FILE__)
+require File.expand_path('../../fixtures/classes', __FILE__)
+require File.expand_path('../shared/basic', __FILE__)
+require File.expand_path('../shared/integer', __FILE__)
+
+describe "String#unpack with format 'I'" do
+ describe "with modifier '<'" do
+ it_behaves_like :string_unpack_32bit_le, 'I<'
+ it_behaves_like :string_unpack_32bit_le_unsigned, 'I<'
+ end
+
+ describe "with modifier '<' and '_'" do
+ it_behaves_like :string_unpack_32bit_le, 'I<_'
+ it_behaves_like :string_unpack_32bit_le, 'I_<'
+ it_behaves_like :string_unpack_32bit_le_unsigned, 'I<_'
+ it_behaves_like :string_unpack_32bit_le_unsigned, 'I_<'
+ end
+
+ describe "with modifier '<' and '!'" do
+ it_behaves_like :string_unpack_32bit_le, 'I<!'
+ it_behaves_like :string_unpack_32bit_le, 'I!<'
+ it_behaves_like :string_unpack_32bit_le_unsigned, 'I<!'
+ it_behaves_like :string_unpack_32bit_le_unsigned, 'I!<'
+ end
+
+ describe "with modifier '>'" do
+ it_behaves_like :string_unpack_32bit_be, 'I>'
+ it_behaves_like :string_unpack_32bit_be_unsigned, 'I>'
+ end
+
+ describe "with modifier '>' and '_'" do
+ it_behaves_like :string_unpack_32bit_be, 'I>_'
+ it_behaves_like :string_unpack_32bit_be, 'I_>'
+ it_behaves_like :string_unpack_32bit_be_unsigned, 'I>_'
+ it_behaves_like :string_unpack_32bit_be_unsigned, 'I_>'
+ end
+
+ describe "with modifier '>' and '!'" do
+ it_behaves_like :string_unpack_32bit_be, 'I>!'
+ it_behaves_like :string_unpack_32bit_be, 'I!>'
+ it_behaves_like :string_unpack_32bit_be_unsigned, 'I>!'
+ it_behaves_like :string_unpack_32bit_be_unsigned, 'I!>'
+ end
+end
+
+describe "String#unpack with format 'i'" do
+ describe "with modifier '<'" do
+ it_behaves_like :string_unpack_32bit_le, 'i<'
+ it_behaves_like :string_unpack_32bit_le_signed, 'i<'
+ end
+
+ describe "with modifier '<' and '_'" do
+ it_behaves_like :string_unpack_32bit_le, 'i<_'
+ it_behaves_like :string_unpack_32bit_le, 'i_<'
+ it_behaves_like :string_unpack_32bit_le_signed, 'i<_'
+ it_behaves_like :string_unpack_32bit_le_signed, 'i_<'
+ end
+
+ describe "with modifier '<' and '!'" do
+ it_behaves_like :string_unpack_32bit_le, 'i<!'
+ it_behaves_like :string_unpack_32bit_le, 'i!<'
+ it_behaves_like :string_unpack_32bit_le_signed, 'i<!'
+ it_behaves_like :string_unpack_32bit_le_signed, 'i!<'
+ end
+
+ describe "with modifier '>'" do
+ it_behaves_like :string_unpack_32bit_be, 'i>'
+ it_behaves_like :string_unpack_32bit_be_signed, 'i>'
+ end
+
+ describe "with modifier '>' and '_'" do
+ it_behaves_like :string_unpack_32bit_be, 'i>_'
+ it_behaves_like :string_unpack_32bit_be, 'i_>'
+ it_behaves_like :string_unpack_32bit_be_signed, 'i>_'
+ it_behaves_like :string_unpack_32bit_be_signed, 'i_>'
+ end
+
+ describe "with modifier '>' and '!'" do
+ it_behaves_like :string_unpack_32bit_be, 'i>!'
+ it_behaves_like :string_unpack_32bit_be, 'i!>'
+ it_behaves_like :string_unpack_32bit_be_signed, 'i>!'
+ it_behaves_like :string_unpack_32bit_be_signed, 'i!>'
+ end
+end
+
+little_endian do
+ describe "String#unpack with format 'I'" do
+ it_behaves_like :string_unpack_basic, 'I'
+ it_behaves_like :string_unpack_32bit_le, 'I'
+ it_behaves_like :string_unpack_32bit_le_unsigned, 'I'
+ end
+
+ describe "String#unpack with format 'I' with modifier '_'" do
+ it_behaves_like :string_unpack_32bit_le, 'I_'
+ it_behaves_like :string_unpack_32bit_le_unsigned, 'I_'
+ end
+
+ describe "String#unpack with format 'I' with modifier '!'" do
+ it_behaves_like :string_unpack_32bit_le, 'I!'
+ it_behaves_like :string_unpack_32bit_le_unsigned, 'I!'
+ end
+
+ describe "String#unpack with format 'i'" do
+ it_behaves_like :string_unpack_basic, 'i'
+ it_behaves_like :string_unpack_32bit_le, 'i'
+ it_behaves_like :string_unpack_32bit_le_signed, 'i'
+ end
+
+ describe "String#unpack with format 'i' with modifier '_'" do
+ it_behaves_like :string_unpack_32bit_le, 'i_'
+ it_behaves_like :string_unpack_32bit_le_signed, 'i_'
+ end
+
+ describe "String#unpack with format 'i' with modifier '!'" do
+ it_behaves_like :string_unpack_32bit_le, 'i!'
+ it_behaves_like :string_unpack_32bit_le_signed, 'i!'
+ end
+end
+
+big_endian do
+ describe "String#unpack with format 'I'" do
+ it_behaves_like :string_unpack_basic, 'I'
+ it_behaves_like :string_unpack_32bit_be, 'I'
+ it_behaves_like :string_unpack_32bit_be_unsigned, 'I'
+ end
+
+ describe "String#unpack with format 'I' with modifier '_'" do
+ it_behaves_like :string_unpack_32bit_be, 'I_'
+ it_behaves_like :string_unpack_32bit_be_unsigned, 'I_'
+ end
+
+ describe "String#unpack with format 'I' with modifier '!'" do
+ it_behaves_like :string_unpack_32bit_be, 'I!'
+ it_behaves_like :string_unpack_32bit_be_unsigned, 'I!'
+ end
+
+ describe "String#unpack with format 'i'" do
+ it_behaves_like :string_unpack_basic, 'i'
+ it_behaves_like :string_unpack_32bit_be, 'i'
+ it_behaves_like :string_unpack_32bit_be_signed, 'i'
+ end
+
+ describe "String#unpack with format 'i' with modifier '_'" do
+ it_behaves_like :string_unpack_32bit_be, 'i_'
+ it_behaves_like :string_unpack_32bit_be_signed, 'i_'
+ end
+
+ describe "String#unpack with format 'i' with modifier '!'" do
+ it_behaves_like :string_unpack_32bit_be, 'i!'
+ it_behaves_like :string_unpack_32bit_be_signed, 'i!'
+ end
+end
diff --git a/spec/rubyspec/core/string/unpack/j_spec.rb b/spec/rubyspec/core/string/unpack/j_spec.rb
new file mode 100644
index 0000000000..49c460aeb3
--- /dev/null
+++ b/spec/rubyspec/core/string/unpack/j_spec.rb
@@ -0,0 +1,277 @@
+require File.expand_path('../../../../spec_helper', __FILE__)
+require File.expand_path('../../fixtures/classes', __FILE__)
+require File.expand_path('../shared/basic', __FILE__)
+require File.expand_path('../shared/integer', __FILE__)
+
+ruby_version_is '2.3' do
+ # To handle the special case of x64-mingw32
+ pointer_size = RUBY_PLATFORM =~ /\bx64\b/ ? 64 : 1.size * 8
+
+ if pointer_size == 64 then
+ little_endian do
+ describe "String#unpack with format 'J'" do
+ describe "with modifier '_'" do
+ it_behaves_like :string_unpack_64bit_le, 'J_'
+ it_behaves_like :string_unpack_64bit_le_unsigned, 'J_'
+ end
+
+ describe "with modifier '!'" do
+ it_behaves_like :string_unpack_64bit_le, 'J!'
+ it_behaves_like :string_unpack_64bit_le_unsigned, 'J!'
+ end
+ end
+
+ describe "String#unpack with format 'j'" do
+ describe "with modifier '_'" do
+ it_behaves_like :string_unpack_64bit_le, 'j_'
+ it_behaves_like :string_unpack_64bit_le_signed, 'j_'
+ end
+
+ describe "with modifier '!'" do
+ it_behaves_like :string_unpack_64bit_le, 'j!'
+ it_behaves_like :string_unpack_64bit_le_signed, 'j!'
+ end
+ end
+ end
+
+ big_endian do
+ describe "String#unpack with format 'J'" do
+ describe "with modifier '_'" do
+ it_behaves_like :string_unpack_64bit_be, 'J_'
+ it_behaves_like :string_unpack_64bit_be_unsigned, 'J_'
+ end
+
+ describe "with modifier '!'" do
+ it_behaves_like :string_unpack_64bit_be, 'J!'
+ it_behaves_like :string_unpack_64bit_be_unsigned, 'J!'
+ end
+ end
+
+ describe "String#unpack with format 'j'" do
+ describe "with modifier '_'" do
+ it_behaves_like :string_unpack_64bit_be, 'j_'
+ it_behaves_like :string_unpack_64bit_be_signed, 'j_'
+ end
+
+ describe "with modifier '!'" do
+ it_behaves_like :string_unpack_64bit_be, 'j!'
+ it_behaves_like :string_unpack_64bit_be_signed, 'j!'
+ end
+ end
+ end
+
+ describe "String#unpack with format 'J'" do
+ describe "with modifier '<'" do
+ it_behaves_like :string_unpack_64bit_le, 'J<'
+ it_behaves_like :string_unpack_64bit_le_unsigned, 'J<'
+ end
+
+ describe "with modifier '>'" do
+ it_behaves_like :string_unpack_64bit_be, 'J>'
+ it_behaves_like :string_unpack_64bit_be_unsigned, 'J>'
+ end
+
+ describe "with modifier '<' and '_'" do
+ it_behaves_like :string_unpack_64bit_le, 'J<_'
+ it_behaves_like :string_unpack_64bit_le, 'J_<'
+ it_behaves_like :string_unpack_64bit_le_unsigned, 'J<_'
+ it_behaves_like :string_unpack_64bit_le_unsigned, 'J_<'
+ end
+
+ describe "with modifier '<' and '!'" do
+ it_behaves_like :string_unpack_64bit_le, 'J<!'
+ it_behaves_like :string_unpack_64bit_le, 'J!<'
+ it_behaves_like :string_unpack_64bit_le_unsigned, 'J<!'
+ it_behaves_like :string_unpack_64bit_le_unsigned, 'J!<'
+ end
+
+ describe "with modifier '>' and '_'" do
+ it_behaves_like :string_unpack_64bit_be, 'J>_'
+ it_behaves_like :string_unpack_64bit_be, 'J_>'
+ it_behaves_like :string_unpack_64bit_be_unsigned, 'J>_'
+ it_behaves_like :string_unpack_64bit_be_unsigned, 'J_>'
+ end
+
+ describe "with modifier '>' and '!'" do
+ it_behaves_like :string_unpack_64bit_be, 'J>!'
+ it_behaves_like :string_unpack_64bit_be, 'J!>'
+ it_behaves_like :string_unpack_64bit_be_unsigned, 'J>!'
+ it_behaves_like :string_unpack_64bit_be_unsigned, 'J!>'
+ end
+ end
+
+ describe "String#unpack with format 'j'" do
+ describe "with modifier '<'" do
+ it_behaves_like :string_unpack_64bit_le, 'j<'
+ it_behaves_like :string_unpack_64bit_le_signed, 'j<'
+ end
+
+ describe "with modifier '>'" do
+ it_behaves_like :string_unpack_64bit_be, 'j>'
+ it_behaves_like :string_unpack_64bit_be_signed, 'j>'
+ end
+
+ describe "with modifier '<' and '_'" do
+ it_behaves_like :string_unpack_64bit_le, 'j<_'
+ it_behaves_like :string_unpack_64bit_le, 'j_<'
+ it_behaves_like :string_unpack_64bit_le_signed, 'j<_'
+ it_behaves_like :string_unpack_64bit_le_signed, 'j_<'
+ end
+
+ describe "with modifier '<' and '!'" do
+ it_behaves_like :string_unpack_64bit_le, 'j<!'
+ it_behaves_like :string_unpack_64bit_le, 'j!<'
+ it_behaves_like :string_unpack_64bit_le_signed, 'j<!'
+ it_behaves_like :string_unpack_64bit_le_signed, 'j!<'
+ end
+
+ describe "with modifier '>' and '_'" do
+ it_behaves_like :string_unpack_64bit_be, 'j>_'
+ it_behaves_like :string_unpack_64bit_be, 'j_>'
+ it_behaves_like :string_unpack_64bit_be_signed, 'j>_'
+ it_behaves_like :string_unpack_64bit_be_signed, 'j_>'
+ end
+
+ describe "with modifier '>' and '!'" do
+ it_behaves_like :string_unpack_64bit_be, 'j>!'
+ it_behaves_like :string_unpack_64bit_be, 'j!>'
+ it_behaves_like :string_unpack_64bit_be_signed, 'j>!'
+ it_behaves_like :string_unpack_64bit_be_signed, 'j!>'
+ end
+ end
+ end
+
+ if pointer_size == 32 then
+ little_endian do
+ describe "String#unpack with format 'J'" do
+ describe "with modifier '_'" do
+ it_behaves_like :string_unpack_32bit_le, 'J_'
+ it_behaves_like :string_unpack_32bit_le_unsigned, 'J_'
+ end
+
+ describe "with modifier '!'" do
+ it_behaves_like :string_unpack_32bit_le, 'J!'
+ it_behaves_like :string_unpack_32bit_le_unsigned, 'J!'
+ end
+ end
+
+ describe "String#unpack with format 'j'" do
+ describe "with modifier '_'" do
+ it_behaves_like :string_unpack_32bit_le, 'j_'
+ it_behaves_like :string_unpack_32bit_le_signed, 'j_'
+ end
+
+ describe "with modifier '!'" do
+ it_behaves_like :string_unpack_32bit_le, 'j!'
+ it_behaves_like :string_unpack_32bit_le_signed, 'j!'
+ end
+ end
+ end
+
+ big_endian do
+ describe "String#unpack with format 'J'" do
+ describe "with modifier '_'" do
+ it_behaves_like :string_unpack_32bit_be, 'J_'
+ it_behaves_like :string_unpack_32bit_be_unsigned, 'J_'
+ end
+
+ describe "with modifier '!'" do
+ it_behaves_like :string_unpack_32bit_be, 'J!'
+ it_behaves_like :string_unpack_32bit_be_unsigned, 'J!'
+ end
+ end
+
+ describe "String#unpack with format 'j'" do
+ describe "with modifier '_'" do
+ it_behaves_like :string_unpack_32bit_be, 'j_'
+ it_behaves_like :string_unpack_32bit_be_signed, 'j_'
+ end
+
+ describe "with modifier '!'" do
+ it_behaves_like :string_unpack_32bit_be, 'j!'
+ it_behaves_like :string_unpack_32bit_be_signed, 'j!'
+ end
+ end
+ end
+
+ describe "String#unpack with format 'J'" do
+ describe "with modifier '<'" do
+ it_behaves_like :string_unpack_32bit_le, 'J<'
+ it_behaves_like :string_unpack_32bit_le_unsigned, 'J<'
+ end
+
+ describe "with modifier '>'" do
+ it_behaves_like :string_unpack_32bit_be, 'J>'
+ it_behaves_like :string_unpack_32bit_be_unsigned, 'J>'
+ end
+
+ describe "with modifier '<' and '_'" do
+ it_behaves_like :string_unpack_32bit_le, 'J<_'
+ it_behaves_like :string_unpack_32bit_le, 'J_<'
+ it_behaves_like :string_unpack_32bit_le_unsigned, 'J<_'
+ it_behaves_like :string_unpack_32bit_le_unsigned, 'J_<'
+ end
+
+ describe "with modifier '<' and '!'" do
+ it_behaves_like :string_unpack_32bit_le, 'J<!'
+ it_behaves_like :string_unpack_32bit_le, 'J!<'
+ it_behaves_like :string_unpack_32bit_le_unsigned, 'J<!'
+ it_behaves_like :string_unpack_32bit_le_unsigned, 'J!<'
+ end
+
+ describe "with modifier '>' and '_'" do
+ it_behaves_like :string_unpack_32bit_be, 'J>_'
+ it_behaves_like :string_unpack_32bit_be, 'J_>'
+ it_behaves_like :string_unpack_32bit_be_unsigned, 'J>_'
+ it_behaves_like :string_unpack_32bit_be_unsigned, 'J_>'
+ end
+
+ describe "with modifier '>' and '!'" do
+ it_behaves_like :string_unpack_32bit_be, 'J>!'
+ it_behaves_like :string_unpack_32bit_be, 'J!>'
+ it_behaves_like :string_unpack_32bit_be_unsigned, 'J>!'
+ it_behaves_like :string_unpack_32bit_be_unsigned, 'J!>'
+ end
+ end
+
+ describe "String#unpack with format 'j'" do
+ describe "with modifier '<'" do
+ it_behaves_like :string_unpack_32bit_le, 'j<'
+ it_behaves_like :string_unpack_32bit_le_signed, 'j<'
+ end
+
+ describe "with modifier '>'" do
+ it_behaves_like :string_unpack_32bit_be, 'j>'
+ it_behaves_like :string_unpack_32bit_be_signed, 'j>'
+ end
+
+ describe "with modifier '<' and '_'" do
+ it_behaves_like :string_unpack_32bit_le, 'j<_'
+ it_behaves_like :string_unpack_32bit_le, 'j_<'
+ it_behaves_like :string_unpack_32bit_le_signed, 'j<_'
+ it_behaves_like :string_unpack_32bit_le_signed, 'j_<'
+ end
+
+ describe "with modifier '<' and '!'" do
+ it_behaves_like :string_unpack_32bit_le, 'j<!'
+ it_behaves_like :string_unpack_32bit_le, 'j!<'
+ it_behaves_like :string_unpack_32bit_le_signed, 'j<!'
+ it_behaves_like :string_unpack_32bit_le_signed, 'j!<'
+ end
+
+ describe "with modifier '>' and '_'" do
+ it_behaves_like :string_unpack_32bit_be, 'j>_'
+ it_behaves_like :string_unpack_32bit_be, 'j_>'
+ it_behaves_like :string_unpack_32bit_be_signed, 'j>_'
+ it_behaves_like :string_unpack_32bit_be_signed, 'j_>'
+ end
+
+ describe "with modifier '>' and '!'" do
+ it_behaves_like :string_unpack_32bit_be, 'j>!'
+ it_behaves_like :string_unpack_32bit_be, 'j!>'
+ it_behaves_like :string_unpack_32bit_be_signed, 'j>!'
+ it_behaves_like :string_unpack_32bit_be_signed, 'j!>'
+ end
+ end
+ end
+end
diff --git a/spec/rubyspec/core/string/unpack/l_spec.rb b/spec/rubyspec/core/string/unpack/l_spec.rb
new file mode 100644
index 0000000000..3a7c55f8da
--- /dev/null
+++ b/spec/rubyspec/core/string/unpack/l_spec.rb
@@ -0,0 +1,376 @@
+require File.expand_path('../../../../spec_helper', __FILE__)
+require File.expand_path('../../fixtures/classes', __FILE__)
+require File.expand_path('../shared/basic', __FILE__)
+require File.expand_path('../shared/integer', __FILE__)
+
+describe "String#unpack with format 'L'" do
+ describe "with modifier '<'" do
+ it_behaves_like :string_unpack_32bit_le, 'L<'
+ it_behaves_like :string_unpack_32bit_le_unsigned, 'L<'
+ end
+
+ describe "with modifier '>'" do
+ it_behaves_like :string_unpack_32bit_be, 'L>'
+ it_behaves_like :string_unpack_32bit_be_unsigned, 'L>'
+ end
+
+ platform_is wordsize: 32 do
+ describe "with modifier '<' and '_'" do
+ it_behaves_like :string_unpack_32bit_le, 'L<_'
+ it_behaves_like :string_unpack_32bit_le, 'L_<'
+ it_behaves_like :string_unpack_32bit_le_unsigned, 'L<_'
+ it_behaves_like :string_unpack_32bit_le_unsigned, 'L_<'
+ end
+
+ describe "with modifier '<' and '!'" do
+ it_behaves_like :string_unpack_32bit_le, 'L<!'
+ it_behaves_like :string_unpack_32bit_le, 'L!<'
+ it_behaves_like :string_unpack_32bit_le_unsigned, 'L<!'
+ it_behaves_like :string_unpack_32bit_le_unsigned, 'L!<'
+ end
+
+ describe "with modifier '>' and '_'" do
+ it_behaves_like :string_unpack_32bit_be, 'L>_'
+ it_behaves_like :string_unpack_32bit_be, 'L_>'
+ it_behaves_like :string_unpack_32bit_be_unsigned, 'L>_'
+ it_behaves_like :string_unpack_32bit_be_unsigned, 'L_>'
+ end
+
+ describe "with modifier '>' and '!'" do
+ it_behaves_like :string_unpack_32bit_be, 'L>!'
+ it_behaves_like :string_unpack_32bit_be, 'L!>'
+ it_behaves_like :string_unpack_32bit_be_unsigned, 'L>!'
+ it_behaves_like :string_unpack_32bit_be_unsigned, 'L!>'
+ end
+ end
+
+ platform_is wordsize: 64 do
+ platform_is_not :mingw32 do
+ describe "with modifier '<' and '_'" do
+ it_behaves_like :string_unpack_64bit_le, 'L<_'
+ it_behaves_like :string_unpack_64bit_le, 'L_<'
+ it_behaves_like :string_unpack_64bit_le_unsigned, 'L<_'
+ it_behaves_like :string_unpack_64bit_le_unsigned, 'L_<'
+ end
+
+ describe "with modifier '<' and '!'" do
+ it_behaves_like :string_unpack_64bit_le, 'L<!'
+ it_behaves_like :string_unpack_64bit_le, 'L!<'
+ it_behaves_like :string_unpack_64bit_le_unsigned, 'L<!'
+ it_behaves_like :string_unpack_64bit_le_unsigned, 'L!<'
+ end
+
+ describe "with modifier '>' and '_'" do
+ it_behaves_like :string_unpack_64bit_be, 'L>_'
+ it_behaves_like :string_unpack_64bit_be, 'L_>'
+ it_behaves_like :string_unpack_64bit_be_unsigned, 'L>_'
+ it_behaves_like :string_unpack_64bit_be_unsigned, 'L_>'
+ end
+
+ describe "with modifier '>' and '!'" do
+ it_behaves_like :string_unpack_64bit_be, 'L>!'
+ it_behaves_like :string_unpack_64bit_be, 'L!>'
+ it_behaves_like :string_unpack_64bit_be_unsigned, 'L>!'
+ it_behaves_like :string_unpack_64bit_be_unsigned, 'L!>'
+ end
+ end
+
+ platform_is :mingw32 do
+ describe "with modifier '<' and '_'" do
+ it_behaves_like :string_unpack_32bit_le, 'L<_'
+ it_behaves_like :string_unpack_32bit_le, 'L_<'
+ it_behaves_like :string_unpack_32bit_le_unsigned, 'L<_'
+ it_behaves_like :string_unpack_32bit_le_unsigned, 'L_<'
+ end
+
+ describe "with modifier '<' and '!'" do
+ it_behaves_like :string_unpack_32bit_le, 'L<!'
+ it_behaves_like :string_unpack_32bit_le, 'L!<'
+ it_behaves_like :string_unpack_32bit_le_unsigned, 'L<!'
+ it_behaves_like :string_unpack_32bit_le_unsigned, 'L!<'
+ end
+
+ describe "with modifier '>' and '_'" do
+ it_behaves_like :string_unpack_32bit_be, 'L>_'
+ it_behaves_like :string_unpack_32bit_be, 'L_>'
+ it_behaves_like :string_unpack_32bit_be_unsigned, 'L>_'
+ it_behaves_like :string_unpack_32bit_be_unsigned, 'L_>'
+ end
+
+ describe "with modifier '>' and '!'" do
+ it_behaves_like :string_unpack_32bit_be, 'L>!'
+ it_behaves_like :string_unpack_32bit_be, 'L!>'
+ it_behaves_like :string_unpack_32bit_be_unsigned, 'L>!'
+ it_behaves_like :string_unpack_32bit_be_unsigned, 'L!>'
+ end
+ end
+ end
+end
+
+describe "String#unpack with format 'l'" do
+ describe "with modifier '<'" do
+ it_behaves_like :string_unpack_32bit_le, 'l<'
+ it_behaves_like :string_unpack_32bit_le_signed, 'l<'
+ end
+
+ describe "with modifier '>'" do
+ it_behaves_like :string_unpack_32bit_be, 'l>'
+ it_behaves_like :string_unpack_32bit_be_signed, 'l>'
+ end
+
+ platform_is wordsize: 32 do
+ describe "with modifier '<' and '_'" do
+ it_behaves_like :string_unpack_32bit_le, 'l<_'
+ it_behaves_like :string_unpack_32bit_le, 'l_<'
+ it_behaves_like :string_unpack_32bit_le_signed, 'l<_'
+ it_behaves_like :string_unpack_32bit_le_signed, 'l_<'
+ end
+
+ describe "with modifier '<' and '!'" do
+ it_behaves_like :string_unpack_32bit_le, 'l<!'
+ it_behaves_like :string_unpack_32bit_le, 'l!<'
+ it_behaves_like :string_unpack_32bit_le_signed, 'l<!'
+ it_behaves_like :string_unpack_32bit_le_signed, 'l!<'
+ end
+
+ describe "with modifier '>' and '_'" do
+ it_behaves_like :string_unpack_32bit_be, 'l>_'
+ it_behaves_like :string_unpack_32bit_be, 'l_>'
+ it_behaves_like :string_unpack_32bit_be_signed, 'l>_'
+ it_behaves_like :string_unpack_32bit_be_signed, 'l_>'
+ end
+
+ describe "with modifier '>' and '!'" do
+ it_behaves_like :string_unpack_32bit_be, 'l>!'
+ it_behaves_like :string_unpack_32bit_be, 'l!>'
+ it_behaves_like :string_unpack_32bit_be_signed, 'l>!'
+ it_behaves_like :string_unpack_32bit_be_signed, 'l!>'
+ end
+ end
+
+ platform_is wordsize: 64 do
+ platform_is_not :mingw32 do
+ describe "with modifier '<' and '_'" do
+ it_behaves_like :string_unpack_64bit_le, 'l<_'
+ it_behaves_like :string_unpack_64bit_le, 'l_<'
+ it_behaves_like :string_unpack_64bit_le_signed, 'l<_'
+ it_behaves_like :string_unpack_64bit_le_signed, 'l_<'
+ end
+
+ describe "with modifier '<' and '!'" do
+ it_behaves_like :string_unpack_64bit_le, 'l<!'
+ it_behaves_like :string_unpack_64bit_le, 'l!<'
+ it_behaves_like :string_unpack_64bit_le_signed, 'l<!'
+ it_behaves_like :string_unpack_64bit_le_signed, 'l!<'
+ end
+
+ describe "with modifier '>' and '_'" do
+ it_behaves_like :string_unpack_64bit_be, 'l>_'
+ it_behaves_like :string_unpack_64bit_be, 'l_>'
+ it_behaves_like :string_unpack_64bit_be_signed, 'l>_'
+ it_behaves_like :string_unpack_64bit_be_signed, 'l_>'
+ end
+
+ describe "with modifier '>' and '!'" do
+ it_behaves_like :string_unpack_64bit_be, 'l>!'
+ it_behaves_like :string_unpack_64bit_be, 'l!>'
+ it_behaves_like :string_unpack_64bit_be_signed, 'l>!'
+ it_behaves_like :string_unpack_64bit_be_signed, 'l!>'
+ end
+ end
+
+ platform_is :mingw32 do
+ describe "with modifier '<' and '_'" do
+ it_behaves_like :string_unpack_32bit_le, 'l<_'
+ it_behaves_like :string_unpack_32bit_le, 'l_<'
+ it_behaves_like :string_unpack_32bit_le_signed, 'l<_'
+ it_behaves_like :string_unpack_32bit_le_signed, 'l_<'
+ end
+
+ describe "with modifier '<' and '!'" do
+ it_behaves_like :string_unpack_32bit_le, 'l<!'
+ it_behaves_like :string_unpack_32bit_le, 'l!<'
+ it_behaves_like :string_unpack_32bit_le_signed, 'l<!'
+ it_behaves_like :string_unpack_32bit_le_signed, 'l!<'
+ end
+
+ describe "with modifier '>' and '_'" do
+ it_behaves_like :string_unpack_32bit_be, 'l>_'
+ it_behaves_like :string_unpack_32bit_be, 'l_>'
+ it_behaves_like :string_unpack_32bit_be_signed, 'l>_'
+ it_behaves_like :string_unpack_32bit_be_signed, 'l_>'
+ end
+
+ describe "with modifier '>' and '!'" do
+ it_behaves_like :string_unpack_32bit_be, 'l>!'
+ it_behaves_like :string_unpack_32bit_be, 'l!>'
+ it_behaves_like :string_unpack_32bit_be_signed, 'l>!'
+ it_behaves_like :string_unpack_32bit_be_signed, 'l!>'
+ end
+ end
+ end
+end
+
+little_endian do
+ describe "String#unpack with format 'L'" do
+ it_behaves_like :string_unpack_basic, 'L'
+ it_behaves_like :string_unpack_32bit_le, 'L'
+ it_behaves_like :string_unpack_32bit_le_unsigned, 'L'
+ end
+
+ describe "String#unpack with format 'l'" do
+ it_behaves_like :string_unpack_basic, 'l'
+ it_behaves_like :string_unpack_32bit_le, 'l'
+ it_behaves_like :string_unpack_32bit_le_signed, 'l'
+ end
+
+ platform_is wordsize: 32 do
+ describe "String#unpack with format 'L' with modifier '_'" do
+ it_behaves_like :string_unpack_32bit_le, 'L_'
+ it_behaves_like :string_unpack_32bit_le_unsigned, 'L_'
+ end
+
+ describe "String#unpack with format 'L' with modifier '!'" do
+ it_behaves_like :string_unpack_32bit_le, 'L!'
+ it_behaves_like :string_unpack_32bit_le_unsigned, 'L!'
+ end
+
+ describe "String#unpack with format 'l' with modifier '_'" do
+ it_behaves_like :string_unpack_32bit_le, 'l_'
+ it_behaves_like :string_unpack_32bit_le_signed, 'l'
+ end
+
+ describe "String#unpack with format 'l' with modifier '!'" do
+ it_behaves_like :string_unpack_32bit_le, 'l!'
+ it_behaves_like :string_unpack_32bit_le_signed, 'l'
+ end
+ end
+
+ platform_is wordsize: 64 do
+ platform_is_not :mingw32 do
+ describe "String#unpack with format 'L' with modifier '_'" do
+ it_behaves_like :string_unpack_64bit_le, 'L_'
+ it_behaves_like :string_unpack_64bit_le_unsigned, 'L_'
+ end
+
+ describe "String#unpack with format 'L' with modifier '!'" do
+ it_behaves_like :string_unpack_64bit_le, 'L!'
+ it_behaves_like :string_unpack_64bit_le_unsigned, 'L!'
+ end
+
+ describe "String#unpack with format 'l' with modifier '_'" do
+ it_behaves_like :string_unpack_64bit_le, 'l_'
+ it_behaves_like :string_unpack_64bit_le_signed, 'l_'
+ end
+
+ describe "String#unpack with format 'l' with modifier '!'" do
+ it_behaves_like :string_unpack_64bit_le, 'l!'
+ it_behaves_like :string_unpack_64bit_le_signed, 'l!'
+ end
+ end
+
+ platform_is :mingw32 do
+ describe "String#unpack with format 'L' with modifier '_'" do
+ it_behaves_like :string_unpack_32bit_le, 'L_'
+ it_behaves_like :string_unpack_32bit_le_unsigned, 'L_'
+ end
+
+ describe "String#unpack with format 'L' with modifier '!'" do
+ it_behaves_like :string_unpack_32bit_le, 'L!'
+ it_behaves_like :string_unpack_32bit_le_unsigned, 'L!'
+ end
+
+ describe "String#unpack with format 'l' with modifier '_'" do
+ it_behaves_like :string_unpack_32bit_le, 'l_'
+ it_behaves_like :string_unpack_32bit_le_signed, 'l_'
+ end
+
+ describe "String#unpack with format 'l' with modifier '!'" do
+ it_behaves_like :string_unpack_32bit_le, 'l!'
+ it_behaves_like :string_unpack_32bit_le_signed, 'l!'
+ end
+ end
+ end
+end
+
+big_endian do
+ describe "String#unpack with format 'L'" do
+ it_behaves_like :string_unpack_basic, 'L'
+ it_behaves_like :string_unpack_32bit_be, 'L'
+ it_behaves_like :string_unpack_32bit_be_unsigned, 'L'
+ end
+
+ describe "String#unpack with format 'l'" do
+ it_behaves_like :string_unpack_basic, 'l'
+ it_behaves_like :string_unpack_32bit_be, 'l'
+ it_behaves_like :string_unpack_32bit_be_signed, 'l'
+ end
+
+ platform_is wordsize: 32 do
+ describe "String#unpack with format 'L' with modifier '_'" do
+ it_behaves_like :string_unpack_32bit_be, 'L_'
+ it_behaves_like :string_unpack_32bit_be_unsigned, 'L_'
+ end
+
+ describe "String#unpack with format 'L' with modifier '!'" do
+ it_behaves_like :string_unpack_32bit_be, 'L!'
+ it_behaves_like :string_unpack_32bit_be_unsigned, 'L!'
+ end
+
+ describe "String#unpack with format 'l' with modifier '_'" do
+ it_behaves_like :string_unpack_32bit_be, 'l_'
+ it_behaves_like :string_unpack_32bit_be_signed, 'l'
+ end
+
+ describe "String#unpack with format 'l' with modifier '!'" do
+ it_behaves_like :string_unpack_32bit_be, 'l!'
+ it_behaves_like :string_unpack_32bit_be_signed, 'l'
+ end
+ end
+
+ platform_is wordsize: 64 do
+ platform_is_not :mingw32 do
+ describe "String#unpack with format 'L' with modifier '_'" do
+ it_behaves_like :string_unpack_64bit_be, 'L_'
+ it_behaves_like :string_unpack_64bit_be_unsigned, 'L_'
+ end
+
+ describe "String#unpack with format 'L' with modifier '!'" do
+ it_behaves_like :string_unpack_64bit_be, 'L!'
+ it_behaves_like :string_unpack_64bit_be_unsigned, 'L!'
+ end
+
+ describe "String#unpack with format 'l' with modifier '_'" do
+ it_behaves_like :string_unpack_64bit_be, 'l_'
+ it_behaves_like :string_unpack_64bit_be_signed, 'l_'
+ end
+
+ describe "String#unpack with format 'l' with modifier '!'" do
+ it_behaves_like :string_unpack_64bit_be, 'l!'
+ it_behaves_like :string_unpack_64bit_be_signed, 'l!'
+ end
+ end
+
+ platform_is :mingw32 do
+ describe "String#unpack with format 'L' with modifier '_'" do
+ it_behaves_like :string_unpack_32bit_be, 'L_'
+ it_behaves_like :string_unpack_32bit_be_unsigned, 'L_'
+ end
+
+ describe "String#unpack with format 'L' with modifier '!'" do
+ it_behaves_like :string_unpack_32bit_be, 'L!'
+ it_behaves_like :string_unpack_32bit_be_unsigned, 'L!'
+ end
+
+ describe "String#unpack with format 'l' with modifier '_'" do
+ it_behaves_like :string_unpack_32bit_be, 'l_'
+ it_behaves_like :string_unpack_32bit_be_signed, 'l_'
+ end
+
+ describe "String#unpack with format 'l' with modifier '!'" do
+ it_behaves_like :string_unpack_32bit_be, 'l!'
+ it_behaves_like :string_unpack_32bit_be_signed, 'l!'
+ end
+ end
+ end
+end
diff --git a/spec/rubyspec/core/string/unpack/m_spec.rb b/spec/rubyspec/core/string/unpack/m_spec.rb
new file mode 100644
index 0000000000..104f282fed
--- /dev/null
+++ b/spec/rubyspec/core/string/unpack/m_spec.rb
@@ -0,0 +1,170 @@
+# -*- encoding: ascii-8bit -*-
+require File.expand_path('../../../../spec_helper', __FILE__)
+require File.expand_path('../../fixtures/classes', __FILE__)
+require File.expand_path('../shared/basic', __FILE__)
+
+describe "String#unpack with format 'M'" do
+ it_behaves_like :string_unpack_basic, 'M'
+ it_behaves_like :string_unpack_no_platform, 'M'
+
+ it "decodes an empty string" do
+ "".unpack("M").should == [""]
+ end
+
+ it "decodes the complete string ignoring newlines when given a single directive" do
+ "a=\nb=\nc=\n".unpack("M").should == ["abc"]
+ end
+
+ it "appends empty string to the array for directives exceeding the input size" do
+ "a=\nb=\nc=\n".unpack("MMM").should == ["abc", "", ""]
+ end
+
+ it "ignores the count or '*' modifier and decodes the entire string" do
+ [ ["a=\nb=\nc=\n", "M238", ["abc"]],
+ ["a=\nb=\nc=\n", "M*", ["abc"]]
+ ].should be_computed_by(:unpack)
+ end
+
+ it "decodes the '=' character" do
+ "=3D=\n".unpack("M").should == ["="]
+ end
+
+ it "decodes an embedded space character" do
+ "a b=\n".unpack("M").should == ["a b"]
+ end
+
+ it "decodes a space at the end of the pre-encoded string" do
+ "a =\n".unpack("M").should == ["a "]
+ end
+
+ it "decodes an embedded tab character" do
+ "a\tb=\n".unpack("M").should == ["a\tb"]
+ end
+
+ it "decodes a tab character at the end of the pre-encoded string" do
+ "a\t=\n".unpack("M").should == ["a\t"]
+ end
+
+ it "decodes an embedded newline" do
+ "a\nb=\n".unpack("M").should == ["a\nb"]
+ end
+
+ it "decodes pre-encoded byte values 33..60" do
+ [ ["!\"\#$%&'()*+,-./=\n", ["!\"\#$%&'()*+,-./"]],
+ ["0123456789=\n", ["0123456789"]],
+ [":;<=\n", [":;<"]]
+ ].should be_computed_by(:unpack, "M")
+ end
+
+ it "decodes pre-encoded byte values 62..126" do
+ [ [">?@=\n", [">?@"]],
+ ["ABCDEFGHIJKLMNOPQRSTUVWXYZ=\n", ["ABCDEFGHIJKLMNOPQRSTUVWXYZ"]],
+ ["[\\]^_`=\n", ["[\\]^_`"]],
+ ["abcdefghijklmnopqrstuvwxyz=\n", ["abcdefghijklmnopqrstuvwxyz"]],
+ ["{|}~=\n", ["{|}~"]]
+ ].should be_computed_by(:unpack, "M")
+ end
+
+ it "decodes pre-encoded byte values 0..31 except tab and newline" do
+ [ ["=00=01=02=03=04=05=06=\n", ["\x00\x01\x02\x03\x04\x05\x06"]],
+ ["=07=08=0B=0C=0D=\n", ["\a\b\v\f\r"]],
+ ["=0E=0F=10=11=12=13=14=\n", ["\x0e\x0f\x10\x11\x12\x13\x14"]],
+ ["=15=16=17=18=19=1A=\n", ["\x15\x16\x17\x18\x19\x1a"]],
+ ["=1B=\n", ["\e"]],
+ ["=1C=1D=1E=1F=\n", ["\x1c\x1d\x1e\x1f"]]
+ ].should be_computed_by(:unpack, "M")
+ end
+
+ it "decodes pre-encoded byte values 127..255" do
+ [ ["=7F=80=81=82=83=84=85=86=\n", ["\x7f\x80\x81\x82\x83\x84\x85\x86"]],
+ ["=87=88=89=8A=8B=8C=8D=8E=\n", ["\x87\x88\x89\x8a\x8b\x8c\x8d\x8e"]],
+ ["=8F=90=91=92=93=94=95=96=\n", ["\x8f\x90\x91\x92\x93\x94\x95\x96"]],
+ ["=97=98=99=9A=9B=9C=9D=9E=\n", ["\x97\x98\x99\x9a\x9b\x9c\x9d\x9e"]],
+ ["=9F=A0=A1=A2=A3=A4=A5=A6=\n", ["\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6"]],
+ ["=A7=A8=A9=AA=AB=AC=AD=AE=\n", ["\xa7\xa8\xa9\xaa\xab\xac\xad\xae"]],
+ ["=AF=B0=B1=B2=B3=B4=B5=B6=\n", ["\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6"]],
+ ["=B7=B8=B9=BA=BB=BC=BD=BE=\n", ["\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe"]],
+ ["=BF=C0=C1=C2=C3=C4=C5=C6=\n", ["\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6"]],
+ ["=C7=C8=C9=CA=CB=CC=CD=CE=\n", ["\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce"]],
+ ["=CF=D0=D1=D2=D3=D4=D5=D6=\n", ["\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6"]],
+ ["=D7=D8=D9=DA=DB=DC=DD=DE=\n", ["\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde"]],
+ ["=DF=E0=E1=E2=E3=E4=E5=E6=\n", ["\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6"]],
+ ["=E7=E8=E9=EA=EB=EC=ED=EE=\n", ["\xe7\xe8\xe9\xea\xeb\xec\xed\xee"]],
+ ["=EF=F0=F1=F2=F3=F4=F5=F6=\n", ["\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6"]],
+ ["=F7=F8=F9=FA=FB=FC=FD=FE=\n", ["\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe"]],
+ ["=FF=\n", ["\xff"]]
+ ].should be_computed_by(:unpack, "M")
+ end
+end
+
+describe "String#unpack with format 'm'" do
+ it_behaves_like :string_unpack_basic, 'm'
+ it_behaves_like :string_unpack_no_platform, 'm'
+
+ it "decodes an empty string" do
+ "".unpack("m").should == [""]
+ end
+
+ it "decodes the complete string ignoring newlines when given a single directive" do
+ "YWJj\nREVG\n".unpack("m").should == ["abcDEF"]
+ end
+
+ it "ignores the count or '*' modifier and decodes the entire string" do
+ [ ["YWJj\nREVG\n", "m238", ["abcDEF"]],
+ ["YWJj\nREVG\n", "m*", ["abcDEF"]]
+ ].should be_computed_by(:unpack)
+ end
+
+ it "appends empty string to the array for directives exceeding the input size" do
+ "YWJj\nREVG\n".unpack("mmm").should == ["abcDEF", "", ""]
+ end
+
+ it "decodes all pre-encoded ascii byte values" do
+ [ ["AAECAwQFBg==\n", ["\x00\x01\x02\x03\x04\x05\x06"]],
+ ["BwgJCgsMDQ==\n", ["\a\b\t\n\v\f\r"]],
+ ["Dg8QERITFBUW\n", ["\x0E\x0F\x10\x11\x12\x13\x14\x15\x16"]],
+ ["FxgZGhscHR4f\n", ["\x17\x18\x19\x1a\e\x1c\x1d\x1e\x1f"]],
+ ["ISIjJCUmJygpKissLS4v\n", ["!\"\#$%&'()*+,-./"]],
+ ["MDEyMzQ1Njc4OQ==\n", ["0123456789"]],
+ ["Ojs8PT4/QA==\n", [":;<=>?@"]],
+ ["QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo=\n", ["ABCDEFGHIJKLMNOPQRSTUVWXYZ"]],
+ ["W1xdXl9g\n", ["[\\]^_`"]],
+ ["YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=\n", ["abcdefghijklmnopqrstuvwxyz"]],
+ ["e3x9fg==\n", ["{|}~"]],
+ ["f8KAwoHCgsKD\n", ["\x7f\xc2\x80\xc2\x81\xc2\x82\xc2\x83"]],
+ ["woTChcKGwofC\n", ["\xc2\x84\xc2\x85\xc2\x86\xc2\x87\xc2"]],
+ ["iMKJworCi8KM\n", ["\x88\xc2\x89\xc2\x8a\xc2\x8b\xc2\x8c"]],
+ ["wo3CjsKPwpDC\n", ["\xc2\x8d\xc2\x8e\xc2\x8f\xc2\x90\xc2"]],
+ ["kcKSwpPClMKV\n", ["\x91\xc2\x92\xc2\x93\xc2\x94\xc2\x95"]],
+ ["wpbCl8KYwpnC\n", ["\xc2\x96\xc2\x97\xc2\x98\xc2\x99\xc2"]],
+ ["msKbwpzCncKe\n", ["\x9a\xc2\x9b\xc2\x9c\xc2\x9d\xc2\x9e"]],
+ ["wp/CoMKhwqLC\n", ["\xc2\x9f\xc2\xa0\xc2\xa1\xc2\xa2\xc2"]],
+ ["o8KkwqXCpsKn\n", ["\xa3\xc2\xa4\xc2\xa5\xc2\xa6\xc2\xa7"]],
+ ["wqjCqcKqwqvC\n", ["\xc2\xa8\xc2\xa9\xc2\xaa\xc2\xab\xc2"]],
+ ["rMKtwq7Cr8Kw\n", ["\xac\xc2\xad\xc2\xae\xc2\xaf\xc2\xb0"]],
+ ["wrHCssKzwrTC\n", ["\xc2\xb1\xc2\xb2\xc2\xb3\xc2\xb4\xc2"]],
+ ["tcK2wrfCuMK5\n", ["\xb5\xc2\xb6\xc2\xb7\xc2\xb8\xc2\xb9"]],
+ ["wrrCu8K8wr3C\n", ["\xc2\xba\xc2\xbb\xc2\xbc\xc2\xbd\xc2"]],
+ ["vsK/w4DDgcOC\n", ["\xbe\xc2\xbf\xc3\x80\xc3\x81\xc3\x82"]],
+ ["w4PDhMOFw4bD\n", ["\xc3\x83\xc3\x84\xc3\x85\xc3\x86\xc3"]],
+ ["h8OIw4nDisOL\n", ["\x87\xc3\x88\xc3\x89\xc3\x8a\xc3\x8b"]],
+ ["w4zDjcOOw4/D\n", ["\xc3\x8c\xc3\x8d\xc3\x8e\xc3\x8f\xc3"]],
+ ["kMORw5LDk8OU\n", ["\x90\xc3\x91\xc3\x92\xc3\x93\xc3\x94"]],
+ ["w5XDlsOXw5jD\n", ["\xc3\x95\xc3\x96\xc3\x97\xc3\x98\xc3"]],
+ ["mcOaw5vDnMOd\n", ["\x99\xc3\x9a\xc3\x9b\xc3\x9c\xc3\x9d"]],
+ ["w57Dn8Ogw6HD\n", ["\xc3\x9e\xc3\x9f\xc3\xa0\xc3\xa1\xc3"]],
+ ["osOjw6TDpcOm\n", ["\xa2\xc3\xa3\xc3\xa4\xc3\xa5\xc3\xa6"]],
+ ["w6fDqMOpw6rD\n", ["\xc3\xa7\xc3\xa8\xc3\xa9\xc3\xaa\xc3"]],
+ ["q8Osw63DrsOv\n", ["\xab\xc3\xac\xc3\xad\xc3\xae\xc3\xaf"]],
+ ["w7DDscOyw7PD\n", ["\xc3\xb0\xc3\xb1\xc3\xb2\xc3\xb3\xc3"]],
+ ["tMO1w7bDt8O4\n", ["\xb4\xc3\xb5\xc3\xb6\xc3\xb7\xc3\xb8"]],
+ ["w7nDusO7w7zD\n", ["\xc3\xb9\xc3\xba\xc3\xbb\xc3\xbc\xc3"]],
+ ["vcO+w78=\n", ["\xbd\xc3\xbe\xc3\xbf"]]
+ ].should be_computed_by(:unpack, "m")
+ end
+
+ it "produces binary strings" do
+ "".unpack("m").first.encoding.should == Encoding::BINARY
+ "Ojs8PT4/QA==\n".unpack("m").first.encoding.should == Encoding::BINARY
+ end
+end
diff --git a/spec/rubyspec/core/string/unpack/n_spec.rb b/spec/rubyspec/core/string/unpack/n_spec.rb
new file mode 100644
index 0000000000..6e85346338
--- /dev/null
+++ b/spec/rubyspec/core/string/unpack/n_spec.rb
@@ -0,0 +1,18 @@
+require File.expand_path('../../../../spec_helper', __FILE__)
+require File.expand_path('../../fixtures/classes', __FILE__)
+require File.expand_path('../shared/basic', __FILE__)
+require File.expand_path('../shared/integer', __FILE__)
+
+describe "String#unpack with format 'N'" do
+ it_behaves_like :string_unpack_basic, 'N'
+ it_behaves_like :string_unpack_32bit_be, 'N'
+ it_behaves_like :string_unpack_32bit_be_unsigned, 'N'
+ it_behaves_like :string_unpack_no_platform, 'N'
+end
+
+describe "String#unpack with format 'n'" do
+ it_behaves_like :string_unpack_basic, 'n'
+ it_behaves_like :string_unpack_16bit_be, 'n'
+ it_behaves_like :string_unpack_16bit_be_unsigned, 'n'
+ it_behaves_like :string_unpack_no_platform, 'n'
+end
diff --git a/spec/rubyspec/core/string/unpack/p_spec.rb b/spec/rubyspec/core/string/unpack/p_spec.rb
new file mode 100644
index 0000000000..7c9a502a15
--- /dev/null
+++ b/spec/rubyspec/core/string/unpack/p_spec.rb
@@ -0,0 +1,21 @@
+require File.expand_path('../../../../spec_helper', __FILE__)
+require File.expand_path('../../fixtures/classes', __FILE__)
+require File.expand_path('../shared/basic', __FILE__)
+
+describe "String#unpack with format 'P'" do
+ it_behaves_like :string_unpack_basic, 'P'
+
+ it "returns a random object after consuming a size-of a machine word bytes" do
+ str = "\0" * 1.size
+ str.unpack("P").should be_kind_of(Object)
+ end
+end
+
+describe "String#unpack with format 'p'" do
+ it_behaves_like :string_unpack_basic, 'p'
+
+ it "returns a random object after consuming a size-of a machine word bytes" do
+ str = "\0" * 1.size
+ str.unpack("p").should be_kind_of(Object)
+ end
+end
diff --git a/spec/rubyspec/core/string/unpack/percent_spec.rb b/spec/rubyspec/core/string/unpack/percent_spec.rb
new file mode 100644
index 0000000000..38cf81b037
--- /dev/null
+++ b/spec/rubyspec/core/string/unpack/percent_spec.rb
@@ -0,0 +1,7 @@
+require File.expand_path('../../../../spec_helper', __FILE__)
+
+describe "String#unpack with format '%'" do
+ it "raises an Argument Error" do
+ lambda { "abc".unpack("%") }.should raise_error(ArgumentError)
+ end
+end
diff --git a/spec/rubyspec/core/string/unpack/q_spec.rb b/spec/rubyspec/core/string/unpack/q_spec.rb
new file mode 100644
index 0000000000..91e65a9405
--- /dev/null
+++ b/spec/rubyspec/core/string/unpack/q_spec.rb
@@ -0,0 +1,64 @@
+require File.expand_path('../../../../spec_helper', __FILE__)
+require File.expand_path('../../fixtures/classes', __FILE__)
+require File.expand_path('../shared/basic', __FILE__)
+require File.expand_path('../shared/integer', __FILE__)
+
+describe "String#unpack with format 'Q'" do
+ describe "with modifier '<'" do
+ it_behaves_like :string_unpack_64bit_le, 'Q<'
+ it_behaves_like :string_unpack_64bit_le_unsigned, 'Q<'
+ end
+
+ describe "with modifier '>'" do
+ it_behaves_like :string_unpack_64bit_be, 'Q>'
+ it_behaves_like :string_unpack_64bit_be_unsigned, 'Q>'
+ end
+end
+
+describe "String#unpack with format 'q'" do
+ describe "with modifier '<'" do
+ it_behaves_like :string_unpack_64bit_le, 'q<'
+ it_behaves_like :string_unpack_64bit_le_signed, 'q<'
+ end
+
+ describe "with modifier '>'" do
+ it_behaves_like :string_unpack_64bit_be, 'q>'
+ it_behaves_like :string_unpack_64bit_be_signed, 'q>'
+ end
+end
+
+describe "String#unpack with format 'Q'" do
+ it_behaves_like :string_unpack_basic, 'Q'
+end
+
+describe "String#unpack with format 'q'" do
+ it_behaves_like :string_unpack_basic, 'q'
+end
+
+little_endian do
+ describe "String#unpack with format 'Q'" do
+ it_behaves_like :string_unpack_64bit_le, 'Q'
+ it_behaves_like :string_unpack_64bit_le_extra, 'Q'
+ it_behaves_like :string_unpack_64bit_le_unsigned, 'Q'
+ end
+
+ describe "String#unpack with format 'q'" do
+ it_behaves_like :string_unpack_64bit_le, 'q'
+ it_behaves_like :string_unpack_64bit_le_extra, 'q'
+ it_behaves_like :string_unpack_64bit_le_signed, 'q'
+ end
+end
+
+big_endian do
+ describe "String#unpack with format 'Q'" do
+ it_behaves_like :string_unpack_64bit_be, 'Q'
+ it_behaves_like :string_unpack_64bit_be_extra, 'Q'
+ it_behaves_like :string_unpack_64bit_be_unsigned, 'Q'
+ end
+
+ describe "String#unpack with format 'q'" do
+ it_behaves_like :string_unpack_64bit_be, 'q'
+ it_behaves_like :string_unpack_64bit_be_extra, 'q'
+ it_behaves_like :string_unpack_64bit_be_signed, 'q'
+ end
+end
diff --git a/spec/rubyspec/core/string/unpack/s_spec.rb b/spec/rubyspec/core/string/unpack/s_spec.rb
new file mode 100644
index 0000000000..c6b079b0a6
--- /dev/null
+++ b/spec/rubyspec/core/string/unpack/s_spec.rb
@@ -0,0 +1,152 @@
+require File.expand_path('../../../../spec_helper', __FILE__)
+require File.expand_path('../../fixtures/classes', __FILE__)
+require File.expand_path('../shared/basic', __FILE__)
+require File.expand_path('../shared/integer', __FILE__)
+
+describe "String#unpack with format 'S'" do
+ describe "with modifier '<'" do
+ it_behaves_like :string_unpack_16bit_le, 'S<'
+ it_behaves_like :string_unpack_16bit_le_unsigned, 'S<'
+ end
+
+ describe "with modifier '<' and '_'" do
+ it_behaves_like :string_unpack_16bit_le, 'S<_'
+ it_behaves_like :string_unpack_16bit_le, 'S_<'
+ it_behaves_like :string_unpack_16bit_le_unsigned, 'S_<'
+ it_behaves_like :string_unpack_16bit_le_unsigned, 'S<_'
+ end
+
+ describe "with modifier '<' and '!'" do
+ it_behaves_like :string_unpack_16bit_le, 'S<!'
+ it_behaves_like :string_unpack_16bit_le, 'S!<'
+ it_behaves_like :string_unpack_16bit_le_unsigned, 'S!<'
+ it_behaves_like :string_unpack_16bit_le_unsigned, 'S<!'
+ end
+
+ describe "with modifier '>'" do
+ it_behaves_like :string_unpack_16bit_be, 'S>'
+ it_behaves_like :string_unpack_16bit_be_unsigned, 'S>'
+ end
+
+ describe "with modifier '>' and '_'" do
+ it_behaves_like :string_unpack_16bit_be, 'S>_'
+ it_behaves_like :string_unpack_16bit_be, 'S_>'
+ it_behaves_like :string_unpack_16bit_be_unsigned, 'S>_'
+ it_behaves_like :string_unpack_16bit_be_unsigned, 'S_>'
+ end
+
+ describe "with modifier '>' and '!'" do
+ it_behaves_like :string_unpack_16bit_be, 'S>!'
+ it_behaves_like :string_unpack_16bit_be, 'S!>'
+ it_behaves_like :string_unpack_16bit_be_unsigned, 'S>!'
+ it_behaves_like :string_unpack_16bit_be_unsigned, 'S!>'
+ end
+end
+
+describe "String#unpack with format 's'" do
+ describe "with modifier '<'" do
+ it_behaves_like :string_unpack_16bit_le, 's<'
+ it_behaves_like :string_unpack_16bit_le_signed, 's<'
+ end
+
+ describe "with modifier '<' and '_'" do
+ it_behaves_like :string_unpack_16bit_le, 's<_'
+ it_behaves_like :string_unpack_16bit_le, 's_<'
+ it_behaves_like :string_unpack_16bit_le_signed, 's<_'
+ it_behaves_like :string_unpack_16bit_le_signed, 's_<'
+ end
+
+ describe "with modifier '<' and '!'" do
+ it_behaves_like :string_unpack_16bit_le, 's<!'
+ it_behaves_like :string_unpack_16bit_le, 's!<'
+ it_behaves_like :string_unpack_16bit_le_signed, 's<!'
+ it_behaves_like :string_unpack_16bit_le_signed, 's!<'
+ end
+
+ describe "with modifier '>'" do
+ it_behaves_like :string_unpack_16bit_be, 's>'
+ it_behaves_like :string_unpack_16bit_be_signed, 's>'
+ end
+
+ describe "with modifier '>' and '_'" do
+ it_behaves_like :string_unpack_16bit_be, 's>_'
+ it_behaves_like :string_unpack_16bit_be, 's_>'
+ it_behaves_like :string_unpack_16bit_be_signed, 's>_'
+ it_behaves_like :string_unpack_16bit_be_signed, 's_>'
+ end
+
+ describe "with modifier '>' and '!'" do
+ it_behaves_like :string_unpack_16bit_be, 's>!'
+ it_behaves_like :string_unpack_16bit_be, 's!>'
+ it_behaves_like :string_unpack_16bit_be_signed, 's>!'
+ it_behaves_like :string_unpack_16bit_be_signed, 's!>'
+ end
+end
+
+little_endian do
+ describe "String#unpack with format 'S'" do
+ it_behaves_like :string_unpack_basic, 'S'
+ it_behaves_like :string_unpack_16bit_le, 'S'
+ it_behaves_like :string_unpack_16bit_le_unsigned, 'S'
+ end
+
+ describe "String#unpack with format 'S' with modifier '_'" do
+ it_behaves_like :string_unpack_16bit_le, 'S_'
+ it_behaves_like :string_unpack_16bit_le_unsigned, 'S_'
+ end
+
+ describe "String#unpack with format 'S' with modifier '!'" do
+ it_behaves_like :string_unpack_16bit_le, 'S!'
+ it_behaves_like :string_unpack_16bit_le_unsigned, 'S!'
+ end
+
+ describe "String#unpack with format 's'" do
+ it_behaves_like :string_unpack_basic, 's'
+ it_behaves_like :string_unpack_16bit_le, 's'
+ it_behaves_like :string_unpack_16bit_le_signed, 's'
+ end
+
+ describe "String#unpack with format 's' with modifier '_'" do
+ it_behaves_like :string_unpack_16bit_le, 's_'
+ it_behaves_like :string_unpack_16bit_le_signed, 's_'
+ end
+
+ describe "String#unpack with format 's' with modifier '!'" do
+ it_behaves_like :string_unpack_16bit_le, 's!'
+ it_behaves_like :string_unpack_16bit_le_signed, 's!'
+ end
+end
+
+big_endian do
+ describe "String#unpack with format 'S'" do
+ it_behaves_like :string_unpack_basic, 'S'
+ it_behaves_like :string_unpack_16bit_be, 'S'
+ it_behaves_like :string_unpack_16bit_be_unsigned, 'S'
+ end
+
+ describe "String#unpack with format 'S' with modifier '_'" do
+ it_behaves_like :string_unpack_16bit_be, 'S_'
+ it_behaves_like :string_unpack_16bit_be_unsigned, 'S_'
+ end
+
+ describe "String#unpack with format 'S' with modifier '!'" do
+ it_behaves_like :string_unpack_16bit_be, 'S!'
+ it_behaves_like :string_unpack_16bit_be_unsigned, 'S!'
+ end
+
+ describe "String#unpack with format 's'" do
+ it_behaves_like :string_unpack_basic, 's'
+ it_behaves_like :string_unpack_16bit_be, 's'
+ it_behaves_like :string_unpack_16bit_be_signed, 's'
+ end
+
+ describe "String#unpack with format 's' with modifier '_'" do
+ it_behaves_like :string_unpack_16bit_be, 's_'
+ it_behaves_like :string_unpack_16bit_be_signed, 's_'
+ end
+
+ describe "String#unpack with format 's' with modifier '!'" do
+ it_behaves_like :string_unpack_16bit_be, 's!'
+ it_behaves_like :string_unpack_16bit_be_signed, 's!'
+ end
+end
diff --git a/spec/rubyspec/core/string/unpack/shared/basic.rb b/spec/rubyspec/core/string/unpack/shared/basic.rb
new file mode 100644
index 0000000000..0ecbf615af
--- /dev/null
+++ b/spec/rubyspec/core/string/unpack/shared/basic.rb
@@ -0,0 +1,29 @@
+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
+
+ it "raises a TypeError when passed nil" do
+ lambda { "abc".unpack(nil) }.should raise_error(TypeError)
+ end
+
+ it "raises a TypeError when passed an Integer" do
+ lambda { "abc".unpack(1) }.should raise_error(TypeError)
+ end
+end
+
+describe :string_unpack_no_platform, shared: true do
+ it "raises an ArgumentError when the format modifier is '_'" do
+ lambda { "abcdefgh".unpack(unpack_format("_")) }.should raise_error(ArgumentError)
+ end
+
+ it "raises an ArgumentError when the format modifier is '!'" do
+ lambda { "abcdefgh".unpack(unpack_format("!")) }.should raise_error(ArgumentError)
+ end
+end
diff --git a/spec/rubyspec/core/string/unpack/shared/float.rb b/spec/rubyspec/core/string/unpack/shared/float.rb
new file mode 100644
index 0000000000..208dc357af
--- /dev/null
+++ b/spec/rubyspec/core/string/unpack/shared/float.rb
@@ -0,0 +1,271 @@
+# -*- encoding: ascii-8bit -*-
+
+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
+
+ it "ignores NULL bytes between directives" do
+ array = "\x9a\x999@33\xb3?".unpack(unpack_format("\000", 2))
+ array.should == [2.9000000953674316, 1.399999976158142]
+ 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
+
+ it "ignores NULL bytes between directives" do
+ array = "@9\x99\x9a?\xb333".unpack(unpack_format("\000", 2))
+ array.should == [2.9000000953674316, 1.399999976158142]
+ 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
+
+ it "ignores NULL bytes between directives" do
+ "333333\x07@ffffff\xf6?".unpack(unpack_format("\000", 2)).should == [2.9, 1.4]
+ 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
+
+ it "ignores NULL bytes between directives" do
+ "@\x07333333?\xf6ffffff".unpack(unpack_format("\000", 2)).should == [2.9, 1.4]
+ end
+
+ it "ignores spaces between directives" do
+ "@\x07333333?\xf6ffffff".unpack(unpack_format(' ', 2)).should == [2.9, 1.4]
+ end
+end
diff --git a/spec/rubyspec/core/string/unpack/shared/integer.rb b/spec/rubyspec/core/string/unpack/shared/integer.rb
new file mode 100644
index 0000000000..03dfb5c682
--- /dev/null
+++ b/spec/rubyspec/core/string/unpack/shared/integer.rb
@@ -0,0 +1,339 @@
+# -*- encoding: ascii-8bit -*-
+
+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
+
+ it "ignores NULL bytes between directives" do
+ "abcd".unpack(unpack_format("\000", 2)).should == [25185, 25699]
+ 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
+
+ it "ignores NULL bytes between directives" do
+ "badc".unpack(unpack_format("\000", 2)).should == [25185, 25699]
+ 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
+
+ it "ignores NULL bytes between directives" do
+ "abcdefgh".unpack(unpack_format("\000", 2)).should == [1684234849, 1751606885]
+ 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
+
+ it "ignores NULL bytes between directives" do
+ "dcbahgfe".unpack(unpack_format("\000", 2)).should == [1684234849, 1751606885]
+ 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
+
+ it "ignores NULL bytes between directives" do
+ array = "abcdefghabghefcd".unpack(unpack_format("\000", 2))
+ array.should == [7523094288207667809, 7233738012216484449]
+ 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
+
+ it "ignores NULL bytes between directives" do
+ array = "hgfedcbadcfehgba".unpack(unpack_format("\000", 2))
+ array.should == [7523094288207667809, 7233738012216484449]
+ 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/rubyspec/core/string/unpack/shared/string.rb b/spec/rubyspec/core/string/unpack/shared/string.rb
new file mode 100644
index 0000000000..9d85eedf26
--- /dev/null
+++ b/spec/rubyspec/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/rubyspec/core/string/unpack/shared/unicode.rb b/spec/rubyspec/core/string/unpack/shared/unicode.rb
new file mode 100644
index 0000000000..a2b4e142b2
--- /dev/null
+++ b/spec/rubyspec/core/string/unpack/shared/unicode.rb
@@ -0,0 +1,60 @@
+# -*- 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
+
+ it "ignores NULL bytes between directives" do
+ "\x01\x02".unpack("U\x00U").should == [1, 2]
+ end
+
+ it "ignores spaces between directives" do
+ "\x01\x02".unpack("U U").should == [1, 2]
+ end
+end
diff --git a/spec/rubyspec/core/string/unpack/u_spec.rb b/spec/rubyspec/core/string/unpack/u_spec.rb
new file mode 100644
index 0000000000..0765da8d96
--- /dev/null
+++ b/spec/rubyspec/core/string/unpack/u_spec.rb
@@ -0,0 +1,94 @@
+# -*- encoding: ascii-8bit -*-
+require File.expand_path('../../../../spec_helper', __FILE__)
+require File.expand_path('../../fixtures/classes', __FILE__)
+require File.expand_path('../shared/basic', __FILE__)
+require File.expand_path('../shared/unicode', __FILE__)
+
+describe "String#unpack with format 'U'" do
+ it_behaves_like :string_unpack_basic, 'U'
+ it_behaves_like :string_unpack_no_platform, 'U'
+ it_behaves_like :string_unpack_unicode, 'U'
+
+ it "raises ArgumentError on a malformed byte sequence" do
+ lambda { "\xE3".unpack('U') }.should raise_error(ArgumentError)
+ end
+
+ it "raises ArgumentError on a malformed byte sequence and doesn't continue when used with the * modifier" do
+ lambda { "\xE3".unpack('U*') }.should raise_error(ArgumentError)
+ end
+end
+
+describe "String#unpack with format 'u'" do
+ it_behaves_like :string_unpack_basic, 'u'
+ it_behaves_like :string_unpack_no_platform, 'u'
+
+ it "decodes an empty string as an empty string" do
+ "".unpack("u").should == [""]
+ end
+
+ it "decodes into raw (ascii) string values" do
+ str = "".unpack("u")[0]
+ str.encoding.name.should == 'ASCII-8BIT'
+
+ str = "1".force_encoding('UTF-8').unpack("u")[0]
+ str.encoding.name.should == 'ASCII-8BIT'
+ end
+
+ it "decodes the complete string ignoring newlines when given a single directive" do
+ "#86)C\n#1$5&\n".unpack("u").should == ["abcDEF"]
+ end
+
+ it "appends empty string to the array for directives exceeding the input size" do
+ "#86)C\n#1$5&\n".unpack("uuu").should == ["abcDEF", "", ""]
+ end
+
+ it "ignores the count or '*' modifier and decodes the entire string" do
+ [ ["#86)C\n#1$5&\n", "u238", ["abcDEF"]],
+ ["#86)C\n#1$5&\n", "u*", ["abcDEF"]]
+ ].should be_computed_by(:unpack)
+ end
+
+ it "decodes all ascii characters" do
+ [ ["'``$\"`P0%!@``\n", ["\x00\x01\x02\x03\x04\x05\x06"]],
+ ["'!P@)\"@L,#0``\n", ["\a\b\t\n\v\f\r"]],
+ [")\#@\\0$1(3%!46\n", ["\x0E\x0F\x10\x11\x12\x13\x14\x15\x16"]],
+ [")%Q@9&AL<'1X?\n", ["\x17\x18\x19\x1a\e\x1c\x1d\x1e\x1f"]],
+ ["/(2(C)\"4F)R@I*BLL+2XO\n", ["!\"\#$%&'()*+,-./"]],
+ ["*,\#$R,S0U-C<X.0``\n", ["0123456789"]],
+ ["'.CL\\/3X_0```\n", [":;<=>?@"]],
+ [":04)#1$5&1TA)2DM,34Y/4%%24U155E=865H`\n", ["ABCDEFGHIJKLMNOPQRSTUVWXYZ"]],
+ ["&6UQ=7E]@\n", ["[\\]^_`"]],
+ [":86)C9&5F9VAI:FML;6YO<'%R<W1U=G=X>7H`\n", ["abcdefghijklmnopqrstuvwxyz"]],
+ ["$>WQ]?@``\n", ["{|}~"]],
+ [")?\\*`PH'\"@L*#\n", ["\x7f\xc2\x80\xc2\x81\xc2\x82\xc2\x83"]],
+ [")PH3\"A<*&PH?\"\n", ["\xc2\x84\xc2\x85\xc2\x86\xc2\x87\xc2"]],
+ [")B,*)PHK\"B\\*,\n", ["\x88\xc2\x89\xc2\x8a\xc2\x8b\xc2\x8c"]],
+ [")PHW\"CL*/PI#\"\n", ["\xc2\x8d\xc2\x8e\xc2\x8f\xc2\x90\xc2"]],
+ [")D<*2PI/\"E,*5\n", ["\x91\xc2\x92\xc2\x93\xc2\x94\xc2\x95"]],
+ [")PI;\"E\\*8PIG\"\n", ["\xc2\x96\xc2\x97\xc2\x98\xc2\x99\xc2"]],
+ [")FL*;PIS\"G<*>\n", ["\x9a\xc2\x9b\xc2\x9c\xc2\x9d\xc2\x9e"]],
+ [")PI_\"H,*APJ+\"\n", ["\xc2\x9f\xc2\xa0\xc2\xa1\xc2\xa2\xc2"]],
+ [")H\\*DPJ7\"IL*G\n", ["\xa3\xc2\xa4\xc2\xa5\xc2\xa6\xc2\xa7"]],
+ [")PJC\"J<*JPJO\"\n", ["\xc2\xa8\xc2\xa9\xc2\xaa\xc2\xab\xc2"]],
+ [")K,*MPJ[\"K\\*P\n", ["\xac\xc2\xad\xc2\xae\xc2\xaf\xc2\xb0"]],
+ [")PK'\"LL*SPK3\"\n", ["\xc2\xb1\xc2\xb2\xc2\xb3\xc2\xb4\xc2"]],
+ [")M<*VPK?\"N,*Y\n", ["\xb5\xc2\xb6\xc2\xb7\xc2\xb8\xc2\xb9"]],
+ [")PKK\"N\\*\\PKW\"\n", ["\xc2\xba\xc2\xbb\xc2\xbc\xc2\xbd\xc2"]],
+ [")OL*_PX#\#@<.\"\n", ["\xbe\xc2\xbf\xc3\x80\xc3\x81\xc3\x82"]],
+ [")PX/#A,.%PX;#\n", ["\xc3\x83\xc3\x84\xc3\x85\xc3\x86\xc3"]],
+ [")A\\.(PXG#BL.+\n", ["\x87\xc3\x88\xc3\x89\xc3\x8a\xc3\x8b"]],
+ [")PXS#C<..PX_#\n", ["\xc3\x8c\xc3\x8d\xc3\x8e\xc3\x8f\xc3"]],
+ [")D,.1PY+#D\\.4\n", ["\x90\xc3\x91\xc3\x92\xc3\x93\xc3\x94"]],
+ [")PY7#EL.7PYC#\n", ["\xc3\x95\xc3\x96\xc3\x97\xc3\x98\xc3"]],
+ [")F<.:PYO#G,.=\n", ["\x99\xc3\x9a\xc3\x9b\xc3\x9c\xc3\x9d"]],
+ [")PY[#G\\.@PZ'#\n", ["\xc3\x9e\xc3\x9f\xc3\xa0\xc3\xa1\xc3"]],
+ [")HL.CPZ3#I<.F\n", ["\xa2\xc3\xa3\xc3\xa4\xc3\xa5\xc3\xa6"]],
+ [")PZ?#J,.IPZK#\n", ["\xc3\xa7\xc3\xa8\xc3\xa9\xc3\xaa\xc3"]],
+ [")J\\.LPZW#KL.O\n", ["\xab\xc3\xac\xc3\xad\xc3\xae\xc3\xaf"]],
+ [")P[##L<.RP[/#\n", ["\xc3\xb0\xc3\xb1\xc3\xb2\xc3\xb3\xc3"]],
+ [")M,.UP[;#M\\.X\n", ["\xb4\xc3\xb5\xc3\xb6\xc3\xb7\xc3\xb8"]],
+ [")P[G#NL.[P[S#\n", ["\xc3\xb9\xc3\xba\xc3\xbb\xc3\xbc\xc3"]],
+ ["%O<.^P[\\`\n", ["\xbd\xc3\xbe\xc3\xbf"]]
+ ].should be_computed_by(:unpack, "u")
+ end
+end
diff --git a/spec/rubyspec/core/string/unpack/v_spec.rb b/spec/rubyspec/core/string/unpack/v_spec.rb
new file mode 100644
index 0000000000..33cf23c68b
--- /dev/null
+++ b/spec/rubyspec/core/string/unpack/v_spec.rb
@@ -0,0 +1,18 @@
+require File.expand_path('../../../../spec_helper', __FILE__)
+require File.expand_path('../../fixtures/classes', __FILE__)
+require File.expand_path('../shared/basic', __FILE__)
+require File.expand_path('../shared/integer', __FILE__)
+
+describe "String#unpack with format 'V'" do
+ it_behaves_like :string_unpack_basic, 'V'
+ it_behaves_like :string_unpack_32bit_le, 'V'
+ it_behaves_like :string_unpack_32bit_le_unsigned, 'V'
+ it_behaves_like :string_unpack_no_platform, 'V'
+end
+
+describe "String#unpack with format 'v'" do
+ it_behaves_like :string_unpack_basic, 'v'
+ it_behaves_like :string_unpack_16bit_le, 'v'
+ it_behaves_like :string_unpack_16bit_le_unsigned, 'v'
+ it_behaves_like :string_unpack_no_platform, 'v'
+end
diff --git a/spec/rubyspec/core/string/unpack/w_spec.rb b/spec/rubyspec/core/string/unpack/w_spec.rb
new file mode 100644
index 0000000000..22f5980a46
--- /dev/null
+++ b/spec/rubyspec/core/string/unpack/w_spec.rb
@@ -0,0 +1,25 @@
+# -*- encoding: ascii-8bit -*-
+require File.expand_path('../../../../spec_helper', __FILE__)
+require File.expand_path('../../fixtures/classes', __FILE__)
+require File.expand_path('../shared/basic', __FILE__)
+
+describe "String#unpack with directive 'w'" do
+ it_behaves_like :string_unpack_basic, 'w'
+ it_behaves_like :string_unpack_no_platform, 'w'
+
+ it "decodes a BER-compressed integer" do
+ [ ["\x00", [0]],
+ ["\x01", [1]],
+ ["\xce\x0f", [9999]],
+ ["\x84\x80\x80\x80\x80\x80\x80\x80\x80\x00", [2**65]]
+ ].should be_computed_by(:unpack, "w")
+ end
+
+ it "ignores NULL bytes between directives" do
+ "\x01\x02\x03".unpack("w\x00w").should == [1, 2]
+ end
+
+ it "ignores spaces between directives" do
+ "\x01\x02\x03".unpack("w w").should == [1, 2]
+ end
+end
diff --git a/spec/rubyspec/core/string/unpack/x_spec.rb b/spec/rubyspec/core/string/unpack/x_spec.rb
new file mode 100644
index 0000000000..e765472413
--- /dev/null
+++ b/spec/rubyspec/core/string/unpack/x_spec.rb
@@ -0,0 +1,62 @@
+# -*- encoding: ascii-8bit -*-
+require File.expand_path('../../../../spec_helper', __FILE__)
+require File.expand_path('../../fixtures/classes', __FILE__)
+require File.expand_path('../shared/basic', __FILE__)
+
+describe "String#unpack with format 'X'" do
+ it_behaves_like :string_unpack_basic, 'X'
+ it_behaves_like :string_unpack_no_platform, 'X'
+
+ it "moves the read index back by the number of bytes specified by count" do
+ "\x01\x02\x03\x04".unpack("C3X2C").should == [1, 2, 3, 2]
+ end
+
+ it "does not change the read index when passed a count of zero" do
+ "\x01\x02\x03\x04".unpack("C3X0C").should == [1, 2, 3, 4]
+ end
+
+ it "implicitly has a count of one when count is not specified" do
+ "\x01\x02\x03\x04".unpack("C3XC").should == [1, 2, 3, 3]
+ end
+
+ it "moves the read index back by the remaining bytes when passed the '*' modifier" do
+ "abcd".unpack("C3X*C").should == [97, 98, 99, 99]
+ end
+
+ it "raises an ArgumentError when passed the '*' modifier if the remaining bytes exceed the bytes from the index to the start of the String" do
+ lambda { "abcd".unpack("CX*C") }.should raise_error(ArgumentError)
+ end
+
+ it "raises an ArgumentError if the count exceeds the bytes from current index to the start of the String" do
+ lambda { "\x01\x02\x03\x04".unpack("C3X4C") }.should raise_error(ArgumentError)
+ end
+end
+
+describe "String#unpack with format 'x'" do
+ it_behaves_like :string_unpack_basic, 'x'
+ it_behaves_like :string_unpack_no_platform, 'x'
+
+ it "moves the read index forward by the number of bytes specified by count" do
+ "\x01\x02\x03\x04".unpack("Cx2C").should == [1, 4]
+ end
+
+ it "implicitly has a count of one when count is not specified" do
+ "\x01\x02\x03\x04".unpack("CxC").should == [1, 3]
+ end
+
+ it "does not change the read index when passed a count of zero" do
+ "\x01\x02\x03\x04".unpack("Cx0C").should == [1, 2]
+ end
+
+ it "moves the read index to the end of the string when passed the '*' modifier" do
+ "\x01\x02\x03\x04".unpack("Cx*C").should == [1, nil]
+ end
+
+ it "positions the read index one beyond the last readable byte in the String" do
+ "\x01\x02\x03\x04".unpack("C2x2C").should == [1, 2, nil]
+ end
+
+ it "raises an ArgumentError if the count exceeds the size of the String" do
+ lambda { "\x01\x02\x03\x04".unpack("C2x3C") }.should raise_error(ArgumentError)
+ end
+end
diff --git a/spec/rubyspec/core/string/unpack/z_spec.rb b/spec/rubyspec/core/string/unpack/z_spec.rb
new file mode 100644
index 0000000000..7c3d167ac2
--- /dev/null
+++ b/spec/rubyspec/core/string/unpack/z_spec.rb
@@ -0,0 +1,21 @@
+# -*- encoding: ascii-8bit -*-
+require File.expand_path('../../../../spec_helper', __FILE__)
+require File.expand_path('../../fixtures/classes', __FILE__)
+require File.expand_path('../shared/basic', __FILE__)
+require File.expand_path('../shared/string', __FILE__)
+
+describe "String#unpack with format 'Z'" do
+ it_behaves_like :string_unpack_basic, 'Z'
+ it_behaves_like :string_unpack_no_platform, 'Z'
+ it_behaves_like :string_unpack_string, 'Z'
+
+ it "stops decoding at NULL bytes when passed the '*' modifier" do
+ "a\x00\x00 b \x00c".unpack('Z*Z*Z*Z*').should == ["a", "", " b ", "c"]
+ end
+
+ it "decodes the number of bytes specified by the count modifier and truncates the decoded string at the first NULL byte" do
+ [ ["a\x00 \x00b c", ["a", " "]],
+ ["\x00a\x00 bc \x00", ["", "c"]]
+ ].should be_computed_by(:unpack, "Z5Z")
+ end
+end