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.rb314
1 files changed, 211 insertions, 103 deletions
diff --git a/spec/ruby/optional/capi/string_spec.rb b/spec/ruby/optional/capi/string_spec.rb
index 3c5b7fe4e0..a8edf998b5 100644
--- a/spec/ruby/optional/capi/string_spec.rb
+++ b/spec/ruby/optional/capi/string_spec.rb
@@ -1,4 +1,5 @@
# encoding: utf-8
+# frozen_string_literal: false
require_relative 'spec_helper'
require_relative '../../shared/string/times'
@@ -47,7 +48,7 @@ describe "C-API String function" do
[Encoding::BINARY, Encoding::UTF_8].each do |enc|
describe "rb_str_set_len on a #{enc.name} String" do
before :each do
- @str = "abcdefghij".force_encoding(enc)
+ @str = "abcdefghij".dup.force_encoding(enc)
# Make sure to unshare the string
@s.rb_str_modify(@str)
end
@@ -97,6 +98,32 @@ describe "C-API String function" do
end
end
+ describe "rb_str_set_len on a UTF-16 String" do
+ before :each do
+ @str = "abcdefghij".dup.force_encoding(Encoding::UTF_16BE)
+ # Make sure to unshare the string
+ @s.rb_str_modify(@str)
+ end
+
+ it "inserts two NULL bytes at the length" do
+ @s.rb_str_set_len(@str, 4).b.should == "abcd".b
+ @s.rb_str_set_len(@str, 8).b.should == "abcd\x00\x00gh".b
+ end
+ end
+
+ describe "rb_str_set_len on a UTF-32 String" do
+ before :each do
+ @str = "abcdefghijkl".dup.force_encoding(Encoding::UTF_32BE)
+ # Make sure to unshare the string
+ @s.rb_str_modify(@str)
+ end
+
+ it "inserts four NULL bytes at the length" do
+ @s.rb_str_set_len(@str, 4).b.should == "abcd".b
+ @s.rb_str_set_len(@str, 12).b.should == "abcd\x00\x00\x00\x00ijkl".b
+ end
+ end
+
describe "rb_str_buf_new" do
it "returns the equivalent of an empty string" do
buf = @s.rb_str_buf_new(10, nil)
@@ -108,7 +135,7 @@ describe "C-API String function" do
it "returns a string with the given capacity" do
buf = @s.rb_str_buf_new(256, nil)
- @s.rb_str_capacity(buf).should == 256
+ @s.rb_str_capacity(buf).should >= 256
end
it "returns a string that can be appended to" do
@@ -181,12 +208,6 @@ describe "C-API String function" do
@s.rb_str_new("hello", 3).should == "hel"
end
- ruby_version_is ''...'2.7' do
- it "returns a non-tainted string" do
- @s.rb_str_new("hello", 5).should_not.tainted?
- end
- end
-
it "returns an empty string if len is 0" do
@s.rb_str_new("hello", 0).should == ""
end
@@ -211,7 +232,7 @@ describe "C-API String function" do
describe "rb_usascii_str_new" do
it "creates a new String with US-ASCII Encoding from a char buffer of len characters" do
- str = "abc".force_encoding("us-ascii")
+ str = "abc".dup.force_encoding("us-ascii")
result = @s.rb_usascii_str_new("abcdef", 3)
result.should == str
result.encoding.should == Encoding::US_ASCII
@@ -227,14 +248,14 @@ describe "C-API String function" do
it "returns US-ASCII string for non-US-ASCII string literal" do
str = @s.rb_usascii_str_new_lit_non_ascii
- str.should == "r\xC3\xA9sum\xC3\xA9".force_encoding(Encoding::US_ASCII)
+ str.should == "r\xC3\xA9sum\xC3\xA9".dup.force_encoding(Encoding::US_ASCII)
str.encoding.should == Encoding::US_ASCII
end
end
describe "rb_usascii_str_new_cstr" do
it "creates a new String with US-ASCII Encoding" do
- str = "abc".force_encoding("us-ascii")
+ str = "abc".dup.force_encoding("us-ascii")
result = @s.rb_usascii_str_new_cstr("abc")
result.should == str
result.encoding.should == Encoding::US_ASCII
@@ -335,24 +356,6 @@ describe "C-API String function" do
end
end
- ruby_version_is ''...'2.7' do
- describe "rb_tainted_str_new" do
- it "creates a new tainted String" do
- newstring = @s.rb_tainted_str_new("test", 4)
- newstring.should == "test"
- newstring.tainted?.should be_true
- end
- end
-
- describe "rb_tainted_str_new2" do
- it "creates a new tainted String" do
- newstring = @s.rb_tainted_str_new2("test")
- newstring.should == "test"
- newstring.tainted?.should be_true
- end
- end
- end
-
describe "rb_str_append" do
it "appends a string to another string" do
@s.rb_str_append("Hello", " Goodbye").should == "Hello Goodbye"
@@ -378,6 +381,14 @@ describe "C-API String function" do
it_behaves_like :string_times, :rb_str_times, -> str, times { @s.rb_str_times(str, times) }
end
+ describe "rb_str_buf_append" do
+ it "concatenates a string to another string" do
+ str = "Your house "
+ @s.rb_str_buf_append(str, "is on fire?").should.equal?(str)
+ str.should == "Your house is on fire?"
+ end
+ end
+
describe "rb_str_buf_cat" do
it "concatenates a C string to a ruby string" do
@s.rb_str_buf_cat("Your house is on fire").should == "Your house is on fire?"
@@ -408,7 +419,7 @@ describe "C-API String function" do
describe "rb_enc_str_buf_cat" do
it "concatenates a C string literal to a ruby string with the given encoding" do
- input = "hello ".force_encoding(Encoding::US_ASCII)
+ input = "hello ".dup.force_encoding(Encoding::US_ASCII)
result = @s.rb_enc_str_buf_cat(input, "résumé", Encoding::UTF_8)
result.should == "hello résumé"
result.encoding.should == Encoding::UTF_8
@@ -488,29 +499,10 @@ describe "C-API String function" do
end
end
- describe "rb_fstring" do
- it 'returns self if the String is frozen' do
- input = 'foo'.freeze
- output = @s.rb_fstring(input)
-
- output.should equal(input)
- output.should.frozen?
- end
-
- it 'returns a frozen copy if the String is not frozen' do
- input = 'foo'
- output = @s.rb_fstring(input)
-
- output.should.frozen?
- output.should_not equal(input)
- output.should == 'foo'
- end
- end
-
describe "rb_str_subseq" do
it "returns a byte-indexed substring" do
- str = "\x00\x01\x02\x03\x04".force_encoding("binary")
- @s.rb_str_subseq(str, 1, 2).should == "\x01\x02".force_encoding("binary")
+ str = "\x00\x01\x02\x03\x04".dup.force_encoding("binary")
+ @s.rb_str_subseq(str, 1, 2).should == "\x01\x02".dup.force_encoding("binary")
end
end
@@ -603,9 +595,17 @@ describe "C-API String function" do
filename = fixture(__FILE__, "read.txt")
str = ""
capacities = @s.RSTRING_PTR_read(str, filename)
- capacities.should == [30, 53]
+ capacities[0].should >= 30
+ capacities[1].should >= 53
+ capacities[0].should < capacities[1]
str.should == "fixture file contents to test read() with RSTRING_PTR"
end
+
+ it "terminates the string with at least (encoding min length) \\0 bytes" do
+ @s.RSTRING_PTR_null_terminate("abc", 1).should == "\x00"
+ @s.RSTRING_PTR_null_terminate("abc".encode("UTF-16BE"), 2).should == "\x00\x00"
+ @s.RSTRING_PTR_null_terminate("abc".encode("UTF-32BE"), 4).should == "\x00\x00\x00\x00"
+ end
end
describe "RSTRING_LEN" do
@@ -655,22 +655,6 @@ describe "C-API String function" do
end
describe "SafeStringValue" do
- ruby_version_is ''...'2.7' do
- it "raises for tained string when $SAFE is 1" do
- begin
- Thread.new {
- $SAFE = 1
- -> {
- @s.SafeStringValue("str".taint)
- }.should raise_error(SecurityError)
- }.join
- ensure
- $SAFE = 0
- end
- end
-
- it_behaves_like :string_value_macro, :SafeStringValue
- end
end
describe "rb_str_modify" do
@@ -682,27 +666,27 @@ describe "C-API String function" do
describe "rb_str_modify_expand" do
it "grows the capacity to bytesize + expand, not changing the bytesize" do
str = @s.rb_str_buf_new(256, "abcd")
- @s.rb_str_capacity(str).should == 256
+ @s.rb_str_capacity(str).should >= 256
@s.rb_str_set_len(str, 3)
str.bytesize.should == 3
@s.RSTRING_LEN(str).should == 3
- @s.rb_str_capacity(str).should == 256
+ @s.rb_str_capacity(str).should >= 256
@s.rb_str_modify_expand(str, 4)
str.bytesize.should == 3
@s.RSTRING_LEN(str).should == 3
- @s.rb_str_capacity(str).should == 7
+ @s.rb_str_capacity(str).should >= 7
@s.rb_str_modify_expand(str, 1024)
str.bytesize.should == 3
@s.RSTRING_LEN(str).should == 3
- @s.rb_str_capacity(str).should == 1027
+ @s.rb_str_capacity(str).should >= 1027
@s.rb_str_modify_expand(str, 1)
str.bytesize.should == 3
@s.RSTRING_LEN(str).should == 3
- @s.rb_str_capacity(str).should == 4
+ @s.rb_str_capacity(str).should >= 4
end
it "raises an error if the string is frozen" do
@@ -729,7 +713,7 @@ describe "C-API String function" do
end
it "increases the size of the string" do
- expected = "test".force_encoding("US-ASCII")
+ expected = "test".dup.force_encoding("US-ASCII")
str = @s.rb_str_resize(expected.dup, 12)
str.size.should == 12
str.bytesize.should == 12
@@ -800,12 +784,6 @@ describe :rb_external_str_new, shared: true do
x80 = [0x80].pack('C')
@s.send(@method, "#{x80}abc").encoding.should == Encoding::BINARY
end
-
- ruby_version_is ''...'2.7' do
- it "returns a tainted String" do
- @s.send(@method, "abc").tainted?.should be_true
- end
- end
end
describe "C-API String function" do
@@ -866,11 +844,11 @@ describe "C-API String function" do
# it "transcodes a String to Encoding.default_internal if it is set" do
# Encoding.default_internal = Encoding::EUC_JP
#
-# - a = "\xE3\x81\x82\xe3\x82\x8c".force_encoding("utf-8")
+# - a = "\xE3\x81\x82\xe3\x82\x8c".dup.force_encoding("utf-8")
# + a = [0xE3, 0x81, 0x82, 0xe3, 0x82, 0x8c].pack('C6').force_encoding("utf-8")
# s = @s.rb_external_str_new_with_enc(a, a.bytesize, Encoding::UTF_8)
# -
-# - s.should == "\xA4\xA2\xA4\xEC".force_encoding("euc-jp")
+# - 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)
@@ -885,19 +863,12 @@ describe "C-API String function" do
s.should == x
s.encoding.should equal(Encoding::EUC_JP)
end
-
- ruby_version_is ''...'2.7' do
- it "returns a tainted String" do
- s = @s.rb_external_str_new_with_enc("abc", 3, Encoding::US_ASCII)
- s.tainted?.should be_true
- end
- end
end
describe "rb_locale_str_new" do
it "returns a String with 'locale' encoding" do
s = @s.rb_locale_str_new("abc", 3)
- s.should == "abc".force_encoding(Encoding.find("locale"))
+ s.should == "abc".dup.force_encoding(Encoding.find("locale"))
s.encoding.should equal(Encoding.find("locale"))
end
end
@@ -905,14 +876,14 @@ describe "C-API String function" do
describe "rb_locale_str_new_cstr" do
it "returns a String with 'locale' encoding" do
s = @s.rb_locale_str_new_cstr("abc")
- s.should == "abc".force_encoding(Encoding.find("locale"))
+ s.should == "abc".dup.force_encoding(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".force_encoding("us-ascii")
+ a = "abc".dup.force_encoding("us-ascii")
@s.rb_str_conv_enc(a, Encoding::US_ASCII, nil).should equal(a)
end
@@ -922,7 +893,7 @@ describe "C-API String function" do
end
it "returns a transcoded String" do
- a = "\xE3\x81\x82\xE3\x82\x8C".force_encoding("utf-8")
+ a = "\xE3\x81\x82\xE3\x82\x8C".dup.force_encoding("utf-8")
result = @s.rb_str_conv_enc(a, Encoding::UTF_8, Encoding::EUC_JP)
x = [0xA4, 0xA2, 0xA4, 0xEC].pack('C4').force_encoding('utf-8')
result.should == x.force_encoding("euc-jp")
@@ -931,7 +902,7 @@ 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".force_encoding("us-ascii")
+ a = "abc".dup.force_encoding("us-ascii")
@s.rb_str_conv_enc(a, Encoding::US_ASCII, Encoding::US_ASCII).should equal(a)
end
@@ -941,7 +912,7 @@ describe "C-API String function" do
end
it "returns the origin String if the destination encoding is BINARY" do
- a = "abc".force_encoding("binary")
+ a = "abc".dup.force_encoding("binary")
@s.rb_str_conv_enc(a, Encoding::US_ASCII, Encoding::BINARY).should equal(a)
end
end
@@ -949,7 +920,7 @@ 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".force_encoding("us-ascii")
+ a = "abc".dup.force_encoding("us-ascii")
@s.rb_str_conv_enc_opts(a, Encoding::US_ASCII, nil, 0, nil).should equal(a)
end
@@ -960,7 +931,7 @@ describe "C-API String function" do
end
it "returns a transcoded String" do
- a = "\xE3\x81\x82\xE3\x82\x8C".force_encoding("utf-8")
+ a = "\xE3\x81\x82\xE3\x82\x8C".dup.force_encoding("utf-8")
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")
@@ -969,7 +940,7 @@ 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".force_encoding("us-ascii")
+ 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)
end
@@ -981,7 +952,7 @@ describe "C-API String function" do
end
it "returns the origin String if the destination encoding is BINARY" do
- a = "abc".force_encoding("binary")
+ a = "abc".dup.force_encoding("binary")
@s.rb_str_conv_enc_opts(a, Encoding::US_ASCII,
Encoding::BINARY, 0, nil).should equal(a)
end
@@ -999,7 +970,7 @@ describe "C-API String function" do
describe "rb_str_export_locale" do
it "returns the original String with the locale encoding" do
s = @s.rb_str_export_locale("abc")
- s.should == "abc".force_encoding(Encoding.find("locale"))
+ s.should == "abc".dup.force_encoding(Encoding.find("locale"))
s.encoding.should equal(Encoding.find("locale"))
end
end
@@ -1051,9 +1022,56 @@ end
@s.rb_sprintf3(true.class).should == s
end
- it "formats a TrueClass VALUE as 'true' if sign specified in format" do
- s = 'Result: true.'
- @s.rb_sprintf4(true.class).should == s
+ 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
+ end
+
+ it "truncates a string to a supplied precision if that is shorter than the string" do
+ s = 'Result: Hel.'
+ @s.rb_sprintf5(0, 3, "Hello").should == s
+ end
+
+ it "does not truncates a string to a supplied precision if that is longer than the string" do
+ s = 'Result: Hello.'
+ @s.rb_sprintf5(0, 8, "Hello").should == s
+ end
+
+ it "pads a string to a supplied width if that is longer than the string" do
+ s = 'Result: Hello.'
+ @s.rb_sprintf5(8, 5, "Hello").should == s
+ end
+
+ it "truncates a VALUE string to a supplied precision if that is shorter than the VALUE string" do
+ s = 'Result: Hel.'
+ @s.rb_sprintf6(0, 3, "Hello").should == s
+ end
+
+ it "does not truncates a VALUE string to a supplied precision if that is longer than the VALUE string" do
+ s = 'Result: Hello.'
+ @s.rb_sprintf6(0, 8, "Hello").should == s
+ end
+
+ it "pads a VALUE string to a supplied width if that is longer than the VALUE string" do
+ s = 'Result: Hello.'
+ @s.rb_sprintf6(8, 5, "Hello").should == s
+ end
+
+ it "can format a nil VALUE as a pointer and gives the same output as sprintf in C" do
+ res = @s.rb_sprintf7("%p", nil);
+ res[0].should == res[1]
+ end
+
+ it "can format a string VALUE as a pointer and gives the same output as sprintf in C" do
+ res = @s.rb_sprintf7("%p", "Hello")
+ res[0].should == res[1]
+ end
+
+ it "can format a raw number a pointer and gives the same output as sprintf in C" do
+ res = @s.rb_sprintf7("%p", 0x223643);
+ res[0].should == res[1]
end
end
@@ -1164,4 +1182,94 @@ end
str.should == "test fmt 41 6 number"
end
end
+
+ describe "rb_str_locktmp" do
+ it "raises an error when trying to lock an already locked string" do
+ str = "test"
+ @s.rb_str_locktmp(str).should == str
+ -> { @s.rb_str_locktmp(str) }.should raise_error(RuntimeError, 'temporal locking already locked string')
+ end
+
+ it "locks a string so that modifications would raise an error" do
+ str = "test"
+ @s.rb_str_locktmp(str).should == str
+ -> { str.upcase! }.should raise_error(RuntimeError, 'can\'t modify string; temporarily locked')
+ end
+ end
+
+ describe "rb_str_unlocktmp" do
+ it "unlocks a locked string" do
+ 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')
+ end
+ end
+
+ describe "rb_enc_interned_str_cstr" do
+ it "returns a frozen string" do
+ str = "hello"
+ val = @s.rb_enc_interned_str_cstr(str, Encoding::US_ASCII)
+
+ val.should.is_a?(String)
+ val.encoding.should == Encoding::US_ASCII
+ val.should.frozen?
+ end
+
+ it "returns the same frozen string" do
+ str = "hello"
+ result1 = @s.rb_enc_interned_str_cstr(str, Encoding::US_ASCII)
+ result2 = @s.rb_enc_interned_str_cstr(str, Encoding::US_ASCII)
+ result1.should.equal?(result2)
+ end
+
+ it "returns different frozen strings for different encodings" do
+ str = "hello"
+ result1 = @s.rb_enc_interned_str_cstr(str, Encoding::US_ASCII)
+ result2 = @s.rb_enc_interned_str_cstr(str, Encoding::UTF_8)
+ result1.should_not.equal?(result2)
+ end
+
+ it "returns the same string as String#-@" do
+ @s.rb_enc_interned_str_cstr("hello", Encoding::UTF_8).should.equal?(-"hello")
+ end
+
+ ruby_bug "#20322", ""..."3.4" do
+ it "uses the default encoding if encoding is null" do
+ str = "hello"
+ val = @s.rb_enc_interned_str_cstr(str, nil)
+ val.encoding.should == Encoding::ASCII_8BIT
+ end
+ end
+ end
+
+ describe "rb_str_to_interned_str" do
+ it "returns a frozen string" do
+ str = "hello"
+ result = @s.rb_str_to_interned_str(str)
+ result.should.is_a?(String)
+ result.should.frozen?
+ end
+
+ it "returns the same frozen string" do
+ str = "hello"
+ result1 = @s.rb_str_to_interned_str(str)
+ result2 = @s.rb_str_to_interned_str(str)
+ result1.should.equal?(result2)
+ end
+
+ it "returns different frozen strings for different encodings" 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.should_not.equal?(result2)
+ end
+
+ it "returns the same string as String#-@" do
+ @s.rb_str_to_interned_str("hello").should.equal?(-"hello")
+ end
+ end
end