summaryrefslogtreecommitdiff
path: root/spec/ruby/core/string
diff options
context:
space:
mode:
Diffstat (limited to 'spec/ruby/core/string')
-rw-r--r--spec/ruby/core/string/allocate_spec.rb4
-rw-r--r--spec/ruby/core/string/append_as_bytes_spec.rb58
-rw-r--r--spec/ruby/core/string/append_spec.rb12
-rw-r--r--spec/ruby/core/string/ascii_only_spec.rb129
-rw-r--r--spec/ruby/core/string/b_spec.rb28
-rw-r--r--spec/ruby/core/string/byteindex_spec.rb298
-rw-r--r--spec/ruby/core/string/byterindex_spec.rb353
-rw-r--r--spec/ruby/core/string/bytes_spec.rb34
-rw-r--r--spec/ruby/core/string/bytesize_spec.rb52
-rw-r--r--spec/ruby/core/string/byteslice_spec.rb28
-rw-r--r--spec/ruby/core/string/bytesplice_spec.rb294
-rw-r--r--spec/ruby/core/string/capitalize_spec.rb189
-rw-r--r--spec/ruby/core/string/case_compare_spec.rb10
-rw-r--r--spec/ruby/core/string/casecmp_spec.rb134
-rw-r--r--spec/ruby/core/string/center_spec.rb82
-rw-r--r--spec/ruby/core/string/chars_spec.rb15
-rw-r--r--spec/ruby/core/string/chilled_string_spec.rb151
-rw-r--r--spec/ruby/core/string/chomp_spec.rb179
-rw-r--r--spec/ruby/core/string/chop_spec.rb71
-rw-r--r--spec/ruby/core/string/chr_spec.rb82
-rw-r--r--spec/ruby/core/string/clear_spec.rb61
-rw-r--r--spec/ruby/core/string/clone_spec.rb9
-rw-r--r--spec/ruby/core/string/codepoints_spec.rb28
-rw-r--r--spec/ruby/core/string/comparison_spec.rb14
-rw-r--r--spec/ruby/core/string/concat_spec.rb37
-rw-r--r--spec/ruby/core/string/count_spec.rb18
-rw-r--r--spec/ruby/core/string/crypt_spec.rb135
-rw-r--r--spec/ruby/core/string/dedup_spec.rb6
-rw-r--r--spec/ruby/core/string/delete_prefix_spec.rb130
-rw-r--r--spec/ruby/core/string/delete_spec.rb40
-rw-r--r--spec/ruby/core/string/delete_suffix_spec.rb130
-rw-r--r--spec/ruby/core/string/downcase_spec.rb182
-rw-r--r--spec/ruby/core/string/dump_spec.rb144
-rw-r--r--spec/ruby/core/string/dup_spec.rb23
-rw-r--r--spec/ruby/core/string/each_byte_spec.rb20
-rw-r--r--spec/ruby/core/string/each_char_spec.rb9
-rw-r--r--spec/ruby/core/string/each_codepoint_spec.rb14
-rw-r--r--spec/ruby/core/string/each_grapheme_cluster_spec.rb16
-rw-r--r--spec/ruby/core/string/each_line_spec.rb12
-rw-r--r--spec/ruby/core/string/element_reference_spec.rb6
-rw-r--r--spec/ruby/core/string/element_set_spec.rb459
-rw-r--r--spec/ruby/core/string/empty_spec.rb14
-rw-r--r--spec/ruby/core/string/encode_spec.rb307
-rw-r--r--spec/ruby/core/string/encoding_spec.rb367
-rw-r--r--spec/ruby/core/string/end_with_spec.rb50
-rw-r--r--spec/ruby/core/string/eql_spec.rb6
-rw-r--r--spec/ruby/core/string/equal_value_spec.rb10
-rw-r--r--spec/ruby/core/string/fixtures/classes.rb13
-rw-r--r--spec/ruby/core/string/fixtures/iso-8859-9-encoding.rb2
-rw-r--r--spec/ruby/core/string/fixtures/to_c.rb5
-rw-r--r--spec/ruby/core/string/fixtures/utf-8-encoding.rb7
-rw-r--r--spec/ruby/core/string/force_encoding_spec.rb93
-rw-r--r--spec/ruby/core/string/freeze_spec.rb8
-rw-r--r--spec/ruby/core/string/getbyte_spec.rb8
-rw-r--r--spec/ruby/core/string/grapheme_clusters_spec.rb14
-rw-r--r--spec/ruby/core/string/gsub_spec.rb241
-rw-r--r--spec/ruby/core/string/hash_spec.rb4
-rw-r--r--spec/ruby/core/string/hex_spec.rb4
-rw-r--r--spec/ruby/core/string/include_spec.rb26
-rw-r--r--spec/ruby/core/string/index_spec.rb104
-rw-r--r--spec/ruby/core/string/initialize_spec.rb6
-rw-r--r--spec/ruby/core/string/insert_spec.rb67
-rw-r--r--spec/ruby/core/string/inspect_spec.rb52
-rw-r--r--spec/ruby/core/string/intern_spec.rb8
-rw-r--r--spec/ruby/core/string/length_spec.rb8
-rw-r--r--spec/ruby/core/string/lines_spec.rb21
-rw-r--r--spec/ruby/core/string/ljust_spec.rb80
-rw-r--r--spec/ruby/core/string/lstrip_spec.rb68
-rw-r--r--spec/ruby/core/string/match_spec.rb66
-rw-r--r--spec/ruby/core/string/modulo_spec.rb284
-rw-r--r--spec/ruby/core/string/multiply_spec.rb8
-rw-r--r--spec/ruby/core/string/new_spec.rb26
-rw-r--r--spec/ruby/core/string/next_spec.rb10
-rw-r--r--spec/ruby/core/string/oct_spec.rb4
-rw-r--r--spec/ruby/core/string/ord_spec.rb45
-rw-r--r--spec/ruby/core/string/partition_spec.rb33
-rw-r--r--spec/ruby/core/string/percent_spec.rb14
-rw-r--r--spec/ruby/core/string/plus_spec.rb26
-rw-r--r--spec/ruby/core/string/prepend_spec.rb51
-rw-r--r--spec/ruby/core/string/replace_spec.rb6
-rw-r--r--spec/ruby/core/string/reverse_spec.rb58
-rw-r--r--spec/ruby/core/string/rindex_spec.rb64
-rw-r--r--spec/ruby/core/string/rjust_spec.rb80
-rw-r--r--spec/ruby/core/string/rpartition_spec.rb46
-rw-r--r--spec/ruby/core/string/rstrip_spec.rb54
-rw-r--r--spec/ruby/core/string/scan_spec.rb75
-rw-r--r--spec/ruby/core/string/scrub_spec.rb71
-rw-r--r--spec/ruby/core/string/setbyte_spec.rb21
-rw-r--r--spec/ruby/core/string/shared/byte_index_common.rb63
-rw-r--r--spec/ruby/core/string/shared/chars.rb92
-rw-r--r--spec/ruby/core/string/shared/codepoints.rb28
-rw-r--r--spec/ruby/core/string/shared/concat.rb85
-rw-r--r--spec/ruby/core/string/shared/dedup.rb51
-rw-r--r--spec/ruby/core/string/shared/each_char_without_block.rb4
-rw-r--r--spec/ruby/core/string/shared/each_codepoint_without_block.rb6
-rw-r--r--spec/ruby/core/string/shared/each_line.rb102
-rw-r--r--spec/ruby/core/string/shared/encode.rb233
-rw-r--r--spec/ruby/core/string/shared/eql.rb16
-rw-r--r--spec/ruby/core/string/shared/equal_value.rb6
-rw-r--r--spec/ruby/core/string/shared/grapheme_clusters.rb16
-rw-r--r--spec/ruby/core/string/shared/length.rb55
-rw-r--r--spec/ruby/core/string/shared/partition.rb33
-rw-r--r--spec/ruby/core/string/shared/replace.rb43
-rw-r--r--spec/ruby/core/string/shared/slice.rb258
-rw-r--r--spec/ruby/core/string/shared/strip.rb14
-rw-r--r--spec/ruby/core/string/shared/succ.rb23
-rw-r--r--spec/ruby/core/string/shared/to_a.rb9
-rw-r--r--spec/ruby/core/string/shared/to_s.rb5
-rw-r--r--spec/ruby/core/string/shared/to_sym.rb13
-rw-r--r--spec/ruby/core/string/size_spec.rb8
-rw-r--r--spec/ruby/core/string/slice_spec.rb246
-rw-r--r--spec/ruby/core/string/split_spec.rb347
-rw-r--r--spec/ruby/core/string/squeeze_spec.rb44
-rw-r--r--spec/ruby/core/string/start_with_spec.rb52
-rw-r--r--spec/ruby/core/string/string_spec.rb2
-rw-r--r--spec/ruby/core/string/strip_spec.rb46
-rw-r--r--spec/ruby/core/string/sub_spec.rb191
-rw-r--r--spec/ruby/core/string/succ_spec.rb10
-rw-r--r--spec/ruby/core/string/sum_spec.rb4
-rw-r--r--spec/ruby/core/string/swapcase_spec.rb175
-rw-r--r--spec/ruby/core/string/to_c_spec.rb118
-rw-r--r--spec/ruby/core/string/to_f_spec.rb109
-rw-r--r--spec/ruby/core/string/to_i_spec.rb40
-rw-r--r--spec/ruby/core/string/to_r_spec.rb8
-rw-r--r--spec/ruby/core/string/to_s_spec.rb8
-rw-r--r--spec/ruby/core/string/to_str_spec.rb8
-rw-r--r--spec/ruby/core/string/to_sym_spec.rb8
-rw-r--r--spec/ruby/core/string/tr_s_spec.rb107
-rw-r--r--spec/ruby/core/string/tr_spec.rb83
-rw-r--r--spec/ruby/core/string/try_convert_spec.rb8
-rw-r--r--spec/ruby/core/string/uminus_spec.rb23
-rw-r--r--spec/ruby/core/string/undump_spec.rb441
-rw-r--r--spec/ruby/core/string/unicode_normalize_spec.rb11
-rw-r--r--spec/ruby/core/string/unicode_normalized_spec.rb15
-rw-r--r--spec/ruby/core/string/unpack/a_spec.rb19
-rw-r--r--spec/ruby/core/string/unpack/at_spec.rb10
-rw-r--r--spec/ruby/core/string/unpack/b_spec.rb51
-rw-r--r--spec/ruby/core/string/unpack/c_spec.rb26
-rw-r--r--spec/ruby/core/string/unpack/comment_spec.rb6
-rw-r--r--spec/ruby/core/string/unpack/d_spec.rb8
-rw-r--r--spec/ruby/core/string/unpack/e_spec.rb8
-rw-r--r--spec/ruby/core/string/unpack/f_spec.rb8
-rw-r--r--spec/ruby/core/string/unpack/g_spec.rb8
-rw-r--r--spec/ruby/core/string/unpack/h_spec.rb51
-rw-r--r--spec/ruby/core/string/unpack/i_spec.rb8
-rw-r--r--spec/ruby/core/string/unpack/j_spec.rb427
-rw-r--r--spec/ruby/core/string/unpack/l_spec.rb24
-rw-r--r--spec/ruby/core/string/unpack/m_spec.rb30
-rw-r--r--spec/ruby/core/string/unpack/n_spec.rb8
-rw-r--r--spec/ruby/core/string/unpack/p_spec.rb41
-rw-r--r--spec/ruby/core/string/unpack/percent_spec.rb4
-rw-r--r--spec/ruby/core/string/unpack/q_spec.rb8
-rw-r--r--spec/ruby/core/string/unpack/s_spec.rb8
-rw-r--r--spec/ruby/core/string/unpack/shared/basic.rb20
-rw-r--r--spec/ruby/core/string/unpack/shared/float.rb70
-rw-r--r--spec/ruby/core/string/unpack/shared/integer.rb102
-rw-r--r--spec/ruby/core/string/unpack/shared/taint.rb2
-rw-r--r--spec/ruby/core/string/unpack/shared/unicode.rb16
-rw-r--r--spec/ruby/core/string/unpack/u_spec.rb23
-rw-r--r--spec/ruby/core/string/unpack/v_spec.rb8
-rw-r--r--spec/ruby/core/string/unpack/w_spec.rb34
-rw-r--r--spec/ruby/core/string/unpack/x_spec.rb14
-rw-r--r--spec/ruby/core/string/unpack/z_spec.rb17
-rw-r--r--spec/ruby/core/string/unpack1_spec.rb53
-rw-r--r--spec/ruby/core/string/unpack_spec.rb32
-rw-r--r--spec/ruby/core/string/upcase_spec.rb171
-rw-r--r--spec/ruby/core/string/uplus_spec.rb58
-rw-r--r--spec/ruby/core/string/upto_spec.rb24
-rw-r--r--spec/ruby/core/string/valid_encoding/utf_8_spec.rb214
-rw-r--r--spec/ruby/core/string/valid_encoding_spec.rb244
170 files changed, 7338 insertions, 4115 deletions
diff --git a/spec/ruby/core/string/allocate_spec.rb b/spec/ruby/core/string/allocate_spec.rb
index 9048815c5d..30d5f60594 100644
--- a/spec/ruby/core/string/allocate_spec.rb
+++ b/spec/ruby/core/string/allocate_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
describe "String.allocate" do
it "returns an instance of String" do
@@ -14,6 +14,6 @@ describe "String.allocate" do
end
it "returns a binary String" do
- String.new.encoding.should == Encoding::BINARY
+ String.allocate.encoding.should == Encoding::BINARY
end
end
diff --git a/spec/ruby/core/string/append_as_bytes_spec.rb b/spec/ruby/core/string/append_as_bytes_spec.rb
new file mode 100644
index 0000000000..b1703e5f89
--- /dev/null
+++ b/spec/ruby/core/string/append_as_bytes_spec.rb
@@ -0,0 +1,58 @@
+require_relative '../../spec_helper'
+
+describe "String#append_bytes" do
+ ruby_version_is "3.4" do
+ it "doesn't allow to mutate frozen strings" do
+ str = "hello".freeze
+ -> { str.append_as_bytes("\xE2\x82") }.should raise_error(FrozenError)
+ end
+
+ it "allows creating broken strings" do
+ str = +"hello"
+ str.append_as_bytes("\xE2\x82")
+ str.valid_encoding?.should == false
+
+ str.append_as_bytes("\xAC")
+ str.valid_encoding?.should == true
+
+ str = "abc".encode(Encoding::UTF_32LE)
+ str.append_as_bytes("def")
+ str.encoding.should == Encoding::UTF_32LE
+ str.valid_encoding?.should == false
+ end
+
+ it "never changes the receiver encoding" do
+ str = "".b
+ str.append_as_bytes("€")
+ str.encoding.should == Encoding::BINARY
+ end
+
+ it "accepts variadic String or Integer arguments" do
+ str = "hello".b
+ str.append_as_bytes("\xE2\x82", 12, 43, "\xAC")
+ str.encoding.should == Encoding::BINARY
+ str.should == "hello\xE2\x82\f+\xAC".b
+ end
+
+ it "truncates integers to the least significant byte" do
+ str = +""
+ str.append_as_bytes(0x131, 0x232, 0x333, bignum_value, bignum_value(1))
+ str.bytes.should == [0x31, 0x32, 0x33, 0, 1]
+ end
+
+ it "wraps negative integers" do
+ str = "".b
+ str.append_as_bytes(-1, -bignum_value, -bignum_value(1))
+ str.bytes.should == [0xFF, 0, 0xFF]
+ end
+
+ it "only accepts strings or integers, and doesn't attempt to cast with #to_str or #to_int" do
+ to_str = mock("to_str")
+ to_str.should_not_receive(:to_str)
+ to_str.should_not_receive(:to_int)
+
+ str = +"hello"
+ -> { str.append_as_bytes(to_str) }.should raise_error(TypeError, "wrong argument type MockObject (expected String or Integer)")
+ end
+ end
+end
diff --git a/spec/ruby/core/string/append_spec.rb b/spec/ruby/core/string/append_spec.rb
index 87b2dca725..8497ce8262 100644
--- a/spec/ruby/core/string/append_spec.rb
+++ b/spec/ruby/core/string/append_spec.rb
@@ -1,8 +1,14 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
-require File.expand_path('../shared/concat', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/concat'
describe "String#<<" do
it_behaves_like :string_concat, :<<
it_behaves_like :string_concat_encoding, :<<
+ it_behaves_like :string_concat_type_coercion, :<<
+
+ it "raises an ArgumentError when given the incorrect number of arguments" do
+ -> { "hello".send(:<<) }.should raise_error(ArgumentError)
+ -> { "hello".send(:<<, "one", "two") }.should raise_error(ArgumentError)
+ end
end
diff --git a/spec/ruby/core/string/ascii_only_spec.rb b/spec/ruby/core/string/ascii_only_spec.rb
index 1bf9cfa4a1..88a0559cfd 100644
--- a/spec/ruby/core/string/ascii_only_spec.rb
+++ b/spec/ruby/core/string/ascii_only_spec.rb
@@ -1,85 +1,82 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
-with_feature :encoding do
- describe "String#ascii_only?" do
- describe "with ASCII only characters" do
- it "returns true if the encoding is UTF-8" do
- [ ["hello", true],
- ["hello".encode('UTF-8'), true],
- ["hello".force_encoding('UTF-8'), true],
- ].should be_computed_by(:ascii_only?)
- end
-
- it "returns true if the encoding is US-ASCII" do
- "hello".force_encoding(Encoding::US_ASCII).ascii_only?.should be_true
- "hello".encode(Encoding::US_ASCII).ascii_only?.should be_true
- end
-
- it "returns true for all single-character UTF-8 Strings" do
- 0.upto(127) do |n|
- n.chr.ascii_only?.should be_true
- end
- end
+describe "String#ascii_only?" do
+ describe "with ASCII only characters" do
+ it "returns true if the encoding is UTF-8" do
+ [ ["hello", true],
+ ["hello".encode('UTF-8'), true],
+ ["hello".dup.force_encoding('UTF-8'), true],
+ ].should be_computed_by(:ascii_only?)
end
- describe "with non-ASCII only characters" do
- it "returns false if the encoding is ASCII-8BIT" do
- chr = 128.chr
- chr.encoding.should == Encoding::ASCII_8BIT
- chr.ascii_only?.should be_false
- end
-
- it "returns false if the String contains any non-ASCII characters" do
- [ ["\u{6666}", false],
- ["hello, \u{6666}", false],
- ["\u{6666}".encode('UTF-8'), false],
- ["\u{6666}".force_encoding('UTF-8'), false],
- ].should be_computed_by(:ascii_only?)
- end
+ it "returns true if the encoding is US-ASCII" do
+ "hello".dup.force_encoding(Encoding::US_ASCII).ascii_only?.should be_true
+ "hello".encode(Encoding::US_ASCII).ascii_only?.should be_true
+ end
- it "returns false if the encoding is US-ASCII" do
- [ ["\u{6666}".force_encoding(Encoding::US_ASCII), false],
- ["hello, \u{6666}".force_encoding(Encoding::US_ASCII), false],
- ].should be_computed_by(:ascii_only?)
+ it "returns true for all single-character UTF-8 Strings" do
+ 0.upto(127) do |n|
+ n.chr.ascii_only?.should be_true
end
end
+ end
- it "returns true for the empty String with an ASCII-compatible encoding" do
- "".ascii_only?.should be_true
- "".encode('UTF-8').ascii_only?.should be_true
+ describe "with non-ASCII only characters" do
+ it "returns false if the encoding is BINARY" do
+ chr = 128.chr
+ chr.encoding.should == Encoding::BINARY
+ chr.ascii_only?.should be_false
end
- it "returns false for the empty String with a non-ASCII-compatible encoding" do
- "".force_encoding('UTF-16LE').ascii_only?.should be_false
- "".encode('UTF-16BE').ascii_only?.should be_false
+ it "returns false if the String contains any non-ASCII characters" do
+ [ ["\u{6666}", false],
+ ["hello, \u{6666}", false],
+ ["\u{6666}".encode('UTF-8'), false],
+ ["\u{6666}".dup.force_encoding('UTF-8'), false],
+ ].should be_computed_by(:ascii_only?)
end
- it "returns false for a non-empty String with non-ASCII-compatible encoding" do
- "\x78\x00".force_encoding("UTF-16LE").ascii_only?.should be_false
+ it "returns false if the encoding is US-ASCII" do
+ [ ["\u{6666}".dup.force_encoding(Encoding::US_ASCII), false],
+ ["hello, \u{6666}".dup.force_encoding(Encoding::US_ASCII), false],
+ ].should be_computed_by(:ascii_only?)
end
+ end
- it "returns false when interpolating non ascii strings" do
- base = "EU currency is"
- base.force_encoding(Encoding::US_ASCII)
- euro = "\u20AC"
- interp = "#{base} #{euro}"
- euro.ascii_only?.should be_false
- base.ascii_only?.should be_true
- interp.ascii_only?.should be_false
- end
+ it "returns true for the empty String with an ASCII-compatible encoding" do
+ "".ascii_only?.should be_true
+ "".encode('UTF-8').ascii_only?.should be_true
+ end
- it "returns false after appending non ASCII characters to an empty String" do
- ("" << "λ").ascii_only?.should be_false
- end
+ it "returns false for the empty String with a non-ASCII-compatible encoding" do
+ "".dup.force_encoding('UTF-16LE').ascii_only?.should be_false
+ "".encode('UTF-16BE').ascii_only?.should be_false
+ end
- it "returns false when concatenating an ASCII and non-ASCII String" do
- "".concat("λ").ascii_only?.should be_false
- end
+ it "returns false for a non-empty String with non-ASCII-compatible encoding" do
+ "\x78\x00".dup.force_encoding("UTF-16LE").ascii_only?.should be_false
+ end
- it "returns false when replacing an ASCII String with a non-ASCII String" do
- "".replace("λ").ascii_only?.should be_false
- end
+ it "returns false when interpolating non ascii strings" do
+ base = "EU currency is".dup.force_encoding(Encoding::US_ASCII)
+ euro = "\u20AC"
+ interp = "#{base} #{euro}"
+ euro.ascii_only?.should be_false
+ base.ascii_only?.should be_true
+ interp.ascii_only?.should be_false
+ end
+
+ it "returns false after appending non ASCII characters to an empty String" do
+ ("".dup << "λ").ascii_only?.should be_false
+ end
+
+ it "returns false when concatenating an ASCII and non-ASCII String" do
+ "".dup.concat("λ").ascii_only?.should be_false
+ end
+
+ it "returns false when replacing an ASCII String with a non-ASCII String" do
+ "".dup.replace("λ").ascii_only?.should be_false
end
end
diff --git a/spec/ruby/core/string/b_spec.rb b/spec/ruby/core/string/b_spec.rb
index 89fcedf7c4..4b1fafff11 100644
--- a/spec/ruby/core/string/b_spec.rb
+++ b/spec/ruby/core/string/b_spec.rb
@@ -1,24 +1,16 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
+# frozen_string_literal: false
+require_relative '../../spec_helper'
describe "String#b" do
- with_feature :encoding do
- it "returns an ASCII-8BIT encoded string" do
- "Hello".b.should == "Hello".force_encoding(Encoding::ASCII_8BIT)
- "こんちには".b.should == "こんちには".force_encoding(Encoding::ASCII_8BIT)
- end
-
- it "returns new string without modifying self" do
- str = "こんちには"
- str.b.should_not equal(str)
- str.should == "こんちには"
- end
+ it "returns a binary encoded string" do
+ "Hello".b.should == "Hello".force_encoding(Encoding::BINARY)
+ "こんちには".b.should == "こんちには".force_encoding(Encoding::BINARY)
+ end
- it "copies own tainted/untrusted status to the returning value" do
- utf_8 = "こんちには".taint.untrust
- ret = utf_8.b
- ret.tainted?.should be_true
- ret.untrusted?.should be_true
- end
+ it "returns new string without modifying self" do
+ str = "こんちには"
+ str.b.should_not equal(str)
+ str.should == "こんちには"
end
end
diff --git a/spec/ruby/core/string/byteindex_spec.rb b/spec/ruby/core/string/byteindex_spec.rb
new file mode 100644
index 0000000000..d420f3f683
--- /dev/null
+++ b/spec/ruby/core/string/byteindex_spec.rb
@@ -0,0 +1,298 @@
+# -*- encoding: utf-8 -*-
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/byte_index_common.rb'
+
+describe "String#byteindex" do
+ it "calls #to_str to convert the first argument" do
+ char = mock("string index char")
+ char.should_receive(:to_str).and_return("b")
+ "abc".byteindex(char).should == 1
+ end
+
+ it "calls #to_int to convert the second argument" do
+ offset = mock("string index offset")
+ offset.should_receive(:to_int).and_return(1)
+ "abc".byteindex("c", offset).should == 2
+ end
+
+ it "does not raise IndexError when byte offset is correct or on string boundary" do
+ "わ".byteindex("").should == 0
+ "わ".byteindex("", 0).should == 0
+ "わ".byteindex("", 3).should == 3
+ end
+
+ it_behaves_like :byte_index_common, :byteindex
+end
+
+describe "String#byteindex with String" do
+ it "behaves the same as String#byteindex(char) for one-character strings" do
+ "blablabla hello cruel world...!".split("").uniq.each do |str|
+ chr = str[0]
+ str.byteindex(str).should == str.byteindex(chr)
+
+ 0.upto(str.size + 1) do |start|
+ str.byteindex(str, start).should == str.byteindex(chr, start)
+ end
+
+ (-str.size - 1).upto(-1) do |start|
+ str.byteindex(str, start).should == str.byteindex(chr, start)
+ end
+ end
+ end
+
+ it "returns the byteindex of the first occurrence of the given substring" do
+ "blablabla".byteindex("").should == 0
+ "blablabla".byteindex("b").should == 0
+ "blablabla".byteindex("bla").should == 0
+ "blablabla".byteindex("blabla").should == 0
+ "blablabla".byteindex("blablabla").should == 0
+
+ "blablabla".byteindex("l").should == 1
+ "blablabla".byteindex("la").should == 1
+ "blablabla".byteindex("labla").should == 1
+ "blablabla".byteindex("lablabla").should == 1
+
+ "blablabla".byteindex("a").should == 2
+ "blablabla".byteindex("abla").should == 2
+ "blablabla".byteindex("ablabla").should == 2
+ end
+
+ it "treats the offset as a byteindex" do
+ "aaaaa".byteindex("a", 0).should == 0
+ "aaaaa".byteindex("a", 2).should == 2
+ "aaaaa".byteindex("a", 4).should == 4
+ end
+
+ it "ignores string subclasses" do
+ "blablabla".byteindex(StringSpecs::MyString.new("bla")).should == 0
+ StringSpecs::MyString.new("blablabla").byteindex("bla").should == 0
+ StringSpecs::MyString.new("blablabla").byteindex(StringSpecs::MyString.new("bla")).should == 0
+ end
+
+ it "starts the search at the given offset" do
+ "blablabla".byteindex("bl", 0).should == 0
+ "blablabla".byteindex("bl", 1).should == 3
+ "blablabla".byteindex("bl", 2).should == 3
+ "blablabla".byteindex("bl", 3).should == 3
+
+ "blablabla".byteindex("bla", 0).should == 0
+ "blablabla".byteindex("bla", 1).should == 3
+ "blablabla".byteindex("bla", 2).should == 3
+ "blablabla".byteindex("bla", 3).should == 3
+
+ "blablabla".byteindex("blab", 0).should == 0
+ "blablabla".byteindex("blab", 1).should == 3
+ "blablabla".byteindex("blab", 2).should == 3
+ "blablabla".byteindex("blab", 3).should == 3
+
+ "blablabla".byteindex("la", 1).should == 1
+ "blablabla".byteindex("la", 2).should == 4
+ "blablabla".byteindex("la", 3).should == 4
+ "blablabla".byteindex("la", 4).should == 4
+
+ "blablabla".byteindex("lab", 1).should == 1
+ "blablabla".byteindex("lab", 2).should == 4
+ "blablabla".byteindex("lab", 3).should == 4
+ "blablabla".byteindex("lab", 4).should == 4
+
+ "blablabla".byteindex("ab", 2).should == 2
+ "blablabla".byteindex("ab", 3).should == 5
+ "blablabla".byteindex("ab", 4).should == 5
+ "blablabla".byteindex("ab", 5).should == 5
+
+ "blablabla".byteindex("", 0).should == 0
+ "blablabla".byteindex("", 1).should == 1
+ "blablabla".byteindex("", 2).should == 2
+ "blablabla".byteindex("", 7).should == 7
+ "blablabla".byteindex("", 8).should == 8
+ "blablabla".byteindex("", 9).should == 9
+ end
+
+ it "starts the search at offset + self.length if offset is negative" do
+ str = "blablabla"
+
+ ["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle|
+ (-str.length .. -1).each do |offset|
+ str.byteindex(needle, offset).should ==
+ str.byteindex(needle, offset + str.length)
+ end
+ end
+ end
+
+ it "returns nil if the substring isn't found" do
+ "blablabla".byteindex("B").should == nil
+ "blablabla".byteindex("z").should == nil
+ "blablabla".byteindex("BLA").should == nil
+ "blablabla".byteindex("blablablabla").should == nil
+ "blablabla".byteindex("", 10).should == nil
+
+ "hello".byteindex("he", 1).should == nil
+ "hello".byteindex("he", 2).should == nil
+ "I’ve got a multibyte character.\n".byteindex("\n\n").should == nil
+ end
+
+ it "returns the character byteindex of a multibyte character" do
+ "ありがとう".byteindex("が").should == 6
+ end
+
+ it "returns the character byteindex after offset" do
+ "われわれ".byteindex("わ", 3).should == 6
+ "ありがとうありがとう".byteindex("が", 9).should == 21
+ end
+
+ it "returns the character byteindex after a partial first match" do
+ "</</h".byteindex("</h").should == 2
+ end
+
+ it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
+ char = "れ".encode Encoding::EUC_JP
+ -> do
+ "あれ".byteindex(char)
+ end.should raise_error(Encoding::CompatibilityError)
+ end
+
+ it "handles a substring in a superset encoding" do
+ 'abc'.dup.force_encoding(Encoding::US_ASCII).byteindex('é').should == nil
+ end
+
+ it "handles a substring in a subset encoding" do
+ 'été'.byteindex('t'.dup.force_encoding(Encoding::US_ASCII)).should == 2
+ end
+end
+
+describe "String#byteindex with Regexp" do
+ it "behaves the same as String#byteindex(string) for escaped string regexps" do
+ ["blablabla", "hello cruel world...!"].each do |str|
+ ["", "b", "bla", "lab", "o c", "d."].each do |needle|
+ regexp = Regexp.new(Regexp.escape(needle))
+ str.byteindex(regexp).should == str.byteindex(needle)
+
+ 0.upto(str.size + 1) do |start|
+ str.byteindex(regexp, start).should == str.byteindex(needle, start)
+ end
+
+ (-str.size - 1).upto(-1) do |start|
+ str.byteindex(regexp, start).should == str.byteindex(needle, start)
+ end
+ end
+ end
+ end
+
+ it "returns the byteindex of the first match of regexp" do
+ "blablabla".byteindex(/bla/).should == 0
+ "blablabla".byteindex(/BLA/i).should == 0
+
+ "blablabla".byteindex(/.{0}/).should == 0
+ "blablabla".byteindex(/.{6}/).should == 0
+ "blablabla".byteindex(/.{9}/).should == 0
+
+ "blablabla".byteindex(/.*/).should == 0
+ "blablabla".byteindex(/.+/).should == 0
+
+ "blablabla".byteindex(/lab|b/).should == 0
+
+ not_supported_on :opal do
+ "blablabla".byteindex(/\A/).should == 0
+ "blablabla".byteindex(/\Z/).should == 9
+ "blablabla".byteindex(/\z/).should == 9
+ "blablabla\n".byteindex(/\Z/).should == 9
+ "blablabla\n".byteindex(/\z/).should == 10
+ end
+
+ "blablabla".byteindex(/^/).should == 0
+ "\nblablabla".byteindex(/^/).should == 0
+ "b\nablabla".byteindex(/$/).should == 1
+ "bl\nablabla".byteindex(/$/).should == 2
+
+ "blablabla".byteindex(/.l./).should == 0
+ end
+
+ it "starts the search at the given offset" do
+ "blablabla".byteindex(/.{0}/, 5).should == 5
+ "blablabla".byteindex(/.{1}/, 5).should == 5
+ "blablabla".byteindex(/.{2}/, 5).should == 5
+ "blablabla".byteindex(/.{3}/, 5).should == 5
+ "blablabla".byteindex(/.{4}/, 5).should == 5
+
+ "blablabla".byteindex(/.{0}/, 3).should == 3
+ "blablabla".byteindex(/.{1}/, 3).should == 3
+ "blablabla".byteindex(/.{2}/, 3).should == 3
+ "blablabla".byteindex(/.{5}/, 3).should == 3
+ "blablabla".byteindex(/.{6}/, 3).should == 3
+
+ "blablabla".byteindex(/.l./, 0).should == 0
+ "blablabla".byteindex(/.l./, 1).should == 3
+ "blablabla".byteindex(/.l./, 2).should == 3
+ "blablabla".byteindex(/.l./, 3).should == 3
+
+ "xblaxbla".byteindex(/x./, 0).should == 0
+ "xblaxbla".byteindex(/x./, 1).should == 4
+ "xblaxbla".byteindex(/x./, 2).should == 4
+
+ not_supported_on :opal do
+ "blablabla\n".byteindex(/\Z/, 9).should == 9
+ end
+ end
+
+ it "starts the search at offset + self.length if offset is negative" do
+ str = "blablabla"
+
+ ["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle|
+ (-str.length .. -1).each do |offset|
+ str.byteindex(needle, offset).should ==
+ str.byteindex(needle, offset + str.length)
+ end
+ end
+ end
+
+ it "returns nil if the substring isn't found" do
+ "blablabla".byteindex(/BLA/).should == nil
+
+ "blablabla".byteindex(/.{10}/).should == nil
+ "blaxbla".byteindex(/.x/, 3).should == nil
+ "blaxbla".byteindex(/..x/, 2).should == nil
+ end
+
+ it "returns nil if the Regexp matches the empty string and the offset is out of range" do
+ "ruby".byteindex(//, 12).should be_nil
+ end
+
+ it "supports \\G which matches at the given start offset" do
+ "helloYOU.".byteindex(/\GYOU/, 5).should == 5
+ "helloYOU.".byteindex(/\GYOU/).should == nil
+
+ re = /\G.+YOU/
+ # The # marks where \G will match.
+ [
+ ["#hi!YOUall.", 0],
+ ["h#i!YOUall.", 1],
+ ["hi#!YOUall.", 2],
+ ["hi!#YOUall.", nil]
+ ].each do |spec|
+
+ start = spec[0].byteindex("#")
+ str = spec[0].delete("#")
+
+ str.byteindex(re, start).should == spec[1]
+ end
+ end
+
+ it "converts start_offset to an integer via to_int" do
+ obj = mock('1')
+ obj.should_receive(:to_int).and_return(1)
+ "RWOARW".byteindex(/R./, obj).should == 4
+ end
+
+ it "returns the character byteindex of a multibyte character" do
+ "ありがとう".byteindex(/が/).should == 6
+ end
+
+ it "returns the character byteindex after offset" do
+ "われわれ".byteindex(/わ/, 3).should == 6
+ end
+
+ it "treats the offset as a byteindex" do
+ "われわわれ".byteindex(/わ/, 6).should == 6
+ end
+end
diff --git a/spec/ruby/core/string/byterindex_spec.rb b/spec/ruby/core/string/byterindex_spec.rb
new file mode 100644
index 0000000000..983222e35d
--- /dev/null
+++ b/spec/ruby/core/string/byterindex_spec.rb
@@ -0,0 +1,353 @@
+# -*- encoding: utf-8 -*-
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/byte_index_common.rb'
+
+describe "String#byterindex with object" do
+ it "tries to convert obj to a string via to_str" do
+ obj = mock('lo')
+ def obj.to_str() "lo" end
+ "hello".byterindex(obj).should == "hello".byterindex("lo")
+
+ obj = mock('o')
+ def obj.respond_to?(arg, *) true end
+ def obj.method_missing(*args) "o" end
+ "hello".byterindex(obj).should == "hello".byterindex("o")
+ end
+
+ it "calls #to_int to convert the second argument" do
+ offset = mock("string index offset")
+ offset.should_receive(:to_int).and_return(3)
+ "abc".byterindex("c", offset).should == 2
+ end
+
+ it "does not raise IndexError when byte offset is correct or on string boundary" do
+ "わ".byterindex("", 0).should == 0
+ "わ".byterindex("", 3).should == 3
+ "わ".byterindex("").should == 3
+ end
+
+ it_behaves_like :byte_index_common, :byterindex
+end
+
+describe "String#byterindex with String" do
+ it "behaves the same as String#byterindex(char) for one-character strings" do
+ "blablabla hello cruel world...!".split("").uniq.each do |str|
+ chr = str[0]
+ str.byterindex(str).should == str.byterindex(chr)
+
+ 0.upto(str.size + 1) do |start|
+ str.byterindex(str, start).should == str.byterindex(chr, start)
+ end
+
+ (-str.size - 1).upto(-1) do |start|
+ str.byterindex(str, start).should == str.byterindex(chr, start)
+ end
+ end
+ end
+
+ it "behaves the same as String#byterindex(?char) for one-character strings" do
+ "blablabla hello cruel world...!".split("").uniq.each do |str|
+ chr = str[0] =~ / / ? str[0] : eval("?#{str[0]}")
+ str.byterindex(str).should == str.byterindex(chr)
+
+ 0.upto(str.size + 1) do |start|
+ str.byterindex(str, start).should == str.byterindex(chr, start)
+ end
+
+ (-str.size - 1).upto(-1) do |start|
+ str.byterindex(str, start).should == str.byterindex(chr, start)
+ end
+ end
+ end
+
+ it "returns the index of the last occurrence of the given substring" do
+ "blablabla".byterindex("").should == 9
+ "blablabla".byterindex("a").should == 8
+ "blablabla".byterindex("la").should == 7
+ "blablabla".byterindex("bla").should == 6
+ "blablabla".byterindex("abla").should == 5
+ "blablabla".byterindex("labla").should == 4
+ "blablabla".byterindex("blabla").should == 3
+ "blablabla".byterindex("ablabla").should == 2
+ "blablabla".byterindex("lablabla").should == 1
+ "blablabla".byterindex("blablabla").should == 0
+
+ "blablabla".byterindex("l").should == 7
+ "blablabla".byterindex("bl").should == 6
+ "blablabla".byterindex("abl").should == 5
+ "blablabla".byterindex("labl").should == 4
+ "blablabla".byterindex("blabl").should == 3
+ "blablabla".byterindex("ablabl").should == 2
+ "blablabla".byterindex("lablabl").should == 1
+ "blablabla".byterindex("blablabl").should == 0
+
+ "blablabla".byterindex("b").should == 6
+ "blablabla".byterindex("ab").should == 5
+ "blablabla".byterindex("lab").should == 4
+ "blablabla".byterindex("blab").should == 3
+ "blablabla".byterindex("ablab").should == 2
+ "blablabla".byterindex("lablab").should == 1
+ "blablabla".byterindex("blablab").should == 0
+ end
+
+ it "ignores string subclasses" do
+ "blablabla".byterindex(StringSpecs::MyString.new("bla")).should == 6
+ StringSpecs::MyString.new("blablabla").byterindex("bla").should == 6
+ StringSpecs::MyString.new("blablabla").byterindex(StringSpecs::MyString.new("bla")).should == 6
+ end
+
+ it "starts the search at the given offset" do
+ "blablabla".byterindex("bl", 0).should == 0
+ "blablabla".byterindex("bl", 1).should == 0
+ "blablabla".byterindex("bl", 2).should == 0
+ "blablabla".byterindex("bl", 3).should == 3
+
+ "blablabla".byterindex("bla", 0).should == 0
+ "blablabla".byterindex("bla", 1).should == 0
+ "blablabla".byterindex("bla", 2).should == 0
+ "blablabla".byterindex("bla", 3).should == 3
+
+ "blablabla".byterindex("blab", 0).should == 0
+ "blablabla".byterindex("blab", 1).should == 0
+ "blablabla".byterindex("blab", 2).should == 0
+ "blablabla".byterindex("blab", 3).should == 3
+ "blablabla".byterindex("blab", 6).should == 3
+ "blablablax".byterindex("blab", 6).should == 3
+
+ "blablabla".byterindex("la", 1).should == 1
+ "blablabla".byterindex("la", 2).should == 1
+ "blablabla".byterindex("la", 3).should == 1
+ "blablabla".byterindex("la", 4).should == 4
+
+ "blablabla".byterindex("lab", 1).should == 1
+ "blablabla".byterindex("lab", 2).should == 1
+ "blablabla".byterindex("lab", 3).should == 1
+ "blablabla".byterindex("lab", 4).should == 4
+
+ "blablabla".byterindex("ab", 2).should == 2
+ "blablabla".byterindex("ab", 3).should == 2
+ "blablabla".byterindex("ab", 4).should == 2
+ "blablabla".byterindex("ab", 5).should == 5
+
+ "blablabla".byterindex("", 0).should == 0
+ "blablabla".byterindex("", 1).should == 1
+ "blablabla".byterindex("", 2).should == 2
+ "blablabla".byterindex("", 7).should == 7
+ "blablabla".byterindex("", 8).should == 8
+ "blablabla".byterindex("", 9).should == 9
+ "blablabla".byterindex("", 10).should == 9
+ end
+
+ it "starts the search at offset + self.length if offset is negative" do
+ str = "blablabla"
+
+ ["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle|
+ (-str.length .. -1).each do |offset|
+ str.byterindex(needle, offset).should ==
+ str.byterindex(needle, offset + str.length)
+ end
+ end
+ end
+
+ it "returns nil if the substring isn't found" do
+ "blablabla".byterindex("B").should == nil
+ "blablabla".byterindex("z").should == nil
+ "blablabla".byterindex("BLA").should == nil
+ "blablabla".byterindex("blablablabla").should == nil
+
+ "hello".byterindex("lo", 0).should == nil
+ "hello".byterindex("lo", 1).should == nil
+ "hello".byterindex("lo", 2).should == nil
+
+ "hello".byterindex("llo", 0).should == nil
+ "hello".byterindex("llo", 1).should == nil
+
+ "hello".byterindex("el", 0).should == nil
+ "hello".byterindex("ello", 0).should == nil
+
+ "hello".byterindex("", -6).should == nil
+ "hello".byterindex("", -7).should == nil
+
+ "hello".byterindex("h", -6).should == nil
+ end
+
+ it "tries to convert start_offset to an integer via to_int" do
+ obj = mock('5')
+ def obj.to_int() 5 end
+ "str".byterindex("st", obj).should == 0
+
+ obj = mock('5')
+ def obj.respond_to?(arg, *) true end
+ def obj.method_missing(*args) 5 end
+ "str".byterindex("st", obj).should == 0
+ end
+
+ it "raises a TypeError when given offset is nil" do
+ -> { "str".byterindex("st", nil) }.should raise_error(TypeError)
+ end
+
+ it "handles a substring in a superset encoding" do
+ 'abc'.dup.force_encoding(Encoding::US_ASCII).byterindex('é').should == nil
+ end
+
+ it "handles a substring in a subset encoding" do
+ 'été'.byterindex('t'.dup.force_encoding(Encoding::US_ASCII)).should == 2
+ end
+end
+
+describe "String#byterindex with Regexp" do
+ it "behaves the same as String#byterindex(string) for escaped string regexps" do
+ ["blablabla", "hello cruel world...!"].each do |str|
+ ["", "b", "bla", "lab", "o c", "d."].each do |needle|
+ regexp = Regexp.new(Regexp.escape(needle))
+ str.byterindex(regexp).should == str.byterindex(needle)
+
+ 0.upto(str.size + 1) do |start|
+ str.byterindex(regexp, start).should == str.byterindex(needle, start)
+ end
+
+ (-str.size - 1).upto(-1) do |start|
+ str.byterindex(regexp, start).should == str.byterindex(needle, start)
+ end
+ end
+ end
+ end
+
+ it "returns the index of the first match from the end of string of regexp" do
+ "blablabla".byterindex(/bla/).should == 6
+ "blablabla".byterindex(/BLA/i).should == 6
+
+ "blablabla".byterindex(/.{0}/).should == 9
+ "blablabla".byterindex(/.{1}/).should == 8
+ "blablabla".byterindex(/.{2}/).should == 7
+ "blablabla".byterindex(/.{6}/).should == 3
+ "blablabla".byterindex(/.{9}/).should == 0
+
+ "blablabla".byterindex(/.*/).should == 9
+ "blablabla".byterindex(/.+/).should == 8
+
+ "blablabla".byterindex(/bla|a/).should == 8
+
+ not_supported_on :opal do
+ "blablabla".byterindex(/\A/).should == 0
+ "blablabla".byterindex(/\Z/).should == 9
+ "blablabla".byterindex(/\z/).should == 9
+ "blablabla\n".byterindex(/\Z/).should == 10
+ "blablabla\n".byterindex(/\z/).should == 10
+ end
+
+ "blablabla".byterindex(/^/).should == 0
+ not_supported_on :opal do
+ "\nblablabla".byterindex(/^/).should == 1
+ "b\nlablabla".byterindex(/^/).should == 2
+ end
+ "blablabla".byterindex(/$/).should == 9
+
+ "blablabla".byterindex(/.l./).should == 6
+ end
+
+ it "starts the search at the given offset" do
+ "blablabla".byterindex(/.{0}/, 5).should == 5
+ "blablabla".byterindex(/.{1}/, 5).should == 5
+ "blablabla".byterindex(/.{2}/, 5).should == 5
+ "blablabla".byterindex(/.{3}/, 5).should == 5
+ "blablabla".byterindex(/.{4}/, 5).should == 5
+
+ "blablabla".byterindex(/.{0}/, 3).should == 3
+ "blablabla".byterindex(/.{1}/, 3).should == 3
+ "blablabla".byterindex(/.{2}/, 3).should == 3
+ "blablabla".byterindex(/.{5}/, 3).should == 3
+ "blablabla".byterindex(/.{6}/, 3).should == 3
+
+ "blablabla".byterindex(/.l./, 0).should == 0
+ "blablabla".byterindex(/.l./, 1).should == 0
+ "blablabla".byterindex(/.l./, 2).should == 0
+ "blablabla".byterindex(/.l./, 3).should == 3
+
+ "blablablax".byterindex(/.x/, 10).should == 8
+ "blablablax".byterindex(/.x/, 9).should == 8
+ "blablablax".byterindex(/.x/, 8).should == 8
+
+ "blablablax".byterindex(/..x/, 10).should == 7
+ "blablablax".byterindex(/..x/, 9).should == 7
+ "blablablax".byterindex(/..x/, 8).should == 7
+ "blablablax".byterindex(/..x/, 7).should == 7
+
+ not_supported_on :opal do
+ "blablabla\n".byterindex(/\Z/, 9).should == 9
+ end
+ end
+
+ it "starts the search at offset + self.length if offset is negative" do
+ str = "blablabla"
+
+ ["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle|
+ (-str.length .. -1).each do |offset|
+ str.byterindex(needle, offset).should ==
+ str.byterindex(needle, offset + str.length)
+ end
+ end
+ end
+
+ it "returns nil if the substring isn't found" do
+ "blablabla".byterindex(/BLA/).should == nil
+ "blablabla".byterindex(/.{10}/).should == nil
+ "blablablax".byterindex(/.x/, 7).should == nil
+ "blablablax".byterindex(/..x/, 6).should == nil
+
+ not_supported_on :opal do
+ "blablabla".byterindex(/\Z/, 5).should == nil
+ "blablabla".byterindex(/\z/, 5).should == nil
+ "blablabla\n".byterindex(/\z/, 9).should == nil
+ end
+ end
+
+ not_supported_on :opal do
+ it "supports \\G which matches at the given start offset" do
+ "helloYOU.".byterindex(/YOU\G/, 8).should == 5
+ "helloYOU.".byterindex(/YOU\G/).should == nil
+
+ idx = "helloYOUall!".index("YOU")
+ re = /YOU.+\G.+/
+ # The # marks where \G will match.
+ [
+ ["helloYOU#all.", nil],
+ ["helloYOUa#ll.", idx],
+ ["helloYOUal#l.", idx],
+ ["helloYOUall#.", idx],
+ ["helloYOUall.#", nil]
+ ].each do |i|
+ start = i[0].index("#")
+ str = i[0].delete("#")
+
+ str.byterindex(re, start).should == i[1]
+ end
+ end
+ end
+
+ it "tries to convert start_offset to an integer" do
+ obj = mock('5')
+ def obj.to_int() 5 end
+ "str".byterindex(/../, obj).should == 1
+
+ obj = mock('5')
+ def obj.respond_to?(arg, *) true end
+ def obj.method_missing(*args); 5; end
+ "str".byterindex(/../, obj).should == 1
+ end
+
+ it "raises a TypeError when given offset is nil" do
+ -> { "str".byterindex(/../, nil) }.should raise_error(TypeError)
+ end
+
+ it "returns the reverse byte index of a multibyte character" do
+ "ありがりがとう".byterindex("が").should == 12
+ "ありがりがとう".byterindex(/が/).should == 12
+ end
+
+ it "returns the character index before the finish" do
+ "ありがりがとう".byterindex("が", 9).should == 6
+ "ありがりがとう".byterindex(/が/, 9).should == 6
+ end
+end
diff --git a/spec/ruby/core/string/bytes_spec.rb b/spec/ruby/core/string/bytes_spec.rb
index b1f5ba412f..02151eebbc 100644
--- a/spec/ruby/core/string/bytes_spec.rb
+++ b/spec/ruby/core/string/bytes_spec.rb
@@ -1,5 +1,5 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
describe "String#bytes" do
before :each do
@@ -22,9 +22,9 @@ describe "String#bytes" do
@utf8_ascii.bytes.to_a.size.should == @utf8_ascii.bytesize
end
- it "returns bytes as Fixnums" do
- @ascii.bytes.to_a.each {|b| b.should be_an_instance_of(Fixnum)}
- @utf8_ascii.bytes { |b| b.should be_an_instance_of(Fixnum) }
+ it "returns bytes as Integers" do
+ @ascii.bytes.to_a.each {|b| b.should be_an_instance_of(Integer)}
+ @utf8_ascii.bytes { |b| b.should be_an_instance_of(Integer) }
end
it "agrees with #unpack('C*')" do
@@ -36,22 +36,20 @@ describe "String#bytes" do
end
end
-with_feature :encoding do
- describe "String#bytes" do
- before :each do
- @utf8 = "東京"
- @ascii = 'Tokyo'
- @utf8_ascii = @utf8 + @ascii
- end
+describe "String#bytes" do
+ before :each do
+ @utf8 = "東京"
+ @ascii = 'Tokyo'
+ @utf8_ascii = @utf8 + @ascii
+ end
- it "agrees with #getbyte" do
- @utf8_ascii.bytes.to_a.each_with_index do |byte,index|
- byte.should == @utf8_ascii.getbyte(index)
- end
+ it "agrees with #getbyte" do
+ @utf8_ascii.bytes.to_a.each_with_index do |byte,index|
+ byte.should == @utf8_ascii.getbyte(index)
end
+ end
- it "is unaffected by #force_encoding" do
- @utf8.force_encoding('ASCII').bytes.to_a.should == @utf8.bytes.to_a
- end
+ it "is unaffected by #force_encoding" do
+ @utf8.dup.force_encoding('ASCII').bytes.to_a.should == @utf8.bytes.to_a
end
end
diff --git a/spec/ruby/core/string/bytesize_spec.rb b/spec/ruby/core/string/bytesize_spec.rb
index 51da179da8..2bbefc0820 100644
--- a/spec/ruby/core/string/bytesize_spec.rb
+++ b/spec/ruby/core/string/bytesize_spec.rb
@@ -1,37 +1,33 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
-with_feature :encoding do
- describe "#String#bytesize" do
- it "needs to be reviewed for spec completeness"
-
- it "returns the length of self in bytes" do
- "hello".bytesize.should == 5
- " ".bytesize.should == 1
- end
+describe "String#bytesize" do
+ it "returns the length of self in bytes" do
+ "hello".bytesize.should == 5
+ " ".bytesize.should == 1
+ end
- it "works with strings containing single UTF-8 characters" do
- "\u{6666}".bytesize.should == 3
- end
+ it "works with strings containing single UTF-8 characters" do
+ "\u{6666}".bytesize.should == 3
+ end
- it "works with pseudo-ASCII strings containing single UTF-8 characters" do
- "\u{6666}".force_encoding('ASCII').bytesize.should == 3
- end
+ it "works with pseudo-ASCII strings containing single UTF-8 characters" do
+ "\u{6666}".dup.force_encoding('ASCII').bytesize.should == 3
+ end
- it "works with strings containing UTF-8 characters" do
- "c \u{6666}".force_encoding('UTF-8').bytesize.should == 5
- "c \u{6666}".bytesize.should == 5
- end
+ it "works with strings containing UTF-8 characters" do
+ "c \u{6666}".dup.force_encoding('UTF-8').bytesize.should == 5
+ "c \u{6666}".bytesize.should == 5
+ end
- it "works with pseudo-ASCII strings containing UTF-8 characters" do
- "c \u{6666}".force_encoding('ASCII').bytesize.should == 5
- end
+ it "works with pseudo-ASCII strings containing UTF-8 characters" do
+ "c \u{6666}".dup.force_encoding('ASCII').bytesize.should == 5
+ end
- it "returns 0 for the empty string" do
- "".bytesize.should == 0
- "".force_encoding('ASCII').bytesize.should == 0
- "".force_encoding('UTF-8').bytesize.should == 0
- end
+ it "returns 0 for the empty string" do
+ "".bytesize.should == 0
+ "".dup.force_encoding('ASCII').bytesize.should == 0
+ "".dup.force_encoding('UTF-8').bytesize.should == 0
end
end
diff --git a/spec/ruby/core/string/byteslice_spec.rb b/spec/ruby/core/string/byteslice_spec.rb
index 263810971e..4ad9e8d8f1 100644
--- a/spec/ruby/core/string/byteslice_spec.rb
+++ b/spec/ruby/core/string/byteslice_spec.rb
@@ -1,7 +1,7 @@
-# -*- encoding: binary -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
-require File.expand_path('../shared/slice.rb', __FILE__)
+# encoding: binary
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/slice'
describe "String#byteslice" do
it "needs to reviewed for spec completeness"
@@ -17,13 +17,17 @@ describe "String#byteslice with Range" do
it_behaves_like :string_slice_range, :byteslice
end
-with_feature :encoding do
- describe "String#byteslice on on non ASCII strings" do
- it "returns byteslice of unicode strings" do
- "\u3042".byteslice(1).should == "\x81".force_encoding("UTF-8")
- "\u3042".byteslice(1, 2).should == "\x81\x82".force_encoding("UTF-8")
- "\u3042".byteslice(1..2).should == "\x81\x82".force_encoding("UTF-8")
- "\u3042".byteslice(-1).should == "\x82".force_encoding("UTF-8")
- end
+describe "String#byteslice on non ASCII strings" do
+ it "returns byteslice of unicode strings" do
+ "\u3042".byteslice(1).should == "\x81".dup.force_encoding("UTF-8")
+ "\u3042".byteslice(1, 2).should == "\x81\x82".dup.force_encoding("UTF-8")
+ "\u3042".byteslice(1..2).should == "\x81\x82".dup.force_encoding("UTF-8")
+ "\u3042".byteslice(-1).should == "\x82".dup.force_encoding("UTF-8")
+ end
+
+ it "returns a String in the same encoding as self" do
+ "ruby".encode("UTF-8").slice(0).encoding.should == Encoding::UTF_8
+ "ruby".encode("US-ASCII").slice(0).encoding.should == Encoding::US_ASCII
+ "ruby".encode("Windows-1251").slice(0).encoding.should == Encoding::Windows_1251
end
end
diff --git a/spec/ruby/core/string/bytesplice_spec.rb b/spec/ruby/core/string/bytesplice_spec.rb
new file mode 100644
index 0000000000..2c770e340a
--- /dev/null
+++ b/spec/ruby/core/string/bytesplice_spec.rb
@@ -0,0 +1,294 @@
+# -*- encoding: utf-8 -*-
+# frozen_string_literal: false
+require_relative '../../spec_helper'
+
+describe "String#bytesplice" do
+ it "raises IndexError when index is less than -bytesize" do
+ -> { "hello".bytesplice(-6, 0, "xxx") }.should raise_error(IndexError, "index -6 out of string")
+ end
+
+ it "raises IndexError when index is greater than bytesize" do
+ -> { "hello".bytesplice(6, 0, "xxx") }.should raise_error(IndexError, "index 6 out of string")
+ end
+
+ it "raises IndexError for negative length" do
+ -> { "abc".bytesplice(0, -2, "") }.should raise_error(IndexError, "negative length -2")
+ end
+
+ it "replaces with integer indices" do
+ "hello".bytesplice(-5, 0, "xxx").should == "xxxhello"
+ "hello".bytesplice(0, 0, "xxx").should == "xxxhello"
+ "hello".bytesplice(0, 1, "xxx").should == "xxxello"
+ "hello".bytesplice(0, 5, "xxx").should == "xxx"
+ "hello".bytesplice(0, 6, "xxx").should == "xxx"
+ end
+
+ it "raises RangeError when range left boundary is less than -bytesize" do
+ -> { "hello".bytesplice(-6...-6, "xxx") }.should raise_error(RangeError, "-6...-6 out of range")
+ end
+
+ it "replaces with ranges" do
+ "hello".bytesplice(-5...-5, "xxx").should == "xxxhello"
+ "hello".bytesplice(0...0, "xxx").should == "xxxhello"
+ "hello".bytesplice(0..0, "xxx").should == "xxxello"
+ "hello".bytesplice(0...1, "xxx").should == "xxxello"
+ "hello".bytesplice(0..1, "xxx").should == "xxxllo"
+ "hello".bytesplice(0..-1, "xxx").should == "xxx"
+ "hello".bytesplice(0...5, "xxx").should == "xxx"
+ "hello".bytesplice(0...6, "xxx").should == "xxx"
+ end
+
+ it "raises TypeError when integer index is provided without length argument" do
+ -> { "hello".bytesplice(0, "xxx") }.should raise_error(TypeError, "wrong argument type Integer (expected Range)")
+ end
+
+ it "replaces on an empty string" do
+ "".bytesplice(0, 0, "").should == ""
+ "".bytesplice(0, 0, "xxx").should == "xxx"
+ end
+
+ it "mutates self" do
+ s = "hello"
+ s.bytesplice(2, 1, "xxx").should.equal?(s)
+ end
+
+ it "raises when string is frozen" do
+ s = "hello".freeze
+ -> { s.bytesplice(2, 1, "xxx") }.should raise_error(FrozenError, "can't modify frozen String: \"hello\"")
+ end
+
+ ruby_version_is "3.3" do
+ it "raises IndexError when str_index is less than -bytesize" do
+ -> { "hello".bytesplice(2, 1, "HELLO", -6, 0) }.should raise_error(IndexError, "index -6 out of string")
+ end
+
+ it "raises IndexError when str_index is greater than bytesize" do
+ -> { "hello".bytesplice(2, 1, "HELLO", 6, 0) }.should raise_error(IndexError, "index 6 out of string")
+ end
+
+ it "raises IndexError for negative str length" do
+ -> { "abc".bytesplice(0, 1, "", 0, -2) }.should raise_error(IndexError, "negative length -2")
+ end
+
+ it "replaces with integer str indices" do
+ "hello".bytesplice(1, 2, "HELLO", -5, 0).should == "hlo"
+ "hello".bytesplice(1, 2, "HELLO", 0, 0).should == "hlo"
+ "hello".bytesplice(1, 2, "HELLO", 0, 1).should == "hHlo"
+ "hello".bytesplice(1, 2, "HELLO", 0, 5).should == "hHELLOlo"
+ "hello".bytesplice(1, 2, "HELLO", 0, 6).should == "hHELLOlo"
+ end
+
+ it "raises RangeError when str range left boundary is less than -bytesize" do
+ -> { "hello".bytesplice(0..1, "HELLO", -6...-6) }.should raise_error(RangeError, "-6...-6 out of range")
+ end
+
+ it "replaces with str ranges" do
+ "hello".bytesplice(1..2, "HELLO", -5...-5).should == "hlo"
+ "hello".bytesplice(1..2, "HELLO", 0...0).should == "hlo"
+ "hello".bytesplice(1..2, "HELLO", 0..0).should == "hHlo"
+ "hello".bytesplice(1..2, "HELLO", 0...1).should == "hHlo"
+ "hello".bytesplice(1..2, "HELLO", 0..1).should == "hHElo"
+ "hello".bytesplice(1..2, "HELLO", 0..-1).should == "hHELLOlo"
+ "hello".bytesplice(1..2, "HELLO", 0...5).should == "hHELLOlo"
+ "hello".bytesplice(1..2, "HELLO", 0...6).should == "hHELLOlo"
+ end
+
+ it "raises ArgumentError when integer str index is provided without str length argument" do
+ -> { "hello".bytesplice(0, 1, "xxx", 0) }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 2, 3, or 5)")
+ end
+
+ it "replaces on an empty string with str index/length" do
+ "".bytesplice(0, 0, "", 0, 0).should == ""
+ "".bytesplice(0, 0, "xxx", 0, 1).should == "x"
+ end
+
+ it "mutates self with substring and str index/length" do
+ s = "hello"
+ s.bytesplice(2, 1, "xxx", 1, 2).should.equal?(s)
+ s.should.eql?("hexxlo")
+ end
+
+ it "raises when string is frozen and str index/length" do
+ s = "hello".freeze
+ -> { s.bytesplice(2, 1, "xxx", 0, 1) }.should raise_error(FrozenError, "can't modify frozen String: \"hello\"")
+ end
+
+ it "replaces on an empty string with str range" do
+ "".bytesplice(0..0, "", 0..0).should == ""
+ "".bytesplice(0..0, "xyz", 0..1).should == "xy"
+ end
+
+ it "mutates self with substring and str range" do
+ s = "hello"
+ s.bytesplice(2..2, "xyz", 1..2).should.equal?(s)
+ s.should.eql?("heyzlo")
+ end
+
+ it "raises when string is frozen and str range" do
+ s = "hello".freeze
+ -> { s.bytesplice(2..2, "yzx", 0..1) }.should raise_error(FrozenError, "can't modify frozen String: \"hello\"")
+ end
+ end
+end
+
+describe "String#bytesplice with multibyte characters" do
+ it "raises IndexError when index is out of byte size boundary" do
+ -> { "こんにちは".bytesplice(-16, 0, "xxx") }.should raise_error(IndexError, "index -16 out of string")
+ end
+
+ it "raises IndexError when index is not on a codepoint boundary" do
+ -> { "こんにちは".bytesplice(1, 0, "xxx") }.should raise_error(IndexError, "offset 1 does not land on character boundary")
+ end
+
+ it "raises IndexError when length is not matching the codepoint boundary" do
+ -> { "こんにちは".bytesplice(0, 1, "xxx") }.should raise_error(IndexError, "offset 1 does not land on character boundary")
+ -> { "こんにちは".bytesplice(0, 2, "xxx") }.should raise_error(IndexError, "offset 2 does not land on character boundary")
+ end
+
+ it "replaces with integer indices" do
+ "こんにちは".bytesplice(-15, 0, "xxx").should == "xxxこんにちは"
+ "こんにちは".bytesplice(0, 0, "xxx").should == "xxxこんにちは"
+ "こんにちは".bytesplice(0, 3, "xxx").should == "xxxんにちは"
+ "こんにちは".bytesplice(3, 3, "はは").should == "こははにちは"
+ "こんにちは".bytesplice(15, 0, "xxx").should == "こんにちはxxx"
+ end
+
+ it "replaces with range" do
+ "こんにちは".bytesplice(-15...-16, "xxx").should == "xxxこんにちは"
+ "こんにちは".bytesplice(0...0, "xxx").should == "xxxこんにちは"
+ "こんにちは".bytesplice(0..2, "xxx").should == "xxxんにちは"
+ "こんにちは".bytesplice(0...3, "xxx").should == "xxxんにちは"
+ "こんにちは".bytesplice(0..5, "xxx").should == "xxxにちは"
+ "こんにちは".bytesplice(0..-1, "xxx").should == "xxx"
+ "こんにちは".bytesplice(0...15, "xxx").should == "xxx"
+ "こんにちは".bytesplice(0...18, "xxx").should == "xxx"
+ end
+
+ it "treats negative length for range as 0" do
+ "こんにちは".bytesplice(0...-100, "xxx").should == "xxxこんにちは"
+ "こんにちは".bytesplice(3...-100, "xxx").should == "こxxxんにちは"
+ "こんにちは".bytesplice(-15...-100, "xxx").should == "xxxこんにちは"
+ end
+
+ it "raises when ranges not match codepoint boundaries" do
+ -> { "こんにちは".bytesplice(0..0, "x") }.should raise_error(IndexError, "offset 1 does not land on character boundary")
+ -> { "こんにちは".bytesplice(0..1, "x") }.should raise_error(IndexError, "offset 2 does not land on character boundary")
+ # Begin is incorrect
+ -> { "こんにちは".bytesplice(-4..-1, "x") }.should raise_error(IndexError, "offset 11 does not land on character boundary")
+ -> { "こんにちは".bytesplice(-5..-1, "x") }.should raise_error(IndexError, "offset 10 does not land on character boundary")
+ # End is incorrect
+ -> { "こんにちは".bytesplice(-3..-2, "x") }.should raise_error(IndexError, "offset 14 does not land on character boundary")
+ -> { "こんにちは".bytesplice(-3..-3, "x") }.should raise_error(IndexError, "offset 13 does not land on character boundary")
+ end
+
+ it "deals with a different encoded argument" do
+ s = "こんにちは"
+ s.encoding.should == Encoding::UTF_8
+ sub = "xxxxxx"
+ sub.force_encoding(Encoding::US_ASCII)
+
+ result = s.bytesplice(0, 3, sub)
+ result.should == "xxxxxxんにちは"
+ result.encoding.should == Encoding::UTF_8
+
+ s = "xxxxxx"
+ s.force_encoding(Encoding::US_ASCII)
+ sub = "こんにちは"
+ sub.encoding.should == Encoding::UTF_8
+
+ result = s.bytesplice(0, 3, sub)
+ result.should == "こんにちはxxx"
+ result.encoding.should == Encoding::UTF_8
+ end
+
+ ruby_version_is "3.3" do
+ it "raises IndexError when str_index is out of byte size boundary" do
+ -> { "こんにちは".bytesplice(3, 3, "こんにちは", -16, 0) }.should raise_error(IndexError, "index -16 out of string")
+ end
+
+ it "raises IndexError when str_index is not on a codepoint boundary" do
+ -> { "こんにちは".bytesplice(3, 3, "こんにちは", 1, 0) }.should raise_error(IndexError, "offset 1 does not land on character boundary")
+ end
+
+ it "raises IndexError when str_length is not matching the codepoint boundary" do
+ -> { "こんにちは".bytesplice(3, 3, "こんにちは", 0, 1) }.should raise_error(IndexError, "offset 1 does not land on character boundary")
+ -> { "こんにちは".bytesplice(3, 3, "こんにちは", 0, 2) }.should raise_error(IndexError, "offset 2 does not land on character boundary")
+ end
+
+ it "replaces with integer str indices" do
+ "こんにちは".bytesplice(3, 3, "こんにちは", -15, 0).should == "こにちは"
+ "こんにちは".bytesplice(3, 3, "こんにちは", 0, 0).should == "こにちは"
+ "こんにちは".bytesplice(3, 3, "こんにちは", 0, 3).should == "ここにちは"
+ "こんにちは".bytesplice(3, 3, "はは", 3, 3).should == "こはにちは"
+ "こんにちは".bytesplice(3, 3, "こんにちは", 15, 0).should == "こにちは"
+ end
+
+ it "replaces with str range" do
+ "こんにちは".bytesplice(0..2, "こんにちは", -15...-16).should == "んにちは"
+ "こんにちは".bytesplice(0..2, "こんにちは", 0...0).should == "んにちは"
+ "こんにちは".bytesplice(0..2, "こんにちは", 3..5).should == "んんにちは"
+ "こんにちは".bytesplice(0..2, "こんにちは", 3...6).should == "んんにちは"
+ "こんにちは".bytesplice(0..2, "こんにちは", 3..8).should == "んにんにちは"
+ "こんにちは".bytesplice(0..2, "こんにちは", 0..-1).should == "こんにちはんにちは"
+ "こんにちは".bytesplice(0..2, "こんにちは", 0...15).should == "こんにちはんにちは"
+ "こんにちは".bytesplice(0..2, "こんにちは", 0...18).should == "こんにちはんにちは"
+ end
+
+ it "treats negative length for str range as 0" do
+ "こんにちは".bytesplice(0..2, "こんにちは", 0...-100).should == "んにちは"
+ "こんにちは".bytesplice(0..2, "こんにちは", 3...-100).should == "んにちは"
+ "こんにちは".bytesplice(0..2, "こんにちは", -15...-100).should == "んにちは"
+ end
+
+ it "raises when ranges not match codepoint boundaries in str" do
+ -> { "こんにちは".bytesplice(3...3, "こ", 0..0) }.should raise_error(IndexError, "offset 1 does not land on character boundary")
+ -> { "こんにちは".bytesplice(3...3, "こ", 0..1) }.should raise_error(IndexError, "offset 2 does not land on character boundary")
+ # Begin is incorrect
+ -> { "こんにちは".bytesplice(3...3, "こんにちは", -4..-1) }.should raise_error(IndexError, "offset 11 does not land on character boundary")
+ -> { "こんにちは".bytesplice(3...3, "こんにちは", -5..-1) }.should raise_error(IndexError, "offset 10 does not land on character boundary")
+ # End is incorrect
+ -> { "こんにちは".bytesplice(3...3, "こんにちは", -3..-2) }.should raise_error(IndexError, "offset 14 does not land on character boundary")
+ -> { "こんにちは".bytesplice(3...3, "こんにちは", -3..-3) }.should raise_error(IndexError, "offset 13 does not land on character boundary")
+ end
+
+ it "deals with a different encoded argument with str index/length" do
+ s = "こんにちは"
+ s.encoding.should == Encoding::UTF_8
+ sub = "goodbye"
+ sub.force_encoding(Encoding::US_ASCII)
+
+ result = s.bytesplice(3, 3, sub, 0, 3)
+ result.should == "こgooにちは"
+ result.encoding.should == Encoding::UTF_8
+
+ s = "hello"
+ s.force_encoding(Encoding::US_ASCII)
+ sub = "こんにちは"
+ sub.encoding.should == Encoding::UTF_8
+
+ result = s.bytesplice(1, 2, sub, 3, 3)
+ result.should == "hんlo"
+ result.encoding.should == Encoding::UTF_8
+ end
+
+ it "deals with a different encoded argument with str range" do
+ s = "こんにちは"
+ s.encoding.should == Encoding::UTF_8
+ sub = "goodbye"
+ sub.force_encoding(Encoding::US_ASCII)
+
+ result = s.bytesplice(3..5, sub, 0..2)
+ result.should == "こgooにちは"
+ result.encoding.should == Encoding::UTF_8
+
+ s = "hello"
+ s.force_encoding(Encoding::US_ASCII)
+ sub = "こんにちは"
+ sub.encoding.should == Encoding::UTF_8
+
+ result = s.bytesplice(1..2, sub, 3..5)
+ result.should == "hんlo"
+ result.encoding.should == Encoding::UTF_8
+ end
+ end
+end
diff --git a/spec/ruby/core/string/capitalize_spec.rb b/spec/ruby/core/string/capitalize_spec.rb
index 497e1453cd..5e59b656c5 100644
--- a/spec/ruby/core/string/capitalize_spec.rb
+++ b/spec/ruby/core/string/capitalize_spec.rb
@@ -1,6 +1,6 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String#capitalize" do
it "returns a copy of self with the first character converted to uppercase and the remainder to lowercase" do
@@ -10,61 +10,198 @@ describe "String#capitalize" do
"hello".capitalize.should == "Hello"
"HELLO".capitalize.should == "Hello"
"123ABC".capitalize.should == "123abc"
+ "abcdef"[1...-1].capitalize.should == "Bcde"
end
- it "taints resulting string when self is tainted" do
- "".taint.capitalize.tainted?.should == true
- "hello".taint.capitalize.tainted?.should == true
+ describe "full Unicode case mapping" do
+ it "works for all of Unicode with no option" do
+ "äöÜ".capitalize.should == "Äöü"
+ end
+
+ it "only capitalizes the first resulting character when upcasing a character produces a multi-character sequence" do
+ "ß".capitalize.should == "Ss"
+ end
+
+ it "updates string metadata" do
+ capitalized = "ßeT".capitalize
+
+ capitalized.should == "Sset"
+ capitalized.size.should == 4
+ capitalized.bytesize.should == 4
+ capitalized.ascii_only?.should be_true
+ end
end
- ruby_version_is ''...'2.4' do
- it "is locale insensitive (only upcases a-z and only downcases A-Z)" do
- "ÄÖÜ".capitalize.should == "ÄÖÜ"
- "ärger".capitalize.should == "ärger"
- "BÄR".capitalize.should == "BÄr"
+ describe "ASCII-only case mapping" do
+ it "does not capitalize non-ASCII characters" do
+ "ßet".capitalize(:ascii).should == "ßet"
+ end
+
+ it "handles non-ASCII substrings properly" do
+ "garçon"[1...-1].capitalize(:ascii).should == "Arço"
end
end
- ruby_version_is '2.4' do
- it "works for all of Unicode" do
- "äöü".capitalize.should == "Äöü"
+ describe "full Unicode case mapping adapted for Turkic languages" do
+ it "capitalizes ASCII characters according to Turkic semantics" do
+ "iSa".capitalize(:turkic).should == "İsa"
+ end
+
+ it "allows Lithuanian as an extra option" do
+ "iSa".capitalize(:turkic, :lithuanian).should == "İsa"
+ end
+
+ it "does not allow any other additional option" do
+ -> { "iSa".capitalize(:turkic, :ascii) }.should raise_error(ArgumentError)
end
end
- it "returns subclass instances when called on a subclass" do
- StringSpecs::MyString.new("hello").capitalize.should be_an_instance_of(StringSpecs::MyString)
- StringSpecs::MyString.new("Hello").capitalize.should be_an_instance_of(StringSpecs::MyString)
+ describe "full Unicode case mapping adapted for Lithuanian" do
+ it "currently works the same as full Unicode case mapping" do
+ "iß".capitalize(:lithuanian).should == "Iß"
+ end
+
+ it "allows Turkic as an extra option (and applies Turkic semantics)" do
+ "iß".capitalize(:lithuanian, :turkic).should == "İß"
+ end
+
+ it "does not allow any other additional option" do
+ -> { "iß".capitalize(:lithuanian, :ascii) }.should raise_error(ArgumentError)
+ end
+ end
+
+ it "does not allow the :fold option for upcasing" do
+ -> { "abc".capitalize(:fold) }.should raise_error(ArgumentError)
+ end
+
+ it "does not allow invalid options" do
+ -> { "abc".capitalize(:invalid_option) }.should raise_error(ArgumentError)
+ end
+
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("hello").capitalize.should be_an_instance_of(String)
+ StringSpecs::MyString.new("Hello").capitalize.should be_an_instance_of(String)
+ end
+
+ it "returns a String in the same encoding as self" do
+ "h".encode("US-ASCII").capitalize.encoding.should == Encoding::US_ASCII
end
end
describe "String#capitalize!" do
it "capitalizes self in place" do
- a = "hello"
+ a = +"hello"
a.capitalize!.should equal(a)
a.should == "Hello"
end
- ruby_version_is '2.4' do
- it "capitalizes self in place for all of Unicode" do
- a = "äöü"
- a.capitalize!.should equal(a)
+ it "modifies self in place for non-ascii-compatible encodings" do
+ a = "heLLo".encode("utf-16le")
+ a.capitalize!
+ a.should == "Hello".encode("utf-16le")
+ end
+
+ describe "full Unicode case mapping" do
+ it "modifies self in place for all of Unicode with no option" do
+ a = +"äöÜ"
+ a.capitalize!
a.should == "Äöü"
end
+
+ it "only capitalizes the first resulting character when upcasing a character produces a multi-character sequence" do
+ a = +"ß"
+ a.capitalize!
+ a.should == "Ss"
+ end
+
+ it "works for non-ascii-compatible encodings" do
+ a = "äöü".encode("utf-16le")
+ a.capitalize!
+ a.should == "Äöü".encode("utf-16le")
+ end
+
+ it "updates string metadata" do
+ capitalized = +"ßeT"
+ capitalized.capitalize!
+
+ capitalized.should == "Sset"
+ capitalized.size.should == 4
+ capitalized.bytesize.should == 4
+ capitalized.ascii_only?.should be_true
+ end
+ end
+
+ describe "modifies self in place for ASCII-only case mapping" do
+ it "does not capitalize non-ASCII characters" do
+ a = +"ßet"
+ a.capitalize!(:ascii)
+ a.should == "ßet"
+ end
+
+ it "works for non-ascii-compatible encodings" do
+ a = "aBc".encode("utf-16le")
+ a.capitalize!(:ascii)
+ a.should == "Abc".encode("utf-16le")
+ end
+ end
+
+ describe "modifies self in place for full Unicode case mapping adapted for Turkic languages" do
+ it "capitalizes ASCII characters according to Turkic semantics" do
+ a = +"iSa"
+ a.capitalize!(:turkic)
+ a.should == "İsa"
+ end
+
+ it "allows Lithuanian as an extra option" do
+ a = +"iSa"
+ a.capitalize!(:turkic, :lithuanian)
+ a.should == "İsa"
+ end
+
+ it "does not allow any other additional option" do
+ -> { a = "iSa"; a.capitalize!(:turkic, :ascii) }.should raise_error(ArgumentError)
+ end
+ end
+
+ describe "modifies self in place for full Unicode case mapping adapted for Lithuanian" do
+ it "currently works the same as full Unicode case mapping" do
+ a = +"iß"
+ a.capitalize!(:lithuanian)
+ a.should == "Iß"
+ end
+
+ it "allows Turkic as an extra option (and applies Turkic semantics)" do
+ a = +"iß"
+ a.capitalize!(:lithuanian, :turkic)
+ a.should == "İß"
+ end
+
+ it "does not allow any other additional option" do
+ -> { a = "iß"; a.capitalize!(:lithuanian, :ascii) }.should raise_error(ArgumentError)
+ end
+ end
+
+ it "does not allow the :fold option for upcasing" do
+ -> { a = "abc"; a.capitalize!(:fold) }.should raise_error(ArgumentError)
+ end
+
+ it "does not allow invalid options" do
+ -> { a = "abc"; a.capitalize!(:invalid_option) }.should raise_error(ArgumentError)
end
it "returns nil when no changes are made" do
- a = "Hello"
+ a = +"Hello"
a.capitalize!.should == nil
a.should == "Hello"
- "".capitalize!.should == nil
- "H".capitalize!.should == nil
+ (+"").capitalize!.should == nil
+ (+"H").capitalize!.should == nil
end
- it "raises a RuntimeError when self is frozen" do
+ it "raises a FrozenError when self is frozen" do
["", "Hello", "hello"].each do |a|
a.freeze
- lambda { a.capitalize! }.should raise_error(RuntimeError)
+ -> { a.capitalize! }.should raise_error(FrozenError)
end
end
end
diff --git a/spec/ruby/core/string/case_compare_spec.rb b/spec/ruby/core/string/case_compare_spec.rb
index 930f5bea90..b83d1adb91 100644
--- a/spec/ruby/core/string/case_compare_spec.rb
+++ b/spec/ruby/core/string/case_compare_spec.rb
@@ -1,8 +1,8 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../shared/eql', __FILE__)
-require File.expand_path('../shared/equal_value', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'shared/eql'
+require_relative 'shared/equal_value'
describe "String#===" do
- it_behaves_like(:string_eql_value, :===)
- it_behaves_like(:string_equal_value, :===)
+ it_behaves_like :string_eql_value, :===
+ it_behaves_like :string_equal_value, :===
end
diff --git a/spec/ruby/core/string/casecmp_spec.rb b/spec/ruby/core/string/casecmp_spec.rb
index c77d97815c..81ebea557c 100644
--- a/spec/ruby/core/string/casecmp_spec.rb
+++ b/spec/ruby/core/string/casecmp_spec.rb
@@ -1,6 +1,6 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String#casecmp independent of case" do
it "returns -1 when less than other" do
@@ -25,16 +25,12 @@ describe "String#casecmp independent of case" do
"abc".casecmp(other).should == 0
end
- ruby_version_is ""..."2.5" do
- it "raises a TypeError if other can't be converted to a string" do
- lambda { "abc".casecmp(mock('abc')) }.should raise_error(TypeError)
- end
+ it "returns nil if other can't be converted to a string" do
+ "abc".casecmp(mock('abc')).should be_nil
end
- ruby_version_is "2.5" do
- it "returns nil if other can't be converted to a string" do
- "abc".casecmp(mock('abc')).should be_nil
- end
+ it "returns nil if incompatible encodings" do
+ "あれ".casecmp("れ".encode(Encoding::EUC_JP)).should be_nil
end
describe "in UTF-8 mode" do
@@ -96,6 +92,10 @@ describe "String#casecmp independent of case" do
it "returns 1 when numerically greater than other" do
@lower_a_tilde.casecmp(@upper_a_tilde).should == 1
end
+
+ it "does not case fold" do
+ "ß".casecmp("ss").should == 1
+ end
end
describe "when comparing a subclass instance" do
@@ -117,68 +117,88 @@ describe "String#casecmp independent of case" do
"B".casecmp(a).should == 1
end
end
+
+ it "returns 0 for empty strings in different encodings" do
+ ''.b.casecmp('').should == 0
+ ''.b.casecmp(''.encode("UTF-32LE")).should == 0
+ end
end
-ruby_version_is "2.4" do
- describe 'String#casecmp? independent of case' do
- it 'returns true when equal to other' do
- 'abc'.casecmp?('abc').should == true
- 'abc'.casecmp?('ABC').should == true
- end
+describe 'String#casecmp? independent of case' do
+ it 'returns true when equal to other' do
+ 'abc'.casecmp?('abc').should == true
+ 'abc'.casecmp?('ABC').should == true
+ end
- it 'returns false when not equal to other' do
- 'abc'.casecmp?('DEF').should == false
- 'abc'.casecmp?('def').should == false
+ it 'returns false when not equal to other' do
+ 'abc'.casecmp?('DEF').should == false
+ 'abc'.casecmp?('def').should == false
+ end
+
+ it "tries to convert other to string using to_str" do
+ other = mock('x')
+ other.should_receive(:to_str).and_return("abc")
+
+ "abc".casecmp?(other).should == true
+ end
+
+ it "returns nil if incompatible encodings" do
+ "あれ".casecmp?("れ".encode(Encoding::EUC_JP)).should be_nil
+ end
+
+ describe 'for UNICODE characters' do
+ it 'returns true when downcase(:fold) on unicode' do
+ 'äöü'.casecmp?('ÄÖÜ').should == true
end
+ end
- it "tries to convert other to string using to_str" do
- other = mock('x')
- other.should_receive(:to_str).and_return("abc")
+ describe "when comparing a subclass instance" do
+ it 'returns true when equal to other' do
+ a = StringSpecs::MyString.new "a"
+ 'a'.casecmp?(a).should == true
+ 'A'.casecmp?(a).should == true
+ end
- "abc".casecmp?(other).should == true
+ it 'returns false when not equal to other' do
+ b = StringSpecs::MyString.new "a"
+ 'b'.casecmp?(b).should == false
+ 'B'.casecmp?(b).should == false
end
+ end
- describe 'for UNICODE characters' do
- it 'returns true when downcase(:fold) on unicode' do
- 'äöü'.casecmp?('ÄÖÜ').should == true
+ describe "in UTF-8 mode" do
+ describe "for non-ASCII characters" do
+ before :each do
+ @upper_a_tilde = "Ã"
+ @lower_a_tilde = "ã"
+ @upper_a_umlaut = "Ä"
+ @lower_a_umlaut = "ä"
end
- end
- describe "when comparing a subclass instance" do
- it 'returns true when equal to other' do
- a = StringSpecs::MyString.new "a"
- 'a'.casecmp?(a).should == true
- 'A'.casecmp?(a).should == true
+ it "returns true when they are the same with normalized case" do
+ @upper_a_tilde.casecmp?(@lower_a_tilde).should == true
end
- it 'returns false when not equal to other' do
- b = StringSpecs::MyString.new "a"
- 'b'.casecmp?(b).should == false
- 'B'.casecmp?(b).should == false
+ it "returns false when they are unrelated" do
+ @upper_a_tilde.casecmp?(@upper_a_umlaut).should == false
end
- end
- describe "in UTF-8 mode" do
- describe "for non-ASCII characters" do
- before :each do
- @upper_a_tilde = "Ã"
- @lower_a_tilde = "ã"
- @upper_a_umlaut = "Ä"
- @lower_a_umlaut = "ä"
- end
-
- it "returns true when they are the same with normalized case" do
- @upper_a_tilde.casecmp?(@lower_a_tilde).should == true
- end
-
- it "returns false when they are unrelated" do
- @upper_a_tilde.casecmp?(@upper_a_umlaut).should == false
- end
-
- it "returns true when they have the same bytes" do
- @upper_a_tilde.casecmp?(@upper_a_tilde).should == true
- end
+ it "returns true when they have the same bytes" do
+ @upper_a_tilde.casecmp?(@upper_a_tilde).should == true
end
end
end
+
+ it "case folds" do
+ "ß".casecmp?("ss").should be_true
+ end
+
+ it "returns nil if other can't be converted to a string" do
+ "abc".casecmp?(mock('abc')).should be_nil
+ end
+
+ it "returns true for empty strings in different encodings" do
+ ''.b.should.casecmp?('')
+ ''.b.should.casecmp?(''.encode("UTF-32LE"))
+ end
end
diff --git a/spec/ruby/core/string/center_spec.rb b/spec/ruby/core/string/center_spec.rb
index 4a40ef88bf..1667b59327 100644
--- a/spec/ruby/core/string/center_spec.rb
+++ b/spec/ruby/core/string/center_spec.rb
@@ -1,6 +1,6 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String#center with length, padding" do
it "returns a new string of specified length with self centered and padded with padstr" do
@@ -47,14 +47,6 @@ describe "String#center with length, padding" do
"radiology".center(8, '-').should == "radiology"
end
- it "taints result when self or padstr is tainted" do
- "x".taint.center(4).tainted?.should == true
- "x".taint.center(0).tainted?.should == true
- "".taint.center(0).tainted?.should == true
- "x".taint.center(4, "*").tainted?.should == true
- "x".center(4, "*".taint).tainted?.should == true
- end
-
it "calls #to_int to convert length to an integer" do
"_".center(3.8, "^").should == "^_^"
@@ -65,10 +57,10 @@ describe "String#center with length, padding" do
end
it "raises a TypeError when length can't be converted to an integer" do
- lambda { "hello".center("x") }.should raise_error(TypeError)
- lambda { "hello".center("x", "y") }.should raise_error(TypeError)
- lambda { "hello".center([]) }.should raise_error(TypeError)
- lambda { "hello".center(mock('x')) }.should raise_error(TypeError)
+ -> { "hello".center("x") }.should raise_error(TypeError)
+ -> { "hello".center("x", "y") }.should raise_error(TypeError)
+ -> { "hello".center([]) }.should raise_error(TypeError)
+ -> { "hello".center(mock('x')) }.should raise_error(TypeError)
end
it "calls #to_str to convert padstr to a String" do
@@ -79,55 +71,47 @@ describe "String#center with length, padding" do
end
it "raises a TypeError when padstr can't be converted to a string" do
- lambda { "hello".center(20, 100) }.should raise_error(TypeError)
- lambda { "hello".center(20, []) }.should raise_error(TypeError)
- lambda { "hello".center(20, mock('x')) }.should raise_error(TypeError)
+ -> { "hello".center(20, 100) }.should raise_error(TypeError)
+ -> { "hello".center(20, []) }.should raise_error(TypeError)
+ -> { "hello".center(20, mock('x')) }.should raise_error(TypeError)
end
it "raises an ArgumentError if padstr is empty" do
- lambda { "hello".center(10, "") }.should raise_error(ArgumentError)
- lambda { "hello".center(0, "") }.should raise_error(ArgumentError)
+ -> { "hello".center(10, "") }.should raise_error(ArgumentError)
+ -> { "hello".center(0, "") }.should raise_error(ArgumentError)
end
- it "returns subclass instances when called on subclasses" do
- StringSpecs::MyString.new("").center(10).should be_an_instance_of(StringSpecs::MyString)
- StringSpecs::MyString.new("foo").center(10).should be_an_instance_of(StringSpecs::MyString)
- StringSpecs::MyString.new("foo").center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(StringSpecs::MyString)
+ it "returns String instances when called on subclasses" do
+ StringSpecs::MyString.new("").center(10).should be_an_instance_of(String)
+ StringSpecs::MyString.new("foo").center(10).should be_an_instance_of(String)
+ StringSpecs::MyString.new("foo").center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
"".center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
"foo".center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
end
- it "when padding is tainted and self is untainted returns a tainted string if and only if length is longer than self" do
- "hello".center(4, 'X'.taint).tainted?.should be_false
- "hello".center(5, 'X'.taint).tainted?.should be_false
- "hello".center(6, 'X'.taint).tainted?.should be_true
+ describe "with width" do
+ it "returns a String in the same encoding as the original" do
+ str = "abc".dup.force_encoding Encoding::IBM437
+ result = str.center 6
+ result.should == " abc "
+ result.encoding.should equal(Encoding::IBM437)
+ end
end
- with_feature :encoding do
- describe "with width" do
- it "returns a String in the same encoding as the original" do
- str = "abc".force_encoding Encoding::IBM437
- result = str.center 6
- result.should == " abc "
- result.encoding.should equal(Encoding::IBM437)
- end
+ describe "with width, pattern" do
+ it "returns a String in the compatible encoding" do
+ str = "abc".dup.force_encoding Encoding::IBM437
+ result = str.center 6, "あ"
+ result.should == "あabcああ"
+ result.encoding.should equal(Encoding::UTF_8)
end
- describe "with width, pattern" do
- it "returns a String in the compatible encoding" do
- str = "abc".force_encoding Encoding::IBM437
- result = str.center 6, "あ"
- result.should == "あabcああ"
- result.encoding.should equal(Encoding::UTF_8)
- end
-
- it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
- pat = "ア".encode Encoding::EUC_JP
- lambda do
- "あれ".center 5, pat
- end.should raise_error(Encoding::CompatibilityError)
- end
+ it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
+ pat = "ア".encode Encoding::EUC_JP
+ -> do
+ "あれ".center 5, pat
+ end.should raise_error(Encoding::CompatibilityError)
end
end
end
diff --git a/spec/ruby/core/string/chars_spec.rb b/spec/ruby/core/string/chars_spec.rb
index 75cef89be1..ee85430574 100644
--- a/spec/ruby/core/string/chars_spec.rb
+++ b/spec/ruby/core/string/chars_spec.rb
@@ -1,11 +1,16 @@
-require File.expand_path('../shared/chars', __FILE__)
-require File.expand_path('../shared/each_char_without_block', __FILE__)
+require_relative "../../spec_helper"
+require_relative 'shared/chars'
describe "String#chars" do
- it_behaves_like(:string_chars, :chars)
+ it_behaves_like :string_chars, :chars
it "returns an array when no block given" do
- ary = "hello".send(@method)
- ary.should == ['h', 'e', 'l', 'l', 'o']
+ "hello".chars.should == ['h', 'e', 'l', 'l', 'o']
+ end
+
+ it "returns Strings in the same encoding as self" do
+ "hello".encode("US-ASCII").chars.each do |c|
+ c.encoding.should == Encoding::US_ASCII
+ end
end
end
diff --git a/spec/ruby/core/string/chilled_string_spec.rb b/spec/ruby/core/string/chilled_string_spec.rb
new file mode 100644
index 0000000000..73d055cbdf
--- /dev/null
+++ b/spec/ruby/core/string/chilled_string_spec.rb
@@ -0,0 +1,151 @@
+require_relative '../../spec_helper'
+
+describe "chilled String" do
+ guard -> { ruby_version_is "3.4" and !"test".equal?("test") } do
+ describe "chilled string literals" do
+
+ describe "#frozen?" do
+ it "returns false" do
+ "chilled".frozen?.should == false
+ end
+ end
+
+ describe "#-@" do
+ it "returns a different instance" do
+ input = "chilled"
+ interned = (-input)
+ interned.frozen?.should == true
+ interned.object_id.should_not == input.object_id
+ end
+ end
+
+ describe "#+@" do
+ it "returns a different instance" do
+ input = "chilled"
+ duped = (+input)
+ duped.frozen?.should == false
+ duped.object_id.should_not == input.object_id
+ end
+ end
+
+ describe "#clone" do
+ it "preserves chilled status" do
+ input = "chilled".clone
+ -> {
+ input << "-mutated"
+ }.should complain(/literal string will be frozen in the future/)
+ input.should == "chilled-mutated"
+ end
+ end
+
+ describe "mutation" do
+ it "emits a warning" do
+ input = "chilled"
+ -> {
+ input << "-mutated"
+ }.should complain(/literal string will be frozen in the future/)
+ input.should == "chilled-mutated"
+ end
+
+ it "emits a warning for concatenated strings" do
+ input = "still" "+chilled"
+ -> {
+ input << "-mutated"
+ }.should complain(/literal string will be frozen in the future/)
+ input.should == "still+chilled-mutated"
+ end
+
+ it "emits a warning on singleton_class creation" do
+ -> {
+ "chilled".singleton_class
+ }.should complain(/literal string will be frozen in the future/)
+ end
+
+ it "emits a warning on instance variable assignment" do
+ -> {
+ "chilled".instance_variable_set(:@ivar, 42)
+ }.should complain(/literal string will be frozen in the future/)
+ end
+
+ it "raises FrozenError after the string was explicitly frozen" do
+ input = "chilled"
+ input.freeze
+ -> {
+ -> {
+ input << "mutated"
+ }.should raise_error(FrozenError)
+ }.should_not complain(/literal string will be frozen in the future/)
+ end
+ end
+ end
+
+ describe "chilled strings returned by Symbol#to_s" do
+
+ describe "#frozen?" do
+ it "returns false" do
+ :chilled.to_s.frozen?.should == false
+ end
+ end
+
+ describe "#-@" do
+ it "returns a different instance" do
+ input = :chilled.to_s
+ interned = (-input)
+ interned.frozen?.should == true
+ interned.object_id.should_not == input.object_id
+ end
+ end
+
+ describe "#+@" do
+ it "returns a different instance" do
+ input = :chilled.to_s
+ duped = (+input)
+ duped.frozen?.should == false
+ duped.object_id.should_not == input.object_id
+ end
+ end
+
+ describe "#clone" do
+ it "preserves chilled status" do
+ input = :chilled.to_s.clone
+ -> {
+ input << "-mutated"
+ }.should complain(/string returned by :chilled\.to_s will be frozen in the future/)
+ input.should == "chilled-mutated"
+ end
+ end
+
+ describe "mutation" do
+ it "emits a warning" do
+ input = :chilled.to_s
+ -> {
+ input << "-mutated"
+ }.should complain(/string returned by :chilled\.to_s will be frozen in the future/)
+ input.should == "chilled-mutated"
+ end
+
+ it "emits a warning on singleton_class creation" do
+ -> {
+ :chilled.to_s.singleton_class
+ }.should complain(/string returned by :chilled\.to_s will be frozen in the future/)
+ end
+
+ it "emits a warning on instance variable assignment" do
+ -> {
+ :chilled.to_s.instance_variable_set(:@ivar, 42)
+ }.should complain(/string returned by :chilled\.to_s will be frozen in the future/)
+ end
+
+ it "raises FrozenError after the string was explicitly frozen" do
+ input = :chilled.to_s
+ input.freeze
+ -> {
+ -> {
+ input << "mutated"
+ }.should raise_error(FrozenError)
+ }.should_not complain(/string returned by :chilled\.to_s will be frozen in the future/)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/string/chomp_spec.rb b/spec/ruby/core/string/chomp_spec.rb
index 5daa8c5a40..d27c84c6f6 100644
--- a/spec/ruby/core/string/chomp_spec.rb
+++ b/spec/ruby/core/string/chomp_spec.rb
@@ -1,16 +1,19 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+# frozen_string_literal: false
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String#chomp" do
describe "when passed no argument" do
before do
# Ensure that $/ is set to the default value
+ @verbose, $VERBOSE = $VERBOSE, nil
@dollar_slash, $/ = $/, "\n"
end
after do
$/ = @dollar_slash
+ $VERBOSE = @verbose
end
it "does not modify a String with no trailing carriage return or newline" do
@@ -30,7 +33,7 @@ describe "String#chomp" do
"abc\r\r".chomp.should == "abc\r"
end
- it "removes one trailing carrige return, newline pair" do
+ it "removes one trailing carriage return, newline pair" do
"abc\r\n\r\n".chomp.should == "abc\r\n"
end
@@ -38,19 +41,23 @@ describe "String#chomp" do
"".chomp.should == ""
end
- it "taints the result if self is tainted" do
- "abc".taint.chomp.tainted?.should be_true
+ it "returns a String in the same encoding as self" do
+ "abc\n\n".encode("US-ASCII").chomp.encoding.should == Encoding::US_ASCII
end
- it "returns subclass instances when called on a subclass" do
+ it "returns String instances when called on a subclass" do
str = StringSpecs::MyString.new("hello\n").chomp
- str.should be_an_instance_of(StringSpecs::MyString)
+ str.should be_an_instance_of(String)
end
it "removes trailing characters that match $/ when it has been assigned a value" do
$/ = "cdef"
"abcdef".chomp.should == "ab"
end
+
+ it "removes one trailing newline for string with invalid encoding" do
+ "\xa0\xa1\n".chomp.should == "\xa0\xa1"
+ end
end
describe "when passed nil" do
@@ -63,10 +70,6 @@ describe "String#chomp" do
str.chomp(nil).should_not equal(str)
end
- it "taints the result if self is tainted" do
- "abc".taint.chomp(nil).tainted?.should be_true
- end
-
it "returns an empty String when self is empty" do
"".chomp(nil).should == ""
end
@@ -93,13 +96,13 @@ describe "String#chomp" do
"abc\r\n\r\n\r\n".chomp("").should == "abc"
end
- it "taints the result if self is tainted" do
- "abc".taint.chomp("").tainted?.should be_true
- end
-
it "returns an empty String when self is empty" do
"".chomp("").should == ""
end
+
+ it "removes one trailing newline for string with invalid encoding" do
+ "\xa0\xa1\n".chomp("").should == "\xa0\xa1"
+ end
end
describe "when passed '\\n'" do
@@ -111,14 +114,10 @@ describe "String#chomp" do
"abc\r\r".chomp("\n").should == "abc\r"
end
- it "removes one trailing carrige return, newline pair" do
+ it "removes one trailing carriage return, newline pair" do
"abc\r\n\r\n".chomp("\n").should == "abc\r\n"
end
- it "taints the result if self is tainted" do
- "abc".taint.chomp("\n").tainted?.should be_true
- end
-
it "returns an empty String when self is empty" do
"".chomp("\n").should == ""
end
@@ -134,7 +133,7 @@ describe "String#chomp" do
it "raises a TypeError if #to_str does not return a String" do
arg = mock("string chomp")
arg.should_receive(:to_str).and_return(1)
- lambda { "abc".chomp(arg) }.should raise_error(TypeError)
+ -> { "abc".chomp(arg) }.should raise_error(TypeError)
end
end
@@ -151,12 +150,8 @@ describe "String#chomp" do
"".chomp("abc").should == ""
end
- it "taints the result if self is tainted" do
- "abc".taint.chomp("abc").tainted?.should be_true
- end
-
- it "does not taint the result when the argument is tainted" do
- "abc".chomp("abc".taint).tainted?.should be_false
+ it "returns an empty String when the argument equals self" do
+ "abc".chomp("abc").should == ""
end
end
end
@@ -165,11 +160,13 @@ describe "String#chomp!" do
describe "when passed no argument" do
before do
# Ensure that $/ is set to the default value
+ @verbose, $VERBOSE = $VERBOSE, nil
@dollar_slash, $/ = $/, "\n"
end
after do
$/ = @dollar_slash
+ $VERBOSE = @verbose
end
it "modifies self" do
@@ -189,7 +186,7 @@ describe "String#chomp!" do
"abc\r\r".chomp!.should == "abc\r"
end
- it "removes one trailing carrige return, newline pair" do
+ it "removes one trailing carriage return, newline pair" do
"abc\r\n\r\n".chomp!.should == "abc\r\n"
end
@@ -197,10 +194,6 @@ describe "String#chomp!" do
"".chomp!.should be_nil
end
- it "taints the result if self is tainted" do
- "abc\n".taint.chomp!.tainted?.should be_true
- end
-
it "returns subclass instances when called on a subclass" do
str = StringSpecs::MyString.new("hello\n").chomp!
str.should be_an_instance_of(StringSpecs::MyString)
@@ -243,10 +236,6 @@ describe "String#chomp!" do
"abc\r\n\r\n\r\n".chomp!("").should == "abc"
end
- it "taints the result if self is tainted" do
- "abc\n".taint.chomp!("").tainted?.should be_true
- end
-
it "returns nil when self is empty" do
"".chomp!("").should be_nil
end
@@ -261,14 +250,10 @@ describe "String#chomp!" do
"abc\r\r".chomp!("\n").should == "abc\r"
end
- it "removes one trailing carrige return, newline pair" do
+ it "removes one trailing carriage return, newline pair" do
"abc\r\n\r\n".chomp!("\n").should == "abc\r\n"
end
- it "taints the result if self is tainted" do
- "abc\n".taint.chomp!("\n").tainted?.should be_true
- end
-
it "returns nil when self is empty" do
"".chomp!("\n").should be_nil
end
@@ -284,7 +269,7 @@ describe "String#chomp!" do
it "raises a TypeError if #to_str does not return a String" do
arg = mock("string chomp")
arg.should_receive(:to_str).and_return(1)
- lambda { "abc".chomp!(arg) }.should raise_error(TypeError)
+ -> { "abc".chomp!(arg) }.should raise_error(TypeError)
end
end
@@ -300,88 +285,82 @@ describe "String#chomp!" do
it "returns nil when self is empty" do
"".chomp!("abc").should be_nil
end
-
- it "taints the result if self is tainted" do
- "abc".taint.chomp!("abc").tainted?.should be_true
- end
-
- it "does not taint the result when the argument is tainted" do
- "abc".chomp!("abc".taint).tainted?.should be_false
- end
end
- it "raises a RuntimeError on a frozen instance when it is modified" do
+ it "raises a FrozenError on a frozen instance when it is modified" do
a = "string\n\r"
a.freeze
- lambda { a.chomp! }.should raise_error(RuntimeError)
+ -> { a.chomp! }.should raise_error(FrozenError)
end
# see [ruby-core:23666]
- it "raises a RuntimeError on a frozen instance when it would not be modified" do
+ it "raises a FrozenError on a frozen instance when it would not be modified" do
a = "string\n\r"
a.freeze
- lambda { a.chomp!(nil) }.should raise_error(RuntimeError)
- lambda { a.chomp!("x") }.should raise_error(RuntimeError)
+ -> { a.chomp!(nil) }.should raise_error(FrozenError)
+ -> { a.chomp!("x") }.should raise_error(FrozenError)
end
end
-with_feature :encoding do
- describe "String#chomp" do
- before :each do
- @before_separator = $/
- end
+describe "String#chomp" do
+ before :each do
+ @verbose, $VERBOSE = $VERBOSE, nil
+ @before_separator = $/
+ end
- after :each do
- $/ = @before_separator
- end
+ after :each do
+ $/ = @before_separator
+ $VERBOSE = @verbose
+ end
- it "does not modify a multi-byte character" do
- "あれ".chomp.should == "あれ"
- end
+ it "does not modify a multi-byte character" do
+ "あれ".chomp.should == "あれ"
+ end
- it "removes the final carriage return, newline from a multibyte String" do
- "あれ\r\n".chomp.should == "あれ"
- end
+ it "removes the final carriage return, newline from a multibyte String" do
+ "あれ\r\n".chomp.should == "あれ"
+ end
- it "removes the final carriage return, newline from a non-ASCII String" do
- str = "abc\r\n".encode "utf-32be"
- str.chomp.should == "abc".encode("utf-32be")
- end
+ it "removes the final carriage return, newline from a non-ASCII String" do
+ str = "abc\r\n".encode "utf-32be"
+ str.chomp.should == "abc".encode("utf-32be")
+ end
- it "removes the final carriage return, newline from a non-ASCII String when the record separator is changed" do
- $/ = "\n".encode("utf-8")
- str = "abc\r\n".encode "utf-32be"
- str.chomp.should == "abc".encode("utf-32be")
- end
+ it "removes the final carriage return, newline from a non-ASCII String when the record separator is changed" do
+ $/ = "\n".encode("utf-8")
+ str = "abc\r\n".encode "utf-32be"
+ str.chomp.should == "abc".encode("utf-32be")
end
+end
- describe "String#chomp!" do
- before :each do
- @before_separator = $/
- end
+describe "String#chomp!" do
+ before :each do
+ @verbose, $VERBOSE = $VERBOSE, nil
+ @before_separator = $/
+ end
- after :each do
- $/ = @before_separator
- end
+ after :each do
+ $/ = @before_separator
+ $VERBOSE = @verbose
+ end
- it "returns nil when the String is not modified" do
- "あれ".chomp!.should be_nil
- end
+ it "returns nil when the String is not modified" do
+ "あれ".chomp!.should be_nil
+ end
- it "removes the final carriage return, newline from a multibyte String" do
- "あれ\r\n".chomp!.should == "あれ"
- end
+ it "removes the final carriage return, newline from a multibyte String" do
+ "あれ\r\n".chomp!.should == "あれ"
+ end
- it "removes the final carriage return, newline from a non-ASCII String" do
- str = "abc\r\n".encode "utf-32be"
- str.chomp!.should == "abc".encode("utf-32be")
- end
+ it "removes the final carriage return, newline from a non-ASCII String" do
+ str = "abc\r\n".encode "utf-32be"
+ str.chomp!.should == "abc".encode("utf-32be")
+ end
- it "removes the final carriage return, newline from a non-ASCII String when the record separator is changed" do
- $/ = "\n".encode("utf-8")
- str = "abc\r\n".encode "utf-32be"
- str.chomp!.should == "abc".encode("utf-32be")
- end
+ it "removes the final carriage return, newline from a non-ASCII String when the record separator is changed" do
+ $/ = "\n".encode("utf-8")
+ str = "abc\r\n".encode "utf-32be"
+ str.chomp!.should == "abc".encode("utf-32be")
end
end
diff --git a/spec/ruby/core/string/chop_spec.rb b/spec/ruby/core/string/chop_spec.rb
index 4e9a39f866..99c2c82190 100644
--- a/spec/ruby/core/string/chop_spec.rb
+++ b/spec/ruby/core/string/chop_spec.rb
@@ -1,6 +1,7 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+# frozen_string_literal: false
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String#chop" do
it "removes the final character" do
@@ -19,7 +20,7 @@ describe "String#chop" do
"abc\r\n".chop.should == "abc"
end
- it "removes the carrige return, newline if they are the only characters" do
+ it "removes the carriage return, newline if they are the only characters" do
"\r\n".chop.should == ""
end
@@ -27,19 +28,17 @@ describe "String#chop" do
"abc\r\n\r\n".chop.should == "abc\r\n"
end
- with_feature :encoding do
- it "removes a multi-byte character" do
- "あれ".chop.should == "あ"
- end
+ it "removes a multi-byte character" do
+ "あれ".chop.should == "あ"
+ end
- it "removes the final carriage return, newline from a multibyte String" do
- "あれ\r\n".chop.should == "あれ"
- end
+ it "removes the final carriage return, newline from a multibyte String" do
+ "あれ\r\n".chop.should == "あれ"
+ end
- it "removes the final carriage return, newline from a non-ASCII String" do
- str = "abc\r\n".encode "utf-32be"
- str.chop.should == "abc".encode("utf-32be")
- end
+ it "removes the final carriage return, newline from a non-ASCII String" do
+ str = "abc\r\n".encode "utf-32be"
+ str.chop.should == "abc".encode("utf-32be")
end
it "returns an empty string when applied to an empty string" do
@@ -51,18 +50,12 @@ describe "String#chop" do
s.chop.should_not equal(s)
end
- it "taints result when self is tainted" do
- "hello".taint.chop.tainted?.should == true
- "".taint.chop.tainted?.should == true
- end
-
- it "untrusts result when self is untrusted" do
- "hello".untrust.chop.untrusted?.should == true
- "".untrust.chop.untrusted?.should == true
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("hello\n").chop.should be_an_instance_of(String)
end
- it "returns subclass instances when called on a subclass" do
- StringSpecs::MyString.new("hello\n").chop.should be_an_instance_of(StringSpecs::MyString)
+ it "returns a String in the same encoding as self" do
+ "abc\n\n".encode("US-ASCII").chop.encoding.should == Encoding::US_ASCII
end
end
@@ -83,7 +76,7 @@ describe "String#chop!" do
"abc\r\n".chop!.should == "abc"
end
- it "removes the carrige return, newline if they are the only characters" do
+ it "removes the carriage return, newline if they are the only characters" do
"\r\n".chop!.should == ""
end
@@ -91,19 +84,17 @@ describe "String#chop!" do
"abc\r\n\r\n".chop!.should == "abc\r\n"
end
- with_feature :encoding do
- it "removes a multi-byte character" do
- "あれ".chop!.should == "あ"
- end
+ it "removes a multi-byte character" do
+ "あれ".chop!.should == "あ"
+ end
- it "removes the final carriage return, newline from a multibyte String" do
- "あれ\r\n".chop!.should == "あれ"
- end
+ it "removes the final carriage return, newline from a multibyte String" do
+ "あれ\r\n".chop!.should == "あれ"
+ end
- it "removes the final carriage return, newline from a non-ASCII String" do
- str = "abc\r\n".encode "utf-32be"
- str.chop!.should == "abc".encode("utf-32be")
- end
+ it "removes the final carriage return, newline from a non-ASCII String" do
+ str = "abc\r\n".encode "utf-32be"
+ str.chop!.should == "abc".encode("utf-32be")
end
it "returns self if modifications were made" do
@@ -115,14 +106,14 @@ describe "String#chop!" do
"".chop!.should be_nil
end
- it "raises a RuntimeError on a frozen instance that is modified" do
- lambda { "string\n\r".freeze.chop! }.should raise_error(RuntimeError)
+ it "raises a FrozenError on a frozen instance that is modified" do
+ -> { "string\n\r".freeze.chop! }.should raise_error(FrozenError)
end
# see [ruby-core:23666]
- it "raises a RuntimeError on a frozen instance that would not be modified" do
+ it "raises a FrozenError on a frozen instance that would not be modified" do
a = ""
a.freeze
- lambda { a.chop! }.should raise_error(RuntimeError)
+ -> { a.chop! }.should raise_error(FrozenError)
end
end
diff --git a/spec/ruby/core/string/chr_spec.rb b/spec/ruby/core/string/chr_spec.rb
index c7834b78b7..9ed29542e6 100644
--- a/spec/ruby/core/string/chr_spec.rb
+++ b/spec/ruby/core/string/chr_spec.rb
@@ -1,44 +1,42 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-
-with_feature :encoding do
- describe "String#chr" do
- it "returns a copy of self" do
- s = 'e'
- s.object_id.should_not == s.chr.object_id
- end
-
- it "returns a String" do
- 'glark'.chr.should be_an_instance_of(String)
- end
-
- it "returns an empty String if self is an empty String" do
- "".chr.should == ""
- end
-
- it "returns a 1-character String" do
- "glark".chr.size.should == 1
- end
-
- it "returns the character at the start of the String" do
- "Goodbye, world".chr.should == "G"
- end
-
- it "returns a String in the same encoding as self" do
- "\x24".encode(Encoding::US_ASCII).chr.encoding.should == Encoding::US_ASCII
- end
-
- it "understands multi-byte characters" do
- s = "\u{9879}"
- s.bytesize.should == 3
- s.chr.should == s
- end
-
- it "understands Strings that contain a mixture of character widths" do
- three = "\u{8082}"
- three.bytesize.should == 3
- four = "\u{77082}"
- four.bytesize.should == 4
- "#{three}#{four}".chr.should == three
- end
+require_relative '../../spec_helper'
+
+describe "String#chr" do
+ it "returns a copy of self" do
+ s = 'e'
+ s.should_not equal s.chr
+ end
+
+ it "returns a String" do
+ 'glark'.chr.should be_an_instance_of(String)
+ end
+
+ it "returns an empty String if self is an empty String" do
+ "".chr.should == ""
+ end
+
+ it "returns a 1-character String" do
+ "glark".chr.size.should == 1
+ end
+
+ it "returns the character at the start of the String" do
+ "Goodbye, world".chr.should == "G"
+ end
+
+ it "returns a String in the same encoding as self" do
+ "\x24".encode(Encoding::US_ASCII).chr.encoding.should == Encoding::US_ASCII
+ end
+
+ it "understands multi-byte characters" do
+ s = "\u{9879}"
+ s.bytesize.should == 3
+ s.chr.should == s
+ end
+
+ it "understands Strings that contain a mixture of character widths" do
+ three = "\u{8082}"
+ three.bytesize.should == 3
+ four = "\u{77082}"
+ four.bytesize.should == 4
+ "#{three}#{four}".chr.should == three
end
end
diff --git a/spec/ruby/core/string/clear_spec.rb b/spec/ruby/core/string/clear_spec.rb
index 6a8b6018d0..152986fd0f 100644
--- a/spec/ruby/core/string/clear_spec.rb
+++ b/spec/ruby/core/string/clear_spec.rb
@@ -1,39 +1,38 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+# frozen_string_literal: false
+require_relative '../../spec_helper'
-with_feature :encoding do
- describe "String#clear" do
- before :each do
- @s = "Jolene"
- end
+describe "String#clear" do
+ before :each do
+ @s = "Jolene"
+ end
- it "sets self equal to the empty String" do
- @s.clear
- @s.should == ""
- end
+ it "sets self equal to the empty String" do
+ @s.clear
+ @s.should == ""
+ end
- it "returns self after emptying it" do
- cleared = @s.clear
- cleared.should == ""
- cleared.object_id.should == @s.object_id
- end
+ it "returns self after emptying it" do
+ cleared = @s.clear
+ cleared.should == ""
+ cleared.should equal @s
+ end
- it "preserves its encoding" do
- @s.encode!(Encoding::SHIFT_JIS)
- @s.encoding.should == Encoding::SHIFT_JIS
- @s.clear.encoding.should == Encoding::SHIFT_JIS
- @s.encoding.should == Encoding::SHIFT_JIS
- end
+ it "preserves its encoding" do
+ @s.encode!(Encoding::SHIFT_JIS)
+ @s.encoding.should == Encoding::SHIFT_JIS
+ @s.clear.encoding.should == Encoding::SHIFT_JIS
+ @s.encoding.should == Encoding::SHIFT_JIS
+ end
- it "works with multibyte Strings" do
- s = "\u{9765}\u{876}"
- s.clear
- s.should == ""
- end
+ it "works with multibyte Strings" do
+ s = "\u{9765}\u{876}"
+ s.clear
+ s.should == ""
+ end
- it "raises a RuntimeError if self is frozen" do
- @s.freeze
- lambda { @s.clear }.should raise_error(RuntimeError)
- lambda { "".freeze.clear }.should raise_error(RuntimeError)
- end
+ it "raises a FrozenError if self is frozen" do
+ @s.freeze
+ -> { @s.clear }.should raise_error(FrozenError)
+ -> { "".freeze.clear }.should raise_error(FrozenError)
end
end
diff --git a/spec/ruby/core/string/clone_spec.rb b/spec/ruby/core/string/clone_spec.rb
index 3940858e53..a2ba2f9877 100644
--- a/spec/ruby/core/string/clone_spec.rb
+++ b/spec/ruby/core/string/clone_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String#clone" do
before :each do
@@ -54,5 +54,8 @@ describe "String#clone" do
orig.should == "xtring"
clone.should == "string"
end
-end
+ it "returns a String in the same encoding as self" do
+ "a".encode("US-ASCII").clone.encoding.should == Encoding::US_ASCII
+ end
+end
diff --git a/spec/ruby/core/string/codepoints_spec.rb b/spec/ruby/core/string/codepoints_spec.rb
index 6304513583..12a5bf5892 100644
--- a/spec/ruby/core/string/codepoints_spec.rb
+++ b/spec/ruby/core/string/codepoints_spec.rb
@@ -1,20 +1,18 @@
-# -*- encoding: binary -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../shared/codepoints', __FILE__)
-require File.expand_path('../shared/each_codepoint_without_block', __FILE__)
+# encoding: binary
+require_relative '../../spec_helper'
+require_relative 'shared/codepoints'
+require_relative 'shared/each_codepoint_without_block'
-with_feature :encoding do
- describe "String#codepoints" do
- it_behaves_like(:string_codepoints, :codepoints)
+describe "String#codepoints" do
+ it_behaves_like :string_codepoints, :codepoints
- it "returns an Array when no block is given" do
- "abc".send(@method).should == [?a.ord, ?b.ord, ?c.ord]
- end
+ it "returns an Array when no block is given" do
+ "abc".codepoints.should == [?a.ord, ?b.ord, ?c.ord]
+ end
- it "raises an ArgumentError when no block is given if self has an invalid encoding" do
- s = "\xDF".force_encoding(Encoding::UTF_8)
- s.valid_encoding?.should be_false
- lambda {s.send(@method)}.should raise_error(ArgumentError)
- end
+ it "raises an ArgumentError when no block is given if self has an invalid encoding" do
+ s = "\xDF".dup.force_encoding(Encoding::UTF_8)
+ s.valid_encoding?.should be_false
+ -> { s.codepoints }.should raise_error(ArgumentError)
end
end
diff --git a/spec/ruby/core/string/comparison_spec.rb b/spec/ruby/core/string/comparison_spec.rb
index 5a0e7fabc3..9db0cff5ee 100644
--- a/spec/ruby/core/string/comparison_spec.rb
+++ b/spec/ruby/core/string/comparison_spec.rb
@@ -1,6 +1,6 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String#<=> with String" do
it "compares individual characters based on their ascii value" do
@@ -61,12 +61,12 @@ describe "String#<=> with String" do
end
it "ignores encoding difference" do
- ("ÄÖÛ".force_encoding("utf-8") <=> "ÄÖÜ".force_encoding("iso-8859-1")).should == -1
- ("ÄÖÜ".force_encoding("utf-8") <=> "ÄÖÛ".force_encoding("iso-8859-1")).should == 1
+ ("ÄÖÛ".dup.force_encoding("utf-8") <=> "ÄÖÜ".dup.force_encoding("iso-8859-1")).should == -1
+ ("ÄÖÜ".dup.force_encoding("utf-8") <=> "ÄÖÛ".dup.force_encoding("iso-8859-1")).should == 1
end
it "returns 0 with identical ASCII-compatible bytes of different encodings" do
- ("abc".force_encoding("utf-8") <=> "abc".force_encoding("iso-8859-1")).should == 0
+ ("abc".dup.force_encoding("utf-8") <=> "abc".dup.force_encoding("iso-8859-1")).should == 0
end
it "compares the indices of the encodings when the strings have identical non-ASCII-compatible bytes" do
@@ -75,6 +75,10 @@ describe "String#<=> with String" do
(xff_1 <=> xff_2).should == -1
(xff_2 <=> xff_1).should == 1
end
+
+ it "returns 0 when comparing 2 empty strings but one is not ASCII-compatible" do
+ ("" <=> "".dup.force_encoding('iso-2022-jp')).should == 0
+ end
end
# Note: This is inconsistent with Array#<=> which calls #to_ary instead of
diff --git a/spec/ruby/core/string/concat_spec.rb b/spec/ruby/core/string/concat_spec.rb
index 939be5ed0a..cbd7df54e2 100644
--- a/spec/ruby/core/string/concat_spec.rb
+++ b/spec/ruby/core/string/concat_spec.rb
@@ -1,28 +1,27 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
-require File.expand_path('../shared/concat', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/concat'
describe "String#concat" do
it_behaves_like :string_concat, :concat
it_behaves_like :string_concat_encoding, :concat
+ it_behaves_like :string_concat_type_coercion, :concat
- ruby_version_is "2.4" do
- it "takes multiple arguments" do
- str = "hello "
- str.concat "wo", "", "rld"
- str.should == "hello world"
- end
+ it "takes multiple arguments" do
+ str = +"hello "
+ str.concat "wo", "", "rld"
+ str.should == "hello world"
+ end
- it "concatenates the initial value when given arguments contain 2 self" do
- str = "hello"
- str.concat str, str
- str.should == "hellohellohello"
- end
+ it "concatenates the initial value when given arguments contain 2 self" do
+ str = +"hello"
+ str.concat str, str
+ str.should == "hellohellohello"
+ end
- it "returns self when given no arguments" do
- str = "hello"
- str.concat.should equal(str)
- str.should == "hello"
- end
+ it "returns self when given no arguments" do
+ str = +"hello"
+ str.concat.should equal(str)
+ str.should == "hello"
end
end
diff --git a/spec/ruby/core/string/count_spec.rb b/spec/ruby/core/string/count_spec.rb
index 3afb79a9fc..e614e901dd 100644
--- a/spec/ruby/core/string/count_spec.rb
+++ b/spec/ruby/core/string/count_spec.rb
@@ -1,6 +1,6 @@
-# -*- encoding: binary -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+# encoding: binary
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String#count" do
it "counts occurrences of chars from the intersection of the specified sets" do
@@ -23,7 +23,7 @@ describe "String#count" do
end
it "raises an ArgumentError when given no arguments" do
- lambda { "hell yeah".count }.should raise_error(ArgumentError)
+ -> { "hell yeah".count }.should raise_error(ArgumentError)
end
it "negates sets starting with ^" do
@@ -76,8 +76,8 @@ describe "String#count" do
it "raises if the given sequences are invalid" do
s = "hel-[()]-lo012^"
- lambda { s.count("h-e") }.should raise_error(ArgumentError)
- lambda { s.count("^h-e") }.should raise_error(ArgumentError)
+ -> { s.count("h-e") }.should raise_error(ArgumentError)
+ -> { s.count("^h-e") }.should raise_error(ArgumentError)
end
it 'returns the number of occurrences of a multi-byte character' do
@@ -98,8 +98,8 @@ describe "String#count" do
end
it "raises a TypeError when a set arg can't be converted to a string" do
- lambda { "hello world".count(100) }.should raise_error(TypeError)
- lambda { "hello world".count([]) }.should raise_error(TypeError)
- lambda { "hello world".count(mock('x')) }.should raise_error(TypeError)
+ -> { "hello world".count(100) }.should raise_error(TypeError)
+ -> { "hello world".count([]) }.should raise_error(TypeError)
+ -> { "hello world".count(mock('x')) }.should raise_error(TypeError)
end
end
diff --git a/spec/ruby/core/string/crypt_spec.rb b/spec/ruby/core/string/crypt_spec.rb
index d3bf5ec732..06f84c70a4 100644
--- a/spec/ruby/core/string/crypt_spec.rb
+++ b/spec/ruby/core/string/crypt_spec.rb
@@ -1,75 +1,92 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String#crypt" do
- # Note: MRI's documentation just says that the C stdlib function crypt() is
- # called.
- #
- # I'm not sure if crypt() is guaranteed to produce the same result across
- # different platforms. It seems that there is one standard UNIX implementation
- # of crypt(), but that alternative implementations are possible. See
- # http://www.unix.org.ua/orelly/networking/puis/ch08_06.htm
- it "returns a cryptographic hash of self by applying the UNIX crypt algorithm with the specified salt" do
- "".crypt("aa").should == "aaQSqAReePlq6"
- "nutmeg".crypt("Mi").should == "MiqkFWCm1fNJI"
- "ellen1".crypt("ri").should == "ri79kNd7V6.Sk"
- "Sharon".crypt("./").should == "./UY9Q7TvYJDg"
- "norahs".crypt("am").should == "amfIADT2iqjA."
- "norahs".crypt("7a").should == "7azfT5tIdyh0I"
-
- # Only uses first 8 chars of string
- "01234567".crypt("aa").should == "aa4c4gpuvCkSE"
- "012345678".crypt("aa").should == "aa4c4gpuvCkSE"
- "0123456789".crypt("aa").should == "aa4c4gpuvCkSE"
-
- # Only uses first 2 chars of salt
- "hello world".crypt("aa").should == "aayPz4hyPS1wI"
- "hello world".crypt("aab").should == "aayPz4hyPS1wI"
- "hello world".crypt("aabc").should == "aayPz4hyPS1wI"
- end
+ platform_is :openbsd do
+ it "returns a cryptographic hash of self by applying the bcrypt algorithm with the specified salt" do
+ "mypassword".crypt("$2a$04$0WVaz0pV3jzfZ5G5tpmHWu").should == "$2a$04$0WVaz0pV3jzfZ5G5tpmHWuBQGbkjzgtSc3gJbmdy0GAGMa45MFM2."
- it "raises an ArgumentError when the salt is shorter than two characters" do
- lambda { "hello".crypt("") }.should raise_error(ArgumentError)
- lambda { "hello".crypt("f") }.should raise_error(ArgumentError)
- lambda { "hello".crypt("\x00\x00") }.should raise_error(ArgumentError)
- lambda { "hello".crypt("\x00a") }.should raise_error(ArgumentError)
- lambda { "hello".crypt("a\x00") }.should raise_error(ArgumentError)
- end
+ # Only uses first 72 characters of string
+ ("12345678"*9).crypt("$2a$04$0WVaz0pV3jzfZ5G5tpmHWu").should == "$2a$04$0WVaz0pV3jzfZ5G5tpmHWukj/ORBnsMjCGpST/zCJnAypc7eAbutK"
+ ("12345678"*10).crypt("$2a$04$0WVaz0pV3jzfZ5G5tpmHWu").should == "$2a$04$0WVaz0pV3jzfZ5G5tpmHWukj/ORBnsMjCGpST/zCJnAypc7eAbutK"
- ruby_version_is "2.3" do
- it "raises an ArgumentError when the string contains NUL character" do
- lambda { "poison\0null".crypt("aa") }.should raise_error(ArgumentError)
+ # Only uses first 29 characters of salt
+ "mypassword".crypt("$2a$04$0WVaz0pV3jzfZ5G5tpmHWuB").should == "$2a$04$0WVaz0pV3jzfZ5G5tpmHWuBQGbkjzgtSc3gJbmdy0GAGMa45MFM2."
end
- end
- it "calls #to_str to converts the salt arg to a String" do
- obj = mock('aa')
- obj.should_receive(:to_str).and_return("aa")
+ it "raises Errno::EINVAL when the salt is shorter than 29 characters" do
+ -> { "mypassword".crypt("$2a$04$0WVaz0pV3jzfZ5G5tpmHW") }.should raise_error(Errno::EINVAL)
+ end
- "".crypt(obj).should == "aaQSqAReePlq6"
- end
+ it "calls #to_str to converts the salt arg to a String" do
+ obj = mock('$2a$04$0WVaz0pV3jzfZ5G5tpmHWu')
+ obj.should_receive(:to_str).and_return("$2a$04$0WVaz0pV3jzfZ5G5tpmHWu")
- it "raises a type error when the salt arg can't be converted to a string" do
- lambda { "".crypt(5) }.should raise_error(TypeError)
- lambda { "".crypt(mock('x')) }.should raise_error(TypeError)
+ "mypassword".crypt(obj).should == "$2a$04$0WVaz0pV3jzfZ5G5tpmHWuBQGbkjzgtSc3gJbmdy0GAGMa45MFM2."
+ end
+
+ it "doesn't return subclass instances" do
+ StringSpecs::MyString.new("mypassword").crypt("$2a$04$0WVaz0pV3jzfZ5G5tpmHWu").should be_an_instance_of(String)
+ "mypassword".crypt(StringSpecs::MyString.new("$2a$04$0WVaz0pV3jzfZ5G5tpmHWu")).should be_an_instance_of(String)
+ StringSpecs::MyString.new("mypassword").crypt(StringSpecs::MyString.new("$2a$04$0WVaz0pV3jzfZ5G5tpmHWu")).should be_an_instance_of(String)
+ end
end
- it "taints the result if either salt or self is tainted" do
- tainted_salt = "aa"
- tainted_str = "hello"
+ platform_is_not :openbsd do
+ # Note: MRI's documentation just says that the C stdlib function crypt() is
+ # called.
+ #
+ # I'm not sure if crypt() is guaranteed to produce the same result across
+ # different platforms. It seems that there is one standard UNIX implementation
+ # of crypt(), but that alternative implementations are possible. See
+ # http://www.unix.org.ua/orelly/networking/puis/ch08_06.htm
+ it "returns a cryptographic hash of self by applying the UNIX crypt algorithm with the specified salt" do
+ "".crypt("aa").should == "aaQSqAReePlq6"
+ "nutmeg".crypt("Mi").should == "MiqkFWCm1fNJI"
+ "ellen1".crypt("ri").should == "ri79kNd7V6.Sk"
+ "Sharon".crypt("./").should == "./UY9Q7TvYJDg"
+ "norahs".crypt("am").should == "amfIADT2iqjA."
+ "norahs".crypt("7a").should == "7azfT5tIdyh0I"
+
+ # Only uses first 8 chars of string
+ "01234567".crypt("aa").should == "aa4c4gpuvCkSE"
+ "012345678".crypt("aa").should == "aa4c4gpuvCkSE"
+ "0123456789".crypt("aa").should == "aa4c4gpuvCkSE"
- tainted_salt.taint
- tainted_str.taint
+ # Only uses first 2 chars of salt
+ "hello world".crypt("aa").should == "aayPz4hyPS1wI"
+ "hello world".crypt("aab").should == "aayPz4hyPS1wI"
+ "hello world".crypt("aabc").should == "aayPz4hyPS1wI"
+ end
+
+ it "raises an ArgumentError when the string contains NUL character" do
+ -> { "poison\0null".crypt("aa") }.should raise_error(ArgumentError)
+ end
+
+ it "calls #to_str to converts the salt arg to a String" do
+ obj = mock('aa')
+ obj.should_receive(:to_str).and_return("aa")
- "hello".crypt("aa").tainted?.should == false
- tainted_str.crypt("aa").tainted?.should == true
- "hello".crypt(tainted_salt).tainted?.should == true
- tainted_str.crypt(tainted_salt).tainted?.should == true
+ "".crypt(obj).should == "aaQSqAReePlq6"
+ end
+
+ it "doesn't return subclass instances" do
+ StringSpecs::MyString.new("hello").crypt("aa").should be_an_instance_of(String)
+ "hello".crypt(StringSpecs::MyString.new("aa")).should be_an_instance_of(String)
+ StringSpecs::MyString.new("hello").crypt(StringSpecs::MyString.new("aa")).should be_an_instance_of(String)
+ end
+
+ it "raises an ArgumentError when the salt is shorter than two characters" do
+ -> { "hello".crypt("") }.should raise_error(ArgumentError)
+ -> { "hello".crypt("f") }.should raise_error(ArgumentError)
+ -> { "hello".crypt("\x00\x00") }.should raise_error(ArgumentError)
+ -> { "hello".crypt("\x00a") }.should raise_error(ArgumentError)
+ -> { "hello".crypt("a\x00") }.should raise_error(ArgumentError)
+ end
end
- it "doesn't return subclass instances" do
- StringSpecs::MyString.new("hello").crypt("aa").should be_an_instance_of(String)
- "hello".crypt(StringSpecs::MyString.new("aa")).should be_an_instance_of(String)
- StringSpecs::MyString.new("hello").crypt(StringSpecs::MyString.new("aa")).should be_an_instance_of(String)
+ it "raises a type error when the salt arg can't be converted to a string" do
+ -> { "".crypt(5) }.should raise_error(TypeError)
+ -> { "".crypt(mock('x')) }.should raise_error(TypeError)
end
end
diff --git a/spec/ruby/core/string/dedup_spec.rb b/spec/ruby/core/string/dedup_spec.rb
new file mode 100644
index 0000000000..2b31d80708
--- /dev/null
+++ b/spec/ruby/core/string/dedup_spec.rb
@@ -0,0 +1,6 @@
+require_relative '../../spec_helper'
+require_relative 'shared/dedup'
+
+describe 'String#dedup' do
+ it_behaves_like :string_dedup, :dedup
+end
diff --git a/spec/ruby/core/string/delete_prefix_spec.rb b/spec/ruby/core/string/delete_prefix_spec.rb
index 94d486eace..ee7f044905 100644
--- a/spec/ruby/core/string/delete_prefix_spec.rb
+++ b/spec/ruby/core/string/delete_prefix_spec.rb
@@ -1,81 +1,83 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+# frozen_string_literal: false
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
-ruby_version_is '2.5' do
- describe "String#delete_prefix" do
- it "returns a copy of the string, with the given prefix removed" do
- 'hello'.delete_prefix('hell').should == 'o'
- 'hello'.delete_prefix('hello').should == ''
- end
+describe "String#delete_prefix" do
+ it "returns a copy of the string, with the given prefix removed" do
+ 'hello'.delete_prefix('hell').should == 'o'
+ 'hello'.delete_prefix('hello').should == ''
+ end
+
+ it "returns a copy of the string, when the prefix isn't found" do
+ s = 'hello'
+ r = s.delete_prefix('hello!')
+ r.should_not equal s
+ r.should == s
+ r = s.delete_prefix('ell')
+ r.should_not equal s
+ r.should == s
+ r = s.delete_prefix('')
+ r.should_not equal s
+ r.should == s
+ end
- it "returns a copy of the string, when the prefix isn't found" do
- s = 'hello'
- r = s.delete_prefix('hello!')
- r.should_not equal s
- r.should == s
- r = s.delete_prefix('ell')
- r.should_not equal s
- r.should == s
- r = s.delete_prefix('')
- r.should_not equal s
- r.should == s
- end
+ it "does not remove partial bytes, only full characters" do
+ "\xe3\x81\x82".delete_prefix("\xe3").should == "\xe3\x81\x82"
+ end
- it "taints resulting strings when other is tainted" do
- 'hello'.taint.delete_prefix('hell').tainted?.should == true
- 'hello'.taint.delete_prefix('').tainted?.should == true
- end
+ it "doesn't set $~" do
+ $~ = nil
- it "doesn't set $~" do
- $~ = nil
+ 'hello'.delete_prefix('hell')
+ $~.should == nil
+ end
- 'hello'.delete_prefix('hell')
- $~.should == nil
- end
+ it "calls to_str on its argument" do
+ o = mock('x')
+ o.should_receive(:to_str).and_return 'hell'
+ 'hello'.delete_prefix(o).should == 'o'
+ end
- it "calls to_str on its argument" do
- o = mock('x')
- o.should_receive(:to_str).and_return 'hell'
- 'hello'.delete_prefix(o).should == 'o'
- end
+ it "returns a String instance when called on a subclass instance" do
+ s = StringSpecs::MyString.new('hello')
+ s.delete_prefix('hell').should be_an_instance_of(String)
+ end
- it "returns a subclass instance when called on a subclass instance" do
- s = StringSpecs::MyString.new('hello')
- s.delete_prefix('hell').should be_an_instance_of(StringSpecs::MyString)
- end
+ it "returns a String in the same encoding as self" do
+ 'hello'.encode("US-ASCII").delete_prefix('hell').encoding.should == Encoding::US_ASCII
end
+end
- describe "String#delete_prefix!" do
- it "removes the found prefix" do
- s = 'hello'
- s.delete_prefix!('hell').should equal(s)
- s.should == 'o'
- end
+describe "String#delete_prefix!" do
+ it "removes the found prefix" do
+ s = 'hello'
+ s.delete_prefix!('hell').should equal(s)
+ s.should == 'o'
+ end
- it "returns nil if no change is made" do
- s = 'hello'
- s.delete_prefix!('ell').should == nil
- s.delete_prefix!('').should == nil
- end
+ it "returns nil if no change is made" do
+ s = 'hello'
+ s.delete_prefix!('ell').should == nil
+ s.delete_prefix!('').should == nil
+ end
- it "doesn't set $~" do
- $~ = nil
+ it "doesn't set $~" do
+ $~ = nil
- 'hello'.delete_prefix!('hell')
- $~.should == nil
- end
+ 'hello'.delete_prefix!('hell')
+ $~.should == nil
+ end
- it "calls to_str on its argument" do
- o = mock('x')
- o.should_receive(:to_str).and_return 'hell'
- 'hello'.delete_prefix!(o).should == 'o'
- end
+ it "calls to_str on its argument" do
+ o = mock('x')
+ o.should_receive(:to_str).and_return 'hell'
+ 'hello'.delete_prefix!(o).should == 'o'
+ end
- it "raises a RuntimeError when self is frozen" do
- lambda { 'hello'.freeze.delete_prefix!('hell') }.should raise_error(RuntimeError)
- lambda { 'hello'.freeze.delete_prefix!('') }.should raise_error(RuntimeError)
- lambda { ''.freeze.delete_prefix!('') }.should raise_error(RuntimeError)
- end
+ it "raises a FrozenError when self is frozen" do
+ -> { 'hello'.freeze.delete_prefix!('hell') }.should raise_error(FrozenError)
+ -> { 'hello'.freeze.delete_prefix!('') }.should raise_error(FrozenError)
+ -> { ''.freeze.delete_prefix!('') }.should raise_error(FrozenError)
end
end
diff --git a/spec/ruby/core/string/delete_spec.rb b/spec/ruby/core/string/delete_spec.rb
index 536d4a95af..6d359776e4 100644
--- a/spec/ruby/core/string/delete_spec.rb
+++ b/spec/ruby/core/string/delete_spec.rb
@@ -1,6 +1,7 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+# frozen_string_literal: false
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String#delete" do
it "returns a new string with the chars from the intersection of sets removed" do
@@ -14,7 +15,7 @@ describe "String#delete" do
end
it "raises an ArgumentError when given no arguments" do
- lambda { "hell yeah".delete }.should raise_error(ArgumentError)
+ -> { "hell yeah".delete }.should raise_error(ArgumentError)
end
it "negates sets starting with ^" do
@@ -62,17 +63,10 @@ describe "String#delete" do
not_supported_on :opal do
xFF = [0xFF].pack('C')
range = "\x00 - #{xFF}".force_encoding('utf-8')
- lambda { "hello".delete(range).should == "" }.should raise_error(ArgumentError)
+ -> { "hello".delete(range).should == "" }.should raise_error(ArgumentError)
end
- lambda { "hello".delete("h-e") }.should raise_error(ArgumentError)
- lambda { "hello".delete("^h-e") }.should raise_error(ArgumentError)
- end
-
- it "taints result when self is tainted" do
- "hello".taint.delete("e").tainted?.should == true
- "hello".taint.delete("a-z").tainted?.should == true
-
- "hello".delete("e".taint).tainted?.should == false
+ -> { "hello".delete("h-e") }.should raise_error(ArgumentError)
+ -> { "hello".delete("^h-e") }.should raise_error(ArgumentError)
end
it "tries to convert each set arg to a string using to_str" do
@@ -86,13 +80,17 @@ describe "String#delete" do
end
it "raises a TypeError when one set arg can't be converted to a string" do
- lambda { "hello world".delete(100) }.should raise_error(TypeError)
- lambda { "hello world".delete([]) }.should raise_error(TypeError)
- lambda { "hello world".delete(mock('x')) }.should raise_error(TypeError)
+ -> { "hello world".delete(100) }.should raise_error(TypeError)
+ -> { "hello world".delete([]) }.should raise_error(TypeError)
+ -> { "hello world".delete(mock('x')) }.should raise_error(TypeError)
+ end
+
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("oh no!!!").delete("!").should be_an_instance_of(String)
end
- it "returns subclass instances when called on a subclass" do
- StringSpecs::MyString.new("oh no!!!").delete("!").should be_an_instance_of(StringSpecs::MyString)
+ it "returns a String in the same encoding as self" do
+ "hello".encode("US-ASCII").delete("lo").encoding.should == Encoding::US_ASCII
end
end
@@ -109,11 +107,11 @@ describe "String#delete!" do
a.should == "hello"
end
- it "raises a RuntimeError when self is frozen" do
+ it "raises a FrozenError when self is frozen" do
a = "hello"
a.freeze
- lambda { a.delete!("") }.should raise_error(RuntimeError)
- lambda { a.delete!("aeiou", "^e") }.should raise_error(RuntimeError)
+ -> { a.delete!("") }.should raise_error(FrozenError)
+ -> { a.delete!("aeiou", "^e") }.should raise_error(FrozenError)
end
end
diff --git a/spec/ruby/core/string/delete_suffix_spec.rb b/spec/ruby/core/string/delete_suffix_spec.rb
index 49689a8da1..1842d75aa5 100644
--- a/spec/ruby/core/string/delete_suffix_spec.rb
+++ b/spec/ruby/core/string/delete_suffix_spec.rb
@@ -1,81 +1,83 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+# frozen_string_literal: false
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
-ruby_version_is '2.5' do
- describe "String#delete_suffix" do
- it "returns a copy of the string, with the given suffix removed" do
- 'hello'.delete_suffix('ello').should == 'h'
- 'hello'.delete_suffix('hello').should == ''
- end
+describe "String#delete_suffix" do
+ it "returns a copy of the string, with the given suffix removed" do
+ 'hello'.delete_suffix('ello').should == 'h'
+ 'hello'.delete_suffix('hello').should == ''
+ end
+
+ it "returns a copy of the string, when the suffix isn't found" do
+ s = 'hello'
+ r = s.delete_suffix('!hello')
+ r.should_not equal s
+ r.should == s
+ r = s.delete_suffix('ell')
+ r.should_not equal s
+ r.should == s
+ r = s.delete_suffix('')
+ r.should_not equal s
+ r.should == s
+ end
- it "returns a copy of the string, when the suffix isn't found" do
- s = 'hello'
- r = s.delete_suffix('!hello')
- r.should_not equal s
- r.should == s
- r = s.delete_suffix('ell')
- r.should_not equal s
- r.should == s
- r = s.delete_suffix('')
- r.should_not equal s
- r.should == s
- end
+ it "does not remove partial bytes, only full characters" do
+ "\xe3\x81\x82".delete_suffix("\x82").should == "\xe3\x81\x82"
+ end
- it "taints resulting strings when other is tainted" do
- 'hello'.taint.delete_suffix('ello').tainted?.should == true
- 'hello'.taint.delete_suffix('').tainted?.should == true
- end
+ it "doesn't set $~" do
+ $~ = nil
- it "doesn't set $~" do
- $~ = nil
+ 'hello'.delete_suffix('ello')
+ $~.should == nil
+ end
- 'hello'.delete_suffix('ello')
- $~.should == nil
- end
+ it "calls to_str on its argument" do
+ o = mock('x')
+ o.should_receive(:to_str).and_return 'ello'
+ 'hello'.delete_suffix(o).should == 'h'
+ end
- it "calls to_str on its argument" do
- o = mock('x')
- o.should_receive(:to_str).and_return 'ello'
- 'hello'.delete_suffix(o).should == 'h'
- end
+ it "returns a String instance when called on a subclass instance" do
+ s = StringSpecs::MyString.new('hello')
+ s.delete_suffix('ello').should be_an_instance_of(String)
+ end
- it "returns a subclass instance when called on a subclass instance" do
- s = StringSpecs::MyString.new('hello')
- s.delete_suffix('ello').should be_an_instance_of(StringSpecs::MyString)
- end
+ it "returns a String in the same encoding as self" do
+ "hello".encode("US-ASCII").delete_suffix("ello").encoding.should == Encoding::US_ASCII
end
+end
- describe "String#delete_suffix!" do
- it "removes the found prefix" do
- s = 'hello'
- s.delete_suffix!('ello').should equal(s)
- s.should == 'h'
- end
+describe "String#delete_suffix!" do
+ it "removes the found prefix" do
+ s = 'hello'
+ s.delete_suffix!('ello').should equal(s)
+ s.should == 'h'
+ end
- it "returns nil if no change is made" do
- s = 'hello'
- s.delete_suffix!('ell').should == nil
- s.delete_suffix!('').should == nil
- end
+ it "returns nil if no change is made" do
+ s = 'hello'
+ s.delete_suffix!('ell').should == nil
+ s.delete_suffix!('').should == nil
+ end
- it "doesn't set $~" do
- $~ = nil
+ it "doesn't set $~" do
+ $~ = nil
- 'hello'.delete_suffix!('ello')
- $~.should == nil
- end
+ 'hello'.delete_suffix!('ello')
+ $~.should == nil
+ end
- it "calls to_str on its argument" do
- o = mock('x')
- o.should_receive(:to_str).and_return 'ello'
- 'hello'.delete_suffix!(o).should == 'h'
- end
+ it "calls to_str on its argument" do
+ o = mock('x')
+ o.should_receive(:to_str).and_return 'ello'
+ 'hello'.delete_suffix!(o).should == 'h'
+ end
- it "raises a RuntimeError when self is frozen" do
- lambda { 'hello'.freeze.delete_suffix!('ello') }.should raise_error(RuntimeError)
- lambda { 'hello'.freeze.delete_suffix!('') }.should raise_error(RuntimeError)
- lambda { ''.freeze.delete_suffix!('') }.should raise_error(RuntimeError)
- end
+ it "raises a FrozenError when self is frozen" do
+ -> { 'hello'.freeze.delete_suffix!('ello') }.should raise_error(FrozenError)
+ -> { 'hello'.freeze.delete_suffix!('') }.should raise_error(FrozenError)
+ -> { ''.freeze.delete_suffix!('') }.should raise_error(FrozenError)
end
end
diff --git a/spec/ruby/core/string/downcase_spec.rb b/spec/ruby/core/string/downcase_spec.rb
index f591c0fa09..2d260f23f1 100644
--- a/spec/ruby/core/string/downcase_spec.rb
+++ b/spec/ruby/core/string/downcase_spec.rb
@@ -1,6 +1,7 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+# frozen_string_literal: false
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String#downcase" do
it "returns a copy of self with all uppercase letters downcased" do
@@ -8,34 +9,76 @@ describe "String#downcase" do
"hello".downcase.should == "hello"
end
- ruby_version_is ''...'2.4' do
- it "is locale insensitive (only replaces A-Z)" do
- "ÄÖÜ".downcase.should == "ÄÖÜ"
+ it "returns a String in the same encoding as self" do
+ "hELLO".encode("US-ASCII").downcase.encoding.should == Encoding::US_ASCII
+ end
+
+ describe "full Unicode case mapping" do
+ it "works for all of Unicode with no option" do
+ "ÄÖÜ".downcase.should == "äöü"
+ end
- str = Array.new(256) { |c| c.chr }.join
- expected = Array.new(256) do |i|
- c = i.chr
- c.between?("A", "Z") ? c.downcase : c
- end.join
+ it "updates string metadata" do
+ downcased = "\u{212A}ING".downcase
- str.downcase.should == expected
+ downcased.should == "king"
+ downcased.size.should == 4
+ downcased.bytesize.should == 4
+ downcased.ascii_only?.should be_true
end
end
- ruby_version_is '2.4' do
- it "works for all of Unicode" do
- "ÄÖÜ".downcase.should == "äöü"
+ describe "ASCII-only case mapping" do
+ it "does not downcase non-ASCII characters" do
+ "CÅR".downcase(:ascii).should == "cÅr"
+ end
+
+ it "works with substrings" do
+ "prefix TÉ"[-2..-1].downcase(:ascii).should == "tÉ"
+ end
+ end
+
+ describe "full Unicode case mapping adapted for Turkic languages" do
+ it "downcases characters according to Turkic semantics" do
+ "İ".downcase(:turkic).should == "i"
+ end
+
+ it "allows Lithuanian as an extra option" do
+ "İ".downcase(:turkic, :lithuanian).should == "i"
+ end
+
+ it "does not allow any other additional option" do
+ -> { "İ".downcase(:turkic, :ascii) }.should raise_error(ArgumentError)
end
end
- it "taints result when self is tainted" do
- "".taint.downcase.tainted?.should == true
- "x".taint.downcase.tainted?.should == true
- "X".taint.downcase.tainted?.should == true
+ describe "full Unicode case mapping adapted for Lithuanian" do
+ it "currently works the same as full Unicode case mapping" do
+ "İS".downcase(:lithuanian).should == "i\u{307}s"
+ end
+
+ it "allows Turkic as an extra option (and applies Turkic semantics)" do
+ "İS".downcase(:lithuanian, :turkic).should == "is"
+ end
+
+ it "does not allow any other additional option" do
+ -> { "İS".downcase(:lithuanian, :ascii) }.should raise_error(ArgumentError)
+ end
+ end
+
+ describe "case folding" do
+ it "case folds special characters" do
+ "ß".downcase.should == "ß"
+ "ß".downcase(:fold).should == "ss"
+ end
+ end
+
+ it "does not allow invalid options" do
+ -> { "ABC".downcase(:invalid_option) }.should raise_error(ArgumentError)
end
- it "returns a subclass instance for subclasses" do
- StringSpecs::MyString.new("FOObar").downcase.should be_an_instance_of(StringSpecs::MyString)
+ it "returns a String instance for subclasses" do
+ StringSpecs::MyString.new("FOObar").downcase.should be_an_instance_of(String)
end
end
@@ -46,12 +89,93 @@ describe "String#downcase!" do
a.should == "hello"
end
- ruby_version_is '2.4' do
- it "modifies self in place for all of Unicode" do
+ it "modifies self in place for non-ascii-compatible encodings" do
+ a = "HeLlO".encode("utf-16le")
+ a.downcase!
+ a.should == "hello".encode("utf-16le")
+ end
+
+ describe "full Unicode case mapping" do
+ it "modifies self in place for all of Unicode with no option" do
a = "ÄÖÜ"
- a.downcase!.should equal(a)
+ a.downcase!
a.should == "äöü"
end
+
+ it "updates string metadata" do
+ downcased = "\u{212A}ING"
+ downcased.downcase!
+
+ downcased.should == "king"
+ downcased.size.should == 4
+ downcased.bytesize.should == 4
+ downcased.ascii_only?.should be_true
+ end
+ end
+
+ describe "ASCII-only case mapping" do
+ it "does not downcase non-ASCII characters" do
+ a = "CÅR"
+ a.downcase!(:ascii)
+ a.should == "cÅr"
+ end
+
+ it "works for non-ascii-compatible encodings" do
+ a = "ABC".encode("utf-16le")
+ a.downcase!(:ascii)
+ a.should == "abc".encode("utf-16le")
+ end
+ end
+
+ describe "full Unicode case mapping adapted for Turkic languages" do
+ it "downcases characters according to Turkic semantics" do
+ a = "İ"
+ a.downcase!(:turkic)
+ a.should == "i"
+ end
+
+ it "allows Lithuanian as an extra option" do
+ a = "İ"
+ a.downcase!(:turkic, :lithuanian)
+ a.should == "i"
+ end
+
+ it "does not allow any other additional option" do
+ -> { a = "İ"; a.downcase!(:turkic, :ascii) }.should raise_error(ArgumentError)
+ end
+ end
+
+ describe "full Unicode case mapping adapted for Lithuanian" do
+ it "currently works the same as full Unicode case mapping" do
+ a = "İS"
+ a.downcase!(:lithuanian)
+ a.should == "i\u{307}s"
+ end
+
+ it "allows Turkic as an extra option (and applies Turkic semantics)" do
+ a = "İS"
+ a.downcase!(:lithuanian, :turkic)
+ a.should == "is"
+ end
+
+ it "does not allow any other additional option" do
+ -> { a = "İS"; a.downcase!(:lithuanian, :ascii) }.should raise_error(ArgumentError)
+ end
+ end
+
+ describe "case folding" do
+ it "case folds special characters" do
+ a = "ß"
+ a.downcase!
+ a.should == "ß"
+
+ a.downcase!(:fold)
+ a.should == "ss"
+ end
+ end
+
+ it "does not allow invalid options" do
+ -> { a = "ABC"; a.downcase!(:invalid_option) }.should raise_error(ArgumentError)
end
it "returns nil if no modifications were made" do
@@ -60,14 +184,12 @@ describe "String#downcase!" do
a.should == "hello"
end
- it "raises a RuntimeError when self is frozen" do
- lambda { "HeLlo".freeze.downcase! }.should raise_error(RuntimeError)
- lambda { "hello".freeze.downcase! }.should raise_error(RuntimeError)
+ it "raises a FrozenError when self is frozen" do
+ -> { "HeLlo".freeze.downcase! }.should raise_error(FrozenError)
+ -> { "hello".freeze.downcase! }.should raise_error(FrozenError)
end
- with_feature :encoding do
- it "sets the result String encoding to the source String encoding" do
- "ABC".downcase.encoding.should equal(Encoding::UTF_8)
- end
+ it "sets the result String encoding to the source String encoding" do
+ "ABC".downcase.encoding.should equal(Encoding::UTF_8)
end
end
diff --git a/spec/ruby/core/string/dump_spec.rb b/spec/ruby/core/string/dump_spec.rb
index db743ad08f..cab8beff5a 100644
--- a/spec/ruby/core/string/dump_spec.rb
+++ b/spec/ruby/core/string/dump_spec.rb
@@ -1,20 +1,18 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String#dump" do
- it "taints the result if self is tainted" do
- "foo".taint.dump.tainted?.should == true
- "foo\n".taint.dump.tainted?.should == true
+ it "does not take into account if a string is frozen" do
+ "foo".freeze.dump.should_not.frozen?
end
- it "untrusts the result if self is untrusted" do
- "foo".untrust.dump.untrusted?.should == true
- "foo\n".untrust.dump.untrusted?.should == true
+ it "returns a String instance" do
+ StringSpecs::MyString.new.dump.should be_an_instance_of(String)
end
- it "returns a subclass instance" do
- StringSpecs::MyString.new.dump.should be_an_instance_of(StringSpecs::MyString)
+ it "wraps string with \"" do
+ "foo".dump.should == '"foo"'
end
it "returns a string with special characters replaced with \\<char> notation" do
@@ -35,10 +33,11 @@ describe "String#dump" do
].should be_computed_by(:dump)
end
- it "returns a string with \\#<char> when # is followed by $, @, {" do
- [ ["\#$", '"\\#$"'],
- ["\#@", '"\\#@"'],
- ["\#{", '"\\#{"']
+ it "returns a string with \\#<char> when # is followed by $, @, @@, {" do
+ [ ["\#$PATH", '"\\#$PATH"'],
+ ["\#@a", '"\\#@a"'],
+ ["\#@@a", '"\\#@@a"'],
+ ["\#{a}", '"\\#{a}"']
].should be_computed_by(:dump)
end
@@ -343,82 +342,55 @@ describe "String#dump" do
].should be_computed_by(:dump)
end
- ruby_version_is ''...'2.4' do
- it "returns a string with multi-byte UTF-8 characters replaced by \\u{} notation with lower-case hex digits" do
- [ [0200.chr('utf-8'), '"\u{80}"'],
- [0201.chr('utf-8'), '"\u{81}"'],
- [0202.chr('utf-8'), '"\u{82}"'],
- [0203.chr('utf-8'), '"\u{83}"'],
- [0204.chr('utf-8'), '"\u{84}"'],
- [0206.chr('utf-8'), '"\u{86}"'],
- [0207.chr('utf-8'), '"\u{87}"'],
- [0210.chr('utf-8'), '"\u{88}"'],
- [0211.chr('utf-8'), '"\u{89}"'],
- [0212.chr('utf-8'), '"\u{8a}"'],
- [0213.chr('utf-8'), '"\u{8b}"'],
- [0214.chr('utf-8'), '"\u{8c}"'],
- [0215.chr('utf-8'), '"\u{8d}"'],
- [0216.chr('utf-8'), '"\u{8e}"'],
- [0217.chr('utf-8'), '"\u{8f}"'],
- [0220.chr('utf-8'), '"\u{90}"'],
- [0221.chr('utf-8'), '"\u{91}"'],
- [0222.chr('utf-8'), '"\u{92}"'],
- [0223.chr('utf-8'), '"\u{93}"'],
- [0224.chr('utf-8'), '"\u{94}"'],
- [0225.chr('utf-8'), '"\u{95}"'],
- [0226.chr('utf-8'), '"\u{96}"'],
- [0227.chr('utf-8'), '"\u{97}"'],
- [0230.chr('utf-8'), '"\u{98}"'],
- [0231.chr('utf-8'), '"\u{99}"'],
- [0232.chr('utf-8'), '"\u{9a}"'],
- [0233.chr('utf-8'), '"\u{9b}"'],
- [0234.chr('utf-8'), '"\u{9c}"'],
- [0235.chr('utf-8'), '"\u{9d}"'],
- [0236.chr('utf-8'), '"\u{9e}"'],
- [0237.chr('utf-8'), '"\u{9f}"'],
- ].should be_computed_by(:dump)
- end
+ it "returns a string with multi-byte UTF-8 characters less than or equal 0xFFFF replaced by \\uXXXX notation with upper-case hex digits" do
+ [ [0200.chr('utf-8'), '"\u0080"'],
+ [0201.chr('utf-8'), '"\u0081"'],
+ [0202.chr('utf-8'), '"\u0082"'],
+ [0203.chr('utf-8'), '"\u0083"'],
+ [0204.chr('utf-8'), '"\u0084"'],
+ [0206.chr('utf-8'), '"\u0086"'],
+ [0207.chr('utf-8'), '"\u0087"'],
+ [0210.chr('utf-8'), '"\u0088"'],
+ [0211.chr('utf-8'), '"\u0089"'],
+ [0212.chr('utf-8'), '"\u008A"'],
+ [0213.chr('utf-8'), '"\u008B"'],
+ [0214.chr('utf-8'), '"\u008C"'],
+ [0215.chr('utf-8'), '"\u008D"'],
+ [0216.chr('utf-8'), '"\u008E"'],
+ [0217.chr('utf-8'), '"\u008F"'],
+ [0220.chr('utf-8'), '"\u0090"'],
+ [0221.chr('utf-8'), '"\u0091"'],
+ [0222.chr('utf-8'), '"\u0092"'],
+ [0223.chr('utf-8'), '"\u0093"'],
+ [0224.chr('utf-8'), '"\u0094"'],
+ [0225.chr('utf-8'), '"\u0095"'],
+ [0226.chr('utf-8'), '"\u0096"'],
+ [0227.chr('utf-8'), '"\u0097"'],
+ [0230.chr('utf-8'), '"\u0098"'],
+ [0231.chr('utf-8'), '"\u0099"'],
+ [0232.chr('utf-8'), '"\u009A"'],
+ [0233.chr('utf-8'), '"\u009B"'],
+ [0234.chr('utf-8'), '"\u009C"'],
+ [0235.chr('utf-8'), '"\u009D"'],
+ [0236.chr('utf-8'), '"\u009E"'],
+ [0237.chr('utf-8'), '"\u009F"'],
+ [0177777.chr('utf-8'), '"\uFFFF"'],
+ ].should be_computed_by(:dump)
end
- ruby_version_is '2.4' do
- it "returns a string with multi-byte UTF-8 characters replaced by \\u{} notation with lower-case hex digits" do
- [ [0200.chr('utf-8'), '"\u0080"'],
- [0201.chr('utf-8'), '"\u0081"'],
- [0202.chr('utf-8'), '"\u0082"'],
- [0203.chr('utf-8'), '"\u0083"'],
- [0204.chr('utf-8'), '"\u0084"'],
- [0206.chr('utf-8'), '"\u0086"'],
- [0207.chr('utf-8'), '"\u0087"'],
- [0210.chr('utf-8'), '"\u0088"'],
- [0211.chr('utf-8'), '"\u0089"'],
- [0212.chr('utf-8'), '"\u008A"'],
- [0213.chr('utf-8'), '"\u008B"'],
- [0214.chr('utf-8'), '"\u008C"'],
- [0215.chr('utf-8'), '"\u008D"'],
- [0216.chr('utf-8'), '"\u008E"'],
- [0217.chr('utf-8'), '"\u008F"'],
- [0220.chr('utf-8'), '"\u0090"'],
- [0221.chr('utf-8'), '"\u0091"'],
- [0222.chr('utf-8'), '"\u0092"'],
- [0223.chr('utf-8'), '"\u0093"'],
- [0224.chr('utf-8'), '"\u0094"'],
- [0225.chr('utf-8'), '"\u0095"'],
- [0226.chr('utf-8'), '"\u0096"'],
- [0227.chr('utf-8'), '"\u0097"'],
- [0230.chr('utf-8'), '"\u0098"'],
- [0231.chr('utf-8'), '"\u0099"'],
- [0232.chr('utf-8'), '"\u009A"'],
- [0233.chr('utf-8'), '"\u009B"'],
- [0234.chr('utf-8'), '"\u009C"'],
- [0235.chr('utf-8'), '"\u009D"'],
- [0236.chr('utf-8'), '"\u009E"'],
- [0237.chr('utf-8'), '"\u009F"'],
- ].should be_computed_by(:dump)
- end
+ it "returns a string with multi-byte UTF-8 characters greater than 0xFFFF replaced by \\u{XXXXXX} notation with upper-case hex digits" do
+ 0x10000.chr('utf-8').dump.should == '"\u{10000}"'
+ 0x10FFFF.chr('utf-8').dump.should == '"\u{10FFFF}"'
end
it "includes .force_encoding(name) if the encoding isn't ASCII compatible" do
- "\u{876}".encode('utf-16be').dump.should == "\"\\bv\".force_encoding(\"UTF-16BE\")"
- "\u{876}".encode('utf-16le').dump.should == "\"v\\b\".force_encoding(\"UTF-16LE\")"
+ "\u{876}".encode('utf-16be').dump.should.end_with?(".force_encoding(\"UTF-16BE\")")
+ "\u{876}".encode('utf-16le').dump.should.end_with?(".force_encoding(\"UTF-16LE\")")
+ end
+
+ it "returns a String in the same encoding as self" do
+ "foo".encode("ISO-8859-1").dump.encoding.should == Encoding::ISO_8859_1
+ "foo".encode('windows-1251').dump.encoding.should == Encoding::Windows_1251
+ 1.chr.dump.encoding.should == Encoding::US_ASCII
end
end
diff --git a/spec/ruby/core/string/dup_spec.rb b/spec/ruby/core/string/dup_spec.rb
index 81fb1308cc..073802d84b 100644
--- a/spec/ruby/core/string/dup_spec.rb
+++ b/spec/ruby/core/string/dup_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String#dup" do
before :each do
@@ -21,7 +21,7 @@ describe "String#dup" do
it "does not copy singleton methods" do
def @obj.special() :the_one end
dup = @obj.dup
- lambda { dup.special }.should raise_error(NameError)
+ -> { dup.special }.should raise_error(NameError)
end
it "does not copy modules included in the singleton class" do
@@ -30,7 +30,7 @@ describe "String#dup" do
end
dup = @obj.dup
- lambda { dup.repr }.should raise_error(NameError)
+ -> { dup.repr }.should raise_error(NameError)
end
it "does not copy constants defined in the singleton class" do
@@ -39,7 +39,7 @@ describe "String#dup" do
end
dup = @obj.dup
- lambda { class << dup; CLONE; end }.should raise_error(NameError)
+ -> { class << dup; CLONE; end }.should raise_error(NameError)
end
it "does not modify the original string when changing dupped string" do
@@ -49,4 +49,17 @@ describe "String#dup" do
orig.should == "xtring"
dup.should == "string"
end
+
+ it "does not modify the original setbyte-mutated string when changing dupped string" do
+ orig = +"a"
+ orig.setbyte 0, "b".ord
+ copy = orig.dup
+ orig.setbyte 0, "c".ord
+ orig.should == "c"
+ copy.should == "b"
+ end
+
+ it "returns a String in the same encoding as self" do
+ "hello".encode("US-ASCII").dup.encoding.should == Encoding::US_ASCII
+ end
end
diff --git a/spec/ruby/core/string/each_byte_spec.rb b/spec/ruby/core/string/each_byte_spec.rb
index 2282cd6d7a..7b3db265ac 100644
--- a/spec/ruby/core/string/each_byte_spec.rb
+++ b/spec/ruby/core/string/each_byte_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String#each_byte" do
it "passes each byte in self to the given block" do
@@ -9,26 +9,26 @@ describe "String#each_byte" do
end
it "keeps iterating from the old position (to new string end) when self changes" do
- r = ""
- s = "hello world"
+ r = +""
+ s = +"hello world"
s.each_byte do |c|
r << c
s.insert(0, "<>") if r.size < 3
end
r.should == "h><>hello world"
- r = ""
- s = "hello world"
+ r = +""
+ s = +"hello world"
s.each_byte { |c| s.slice!(-1); r << c }
r.should == "hello "
- r = ""
- s = "hello world"
+ r = +""
+ s = +"hello world"
s.each_byte { |c| s.slice!(0); r << c }
r.should == "hlowrd"
- r = ""
- s = "hello world"
+ r = +""
+ s = +"hello world"
s.each_byte { |c| s.slice!(0..-1); r << c }
r.should == "h"
end
diff --git a/spec/ruby/core/string/each_char_spec.rb b/spec/ruby/core/string/each_char_spec.rb
index 3233c7609d..36219f79db 100644
--- a/spec/ruby/core/string/each_char_spec.rb
+++ b/spec/ruby/core/string/each_char_spec.rb
@@ -1,7 +1,8 @@
-require File.expand_path('../shared/chars', __FILE__)
-require File.expand_path('../shared/each_char_without_block', __FILE__)
+require_relative "../../spec_helper"
+require_relative 'shared/chars'
+require_relative 'shared/each_char_without_block'
describe "String#each_char" do
- it_behaves_like(:string_chars, :each_char)
- it_behaves_like(:string_each_char_without_block, :each_char)
+ it_behaves_like :string_chars, :each_char
+ it_behaves_like :string_each_char_without_block, :each_char
end
diff --git a/spec/ruby/core/string/each_codepoint_spec.rb b/spec/ruby/core/string/each_codepoint_spec.rb
index 4e910f44b5..c11cb1beae 100644
--- a/spec/ruby/core/string/each_codepoint_spec.rb
+++ b/spec/ruby/core/string/each_codepoint_spec.rb
@@ -1,10 +1,8 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../shared/codepoints', __FILE__)
-require File.expand_path('../shared/each_codepoint_without_block', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'shared/codepoints'
+require_relative 'shared/each_codepoint_without_block'
-with_feature :encoding do
- describe "String#each_codepoint" do
- it_behaves_like(:string_codepoints, :each_codepoint)
- it_behaves_like(:string_each_codepoint_without_block, :each_codepoint)
- end
+describe "String#each_codepoint" do
+ it_behaves_like :string_codepoints, :each_codepoint
+ it_behaves_like :string_each_codepoint_without_block, :each_codepoint
end
diff --git a/spec/ruby/core/string/each_grapheme_cluster_spec.rb b/spec/ruby/core/string/each_grapheme_cluster_spec.rb
new file mode 100644
index 0000000000..e1fa4ae67b
--- /dev/null
+++ b/spec/ruby/core/string/each_grapheme_cluster_spec.rb
@@ -0,0 +1,16 @@
+require_relative "../../spec_helper"
+require_relative 'shared/chars'
+require_relative 'shared/grapheme_clusters'
+require_relative 'shared/each_char_without_block'
+
+describe "String#each_grapheme_cluster" do
+ it_behaves_like :string_chars, :each_grapheme_cluster
+ it_behaves_like :string_grapheme_clusters, :each_grapheme_cluster
+ it_behaves_like :string_each_char_without_block, :each_grapheme_cluster
+
+ it "yields String instances for subclasses" do
+ a = []
+ StringSpecs::MyString.new("abc").each_grapheme_cluster { |s| a << s.class }
+ a.should == [String, String, String]
+ end
+end
diff --git a/spec/ruby/core/string/each_line_spec.rb b/spec/ruby/core/string/each_line_spec.rb
index 865ae264d6..90fc920bf1 100644
--- a/spec/ruby/core/string/each_line_spec.rb
+++ b/spec/ruby/core/string/each_line_spec.rb
@@ -1,9 +1,9 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
-require File.expand_path('../shared/each_line', __FILE__)
-require File.expand_path('../shared/each_line_without_block', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/each_line'
+require_relative 'shared/each_line_without_block'
describe "String#each_line" do
- it_behaves_like(:string_each_line, :each_line)
- it_behaves_like(:string_each_line_without_block, :each_line)
+ it_behaves_like :string_each_line, :each_line
+ it_behaves_like :string_each_line_without_block, :each_line
end
diff --git a/spec/ruby/core/string/element_reference_spec.rb b/spec/ruby/core/string/element_reference_spec.rb
index 785bbdaf80..f6e1750c93 100644
--- a/spec/ruby/core/string/element_reference_spec.rb
+++ b/spec/ruby/core/string/element_reference_spec.rb
@@ -1,6 +1,6 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
-require File.expand_path('../shared/slice.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/slice'
describe "String#[]" do
it_behaves_like :string_slice, :[]
diff --git a/spec/ruby/core/string/element_set_spec.rb b/spec/ruby/core/string/element_set_spec.rb
index fea03607f2..e7599f832c 100644
--- a/spec/ruby/core/string/element_set_spec.rb
+++ b/spec/ruby/core/string/element_set_spec.rb
@@ -1,11 +1,12 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+# frozen_string_literal: false
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
# TODO: Add missing String#[]= specs:
# String#[re, idx] = obj
-describe "String#[]= with Fixnum index" do
+describe "String#[]= with Integer index" do
it "replaces the char at idx with other_str" do
a = "hello"
a[0] = "bam"
@@ -14,29 +15,19 @@ describe "String#[]= with Fixnum index" do
a.should == "bamelo"
end
- it "taints self if other_str is tainted" do
- a = "hello"
- a[0] = "".taint
- a.tainted?.should == true
-
- a = "hello"
- a[0] = "x".taint
- a.tainted?.should == true
- end
-
it "raises an IndexError without changing self if idx is outside of self" do
str = "hello"
- lambda { str[20] = "bam" }.should raise_error(IndexError)
+ -> { str[20] = "bam" }.should raise_error(IndexError)
str.should == "hello"
- lambda { str[-20] = "bam" }.should raise_error(IndexError)
+ -> { str[-20] = "bam" }.should raise_error(IndexError)
str.should == "hello"
- lambda { ""[-1] = "bam" }.should raise_error(IndexError)
+ -> { ""[-1] = "bam" }.should raise_error(IndexError)
end
- # Behaviour verfieid correct by matz in
+ # Behaviour is verified by matz in
# http://redmine.ruby-lang.org/issues/show/1750
it "allows assignment to the zero'th element of an empty String" do
str = ""
@@ -46,15 +37,15 @@ describe "String#[]= with Fixnum index" do
it "raises IndexError if the string index doesn't match a position in the string" do
str = "hello"
- lambda { str['y'] = "bam" }.should raise_error(IndexError)
+ -> { str['y'] = "bam" }.should raise_error(IndexError)
str.should == "hello"
end
- it "raises a RuntimeError when self is frozen" do
+ it "raises a FrozenError when self is frozen" do
a = "hello"
a.freeze
- lambda { a[0] = "bam" }.should raise_error(RuntimeError)
+ -> { a[0] = "bam" }.should raise_error(FrozenError)
end
it "calls to_int on index" do
@@ -78,73 +69,77 @@ describe "String#[]= with Fixnum index" do
end
it "raises a TypeError if other_str can't be converted to a String" do
- lambda { "test"[1] = [] }.should raise_error(TypeError)
- lambda { "test"[1] = mock('x') }.should raise_error(TypeError)
- lambda { "test"[1] = nil }.should raise_error(TypeError)
+ -> { "test"[1] = [] }.should raise_error(TypeError)
+ -> { "test"[1] = mock('x') }.should raise_error(TypeError)
+ -> { "test"[1] = nil }.should raise_error(TypeError)
end
- with_feature :encoding do
- it "raises a TypeError if passed a Fixnum replacement" do
- lambda { "abc"[1] = 65 }.should raise_error(TypeError)
- end
+ it "raises a TypeError if passed an Integer replacement" do
+ -> { "abc"[1] = 65 }.should raise_error(TypeError)
+ end
- it "raises an IndexError if the index is greater than character size" do
- lambda { "あれ"[4] = "a" }.should raise_error(IndexError)
- end
+ it "raises an IndexError if the index is greater than character size" do
+ -> { "あれ"[4] = "a" }.should raise_error(IndexError)
+ end
- it "calls #to_int to convert the index" do
- index = mock("string element set")
- index.should_receive(:to_int).and_return(1)
+ it "calls #to_int to convert the index" do
+ index = mock("string element set")
+ index.should_receive(:to_int).and_return(1)
- str = "あれ"
- str[index] = "a"
- str.should == "あa"
- end
+ str = "あれ"
+ str[index] = "a"
+ str.should == "あa"
+ end
- it "raises a TypeError if #to_int does not return an Fixnum" do
- index = mock("string element set")
- index.should_receive(:to_int).and_return('1')
+ it "raises a TypeError if #to_int does not return an Integer" do
+ index = mock("string element set")
+ index.should_receive(:to_int).and_return('1')
- lambda { "abc"[index] = "d" }.should raise_error(TypeError)
- end
+ -> { "abc"[index] = "d" }.should raise_error(TypeError)
+ end
- it "raises an IndexError if #to_int returns a value out of range" do
- index = mock("string element set")
- index.should_receive(:to_int).and_return(4)
+ it "raises an IndexError if #to_int returns a value out of range" do
+ index = mock("string element set")
+ index.should_receive(:to_int).and_return(4)
- lambda { "ab"[index] = "c" }.should raise_error(IndexError)
- end
+ -> { "ab"[index] = "c" }.should raise_error(IndexError)
+ end
- it "replaces a character with a multibyte character" do
- str = "ありがとu"
- str[4] = "う"
- str.should == "ありがとう"
- end
+ it "replaces a character with a multibyte character" do
+ str = "ありがとu"
+ str[4] = "う"
+ str.should == "ありがとう"
+ end
- it "replaces a multibyte character with a character" do
- str = "ありがとう"
- str[4] = "u"
- str.should == "ありがとu"
- end
+ it "replaces a multibyte character with a character" do
+ str = "ありがとう"
+ str[4] = "u"
+ str.should == "ありがとu"
+ end
- it "replaces a multibyte character with a multibyte character" do
- str = "ありがとお"
- str[4] = "う"
- str.should == "ありがとう"
- end
+ it "replaces a multibyte character with a multibyte character" do
+ str = "ありがとお"
+ str[4] = "う"
+ str.should == "ありがとう"
+ end
- it "encodes the String in an encoding compatible with the replacement" do
- str = " ".force_encoding Encoding::US_ASCII
- rep = [160].pack('C').force_encoding Encoding::ASCII_8BIT
- str[0] = rep
- str.encoding.should equal(Encoding::ASCII_8BIT)
- end
+ it "encodes the String in an encoding compatible with the replacement" do
+ str = " ".force_encoding Encoding::US_ASCII
+ rep = [160].pack('C').force_encoding Encoding::BINARY
+ str[0] = rep
+ str.encoding.should equal(Encoding::BINARY)
+ end
- it "raises an Encoding::CompatibilityError if the replacement encoding is incompatible" do
- str = "あれ"
- rep = "が".encode Encoding::EUC_JP
- lambda { str[0] = rep }.should raise_error(Encoding::CompatibilityError)
- end
+ it "updates the string to a compatible encoding" do
+ str = " "
+ str[1] = [0xB9].pack("C*")
+ str.encoding.should == Encoding::ASCII_8BIT
+ end
+
+ it "raises an Encoding::CompatibilityError if the replacement encoding is incompatible" do
+ str = "あれ"
+ rep = "が".encode Encoding::EUC_JP
+ -> { str[0] = rep }.should raise_error(Encoding::CompatibilityError)
end
end
@@ -169,40 +164,38 @@ describe "String#[]= with String index" do
it "raises an IndexError if the search String is not found" do
str = "abcde"
- lambda { str["g"] = "h" }.should raise_error(IndexError)
+ -> { str["g"] = "h" }.should raise_error(IndexError)
end
- with_feature :encoding do
- it "replaces characters with a multibyte character" do
- str = "ありgaとう"
- str["ga"] = "が"
- str.should == "ありがとう"
- end
+ it "replaces characters with a multibyte character" do
+ str = "ありgaとう"
+ str["ga"] = "が"
+ str.should == "ありがとう"
+ end
- it "replaces multibyte characters with characters" do
- str = "ありがとう"
- str["が"] = "ga"
- str.should == "ありgaとう"
- end
+ it "replaces multibyte characters with characters" do
+ str = "ありがとう"
+ str["が"] = "ga"
+ str.should == "ありgaとう"
+ end
- it "replaces multibyte characters with multibyte characters" do
- str = "ありがとう"
- str["が"] = "か"
- str.should == "ありかとう"
- end
+ it "replaces multibyte characters with multibyte characters" do
+ str = "ありがとう"
+ str["が"] = "か"
+ str.should == "ありかとう"
+ end
- it "encodes the String in an encoding compatible with the replacement" do
- str = " ".force_encoding Encoding::US_ASCII
- rep = [160].pack('C').force_encoding Encoding::ASCII_8BIT
- str[" "] = rep
- str.encoding.should equal(Encoding::ASCII_8BIT)
- end
+ it "encodes the String in an encoding compatible with the replacement" do
+ str = " ".force_encoding Encoding::US_ASCII
+ rep = [160].pack('C').force_encoding Encoding::BINARY
+ str[" "] = rep
+ str.encoding.should equal(Encoding::BINARY)
+ end
- it "raises an Encoding::CompatibilityError if the replacement encoding is incompatible" do
- str = "あれ"
- rep = "が".encode Encoding::EUC_JP
- lambda { str["れ"] = rep }.should raise_error(Encoding::CompatibilityError)
- end
+ it "raises an Encoding::CompatibilityError if the replacement encoding is incompatible" do
+ str = "あれ"
+ rep = "が".encode Encoding::EUC_JP
+ -> { str["れ"] = rep }.should raise_error(Encoding::CompatibilityError)
end
end
@@ -215,7 +208,7 @@ describe "String#[]= with a Regexp index" do
it "raises IndexError if the regexp index doesn't match a position in the string" do
str = "hello"
- lambda { str[/y/] = "bam" }.should raise_error(IndexError)
+ -> { str[/y/] = "bam" }.should raise_error(IndexError)
str.should == "hello"
end
@@ -232,7 +225,7 @@ describe "String#[]= with a Regexp index" do
rep = mock("string element set regexp")
rep.should_not_receive(:to_str)
- lambda { "abc"[/def/] = rep }.should raise_error(IndexError)
+ -> { "abc"[/def/] = rep }.should raise_error(IndexError)
end
describe "with 3 arguments" do
@@ -245,11 +238,11 @@ describe "String#[]= with a Regexp index" do
str.should == "axc"
end
- it "raises a TypeError if #to_int does not return a Fixnum" do
+ it "raises a TypeError if #to_int does not return an Integer" do
ref = mock("string element set regexp ref")
ref.should_receive(:to_int).and_return(nil)
- lambda { "abc"[/a(b)/, ref] = "x" }.should raise_error(TypeError)
+ -> { "abc"[/a(b)/, ref] = "x" }.should raise_error(TypeError)
end
it "uses the 2nd of 3 arguments as which capture should be replaced" do
@@ -268,56 +261,54 @@ describe "String#[]= with a Regexp index" do
rep = mock("string element set regexp")
rep.should_not_receive(:to_str)
- lambda { "abc"[/a(b)/, 2] = rep }.should raise_error(IndexError)
+ -> { "abc"[/a(b)/, 2] = rep }.should raise_error(IndexError)
end
it "raises IndexError if the specified capture isn't available" do
str = "aaa bbb ccc"
- lambda { str[/a (bbb) c/, 2] = "ddd" }.should raise_error(IndexError)
- lambda { str[/a (bbb) c/, -2] = "ddd" }.should raise_error(IndexError)
+ -> { str[/a (bbb) c/, 2] = "ddd" }.should raise_error(IndexError)
+ -> { str[/a (bbb) c/, -2] = "ddd" }.should raise_error(IndexError)
end
describe "when the optional capture does not match" do
it "raises an IndexError before setting the replacement" do
str1 = "a b c"
str2 = str1.dup
- lambda { str2[/a (b) (Z)?/, 2] = "d" }.should raise_error(IndexError)
+ -> { str2[/a (b) (Z)?/, 2] = "d" }.should raise_error(IndexError)
str2.should == str1
end
end
end
- with_feature :encoding do
- it "replaces characters with a multibyte character" do
- str = "ありgaとう"
- str[/ga/] = "が"
- str.should == "ありがとう"
- end
+ it "replaces characters with a multibyte character" do
+ str = "ありgaとう"
+ str[/ga/] = "が"
+ str.should == "ありがとう"
+ end
- it "replaces multibyte characters with characters" do
- str = "ありがとう"
- str[/が/] = "ga"
- str.should == "ありgaとう"
- end
+ it "replaces multibyte characters with characters" do
+ str = "ありがとう"
+ str[/が/] = "ga"
+ str.should == "ありgaとう"
+ end
- it "replaces multibyte characters with multibyte characters" do
- str = "ありがとう"
- str[/が/] = "か"
- str.should == "ありかとう"
- end
+ it "replaces multibyte characters with multibyte characters" do
+ str = "ありがとう"
+ str[/が/] = "か"
+ str.should == "ありかとう"
+ end
- it "encodes the String in an encoding compatible with the replacement" do
- str = " ".force_encoding Encoding::US_ASCII
- rep = [160].pack('C').force_encoding Encoding::ASCII_8BIT
- str[/ /] = rep
- str.encoding.should equal(Encoding::ASCII_8BIT)
- end
+ it "encodes the String in an encoding compatible with the replacement" do
+ str = " ".force_encoding Encoding::US_ASCII
+ rep = [160].pack('C').force_encoding Encoding::BINARY
+ str[/ /] = rep
+ str.encoding.should equal(Encoding::BINARY)
+ end
- it "raises an Encoding::CompatibilityError if the replacement encoding is incompatible" do
- str = "あれ"
- rep = "が".encode Encoding::EUC_JP
- lambda { str[/れ/] = rep }.should raise_error(Encoding::CompatibilityError)
- end
+ it "raises an Encoding::CompatibilityError if the replacement encoding is incompatible" do
+ str = "あれ"
+ rep = "が".encode Encoding::EUC_JP
+ -> { str[/れ/] = rep }.should raise_error(Encoding::CompatibilityError)
end
end
@@ -367,11 +358,11 @@ describe "String#[]= with a Range index" do
end
it "raises a RangeError if negative Range begin is out of range" do
- lambda { "abc"[-4..-2] = "x" }.should raise_error(RangeError)
+ -> { "abc"[-4..-2] = "x" }.should raise_error(RangeError, "-4..-2 out of range")
end
it "raises a RangeError if positive Range begin is greater than String size" do
- lambda { "abc"[4..2] = "x" }.should raise_error(RangeError)
+ -> { "abc"[4..2] = "x" }.should raise_error(RangeError, "4..2 out of range")
end
it "uses the Range end as an index rather than a count" do
@@ -392,59 +383,57 @@ describe "String#[]= with a Range index" do
str.should == "abcxd"
end
- with_feature :encoding do
- it "replaces characters with a multibyte character" do
- str = "ありgaとう"
- str[2..3] = "が"
- str.should == "ありがとう"
- end
+ it "replaces characters with a multibyte character" do
+ str = "ありgaとう"
+ str[2..3] = "が"
+ str.should == "ありがとう"
+ end
- it "replaces multibyte characters with characters" do
- str = "ありがとう"
- str[2...3] = "ga"
- str.should == "ありgaとう"
- end
+ it "replaces multibyte characters with characters" do
+ str = "ありがとう"
+ str[2...3] = "ga"
+ str.should == "ありgaとう"
+ end
- it "replaces multibyte characters by negative indexes" do
- str = "ありがとう"
- str[-3...-2] = "ga"
- str.should == "ありgaとう"
- end
+ it "replaces multibyte characters by negative indexes" do
+ str = "ありがとう"
+ str[-3...-2] = "ga"
+ str.should == "ありgaとう"
+ end
- it "replaces multibyte characters with multibyte characters" do
- str = "ありがとう"
- str[2..2] = "か"
- str.should == "ありかとう"
- end
+ it "replaces multibyte characters with multibyte characters" do
+ str = "ありがとう"
+ str[2..2] = "か"
+ str.should == "ありかとう"
+ end
- it "deletes a multibyte character" do
- str = "ありとう"
- str[2..3] = ""
- str.should == "あり"
- end
+ it "deletes a multibyte character" do
+ str = "ありとう"
+ str[2..3] = ""
+ str.should == "あり"
+ end
- it "inserts a multibyte character" do
- str = "ありとう"
- str[2...2] = "が"
- str.should == "ありがとう"
- end
+ it "inserts a multibyte character" do
+ str = "ありとう"
+ str[2...2] = "が"
+ str.should == "ありがとう"
+ end
- it "encodes the String in an encoding compatible with the replacement" do
- str = " ".force_encoding Encoding::US_ASCII
- rep = [160].pack('C').force_encoding Encoding::ASCII_8BIT
- str[0..1] = rep
- str.encoding.should equal(Encoding::ASCII_8BIT)
- end
+ it "encodes the String in an encoding compatible with the replacement" do
+ str = " ".force_encoding Encoding::US_ASCII
+ rep = [160].pack('C').force_encoding Encoding::BINARY
+ str[0..1] = rep
+ str.encoding.should equal(Encoding::BINARY)
+ end
- it "raises an Encoding::CompatibilityError if the replacement encoding is incompatible" do
- str = "あれ"
- rep = "が".encode Encoding::EUC_JP
- lambda { str[0..1] = rep }.should raise_error(Encoding::CompatibilityError)
- end
+ it "raises an Encoding::CompatibilityError if the replacement encoding is incompatible" do
+ str = "あれ"
+ rep = "が".encode Encoding::EUC_JP
+ -> { str[0..1] = rep }.should raise_error(Encoding::CompatibilityError)
end
end
-describe "String#[]= with Fixnum index, count" do
+describe "String#[]= with Integer index, count" do
it "starts at idx and overwrites count characters before inserting the rest of other_str" do
a = "hello"
a[0, 2] = "xx"
@@ -493,16 +482,6 @@ describe "String#[]= with Fixnum index, count" do
a.should == "hellobob"
end
- it "taints self if other_str is tainted" do
- a = "hello"
- a[0, 0] = "".taint
- a.tainted?.should == true
-
- a = "hello"
- a[1, 4] = "x".taint
- a.tainted?.should == true
- end
-
it "calls #to_int to convert the index and count objects" do
index = mock("string element set index")
index.should_receive(:to_int).and_return(-4)
@@ -519,14 +498,14 @@ describe "String#[]= with Fixnum index, count" do
index = mock("string element set index")
index.should_receive(:to_int).and_return("1")
- lambda { "abc"[index, 2] = "xyz" }.should raise_error(TypeError)
+ -> { "abc"[index, 2] = "xyz" }.should raise_error(TypeError)
end
it "raises a TypeError if #to_int for count does not return an Integer" do
count = mock("string element set count")
count.should_receive(:to_int).and_return("1")
- lambda { "abc"[1, count] = "xyz" }.should raise_error(TypeError)
+ -> { "abc"[1, count] = "xyz" }.should raise_error(TypeError)
end
it "calls #to_str to convert the replacement object" do
@@ -542,71 +521,69 @@ describe "String#[]= with Fixnum index, count" do
r = mock("string element set replacement")
r.should_receive(:to_str).and_return(nil)
- lambda { "abc"[1, 1] = r }.should raise_error(TypeError)
+ -> { "abc"[1, 1] = r }.should raise_error(TypeError)
end
it "raises an IndexError if |idx| is greater than the length of the string" do
- lambda { "hello"[6, 0] = "bob" }.should raise_error(IndexError)
- lambda { "hello"[-6, 0] = "bob" }.should raise_error(IndexError)
+ -> { "hello"[6, 0] = "bob" }.should raise_error(IndexError)
+ -> { "hello"[-6, 0] = "bob" }.should raise_error(IndexError)
end
it "raises an IndexError if count < 0" do
- lambda { "hello"[0, -1] = "bob" }.should raise_error(IndexError)
- lambda { "hello"[1, -1] = "bob" }.should raise_error(IndexError)
+ -> { "hello"[0, -1] = "bob" }.should raise_error(IndexError)
+ -> { "hello"[1, -1] = "bob" }.should raise_error(IndexError)
end
it "raises a TypeError if other_str is a type other than String" do
- lambda { "hello"[0, 2] = nil }.should raise_error(TypeError)
- lambda { "hello"[0, 2] = [] }.should raise_error(TypeError)
- lambda { "hello"[0, 2] = 33 }.should raise_error(TypeError)
+ -> { "hello"[0, 2] = nil }.should raise_error(TypeError)
+ -> { "hello"[0, 2] = [] }.should raise_error(TypeError)
+ -> { "hello"[0, 2] = 33 }.should raise_error(TypeError)
end
- with_feature :encoding do
- it "replaces characters with a multibyte character" do
- str = "ありgaとう"
- str[2, 2] = "が"
- str.should == "ありがとう"
- end
+ it "replaces characters with a multibyte character" do
+ str = "ありgaとう"
+ str[2, 2] = "が"
+ str.should == "ありがとう"
+ end
- it "replaces multibyte characters with characters" do
- str = "ありがとう"
- str[2, 1] = "ga"
- str.should == "ありgaとう"
- end
+ it "replaces multibyte characters with characters" do
+ str = "ありがとう"
+ str[2, 1] = "ga"
+ str.should == "ありgaとう"
+ end
- it "replaces multibyte characters with multibyte characters" do
- str = "ありがとう"
- str[2, 1] = "か"
- str.should == "ありかとう"
- end
+ it "replaces multibyte characters with multibyte characters" do
+ str = "ありがとう"
+ str[2, 1] = "か"
+ str.should == "ありかとう"
+ end
- it "deletes a multibyte character" do
- str = "ありとう"
- str[2, 2] = ""
- str.should == "あり"
- end
+ it "deletes a multibyte character" do
+ str = "ありとう"
+ str[2, 2] = ""
+ str.should == "あり"
+ end
- it "inserts a multibyte character" do
- str = "ありとう"
- str[2, 0] = "が"
- str.should == "ありがとう"
- end
+ it "inserts a multibyte character" do
+ str = "ありとう"
+ str[2, 0] = "が"
+ str.should == "ありがとう"
+ end
- it "raises an IndexError if the character index is out of range of a multibyte String" do
- lambda { "あれ"[3, 0] = "り" }.should raise_error(IndexError)
- end
+ it "raises an IndexError if the character index is out of range of a multibyte String" do
+ -> { "あれ"[3, 0] = "り" }.should raise_error(IndexError)
+ end
- it "encodes the String in an encoding compatible with the replacement" do
- str = " ".force_encoding Encoding::US_ASCII
- rep = [160].pack('C').force_encoding Encoding::ASCII_8BIT
- str[0, 1] = rep
- str.encoding.should equal(Encoding::ASCII_8BIT)
- end
+ it "encodes the String in an encoding compatible with the replacement" do
+ str = " ".force_encoding Encoding::US_ASCII
+ rep = [160].pack('C').force_encoding Encoding::BINARY
+ str[0, 1] = rep
+ str.encoding.should equal(Encoding::BINARY)
+ end
- it "raises an Encoding::CompatibilityError if the replacement encoding is incompatible" do
- str = "あれ"
- rep = "が".encode Encoding::EUC_JP
- lambda { str[0, 1] = rep }.should raise_error(Encoding::CompatibilityError)
- end
+ it "raises an Encoding::CompatibilityError if the replacement encoding is incompatible" do
+ str = "あれ"
+ rep = "が".encode Encoding::EUC_JP
+ -> { str[0, 1] = rep }.should raise_error(Encoding::CompatibilityError)
end
end
diff --git a/spec/ruby/core/string/empty_spec.rb b/spec/ruby/core/string/empty_spec.rb
index c13e1145e4..8e53a16afc 100644
--- a/spec/ruby/core/string/empty_spec.rb
+++ b/spec/ruby/core/string/empty_spec.rb
@@ -1,12 +1,12 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String#empty?" do
it "returns true if the string has a length of zero" do
- "hello".empty?.should == false
- " ".empty?.should == false
- "\x00".empty?.should == false
- "".empty?.should == true
- StringSpecs::MyString.new("").empty?.should == true
+ "hello".should_not.empty?
+ " ".should_not.empty?
+ "\x00".should_not.empty?
+ "".should.empty?
+ StringSpecs::MyString.new("").should.empty?
end
end
diff --git a/spec/ruby/core/string/encode_spec.rb b/spec/ruby/core/string/encode_spec.rb
index d051dd58c9..cd449498a3 100644
--- a/spec/ruby/core/string/encode_spec.rb
+++ b/spec/ruby/core/string/encode_spec.rb
@@ -1,159 +1,240 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../shared/encode', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'shared/encode'
-with_feature :encoding do
- describe "String#encode" do
- before :each do
- @external = Encoding.default_external
- @internal = Encoding.default_internal
+describe "String#encode" do
+ before :each do
+ @external = Encoding.default_external
+ @internal = Encoding.default_internal
+ end
+
+ after :each do
+ Encoding.default_external = @external
+ Encoding.default_internal = @internal
+ end
+
+ it_behaves_like :string_encode, :encode
+
+ describe "when passed no options" do
+ it "returns a copy when Encoding.default_internal is nil" do
+ Encoding.default_internal = nil
+ str = "あ"
+ encoded = str.encode
+ encoded.should_not equal(str)
+ encoded.should == str
end
- after :each do
- Encoding.default_external = @external
- Encoding.default_internal = @internal
+ it "returns a copy for a ASCII-only String when Encoding.default_internal is nil" do
+ Encoding.default_internal = nil
+ str = "abc"
+ encoded = str.encode
+ encoded.should_not equal(str)
+ encoded.should == str
+ end
+
+ it "encodes an ascii substring of a binary string to UTF-8" do
+ x82 = [0x82].pack('C')
+ str = "#{x82}foo".dup.force_encoding("binary")[1..-1].encode("utf-8")
+ str.should == "foo".dup.force_encoding("utf-8")
+ str.encoding.should equal(Encoding::UTF_8)
+ end
+ end
+
+ describe "when passed to encoding" do
+ it "returns a copy when passed the same encoding as the String" do
+ str = "あ"
+ encoded = str.encode(Encoding::UTF_8)
+ encoded.should_not equal(str)
+ encoded.should == str
end
- it_behaves_like :string_encode, :encode
+ it "round trips a String" do
+ str = "abc def".dup.force_encoding Encoding::US_ASCII
+ str.encode("utf-32be").encode("ascii").should == "abc def"
+ end
+ end
- describe "when passed no options" do
- it "returns a copy when Encoding.default_internal is nil" do
- Encoding.default_internal = nil
- str = "あ"
- str.encode.should_not equal(str)
- end
+ describe "when passed options" do
+ it "returns a copy when Encoding.default_internal is nil" do
+ Encoding.default_internal = nil
+ str = "あ"
+ str.encode(invalid: :replace).should_not equal(str)
+ end
- it "returns a copy for a ASCII-only String when Encoding.default_internal is nil" do
- Encoding.default_internal = nil
- str = "abc"
- str.encode.should_not equal(str)
- end
+ it "normalizes newlines with cr_newline option" do
+ "\r\nfoo".encode(cr_newline: true).should == "\r\rfoo"
+ "\rfoo".encode(cr_newline: true).should == "\rfoo"
+ "\nfoo".encode(cr_newline: true).should == "\rfoo"
+ end
- it "encodes an ascii substring of a binary string to UTF-8" do
- x82 = [0x82].pack('C')
- str = "#{x82}foo".force_encoding("ascii-8bit")[1..-1].encode("utf-8")
- str.should == "foo".force_encoding("utf-8")
- str.encoding.should equal(Encoding::UTF_8)
- end
+ it "normalizes newlines with crlf_newline option" do
+ "\r\nfoo".encode(crlf_newline: true).should == "\r\r\nfoo"
+ "\rfoo".encode(crlf_newline: true).should == "\rfoo"
+ "\nfoo".encode(crlf_newline: true).should == "\r\nfoo"
end
- describe "when passed to encoding" do
- it "returns a copy when passed the same encoding as the String" do
- str = "あ"
- str.encode(Encoding::UTF_8).should_not equal(str)
- end
+ it "normalizes newlines with universal_newline option" do
+ "\r\nfoo".encode(universal_newline: true).should == "\nfoo"
+ "\rfoo".encode(universal_newline: true).should == "\nfoo"
+ "\nfoo".encode(universal_newline: true).should == "\nfoo"
+ end
- it "round trips a String" do
- str = "abc def".force_encoding Encoding::US_ASCII
- str.encode("utf-32be").encode("ascii").should == "abc def"
- end
+ it "replaces invalid encoding in source with default replacement" do
+ encoded = "ち\xE3\x81\xFF".encode("UTF-16LE", invalid: :replace)
+ encoded.should == "\u3061\ufffd\ufffd".encode("UTF-16LE")
+ encoded.encode("UTF-8").should == "ち\ufffd\ufffd"
end
- describe "when passed options" do
- it "returns a copy when Encoding.default_internal is nil" do
- Encoding.default_internal = nil
- str = "あ"
- str.encode(invalid: :replace).should_not equal(str)
- end
+ it "replaces invalid encoding in source with a specified replacement" do
+ encoded = "ち\xE3\x81\xFF".encode("UTF-16LE", invalid: :replace, replace: "foo")
+ encoded.should == "\u3061foofoo".encode("UTF-16LE")
+ encoded.encode("UTF-8").should == "ちfoofoo"
+ end
- it "normalizes newlines" do
- "\r\nfoo".encode(universal_newline: true).should == "\nfoo"
+ it "replace multiple invalid bytes at the end with a single replacement character" do
+ "\xE3\x81\x93\xE3\x81".encode("UTF-8", invalid: :replace).should == "\u3053\ufffd"
+ end
- "\rfoo".encode(universal_newline: true).should == "\nfoo"
- end
+ it "replaces invalid encoding in source using a specified replacement even when a fallback is given" do
+ encoded = "ち\xE3\x81\xFF".encode("UTF-16LE", invalid: :replace, replace: "foo", fallback: -> c { "bar" })
+ encoded.should == "\u3061foofoo".encode("UTF-16LE")
+ encoded.encode("UTF-8").should == "ちfoofoo"
end
- describe "when passed to, from" do
- it "returns a copy in the destination encoding when both encodings are the same" do
- str = "あ"
- str.force_encoding("ascii-8bit")
- encoded = str.encode("utf-8", "utf-8")
+ it "replaces undefined encoding in destination with default replacement" do
+ encoded = "B\ufffd".encode(Encoding::US_ASCII, undef: :replace)
+ encoded.should == "B?".encode(Encoding::US_ASCII)
+ encoded.encode("UTF-8").should == "B?"
+ end
- encoded.should_not equal(str)
- encoded.encoding.should == Encoding::UTF_8
- end
+ it "replaces undefined encoding in destination with a specified replacement" do
+ encoded = "B\ufffd".encode(Encoding::US_ASCII, undef: :replace, replace: "foo")
+ encoded.should == "Bfoo".encode(Encoding::US_ASCII)
+ encoded.encode("UTF-8").should == "Bfoo"
+ end
- it "returns the transcoded string" do
- str = "\x00\x00\x00\x1F"
- str.encode(Encoding::UTF_8, Encoding::UTF_16BE).should == "\u0000\u001f"
- end
+ it "replaces undefined encoding in destination with a specified replacement even if a fallback is given" do
+ encoded = "B\ufffd".encode(Encoding::US_ASCII, undef: :replace, replace: "foo", fallback: proc {|x| "bar"})
+ encoded.should == "Bfoo".encode(Encoding::US_ASCII)
+ encoded.encode("UTF-8").should == "Bfoo"
end
- describe "when passed to, options" do
- it "returns a copy when the destination encoding is the same as the String encoding" do
- str = "あ"
- str.encode(Encoding::UTF_8, undef: :replace).should_not equal(str)
- end
+ it "replaces undefined encoding in destination using a fallback proc" do
+ encoded = "B\ufffd".encode(Encoding::US_ASCII, fallback: proc {|x| "bar"})
+ encoded.should == "Bbar".encode(Encoding::US_ASCII)
+ encoded.encode("UTF-8").should == "Bbar"
end
- describe "when passed to, from, options" do
- it "returns a copy when both encodings are the same" do
- str = "あ"
- str.encode("utf-8", "utf-8", invalid: :replace).should_not equal(str)
- end
+ it "replaces invalid encoding in source using replace even when fallback is given as proc" do
+ encoded = "ち\xE3\x81\xFF".encode("UTF-16LE", invalid: :replace, replace: "foo", fallback: proc {|x| "bar"})
+ encoded.should == "\u3061foofoo".encode("UTF-16LE")
+ encoded.encode("UTF-8").should == "ちfoofoo"
end
end
- describe "String#encode!" do
- before :each do
- @external = Encoding.default_external
- @internal = Encoding.default_internal
+ describe "when passed to, from" do
+ it "returns a copy in the destination encoding when both encodings are the same" do
+ str = "あ".dup.force_encoding("binary")
+ encoded = str.encode("utf-8", "utf-8")
+
+ encoded.should_not equal(str)
+ encoded.should == str.force_encoding("utf-8")
+ encoded.encoding.should == Encoding::UTF_8
end
- after :each do
- Encoding.default_external = @external
- Encoding.default_internal = @internal
+ it "returns the transcoded string" do
+ str = "\x00\x00\x00\x1F"
+ str.encode(Encoding::UTF_8, Encoding::UTF_16BE).should == "\u0000\u001f"
end
+ end
- it_behaves_like :string_encode, :encode!
+ describe "when passed to, options" do
+ it "returns a copy when the destination encoding is the same as the String encoding" do
+ str = "あ"
+ encoded = str.encode(Encoding::UTF_8, undef: :replace)
+ encoded.should_not equal(str)
+ encoded.should == str
+ end
+ end
- it "raises a RuntimeError when called on a frozen String" do
- lambda { "foo".freeze.encode!("euc-jp") }.should raise_error(RuntimeError)
+ describe "when passed to, from, options" do
+ it "returns a copy when both encodings are the same" do
+ str = "あ"
+ encoded = str.encode("utf-8", "utf-8", invalid: :replace)
+ encoded.should_not equal(str)
+ encoded.should == str
end
- # http://redmine.ruby-lang.org/issues/show/1836
- it "raises a RuntimeError when called on a frozen String when it's a no-op" do
- lambda { "foo".freeze.encode!("utf-8") }.should raise_error(RuntimeError)
+ it "returns a copy in the destination encoding when both encodings are the same" do
+ str = "あ".dup.force_encoding("binary")
+ encoded = str.encode("utf-8", "utf-8", invalid: :replace)
+
+ encoded.should_not equal(str)
+ encoded.should == str.force_encoding("utf-8")
+ encoded.encoding.should == Encoding::UTF_8
end
+ end
+end
+
+describe "String#encode!" do
+ before :each do
+ @external = Encoding.default_external
+ @internal = Encoding.default_internal
+ end
+
+ after :each do
+ Encoding.default_external = @external
+ Encoding.default_internal = @internal
+ end
- describe "when passed no options" do
- it "returns self when Encoding.default_internal is nil" do
- Encoding.default_internal = nil
- str = "あ"
- str.encode!.should equal(str)
- end
+ it_behaves_like :string_encode, :encode!
- it "returns self for a ASCII-only String when Encoding.default_internal is nil" do
- Encoding.default_internal = nil
- str = "abc"
- str.encode!.should equal(str)
- end
+ it "raises a FrozenError when called on a frozen String" do
+ -> { "foo".freeze.encode!("euc-jp") }.should raise_error(FrozenError)
+ end
+
+ # http://redmine.ruby-lang.org/issues/show/1836
+ it "raises a FrozenError when called on a frozen String when it's a no-op" do
+ -> { "foo".freeze.encode!("utf-8") }.should raise_error(FrozenError)
+ end
+
+ describe "when passed no options" do
+ it "returns self when Encoding.default_internal is nil" do
+ Encoding.default_internal = nil
+ str = +"あ"
+ str.encode!.should equal(str)
end
- describe "when passed options" do
- it "returns self for ASCII-only String when Encoding.default_internal is nil" do
- Encoding.default_internal = nil
- str = "abc"
- str.encode!(invalid: :replace).should equal(str)
- end
+ it "returns self for a ASCII-only String when Encoding.default_internal is nil" do
+ Encoding.default_internal = nil
+ str = +"abc"
+ str.encode!.should equal(str)
end
+ end
- describe "when passed to encoding" do
- it "returns self" do
- str = "abc"
- result = str.encode!(Encoding::BINARY)
- result.encoding.should equal(Encoding::BINARY)
- result.should equal(str)
- end
+ describe "when passed options" do
+ it "returns self for ASCII-only String when Encoding.default_internal is nil" do
+ Encoding.default_internal = nil
+ str = +"abc"
+ str.encode!(invalid: :replace).should equal(str)
end
+ end
+
+ describe "when passed to encoding" do
+ it "returns self" do
+ str = +"abc"
+ result = str.encode!(Encoding::BINARY)
+ result.encoding.should equal(Encoding::BINARY)
+ result.should equal(str)
+ end
+ end
- describe "when passed to, from" do
- it "returns self" do
- str = "ああ"
- result = str.encode!("euc-jp", "utf-8")
- result.encoding.should equal(Encoding::EUC_JP)
- result.should equal(str)
- end
+ describe "when passed to, from" do
+ it "returns self" do
+ str = +"ああ"
+ result = str.encode!("euc-jp", "utf-8")
+ result.encoding.should equal(Encoding::EUC_JP)
+ result.should equal(str)
end
end
end
diff --git a/spec/ruby/core/string/encoding_spec.rb b/spec/ruby/core/string/encoding_spec.rb
index 9c655757a8..f6e8fd3470 100644
--- a/spec/ruby/core/string/encoding_spec.rb
+++ b/spec/ruby/core/string/encoding_spec.rb
@@ -1,189 +1,184 @@
# -*- encoding: us-ascii -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/iso-8859-9-encoding', __FILE__)
-
-with_feature :encoding do
- describe "String#encoding" do
- it "returns an Encoding object" do
- String.new.encoding.should be_an_instance_of(Encoding)
- end
-
- it "is equal to the source encoding by default" do
- s = StringSpecs::ISO88599Encoding.new
- s.cedilla.encoding.should == s.source_encoding
- end
-
- it "returns the given encoding if #force_encoding has been called" do
- "a".force_encoding(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
- end
-
- it "returns the given encoding if #encode!has been called" do
- "a".encode!(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
- end
- end
-
- describe "String#encoding for US-ASCII Strings" do
- it "returns US-ASCII if self is US-ASCII" do
- "a".encoding.should == Encoding::US_ASCII
- end
-
- it "returns US-ASCII if self is US-ASCII only, despite the default internal encoding being different" do
- default_internal = Encoding.default_internal
- Encoding.default_internal = Encoding::UTF_8
- "a".encoding.should == Encoding::US_ASCII
- Encoding.default_internal = default_internal
- end
-
- it "returns US-ASCII if self is US-ASCII only, despite the default external encoding being different" do
- default_external = Encoding.default_external
- Encoding.default_external = Encoding::UTF_8
- "a".encoding.should == Encoding::US_ASCII
- Encoding.default_external = default_external
- end
-
- it "returns US-ASCII if self is US-ASCII only, despite the default internal and external encodings being different" do
- default_internal = Encoding.default_internal
- default_external = Encoding.default_external
- Encoding.default_internal = Encoding::UTF_8
- Encoding.default_external = Encoding::UTF_8
- "a".encoding.should == Encoding::US_ASCII
- Encoding.default_external = default_external
- Encoding.default_internal = default_internal
- end
-
- it "returns US-ASCII if self is US-ASCII only, despite the default encodings being different" do
- default_internal = Encoding.default_internal
- default_external = Encoding.default_external
- Encoding.default_internal = Encoding::UTF_8
- Encoding.default_external = Encoding::UTF_8
- "a".encoding.should == Encoding::US_ASCII
- Encoding.default_external = default_external
- Encoding.default_internal = default_internal
- end
-
- end
-
- describe "String#encoding for Strings with \\u escapes" do
- it "returns UTF-8" do
- "\u{4040}".encoding.should == Encoding::UTF_8
- end
-
- it "returns US-ASCII if self is US-ASCII only" do
- s = "\u{40}"
- s.ascii_only?.should be_true
- s.encoding.should == Encoding::US_ASCII
- end
-
- it "returns UTF-8 if self isn't US-ASCII only" do
- s = "\u{4076}\u{619}"
- s.ascii_only?.should be_false
- s.encoding.should == Encoding::UTF_8
- end
-
- it "is not affected by the default internal encoding" do
- default_internal = Encoding.default_internal
- Encoding.default_internal = Encoding::ISO_8859_15
- "\u{5050}".encoding.should == Encoding::UTF_8
- "\u{50}".encoding.should == Encoding::US_ASCII
- Encoding.default_internal = default_internal
- end
-
- it "is not affected by the default external encoding" do
- default_external = Encoding.default_external
- Encoding.default_external = Encoding::SHIFT_JIS
- "\u{50}".encoding.should == Encoding::US_ASCII
- "\u{5050}".encoding.should == Encoding::UTF_8
- Encoding.default_external = default_external
- end
-
- it "is not affected by both the default internal and external encoding being set at the same time" do
- default_internal = Encoding.default_internal
- default_external = Encoding.default_external
- Encoding.default_internal = Encoding::EUC_JP
- Encoding.default_external = Encoding::SHIFT_JIS
- "\u{50}".encoding.should == Encoding::US_ASCII
- "\u{507}".encoding.should == Encoding::UTF_8
- Encoding.default_external = default_external
- Encoding.default_internal = default_internal
- end
-
- it "returns the given encoding if #force_encoding has been called" do
- "\u{20}".force_encoding(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
- "\u{2020}".force_encoding(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
- end
-
- it "returns the given encoding if #encode!has been called" do
- "\u{20}".encode!(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
- "\u{2020}".encode!(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
- end
- end
-
- describe "String#encoding for Strings with \\x escapes" do
-
- it "returns US-ASCII if self is US-ASCII only" do
- s = "\x61"
- s.ascii_only?.should be_true
- s.encoding.should == Encoding::US_ASCII
- end
-
- it "returns ASCII-8BIT when an escape creates a byte with the 8th bit set if the source encoding is US-ASCII" do
- __ENCODING__.should == Encoding::US_ASCII
- str = " "
- str.encoding.should == Encoding::US_ASCII
- str += [0xDF].pack('C')
- str.ascii_only?.should be_false
- str.encoding.should == Encoding::ASCII_8BIT
- end
-
- # TODO: Deal with case when the byte in question isn't valid in the source
- # encoding?
- it "returns the source encoding when an escape creates a byte with the 8th bit set if the source encoding isn't US-ASCII" do
- fixture = StringSpecs::ISO88599Encoding.new
- fixture.source_encoding.should == Encoding::ISO8859_9
- fixture.x_escape.ascii_only?.should be_false
- fixture.x_escape.encoding.should == Encoding::ISO8859_9
- end
-
- it "is not affected by the default internal encoding" do
- default_internal = Encoding.default_internal
- Encoding.default_internal = Encoding::ISO_8859_15
- "\x50".encoding.should == Encoding::US_ASCII
- "\x50".encoding.should == Encoding::US_ASCII
- Encoding.default_internal = default_internal
- end
-
- it "is not affected by the default external encoding" do
- default_external = Encoding.default_external
- Encoding.default_external = Encoding::SHIFT_JIS
- "\x50".encoding.should == Encoding::US_ASCII
- [0xD4].pack('C').encoding.should == Encoding::ASCII_8BIT
- Encoding.default_external = default_external
- end
-
- it "is not affected by both the default internal and external encoding being set at the same time" do
- default_internal = Encoding.default_internal
- default_external = Encoding.default_external
- Encoding.default_internal = Encoding::EUC_JP
- Encoding.default_external = Encoding::SHIFT_JIS
- x50 = "\x50"
- x50.encoding.should == Encoding::US_ASCII
- [0xD4].pack('C').encoding.should == Encoding::ASCII_8BIT
- Encoding.default_external = default_external
- Encoding.default_internal = default_internal
- end
-
- it "returns the given encoding if #force_encoding has been called" do
- x50 = "\x50"
- x50.force_encoding(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
- xD4 = [212].pack('C')
- xD4.force_encoding(Encoding::ISO_8859_9).encoding.should == Encoding::ISO_8859_9
- end
-
- it "returns the given encoding if #encode!has been called" do
- x50 = "\x50"
- x50.encode!(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
- x00 = "x\00"
- x00.encode!(Encoding::UTF_8).encoding.should == Encoding::UTF_8
- end
+require_relative '../../spec_helper'
+require_relative 'fixtures/iso-8859-9-encoding'
+
+describe "String#encoding" do
+ it "returns an Encoding object" do
+ String.new.encoding.should be_an_instance_of(Encoding)
+ end
+
+ it "is equal to the source encoding by default" do
+ s = StringSpecs::ISO88599Encoding.new
+ s.cedilla.encoding.should == s.source_encoding
+ s.cedilla.encode("utf-8").should == 350.chr(Encoding::UTF_8) # S-cedilla
+ end
+
+ it "returns the given encoding if #force_encoding has been called" do
+ "a".dup.force_encoding(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
+ end
+
+ it "returns the given encoding if #encode!has been called" do
+ "a".dup.encode!(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
+ end
+end
+
+describe "String#encoding for US-ASCII Strings" do
+ it "returns US-ASCII if self is US-ASCII" do
+ "a".encoding.should == Encoding::US_ASCII
+ end
+
+ it "returns US-ASCII if self is US-ASCII only, despite the default internal encoding being different" do
+ default_internal = Encoding.default_internal
+ Encoding.default_internal = Encoding::UTF_8
+ "a".encoding.should == Encoding::US_ASCII
+ Encoding.default_internal = default_internal
+ end
+
+ it "returns US-ASCII if self is US-ASCII only, despite the default external encoding being different" do
+ default_external = Encoding.default_external
+ Encoding.default_external = Encoding::UTF_8
+ "a".encoding.should == Encoding::US_ASCII
+ Encoding.default_external = default_external
+ end
+
+ it "returns US-ASCII if self is US-ASCII only, despite the default internal and external encodings being different" do
+ default_internal = Encoding.default_internal
+ default_external = Encoding.default_external
+ Encoding.default_internal = Encoding::UTF_8
+ Encoding.default_external = Encoding::UTF_8
+ "a".encoding.should == Encoding::US_ASCII
+ Encoding.default_external = default_external
+ Encoding.default_internal = default_internal
+ end
+
+ it "returns US-ASCII if self is US-ASCII only, despite the default encodings being different" do
+ default_internal = Encoding.default_internal
+ default_external = Encoding.default_external
+ Encoding.default_internal = Encoding::UTF_8
+ Encoding.default_external = Encoding::UTF_8
+ "a".encoding.should == Encoding::US_ASCII
+ Encoding.default_external = default_external
+ Encoding.default_internal = default_internal
+ end
+
+end
+
+describe "String#encoding for Strings with \\u escapes" do
+ it "returns UTF-8" do
+ "\u{4040}".encoding.should == Encoding::UTF_8
+ end
+
+ it "returns US-ASCII if self is US-ASCII only" do
+ s = "\u{40}"
+ s.ascii_only?.should be_true
+ s.encoding.should == Encoding::US_ASCII
+ end
+
+ it "returns UTF-8 if self isn't US-ASCII only" do
+ s = "\u{4076}\u{619}"
+ s.ascii_only?.should be_false
+ s.encoding.should == Encoding::UTF_8
+ end
+
+ it "is not affected by the default internal encoding" do
+ default_internal = Encoding.default_internal
+ Encoding.default_internal = Encoding::ISO_8859_15
+ "\u{5050}".encoding.should == Encoding::UTF_8
+ "\u{50}".encoding.should == Encoding::US_ASCII
+ Encoding.default_internal = default_internal
+ end
+
+ it "is not affected by the default external encoding" do
+ default_external = Encoding.default_external
+ Encoding.default_external = Encoding::SHIFT_JIS
+ "\u{50}".encoding.should == Encoding::US_ASCII
+ "\u{5050}".encoding.should == Encoding::UTF_8
+ Encoding.default_external = default_external
+ end
+
+ it "is not affected by both the default internal and external encoding being set at the same time" do
+ default_internal = Encoding.default_internal
+ default_external = Encoding.default_external
+ Encoding.default_internal = Encoding::EUC_JP
+ Encoding.default_external = Encoding::SHIFT_JIS
+ "\u{50}".encoding.should == Encoding::US_ASCII
+ "\u{507}".encoding.should == Encoding::UTF_8
+ Encoding.default_external = default_external
+ Encoding.default_internal = default_internal
+ end
+
+ it "returns the given encoding if #force_encoding has been called" do
+ "\u{20}".dup.force_encoding(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
+ "\u{2020}".dup.force_encoding(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
+ end
+
+ it "returns the given encoding if #encode!has been called" do
+ "\u{20}".dup.encode!(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
+ "\u{2020}".dup.encode!(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
+ end
+end
+
+describe "String#encoding for Strings with \\x escapes" do
+
+ it "returns US-ASCII if self is US-ASCII only" do
+ s = "\x61"
+ s.ascii_only?.should be_true
+ s.encoding.should == Encoding::US_ASCII
+ end
+
+ it "returns BINARY when an escape creates a byte with the 8th bit set if the source encoding is US-ASCII" do
+ __ENCODING__.should == Encoding::US_ASCII
+ str = " "
+ str.encoding.should == Encoding::US_ASCII
+ str += [0xDF].pack('C')
+ str.ascii_only?.should be_false
+ str.encoding.should == Encoding::BINARY
+ end
+
+ # TODO: Deal with case when the byte in question isn't valid in the source
+ # encoding?
+ it "returns the source encoding when an escape creates a byte with the 8th bit set if the source encoding isn't US-ASCII" do
+ fixture = StringSpecs::ISO88599Encoding.new
+ fixture.source_encoding.should == Encoding::ISO8859_9
+ fixture.x_escape.ascii_only?.should be_false
+ fixture.x_escape.encoding.should == Encoding::ISO8859_9
+ end
+
+ it "is not affected by the default internal encoding" do
+ default_internal = Encoding.default_internal
+ Encoding.default_internal = Encoding::ISO_8859_15
+ "\x50".encoding.should == Encoding::US_ASCII
+ "\x50".encoding.should == Encoding::US_ASCII
+ Encoding.default_internal = default_internal
+ end
+
+ it "is not affected by the default external encoding" do
+ default_external = Encoding.default_external
+ Encoding.default_external = Encoding::SHIFT_JIS
+ "\x50".encoding.should == Encoding::US_ASCII
+ [0xD4].pack('C').encoding.should == Encoding::BINARY
+ Encoding.default_external = default_external
+ end
+
+ it "is not affected by both the default internal and external encoding being set at the same time" do
+ default_internal = Encoding.default_internal
+ default_external = Encoding.default_external
+ Encoding.default_internal = Encoding::EUC_JP
+ Encoding.default_external = Encoding::SHIFT_JIS
+ x50 = "\x50"
+ x50.encoding.should == Encoding::US_ASCII
+ [0xD4].pack('C').encoding.should == Encoding::BINARY
+ Encoding.default_external = default_external
+ Encoding.default_internal = default_internal
+ end
+
+ it "returns the given encoding if #force_encoding has been called" do
+ "\x50".dup.force_encoding(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
+ [212].pack('C').force_encoding(Encoding::ISO_8859_9).encoding.should == Encoding::ISO_8859_9
+ end
+
+ it "returns the given encoding if #encode!has been called" do
+ "\x50".dup.encode!(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
+ "x\00".dup.encode!(Encoding::UTF_8).encoding.should == Encoding::UTF_8
end
end
diff --git a/spec/ruby/core/string/end_with_spec.rb b/spec/ruby/core/string/end_with_spec.rb
index 2c3ff07272..ac4fff72ad 100644
--- a/spec/ruby/core/string/end_with_spec.rb
+++ b/spec/ruby/core/string/end_with_spec.rb
@@ -1,50 +1,8 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative '../../shared/string/end_with'
describe "String#end_with?" do
- it "returns true only if ends match" do
- s = "hello"
- s.end_with?('o').should be_true
- s.end_with?('llo').should be_true
- end
-
- it 'returns false if the end does not match' do
- s = 'hello'
- s.end_with?('ll').should be_false
- end
-
- it "returns true if the search string is empty" do
- "hello".end_with?("").should be_true
- "".end_with?("").should be_true
- end
-
- it "returns true only if any ending match" do
- "hello".end_with?('x', 'y', 'llo', 'z').should be_true
- end
-
- it "converts its argument using :to_str" do
- s = "hello"
- find = mock('o')
- find.should_receive(:to_str).and_return("o")
- s.end_with?(find).should be_true
- end
-
- it "ignores arguments not convertible to string" do
- "hello".end_with?().should be_false
- lambda { "hello".end_with?(1) }.should raise_error(TypeError)
- lambda { "hello".end_with?(["o"]) }.should raise_error(TypeError)
- lambda { "hello".end_with?(1, nil, "o") }.should raise_error(TypeError)
- end
-
- it "uses only the needed arguments" do
- find = mock('h')
- find.should_not_receive(:to_str)
- "hello".end_with?("o",find).should be_true
- end
-
- it "works for multibyte strings" do
- "céréale".end_with?("réale").should be_true
- end
-
+ it_behaves_like :end_with, :to_s
end
diff --git a/spec/ruby/core/string/eql_spec.rb b/spec/ruby/core/string/eql_spec.rb
index df094e122f..397974d9fb 100644
--- a/spec/ruby/core/string/eql_spec.rb
+++ b/spec/ruby/core/string/eql_spec.rb
@@ -1,8 +1,8 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../shared/eql', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'shared/eql'
describe "String#eql?" do
- it_behaves_like(:string_eql_value, :eql?)
+ it_behaves_like :string_eql_value, :eql?
describe "when given a non-String" do
it "returns false" do
diff --git a/spec/ruby/core/string/equal_value_spec.rb b/spec/ruby/core/string/equal_value_spec.rb
index bf252d6d30..b9c9c372f8 100644
--- a/spec/ruby/core/string/equal_value_spec.rb
+++ b/spec/ruby/core/string/equal_value_spec.rb
@@ -1,8 +1,8 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../shared/eql', __FILE__)
-require File.expand_path('../shared/equal_value', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'shared/eql'
+require_relative 'shared/equal_value'
describe "String#==" do
- it_behaves_like(:string_eql_value, :==)
- it_behaves_like(:string_equal_value, :==)
+ it_behaves_like :string_eql_value, :==
+ it_behaves_like :string_equal_value, :==
end
diff --git a/spec/ruby/core/string/fixtures/classes.rb b/spec/ruby/core/string/fixtures/classes.rb
index 6af106f9d3..26fcd51b5d 100644
--- a/spec/ruby/core/string/fixtures/classes.rb
+++ b/spec/ruby/core/string/fixtures/classes.rb
@@ -4,7 +4,7 @@ class Object
def unpack_format(count=nil, repeat=nil)
format = "#{instance_variable_get(:@method)}#{count}"
format *= repeat if repeat
- format
+ format.dup # because it may then become tainted
end
end
@@ -46,4 +46,15 @@ module StringSpecs
self.replace(str)
end
end
+
+ class SpecialVarProcessor
+ def process(match)
+ if $~ != nil
+ str = $~[0]
+ else
+ str = "unset"
+ end
+ "<#{str}>"
+ end
+ end
end
diff --git a/spec/ruby/core/string/fixtures/iso-8859-9-encoding.rb b/spec/ruby/core/string/fixtures/iso-8859-9-encoding.rb
index 61a691ff78..cfa91dedc3 100644
--- a/spec/ruby/core/string/fixtures/iso-8859-9-encoding.rb
+++ b/spec/ruby/core/string/fixtures/iso-8859-9-encoding.rb
@@ -4,6 +4,6 @@ module StringSpecs
def source_encoding; __ENCODING__; end
def x_escape; [0xDF].pack('C').force_encoding("iso-8859-9"); end
def ascii_only; "glark"; end
- def cedilla; "Ş"; end
+ def cedilla; ""; end # S-cedilla
end
end
diff --git a/spec/ruby/core/string/fixtures/to_c.rb b/spec/ruby/core/string/fixtures/to_c.rb
new file mode 100644
index 0000000000..7776933263
--- /dev/null
+++ b/spec/ruby/core/string/fixtures/to_c.rb
@@ -0,0 +1,5 @@
+module StringSpecs
+ def self.to_c_method(string)
+ string.to_c
+ end
+end
diff --git a/spec/ruby/core/string/fixtures/utf-8-encoding.rb b/spec/ruby/core/string/fixtures/utf-8-encoding.rb
deleted file mode 100644
index fd243ec522..0000000000
--- a/spec/ruby/core/string/fixtures/utf-8-encoding.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-# -*- encoding: utf-8 -*-
-module StringSpecs
- class UTF8Encoding
- def self.source_encoding; __ENCODING__; end
- def self.egrave; "é"; end
- end
-end
diff --git a/spec/ruby/core/string/force_encoding_spec.rb b/spec/ruby/core/string/force_encoding_spec.rb
index d163c75ac3..2259dcf3cf 100644
--- a/spec/ruby/core/string/force_encoding_spec.rb
+++ b/spec/ruby/core/string/force_encoding_spec.rb
@@ -1,53 +1,72 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+# frozen_string_literal: false
+require_relative '../../spec_helper'
-with_feature :encoding do
- describe "String#force_encoding" do
- it "accepts a String as the name of an Encoding" do
- "abc".force_encoding('shift_jis').encoding.should == Encoding::Shift_JIS
+describe "String#force_encoding" do
+ it "accepts a String as the name of an Encoding" do
+ "abc".force_encoding('shift_jis').encoding.should == Encoding::Shift_JIS
+ end
+
+ describe "with a special encoding name" do
+ before :each do
+ @original_encoding = Encoding.default_internal
end
- it "accepts an Encoding instance" do
- "abc".force_encoding(Encoding::SHIFT_JIS).encoding.should == Encoding::Shift_JIS
+ after :each do
+ Encoding.default_internal = @original_encoding
end
- it "calls #to_str to convert an object to an encoding name" do
- obj = mock("force_encoding")
- obj.should_receive(:to_str).and_return("utf-8")
+ it "accepts valid special encoding names" do
+ Encoding.default_internal = "US-ASCII"
+ "abc".force_encoding("internal").encoding.should == Encoding::US_ASCII
+ end
- "abc".force_encoding(obj).encoding.should == Encoding::UTF_8
+ it "defaults to BINARY if special encoding name is not set" do
+ Encoding.default_internal = nil
+ "abc".force_encoding("internal").encoding.should == Encoding::BINARY
end
+ end
- it "raises a TypeError if #to_str does not return a String" do
- obj = mock("force_encoding")
- obj.should_receive(:to_str).and_return(1)
+ it "accepts an Encoding instance" do
+ "abc".force_encoding(Encoding::SHIFT_JIS).encoding.should == Encoding::Shift_JIS
+ end
- lambda { "abc".force_encoding(obj) }.should raise_error(TypeError)
- end
+ it "calls #to_str to convert an object to an encoding name" do
+ obj = mock("force_encoding")
+ obj.should_receive(:to_str).and_return("utf-8")
- it "raises a TypeError if passed nil" do
- lambda { "abc".force_encoding(nil) }.should raise_error(TypeError)
- end
+ "abc".force_encoding(obj).encoding.should == Encoding::UTF_8
+ end
- it "returns self" do
- str = "abc"
- str.force_encoding('utf-8').should equal(str)
- end
+ it "raises a TypeError if #to_str does not return a String" do
+ obj = mock("force_encoding")
+ obj.should_receive(:to_str).and_return(1)
- it "sets the encoding even if the String contents are invalid in that encoding" do
- str = "\u{9765}"
- str.force_encoding('euc-jp')
- str.encoding.should == Encoding::EUC_JP
- str.valid_encoding?.should be_false
- end
+ -> { "abc".force_encoding(obj) }.should raise_error(TypeError)
+ end
- it "does not transcode self" do
- str = "\u{8612}"
- str.dup.force_encoding('utf-16le').should_not == str.encode('utf-16le')
- end
+ it "raises a TypeError if passed nil" do
+ -> { "abc".force_encoding(nil) }.should raise_error(TypeError)
+ end
- it "raises a RuntimeError if self is frozen" do
- str = "abcd".freeze
- lambda { str.force_encoding(str.encoding) }.should raise_error(RuntimeError)
- end
+ it "returns self" do
+ str = "abc"
+ str.force_encoding('utf-8').should equal(str)
+ end
+
+ it "sets the encoding even if the String contents are invalid in that encoding" do
+ str = "\u{9765}"
+ str.force_encoding('euc-jp')
+ str.encoding.should == Encoding::EUC_JP
+ str.valid_encoding?.should be_false
+ end
+
+ it "does not transcode self" do
+ str = "é"
+ str.dup.force_encoding('utf-16le').should_not == str.encode('utf-16le')
+ end
+
+ it "raises a FrozenError if self is frozen" do
+ str = "abcd".freeze
+ -> { str.force_encoding(str.encoding) }.should raise_error(FrozenError)
end
end
diff --git a/spec/ruby/core/string/freeze_spec.rb b/spec/ruby/core/string/freeze_spec.rb
index bd7c2fbc73..2e8e70386d 100644
--- a/spec/ruby/core/string/freeze_spec.rb
+++ b/spec/ruby/core/string/freeze_spec.rb
@@ -1,14 +1,14 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+# frozen_string_literal: false
+require_relative '../../spec_helper'
describe "String#freeze" do
it "produces the same object whenever called on an instance of a literal in the source" do
- ids = Array.new(2) { "abc".freeze.object_id }
- ids.first.should == ids.last
+ "abc".freeze.should equal "abc".freeze
end
it "doesn't produce the same object for different instances of literals in the source" do
- "abc".object_id.should_not == "abc".object_id
+ "abc".should_not equal "abc"
end
it "being a special form doesn't change the value of defined?" do
diff --git a/spec/ruby/core/string/getbyte_spec.rb b/spec/ruby/core/string/getbyte_spec.rb
index b46ab1ab64..27b7d826ea 100644
--- a/spec/ruby/core/string/getbyte_spec.rb
+++ b/spec/ruby/core/string/getbyte_spec.rb
@@ -1,5 +1,5 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
describe "String#getbyte" do
it "returns an Integer if given a valid index" do
@@ -59,11 +59,11 @@ describe "String#getbyte" do
end
it "raises an ArgumentError unless given one argument" do
- lambda { "glark".getbyte }.should raise_error(ArgumentError)
- lambda { "food".getbyte(0,0) }.should raise_error(ArgumentError)
+ -> { "glark".getbyte }.should raise_error(ArgumentError)
+ -> { "food".getbyte(0,0) }.should raise_error(ArgumentError)
end
it "raises a TypeError unless its argument can be coerced into an Integer" do
- lambda { "a".getbyte('a') }.should raise_error(TypeError)
+ -> { "a".getbyte('a') }.should raise_error(TypeError)
end
end
diff --git a/spec/ruby/core/string/grapheme_clusters_spec.rb b/spec/ruby/core/string/grapheme_clusters_spec.rb
new file mode 100644
index 0000000000..380a245083
--- /dev/null
+++ b/spec/ruby/core/string/grapheme_clusters_spec.rb
@@ -0,0 +1,14 @@
+require_relative "../../spec_helper"
+require_relative 'shared/chars'
+require_relative 'shared/grapheme_clusters'
+
+describe "String#grapheme_clusters" do
+ it_behaves_like :string_chars, :grapheme_clusters
+ it_behaves_like :string_grapheme_clusters, :grapheme_clusters
+
+ it "returns an array when no block given" do
+ string = "ab\u{1f3f3}\u{fe0f}\u{200d}\u{1f308}\u{1F43E}"
+ string.grapheme_clusters.should == ['a', 'b', "\u{1f3f3}\u{fe0f}\u{200d}\u{1f308}", "\u{1F43E}"]
+
+ end
+end
diff --git a/spec/ruby/core/string/gsub_spec.rb b/spec/ruby/core/string/gsub_spec.rb
index 026b037b6c..0d9f32eca2 100644
--- a/spec/ruby/core/string/gsub_spec.rb
+++ b/spec/ruby/core/string/gsub_spec.rb
@@ -1,6 +1,7 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+# frozen_string_literal: false
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe :string_gsub_named_capture, shared: true do
it "replaces \\k named backreferences with the regexp's corresponding capture" do
@@ -160,52 +161,12 @@ describe "String#gsub with pattern and replacement" do
it_behaves_like :string_gsub_named_capture, :gsub
- it "taints the result if the original string or replacement is tainted" do
- hello = "hello"
- hello_t = "hello"
- a = "a"
- a_t = "a"
- empty = ""
- empty_t = ""
-
- hello_t.taint; a_t.taint; empty_t.taint
-
- hello_t.gsub(/./, a).tainted?.should == true
- hello_t.gsub(/./, empty).tainted?.should == true
-
- hello.gsub(/./, a_t).tainted?.should == true
- hello.gsub(/./, empty_t).tainted?.should == true
- hello.gsub(//, empty_t).tainted?.should == true
-
- hello.gsub(//.taint, "foo").tainted?.should == false
- end
-
it "handles pattern collapse" do
str = "こにちわ"
reg = %r!!
str.gsub(reg, ".").should == ".こ.に.ち.わ."
end
- it "untrusts the result if the original string or replacement is untrusted" do
- hello = "hello"
- hello_t = "hello"
- a = "a"
- a_t = "a"
- empty = ""
- empty_t = ""
-
- hello_t.untrust; a_t.untrust; empty_t.untrust
-
- hello_t.gsub(/./, a).untrusted?.should == true
- hello_t.gsub(/./, empty).untrusted?.should == true
-
- hello.gsub(/./, a_t).untrusted?.should == true
- hello.gsub(/./, empty_t).untrusted?.should == true
- hello.gsub(//, empty_t).untrusted?.should == true
-
- hello.gsub(//.untrust, "foo").untrusted?.should == false
- end
-
it "tries to convert pattern to a string using to_str" do
pattern = mock('.')
def pattern.to_str() "." end
@@ -214,9 +175,9 @@ describe "String#gsub with pattern and replacement" do
end
it "raises a TypeError when pattern can't be converted to a string" do
- lambda { "hello".gsub([], "x") }.should raise_error(TypeError)
- lambda { "hello".gsub(Object.new, "x") }.should raise_error(TypeError)
- lambda { "hello".gsub(nil, "x") }.should raise_error(TypeError)
+ -> { "hello".gsub([], "x") }.should raise_error(TypeError)
+ -> { "hello".gsub(Object.new, "x") }.should raise_error(TypeError)
+ -> { "hello".gsub(nil, "x") }.should raise_error(TypeError)
end
it "tries to convert replacement to a string using to_str" do
@@ -227,20 +188,18 @@ describe "String#gsub with pattern and replacement" do
end
it "raises a TypeError when replacement can't be converted to a string" do
- lambda { "hello".gsub(/[aeiou]/, []) }.should raise_error(TypeError)
- lambda { "hello".gsub(/[aeiou]/, Object.new) }.should raise_error(TypeError)
- lambda { "hello".gsub(/[aeiou]/, nil) }.should raise_error(TypeError)
+ -> { "hello".gsub(/[aeiou]/, []) }.should raise_error(TypeError)
+ -> { "hello".gsub(/[aeiou]/, Object.new) }.should raise_error(TypeError)
+ -> { "hello".gsub(/[aeiou]/, nil) }.should raise_error(TypeError)
end
- it "returns subclass instances when called on a subclass" do
- StringSpecs::MyString.new("").gsub(//, "").should be_an_instance_of(StringSpecs::MyString)
- StringSpecs::MyString.new("").gsub(/foo/, "").should be_an_instance_of(StringSpecs::MyString)
- StringSpecs::MyString.new("foo").gsub(/foo/, "").should be_an_instance_of(StringSpecs::MyString)
- StringSpecs::MyString.new("foo").gsub("foo", "").should be_an_instance_of(StringSpecs::MyString)
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("").gsub(//, "").should be_an_instance_of(String)
+ StringSpecs::MyString.new("").gsub(/foo/, "").should be_an_instance_of(String)
+ StringSpecs::MyString.new("foo").gsub(/foo/, "").should be_an_instance_of(String)
+ StringSpecs::MyString.new("foo").gsub("foo", "").should be_an_instance_of(String)
end
- # Note: $~ cannot be tested because mspec messes with it
-
it "sets $~ to MatchData of last match and nil when there's none" do
'hello.'.gsub('hello', 'x')
$~[0].should == 'hello'
@@ -254,6 +213,18 @@ describe "String#gsub with pattern and replacement" do
'hello.'.gsub(/not/, 'x')
$~.should == nil
end
+
+ it "handles a pattern in a superset encoding" do
+ result = 'abc'.force_encoding(Encoding::US_ASCII).gsub('é', 'è')
+ result.should == 'abc'
+ result.encoding.should == Encoding::US_ASCII
+ end
+
+ it "handles a pattern in a subset encoding" do
+ result = 'été'.gsub('t'.force_encoding(Encoding::US_ASCII), 'u')
+ result.should == 'éué'
+ result.encoding.should == Encoding::UTF_8
+ end
end
describe "String#gsub with pattern and Hash" do
@@ -298,7 +269,7 @@ describe "String#gsub with pattern and Hash" do
it "uses the hash's value set from default_proc for missing keys" do
hsh = {}
- hsh.default_proc = lambda { |k,v| 'lamb' }
+ hsh.default_proc = -> k, v { 'lamb' }
"food!".gsub(/./, hsh).should == "lamblamblamblamblamb"
end
@@ -321,27 +292,6 @@ describe "String#gsub with pattern and Hash" do
repl = '\& \0 \1 \` \\\' \+ \\\\ foo'
"hello".gsub(/(.+)/, 'hello' => repl ).should == repl
end
-
- it "untrusts the result if the original string is untrusted" do
- str = "Ghana".untrust
- str.gsub(/[Aa]na/, 'ana' => '').untrusted?.should be_true
- end
-
- it "untrusts the result if a hash value is untrusted" do
- str = "Ghana"
- str.gsub(/a$/, 'a' => 'di'.untrust).untrusted?.should be_true
- end
-
- it "taints the result if the original string is tainted" do
- str = "Ghana".taint
- str.gsub(/[Aa]na/, 'ana' => '').tainted?.should be_true
- end
-
- it "taints the result if a hash value is tainted" do
- str = "Ghana"
- str.gsub(/a$/, 'a' => 'di'.taint).tainted?.should be_true
- end
-
end
describe "String#gsub! with pattern and Hash" do
@@ -387,7 +337,7 @@ describe "String#gsub! with pattern and Hash" do
it "uses the hash's value set from default_proc for missing keys" do
hsh = {}
- hsh.default_proc = lambda { |k,v| 'lamb' }
+ hsh.default_proc = -> k, v { 'lamb' }
"food!".gsub!(/./, hsh).should == "lamblamblamblamblamb"
end
@@ -410,27 +360,6 @@ describe "String#gsub! with pattern and Hash" do
repl = '\& \0 \1 \` \\\' \+ \\\\ foo'
"hello".gsub!(/(.+)/, 'hello' => repl ).should == repl
end
-
- it "keeps untrusted state" do
- str = "Ghana".untrust
- str.gsub!(/[Aa]na/, 'ana' => '').untrusted?.should be_true
- end
-
- it "untrusts self if a hash value is untrusted" do
- str = "Ghana"
- str.gsub!(/a$/, 'a' => 'di'.untrust).untrusted?.should be_true
- end
-
- it "keeps tainted state" do
- str = "Ghana".taint
- str.gsub!(/[Aa]na/, 'ana' => '').tainted?.should be_true
- end
-
- it "taints self if a hash value is tainted" do
- str = "Ghana"
- str.gsub!(/a$/, 'a' => 'di'.taint).tainted?.should be_true
- end
-
end
describe "String#gsub with pattern and block" do
@@ -458,6 +387,11 @@ describe "String#gsub with pattern and block" do
offsets.should == [[1, 2], [4, 5]]
end
+ it "does not set $~ for procs created from methods" do
+ str = "hello"
+ str.gsub("l", &StringSpecs::SpecialVarProcessor.new.method(:process)).should == "he<unset><unset>o"
+ end
+
it "restores $~ after leaving the block" do
[/./, "l"].each do |pattern|
old_md = nil
@@ -504,40 +438,20 @@ describe "String#gsub with pattern and block" do
"hello".gsub(/.+/) { obj }.should == "ok"
end
- it "untrusts the result if the original string or replacement is untrusted" do
- hello = "hello"
- hello_t = "hello"
- a = "a"
- a_t = "a"
- empty = ""
- empty_t = ""
-
- hello_t.untrust; a_t.untrust; empty_t.untrust
-
- hello_t.gsub(/./) { a }.untrusted?.should == true
- hello_t.gsub(/./) { empty }.untrusted?.should == true
-
- hello.gsub(/./) { a_t }.untrusted?.should == true
- hello.gsub(/./) { empty_t }.untrusted?.should == true
- hello.gsub(//) { empty_t }.untrusted?.should == true
-
- hello.gsub(//.untrust) { "foo" }.untrusted?.should == false
- end
-
it "uses the compatible encoding if they are compatible" do
s = "hello"
s2 = "#{195.chr}#{192.chr}#{195.chr}"
- s.gsub(/l/) { |bar| 195.chr }.encoding.should == Encoding::ASCII_8BIT
- s2.gsub("#{192.chr}") { |bar| "hello" }.encoding.should == Encoding::ASCII_8BIT
+ s.gsub(/l/) { |bar| 195.chr }.encoding.should == Encoding::BINARY
+ s2.gsub("#{192.chr}") { |bar| "hello" }.encoding.should == Encoding::BINARY
end
it "raises an Encoding::CompatibilityError if the encodings are not compatible" do
s = "hllëllo"
s2 = "hellö"
- lambda { s.gsub(/l/) { |bar| "Русский".force_encoding("iso-8859-5") } }.should raise_error(Encoding::CompatibilityError)
- lambda { s2.gsub(/l/) { |bar| "Русский".force_encoding("iso-8859-5") } }.should raise_error(Encoding::CompatibilityError)
+ -> { s.gsub(/l/) { |bar| "Русский".force_encoding("iso-8859-5") } }.should raise_error(Encoding::CompatibilityError)
+ -> { s2.gsub(/l/) { |bar| "Русский".force_encoding("iso-8859-5") } }.should raise_error(Encoding::CompatibilityError)
end
it "replaces the incompatible part properly even if the encodings are not compatible" do
@@ -549,7 +463,7 @@ describe "String#gsub with pattern and block" do
not_supported_on :opal do
it "raises an ArgumentError if encoding is not valid" do
x92 = [0x92].pack('C').force_encoding('utf-8')
- lambda { "a#{x92}b".gsub(/[^\x00-\x7f]/u, '') }.should raise_error(ArgumentError)
+ -> { "a#{x92}b".gsub(/[^\x00-\x7f]/u, '') }.should raise_error(ArgumentError)
end
end
end
@@ -570,6 +484,14 @@ describe "String#gsub with pattern and without replacement and block" do
end
end
+describe "String#gsub with a string pattern" do
+ it "handles multibyte characters" do
+ "é".gsub("é", "â").should == "â"
+ "aé".gsub("é", "â").should == "aâ"
+ "éa".gsub("é", "â").should == "âa"
+ end
+end
+
describe "String#gsub! with pattern and replacement" do
it "modifies self in place and returns self" do
a = "hello"
@@ -583,18 +505,6 @@ describe "String#gsub! with pattern and replacement" do
a.should == "*¿** **é*?*"
end
- it "taints self if replacement is tainted" do
- a = "hello"
- a.gsub!(/./.taint, "foo").tainted?.should == false
- a.gsub!(/./, "foo".taint).tainted?.should == true
- end
-
- it "untrusts self if replacement is untrusted" do
- a = "hello"
- a.gsub!(/./.untrust, "foo").untrusted?.should == false
- a.gsub!(/./, "foo".untrust).untrusted?.should == true
- end
-
it "returns nil if no modifications were made" do
a = "hello"
a.gsub!(/z/, '*').should == nil
@@ -603,13 +513,34 @@ describe "String#gsub! with pattern and replacement" do
end
# See [ruby-core:23666]
- it "raises a RuntimeError when self is frozen" do
+ it "raises a FrozenError when self is frozen" do
s = "hello"
s.freeze
- lambda { s.gsub!(/ROAR/, "x") }.should raise_error(RuntimeError)
- lambda { s.gsub!(/e/, "e") }.should raise_error(RuntimeError)
- lambda { s.gsub!(/[aeiou]/, '*') }.should raise_error(RuntimeError)
+ -> { s.gsub!(/ROAR/, "x") }.should raise_error(FrozenError)
+ -> { s.gsub!(/e/, "e") }.should raise_error(FrozenError)
+ -> { s.gsub!(/[aeiou]/, '*') }.should raise_error(FrozenError)
+ end
+
+ it "handles a pattern in a superset encoding" do
+ string = 'abc'.force_encoding(Encoding::US_ASCII)
+
+ result = string.gsub!('é', 'è')
+
+ result.should == nil
+ string.should == 'abc'
+ string.encoding.should == Encoding::US_ASCII
+ end
+
+ it "handles a pattern in a subset encoding" do
+ string = 'été'
+ pattern = 't'.force_encoding(Encoding::US_ASCII)
+
+ result = string.gsub!(pattern, 'u')
+
+ result.should == string
+ string.should == 'éué'
+ string.encoding.should == Encoding::UTF_8
end
end
@@ -620,18 +551,6 @@ describe "String#gsub! with pattern and block" do
a.should == "h*ll*"
end
- it "taints self if block's result is tainted" do
- a = "hello"
- a.gsub!(/./.taint) { "foo" }.tainted?.should == false
- a.gsub!(/./) { "foo".taint }.tainted?.should == true
- end
-
- it "untrusts self if block's result is untrusted" do
- a = "hello"
- a.gsub!(/./.untrust) { "foo" }.untrusted?.should == false
- a.gsub!(/./) { "foo".untrust }.untrusted?.should == true
- end
-
it "returns nil if no modifications were made" do
a = "hello"
a.gsub!(/z/) { '*' }.should == nil
@@ -640,29 +559,29 @@ describe "String#gsub! with pattern and block" do
end
# See [ruby-core:23663]
- it "raises a RuntimeError when self is frozen" do
+ it "raises a FrozenError when self is frozen" do
s = "hello"
s.freeze
- lambda { s.gsub!(/ROAR/) { "x" } }.should raise_error(RuntimeError)
- lambda { s.gsub!(/e/) { "e" } }.should raise_error(RuntimeError)
- lambda { s.gsub!(/[aeiou]/) { '*' } }.should raise_error(RuntimeError)
+ -> { s.gsub!(/ROAR/) { "x" } }.should raise_error(FrozenError)
+ -> { s.gsub!(/e/) { "e" } }.should raise_error(FrozenError)
+ -> { s.gsub!(/[aeiou]/) { '*' } }.should raise_error(FrozenError)
end
it "uses the compatible encoding if they are compatible" do
s = "hello"
s2 = "#{195.chr}#{192.chr}#{195.chr}"
- s.gsub!(/l/) { |bar| 195.chr }.encoding.should == Encoding::ASCII_8BIT
- s2.gsub!("#{192.chr}") { |bar| "hello" }.encoding.should == Encoding::ASCII_8BIT
+ s.gsub!(/l/) { |bar| 195.chr }.encoding.should == Encoding::BINARY
+ s2.gsub!("#{192.chr}") { |bar| "hello" }.encoding.should == Encoding::BINARY
end
it "raises an Encoding::CompatibilityError if the encodings are not compatible" do
s = "hllëllo"
s2 = "hellö"
- lambda { s.gsub!(/l/) { |bar| "Русский".force_encoding("iso-8859-5") } }.should raise_error(Encoding::CompatibilityError)
- lambda { s2.gsub!(/l/) { |bar| "Русский".force_encoding("iso-8859-5") } }.should raise_error(Encoding::CompatibilityError)
+ -> { s.gsub!(/l/) { |bar| "Русский".force_encoding("iso-8859-5") } }.should raise_error(Encoding::CompatibilityError)
+ -> { s2.gsub!(/l/) { |bar| "Русский".force_encoding("iso-8859-5") } }.should raise_error(Encoding::CompatibilityError)
end
it "replaces the incompatible part properly even if the encodings are not compatible" do
@@ -674,7 +593,7 @@ describe "String#gsub! with pattern and block" do
not_supported_on :opal do
it "raises an ArgumentError if encoding is not valid" do
x92 = [0x92].pack('C').force_encoding('utf-8')
- lambda { "a#{x92}b".gsub!(/[^\x00-\x7f]/u, '') }.should raise_error(ArgumentError)
+ -> { "a#{x92}b".gsub!(/[^\x00-\x7f]/u, '') }.should raise_error(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/string/hash_spec.rb b/spec/ruby/core/string/hash_spec.rb
index 255168cebd..0b26214b55 100644
--- a/spec/ruby/core/string/hash_spec.rb
+++ b/spec/ruby/core/string/hash_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String#hash" do
it "returns a hash based on a string's length and content" do
diff --git a/spec/ruby/core/string/hex_spec.rb b/spec/ruby/core/string/hex_spec.rb
index 8a9257c310..364e915681 100644
--- a/spec/ruby/core/string/hex_spec.rb
+++ b/spec/ruby/core/string/hex_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
# TODO: Move actual results to String#to_int() and spec in terms of it
describe "String#hex" do
diff --git a/spec/ruby/core/string/include_spec.rb b/spec/ruby/core/string/include_spec.rb
index d7780de602..9781140a55 100644
--- a/spec/ruby/core/string/include_spec.rb
+++ b/spec/ruby/core/string/include_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String#include? with String" do
it "returns true if self contains other_str" do
@@ -13,6 +13,20 @@ describe "String#include? with String" do
StringSpecs::MyString.new("hello").include?(StringSpecs::MyString.new("lo")).should == true
end
+ it "returns true if both strings are empty" do
+ "".should.include?("")
+ "".dup.force_encoding("EUC-JP").should.include?("")
+ "".should.include?("".dup.force_encoding("EUC-JP"))
+ "".dup.force_encoding("EUC-JP").should.include?("".dup.force_encoding("EUC-JP"))
+ end
+
+ it "returns true if the RHS is empty" do
+ "a".should.include?("")
+ "a".dup.force_encoding("EUC-JP").should.include?("")
+ "a".should.include?("".dup.force_encoding("EUC-JP"))
+ "a".dup.force_encoding("EUC-JP").should.include?("".dup.force_encoding("EUC-JP"))
+ end
+
it "tries to convert other to string using to_str" do
other = mock('lo')
other.should_receive(:to_str).and_return("lo")
@@ -21,14 +35,14 @@ describe "String#include? with String" do
end
it "raises a TypeError if other can't be converted to string" do
- lambda { "hello".include?([]) }.should raise_error(TypeError)
- lambda { "hello".include?('h'.ord) }.should raise_error(TypeError)
- lambda { "hello".include?(mock('x')) }.should raise_error(TypeError)
+ -> { "hello".include?([]) }.should raise_error(TypeError)
+ -> { "hello".include?('h'.ord) }.should raise_error(TypeError)
+ -> { "hello".include?(mock('x')) }.should raise_error(TypeError)
end
it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
pat = "ア".encode Encoding::EUC_JP
- lambda do
+ -> do
"あれ".include?(pat)
end.should raise_error(Encoding::CompatibilityError)
end
diff --git a/spec/ruby/core/string/index_spec.rb b/spec/ruby/core/string/index_spec.rb
index 7889f69c5d..835263a2cd 100644
--- a/spec/ruby/core/string/index_spec.rb
+++ b/spec/ruby/core/string/index_spec.rb
@@ -1,18 +1,18 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String#index" do
it "raises a TypeError if passed nil" do
- lambda { "abc".index nil }.should raise_error(TypeError)
+ -> { "abc".index nil }.should raise_error(TypeError)
end
it "raises a TypeError if passed a boolean" do
- lambda { "abc".index true }.should raise_error(TypeError)
+ -> { "abc".index true }.should raise_error(TypeError)
end
it "raises a TypeError if passed a Symbol" do
- lambda { "abc".index :a }.should raise_error(TypeError)
+ -> { "abc".index :a }.should raise_error(TypeError)
end
it "calls #to_str to convert the first argument" do
@@ -27,8 +27,8 @@ describe "String#index" do
"abc".index("c", offset).should == 2
end
- it "raises a TypeError if passed a Fixnum" do
- lambda { "abc".index 97 }.should raise_error(TypeError)
+ it "raises a TypeError if passed an Integer" do
+ -> { "abc".index 97 }.should raise_error(TypeError)
end
end
@@ -140,25 +140,39 @@ describe "String#index with String" do
"I’ve got a multibyte character.\n".index("\n\n").should == nil
end
- with_feature :encoding do
- it "returns the character index of a multibyte character" do
- "ありがとう".index("が").should == 2
- end
+ it "returns the character index of a multibyte character" do
+ "ありがとう".index("が").should == 2
+ end
- it "returns the character index after offset" do
- "われわれ".index("わ", 1).should == 2
- end
+ it "returns the character index after offset" do
+ "われわれ".index("わ", 1).should == 2
+ "ありがとうありがとう".index("が", 3).should == 7
+ end
- it "returns the character index after a partial first match" do
- "</</h".index("</h").should == 2
- end
+ it "returns the character index after a partial first match" do
+ "</</h".index("</h").should == 2
+ end
- it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
- char = "れ".encode Encoding::EUC_JP
- lambda do
- "あれ".index char
- end.should raise_error(Encoding::CompatibilityError)
- end
+ it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
+ char = "れ".encode Encoding::EUC_JP
+ -> do
+ "あれ".index char
+ end.should raise_error(Encoding::CompatibilityError)
+ end
+
+ it "handles a substring in a superset encoding" do
+ 'abc'.dup.force_encoding(Encoding::US_ASCII).index('é').should == nil
+ end
+
+ it "handles a substring in a subset encoding" do
+ 'été'.index('t'.dup.force_encoding(Encoding::US_ASCII)).should == 1
+ end
+
+ it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
+ str = 'abc'.dup.force_encoding("ISO-2022-JP")
+ pattern = 'b'.dup.force_encoding("EUC-JP")
+
+ -> { str.index(pattern) }.should raise_error(Encoding::CompatibilityError, "incompatible character encodings: ISO-2022-JP and EUC-JP")
end
end
@@ -217,6 +231,17 @@ describe "String#index with Regexp" do
$~.should == nil
end
+ ruby_bug "#20421", ""..."3.3" do
+ it "always clear $~" do
+ "a".index(/a/)
+ $~.should_not == nil
+
+ string = "blablabla"
+ string.index(/bla/, string.length + 1)
+ $~.should == nil
+ end
+ end
+
it "starts the search at the given offset" do
"blablabla".index(/.{0}/, 5).should == 5
"blablabla".index(/.{1}/, 5).should == 5
@@ -293,24 +318,33 @@ describe "String#index with Regexp" do
"RWOARW".index(/R./, obj).should == 4
end
- with_feature :encoding do
- it "returns the character index of a multibyte character" do
- "ありがとう".index(/が/).should == 2
- end
+ it "returns the character index of a multibyte character" do
+ "ありがとう".index(/が/).should == 2
+ end
- it "returns the character index after offset" do
- "われわれ".index(/わ/, 1).should == 2
- end
+ it "returns the character index after offset" do
+ "われわれ".index(/わ/, 1).should == 2
+ end
- it "treats the offset as a character index" do
- "われわわれ".index(/わ/, 3).should == 3
- end
+ it "treats the offset as a character index" do
+ "われわわれ".index(/わ/, 3).should == 3
+ end
+ ruby_bug "#19763", ""..."3.3.0" do
it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
re = Regexp.new "れ".encode(Encoding::EUC_JP)
- lambda do
+ -> do
"あれ".index re
- end.should raise_error(Encoding::CompatibilityError)
+ end.should raise_error(Encoding::CompatibilityError, "incompatible encoding regexp match (EUC-JP regexp with UTF-8 string)")
end
end
+
+ # The exception message was incorrectly "incompatible character encodings: UTF-8 and EUC-JP" before 3.3.0
+ # Still test that the right exception class is used before that.
+ it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
+ re = Regexp.new "れ".encode(Encoding::EUC_JP)
+ -> do
+ "あれ".index re
+ end.should raise_error(Encoding::CompatibilityError)
+ end
end
diff --git a/spec/ruby/core/string/initialize_spec.rb b/spec/ruby/core/string/initialize_spec.rb
index cbb281c8d5..08734cc916 100644
--- a/spec/ruby/core/string/initialize_spec.rb
+++ b/spec/ruby/core/string/initialize_spec.rb
@@ -1,6 +1,6 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
-require File.expand_path('../shared/replace', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/replace'
describe "String#initialize" do
it "is a private method" do
diff --git a/spec/ruby/core/string/insert_spec.rb b/spec/ruby/core/string/insert_spec.rb
index c207fcc13b..483f3c9367 100644
--- a/spec/ruby/core/string/insert_spec.rb
+++ b/spec/ruby/core/string/insert_spec.rb
@@ -1,7 +1,7 @@
# -*- encoding: utf-8 -*-
-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+# frozen_string_literal: false
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String#insert with index, other" do
it "inserts other before the character at the given index" do
@@ -23,8 +23,8 @@ describe "String#insert with index, other" do
end
it "raises an IndexError if the index is beyond string" do
- lambda { "abcd".insert(5, 'X') }.should raise_error(IndexError)
- lambda { "abcd".insert(-6, 'X') }.should raise_error(IndexError)
+ -> { "abcd".insert(5, 'X') }.should raise_error(IndexError)
+ -> { "abcd".insert(-6, 'X') }.should raise_error(IndexError)
end
it "converts index to an integer using to_int" do
@@ -41,44 +41,41 @@ describe "String#insert with index, other" do
"abcd".insert(-3, other).should == "abXYZcd"
end
- it "taints self if string to insert is tainted" do
- str = "abcd"
- str.insert(0, "T".taint).tainted?.should == true
-
- str = "abcd"
- other = mock('T')
- def other.to_str() "T".taint end
- str.insert(0, other).tainted?.should == true
- end
-
it "raises a TypeError if other can't be converted to string" do
- lambda { "abcd".insert(-6, Object.new)}.should raise_error(TypeError)
- lambda { "abcd".insert(-6, []) }.should raise_error(TypeError)
- lambda { "abcd".insert(-6, mock('x')) }.should raise_error(TypeError)
+ -> { "abcd".insert(-6, Object.new)}.should raise_error(TypeError)
+ -> { "abcd".insert(-6, []) }.should raise_error(TypeError)
+ -> { "abcd".insert(-6, mock('x')) }.should raise_error(TypeError)
end
- it "raises a RuntimeError if self is frozen" do
+ it "raises a FrozenError if self is frozen" do
str = "abcd".freeze
- lambda { str.insert(4, '') }.should raise_error(RuntimeError)
- lambda { str.insert(4, 'X') }.should raise_error(RuntimeError)
+ -> { str.insert(4, '') }.should raise_error(FrozenError)
+ -> { str.insert(4, 'X') }.should raise_error(FrozenError)
end
- with_feature :encoding do
- it "inserts a character into a multibyte encoded string" do
- "ありがとう".insert(1, 'ü').should == "あüりがとう"
- end
+ it "inserts a character into a multibyte encoded string" do
+ "ありがとう".insert(1, 'ü').should == "あüりがとう"
+ end
- it "returns a String in the compatible encoding" do
- str = "".force_encoding(Encoding::US_ASCII)
- str.insert(0, "ありがとう")
- str.encoding.should == Encoding::UTF_8
- end
+ it "returns a String in the compatible encoding" do
+ str = "".force_encoding(Encoding::US_ASCII)
+ str.insert(0, "ありがとう")
+ str.encoding.should == Encoding::UTF_8
+ end
+
+ it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
+ pat = "ア".encode Encoding::EUC_JP
+ -> do
+ "あれ".insert 0, pat
+ end.should raise_error(Encoding::CompatibilityError)
+ end
- it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
- pat = "ア".encode Encoding::EUC_JP
- lambda do
- "あれ".insert 0, pat
- end.should raise_error(Encoding::CompatibilityError)
+ it "should not call subclassed string methods" do
+ cls = Class.new(String) do
+ def replace(arg)
+ raise "should not call replace"
+ end
end
+ cls.new("abcd").insert(0, 'X').should == "Xabcd"
end
end
diff --git a/spec/ruby/core/string/inspect_spec.rb b/spec/ruby/core/string/inspect_spec.rb
index a3e18c0ee3..15db06c7f5 100644
--- a/spec/ruby/core/string/inspect_spec.rb
+++ b/spec/ruby/core/string/inspect_spec.rb
@@ -1,18 +1,8 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String#inspect" do
- it "taints the result if self is tainted" do
- "foo".taint.inspect.tainted?.should == true
- "foo\n".taint.inspect.tainted?.should == true
- end
-
- it "untrusts the result if self is untrusted" do
- "foo".untrust.inspect.untrusted?.should == true
- "foo\n".untrust.inspect.untrusted?.should == true
- end
-
it "does not return a subclass instance" do
StringSpecs::MyString.new.inspect.should be_an_instance_of(String)
end
@@ -29,6 +19,21 @@ describe "String#inspect" do
].should be_computed_by(:inspect)
end
+ it "returns a string with special characters replaced with \\<char> notation for UTF-16" do
+ pairs = [
+ ["\a", '"\\a"'],
+ ["\b", '"\\b"'],
+ ["\t", '"\\t"'],
+ ["\n", '"\\n"'],
+ ["\v", '"\\v"'],
+ ["\f", '"\\f"'],
+ ["\r", '"\\r"'],
+ ["\e", '"\\e"']
+ ].map { |str, result| [str.encode('UTF-16LE'), result] }
+
+ pairs.should be_computed_by(:inspect)
+ end
+
it "returns a string with \" and \\ escaped with a backslash" do
[ ["\"", '"\\""'],
["\\", '"\\\\"']
@@ -317,6 +322,15 @@ describe "String#inspect" do
0.chr.inspect.should == '"\\x00"'
end
+ it "uses \\x notation for broken UTF-8 sequences" do
+ "\xF0\x9F".inspect.should == '"\\xF0\\x9F"'
+ end
+
+ it "works for broken US-ASCII strings" do
+ s = "©".dup.force_encoding("US-ASCII")
+ s.inspect.should == '"\xC2\xA9"'
+ end
+
describe "when default external is UTF-8" do
before :each do
@extenc, Encoding.default_external = Encoding.default_external, Encoding::UTF_8
@@ -489,4 +503,18 @@ describe "String#inspect" do
].should be_computed_by(:inspect)
end
end
+
+ describe "when the string's encoding is different than the result's encoding" do
+ describe "and the string's encoding is ASCII-compatible but the characters are non-ASCII" do
+ it "returns a string with the non-ASCII characters replaced by \\x notation" do
+ "\u{3042}".encode("EUC-JP").inspect.should == '"\\x{A4A2}"'
+ end
+ end
+
+ describe "and the string has both ASCII-compatible and ASCII-incompatible chars" do
+ it "returns a string with the non-ASCII characters replaced by \\u notation" do
+ "hello привет".encode("utf-16le").inspect.should == '"hello \\u043F\\u0440\\u0438\\u0432\\u0435\\u0442"'
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/string/intern_spec.rb b/spec/ruby/core/string/intern_spec.rb
index 71f3633920..cd7dad4359 100644
--- a/spec/ruby/core/string/intern_spec.rb
+++ b/spec/ruby/core/string/intern_spec.rb
@@ -1,7 +1,7 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
-require File.expand_path('../shared/to_sym.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/to_sym'
describe "String#intern" do
- it_behaves_like(:string_to_sym, :intern)
+ it_behaves_like :string_to_sym, :intern
end
diff --git a/spec/ruby/core/string/length_spec.rb b/spec/ruby/core/string/length_spec.rb
index 5f51f6bc01..98cee1f03d 100644
--- a/spec/ruby/core/string/length_spec.rb
+++ b/spec/ruby/core/string/length_spec.rb
@@ -1,7 +1,7 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
-require File.expand_path('../shared/length', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/length'
describe "String#length" do
- it_behaves_like(:string_length, :length)
+ it_behaves_like :string_length, :length
end
diff --git a/spec/ruby/core/string/lines_spec.rb b/spec/ruby/core/string/lines_spec.rb
index e5f24816af..40ab5f71d8 100644
--- a/spec/ruby/core/string/lines_spec.rb
+++ b/spec/ruby/core/string/lines_spec.rb
@@ -1,22 +1,19 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
-require File.expand_path('../shared/each_line', __FILE__)
-require File.expand_path('../shared/each_line_without_block', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/each_line'
describe "String#lines" do
- it_behaves_like(:string_each_line, :lines)
+ it_behaves_like :string_each_line, :lines
it "returns an array when no block given" do
- ary = "hello world".send(@method, ' ')
+ ary = "hello world".lines(' ')
ary.should == ["hello ", "world"]
end
- ruby_version_is '2.4' do
- context "when `chomp` keyword argument is passed" do
- it "removes new line characters" do
- "hello \nworld\n".lines(chomp: true).should == ["hello ", "world"]
- "hello \r\nworld\r\n".lines(chomp: true).should == ["hello ", "world"]
- end
+ context "when `chomp` keyword argument is passed" do
+ it "removes new line characters" do
+ "hello \nworld\n".lines(chomp: true).should == ["hello ", "world"]
+ "hello \r\nworld\r\n".lines(chomp: true).should == ["hello ", "world"]
end
end
end
diff --git a/spec/ruby/core/string/ljust_spec.rb b/spec/ruby/core/string/ljust_spec.rb
index f66fb0c573..47324c59d2 100644
--- a/spec/ruby/core/string/ljust_spec.rb
+++ b/spec/ruby/core/string/ljust_spec.rb
@@ -1,6 +1,6 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String#ljust with length, padding" do
it "returns a new string of specified length with self left justified and padded with padstr" do
@@ -31,14 +31,6 @@ describe "String#ljust with length, padding" do
"radiology".ljust(8, '-').should == "radiology"
end
- it "taints result when self or padstr is tainted" do
- "x".taint.ljust(4).tainted?.should == true
- "x".taint.ljust(0).tainted?.should == true
- "".taint.ljust(0).tainted?.should == true
- "x".taint.ljust(4, "*").tainted?.should == true
- "x".ljust(4, "*".taint).tainted?.should == true
- end
-
it "tries to convert length to an integer using to_int" do
"^".ljust(3.8, "_^").should == "^_^"
@@ -49,10 +41,10 @@ describe "String#ljust with length, padding" do
end
it "raises a TypeError when length can't be converted to an integer" do
- lambda { "hello".ljust("x") }.should raise_error(TypeError)
- lambda { "hello".ljust("x", "y") }.should raise_error(TypeError)
- lambda { "hello".ljust([]) }.should raise_error(TypeError)
- lambda { "hello".ljust(mock('x')) }.should raise_error(TypeError)
+ -> { "hello".ljust("x") }.should raise_error(TypeError)
+ -> { "hello".ljust("x", "y") }.should raise_error(TypeError)
+ -> { "hello".ljust([]) }.should raise_error(TypeError)
+ -> { "hello".ljust(mock('x')) }.should raise_error(TypeError)
end
it "tries to convert padstr to a string using to_str" do
@@ -63,54 +55,46 @@ describe "String#ljust with length, padding" do
end
it "raises a TypeError when padstr can't be converted" do
- lambda { "hello".ljust(20, []) }.should raise_error(TypeError)
- lambda { "hello".ljust(20, Object.new)}.should raise_error(TypeError)
- lambda { "hello".ljust(20, mock('x')) }.should raise_error(TypeError)
+ -> { "hello".ljust(20, []) }.should raise_error(TypeError)
+ -> { "hello".ljust(20, Object.new)}.should raise_error(TypeError)
+ -> { "hello".ljust(20, mock('x')) }.should raise_error(TypeError)
end
it "raises an ArgumentError when padstr is empty" do
- lambda { "hello".ljust(10, '') }.should raise_error(ArgumentError)
+ -> { "hello".ljust(10, '') }.should raise_error(ArgumentError)
end
- it "returns subclass instances when called on subclasses" do
- StringSpecs::MyString.new("").ljust(10).should be_an_instance_of(StringSpecs::MyString)
- StringSpecs::MyString.new("foo").ljust(10).should be_an_instance_of(StringSpecs::MyString)
- StringSpecs::MyString.new("foo").ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(StringSpecs::MyString)
+ it "returns String instances when called on subclasses" do
+ StringSpecs::MyString.new("").ljust(10).should be_an_instance_of(String)
+ StringSpecs::MyString.new("foo").ljust(10).should be_an_instance_of(String)
+ StringSpecs::MyString.new("foo").ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
"".ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
"foo".ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
end
- it "when padding is tainted and self is untainted returns a tainted string if and only if length is longer than self" do
- "hello".ljust(4, 'X'.taint).tainted?.should be_false
- "hello".ljust(5, 'X'.taint).tainted?.should be_false
- "hello".ljust(6, 'X'.taint).tainted?.should be_true
+ describe "with width" do
+ it "returns a String in the same encoding as the original" do
+ str = "abc".dup.force_encoding Encoding::IBM437
+ result = str.ljust 5
+ result.should == "abc "
+ result.encoding.should equal(Encoding::IBM437)
+ end
end
- with_feature :encoding do
- describe "with width" do
- it "returns a String in the same encoding as the original" do
- str = "abc".force_encoding Encoding::IBM437
- result = str.ljust 5
- result.should == "abc "
- result.encoding.should equal(Encoding::IBM437)
- end
+ describe "with width, pattern" do
+ it "returns a String in the compatible encoding" do
+ str = "abc".dup.force_encoding Encoding::IBM437
+ result = str.ljust 5, "あ"
+ result.should == "abcああ"
+ result.encoding.should equal(Encoding::UTF_8)
end
- describe "with width, pattern" do
- it "returns a String in the compatible encoding" do
- str = "abc".force_encoding Encoding::IBM437
- result = str.ljust 5, "あ"
- result.should == "abcああ"
- result.encoding.should equal(Encoding::UTF_8)
- end
-
- it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
- pat = "ア".encode Encoding::EUC_JP
- lambda do
- "あれ".ljust 5, pat
- end.should raise_error(Encoding::CompatibilityError)
- end
+ it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
+ pat = "ア".encode Encoding::EUC_JP
+ -> do
+ "あれ".ljust 5, pat
+ end.should raise_error(Encoding::CompatibilityError)
end
end
end
diff --git a/spec/ruby/core/string/lstrip_spec.rb b/spec/ruby/core/string/lstrip_spec.rb
index 7ef94be567..c83650207e 100644
--- a/spec/ruby/core/string/lstrip_spec.rb
+++ b/spec/ruby/core/string/lstrip_spec.rb
@@ -1,23 +1,29 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+# frozen_string_literal: false
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/strip'
describe "String#lstrip" do
+ it_behaves_like :string_strip, :lstrip
+
it "returns a copy of self with leading whitespace removed" do
- " hello ".lstrip.should == "hello "
- " hello world ".lstrip.should == "hello world "
- "\n\r\t\n\v\r hello world ".lstrip.should == "hello world "
- "hello".lstrip.should == "hello"
- "\000 \000hello\000 \000".lstrip.should == "\000 \000hello\000 \000"
+ " hello ".lstrip.should == "hello "
+ " hello world ".lstrip.should == "hello world "
+ "\n\r\t\n\v\r hello world ".lstrip.should == "hello world "
+ "hello".lstrip.should == "hello"
+ " こにちわ".lstrip.should == "こにちわ"
end
- it "does not strip leading \\0" do
- "\x00hello".lstrip.should == "\x00hello"
+ it "works with lazy substrings" do
+ " hello "[1...-1].lstrip.should == "hello "
+ " hello world "[1...-1].lstrip.should == "hello world "
+ "\n\r\t\n\v\r hello world "[1...-1].lstrip.should == "hello world "
+ " こにちわ "[1...-1].lstrip.should == "こにちわ"
end
- it "taints the result when self is tainted" do
- "".taint.lstrip.tainted?.should == true
- "ok".taint.lstrip.tainted?.should == true
- " ok".taint.lstrip.tainted?.should == true
+ it "strips leading \\0" do
+ "\x00hello".lstrip.should == "hello"
+ "\000 \000hello\000 \000".lstrip.should == "hello\000 \000"
end
end
@@ -26,10 +32,6 @@ describe "String#lstrip!" do
a = " hello "
a.lstrip!.should equal(a)
a.should == "hello "
-
- a = "\000 \000hello\000 \000"
- a.lstrip!
- a.should == "\000 \000hello\000 \000"
end
it "returns nil if no modifications were made" do
@@ -38,13 +40,35 @@ describe "String#lstrip!" do
a.should == "hello"
end
- it "raises a RuntimeError on a frozen instance that is modified" do
- lambda { " hello ".freeze.lstrip! }.should raise_error(RuntimeError)
+ it "makes a string empty if it is only whitespace" do
+ "".lstrip!.should == nil
+ " ".lstrip.should == ""
+ " ".lstrip.should == ""
+ end
+
+ it "removes leading NULL bytes and whitespace" do
+ a = "\000 \000hello\000 \000"
+ a.lstrip!
+ a.should == "hello\000 \000"
+ end
+
+ it "raises a FrozenError on a frozen instance that is modified" do
+ -> { " hello ".freeze.lstrip! }.should raise_error(FrozenError)
end
# see [ruby-core:23657]
- it "raises a RuntimeError on a frozen instance that would not be modified" do
- lambda { "hello".freeze.lstrip! }.should raise_error(RuntimeError)
- lambda { "".freeze.lstrip! }.should raise_error(RuntimeError)
+ it "raises a FrozenError on a frozen instance that would not be modified" do
+ -> { "hello".freeze.lstrip! }.should raise_error(FrozenError)
+ -> { "".freeze.lstrip! }.should raise_error(FrozenError)
+ end
+
+ it "raises an ArgumentError if the first non-space codepoint is invalid" do
+ s = "\xDFabc".force_encoding(Encoding::UTF_8)
+ s.valid_encoding?.should be_false
+ -> { s.lstrip! }.should raise_error(ArgumentError)
+
+ s = " \xDFabc".force_encoding(Encoding::UTF_8)
+ s.valid_encoding?.should be_false
+ -> { s.lstrip! }.should raise_error(ArgumentError)
end
end
diff --git a/spec/ruby/core/string/match_spec.rb b/spec/ruby/core/string/match_spec.rb
index 94e28e7297..5e988f34ca 100644
--- a/spec/ruby/core/string/match_spec.rb
+++ b/spec/ruby/core/string/match_spec.rb
@@ -1,6 +1,6 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe :string_match_escaped_literal, shared: true do
not_supported_on :opal do
@@ -19,8 +19,8 @@ describe "String#=~" do
end
it "raises a TypeError if a obj is a string" do
- lambda { "some string" =~ "another string" }.should raise_error(TypeError)
- lambda { "a" =~ StringSpecs::MyString.new("b") }.should raise_error(TypeError)
+ -> { "some string" =~ "another string" }.should raise_error(TypeError)
+ -> { "a" =~ StringSpecs::MyString.new("b") }.should raise_error(TypeError)
end
it "invokes obj.=~ with self if obj is neither a string nor regexp" do
@@ -43,10 +43,8 @@ describe "String#=~" do
$~.should == nil
end
- with_feature :encoding do
- it "returns the character index of a found match" do
- ("こにちわ" =~ /に/).should == 1
- end
+ it "returns the character index of a found match" do
+ ("こにちわ" =~ /に/).should == 1
end
end
@@ -64,10 +62,8 @@ describe "String#match" do
"01234".match(/(.).(.)/, 1).captures.should == ["1", "3"]
end
- with_feature :encoding do
- it "uses the start as a character offset" do
- "零一二三四".match(/(.).(.)/, 1).captures.should == ["一", "三"]
- end
+ it "uses the start as a character offset" do
+ "零一二三四".match(/(.).(.)/, 1).captures.should == ["一", "三"]
end
end
@@ -76,10 +72,8 @@ describe "String#match" do
"01234".match(/(.).(.)/, -4).captures.should == ["1", "3"]
end
- with_feature :encoding do
- it "uses the start as a character offset" do
- "零一二三四".match(/(.).(.)/, -4).captures.should == ["一", "三"]
- end
+ it "uses the start as a character offset" do
+ "零一二三四".match(/(.).(.)/, -4).captures.should == ["一", "三"]
end
end
end
@@ -113,9 +107,9 @@ describe "String#match" do
end
it "raises a TypeError if pattern is not a regexp or a string" do
- lambda { 'hello'.match(10) }.should raise_error(TypeError)
+ -> { 'hello'.match(10) }.should raise_error(TypeError)
not_supported_on :opal do
- lambda { 'hello'.match(:ell) }.should raise_error(TypeError)
+ -> { 'hello'.match(:ell) }.should raise_error(TypeError)
end
end
@@ -143,33 +137,31 @@ describe "String#match" do
end
it "calls match on the regular expression" do
- regexp = /./
+ regexp = /./.dup
regexp.should_receive(:match).and_return(:foo)
'hello'.match(regexp).should == :foo
end
end
-ruby_version_is "2.4" do
- describe "String#match?" do
- before :each do
- # Resetting Regexp.last_match
- /DONTMATCH/.match ''
- end
+describe "String#match?" do
+ before :each do
+ # Resetting Regexp.last_match
+ /DONTMATCH/.match ''
+ end
- context "when matches the given regex" do
- it "returns true but does not set Regexp.last_match" do
- 'string'.match?(/string/i).should be_true
- Regexp.last_match.should be_nil
- end
+ context "when matches the given regex" do
+ it "returns true but does not set Regexp.last_match" do
+ 'string'.match?(/string/i).should be_true
+ Regexp.last_match.should be_nil
end
+ end
- it "returns false when does not match the given regex" do
- 'string'.match?(/STRING/).should be_false
- end
+ it "returns false when does not match the given regex" do
+ 'string'.match?(/STRING/).should be_false
+ end
- it "takes matching position as the 2nd argument" do
- 'string'.match?(/str/i, 0).should be_true
- 'string'.match?(/str/i, 1).should be_false
- end
+ it "takes matching position as the 2nd argument" do
+ 'string'.match?(/str/i, 0).should be_true
+ 'string'.match?(/str/i, 1).should be_false
end
end
diff --git a/spec/ruby/core/string/modulo_spec.rb b/spec/ruby/core/string/modulo_spec.rb
index 4f26ac5033..46e0aa0f36 100644
--- a/spec/ruby/core/string/modulo_spec.rb
+++ b/spec/ruby/core/string/modulo_spec.rb
@@ -1,7 +1,26 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative '../kernel/shared/sprintf'
+require_relative '../kernel/shared/sprintf_encoding'
+require_relative 'fixtures/classes'
+require_relative '../../shared/hash/key_error'
describe "String#%" do
+ it_behaves_like :kernel_sprintf, -> format, *args {
+ format % args
+ }
+
+ it_behaves_like :kernel_sprintf_encoding, -> format, *args {
+ format % args
+ }
+end
+
+# TODO: these specs are mostly redundant with kernel/shared/sprintf.rb specs.
+# These specs should be moved there and deduplicated.
+describe "String#%" do
+ context "when key is missing from passed-in hash" do
+ it_behaves_like :key_error, -> obj, key { "%{#{key}}" % obj }, { a: 5 }
+ end
+
it "formats multiple expressions" do
("%b %x %d %s" % [10, 10, 10, 10]).should == "1010 a 10 10"
end
@@ -14,47 +33,70 @@ describe "String#%" do
("%d%% %s" % [10, "of chickens!"]).should == "10% of chickens!"
end
- ruby_version_is ""..."2.5" do
- it "formats single % character at the end as literal %" do
- ("%" % []).should == "%"
- ("foo%" % []).should == "foo%"
+ describe "output's encoding" do
+ it "is the same as the format string if passed value is encoding-compatible" do
+ [Encoding::BINARY, Encoding::US_ASCII, Encoding::UTF_8, Encoding::SHIFT_JIS].each do |encoding|
+ ("hello %s!".encode(encoding) % "world").encoding.should == encoding
+ end
end
- end
- ruby_version_is "2.5" do
- it "raises an error if single % appears at the end" do
- lambda { ("%" % []) }.should raise_error(ArgumentError)
- lambda { ("foo%" % [])}.should raise_error(ArgumentError)
+ it "negotiates a compatible encoding if necessary" do
+ ("hello %s" % 195.chr).encoding.should == Encoding::BINARY
+ ("hello %s".encode("shift_jis") % "wörld").encoding.should == Encoding::UTF_8
end
- end
- it "formats single % character before a newline as literal %" do
- ("%\n" % []).should == "%\n"
- ("foo%\n" % []).should == "foo%\n"
- ("%\n.3f" % 1.2).should == "%\n.3f"
+ it "raises if a compatible encoding can't be found" do
+ -> { "hello %s".encode("utf-8") % "world".encode("UTF-16LE") }.should raise_error(Encoding::CompatibilityError)
+ end
end
- it "formats single % character before a NUL as literal %" do
- ("%\0" % []).should == "%\0"
- ("foo%\0" % []).should == "foo%\0"
- ("%\0.3f" % 1.2).should == "%\0.3f"
+ it "raises an error if single % appears at the end" do
+ -> { ("%" % []) }.should raise_error(ArgumentError)
+ -> { ("foo%" % [])}.should raise_error(ArgumentError)
end
- it "raises an error if single % appears anywhere else" do
- lambda { (" % " % []) }.should raise_error(ArgumentError)
- lambda { ("foo%quux" % []) }.should raise_error(ArgumentError)
- end
+ ruby_version_is ""..."3.4" do
+ it "formats single % character before a newline as literal %" do
+ ("%\n" % []).should == "%\n"
+ ("foo%\n" % []).should == "foo%\n"
+ ("%\n.3f" % 1.2).should == "%\n.3f"
+ end
- it "raises an error if NULL or \\n appear anywhere else in the format string" do
- begin
- old_debug, $DEBUG = $DEBUG, false
+ it "formats single % character before a NUL as literal %" do
+ ("%\0" % []).should == "%\0"
+ ("foo%\0" % []).should == "foo%\0"
+ ("%\0.3f" % 1.2).should == "%\0.3f"
+ end
- lambda { "%.\n3f" % 1.2 }.should raise_error(ArgumentError)
- lambda { "%.3\nf" % 1.2 }.should raise_error(ArgumentError)
- lambda { "%.\03f" % 1.2 }.should raise_error(ArgumentError)
- lambda { "%.3\0f" % 1.2 }.should raise_error(ArgumentError)
- ensure
- $DEBUG = old_debug
+ it "raises an error if single % appears anywhere else" do
+ -> { (" % " % []) }.should raise_error(ArgumentError)
+ -> { ("foo%quux" % []) }.should raise_error(ArgumentError)
+ end
+
+ it "raises an error if NULL or \\n appear anywhere else in the format string" do
+ begin
+ old_debug, $DEBUG = $DEBUG, false
+
+ -> { "%.\n3f" % 1.2 }.should raise_error(ArgumentError)
+ -> { "%.3\nf" % 1.2 }.should raise_error(ArgumentError)
+ -> { "%.\03f" % 1.2 }.should raise_error(ArgumentError)
+ -> { "%.3\0f" % 1.2 }.should raise_error(ArgumentError)
+ ensure
+ $DEBUG = old_debug
+ end
+ end
+ end
+
+ ruby_version_is "3.4" do
+ it "raises an ArgumentError if % is not followed by a conversion specifier" do
+ -> { "%" % [] }.should raise_error(ArgumentError)
+ -> { "%\n" % [] }.should raise_error(ArgumentError)
+ -> { "%\0" % [] }.should raise_error(ArgumentError)
+ -> { " % " % [] }.should raise_error(ArgumentError)
+ -> { "%.\n3f" % 1.2 }.should raise_error(ArgumentError)
+ -> { "%.3\nf" % 1.2 }.should raise_error(ArgumentError)
+ -> { "%.\03f" % 1.2 }.should raise_error(ArgumentError)
+ -> { "%.3\0f" % 1.2 }.should raise_error(ArgumentError)
end
end
@@ -77,8 +119,8 @@ describe "String#%" do
s = $stderr
$stderr = IOStub.new
- lambda { "" % [1, 2, 3] }.should raise_error(ArgumentError)
- lambda { "%s" % [1, 2, 3] }.should raise_error(ArgumentError)
+ -> { "" % [1, 2, 3] }.should raise_error(ArgumentError)
+ -> { "%s" % [1, 2, 3] }.should raise_error(ArgumentError)
ensure
$DEBUG = old_debug
$stderr = s
@@ -98,26 +140,34 @@ describe "String#%" do
end
end
- it "replaces trailing absolute argument specifier without type with percent sign" do
- ("hello %1$" % "foo").should == "hello %"
+ ruby_version_is ""..."3.4" do
+ it "replaces trailing absolute argument specifier without type with percent sign" do
+ ("hello %1$" % "foo").should == "hello %"
+ end
+ end
+
+ ruby_version_is "3.4" do
+ it "raises an ArgumentError if absolute argument specifier is followed by a conversion specifier" do
+ -> { "hello %1$" % "foo" }.should raise_error(ArgumentError)
+ end
end
it "raises an ArgumentError when given invalid argument specifiers" do
- lambda { "%1" % [] }.should raise_error(ArgumentError)
- lambda { "%+" % [] }.should raise_error(ArgumentError)
- lambda { "%-" % [] }.should raise_error(ArgumentError)
- lambda { "%#" % [] }.should raise_error(ArgumentError)
- lambda { "%0" % [] }.should raise_error(ArgumentError)
- lambda { "%*" % [] }.should raise_error(ArgumentError)
- lambda { "%." % [] }.should raise_error(ArgumentError)
- lambda { "%_" % [] }.should raise_error(ArgumentError)
- lambda { "%0$s" % "x" }.should raise_error(ArgumentError)
- lambda { "%*0$s" % [5, "x"] }.should raise_error(ArgumentError)
- lambda { "%*1$.*0$1$s" % [1, 2, 3] }.should raise_error(ArgumentError)
+ -> { "%1" % [] }.should raise_error(ArgumentError)
+ -> { "%+" % [] }.should raise_error(ArgumentError)
+ -> { "%-" % [] }.should raise_error(ArgumentError)
+ -> { "%#" % [] }.should raise_error(ArgumentError)
+ -> { "%0" % [] }.should raise_error(ArgumentError)
+ -> { "%*" % [] }.should raise_error(ArgumentError)
+ -> { "%." % [] }.should raise_error(ArgumentError)
+ -> { "%_" % [] }.should raise_error(ArgumentError)
+ -> { "%0$s" % "x" }.should raise_error(ArgumentError)
+ -> { "%*0$s" % [5, "x"] }.should raise_error(ArgumentError)
+ -> { "%*1$.*0$1$s" % [1, 2, 3] }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when multiple positional argument tokens are given for one format specifier" do
- lambda { "%1$1$s" % "foo" }.should raise_error(ArgumentError)
+ -> { "%1$1$s" % "foo" }.should raise_error(ArgumentError)
end
it "respects positional arguments and precision tokens given for one format specifier" do
@@ -133,36 +183,36 @@ describe "String#%" do
end
it "raises an ArgumentError when multiple width star tokens are given for one format specifier" do
- lambda { "%**s" % [5, 5, 5] }.should raise_error(ArgumentError)
+ -> { "%**s" % [5, 5, 5] }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when a width star token is seen after a width token" do
- lambda { "%5*s" % [5, 5] }.should raise_error(ArgumentError)
+ -> { "%5*s" % [5, 5] }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when multiple precision tokens are given" do
- lambda { "%.5.5s" % 5 }.should raise_error(ArgumentError)
- lambda { "%.5.*s" % [5, 5] }.should raise_error(ArgumentError)
- lambda { "%.*.5s" % [5, 5] }.should raise_error(ArgumentError)
+ -> { "%.5.5s" % 5 }.should raise_error(ArgumentError)
+ -> { "%.5.*s" % [5, 5] }.should raise_error(ArgumentError)
+ -> { "%.*.5s" % [5, 5] }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when there are less arguments than format specifiers" do
("foo" % []).should == "foo"
- lambda { "%s" % [] }.should raise_error(ArgumentError)
- lambda { "%s %s" % [1] }.should raise_error(ArgumentError)
+ -> { "%s" % [] }.should raise_error(ArgumentError)
+ -> { "%s %s" % [1] }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when absolute and relative argument numbers are mixed" do
- lambda { "%s %1$s" % "foo" }.should raise_error(ArgumentError)
- lambda { "%1$s %s" % "foo" }.should raise_error(ArgumentError)
+ -> { "%s %1$s" % "foo" }.should raise_error(ArgumentError)
+ -> { "%1$s %s" % "foo" }.should raise_error(ArgumentError)
- lambda { "%s %2$s" % ["foo", "bar"] }.should raise_error(ArgumentError)
- lambda { "%2$s %s" % ["foo", "bar"] }.should raise_error(ArgumentError)
+ -> { "%s %2$s" % ["foo", "bar"] }.should raise_error(ArgumentError)
+ -> { "%2$s %s" % ["foo", "bar"] }.should raise_error(ArgumentError)
- lambda { "%*2$s" % [5, 5, 5] }.should raise_error(ArgumentError)
- lambda { "%*.*2$s" % [5, 5, 5] }.should raise_error(ArgumentError)
- lambda { "%*2$.*2$s" % [5, 5, 5] }.should raise_error(ArgumentError)
- lambda { "%*.*2$s" % [5, 5, 5] }.should raise_error(ArgumentError)
+ -> { "%*2$s" % [5, 5, 5] }.should raise_error(ArgumentError)
+ -> { "%*.*2$s" % [5, 5, 5] }.should raise_error(ArgumentError)
+ -> { "%*2$.*2$s" % [5, 5, 5] }.should raise_error(ArgumentError)
+ -> { "%*.*2$s" % [5, 5, 5] }.should raise_error(ArgumentError)
end
it "allows reuse of the one argument multiple via absolute argument numbers" do
@@ -171,13 +221,13 @@ describe "String#%" do
end
it "always interprets an array argument as a list of argument parameters" do
- lambda { "%p" % [] }.should raise_error(ArgumentError)
+ -> { "%p" % [] }.should raise_error(ArgumentError)
("%p" % [1]).should == "1"
("%p %p" % [1, 2]).should == "1 2"
end
it "always interprets an array subclass argument as a list of argument parameters" do
- lambda { "%p" % StringSpecs::MyArray[] }.should raise_error(ArgumentError)
+ -> { "%p" % StringSpecs::MyArray[] }.should raise_error(ArgumentError)
("%p" % StringSpecs::MyArray[1]).should == "1"
("%p %p" % StringSpecs::MyArray[1, 2]).should == "1 2"
end
@@ -248,7 +298,7 @@ describe "String#%" do
x = mock("string modulo to_ary")
x.should_receive(:to_ary).and_return("x")
- lambda { "%s" % x }.should raise_error(TypeError)
+ -> { "%s" % x }.should raise_error(TypeError)
end
it "tries to convert the argument to Array by calling #to_ary" do
@@ -275,27 +325,6 @@ describe "String#%" do
end
end
- it "always taints the result when the format string is tainted" do
- universal = mock('0')
- def universal.to_int() 0 end
- def universal.to_str() "0" end
- def universal.to_f() 0.0 end
-
- [
- "", "foo",
- "%b", "%B", "%c", "%d", "%e", "%E",
- "%f", "%g", "%G", "%i", "%o", "%p",
- "%s", "%u", "%x", "%X"
- ].each do |format|
- subcls_format = StringSpecs::MyString.new(format)
- subcls_format.taint
- format.taint
-
- (format % universal).tainted?.should == true
- (subcls_format % universal).tainted?.should == true
- end
- end
-
it "supports binary formats using %b for positive numbers" do
("%b" % 10).should == "1010"
("% b" % 10).should == " 1010"
@@ -355,15 +384,15 @@ describe "String#%" do
("%*c" % [10, 3]).should == " \003"
("%c" % 42).should == "*"
- lambda { "%c" % Object }.should raise_error(TypeError)
+ -> { "%c" % Object }.should raise_error(TypeError)
end
it "supports single character strings as argument for %c" do
("%c" % 'A').should == "A"
end
- it "raises an exception for multiple character strings as argument for %c" do
- lambda { "%c" % 'AA' }.should raise_error(ArgumentError)
+ it "supports only the first character as argument for %c" do
+ ("%c" % 'AA').should == "A"
end
it "calls to_str on argument for %c formats" do
@@ -533,7 +562,7 @@ describe "String#%" do
("%1$p" % [10, 5]).should == "10"
("%-22p" % 10).should == "10 "
("%*p" % [10, 10]).should == " 10"
- ("%p" % {capture: 1}).should == "{:capture=>1}"
+ ("%p" % {capture: 1}).should == {capture: 1}.inspect
("%p" % "str").should == "\"str\""
end
@@ -549,18 +578,6 @@ describe "String#%" do
# ("%p" % obj).should == "obj"
end
- it "taints result for %p when argument.inspect is tainted" do
- obj = mock('x')
- def obj.inspect() "x".taint end
-
- ("%p" % obj).tainted?.should == true
-
- obj = mock('x'); obj.taint
- def obj.inspect() "x" end
-
- ("%p" % obj).tainted?.should == false
- end
-
it "supports string formats using %s" do
("%s" % "hello").should == "hello"
("%s" % "").should == ""
@@ -589,15 +606,10 @@ describe "String#%" do
# ("%s" % obj).should == "obj"
end
- it "taints result for %s when argument is tainted" do
- ("%s" % "x".taint).tainted?.should == true
- ("%s" % mock('x').taint).tainted?.should == true
- end
-
# MRI crashes on this one.
# See http://groups.google.com/group/ruby-core-google/t/c285c18cd94c216d
it "raises an ArgumentError for huge precisions for %s" do
- block = lambda { "%.25555555555555555555555555555555555555s" % "hello world" }
+ block = -> { "%.25555555555555555555555555555555555555s" % "hello world" }
block.should raise_error(ArgumentError)
end
@@ -690,19 +702,19 @@ describe "String#%" do
(format % "0b1101").should == (format % Kernel.Integer("0b1101"))
(format % "0b1101_0000").should == (format % Kernel.Integer("0b1101_0000"))
(format % "0777").should == (format % Kernel.Integer("0777"))
- lambda {
+ -> {
# see [ruby-core:14139] for more details
(format % "0777").should == (format % Kernel.Integer("0777"))
}.should_not raise_error(ArgumentError)
- lambda { format % "0__7_7_7" }.should raise_error(ArgumentError)
+ -> { format % "0__7_7_7" }.should raise_error(ArgumentError)
- lambda { format % "" }.should raise_error(ArgumentError)
- lambda { format % "x" }.should raise_error(ArgumentError)
- lambda { format % "5x" }.should raise_error(ArgumentError)
- lambda { format % "08" }.should raise_error(ArgumentError)
- lambda { format % "0b2" }.should raise_error(ArgumentError)
- lambda { format % "123__456" }.should raise_error(ArgumentError)
+ -> { format % "" }.should raise_error(ArgumentError)
+ -> { format % "x" }.should raise_error(ArgumentError)
+ -> { format % "5x" }.should raise_error(ArgumentError)
+ -> { format % "08" }.should raise_error(ArgumentError)
+ -> { format % "0b2" }.should raise_error(ArgumentError)
+ -> { format % "123__456" }.should raise_error(ArgumentError)
obj = mock('5')
obj.should_receive(:to_i).and_return(5)
@@ -729,21 +741,25 @@ describe "String#%" do
(format % "-10.4e-20").should == (format % -10.4e-20)
(format % ".5").should == (format % 0.5)
(format % "-.5").should == (format % -0.5)
+
+ ruby_version_is "3.4" do
+ (format % "10.").should == (format % 10)
+ end
+
# Something's strange with this spec:
# it works just fine in individual mode, but not when run as part of a group
(format % "10_1_0.5_5_5").should == (format % 1010.555)
(format % "0777").should == (format % 777)
- lambda { format % "" }.should raise_error(ArgumentError)
- lambda { format % "x" }.should raise_error(ArgumentError)
- lambda { format % "." }.should raise_error(ArgumentError)
- lambda { format % "10." }.should raise_error(ArgumentError)
- lambda { format % "5x" }.should raise_error(ArgumentError)
- lambda { format % "0b1" }.should raise_error(ArgumentError)
- lambda { format % "10e10.5" }.should raise_error(ArgumentError)
- lambda { format % "10__10" }.should raise_error(ArgumentError)
- lambda { format % "10.10__10" }.should raise_error(ArgumentError)
+ -> { format % "" }.should raise_error(ArgumentError)
+ -> { format % "x" }.should raise_error(ArgumentError)
+ -> { format % "." }.should raise_error(ArgumentError)
+ -> { format % "5x" }.should raise_error(ArgumentError)
+ -> { format % "0b1" }.should raise_error(ArgumentError)
+ -> { format % "10e10.5" }.should raise_error(ArgumentError)
+ -> { format % "10__10" }.should raise_error(ArgumentError)
+ -> { format % "10.10__10" }.should raise_error(ArgumentError)
obj = mock('5.0')
obj.should_receive(:to_f).and_return(5.0)
@@ -753,10 +769,6 @@ describe "String#%" do
it "behaves as if calling Kernel#Float for #{format} arguments, when the passed argument is hexadecimal string" do
(format % "0xA").should == (format % 0xA)
end
-
- it "doesn't taint the result for #{format} when argument is tainted" do
- (format % "5".taint).tainted?.should == false
- end
end
describe "when format string contains %{} sections" do
@@ -764,12 +776,8 @@ describe "String#%" do
("%{foo}bar" % {foo: 'oof'}).should == "oofbar"
end
- it "raises KeyError if key is missing from passed-in hash" do
- lambda {"%{foo}" % {}}.should raise_error(KeyError)
- end
-
it "should raise ArgumentError if no hash given" do
- lambda {"%{foo}" % []}.should raise_error(ArgumentError)
+ -> {"%{foo}" % []}.should raise_error(ArgumentError)
end
end
@@ -779,11 +787,11 @@ describe "String#%" do
end
it "raises KeyError if key is missing from passed-in hash" do
- lambda {"%<foo>d" % {}}.should raise_error(KeyError)
+ -> {"%<foo>d" % {}}.should raise_error(KeyError)
end
it "should raise ArgumentError if no hash given" do
- lambda {"%<foo>" % []}.should raise_error(ArgumentError)
+ -> {"%<foo>" % []}.should raise_error(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/string/multiply_spec.rb b/spec/ruby/core/string/multiply_spec.rb
index d932ebeb8e..c15f670c46 100644
--- a/spec/ruby/core/string/multiply_spec.rb
+++ b/spec/ruby/core/string/multiply_spec.rb
@@ -1,7 +1,7 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
-require File.expand_path('../../../shared/string/times', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative '../../shared/string/times'
describe "String#*" do
- it_behaves_like :string_times, :*, ->(str, times) { str * times }
+ it_behaves_like :string_times, :*, -> str, times { str * times }
end
diff --git a/spec/ruby/core/string/new_spec.rb b/spec/ruby/core/string/new_spec.rb
index b429ac48d2..ca678f5323 100644
--- a/spec/ruby/core/string/new_spec.rb
+++ b/spec/ruby/core/string/new_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String.new" do
it "returns an instance of String" do
@@ -7,19 +7,15 @@ describe "String.new" do
str.should be_an_instance_of(String)
end
- ruby_version_is "2.3" do
- it "accepts an encoding argument" do
- xA4xA2 = [0xA4, 0xA2].pack('CC').force_encoding 'utf-8'
- str = String.new(xA4xA2, encoding: 'euc-jp')
- str.encoding.should == Encoding::EUC_JP
- end
+ it "accepts an encoding argument" do
+ xA4xA2 = [0xA4, 0xA2].pack('CC').force_encoding 'utf-8'
+ str = String.new(xA4xA2, encoding: 'euc-jp')
+ str.encoding.should == Encoding::EUC_JP
end
- ruby_version_is "2.4" do
- it "accepts a capacity argument" do
- String.new("", capacity: 100_000).should == ""
- String.new("abc", capacity: 100_000).should == "abc"
- end
+ it "accepts a capacity argument" do
+ String.new("", capacity: 100_000).should == ""
+ String.new("abc", capacity: 100_000).should == "abc"
end
it "returns a fully-formed String" do
@@ -55,8 +51,8 @@ describe "String.new" do
end
it "raises TypeError on inconvertible object" do
- lambda { String.new 5 }.should raise_error(TypeError)
- lambda { String.new nil }.should raise_error(TypeError)
+ -> { String.new 5 }.should raise_error(TypeError)
+ -> { String.new nil }.should raise_error(TypeError)
end
it "returns a binary String" do
diff --git a/spec/ruby/core/string/next_spec.rb b/spec/ruby/core/string/next_spec.rb
index 6b4a98d993..fcd3e5ef90 100644
--- a/spec/ruby/core/string/next_spec.rb
+++ b/spec/ruby/core/string/next_spec.rb
@@ -1,11 +1,11 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
-require File.expand_path('../shared/succ.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/succ'
describe "String#next" do
- it_behaves_like(:string_succ, :next)
+ it_behaves_like :string_succ, :next
end
describe "String#next!" do
- it_behaves_like(:string_succ_bang, :"next!")
+ it_behaves_like :string_succ_bang, :"next!"
end
diff --git a/spec/ruby/core/string/oct_spec.rb b/spec/ruby/core/string/oct_spec.rb
index 7cdbabc436..7637692217 100644
--- a/spec/ruby/core/string/oct_spec.rb
+++ b/spec/ruby/core/string/oct_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
# Note: We can't completely spec this in terms of to_int() because hex()
# allows the base to be changed by a base specifier in the string.
diff --git a/spec/ruby/core/string/ord_spec.rb b/spec/ruby/core/string/ord_spec.rb
index 64466fde58..35af3b5458 100644
--- a/spec/ruby/core/string/ord_spec.rb
+++ b/spec/ruby/core/string/ord_spec.rb
@@ -1,30 +1,33 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
-with_feature :encoding do
- describe "String#ord" do
- it "returns a Fixnum" do
- 'a'.ord.should be_an_instance_of(Fixnum)
- end
+describe "String#ord" do
+ it "returns an Integer" do
+ 'a'.ord.should be_an_instance_of(Integer)
+ end
- it "returns the codepoint of the first character in the String" do
- 'a'.ord.should == 97
- end
+ it "returns the codepoint of the first character in the String" do
+ 'a'.ord.should == 97
+ end
- it "ignores subsequent characters" do
- "\u{287}a".ord.should == "\u{287}".ord
- end
+ it "ignores subsequent characters" do
+ "\u{287}a".ord.should == "\u{287}".ord
+ end
- it "understands multibyte characters" do
- "\u{9879}".ord.should == 39033
- end
+ it "understands multibyte characters" do
+ "\u{9879}".ord.should == 39033
+ end
- it "is equivalent to #codepoints.first" do
- "\u{981}\u{982}".ord.should == "\u{981}\u{982}".codepoints.first
- end
+ it "is equivalent to #codepoints.first" do
+ "\u{981}\u{982}".ord.should == "\u{981}\u{982}".codepoints.first
+ end
+
+ it "raises an ArgumentError if called on an empty String" do
+ -> { ''.ord }.should raise_error(ArgumentError)
+ end
- it "raises an ArgumentError if called on an empty String" do
- lambda { ''.ord }.should raise_error(ArgumentError)
- end
+ it "raises ArgumentError if the character is broken" do
+ s = "©".dup.force_encoding("US-ASCII")
+ -> { s.ord }.should raise_error(ArgumentError, "invalid byte sequence in US-ASCII")
end
end
diff --git a/spec/ruby/core/string/partition_spec.rb b/spec/ruby/core/string/partition_spec.rb
index 04f49db1b1..d5370dcc73 100644
--- a/spec/ruby/core/string/partition_spec.rb
+++ b/spec/ruby/core/string/partition_spec.rb
@@ -1,7 +1,10 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/partition'
describe "String#partition with String" do
+ it_behaves_like :string_partition, :partition
+
it "returns an array of substrings based on splitting on the given string" do
"hello world".partition("o").should == ["hell", "o", " world"]
end
@@ -28,11 +31,33 @@ describe "String#partition with String" do
end
it "raises an error if not convertible to string" do
- lambda{ "hello".partition(5) }.should raise_error(TypeError)
- lambda{ "hello".partition(nil) }.should raise_error(TypeError)
+ ->{ "hello".partition(5) }.should raise_error(TypeError)
+ ->{ "hello".partition(nil) }.should raise_error(TypeError)
end
it "takes precedence over a given block" do
"hello world".partition("o") { true }.should == ["hell", "o", " world"]
end
+
+ it "handles a pattern in a superset encoding" do
+ string = "hello".dup.force_encoding(Encoding::US_ASCII)
+
+ result = string.partition("é")
+
+ result.should == ["hello", "", ""]
+ result[0].encoding.should == Encoding::US_ASCII
+ result[1].encoding.should == Encoding::US_ASCII
+ result[2].encoding.should == Encoding::US_ASCII
+ end
+
+ it "handles a pattern in a subset encoding" do
+ pattern = "o".dup.force_encoding(Encoding::US_ASCII)
+
+ result = "héllo world".partition(pattern)
+
+ result.should == ["héll", "o", " world"]
+ result[0].encoding.should == Encoding::UTF_8
+ result[1].encoding.should == Encoding::US_ASCII
+ result[2].encoding.should == Encoding::UTF_8
+ end
end
diff --git a/spec/ruby/core/string/percent_spec.rb b/spec/ruby/core/string/percent_spec.rb
deleted file mode 100644
index 5eeb98c217..0000000000
--- a/spec/ruby/core/string/percent_spec.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../../kernel/shared/sprintf', __FILE__)
-require File.expand_path('../../kernel/shared/sprintf_encoding', __FILE__)
-
-describe "String#%" do
- it_behaves_like :kernel_sprintf, -> (format, *args) {
- format % args
- }
-
- it_behaves_like :kernel_sprintf_encoding, -> (format, *args) {
- format % args
- }
-end
-
diff --git a/spec/ruby/core/string/plus_spec.rb b/spec/ruby/core/string/plus_spec.rb
index addc8873eb..9da17451c6 100644
--- a/spec/ruby/core/string/plus_spec.rb
+++ b/spec/ruby/core/string/plus_spec.rb
@@ -1,8 +1,11 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
-require File.expand_path('../shared/concat', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/concat'
describe "String#+" do
+ it_behaves_like :string_concat_encoding, :+
+ it_behaves_like :string_concat_type_coercion, :+
+
it "returns a new string containing the given string concatenated to self" do
("" + "").should == ""
("" + "Hello").should == "Hello"
@@ -18,8 +21,8 @@ describe "String#+" do
end
it "raises a TypeError when given any object that fails #to_str" do
- lambda { "" + Object.new }.should raise_error(TypeError)
- lambda { "" + 65 }.should raise_error(TypeError)
+ -> { "" + Object.new }.should raise_error(TypeError)
+ -> { "" + 65 }.should raise_error(TypeError)
end
it "doesn't return subclass instances" do
@@ -31,17 +34,4 @@ describe "String#+" do
("hello" + StringSpecs::MyString.new("foo")).should be_an_instance_of(String)
("hello" + StringSpecs::MyString.new("")).should be_an_instance_of(String)
end
-
- it "taints the result when self or other is tainted" do
- strs = ["", "OK", StringSpecs::MyString.new(""), StringSpecs::MyString.new("OK")]
- strs += strs.map { |s| s.dup.taint }
-
- strs.each do |str|
- strs.each do |other|
- (str + other).tainted?.should == (str.tainted? | other.tainted?)
- end
- end
- end
-
- it_behaves_like :string_concat_encoding, :+
end
diff --git a/spec/ruby/core/string/prepend_spec.rb b/spec/ruby/core/string/prepend_spec.rb
index 17e97fd844..5248ea8056 100644
--- a/spec/ruby/core/string/prepend_spec.rb
+++ b/spec/ruby/core/string/prepend_spec.rb
@@ -1,5 +1,6 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+# frozen_string_literal: false
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String#prepend" do
it "prepends the given argument to self and returns self" do
@@ -16,16 +17,16 @@ describe "String#prepend" do
end
it "raises a TypeError if the given argument can't be converted to a String" do
- lambda { "hello ".prepend [] }.should raise_error(TypeError)
- lambda { 'hello '.prepend mock('x') }.should raise_error(TypeError)
+ -> { "hello ".prepend [] }.should raise_error(TypeError)
+ -> { 'hello '.prepend mock('x') }.should raise_error(TypeError)
end
- it "raises a RuntimeError when self is frozen" do
+ it "raises a FrozenError when self is frozen" do
a = "hello"
a.freeze
- lambda { a.prepend "" }.should raise_error(RuntimeError)
- lambda { a.prepend "test" }.should raise_error(RuntimeError)
+ -> { a.prepend "" }.should raise_error(FrozenError)
+ -> { a.prepend "test" }.should raise_error(FrozenError)
end
it "works when given a subclass instance" do
@@ -34,31 +35,21 @@ describe "String#prepend" do
a.should == "hello world"
end
- it "taints self if other is tainted" do
- x = "x"
- x.prepend("".taint).tainted?.should be_true
-
- x = "x"
- x.prepend("y".taint).tainted?.should be_true
+ it "takes multiple arguments" do
+ str = " world"
+ str.prepend "he", "", "llo"
+ str.should == "hello world"
end
- ruby_version_is "2.4" do
- it "takes multiple arguments" do
- str = " world"
- str.prepend "he", "", "llo"
- str.should == "hello world"
- end
-
- it "prepends the initial value when given arguments contain 2 self" do
- str = "hello"
- str.prepend str, str
- str.should == "hellohellohello"
- end
+ it "prepends the initial value when given arguments contain 2 self" do
+ str = "hello"
+ str.prepend str, str
+ str.should == "hellohellohello"
+ end
- it "returns self when given no arguments" do
- str = "hello"
- str.prepend.should equal(str)
- str.should == "hello"
- end
+ it "returns self when given no arguments" do
+ str = "hello"
+ str.prepend.should equal(str)
+ str.should == "hello"
end
end
diff --git a/spec/ruby/core/string/replace_spec.rb b/spec/ruby/core/string/replace_spec.rb
index 0f59a9a1ab..ef9bab4f3c 100644
--- a/spec/ruby/core/string/replace_spec.rb
+++ b/spec/ruby/core/string/replace_spec.rb
@@ -1,6 +1,6 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
-require File.expand_path('../shared/replace', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/replace'
describe "String#replace" do
it_behaves_like :string_replace, :replace
diff --git a/spec/ruby/core/string/reverse_spec.rb b/spec/ruby/core/string/reverse_spec.rb
index c37e815ba3..aa6abe6036 100644
--- a/spec/ruby/core/string/reverse_spec.rb
+++ b/spec/ruby/core/string/reverse_spec.rb
@@ -1,7 +1,8 @@
# encoding: utf-8
+# frozen_string_literal: false
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String#reverse" do
it "returns a new string with the characters of self in reverse order" do
@@ -10,17 +11,27 @@ describe "String#reverse" do
"".reverse.should == ""
end
- it "taints the result if self is tainted" do
- "".taint.reverse.tainted?.should == true
- "m".taint.reverse.tainted?.should == true
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("stressed").reverse.should be_an_instance_of(String)
+ StringSpecs::MyString.new("m").reverse.should be_an_instance_of(String)
+ StringSpecs::MyString.new("").reverse.should be_an_instance_of(String)
end
- with_feature :encoding do
- it "reverses a string with multi byte characters" do
- "微軟正黑體".reverse.should == "體黑正軟微"
- end
+ it "reverses a string with multi byte characters" do
+ "微軟正黑體".reverse.should == "體黑正軟微"
end
+ it "works with a broken string" do
+ str = "微軟\xDF\xDE正黑體".force_encoding(Encoding::UTF_8)
+
+ str.valid_encoding?.should be_false
+
+ str.reverse.should == "體黑正\xDE\xDF軟微"
+ end
+
+ it "returns a String in the same encoding as self" do
+ "stressed".encode("US-ASCII").reverse.encoding.should == Encoding::US_ASCII
+ end
end
describe "String#reverse!" do
@@ -32,21 +43,28 @@ describe "String#reverse!" do
"".reverse!.should == ""
end
- it "raises a RuntimeError on a frozen instance that is modified" do
- lambda { "anna".freeze.reverse! }.should raise_error(RuntimeError)
- lambda { "hello".freeze.reverse! }.should raise_error(RuntimeError)
+ it "raises a FrozenError on a frozen instance that is modified" do
+ -> { "anna".freeze.reverse! }.should raise_error(FrozenError)
+ -> { "hello".freeze.reverse! }.should raise_error(FrozenError)
end
# see [ruby-core:23666]
- it "raises a RuntimeError on a frozen instance that would not be modified" do
- lambda { "".freeze.reverse! }.should raise_error(RuntimeError)
+ it "raises a FrozenError on a frozen instance that would not be modified" do
+ -> { "".freeze.reverse! }.should raise_error(FrozenError)
end
- with_feature :encoding do
- it "reverses a string with multi byte characters" do
- str = "微軟正黑體"
- str.reverse!
- str.should == "體黑正軟微"
- end
+ it "reverses a string with multi byte characters" do
+ str = "微軟正黑體"
+ str.reverse!
+ str.should == "體黑正軟微"
+ end
+
+ it "works with a broken string" do
+ str = "微軟\xDF\xDE正黑體".force_encoding(Encoding::UTF_8)
+
+ str.valid_encoding?.should be_false
+ str.reverse!
+
+ str.should == "體黑正\xDE\xDF軟微"
end
end
diff --git a/spec/ruby/core/string/rindex_spec.rb b/spec/ruby/core/string/rindex_spec.rb
index 7085914189..0863a9c3be 100644
--- a/spec/ruby/core/string/rindex_spec.rb
+++ b/spec/ruby/core/string/rindex_spec.rb
@@ -1,20 +1,23 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
-require File.expand_path('../fixtures/utf-8-encoding.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String#rindex with object" do
- it "raises a TypeError if obj isn't a String, Fixnum or Regexp" do
+ it "raises a TypeError if obj isn't a String or Regexp" do
not_supported_on :opal do
- lambda { "hello".rindex(:sym) }.should raise_error(TypeError)
+ -> { "hello".rindex(:sym) }.should raise_error(TypeError)
end
- lambda { "hello".rindex(mock('x')) }.should raise_error(TypeError)
+ -> { "hello".rindex(mock('x')) }.should raise_error(TypeError)
+ end
+
+ it "raises a TypeError if obj is an Integer" do
+ -> { "hello".rindex(42) }.should raise_error(TypeError)
end
it "doesn't try to convert obj to an integer via to_int" do
obj = mock('x')
obj.should_not_receive(:to_int)
- lambda { "hello".rindex(obj) }.should raise_error(TypeError)
+ -> { "hello".rindex(obj) }.should raise_error(TypeError)
end
it "tries to convert obj to a string via to_str" do
@@ -190,7 +193,22 @@ describe "String#rindex with String" do
end
it "raises a TypeError when given offset is nil" do
- lambda { "str".rindex("st", nil) }.should raise_error(TypeError)
+ -> { "str".rindex("st", nil) }.should raise_error(TypeError)
+ end
+
+ it "handles a substring in a superset encoding" do
+ 'abc'.dup.force_encoding(Encoding::US_ASCII).rindex('é').should == nil
+ end
+
+ it "handles a substring in a subset encoding" do
+ 'été'.rindex('t'.dup.force_encoding(Encoding::US_ASCII)).should == 1
+ end
+
+ it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
+ str = 'abc'.dup.force_encoding("ISO-2022-JP")
+ pattern = 'b'.dup.force_encoding("EUC-JP")
+
+ -> { str.rindex(pattern) }.should raise_error(Encoding::CompatibilityError, "incompatible character encodings: ISO-2022-JP and EUC-JP")
end
end
@@ -344,25 +362,23 @@ describe "String#rindex with Regexp" do
end
it "raises a TypeError when given offset is nil" do
- lambda { "str".rindex(/../, nil) }.should raise_error(TypeError)
+ -> { "str".rindex(/../, nil) }.should raise_error(TypeError)
end
- with_feature :encoding do
- it "returns the reverse character index of a multibyte character" do
- "ありがりがとう".rindex("が").should == 4
- "ありがりがとう".rindex(/が/).should == 4
- end
+ it "returns the reverse character index of a multibyte character" do
+ "ありがりがとう".rindex("が").should == 4
+ "ありがりがとう".rindex(/が/).should == 4
+ end
- it "returns the character index before the finish" do
- "ありがりがとう".rindex("が", 3).should == 2
- "ありがりがとう".rindex(/が/, 3).should == 2
- end
+ it "returns the character index before the finish" do
+ "ありがりがとう".rindex("が", 3).should == 2
+ "ありがりがとう".rindex(/が/, 3).should == 2
+ end
- it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
- re = Regexp.new "れ".encode(Encoding::EUC_JP)
- lambda do
- "あれ".rindex re
- end.should raise_error(Encoding::CompatibilityError)
- end
+ it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
+ re = Regexp.new "れ".encode(Encoding::EUC_JP)
+ -> do
+ "あれ".rindex re
+ end.should raise_error(Encoding::CompatibilityError, "incompatible encoding regexp match (EUC-JP regexp with UTF-8 string)")
end
end
diff --git a/spec/ruby/core/string/rjust_spec.rb b/spec/ruby/core/string/rjust_spec.rb
index 85cb1fe213..4ad3e54aea 100644
--- a/spec/ruby/core/string/rjust_spec.rb
+++ b/spec/ruby/core/string/rjust_spec.rb
@@ -1,6 +1,6 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String#rjust with length, padding" do
it "returns a new string of specified length with self right justified and padded with padstr" do
@@ -31,14 +31,6 @@ describe "String#rjust with length, padding" do
"radiology".rjust(8, '-').should == "radiology"
end
- it "taints result when self or padstr is tainted" do
- "x".taint.rjust(4).tainted?.should == true
- "x".taint.rjust(0).tainted?.should == true
- "".taint.rjust(0).tainted?.should == true
- "x".taint.rjust(4, "*").tainted?.should == true
- "x".rjust(4, "*".taint).tainted?.should == true
- end
-
it "tries to convert length to an integer using to_int" do
"^".rjust(3.8, "^_").should == "^_^"
@@ -49,10 +41,10 @@ describe "String#rjust with length, padding" do
end
it "raises a TypeError when length can't be converted to an integer" do
- lambda { "hello".rjust("x") }.should raise_error(TypeError)
- lambda { "hello".rjust("x", "y") }.should raise_error(TypeError)
- lambda { "hello".rjust([]) }.should raise_error(TypeError)
- lambda { "hello".rjust(mock('x')) }.should raise_error(TypeError)
+ -> { "hello".rjust("x") }.should raise_error(TypeError)
+ -> { "hello".rjust("x", "y") }.should raise_error(TypeError)
+ -> { "hello".rjust([]) }.should raise_error(TypeError)
+ -> { "hello".rjust(mock('x')) }.should raise_error(TypeError)
end
it "tries to convert padstr to a string using to_str" do
@@ -63,54 +55,46 @@ describe "String#rjust with length, padding" do
end
it "raises a TypeError when padstr can't be converted" do
- lambda { "hello".rjust(20, []) }.should raise_error(TypeError)
- lambda { "hello".rjust(20, Object.new)}.should raise_error(TypeError)
- lambda { "hello".rjust(20, mock('x')) }.should raise_error(TypeError)
+ -> { "hello".rjust(20, []) }.should raise_error(TypeError)
+ -> { "hello".rjust(20, Object.new)}.should raise_error(TypeError)
+ -> { "hello".rjust(20, mock('x')) }.should raise_error(TypeError)
end
it "raises an ArgumentError when padstr is empty" do
- lambda { "hello".rjust(10, '') }.should raise_error(ArgumentError)
+ -> { "hello".rjust(10, '') }.should raise_error(ArgumentError)
end
- it "returns subclass instances when called on subclasses" do
- StringSpecs::MyString.new("").rjust(10).should be_an_instance_of(StringSpecs::MyString)
- StringSpecs::MyString.new("foo").rjust(10).should be_an_instance_of(StringSpecs::MyString)
- StringSpecs::MyString.new("foo").rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(StringSpecs::MyString)
+ it "returns String instances when called on subclasses" do
+ StringSpecs::MyString.new("").rjust(10).should be_an_instance_of(String)
+ StringSpecs::MyString.new("foo").rjust(10).should be_an_instance_of(String)
+ StringSpecs::MyString.new("foo").rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
"".rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
"foo".rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
end
- it "when padding is tainted and self is untainted returns a tainted string if and only if length is longer than self" do
- "hello".rjust(4, 'X'.taint).tainted?.should be_false
- "hello".rjust(5, 'X'.taint).tainted?.should be_false
- "hello".rjust(6, 'X'.taint).tainted?.should be_true
+ describe "with width" do
+ it "returns a String in the same encoding as the original" do
+ str = "abc".dup.force_encoding Encoding::IBM437
+ result = str.rjust 5
+ result.should == " abc"
+ result.encoding.should equal(Encoding::IBM437)
+ end
end
- with_feature :encoding do
- describe "with width" do
- it "returns a String in the same encoding as the original" do
- str = "abc".force_encoding Encoding::IBM437
- result = str.rjust 5
- result.should == " abc"
- result.encoding.should equal(Encoding::IBM437)
- end
+ describe "with width, pattern" do
+ it "returns a String in the compatible encoding" do
+ str = "abc".dup.force_encoding Encoding::IBM437
+ result = str.rjust 5, "あ"
+ result.should == "ああabc"
+ result.encoding.should equal(Encoding::UTF_8)
end
- describe "with width, pattern" do
- it "returns a String in the compatible encoding" do
- str = "abc".force_encoding Encoding::IBM437
- result = str.rjust 5, "あ"
- result.should == "ああabc"
- result.encoding.should equal(Encoding::UTF_8)
- end
-
- it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
- pat = "ア".encode Encoding::EUC_JP
- lambda do
- "あれ".rjust 5, pat
- end.should raise_error(Encoding::CompatibilityError)
- end
+ it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
+ pat = "ア".encode Encoding::EUC_JP
+ -> do
+ "あれ".rjust 5, pat
+ end.should raise_error(Encoding::CompatibilityError)
end
end
end
diff --git a/spec/ruby/core/string/rpartition_spec.rb b/spec/ruby/core/string/rpartition_spec.rb
index c58d96f298..cef0384c73 100644
--- a/spec/ruby/core/string/rpartition_spec.rb
+++ b/spec/ruby/core/string/rpartition_spec.rb
@@ -1,7 +1,10 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/partition'
describe "String#rpartition with String" do
+ it_behaves_like :string_partition, :rpartition
+
it "returns an array of substrings based on splitting on the given string" do
"hello world".rpartition("o").should == ["hello w", "o", "rld"]
end
@@ -11,6 +14,19 @@ describe "String#rpartition with String" do
"hello".rpartition("hello").should == ["", "hello", ""]
end
+ it "returns original string if regexp doesn't match" do
+ "hello".rpartition("/x/").should == ["", "", "hello"]
+ end
+
+ it "returns new object if doesn't match" do
+ str = "hello"
+ str.rpartition("/no_match/").last.should_not.equal?(str)
+ end
+
+ it "handles multibyte string correctly" do
+ "ユーザ@ドメイン".rpartition(/@/).should == ["ユーザ", "@", "ドメイン"]
+ end
+
it "accepts regexp" do
"hello!".rpartition(/l./).should == ["hel", "lo", "!"]
end
@@ -27,7 +43,29 @@ describe "String#rpartition with String" do
end
it "raises an error if not convertible to string" do
- lambda{ "hello".rpartition(5) }.should raise_error(TypeError)
- lambda{ "hello".rpartition(nil) }.should raise_error(TypeError)
+ ->{ "hello".rpartition(5) }.should raise_error(TypeError)
+ ->{ "hello".rpartition(nil) }.should raise_error(TypeError)
+ end
+
+ it "handles a pattern in a superset encoding" do
+ string = "hello".dup.force_encoding(Encoding::US_ASCII)
+
+ result = string.rpartition("é")
+
+ result.should == ["", "", "hello"]
+ result[0].encoding.should == Encoding::US_ASCII
+ result[1].encoding.should == Encoding::US_ASCII
+ result[2].encoding.should == Encoding::US_ASCII
+ end
+
+ it "handles a pattern in a subset encoding" do
+ pattern = "o".dup.force_encoding(Encoding::US_ASCII)
+
+ result = "héllo world".rpartition(pattern)
+
+ result.should == ["héllo w", "o", "rld"]
+ result[0].encoding.should == Encoding::UTF_8
+ result[1].encoding.should == Encoding::US_ASCII
+ result[2].encoding.should == Encoding::UTF_8
end
end
diff --git a/spec/ruby/core/string/rstrip_spec.rb b/spec/ruby/core/string/rstrip_spec.rb
index 9dd686ce55..55773f5238 100644
--- a/spec/ruby/core/string/rstrip_spec.rb
+++ b/spec/ruby/core/string/rstrip_spec.rb
@@ -1,23 +1,29 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+# frozen_string_literal: false
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/strip'
describe "String#rstrip" do
+ it_behaves_like :string_strip, :rstrip
+
it "returns a copy of self with trailing whitespace removed" do
" hello ".rstrip.should == " hello"
" hello world ".rstrip.should == " hello world"
" hello world \n\r\t\n\v\r".rstrip.should == " hello world"
"hello".rstrip.should == "hello"
"hello\x00".rstrip.should == "hello"
+ "こにちわ ".rstrip.should == "こにちわ"
end
- it "returns a copy of self with all trailing whitespace and NULL bytes removed" do
- "\x00 \x00hello\x00 \x00".rstrip.should == "\x00 \x00hello"
+ it "works with lazy substrings" do
+ " hello "[1...-1].rstrip.should == " hello"
+ " hello world "[1...-1].rstrip.should == " hello world"
+ " hello world \n\r\t\n\v\r"[1...-1].rstrip.should == " hello world"
+ " こにちわ "[1...-1].rstrip.should == "こにちわ"
end
- it "taints the result when self is tainted" do
- "".taint.rstrip.tainted?.should == true
- "ok".taint.rstrip.tainted?.should == true
- "ok ".taint.rstrip.tainted?.should == true
+ it "returns a copy of self with all trailing whitespace and NULL bytes removed" do
+ "\x00 \x00hello\x00 \x00".rstrip.should == "\x00 \x00hello"
end
end
@@ -40,13 +46,35 @@ describe "String#rstrip!" do
a.should == "hello"
end
- it "raises a RuntimeError on a frozen instance that is modified" do
- lambda { " hello ".freeze.rstrip! }.should raise_error(RuntimeError)
+ it "makes a string empty if it is only whitespace" do
+ "".rstrip!.should == nil
+ " ".rstrip.should == ""
+ " ".rstrip.should == ""
+ end
+
+ it "removes trailing NULL bytes and whitespace" do
+ a = "\000 goodbye \000"
+ a.rstrip!
+ a.should == "\000 goodbye"
+ end
+
+ it "raises a FrozenError on a frozen instance that is modified" do
+ -> { " hello ".freeze.rstrip! }.should raise_error(FrozenError)
end
# see [ruby-core:23666]
- it "raises a RuntimeError on a frozen instance that would not be modified" do
- lambda { "hello".freeze.rstrip! }.should raise_error(RuntimeError)
- lambda { "".freeze.rstrip! }.should raise_error(RuntimeError)
+ it "raises a FrozenError on a frozen instance that would not be modified" do
+ -> { "hello".freeze.rstrip! }.should raise_error(FrozenError)
+ -> { "".freeze.rstrip! }.should raise_error(FrozenError)
+ end
+
+ it "raises an Encoding::CompatibilityError if the last non-space codepoint is invalid" do
+ s = "abc\xDF".force_encoding(Encoding::UTF_8)
+ s.valid_encoding?.should be_false
+ -> { s.rstrip! }.should raise_error(Encoding::CompatibilityError)
+
+ s = "abc\xDF ".force_encoding(Encoding::UTF_8)
+ s.valid_encoding?.should be_false
+ -> { s.rstrip! }.should raise_error(Encoding::CompatibilityError)
end
end
diff --git a/spec/ruby/core/string/scan_spec.rb b/spec/ruby/core/string/scan_spec.rb
index f09daa1b74..bbe843b591 100644
--- a/spec/ruby/core/string/scan_spec.rb
+++ b/spec/ruby/core/string/scan_spec.rb
@@ -1,6 +1,6 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String#scan" do
it "returns an array containing all matches" do
@@ -58,31 +58,22 @@ describe "String#scan" do
end
it "raises a TypeError if pattern isn't a Regexp and can't be converted to a String" do
- lambda { "cruel world".scan(5) }.should raise_error(TypeError)
+ -> { "cruel world".scan(5) }.should raise_error(TypeError)
not_supported_on :opal do
- lambda { "cruel world".scan(:test) }.should raise_error(TypeError)
+ -> { "cruel world".scan(:test) }.should raise_error(TypeError)
end
- lambda { "cruel world".scan(mock('x')) }.should raise_error(TypeError)
+ -> { "cruel world".scan(mock('x')) }.should raise_error(TypeError)
end
- it "taints the results if the String argument is tainted" do
- a = "hello hello hello".scan("hello".taint)
- a.each { |m| m.tainted?.should be_true }
+ # jruby/jruby#5513
+ it "does not raise any errors when passed a multi-byte string" do
+ "あああaaaあああ".scan("あああ").should == ["あああ", "あああ"]
end
- it "taints the results when passed a String argument if self is tainted" do
- a = "hello hello hello".taint.scan("hello")
- a.each { |m| m.tainted?.should be_true }
- end
-
- it "taints the results if the Regexp argument is tainted" do
- a = "hello".scan(/./.taint)
- a.each { |m| m.tainted?.should be_true }
- end
-
- it "taints the results when passed a Regexp argument if self is tainted" do
- a = "hello".taint.scan(/./)
- a.each { |m| m.tainted?.should be_true }
+ it "returns Strings in the same encoding as self" do
+ "cruel world".encode("US-ASCII").scan(/\w+/).each do |s|
+ s.encoding.should == Encoding::US_ASCII
+ end
end
end
@@ -112,11 +103,11 @@ describe "String#scan with pattern and block" do
offsets = []
str.scan(/([aeiou])/) do
- md = $~
- md.string.should == str
- matches << md.to_a
- offsets << md.offset(0)
- str
+ md = $~
+ md.string.should == str
+ matches << md.to_a
+ offsets << md.offset(0)
+ str
end
matches.should == [["e", "e"], ["o", "o"]]
@@ -126,11 +117,11 @@ describe "String#scan with pattern and block" do
offsets = []
str.scan("l") do
- md = $~
- md.string.should == str
- matches << md.to_a
- offsets << md.offset(0)
- str
+ md = $~
+ md.string.should == str
+ matches << md.to_a
+ offsets << md.offset(0)
+ str
end
matches.should == [["l"], ["l"]]
@@ -166,22 +157,6 @@ describe "String#scan with pattern and block" do
$~.should == nil
end
- it "taints the results if the String argument is tainted" do
- "hello hello hello".scan("hello".taint).each { |m| m.tainted?.should be_true }
- end
-
- it "taints the results when passed a String argument if self is tainted" do
- "hello hello hello".taint.scan("hello").each { |m| m.tainted?.should be_true }
- end
-
- it "taints the results if the Regexp argument is tainted" do
- "hello".scan(/./.taint).each { |m| m.tainted?.should be_true }
- end
-
- it "taints the results when passed a Regexp argument if self is tainted" do
- "hello".taint.scan(/./).each { |m| m.tainted?.should be_true }
- end
-
it "passes block arguments as individual arguments when blocks are provided" do
"a b c\na b c\na b c".scan(/(\w*) (\w*) (\w*)/) do |first,second,third|
first.should == 'a';
@@ -189,4 +164,10 @@ describe "String#scan with pattern and block" do
third.should == 'c';
end
end
+
+ it "yields String instances for subclasses" do
+ a = []
+ StringSpecs::MyString.new("abc").scan(/./) { |s| a << s.class }
+ a.should == [String, String, String]
+ end
end
diff --git a/spec/ruby/core/string/scrub_spec.rb b/spec/ruby/core/string/scrub_spec.rb
index 815eb0fbb7..b9ef0f1a16 100644
--- a/spec/ruby/core/string/scrub_spec.rb
+++ b/spec/ruby/core/string/scrub_spec.rb
@@ -1,5 +1,7 @@
# -*- encoding: utf-8 -*-
-require File.expand_path("../../../spec_helper", __FILE__)
+# frozen_string_literal: false
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String#scrub with a default replacement" do
it "returns self for valid strings" do
@@ -13,18 +15,33 @@ describe "String#scrub with a default replacement" do
"abc\u3042#{x81}".scrub.should == "abc\u3042\uFFFD"
end
+ it "replaces invalid byte sequences in lazy substrings" do
+ x81 = [0x81].pack('C').force_encoding('utf-8')
+ "abc\u3042#{x81}def"[1...-1].scrub.should == "bc\u3042\uFFFDde"
+ end
+
it "returns a copy of self when the input encoding is BINARY" do
input = "foo".encode('BINARY')
input.scrub.should == "foo"
end
-
it "replaces invalid byte sequences when using ASCII as the input encoding" do
xE3x80 = [0xE3, 0x80].pack('CC').force_encoding 'utf-8'
input = "abc\u3042#{xE3x80}".force_encoding('ASCII')
input.scrub.should == "abc?????"
end
+
+ it "returns a String in the same encoding as self" do
+ x81 = [0x81].pack('C').force_encoding('utf-8')
+ "abc\u3042#{x81}".scrub.encoding.should == Encoding::UTF_8
+ end
+
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("foo").scrub.should be_an_instance_of(String)
+ input = [0x81].pack('C').force_encoding('utf-8')
+ StringSpecs::MyString.new(input).scrub.should be_an_instance_of(String)
+ end
end
describe "String#scrub with a custom replacement" do
@@ -39,6 +56,15 @@ describe "String#scrub with a custom replacement" do
"abc\u3042#{x81}".scrub("*").should == "abc\u3042*"
end
+ it "replaces invalid byte sequences in frozen strings" do
+ x81 = [0x81].pack('C').force_encoding('utf-8')
+ (-"abc\u3042#{x81}").scrub("*").should == "abc\u3042*"
+
+ leading_surrogate = [0x00, 0xD8]
+ utf16_str = ("abc".encode('UTF-16LE').bytes + leading_surrogate).pack('c*').force_encoding('UTF-16LE')
+ (-(utf16_str)).scrub("*".encode('UTF-16LE')).should == "abc*".encode('UTF-16LE')
+ end
+
it "replaces an incomplete character at the end with a single replacement" do
xE3x80 = [0xE3, 0x80].pack('CC').force_encoding 'utf-8'
xE3x80.scrub("*").should == "*"
@@ -47,17 +73,28 @@ describe "String#scrub with a custom replacement" do
it "raises ArgumentError for replacements with an invalid encoding" do
x81 = [0x81].pack('C').force_encoding('utf-8')
xE4 = [0xE4].pack('C').force_encoding('utf-8')
- block = lambda { "foo#{x81}".scrub(xE4) }
+ block = -> { "foo#{x81}".scrub(xE4) }
block.should raise_error(ArgumentError)
end
+ it "returns a String in the same encoding as self" do
+ x81 = [0x81].pack('C').force_encoding('utf-8')
+ "abc\u3042#{x81}".scrub("*").encoding.should == Encoding::UTF_8
+ end
+
it "raises TypeError when a non String replacement is given" do
x81 = [0x81].pack('C').force_encoding('utf-8')
- block = lambda { "foo#{x81}".scrub(1) }
+ block = -> { "foo#{x81}".scrub(1) }
block.should raise_error(TypeError)
end
+
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("foo").scrub("*").should be_an_instance_of(String)
+ input = [0x81].pack('C').force_encoding('utf-8')
+ StringSpecs::MyString.new(input).scrub("*").should be_an_instance_of(String)
+ end
end
describe "String#scrub with a block" do
@@ -82,6 +119,12 @@ describe "String#scrub with a block" do
replaced.should == "€€"
end
+
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("foo").scrub { |b| "*" }.should be_an_instance_of(String)
+ input = [0x81].pack('C').force_encoding('utf-8')
+ StringSpecs::MyString.new(input).scrub { |b| "<#{b.unpack("H*")[0]}>" }.should be_an_instance_of(String)
+ end
end
describe "String#scrub!" do
@@ -98,4 +141,24 @@ describe "String#scrub!" do
input.scrub! { |b| "<?>" }
input.should == "a<?>"
end
+
+ it "maintains the state of frozen strings that are already valid" do
+ input = "a"
+ input.freeze
+ input.scrub!
+ input.frozen?.should be_true
+ end
+
+ it "preserves the instance variables of already valid strings" do
+ input = "a"
+ input.instance_variable_set(:@a, 'b')
+ input.scrub!
+ input.instance_variable_get(:@a).should == 'b'
+ end
+
+ it "accepts a frozen string as a replacement" do
+ input = "a\xE2"
+ input.scrub!('.'.freeze)
+ input.should == 'a.'
+ end
end
diff --git a/spec/ruby/core/string/setbyte_spec.rb b/spec/ruby/core/string/setbyte_spec.rb
index 6373d74be1..85403ca62c 100644
--- a/spec/ruby/core/string/setbyte_spec.rb
+++ b/spec/ruby/core/string/setbyte_spec.rb
@@ -1,5 +1,6 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
+# frozen_string_literal: false
+require_relative '../../spec_helper'
describe "String#setbyte" do
it "returns an Integer" do
@@ -36,6 +37,12 @@ describe "String#setbyte" do
str.valid_encoding?.should be_true
str.setbyte(2,253)
str.valid_encoding?.should be_false
+
+ str = "ABC"
+ str.setbyte(0, 0x20) # ' '
+ str.should.valid_encoding?
+ str.setbyte(0, 0xE3)
+ str.should_not.valid_encoding?
end
it "regards a negative index as counting from the end of the String" do
@@ -51,11 +58,11 @@ describe "String#setbyte" do
end
it "raises an IndexError if the index is greater than the String bytesize" do
- lambda { "?".setbyte(1, 97) }.should raise_error(IndexError)
+ -> { "?".setbyte(1, 97) }.should raise_error(IndexError)
end
- it "raises an IndexError if the nexgative index is greater magnitude than the String bytesize" do
- lambda { "???".setbyte(-5, 97) }.should raise_error(IndexError)
+ it "raises an IndexError if the negative index is greater magnitude than the String bytesize" do
+ -> { "???".setbyte(-5, 97) }.should raise_error(IndexError)
end
it "sets a byte at an index greater than String size" do
@@ -75,14 +82,14 @@ describe "String#setbyte" do
str1.should_not == "ledgehog"
end
- it "raises a RuntimeError if self is frozen" do
+ it "raises a FrozenError if self is frozen" do
str = "cold".freeze
str.frozen?.should be_true
- lambda { str.setbyte(3,96) }.should raise_error(RuntimeError)
+ -> { str.setbyte(3,96) }.should raise_error(FrozenError)
end
it "raises a TypeError unless the second argument is an Integer" do
- lambda { "a".setbyte(0,'a') }.should raise_error(TypeError)
+ -> { "a".setbyte(0,'a') }.should raise_error(TypeError)
end
it "calls #to_int to convert the index" do
diff --git a/spec/ruby/core/string/shared/byte_index_common.rb b/spec/ruby/core/string/shared/byte_index_common.rb
new file mode 100644
index 0000000000..3de1453f4f
--- /dev/null
+++ b/spec/ruby/core/string/shared/byte_index_common.rb
@@ -0,0 +1,63 @@
+# -*- encoding: utf-8 -*-
+require_relative '../../../spec_helper'
+
+describe :byte_index_common, shared: true do
+ describe "raises on type errors" do
+ it "raises a TypeError if passed nil" do
+ -> { "abc".send(@method, nil) }.should raise_error(TypeError, "no implicit conversion of nil into String")
+ end
+
+ it "raises a TypeError if passed a boolean" do
+ -> { "abc".send(@method, true) }.should raise_error(TypeError, "no implicit conversion of true into String")
+ end
+
+ it "raises a TypeError if passed a Symbol" do
+ not_supported_on :opal do
+ -> { "abc".send(@method, :a) }.should raise_error(TypeError, "no implicit conversion of Symbol into String")
+ end
+ end
+
+ it "raises a TypeError if passed a Symbol" do
+ obj = mock('x')
+ obj.should_not_receive(:to_int)
+ -> { "hello".send(@method, obj) }.should raise_error(TypeError, "no implicit conversion of MockObject into String")
+ end
+
+ it "raises a TypeError if passed an Integer" do
+ -> { "abc".send(@method, 97) }.should raise_error(TypeError, "no implicit conversion of Integer into String")
+ end
+ end
+
+ describe "with multibyte codepoints" do
+ it "raises an IndexError when byte offset lands in the middle of a multibyte character" do
+ -> { "わ".send(@method, "", 1) }.should raise_error(IndexError, "offset 1 does not land on character boundary")
+ -> { "わ".send(@method, "", 2) }.should raise_error(IndexError, "offset 2 does not land on character boundary")
+ -> { "わ".send(@method, "", -1) }.should raise_error(IndexError, "offset 2 does not land on character boundary")
+ -> { "わ".send(@method, "", -2) }.should raise_error(IndexError, "offset 1 does not land on character boundary")
+ end
+
+ it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
+ re = Regexp.new "れ".encode(Encoding::EUC_JP)
+ -> do
+ "あれ".send(@method, re)
+ end.should raise_error(Encoding::CompatibilityError, "incompatible encoding regexp match (EUC-JP regexp with UTF-8 string)")
+ end
+ end
+
+ describe "with global variables" do
+ it "doesn't set $~ for non regex search" do
+ $~ = nil
+
+ 'hello.'.send(@method, 'll')
+ $~.should == nil
+ end
+
+ it "sets $~ to MatchData of match and nil when there's none" do
+ 'hello.'.send(@method, /.e./)
+ $~[0].should == 'hel'
+
+ 'hello.'.send(@method, /not/)
+ $~.should == nil
+ end
+ end
+end
diff --git a/spec/ruby/core/string/shared/chars.rb b/spec/ruby/core/string/shared/chars.rb
index c1cf324dc5..c730643cf4 100644
--- a/spec/ruby/core/string/shared/chars.rb
+++ b/spec/ruby/core/string/shared/chars.rb
@@ -1,6 +1,6 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../../spec_helper', __FILE__)
-require File.expand_path('../../fixtures/classes', __FILE__)
+require_relative '../../../spec_helper'
+require_relative '../fixtures/classes'
describe :string_chars, shared: true do
it "passes each char in self to the given block" do
@@ -20,61 +20,47 @@ describe :string_chars, shared: true do
["\303\207", "\342\210\202", "\303\251", "\306\222", "g"]
end
- with_feature :encoding do
- it "returns characters in the same encoding as self" do
- "&%".force_encoding('Shift_JIS').send(@method).to_a.all? {|c| c.encoding.name.should == 'Shift_JIS'}
- "&%".encode('ASCII-8BIT').send(@method).to_a.all? {|c| c.encoding.name.should == 'ASCII-8BIT'}
- end
-
- it "works with multibyte characters" do
- s = "\u{8987}".force_encoding("UTF-8")
- s.bytesize.should == 3
- s.send(@method).to_a.should == [s]
- end
-
- it "works if the String's contents is invalid for its encoding" do
- xA4 = [0xA4].pack('C')
- xA4.force_encoding('UTF-8')
- xA4.valid_encoding?.should be_false
- xA4.send(@method).to_a.should == [xA4.force_encoding("UTF-8")]
- end
-
- it "returns a different character if the String is transcoded" do
- s = "\u{20AC}".force_encoding('UTF-8')
- s.encode('UTF-8').send(@method).to_a.should == ["\u{20AC}".force_encoding('UTF-8')]
- s.encode('iso-8859-15').send(@method).to_a.should == [[0xA4].pack('C').force_encoding('iso-8859-15')]
- s.encode('iso-8859-15').encode('UTF-8').send(@method).to_a.should == ["\u{20AC}".force_encoding('UTF-8')]
- end
+ it "returns characters in the same encoding as self" do
+ "&%".dup.force_encoding('Shift_JIS').send(@method).to_a.all? {|c| c.encoding.name.should == 'Shift_JIS'}
+ "&%".encode('BINARY').send(@method).to_a.all? {|c| c.encoding.should == Encoding::BINARY }
+ end
- it "uses the String's encoding to determine what characters it contains" do
- s = "\u{24B62}"
+ it "works with multibyte characters" do
+ s = "\u{8987}".dup.force_encoding("UTF-8")
+ s.bytesize.should == 3
+ s.send(@method).to_a.should == [s]
+ end
- s.force_encoding('UTF-8').send(@method).to_a.should == [
- s.force_encoding('UTF-8')
- ]
- s.force_encoding('BINARY').send(@method).to_a.should == [
- [0xF0].pack('C').force_encoding('BINARY'),
- [0xA4].pack('C').force_encoding('BINARY'),
- [0xAD].pack('C').force_encoding('BINARY'),
- [0xA2].pack('C').force_encoding('BINARY')
- ]
- s.force_encoding('SJIS').send(@method).to_a.should == [
- [0xF0,0xA4].pack('CC').force_encoding('SJIS'),
- [0xAD].pack('C').force_encoding('SJIS'),
- [0xA2].pack('C').force_encoding('SJIS')
- ]
- end
+ it "works if the String's contents is invalid for its encoding" do
+ xA4 = [0xA4].pack('C')
+ xA4.force_encoding('UTF-8')
+ xA4.valid_encoding?.should be_false
+ xA4.send(@method).to_a.should == [xA4.force_encoding("UTF-8")]
+ end
- it "taints resulting strings when self is tainted" do
- str = "hello"
+ it "returns a different character if the String is transcoded" do
+ s = "\u{20AC}".dup.force_encoding('UTF-8')
+ s.encode('UTF-8').send(@method).to_a.should == ["\u{20AC}".dup.force_encoding('UTF-8')]
+ s.encode('iso-8859-15').send(@method).to_a.should == [[0xA4].pack('C').force_encoding('iso-8859-15')]
+ s.encode('iso-8859-15').encode('UTF-8').send(@method).to_a.should == ["\u{20AC}".dup.force_encoding('UTF-8')]
+ end
- str.send(@method) do |x|
- x.tainted?.should == false
- end
+ it "uses the String's encoding to determine what characters it contains" do
+ s = +"\u{24B62}"
- str.dup.taint.send(@method) do |x|
- x.tainted?.should == true
- end
- end
+ s.force_encoding('UTF-8').send(@method).to_a.should == [
+ s.force_encoding('UTF-8')
+ ]
+ s.force_encoding('BINARY').send(@method).to_a.should == [
+ [0xF0].pack('C').force_encoding('BINARY'),
+ [0xA4].pack('C').force_encoding('BINARY'),
+ [0xAD].pack('C').force_encoding('BINARY'),
+ [0xA2].pack('C').force_encoding('BINARY')
+ ]
+ s.force_encoding('SJIS').send(@method).to_a.should == [
+ [0xF0,0xA4].pack('CC').force_encoding('SJIS'),
+ [0xAD].pack('C').force_encoding('SJIS'),
+ [0xA2].pack('C').force_encoding('SJIS')
+ ]
end
end
diff --git a/spec/ruby/core/string/shared/codepoints.rb b/spec/ruby/core/string/shared/codepoints.rb
index 68f82b4468..1c28ba3d5e 100644
--- a/spec/ruby/core/string/shared/codepoints.rb
+++ b/spec/ruby/core/string/shared/codepoints.rb
@@ -1,9 +1,15 @@
-# -*- encoding: binary -*-
+# encoding: binary
describe :string_codepoints, shared: true do
+ it "returns self" do
+ s = "foo"
+ result = s.send(@method) {}
+ result.should equal s
+ end
+
it "raises an ArgumentError when self has an invalid encoding and a method is called on the returned Enumerator" do
- s = "\xDF".force_encoding(Encoding::UTF_8)
+ s = "\xDF".dup.force_encoding(Encoding::UTF_8)
s.valid_encoding?.should be_false
- lambda { s.send(@method).to_a }.should raise_error(ArgumentError)
+ -> { s.send(@method).to_a }.should raise_error(ArgumentError)
end
it "yields each codepoint to the block if one is given" do
@@ -15,18 +21,18 @@ describe :string_codepoints, shared: true do
end
it "raises an ArgumentError if self's encoding is invalid and a block is given" do
- s = "\xDF".force_encoding(Encoding::UTF_8)
+ s = "\xDF".dup.force_encoding(Encoding::UTF_8)
s.valid_encoding?.should be_false
- lambda { s.send(@method) { } }.should raise_error(ArgumentError)
+ -> { s.send(@method) { } }.should raise_error(ArgumentError)
end
- it "returns codepoints as Fixnums" do
+ it "yields codepoints as Integers" do
"glark\u{20}".send(@method).to_a.each do |codepoint|
- codepoint.should be_an_instance_of(Fixnum)
+ codepoint.should be_an_instance_of(Integer)
end
end
- it "returns one codepoint for each character" do
+ it "yields one codepoint for each character" do
s = "\u{9876}\u{28}\u{1987}"
s.send(@method).to_a.size.should == s.chars.to_a.size
end
@@ -37,18 +43,18 @@ describe :string_codepoints, shared: true do
s.send(@method).to_a.should == [38937]
end
- it "returns the codepoint corresponding to the character's position in the String's encoding" do
+ it "yields the codepoints corresponding to the character's position in the String's encoding" do
"\u{787}".send(@method).to_a.should == [1927]
end
it "round-trips to the original String using Integer#chr" do
s = "\u{13}\u{7711}\u{1010}"
- s2 = ""
+ s2 = +""
s.send(@method) {|n| s2 << n.chr(Encoding::UTF_8)}
s.should == s2
end
- it "is synonymous with #bytes for Strings which are single-byte optimisable" do
+ it "is synonymous with #bytes for Strings which are single-byte optimizable" do
s = "(){}".encode('ascii')
s.ascii_only?.should be_true
s.send(@method).to_a.should == s.bytes.to_a
diff --git a/spec/ruby/core/string/shared/concat.rb b/spec/ruby/core/string/shared/concat.rb
index 7da995fdc7..dded9a69e7 100644
--- a/spec/ruby/core/string/shared/concat.rb
+++ b/spec/ruby/core/string/shared/concat.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: false
describe :string_concat, shared: true do
it "concatenates the given argument to self and returns self" do
str = 'hello '
@@ -5,24 +6,12 @@ describe :string_concat, shared: true do
str.should == "hello world"
end
- it "converts the given argument to a String using to_str" do
- obj = mock('world!')
- obj.should_receive(:to_str).and_return("world!")
- a = 'hello '.send(@method, obj)
- a.should == 'hello world!'
- end
-
- it "raises a TypeError if the given argument can't be converted to a String" do
- lambda { 'hello '.send(@method, []) }.should raise_error(TypeError)
- lambda { 'hello '.send(@method, mock('x')) }.should raise_error(TypeError)
- end
-
- it "raises a RuntimeError when self is frozen" do
+ it "raises a FrozenError when self is frozen" do
a = "hello"
a.freeze
- lambda { a.send(@method, "") }.should raise_error(RuntimeError)
- lambda { a.send(@method, "test") }.should raise_error(RuntimeError)
+ -> { a.send(@method, "") }.should raise_error(FrozenError)
+ -> { a.send(@method, "test") }.should raise_error(FrozenError)
end
it "returns a String when given a subclass instance" do
@@ -39,18 +28,8 @@ describe :string_concat, shared: true do
str.should be_an_instance_of(StringSpecs::MyString)
end
- it "taints self if other is tainted" do
- "x".send(@method, "".taint).tainted?.should == true
- "x".send(@method, "y".taint).tainted?.should == true
- end
-
- it "untrusts self if other is untrusted" do
- "x".send(@method, "".untrust).untrusted?.should == true
- "x".send(@method, "y".untrust).untrusted?.should == true
- end
-
describe "with Integer" do
- it "concatencates the argument interpreted as a codepoint" do
+ it "concatenates the argument interpreted as a codepoint" do
b = "".send(@method, 33)
b.should == "!"
@@ -60,39 +39,39 @@ describe :string_concat, shared: true do
end
# #5855
- it "returns a ASCII-8BIT string if self is US-ASCII and the argument is between 128-255 (inclusive)" do
+ it "returns a BINARY string if self is US-ASCII and the argument is between 128-255 (inclusive)" do
a = ("".encode(Encoding::US_ASCII).send(@method, 128))
- a.encoding.should == Encoding::ASCII_8BIT
+ a.encoding.should == Encoding::BINARY
a.should == 128.chr
a = ("".encode(Encoding::US_ASCII).send(@method, 255))
- a.encoding.should == Encoding::ASCII_8BIT
+ a.encoding.should == Encoding::BINARY
a.should == 255.chr
end
it "raises RangeError if the argument is an invalid codepoint for self's encoding" do
- lambda { "".encode(Encoding::US_ASCII).send(@method, 256) }.should raise_error(RangeError)
- lambda { "".encode(Encoding::EUC_JP).send(@method, 0x81) }.should raise_error(RangeError)
+ -> { "".encode(Encoding::US_ASCII).send(@method, 256) }.should raise_error(RangeError)
+ -> { "".encode(Encoding::EUC_JP).send(@method, 0x81) }.should raise_error(RangeError)
end
it "raises RangeError if the argument is negative" do
- lambda { "".send(@method, -200) }.should raise_error(RangeError)
- lambda { "".send(@method, -bignum_value) }.should raise_error(RangeError)
+ -> { "".send(@method, -200) }.should raise_error(RangeError)
+ -> { "".send(@method, -bignum_value) }.should raise_error(RangeError)
end
it "doesn't call to_int on its argument" do
x = mock('x')
x.should_not_receive(:to_int)
- lambda { "".send(@method, x) }.should raise_error(TypeError)
+ -> { "".send(@method, x) }.should raise_error(TypeError)
end
- it "raises a RuntimeError when self is frozen" do
+ it "raises a FrozenError when self is frozen" do
a = "hello"
a.freeze
- lambda { a.send(@method, 0) }.should raise_error(RuntimeError)
- lambda { a.send(@method, 33) }.should raise_error(RuntimeError)
+ -> { a.send(@method, 0) }.should raise_error(FrozenError)
+ -> { a.send(@method, 33) }.should raise_error(FrozenError)
end
end
end
@@ -112,7 +91,7 @@ describe :string_concat_encoding, shared: true do
end
it "raises Encoding::CompatibilityError if neither are empty" do
- lambda { "x".encode("UTF-16LE").send(@method, "y".encode("UTF-8")) }.should raise_error(Encoding::CompatibilityError)
+ -> { "x".encode("UTF-16LE").send(@method, "y".encode("UTF-8")) }.should raise_error(Encoding::CompatibilityError)
end
end
@@ -130,7 +109,7 @@ describe :string_concat_encoding, shared: true do
end
it "raises Encoding::CompatibilityError if neither are empty" do
- lambda { "x".encode("UTF-8").send(@method, "y".encode("UTF-16LE")) }.should raise_error(Encoding::CompatibilityError)
+ -> { "x".encode("UTF-8").send(@method, "y".encode("UTF-16LE")) }.should raise_error(Encoding::CompatibilityError)
end
end
@@ -148,13 +127,33 @@ describe :string_concat_encoding, shared: true do
end
it "raises Encoding::CompatibilityError if neither are ASCII-only" do
- lambda { "\u00E9".encode("UTF-8").send(@method, "\u00E9".encode("ISO-8859-1")) }.should raise_error(Encoding::CompatibilityError)
+ -> { "\u00E9".encode("UTF-8").send(@method, "\u00E9".encode("ISO-8859-1")) }.should raise_error(Encoding::CompatibilityError)
end
end
- describe "when self is ASCII-8BIT and argument is US-ASCII" do
- it "uses ASCII-8BIT encoding" do
- "abc".encode("ASCII-8BIT").send(@method, "123".encode("US-ASCII")).encoding.should == Encoding::ASCII_8BIT
+ describe "when self is BINARY and argument is US-ASCII" do
+ it "uses BINARY encoding" do
+ "abc".encode("BINARY").send(@method, "123".encode("US-ASCII")).encoding.should == Encoding::BINARY
end
end
end
+
+describe :string_concat_type_coercion, shared: true do
+ it "converts the given argument to a String using to_str" do
+ obj = mock('world!')
+ obj.should_receive(:to_str).and_return("world!")
+ a = 'hello '.send(@method, obj)
+ a.should == 'hello world!'
+ end
+
+ it "raises a TypeError if the given argument can't be converted to a String" do
+ -> { 'hello '.send(@method, []) }.should raise_error(TypeError)
+ -> { 'hello '.send(@method, mock('x')) }.should raise_error(TypeError)
+ end
+
+ it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to a String" do
+ obj = mock('world!')
+ obj.should_receive(:to_str).and_raise(NoMethodError)
+ -> { 'hello '.send(@method, obj) }.should raise_error(NoMethodError)
+ end
+end
diff --git a/spec/ruby/core/string/shared/dedup.rb b/spec/ruby/core/string/shared/dedup.rb
new file mode 100644
index 0000000000..1ffd6aa0fd
--- /dev/null
+++ b/spec/ruby/core/string/shared/dedup.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: false
+describe :string_dedup, shared: true do
+ it 'returns self if the String is frozen' do
+ input = 'foo'.freeze
+ output = input.send(@method)
+
+ output.should equal(input)
+ output.should.frozen?
+ end
+
+ it 'returns a frozen copy if the String is not frozen' do
+ input = 'foo'
+ output = input.send(@method)
+
+ output.should.frozen?
+ output.should_not equal(input)
+ output.should == 'foo'
+ end
+
+ it "returns the same object for equal unfrozen strings" do
+ origin = "this is a string"
+ dynamic = %w(this is a string).join(' ')
+
+ origin.should_not equal(dynamic)
+ origin.send(@method).should equal(dynamic.send(@method))
+ end
+
+ it "returns the same object when it's called on the same String literal" do
+ "unfrozen string".send(@method).should equal("unfrozen string".send(@method))
+ "unfrozen string".send(@method).should_not equal("another unfrozen string".send(@method))
+ end
+
+ it "deduplicates frozen strings" do
+ dynamic = %w(this string is frozen).join(' ').freeze
+
+ dynamic.should_not equal("this string is frozen".freeze)
+
+ dynamic.send(@method).should equal("this string is frozen".freeze)
+ dynamic.send(@method).should equal("this string is frozen".send(@method).freeze)
+ end
+
+ it "does not deduplicate a frozen string when it has instance variables" do
+ dynamic = %w(this string is frozen).join(' ')
+ dynamic.instance_variable_set(:@a, 1)
+ dynamic.freeze
+
+ dynamic.send(@method).should_not equal("this string is frozen".freeze)
+ dynamic.send(@method).should_not equal("this string is frozen".send(@method).freeze)
+ dynamic.send(@method).should equal(dynamic)
+ end
+end
diff --git a/spec/ruby/core/string/shared/each_char_without_block.rb b/spec/ruby/core/string/shared/each_char_without_block.rb
index 40808cfd9f..397100ce0e 100644
--- a/spec/ruby/core/string/shared/each_char_without_block.rb
+++ b/spec/ruby/core/string/shared/each_char_without_block.rb
@@ -1,6 +1,6 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../../spec_helper', __FILE__)
-require File.expand_path('../../fixtures/classes', __FILE__)
+require_relative '../../../spec_helper'
+require_relative '../fixtures/classes'
describe :string_each_char_without_block, shared: true do
describe "when no block is given" do
diff --git a/spec/ruby/core/string/shared/each_codepoint_without_block.rb b/spec/ruby/core/string/shared/each_codepoint_without_block.rb
index 92b7f76032..c88e5c54c7 100644
--- a/spec/ruby/core/string/shared/each_codepoint_without_block.rb
+++ b/spec/ruby/core/string/shared/each_codepoint_without_block.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
describe :string_each_codepoint_without_block, shared: true do
describe "when no block is given" do
it "returns an Enumerator" do
@@ -6,7 +6,7 @@ describe :string_each_codepoint_without_block, shared: true do
end
it "returns an Enumerator even when self has an invalid encoding" do
- s = "\xDF".force_encoding(Encoding::UTF_8)
+ s = "\xDF".dup.force_encoding(Encoding::UTF_8)
s.valid_encoding?.should be_false
s.send(@method).should be_an_instance_of(Enumerator)
end
@@ -23,7 +23,7 @@ describe :string_each_codepoint_without_block, shared: true do
end
it "should return the size of the string even when the string has an invalid encoding" do
- s = "\xDF".force_encoding(Encoding::UTF_8)
+ s = "\xDF".dup.force_encoding(Encoding::UTF_8)
s.valid_encoding?.should be_false
s.send(@method).size.should == 1
end
diff --git a/spec/ruby/core/string/shared/each_line.rb b/spec/ruby/core/string/shared/each_line.rb
index dee741e270..231a6d9d4f 100644
--- a/spec/ruby/core/string/shared/each_line.rb
+++ b/spec/ruby/core/string/shared/each_line.rb
@@ -27,10 +27,17 @@ describe :string_each_line, shared: true do
c.should == ["hello\n", "\n", "\n", "world"]
end
- it "taints substrings that are passed to the block if self is tainted" do
- "one\ntwo\r\nthree".taint.send(@method) { |s| s.tainted?.should == true }
+ it "splits strings containing multibyte characters" do
+ s = <<~EOS
+ foo
+ 🤡🤡🤡🤡🤡🤡🤡
+ bar
+ baz
+ EOS
- "x.y.".send(@method, ".".taint) { |s| s.tainted?.should == false }
+ b = []
+ s.send(@method) { |part| b << part }
+ b.should == ["foo\n", "🤡🤡🤡🤡🤡🤡🤡\n", "bar\n", "baz\n"]
end
it "passes self as a whole to the block if the separator is nil" do
@@ -39,31 +46,15 @@ describe :string_each_line, shared: true do
a.should == ["one\ntwo\r\nthree"]
end
- ruby_version_is ''...'2.5' do
- it "yields paragraphs (broken by 2 or more successive newlines) when passed ''" do
- a = []
- "hello\nworld\n\n\nand\nuniverse\n\n\n\n\n".send(@method, '') { |s| a << s }
- a.should == ["hello\nworld\n\n\n", "and\nuniverse\n\n\n\n\n"]
-
- a = []
- "hello\nworld\n\n\nand\nuniverse\n\n\n\n\ndog".send(@method, '') { |s| a << s }
- a.should == ["hello\nworld\n\n\n", "and\nuniverse\n\n\n\n\n", "dog"]
- end
- end
-
-quarantine! do # Currently fails on Travis
- ruby_version_is '2.5' do
- it "yields paragraphs (broken by 2 or more successive newlines) when passed ''" do
- a = []
- "hello\nworld\n\n\nand\nuniverse\n\n\n\n\n".send(@method, '') { |s| a << s }
- a.should == ["hello\nworld\n\n", "and\nuniverse\n\n"]
+ it "yields paragraphs (broken by 2 or more successive newlines) when passed '' and replaces multiple newlines with only two ones" do
+ a = []
+ "hello\nworld\n\n\nand\nuniverse\n\n\n\n\n".send(@method, '') { |s| a << s }
+ a.should == ["hello\nworld\n\n", "and\nuniverse\n\n"]
- a = []
- "hello\nworld\n\n\nand\nuniverse\n\n\n\n\ndog".send(@method, '') { |s| a << s }
- a.should == ["hello\nworld\n\n", "and\nuniverse\n\n", "dog"]
- end
+ a = []
+ "hello\nworld\n\n\nand\nuniverse\n\n\n\n\ndog".send(@method, '') { |s| a << s }
+ a.should == ["hello\nworld\n\n", "and\nuniverse\n\n", "dog"]
end
-end
describe "uses $/" do
before :each do
@@ -71,7 +62,7 @@ end
end
after :each do
- $/ = @before_separator
+ suppress_warning {$/ = @before_separator}
end
it "as the separator when none is given" do
@@ -83,10 +74,10 @@ end
expected = []
str.send(@method, sep) { |x| expected << x }
- $/ = sep
+ suppress_warning {$/ = sep}
actual = []
- str.send(@method) { |x| actual << x }
+ suppress_warning {str.send(@method) { |x| actual << x }}
actual.should == expected
end
@@ -94,10 +85,10 @@ end
end
end
- it "yields subclass instances for subclasses" do
+ it "yields String instances for subclasses" do
a = []
StringSpecs::MyString.new("hello\nworld").send(@method) { |s| a << s.class }
- a.should == [StringSpecs::MyString, StringSpecs::MyString]
+ a.should == [String, String]
end
it "returns self" do
@@ -115,15 +106,21 @@ end
end
it "does not care if the string is modified while substituting" do
- str = "hello\nworld."
+ str = +"hello\nworld."
out = []
str.send(@method){|x| out << x; str[-1] = '!' }.should == "hello\nworld!"
out.should == ["hello\n", "world."]
end
+ it "returns Strings in the same encoding as self" do
+ "one\ntwo\r\nthree".encode("US-ASCII").send(@method) do |s|
+ s.encoding.should == Encoding::US_ASCII
+ end
+ end
+
it "raises a TypeError when the separator can't be converted to a string" do
- lambda { "hello world".send(@method, false) {} }.should raise_error(TypeError)
- lambda { "hello world".send(@method, mock('x')) {} }.should raise_error(TypeError)
+ -> { "hello world".send(@method, false) {} }.should raise_error(TypeError)
+ -> { "hello world".send(@method, mock('x')) {} }.should raise_error(TypeError)
end
it "accepts a string separator" do
@@ -131,20 +128,35 @@ end
end
it "raises a TypeError when the separator is a symbol" do
- lambda { "hello world".send(@method, :o).to_a }.should raise_error(TypeError)
+ -> { "hello world".send(@method, :o).to_a }.should raise_error(TypeError)
end
- ruby_version_is '2.4' do
- context "when `chomp` keyword argument is passed" do
- it "removes new line characters" do
- a = []
- "hello \nworld\n".send(@method, chomp: true) { |s| a << s }
- a.should == ["hello ", "world"]
+ context "when `chomp` keyword argument is passed" do
+ it "removes new line characters when separator is not specified" do
+ a = []
+ "hello \nworld\n".send(@method, chomp: true) { |s| a << s }
+ a.should == ["hello ", "world"]
- a = []
- "hello \r\nworld\r\n".send(@method, chomp: true) { |s| a << s }
- a.should == ["hello ", "world"]
- end
+ a = []
+ "hello \r\nworld\r\n".send(@method, chomp: true) { |s| a << s }
+ a.should == ["hello ", "world"]
+ end
+
+ it "removes only specified separator" do
+ a = []
+ "hello world".send(@method, ' ', chomp: true) { |s| a << s }
+ a.should == ["hello", "world"]
+ end
+
+ # https://bugs.ruby-lang.org/issues/14257
+ it "ignores new line characters when separator is specified" do
+ a = []
+ "hello\n world\n".send(@method, ' ', chomp: true) { |s| a << s }
+ a.should == ["hello\n", "world\n"]
+
+ a = []
+ "hello\r\n world\r\n".send(@method, ' ', chomp: true) { |s| a << s }
+ a.should == ["hello\r\n", "world\r\n"]
end
end
end
diff --git a/spec/ruby/core/string/shared/encode.rb b/spec/ruby/core/string/shared/encode.rb
index 71d46b1bd3..9466308886 100644
--- a/spec/ruby/core/string/shared/encode.rb
+++ b/spec/ruby/core/string/shared/encode.rb
@@ -1,4 +1,5 @@
# -*- encoding: utf-8 -*-
+# frozen_string_literal: false
describe :string_encode, shared: true do
describe "when passed no options" do
it "transcodes to Encoding.default_internal when set" do
@@ -8,20 +9,20 @@ describe :string_encode, shared: true do
end
it "transcodes a 7-bit String despite no generic converting being available" do
- lambda do
- Encoding::Converter.new Encoding::Emacs_Mule, Encoding::ASCII_8BIT
+ -> do
+ Encoding::Converter.new Encoding::Emacs_Mule, Encoding::BINARY
end.should raise_error(Encoding::ConverterNotFoundError)
Encoding.default_internal = Encoding::Emacs_Mule
- str = "\x79".force_encoding Encoding::ASCII_8BIT
+ str = "\x79".force_encoding Encoding::BINARY
- str.send(@method).should == "y".force_encoding(Encoding::ASCII_8BIT)
+ str.send(@method).should == "y".force_encoding(Encoding::BINARY)
end
it "raises an Encoding::ConverterNotFoundError when no conversion is possible" do
Encoding.default_internal = Encoding::Emacs_Mule
- str = [0x80].pack('C').force_encoding Encoding::ASCII_8BIT
- lambda { str.send(@method) }.should raise_error(Encoding::ConverterNotFoundError)
+ str = [0x80].pack('C').force_encoding Encoding::BINARY
+ -> { str.send(@method) }.should raise_error(Encoding::ConverterNotFoundError)
end
end
@@ -51,23 +52,23 @@ describe :string_encode, shared: true do
end
it "transcodes a 7-bit String despite no generic converting being available" do
- lambda do
- Encoding::Converter.new Encoding::Emacs_Mule, Encoding::ASCII_8BIT
+ -> do
+ Encoding::Converter.new Encoding::Emacs_Mule, Encoding::BINARY
end.should raise_error(Encoding::ConverterNotFoundError)
- str = "\x79".force_encoding Encoding::ASCII_8BIT
- str.send(@method, Encoding::Emacs_Mule).should == "y".force_encoding(Encoding::ASCII_8BIT)
+ str = "\x79".force_encoding Encoding::BINARY
+ str.send(@method, Encoding::Emacs_Mule).should == "y".force_encoding(Encoding::BINARY)
end
it "raises an Encoding::ConverterNotFoundError when no conversion is possible" do
- str = [0x80].pack('C').force_encoding Encoding::ASCII_8BIT
- lambda do
+ str = [0x80].pack('C').force_encoding Encoding::BINARY
+ -> do
str.send(@method, Encoding::Emacs_Mule)
end.should raise_error(Encoding::ConverterNotFoundError)
end
it "raises an Encoding::ConverterNotFoundError for an invalid encoding" do
- lambda do
+ -> do
"abc".send(@method, "xyz")
end.should raise_error(Encoding::ConverterNotFoundError)
end
@@ -83,7 +84,7 @@ describe :string_encode, shared: true do
options = mock("string encode options")
options.should_receive(:to_hash).and_return({ undef: :replace })
- result = "あ\ufffdあ".send(@method, options)
+ result = "あ\ufffdあ".send(@method, **options)
result.should == "あ\ufffdあ"
end
@@ -95,8 +96,8 @@ describe :string_encode, shared: true do
it "raises an Encoding::ConverterNotFoundError when no conversion is possible despite 'invalid: :replace, undef: :replace'" do
Encoding.default_internal = Encoding::Emacs_Mule
- str = [0x80].pack('C').force_encoding Encoding::ASCII_8BIT
- lambda do
+ str = [0x80].pack('C').force_encoding Encoding::BINARY
+ -> do
str.send(@method, invalid: :replace, undef: :replace)
end.should raise_error(Encoding::ConverterNotFoundError)
end
@@ -145,7 +146,7 @@ describe :string_encode, shared: true do
options = mock("string encode options")
options.should_receive(:to_hash).and_return({ undef: :replace })
- result = "あ?あ".send(@method, Encoding::EUC_JP, options)
+ result = "あ?あ".send(@method, Encoding::EUC_JP, **options)
xA4xA2 = [0xA4, 0xA2].pack('CC').force_encoding('utf-8')
result.should == "#{xA4xA2}?#{xA4xA2}".force_encoding("euc-jp")
end
@@ -153,7 +154,7 @@ describe :string_encode, shared: true do
describe "when passed to, from, options" do
it "replaces undefined characters in the destination encoding" do
- str = "あ?あ".force_encoding Encoding::ASCII_8BIT
+ str = "あ?あ".force_encoding Encoding::BINARY
result = str.send(@method, "euc-jp", "utf-8", undef: :replace)
xA4xA2 = [0xA4, 0xA2].pack('CC').force_encoding('utf-8')
result.should == "#{xA4xA2}?#{xA4xA2}".force_encoding("euc-jp")
@@ -161,7 +162,7 @@ describe :string_encode, shared: true do
it "replaces invalid characters in the destination encoding" do
xFF = [0xFF].pack('C').force_encoding('utf-8')
- str = "ab#{xFF}c".force_encoding Encoding::ASCII_8BIT
+ str = "ab#{xFF}c".force_encoding Encoding::BINARY
str.send(@method, "iso-8859-1", "utf-8", invalid: :replace).should == "ab?c"
end
@@ -170,7 +171,7 @@ describe :string_encode, shared: true do
to.should_receive(:to_str).and_return("iso-8859-1")
xFF = [0xFF].pack('C').force_encoding('utf-8')
- str = "ab#{xFF}c".force_encoding Encoding::ASCII_8BIT
+ str = "ab#{xFF}c".force_encoding Encoding::BINARY
str.send(@method, to, "utf-8", invalid: :replace).should == "ab?c"
end
@@ -179,7 +180,7 @@ describe :string_encode, shared: true do
from.should_receive(:to_str).and_return("utf-8")
xFF = [0xFF].pack('C').force_encoding('utf-8')
- str = "ab#{xFF}c".force_encoding Encoding::ASCII_8BIT
+ str = "ab#{xFF}c".force_encoding Encoding::BINARY
str.send(@method, "iso-8859-1", from, invalid: :replace).should == "ab?c"
end
@@ -188,8 +189,192 @@ describe :string_encode, shared: true do
options.should_receive(:to_hash).and_return({ invalid: :replace })
xFF = [0xFF].pack('C').force_encoding('utf-8')
- str = "ab#{xFF}c".force_encoding Encoding::ASCII_8BIT
- str.send(@method, "iso-8859-1", "utf-8", options).should == "ab?c"
+ str = "ab#{xFF}c".force_encoding Encoding::BINARY
+ str.send(@method, "iso-8859-1", "utf-8", **options).should == "ab?c"
+ end
+ end
+
+ describe "given the fallback option" do
+ context "given a hash" do
+ it "looks up the replacement value from the hash" do
+ encoded = "B\ufffd".encode(Encoding::US_ASCII, fallback: { "\ufffd" => "bar" })
+ encoded.should == "Bbar"
+ end
+
+ it "calls to_str on the returned value" do
+ obj = Object.new
+ obj.should_receive(:to_str).and_return("bar")
+ encoded = "B\ufffd".encode(Encoding::US_ASCII, fallback: { "\ufffd" => obj })
+ encoded.should == "Bbar"
+ end
+
+ it "does not call to_s on the returned value" do
+ obj = Object.new
+ obj.should_not_receive(:to_s)
+ -> {
+ "B\ufffd".encode(Encoding::US_ASCII, fallback: { "\ufffd" => obj })
+ }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ end
+
+ it "raises an error if the key is not present in the hash" do
+ -> {
+ "B\ufffd".encode(Encoding::US_ASCII, fallback: { "foo" => "bar" })
+ }.should raise_error(Encoding::UndefinedConversionError, "U+FFFD from UTF-8 to US-ASCII")
+ end
+
+ it "raises an error if the value is itself invalid" do
+ -> {
+ "B\ufffd".encode(Encoding::US_ASCII, fallback: { "\ufffd" => "\uffee" })
+ }.should raise_error(ArgumentError, "too big fallback string")
+ end
+
+ it "uses the hash's default value if set" do
+ hash = {}
+ hash.default = "bar"
+ encoded = "B\ufffd".encode(Encoding::US_ASCII, fallback: hash)
+ encoded.should == "Bbar"
+ end
+
+ it "uses the result of calling default_proc if set" do
+ hash = {}
+ hash.default_proc = -> _, _ { "bar" }
+ encoded = "B\ufffd".encode(Encoding::US_ASCII, fallback: hash)
+ encoded.should == "Bbar"
+ end
+ end
+
+ context "given an object inheriting from Hash" do
+ before do
+ klass = Class.new(Hash)
+ @hash_like = klass.new
+ @hash_like["\ufffd"] = "bar"
+ end
+
+ it "looks up the replacement value from the object" do
+ encoded = "B\ufffd".encode(Encoding::US_ASCII, fallback: @hash_like)
+ encoded.should == "Bbar"
+ end
+ end
+
+ context "given an object responding to []" do
+ before do
+ klass = Class.new do
+ def [](c) = c.bytes.inspect
+ end
+ @hash_like = klass.new
+ end
+
+ it "calls [] on the object, passing the invalid character" do
+ encoded = "B\ufffd".encode(Encoding::US_ASCII, fallback: @hash_like)
+ encoded.should == "B[239, 191, 189]"
+ end
+ end
+
+ context "given an object not responding to []" do
+ before do
+ @non_hash_like = Object.new
+ end
+
+ it "raises an error" do
+ -> {
+ "B\ufffd".encode(Encoding::US_ASCII, fallback: @non_hash_like)
+ }.should raise_error(Encoding::UndefinedConversionError, "U+FFFD from UTF-8 to US-ASCII")
+ end
+ end
+
+ context "given a proc" do
+ it "calls the proc to get the replacement value, passing in the invalid character" do
+ encoded = "B\ufffd".encode(Encoding::US_ASCII, fallback: proc { |c| c.bytes.inspect })
+ encoded.should == "B[239, 191, 189]"
+ end
+
+ it "calls to_str on the returned value" do
+ obj = Object.new
+ obj.should_receive(:to_str).and_return("bar")
+ encoded = "B\ufffd".encode(Encoding::US_ASCII, fallback: proc { |c| obj })
+ encoded.should == "Bbar"
+ end
+
+ it "does not call to_s on the returned value" do
+ obj = Object.new
+ obj.should_not_receive(:to_s)
+ -> {
+ "B\ufffd".encode(Encoding::US_ASCII, fallback: proc { |c| obj })
+ }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ end
+
+ it "raises an error if the returned value is itself invalid" do
+ -> {
+ "B\ufffd".encode(Encoding::US_ASCII, fallback: -> c { "\uffee" })
+ }.should raise_error(ArgumentError, "too big fallback string")
+ end
+ end
+
+ context "given a lambda" do
+ it "calls the lambda to get the replacement value, passing in the invalid character" do
+ encoded = "B\ufffd".encode(Encoding::US_ASCII, fallback: -> c { c.bytes.inspect })
+ encoded.should == "B[239, 191, 189]"
+ end
+
+ it "calls to_str on the returned value" do
+ obj = Object.new
+ obj.should_receive(:to_str).and_return("bar")
+ encoded = "B\ufffd".encode(Encoding::US_ASCII, fallback: -> c { obj })
+ encoded.should == "Bbar"
+ end
+
+ it "does not call to_s on the returned value" do
+ obj = Object.new
+ obj.should_not_receive(:to_s)
+ -> {
+ "B\ufffd".encode(Encoding::US_ASCII, fallback: -> c { obj })
+ }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ end
+
+ it "raises an error if the returned value is itself invalid" do
+ -> {
+ "B\ufffd".encode(Encoding::US_ASCII, fallback: -> c { "\uffee" })
+ }.should raise_error(ArgumentError, "too big fallback string")
+ end
+ end
+
+ context "given a method" do
+ def replace(c) = c.bytes.inspect
+ def replace_bad(c) = "\uffee"
+
+ def replace_to_str(c)
+ obj = Object.new
+ obj.should_receive(:to_str).and_return("bar")
+ obj
+ end
+
+ def replace_to_s(c)
+ obj = Object.new
+ obj.should_not_receive(:to_s)
+ obj
+ end
+
+ it "calls the method to get the replacement value, passing in the invalid character" do
+ encoded = "B\ufffd".encode(Encoding::US_ASCII, fallback: method(:replace))
+ encoded.should == "B[239, 191, 189]"
+ end
+
+ it "calls to_str on the returned value" do
+ encoded = "B\ufffd".encode(Encoding::US_ASCII, fallback: method(:replace_to_str))
+ encoded.should == "Bbar"
+ end
+
+ it "does not call to_s on the returned value" do
+ -> {
+ "B\ufffd".encode(Encoding::US_ASCII, fallback: method(:replace_to_s))
+ }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ end
+
+ it "raises an error if the returned value is itself invalid" do
+ -> {
+ "B\ufffd".encode(Encoding::US_ASCII, fallback: method(:replace_bad))
+ }.should raise_error(ArgumentError, "too big fallback string")
+ end
end
end
@@ -242,6 +427,6 @@ describe :string_encode, shared: true do
end
it "raises ArgumentError if the value of the :xml option is not :text or :attr" do
- lambda { ''.send(@method, "UTF-8", xml: :other) }.should raise_error(ArgumentError)
+ -> { ''.send(@method, "UTF-8", xml: :other) }.should raise_error(ArgumentError)
end
end
diff --git a/spec/ruby/core/string/shared/eql.rb b/spec/ruby/core/string/shared/eql.rb
index 92dfa91923..d5af337d53 100644
--- a/spec/ruby/core/string/shared/eql.rb
+++ b/spec/ruby/core/string/shared/eql.rb
@@ -1,6 +1,6 @@
-# -*- encoding: binary -*-
-require File.expand_path('../../../../spec_helper', __FILE__)
-require File.expand_path('../../fixtures/classes', __FILE__)
+# encoding: binary
+require_relative '../../../spec_helper'
+require_relative '../fixtures/classes'
describe :string_eql_value, shared: true do
it "returns true if self <=> string returns 0" do
@@ -13,15 +13,15 @@ describe :string_eql_value, shared: true do
end
it "ignores encoding difference of compatible string" do
- "hello".force_encoding("utf-8").send(@method, "hello".force_encoding("iso-8859-1")).should be_true
+ "hello".dup.force_encoding("utf-8").send(@method, "hello".dup.force_encoding("iso-8859-1")).should be_true
end
it "considers encoding difference of incompatible string" do
- "\xff".force_encoding("utf-8").send(@method, "\xff".force_encoding("iso-8859-1")).should be_false
+ "\xff".dup.force_encoding("utf-8").send(@method, "\xff".dup.force_encoding("iso-8859-1")).should be_false
end
it "considers encoding compatibility" do
- "hello".force_encoding("utf-8").send(@method, "hello".force_encoding("utf-32le")).should be_false
+ "abcd".dup.force_encoding("utf-8").send(@method, "abcd".dup.force_encoding("utf-32le")).should be_false
end
it "ignores subclass differences" do
@@ -31,4 +31,8 @@ describe :string_eql_value, shared: true do
a.send(@method, b).should be_true
b.send(@method, a).should be_true
end
+
+ it "returns true when comparing 2 empty strings but one is not ASCII-compatible" do
+ "".send(@method, "".dup.force_encoding('iso-2022-jp')).should == true
+ end
end
diff --git a/spec/ruby/core/string/shared/equal_value.rb b/spec/ruby/core/string/shared/equal_value.rb
index 6df76478c7..fccafb5821 100644
--- a/spec/ruby/core/string/shared/equal_value.rb
+++ b/spec/ruby/core/string/shared/equal_value.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
-require File.expand_path('../../fixtures/classes', __FILE__)
+require_relative '../../../spec_helper'
+require_relative '../fixtures/classes'
describe :string_equal_value, shared: true do
it "returns false if obj does not respond to to_str" do
@@ -17,7 +17,7 @@ describe :string_equal_value, shared: true do
# not call it.
obj.stub!(:to_str)
- # Don't use @method for :== in `obj.should_recerive(:==)`
+ # Don't use @method for :== in `obj.should_receive(:==)`
obj.should_receive(:==).and_return(true)
'hello'.send(@method, obj).should be_true
diff --git a/spec/ruby/core/string/shared/grapheme_clusters.rb b/spec/ruby/core/string/shared/grapheme_clusters.rb
new file mode 100644
index 0000000000..8b666868b1
--- /dev/null
+++ b/spec/ruby/core/string/shared/grapheme_clusters.rb
@@ -0,0 +1,16 @@
+require_relative '../../../spec_helper'
+require_relative '../fixtures/classes'
+
+describe :string_grapheme_clusters, shared: true do
+ it "passes each grapheme cluster in self to the given block" do
+ a = []
+ # test string: abc[rainbow flag emoji][paw prints]
+ "ab\u{1f3f3}\u{fe0f}\u{200d}\u{1f308}\u{1F43E}".send(@method) { |c| a << c }
+ a.should == ['a', 'b', "\u{1f3f3}\u{fe0f}\u{200d}\u{1f308}", "\u{1F43E}"]
+ end
+
+ it "returns self" do
+ s = StringSpecs::MyString.new "ab\u{1f3f3}\u{fe0f}\u{200d}\u{1f308}\u{1F43E}"
+ s.send(@method) {}.should equal(s)
+ end
+end
diff --git a/spec/ruby/core/string/shared/length.rb b/spec/ruby/core/string/shared/length.rb
index 0e6e66ee1c..ae572ba755 100644
--- a/spec/ruby/core/string/shared/length.rb
+++ b/spec/ruby/core/string/shared/length.rb
@@ -10,19 +10,46 @@ describe :string_length, shared: true do
"four".send(@method).should == 4
end
- with_feature :encoding do
- it "returns the length of a string in different encodings" do
- utf8_str = 'こにちわ' * 100
- utf8_str.size.should == 400
- utf8_str.encode(Encoding::UTF_32BE).size.should == 400
- utf8_str.encode(Encoding::SHIFT_JIS).size.should == 400
- end
-
- it "returns the length of the new self after encoding is changed" do
- str = 'こにちわ'
- str.send(@method)
-
- str.force_encoding('ASCII-8BIT').send(@method).should == 12
- end
+ it "returns the length of a string in different encodings" do
+ utf8_str = 'こにちわ' * 100
+ utf8_str.send(@method).should == 400
+ utf8_str.encode(Encoding::UTF_32BE).send(@method).should == 400
+ utf8_str.encode(Encoding::SHIFT_JIS).send(@method).should == 400
+ end
+
+ it "returns the length of the new self after encoding is changed" do
+ str = +'こにちわ'
+ str.send(@method)
+
+ str.force_encoding('BINARY').send(@method).should == 12
+ end
+
+ it "returns the correct length after force_encoding(BINARY)" do
+ utf8 = "あ"
+ ascii = "a"
+ concat = utf8 + ascii
+
+ concat.encoding.should == Encoding::UTF_8
+ concat.bytesize.should == 4
+
+ concat.send(@method).should == 2
+ concat.force_encoding(Encoding::ASCII_8BIT)
+ concat.send(@method).should == 4
+ end
+
+ it "adds 1 for every invalid byte in UTF-8" do
+ "\xF4\x90\x80\x80".send(@method).should == 4
+ "a\xF4\x90\x80\x80b".send(@method).should == 6
+ "é\xF4\x90\x80\x80è".send(@method).should == 6
+ end
+
+ it "adds 1 (and not 2) for a incomplete surrogate in UTF-16" do
+ "\x00\xd8".dup.force_encoding("UTF-16LE").send(@method).should == 1
+ "\xd8\x00".dup.force_encoding("UTF-16BE").send(@method).should == 1
+ end
+
+ it "adds 1 for a broken sequence in UTF-32" do
+ "\x04\x03\x02\x01".dup.force_encoding("UTF-32LE").send(@method).should == 1
+ "\x01\x02\x03\x04".dup.force_encoding("UTF-32BE").send(@method).should == 1
end
end
diff --git a/spec/ruby/core/string/shared/partition.rb b/spec/ruby/core/string/shared/partition.rb
new file mode 100644
index 0000000000..4cac149ce5
--- /dev/null
+++ b/spec/ruby/core/string/shared/partition.rb
@@ -0,0 +1,33 @@
+require_relative '../../../spec_helper'
+require_relative '../fixtures/classes'
+
+describe :string_partition, shared: true do
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("hello").send(@method, "l").each do |item|
+ item.should be_an_instance_of(String)
+ end
+
+ StringSpecs::MyString.new("hello").send(@method, "x").each do |item|
+ item.should be_an_instance_of(String)
+ end
+
+ StringSpecs::MyString.new("hello").send(@method, /l./).each do |item|
+ item.should be_an_instance_of(String)
+ end
+ end
+
+ it "returns before- and after- parts in the same encoding as self" do
+ strings = "hello".encode("US-ASCII").send(@method, "ello")
+ strings[0].encoding.should == Encoding::US_ASCII
+ strings[2].encoding.should == Encoding::US_ASCII
+
+ strings = "hello".encode("US-ASCII").send(@method, /ello/)
+ strings[0].encoding.should == Encoding::US_ASCII
+ strings[2].encoding.should == Encoding::US_ASCII
+ end
+
+ it "returns the matching part in the separator's encoding" do
+ strings = "hello".encode("US-ASCII").send(@method, "ello")
+ strings[1].encoding.should == Encoding::UTF_8
+ end
+end
diff --git a/spec/ruby/core/string/shared/replace.rb b/spec/ruby/core/string/shared/replace.rb
index 9f5446fbbe..24dac0eb27 100644
--- a/spec/ruby/core/string/shared/replace.rb
+++ b/spec/ruby/core/string/shared/replace.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: false
describe :string_replace, shared: true do
it "returns self" do
a = "a"
@@ -10,34 +11,6 @@ describe :string_replace, shared: true do
a.should == "another string"
end
- it "taints self if other is tainted" do
- a = ""
- b = "".taint
- a.send(@method, b)
- a.tainted?.should == true
- end
-
- it "does not untaint self if other is untainted" do
- a = "".taint
- b = ""
- a.send(@method, b)
- a.tainted?.should == true
- end
-
- it "untrusts self if other is untrusted" do
- a = ""
- b = "".untrust
- a.send(@method, b)
- a.untrusted?.should == true
- end
-
- it "does not trust self if other is trusted" do
- a = "".untrust
- b = ""
- a.send(@method, b)
- a.untrusted?.should == true
- end
-
it "replaces the encoding of self with that of other" do
a = "".encode("UTF-16LE")
b = "".encode("UTF-8")
@@ -57,19 +30,19 @@ describe :string_replace, shared: true do
end
it "raises a TypeError if other can't be converted to string" do
- lambda { "hello".send(@method, 123) }.should raise_error(TypeError)
- lambda { "hello".send(@method, []) }.should raise_error(TypeError)
- lambda { "hello".send(@method, mock('x')) }.should raise_error(TypeError)
+ -> { "hello".send(@method, 123) }.should raise_error(TypeError)
+ -> { "hello".send(@method, []) }.should raise_error(TypeError)
+ -> { "hello".send(@method, mock('x')) }.should raise_error(TypeError)
end
- it "raises a RuntimeError on a frozen instance that is modified" do
+ it "raises a FrozenError on a frozen instance that is modified" do
a = "hello".freeze
- lambda { a.send(@method, "world") }.should raise_error(RuntimeError)
+ -> { a.send(@method, "world") }.should raise_error(FrozenError)
end
# see [ruby-core:23666]
- it "raises a RuntimeError on a frozen instance when self-replacing" do
+ it "raises a FrozenError on a frozen instance when self-replacing" do
a = "hello".freeze
- lambda { a.send(@method, a) }.should raise_error(RuntimeError)
+ -> { a.send(@method, a) }.should raise_error(FrozenError)
end
end
diff --git a/spec/ruby/core/string/shared/slice.rb b/spec/ruby/core/string/shared/slice.rb
index 697fa2e530..7b9b9f6a14 100644
--- a/spec/ruby/core/string/shared/slice.rb
+++ b/spec/ruby/core/string/shared/slice.rb
@@ -21,17 +21,17 @@ describe :string_slice, shared: true do
end
it "raises a TypeError if the given index is nil" do
- lambda { "hello".send(@method, nil) }.should raise_error(TypeError)
+ -> { "hello".send(@method, nil) }.should raise_error(TypeError)
end
it "raises a TypeError if the given index can't be converted to an Integer" do
- lambda { "hello".send(@method, mock('x')) }.should raise_error(TypeError)
- lambda { "hello".send(@method, {}) }.should raise_error(TypeError)
- lambda { "hello".send(@method, []) }.should raise_error(TypeError)
+ -> { "hello".send(@method, mock('x')) }.should raise_error(TypeError)
+ -> { "hello".send(@method, {}) }.should raise_error(TypeError)
+ -> { "hello".send(@method, []) }.should raise_error(TypeError)
end
it "raises a RangeError if the index is too big" do
- lambda { "hello".send(@method, bignum_value) }.should raise_error(RangeError)
+ -> { "hello".send(@method, bignum_value) }.should raise_error(RangeError)
end
end
@@ -80,21 +80,12 @@ describe :string_slice_index_length, shared: true do
"hello there".send(@method, -3,2).should == "er"
end
- it "always taints resulting strings when self is tainted" do
- str = "hello world"
- str.taint
-
- str.send(@method, 0,0).tainted?.should == true
- str.send(@method, 0,1).tainted?.should == true
- str.send(@method, 2,1).tainted?.should == true
- end
-
- it "returns a string with the same encoding" do
+ it "returns a string with the same encoding as self" do
s = "hello there"
s.send(@method, 1, 9).encoding.should == s.encoding
- a = "hello".force_encoding("binary")
- b = " there".force_encoding("ISO-8859-1")
+ a = "hello".dup.force_encoding("binary")
+ b = " there".dup.force_encoding("ISO-8859-1")
c = (a + b).force_encoding(Encoding::US_ASCII)
c.send(@method, 0, 5).encoding.should == Encoding::US_ASCII
@@ -119,6 +110,8 @@ describe :string_slice_index_length, shared: true do
"x".send(@method, -2,0).should == nil
"x".send(@method, -2,1).should == nil
+
+ "x".send(@method, fixnum_max, 1).should == nil
end
it "returns nil if the length is negative" do
@@ -126,6 +119,18 @@ describe :string_slice_index_length, shared: true do
"hello there".send(@method, -4,-3).should == nil
end
+ platform_is pointer_size: 64 do
+ it "returns nil if the length is negative big value" do
+ "hello there".send(@method, 4, -(1 << 31)).should == nil
+
+ # by some reason length < -(1 << 31) on CI on Windows leads to
+ # 'RangeError: bignum too big to convert into `long'' error
+ platform_is_not :windows do
+ "hello there".send(@method, 4, -(1 << 63)).should == nil
+ end
+ end
+ end
+
it "calls to_int on the given index and the given length" do
"hello".send(@method, 0.5, 1).should == "h"
"hello".send(@method, 0.5, 2.5).should == "he"
@@ -140,30 +145,35 @@ describe :string_slice_index_length, shared: true do
end
it "raises a TypeError when idx or length can't be converted to an integer" do
- lambda { "hello".send(@method, mock('x'), 0) }.should raise_error(TypeError)
- lambda { "hello".send(@method, 0, mock('x')) }.should raise_error(TypeError)
+ -> { "hello".send(@method, mock('x'), 0) }.should raise_error(TypeError)
+ -> { "hello".send(@method, 0, mock('x')) }.should raise_error(TypeError)
# I'm deliberately including this here.
# It means that str.send(@method, other, idx) isn't supported.
- lambda { "hello".send(@method, "", 0) }.should raise_error(TypeError)
+ -> { "hello".send(@method, "", 0) }.should raise_error(TypeError)
end
it "raises a TypeError when the given index or the given length is nil" do
- lambda { "hello".send(@method, 1, nil) }.should raise_error(TypeError)
- lambda { "hello".send(@method, nil, 1) }.should raise_error(TypeError)
- lambda { "hello".send(@method, nil, nil) }.should raise_error(TypeError)
+ -> { "hello".send(@method, 1, nil) }.should raise_error(TypeError)
+ -> { "hello".send(@method, nil, 1) }.should raise_error(TypeError)
+ -> { "hello".send(@method, nil, nil) }.should raise_error(TypeError)
end
it "raises a RangeError if the index or length is too big" do
- lambda { "hello".send(@method, bignum_value, 1) }.should raise_error(RangeError)
- lambda { "hello".send(@method, 0, bignum_value) }.should raise_error(RangeError)
+ -> { "hello".send(@method, bignum_value, 1) }.should raise_error(RangeError)
+ -> { "hello".send(@method, 0, bignum_value) }.should raise_error(RangeError)
+ end
+
+ it "raises a RangeError if the index or length is too small" do
+ -> { "hello".send(@method, -bignum_value, 1) }.should raise_error(RangeError)
+ -> { "hello".send(@method, 0, -bignum_value) }.should raise_error(RangeError)
end
- it "returns subclass instances" do
+ it "returns String instances" do
s = StringSpecs::MyString.new("hello")
- s.send(@method, 0,0).should be_an_instance_of(StringSpecs::MyString)
- s.send(@method, 0,4).should be_an_instance_of(StringSpecs::MyString)
- s.send(@method, 1,4).should be_an_instance_of(StringSpecs::MyString)
+ s.send(@method, 0,0).should be_an_instance_of(String)
+ s.send(@method, 0,4).should be_an_instance_of(String)
+ s.send(@method, 1,4).should be_an_instance_of(String)
end
it "handles repeated application" do
@@ -202,6 +212,10 @@ describe :string_slice_range, shared: true do
"x".send(@method, 1..-1).should == ""
end
+ it "returns a String in the same encoding as self" do
+ "hello there".encode("US-ASCII").send(@method, 1..1).encoding.should == Encoding::US_ASCII
+ end
+
it "returns nil if the beginning of the range falls outside of self" do
"hello there".send(@method, 12..-1).should == nil
"hello there".send(@method, 20..25).should == nil
@@ -234,23 +248,11 @@ describe :string_slice_range, shared: true do
"x".send(@method, 1...-1).should == ""
end
- it "always taints resulting strings when self is tainted" do
- str = "hello world"
- str.taint
-
- str.send(@method, 0..0).tainted?.should == true
- str.send(@method, 0...0).tainted?.should == true
- str.send(@method, 0..1).tainted?.should == true
- str.send(@method, 0...1).tainted?.should == true
- str.send(@method, 2..3).tainted?.should == true
- str.send(@method, 2..0).tainted?.should == true
- end
-
- it "returns subclass instances" do
+ it "returns String instances" do
s = StringSpecs::MyString.new("hello")
- s.send(@method, 0...0).should be_an_instance_of(StringSpecs::MyString)
- s.send(@method, 0..4).should be_an_instance_of(StringSpecs::MyString)
- s.send(@method, 1..4).should be_an_instance_of(StringSpecs::MyString)
+ s.send(@method, 0...0).should be_an_instance_of(String)
+ s.send(@method, 0..4).should be_an_instance_of(String)
+ s.send(@method, 1..4).should be_an_instance_of(String)
end
it "calls to_int on range arguments" do
@@ -289,6 +291,30 @@ describe :string_slice_range, shared: true do
"hello world".send(@method, 6..5).send(@method, -1..-1).should == nil
"hello world".send(@method, 6..5).send(@method, 1..1).should == nil
end
+
+ it "raises a type error if a range is passed with a length" do
+ ->{ "hello".send(@method, 1..2, 1) }.should raise_error(TypeError)
+ end
+
+ it "raises a RangeError if one of the bound is too big" do
+ -> { "hello".send(@method, bignum_value..(bignum_value + 1)) }.should raise_error(RangeError)
+ -> { "hello".send(@method, 0..bignum_value) }.should raise_error(RangeError)
+ end
+
+ it "works with endless ranges" do
+ "hello there".send(@method, eval("(2..)")).should == "llo there"
+ "hello there".send(@method, eval("(2...)")).should == "llo there"
+ "hello there".send(@method, eval("(-4..)")).should == "here"
+ "hello there".send(@method, eval("(-4...)")).should == "here"
+ end
+
+ it "works with beginless ranges" do
+ "hello there".send(@method, (..5)).should == "hello "
+ "hello there".send(@method, (...5)).should == "hello"
+ "hello there".send(@method, (..-4)).should == "hello th"
+ "hello there".send(@method, (...-4)).should == "hello t"
+ "hello there".send(@method, (...nil)).should == "hello there"
+ end
end
describe :string_slice_regexp, shared: true do
@@ -301,31 +327,14 @@ describe :string_slice_regexp, shared: true do
"hello there".send(@method, /xyz/).should == nil
end
- not_supported_on :opal do
- it "always taints resulting strings when self or regexp is tainted" do
- strs = ["hello world"]
- strs += strs.map { |s| s.dup.taint }
-
- strs.each do |str|
- str.send(@method, //).tainted?.should == str.tainted?
- str.send(@method, /hello/).tainted?.should == str.tainted?
-
- tainted_re = /./
- tainted_re.taint
-
- str.send(@method, tainted_re).tainted?.should == true
- end
- end
-
- it "returns an untrusted string if the regexp is untrusted" do
- "hello".send(@method, /./.untrust).untrusted?.should be_true
- end
+ it "returns a String in the same encoding as self" do
+ "hello there".encode("US-ASCII").send(@method, /[aeiou](.)\1/).encoding.should == Encoding::US_ASCII
end
- it "returns subclass instances" do
+ it "returns String instances" do
s = StringSpecs::MyString.new("hello")
- s.send(@method, //).should be_an_instance_of(StringSpecs::MyString)
- s.send(@method, /../).should be_an_instance_of(StringSpecs::MyString)
+ s.send(@method, //).should be_an_instance_of(String)
+ s.send(@method, /../).should be_an_instance_of(String)
end
it "sets $~ to MatchData when there is a match and nil when there's none" do
@@ -352,42 +361,28 @@ describe :string_slice_regexp_index, shared: true do
"har".send(@method, /(.)(.)(.)/, -3).should == "h"
end
- it "always taints resulting strings when self or regexp is tainted" do
- strs = ["hello world"]
- strs += strs.map { |s| s.dup.taint }
-
- strs.each do |str|
- str.send(@method, //, 0).tainted?.should == str.tainted?
- str.send(@method, /hello/, 0).tainted?.should == str.tainted?
-
- str.send(@method, /(.)(.)(.)/, 0).tainted?.should == str.tainted?
- str.send(@method, /(.)(.)(.)/, 1).tainted?.should == str.tainted?
- str.send(@method, /(.)(.)(.)/, -1).tainted?.should == str.tainted?
- str.send(@method, /(.)(.)(.)/, -2).tainted?.should == str.tainted?
-
- tainted_re = /(.)(.)(.)/
- tainted_re.taint
+ it "returns nil if there is no match" do
+ "hello there".send(@method, /(what?)/, 1).should == nil
+ end
- str.send(@method, tainted_re, 0).tainted?.should == true
- str.send(@method, tainted_re, 1).tainted?.should == true
- str.send(@method, tainted_re, -1).tainted?.should == true
- end
+ it "returns nil if the index is larger than the number of captures" do
+ "hello there".send(@method, /hello (.)/, 2).should == nil
+ # You can't refer to 0 using negative indices
+ "hello there".send(@method, /hello (.)/, -2).should == nil
end
- not_supported_on :opal do
- it "returns an untrusted string if the regexp is untrusted" do
- "hello".send(@method, /(.)/.untrust, 1).untrusted?.should be_true
- end
+ it "returns nil if there is no capture for the given index" do
+ "hello there".send(@method, /[aeiou](.)\1/, 2).should == nil
end
- it "returns nil if there is no match" do
- "hello there".send(@method, /(what?)/, 1).should == nil
+ it "returns nil if the given capture group was not matched but still sets $~" do
+ "test".send(@method, /te(z)?/, 1).should == nil
+ $~[0].should == "te"
+ $~[1].should == nil
end
- it "returns nil if there is no capture for the given index" do
- "hello there".send(@method, /[aeiou](.)\1/, 2).should == nil
- # You can't refer to 0 using negative indices
- "hello there".send(@method, /[aeiou](.)\1/, -2).should == nil
+ it "returns a String in the same encoding as self" do
+ "hello there".encode("US-ASCII").send(@method, /[aeiou](.)\1/, 0).encoding.should == Encoding::US_ASCII
end
it "calls to_int on the given index" do
@@ -399,19 +394,19 @@ describe :string_slice_regexp_index, shared: true do
end
it "raises a TypeError when the given index can't be converted to Integer" do
- lambda { "hello".send(@method, /(.)(.)(.)/, mock('x')) }.should raise_error(TypeError)
- lambda { "hello".send(@method, /(.)(.)(.)/, {}) }.should raise_error(TypeError)
- lambda { "hello".send(@method, /(.)(.)(.)/, []) }.should raise_error(TypeError)
+ -> { "hello".send(@method, /(.)(.)(.)/, mock('x')) }.should raise_error(TypeError)
+ -> { "hello".send(@method, /(.)(.)(.)/, {}) }.should raise_error(TypeError)
+ -> { "hello".send(@method, /(.)(.)(.)/, []) }.should raise_error(TypeError)
end
it "raises a TypeError when the given index is nil" do
- lambda { "hello".send(@method, /(.)(.)(.)/, nil) }.should raise_error(TypeError)
+ -> { "hello".send(@method, /(.)(.)(.)/, nil) }.should raise_error(TypeError)
end
- it "returns subclass instances" do
+ it "returns String instances" do
s = StringSpecs::MyString.new("hello")
- s.send(@method, /(.)(.)/, 0).should be_an_instance_of(StringSpecs::MyString)
- s.send(@method, /(.)(.)/, 1).should be_an_instance_of(StringSpecs::MyString)
+ s.send(@method, /(.)(.)/, 0).should be_an_instance_of(String)
+ s.send(@method, /(.)(.)/, 1).should be_an_instance_of(String)
end
it "sets $~ to MatchData when there is a match and nil when there's none" do
@@ -432,19 +427,6 @@ describe :string_slice_string, shared: true do
"hello there".send(@method, s).should == s
end
- it "taints resulting strings when other is tainted" do
- strs = ["", "hello world", "hello"]
- strs += strs.map { |s| s.dup.taint }
-
- strs.each do |str|
- strs.each do |other|
- r = str.send(@method, other)
-
- r.tainted?.should == !r.nil? & other.tainted?
- end
- end
- end
-
it "doesn't set $~" do
$~ = nil
@@ -460,14 +442,14 @@ describe :string_slice_string, shared: true do
o = mock('x')
o.should_not_receive(:to_str)
- lambda { "hello".send(@method, o) }.should raise_error(TypeError)
+ -> { "hello".send(@method, o) }.should raise_error(TypeError)
end
- it "returns a subclass instance when given a subclass instance" do
+ it "returns a String instance when given a subclass instance" do
s = StringSpecs::MyString.new("el")
r = "hello".send(@method, s)
r.should == "el"
- r.should be_an_instance_of(StringSpecs::MyString)
+ r.should be_an_instance_of(String)
end
end
@@ -493,51 +475,29 @@ describe :string_slice_regexp_group, shared: true do
"hello there".send(@method, /(?<g>h(?<g>.))/, 'g').should == "e"
end
- it "always taints resulting strings when self or regexp is tainted" do
- strs = ["hello world"]
- strs += strs.map { |s| s.dup.taint }
-
- strs.each do |str|
- str.send(@method, /(?<hi>hello)/, 'hi').tainted?.should == str.tainted?
-
- str.send(@method, /(?<g>(.)(.)(.))/, 'g').tainted?.should == str.tainted?
- str.send(@method, /(?<h>.)(.)(.)/, 'h').tainted?.should == str.tainted?
- str.send(@method, /(.)(?<a>.)(.)/, 'a').tainted?.should == str.tainted?
- str.send(@method, /(.)(.)(?<r>.)/, 'r').tainted?.should == str.tainted?
- str.send(@method, /(?<h>.)(?<a>.)(?<r>.)/, 'r').tainted?.should == str.tainted?
-
- tainted_re = /(?<a>.)(?<b>.)(?<c>.)/
- tainted_re.taint
-
- str.send(@method, tainted_re, 'a').tainted?.should be_true
- str.send(@method, tainted_re, 'b').tainted?.should be_true
- str.send(@method, tainted_re, 'c').tainted?.should be_true
- end
- end
-
it "returns nil if there is no match" do
"hello there".send(@method, /(?<whut>what?)/, 'whut').should be_nil
end
it "raises an IndexError if there is no capture for the given name" do
- lambda do
+ -> do
"hello there".send(@method, /[aeiou](.)\1/, 'non')
end.should raise_error(IndexError)
end
it "raises a TypeError when the given name is not a String" do
- lambda { "hello".send(@method, /(?<q>.)/, mock('x')) }.should raise_error(TypeError)
- lambda { "hello".send(@method, /(?<q>.)/, {}) }.should raise_error(TypeError)
- lambda { "hello".send(@method, /(?<q>.)/, []) }.should raise_error(TypeError)
+ -> { "hello".send(@method, /(?<q>.)/, mock('x')) }.should raise_error(TypeError)
+ -> { "hello".send(@method, /(?<q>.)/, {}) }.should raise_error(TypeError)
+ -> { "hello".send(@method, /(?<q>.)/, []) }.should raise_error(TypeError)
end
it "raises an IndexError when given the empty String as a group name" do
- lambda { "hello".send(@method, /(?<q>)/, '') }.should raise_error(IndexError)
+ -> { "hello".send(@method, /(?<q>)/, '') }.should raise_error(IndexError)
end
- it "returns subclass instances" do
+ it "returns String instances" do
s = StringSpecs::MyString.new("hello")
- s.send(@method, /(?<q>.)/, 'q').should be_an_instance_of(StringSpecs::MyString)
+ s.send(@method, /(?<q>.)/, 'q').should be_an_instance_of(String)
end
it "sets $~ to MatchData when there is a match and nil when there's none" do
@@ -552,6 +512,6 @@ end
describe :string_slice_symbol, shared: true do
it "raises TypeError" do
- lambda { 'hello'.send(@method, :hello) }.should raise_error(TypeError)
+ -> { 'hello'.send(@method, :hello) }.should raise_error(TypeError)
end
end
diff --git a/spec/ruby/core/string/shared/strip.rb b/spec/ruby/core/string/shared/strip.rb
new file mode 100644
index 0000000000..3af77b50fe
--- /dev/null
+++ b/spec/ruby/core/string/shared/strip.rb
@@ -0,0 +1,14 @@
+require_relative '../../../spec_helper'
+require_relative '../fixtures/classes'
+
+describe :string_strip, shared: true do
+ it "returns a String in the same encoding as self" do
+ " hello ".encode("US-ASCII").send(@method).encoding.should == Encoding::US_ASCII
+ end
+
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new(" hello ").send(@method).should be_an_instance_of(String)
+ StringSpecs::MyString.new(" ").send(@method).should be_an_instance_of(String)
+ StringSpecs::MyString.new("").send(@method).should be_an_instance_of(String)
+ end
+end
diff --git a/spec/ruby/core/string/shared/succ.rb b/spec/ruby/core/string/shared/succ.rb
index 4854cb7146..7c68345f10 100644
--- a/spec/ruby/core/string/shared/succ.rb
+++ b/spec/ruby/core/string/shared/succ.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
describe :string_succ, shared: true do
it "returns an empty string for empty strings" do
"".send(@method).should == ""
@@ -59,30 +59,29 @@ describe :string_succ, shared: true do
"\xFF\xFF".send(@method).should == "\x01\x00\x00"
end
- it "returns subclass instances when called on a subclass" do
- StringSpecs::MyString.new("").send(@method).should be_an_instance_of(StringSpecs::MyString)
- StringSpecs::MyString.new("a").send(@method).should be_an_instance_of(StringSpecs::MyString)
- StringSpecs::MyString.new("z").send(@method).should be_an_instance_of(StringSpecs::MyString)
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("").send(@method).should be_an_instance_of(String)
+ StringSpecs::MyString.new("a").send(@method).should be_an_instance_of(String)
+ StringSpecs::MyString.new("z").send(@method).should be_an_instance_of(String)
end
- it "taints the result if self is tainted" do
- ["", "a", "z", "Z", "9", "\xFF", "\xFF\xFF"].each do |s|
- s.taint.send(@method).tainted?.should == true
- end
+ it "returns a String in the same encoding as self" do
+ "z".encode("US-ASCII").send(@method).encoding.should == Encoding::US_ASCII
end
end
describe :string_succ_bang, shared: true do
it "is equivalent to succ, but modifies self in place (still returns self)" do
["", "abcd", "THX1138"].each do |s|
+ s = +s
r = s.dup.send(@method)
s.send(@method).should equal(s)
s.should == r
end
end
- it "raises a RuntimeError if self is frozen" do
- lambda { "".freeze.send(@method) }.should raise_error(RuntimeError)
- lambda { "abcd".freeze.send(@method) }.should raise_error(RuntimeError)
+ it "raises a FrozenError if self is frozen" do
+ -> { "".freeze.send(@method) }.should raise_error(FrozenError)
+ -> { "abcd".freeze.send(@method) }.should raise_error(FrozenError)
end
end
diff --git a/spec/ruby/core/string/shared/to_a.rb b/spec/ruby/core/string/shared/to_a.rb
deleted file mode 100644
index bad3ea6584..0000000000
--- a/spec/ruby/core/string/shared/to_a.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-describe :string_to_a, shared: true do
- it "returns an empty array for empty strings" do
- "".send(@method).should == []
- end
-
- it "returns an array containing the string for non-empty strings" do
- "hello".send(@method).should == ["hello"]
- end
-end
diff --git a/spec/ruby/core/string/shared/to_s.rb b/spec/ruby/core/string/shared/to_s.rb
index a5a13e4f26..4b87a6cbe1 100644
--- a/spec/ruby/core/string/shared/to_s.rb
+++ b/spec/ruby/core/string/shared/to_s.rb
@@ -10,9 +10,4 @@ describe :string_to_s, shared: true do
s.should == "a string"
s.should be_an_instance_of(String)
end
-
- it "taints the result when self is tainted" do
- "x".taint.send(@method).tainted?.should == true
- StringSpecs::MyString.new("x").taint.send(@method).tainted?.should == true
- end
end
diff --git a/spec/ruby/core/string/shared/to_sym.rb b/spec/ruby/core/string/shared/to_sym.rb
index 1180d64712..833eae100e 100644
--- a/spec/ruby/core/string/shared/to_sym.rb
+++ b/spec/ruby/core/string/shared/to_sym.rb
@@ -53,11 +53,20 @@ describe :string_to_sym, shared: true do
sym.to_s.should == binary_string
end
+ it "ignores existing symbols with different encoding" do
+ source = "fée"
+
+ iso_symbol = source.dup.force_encoding(Encoding::ISO_8859_1).send(@method)
+ iso_symbol.encoding.should == Encoding::ISO_8859_1
+ binary_symbol = source.dup.force_encoding(Encoding::BINARY).send(@method)
+ binary_symbol.encoding.should == Encoding::BINARY
+ end
+
it "raises an EncodingError for UTF-8 String containing invalid bytes" do
invalid_utf8 = "\xC3"
- invalid_utf8.valid_encoding?.should == false
+ invalid_utf8.should_not.valid_encoding?
-> {
invalid_utf8.send(@method)
- }.should raise_error(EncodingError, /invalid/)
+ }.should raise_error(EncodingError, 'invalid symbol in encoding UTF-8 :"\xC3"')
end
end
diff --git a/spec/ruby/core/string/size_spec.rb b/spec/ruby/core/string/size_spec.rb
index b3172453ea..9e1f40c5ae 100644
--- a/spec/ruby/core/string/size_spec.rb
+++ b/spec/ruby/core/string/size_spec.rb
@@ -1,7 +1,7 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
-require File.expand_path('../shared/length', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/length'
describe "String#size" do
- it_behaves_like(:string_length, :size)
+ it_behaves_like :string_length, :size
end
diff --git a/spec/ruby/core/string/slice_spec.rb b/spec/ruby/core/string/slice_spec.rb
index 8018cc2140..5aba2d3be0 100644
--- a/spec/ruby/core/string/slice_spec.rb
+++ b/spec/ruby/core/string/slice_spec.rb
@@ -1,8 +1,8 @@
# -*- encoding: utf-8 -*-
-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
-require File.expand_path('../shared/slice.rb', __FILE__)
+# frozen_string_literal: false
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/slice'
describe "String#slice" do
it_behaves_like :string_slice, :slice
@@ -53,10 +53,10 @@ describe "String#slice! with index" do
a.should == "hello"
end
- it "raises a RuntimeError if self is frozen" do
- lambda { "hello".freeze.slice!(1) }.should raise_error(RuntimeError)
- lambda { "hello".freeze.slice!(10) }.should raise_error(RuntimeError)
- lambda { "".freeze.slice!(0) }.should raise_error(RuntimeError)
+ it "raises a FrozenError if self is frozen" do
+ -> { "hello".freeze.slice!(1) }.should raise_error(FrozenError)
+ -> { "hello".freeze.slice!(10) }.should raise_error(FrozenError)
+ -> { "".freeze.slice!(0) }.should raise_error(FrozenError)
end
it "calls to_int on index" do
@@ -72,15 +72,13 @@ describe "String#slice! with index" do
"hello".slice!(obj).should == ?e
end
- with_feature :encoding do
-
- it "returns the character given by the character index" do
- "hellö there".send(@method, 1).should == "e"
- "hellö there".send(@method, 4).should == "ö"
- "hellö there".send(@method, 6).should == "t"
- end
+ it "returns the character given by the character index" do
+ "hellö there".slice!(1).should == "e"
+ "hellö there".slice!(4).should == "ö"
+ "hellö there".slice!(6).should == "t"
end
+
end
describe "String#slice! with index, length" do
@@ -96,14 +94,6 @@ describe "String#slice! with index, length" do
a.should == "h"
end
- it "always taints resulting strings when self is tainted" do
- str = "hello world"
- str.taint
-
- str.slice!(0, 0).tainted?.should == true
- str.slice!(2, 1).tainted?.should == true
- end
-
it "returns nil if the given position is out of self" do
a = "hello"
a.slice(10, 3).should == nil
@@ -119,14 +109,14 @@ describe "String#slice! with index, length" do
a.should == "hello"
end
- it "raises a RuntimeError if self is frozen" do
- lambda { "hello".freeze.slice!(1, 2) }.should raise_error(RuntimeError)
- lambda { "hello".freeze.slice!(10, 3) }.should raise_error(RuntimeError)
- lambda { "hello".freeze.slice!(-10, 3)}.should raise_error(RuntimeError)
- lambda { "hello".freeze.slice!(4, -3) }.should raise_error(RuntimeError)
- lambda { "hello".freeze.slice!(10, 3) }.should raise_error(RuntimeError)
- lambda { "hello".freeze.slice!(-10, 3)}.should raise_error(RuntimeError)
- lambda { "hello".freeze.slice!(4, -3) }.should raise_error(RuntimeError)
+ it "raises a FrozenError if self is frozen" do
+ -> { "hello".freeze.slice!(1, 2) }.should raise_error(FrozenError)
+ -> { "hello".freeze.slice!(10, 3) }.should raise_error(FrozenError)
+ -> { "hello".freeze.slice!(-10, 3)}.should raise_error(FrozenError)
+ -> { "hello".freeze.slice!(4, -3) }.should raise_error(FrozenError)
+ -> { "hello".freeze.slice!(10, 3) }.should raise_error(FrozenError)
+ -> { "hello".freeze.slice!(-10, 3)}.should raise_error(FrozenError)
+ -> { "hello".freeze.slice!(4, -3) }.should raise_error(FrozenError)
end
it "calls to_int on idx and length" do
@@ -142,25 +132,22 @@ describe "String#slice! with index, length" do
"hello".slice!(obj, obj).should == "ll"
end
- it "returns subclass instances" do
+ it "returns String instances" do
s = StringSpecs::MyString.new("hello")
- s.slice!(0, 0).should be_an_instance_of(StringSpecs::MyString)
- s.slice!(0, 4).should be_an_instance_of(StringSpecs::MyString)
+ s.slice!(0, 0).should be_an_instance_of(String)
+ s.slice!(0, 4).should be_an_instance_of(String)
end
- with_feature :encoding do
-
- it "returns the substring given by the character offsets" do
- "hellö there".send(@method, 1,0).should == ""
- "hellö there".send(@method, 1,3).should == "ell"
- "hellö there".send(@method, 1,6).should == "ellö t"
- "hellö there".send(@method, 1,9).should == "ellö ther"
- end
+ it "returns the substring given by the character offsets" do
+ "hellö there".slice!(1,0).should == ""
+ "hellö there".slice!(1,3).should == "ell"
+ "hellö there".slice!(1,6).should == "ellö t"
+ "hellö there".slice!(1,9).should == "ellö ther"
+ end
- it "treats invalid bytes as single bytes" do
- xE6xCB = [0xE6,0xCB].pack('CC').force_encoding('utf-8')
- "a#{xE6xCB}b".send(@method, 1, 2).should == xE6xCB
- end
+ it "treats invalid bytes as single bytes" do
+ xE6xCB = [0xE6,0xCB].pack('CC').force_encoding('utf-8')
+ "a#{xE6xCB}b".slice!(1, 2).should == xE6xCB
end
end
@@ -188,18 +175,10 @@ describe "String#slice! Range" do
b.should == "hello"
end
- it "always taints resulting strings when self is tainted" do
- str = "hello world"
- str.taint
-
- str.slice!(0..0).tainted?.should == true
- str.slice!(2..3).tainted?.should == true
- end
-
- it "returns subclass instances" do
+ it "returns String instances" do
s = StringSpecs::MyString.new("hello")
- s.slice!(0...0).should be_an_instance_of(StringSpecs::MyString)
- s.slice!(0..4).should be_an_instance_of(StringSpecs::MyString)
+ s.slice!(0...0).should be_an_instance_of(String)
+ s.slice!(0..4).should be_an_instance_of(String)
end
it "calls to_int on range arguments" do
@@ -236,27 +215,25 @@ describe "String#slice! Range" do
a.slice!(range_incl).should == "OO"
end
- with_feature :encoding do
-
- it "returns the substring given by the character offsets of the range" do
- "hellö there".send(@method, 1..1).should == "e"
- "hellö there".send(@method, 1..3).should == "ell"
- "hellö there".send(@method, 1...3).should == "el"
- "hellö there".send(@method, -4..-2).should == "her"
- "hellö there".send(@method, -4...-2).should == "he"
- "hellö there".send(@method, 5..-1).should == " there"
- "hellö there".send(@method, 5...-1).should == " ther"
- end
+ it "returns the substring given by the character offsets of the range" do
+ "hellö there".slice!(1..1).should == "e"
+ "hellö there".slice!(1..3).should == "ell"
+ "hellö there".slice!(1...3).should == "el"
+ "hellö there".slice!(-4..-2).should == "her"
+ "hellö there".slice!(-4...-2).should == "he"
+ "hellö there".slice!(5..-1).should == " there"
+ "hellö there".slice!(5...-1).should == " ther"
end
- it "raises a RuntimeError on a frozen instance that is modified" do
- lambda { "hello".freeze.slice!(1..3) }.should raise_error(RuntimeError)
+
+ it "raises a FrozenError on a frozen instance that is modified" do
+ -> { "hello".freeze.slice!(1..3) }.should raise_error(FrozenError)
end
# see redmine #1551
- it "raises a RuntimeError on a frozen instance that would not be modified" do
- lambda { "hello".freeze.slice!(10..20)}.should raise_error(RuntimeError)
+ it "raises a FrozenError on a frozen instance that would not be modified" do
+ -> { "hello".freeze.slice!(10..20)}.should raise_error(FrozenError)
end
end
@@ -277,39 +254,15 @@ describe "String#slice! with Regexp" do
s.should == "this is a string"
end
- it "always taints resulting strings when self or regexp is tainted" do
- strs = ["hello world"]
- strs += strs.map { |s| s.dup.taint }
-
- strs.each do |str|
- str = str.dup
- str.slice!(//).tainted?.should == str.tainted?
- str.slice!(/hello/).tainted?.should == str.tainted?
-
- tainted_re = /./
- tainted_re.taint
-
- str.slice!(tainted_re).tainted?.should == true
- end
- end
-
- it "doesn't taint self when regexp is tainted" do
- s = "hello"
- s.slice!(/./.taint)
- s.tainted?.should == false
- end
-
- it "returns subclass instances" do
+ it "returns String instances" do
s = StringSpecs::MyString.new("hello")
- s.slice!(//).should be_an_instance_of(StringSpecs::MyString)
- s.slice!(/../).should be_an_instance_of(StringSpecs::MyString)
+ s.slice!(//).should be_an_instance_of(String)
+ s.slice!(/../).should be_an_instance_of(String)
end
- with_feature :encoding do
- it "returns the matching portion of self with a multi byte character" do
- "hëllo there".send(@method, /[ë](.)\1/).should == "ëll"
- "".send(@method, //).should == ""
- end
+ it "returns the matching portion of self with a multi byte character" do
+ "hëllo there".slice!(/[ë](.)\1/).should == "ëll"
+ "".slice!(//).should == ""
end
it "sets $~ to MatchData when there is a match and nil when there's none" do
@@ -320,12 +273,12 @@ describe "String#slice! with Regexp" do
$~.should == nil
end
- it "raises a RuntimeError on a frozen instance that is modified" do
- lambda { "this is a string".freeze.slice!(/s.*t/) }.should raise_error(RuntimeError)
+ it "raises a FrozenError on a frozen instance that is modified" do
+ -> { "this is a string".freeze.slice!(/s.*t/) }.should raise_error(FrozenError)
end
- it "raises a RuntimeError on a frozen instance that would not be modified" do
- lambda { "this is a string".freeze.slice!(/zzz/) }.should raise_error(RuntimeError)
+ it "raises a FrozenError on a frozen instance that would not be modified" do
+ -> { "this is a string".freeze.slice!(/zzz/) }.should raise_error(FrozenError)
end
end
@@ -338,28 +291,6 @@ describe "String#slice! with Regexp, index" do
str.should == "ho here"
end
- it "always taints resulting strings when self or regexp is tainted" do
- strs = ["hello world"]
- strs += strs.map { |s| s.dup.taint }
-
- strs.each do |str|
- str = str.dup
- str.slice!(//, 0).tainted?.should == str.tainted?
- str.slice!(/hello/, 0).tainted?.should == str.tainted?
-
- tainted_re = /(.)(.)(.)/
- tainted_re.taint
-
- str.slice!(tainted_re, 1).tainted?.should == true
- end
- end
-
- it "doesn't taint self when regexp is tainted" do
- s = "hello"
- s.slice!(/(.)(.)/.taint, 1)
- s.tainted?.should == false
- end
-
it "returns nil if there was no match" do
s = "this is a string"
s.slice!(/x(zzz)/, 1).should == nil
@@ -383,22 +314,20 @@ describe "String#slice! with Regexp, index" do
"har".slice!(/(.)(.)(.)/, obj).should == "a"
end
- it "returns subclass instances" do
+ it "returns String instances" do
s = StringSpecs::MyString.new("hello")
- s.slice!(/(.)(.)/, 0).should be_an_instance_of(StringSpecs::MyString)
- s.slice!(/(.)(.)/, 1).should be_an_instance_of(StringSpecs::MyString)
+ s.slice!(/(.)(.)/, 0).should be_an_instance_of(String)
+ s.slice!(/(.)(.)/, 1).should be_an_instance_of(String)
end
- with_feature :encoding do
- it "returns the encoding aware capture for the given index" do
- "hår".send(@method, /(.)(.)(.)/, 0).should == "hår"
- "hår".send(@method, /(.)(.)(.)/, 1).should == "h"
- "hår".send(@method, /(.)(.)(.)/, 2).should == "å"
- "hår".send(@method, /(.)(.)(.)/, 3).should == "r"
- "hår".send(@method, /(.)(.)(.)/, -1).should == "r"
- "hår".send(@method, /(.)(.)(.)/, -2).should == "å"
- "hår".send(@method, /(.)(.)(.)/, -3).should == "h"
- end
+ it "returns the encoding aware capture for the given index" do
+ "hår".slice!(/(.)(.)(.)/, 0).should == "hår"
+ "hår".slice!(/(.)(.)(.)/, 1).should == "h"
+ "hår".slice!(/(.)(.)(.)/, 2).should == "å"
+ "hår".slice!(/(.)(.)(.)/, 3).should == "r"
+ "hår".slice!(/(.)(.)(.)/, -1).should == "r"
+ "hår".slice!(/(.)(.)(.)/, -2).should == "å"
+ "hår".slice!(/(.)(.)(.)/, -3).should == "h"
end
it "sets $~ to MatchData when there is a match and nil when there's none" do
@@ -412,10 +341,10 @@ describe "String#slice! with Regexp, index" do
$~.should == nil
end
- it "raises a RuntimeError if self is frozen" do
- lambda { "this is a string".freeze.slice!(/s.*t/) }.should raise_error(RuntimeError)
- lambda { "this is a string".freeze.slice!(/zzz/, 0)}.should raise_error(RuntimeError)
- lambda { "this is a string".freeze.slice!(/(.)/, 2)}.should raise_error(RuntimeError)
+ it "raises a FrozenError if self is frozen" do
+ -> { "this is a string".freeze.slice!(/s.*t/) }.should raise_error(FrozenError)
+ -> { "this is a string".freeze.slice!(/zzz/, 0)}.should raise_error(FrozenError)
+ -> { "this is a string".freeze.slice!(/(.)/, 2)}.should raise_error(FrozenError)
end
end
@@ -426,21 +355,6 @@ describe "String#slice! with String" do
c.should == "he hello"
end
- it "taints resulting strings when other is tainted" do
- strs = ["", "hello world", "hello"]
- strs += strs.map { |s| s.dup.taint }
-
- strs.each do |str|
- str = str.dup
- strs.each do |other|
- other = other.dup
- r = str.slice!(other)
-
- r.tainted?.should == !r.nil? & other.tainted?
- end
- end
- end
-
it "doesn't set $~" do
$~ = nil
@@ -458,19 +372,19 @@ describe "String#slice! with String" do
o = mock('x')
o.should_not_receive(:to_str)
- lambda { "hello".slice!(o) }.should raise_error(TypeError)
+ -> { "hello".slice!(o) }.should raise_error(TypeError)
end
it "returns a subclass instance when given a subclass instance" do
s = StringSpecs::MyString.new("el")
r = "hello".slice!(s)
r.should == "el"
- r.should be_an_instance_of(StringSpecs::MyString)
+ r.should be_an_instance_of(String)
end
- it "raises a RuntimeError if self is frozen" do
- lambda { "hello hello".freeze.slice!('llo') }.should raise_error(RuntimeError)
- lambda { "this is a string".freeze.slice!('zzz')}.should raise_error(RuntimeError)
- lambda { "this is a string".freeze.slice!('zzz')}.should raise_error(RuntimeError)
+ it "raises a FrozenError if self is frozen" do
+ -> { "hello hello".freeze.slice!('llo') }.should raise_error(FrozenError)
+ -> { "this is a string".freeze.slice!('zzz')}.should raise_error(FrozenError)
+ -> { "this is a string".freeze.slice!('zzz')}.should raise_error(FrozenError)
end
end
diff --git a/spec/ruby/core/string/split_spec.rb b/spec/ruby/core/string/split_spec.rb
index 1a4128f828..3c6d1864d1 100644
--- a/spec/ruby/core/string/split_spec.rb
+++ b/spec/ruby/core/string/split_spec.rb
@@ -1,21 +1,24 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String#split with String" do
- with_feature :encoding do
- it "throws an ArgumentError if the pattern is not a valid string" do
- str = 'проверка'
- broken_str = 'проверка'
- broken_str.force_encoding('binary')
- broken_str.chop!
- broken_str.force_encoding('utf-8')
- lambda { str.split(broken_str) }.should raise_error(ArgumentError)
- end
+ it "throws an ArgumentError if the string is not a valid" do
+ s = "\xDF".dup.force_encoding(Encoding::UTF_8)
- it "splits on multibyte characters" do
- "ありがりがとう".split("が").should == ["あり", "り", "とう"]
- end
+ -> { s.split }.should raise_error(ArgumentError)
+ -> { s.split(':') }.should raise_error(ArgumentError)
+ end
+
+ it "throws an ArgumentError if the pattern is not a valid string" do
+ str = 'проверка'
+ broken_str = "\xDF".dup.force_encoding(Encoding::UTF_8)
+
+ -> { str.split(broken_str) }.should raise_error(ArgumentError)
+ end
+
+ it "splits on multibyte characters" do
+ "ありがりがとう".split("が").should == ["あり", "り", "とう"]
end
it "returns an array of substrings based on splitting on the given string" do
@@ -26,9 +29,35 @@ describe "String#split with String" do
"1,2,,3,4,,".split(',').should == ["1", "2", "", "3", "4"]
"1,2,,3,4,,".split(',', 0).should == ["1", "2", "", "3", "4"]
" a b c\nd ".split(" ").should == ["", "a", "b", "c\nd"]
+ " a あ c\nd ".split(" ").should == ["", "a", "あ", "c\nd"]
"hai".split("hai").should == []
",".split(",").should == []
",".split(",", 0).should == []
+ "あ".split("あ").should == []
+ "あ".split("あ", 0).should == []
+ end
+
+ it "does not suppress trailing empty fields when a positive limit is given" do
+ " 1 2 ".split(" ", 2).should == ["1", "2 "]
+ " 1 2 ".split(" ", 3).should == ["1", "2", ""]
+ " 1 2 ".split(" ", 4).should == ["1", "2", ""]
+ " 1 あ ".split(" ", 2).should == ["1", "あ "]
+ " 1 あ ".split(" ", 3).should == ["1", "あ", ""]
+ " 1 あ ".split(" ", 4).should == ["1", "あ", ""]
+
+ "1,2,".split(',', 2).should == ["1", "2,"]
+ "1,2,".split(',', 3).should == ["1", "2", ""]
+ "1,2,".split(',', 4).should == ["1", "2", ""]
+ "1,あ,".split(',', 2).should == ["1", "あ,"]
+ "1,あ,".split(',', 3).should == ["1", "あ", ""]
+ "1,あ,".split(',', 4).should == ["1", "あ", ""]
+
+ "1 2 ".split(/ /, 2).should == ["1", "2 "]
+ "1 2 ".split(/ /, 3).should == ["1", "2", ""]
+ "1 2 ".split(/ /, 4).should == ["1", "2", ""]
+ "1 あ ".split(/ /, 2).should == ["1", "あ "]
+ "1 あ ".split(/ /, 3).should == ["1", "あ", ""]
+ "1 あ ".split(/ /, 4).should == ["1", "あ", ""]
end
it "returns an array with one entry if limit is 1: the original string" do
@@ -64,26 +93,47 @@ describe "String#split with String" do
",".split(",", -1).should == ["", ""]
end
+ it "raises a RangeError when the limit is larger than int" do
+ -> { "a,b".split(" ", 2147483649) }.should raise_error(RangeError)
+ end
+
it "defaults to $; when string isn't given or nil" do
- begin
+ suppress_warning do
old_fs = $;
+ begin
+ [",", ":", "", "XY", nil].each do |fs|
+ $; = fs
- [",", ":", "", "XY", nil].each do |fs|
- $; = fs
+ ["x,y,z,,,", "1:2:", "aXYbXYcXY", ""].each do |str|
+ expected = str.split(fs || " ")
- ["x,y,z,,,", "1:2:", "aXYbXYcXY", ""].each do |str|
- expected = str.split(fs || " ")
+ str.split(nil).should == expected
+ str.split.should == expected
- str.split(nil).should == expected
- str.split.should == expected
+ str.split(nil, -1).should == str.split(fs || " ", -1)
+ str.split(nil, 0).should == str.split(fs || " ", 0)
+ str.split(nil, 2).should == str.split(fs || " ", 2)
+ end
+ end
+ ensure
+ $; = old_fs
+ end
+ end
- str.split(nil, -1).should == str.split(fs || " ", -1)
- str.split(nil, 0).should == str.split(fs || " ", 0)
- str.split(nil, 2).should == str.split(fs || " ", 2)
+ context "when $; is not nil" do
+ before do
+ suppress_warning do
+ @old_value, $; = $;, 'foobar'
end
end
- ensure
- $; = old_fs
+
+ after do
+ $; = @old_value
+ end
+
+ it "warns" do
+ -> { "".split }.should complain(/warning: \$; is set to non-nil value/)
+ end
end
end
@@ -142,12 +192,12 @@ describe "String#split with String" do
"foo".split("bar", 3).should == ["foo"]
end
- it "returns subclass instances based on self" do
+ it "returns String instances based on self" do
["", "x.y.z.", " x y "].each do |str|
["", ".", " "].each do |pat|
[-1, 0, 1, 2].each do |limit|
StringSpecs::MyString.new(str).split(pat, limit).each do |x|
- x.should be_an_instance_of(StringSpecs::MyString)
+ x.should be_an_instance_of(String)
end
str.split(StringSpecs::MyString.new(pat), limit).each do |x|
@@ -158,32 +208,32 @@ describe "String#split with String" do
end
end
- it "does not call constructor on created subclass instances" do
- # can't call should_not_receive on an object that doesn't yet exist
- # so failure here is signalled by exception, not expectation failure
+ it "returns an empty array when whitespace is split on whitespace" do
+ " ".split(" ").should == []
+ " \n ".split(" ").should == []
+ " ".split(" ").should == []
+ " \t ".split(" ").should == []
+ end
- s = StringSpecs::StringWithRaisingConstructor.new('silly:string')
- s.split(':').first.should == 'silly'
+ it "doesn't split on non-ascii whitespace" do
+ "a\u{2008}b".split(" ").should == ["a\u{2008}b"]
end
- it "taints the resulting strings if self is tainted" do
- ["", "x.y.z.", " x y "].each do |str|
- ["", ".", " "].each do |pat|
- [-1, 0, 1, 2].each do |limit|
- str.dup.taint.split(pat).each do |x|
- x.tainted?.should == true
- end
+ it "returns Strings in the same encoding as self" do
+ strings = "hello world".encode("US-ASCII").split(" ")
- str.split(pat.dup.taint).each do |x|
- x.tainted?.should == false
- end
- end
- end
- end
+ strings[0].encoding.should == Encoding::US_ASCII
+ strings[1].encoding.should == Encoding::US_ASCII
end
end
describe "String#split with Regexp" do
+ it "throws an ArgumentError if the string is not a valid" do
+ s = "\xDF".dup.force_encoding(Encoding::UTF_8)
+
+ -> { s.split(/./) }.should raise_error(ArgumentError)
+ end
+
it "divides self on regexp matches" do
" now's the time".split(/ /).should == ["", "now's", "", "the", "time"]
" x\ny ".split(/ /).should == ["", "x\ny"]
@@ -238,25 +288,26 @@ describe "String#split with Regexp" do
end
it "defaults to $; when regexp isn't given or nil" do
- begin
+ suppress_warning do
old_fs = $;
+ begin
+ [/,/, /:/, //, /XY/, /./].each do |fs|
+ $; = fs
- [/,/, /:/, //, /XY/, /./].each do |fs|
- $; = fs
+ ["x,y,z,,,", "1:2:", "aXYbXYcXY", ""].each do |str|
+ expected = str.split(fs)
- ["x,y,z,,,", "1:2:", "aXYbXYcXY", ""].each do |str|
- expected = str.split(fs)
+ str.split(nil).should == expected
+ str.split.should == expected
- str.split(nil).should == expected
- str.split.should == expected
-
- str.split(nil, -1).should == str.split(fs, -1)
- str.split(nil, 0).should == str.split(fs, 0)
- str.split(nil, 2).should == str.split(fs, 2)
+ str.split(nil, -1).should == str.split(fs, -1)
+ str.split(nil, 0).should == str.split(fs, 0)
+ str.split(nil, 2).should == str.split(fs, 2)
+ end
end
+ ensure
+ $; = old_fs
end
- ensure
- $; = old_fs
end
end
@@ -316,8 +367,8 @@ describe "String#split with Regexp" do
end
it "returns a type error if limit can't be converted to an integer" do
- lambda {"1.2.3.4".split(".", "three")}.should raise_error(TypeError)
- lambda {"1.2.3.4".split(".", nil) }.should raise_error(TypeError)
+ -> {"1.2.3.4".split(".", "three")}.should raise_error(TypeError)
+ -> {"1.2.3.4".split(".", nil) }.should raise_error(TypeError)
end
it "doesn't set $~" do
@@ -335,71 +386,161 @@ describe "String#split with Regexp" do
"foo".split(/bar/, 3).should == ["foo"]
end
- it "returns subclass instances based on self" do
+ it "returns String instances based on self" do
["", "x:y:z:", " x y "].each do |str|
[//, /:/, /\s+/].each do |pat|
[-1, 0, 1, 2].each do |limit|
StringSpecs::MyString.new(str).split(pat, limit).each do |x|
- x.should be_an_instance_of(StringSpecs::MyString)
+ x.should be_an_instance_of(String)
end
end
end
end
end
- it "does not call constructor on created subclass instances" do
- # can't call should_not_receive on an object that doesn't yet exist
- # so failure here is signalled by exception, not expectation failure
+ it "returns Strings in the same encoding as self" do
+ ary = "а б в".split
+ encodings = ary.map { |s| s.encoding }
+ encodings.should == [Encoding::UTF_8, Encoding::UTF_8, Encoding::UTF_8]
+ end
- s = StringSpecs::StringWithRaisingConstructor.new('silly:string')
- s.split(/:/).first.should == 'silly'
+ it "splits a string on each character for a multibyte encoding and empty split" do
+ "That's why efficiency could not be helped".split("").size.should == 39
end
- it "taints the resulting strings if self is tainted" do
- ["", "x:y:z:", " x y "].each do |str|
- [//, /:/, /\s+/].each do |pat|
- [-1, 0, 1, 2].each do |limit|
- str.dup.taint.split(pat, limit).each do |x|
- # See the spec below for why the conditional is here
- x.tainted?.should be_true unless x.empty?
- end
- end
- end
- end
+ it "returns an ArgumentError if an invalid UTF-8 string is supplied" do
+ broken_str = +'проверка' # in russian, means "test"
+ broken_str.force_encoding('binary')
+ broken_str.chop!
+ broken_str.force_encoding('utf-8')
+ ->{ broken_str.split(/\r\n|\r|\n/) }.should raise_error(ArgumentError)
end
- it "taints an empty string if self is tainted" do
- ":".taint.split(//, -1).last.tainted?.should be_true
+ # See https://bugs.ruby-lang.org/issues/12689 and https://github.com/jruby/jruby/issues/4868
+ it "allows concurrent Regexp calls in a shared context" do
+ str = 'a,b,c,d,e'
+
+ p = proc { str.split(/,/) }
+ results = 10.times.map { Thread.new { x = nil; 100.times { x = p.call }; x } }.map(&:value)
+
+ results.should == [%w[a b c d e]] * 10
end
- it "doesn't taints the resulting strings if the Regexp is tainted" do
- ["", "x:y:z:", " x y "].each do |str|
- [//, /:/, /\s+/].each do |pat|
- [-1, 0, 1, 2].each do |limit|
- str.split(pat.dup.taint, limit).each do |x|
- x.tainted?.should be_false
- end
- end
- end
+ context "when a block is given" do
+ it "yields each split substring with default pattern" do
+ a = []
+ returned_object = "chunky bacon".split { |str| a << str.capitalize }
+
+ returned_object.should == "chunky bacon"
+ a.should == ["Chunky", "Bacon"]
end
- end
- it "retains the encoding of the source string" do
- ary = "а б в".split
- encodings = ary.map { |s| s.encoding }
- encodings.should == [Encoding::UTF_8, Encoding::UTF_8, Encoding::UTF_8]
+ it "yields each split substring with default pattern for a lazy substring" do
+ a = []
+ returned_object = "chunky bacon"[1...-1].split { |str| a << str.capitalize }
+
+ returned_object.should == "hunky baco"
+ a.should == ["Hunky", "Baco"]
+ end
+
+ it "yields each split substring with default pattern for a non-ASCII string" do
+ a = []
+ returned_object = "l'été arrive bientôt".split { |str| a << str }
+
+ returned_object.should == "l'été arrive bientôt"
+ a.should == ["l'été", "arrive", "bientôt"]
+ end
+
+ it "yields each split substring with default pattern for a non-ASCII lazy substring" do
+ a = []
+ returned_object = "l'été arrive bientôt"[1...-1].split { |str| a << str }
+
+ returned_object.should == "'été arrive bientô"
+ a.should == ["'été", "arrive", "bientô"]
+ end
+
+ it "yields the string when limit is 1" do
+ a = []
+ returned_object = "chunky bacon".split("", 1) { |str| a << str.capitalize }
+
+ returned_object.should == "chunky bacon"
+ a.should == ["Chunky bacon"]
+ end
+
+ it "yields each split letter" do
+ a = []
+ returned_object = "chunky".split("", 0) { |str| a << str.capitalize }
+
+ returned_object.should == "chunky"
+ a.should == %w(C H U N K Y)
+ end
+
+ it "yields each split substring with a pattern" do
+ a = []
+ returned_object = "chunky-bacon".split("-", 0) { |str| a << str.capitalize }
+
+ returned_object.should == "chunky-bacon"
+ a.should == ["Chunky", "Bacon"]
+ end
+
+ it "yields each split substring with empty regexp pattern" do
+ a = []
+ returned_object = "chunky".split(//) { |str| a << str.capitalize }
+
+ returned_object.should == "chunky"
+ a.should == %w(C H U N K Y)
+ end
+
+ it "yields each split substring with empty regexp pattern and limit" do
+ a = []
+ returned_object = "chunky".split(//, 3) { |str| a << str.capitalize }
+
+ returned_object.should == "chunky"
+ a.should == %w(C H Unky)
+ end
+
+ it "yields each split substring with a regexp pattern" do
+ a = []
+ returned_object = "chunky:bacon".split(/:/) { |str| a << str.capitalize }
+
+ returned_object.should == "chunky:bacon"
+ a.should == ["Chunky", "Bacon"]
+ end
+
+ it "returns a string as is (and doesn't call block) if it is empty" do
+ a = []
+ returned_object = "".split { |str| a << str.capitalize }
+
+ returned_object.should == ""
+ a.should == []
+ end
end
+ describe "for a String subclass" do
+ it "yields instances of String" do
+ a = []
+ StringSpecs::MyString.new("a|b").split("|") { |str| a << str }
+ first, last = a
- it "splits a string on each character for a multibyte encoding and empty split" do
- "That's why efficiency could not be helped".split("").size.should == 39
+ first.should be_an_instance_of(String)
+ first.should == "a"
+
+ last.should be_an_instance_of(String)
+ last.should == "b"
+ end
end
- it "returns an ArgumentError if an invalid UTF-8 string is supplied" do
- broken_str = 'проверка' # in russian, means "test"
- broken_str.force_encoding('binary')
- broken_str.chop!
- broken_str.force_encoding('utf-8')
- lambda{ broken_str.split(/\r\n|\r|\n/) }.should raise_error(ArgumentError)
+ it "raises a TypeError when not called with nil, String, or Regexp" do
+ -> { "hello".split(42) }.should raise_error(TypeError)
+ -> { "hello".split(:ll) }.should raise_error(TypeError)
+ -> { "hello".split(false) }.should raise_error(TypeError)
+ -> { "hello".split(Object.new) }.should raise_error(TypeError)
+ end
+
+ it "returns Strings in the same encoding as self" do
+ strings = "hello world".encode("US-ASCII").split(/ /)
+
+ strings[0].encoding.should == Encoding::US_ASCII
+ strings[1].encoding.should == Encoding::US_ASCII
end
end
diff --git a/spec/ruby/core/string/squeeze_spec.rb b/spec/ruby/core/string/squeeze_spec.rb
index d6b3fb6de6..981d480684 100644
--- a/spec/ruby/core/string/squeeze_spec.rb
+++ b/spec/ruby/core/string/squeeze_spec.rb
@@ -1,6 +1,7 @@
-# -*- encoding: binary -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+# encoding: binary
+# frozen_string_literal: false
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
# TODO: rewrite all these specs
@@ -50,16 +51,8 @@ describe "String#squeeze" do
it "raises an ArgumentError when the parameter is out of sequence" do
s = "--subbookkeeper--"
- lambda { s.squeeze("e-b") }.should raise_error(ArgumentError)
- lambda { s.squeeze("^e-b") }.should raise_error(ArgumentError)
- end
-
- it "taints the result when self is tainted" do
- "hello".taint.squeeze("e").tainted?.should == true
- "hello".taint.squeeze("a-z").tainted?.should == true
-
- "hello".squeeze("e".taint).tainted?.should == false
- "hello".squeeze("l".taint).tainted?.should == false
+ -> { s.squeeze("e-b") }.should raise_error(ArgumentError)
+ -> { s.squeeze("^e-b") }.should raise_error(ArgumentError)
end
it "tries to convert each set arg to a string using to_str" do
@@ -72,14 +65,19 @@ describe "String#squeeze" do
"hello room".squeeze(other_string, other_string2).should == "hello rom"
end
+ it "returns a String in the same encoding as self" do
+ "yellow moon".encode("US-ASCII").squeeze.encoding.should == Encoding::US_ASCII
+ "yellow moon".encode("US-ASCII").squeeze("a").encoding.should == Encoding::US_ASCII
+ end
+
it "raises a TypeError when one set arg can't be converted to a string" do
- lambda { "hello world".squeeze([]) }.should raise_error(TypeError)
- lambda { "hello world".squeeze(Object.new)}.should raise_error(TypeError)
- lambda { "hello world".squeeze(mock('x')) }.should raise_error(TypeError)
+ -> { "hello world".squeeze([]) }.should raise_error(TypeError)
+ -> { "hello world".squeeze(Object.new)}.should raise_error(TypeError)
+ -> { "hello world".squeeze(mock('x')) }.should raise_error(TypeError)
end
- it "returns subclass instances when called on a subclass" do
- StringSpecs::MyString.new("oh no!!!").squeeze("!").should be_an_instance_of(StringSpecs::MyString)
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("oh no!!!").squeeze("!").should be_an_instance_of(String)
end
end
@@ -99,15 +97,15 @@ describe "String#squeeze!" do
it "raises an ArgumentError when the parameter is out of sequence" do
s = "--subbookkeeper--"
- lambda { s.squeeze!("e-b") }.should raise_error(ArgumentError)
- lambda { s.squeeze!("^e-b") }.should raise_error(ArgumentError)
+ -> { s.squeeze!("e-b") }.should raise_error(ArgumentError)
+ -> { s.squeeze!("^e-b") }.should raise_error(ArgumentError)
end
- it "raises a RuntimeError when self is frozen" do
+ it "raises a FrozenError when self is frozen" do
a = "yellow moon"
a.freeze
- lambda { a.squeeze!("") }.should raise_error(RuntimeError)
- lambda { a.squeeze! }.should raise_error(RuntimeError)
+ -> { a.squeeze!("") }.should raise_error(FrozenError)
+ -> { a.squeeze! }.should raise_error(FrozenError)
end
end
diff --git a/spec/ruby/core/string/start_with_spec.rb b/spec/ruby/core/string/start_with_spec.rb
index 1b27fdaed7..35e33b46a6 100644
--- a/spec/ruby/core/string/start_with_spec.rb
+++ b/spec/ruby/core/string/start_with_spec.rb
@@ -1,45 +1,27 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative '../../shared/string/start_with'
describe "String#start_with?" do
- it "returns true only if beginning match" do
- s = "hello"
- s.start_with?('h').should be_true
- s.start_with?('hel').should be_true
- s.start_with?('el').should be_false
- end
-
- it "returns true only if any beginning match" do
- "hello".start_with?('x', 'y', 'he', 'z').should be_true
- end
-
- it "returns true if the search string is empty" do
- "hello".start_with?("").should be_true
- "".start_with?("").should be_true
- end
-
- it "converts its argument using :to_str" do
- s = "hello"
- find = mock('h')
- find.should_receive(:to_str).and_return("h")
- s.start_with?(find).should be_true
- end
+ it_behaves_like :start_with, :to_s
- it "ignores arguments not convertible to string" do
- "hello".start_with?().should be_false
- lambda { "hello".start_with?(1) }.should raise_error(TypeError)
- lambda { "hello".start_with?(["h"]) }.should raise_error(TypeError)
- lambda { "hello".start_with?(1, nil, "h") }.should raise_error(TypeError)
+ # Here and not in the shared examples because this is invalid as a Symbol
+ it "matches part of a character with the same part" do
+ "\xA9".should.start_with?("\xA9") # A9 is not a character head for UTF-8
end
- it "uses only the needed arguments" do
- find = mock('h')
- find.should_not_receive(:to_str)
- "hello".start_with?("h",find).should be_true
+ ruby_version_is ""..."3.3" do
+ it "does not check we are matching only part of a character" do
+ "\xe3\x81\x82".size.should == 1
+ "\xe3\x81\x82".should.start_with?("\xe3")
+ end
end
- it "works for multibyte strings" do
- "céréale".start_with?("cér").should be_true
+ ruby_version_is "3.3" do # #19784
+ it "checks we are matching only part of a character" do
+ "\xe3\x81\x82".size.should == 1
+ "\xe3\x81\x82".should_not.start_with?("\xe3")
+ end
end
end
diff --git a/spec/ruby/core/string/string_spec.rb b/spec/ruby/core/string/string_spec.rb
index 37a858acae..cdefbbecbd 100644
--- a/spec/ruby/core/string/string_spec.rb
+++ b/spec/ruby/core/string/string_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
describe "String" do
it "includes Comparable" do
diff --git a/spec/ruby/core/string/strip_spec.rb b/spec/ruby/core/string/strip_spec.rb
index 747fd8cdf2..edb6ea3b44 100644
--- a/spec/ruby/core/string/strip_spec.rb
+++ b/spec/ruby/core/string/strip_spec.rb
@@ -1,22 +1,19 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+# frozen_string_literal: false
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/strip'
describe "String#strip" do
+ it_behaves_like :string_strip, :strip
+
it "returns a new string with leading and trailing whitespace removed" do
" hello ".strip.should == "hello"
" hello world ".strip.should == "hello world"
"\tgoodbye\r\v\n".strip.should == "goodbye"
- "\x00 goodbye \x00".strip.should == "\x00 goodbye"
- end
-
- it "returns a copy of self with trailing NULL bytes and whitespace" do
- " \x00 goodbye \x00 ".strip.should == "\x00 goodbye"
end
- it "taints the result when self is tainted" do
- "".taint.strip.tainted?.should == true
- "ok".taint.strip.tainted?.should == true
- " ok ".taint.strip.tainted?.should == true
+ it "returns a copy of self without leading and trailing NULL bytes and whitespace" do
+ " \x00 goodbye \x00 ".strip.should == "goodbye"
end
end
@@ -29,11 +26,6 @@ describe "String#strip!" do
a = "\tgoodbye\r\v\n"
a.strip!
a.should == "goodbye"
-
- a = "\000 goodbye \000"
- a.strip!
- a.should == "\000 goodbye"
-
end
it "returns nil if no modifications where made" do
@@ -42,19 +34,25 @@ describe "String#strip!" do
a.should == "hello"
end
- it "modifies self removing trailing NULL bytes and whitespace" do
- a = " \x00 goodbye \x00 "
+ it "makes a string empty if it is only whitespace" do
+ "".strip!.should == nil
+ " ".strip.should == ""
+ " ".strip.should == ""
+ end
+
+ it "removes leading and trailing NULL bytes and whitespace" do
+ a = "\000 goodbye \000"
a.strip!
- a.should == "\x00 goodbye"
+ a.should == "goodbye"
end
- it "raises a RuntimeError on a frozen instance that is modified" do
- lambda { " hello ".freeze.strip! }.should raise_error(RuntimeError)
+ it "raises a FrozenError on a frozen instance that is modified" do
+ -> { " hello ".freeze.strip! }.should raise_error(FrozenError)
end
# see #1552
- it "raises a RuntimeError on a frozen instance that would not be modified" do
- lambda {"hello".freeze.strip! }.should raise_error(RuntimeError)
- lambda {"".freeze.strip! }.should raise_error(RuntimeError)
+ it "raises a FrozenError on a frozen instance that would not be modified" do
+ -> {"hello".freeze.strip! }.should raise_error(FrozenError)
+ -> {"".freeze.strip! }.should raise_error(FrozenError)
end
end
diff --git a/spec/ruby/core/string/sub_spec.rb b/spec/ruby/core/string/sub_spec.rb
index deaa7e27f1..6ff28ec851 100644
--- a/spec/ruby/core/string/sub_spec.rb
+++ b/spec/ruby/core/string/sub_spec.rb
@@ -1,5 +1,6 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+# frozen_string_literal: false
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String#sub with pattern, replacement" do
it "returns a copy of self when no modification is made" do
@@ -137,26 +138,6 @@ describe "String#sub with pattern, replacement" do
"hello".sub(/./, 'hah\\').should == 'hah\\ello'
end
- it "taints the result if the original string or replacement is tainted" do
- hello = "hello"
- hello_t = "hello"
- a = "a"
- a_t = "a"
- empty = ""
- empty_t = ""
-
- hello_t.taint; a_t.taint; empty_t.taint
-
- hello_t.sub(/./, a).tainted?.should == true
- hello_t.sub(/./, empty).tainted?.should == true
-
- hello.sub(/./, a_t).tainted?.should == true
- hello.sub(/./, empty_t).tainted?.should == true
- hello.sub(//, empty_t).tainted?.should == true
-
- hello.sub(//.taint, "foo").tainted?.should == false
- end
-
it "tries to convert pattern to a string using to_str" do
pattern = mock('.')
pattern.should_receive(:to_str).and_return(".")
@@ -166,16 +147,16 @@ describe "String#sub with pattern, replacement" do
not_supported_on :opal do
it "raises a TypeError when pattern is a Symbol" do
- lambda { "hello".sub(:woot, "x") }.should raise_error(TypeError)
+ -> { "hello".sub(:woot, "x") }.should raise_error(TypeError)
end
end
it "raises a TypeError when pattern is an Array" do
- lambda { "hello".sub([], "x") }.should raise_error(TypeError)
+ -> { "hello".sub([], "x") }.should raise_error(TypeError)
end
it "raises a TypeError when pattern can't be converted to a string" do
- lambda { "hello".sub(Object.new, nil) }.should raise_error(TypeError)
+ -> { "hello".sub(Object.new, nil) }.should raise_error(TypeError)
end
it "tries to convert replacement to a string using to_str" do
@@ -186,15 +167,15 @@ describe "String#sub with pattern, replacement" do
end
it "raises a TypeError when replacement can't be converted to a string" do
- lambda { "hello".sub(/[aeiou]/, []) }.should raise_error(TypeError)
- lambda { "hello".sub(/[aeiou]/, 99) }.should raise_error(TypeError)
+ -> { "hello".sub(/[aeiou]/, []) }.should raise_error(TypeError)
+ -> { "hello".sub(/[aeiou]/, 99) }.should raise_error(TypeError)
end
- it "returns subclass instances when called on a subclass" do
- StringSpecs::MyString.new("").sub(//, "").should be_an_instance_of(StringSpecs::MyString)
- StringSpecs::MyString.new("").sub(/foo/, "").should be_an_instance_of(StringSpecs::MyString)
- StringSpecs::MyString.new("foo").sub(/foo/, "").should be_an_instance_of(StringSpecs::MyString)
- StringSpecs::MyString.new("foo").sub("foo", "").should be_an_instance_of(StringSpecs::MyString)
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("").sub(//, "").should be_an_instance_of(String)
+ StringSpecs::MyString.new("").sub(/foo/, "").should be_an_instance_of(String)
+ StringSpecs::MyString.new("foo").sub(/foo/, "").should be_an_instance_of(String)
+ StringSpecs::MyString.new("foo").sub("foo", "").should be_an_instance_of(String)
end
it "sets $~ to MatchData of match and nil when there's none" do
@@ -223,6 +204,17 @@ describe "String#sub with pattern, replacement" do
"ababa".sub(/(b)/, '\\\\\1').should == "a\\baba"
end
+ it "handles a pattern in a superset encoding" do
+ result = 'abc'.force_encoding(Encoding::US_ASCII).sub('é', 'è')
+ result.should == 'abc'
+ result.encoding.should == Encoding::US_ASCII
+ end
+
+ it "handles a pattern in a subset encoding" do
+ result = 'été'.sub('t'.force_encoding(Encoding::US_ASCII), 'u')
+ result.should == 'éué'
+ result.encoding.should == Encoding::UTF_8
+ end
end
describe "String#sub with pattern and block" do
@@ -240,10 +232,10 @@ describe "String#sub with pattern and block" do
offsets = []
str.sub(/([aeiou])/) do
- md = $~
- md.string.should == str
- offsets << md.offset(0)
- str
+ md = $~
+ md.string.should == str
+ offsets << md.offset(0)
+ str
end.should == "hhellollo"
offsets.should == [[1, 2]]
@@ -284,26 +276,6 @@ describe "String#sub with pattern and block" do
obj.should_receive(:to_s).and_return("ok")
"hello".sub(/.+/) { obj }.should == "ok"
end
-
- it "taints the result if the original string or replacement is tainted" do
- hello = "hello"
- hello_t = "hello"
- a = "a"
- a_t = "a"
- empty = ""
- empty_t = ""
-
- hello_t.taint; a_t.taint; empty_t.taint
-
- hello_t.sub(/./) { a }.tainted?.should == true
- hello_t.sub(/./) { empty }.tainted?.should == true
-
- hello.sub(/./) { a_t }.tainted?.should == true
- hello.sub(/./) { empty_t }.tainted?.should == true
- hello.sub(//) { empty_t }.tainted?.should == true
-
- hello.sub(//.taint) { "foo" }.tainted?.should == false
- end
end
describe "String#sub! with pattern, replacement" do
@@ -313,12 +285,6 @@ describe "String#sub! with pattern, replacement" do
a.should == "h*llo"
end
- it "taints self if replacement is tainted" do
- a = "hello"
- a.sub!(/./.taint, "foo").tainted?.should == false
- a.sub!(/./, "foo".taint).tainted?.should == true
- end
-
it "returns nil if no modifications were made" do
a = "hello"
a.sub!(/z/, '*').should == nil
@@ -326,13 +292,34 @@ describe "String#sub! with pattern, replacement" do
a.should == "hello"
end
- it "raises a RuntimeError when self is frozen" do
+ it "raises a FrozenError when self is frozen" do
s = "hello"
s.freeze
- lambda { s.sub!(/ROAR/, "x") }.should raise_error(RuntimeError)
- lambda { s.sub!(/e/, "e") }.should raise_error(RuntimeError)
- lambda { s.sub!(/[aeiou]/, '*') }.should raise_error(RuntimeError)
+ -> { s.sub!(/ROAR/, "x") }.should raise_error(FrozenError)
+ -> { s.sub!(/e/, "e") }.should raise_error(FrozenError)
+ -> { s.sub!(/[aeiou]/, '*') }.should raise_error(FrozenError)
+ end
+
+ it "handles a pattern in a superset encoding" do
+ string = 'abc'.force_encoding(Encoding::US_ASCII)
+
+ result = string.sub!('é', 'è')
+
+ result.should == nil
+ string.should == 'abc'
+ string.encoding.should == Encoding::US_ASCII
+ end
+
+ it "handles a pattern in a subset encoding" do
+ string = 'été'
+ pattern = 't'.force_encoding(Encoding::US_ASCII)
+
+ result = string.sub!(pattern, 'u')
+
+ result.should == string
+ string.should == 'éué'
+ string.encoding.should == Encoding::UTF_8
end
end
@@ -352,21 +339,15 @@ describe "String#sub! with pattern and block" do
offsets = []
str.dup.sub!(/([aeiou])/) do
- md = $~
- md.string.should == str
- offsets << md.offset(0)
- str
+ md = $~
+ md.string.should == str
+ offsets << md.offset(0)
+ str
end.should == "hhellollo"
offsets.should == [[1, 2]]
end
- it "taints self if block's result is tainted" do
- a = "hello"
- a.sub!(/./.taint) { "foo" }.tainted?.should == false
- a.sub!(/./) { "foo".taint }.tainted?.should == true
- end
-
it "returns nil if no modifications were made" do
a = "hello"
a.sub!(/z/) { '*' }.should == nil
@@ -376,16 +357,16 @@ describe "String#sub! with pattern and block" do
it "raises a RuntimeError if the string is modified while substituting" do
str = "hello"
- lambda { str.sub!(//) { str << 'x' } }.should raise_error(RuntimeError)
+ -> { str.sub!(//) { str << 'x' } }.should raise_error(RuntimeError)
end
- it "raises a RuntimeError when self is frozen" do
+ it "raises a FrozenError when self is frozen" do
s = "hello"
s.freeze
- lambda { s.sub!(/ROAR/) { "x" } }.should raise_error(RuntimeError)
- lambda { s.sub!(/e/) { "e" } }.should raise_error(RuntimeError)
- lambda { s.sub!(/[aeiou]/) { '*' } }.should raise_error(RuntimeError)
+ -> { s.sub!(/ROAR/) { "x" } }.should raise_error(FrozenError)
+ -> { s.sub!(/e/) { "e" } }.should raise_error(FrozenError)
+ -> { s.sub!(/[aeiou]/) { '*' } }.should raise_error(FrozenError)
end
end
@@ -428,7 +409,7 @@ describe "String#sub with pattern and Hash" do
it "uses the hash's value set from default_proc for missing keys" do
hsh = {}
- hsh.default_proc = lambda { |k,v| 'lamb' }
+ hsh.default_proc = -> k, v { 'lamb' }
"food!".sub(/./, hsh).should == "lambood!"
end
@@ -452,26 +433,6 @@ describe "String#sub with pattern and Hash" do
"hello".sub(/(.+)/, 'hello' => repl ).should == repl
end
- it "untrusts the result if the original string is untrusted" do
- str = "Ghana".untrust
- str.sub(/[Aa]na/, 'ana' => '').untrusted?.should be_true
- end
-
- it "untrusts the result if a hash value is untrusted" do
- str = "Ghana"
- str.sub(/a$/, 'a' => 'di'.untrust).untrusted?.should be_true
- end
-
- it "taints the result if the original string is tainted" do
- str = "Ghana".taint
- str.sub(/[Aa]na/, 'ana' => '').tainted?.should be_true
- end
-
- it "taints the result if a hash value is tainted" do
- str = "Ghana"
- str.sub(/a$/, 'a' => 'di'.taint).tainted?.should be_true
- end
-
end
describe "String#sub! with pattern and Hash" do
@@ -513,7 +474,7 @@ describe "String#sub! with pattern and Hash" do
it "uses the hash's value set from default_proc for missing keys" do
hsh = {}
- hsh.default_proc = lambda { |k,v| 'lamb' }
+ hsh.default_proc = -> k, v { 'lamb' }
"food!".sub!(/./, hsh).should == "lambood!"
end
@@ -536,36 +497,16 @@ describe "String#sub! with pattern and Hash" do
repl = '\& \0 \1 \` \\\' \+ \\\\ foo'
"hello".sub!(/(.+)/, 'hello' => repl ).should == repl
end
-
- it "keeps untrusted state" do
- str = "Ghana".untrust
- str.sub!(/[Aa]na/, 'ana' => '').untrusted?.should be_true
- end
-
- it "untrusts self if a hash value is untrusted" do
- str = "Ghana"
- str.sub!(/a$/, 'a' => 'di'.untrust).untrusted?.should be_true
- end
-
- it "keeps tainted state" do
- str = "Ghana".taint
- str.sub!(/[Aa]na/, 'ana' => '').tainted?.should be_true
- end
-
- it "taints self if a hash value is tainted" do
- str = "Ghana"
- str.sub!(/a$/, 'a' => 'di'.taint).tainted?.should be_true
- end
end
describe "String#sub with pattern and without replacement and block" do
it "raises a ArgumentError" do
- lambda { "abca".sub(/a/) }.should raise_error(ArgumentError)
+ -> { "abca".sub(/a/) }.should raise_error(ArgumentError)
end
end
describe "String#sub! with pattern and without replacement and block" do
it "raises a ArgumentError" do
- lambda { "abca".sub!(/a/) }.should raise_error(ArgumentError)
+ -> { "abca".sub!(/a/) }.should raise_error(ArgumentError)
end
end
diff --git a/spec/ruby/core/string/succ_spec.rb b/spec/ruby/core/string/succ_spec.rb
index 311453702d..65047e0aa2 100644
--- a/spec/ruby/core/string/succ_spec.rb
+++ b/spec/ruby/core/string/succ_spec.rb
@@ -1,11 +1,11 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
-require File.expand_path('../shared/succ.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/succ'
describe "String#succ" do
- it_behaves_like(:string_succ, :succ)
+ it_behaves_like :string_succ, :succ
end
describe "String#succ!" do
- it_behaves_like(:string_succ_bang, :"succ!")
+ it_behaves_like :string_succ_bang, :"succ!"
end
diff --git a/spec/ruby/core/string/sum_spec.rb b/spec/ruby/core/string/sum_spec.rb
index 2d68668f49..c283b7c254 100644
--- a/spec/ruby/core/string/sum_spec.rb
+++ b/spec/ruby/core/string/sum_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String#sum" do
it "returns a basic n-bit checksum of the characters in self" do
diff --git a/spec/ruby/core/string/swapcase_spec.rb b/spec/ruby/core/string/swapcase_spec.rb
index c2b583acab..011a213501 100644
--- a/spec/ruby/core/string/swapcase_spec.rb
+++ b/spec/ruby/core/string/swapcase_spec.rb
@@ -1,36 +1,83 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+# frozen_string_literal: false
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String#swapcase" do
it "returns a new string with all uppercase chars from self converted to lowercase and vice versa" do
- "Hello".swapcase.should == "hELLO"
- "cYbEr_PuNk11".swapcase.should == "CyBeR_pUnK11"
- "+++---111222???".swapcase.should == "+++---111222???"
+ "Hello".swapcase.should == "hELLO"
+ "cYbEr_PuNk11".swapcase.should == "CyBeR_pUnK11"
+ "+++---111222???".swapcase.should == "+++---111222???"
end
- it "taints resulting string when self is tainted" do
- "".taint.swapcase.tainted?.should == true
- "hello".taint.swapcase.tainted?.should == true
+ it "returns a String in the same encoding as self" do
+ "Hello".encode("US-ASCII").swapcase.encoding.should == Encoding::US_ASCII
end
- ruby_version_is ''...'2.4' do
- it "is locale insensitive (only upcases a-z and only downcases A-Z)" do
- "ÄÖÜ".swapcase.should == "ÄÖÜ"
- "ärger".swapcase.should == "äRGER"
- "BÄR".swapcase.should == "bÄr"
+ describe "full Unicode case mapping" do
+ it "works for all of Unicode with no option" do
+ "äÖü".swapcase.should == "ÄöÜ"
+ end
+
+ it "updates string metadata" do
+ swapcased = "Aßet".swapcase
+
+ swapcased.should == "aSSET"
+ swapcased.size.should == 5
+ swapcased.bytesize.should == 5
+ swapcased.ascii_only?.should be_true
end
end
- ruby_version_is '2.4' do
- it "works for all of Unicode" do
- "äÖü".swapcase.should == "ÄöÜ"
+ describe "ASCII-only case mapping" do
+ it "does not swapcase non-ASCII characters" do
+ "aßet".swapcase(:ascii).should == "AßET"
+ end
+
+ it "works with substrings" do
+ "prefix aTé"[-3..-1].swapcase(:ascii).should == "Até"
+ end
+ end
+
+ describe "full Unicode case mapping adapted for Turkic languages" do
+ it "swaps case of ASCII characters according to Turkic semantics" do
+ "aiS".swapcase(:turkic).should == "Aİs"
+ end
+
+ it "allows Lithuanian as an extra option" do
+ "aiS".swapcase(:turkic, :lithuanian).should == "Aİs"
+ end
+
+ it "does not allow any other additional option" do
+ -> { "aiS".swapcase(:turkic, :ascii) }.should raise_error(ArgumentError)
end
end
- it "returns subclass instances when called on a subclass" do
- StringSpecs::MyString.new("").swapcase.should be_an_instance_of(StringSpecs::MyString)
- StringSpecs::MyString.new("hello").swapcase.should be_an_instance_of(StringSpecs::MyString)
+ describe "full Unicode case mapping adapted for Lithuanian" do
+ it "currently works the same as full Unicode case mapping" do
+ "Iß".swapcase(:lithuanian).should == "iSS"
+ end
+
+ it "allows Turkic as an extra option (and applies Turkic semantics)" do
+ "iS".swapcase(:lithuanian, :turkic).should == "İs"
+ end
+
+ it "does not allow any other additional option" do
+ -> { "aiS".swapcase(:lithuanian, :ascii) }.should raise_error(ArgumentError)
+ end
+ end
+
+ it "does not allow the :fold option for upcasing" do
+ -> { "abc".swapcase(:fold) }.should raise_error(ArgumentError)
+ end
+
+ it "does not allow invalid options" do
+ -> { "abc".swapcase(:invalid_option) }.should raise_error(ArgumentError)
+ end
+
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("").swapcase.should be_an_instance_of(String)
+ StringSpecs::MyString.new("hello").swapcase.should be_an_instance_of(String)
end
end
@@ -41,12 +88,92 @@ describe "String#swapcase!" do
a.should == "CyBeR_pUnK11"
end
- ruby_version_is '2.4' do
- it "modifies self in place for all of Unicode" do
+ it "modifies self in place for non-ascii-compatible encodings" do
+ a = "cYbEr_PuNk11".encode("utf-16le")
+ a.swapcase!
+ a.should == "CyBeR_pUnK11".encode("utf-16le")
+ end
+
+ describe "full Unicode case mapping" do
+ it "modifies self in place for all of Unicode with no option" do
a = "äÖü"
- a.swapcase!.should equal(a)
+ a.swapcase!
a.should == "ÄöÜ"
end
+
+ it "works for non-ascii-compatible encodings" do
+ a = "äÖü".encode("utf-16le")
+ a.swapcase!
+ a.should == "ÄöÜ".encode("utf-16le")
+ end
+
+ it "updates string metadata" do
+ swapcased = "Aßet"
+ swapcased.swapcase!
+
+ swapcased.should == "aSSET"
+ swapcased.size.should == 5
+ swapcased.bytesize.should == 5
+ swapcased.ascii_only?.should be_true
+ end
+ end
+
+ describe "modifies self in place for ASCII-only case mapping" do
+ it "does not swapcase non-ASCII characters" do
+ a = "aßet"
+ a.swapcase!(:ascii)
+ a.should == "AßET"
+ end
+
+ it "works for non-ascii-compatible encodings" do
+ a = "aBc".encode("utf-16le")
+ a.swapcase!(:ascii)
+ a.should == "AbC".encode("utf-16le")
+ end
+ end
+
+ describe "modifies self in place for full Unicode case mapping adapted for Turkic languages" do
+ it "swaps case of ASCII characters according to Turkic semantics" do
+ a = "aiS"
+ a.swapcase!(:turkic)
+ a.should == "Aİs"
+ end
+
+ it "allows Lithuanian as an extra option" do
+ a = "aiS"
+ a.swapcase!(:turkic, :lithuanian)
+ a.should == "Aİs"
+ end
+
+ it "does not allow any other additional option" do
+ -> { a = "aiS"; a.swapcase!(:turkic, :ascii) }.should raise_error(ArgumentError)
+ end
+ end
+
+ describe "full Unicode case mapping adapted for Lithuanian" do
+ it "currently works the same as full Unicode case mapping" do
+ a = "Iß"
+ a.swapcase!(:lithuanian)
+ a.should == "iSS"
+ end
+
+ it "allows Turkic as an extra option (and applies Turkic semantics)" do
+ a = "iS"
+ a.swapcase!(:lithuanian, :turkic)
+ a.should == "İs"
+ end
+
+ it "does not allow any other additional option" do
+ -> { a = "aiS"; a.swapcase!(:lithuanian, :ascii) }.should raise_error(ArgumentError)
+ end
+ end
+
+ it "does not allow the :fold option for upcasing" do
+ -> { a = "abc"; a.swapcase!(:fold) }.should raise_error(ArgumentError)
+ end
+
+ it "does not allow invalid options" do
+ -> { a = "abc"; a.swapcase!(:invalid_option) }.should raise_error(ArgumentError)
end
it "returns nil if no modifications were made" do
@@ -57,10 +184,10 @@ describe "String#swapcase!" do
"".swapcase!.should == nil
end
- it "raises a RuntimeError when self is frozen" do
+ it "raises a FrozenError when self is frozen" do
["", "hello"].each do |a|
a.freeze
- lambda { a.swapcase! }.should raise_error(RuntimeError)
+ -> { a.swapcase! }.should raise_error(FrozenError)
end
end
end
diff --git a/spec/ruby/core/string/to_c_spec.rb b/spec/ruby/core/string/to_c_spec.rb
index da353e18d5..1813890e72 100644
--- a/spec/ruby/core/string/to_c_spec.rb
+++ b/spec/ruby/core/string/to_c_spec.rb
@@ -1,99 +1,53 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
+require_relative '../../shared/kernel/complex'
+require_relative 'fixtures/to_c'
describe "String#to_c" do
- it "returns a Complex object" do
- '9'.to_c.should be_an_instance_of(Complex)
- end
-
- it "understands integers" do
- '20'.to_c.should == Complex(20)
- end
-
- it "understands negative integers" do
- '-3'.to_c.should == Complex(-3)
- end
-
- it "understands fractions (numerator/denominator) for the real part" do
- '2/3'.to_c.should == Complex(Rational(2, 3))
- end
-
- it "understands fractions (numerator/denominator) for the imaginary part" do
- '4+2/3i'.to_c.should == Complex(4, Rational(2, 3))
- end
-
- it "understands negative fractions (-numerator/denominator) for the real part" do
- '-2/3'.to_c.should == Complex(Rational(-2, 3))
- end
-
- it "understands negative fractions (-numerator/denominator) for the imaginary part" do
- '7-2/3i'.to_c.should == Complex(7, Rational(-2, 3))
- end
-
- it "understands floats (a.b) for the real part" do
- '2.3'.to_c.should == Complex(2.3)
- end
-
- it "understands floats (a.b) for the imaginary part" do
- '4+2.3i'.to_c.should == Complex(4, 2.3)
- end
-
- it "understands negative floats (-a.b) for the real part" do
- '-2.33'.to_c.should == Complex(-2.33)
- end
-
- it "understands negative floats (-a.b) for the imaginary part" do
- '7-28.771i'.to_c.should == Complex(7, -28.771)
- end
-
- it "understands an integer followed by 'i' to mean that integer is the imaginary part" do
- '35i'.to_c.should == Complex(0,35)
- end
-
- it "understands a negative integer followed by 'i' to mean that negative integer is the imaginary part" do
- '-29i'.to_c.should == Complex(0,-29)
- end
-
- it "understands an 'i' by itself as denoting a complex number with an imaginary part of 1" do
- 'i'.to_c.should == Complex(0,1)
- end
-
- it "understands a '-i' by itself as denoting a complex number with an imaginary part of -1" do
- '-i'.to_c.should == Complex(0,-1)
- end
-
- it "understands 'a+bi' to mean a complex number with 'a' as the real part, 'b' as the imaginary" do
- '79+4i'.to_c.should == Complex(79,4)
- end
+ it_behaves_like :kernel_complex, :to_c_method, StringSpecs
+end
- it "understands 'a-bi' to mean a complex number with 'a' as the real part, '-b' as the imaginary" do
- '79-4i'.to_c.should == Complex(79,-4)
+describe "String#to_c" do
+ it "returns a complex number with 0 as the real part, 0 as the imaginary part for unrecognised Strings" do
+ 'ruby'.to_c.should == Complex(0, 0)
end
- it "understands scientific notation for the real part" do
- '2e3+4i'.to_c.should == Complex(2e3,4)
+ it "ignores trailing garbage" do
+ '79+4iruby'.to_c.should == Complex(79, 4)
+ '7__9+4__0i'.to_c.should == Complex(7, 0)
end
- it "understands negative scientific notation for the real part" do
- '-2e3+4i'.to_c.should == Complex(-2e3,4)
- end
+ context "it treats special float value strings as characters" do
+ it "parses any string that starts with 'I' as 1i" do
+ 'Infinity'.to_c.should == Complex(0, 1)
+ '-Infinity'.to_c.should == Complex(0, -1)
+ 'Insecure'.to_c.should == Complex(0, 1)
+ '-Insecure'.to_c.should == Complex(0, -1)
+ end
- it "understands scientific notation for the imaginary part" do
- '4+2e3i'.to_c.should == Complex(4, 2e3)
+ it "does not parse any numeric information in 'NaN'" do
+ 'NaN'.to_c.should == Complex(0, 0)
+ end
end
- it "understands negative scientific notation for the imaginary part" do
- '4-2e3i'.to_c.should == Complex(4, -2e3)
+ it "allows null-byte" do
+ "1-2i\0".to_c.should == Complex(1, -2)
+ "1\0-2i".to_c.should == Complex(1, 0)
+ "\01-2i".to_c.should == Complex(0, 0)
end
- it "understands scientific notation for the real and imaginary part in the same String" do
- '2e3+2e4i'.to_c.should == Complex(2e3,2e4)
+ it "raises Encoding::CompatibilityError if String is in not ASCII-compatible encoding" do
+ -> {
+ '79+4i'.encode("UTF-16").to_c
+ }.should raise_error(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16")
end
- it "understands negative scientific notation for the real and imaginary part in the same String" do
- '-2e3-2e4i'.to_c.should == Complex(-2e3,-2e4)
- end
+ it "treats a sequence of underscores as an end of Complex string" do
+ "5+3_1i".to_c.should == Complex(5, 31)
+ "5+3__1i".to_c.should == Complex(5)
+ "5+3___1i".to_c.should == Complex(5)
- it "returns a complex number with 0 as the real part, 0 as the imaginary part for unrecognised Strings" do
- 'ruby'.to_c.should == Complex(0,0)
+ "12_3".to_c.should == Complex(123)
+ "12__3".to_c.should == Complex(12)
+ "12___3".to_c.should == Complex(12)
end
end
diff --git a/spec/ruby/core/string/to_f_spec.rb b/spec/ruby/core/string/to_f_spec.rb
index 8454651ab2..abfd2517b6 100644
--- a/spec/ruby/core/string/to_f_spec.rb
+++ b/spec/ruby/core/string/to_f_spec.rb
@@ -1,19 +1,19 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
# src.scan(/[+-]?[\d_]+\.[\d_]+(e[+-]?[\d_]+)?\b|[+-]?[\d_]+e[+-]?[\d_]+\b/i)
describe "String#to_f" do
it "treats leading characters of self as a floating point number" do
- "123.45e1".to_f.should == 1234.5
- "45.67 degrees".to_f.should == 45.67
- "0".to_f.should == 0.0
- "123.45e1".to_f.should == 1234.5
+ "123.45e1".to_f.should == 1234.5
+ "45.67 degrees".to_f.should == 45.67
+ "0".to_f.should == 0.0
- ".5".to_f.should == 0.5
- ".5e1".to_f.should == 5.0
- "5e".to_f.should == 5.0
- "5E".to_f.should == 5.0
+ ".5".to_f.should == 0.5
+ ".5e1".to_f.should == 5.0
+ "5.".to_f.should == 5.0
+ "5e".to_f.should == 5.0
+ "5E".to_f.should == 5.0
end
it "treats special float value strings as characters" do
@@ -42,18 +42,39 @@ describe "String#to_f" do
"1_234_567.890_1".to_f.should == 1_234_567.890_1
end
- it "returns 0 for strings with any non-digit in them" do
- "blah".to_f.should == 0
- "0b5".to_f.should == 0
- "0d5".to_f.should == 0
- "0o5".to_f.should == 0
- "0xx5".to_f.should == 0
- end
-
it "returns 0 for strings with leading underscores" do
"_9".to_f.should == 0
end
+ it "stops if the underscore is not followed or preceded by a number" do
+ "1__2".to_f.should == 1.0
+ "1_.2".to_f.should == 1.0
+ "1._2".to_f.should == 1.0
+ "1.2_e2".to_f.should == 1.2
+ "1.2e_2".to_f.should == 1.2
+ "1_x2".to_f.should == 1.0
+ "1x_2".to_f.should == 1.0
+ "+_1".to_f.should == 0.0
+ "-_1".to_f.should == 0.0
+ end
+
+ it "does not allow prefixes to autodetect the base" do
+ "0b10".to_f.should == 0
+ "010".to_f.should == 10
+ "0o10".to_f.should == 0
+ "0d10".to_f.should == 0
+ "0x10".to_f.should == 0
+ end
+
+ it "treats any non-numeric character other than '.', 'e' and '_' as terminals" do
+ "blah".to_f.should == 0
+ "1b5".to_f.should == 1
+ "1d5".to_f.should == 1
+ "1o5".to_f.should == 1
+ "1xx5".to_f.should == 1
+ "x5".to_f.should == 0
+ end
+
it "takes an optional sign" do
"-45.67 degrees".to_f.should == -45.67
"+45.67 degrees".to_f.should == 45.67
@@ -62,8 +83,60 @@ describe "String#to_f" do
(1.0 / "-0".to_f).to_s.should == "-Infinity"
end
+ it "treats a second 'e' as terminal" do
+ "1.234e1e2".to_f.should == 1.234e1
+ end
+
+ it "treats a second '.' as terminal" do
+ "1.2.3".to_f.should == 1.2
+ end
+
+ it "treats a '.' after an 'e' as terminal" do
+ "1.234e1.9".to_f.should == 1.234e1
+ end
+
it "returns 0.0 if the conversion fails" do
"bad".to_f.should == 0.0
"thx1138".to_f.should == 0.0
end
+
+ it "ignores leading and trailing whitespace" do
+ " 1.2".to_f.should == 1.2
+ "1.2 ".to_f.should == 1.2
+ " 1.2 ".to_f.should == 1.2
+ "\t1.2".to_f.should == 1.2
+ "\n1.2".to_f.should == 1.2
+ "\v1.2".to_f.should == 1.2
+ "\f1.2".to_f.should == 1.2
+ "\r1.2".to_f.should == 1.2
+ end
+
+ it "treats non-printable ASCII characters as terminals" do
+ "\0001.2".to_f.should == 0
+ "\0011.2".to_f.should == 0
+ "\0371.2".to_f.should == 0
+ "\1771.2".to_f.should == 0
+ "\2001.2".b.to_f.should == 0
+ "\3771.2".b.to_f.should == 0
+ end
+
+ ruby_version_is "3.2.3" do
+ it "raises Encoding::CompatibilityError if String is in not ASCII-compatible encoding" do
+ -> {
+ '1.2'.encode("UTF-16").to_f
+ }.should raise_error(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16")
+ end
+ end
+
+ it "allows String representation without a fractional part" do
+ "1.".to_f.should == 1.0
+ "+1.".to_f.should == 1.0
+ "-1.".to_f.should == -1.0
+ "1.e+0".to_f.should == 1.0
+ "1.e+0".to_f.should == 1.0
+
+ ruby_bug "#20705", ""..."3.4" do
+ "1.e-2".to_f.should be_close(0.01, TOLERANCE)
+ end
+ end
end
diff --git a/spec/ruby/core/string/to_i_spec.rb b/spec/ruby/core/string/to_i_spec.rb
index be0f67a46a..39f69acda3 100644
--- a/spec/ruby/core/string/to_i_spec.rb
+++ b/spec/ruby/core/string/to_i_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String#to_i" do
it "returns 0 for strings with leading underscores" do
@@ -10,6 +10,18 @@ describe "String#to_i" do
"1_2_3asdf".to_i.should == 123
end
+ it "ignores multiple non-consecutive underscores when the first digit is 0" do
+ (2..16).each do |base|
+ "0_0_010".to_i(base).should == base;
+ end
+ end
+
+ it "bails out at the first double underscore if the first digit is 0" do
+ (2..16).each do |base|
+ "010__1".to_i(base).should == base;
+ end
+ end
+
it "ignores leading whitespaces" do
[ " 123", " 123", "\r\n\r\n123", "\t\t123",
"\r\n\t\n123", " \t\n\r\t 123"].each do |str|
@@ -126,34 +138,34 @@ describe "String#to_i" do
end
it "raises an ArgumentError for illegal bases (1, < 0 or > 36)" do
- lambda { "".to_i(1) }.should raise_error(ArgumentError)
- lambda { "".to_i(-1) }.should raise_error(ArgumentError)
- lambda { "".to_i(37) }.should raise_error(ArgumentError)
+ -> { "".to_i(1) }.should raise_error(ArgumentError)
+ -> { "".to_i(-1) }.should raise_error(ArgumentError)
+ -> { "".to_i(37) }.should raise_error(ArgumentError)
end
- it "returns a Fixnum for long strings with trailing spaces" do
+ it "returns an Integer for long strings with trailing spaces" do
"0 ".to_i.should == 0
- "0 ".to_i.should be_an_instance_of(Fixnum)
+ "0 ".to_i.should be_an_instance_of(Integer)
"10 ".to_i.should == 10
- "10 ".to_i.should be_an_instance_of(Fixnum)
+ "10 ".to_i.should be_an_instance_of(Integer)
"-10 ".to_i.should == -10
- "-10 ".to_i.should be_an_instance_of(Fixnum)
+ "-10 ".to_i.should be_an_instance_of(Integer)
end
- it "returns a Fixnum for long strings with leading spaces" do
+ it "returns an Integer for long strings with leading spaces" do
" 0".to_i.should == 0
- " 0".to_i.should be_an_instance_of(Fixnum)
+ " 0".to_i.should be_an_instance_of(Integer)
" 10".to_i.should == 10
- " 10".to_i.should be_an_instance_of(Fixnum)
+ " 10".to_i.should be_an_instance_of(Integer)
" -10".to_i.should == -10
- " -10".to_i.should be_an_instance_of(Fixnum)
+ " -10".to_i.should be_an_instance_of(Integer)
end
- it "returns the correct Bignum for long strings" do
+ it "returns the correct Integer for long strings" do
"245789127594125924165923648312749312749327482".to_i.should == 245789127594125924165923648312749312749327482
"-245789127594125924165923648312749312749327482".to_i.should == -245789127594125924165923648312749312749327482
end
diff --git a/spec/ruby/core/string/to_r_spec.rb b/spec/ruby/core/string/to_r_spec.rb
index 7fa16f6f49..4ffbb10d98 100644
--- a/spec/ruby/core/string/to_r_spec.rb
+++ b/spec/ruby/core/string/to_r_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
describe "String#to_r" do
it "returns a Rational object" do
@@ -29,10 +29,14 @@ describe "String#to_r" do
"a1765, ".to_r.should_not == Rational(1765, 1)
end
- it "treats leading hypens as minus signs" do
+ it "treats leading hyphen as minus signs" do
"-20".to_r.should == Rational(-20, 1)
end
+ it "accepts leading plus signs" do
+ "+20".to_r.should == Rational(20, 1)
+ end
+
it "does not treat a leading period without a numeric prefix as a decimal point" do
".9".to_r.should_not == Rational(8106479329266893, 9007199254740992)
end
diff --git a/spec/ruby/core/string/to_s_spec.rb b/spec/ruby/core/string/to_s_spec.rb
index b483b1b138..e5872745a8 100644
--- a/spec/ruby/core/string/to_s_spec.rb
+++ b/spec/ruby/core/string/to_s_spec.rb
@@ -1,7 +1,7 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
-require File.expand_path('../shared/to_s.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/to_s'
describe "String#to_s" do
- it_behaves_like(:string_to_s, :to_s)
+ it_behaves_like :string_to_s, :to_s
end
diff --git a/spec/ruby/core/string/to_str_spec.rb b/spec/ruby/core/string/to_str_spec.rb
index fb1260a687..e24262a7ae 100644
--- a/spec/ruby/core/string/to_str_spec.rb
+++ b/spec/ruby/core/string/to_str_spec.rb
@@ -1,7 +1,7 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
-require File.expand_path('../shared/to_s.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/to_s'
describe "String#to_str" do
- it_behaves_like(:string_to_s, :to_str)
+ it_behaves_like :string_to_s, :to_str
end
diff --git a/spec/ruby/core/string/to_sym_spec.rb b/spec/ruby/core/string/to_sym_spec.rb
index 7659f266cd..f9135211ce 100644
--- a/spec/ruby/core/string/to_sym_spec.rb
+++ b/spec/ruby/core/string/to_sym_spec.rb
@@ -1,7 +1,7 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
-require File.expand_path('../shared/to_sym.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/to_sym'
describe "String#to_sym" do
- it_behaves_like(:string_to_sym, :to_sym)
+ it_behaves_like :string_to_sym, :to_sym
end
diff --git a/spec/ruby/core/string/tr_s_spec.rb b/spec/ruby/core/string/tr_s_spec.rb
index ea2ffa71b9..dd72da440c 100644
--- a/spec/ruby/core/string/tr_s_spec.rb
+++ b/spec/ruby/core/string/tr_s_spec.rb
@@ -1,6 +1,7 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+# frozen_string_literal: false
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String#tr_s" do
it "returns a string processed according to tr with newly duplicate characters removed" do
@@ -17,6 +18,15 @@ describe "String#tr_s" do
"hello ^--^".tr_s("---", "_").should == "hello ^_^"
end
+ ruby_bug "#19769", ""..."3.3" do
+ it "accepts c1-c1 notation to denote range of one character" do
+ "hello".tr_s('e-e', 'x').should == "hxllo"
+ "123456789".tr_s("2-23","xy").should == "1xy456789"
+ "hello ^-^".tr_s("e-", "a-a_").should == "hallo ^_^"
+ "hello ^-^".tr_s("---o", "_a").should == "hella ^_^"
+ end
+ end
+
it "pads to_str with its last char if it is shorter than from_string" do
"this".tr_s("this", "x").should == "x"
end
@@ -45,64 +55,51 @@ describe "String#tr_s" do
"bla".tr_s(from_str, to_str).should == "BlA"
end
- it "returns subclass instances when called on a subclass" do
- StringSpecs::MyString.new("hello").tr_s("e", "a").should be_an_instance_of(StringSpecs::MyString)
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("hello").tr_s("e", "a").should be_an_instance_of(String)
end
- it "taints the result when self is tainted" do
- ["h", "hello"].each do |str|
- tainted_str = str.dup.taint
-
- tainted_str.tr_s("e", "a").tainted?.should == true
-
- str.tr_s("e".taint, "a").tainted?.should == false
- str.tr_s("e", "a".taint).tainted?.should == false
- end
+ # http://redmine.ruby-lang.org/issues/show/1839
+ it "can replace a 7-bit ASCII character with a multibyte one" do
+ a = "uber"
+ a.encoding.should == Encoding::UTF_8
+ b = a.tr_s("u","ü")
+ b.should == "über"
+ b.encoding.should == Encoding::UTF_8
end
- with_feature :encoding do
- # http://redmine.ruby-lang.org/issues/show/1839
- it "can replace a 7-bit ASCII character with a multibyte one" do
- a = "uber"
- a.encoding.should == Encoding::UTF_8
- b = a.tr_s("u","ü")
- b.should == "über"
- b.encoding.should == Encoding::UTF_8
- end
-
- it "can replace multiple 7-bit ASCII characters with a multibyte one" do
- a = "uuuber"
- a.encoding.should == Encoding::UTF_8
- b = a.tr_s("u","ü")
- b.should == "über"
- b.encoding.should == Encoding::UTF_8
- end
-
- it "can replace a multibyte character with a single byte one" do
- a = "über"
- a.encoding.should == Encoding::UTF_8
- b = a.tr_s("ü","u")
- b.should == "uber"
- b.encoding.should == Encoding::UTF_8
- end
+ it "can replace multiple 7-bit ASCII characters with a multibyte one" do
+ a = "uuuber"
+ a.encoding.should == Encoding::UTF_8
+ b = a.tr_s("u","ü")
+ b.should == "über"
+ b.encoding.should == Encoding::UTF_8
+ end
- it "can replace multiple multibyte characters with a single byte one" do
- a = "üüüber"
- a.encoding.should == Encoding::UTF_8
- b = a.tr_s("ü","u")
- b.should == "uber"
- b.encoding.should == Encoding::UTF_8
- end
+ it "can replace a multibyte character with a single byte one" do
+ a = "über"
+ a.encoding.should == Encoding::UTF_8
+ b = a.tr_s("ü","u")
+ b.should == "uber"
+ b.encoding.should == Encoding::UTF_8
+ end
- it "does not replace a multibyte character where part of the bytes match the tr string" do
- str = "椎名深夏"
- a = "\u0080\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008A\u008B\u008C\u008E\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009A\u009B\u009C\u009E\u009F"
- b = "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ"
- str.tr_s(a, b).should == "椎名深夏"
- end
+ it "can replace multiple multibyte characters with a single byte one" do
+ a = "üüüber"
+ a.encoding.should == Encoding::UTF_8
+ b = a.tr_s("ü","u")
+ b.should == "uber"
+ b.encoding.should == Encoding::UTF_8
+ end
+ it "does not replace a multibyte character where part of the bytes match the tr string" do
+ str = "椎名深夏"
+ a = "\u0080\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008A\u008B\u008C\u008E\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009A\u009B\u009C\u009E\u009F"
+ b = "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ"
+ str.tr_s(a, b).should == "椎名深夏"
end
+
end
describe "String#tr_s!" do
@@ -127,10 +124,10 @@ describe "String#tr_s!" do
s.should == "hello"
end
- it "raises a RuntimeError if self is frozen" do
+ it "raises a FrozenError if self is frozen" do
s = "hello".freeze
- lambda { s.tr_s!("el", "ar") }.should raise_error(RuntimeError)
- lambda { s.tr_s!("l", "r") }.should raise_error(RuntimeError)
- lambda { s.tr_s!("", "") }.should raise_error(RuntimeError)
+ -> { s.tr_s!("el", "ar") }.should raise_error(FrozenError)
+ -> { s.tr_s!("l", "r") }.should raise_error(FrozenError)
+ -> { s.tr_s!("", "") }.should raise_error(FrozenError)
end
end
diff --git a/spec/ruby/core/string/tr_spec.rb b/spec/ruby/core/string/tr_spec.rb
index 16d2d318e1..75841a974f 100644
--- a/spec/ruby/core/string/tr_spec.rb
+++ b/spec/ruby/core/string/tr_spec.rb
@@ -1,6 +1,7 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+# frozen_string_literal: false
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String#tr" do
it "returns a new string with the characters from from_string replaced by the ones in to_string" do
@@ -16,17 +17,26 @@ describe "String#tr" do
"hello ^-^".tr("---", "_").should == "hello ^_^"
end
+ ruby_bug "#19769", ""..."3.3" do
+ it "accepts c1-c1 notation to denote range of one character" do
+ "hello".tr('e-e', 'x').should == "hxllo"
+ "123456789".tr("2-23","xy").should == "1xy456789"
+ "hello ^-^".tr("e-", "a-a_").should == "hallo ^_^"
+ "hello ^-^".tr("---o", "_a").should == "hella ^_^"
+ end
+ end
+
it "pads to_str with its last char if it is shorter than from_string" do
"this".tr("this", "x").should == "xxxx"
"hello".tr("a-z", "A-H.").should == "HE..."
end
it "raises an ArgumentError a descending range in the replacement as containing just the start character" do
- lambda { "hello".tr("a-y", "z-b") }.should raise_error(ArgumentError)
+ -> { "hello".tr("a-y", "z-b") }.should raise_error(ArgumentError)
end
it "raises an ArgumentError a descending range in the source as empty" do
- lambda { "hello".tr("l-a", "z") }.should raise_error(ArgumentError)
+ -> { "hello".tr("l-a", "z") }.should raise_error(ArgumentError)
end
it "translates chars not in from_string when it starts with a ^" do
@@ -57,47 +67,34 @@ describe "String#tr" do
"bla".tr(from_str, to_str).should == "BlA"
end
- it "returns subclass instances when called on a subclass" do
- StringSpecs::MyString.new("hello").tr("e", "a").should be_an_instance_of(StringSpecs::MyString)
+ it "returns Stringinstances when called on a subclass" do
+ StringSpecs::MyString.new("hello").tr("e", "a").should be_an_instance_of(String)
end
- it "taints the result when self is tainted" do
- ["h", "hello"].each do |str|
- tainted_str = str.dup.taint
-
- tainted_str.tr("e", "a").tainted?.should == true
-
- str.tr("e".taint, "a").tainted?.should == false
- str.tr("e", "a".taint).tainted?.should == false
- end
+ # http://redmine.ruby-lang.org/issues/show/1839
+ it "can replace a 7-bit ASCII character with a multibyte one" do
+ a = "uber"
+ a.encoding.should == Encoding::UTF_8
+ b = a.tr("u","ü")
+ b.should == "über"
+ b.encoding.should == Encoding::UTF_8
end
- with_feature :encoding do
- # http://redmine.ruby-lang.org/issues/show/1839
- it "can replace a 7-bit ASCII character with a multibyte one" do
- a = "uber"
- a.encoding.should == Encoding::UTF_8
- b = a.tr("u","ü")
- b.should == "über"
- b.encoding.should == Encoding::UTF_8
- end
-
- it "can replace a multibyte character with a single byte one" do
- a = "über"
- a.encoding.should == Encoding::UTF_8
- b = a.tr("ü","u")
- b.should == "uber"
- b.encoding.should == Encoding::UTF_8
- end
-
- it "does not replace a multibyte character where part of the bytes match the tr string" do
- str = "椎名深夏"
- a = "\u0080\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008A\u008B\u008C\u008E\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009A\u009B\u009C\u009E\u009F"
- b = "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ"
- str.tr(a, b).should == "椎名深夏"
- end
+ it "can replace a multibyte character with a single byte one" do
+ a = "über"
+ a.encoding.should == Encoding::UTF_8
+ b = a.tr("ü","u")
+ b.should == "uber"
+ b.encoding.should == Encoding::UTF_8
+ end
+ it "does not replace a multibyte character where part of the bytes match the tr string" do
+ str = "椎名深夏"
+ a = "\u0080\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008A\u008B\u008C\u008E\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009A\u009B\u009C\u009E\u009F"
+ b = "€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ"
+ str.tr(a, b).should == "椎名深夏"
end
+
end
describe "String#tr!" do
@@ -122,10 +119,10 @@ describe "String#tr!" do
s.should == "hello"
end
- it "raises a RuntimeError if self is frozen" do
+ it "raises a FrozenError if self is frozen" do
s = "abcdefghijklmnopqR".freeze
- lambda { s.tr!("cdefg", "12") }.should raise_error(RuntimeError)
- lambda { s.tr!("R", "S") }.should raise_error(RuntimeError)
- lambda { s.tr!("", "") }.should raise_error(RuntimeError)
+ -> { s.tr!("cdefg", "12") }.should raise_error(FrozenError)
+ -> { s.tr!("R", "S") }.should raise_error(FrozenError)
+ -> { s.tr!("", "") }.should raise_error(FrozenError)
end
end
diff --git a/spec/ruby/core/string/try_convert_spec.rb b/spec/ruby/core/string/try_convert_spec.rb
index ce12839c59..72ce5dd8b2 100644
--- a/spec/ruby/core/string/try_convert_spec.rb
+++ b/spec/ruby/core/string/try_convert_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String.try_convert" do
it "returns the argument if it's a String" do
@@ -39,12 +39,12 @@ describe "String.try_convert" do
it "sends #to_str to the argument and raises TypeError if it's not a kind of String" do
obj = mock("to_str")
obj.should_receive(:to_str).and_return(Object.new)
- lambda { String.try_convert obj }.should raise_error(TypeError)
+ -> { String.try_convert obj }.should raise_error(TypeError, "can't convert MockObject to String (MockObject#to_str gives Object)")
end
it "does not rescue exceptions raised by #to_str" do
obj = mock("to_str")
obj.should_receive(:to_str).and_raise(RuntimeError)
- lambda { String.try_convert obj }.should raise_error(RuntimeError)
+ -> { String.try_convert obj }.should raise_error(RuntimeError)
end
end
diff --git a/spec/ruby/core/string/uminus_spec.rb b/spec/ruby/core/string/uminus_spec.rb
index 53e73b7e67..46d88f6704 100644
--- a/spec/ruby/core/string/uminus_spec.rb
+++ b/spec/ruby/core/string/uminus_spec.rb
@@ -1,21 +1,6 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'shared/dedup'
-ruby_version_is "2.3" do
- describe 'String#-@' do
- it 'returns self if the String is frozen' do
- input = 'foo'.freeze
- output = -input
-
- output.equal?(input).should == true
- output.frozen?.should == true
- end
-
- it 'returns a frozen copy if the String is not frozen' do
- input = 'foo'
- output = -input
-
- output.frozen?.should == true
- output.should == 'foo'
- end
- end
+describe 'String#-@' do
+ it_behaves_like :string_dedup, :-@
end
diff --git a/spec/ruby/core/string/undump_spec.rb b/spec/ruby/core/string/undump_spec.rb
new file mode 100644
index 0000000000..6ff220161c
--- /dev/null
+++ b/spec/ruby/core/string/undump_spec.rb
@@ -0,0 +1,441 @@
+# encoding: utf-8
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+describe "String#undump" do
+ it "does not take into account if a string is frozen" do
+ '"foo"'.freeze.undump.should_not.frozen?
+ end
+
+ it "always returns String instance" do
+ StringSpecs::MyString.new('"foo"').undump.should be_an_instance_of(String)
+ end
+
+ it "strips outer \"" do
+ '"foo"'.undump.should == 'foo'
+ end
+
+ it "returns a string with special characters in \\<char> notation replaced with the characters" do
+ [ ['"\\a"', "\a"],
+ ['"\\b"', "\b"],
+ ['"\\t"', "\t"],
+ ['"\\n"', "\n"],
+ ['"\\v"', "\v"],
+ ['"\\f"', "\f"],
+ ['"\\r"', "\r"],
+ ['"\\e"', "\e"]
+ ].should be_computed_by(:undump)
+ end
+
+ it "returns a string with unescaped sequences \" and \\" do
+ [ ['"\\""' , "\""],
+ ['"\\\\"', "\\"]
+ ].should be_computed_by(:undump)
+ end
+
+ it "returns a string with unescaped sequences \\#<char> when # is followed by $, @, {" do
+ [ ['"\\#$PATH"', "\#$PATH"],
+ ['"\\#@a"', "\#@a"],
+ ['"\\#@@a"', "\#@@a"],
+ ['"\\#{a}"', "\#{a}"]
+ ].should be_computed_by(:undump)
+ end
+
+ it "returns a string with # not escaped when followed by any other character" do
+ [ ['"#"', '#'],
+ ['"#1"', '#1']
+ ].should be_computed_by(:undump)
+ end
+
+ it "returns a string with printable non-alphanumeric characters" do
+ [ ['" "', ' '],
+ ['"!"', '!'],
+ ['"$"', '$'],
+ ['"%"', '%'],
+ ['"&"', '&'],
+ ['"\'"', '\''],
+ ['"("', '('],
+ ['")"', ')'],
+ ['"*"', '*'],
+ ['"+"', '+'],
+ ['","', ','],
+ ['"-"', '-'],
+ ['"."', '.'],
+ ['"/"', '/'],
+ ['":"', ':'],
+ ['";"', ';'],
+ ['"<"', '<'],
+ ['"="', '='],
+ ['">"', '>'],
+ ['"?"', '?'],
+ ['"@"', '@'],
+ ['"["', '['],
+ ['"]"', ']'],
+ ['"^"', '^'],
+ ['"_"', '_'],
+ ['"`"', '`'],
+ ['"{"', '{'],
+ ['"|"', '|'],
+ ['"}"', '}'],
+ ['"~"', '~']
+ ].should be_computed_by(:undump)
+ end
+
+ it "returns a string with numeric characters unescaped" do
+ [ ['"0"', "0"],
+ ['"1"', "1"],
+ ['"2"', "2"],
+ ['"3"', "3"],
+ ['"4"', "4"],
+ ['"5"', "5"],
+ ['"6"', "6"],
+ ['"7"', "7"],
+ ['"8"', "8"],
+ ['"9"', "9"],
+ ].should be_computed_by(:undump)
+ end
+
+ it "returns a string with upper-case alpha characters unescaped" do
+ [ ['"A"', 'A'],
+ ['"B"', 'B'],
+ ['"C"', 'C'],
+ ['"D"', 'D'],
+ ['"E"', 'E'],
+ ['"F"', 'F'],
+ ['"G"', 'G'],
+ ['"H"', 'H'],
+ ['"I"', 'I'],
+ ['"J"', 'J'],
+ ['"K"', 'K'],
+ ['"L"', 'L'],
+ ['"M"', 'M'],
+ ['"N"', 'N'],
+ ['"O"', 'O'],
+ ['"P"', 'P'],
+ ['"Q"', 'Q'],
+ ['"R"', 'R'],
+ ['"S"', 'S'],
+ ['"T"', 'T'],
+ ['"U"', 'U'],
+ ['"V"', 'V'],
+ ['"W"', 'W'],
+ ['"X"', 'X'],
+ ['"Y"', 'Y'],
+ ['"Z"', 'Z']
+ ].should be_computed_by(:undump)
+ end
+
+ it "returns a string with lower-case alpha characters unescaped" do
+ [ ['"a"', 'a'],
+ ['"b"', 'b'],
+ ['"c"', 'c'],
+ ['"d"', 'd'],
+ ['"e"', 'e'],
+ ['"f"', 'f'],
+ ['"g"', 'g'],
+ ['"h"', 'h'],
+ ['"i"', 'i'],
+ ['"j"', 'j'],
+ ['"k"', 'k'],
+ ['"l"', 'l'],
+ ['"m"', 'm'],
+ ['"n"', 'n'],
+ ['"o"', 'o'],
+ ['"p"', 'p'],
+ ['"q"', 'q'],
+ ['"r"', 'r'],
+ ['"s"', 's'],
+ ['"t"', 't'],
+ ['"u"', 'u'],
+ ['"v"', 'v'],
+ ['"w"', 'w'],
+ ['"x"', 'x'],
+ ['"y"', 'y'],
+ ['"z"', 'z']
+ ].should be_computed_by(:undump)
+ end
+
+ it "returns a string with \\x notation replaced with non-printing ASCII character" do
+ [ ['"\\x00"', 0000.chr.force_encoding('utf-8')],
+ ['"\\x01"', 0001.chr.force_encoding('utf-8')],
+ ['"\\x02"', 0002.chr.force_encoding('utf-8')],
+ ['"\\x03"', 0003.chr.force_encoding('utf-8')],
+ ['"\\x04"', 0004.chr.force_encoding('utf-8')],
+ ['"\\x05"', 0005.chr.force_encoding('utf-8')],
+ ['"\\x06"', 0006.chr.force_encoding('utf-8')],
+ ['"\\x0E"', 0016.chr.force_encoding('utf-8')],
+ ['"\\x0F"', 0017.chr.force_encoding('utf-8')],
+ ['"\\x10"', 0020.chr.force_encoding('utf-8')],
+ ['"\\x11"', 0021.chr.force_encoding('utf-8')],
+ ['"\\x12"', 0022.chr.force_encoding('utf-8')],
+ ['"\\x13"', 0023.chr.force_encoding('utf-8')],
+ ['"\\x14"', 0024.chr.force_encoding('utf-8')],
+ ['"\\x15"', 0025.chr.force_encoding('utf-8')],
+ ['"\\x16"', 0026.chr.force_encoding('utf-8')],
+ ['"\\x17"', 0027.chr.force_encoding('utf-8')],
+ ['"\\x18"', 0030.chr.force_encoding('utf-8')],
+ ['"\\x19"', 0031.chr.force_encoding('utf-8')],
+ ['"\\x1A"', 0032.chr.force_encoding('utf-8')],
+ ['"\\x1C"', 0034.chr.force_encoding('utf-8')],
+ ['"\\x1D"', 0035.chr.force_encoding('utf-8')],
+ ['"\\x1E"', 0036.chr.force_encoding('utf-8')],
+ ['"\\x1F"', 0037.chr.force_encoding('utf-8')],
+ ['"\\x7F"', 0177.chr.force_encoding('utf-8')],
+ ['"\\x80"', 0200.chr.force_encoding('utf-8')],
+ ['"\\x81"', 0201.chr.force_encoding('utf-8')],
+ ['"\\x82"', 0202.chr.force_encoding('utf-8')],
+ ['"\\x83"', 0203.chr.force_encoding('utf-8')],
+ ['"\\x84"', 0204.chr.force_encoding('utf-8')],
+ ['"\\x85"', 0205.chr.force_encoding('utf-8')],
+ ['"\\x86"', 0206.chr.force_encoding('utf-8')],
+ ['"\\x87"', 0207.chr.force_encoding('utf-8')],
+ ['"\\x88"', 0210.chr.force_encoding('utf-8')],
+ ['"\\x89"', 0211.chr.force_encoding('utf-8')],
+ ['"\\x8A"', 0212.chr.force_encoding('utf-8')],
+ ['"\\x8B"', 0213.chr.force_encoding('utf-8')],
+ ['"\\x8C"', 0214.chr.force_encoding('utf-8')],
+ ['"\\x8D"', 0215.chr.force_encoding('utf-8')],
+ ['"\\x8E"', 0216.chr.force_encoding('utf-8')],
+ ['"\\x8F"', 0217.chr.force_encoding('utf-8')],
+ ['"\\x90"', 0220.chr.force_encoding('utf-8')],
+ ['"\\x91"', 0221.chr.force_encoding('utf-8')],
+ ['"\\x92"', 0222.chr.force_encoding('utf-8')],
+ ['"\\x93"', 0223.chr.force_encoding('utf-8')],
+ ['"\\x94"', 0224.chr.force_encoding('utf-8')],
+ ['"\\x95"', 0225.chr.force_encoding('utf-8')],
+ ['"\\x96"', 0226.chr.force_encoding('utf-8')],
+ ['"\\x97"', 0227.chr.force_encoding('utf-8')],
+ ['"\\x98"', 0230.chr.force_encoding('utf-8')],
+ ['"\\x99"', 0231.chr.force_encoding('utf-8')],
+ ['"\\x9A"', 0232.chr.force_encoding('utf-8')],
+ ['"\\x9B"', 0233.chr.force_encoding('utf-8')],
+ ['"\\x9C"', 0234.chr.force_encoding('utf-8')],
+ ['"\\x9D"', 0235.chr.force_encoding('utf-8')],
+ ['"\\x9E"', 0236.chr.force_encoding('utf-8')],
+ ['"\\x9F"', 0237.chr.force_encoding('utf-8')],
+ ['"\\xA0"', 0240.chr.force_encoding('utf-8')],
+ ['"\\xA1"', 0241.chr.force_encoding('utf-8')],
+ ['"\\xA2"', 0242.chr.force_encoding('utf-8')],
+ ['"\\xA3"', 0243.chr.force_encoding('utf-8')],
+ ['"\\xA4"', 0244.chr.force_encoding('utf-8')],
+ ['"\\xA5"', 0245.chr.force_encoding('utf-8')],
+ ['"\\xA6"', 0246.chr.force_encoding('utf-8')],
+ ['"\\xA7"', 0247.chr.force_encoding('utf-8')],
+ ['"\\xA8"', 0250.chr.force_encoding('utf-8')],
+ ['"\\xA9"', 0251.chr.force_encoding('utf-8')],
+ ['"\\xAA"', 0252.chr.force_encoding('utf-8')],
+ ['"\\xAB"', 0253.chr.force_encoding('utf-8')],
+ ['"\\xAC"', 0254.chr.force_encoding('utf-8')],
+ ['"\\xAD"', 0255.chr.force_encoding('utf-8')],
+ ['"\\xAE"', 0256.chr.force_encoding('utf-8')],
+ ['"\\xAF"', 0257.chr.force_encoding('utf-8')],
+ ['"\\xB0"', 0260.chr.force_encoding('utf-8')],
+ ['"\\xB1"', 0261.chr.force_encoding('utf-8')],
+ ['"\\xB2"', 0262.chr.force_encoding('utf-8')],
+ ['"\\xB3"', 0263.chr.force_encoding('utf-8')],
+ ['"\\xB4"', 0264.chr.force_encoding('utf-8')],
+ ['"\\xB5"', 0265.chr.force_encoding('utf-8')],
+ ['"\\xB6"', 0266.chr.force_encoding('utf-8')],
+ ['"\\xB7"', 0267.chr.force_encoding('utf-8')],
+ ['"\\xB8"', 0270.chr.force_encoding('utf-8')],
+ ['"\\xB9"', 0271.chr.force_encoding('utf-8')],
+ ['"\\xBA"', 0272.chr.force_encoding('utf-8')],
+ ['"\\xBB"', 0273.chr.force_encoding('utf-8')],
+ ['"\\xBC"', 0274.chr.force_encoding('utf-8')],
+ ['"\\xBD"', 0275.chr.force_encoding('utf-8')],
+ ['"\\xBE"', 0276.chr.force_encoding('utf-8')],
+ ['"\\xBF"', 0277.chr.force_encoding('utf-8')],
+ ['"\\xC0"', 0300.chr.force_encoding('utf-8')],
+ ['"\\xC1"', 0301.chr.force_encoding('utf-8')],
+ ['"\\xC2"', 0302.chr.force_encoding('utf-8')],
+ ['"\\xC3"', 0303.chr.force_encoding('utf-8')],
+ ['"\\xC4"', 0304.chr.force_encoding('utf-8')],
+ ['"\\xC5"', 0305.chr.force_encoding('utf-8')],
+ ['"\\xC6"', 0306.chr.force_encoding('utf-8')],
+ ['"\\xC7"', 0307.chr.force_encoding('utf-8')],
+ ['"\\xC8"', 0310.chr.force_encoding('utf-8')],
+ ['"\\xC9"', 0311.chr.force_encoding('utf-8')],
+ ['"\\xCA"', 0312.chr.force_encoding('utf-8')],
+ ['"\\xCB"', 0313.chr.force_encoding('utf-8')],
+ ['"\\xCC"', 0314.chr.force_encoding('utf-8')],
+ ['"\\xCD"', 0315.chr.force_encoding('utf-8')],
+ ['"\\xCE"', 0316.chr.force_encoding('utf-8')],
+ ['"\\xCF"', 0317.chr.force_encoding('utf-8')],
+ ['"\\xD0"', 0320.chr.force_encoding('utf-8')],
+ ['"\\xD1"', 0321.chr.force_encoding('utf-8')],
+ ['"\\xD2"', 0322.chr.force_encoding('utf-8')],
+ ['"\\xD3"', 0323.chr.force_encoding('utf-8')],
+ ['"\\xD4"', 0324.chr.force_encoding('utf-8')],
+ ['"\\xD5"', 0325.chr.force_encoding('utf-8')],
+ ['"\\xD6"', 0326.chr.force_encoding('utf-8')],
+ ['"\\xD7"', 0327.chr.force_encoding('utf-8')],
+ ['"\\xD8"', 0330.chr.force_encoding('utf-8')],
+ ['"\\xD9"', 0331.chr.force_encoding('utf-8')],
+ ['"\\xDA"', 0332.chr.force_encoding('utf-8')],
+ ['"\\xDB"', 0333.chr.force_encoding('utf-8')],
+ ['"\\xDC"', 0334.chr.force_encoding('utf-8')],
+ ['"\\xDD"', 0335.chr.force_encoding('utf-8')],
+ ['"\\xDE"', 0336.chr.force_encoding('utf-8')],
+ ['"\\xDF"', 0337.chr.force_encoding('utf-8')],
+ ['"\\xE0"', 0340.chr.force_encoding('utf-8')],
+ ['"\\xE1"', 0341.chr.force_encoding('utf-8')],
+ ['"\\xE2"', 0342.chr.force_encoding('utf-8')],
+ ['"\\xE3"', 0343.chr.force_encoding('utf-8')],
+ ['"\\xE4"', 0344.chr.force_encoding('utf-8')],
+ ['"\\xE5"', 0345.chr.force_encoding('utf-8')],
+ ['"\\xE6"', 0346.chr.force_encoding('utf-8')],
+ ['"\\xE7"', 0347.chr.force_encoding('utf-8')],
+ ['"\\xE8"', 0350.chr.force_encoding('utf-8')],
+ ['"\\xE9"', 0351.chr.force_encoding('utf-8')],
+ ['"\\xEA"', 0352.chr.force_encoding('utf-8')],
+ ['"\\xEB"', 0353.chr.force_encoding('utf-8')],
+ ['"\\xEC"', 0354.chr.force_encoding('utf-8')],
+ ['"\\xED"', 0355.chr.force_encoding('utf-8')],
+ ['"\\xEE"', 0356.chr.force_encoding('utf-8')],
+ ['"\\xEF"', 0357.chr.force_encoding('utf-8')],
+ ['"\\xF0"', 0360.chr.force_encoding('utf-8')],
+ ['"\\xF1"', 0361.chr.force_encoding('utf-8')],
+ ['"\\xF2"', 0362.chr.force_encoding('utf-8')],
+ ['"\\xF3"', 0363.chr.force_encoding('utf-8')],
+ ['"\\xF4"', 0364.chr.force_encoding('utf-8')],
+ ['"\\xF5"', 0365.chr.force_encoding('utf-8')],
+ ['"\\xF6"', 0366.chr.force_encoding('utf-8')],
+ ['"\\xF7"', 0367.chr.force_encoding('utf-8')],
+ ['"\\xF8"', 0370.chr.force_encoding('utf-8')],
+ ['"\\xF9"', 0371.chr.force_encoding('utf-8')],
+ ['"\\xFA"', 0372.chr.force_encoding('utf-8')],
+ ['"\\xFB"', 0373.chr.force_encoding('utf-8')],
+ ['"\\xFC"', 0374.chr.force_encoding('utf-8')],
+ ['"\\xFD"', 0375.chr.force_encoding('utf-8')],
+ ['"\\xFE"', 0376.chr.force_encoding('utf-8')],
+ ['"\\xFF"', 0377.chr.force_encoding('utf-8')]
+ ].should be_computed_by(:undump)
+ end
+
+ it "returns a string with \\u{} notation replaced with multi-byte UTF-8 characters" do
+ [ ['"\u{80}"', 0200.chr('utf-8')],
+ ['"\u{81}"', 0201.chr('utf-8')],
+ ['"\u{82}"', 0202.chr('utf-8')],
+ ['"\u{83}"', 0203.chr('utf-8')],
+ ['"\u{84}"', 0204.chr('utf-8')],
+ ['"\u{86}"', 0206.chr('utf-8')],
+ ['"\u{87}"', 0207.chr('utf-8')],
+ ['"\u{88}"', 0210.chr('utf-8')],
+ ['"\u{89}"', 0211.chr('utf-8')],
+ ['"\u{8a}"', 0212.chr('utf-8')],
+ ['"\u{8b}"', 0213.chr('utf-8')],
+ ['"\u{8c}"', 0214.chr('utf-8')],
+ ['"\u{8d}"', 0215.chr('utf-8')],
+ ['"\u{8e}"', 0216.chr('utf-8')],
+ ['"\u{8f}"', 0217.chr('utf-8')],
+ ['"\u{90}"', 0220.chr('utf-8')],
+ ['"\u{91}"', 0221.chr('utf-8')],
+ ['"\u{92}"', 0222.chr('utf-8')],
+ ['"\u{93}"', 0223.chr('utf-8')],
+ ['"\u{94}"', 0224.chr('utf-8')],
+ ['"\u{95}"', 0225.chr('utf-8')],
+ ['"\u{96}"', 0226.chr('utf-8')],
+ ['"\u{97}"', 0227.chr('utf-8')],
+ ['"\u{98}"', 0230.chr('utf-8')],
+ ['"\u{99}"', 0231.chr('utf-8')],
+ ['"\u{9a}"', 0232.chr('utf-8')],
+ ['"\u{9b}"', 0233.chr('utf-8')],
+ ['"\u{9c}"', 0234.chr('utf-8')],
+ ['"\u{9d}"', 0235.chr('utf-8')],
+ ['"\u{9e}"', 0236.chr('utf-8')],
+ ['"\u{9f}"', 0237.chr('utf-8')],
+ ].should be_computed_by(:undump)
+ end
+
+ it "returns a string with \\uXXXX notation replaced with multi-byte UTF-8 characters" do
+ [ ['"\u0080"', 0200.chr('utf-8')],
+ ['"\u0081"', 0201.chr('utf-8')],
+ ['"\u0082"', 0202.chr('utf-8')],
+ ['"\u0083"', 0203.chr('utf-8')],
+ ['"\u0084"', 0204.chr('utf-8')],
+ ['"\u0086"', 0206.chr('utf-8')],
+ ['"\u0087"', 0207.chr('utf-8')],
+ ['"\u0088"', 0210.chr('utf-8')],
+ ['"\u0089"', 0211.chr('utf-8')],
+ ['"\u008a"', 0212.chr('utf-8')],
+ ['"\u008b"', 0213.chr('utf-8')],
+ ['"\u008c"', 0214.chr('utf-8')],
+ ['"\u008d"', 0215.chr('utf-8')],
+ ['"\u008e"', 0216.chr('utf-8')],
+ ['"\u008f"', 0217.chr('utf-8')],
+ ['"\u0090"', 0220.chr('utf-8')],
+ ['"\u0091"', 0221.chr('utf-8')],
+ ['"\u0092"', 0222.chr('utf-8')],
+ ['"\u0093"', 0223.chr('utf-8')],
+ ['"\u0094"', 0224.chr('utf-8')],
+ ['"\u0095"', 0225.chr('utf-8')],
+ ['"\u0096"', 0226.chr('utf-8')],
+ ['"\u0097"', 0227.chr('utf-8')],
+ ['"\u0098"', 0230.chr('utf-8')],
+ ['"\u0099"', 0231.chr('utf-8')],
+ ['"\u009a"', 0232.chr('utf-8')],
+ ['"\u009b"', 0233.chr('utf-8')],
+ ['"\u009c"', 0234.chr('utf-8')],
+ ['"\u009d"', 0235.chr('utf-8')],
+ ['"\u009e"', 0236.chr('utf-8')],
+ ['"\u009f"', 0237.chr('utf-8')],
+ ].should be_computed_by(:undump)
+ end
+
+ it "undumps correctly string produced from non ASCII-compatible one" do
+ s = "\u{876}".encode('utf-16be')
+ s.dump.undump.should == s
+
+ '"\\bv".force_encoding("UTF-16BE")'.undump.should == "\u0876".encode('utf-16be')
+ end
+
+ it "returns a String in the same encoding as self" do
+ '"foo"'.encode("ISO-8859-1").undump.encoding.should == Encoding::ISO_8859_1
+ '"foo"'.encode('windows-1251').undump.encoding.should == Encoding::Windows_1251
+ end
+
+ describe "Limitations" do
+ it "cannot undump non ASCII-compatible string" do
+ -> { '"foo"'.encode('utf-16le').undump }.should raise_error(Encoding::CompatibilityError)
+ end
+ end
+
+ describe "invalid dump" do
+ it "raises RuntimeError exception if wrapping \" are missing" do
+ -> { 'foo'.undump }.should raise_error(RuntimeError, /invalid dumped string/)
+ -> { '"foo'.undump }.should raise_error(RuntimeError, /unterminated dumped string/)
+ -> { 'foo"'.undump }.should raise_error(RuntimeError, /invalid dumped string/)
+ -> { "'foo'".undump }.should raise_error(RuntimeError, /invalid dumped string/)
+ end
+
+ it "raises RuntimeError if there is incorrect \\x sequence" do
+ -> { '"\x"'.undump }.should raise_error(RuntimeError, /invalid hex escape/)
+ -> { '"\\x3y"'.undump }.should raise_error(RuntimeError, /invalid hex escape/)
+ end
+
+ it "raises RuntimeError in there is incorrect \\u sequence" do
+ -> { '"\\u"'.undump }.should raise_error(RuntimeError, /invalid Unicode escape/)
+ -> { '"\\u{"'.undump }.should raise_error(RuntimeError, /invalid Unicode escape/)
+ -> { '"\\u{3042"'.undump }.should raise_error(RuntimeError, /invalid Unicode escape/)
+ -> { '"\\u"'.undump }.should raise_error(RuntimeError, /invalid Unicode escape/)
+ end
+
+ it "raises RuntimeError if there is malformed dump of non ASCII-compatible string" do
+ -> { '"".force_encoding("BINARY"'.undump }.should raise_error(RuntimeError, /invalid dumped string/)
+ -> { '"".force_encoding("Unknown")'.undump }.should raise_error(RuntimeError, /dumped string has unknown encoding name/)
+ -> { '"".force_encoding()'.undump }.should raise_error(RuntimeError, /invalid dumped string/)
+ end
+
+ it "raises RuntimeError if string contains \0 character" do
+ -> { "\"foo\0\"".undump }.should raise_error(RuntimeError, /string contains null byte/)
+ end
+
+ it "raises RuntimeError if string contains non ASCII character" do
+ -> { "\"\u3042\"".undump }.should raise_error(RuntimeError, /non-ASCII character detected/)
+ end
+
+ it "raises RuntimeError if there are some excessive \"" do
+ -> { '" "" "'.undump }.should raise_error(RuntimeError, /invalid dumped string/)
+ end
+ end
+end
diff --git a/spec/ruby/core/string/unicode_normalize_spec.rb b/spec/ruby/core/string/unicode_normalize_spec.rb
index 138c0455fd..2e7d22394a 100644
--- a/spec/ruby/core/string/unicode_normalize_spec.rb
+++ b/spec/ruby/core/string/unicode_normalize_spec.rb
@@ -1,5 +1,6 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
+# frozen_string_literal: false
+require_relative '../../spec_helper'
# Examples taken from http://www.unicode.org/reports/tr15/#Norm_Forms
@@ -48,13 +49,13 @@ describe "String#unicode_normalize" do
end
it "raises an Encoding::CompatibilityError if string is not in an unicode encoding" do
- lambda do
+ -> do
[0xE0].pack('C').force_encoding("ISO-8859-1").unicode_normalize(:nfd)
end.should raise_error(Encoding::CompatibilityError)
end
it "raises an ArgumentError if the specified form is invalid" do
- lambda {
+ -> {
@angstrom.unicode_normalize(:invalid_form)
}.should raise_error(ArgumentError)
end
@@ -101,14 +102,14 @@ describe "String#unicode_normalize!" do
end
it "raises an Encoding::CompatibilityError if the string is not in an unicode encoding" do
- lambda {
+ -> {
[0xE0].pack('C').force_encoding("ISO-8859-1").unicode_normalize!
}.should raise_error(Encoding::CompatibilityError)
end
it "raises an ArgumentError if the specified form is invalid" do
ohm = "\u2126"
- lambda {
+ -> {
ohm.unicode_normalize!(:invalid_form)
}.should raise_error(ArgumentError)
end
diff --git a/spec/ruby/core/string/unicode_normalized_spec.rb b/spec/ruby/core/string/unicode_normalized_spec.rb
index dc5e2742e4..91cf2086b2 100644
--- a/spec/ruby/core/string/unicode_normalized_spec.rb
+++ b/spec/ruby/core/string/unicode_normalized_spec.rb
@@ -1,5 +1,6 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
+# frozen_string_literal: false
+require_relative '../../spec_helper'
describe "String#unicode_normalized?" do
before :each do
@@ -24,24 +25,24 @@ describe "String#unicode_normalized?" do
end
it "defaults to the nfc normalization form if no forms are specified" do
- @nfc_normalized_str.unicode_normalized?.should == true
- @nfd_normalized_str.unicode_normalized?.should == false
+ @nfc_normalized_str.should.unicode_normalized?
+ @nfd_normalized_str.should_not.unicode_normalized?
end
it "returns true if string is empty" do
- "".unicode_normalized?.should == true
+ "".should.unicode_normalized?
end
it "returns true if string does not contain any unicode codepoints" do
- "abc".unicode_normalized?.should == true
+ "abc".should.unicode_normalized?
end
it "raises an Encoding::CompatibilityError if the string is not in an unicode encoding" do
- lambda { @nfc_normalized_str.force_encoding("ISO-8859-1").unicode_normalized? }.should raise_error(Encoding::CompatibilityError)
+ -> { @nfc_normalized_str.force_encoding("ISO-8859-1").unicode_normalized? }.should raise_error(Encoding::CompatibilityError)
end
it "raises an ArgumentError if the specified form is invalid" do
- lambda { @nfc_normalized_str.unicode_normalized?(:invalid_form) }.should raise_error(ArgumentError)
+ -> { @nfc_normalized_str.unicode_normalized?(:invalid_form) }.should raise_error(ArgumentError)
end
it "returns true if str is in Unicode normalization form (nfc)" do
diff --git a/spec/ruby/core/string/unpack/a_spec.rb b/spec/ruby/core/string/unpack/a_spec.rb
index 18882c91a6..a68e842e15 100644
--- a/spec/ruby/core/string/unpack/a_spec.rb
+++ b/spec/ruby/core/string/unpack/a_spec.rb
@@ -1,14 +1,16 @@
-# -*- 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__)
+# encoding: binary
+require_relative '../../../spec_helper'
+require_relative '../fixtures/classes'
+require_relative 'shared/basic'
+require_relative 'shared/string'
+require_relative 'shared/taint'
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_behaves_like :string_unpack_taint, 'A'
it "removes trailing space and NULL bytes from the decoded string" do
[ ["a\x00 b \x00", ["a\x00 b", ""]],
@@ -29,8 +31,8 @@ describe "String#unpack with format 'A'" do
end
it "decodes into raw (ascii) string values" do
- str = "str".force_encoding('UTF-8').unpack("A*")[0]
- str.encoding.name.should == 'ASCII-8BIT'
+ str = "str".dup.force_encoding('UTF-8').unpack("A*")[0]
+ str.encoding.should == Encoding::BINARY
end
end
@@ -40,6 +42,7 @@ describe "String#unpack with format 'a'" do
it_behaves_like :string_unpack_no_platform, 'a'
it_behaves_like :string_unpack_string, 'a'
it_behaves_like :string_unpack_Aa, 'a'
+ it_behaves_like :string_unpack_taint, 'a'
it "does not remove trailing whitespace or NULL bytes from the decoded string" do
[ ["a\x00 b \x00", ["a\x00 b \x00"]],
@@ -57,7 +60,7 @@ describe "String#unpack with format 'a'" do
it "decodes into raw (ascii) string values" do
str = "".unpack("a*")[0]
- str.encoding.name.should == 'ASCII-8BIT'
+ str.encoding.should == Encoding::BINARY
end
end
diff --git a/spec/ruby/core/string/unpack/at_spec.rb b/spec/ruby/core/string/unpack/at_spec.rb
index 70cbebd2ba..d4133c23ee 100644
--- a/spec/ruby/core/string/unpack/at_spec.rb
+++ b/spec/ruby/core/string/unpack/at_spec.rb
@@ -1,7 +1,7 @@
-# -*- encoding: ascii-8bit -*-
-require File.expand_path('../../../../spec_helper', __FILE__)
-require File.expand_path('../../fixtures/classes', __FILE__)
-require File.expand_path('../shared/basic', __FILE__)
+# encoding: binary
+require_relative '../../../spec_helper'
+require_relative '../fixtures/classes'
+require_relative 'shared/basic'
describe "String#unpack with format '@'" do
it_behaves_like :string_unpack_basic, '@'
@@ -24,6 +24,6 @@ describe "String#unpack with format '@'" do
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)
+ -> { "\x01\x02\x03\x04".unpack("C2@5C") }.should raise_error(ArgumentError)
end
end
diff --git a/spec/ruby/core/string/unpack/b_spec.rb b/spec/ruby/core/string/unpack/b_spec.rb
index fa632e6526..b088f901fc 100644
--- a/spec/ruby/core/string/unpack/b_spec.rb
+++ b/spec/ruby/core/string/unpack/b_spec.rb
@@ -1,11 +1,13 @@
-# -*- encoding: ascii-8bit -*-
-require File.expand_path('../../../../spec_helper', __FILE__)
-require File.expand_path('../../fixtures/classes', __FILE__)
-require File.expand_path('../shared/basic', __FILE__)
+# encoding: binary
+require_relative '../../../spec_helper'
+require_relative '../fixtures/classes'
+require_relative 'shared/basic'
+require_relative 'shared/taint'
describe "String#unpack with format 'B'" do
it_behaves_like :string_unpack_basic, 'B'
it_behaves_like :string_unpack_no_platform, 'B'
+ it_behaves_like :string_unpack_taint, 'B'
it "decodes one bit from each byte for each format character starting with the most significant bit" do
[ ["\x00", "B", ["0"]],
@@ -84,18 +86,36 @@ describe "String#unpack with format 'B'" do
].should be_computed_by(:unpack, "BBB")
end
- it "ignores NULL bytes between directives" do
- "\x80\x00".unpack("B\x00B").should == ["1", "0"]
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ "\x80\x00".unpack("B\x00B").should == ["1", "0"]
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "\x80\x00".unpack("B\x00B")
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
+ end
end
it "ignores spaces between directives" do
"\x80\x00".unpack("B B").should == ["1", "0"]
end
+
+ it "decodes into US-ASCII string values" do
+ str = "s".dup.force_encoding('UTF-8').unpack("B*")[0]
+ str.encoding.name.should == 'US-ASCII'
+ 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_behaves_like :string_unpack_taint, 'b'
it "decodes one bit from each byte for each format character starting with the least significant bit" do
[ ["\x00", "b", ["0"]],
@@ -174,8 +194,20 @@ describe "String#unpack with format 'b'" do
].should be_computed_by(:unpack, "bbb")
end
- it "ignores NULL bytes between directives" do
- "\x01\x00".unpack("b\x00b").should == ["1", "0"]
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ "\x01\x00".unpack("b\x00b").should == ["1", "0"]
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "\x01\x00".unpack("b\x00b")
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
+ end
end
it "ignores spaces between directives" do
@@ -183,8 +215,7 @@ describe "String#unpack with format 'b'" do
end
it "decodes into US-ASCII string values" do
- str = "s".force_encoding('UTF-8').unpack("b*")[0]
+ str = "s".dup.force_encoding('UTF-8').unpack("b*")[0]
str.encoding.name.should == 'US-ASCII'
end
-
end
diff --git a/spec/ruby/core/string/unpack/c_spec.rb b/spec/ruby/core/string/unpack/c_spec.rb
index 36de462cac..1e9548fb82 100644
--- a/spec/ruby/core/string/unpack/c_spec.rb
+++ b/spec/ruby/core/string/unpack/c_spec.rb
@@ -1,7 +1,7 @@
-# -*- encoding: ascii-8bit -*-
-require File.expand_path('../../../../spec_helper', __FILE__)
-require File.expand_path('../../fixtures/classes', __FILE__)
-require File.expand_path('../shared/basic', __FILE__)
+# encoding: binary
+require_relative '../../../spec_helper'
+require_relative '../fixtures/classes'
+require_relative 'shared/basic'
describe :string_unpack_8bit, shared: true do
it "decodes one byte for a single format character" do
@@ -20,7 +20,7 @@ describe :string_unpack_8bit, shared: true do
"abc".unpack(unpack_format('*')).should == [97, 98, 99]
end
- it "decodes the remaining bytes when passed the '*' modifer after another directive" do
+ it "decodes the remaining bytes when passed the '*' modifier after another directive" do
"abc".unpack(unpack_format()+unpack_format('*')).should == [97, 98, 99]
end
@@ -35,8 +35,20 @@ describe :string_unpack_8bit, shared: true do
].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]
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ "abc".unpack(unpack_format("\000", 2)).should == [97, 98]
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "abc".unpack(unpack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
+ end
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/string/unpack/comment_spec.rb b/spec/ruby/core/string/unpack/comment_spec.rb
index 884960b337..050d2b7fc0 100644
--- a/spec/ruby/core/string/unpack/comment_spec.rb
+++ b/spec/ruby/core/string/unpack/comment_spec.rb
@@ -1,6 +1,6 @@
-# -*- encoding: ascii-8bit -*-
-require File.expand_path('../../../../spec_helper', __FILE__)
-require File.expand_path('../../fixtures/classes', __FILE__)
+# encoding: binary
+require_relative '../../../spec_helper'
+require_relative '../fixtures/classes'
describe "String#unpack" do
it "ignores directives text from '#' to the first newline" do
diff --git a/spec/ruby/core/string/unpack/d_spec.rb b/spec/ruby/core/string/unpack/d_spec.rb
index db4638f8ef..0e4f57ec04 100644
--- a/spec/ruby/core/string/unpack/d_spec.rb
+++ b/spec/ruby/core/string/unpack/d_spec.rb
@@ -1,7 +1,7 @@
-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__)
+require_relative '../../../spec_helper'
+require_relative '../fixtures/classes'
+require_relative 'shared/basic'
+require_relative 'shared/float'
little_endian do
describe "String#unpack with format 'D'" do
diff --git a/spec/ruby/core/string/unpack/e_spec.rb b/spec/ruby/core/string/unpack/e_spec.rb
index cb74c00206..c958be1c8b 100644
--- a/spec/ruby/core/string/unpack/e_spec.rb
+++ b/spec/ruby/core/string/unpack/e_spec.rb
@@ -1,7 +1,7 @@
-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__)
+require_relative '../../../spec_helper'
+require_relative '../fixtures/classes'
+require_relative 'shared/basic'
+require_relative 'shared/float'
describe "String#unpack with format 'E'" do
it_behaves_like :string_unpack_basic, 'E'
diff --git a/spec/ruby/core/string/unpack/f_spec.rb b/spec/ruby/core/string/unpack/f_spec.rb
index 60dad46703..ec8b9d435e 100644
--- a/spec/ruby/core/string/unpack/f_spec.rb
+++ b/spec/ruby/core/string/unpack/f_spec.rb
@@ -1,7 +1,7 @@
-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__)
+require_relative '../../../spec_helper'
+require_relative '../fixtures/classes'
+require_relative 'shared/basic'
+require_relative 'shared/float'
little_endian do
describe "String#unpack with format 'F'" do
diff --git a/spec/ruby/core/string/unpack/g_spec.rb b/spec/ruby/core/string/unpack/g_spec.rb
index f5bec1534e..ffc423b152 100644
--- a/spec/ruby/core/string/unpack/g_spec.rb
+++ b/spec/ruby/core/string/unpack/g_spec.rb
@@ -1,7 +1,7 @@
-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__)
+require_relative '../../../spec_helper'
+require_relative '../fixtures/classes'
+require_relative 'shared/basic'
+require_relative 'shared/float'
describe "String#unpack with format 'G'" do
it_behaves_like :string_unpack_basic, 'G'
diff --git a/spec/ruby/core/string/unpack/h_spec.rb b/spec/ruby/core/string/unpack/h_spec.rb
index 00d6d68eee..535836087d 100644
--- a/spec/ruby/core/string/unpack/h_spec.rb
+++ b/spec/ruby/core/string/unpack/h_spec.rb
@@ -1,11 +1,13 @@
-# -*- encoding: ascii-8bit -*-
-require File.expand_path('../../../../spec_helper', __FILE__)
-require File.expand_path('../../fixtures/classes', __FILE__)
-require File.expand_path('../shared/basic', __FILE__)
+# encoding: binary
+require_relative '../../../spec_helper'
+require_relative '../fixtures/classes'
+require_relative 'shared/basic'
+require_relative 'shared/taint'
describe "String#unpack with format 'H'" do
it_behaves_like :string_unpack_basic, 'H'
it_behaves_like :string_unpack_no_platform, 'H'
+ it_behaves_like :string_unpack_taint, 'H'
it "decodes one nibble from each byte for each format character starting with the most significant bit" do
[ ["\x8f", "H", ["8"]],
@@ -54,18 +56,35 @@ describe "String#unpack with format 'H'" do
].should be_computed_by(:unpack, "HHH")
end
- it "ignores NULL bytes between directives" do
- "\x01\x10".unpack("H\x00H").should == ["0", "1"]
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ "\x01\x10".unpack("H\x00H").should == ["0", "1"]
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "\x01\x10".unpack("H\x00H")
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
+ end
end
it "ignores spaces between directives" do
"\x01\x10".unpack("H H").should == ["0", "1"]
end
+
+ it "should make strings with US_ASCII encoding" do
+ "\x01".unpack("H")[0].encoding.should == Encoding::US_ASCII
+ 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_behaves_like :string_unpack_taint, 'h'
it "decodes one nibble from each byte for each format character starting with the least significant bit" do
[ ["\x8f", "h", ["f"]],
@@ -114,11 +133,27 @@ describe "String#unpack with format 'h'" do
].should be_computed_by(:unpack, "hhh")
end
- it "ignores NULL bytes between directives" do
- "\x01\x10".unpack("h\x00h").should == ["1", "0"]
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ "\x01\x10".unpack("h\x00h").should == ["1", "0"]
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "\x01\x10".unpack("h\x00h")
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
+ end
end
it "ignores spaces between directives" do
"\x01\x10".unpack("h h").should == ["1", "0"]
end
+
+ it "should make strings with US_ASCII encoding" do
+ "\x01".unpack("h")[0].encoding.should == Encoding::US_ASCII
+ end
end
diff --git a/spec/ruby/core/string/unpack/i_spec.rb b/spec/ruby/core/string/unpack/i_spec.rb
index f3183afe99..b4bbba1923 100644
--- a/spec/ruby/core/string/unpack/i_spec.rb
+++ b/spec/ruby/core/string/unpack/i_spec.rb
@@ -1,7 +1,7 @@
-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__)
+require_relative '../../../spec_helper'
+require_relative '../fixtures/classes'
+require_relative 'shared/basic'
+require_relative 'shared/integer'
describe "String#unpack with format 'I'" do
describe "with modifier '<'" do
diff --git a/spec/ruby/core/string/unpack/j_spec.rb b/spec/ruby/core/string/unpack/j_spec.rb
index 49c460aeb3..3c2baad642 100644
--- a/spec/ruby/core/string/unpack/j_spec.rb
+++ b/spec/ruby/core/string/unpack/j_spec.rb
@@ -1,277 +1,272 @@
-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
+require_relative '../../../spec_helper'
+require_relative '../fixtures/classes'
+require_relative 'shared/basic'
+require_relative 'shared/integer'
- 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
+platform_is pointer_size: 64 do
+ 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_signed, '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
- 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
+ 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 "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
+ 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_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>'
+ 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!<'
+ describe "with modifier '!'" do
+ it_behaves_like :string_unpack_64bit_be, 'J!'
+ it_behaves_like :string_unpack_64bit_be_unsigned, 'J!'
end
+ 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_>'
+ 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 '>' 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!>'
+ 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_signed, 'j<'
- 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_signed, '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_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_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_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_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_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_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_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_unsigned, 'J>!'
+ it_behaves_like :string_unpack_64bit_be_unsigned, 'J!>'
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 "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_32bit_le, 'j!'
- it_behaves_like :string_unpack_32bit_le_signed, 'j!'
- end
- end
+ describe "with modifier '>'" do
+ it_behaves_like :string_unpack_64bit_be, 'j>'
+ it_behaves_like :string_unpack_64bit_be_signed, 'j>'
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 '<' 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 '!'" do
- it_behaves_like :string_unpack_32bit_be, 'J!'
- it_behaves_like :string_unpack_32bit_be_unsigned, 'J!'
- end
- 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 "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 '>' 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 '!'" do
- it_behaves_like :string_unpack_32bit_be, 'j!'
- it_behaves_like :string_unpack_32bit_be_signed, 'j!'
- end
- 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
+platform_is pointer_size: 32 do
+ 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<'
+ 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>'
+ describe "with modifier '!'" do
+ it_behaves_like :string_unpack_32bit_le, 'J!'
+ it_behaves_like :string_unpack_32bit_le_unsigned, 'J!'
end
+ 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_<'
+ 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 '<' 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!<'
+ describe "with modifier '!'" do
+ it_behaves_like :string_unpack_32bit_le, 'j!'
+ it_behaves_like :string_unpack_32bit_le_signed, 'j!'
end
+ end
+ 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_>'
+ 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 '>' 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!>'
+ 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_le, 'j<'
- it_behaves_like :string_unpack_32bit_le_signed, 'j<'
+ 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>'
+ 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 "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 "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 '<' 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 '>'" 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_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_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_signed, '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_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
diff --git a/spec/ruby/core/string/unpack/l_spec.rb b/spec/ruby/core/string/unpack/l_spec.rb
index 11f0648fc7..0adb567eca 100644
--- a/spec/ruby/core/string/unpack/l_spec.rb
+++ b/spec/ruby/core/string/unpack/l_spec.rb
@@ -1,7 +1,7 @@
-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__)
+require_relative '../../../spec_helper'
+require_relative '../fixtures/classes'
+require_relative 'shared/basic'
+require_relative 'shared/integer'
describe "String#unpack with format 'L'" do
describe "with modifier '<'" do
@@ -14,7 +14,7 @@ describe "String#unpack with format 'L'" do
it_behaves_like :string_unpack_32bit_be_unsigned, 'L>'
end
- guard -> { platform_is wordsize: 32 or platform_is :mingw32 } do
+ platform_is c_long_size: 32 do
describe "with modifier '<' and '_'" do
it_behaves_like :string_unpack_32bit_le, 'L<_'
it_behaves_like :string_unpack_32bit_le, 'L_<'
@@ -44,7 +44,7 @@ describe "String#unpack with format 'L'" do
end
end
- guard -> { platform_is wordsize: 64 and platform_is_not :mingw32 } do
+ platform_is c_long_size: 64 do
describe "with modifier '<' and '_'" do
it_behaves_like :string_unpack_64bit_le, 'L<_'
it_behaves_like :string_unpack_64bit_le, 'L_<'
@@ -86,7 +86,7 @@ describe "String#unpack with format 'l'" do
it_behaves_like :string_unpack_32bit_be_signed, 'l>'
end
- guard -> { platform_is wordsize: 32 or platform_is :mingw32 } do
+ platform_is c_long_size: 32 do
describe "with modifier '<' and '_'" do
it_behaves_like :string_unpack_32bit_le, 'l<_'
it_behaves_like :string_unpack_32bit_le, 'l_<'
@@ -116,7 +116,7 @@ describe "String#unpack with format 'l'" do
end
end
- guard -> { platform_is wordsize: 64 and platform_is_not :mingw32 } do
+ platform_is c_long_size: 64 do
describe "with modifier '<' and '_'" do
it_behaves_like :string_unpack_64bit_le, 'l<_'
it_behaves_like :string_unpack_64bit_le, 'l_<'
@@ -160,7 +160,7 @@ little_endian do
it_behaves_like :string_unpack_32bit_le_signed, 'l'
end
- guard -> { platform_is wordsize: 32 or platform_is :mingw32 } do
+ platform_is c_long_size: 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_'
@@ -182,7 +182,7 @@ little_endian do
end
end
- guard -> { platform_is wordsize: 64 and platform_is_not :mingw32 } do
+ platform_is c_long_size: 64 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_'
@@ -218,7 +218,7 @@ big_endian do
it_behaves_like :string_unpack_32bit_be_signed, 'l'
end
- guard -> { platform_is wordsize: 32 or platform_is :mingw32 } do
+ platform_is c_long_size: 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_'
@@ -240,7 +240,7 @@ big_endian do
end
end
- guard -> { platform_is wordsize: 64 and platform_is_not :mingw32 } do
+ platform_is c_long_size: 64 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_'
diff --git a/spec/ruby/core/string/unpack/m_spec.rb b/spec/ruby/core/string/unpack/m_spec.rb
index 104f282fed..357987a053 100644
--- a/spec/ruby/core/string/unpack/m_spec.rb
+++ b/spec/ruby/core/string/unpack/m_spec.rb
@@ -1,11 +1,13 @@
-# -*- encoding: ascii-8bit -*-
-require File.expand_path('../../../../spec_helper', __FILE__)
-require File.expand_path('../../fixtures/classes', __FILE__)
-require File.expand_path('../shared/basic', __FILE__)
+# encoding: binary
+require_relative '../../../spec_helper'
+require_relative '../fixtures/classes'
+require_relative 'shared/basic'
+require_relative 'shared/taint'
describe "String#unpack with format 'M'" do
it_behaves_like :string_unpack_basic, 'M'
it_behaves_like :string_unpack_no_platform, 'M'
+ it_behaves_like :string_unpack_taint, 'M'
it "decodes an empty string" do
"".unpack("M").should == [""]
@@ -95,11 +97,17 @@ describe "String#unpack with format 'M'" do
["=FF=\n", ["\xff"]]
].should be_computed_by(:unpack, "M")
end
+
+ it "unpacks incomplete escape sequences as literal characters" do
+ "foo=".unpack("M").should == ["foo="]
+ "foo=4".unpack("M").should == ["foo=4"]
+ 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_behaves_like :string_unpack_taint, 'm'
it "decodes an empty string" do
"".unpack("m").should == [""]
@@ -167,4 +175,18 @@ describe "String#unpack with format 'm'" do
"".unpack("m").first.encoding.should == Encoding::BINARY
"Ojs8PT4/QA==\n".unpack("m").first.encoding.should == Encoding::BINARY
end
+
+ it "does not raise an error for an invalid base64 character" do
+ "dGV%zdA==".unpack("m").should == ["test"]
+ end
+
+ describe "when given count 0" do
+ it "decodes base64" do
+ "dGVzdA==".unpack("m0").should == ["test"]
+ end
+
+ it "raises an ArgumentError for an invalid base64 character" do
+ -> { "dGV%zdA==".unpack("m0") }.should raise_error(ArgumentError)
+ end
+ end
end
diff --git a/spec/ruby/core/string/unpack/n_spec.rb b/spec/ruby/core/string/unpack/n_spec.rb
index 6e85346338..09173f4fcb 100644
--- a/spec/ruby/core/string/unpack/n_spec.rb
+++ b/spec/ruby/core/string/unpack/n_spec.rb
@@ -1,7 +1,7 @@
-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__)
+require_relative '../../../spec_helper'
+require_relative '../fixtures/classes'
+require_relative 'shared/basic'
+require_relative 'shared/integer'
describe "String#unpack with format 'N'" do
it_behaves_like :string_unpack_basic, 'N'
diff --git a/spec/ruby/core/string/unpack/p_spec.rb b/spec/ruby/core/string/unpack/p_spec.rb
index 7c9a502a15..cd48c0523d 100644
--- a/spec/ruby/core/string/unpack/p_spec.rb
+++ b/spec/ruby/core/string/unpack/p_spec.rb
@@ -1,21 +1,44 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
-require File.expand_path('../../fixtures/classes', __FILE__)
-require File.expand_path('../shared/basic', __FILE__)
+require_relative '../../../spec_helper'
+require_relative '../fixtures/classes'
+require_relative 'shared/basic'
+require_relative 'shared/taint'
describe "String#unpack with format 'P'" do
it_behaves_like :string_unpack_basic, 'P'
+ it_behaves_like :string_unpack_taint, '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)
+ it "round-trips a string through pack and unpack" do
+ ["hello"].pack("P").unpack("P5").should == ["hello"]
+ end
+
+ it "cannot unpack a string except from the same object that created it, or a duplicate of it" do
+ packed = ["hello"].pack("P")
+ packed.unpack("P5").should == ["hello"]
+ packed.dup.unpack("P5").should == ["hello"]
+ -> { packed.to_sym.to_s.unpack("P5") }.should raise_error(ArgumentError, /no associated pointer/)
+ end
+
+ it "reads as many characters as specified" do
+ ["hello"].pack("P").unpack("P1").should == ["h"]
+ end
+
+ it "reads only as far as a NUL character" do
+ ["hello"].pack("P").unpack("P10").should == ["hello"]
end
end
describe "String#unpack with format 'p'" do
it_behaves_like :string_unpack_basic, 'p'
+ it_behaves_like :string_unpack_taint, 'p'
+
+ it "round-trips a string through pack and unpack" do
+ ["hello"].pack("p").unpack("p").should == ["hello"]
+ end
- 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)
+ it "cannot unpack a string except from the same object that created it, or a duplicate of it" do
+ packed = ["hello"].pack("p")
+ packed.unpack("p").should == ["hello"]
+ packed.dup.unpack("p").should == ["hello"]
+ -> { packed.to_sym.to_s.unpack("p") }.should raise_error(ArgumentError, /no associated pointer/)
end
end
diff --git a/spec/ruby/core/string/unpack/percent_spec.rb b/spec/ruby/core/string/unpack/percent_spec.rb
index 38cf81b037..0e27663195 100644
--- a/spec/ruby/core/string/unpack/percent_spec.rb
+++ b/spec/ruby/core/string/unpack/percent_spec.rb
@@ -1,7 +1,7 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "String#unpack with format '%'" do
it "raises an Argument Error" do
- lambda { "abc".unpack("%") }.should raise_error(ArgumentError)
+ -> { "abc".unpack("%") }.should raise_error(ArgumentError)
end
end
diff --git a/spec/ruby/core/string/unpack/q_spec.rb b/spec/ruby/core/string/unpack/q_spec.rb
index 91e65a9405..2f667d6c4d 100644
--- a/spec/ruby/core/string/unpack/q_spec.rb
+++ b/spec/ruby/core/string/unpack/q_spec.rb
@@ -1,7 +1,7 @@
-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__)
+require_relative '../../../spec_helper'
+require_relative '../fixtures/classes'
+require_relative 'shared/basic'
+require_relative 'shared/integer'
describe "String#unpack with format 'Q'" do
describe "with modifier '<'" do
diff --git a/spec/ruby/core/string/unpack/s_spec.rb b/spec/ruby/core/string/unpack/s_spec.rb
index c6b079b0a6..d331fd720e 100644
--- a/spec/ruby/core/string/unpack/s_spec.rb
+++ b/spec/ruby/core/string/unpack/s_spec.rb
@@ -1,7 +1,7 @@
-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__)
+require_relative '../../../spec_helper'
+require_relative '../fixtures/classes'
+require_relative 'shared/basic'
+require_relative 'shared/integer'
describe "String#unpack with format 'S'" do
describe "with modifier '<'" do
diff --git a/spec/ruby/core/string/unpack/shared/basic.rb b/spec/ruby/core/string/unpack/shared/basic.rb
index 0ecbf615af..734630bda0 100644
--- a/spec/ruby/core/string/unpack/shared/basic.rb
+++ b/spec/ruby/core/string/unpack/shared/basic.rb
@@ -9,21 +9,29 @@ describe :string_unpack_basic, shared: true do
"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)
+ ruby_version_is ""..."3.3" do
+ it "warns about using an unknown directive" do
+ -> { "abcdefgh".unpack("a R" + unpack_format) }.should complain(/unknown unpack directive 'R' in 'a R#{unpack_format}'/)
+ -> { "abcdefgh".unpack("a 0" + unpack_format) }.should complain(/unknown unpack directive '0' in 'a 0#{unpack_format}'/)
+ -> { "abcdefgh".unpack("a :" + unpack_format) }.should complain(/unknown unpack directive ':' in 'a :#{unpack_format}'/)
+ end
end
- it "raises a TypeError when passed an Integer" do
- lambda { "abc".unpack(1) }.should raise_error(TypeError)
+ ruby_version_is "3.3" do
+ it "raises ArgumentError when a directive is unknown" do
+ -> { "abcdefgh".unpack("a K" + unpack_format) }.should raise_error(ArgumentError, "unknown unpack directive 'K' in 'a K#{unpack_format}'")
+ -> { "abcdefgh".unpack("a 0" + unpack_format) }.should raise_error(ArgumentError, "unknown unpack directive '0' in 'a 0#{unpack_format}'")
+ -> { "abcdefgh".unpack("a :" + unpack_format) }.should raise_error(ArgumentError, "unknown unpack directive ':' in 'a :#{unpack_format}'")
+ end
end
end
describe :string_unpack_no_platform, shared: true do
it "raises an ArgumentError when the format modifier is '_'" do
- lambda { "abcdefgh".unpack(unpack_format("_")) }.should raise_error(ArgumentError)
+ -> { "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)
+ -> { "abcdefgh".unpack(unpack_format("!")) }.should raise_error(ArgumentError)
end
end
diff --git a/spec/ruby/core/string/unpack/shared/float.rb b/spec/ruby/core/string/unpack/shared/float.rb
index 208dc357af..b31c2c8bdc 100644
--- a/spec/ruby/core/string/unpack/shared/float.rb
+++ b/spec/ruby/core/string/unpack/shared/float.rb
@@ -1,4 +1,4 @@
-# -*- encoding: ascii-8bit -*-
+# encoding: binary
describe :string_unpack_float_le, shared: true do
it "decodes one float for a single format character" do
@@ -56,9 +56,21 @@ describe :string_unpack_float_le, shared: true do
[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]
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ array = "\x9a\x999@33\xb3?".unpack(unpack_format("\000", 2))
+ array.should == [2.9000000953674316, 1.399999976158142]
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "\x9a\x999@33\xb3?".unpack(unpack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
+ end
end
it "ignores spaces between directives" do
@@ -123,9 +135,21 @@ describe :string_unpack_float_be, shared: true do
[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]
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ array = "@9\x99\x9a?\xb333".unpack(unpack_format("\000", 2))
+ array.should == [2.9000000953674316, 1.399999976158142]
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "@9\x99\x9a?\xb333".unpack(unpack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
+ end
end
it "ignores spaces between directives" do
@@ -193,8 +217,20 @@ describe :string_unpack_double_le, shared: true do
[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]
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ "333333\x07@ffffff\xf6?".unpack(unpack_format("\000", 2)).should == [2.9, 1.4]
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "333333\x07@ffffff\xf6?".unpack(unpack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
+ end
end
it "ignores spaces between directives" do
@@ -261,8 +297,20 @@ describe :string_unpack_double_be, shared: true do
[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]
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ "@\x07333333?\xf6ffffff".unpack(unpack_format("\000", 2)).should == [2.9, 1.4]
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "@\x07333333?\xf6ffffff".unpack(unpack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
+ end
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/string/unpack/shared/integer.rb b/spec/ruby/core/string/unpack/shared/integer.rb
index 03dfb5c682..d3934753ba 100644
--- a/spec/ruby/core/string/unpack/shared/integer.rb
+++ b/spec/ruby/core/string/unpack/shared/integer.rb
@@ -1,4 +1,4 @@
-# -*- encoding: ascii-8bit -*-
+# encoding: binary
describe :string_unpack_16bit_le, shared: true do
it "decodes one short for a single format character" do
@@ -32,8 +32,20 @@ describe :string_unpack_16bit_le, shared: true do
].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]
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ "abcd".unpack(unpack_format("\000", 2)).should == [25185, 25699]
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "abcd".unpack(unpack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
+ end
end
it "ignores spaces between directives" do
@@ -85,8 +97,20 @@ describe :string_unpack_16bit_be, shared: true do
].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]
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ "badc".unpack(unpack_format("\000", 2)).should == [25185, 25699]
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "badc".unpack(unpack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
+ end
end
it "ignores spaces between directives" do
@@ -139,8 +163,20 @@ describe :string_unpack_32bit_le, shared: true do
].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]
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ "abcdefgh".unpack(unpack_format("\000", 2)).should == [1684234849, 1751606885]
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "abcdefgh".unpack(unpack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
+ end
end
it "ignores spaces between directives" do
@@ -193,8 +229,20 @@ describe :string_unpack_32bit_be, shared: true do
].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]
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ "dcbahgfe".unpack(unpack_format("\000", 2)).should == [1684234849, 1751606885]
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "dcbahgfe".unpack(unpack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
+ end
end
it "ignores spaces between directives" do
@@ -243,9 +291,21 @@ describe :string_unpack_64bit_le, shared: true 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]
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ array = "abcdefghabghefcd".unpack(unpack_format("\000", 2))
+ array.should == [7523094288207667809, 7233738012216484449]
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "badc".unpack(unpack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
+ end
end
it "ignores spaces between directives" do
@@ -305,9 +365,21 @@ describe :string_unpack_64bit_be, shared: true 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]
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ array = "hgfedcbadcfehgba".unpack(unpack_format("\000", 2))
+ array.should == [7523094288207667809, 7233738012216484449]
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "hgfedcbadcfehgba".unpack(unpack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
+ end
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/string/unpack/shared/taint.rb b/spec/ruby/core/string/unpack/shared/taint.rb
new file mode 100644
index 0000000000..79c7251f01
--- /dev/null
+++ b/spec/ruby/core/string/unpack/shared/taint.rb
@@ -0,0 +1,2 @@
+describe :string_unpack_taint, shared: true do
+end
diff --git a/spec/ruby/core/string/unpack/shared/unicode.rb b/spec/ruby/core/string/unpack/shared/unicode.rb
index a2b4e142b2..9fe07f53ae 100644
--- a/spec/ruby/core/string/unpack/shared/unicode.rb
+++ b/spec/ruby/core/string/unpack/shared/unicode.rb
@@ -50,8 +50,20 @@ describe :string_unpack_unicode, shared: true do
"\xc2\x80".unpack("UUUU").should == [0x80]
end
- it "ignores NULL bytes between directives" do
- "\x01\x02".unpack("U\x00U").should == [1, 2]
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ "\x01\x02".unpack("U\x00U").should == [1, 2]
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "\x01\x02".unpack("U\x00U")
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
+ end
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/string/unpack/u_spec.rb b/spec/ruby/core/string/unpack/u_spec.rb
index 0765da8d96..68c8f6f11c 100644
--- a/spec/ruby/core/string/unpack/u_spec.rb
+++ b/spec/ruby/core/string/unpack/u_spec.rb
@@ -1,26 +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__)
-require File.expand_path('../shared/unicode', __FILE__)
+# encoding: binary
+require_relative '../../../spec_helper'
+require_relative '../fixtures/classes'
+require_relative 'shared/basic'
+require_relative 'shared/unicode'
+require_relative 'shared/taint'
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_behaves_like :string_unpack_taint, 'U'
it "raises ArgumentError on a malformed byte sequence" do
- lambda { "\xE3".unpack('U') }.should raise_error(ArgumentError)
+ -> { "\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)
+ -> { "\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_behaves_like :string_unpack_taint, 'u'
it "decodes an empty string as an empty string" do
"".unpack("u").should == [""]
@@ -28,10 +31,10 @@ describe "String#unpack with format 'u'" do
it "decodes into raw (ascii) string values" do
str = "".unpack("u")[0]
- str.encoding.name.should == 'ASCII-8BIT'
+ str.encoding.should == Encoding::BINARY
- str = "1".force_encoding('UTF-8').unpack("u")[0]
- str.encoding.name.should == 'ASCII-8BIT'
+ str = "1".dup.force_encoding('UTF-8').unpack("u")[0]
+ str.encoding.should == Encoding::BINARY
end
it "decodes the complete string ignoring newlines when given a single directive" do
diff --git a/spec/ruby/core/string/unpack/v_spec.rb b/spec/ruby/core/string/unpack/v_spec.rb
index 33cf23c68b..929e8712cb 100644
--- a/spec/ruby/core/string/unpack/v_spec.rb
+++ b/spec/ruby/core/string/unpack/v_spec.rb
@@ -1,7 +1,7 @@
-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__)
+require_relative '../../../spec_helper'
+require_relative '../fixtures/classes'
+require_relative 'shared/basic'
+require_relative 'shared/integer'
describe "String#unpack with format 'V'" do
it_behaves_like :string_unpack_basic, 'V'
diff --git a/spec/ruby/core/string/unpack/w_spec.rb b/spec/ruby/core/string/unpack/w_spec.rb
index 22f5980a46..7d3533ccae 100644
--- a/spec/ruby/core/string/unpack/w_spec.rb
+++ b/spec/ruby/core/string/unpack/w_spec.rb
@@ -1,7 +1,7 @@
-# -*- encoding: ascii-8bit -*-
-require File.expand_path('../../../../spec_helper', __FILE__)
-require File.expand_path('../../fixtures/classes', __FILE__)
-require File.expand_path('../shared/basic', __FILE__)
+# encoding: binary
+require_relative '../../../spec_helper'
+require_relative '../fixtures/classes'
+require_relative 'shared/basic'
describe "String#unpack with directive 'w'" do
it_behaves_like :string_unpack_basic, 'w'
@@ -15,11 +15,33 @@ describe "String#unpack with directive 'w'" do
].should be_computed_by(:unpack, "w")
end
- it "ignores NULL bytes between directives" do
- "\x01\x02\x03".unpack("w\x00w").should == [1, 2]
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ "\x01\x02\x03".unpack("w\x00w").should == [1, 2]
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "\x01\x02\x03".unpack("w\x00w")
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
+ end
end
it "ignores spaces between directives" do
"\x01\x02\x03".unpack("w w").should == [1, 2]
end
end
+
+describe "String#unpack with directive 'w*'" do
+
+ it "decodes BER-compressed integers" do
+ "\x01\x02\x03\x04".unpack("w*").should == [1, 2, 3, 4]
+ "\x00\xCE\x0F\x84\x80\x80\x80\x80\x80\x80\x80\x80\x00\x01\x00".unpack("w*").should == [0, 9999, 2**65, 1, 0]
+ "\x81\x80\x80\x80\x80\x80\x80\x80\x80\x00\x90\x80\x80\x80\x80\x80\x80\x80\x03\x01\x02".unpack("w*").should == [2**63, (2**60 + 3), 1, 2]
+ end
+
+end
diff --git a/spec/ruby/core/string/unpack/x_spec.rb b/spec/ruby/core/string/unpack/x_spec.rb
index e765472413..2926ebbe0f 100644
--- a/spec/ruby/core/string/unpack/x_spec.rb
+++ b/spec/ruby/core/string/unpack/x_spec.rb
@@ -1,7 +1,7 @@
-# -*- encoding: ascii-8bit -*-
-require File.expand_path('../../../../spec_helper', __FILE__)
-require File.expand_path('../../fixtures/classes', __FILE__)
-require File.expand_path('../shared/basic', __FILE__)
+# encoding: binary
+require_relative '../../../spec_helper'
+require_relative '../fixtures/classes'
+require_relative 'shared/basic'
describe "String#unpack with format 'X'" do
it_behaves_like :string_unpack_basic, 'X'
@@ -24,11 +24,11 @@ describe "String#unpack with format 'X'" do
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)
+ -> { "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)
+ -> { "\x01\x02\x03\x04".unpack("C3X4C") }.should raise_error(ArgumentError)
end
end
@@ -57,6 +57,6 @@ describe "String#unpack with format 'x'" do
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)
+ -> { "\x01\x02\x03\x04".unpack("C2x3C") }.should raise_error(ArgumentError)
end
end
diff --git a/spec/ruby/core/string/unpack/z_spec.rb b/spec/ruby/core/string/unpack/z_spec.rb
index 7c3d167ac2..1030390550 100644
--- a/spec/ruby/core/string/unpack/z_spec.rb
+++ b/spec/ruby/core/string/unpack/z_spec.rb
@@ -1,13 +1,15 @@
-# -*- 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__)
+# encoding: binary
+require_relative '../../../spec_helper'
+require_relative '../fixtures/classes'
+require_relative 'shared/basic'
+require_relative 'shared/string'
+require_relative 'shared/taint'
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_behaves_like :string_unpack_taint, '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"]
@@ -18,4 +20,9 @@ describe "String#unpack with format 'Z'" do
["\x00a\x00 bc \x00", ["", "c"]]
].should be_computed_by(:unpack, "Z5Z")
end
+
+ it "does not advance past the null byte when given a 'Z' format specifier" do
+ "a\x00\x0f".unpack('Zxc').should == ['a', 15]
+ "a\x00\x0f".unpack('Zcc').should == ['a', 0, 15]
+ end
end
diff --git a/spec/ruby/core/string/unpack1_spec.rb b/spec/ruby/core/string/unpack1_spec.rb
index 6941bc1173..cfb47fe695 100644
--- a/spec/ruby/core/string/unpack1_spec.rb
+++ b/spec/ruby/core/string/unpack1_spec.rb
@@ -1,12 +1,47 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-
-ruby_version_is "2.4" do
- describe "String#unpack1" do
- it "returns the first value of #unpack" do
- "ABCD".unpack1('x3C').should == "ABCD".unpack('x3C')[0]
- "\u{3042 3044 3046}".unpack1("U*").should == 0x3042
- "aG9nZWZ1Z2E=".unpack1("m").should == "hogefuga"
- "A".unpack1("B*").should == "01000001"
+require_relative '../../spec_helper'
+
+describe "String#unpack1" do
+ it "returns the first value of #unpack" do
+ "ABCD".unpack1('x3C').should == "ABCD".unpack('x3C')[0]
+ "\u{3042 3044 3046}".unpack1("U*").should == 0x3042
+ "aG9nZWZ1Z2E=".unpack1("m").should == "hogefuga"
+ "A".unpack1("B*").should == "01000001"
+ end
+
+ it "starts unpacking from the given offset" do
+ "ZZABCD".unpack1('x3C', offset: 2).should == "ABCD".unpack('x3C')[0]
+ "ZZZZaG9nZWZ1Z2E=".unpack1("m", offset: 4).should == "hogefuga"
+ "ZA".unpack1("B*", offset: 1).should == "01000001"
+ end
+
+ it "traits offset as a bytes offset" do
+ "؈".unpack("CC").should == [216, 136]
+ "؈".unpack1("C").should == 216
+ "؈".unpack1("C", offset: 1).should == 136
+ end
+
+ it "raises an ArgumentError when the offset is negative" do
+ -> { "a".unpack1("C", offset: -1) }.should raise_error(ArgumentError, "offset can't be negative")
+ end
+
+ it "returns nil if the offset is at the end of the string" do
+ "a".unpack1("C", offset: 1).should == nil
+ end
+
+ it "raises an ArgumentError when the offset is larger than the string bytesize" do
+ -> { "a".unpack1("C", offset: 2) }.should raise_error(ArgumentError, "offset outside of string")
+ end
+
+ context "with format 'm0'" do
+ # unpack1("m0") takes a special code path that calls Pack.unpackBase46Strict instead of Pack.unpack_m,
+ # which is why we repeat the tests for unpack("m0") here.
+
+ it "decodes base64" do
+ "dGVzdA==".unpack1("m0").should == "test"
+ end
+
+ it "raises an ArgumentError for an invalid base64 character" do
+ -> { "dGV%zdA==".unpack1("m0") }.should raise_error(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/string/unpack_spec.rb b/spec/ruby/core/string/unpack_spec.rb
new file mode 100644
index 0000000000..a0abf8fa99
--- /dev/null
+++ b/spec/ruby/core/string/unpack_spec.rb
@@ -0,0 +1,32 @@
+require_relative '../../spec_helper'
+
+describe "String#unpack" do
+ it "raises a TypeError when passed nil" do
+ -> { "abc".unpack(nil) }.should raise_error(TypeError)
+ end
+
+ it "raises a TypeError when passed an Integer" do
+ -> { "abc".unpack(1) }.should raise_error(TypeError)
+ end
+
+ it "starts unpacking from the given offset" do
+ "abc".unpack("CC", offset: 1).should == [98, 99]
+ end
+
+ it "traits offset as a bytes offset" do
+ "؈".unpack("CC").should == [216, 136]
+ "؈".unpack("CC", offset: 1).should == [136, nil]
+ end
+
+ it "raises an ArgumentError when the offset is negative" do
+ -> { "a".unpack("C", offset: -1) }.should raise_error(ArgumentError, "offset can't be negative")
+ end
+
+ it "returns nil if the offset is at the end of the string" do
+ "a".unpack("C", offset: 1).should == [nil]
+ end
+
+ it "raises an ArgumentError when the offset is larger than the string" do
+ -> { "a".unpack("C", offset: 2) }.should raise_error(ArgumentError, "offset outside of string")
+ end
+end
diff --git a/spec/ruby/core/string/upcase_spec.rb b/spec/ruby/core/string/upcase_spec.rb
index 0094380664..652de5c2ef 100644
--- a/spec/ruby/core/string/upcase_spec.rb
+++ b/spec/ruby/core/string/upcase_spec.rb
@@ -1,6 +1,7 @@
# -*- encoding: utf-8 -*-
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+# frozen_string_literal: false
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String#upcase" do
it "returns a copy of self with all lowercase letters upcased" do
@@ -8,34 +9,73 @@ describe "String#upcase" do
"hello".upcase.should == "HELLO"
end
- ruby_version_is ''...'2.4' do
- it "is locale insensitive (only replaces a-z)" do
- "äöü".upcase.should == "äöü"
+ it "returns a String in the same encoding as self" do
+ "hello".encode("US-ASCII").upcase.encoding.should == Encoding::US_ASCII
+ end
+
+ describe "full Unicode case mapping" do
+ it "works for all of Unicode with no option" do
+ "äöü".upcase.should == "ÄÖÜ"
+ end
- str = Array.new(256) { |c| c.chr }.join
- expected = Array.new(256) do |i|
- c = i.chr
- c.between?("a", "z") ? c.upcase : c
- end.join
+ it "updates string metadata" do
+ upcased = "aßet".upcase
- str.upcase.should == expected
+ upcased.should == "ASSET"
+ upcased.size.should == 5
+ upcased.bytesize.should == 5
+ upcased.ascii_only?.should be_true
end
end
- ruby_version_is '2.4' do
- it "works for all of Unicode" do
- "äöü".upcase.should == "ÄÖÜ"
+ describe "ASCII-only case mapping" do
+ it "does not upcase non-ASCII characters" do
+ "aßet".upcase(:ascii).should == "AßET"
+ end
+
+ it "works with substrings" do
+ "prefix té"[-2..-1].upcase(:ascii).should == "Té"
+ end
+ end
+
+ describe "full Unicode case mapping adapted for Turkic languages" do
+ it "upcases ASCII characters according to Turkic semantics" do
+ "i".upcase(:turkic).should == "İ"
+ end
+
+ it "allows Lithuanian as an extra option" do
+ "i".upcase(:turkic, :lithuanian).should == "İ"
+ end
+
+ it "does not allow any other additional option" do
+ -> { "i".upcase(:turkic, :ascii) }.should raise_error(ArgumentError)
end
end
- it "taints result when self is tainted" do
- "".taint.upcase.tainted?.should == true
- "X".taint.upcase.tainted?.should == true
- "x".taint.upcase.tainted?.should == true
+ describe "full Unicode case mapping adapted for Lithuanian" do
+ it "currently works the same as full Unicode case mapping" do
+ "iß".upcase(:lithuanian).should == "ISS"
+ end
+
+ it "allows Turkic as an extra option (and applies Turkic semantics)" do
+ "iß".upcase(:lithuanian, :turkic).should == "İSS"
+ end
+
+ it "does not allow any other additional option" do
+ -> { "iß".upcase(:lithuanian, :ascii) }.should raise_error(ArgumentError)
+ end
end
- it "returns a subclass instance for subclasses" do
- StringSpecs::MyString.new("fooBAR").upcase.should be_an_instance_of(StringSpecs::MyString)
+ it "does not allow the :fold option for upcasing" do
+ -> { "abc".upcase(:fold) }.should raise_error(ArgumentError)
+ end
+
+ it "does not allow invalid options" do
+ -> { "abc".upcase(:invalid_option) }.should raise_error(ArgumentError)
+ end
+
+ it "returns a String instance for subclasses" do
+ StringSpecs::MyString.new("fooBAR").upcase.should be_an_instance_of(String)
end
end
@@ -46,13 +86,92 @@ describe "String#upcase!" do
a.should == "HELLO"
end
+ it "modifies self in place for non-ascii-compatible encodings" do
+ a = "HeLlO".encode("utf-16le")
+ a.upcase!
+ a.should == "HELLO".encode("utf-16le")
+ end
- ruby_version_is '2.4' do
- it "modifies self in place for all of Unicode" do
+ describe "full Unicode case mapping" do
+ it "modifies self in place for all of Unicode with no option" do
a = "äöü"
- a.upcase!.should equal(a)
+ a.upcase!
a.should == "ÄÖÜ"
end
+
+ it "works for non-ascii-compatible encodings" do
+ a = "äöü".encode("utf-16le")
+ a.upcase!
+ a.should == "ÄÖÜ".encode("utf-16le")
+ end
+
+ it "updates string metadata for self" do
+ upcased = "aßet"
+ upcased.upcase!
+
+ upcased.should == "ASSET"
+ upcased.size.should == 5
+ upcased.bytesize.should == 5
+ upcased.ascii_only?.should be_true
+ end
+ end
+
+ describe "modifies self in place for ASCII-only case mapping" do
+ it "does not upcase non-ASCII characters" do
+ a = "aßet"
+ a.upcase!(:ascii)
+ a.should == "AßET"
+ end
+
+ it "works for non-ascii-compatible encodings" do
+ a = "abc".encode("utf-16le")
+ a.upcase!(:ascii)
+ a.should == "ABC".encode("utf-16le")
+ end
+ end
+
+ describe "modifies self in place for full Unicode case mapping adapted for Turkic languages" do
+ it "upcases ASCII characters according to Turkic semantics" do
+ a = "i"
+ a.upcase!(:turkic)
+ a.should == "İ"
+ end
+
+ it "allows Lithuanian as an extra option" do
+ a = "i"
+ a.upcase!(:turkic, :lithuanian)
+ a.should == "İ"
+ end
+
+ it "does not allow any other additional option" do
+ -> { a = "i"; a.upcase!(:turkic, :ascii) }.should raise_error(ArgumentError)
+ end
+ end
+
+ describe "modifies self in place for full Unicode case mapping adapted for Lithuanian" do
+ it "currently works the same as full Unicode case mapping" do
+ a = "iß"
+ a.upcase!(:lithuanian)
+ a.should == "ISS"
+ end
+
+ it "allows Turkic as an extra option (and applies Turkic semantics)" do
+ a = "iß"
+ a.upcase!(:lithuanian, :turkic)
+ a.should == "İSS"
+ end
+
+ it "does not allow any other additional option" do
+ -> { a = "iß"; a.upcase!(:lithuanian, :ascii) }.should raise_error(ArgumentError)
+ end
+ end
+
+ it "does not allow the :fold option for upcasing" do
+ -> { a = "abc"; a.upcase!(:fold) }.should raise_error(ArgumentError)
+ end
+
+ it "does not allow invalid options" do
+ -> { a = "abc"; a.upcase!(:invalid_option) }.should raise_error(ArgumentError)
end
it "returns nil if no modifications were made" do
@@ -61,8 +180,8 @@ describe "String#upcase!" do
a.should == "HELLO"
end
- it "raises a RuntimeError when self is frozen" do
- lambda { "HeLlo".freeze.upcase! }.should raise_error(RuntimeError)
- lambda { "HELLO".freeze.upcase! }.should raise_error(RuntimeError)
+ it "raises a FrozenError when self is frozen" do
+ -> { "HeLlo".freeze.upcase! }.should raise_error(FrozenError)
+ -> { "HELLO".freeze.upcase! }.should raise_error(FrozenError)
end
end
diff --git a/spec/ruby/core/string/uplus_spec.rb b/spec/ruby/core/string/uplus_spec.rb
index eafa721903..20767bcc01 100644
--- a/spec/ruby/core/string/uplus_spec.rb
+++ b/spec/ruby/core/string/uplus_spec.rb
@@ -1,24 +1,60 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+# frozen_string_literal: false
+require_relative '../../spec_helper'
-ruby_version_is "2.3" do
- describe 'String#+@' do
- it 'returns an unfrozen copy of a frozen String' do
- input = 'foo'.freeze
- output = +input
+describe 'String#+@' do
+ it 'returns an unfrozen copy of a frozen String' do
+ input = 'foo'.freeze
+ output = +input
+
+ output.should_not.frozen?
+ output.should == 'foo'
+
+ output << 'bar'
+ output.should == 'foobar'
+ end
+
+ it 'returns a mutable String itself' do
+ input = String.new("foo")
+ output = +input
+
+ output.should.equal?(input)
+
+ input << "bar"
+ output.should == "foobar"
+ end
- output.frozen?.should == false
- output.should == 'foo'
+ context 'if file has "frozen_string_literal: true" magic comment' do
+ it 'returns mutable copy of a literal' do
+ ruby_exe(fixture(__FILE__, "freeze_magic_comment.rb")).should == 'mutable'
end
+ end
- it 'returns self if the String is not frozen' do
+ context 'if file has "frozen_string_literal: false" magic comment' do
+ it 'returns literal string itself' do
input = 'foo'
output = +input
output.equal?(input).should == true
end
+ end
- it 'returns mutable copy despite freeze-magic-comment in file' do
- ruby_exe(fixture(__FILE__, "freeze_magic_comment.rb")).should == 'mutable'
+ context 'if file has no frozen_string_literal magic comment' do
+ ruby_version_is ''...'3.4' do
+ it 'returns literal string itself' do
+ eval(<<~RUBY).should == true
+ s = "foo"
+ s.equal?(+s)
+ RUBY
+ end
+ end
+
+ ruby_version_is '3.4' do
+ it 'returns mutable copy of a literal' do
+ eval(<<~RUBY).should == false
+ s = "foo"
+ s.equal?(+s)
+ RUBY
+ end
end
end
end
diff --git a/spec/ruby/core/string/upto_spec.rb b/spec/ruby/core/string/upto_spec.rb
index 6b998eed3c..8bc847d5ac 100644
--- a/spec/ruby/core/string/upto_spec.rb
+++ b/spec/ruby/core/string/upto_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/classes.rb', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "String#upto" do
it "passes successive values, starting at self and ending at other_string, to the block" do
@@ -8,7 +8,7 @@ describe "String#upto" do
a.should == ["*+", "*,", "*-", "*.", "*/", "*0", "*1", "*2", "*3"]
end
- it "calls the block once even when start eqals stop" do
+ it "calls the block once even when start equals stop" do
a = []
"abc".upto("abc") { |s| a << s }
a.should == ["abc"]
@@ -53,13 +53,13 @@ describe "String#upto" do
end
it "raises a TypeError if other can't be converted to a string" do
- lambda { "abc".upto(123) { } }.should raise_error(TypeError)
- lambda { "abc".upto(mock('x')){ } }.should raise_error(TypeError)
+ -> { "abc".upto(123) { } }.should raise_error(TypeError)
+ -> { "abc".upto(mock('x')){ } }.should raise_error(TypeError)
end
it "does not work with symbols" do
- lambda { "a".upto(:c).to_a }.should raise_error(TypeError)
+ -> { "a".upto(:c).to_a }.should raise_error(TypeError)
end
it "returns non-alphabetic characters in the ASCII range for single letters" do
@@ -74,6 +74,18 @@ describe "String#upto" do
a.should == ["a", "b", "c"]
end
+ it "works with non-ASCII ranges" do
+ a = []
+ 'Σ'.upto('Ω') { |s| a << s }
+ a.should == ["Σ", "Τ", "Υ", "Φ", "Χ", "Ψ", "Ω"]
+ end
+
+ it "raises Encoding::CompatibilityError when incompatible characters are given" do
+ char1 = 'a'.dup.force_encoding("EUC-JP")
+ char2 = 'b'.dup.force_encoding("ISO-2022-JP")
+ -> { char1.upto(char2) {} }.should raise_error(Encoding::CompatibilityError, "incompatible character encodings: EUC-JP and ISO-2022-JP")
+ end
+
describe "on sequence of numbers" do
it "calls the block as Integer#upto" do
"8".upto("11").to_a.should == 8.upto(11).map(&:to_s)
diff --git a/spec/ruby/core/string/valid_encoding/utf_8_spec.rb b/spec/ruby/core/string/valid_encoding/utf_8_spec.rb
new file mode 100644
index 0000000000..a14c3af830
--- /dev/null
+++ b/spec/ruby/core/string/valid_encoding/utf_8_spec.rb
@@ -0,0 +1,214 @@
+# -*- encoding: utf-8 -*-
+require_relative '../../../spec_helper'
+
+describe "String#valid_encoding? and UTF-8" do
+ def utf8(bytes)
+ bytes.pack("C*").force_encoding("UTF-8")
+ end
+
+ describe "1-byte character" do
+ it "is valid if is in format 0xxxxxxx" do
+ utf8([0b00000000]).valid_encoding?.should == true
+ utf8([0b01111111]).valid_encoding?.should == true
+ end
+
+ it "is not valid if is not in format 0xxxxxxx" do
+ utf8([0b10000000]).valid_encoding?.should == false
+ utf8([0b11111111]).valid_encoding?.should == false
+ end
+ end
+
+ describe "2-bytes character" do
+ it "is valid if in format [110xxxxx 10xxxxx]" do
+ utf8([0b11000010, 0b10000000]).valid_encoding?.should == true
+ utf8([0b11000010, 0b10111111]).valid_encoding?.should == true
+
+ utf8([0b11011111, 0b10000000]).valid_encoding?.should == true
+ utf8([0b11011111, 0b10111111]).valid_encoding?.should == true
+ end
+
+ it "is not valid if the first byte is not in format 110xxxxx" do
+ utf8([0b00000010, 0b10000000]).valid_encoding?.should == false
+ utf8([0b00100010, 0b10000000]).valid_encoding?.should == false
+ utf8([0b01000010, 0b10000000]).valid_encoding?.should == false
+ utf8([0b01100010, 0b10000000]).valid_encoding?.should == false
+ utf8([0b10000010, 0b10000000]).valid_encoding?.should == false
+ utf8([0b10100010, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11000010, 0b10000000]).valid_encoding?.should == true # correct bytes
+ utf8([0b11100010, 0b10000000]).valid_encoding?.should == false
+ end
+
+ it "is not valid if the second byte is not in format 10xxxxxx" do
+ utf8([0b11000010, 0b00000000]).valid_encoding?.should == false
+ utf8([0b11000010, 0b01000000]).valid_encoding?.should == false
+ utf8([0b11000010, 0b11000000]).valid_encoding?.should == false
+ end
+
+ it "is not valid if is smaller than [xxxxxx10 xx000000] (codepoints < U+007F, that are encoded with the 1-byte format)" do
+ utf8([0b11000000, 0b10111111]).valid_encoding?.should == false
+ utf8([0b11000001, 0b10111111]).valid_encoding?.should == false
+ end
+
+ it "is not valid if the first byte is missing" do
+ bytes = [0b11000010, 0b10000000]
+ utf8(bytes[1..1]).valid_encoding?.should == false
+ end
+
+ it "is not valid if the second byte is missing" do
+ bytes = [0b11000010, 0b10000000]
+ utf8(bytes[0..0]).valid_encoding?.should == false
+ end
+ end
+
+ describe "3-bytes character" do
+ it "is valid if in format [1110xxxx 10xxxxxx 10xxxxxx]" do
+ utf8([0b11100000, 0b10100000, 0b10000000]).valid_encoding?.should == true
+ utf8([0b11100000, 0b10100000, 0b10111111]).valid_encoding?.should == true
+ utf8([0b11100000, 0b10111111, 0b10111111]).valid_encoding?.should == true
+ utf8([0b11101111, 0b10111111, 0b10111111]).valid_encoding?.should == true
+ end
+
+ it "is not valid if the first byte is not in format 1110xxxx" do
+ utf8([0b00000000, 0b10100000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b00010000, 0b10100000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b00100000, 0b10100000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b00110000, 0b10100000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b01000000, 0b10100000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b01010000, 0b10100000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b01100000, 0b10100000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b01110000, 0b10100000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b10000000, 0b10100000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b10010000, 0b10100000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b10100000, 0b10100000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b10110000, 0b10100000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11000000, 0b10100000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11010000, 0b10100000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11100000, 0b10100000, 0b10000000]).valid_encoding?.should == true # correct bytes
+ utf8([0b11110000, 0b10100000, 0b10000000]).valid_encoding?.should == false
+ end
+
+ it "is not valid if the second byte is not in format 10xxxxxx" do
+ utf8([0b11100000, 0b00100000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11100000, 0b01100000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11100000, 0b11100000, 0b10000000]).valid_encoding?.should == false
+ end
+
+ it "is not valid if the third byte is not in format 10xxxxxx" do
+ utf8([0b11100000, 0b10100000, 0b00000000]).valid_encoding?.should == false
+ utf8([0b11100000, 0b10100000, 0b01000000]).valid_encoding?.should == false
+ utf8([0b11100000, 0b10100000, 0b01000000]).valid_encoding?.should == false
+ end
+
+ it "is not valid if is smaller than [xxxx0000 xx100000 xx000000] (codepoints < U+07FF that are encoded with the 2-byte format)" do
+ utf8([0b11100000, 0b10010000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11100000, 0b10001000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11100000, 0b10000100, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11100000, 0b10000010, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11100000, 0b10000001, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11100000, 0b10000000, 0b10000000]).valid_encoding?.should == false
+ end
+
+ it "is not valid if in range [xxxx1101 xx100000 xx000000] - [xxxx1101 xx111111 xx111111] (codepoints U+D800 - U+DFFF)" do
+ utf8([0b11101101, 0b10100000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11101101, 0b10100000, 0b10000001]).valid_encoding?.should == false
+ utf8([0b11101101, 0b10111111, 0b10111111]).valid_encoding?.should == false
+
+ utf8([0b11101101, 0b10011111, 0b10111111]).valid_encoding?.should == true # lower boundary - 1
+ utf8([0b11101110, 0b10000000, 0b10000000]).valid_encoding?.should == true # upper boundary + 1
+ end
+
+ it "is not valid if the first byte is missing" do
+ bytes = [0b11100000, 0b10100000, 0b10000000]
+ utf8(bytes[2..3]).valid_encoding?.should == false
+ end
+
+ it "is not valid if the second byte is missing" do
+ bytes = [0b11100000, 0b10100000, 0b10000000]
+ utf8([bytes[0], bytes[2]]).valid_encoding?.should == false
+ end
+
+ it "is not valid if the second and the third bytes are missing" do
+ bytes = [0b11100000, 0b10100000, 0b10000000]
+ utf8(bytes[0..0]).valid_encoding?.should == false
+ end
+ end
+
+ describe "4-bytes character" do
+ it "is valid if in format [11110xxx 10xxxxxx 10xxxxxx 10xxxxxx]" do
+ utf8([0b11110000, 0b10010000, 0b10000000, 0b10000000]).valid_encoding?.should == true
+ utf8([0b11110000, 0b10010000, 0b10000000, 0b10111111]).valid_encoding?.should == true
+ utf8([0b11110000, 0b10010000, 0b10111111, 0b10111111]).valid_encoding?.should == true
+ utf8([0b11110000, 0b10111111, 0b10111111, 0b10111111]).valid_encoding?.should == true
+ utf8([0b11110100, 0b10001111, 0b10111111, 0b10111111]).valid_encoding?.should == true
+ end
+
+ it "is not valid if the first byte is not in format 11110xxx" do
+ utf8([0b11100000, 0b10010000, 0b10000000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11010000, 0b10010000, 0b10000000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b10110000, 0b10010000, 0b10000000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b01110000, 0b10010000, 0b10000000, 0b10000000]).valid_encoding?.should == false
+ end
+
+ it "is not valid if the second byte is not in format 10xxxxxx" do
+ utf8([0b11110000, 0b00010000, 0b10000000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11110000, 0b01010000, 0b10000000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11110000, 0b10010000, 0b10000000, 0b10000000]).valid_encoding?.should == true # correct bytes
+ utf8([0b11110000, 0b11010000, 0b10000000, 0b10000000]).valid_encoding?.should == false
+ end
+
+ it "is not valid if the third byte is not in format 10xxxxxx" do
+ utf8([0b11110000, 0b10010000, 0b00000000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11110000, 0b10010000, 0b01000000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11110000, 0b10010000, 0b10000000, 0b10000000]).valid_encoding?.should == true # correct bytes
+ utf8([0b11110000, 0b10010000, 0b11000000, 0b10000000]).valid_encoding?.should == false
+ end
+
+ it "is not valid if the forth byte is not in format 10xxxxxx" do
+ utf8([0b11110000, 0b10010000, 0b10000000, 0b00000000]).valid_encoding?.should == false
+ utf8([0b11110000, 0b10010000, 0b10000000, 0b01000000]).valid_encoding?.should == false
+ utf8([0b11110000, 0b10010000, 0b10000000, 0b10000000]).valid_encoding?.should == true # correct bytes
+ utf8([0b11110000, 0b10010000, 0b10000000, 0b11000000]).valid_encoding?.should == false
+ end
+
+ it "is not valid if is smaller than [xxxxx000 xx001000 xx000000 xx000000] (codepoint < U+10000)" do
+ utf8([0b11110000, 0b10000111, 0b10000000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11110000, 0b10000110, 0b10000000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11110000, 0b10000101, 0b10000000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11110000, 0b10000100, 0b10000000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11110000, 0b10000011, 0b10000000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11110000, 0b10000010, 0b10000000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11110000, 0b10000001, 0b10000000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11110000, 0b10000000, 0b10000000, 0b10000000]).valid_encoding?.should == false
+ end
+
+ it "is not valid if is greater than [xxxxx100 xx001111 xx111111 xx111111] (codepoint > U+10FFFF)" do
+ utf8([0b11110100, 0b10010000, 0b10000000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11110100, 0b10100000, 0b10000000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11110100, 0b10110000, 0b10000000, 0b10000000]).valid_encoding?.should == false
+
+ utf8([0b11110101, 0b10001111, 0b10111111, 0b10111111]).valid_encoding?.should == false
+ utf8([0b11110110, 0b10001111, 0b10111111, 0b10111111]).valid_encoding?.should == false
+ utf8([0b11110111, 0b10001111, 0b10111111, 0b10111111]).valid_encoding?.should == false
+ end
+
+ it "is not valid if the first byte is missing" do
+ bytes = [0b11110000, 0b10010000, 0b10000000, 0b10000000]
+ utf8(bytes[1..3]).valid_encoding?.should == false
+ end
+
+ it "is not valid if the second byte is missing" do
+ bytes = [0b11110000, 0b10010000, 0b10000000, 0b10000000]
+ utf8([bytes[0], bytes[2], bytes[3]]).valid_encoding?.should == false
+ end
+
+ it "is not valid if the second and the third bytes are missing" do
+ bytes = [0b11110000, 0b10010000, 0b10000000, 0b10000000]
+ utf8([bytes[0], bytes[3]]).valid_encoding?.should == false
+ end
+
+ it "is not valid if the second, the third and the fourth bytes are missing" do
+ bytes = [0b11110000, 0b10010000, 0b10000000, 0b10000000]
+ utf8(bytes[0..0]).valid_encoding?.should == false
+ end
+ end
+end
diff --git a/spec/ruby/core/string/valid_encoding_spec.rb b/spec/ruby/core/string/valid_encoding_spec.rb
index ddd0fe52a2..375035cd94 100644
--- a/spec/ruby/core/string/valid_encoding_spec.rb
+++ b/spec/ruby/core/string/valid_encoding_spec.rb
@@ -1,129 +1,133 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
-with_feature :encoding do
- describe "String#valid_encoding?" do
- it "returns true if the String's encoding is valid" do
- "a".valid_encoding?.should be_true
- "\u{8365}\u{221}".valid_encoding?.should be_true
- end
+describe "String#valid_encoding?" do
+ it "returns true if the String's encoding is valid" do
+ "a".valid_encoding?.should be_true
+ "\u{8365}\u{221}".valid_encoding?.should be_true
+ end
+
+ it "returns true if self is valid in the current encoding and other encodings" do
+ str = +"\x77"
+ str.force_encoding('utf-8').valid_encoding?.should be_true
+ str.force_encoding('binary').valid_encoding?.should be_true
+ end
- it "returns true if self is valid in the current encoding and other encodings" do
- str = "\x77"
- str.force_encoding('utf-8').valid_encoding?.should be_true
- str.force_encoding('ascii-8bit').valid_encoding?.should be_true
- end
+ it "returns true for all encodings self is valid in" do
+ str = +"\xE6\x9D\x94"
+ str.force_encoding('BINARY').valid_encoding?.should be_true
+ str.force_encoding('UTF-8').valid_encoding?.should be_true
+ str.force_encoding('US-ASCII').valid_encoding?.should be_false
+ str.force_encoding('Big5').valid_encoding?.should be_false
+ str.force_encoding('CP949').valid_encoding?.should be_false
+ str.force_encoding('Emacs-Mule').valid_encoding?.should be_false
+ str.force_encoding('EUC-JP').valid_encoding?.should be_false
+ str.force_encoding('EUC-KR').valid_encoding?.should be_false
+ str.force_encoding('EUC-TW').valid_encoding?.should be_false
+ str.force_encoding('GB18030').valid_encoding?.should be_false
+ str.force_encoding('GBK').valid_encoding?.should be_false
+ str.force_encoding('ISO-8859-1').valid_encoding?.should be_true
+ str.force_encoding('ISO-8859-2').valid_encoding?.should be_true
+ str.force_encoding('ISO-8859-3').valid_encoding?.should be_true
+ str.force_encoding('ISO-8859-4').valid_encoding?.should be_true
+ str.force_encoding('ISO-8859-5').valid_encoding?.should be_true
+ str.force_encoding('ISO-8859-6').valid_encoding?.should be_true
+ str.force_encoding('ISO-8859-7').valid_encoding?.should be_true
+ str.force_encoding('ISO-8859-8').valid_encoding?.should be_true
+ str.force_encoding('ISO-8859-9').valid_encoding?.should be_true
+ str.force_encoding('ISO-8859-10').valid_encoding?.should be_true
+ str.force_encoding('ISO-8859-11').valid_encoding?.should be_true
+ str.force_encoding('ISO-8859-13').valid_encoding?.should be_true
+ str.force_encoding('ISO-8859-14').valid_encoding?.should be_true
+ str.force_encoding('ISO-8859-15').valid_encoding?.should be_true
+ str.force_encoding('ISO-8859-16').valid_encoding?.should be_true
+ str.force_encoding('KOI8-R').valid_encoding?.should be_true
+ str.force_encoding('KOI8-U').valid_encoding?.should be_true
+ str.force_encoding('Shift_JIS').valid_encoding?.should be_false
+ "\xD8\x00".dup.force_encoding('UTF-16BE').valid_encoding?.should be_false
+ "\x00\xD8".dup.force_encoding('UTF-16LE').valid_encoding?.should be_false
+ "\x04\x03\x02\x01".dup.force_encoding('UTF-32BE').valid_encoding?.should be_false
+ "\x01\x02\x03\x04".dup.force_encoding('UTF-32LE').valid_encoding?.should be_false
+ str.force_encoding('Windows-1251').valid_encoding?.should be_true
+ str.force_encoding('IBM437').valid_encoding?.should be_true
+ str.force_encoding('IBM737').valid_encoding?.should be_true
+ str.force_encoding('IBM775').valid_encoding?.should be_true
+ str.force_encoding('CP850').valid_encoding?.should be_true
+ str.force_encoding('IBM852').valid_encoding?.should be_true
+ str.force_encoding('CP852').valid_encoding?.should be_true
+ str.force_encoding('IBM855').valid_encoding?.should be_true
+ str.force_encoding('CP855').valid_encoding?.should be_true
+ str.force_encoding('IBM857').valid_encoding?.should be_true
+ str.force_encoding('IBM860').valid_encoding?.should be_true
+ str.force_encoding('IBM861').valid_encoding?.should be_true
+ str.force_encoding('IBM862').valid_encoding?.should be_true
+ str.force_encoding('IBM863').valid_encoding?.should be_true
+ str.force_encoding('IBM864').valid_encoding?.should be_true
+ str.force_encoding('IBM865').valid_encoding?.should be_true
+ str.force_encoding('IBM866').valid_encoding?.should be_true
+ str.force_encoding('IBM869').valid_encoding?.should be_true
+ str.force_encoding('Windows-1258').valid_encoding?.should be_true
+ str.force_encoding('GB1988').valid_encoding?.should be_true
+ str.force_encoding('macCentEuro').valid_encoding?.should be_true
+ str.force_encoding('macCroatian').valid_encoding?.should be_true
+ str.force_encoding('macCyrillic').valid_encoding?.should be_true
+ str.force_encoding('macGreek').valid_encoding?.should be_true
+ str.force_encoding('macIceland').valid_encoding?.should be_true
+ str.force_encoding('macRoman').valid_encoding?.should be_true
+ str.force_encoding('macRomania').valid_encoding?.should be_true
+ str.force_encoding('macThai').valid_encoding?.should be_true
+ str.force_encoding('macTurkish').valid_encoding?.should be_true
+ str.force_encoding('macUkraine').valid_encoding?.should be_true
+ str.force_encoding('stateless-ISO-2022-JP').valid_encoding?.should be_false
+ str.force_encoding('eucJP-ms').valid_encoding?.should be_false
+ str.force_encoding('CP51932').valid_encoding?.should be_false
+ str.force_encoding('GB2312').valid_encoding?.should be_false
+ str.force_encoding('GB12345').valid_encoding?.should be_false
+ str.force_encoding('ISO-2022-JP').valid_encoding?.should be_true
+ str.force_encoding('ISO-2022-JP-2').valid_encoding?.should be_true
+ str.force_encoding('CP50221').valid_encoding?.should be_true
+ str.force_encoding('Windows-1252').valid_encoding?.should be_true
+ str.force_encoding('Windows-1250').valid_encoding?.should be_true
+ str.force_encoding('Windows-1256').valid_encoding?.should be_true
+ str.force_encoding('Windows-1253').valid_encoding?.should be_true
+ str.force_encoding('Windows-1255').valid_encoding?.should be_true
+ str.force_encoding('Windows-1254').valid_encoding?.should be_true
+ str.force_encoding('TIS-620').valid_encoding?.should be_true
+ str.force_encoding('Windows-874').valid_encoding?.should be_true
+ str.force_encoding('Windows-1257').valid_encoding?.should be_true
+ str.force_encoding('Windows-31J').valid_encoding?.should be_false
+ str.force_encoding('MacJapanese').valid_encoding?.should be_false
+ str.force_encoding('UTF-7').valid_encoding?.should be_true
+ str.force_encoding('UTF8-MAC').valid_encoding?.should be_true
+ end
- it "returns true for all encodings self is valid in" do
- str = "\u{6754}"
- str.force_encoding('ASCII-8BIT').valid_encoding?.should be_true
- str.force_encoding('UTF-8').valid_encoding?.should be_true
- str.force_encoding('US-ASCII').valid_encoding?.should be_false
- str.force_encoding('Big5').valid_encoding?.should be_false
- str.force_encoding('CP949').valid_encoding?.should be_false
- str.force_encoding('Emacs-Mule').valid_encoding?.should be_false
- str.force_encoding('EUC-JP').valid_encoding?.should be_false
- str.force_encoding('EUC-KR').valid_encoding?.should be_false
- str.force_encoding('EUC-TW').valid_encoding?.should be_false
- str.force_encoding('GB18030').valid_encoding?.should be_false
- str.force_encoding('GBK').valid_encoding?.should be_false
- str.force_encoding('ISO-8859-1').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-2').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-3').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-4').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-5').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-6').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-7').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-8').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-9').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-10').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-11').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-13').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-14').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-15').valid_encoding?.should be_true
- str.force_encoding('ISO-8859-16').valid_encoding?.should be_true
- str.force_encoding('KOI8-R').valid_encoding?.should be_true
- str.force_encoding('KOI8-U').valid_encoding?.should be_true
- str.force_encoding('Shift_JIS').valid_encoding?.should be_false
- str.force_encoding('UTF-16BE').valid_encoding?.should be_false
- str.force_encoding('UTF-16LE').valid_encoding?.should be_false
- str.force_encoding('UTF-32BE').valid_encoding?.should be_false
- str.force_encoding('UTF-32LE').valid_encoding?.should be_false
- str.force_encoding('Windows-1251').valid_encoding?.should be_true
- str.force_encoding('IBM437').valid_encoding?.should be_true
- str.force_encoding('IBM737').valid_encoding?.should be_true
- str.force_encoding('IBM775').valid_encoding?.should be_true
- str.force_encoding('CP850').valid_encoding?.should be_true
- str.force_encoding('IBM852').valid_encoding?.should be_true
- str.force_encoding('CP852').valid_encoding?.should be_true
- str.force_encoding('IBM855').valid_encoding?.should be_true
- str.force_encoding('CP855').valid_encoding?.should be_true
- str.force_encoding('IBM857').valid_encoding?.should be_true
- str.force_encoding('IBM860').valid_encoding?.should be_true
- str.force_encoding('IBM861').valid_encoding?.should be_true
- str.force_encoding('IBM862').valid_encoding?.should be_true
- str.force_encoding('IBM863').valid_encoding?.should be_true
- str.force_encoding('IBM864').valid_encoding?.should be_true
- str.force_encoding('IBM865').valid_encoding?.should be_true
- str.force_encoding('IBM866').valid_encoding?.should be_true
- str.force_encoding('IBM869').valid_encoding?.should be_true
- str.force_encoding('Windows-1258').valid_encoding?.should be_true
- str.force_encoding('GB1988').valid_encoding?.should be_true
- str.force_encoding('macCentEuro').valid_encoding?.should be_true
- str.force_encoding('macCroatian').valid_encoding?.should be_true
- str.force_encoding('macCyrillic').valid_encoding?.should be_true
- str.force_encoding('macGreek').valid_encoding?.should be_true
- str.force_encoding('macIceland').valid_encoding?.should be_true
- str.force_encoding('macRoman').valid_encoding?.should be_true
- str.force_encoding('macRomania').valid_encoding?.should be_true
- str.force_encoding('macThai').valid_encoding?.should be_true
- str.force_encoding('macTurkish').valid_encoding?.should be_true
- str.force_encoding('macUkraine').valid_encoding?.should be_true
- str.force_encoding('stateless-ISO-2022-JP').valid_encoding?.should be_false
- str.force_encoding('eucJP-ms').valid_encoding?.should be_false
- str.force_encoding('CP51932').valid_encoding?.should be_false
- str.force_encoding('GB2312').valid_encoding?.should be_false
- str.force_encoding('GB12345').valid_encoding?.should be_false
- str.force_encoding('ISO-2022-JP').valid_encoding?.should be_true
- str.force_encoding('ISO-2022-JP-2').valid_encoding?.should be_true
- str.force_encoding('CP50221').valid_encoding?.should be_true
- str.force_encoding('Windows-1252').valid_encoding?.should be_true
- str.force_encoding('Windows-1250').valid_encoding?.should be_true
- str.force_encoding('Windows-1256').valid_encoding?.should be_true
- str.force_encoding('Windows-1253').valid_encoding?.should be_true
- str.force_encoding('Windows-1255').valid_encoding?.should be_true
- str.force_encoding('Windows-1254').valid_encoding?.should be_true
- str.force_encoding('TIS-620').valid_encoding?.should be_true
- str.force_encoding('Windows-874').valid_encoding?.should be_true
- str.force_encoding('Windows-1257').valid_encoding?.should be_true
- str.force_encoding('Windows-31J').valid_encoding?.should be_false
- str.force_encoding('MacJapanese').valid_encoding?.should be_false
- str.force_encoding('UTF-7').valid_encoding?.should be_true
- str.force_encoding('UTF8-MAC').valid_encoding?.should be_true
- end
+ it "returns true for IBM720 encoding self is valid in" do
+ str = +"\xE6\x9D\x94"
+ str.force_encoding('IBM720').valid_encoding?.should be_true
+ str.force_encoding('CP720').valid_encoding?.should be_true
+ end
- it "returns false if self is valid in one encoding, but invalid in the one it's tagged with" do
- str = "\u{8765}"
- str.valid_encoding?.should be_true
- str = str.force_encoding('ascii')
- str.valid_encoding?.should be_false
- end
+ it "returns false if self is valid in one encoding, but invalid in the one it's tagged with" do
+ str = +"\u{8765}"
+ str.valid_encoding?.should be_true
+ str.force_encoding('ascii')
+ str.valid_encoding?.should be_false
+ end
- it "returns false if self contains a character invalid in the associated encoding" do
- "abc#{[0x80].pack('C')}".force_encoding('ascii').valid_encoding?.should be_false
- end
+ it "returns false if self contains a character invalid in the associated encoding" do
+ "abc#{[0x80].pack('C')}".dup.force_encoding('ascii').valid_encoding?.should be_false
+ end
- it "returns false if a valid String had an invalid character appended to it" do
- str = "a"
- str.valid_encoding?.should be_true
- str << [0xDD].pack('C').force_encoding('utf-8')
- str.valid_encoding?.should be_false
- end
+ it "returns false if a valid String had an invalid character appended to it" do
+ str = +"a"
+ str.valid_encoding?.should be_true
+ str << [0xDD].pack('C').force_encoding('utf-8')
+ str.valid_encoding?.should be_false
+ end
- it "returns true if an invalid string is appended another invalid one but both make a valid string" do
- str = [0xD0].pack('C').force_encoding('utf-8')
- str.valid_encoding?.should be_false
- str << [0xBF].pack('C').force_encoding('utf-8')
- str.valid_encoding?.should be_true
- end
+ it "returns true if an invalid string is appended another invalid one but both make a valid string" do
+ str = [0xD0].pack('C').force_encoding('utf-8')
+ str.valid_encoding?.should be_false
+ str << [0xBF].pack('C').force_encoding('utf-8')
+ str.valid_encoding?.should be_true
end
end