summaryrefslogtreecommitdiff
path: root/spec/ruby/optional/capi/string_spec.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/ruby/optional/capi/string_spec.rb')
-rw-r--r--spec/ruby/optional/capi/string_spec.rb332
1 files changed, 276 insertions, 56 deletions
diff --git a/spec/ruby/optional/capi/string_spec.rb b/spec/ruby/optional/capi/string_spec.rb
index 18eaeda8e0..3e095f05c8 100644
--- a/spec/ruby/optional/capi/string_spec.rb
+++ b/spec/ruby/optional/capi/string_spec.rb
@@ -191,11 +191,19 @@ describe "C-API String function" do
end
it "returns a new String object filled with \\0 bytes" do
- s = @s.rb_str_tmp_new(4)
- s.encoding.should == Encoding::BINARY
- s.bytesize.should == 4
- s.size.should == 4
- s.should == "\x00\x00\x00\x00"
+ lens = [4]
+
+ ruby_version_is "4.0" do
+ lens << 100
+ end
+
+ lens.each do |len|
+ s = @s.rb_str_tmp_new(len)
+ s.encoding.should == Encoding::BINARY
+ s.bytesize.should == len
+ s.size.should == len
+ s.should == "\x00" * len
+ end
end
end
@@ -278,13 +286,13 @@ describe "C-API String function" do
it "returns a dup of the original String" do
a = "abc"
b = @s.rb_str_encode("abc", "us-ascii", 0, nil)
- a.should_not equal(b)
+ a.should_not.equal?(b)
end
it "returns a duplicate of the original when the encoding doesn't change" do
a = "abc"
b = @s.rb_str_encode("abc", Encoding::UTF_8, 0, nil)
- a.should_not equal(b)
+ a.should_not.equal?(b)
end
it "accepts encoding flags" do
@@ -312,7 +320,7 @@ describe "C-API String function" do
str1 = "hi"
str2 = @s.rb_str_new3 str1
str1.should == str2
- str1.should_not equal str2
+ str1.should_not.equal? str2
end
end
@@ -322,7 +330,7 @@ describe "C-API String function" do
str1.freeze
str2 = @s.rb_str_new4 str1
str1.should == str2
- str1.should equal(str2)
+ str1.should.equal?(str2)
str1.should.frozen?
str2.should.frozen?
end
@@ -331,7 +339,7 @@ describe "C-API String function" do
str1 = "hi"
str2 = @s.rb_str_new4 str1
str1.should == str2
- str1.should_not equal(str2)
+ str1.should_not.equal?(str2)
str2.should.frozen?
end
end
@@ -341,7 +349,7 @@ describe "C-API String function" do
str1 = "hi"
str2 = @s.rb_str_dup str1
str1.should == str2
- str1.should_not equal str2
+ str1.should_not.equal? str2
end
end
@@ -362,7 +370,7 @@ describe "C-API String function" do
end
it "raises a TypeError trying to append non-String-like object" do
- -> { @s.rb_str_append("Hello", 32323)}.should raise_error(TypeError)
+ -> { @s.rb_str_append("Hello", 32323)}.should.raise(TypeError)
end
it "changes Encoding if a string is appended to an empty string" do
@@ -491,7 +499,7 @@ describe "C-API String function" do
end
it "converts a C string to a Fixnum strictly if base is 0" do
- -> { @s.rb_cstr2inum("1234a", 0) }.should raise_error(ArgumentError)
+ -> { @s.rb_cstr2inum("1234a", 0) }.should.raise(ArgumentError)
end
end
@@ -509,7 +517,7 @@ describe "C-API String function" do
end
it "converts a C string to a Fixnum strictly" do
- -> { @s.rb_cstr_to_inum("1234a", 10, true) }.should raise_error(ArgumentError)
+ -> { @s.rb_cstr_to_inum("1234a", 10, true) }.should.raise(ArgumentError)
end
end
@@ -528,6 +536,61 @@ describe "C-API String function" do
end
end
+ describe "rb_str_sublen" do
+ it "returns the character length for a given byte offset in an ASCII string" do
+ @s.rb_str_sublen("hello", 3).should == 3
+ end
+
+ it "returns the character length for a given byte offset in a multibyte string" do
+ # "hëllo" where 'ë' is 2 bytes in UTF-8, total 6 bytes
+ str = "hëllo"
+ @s.rb_str_sublen(str, 3).should == 2
+ end
+
+ it "returns 0 for byte offset 0" do
+ @s.rb_str_sublen("hello", 0).should == 0
+ end
+
+ it "returns the full character length for the total byte length" do
+ str = "hëllo"
+ @s.rb_str_sublen(str, str.bytesize).should == str.length
+ end
+ end
+
+ describe "rb_str_subpos" do
+ it "returns [byte_offset, byte_length] for a valid character offset in an ASCII string" do
+ @s.rb_str_subpos("hello", 1).should == [1, 4]
+ end
+
+ it "returns [byte_offset, byte_length] for a valid character offset in a multibyte string" do
+ # "hëllo" where 'ë' is 2 bytes in UTF-8
+ str = "hëllo"
+ @s.rb_str_subpos(str, 0).should == [0, 6]
+ @s.rb_str_subpos(str, 1).should == [1, 5]
+ @s.rb_str_subpos(str, 2).should == [3, 3]
+ end
+
+ it "returns [0, byte_length] for offset 0" do
+ @s.rb_str_subpos("hello", 0).should == [0, 5]
+ end
+
+ it "returns nil for a negative offset that is out of range" do
+ @s.rb_str_subpos("hello", -6).should == nil
+ end
+
+ it "returns the correct position for a negative offset" do
+ @s.rb_str_subpos("hello", -2).should == [3, 2]
+ end
+
+ it "returns [byte_length, 0] when offset equals string length" do
+ @s.rb_str_subpos("hello", 5).should == [5, 0]
+ end
+
+ it "returns nil when offset is beyond string length" do
+ @s.rb_str_subpos("hello", 6).should == nil
+ end
+ end
+
describe "rb_str_to_str" do
it "calls #to_str to coerce the value to a String" do
@s.rb_str_to_str("foo").should == "foo"
@@ -535,8 +598,8 @@ describe "C-API String function" do
end
it "raises a TypeError if coercion fails" do
- -> { @s.rb_str_to_str(0) }.should raise_error(TypeError)
- -> { @s.rb_str_to_str(CApiStringSpecs::InvalidTostrTest.new) }.should raise_error(TypeError)
+ -> { @s.rb_str_to_str(0) }.should.raise(TypeError)
+ -> { @s.rb_str_to_str(CApiStringSpecs::InvalidTostrTest.new) }.should.raise(TypeError)
end
end
@@ -660,7 +723,7 @@ describe "C-API String function" do
it "does not call #to_s on non-String objects" do
str = mock("fake")
str.should_not_receive(:to_s)
- -> { @s.send(@method, str) }.should raise_error(TypeError)
+ -> { @s.send(@method, str) }.should.raise(TypeError)
end
end
@@ -673,7 +736,7 @@ describe "C-API String function" do
describe "rb_str_modify" do
it "raises an error if the string is frozen" do
- -> { @s.rb_str_modify("frozen".freeze) }.should raise_error(FrozenError)
+ -> { @s.rb_str_modify("frozen".freeze) }.should.raise(FrozenError)
end
end
@@ -704,7 +767,7 @@ describe "C-API String function" do
end
it "raises an error if the string is frozen" do
- -> { @s.rb_str_modify_expand("frozen".freeze, 10) }.should raise_error(FrozenError)
+ -> { @s.rb_str_modify_expand("frozen".freeze, 10) }.should.raise(FrozenError)
end
end
@@ -760,14 +823,14 @@ describe "C-API String function" do
it "freezes the string" do
s = ""
@s.rb_str_freeze(s).should == s
- s.frozen?.should be_true
+ s.frozen?.should == true
end
end
describe "rb_str_hash" do
it "hashes the string into a number" do
s = "hello"
- @s.rb_str_hash(s).should be_kind_of(Integer)
+ @s.rb_str_hash(s).should.is_a?(Integer)
end
end
@@ -783,7 +846,7 @@ describe "rb_str_free" do
# is available. There is no guarantee this even does
# anything at all
it "indicates data for a string might be freed" do
- @s.rb_str_free("xyz").should be_nil
+ @s.rb_str_free("xyz").should == nil
end
end
@@ -825,12 +888,12 @@ describe "C-API String function" do
describe "rb_str_equal" do
it "compares two same strings" do
s = "hello"
- @s.rb_str_equal(s, "hello").should be_true
+ @s.rb_str_equal(s, "hello").should == true
end
it "compares two different strings" do
s = "hello"
- @s.rb_str_equal(s, "hella").should be_false
+ @s.rb_str_equal(s, "hella").should == false
end
end
@@ -865,7 +928,7 @@ describe "C-API String function" do
# - s.should == "\xA4\xA2\xA4\xEC".dup.force_encoding("euc-jp")
# + x = [0xA4, 0xA2, 0xA4, 0xEC].pack('C4')#.force_encoding('binary')
# + s.should == x
-# s.encoding.should equal(Encoding::EUC_JP)
+# s.encoding.should.equal?(Encoding::EUC_JP)
# end
it "transcodes a String to Encoding.default_internal if it is set" do
@@ -875,7 +938,7 @@ describe "C-API String function" do
s = @s.rb_external_str_new_with_enc(a, a.bytesize, Encoding::UTF_8)
x = [0xA4, 0xA2, 0xA4, 0xEC].pack('C4').force_encoding('euc-jp')
s.should == x
- s.encoding.should equal(Encoding::EUC_JP)
+ s.encoding.should.equal?(Encoding::EUC_JP)
end
end
@@ -883,7 +946,7 @@ describe "C-API String function" do
it "returns a String with 'locale' encoding" do
s = @s.rb_locale_str_new("abc", 3)
s.should == "abc".dup.force_encoding(Encoding.find("locale"))
- s.encoding.should equal(Encoding.find("locale"))
+ s.encoding.should.equal?(Encoding.find("locale"))
end
end
@@ -891,14 +954,14 @@ describe "C-API String function" do
it "returns a String with 'locale' encoding" do
s = @s.rb_locale_str_new_cstr("abc")
s.should == "abc".dup.force_encoding(Encoding.find("locale"))
- s.encoding.should equal(Encoding.find("locale"))
+ s.encoding.should.equal?(Encoding.find("locale"))
end
end
describe "rb_str_conv_enc" do
it "returns the original String when to encoding is not specified" do
a = "abc".dup.force_encoding("us-ascii")
- @s.rb_str_conv_enc(a, Encoding::US_ASCII, nil).should equal(a)
+ @s.rb_str_conv_enc(a, Encoding::US_ASCII, nil).should.equal?(a)
end
it "returns the original String if a transcoding error occurs" do
@@ -921,17 +984,17 @@ describe "C-API String function" do
describe "when the String encoding is equal to the destination encoding" do
it "returns the original String" do
a = "abc".dup.force_encoding("us-ascii")
- @s.rb_str_conv_enc(a, Encoding::US_ASCII, Encoding::US_ASCII).should equal(a)
+ @s.rb_str_conv_enc(a, Encoding::US_ASCII, Encoding::US_ASCII).should.equal?(a)
end
it "returns the original String if the destination encoding is ASCII compatible and the String has no high bits set" do
a = "abc".encode("us-ascii")
- @s.rb_str_conv_enc(a, Encoding::UTF_8, Encoding::US_ASCII).should equal(a)
+ @s.rb_str_conv_enc(a, Encoding::UTF_8, Encoding::US_ASCII).should.equal?(a)
end
it "returns the origin String if the destination encoding is BINARY" do
a = "abc".dup.force_encoding("binary")
- @s.rb_str_conv_enc(a, Encoding::US_ASCII, Encoding::BINARY).should equal(a)
+ @s.rb_str_conv_enc(a, Encoding::US_ASCII, Encoding::BINARY).should.equal?(a)
end
end
end
@@ -939,13 +1002,13 @@ describe "C-API String function" do
describe "rb_str_conv_enc_opts" do
it "returns the original String when to encoding is not specified" do
a = "abc".dup.force_encoding("us-ascii")
- @s.rb_str_conv_enc_opts(a, Encoding::US_ASCII, nil, 0, nil).should equal(a)
+ @s.rb_str_conv_enc_opts(a, Encoding::US_ASCII, nil, 0, nil).should.equal?(a)
end
it "returns the original String if a transcoding error occurs" do
a = [0xEE].pack('C').force_encoding("utf-8")
@s.rb_str_conv_enc_opts(a, Encoding::UTF_8,
- Encoding::EUC_JP, 0, nil).should equal(a)
+ Encoding::EUC_JP, 0, nil).should.equal?(a)
end
it "returns a transcoded String" do
@@ -953,26 +1016,26 @@ describe "C-API String function" do
result = @s.rb_str_conv_enc_opts(a, Encoding::UTF_8, Encoding::EUC_JP, 0, nil)
x = [0xA4, 0xA2, 0xA4, 0xEC].pack('C4').force_encoding('utf-8')
result.should == x.force_encoding("euc-jp")
- result.encoding.should equal(Encoding::EUC_JP)
+ result.encoding.should.equal?(Encoding::EUC_JP)
end
describe "when the String encoding is equal to the destination encoding" do
it "returns the original String" do
a = "abc".dup.force_encoding("us-ascii")
@s.rb_str_conv_enc_opts(a, Encoding::US_ASCII,
- Encoding::US_ASCII, 0, nil).should equal(a)
+ Encoding::US_ASCII, 0, nil).should.equal?(a)
end
it "returns the original String if the destination encoding is ASCII compatible and the String has no high bits set" do
a = "abc".encode("us-ascii")
@s.rb_str_conv_enc_opts(a, Encoding::UTF_8,
- Encoding::US_ASCII, 0, nil).should equal(a)
+ Encoding::US_ASCII, 0, nil).should.equal?(a)
end
it "returns the origin String if the destination encoding is BINARY" do
a = "abc".dup.force_encoding("binary")
@s.rb_str_conv_enc_opts(a, Encoding::US_ASCII,
- Encoding::BINARY, 0, nil).should equal(a)
+ Encoding::BINARY, 0, nil).should.equal?(a)
end
end
end
@@ -981,7 +1044,7 @@ describe "C-API String function" do
it "returns the original String with the external encoding" do
Encoding.default_external = Encoding::ISO_8859_1
s = @s.rb_str_export("Hëllo")
- s.encoding.should equal(Encoding::ISO_8859_1)
+ s.encoding.should.equal?(Encoding::ISO_8859_1)
end
end
@@ -989,7 +1052,7 @@ describe "C-API String function" do
it "returns the original String with the locale encoding" do
s = @s.rb_str_export_locale("abc")
s.should == "abc".dup.force_encoding(Encoding.find("locale"))
- s.encoding.should equal(Encoding.find("locale"))
+ s.encoding.should.equal?(Encoding.find("locale"))
end
end
@@ -1004,7 +1067,7 @@ describe "C-API String function" do
it "returns the source string if it can not be converted" do
source = ["00ff"].pack("H*");
result = @s.rb_str_export_to_enc(source, Encoding::UTF_8)
- result.should equal(source)
+ result.should.equal?(source)
end
it "does not alter the source string if it can not be converted" do
@@ -1040,11 +1103,19 @@ describe "C-API String function" do
@s.rb_sprintf3(true.class).should == s
end
- ruby_bug "#19167", ""..."3.2" do
- it "formats a TrueClass VALUE as 'true' if sign specified in format" do
- s = 'Result: TrueClass.'
- @s.rb_sprintf4(true.class).should == s
- end
+ it "formats a TrueClass VALUE as 'true' if sign specified in format" do
+ s = 'Result: TrueClass.'
+ @s.rb_sprintf4(true.class).should == s
+ end
+
+ it "formats nil using to_s if sign not specified in format" do
+ s = 'Result: .'
+ @s.rb_sprintf3(nil).should == s
+ end
+
+ it "formats nil using inspect if sign specified in format" do
+ s = 'Result: nil.'
+ @s.rb_sprintf4(nil).should == s
end
it "truncates a string to a supplied precision if that is shorter than the string" do
@@ -1110,7 +1181,7 @@ describe "C-API String function" do
end
it "raises a TypeError if #to_str does not return a string" do
- -> { @s.rb_String(CApiStringSpecs::InvalidTostrTest.new) }.should raise_error(TypeError)
+ -> { @s.rb_String(CApiStringSpecs::InvalidTostrTest.new) }.should.raise(TypeError)
end
it "tries to convert the passed argument to a string by calling #to_s" do
@@ -1128,11 +1199,11 @@ describe "C-API String function" do
end
it "raises an error if a string contains a null" do
- -> { @s.rb_string_value_cstr("Hello\0 with a null.") }.should raise_error(ArgumentError)
+ -> { @s.rb_string_value_cstr("Hello\0 with a null.") }.should.raise(ArgumentError)
end
it "raises an error if a UTF-16 string contains a null" do
- -> { @s.rb_string_value_cstr("Hello\0 with a null.".encode('UTF-16BE')) }.should raise_error(ArgumentError)
+ -> { @s.rb_string_value_cstr("Hello\0 with a null.".encode('UTF-16BE')) }.should.raise(ArgumentError)
end
end
@@ -1159,9 +1230,11 @@ describe "C-API String function" do
describe "rb_utf8_str_new_static" do
it "returns a UTF-8 string of the correct characters and length" do
- str = @s.rb_utf8_str_new_static
+ str, ptr = @s.rb_utf8_str_new_static
str.should == "nokogiri"
str.encoding.should == Encoding::UTF_8
+
+ @s.RSTRING_PTR(str).should == ptr
end
end
@@ -1203,28 +1276,50 @@ describe "C-API String function" do
describe "rb_str_locktmp" do
it "raises an error when trying to lock an already locked string" do
- str = "test"
+ str = +"test"
@s.rb_str_locktmp(str).should == str
- -> { @s.rb_str_locktmp(str) }.should raise_error(RuntimeError, 'temporal locking already locked string')
+ -> { @s.rb_str_locktmp(str) }.should.raise(RuntimeError, 'temporal locking already locked string')
end
it "locks a string so that modifications would raise an error" do
- str = "test"
+ str = +"test"
@s.rb_str_locktmp(str).should == str
- -> { str.upcase! }.should raise_error(RuntimeError, 'can\'t modify string; temporarily locked')
+ -> { str.upcase! }.should.raise(RuntimeError, 'can\'t modify string; temporarily locked')
+ end
+
+ ruby_version_is "4.0" do
+ it "raises FrozenError if string is frozen" do
+ str = -"rb_str_locktmp"
+ -> { @s.rb_str_locktmp(str) }.should.raise(FrozenError)
+
+ str = +"rb_str_locktmp"
+ str.freeze
+ -> { @s.rb_str_locktmp(str) }.should.raise(FrozenError)
+ end
end
end
describe "rb_str_unlocktmp" do
it "unlocks a locked string" do
- str = "test"
+ str = +"test"
@s.rb_str_locktmp(str)
@s.rb_str_unlocktmp(str).should == str
str.upcase!.should == "TEST"
end
it "raises an error when trying to unlock an already unlocked string" do
- -> { @s.rb_str_unlocktmp("test") }.should raise_error(RuntimeError, 'temporal unlocking already unlocked string')
+ -> { @s.rb_str_unlocktmp(+"test") }.should.raise(RuntimeError, 'temporal unlocking already unlocked string')
+ end
+
+ ruby_version_is "4.0" do
+ it "raises FrozenError if string is frozen" do
+ str = -"rb_str_locktmp"
+ -> { @s.rb_str_unlocktmp(str) }.should.raise(FrozenError)
+
+ str = +"rb_str_locktmp"
+ str.freeze
+ -> { @s.rb_str_unlocktmp(str) }.should.raise(FrozenError)
+ end
end
end
@@ -1331,8 +1426,133 @@ describe "C-API String function" do
result1.should_not.equal?(result2)
end
+ it "preserves the encoding of the original string" do
+ result1 = @s.rb_str_to_interned_str("hello".dup.force_encoding(Encoding::US_ASCII))
+ result2 = @s.rb_str_to_interned_str("hello".dup.force_encoding(Encoding::UTF_8))
+ result1.encoding.should == Encoding::US_ASCII
+ result2.encoding.should == Encoding::UTF_8
+ end
+
it "returns the same string as String#-@" do
@s.rb_str_to_interned_str("hello").should.equal?(-"hello")
end
end
+
+ describe "rb_interned_str" do
+ it "returns a frozen string" do
+ str = "hello"
+ result = @s.rb_interned_str(str, str.bytesize)
+ result.should.is_a?(String)
+ result.should.frozen?
+ result.encoding.should == Encoding::US_ASCII
+ end
+
+ it "returns the same frozen string" do
+ str = "hello"
+ result1 = @s.rb_interned_str(str, str.bytesize)
+ result2 = @s.rb_interned_str(str, str.bytesize)
+ result1.should.equal?(result2)
+ end
+
+ it "supports strings with embedded null bytes" do
+ str = "foo\x00bar\x00baz".b
+ result = @s.rb_interned_str(str, str.bytesize)
+ result.should == str
+ end
+
+ it "return US_ASCII encoding for an empty string" do
+ result = @s.rb_interned_str("", 0)
+ result.should == ""
+ result.encoding.should == Encoding::US_ASCII
+ end
+
+ it "returns US_ASCII encoding for strings of only 7 bit ASCII" do
+ 0x00.upto(0x7f).each do |char|
+ result = @s.rb_interned_str(char.chr, 1)
+ result.encoding.should == Encoding::US_ASCII
+ end
+ end
+
+ ruby_bug "21842", ""..."4.1" do
+ it "returns BINARY encoding for strings that use the 8th bit" do
+ 0x80.upto(0xff) do |char|
+ result = @s.rb_interned_str(char.chr, 1)
+ result.encoding.should == Encoding::BINARY
+ end
+ end
+ end
+
+ it 'returns the same string when using non-ascii characters' do
+ str = 'こんにちは'
+ result1 = @s.rb_interned_str(str, str.bytesize)
+ result2 = @s.rb_interned_str(str, str.bytesize)
+ result1.should.equal?(result2)
+ end
+
+ ruby_bug "21842", ""..."4.1" do
+ it "returns the same string as String#-@" do
+ str = "hello".dup.force_encoding(Encoding::US_ASCII)
+ @s.rb_interned_str(str, str.bytesize).should.equal?(-str)
+ end
+ end
+ end
+
+ describe "rb_interned_str_cstr" do
+ it "returns a frozen string" do
+ str = "hello"
+ result = @s.rb_interned_str_cstr(str)
+ result.should.is_a?(String)
+ result.should.frozen?
+ result.encoding.should == Encoding::US_ASCII
+ end
+
+ it "returns the same frozen string" do
+ str = "hello"
+ result1 = @s.rb_interned_str_cstr(str)
+ result2 = @s.rb_interned_str_cstr(str)
+ result1.should.equal?(result2)
+ end
+
+ it "does not support strings with embedded null bytes" do
+ str = "foo\x00bar\x00baz".b
+ result = @s.rb_interned_str_cstr(str)
+ result.should == "foo"
+ end
+
+ it "return US_ASCII encoding for an empty string" do
+ result = @s.rb_interned_str_cstr("")
+ result.should == ""
+ result.encoding.should == Encoding::US_ASCII
+ end
+
+ it "returns US_ASCII encoding for strings of only 7 bit ASCII" do
+ 0x01.upto(0x7f).each do |char|
+ result = @s.rb_interned_str_cstr(char.chr)
+ result.encoding.should == Encoding::US_ASCII
+ end
+ end
+
+ ruby_bug "21842", ""..."4.1" do
+ it "returns BINARY encoding for strings that use the 8th bit" do
+ 0x80.upto(0xff) do |char|
+ result = @s.rb_interned_str_cstr(char.chr)
+ result.encoding.should == Encoding::BINARY
+ end
+ end
+ end
+
+ it 'returns the same string when using non-ascii characters' do
+ str = 'こんにちは'
+ result1 = @s.rb_interned_str_cstr(str)
+ result2 = @s.rb_interned_str_cstr(str)
+ result1.should.equal?(result2)
+ end
+
+ ruby_bug "21842", ""..."4.1" do
+ it "returns the same string as String#-@" do
+ str = "hello".dup.force_encoding(Encoding::US_ASCII)
+ @s.rb_interned_str_cstr(str).should.equal?(-str)
+ end
+ end
+ end
end