summaryrefslogtreecommitdiff
path: root/test/-ext-/string
diff options
context:
space:
mode:
Diffstat (limited to 'test/-ext-/string')
-rw-r--r--test/-ext-/string/test_capacity.rb75
-rw-r--r--test/-ext-/string/test_coderange.rb60
-rw-r--r--test/-ext-/string/test_cstr.rb168
-rw-r--r--test/-ext-/string/test_ellipsize.rb47
-rw-r--r--test/-ext-/string/test_enc_associate.rb24
-rw-r--r--test/-ext-/string/test_enc_str_buf_cat.rb25
-rw-r--r--test/-ext-/string/test_external_new.rb17
-rw-r--r--test/-ext-/string/test_fstring.rb72
-rw-r--r--test/-ext-/string/test_interned_str.rb17
-rw-r--r--test/-ext-/string/test_modify_expand.rb26
-rw-r--r--test/-ext-/string/test_nofree.rb13
-rw-r--r--test/-ext-/string/test_normalize.rb110
-rw-r--r--test/-ext-/string/test_qsort.rb20
-rw-r--r--test/-ext-/string/test_rb_str_dup.rb18
-rw-r--r--test/-ext-/string/test_set_len.rb84
-rw-r--r--test/-ext-/string/test_too_many_dummy_encodings.rb15
16 files changed, 791 insertions, 0 deletions
diff --git a/test/-ext-/string/test_capacity.rb b/test/-ext-/string/test_capacity.rb
new file mode 100644
index 0000000000..df000f7cdb
--- /dev/null
+++ b/test/-ext-/string/test_capacity.rb
@@ -0,0 +1,75 @@
+# frozen_string_literal: true
+require 'test/unit'
+require '-test-/string'
+require 'rbconfig/sizeof'
+
+class Test_StringCapacity < Test::Unit::TestCase
+ def test_capacity_embedded
+ assert_equal GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE] - embed_header_size - 1, capa('foo')
+ assert_equal max_embed_len, capa('1' * max_embed_len)
+ assert_equal max_embed_len, capa('1' * (max_embed_len - 1))
+ end
+
+ def test_capacity_shared
+ sym = ("a" * GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE]).to_sym
+ assert_equal 0, capa(sym.to_s)
+ end
+
+ def test_capacity_normal
+ assert_equal max_embed_len + 1, capa('1' * (max_embed_len + 1))
+ assert_equal max_embed_len + 100, capa('1' * (max_embed_len + 100))
+ end
+
+ def test_s_new_capacity
+ assert_equal("", String.new(capacity: 1000))
+ assert_equal(String, String.new(capacity: 1000).class)
+ assert_equal(10_000, capa(String.new(capacity: 10_000)))
+
+ assert_equal("", String.new(capacity: -1000))
+ assert_equal(capa(String.new(capacity: -10000)), capa(String.new(capacity: -1000)))
+ end
+
+ def test_io_read
+ s = String.new(capacity: 1000)
+ open(__FILE__) {|f|f.read(1024*1024, s)}
+ assert_equal(1024*1024, capa(s))
+ open(__FILE__) {|f|s = f.read(1024*1024)}
+ assert_operator(capa(s), :<=, s.bytesize+4096)
+ end
+
+ def test_literal_capacity
+ s = eval(%{
+ # frozen_string_literal: true
+ "#{"a" * (max_embed_len + 1)}"
+ })
+ assert_equal(s.length, capa(s))
+ end
+
+ def test_capacity_frozen
+ s = String.new("I am testing", capacity: 1000)
+ s << "a" * GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE]
+ s.freeze
+ assert_equal(s.length, capa(s))
+ end
+
+ def test_capacity_fstring
+ s = String.new("a" * max_embed_len, capacity: max_embed_len * 3)
+ s << "fstring capacity"
+ s = -s
+ assert_equal(s.length, capa(s))
+ end
+
+ private
+
+ def capa(str)
+ Bug::String.capacity(str)
+ end
+
+ def embed_header_size
+ GC::INTERNAL_CONSTANTS[:RBASIC_SIZE] + RbConfig::SIZEOF['void*']
+ end
+
+ def max_embed_len
+ GC::INTERNAL_CONSTANTS[:RVARGC_MAX_ALLOCATE_SIZE] - embed_header_size - 1
+ end
+end
diff --git a/test/-ext-/string/test_coderange.rb b/test/-ext-/string/test_coderange.rb
new file mode 100644
index 0000000000..18b256fcea
--- /dev/null
+++ b/test/-ext-/string/test_coderange.rb
@@ -0,0 +1,60 @@
+# coding: ascii-8bit
+# frozen_string_literal: false
+require 'test/unit'
+require "-test-/string"
+require "rbconfig/sizeof"
+
+class Test_StringCoderange < Test::Unit::TestCase
+ def setup
+ @sizeof_voidp = RbConfig::SIZEOF["void*"]
+ @a8 = Encoding::ASCII_8BIT
+ @a7 = Encoding::US_ASCII
+ @u8 = Encoding::UTF_8
+ end
+
+ def test_ascii8bit
+ enc = @a8
+ str = "a"
+ str.force_encoding(enc)
+ assert_equal :"7bit", Bug::String.new(str).coderange_scan
+
+ str = "a\xBE".force_encoding(enc)
+ assert_equal :valid, Bug::String.new(str).coderange_scan
+ end
+
+ def test_usascii
+ enc = @a7
+ str = "a"
+ str.force_encoding(enc)
+ assert_equal :"7bit", Bug::String.new(str).coderange_scan
+
+ str = "a" * (@sizeof_voidp * 2)
+ str << "\xBE"
+ str.force_encoding(enc)
+ assert_equal :broken, Bug::String.new(str).coderange_scan
+ end
+
+ def test_utf8
+ enc = @u8
+ str = "a"
+ str.force_encoding(enc)
+ assert_equal :"7bit", Bug::String.new(str).coderange_scan
+
+ str = "a" * (@sizeof_voidp * 3)
+ str << "aa\xC2\x80"
+ str.force_encoding(enc)
+ assert_equal :valid, Bug::String.new(str).coderange_scan
+
+ str = "a" * (@sizeof_voidp * 2)
+ str << "\xC2\x80"
+ str << "a" * (@sizeof_voidp * 2)
+ str.force_encoding(enc)
+ assert_equal :valid, Bug::String.new(str).coderange_scan
+
+ str = "a" * (@sizeof_voidp * 2)
+ str << "\xC1\x80"
+ str << "a" * (@sizeof_voidp * 2)
+ str.force_encoding(enc)
+ assert_equal :broken, Bug::String.new(str).coderange_scan
+ end
+end
diff --git a/test/-ext-/string/test_cstr.rb b/test/-ext-/string/test_cstr.rb
new file mode 100644
index 0000000000..efc64119dc
--- /dev/null
+++ b/test/-ext-/string/test_cstr.rb
@@ -0,0 +1,168 @@
+# frozen_string_literal: false
+require 'test/unit'
+require "-test-/string"
+
+class Test_StringCStr < Test::Unit::TestCase
+ Bug4319 = '[ruby-dev:43094]'
+
+ def test_embed
+ s = Bug::String.new("abcdef")
+ s.set_len(3)
+ s.cstr_unterm('x')
+ assert_equal(0, s.cstr_term, Bug4319)
+ end
+
+ def test_long
+ s = Bug::String.new(Bug::String.new("abcdef")*100000)
+ s.cstr_unterm('x')
+ assert_equal(0, s.cstr_term, Bug4319)
+ end
+
+ def test_shared
+ s = Bug::String.new(Bug::String.new("abcdef")*5)
+ s = s.unterminated_substring(0, 29)
+ assert_equal(0, s.cstr_term, Bug4319)
+ end
+
+ def test_frozen
+ s0 = Bug::String.new("abcdefgh"*8)
+
+ [4, 4*3-1, 8*3-1, 64].each do |n|
+ s = Bug::String.new(s0[0, n])
+ s.cstr_unterm('x')
+ s.freeze
+ assert_equal(0, s.cstr_term)
+ WCHARS.each do |enc|
+ s = s0.encode(enc)
+ s.set_len(n - n % s[0].bytesize)
+ s.cstr_unterm('x')
+ s.freeze
+ assert_equal(0, s.cstr_term)
+ end
+ end
+ end
+
+ def test_rb_str_new_frozen_embed
+ # "rbconfi" is the smallest "maximum embeddable string". VWA adds
+ # a capacity field, which removes one pointer capacity for embedded objects,
+ # so if VWA is enabled, but there is only one size pool, then the
+ # maximum embeddable capacity on 32 bit machines is 8 bytes.
+ str = Bug::String.cstr_noembed("rbconfi")
+ str = Bug::String.rb_str_new_frozen(str)
+ assert_equal true, Bug::String.cstr_embedded?(str)
+ end
+
+ WCHARS = [Encoding::UTF_16BE, Encoding::UTF_16LE, Encoding::UTF_32BE, Encoding::UTF_32LE]
+
+ def test_wchar_embed
+ WCHARS.each do |enc|
+ s = Bug::String.new("\u{4022}a".encode(enc))
+ s.cstr_unterm('x')
+ assert_nothing_raised(ArgumentError) {s.cstr_term}
+ s.set_len(s.bytesize / 2)
+ assert_equal(1, s.size)
+ s.cstr_unterm('x')
+ assert_equal(0, s.cstr_term)
+ end
+ end
+
+ def test_wchar_long
+ str = "\u{4022}abcdef"
+ n = 100
+ len = str.size * n
+ WCHARS.each do |enc|
+ s = Bug::String.new(Bug::String.new(str.encode(enc))*n)
+ s.cstr_unterm('x')
+ assert_nothing_raised(ArgumentError, enc.name) {s.cstr_term}
+ s.set_len(s.bytesize / 2)
+ assert_equal(len / 2, s.size, enc.name)
+ s.cstr_unterm('x')
+ assert_equal(0, s.cstr_term, enc.name)
+ end
+ end
+
+ def test_wchar_lstrip!
+ assert_wchars_term_char(" a") {|s| s.lstrip!}
+ end
+
+ def test_wchar_rstrip!
+ assert_wchars_term_char("a ") {|s| s.rstrip!}
+ end
+
+ def test_wchar_chop!
+ assert_wchars_term_char("a\n") {|s| s.chop!}
+ end
+
+ def test_wchar_chomp!
+ assert_wchars_term_char("a\n") {|s| s.chomp!}
+ end
+
+ def test_wchar_aset
+ assert_wchars_term_char("a"*30) {|s| s[29,1] = ""}
+ end
+
+ def test_wchar_sub!
+ assert_wchars_term_char("foobar") {|s| s.sub!(/#{"foo".encode(s.encoding)}/, "")}
+ end
+
+ def test_wchar_delete!
+ assert_wchars_term_char("foobar") {|s| s.delete!("ao".encode(s.encoding))}
+ end
+
+ def test_wchar_squeeze!
+ assert_wchars_term_char("foo!") {|s| s.squeeze!}
+ end
+
+ def test_wchar_tr!
+ assert_wchars_term_char("\u{3042}foobar") {|s|
+ enc = s.encoding
+ s.tr!("\u{3042}".encode(enc), "c".encode(enc))
+ }
+ end
+
+ def test_wchar_tr_s!
+ assert_wchars_term_char("\u{3042}foobar") {|s|
+ enc = s.encoding
+ s.tr_s!("\u{3042}".encode(enc), "c".encode(enc))
+ }
+ end
+
+ def test_wchar_replace
+ assert_wchars_term_char("abc") {|s|
+ w = s.dup
+ s.replace("abcdefghijklmnop")
+ s.replace(w)
+ }
+ end
+
+ def test_embedded_from_heap
+ gh821 = "[GH-821]"
+ embedded_string = "abcdefghi"
+ string = embedded_string.gsub("efg", "123")
+ {}[string] = 1
+ non_terminated = "#{string}#{nil}"
+ assert_nil(Bug::String.cstr_term_char(non_terminated), gh821)
+
+ result = {}
+ WCHARS.map do |enc|
+ embedded_string = "ab".encode(enc)
+ string = embedded_string.gsub("b".encode(enc), "1".encode(enc))
+ {}[string] = 1
+ non_terminated = "#{string}#{nil}"
+ c = Bug::String.cstr_term_char(non_terminated)
+ result[enc] = c if c
+ end
+ assert_empty(result, gh821)
+ end
+
+ def assert_wchars_term_char(str)
+ result = {}
+ WCHARS.map do |enc|
+ s = Bug::String.new(str.encode(enc))
+ yield s
+ c = s.cstr_term_char
+ result[enc] = c if c
+ end
+ assert_empty(result)
+ end
+end
diff --git a/test/-ext-/string/test_ellipsize.rb b/test/-ext-/string/test_ellipsize.rb
new file mode 100644
index 0000000000..d340abd58a
--- /dev/null
+++ b/test/-ext-/string/test_ellipsize.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: false
+require 'test/unit'
+require "-test-/string"
+
+class Test_StringEllipsize < Test::Unit::TestCase
+ def setup
+ @foobar = Bug::String.new("foobar")
+ end
+
+ def assert_equal_with_class(expected, result, *rest)
+ assert_equal(expected.encoding, result.encoding, *rest)
+ assert_equal(expected, result, result.encoding.name)
+ assert_instance_of(String, result, *rest)
+ end
+
+ def test_longer
+ assert_equal_with_class("", @foobar.ellipsize(0))
+ assert_equal_with_class(".", @foobar.ellipsize(1))
+ assert_equal_with_class("..", @foobar.ellipsize(2))
+ assert_equal_with_class("...", @foobar.ellipsize(3))
+ assert_equal_with_class("f...", @foobar.ellipsize(4))
+ assert_equal_with_class("fo...", @foobar.ellipsize(5))
+ end
+
+ def test_shorter
+ assert_same(@foobar, @foobar.ellipsize(6))
+ assert_same(@foobar, @foobar.ellipsize(7))
+ end
+
+ def test_negative_length
+ assert_raise(IndexError) {@foobar.ellipsize(-1)}
+ end
+
+ def test_nonascii
+ a = "\u3042"
+ Encoding.list.each do |enc|
+ next if enc.dummy?
+ begin
+ s = a.encode(enc)
+ e = "...".encode(enc)
+ rescue
+ else
+ assert_equal_with_class(s*12+e, Bug::String.new(s*20).ellipsize(15))
+ end
+ end
+ end
+end
diff --git a/test/-ext-/string/test_enc_associate.rb b/test/-ext-/string/test_enc_associate.rb
new file mode 100644
index 0000000000..95d1f00cd2
--- /dev/null
+++ b/test/-ext-/string/test_enc_associate.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: false
+require 'test/unit'
+require "-test-/string"
+
+class Test_StrEncAssociate < Test::Unit::TestCase
+ def test_frozen
+ s = Bug::String.new("abc")
+ s.force_encoding(Encoding::US_ASCII)
+ s.freeze
+ assert_raise(FrozenError) {s.associate_encoding!(Encoding::US_ASCII)}
+ assert_raise(FrozenError) {s.associate_encoding!(Encoding::UTF_8)}
+ end
+
+ Encoding.list.select(&:dummy?).each do |enc|
+ enc = enc.name.tr('-', '_')
+ define_method("test_dummy_encoding_index_#{enc}") do
+ assert_separately(["-r-test-/string", "-", enc], <<-"end;") #do
+ enc = Encoding.const_get(ARGV[0])
+ index = Bug::String.encoding_index(enc)
+ assert(index < 0xffff, "<%#x> expected but was\n<%#x>" % [index & 0xffff, index])
+ end;
+ end
+ end
+end
diff --git a/test/-ext-/string/test_enc_str_buf_cat.rb b/test/-ext-/string/test_enc_str_buf_cat.rb
new file mode 100644
index 0000000000..b9a63ec2de
--- /dev/null
+++ b/test/-ext-/string/test_enc_str_buf_cat.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: false
+require 'test/unit'
+require "-test-/string"
+
+class Test_StringEncStrBufCat < Test::Unit::TestCase
+ Bug6509 = '[ruby-dev:45688]'
+
+ def test_unknown
+ a8_str = "a\xBE".force_encoding(Encoding::ASCII_8BIT)
+ cr_unknown_str = [0x62].pack('C*')
+ assert_equal(true, a8_str.valid_encoding?, "an assertion for following tests")
+ assert_equal(:valid, Bug::String.new(a8_str).coderange, "an assertion for following tests")
+ assert_equal(:unknown, Bug::String.new(cr_unknown_str).coderange, "an assertion for following tests")
+ assert_equal(:valid, Bug::String.new(a8_str).enc_str_buf_cat(cr_unknown_str).coderange, Bug6509)
+ end
+
+ def test_str_conv_enc
+ str = Bug::String.new("aaa".encode("US-ASCII"))
+ assert_same(str, str.str_conv_enc_opts("UTF-8", "US-ASCII", 0, nil))
+
+ str = Bug::String.new("aaa".encode("UTF-16LE").force_encoding("UTF-8"))
+ assert_predicate(str, :ascii_only?) # cache coderange
+ assert_equal("aaa", str.str_conv_enc_opts("UTF-16LE", "UTF-8", 0, nil))
+ end
+end
diff --git a/test/-ext-/string/test_external_new.rb b/test/-ext-/string/test_external_new.rb
new file mode 100644
index 0000000000..f8ee773b16
--- /dev/null
+++ b/test/-ext-/string/test_external_new.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: false
+require 'test/unit'
+require '-test-/string'
+
+class Test_StringExternalNew < Test::Unit::TestCase
+ def test_buf_new
+ assert_operator(0, :<=, Bug::String.capacity(Bug::String.buf_new(0)))
+ assert_operator(127, :<=, Bug::String.capacity(Bug::String.buf_new(127)))
+ assert_operator(128, :<=, Bug::String.capacity(Bug::String.buf_new(128)))
+ end
+
+ def test_external_new_with_enc
+ Encoding.list.each do |enc|
+ assert_equal(enc, Bug::String.external_new(0, enc).encoding)
+ end
+ end
+end
diff --git a/test/-ext-/string/test_fstring.rb b/test/-ext-/string/test_fstring.rb
new file mode 100644
index 0000000000..fcec6be543
--- /dev/null
+++ b/test/-ext-/string/test_fstring.rb
@@ -0,0 +1,72 @@
+# frozen_string_literal: false
+require 'test/unit'
+require '-test-/string'
+require_relative '../symbol/noninterned_name'
+
+class Test_String_Fstring < Test::Unit::TestCase
+ include Test_Symbol::NonInterned
+
+ def assert_fstring(str)
+ fstr = Bug::String.fstring(str)
+ yield str
+ yield fstr
+ end
+
+ def test_rb_enc_interned_str_autoloaded_encoding
+ assert_separately([], <<~RUBY)
+ require '-test-/string'
+ assert_include(Encoding::CESU_8.inspect, 'autoload')
+ Bug::String.rb_enc_interned_str(Encoding::CESU_8)
+ RUBY
+ end
+
+ def test_rb_enc_interned_str_null_encoding
+ assert_equal Encoding::ASCII_8BIT, Bug::String.rb_enc_interned_str(nil).encoding
+ end
+
+ def test_rb_enc_str_new_autoloaded_encoding
+ assert_separately([], <<~RUBY)
+ require '-test-/string'
+ assert_include(Encoding::CESU_8.inspect, 'autoload')
+ Bug::String.rb_enc_str_new(Encoding::CESU_8)
+ RUBY
+ end
+
+ def test_rb_enc_str_new_null_encoding
+ assert_equal Encoding::ASCII_8BIT, Bug::String.rb_enc_str_new(nil).encoding
+ end
+
+ def test_instance_variable
+ str = __method__.to_s * 3
+ str.instance_variable_set(:@test, 42)
+ str.freeze
+ assert_fstring(str) {|s| assert_send([s, :instance_variable_defined?, :@test])}
+ end
+
+ def test_singleton_method
+ str = __method__.to_s * 3
+ def str.foo
+ end
+ str.freeze
+ assert_fstring(str) {|s| assert_send([s, :respond_to?, :foo])}
+ end
+
+ def test_singleton_class
+ str = noninterned_name
+ fstr = Bug::String.fstring(str)
+ assert_raise(TypeError) {fstr.singleton_class}
+ end
+
+ def test_fake_str
+ assert_equal([*"a".."z"].join(""), Bug::String.fstring_fake_str)
+ end
+
+ class S < String
+ end
+
+ def test_subclass
+ str = S.new(__method__.to_s * 3)
+ str.freeze
+ assert_fstring(str) {|s| assert_instance_of(S, s)}
+ end
+end
diff --git a/test/-ext-/string/test_interned_str.rb b/test/-ext-/string/test_interned_str.rb
new file mode 100644
index 0000000000..a81cb59aa5
--- /dev/null
+++ b/test/-ext-/string/test_interned_str.rb
@@ -0,0 +1,17 @@
+require 'test/unit'
+require '-test-/string'
+
+class Test_RbInternedStr < Test::Unit::TestCase
+ def test_interned_str
+ src = "a" * 20
+ interned_str = Bug::String.rb_interned_str_dup(src)
+ src.clear
+ src << "b" * 20
+ assert_equal "a" * 20, interned_str
+ end
+
+ def test_interned_str_encoding
+ src = :ascii.name
+ assert_equal Encoding::US_ASCII, Bug::String.rb_interned_str_dup(src).encoding
+ end
+end
diff --git a/test/-ext-/string/test_modify_expand.rb b/test/-ext-/string/test_modify_expand.rb
new file mode 100644
index 0000000000..9aa3b9a6ca
--- /dev/null
+++ b/test/-ext-/string/test_modify_expand.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: false
+require 'test/unit'
+require "-test-/string"
+require "rbconfig/sizeof"
+
+class Test_StringModifyExpand < Test::Unit::TestCase
+ def test_modify_expand_memory_leak
+ assert_no_memory_leak(["-r-test-/string"],
+ <<-PRE, <<-CMD, "rb_str_modify_expand()", limit: 2.5)
+ s=Bug::String.new
+ PRE
+ size = $initial_size
+ 10.times{s.modify_expand!(size)}
+ s.replace("")
+ CMD
+ end
+
+ def test_integer_overflow
+ return if RbConfig::SIZEOF['size_t'] > RbConfig::SIZEOF['long']
+ bug12390 = '[ruby-core:75592] [Bug #12390]'
+ s = Bug::String.new
+ assert_raise(ArgumentError, bug12390) {
+ s.modify_expand!(RbConfig::LIMITS["LONG_MAX"])
+ }
+ end
+end
diff --git a/test/-ext-/string/test_nofree.rb b/test/-ext-/string/test_nofree.rb
new file mode 100644
index 0000000000..86681e4652
--- /dev/null
+++ b/test/-ext-/string/test_nofree.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: false
+require 'test/unit'
+
+class Test_StringNoFree < Test::Unit::TestCase
+ def test_no_memory_leak
+ bug10942 = '[ruby-core:68436] [Bug #10942] no leak on nofree string'
+ code = '.times {Bug::String.nofree << "a" * 100}'
+ assert_no_memory_leak(%w(-r-test-/string),
+ "100_000#{code}",
+ "1_000_000#{code}",
+ bug10942, rss: true)
+ end
+end
diff --git a/test/-ext-/string/test_normalize.rb b/test/-ext-/string/test_normalize.rb
new file mode 100644
index 0000000000..80b21dff38
--- /dev/null
+++ b/test/-ext-/string/test_normalize.rb
@@ -0,0 +1,110 @@
+# frozen_string_literal: false
+require 'test/unit'
+require "-test-/string"
+require "tempfile"
+
+class Test_StringNormalize < Test::Unit::TestCase
+=begin
+ def test_normalize_all
+ exclude = [
+ #0x340, 0x341, 0x343, 0x344
+ ]
+ (0x0080..0xFFFD).each do |n|
+ next if 0xD800 <= n && n <= 0xDFFF
+ next if exclude.include? n
+ code = n.to_s(16)
+ Tempfile.create("#{code}-#{n.chr(Encoding::UTF_8)}-") do |tempfile|
+ ary = Dir.glob(File.expand_path("../#{code}-*", tempfile.path))
+ assert_equal 1, ary.size
+ result = ary[0]
+ rn = result[/\/\h+-(.+?)-/, 1]
+ #assert_equal tempfile.path, result, "#{rn.dump} is not U+#{n.to_s(16)}"
+ r2 = Bug::String.new(result ).normalize_ospath
+ rn2 = r2[/\/\h+-(.+?)-/, 1]
+ if tempfile.path == result
+ if tempfile.path == r2
+ else
+ puts "U+#{n.to_s(16)} shouldn't be r2#{rn2.dump}"
+ end
+ else
+ if tempfile.path == r2
+ # puts "U+#{n.to_s(16)} shouldn't be r#{rn.dump}"
+ elsif result == r2
+ puts "U+#{n.to_s(16)} shouldn't be #{rn.dump}"
+ else
+ puts "U+#{n.to_s(16)} shouldn't be r#{rn.dump} r2#{rn2.dump}"
+ end
+ end
+ end
+ end
+ end
+=end
+
+ def test_normalize
+ %[
+ \u304C \u304B\u3099
+ \u3077 \u3075\u309A
+ \u308F\u3099 \u308F\u3099
+ \u30F4 \u30A6\u3099
+ \u30DD \u30DB\u309A
+ \u30AB\u303A \u30AB\u303A
+ \u00C1 A\u0301
+ B\u030A B\u030A
+ \u0386 \u0391\u0301
+ \u03D3 \u03D2\u0301
+ \u0401 \u0415\u0308
+ \u2260 =\u0338
+ \u{c548} \u{110b}\u{1161}\u{11ab}
+ ].scan(/(\S+)\s+(\S+)/) do |expected, src|
+ result = Bug::String.new(src).normalize_ospath
+ assert_equal expected, result,
+ "#{expected.dump} is expected but #{src.dump}"
+ end
+ end
+
+ def test_not_normalize_kc
+ %W[
+ \u2460
+ \u2162
+ \u3349
+ \u33A1
+ \u337B
+ \u2116
+ \u33CD
+ \u2121
+ \u32A4
+ \u3231
+ ].each do |src|
+ result = Bug::String.new(src).normalize_ospath
+ assert_equal src, result,
+ "#{src.dump} is expected not to be normalized, but #{result.dump}"
+ end
+ end
+
+ def test_dont_normalize_hfsplus
+ %W[
+ \u2190\u0338
+ \u219A
+ \u212B
+ \uF90A
+ \uF9F4
+ \uF961 \uF9DB
+ \uF96F \uF3AA
+ \uF915 \uF95C \uF9BF
+ \uFA0C
+ \uFA10
+ \uFA19
+ \uFA26
+ ].each do |src|
+ result = Bug::String.new(src).normalize_ospath
+ assert_equal src, result,
+ "#{src.dump} is expected not to be normalized, but #{result.dump}"
+ end
+ end
+
+ def test_invalid_sequence
+ assert_separately(%w[-r-test-/string], <<-'end;')
+ assert_equal("\u{fffd}", Bug::String.new("\xff").normalize_ospath)
+ end;
+ end
+end if Bug::String.method_defined?(:normalize_ospath)
diff --git a/test/-ext-/string/test_qsort.rb b/test/-ext-/string/test_qsort.rb
new file mode 100644
index 0000000000..94aff8c3c4
--- /dev/null
+++ b/test/-ext-/string/test_qsort.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: false
+require 'test/unit'
+require "-test-/string"
+
+class Test_StringQSort < Test::Unit::TestCase
+ def test_qsort
+ s = Bug::String.new("xxozfxx")
+ s.qsort!
+ assert_equal("foxxxxz", s)
+ end
+
+ def test_qsort_slice
+ s = Bug::String.new("xxofzx1")
+ s.qsort!(nil, nil, 3)
+ assert_equal("fzxxxo1", s)
+ s = Bug::String.new("xxofzx231")
+ s.qsort!(nil, nil, 3)
+ assert_equal("231fzxxxo", s)
+ end
+end
diff --git a/test/-ext-/string/test_rb_str_dup.rb b/test/-ext-/string/test_rb_str_dup.rb
new file mode 100644
index 0000000000..c76a90252f
--- /dev/null
+++ b/test/-ext-/string/test_rb_str_dup.rb
@@ -0,0 +1,18 @@
+require 'test/unit'
+require '-test-/string'
+
+class Test_RbStrDup < Test::Unit::TestCase
+ def test_nested_shared_non_frozen
+ orig_str = "a" * GC::INTERNAL_CONSTANTS[:RVARGC_MAX_ALLOCATE_SIZE]
+ str = Bug::String.rb_str_dup(Bug::String.rb_str_dup(orig_str))
+ assert_send([Bug::String, :shared_string?, str])
+ assert_not_send([Bug::String, :sharing_with_shared?, str], '[Bug #15792]')
+ end
+
+ def test_nested_shared_frozen
+ orig_str = "a" * GC::INTERNAL_CONSTANTS[:RVARGC_MAX_ALLOCATE_SIZE]
+ str = Bug::String.rb_str_dup(Bug::String.rb_str_dup(orig_str).freeze)
+ assert_send([Bug::String, :shared_string?, str])
+ assert_not_send([Bug::String, :sharing_with_shared?, str], '[Bug #15792]')
+ end
+end
diff --git a/test/-ext-/string/test_set_len.rb b/test/-ext-/string/test_set_len.rb
new file mode 100644
index 0000000000..1531d76167
--- /dev/null
+++ b/test/-ext-/string/test_set_len.rb
@@ -0,0 +1,84 @@
+# frozen_string_literal: false
+require 'test/unit'
+require "-test-/string"
+
+class Test_StrSetLen < Test::Unit::TestCase
+ def setup
+ # Make string long enough so that it is not embedded
+ @range_end = ("0".ord + GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE]).chr
+ @s0 = [*"0"..@range_end].join("").freeze
+ @s1 = Bug::String.new(@s0)
+ end
+
+ def teardown
+ orig = [*"0"..@range_end].join("")
+ assert_equal(orig, @s0)
+ end
+
+ def test_non_shared
+ @s1.modify!
+ assert_equal("012", @s1.set_len(3))
+ end
+
+ def test_shared
+ assert_raise(RuntimeError) {
+ @s1.set_len(3)
+ }
+ end
+
+ def test_capacity_equals_to_new_size
+ bug12757 = "[ruby-core:77257] [Bug #12757]"
+ # fill to ensure capacity does not decrease with force_encoding
+ str = Bug::String.new("\x00" * 128, capacity: 128)
+ str.force_encoding("UTF-32BE")
+ assert_equal 128, Bug::String.capacity(str)
+ assert_equal 127, str.set_len(127).bytesize, bug12757
+ end
+
+ def test_coderange_after_append
+ u = -"\u3042"
+ str = Bug::String.new(encoding: Encoding::UTF_8)
+ bsize = u.bytesize
+ str.append(u)
+ assert_equal 0, str.bytesize
+ str.set_len(bsize)
+ assert_equal bsize, str.bytesize
+ assert_predicate str, :valid_encoding?
+ assert_not_predicate str, :ascii_only?
+ assert_equal u, str
+ end
+
+ def test_coderange_after_trunc
+ u = -"\u3042"
+ bsize = u.bytesize
+ str = Bug::String.new(u)
+ str.set_len(bsize - 1)
+ assert_equal bsize - 1, str.bytesize
+ assert_not_predicate str, :valid_encoding?
+ assert_not_predicate str, :ascii_only?
+ str.append(u.byteslice(-1))
+ str.set_len(bsize)
+ assert_equal bsize, str.bytesize
+ assert_predicate str, :valid_encoding?
+ assert_not_predicate str, :ascii_only?
+ assert_equal u, str
+ end
+
+ def test_valid_encoding_after_resized
+ s = "\0\0".force_encoding(Encoding::UTF_16BE)
+ str = Bug::String.new(s)
+ assert_predicate str, :valid_encoding?
+ str.resize(1)
+ assert_not_predicate str, :valid_encoding?
+ str.resize(2)
+ assert_predicate str, :valid_encoding?
+ str.resize(3)
+ assert_not_predicate str, :valid_encoding?
+
+ s = "\xDB\x00\xDC\x00".force_encoding(Encoding::UTF_16BE)
+ str = Bug::String.new(s)
+ assert_predicate str, :valid_encoding?
+ str.resize(2)
+ assert_not_predicate str, :valid_encoding?
+ end
+end
diff --git a/test/-ext-/string/test_too_many_dummy_encodings.rb b/test/-ext-/string/test_too_many_dummy_encodings.rb
new file mode 100644
index 0000000000..b96b40db7b
--- /dev/null
+++ b/test/-ext-/string/test_too_many_dummy_encodings.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: false
+require 'test/unit'
+require "-test-/string"
+
+class Test_TooManyDummyEncodings < Test::Unit::TestCase
+ def test_exceed_encoding_table_size
+ assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
+ begin;
+ require "-test-/string"
+ assert_raise_with_message(EncodingError, /too many encoding/) do
+ 1_000.times{|i| Bug::String.rb_define_dummy_encoding("R_#{i}") } # now 256 entries
+ end
+ end;
+ end
+end