mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Move spec/rubyspec to spec/ruby for consistency
* Other ruby implementations use the spec/ruby directory. [Misc #13792] [ruby-core:82287] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59979 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
75bfc6440d
commit
1d15d5f080
4370 changed files with 0 additions and 0 deletions
19
spec/ruby/core/string/allocate_spec.rb
Normal file
19
spec/ruby/core/string/allocate_spec.rb
Normal file
|
@ -0,0 +1,19 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
|
||||
describe "String.allocate" do
|
||||
it "returns an instance of String" do
|
||||
str = String.allocate
|
||||
str.should be_an_instance_of(String)
|
||||
end
|
||||
|
||||
it "returns a fully-formed String" do
|
||||
str = String.allocate
|
||||
str.size.should == 0
|
||||
str << "more"
|
||||
str.should == "more"
|
||||
end
|
||||
|
||||
it "returns a binary String" do
|
||||
String.new.encoding.should == Encoding::BINARY
|
||||
end
|
||||
end
|
8
spec/ruby/core/string/append_spec.rb
Normal file
8
spec/ruby/core/string/append_spec.rb
Normal file
|
@ -0,0 +1,8 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
require File.expand_path('../shared/concat', __FILE__)
|
||||
|
||||
describe "String#<<" do
|
||||
it_behaves_like :string_concat, :<<
|
||||
it_behaves_like :string_concat_encoding, :<<
|
||||
end
|
85
spec/ruby/core/string/ascii_only_spec.rb
Normal file
85
spec/ruby/core/string/ascii_only_spec.rb
Normal file
|
@ -0,0 +1,85 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
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
|
||||
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 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?)
|
||||
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
|
||||
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
|
||||
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
|
||||
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 false after appending non ASCII characters to an empty String" do
|
||||
("" << "λ").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 when replacing an ASCII String with a non-ASCII String" do
|
||||
"".replace("λ").ascii_only?.should be_false
|
||||
end
|
||||
end
|
||||
end
|
24
spec/ruby/core/string/b_spec.rb
Normal file
24
spec/ruby/core/string/b_spec.rb
Normal file
|
@ -0,0 +1,24 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
|
||||
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 "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
|
||||
end
|
||||
end
|
57
spec/ruby/core/string/bytes_spec.rb
Normal file
57
spec/ruby/core/string/bytes_spec.rb
Normal file
|
@ -0,0 +1,57 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
|
||||
describe "String#bytes" do
|
||||
before :each do
|
||||
@utf8 = "東京"
|
||||
@ascii = 'Tokyo'
|
||||
@utf8_ascii = @utf8 + @ascii
|
||||
end
|
||||
|
||||
it "returns an Array when no block is given" do
|
||||
@utf8.bytes.should be_an_instance_of(Array)
|
||||
end
|
||||
|
||||
it "yields each byte to a block if one is given, returning self" do
|
||||
bytes = []
|
||||
@utf8.bytes {|b| bytes << b}.should == @utf8
|
||||
bytes.should == @utf8.bytes.to_a
|
||||
end
|
||||
|
||||
it "returns #bytesize 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) }
|
||||
end
|
||||
|
||||
it "agrees with #unpack('C*')" do
|
||||
@utf8_ascii.bytes.to_a.should == @utf8_ascii.unpack("C*")
|
||||
end
|
||||
|
||||
it "yields/returns no bytes for the empty string" do
|
||||
''.bytes.to_a.should == []
|
||||
end
|
||||
end
|
||||
|
||||
with_feature :encoding do
|
||||
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
|
||||
end
|
||||
|
||||
it "is unaffected by #force_encoding" do
|
||||
@utf8.force_encoding('ASCII').bytes.to_a.should == @utf8.bytes.to_a
|
||||
end
|
||||
end
|
||||
end
|
37
spec/ruby/core/string/bytesize_spec.rb
Normal file
37
spec/ruby/core/string/bytesize_spec.rb
Normal file
|
@ -0,0 +1,37 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
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
|
||||
|
||||
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 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 pseudo-ASCII strings containing UTF-8 characters" do
|
||||
"c \u{6666}".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
|
||||
end
|
||||
end
|
29
spec/ruby/core/string/byteslice_spec.rb
Normal file
29
spec/ruby/core/string/byteslice_spec.rb
Normal file
|
@ -0,0 +1,29 @@
|
|||
# -*- 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__)
|
||||
|
||||
describe "String#byteslice" do
|
||||
it "needs to reviewed for spec completeness"
|
||||
|
||||
it_behaves_like :string_slice, :byteslice
|
||||
end
|
||||
|
||||
describe "String#byteslice with index, length" do
|
||||
it_behaves_like :string_slice_index_length, :byteslice
|
||||
end
|
||||
|
||||
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
|
||||
end
|
||||
end
|
62
spec/ruby/core/string/capitalize_spec.rb
Normal file
62
spec/ruby/core/string/capitalize_spec.rb
Normal file
|
@ -0,0 +1,62 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
describe "String#capitalize" do
|
||||
it "returns a copy of self with the first character converted to uppercase and the remainder to lowercase" do
|
||||
"".capitalize.should == ""
|
||||
"h".capitalize.should == "H"
|
||||
"H".capitalize.should == "H"
|
||||
"hello".capitalize.should == "Hello"
|
||||
"HELLO".capitalize.should == "Hello"
|
||||
"123ABC".capitalize.should == "123abc"
|
||||
end
|
||||
|
||||
it "taints resulting string when self is tainted" do
|
||||
"".taint.capitalize.tainted?.should == true
|
||||
"hello".taint.capitalize.tainted?.should == true
|
||||
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"
|
||||
end
|
||||
end
|
||||
|
||||
ruby_version_is '2.4' do
|
||||
it "works for all of Unicode" do
|
||||
"äöü".capitalize.should == "Äöü"
|
||||
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)
|
||||
end
|
||||
end
|
||||
|
||||
describe "String#capitalize!" do
|
||||
it "capitalizes self in place" do
|
||||
a = "hello"
|
||||
a.capitalize!.should equal(a)
|
||||
a.should == "Hello"
|
||||
end
|
||||
|
||||
it "returns nil when no changes are made" do
|
||||
a = "Hello"
|
||||
a.capitalize!.should == nil
|
||||
a.should == "Hello"
|
||||
|
||||
"".capitalize!.should == nil
|
||||
"H".capitalize!.should == nil
|
||||
end
|
||||
|
||||
it "raises a RuntimeError when self is frozen" do
|
||||
["", "Hello", "hello"].each do |a|
|
||||
a.freeze
|
||||
lambda { a.capitalize! }.should raise_error(RuntimeError)
|
||||
end
|
||||
end
|
||||
end
|
8
spec/ruby/core/string/case_compare_spec.rb
Normal file
8
spec/ruby/core/string/case_compare_spec.rb
Normal file
|
@ -0,0 +1,8 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../shared/eql', __FILE__)
|
||||
require File.expand_path('../shared/equal_value', __FILE__)
|
||||
|
||||
describe "String#===" do
|
||||
it_behaves_like(:string_eql_value, :===)
|
||||
it_behaves_like(:string_equal_value, :===)
|
||||
end
|
120
spec/ruby/core/string/casecmp_spec.rb
Normal file
120
spec/ruby/core/string/casecmp_spec.rb
Normal file
|
@ -0,0 +1,120 @@
|
|||
# -*- encoding: ascii-8bit -*-
|
||||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
describe "String#casecmp independent of case" do
|
||||
it "returns -1 when less than other" do
|
||||
"a".casecmp("b").should == -1
|
||||
"A".casecmp("b").should == -1
|
||||
end
|
||||
|
||||
it "returns 0 when equal to other" do
|
||||
"a".casecmp("a").should == 0
|
||||
"A".casecmp("a").should == 0
|
||||
end
|
||||
|
||||
it "returns 1 when greater than other" do
|
||||
"b".casecmp("a").should == 1
|
||||
"B".casecmp("a").should == 1
|
||||
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 == 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
|
||||
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
|
||||
end
|
||||
|
||||
describe "in UTF-8 mode" do
|
||||
describe "for non-ASCII characters" do
|
||||
before :each do
|
||||
@upper_a_tilde = "\xc3\x83"
|
||||
@lower_a_tilde = "\xc3\xa3"
|
||||
@upper_a_umlaut = "\xc3\x84"
|
||||
@lower_a_umlaut = "\xc3\xa4"
|
||||
end
|
||||
|
||||
it "returns -1 when numerically less than other" do
|
||||
@upper_a_tilde.casecmp(@lower_a_tilde).should == -1
|
||||
@upper_a_tilde.casecmp(@upper_a_umlaut).should == -1
|
||||
end
|
||||
|
||||
it "returns 0 when numerically equal to other" do
|
||||
@upper_a_tilde.casecmp(@upper_a_tilde).should == 0
|
||||
end
|
||||
|
||||
it "returns 1 when numerically greater than other" do
|
||||
@lower_a_umlaut.casecmp(@upper_a_umlaut).should == 1
|
||||
@lower_a_umlaut.casecmp(@lower_a_tilde).should == 1
|
||||
end
|
||||
end
|
||||
|
||||
describe "for ASCII characters" do
|
||||
it "returns -1 when less than other" do
|
||||
"a".casecmp("b").should == -1
|
||||
"A".casecmp("b").should == -1
|
||||
end
|
||||
|
||||
it "returns 0 when equal to other" do
|
||||
"a".casecmp("a").should == 0
|
||||
"A".casecmp("a").should == 0
|
||||
end
|
||||
|
||||
it "returns 1 when greater than other" do
|
||||
"b".casecmp("a").should == 1
|
||||
"B".casecmp("a").should == 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "for non-ASCII characters" do
|
||||
before :each do
|
||||
@upper_a_tilde = "\xc3"
|
||||
@lower_a_tilde = "\xe3"
|
||||
end
|
||||
|
||||
it "returns -1 when numerically less than other" do
|
||||
@upper_a_tilde.casecmp(@lower_a_tilde).should == -1
|
||||
end
|
||||
|
||||
it "returns 0 when equal to other" do
|
||||
@upper_a_tilde.casecmp("\xc3").should == 0
|
||||
end
|
||||
|
||||
it "returns 1 when numerically greater than other" do
|
||||
@lower_a_tilde.casecmp(@upper_a_tilde).should == 1
|
||||
end
|
||||
end
|
||||
|
||||
describe "when comparing a subclass instance" do
|
||||
it "returns -1 when less than other" do
|
||||
b = StringSpecs::MyString.new "b"
|
||||
"a".casecmp(b).should == -1
|
||||
"A".casecmp(b).should == -1
|
||||
end
|
||||
|
||||
it "returns 0 when equal to other" do
|
||||
a = StringSpecs::MyString.new "a"
|
||||
"a".casecmp(a).should == 0
|
||||
"A".casecmp(a).should == 0
|
||||
end
|
||||
|
||||
it "returns 1 when greater than other" do
|
||||
a = StringSpecs::MyString.new "a"
|
||||
"b".casecmp(a).should == 1
|
||||
"B".casecmp(a).should == 1
|
||||
end
|
||||
end
|
||||
end
|
133
spec/ruby/core/string/center_spec.rb
Normal file
133
spec/ruby/core/string/center_spec.rb
Normal file
|
@ -0,0 +1,133 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
describe "String#center with length, padding" do
|
||||
it "returns a new string of specified length with self centered and padded with padstr" do
|
||||
"one".center(9, '.').should == "...one..."
|
||||
"hello".center(20, '123').should == "1231231hello12312312"
|
||||
"middle".center(13, '-').should == "---middle----"
|
||||
|
||||
"".center(1, "abcd").should == "a"
|
||||
"".center(2, "abcd").should == "aa"
|
||||
"".center(3, "abcd").should == "aab"
|
||||
"".center(4, "abcd").should == "abab"
|
||||
"".center(6, "xy").should == "xyxxyx"
|
||||
"".center(11, "12345").should == "12345123451"
|
||||
|
||||
"|".center(2, "abcd").should == "|a"
|
||||
"|".center(3, "abcd").should == "a|a"
|
||||
"|".center(4, "abcd").should == "a|ab"
|
||||
"|".center(5, "abcd").should == "ab|ab"
|
||||
"|".center(6, "xy").should == "xy|xyx"
|
||||
"|".center(7, "xy").should == "xyx|xyx"
|
||||
"|".center(11, "12345").should == "12345|12345"
|
||||
"|".center(12, "12345").should == "12345|123451"
|
||||
|
||||
"||".center(3, "abcd").should == "||a"
|
||||
"||".center(4, "abcd").should == "a||a"
|
||||
"||".center(5, "abcd").should == "a||ab"
|
||||
"||".center(6, "abcd").should == "ab||ab"
|
||||
"||".center(8, "xy").should == "xyx||xyx"
|
||||
"||".center(12, "12345").should == "12345||12345"
|
||||
"||".center(13, "12345").should == "12345||123451"
|
||||
end
|
||||
|
||||
it "pads with whitespace if no padstr is given" do
|
||||
"two".center(5).should == " two "
|
||||
"hello".center(20).should == " hello "
|
||||
end
|
||||
|
||||
it "returns self if it's longer than or as long as the specified length" do
|
||||
"".center(0).should == ""
|
||||
"".center(-1).should == ""
|
||||
"hello".center(4).should == "hello"
|
||||
"hello".center(-1).should == "hello"
|
||||
"this".center(3).should == "this"
|
||||
"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 == "^_^"
|
||||
|
||||
obj = mock('3')
|
||||
obj.should_receive(:to_int).and_return(3)
|
||||
|
||||
"_".center(obj, "o").should == "o_o"
|
||||
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)
|
||||
end
|
||||
|
||||
it "calls #to_str to convert padstr to a String" do
|
||||
padstr = mock('123')
|
||||
padstr.should_receive(:to_str).and_return("123")
|
||||
|
||||
"hello".center(20, padstr).should == "1231231hello12312312"
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
|
||||
"".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
|
||||
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
|
||||
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
|
||||
end
|
||||
end
|
||||
end
|
11
spec/ruby/core/string/chars_spec.rb
Normal file
11
spec/ruby/core/string/chars_spec.rb
Normal file
|
@ -0,0 +1,11 @@
|
|||
require File.expand_path('../shared/chars', __FILE__)
|
||||
require File.expand_path('../shared/each_char_without_block', __FILE__)
|
||||
|
||||
describe "String#chars" do
|
||||
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']
|
||||
end
|
||||
end
|
387
spec/ruby/core/string/chomp_spec.rb
Normal file
387
spec/ruby/core/string/chomp_spec.rb
Normal file
|
@ -0,0 +1,387 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
describe "String#chomp" do
|
||||
describe "when passed no argument" do
|
||||
before do
|
||||
# Ensure that $/ is set to the default value
|
||||
@dollar_slash, $/ = $/, "\n"
|
||||
end
|
||||
|
||||
after do
|
||||
$/ = @dollar_slash
|
||||
end
|
||||
|
||||
it "does not modify a String with no trailing carriage return or newline" do
|
||||
"abc".chomp.should == "abc"
|
||||
end
|
||||
|
||||
it "returns a copy of the String when it is not modified" do
|
||||
str = "abc"
|
||||
str.chomp.should_not equal(str)
|
||||
end
|
||||
|
||||
it "removes one trailing newline" do
|
||||
"abc\n\n".chomp.should == "abc\n"
|
||||
end
|
||||
|
||||
it "removes one trailing carriage return" do
|
||||
"abc\r\r".chomp.should == "abc\r"
|
||||
end
|
||||
|
||||
it "removes one trailing carrige return, newline pair" do
|
||||
"abc\r\n\r\n".chomp.should == "abc\r\n"
|
||||
end
|
||||
|
||||
it "returns an empty String when self is empty" do
|
||||
"".chomp.should == ""
|
||||
end
|
||||
|
||||
it "taints the result if self is tainted" do
|
||||
"abc".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)
|
||||
end
|
||||
|
||||
it "removes trailing characters that match $/ when it has been assigned a value" do
|
||||
$/ = "cdef"
|
||||
"abcdef".chomp.should == "ab"
|
||||
end
|
||||
end
|
||||
|
||||
describe "when passed nil" do
|
||||
it "does not modify the String" do
|
||||
"abc\r\n".chomp(nil).should == "abc\r\n"
|
||||
end
|
||||
|
||||
it "returns a copy of the String" do
|
||||
str = "abc"
|
||||
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
|
||||
end
|
||||
|
||||
describe "when passed ''" do
|
||||
it "removes a final newline" do
|
||||
"abc\n".chomp("").should == "abc"
|
||||
end
|
||||
|
||||
it "removes a final carriage return, newline" do
|
||||
"abc\r\n".chomp("").should == "abc"
|
||||
end
|
||||
|
||||
it "does not remove a final carriage return" do
|
||||
"abc\r".chomp("").should == "abc\r"
|
||||
end
|
||||
|
||||
it "removes more than one trailing newlines" do
|
||||
"abc\n\n\n".chomp("").should == "abc"
|
||||
end
|
||||
|
||||
it "removes more than one trailing carriage return, newline pairs" 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
|
||||
end
|
||||
|
||||
describe "when passed '\\n'" do
|
||||
it "removes one trailing newline" do
|
||||
"abc\n\n".chomp("\n").should == "abc\n"
|
||||
end
|
||||
|
||||
it "removes one trailing carriage return" do
|
||||
"abc\r\r".chomp("\n").should == "abc\r"
|
||||
end
|
||||
|
||||
it "removes one trailing carrige 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
|
||||
end
|
||||
|
||||
describe "when passed an Object" do
|
||||
it "calls #to_str to convert to a String" do
|
||||
arg = mock("string chomp")
|
||||
arg.should_receive(:to_str).and_return("bc")
|
||||
"abc".chomp(arg).should == "a"
|
||||
end
|
||||
|
||||
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)
|
||||
end
|
||||
end
|
||||
|
||||
describe "when passed a String" do
|
||||
it "removes the trailing characters if they match the argument" do
|
||||
"abcabc".chomp("abc").should == "abc"
|
||||
end
|
||||
|
||||
it "does not modify the String if the argument does not match the trailing characters" do
|
||||
"abc".chomp("def").should == "abc"
|
||||
end
|
||||
|
||||
it "returns an empty String when self is empty" 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
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "String#chomp!" do
|
||||
describe "when passed no argument" do
|
||||
before do
|
||||
# Ensure that $/ is set to the default value
|
||||
@dollar_slash, $/ = $/, "\n"
|
||||
end
|
||||
|
||||
after do
|
||||
$/ = @dollar_slash
|
||||
end
|
||||
|
||||
it "modifies self" do
|
||||
str = "abc\n"
|
||||
str.chomp!.should equal(str)
|
||||
end
|
||||
|
||||
it "returns nil if self is not modified" do
|
||||
"abc".chomp!.should be_nil
|
||||
end
|
||||
|
||||
it "removes one trailing newline" do
|
||||
"abc\n\n".chomp!.should == "abc\n"
|
||||
end
|
||||
|
||||
it "removes one trailing carriage return" do
|
||||
"abc\r\r".chomp!.should == "abc\r"
|
||||
end
|
||||
|
||||
it "removes one trailing carrige return, newline pair" do
|
||||
"abc\r\n\r\n".chomp!.should == "abc\r\n"
|
||||
end
|
||||
|
||||
it "returns nil when self is empty" 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)
|
||||
end
|
||||
|
||||
it "removes trailing characters that match $/ when it has been assigned a value" do
|
||||
$/ = "cdef"
|
||||
"abcdef".chomp!.should == "ab"
|
||||
end
|
||||
end
|
||||
|
||||
describe "when passed nil" do
|
||||
it "returns nil" do
|
||||
"abc\r\n".chomp!(nil).should be_nil
|
||||
end
|
||||
|
||||
it "returns nil when self is empty" do
|
||||
"".chomp!(nil).should be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe "when passed ''" do
|
||||
it "removes a final newline" do
|
||||
"abc\n".chomp!("").should == "abc"
|
||||
end
|
||||
|
||||
it "removes a final carriage return, newline" do
|
||||
"abc\r\n".chomp!("").should == "abc"
|
||||
end
|
||||
|
||||
it "does not remove a final carriage return" do
|
||||
"abc\r".chomp!("").should be_nil
|
||||
end
|
||||
|
||||
it "removes more than one trailing newlines" do
|
||||
"abc\n\n\n".chomp!("").should == "abc"
|
||||
end
|
||||
|
||||
it "removes more than one trailing carriage return, newline pairs" 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
|
||||
end
|
||||
|
||||
describe "when passed '\\n'" do
|
||||
it "removes one trailing newline" do
|
||||
"abc\n\n".chomp!("\n").should == "abc\n"
|
||||
end
|
||||
|
||||
it "removes one trailing carriage return" do
|
||||
"abc\r\r".chomp!("\n").should == "abc\r"
|
||||
end
|
||||
|
||||
it "removes one trailing carrige 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
|
||||
end
|
||||
|
||||
describe "when passed an Object" do
|
||||
it "calls #to_str to convert to a String" do
|
||||
arg = mock("string chomp")
|
||||
arg.should_receive(:to_str).and_return("bc")
|
||||
"abc".chomp!(arg).should == "a"
|
||||
end
|
||||
|
||||
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)
|
||||
end
|
||||
end
|
||||
|
||||
describe "when passed a String" do
|
||||
it "removes the trailing characters if they match the argument" do
|
||||
"abcabc".chomp!("abc").should == "abc"
|
||||
end
|
||||
|
||||
it "returns nil if the argument does not match the trailing characters" do
|
||||
"abc".chomp!("def").should be_nil
|
||||
end
|
||||
|
||||
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
|
||||
a = "string\n\r"
|
||||
a.freeze
|
||||
|
||||
lambda { a.chomp! }.should raise_error(RuntimeError)
|
||||
end
|
||||
|
||||
# see [ruby-core:23666]
|
||||
it "raises a RuntimeError 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)
|
||||
end
|
||||
end
|
||||
|
||||
with_feature :encoding do
|
||||
describe "String#chomp" do
|
||||
before :each do
|
||||
@before_separator = $/
|
||||
end
|
||||
|
||||
after :each do
|
||||
$/ = @before_separator
|
||||
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 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
|
||||
end
|
||||
|
||||
describe "String#chomp!" do
|
||||
before :each do
|
||||
@before_separator = $/
|
||||
end
|
||||
|
||||
after :each do
|
||||
$/ = @before_separator
|
||||
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 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
|
||||
end
|
||||
end
|
128
spec/ruby/core/string/chop_spec.rb
Normal file
128
spec/ruby/core/string/chop_spec.rb
Normal file
|
@ -0,0 +1,128 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
describe "String#chop" do
|
||||
it "removes the final character" do
|
||||
"abc".chop.should == "ab"
|
||||
end
|
||||
|
||||
it "removes the final carriage return" do
|
||||
"abc\r".chop.should == "abc"
|
||||
end
|
||||
|
||||
it "removes the final newline" do
|
||||
"abc\n".chop.should == "abc"
|
||||
end
|
||||
|
||||
it "removes the final carriage return, newline" do
|
||||
"abc\r\n".chop.should == "abc"
|
||||
end
|
||||
|
||||
it "removes the carrige return, newline if they are the only characters" do
|
||||
"\r\n".chop.should == ""
|
||||
end
|
||||
|
||||
it "does not remove more than the final carriage return, newline" 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 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
|
||||
end
|
||||
|
||||
it "returns an empty string when applied to an empty string" do
|
||||
"".chop.should == ""
|
||||
end
|
||||
|
||||
it "returns a new string when applied to an empty string" do
|
||||
s = ""
|
||||
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
|
||||
end
|
||||
|
||||
it "returns subclass instances when called on a subclass" do
|
||||
StringSpecs::MyString.new("hello\n").chop.should be_an_instance_of(StringSpecs::MyString)
|
||||
end
|
||||
end
|
||||
|
||||
describe "String#chop!" do
|
||||
it "removes the final character" do
|
||||
"abc".chop!.should == "ab"
|
||||
end
|
||||
|
||||
it "removes the final carriage return" do
|
||||
"abc\r".chop!.should == "abc"
|
||||
end
|
||||
|
||||
it "removes the final newline" do
|
||||
"abc\n".chop!.should == "abc"
|
||||
end
|
||||
|
||||
it "removes the final carriage return, newline" do
|
||||
"abc\r\n".chop!.should == "abc"
|
||||
end
|
||||
|
||||
it "removes the carrige return, newline if they are the only characters" do
|
||||
"\r\n".chop!.should == ""
|
||||
end
|
||||
|
||||
it "does not remove more than the final carriage return, newline" 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 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
|
||||
end
|
||||
|
||||
it "returns self if modifications were made" do
|
||||
str = "hello"
|
||||
str.chop!.should equal(str)
|
||||
end
|
||||
|
||||
it "returns nil when called on an empty string" 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)
|
||||
end
|
||||
|
||||
# see [ruby-core:23666]
|
||||
it "raises a RuntimeError on a frozen instance that would not be modified" do
|
||||
a = ""
|
||||
a.freeze
|
||||
lambda { a.chop! }.should raise_error(RuntimeError)
|
||||
end
|
||||
end
|
44
spec/ruby/core/string/chr_spec.rb
Normal file
44
spec/ruby/core/string/chr_spec.rb
Normal file
|
@ -0,0 +1,44 @@
|
|||
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
|
||||
end
|
||||
end
|
39
spec/ruby/core/string/clear_spec.rb
Normal file
39
spec/ruby/core/string/clear_spec.rb
Normal file
|
@ -0,0 +1,39 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
|
||||
with_feature :encoding do
|
||||
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 "returns self after emptying it" do
|
||||
cleared = @s.clear
|
||||
cleared.should == ""
|
||||
cleared.object_id.should == @s.object_id
|
||||
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 "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
|
||||
end
|
||||
end
|
58
spec/ruby/core/string/clone_spec.rb
Normal file
58
spec/ruby/core/string/clone_spec.rb
Normal file
|
@ -0,0 +1,58 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "String#clone" do
|
||||
before :each do
|
||||
ScratchPad.clear
|
||||
@obj = StringSpecs::InitializeString.new "string"
|
||||
end
|
||||
|
||||
it "calls #initialize_copy on the new instance" do
|
||||
clone = @obj.clone
|
||||
ScratchPad.recorded.should_not == @obj.object_id
|
||||
ScratchPad.recorded.should == clone.object_id
|
||||
end
|
||||
|
||||
it "copies instance variables" do
|
||||
clone = @obj.clone
|
||||
clone.ivar.should == 1
|
||||
end
|
||||
|
||||
it "copies singleton methods" do
|
||||
def @obj.special() :the_one end
|
||||
clone = @obj.clone
|
||||
clone.special.should == :the_one
|
||||
end
|
||||
|
||||
it "copies modules included in the singleton class" do
|
||||
class << @obj
|
||||
include StringSpecs::StringModule
|
||||
end
|
||||
|
||||
clone = @obj.clone
|
||||
clone.repr.should == 1
|
||||
end
|
||||
|
||||
it "copies constants defined in the singleton class" do
|
||||
class << @obj
|
||||
CLONE = :clone
|
||||
end
|
||||
|
||||
clone = @obj.clone
|
||||
(class << clone; CLONE; end).should == :clone
|
||||
end
|
||||
|
||||
it "copies frozen state" do
|
||||
@obj.freeze.clone.frozen?.should be_true
|
||||
"".freeze.clone.frozen?.should be_true
|
||||
end
|
||||
|
||||
it "does not modify the original string when changing cloned string" do
|
||||
orig = "string"[0..100]
|
||||
clone = orig.clone
|
||||
orig[0] = 'x'
|
||||
orig.should == "xtring"
|
||||
clone.should == "string"
|
||||
end
|
||||
end
|
||||
|
20
spec/ruby/core/string/codepoints_spec.rb
Normal file
20
spec/ruby/core/string/codepoints_spec.rb
Normal file
|
@ -0,0 +1,20 @@
|
|||
# -*- 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__)
|
||||
|
||||
with_feature :encoding do
|
||||
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 "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
|
||||
end
|
||||
end
|
108
spec/ruby/core/string/comparison_spec.rb
Normal file
108
spec/ruby/core/string/comparison_spec.rb
Normal file
|
@ -0,0 +1,108 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
describe "String#<=> with String" do
|
||||
it "compares individual characters based on their ascii value" do
|
||||
ascii_order = Array.new(256) { |x| x.chr }
|
||||
sort_order = ascii_order.sort
|
||||
sort_order.should == ascii_order
|
||||
end
|
||||
|
||||
it "returns -1 when self is less than other" do
|
||||
("this" <=> "those").should == -1
|
||||
end
|
||||
|
||||
it "returns 0 when self is equal to other" do
|
||||
("yep" <=> "yep").should == 0
|
||||
end
|
||||
|
||||
it "returns 1 when self is greater than other" do
|
||||
("yoddle" <=> "griddle").should == 1
|
||||
end
|
||||
|
||||
it "considers string that comes lexicographically first to be less if strings have same size" do
|
||||
("aba" <=> "abc").should == -1
|
||||
("abc" <=> "aba").should == 1
|
||||
end
|
||||
|
||||
it "doesn't consider shorter string to be less if longer string starts with shorter one" do
|
||||
("abc" <=> "abcd").should == -1
|
||||
("abcd" <=> "abc").should == 1
|
||||
end
|
||||
|
||||
it "compares shorter string with corresponding number of first chars of longer string" do
|
||||
("abx" <=> "abcd").should == 1
|
||||
("abcd" <=> "abx").should == -1
|
||||
end
|
||||
|
||||
it "ignores subclass differences" do
|
||||
a = "hello"
|
||||
b = StringSpecs::MyString.new("hello")
|
||||
|
||||
(a <=> b).should == 0
|
||||
(b <=> a).should == 0
|
||||
end
|
||||
|
||||
it "returns 0 if self and other are bytewise identical and have the same encoding" do
|
||||
("ÄÖÜ" <=> "ÄÖÜ").should == 0
|
||||
end
|
||||
|
||||
it "returns 0 if self and other are bytewise identical and have the same encoding" do
|
||||
("ÄÖÜ" <=> "ÄÖÜ").should == 0
|
||||
end
|
||||
|
||||
it "returns -1 if self is bytewise less than other" do
|
||||
("ÄÖÛ" <=> "ÄÖÜ").should == -1
|
||||
end
|
||||
|
||||
it "returns 1 if self is bytewise greater than other" do
|
||||
("ÄÖÜ" <=> "ÄÖÛ").should == 1
|
||||
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
|
||||
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
|
||||
end
|
||||
|
||||
it "compares the indices of the encodings when the strings have identical non-ASCII-compatible bytes" do
|
||||
xff_1 = [0xFF].pack('C').force_encoding("utf-8")
|
||||
xff_2 = [0xFF].pack('C').force_encoding("iso-8859-1")
|
||||
(xff_1 <=> xff_2).should == -1
|
||||
(xff_2 <=> xff_1).should == 1
|
||||
end
|
||||
end
|
||||
|
||||
# Note: This is inconsistent with Array#<=> which calls #to_ary instead of
|
||||
# just using it as an indicator.
|
||||
describe "String#<=>" do
|
||||
it "returns nil if its argument provides neither #to_str nor #<=>" do
|
||||
("abc" <=> mock('x')).should be_nil
|
||||
end
|
||||
|
||||
it "uses the result of calling #to_str for comparison when #to_str is defined" do
|
||||
obj = mock('x')
|
||||
obj.should_receive(:to_str).and_return("aaa")
|
||||
|
||||
("abc" <=> obj).should == 1
|
||||
end
|
||||
|
||||
it "uses the result of calling #<=> on its argument when #<=> is defined but #to_str is not" do
|
||||
obj = mock('x')
|
||||
obj.should_receive(:<=>).and_return(-1)
|
||||
|
||||
("abc" <=> obj).should == 1
|
||||
end
|
||||
|
||||
it "returns nil if argument also uses an inverse comparison for <=>" do
|
||||
obj = mock('x')
|
||||
def obj.<=>(other); other <=> self; end
|
||||
obj.should_receive(:<=>).once
|
||||
|
||||
("abc" <=> obj).should be_nil
|
||||
end
|
||||
end
|
28
spec/ruby/core/string/concat_spec.rb
Normal file
28
spec/ruby/core/string/concat_spec.rb
Normal file
|
@ -0,0 +1,28 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
require File.expand_path('../shared/concat', __FILE__)
|
||||
|
||||
describe "String#concat" do
|
||||
it_behaves_like :string_concat, :concat
|
||||
it_behaves_like :string_concat_encoding, :concat
|
||||
|
||||
ruby_version_is "2.4" do
|
||||
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 "returns self when given no arguments" do
|
||||
str = "hello"
|
||||
str.concat.should equal(str)
|
||||
str.should == "hello"
|
||||
end
|
||||
end
|
||||
end
|
105
spec/ruby/core/string/count_spec.rb
Normal file
105
spec/ruby/core/string/count_spec.rb
Normal file
|
@ -0,0 +1,105 @@
|
|||
# -*- encoding: binary -*-
|
||||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
describe "String#count" do
|
||||
it "counts occurrences of chars from the intersection of the specified sets" do
|
||||
s = "hello\nworld\x00\x00"
|
||||
|
||||
s.count(s).should == s.size
|
||||
s.count("lo").should == 5
|
||||
s.count("eo").should == 3
|
||||
s.count("l").should == 3
|
||||
s.count("\n").should == 1
|
||||
s.count("\x00").should == 2
|
||||
|
||||
s.count("").should == 0
|
||||
"".count("").should == 0
|
||||
|
||||
s.count("l", "lo").should == s.count("l")
|
||||
s.count("l", "lo", "o").should == s.count("")
|
||||
s.count("helo", "hel", "h").should == s.count("h")
|
||||
s.count("helo", "", "x").should == 0
|
||||
end
|
||||
|
||||
it "raises an ArgumentError when given no arguments" do
|
||||
lambda { "hell yeah".count }.should raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it "negates sets starting with ^" do
|
||||
s = "^hello\nworld\x00\x00"
|
||||
|
||||
s.count("^").should == 1 # no negation, counts ^
|
||||
|
||||
s.count("^leh").should == 9
|
||||
s.count("^o").should == 12
|
||||
|
||||
s.count("helo", "^el").should == s.count("ho")
|
||||
s.count("aeiou", "^e").should == s.count("aiou")
|
||||
|
||||
"^_^".count("^^").should == 1
|
||||
"oa^_^o".count("a^").should == 3
|
||||
end
|
||||
|
||||
it "counts all chars in a sequence" do
|
||||
s = "hel-[()]-lo012^"
|
||||
|
||||
s.count("\x00-\xFF").should == s.size
|
||||
s.count("ej-m").should == 3
|
||||
s.count("e-h").should == 2
|
||||
|
||||
# no sequences
|
||||
s.count("-").should == 2
|
||||
s.count("e-").should == s.count("e") + s.count("-")
|
||||
s.count("-h").should == s.count("h") + s.count("-")
|
||||
|
||||
s.count("---").should == s.count("-")
|
||||
|
||||
# see an ASCII table for reference
|
||||
s.count("--2").should == s.count("-./012")
|
||||
s.count("(--").should == s.count("()*+,-")
|
||||
s.count("A-a").should == s.count("A-Z[\\]^_`a")
|
||||
|
||||
# negated sequences
|
||||
s.count("^e-h").should == s.size - s.count("e-h")
|
||||
s.count("^^-^").should == s.size - s.count("^")
|
||||
s.count("^---").should == s.size - s.count("-")
|
||||
|
||||
"abcdefgh".count("a-ce-fh").should == 6
|
||||
"abcdefgh".count("he-fa-c").should == 6
|
||||
"abcdefgh".count("e-fha-c").should == 6
|
||||
|
||||
"abcde".count("ac-e").should == 4
|
||||
"abcde".count("^ac-e").should == 1
|
||||
end
|
||||
|
||||
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)
|
||||
end
|
||||
|
||||
it 'returns the number of occurrences of a multi-byte character' do
|
||||
str = "\u{2605}"
|
||||
str.count(str).should == 1
|
||||
"asd#{str}zzz#{str}ggg".count(str).should == 2
|
||||
end
|
||||
|
||||
it "calls #to_str to convert each set arg to a String" do
|
||||
other_string = mock('lo')
|
||||
other_string.should_receive(:to_str).and_return("lo")
|
||||
|
||||
other_string2 = mock('o')
|
||||
other_string2.should_receive(:to_str).and_return("o")
|
||||
|
||||
s = "hello world"
|
||||
s.count(other_string, other_string2).should == s.count("o")
|
||||
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)
|
||||
end
|
||||
end
|
75
spec/ruby/core/string/crypt_spec.rb
Normal file
75
spec/ruby/core/string/crypt_spec.rb
Normal file
|
@ -0,0 +1,75 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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)
|
||||
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")
|
||||
|
||||
"".crypt(obj).should == "aaQSqAReePlq6"
|
||||
end
|
||||
|
||||
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)
|
||||
end
|
||||
|
||||
it "taints the result if either salt or self is tainted" do
|
||||
tainted_salt = "aa"
|
||||
tainted_str = "hello"
|
||||
|
||||
tainted_salt.taint
|
||||
tainted_str.taint
|
||||
|
||||
"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
|
||||
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
|
||||
end
|
119
spec/ruby/core/string/delete_spec.rb
Normal file
119
spec/ruby/core/string/delete_spec.rb
Normal file
|
@ -0,0 +1,119 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
describe "String#delete" do
|
||||
it "returns a new string with the chars from the intersection of sets removed" do
|
||||
s = "hello"
|
||||
s.delete("lo").should == "he"
|
||||
s.should == "hello"
|
||||
|
||||
"hello".delete("l", "lo").should == "heo"
|
||||
|
||||
"hell yeah".delete("").should == "hell yeah"
|
||||
end
|
||||
|
||||
it "raises an ArgumentError when given no arguments" do
|
||||
lambda { "hell yeah".delete }.should raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it "negates sets starting with ^" do
|
||||
"hello".delete("aeiou", "^e").should == "hell"
|
||||
"hello".delete("^leh").should == "hell"
|
||||
"hello".delete("^o").should == "o"
|
||||
"hello".delete("^").should == "hello"
|
||||
"^_^".delete("^^").should == "^^"
|
||||
"oa^_^o".delete("a^").should == "o_o"
|
||||
end
|
||||
|
||||
it "deletes all chars in a sequence" do
|
||||
"hello".delete("ej-m").should == "ho"
|
||||
"hello".delete("e-h").should == "llo"
|
||||
"hel-lo".delete("e-").should == "hllo"
|
||||
"hel-lo".delete("-h").should == "ello"
|
||||
"hel-lo".delete("---").should == "hello"
|
||||
"hel-012".delete("--2").should == "hel"
|
||||
"hel-()".delete("(--").should == "hel"
|
||||
"hello".delete("^e-h").should == "he"
|
||||
"hello^".delete("^^-^").should == "^"
|
||||
"hel--lo".delete("^---").should == "--"
|
||||
|
||||
"abcdefgh".delete("a-ce-fh").should == "dg"
|
||||
"abcdefgh".delete("he-fa-c").should == "dg"
|
||||
"abcdefgh".delete("e-fha-c").should == "dg"
|
||||
|
||||
"abcde".delete("ac-e").should == "b"
|
||||
"abcde".delete("^ac-e").should == "acde"
|
||||
|
||||
"ABCabc[]".delete("A-a").should == "bc"
|
||||
end
|
||||
|
||||
it "deletes multibyte characters" do
|
||||
"四月".delete("月").should == "四"
|
||||
'哥哥我倒'.delete('哥').should == "我倒"
|
||||
end
|
||||
|
||||
it "respects backslash for escaping a -" do
|
||||
'Non-Authoritative Information'.delete(' \-\'').should ==
|
||||
'NonAuthoritativeInformation'
|
||||
end
|
||||
|
||||
it "raises if the given ranges are invalid" 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)
|
||||
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
|
||||
end
|
||||
|
||||
it "tries to convert each set arg to a string using to_str" do
|
||||
other_string = mock('lo')
|
||||
other_string.should_receive(:to_str).and_return("lo")
|
||||
|
||||
other_string2 = mock('o')
|
||||
other_string2.should_receive(:to_str).and_return("o")
|
||||
|
||||
"hello world".delete(other_string, other_string2).should == "hell wrld"
|
||||
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)
|
||||
end
|
||||
|
||||
it "returns subclass instances when called on a subclass" do
|
||||
StringSpecs::MyString.new("oh no!!!").delete("!").should be_an_instance_of(StringSpecs::MyString)
|
||||
end
|
||||
end
|
||||
|
||||
describe "String#delete!" do
|
||||
it "modifies self in place and returns self" do
|
||||
a = "hello"
|
||||
a.delete!("aeiou", "^e").should equal(a)
|
||||
a.should == "hell"
|
||||
end
|
||||
|
||||
it "returns nil if no modifications were made" do
|
||||
a = "hello"
|
||||
a.delete!("z").should == nil
|
||||
a.should == "hello"
|
||||
end
|
||||
|
||||
it "raises a RuntimeError 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)
|
||||
end
|
||||
end
|
65
spec/ruby/core/string/downcase_spec.rb
Normal file
65
spec/ruby/core/string/downcase_spec.rb
Normal file
|
@ -0,0 +1,65 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
describe "String#downcase" do
|
||||
it "returns a copy of self with all uppercase letters downcased" do
|
||||
"hELLO".downcase.should == "hello"
|
||||
"hello".downcase.should == "hello"
|
||||
end
|
||||
|
||||
ruby_version_is ''...'2.4' do
|
||||
it "is locale insensitive (only replaces A-Z)" do
|
||||
"ÄÖÜ".downcase.should == "ÄÖÜ"
|
||||
|
||||
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
|
||||
|
||||
str.downcase.should == expected
|
||||
end
|
||||
end
|
||||
|
||||
ruby_version_is '2.4' do
|
||||
it "works for all of Unicode" do
|
||||
"ÄÖÜ".downcase.should == "äöü"
|
||||
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
|
||||
end
|
||||
|
||||
it "returns a subclass instance for subclasses" do
|
||||
StringSpecs::MyString.new("FOObar").downcase.should be_an_instance_of(StringSpecs::MyString)
|
||||
end
|
||||
end
|
||||
|
||||
describe "String#downcase!" do
|
||||
it "modifies self in place" do
|
||||
a = "HeLlO"
|
||||
a.downcase!.should equal(a)
|
||||
a.should == "hello"
|
||||
end
|
||||
|
||||
it "returns nil if no modifications were made" do
|
||||
a = "hello"
|
||||
a.downcase!.should == nil
|
||||
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)
|
||||
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
|
||||
end
|
||||
end
|
424
spec/ruby/core/string/dump_spec.rb
Normal file
424
spec/ruby/core/string/dump_spec.rb
Normal file
|
@ -0,0 +1,424 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
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
|
||||
end
|
||||
|
||||
it "untrusts the result if self is untrusted" do
|
||||
"foo".untrust.dump.untrusted?.should == true
|
||||
"foo\n".untrust.dump.untrusted?.should == true
|
||||
end
|
||||
|
||||
it "returns a subclass instance" do
|
||||
StringSpecs::MyString.new.dump.should be_an_instance_of(StringSpecs::MyString)
|
||||
end
|
||||
|
||||
it "returns a string with special characters replaced with \\<char> notation" do
|
||||
[ ["\a", '"\\a"'],
|
||||
["\b", '"\\b"'],
|
||||
["\t", '"\\t"'],
|
||||
["\n", '"\\n"'],
|
||||
["\v", '"\\v"'],
|
||||
["\f", '"\\f"'],
|
||||
["\r", '"\\r"'],
|
||||
["\e", '"\\e"']
|
||||
].should be_computed_by(:dump)
|
||||
end
|
||||
|
||||
it "returns a string with \" and \\ escaped with a backslash" do
|
||||
[ ["\"", '"\\""'],
|
||||
["\\", '"\\\\"']
|
||||
].should be_computed_by(:dump)
|
||||
end
|
||||
|
||||
it "returns a string with \\#<char> when # is followed by $, @, {" do
|
||||
[ ["\#$", '"\\#$"'],
|
||||
["\#@", '"\\#@"'],
|
||||
["\#{", '"\\#{"']
|
||||
].should be_computed_by(:dump)
|
||||
end
|
||||
|
||||
it "returns a string with # not escaped when followed by any other character" do
|
||||
[ ["#", '"#"'],
|
||||
["#1", '"#1"']
|
||||
].should be_computed_by(:dump)
|
||||
end
|
||||
|
||||
it "returns a string with printable non-alphanumeric characters unescaped" do
|
||||
[ [" ", '" "'],
|
||||
["!", '"!"'],
|
||||
["$", '"$"'],
|
||||
["%", '"%"'],
|
||||
["&", '"&"'],
|
||||
["'", '"\'"'],
|
||||
["(", '"("'],
|
||||
[")", '")"'],
|
||||
["*", '"*"'],
|
||||
["+", '"+"'],
|
||||
[",", '","'],
|
||||
["-", '"-"'],
|
||||
[".", '"."'],
|
||||
["/", '"/"'],
|
||||
[":", '":"'],
|
||||
[";", '";"'],
|
||||
["<", '"<"'],
|
||||
["=", '"="'],
|
||||
[">", '">"'],
|
||||
["?", '"?"'],
|
||||
["@", '"@"'],
|
||||
["[", '"["'],
|
||||
["]", '"]"'],
|
||||
["^", '"^"'],
|
||||
["_", '"_"'],
|
||||
["`", '"`"'],
|
||||
["{", '"{"'],
|
||||
["|", '"|"'],
|
||||
["}", '"}"'],
|
||||
["~", '"~"']
|
||||
].should be_computed_by(:dump)
|
||||
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(:dump)
|
||||
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(:dump)
|
||||
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(:dump)
|
||||
end
|
||||
|
||||
it "returns a string with non-printing ASCII characters replaced by \\x notation" do
|
||||
# Avoid the file encoding by computing the string with #chr.
|
||||
[ [0000.chr, '"\\x00"'],
|
||||
[0001.chr, '"\\x01"'],
|
||||
[0002.chr, '"\\x02"'],
|
||||
[0003.chr, '"\\x03"'],
|
||||
[0004.chr, '"\\x04"'],
|
||||
[0005.chr, '"\\x05"'],
|
||||
[0006.chr, '"\\x06"'],
|
||||
[0016.chr, '"\\x0E"'],
|
||||
[0017.chr, '"\\x0F"'],
|
||||
[0020.chr, '"\\x10"'],
|
||||
[0021.chr, '"\\x11"'],
|
||||
[0022.chr, '"\\x12"'],
|
||||
[0023.chr, '"\\x13"'],
|
||||
[0024.chr, '"\\x14"'],
|
||||
[0025.chr, '"\\x15"'],
|
||||
[0026.chr, '"\\x16"'],
|
||||
[0027.chr, '"\\x17"'],
|
||||
[0030.chr, '"\\x18"'],
|
||||
[0031.chr, '"\\x19"'],
|
||||
[0032.chr, '"\\x1A"'],
|
||||
[0034.chr, '"\\x1C"'],
|
||||
[0035.chr, '"\\x1D"'],
|
||||
[0036.chr, '"\\x1E"'],
|
||||
[0037.chr, '"\\x1F"'],
|
||||
[0177.chr, '"\\x7F"'],
|
||||
[0200.chr, '"\\x80"'],
|
||||
[0201.chr, '"\\x81"'],
|
||||
[0202.chr, '"\\x82"'],
|
||||
[0203.chr, '"\\x83"'],
|
||||
[0204.chr, '"\\x84"'],
|
||||
[0205.chr, '"\\x85"'],
|
||||
[0206.chr, '"\\x86"'],
|
||||
[0207.chr, '"\\x87"'],
|
||||
[0210.chr, '"\\x88"'],
|
||||
[0211.chr, '"\\x89"'],
|
||||
[0212.chr, '"\\x8A"'],
|
||||
[0213.chr, '"\\x8B"'],
|
||||
[0214.chr, '"\\x8C"'],
|
||||
[0215.chr, '"\\x8D"'],
|
||||
[0216.chr, '"\\x8E"'],
|
||||
[0217.chr, '"\\x8F"'],
|
||||
[0220.chr, '"\\x90"'],
|
||||
[0221.chr, '"\\x91"'],
|
||||
[0222.chr, '"\\x92"'],
|
||||
[0223.chr, '"\\x93"'],
|
||||
[0224.chr, '"\\x94"'],
|
||||
[0225.chr, '"\\x95"'],
|
||||
[0226.chr, '"\\x96"'],
|
||||
[0227.chr, '"\\x97"'],
|
||||
[0230.chr, '"\\x98"'],
|
||||
[0231.chr, '"\\x99"'],
|
||||
[0232.chr, '"\\x9A"'],
|
||||
[0233.chr, '"\\x9B"'],
|
||||
[0234.chr, '"\\x9C"'],
|
||||
[0235.chr, '"\\x9D"'],
|
||||
[0236.chr, '"\\x9E"'],
|
||||
[0237.chr, '"\\x9F"'],
|
||||
[0240.chr, '"\\xA0"'],
|
||||
[0241.chr, '"\\xA1"'],
|
||||
[0242.chr, '"\\xA2"'],
|
||||
[0243.chr, '"\\xA3"'],
|
||||
[0244.chr, '"\\xA4"'],
|
||||
[0245.chr, '"\\xA5"'],
|
||||
[0246.chr, '"\\xA6"'],
|
||||
[0247.chr, '"\\xA7"'],
|
||||
[0250.chr, '"\\xA8"'],
|
||||
[0251.chr, '"\\xA9"'],
|
||||
[0252.chr, '"\\xAA"'],
|
||||
[0253.chr, '"\\xAB"'],
|
||||
[0254.chr, '"\\xAC"'],
|
||||
[0255.chr, '"\\xAD"'],
|
||||
[0256.chr, '"\\xAE"'],
|
||||
[0257.chr, '"\\xAF"'],
|
||||
[0260.chr, '"\\xB0"'],
|
||||
[0261.chr, '"\\xB1"'],
|
||||
[0262.chr, '"\\xB2"'],
|
||||
[0263.chr, '"\\xB3"'],
|
||||
[0264.chr, '"\\xB4"'],
|
||||
[0265.chr, '"\\xB5"'],
|
||||
[0266.chr, '"\\xB6"'],
|
||||
[0267.chr, '"\\xB7"'],
|
||||
[0270.chr, '"\\xB8"'],
|
||||
[0271.chr, '"\\xB9"'],
|
||||
[0272.chr, '"\\xBA"'],
|
||||
[0273.chr, '"\\xBB"'],
|
||||
[0274.chr, '"\\xBC"'],
|
||||
[0275.chr, '"\\xBD"'],
|
||||
[0276.chr, '"\\xBE"'],
|
||||
[0277.chr, '"\\xBF"'],
|
||||
[0300.chr, '"\\xC0"'],
|
||||
[0301.chr, '"\\xC1"'],
|
||||
[0302.chr, '"\\xC2"'],
|
||||
[0303.chr, '"\\xC3"'],
|
||||
[0304.chr, '"\\xC4"'],
|
||||
[0305.chr, '"\\xC5"'],
|
||||
[0306.chr, '"\\xC6"'],
|
||||
[0307.chr, '"\\xC7"'],
|
||||
[0310.chr, '"\\xC8"'],
|
||||
[0311.chr, '"\\xC9"'],
|
||||
[0312.chr, '"\\xCA"'],
|
||||
[0313.chr, '"\\xCB"'],
|
||||
[0314.chr, '"\\xCC"'],
|
||||
[0315.chr, '"\\xCD"'],
|
||||
[0316.chr, '"\\xCE"'],
|
||||
[0317.chr, '"\\xCF"'],
|
||||
[0320.chr, '"\\xD0"'],
|
||||
[0321.chr, '"\\xD1"'],
|
||||
[0322.chr, '"\\xD2"'],
|
||||
[0323.chr, '"\\xD3"'],
|
||||
[0324.chr, '"\\xD4"'],
|
||||
[0325.chr, '"\\xD5"'],
|
||||
[0326.chr, '"\\xD6"'],
|
||||
[0327.chr, '"\\xD7"'],
|
||||
[0330.chr, '"\\xD8"'],
|
||||
[0331.chr, '"\\xD9"'],
|
||||
[0332.chr, '"\\xDA"'],
|
||||
[0333.chr, '"\\xDB"'],
|
||||
[0334.chr, '"\\xDC"'],
|
||||
[0335.chr, '"\\xDD"'],
|
||||
[0336.chr, '"\\xDE"'],
|
||||
[0337.chr, '"\\xDF"'],
|
||||
[0340.chr, '"\\xE0"'],
|
||||
[0341.chr, '"\\xE1"'],
|
||||
[0342.chr, '"\\xE2"'],
|
||||
[0343.chr, '"\\xE3"'],
|
||||
[0344.chr, '"\\xE4"'],
|
||||
[0345.chr, '"\\xE5"'],
|
||||
[0346.chr, '"\\xE6"'],
|
||||
[0347.chr, '"\\xE7"'],
|
||||
[0350.chr, '"\\xE8"'],
|
||||
[0351.chr, '"\\xE9"'],
|
||||
[0352.chr, '"\\xEA"'],
|
||||
[0353.chr, '"\\xEB"'],
|
||||
[0354.chr, '"\\xEC"'],
|
||||
[0355.chr, '"\\xED"'],
|
||||
[0356.chr, '"\\xEE"'],
|
||||
[0357.chr, '"\\xEF"'],
|
||||
[0360.chr, '"\\xF0"'],
|
||||
[0361.chr, '"\\xF1"'],
|
||||
[0362.chr, '"\\xF2"'],
|
||||
[0363.chr, '"\\xF3"'],
|
||||
[0364.chr, '"\\xF4"'],
|
||||
[0365.chr, '"\\xF5"'],
|
||||
[0366.chr, '"\\xF6"'],
|
||||
[0367.chr, '"\\xF7"'],
|
||||
[0370.chr, '"\\xF8"'],
|
||||
[0371.chr, '"\\xF9"'],
|
||||
[0372.chr, '"\\xFA"'],
|
||||
[0373.chr, '"\\xFB"'],
|
||||
[0374.chr, '"\\xFC"'],
|
||||
[0375.chr, '"\\xFD"'],
|
||||
[0376.chr, '"\\xFE"'],
|
||||
[0377.chr, '"\\xFF"']
|
||||
].should be_computed_by(:dump)
|
||||
end
|
||||
|
||||
it "returns a string with non-printing single-byte UTF-8 characters replaced by \\x notation" do
|
||||
[ [0000.chr('utf-8'), '"\x00"'],
|
||||
[0001.chr('utf-8'), '"\x01"'],
|
||||
[0002.chr('utf-8'), '"\x02"'],
|
||||
[0003.chr('utf-8'), '"\x03"'],
|
||||
[0004.chr('utf-8'), '"\x04"'],
|
||||
[0005.chr('utf-8'), '"\x05"'],
|
||||
[0006.chr('utf-8'), '"\x06"'],
|
||||
[0016.chr('utf-8'), '"\x0E"'],
|
||||
[0017.chr('utf-8'), '"\x0F"'],
|
||||
[0020.chr('utf-8'), '"\x10"'],
|
||||
[0021.chr('utf-8'), '"\x11"'],
|
||||
[0022.chr('utf-8'), '"\x12"'],
|
||||
[0023.chr('utf-8'), '"\x13"'],
|
||||
[0024.chr('utf-8'), '"\x14"'],
|
||||
[0025.chr('utf-8'), '"\x15"'],
|
||||
[0026.chr('utf-8'), '"\x16"'],
|
||||
[0027.chr('utf-8'), '"\x17"'],
|
||||
[0030.chr('utf-8'), '"\x18"'],
|
||||
[0031.chr('utf-8'), '"\x19"'],
|
||||
[0032.chr('utf-8'), '"\x1A"'],
|
||||
[0034.chr('utf-8'), '"\x1C"'],
|
||||
[0035.chr('utf-8'), '"\x1D"'],
|
||||
[0036.chr('utf-8'), '"\x1E"'],
|
||||
[0037.chr('utf-8'), '"\x1F"'],
|
||||
[0177.chr('utf-8'), '"\x7F"']
|
||||
].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
|
||||
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
|
||||
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\")"
|
||||
end
|
||||
end
|
52
spec/ruby/core/string/dup_spec.rb
Normal file
52
spec/ruby/core/string/dup_spec.rb
Normal file
|
@ -0,0 +1,52 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "String#dup" do
|
||||
before :each do
|
||||
ScratchPad.clear
|
||||
@obj = StringSpecs::InitializeString.new "string"
|
||||
end
|
||||
|
||||
it "calls #initialize_copy on the new instance" do
|
||||
dup = @obj.dup
|
||||
ScratchPad.recorded.should_not == @obj.object_id
|
||||
ScratchPad.recorded.should == dup.object_id
|
||||
end
|
||||
|
||||
it "copies instance variables" do
|
||||
dup = @obj.dup
|
||||
dup.ivar.should == 1
|
||||
end
|
||||
|
||||
it "does not copy singleton methods" do
|
||||
def @obj.special() :the_one end
|
||||
dup = @obj.dup
|
||||
lambda { dup.special }.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "does not copy modules included in the singleton class" do
|
||||
class << @obj
|
||||
include StringSpecs::StringModule
|
||||
end
|
||||
|
||||
dup = @obj.dup
|
||||
lambda { dup.repr }.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "does not copy constants defined in the singleton class" do
|
||||
class << @obj
|
||||
CLONE = :clone
|
||||
end
|
||||
|
||||
dup = @obj.dup
|
||||
lambda { class << dup; CLONE; end }.should raise_error(NameError)
|
||||
end
|
||||
|
||||
it "does not modify the original string when changing dupped string" do
|
||||
orig = "string"[0..100]
|
||||
dup = orig.dup
|
||||
orig[0] = 'x'
|
||||
orig.should == "xtring"
|
||||
dup.should == "string"
|
||||
end
|
||||
end
|
61
spec/ruby/core/string/each_byte_spec.rb
Normal file
61
spec/ruby/core/string/each_byte_spec.rb
Normal file
|
@ -0,0 +1,61 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
describe "String#each_byte" do
|
||||
it "passes each byte in self to the given block" do
|
||||
a = []
|
||||
"hello\x00".each_byte { |c| a << c }
|
||||
a.should == [104, 101, 108, 108, 111, 0]
|
||||
end
|
||||
|
||||
it "keeps iterating from the old position (to new string end) when self changes" do
|
||||
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"
|
||||
s.each_byte { |c| s.slice!(-1); r << c }
|
||||
r.should == "hello "
|
||||
|
||||
r = ""
|
||||
s = "hello world"
|
||||
s.each_byte { |c| s.slice!(0); r << c }
|
||||
r.should == "hlowrd"
|
||||
|
||||
r = ""
|
||||
s = "hello world"
|
||||
s.each_byte { |c| s.slice!(0..-1); r << c }
|
||||
r.should == "h"
|
||||
end
|
||||
|
||||
it "returns self" do
|
||||
s = "hello"
|
||||
(s.each_byte {}).should equal(s)
|
||||
end
|
||||
|
||||
describe "when no block is given" do
|
||||
it "returns an enumerator" do
|
||||
enum = "hello".each_byte
|
||||
enum.should be_an_instance_of(Enumerator)
|
||||
enum.to_a.should == [104, 101, 108, 108, 111]
|
||||
end
|
||||
|
||||
describe "returned enumerator" do
|
||||
describe "size" do
|
||||
it "should return the bytesize of the string" do
|
||||
str = "hello"
|
||||
str.each_byte.size.should == str.bytesize
|
||||
str = "ola"
|
||||
str.each_byte.size.should == str.bytesize
|
||||
str = "\303\207\342\210\202\303\251\306\222g"
|
||||
str.each_byte.size.should == str.bytesize
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
7
spec/ruby/core/string/each_char_spec.rb
Normal file
7
spec/ruby/core/string/each_char_spec.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
require File.expand_path('../shared/chars', __FILE__)
|
||||
require File.expand_path('../shared/each_char_without_block', __FILE__)
|
||||
|
||||
describe "String#each_char" do
|
||||
it_behaves_like(:string_chars, :each_char)
|
||||
it_behaves_like(:string_each_char_without_block, :each_char)
|
||||
end
|
10
spec/ruby/core/string/each_codepoint_spec.rb
Normal file
10
spec/ruby/core/string/each_codepoint_spec.rb
Normal file
|
@ -0,0 +1,10 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../shared/codepoints', __FILE__)
|
||||
require File.expand_path('../shared/each_codepoint_without_block', __FILE__)
|
||||
|
||||
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
|
||||
end
|
9
spec/ruby/core/string/each_line_spec.rb
Normal file
9
spec/ruby/core/string/each_line_spec.rb
Normal file
|
@ -0,0 +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__)
|
||||
|
||||
describe "String#each_line" do
|
||||
it_behaves_like(:string_each_line, :each_line)
|
||||
it_behaves_like(:string_each_line_without_block, :each_line)
|
||||
end
|
35
spec/ruby/core/string/element_reference_spec.rb
Normal file
35
spec/ruby/core/string/element_reference_spec.rb
Normal file
|
@ -0,0 +1,35 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
require File.expand_path('../shared/slice.rb', __FILE__)
|
||||
|
||||
describe "String#[]" do
|
||||
it_behaves_like :string_slice, :[]
|
||||
end
|
||||
|
||||
describe "String#[] with index, length" do
|
||||
it_behaves_like :string_slice_index_length, :[]
|
||||
end
|
||||
|
||||
describe "String#[] with Range" do
|
||||
it_behaves_like :string_slice_range, :[]
|
||||
end
|
||||
|
||||
describe "String#[] with Regexp" do
|
||||
it_behaves_like :string_slice_regexp, :[]
|
||||
end
|
||||
|
||||
describe "String#[] with Regexp, index" do
|
||||
it_behaves_like :string_slice_regexp_index, :[]
|
||||
end
|
||||
|
||||
describe "String#[] with Regexp, group" do
|
||||
it_behaves_like :string_slice_regexp_group, :[]
|
||||
end
|
||||
|
||||
describe "String#[] with String" do
|
||||
it_behaves_like :string_slice_string, :[]
|
||||
end
|
||||
|
||||
describe "String#[] with Symbol" do
|
||||
it_behaves_like :string_slice_symbol, :[]
|
||||
end
|
612
spec/ruby/core/string/element_set_spec.rb
Normal file
612
spec/ruby/core/string/element_set_spec.rb
Normal file
|
@ -0,0 +1,612 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
# TODO: Add missing String#[]= specs:
|
||||
# String#[re, idx] = obj
|
||||
|
||||
describe "String#[]= with Fixnum index" do
|
||||
it "replaces the char at idx with other_str" do
|
||||
a = "hello"
|
||||
a[0] = "bam"
|
||||
a.should == "bamello"
|
||||
a[-2] = ""
|
||||
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.should == "hello"
|
||||
|
||||
lambda { str[-20] = "bam" }.should raise_error(IndexError)
|
||||
str.should == "hello"
|
||||
|
||||
lambda { ""[-1] = "bam" }.should raise_error(IndexError)
|
||||
end
|
||||
|
||||
# Behaviour verfieid correct 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 = ""
|
||||
str[0] = "bam"
|
||||
str.should == "bam"
|
||||
end
|
||||
|
||||
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.should == "hello"
|
||||
end
|
||||
|
||||
it "raises a RuntimeError when self is frozen" do
|
||||
a = "hello"
|
||||
a.freeze
|
||||
|
||||
lambda { a[0] = "bam" }.should raise_error(RuntimeError)
|
||||
end
|
||||
|
||||
it "calls to_int on index" do
|
||||
str = "hello"
|
||||
str[0.5] = "hi "
|
||||
str.should == "hi ello"
|
||||
|
||||
obj = mock('-1')
|
||||
obj.should_receive(:to_int).and_return(-1)
|
||||
str[obj] = "!"
|
||||
str.should == "hi ell!"
|
||||
end
|
||||
|
||||
it "calls #to_str to convert other to a String" do
|
||||
other_str = mock('-test-')
|
||||
other_str.should_receive(:to_str).and_return("-test-")
|
||||
|
||||
a = "abc"
|
||||
a[1] = other_str
|
||||
a.should == "a-test-c"
|
||||
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)
|
||||
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 an IndexError if the index is greater than character size" do
|
||||
lambda { "あれ"[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)
|
||||
|
||||
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')
|
||||
|
||||
lambda { "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)
|
||||
|
||||
lambda { "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 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 "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 "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
|
||||
end
|
||||
end
|
||||
|
||||
describe "String#[]= with String index" do
|
||||
it "replaces fewer characters with more characters" do
|
||||
str = "abcde"
|
||||
str["cd"] = "ghi"
|
||||
str.should == "abghie"
|
||||
end
|
||||
|
||||
it "replaces more characters with fewer characters" do
|
||||
str = "abcde"
|
||||
str["bcd"] = "f"
|
||||
str.should == "afe"
|
||||
end
|
||||
|
||||
it "replaces characters with no characters" do
|
||||
str = "abcde"
|
||||
str["cd"] = ""
|
||||
str.should == "abe"
|
||||
end
|
||||
|
||||
it "raises an IndexError if the search String is not found" do
|
||||
str = "abcde"
|
||||
lambda { 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 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 "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 "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
|
||||
end
|
||||
end
|
||||
|
||||
describe "String#[]= with a Regexp index" do
|
||||
it "replaces the matched text with the rhs" do
|
||||
str = "hello"
|
||||
str[/lo/] = "x"
|
||||
str.should == "helx"
|
||||
end
|
||||
|
||||
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.should == "hello"
|
||||
end
|
||||
|
||||
it "calls #to_str to convert the replacement" do
|
||||
rep = mock("string element set regexp")
|
||||
rep.should_receive(:to_str).and_return("b")
|
||||
|
||||
str = "abc"
|
||||
str[/ab/] = rep
|
||||
str.should == "bc"
|
||||
end
|
||||
|
||||
it "checks the match before calling #to_str to convert the replacement" do
|
||||
rep = mock("string element set regexp")
|
||||
rep.should_not_receive(:to_str)
|
||||
|
||||
lambda { "abc"[/def/] = rep }.should raise_error(IndexError)
|
||||
end
|
||||
|
||||
describe "with 3 arguments" do
|
||||
it "calls #to_int to convert the second object" do
|
||||
ref = mock("string element set regexp ref")
|
||||
ref.should_receive(:to_int).and_return(1)
|
||||
|
||||
str = "abc"
|
||||
str[/a(b)/, ref] = "x"
|
||||
str.should == "axc"
|
||||
end
|
||||
|
||||
it "raises a TypeError if #to_int does not return a Fixnum" 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)
|
||||
end
|
||||
|
||||
it "uses the 2nd of 3 arguments as which capture should be replaced" do
|
||||
str = "aaa bbb ccc"
|
||||
str[/a (bbb) c/, 1] = "ddd"
|
||||
str.should == "aaa ddd ccc"
|
||||
end
|
||||
|
||||
it "allows the specified capture to be negative and count from the end" do
|
||||
str = "abcd"
|
||||
str[/(a)(b)(c)(d)/, -2] = "e"
|
||||
str.should == "abed"
|
||||
end
|
||||
|
||||
it "checks the match index before calling #to_str to convert the replacement" do
|
||||
rep = mock("string element set regexp")
|
||||
rep.should_not_receive(:to_str)
|
||||
|
||||
lambda { "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)
|
||||
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.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 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 "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 "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
|
||||
end
|
||||
end
|
||||
|
||||
describe "String#[]= with a Range index" do
|
||||
describe "with an empty replacement" do
|
||||
it "does not replace a character with a zero-index, zero exclude-end range" do
|
||||
str = "abc"
|
||||
str[0...0] = ""
|
||||
str.should == "abc"
|
||||
end
|
||||
|
||||
it "does not replace a character with a zero exclude-end range" do
|
||||
str = "abc"
|
||||
str[1...1] = ""
|
||||
str.should == "abc"
|
||||
end
|
||||
|
||||
it "replaces a character with zero-index, zero non-exclude-end range" do
|
||||
str = "abc"
|
||||
str[0..0] = ""
|
||||
str.should == "bc"
|
||||
end
|
||||
|
||||
it "replaces a character with a zero non-exclude-end range" do
|
||||
str = "abc"
|
||||
str[1..1] = ""
|
||||
str.should == "ac"
|
||||
end
|
||||
end
|
||||
|
||||
it "replaces the contents with a shorter String" do
|
||||
str = "abcde"
|
||||
str[0..-1] = "hg"
|
||||
str.should == "hg"
|
||||
end
|
||||
|
||||
it "replaces the contents with a longer String" do
|
||||
str = "abc"
|
||||
str[0...4] = "uvwxyz"
|
||||
str.should == "uvwxyz"
|
||||
end
|
||||
|
||||
it "replaces a partial string" do
|
||||
str = "abcde"
|
||||
str[1..3] = "B"
|
||||
str.should == "aBe"
|
||||
end
|
||||
|
||||
it "raises a RangeError if negative Range begin is out of range" do
|
||||
lambda { "abc"[-4..-2] = "x" }.should raise_error(RangeError)
|
||||
end
|
||||
|
||||
it "raises a RangeError if positive Range begin is greater than String size" do
|
||||
lambda { "abc"[4..2] = "x" }.should raise_error(RangeError)
|
||||
end
|
||||
|
||||
it "uses the Range end as an index rather than a count" do
|
||||
str = "abcdefg"
|
||||
str[-5..3] = "xyz"
|
||||
str.should == "abxyzefg"
|
||||
end
|
||||
|
||||
it "treats a negative out-of-range Range end with a positive Range begin as a zero count" do
|
||||
str = "abc"
|
||||
str[1..-4] = "x"
|
||||
str.should == "axbc"
|
||||
end
|
||||
|
||||
it "treats a negative out-of-range Range end with a negative Range begin as a zero count" do
|
||||
str = "abcd"
|
||||
str[-1..-4] = "x"
|
||||
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 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 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 "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 "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
|
||||
end
|
||||
end
|
||||
|
||||
describe "String#[]= with Fixnum 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"
|
||||
a.should == "xxllo"
|
||||
a = "hello"
|
||||
a[0, 2] = "jello"
|
||||
a.should == "jellollo"
|
||||
end
|
||||
|
||||
it "counts negative idx values from end of the string" do
|
||||
a = "hello"
|
||||
a[-1, 0] = "bob"
|
||||
a.should == "hellbobo"
|
||||
a = "hello"
|
||||
a[-5, 0] = "bob"
|
||||
a.should == "bobhello"
|
||||
end
|
||||
|
||||
it "overwrites and deletes characters if count is more than the length of other_str" do
|
||||
a = "hello"
|
||||
a[0, 4] = "x"
|
||||
a.should == "xo"
|
||||
a = "hello"
|
||||
a[0, 5] = "x"
|
||||
a.should == "x"
|
||||
end
|
||||
|
||||
it "deletes characters if other_str is an empty string" do
|
||||
a = "hello"
|
||||
a[0, 2] = ""
|
||||
a.should == "llo"
|
||||
end
|
||||
|
||||
it "deletes characters up to the maximum length of the existing string" do
|
||||
a = "hello"
|
||||
a[0, 6] = "x"
|
||||
a.should == "x"
|
||||
a = "hello"
|
||||
a[0, 100] = ""
|
||||
a.should == ""
|
||||
end
|
||||
|
||||
it "appends other_str to the end of the string if idx == the length of the string" do
|
||||
a = "hello"
|
||||
a[5, 0] = "bob"
|
||||
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)
|
||||
|
||||
count = mock("string element set count")
|
||||
count.should_receive(:to_int).and_return(2)
|
||||
|
||||
str = "abcde"
|
||||
str[index, count] = "xyz"
|
||||
str.should == "axyzde"
|
||||
end
|
||||
|
||||
it "raises a TypeError if #to_int for index does not return an Integer" do
|
||||
index = mock("string element set index")
|
||||
index.should_receive(:to_int).and_return("1")
|
||||
|
||||
lambda { "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)
|
||||
end
|
||||
|
||||
it "calls #to_str to convert the replacement object" do
|
||||
r = mock("string element set replacement")
|
||||
r.should_receive(:to_str).and_return("xyz")
|
||||
|
||||
str = "abcde"
|
||||
str[2, 2] = r
|
||||
str.should == "abxyze"
|
||||
end
|
||||
|
||||
it "raises a TypeError of #to_str does not return a String" do
|
||||
r = mock("string element set replacement")
|
||||
r.should_receive(:to_str).and_return(nil)
|
||||
|
||||
lambda { "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)
|
||||
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)
|
||||
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)
|
||||
end
|
||||
|
||||
with_feature :encoding do
|
||||
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 multibyte characters" do
|
||||
str = "ありがとう"
|
||||
str[2, 1] = "か"
|
||||
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 "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 "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 "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
|
||||
end
|
||||
end
|
12
spec/ruby/core/string/empty_spec.rb
Normal file
12
spec/ruby/core/string/empty_spec.rb
Normal file
|
@ -0,0 +1,12 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
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
|
||||
end
|
||||
end
|
159
spec/ruby/core/string/encode_spec.rb
Normal file
159
spec/ruby/core/string/encode_spec.rb
Normal file
|
@ -0,0 +1,159 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../shared/encode', __FILE__)
|
||||
|
||||
with_feature :encoding do
|
||||
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 = "あ"
|
||||
str.encode.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 "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
|
||||
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 "round trips a String" do
|
||||
str = "abc def".force_encoding Encoding::US_ASCII
|
||||
str.encode("utf-32be").encode("ascii").should == "abc def"
|
||||
end
|
||||
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 "normalizes newlines" do
|
||||
"\r\nfoo".encode(universal_newline: true).should == "\nfoo"
|
||||
|
||||
"\rfoo".encode(universal_newline: true).should == "\nfoo"
|
||||
end
|
||||
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")
|
||||
|
||||
encoded.should_not equal(str)
|
||||
encoded.encoding.should == Encoding::UTF_8
|
||||
end
|
||||
|
||||
it "returns the transcoded string" do
|
||||
str = "\x00\x00\x00\x1F"
|
||||
str.encode(Encoding::UTF_8, Encoding::UTF_16BE).should == "\u0000\u001f"
|
||||
end
|
||||
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
|
||||
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
|
||||
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
|
||||
|
||||
it_behaves_like :string_encode, :encode!
|
||||
|
||||
it "raises a RuntimeError when called on a frozen String" do
|
||||
lambda { "foo".freeze.encode!("euc-jp") }.should raise_error(RuntimeError)
|
||||
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)
|
||||
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 "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 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
|
||||
end
|
||||
end
|
||||
end
|
189
spec/ruby/core/string/encoding_spec.rb
Normal file
189
spec/ruby/core/string/encoding_spec.rb
Normal file
|
@ -0,0 +1,189 @@
|
|||
# -*- 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
|
||||
end
|
||||
end
|
50
spec/ruby/core/string/end_with_spec.rb
Normal file
50
spec/ruby/core/string/end_with_spec.rb
Normal file
|
@ -0,0 +1,50 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
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
|
||||
|
||||
end
|
21
spec/ruby/core/string/eql_spec.rb
Normal file
21
spec/ruby/core/string/eql_spec.rb
Normal file
|
@ -0,0 +1,21 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../shared/eql', __FILE__)
|
||||
|
||||
describe "String#eql?" do
|
||||
it_behaves_like(:string_eql_value, :eql?)
|
||||
|
||||
describe "when given a non-String" do
|
||||
it "returns false" do
|
||||
'hello'.should_not eql(5)
|
||||
not_supported_on :opal do
|
||||
'hello'.should_not eql(:hello)
|
||||
end
|
||||
'hello'.should_not eql(mock('x'))
|
||||
end
|
||||
|
||||
it "does not try to call #to_str on the given argument" do
|
||||
(obj = mock('x')).should_not_receive(:to_str)
|
||||
'hello'.should_not eql(obj)
|
||||
end
|
||||
end
|
||||
end
|
8
spec/ruby/core/string/equal_value_spec.rb
Normal file
8
spec/ruby/core/string/equal_value_spec.rb
Normal file
|
@ -0,0 +1,8 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../shared/eql', __FILE__)
|
||||
require File.expand_path('../shared/equal_value', __FILE__)
|
||||
|
||||
describe "String#==" do
|
||||
it_behaves_like(:string_eql_value, :==)
|
||||
it_behaves_like(:string_equal_value, :==)
|
||||
end
|
49
spec/ruby/core/string/fixtures/classes.rb
Normal file
49
spec/ruby/core/string/fixtures/classes.rb
Normal file
|
@ -0,0 +1,49 @@
|
|||
class Object
|
||||
# This helper is defined here rather than in MSpec because
|
||||
# it is only used in #unpack specs.
|
||||
def unpack_format(count=nil, repeat=nil)
|
||||
format = "#{instance_variable_get(:@method)}#{count}"
|
||||
format *= repeat if repeat
|
||||
format
|
||||
end
|
||||
end
|
||||
|
||||
module StringSpecs
|
||||
class MyString < String; end
|
||||
class MyArray < Array; end
|
||||
class MyRange < Range; end
|
||||
|
||||
class SubString < String
|
||||
attr_reader :special
|
||||
|
||||
def initialize(str=nil)
|
||||
@special = str
|
||||
end
|
||||
end
|
||||
|
||||
class InitializeString < String
|
||||
attr_reader :ivar
|
||||
|
||||
def initialize(other)
|
||||
super
|
||||
@ivar = 1
|
||||
end
|
||||
|
||||
def initialize_copy(other)
|
||||
ScratchPad.record object_id
|
||||
end
|
||||
end
|
||||
|
||||
module StringModule
|
||||
def repr
|
||||
1
|
||||
end
|
||||
end
|
||||
|
||||
class StringWithRaisingConstructor < String
|
||||
def initialize(str)
|
||||
raise ArgumentError.new('constructor was called') unless str == 'silly:string'
|
||||
self.replace(str)
|
||||
end
|
||||
end
|
||||
end
|
3
spec/ruby/core/string/fixtures/freeze_magic_comment.rb
Normal file
3
spec/ruby/core/string/fixtures/freeze_magic_comment.rb
Normal file
|
@ -0,0 +1,3 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
print (+ 'frozen string').frozen? ? 'immutable' : 'mutable'
|
9
spec/ruby/core/string/fixtures/iso-8859-9-encoding.rb
Normal file
9
spec/ruby/core/string/fixtures/iso-8859-9-encoding.rb
Normal file
|
@ -0,0 +1,9 @@
|
|||
# -*- encoding: iso-8859-9 -*-
|
||||
module StringSpecs
|
||||
class ISO88599Encoding
|
||||
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
|
||||
end
|
||||
end
|
7
spec/ruby/core/string/fixtures/utf-8-encoding.rb
Normal file
7
spec/ruby/core/string/fixtures/utf-8-encoding.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
module StringSpecs
|
||||
class UTF8Encoding
|
||||
def self.source_encoding; __ENCODING__; end
|
||||
def self.egrave; "é"; end
|
||||
end
|
||||
end
|
53
spec/ruby/core/string/force_encoding_spec.rb
Normal file
53
spec/ruby/core/string/force_encoding_spec.rb
Normal file
|
@ -0,0 +1,53 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
|
||||
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
|
||||
end
|
||||
|
||||
it "accepts an Encoding instance" do
|
||||
"abc".force_encoding(Encoding::SHIFT_JIS).encoding.should == Encoding::Shift_JIS
|
||||
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")
|
||||
|
||||
"abc".force_encoding(obj).encoding.should == Encoding::UTF_8
|
||||
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)
|
||||
|
||||
lambda { "abc".force_encoding(obj) }.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "raises a TypeError if passed nil" do
|
||||
lambda { "abc".force_encoding(nil) }.should raise_error(TypeError)
|
||||
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 = "\u{8612}"
|
||||
str.dup.force_encoding('utf-16le').should_not == str.encode('utf-16le')
|
||||
end
|
||||
|
||||
it "raises a RuntimeError if self is frozen" do
|
||||
str = "abcd".freeze
|
||||
lambda { str.force_encoding(str.encoding) }.should raise_error(RuntimeError)
|
||||
end
|
||||
end
|
||||
end
|
18
spec/ruby/core/string/freeze_spec.rb
Normal file
18
spec/ruby/core/string/freeze_spec.rb
Normal file
|
@ -0,0 +1,18 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
|
||||
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
|
||||
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
|
||||
end
|
||||
|
||||
it "being a special form doesn't change the value of defined?" do
|
||||
defined?("abc".freeze).should == "method"
|
||||
end
|
||||
|
||||
end
|
69
spec/ruby/core/string/getbyte_spec.rb
Normal file
69
spec/ruby/core/string/getbyte_spec.rb
Normal file
|
@ -0,0 +1,69 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
|
||||
describe "String#getbyte" do
|
||||
it "returns an Integer if given a valid index" do
|
||||
"a".getbyte(0).should be_kind_of(Integer)
|
||||
end
|
||||
|
||||
it "starts indexing at 0" do
|
||||
"b".getbyte(0).should == 98
|
||||
|
||||
# copy-on-write case
|
||||
_str1, str2 = "fooXbar".split("X")
|
||||
str2.getbyte(0).should == 98
|
||||
end
|
||||
|
||||
it "counts from the end of the String if given a negative argument" do
|
||||
"glark".getbyte(-1).should == "glark".getbyte(4)
|
||||
|
||||
# copy-on-write case
|
||||
_str1, str2 = "fooXbar".split("X")
|
||||
str2.getbyte(-1).should == 114
|
||||
end
|
||||
|
||||
it "returns an Integer between 0 and 255" do
|
||||
"\x00".getbyte(0).should == 0
|
||||
[0xFF].pack('C').getbyte(0).should == 255
|
||||
256.chr('utf-8').getbyte(0).should == 196
|
||||
256.chr('utf-8').getbyte(1).should == 128
|
||||
end
|
||||
|
||||
it "regards a multi-byte character as having multiple bytes" do
|
||||
chr = "\u{998}"
|
||||
chr.bytesize.should == 3
|
||||
chr.getbyte(0).should == 224
|
||||
chr.getbyte(1).should == 166
|
||||
chr.getbyte(2).should == 152
|
||||
end
|
||||
|
||||
it "mirrors the output of #bytes" do
|
||||
xDE = [0xDE].pack('C').force_encoding('utf-8')
|
||||
str = "UTF-8 (\u{9865}} characters and hex escapes (#{xDE})"
|
||||
str.bytes.to_a.each_with_index do |byte, index|
|
||||
str.getbyte(index).should == byte
|
||||
end
|
||||
end
|
||||
|
||||
it "interprets bytes relative to the String's encoding" do
|
||||
str = "\u{333}"
|
||||
str.encode('utf-8').getbyte(0).should_not == str.encode('utf-16le').getbyte(0)
|
||||
end
|
||||
|
||||
it "returns nil for out-of-bound indexes" do
|
||||
"g".getbyte(1).should be_nil
|
||||
end
|
||||
|
||||
it "regards the empty String as containing no bytes" do
|
||||
"".getbyte(0).should be_nil
|
||||
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)
|
||||
end
|
||||
|
||||
it "raises a TypeError unless its argument can be coerced into an Integer" do
|
||||
lambda { "a".getbyte('a') }.should raise_error(TypeError)
|
||||
end
|
||||
end
|
696
spec/ruby/core/string/gsub_spec.rb
Normal file
696
spec/ruby/core/string/gsub_spec.rb
Normal file
|
@ -0,0 +1,696 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
describe :string_gsub_named_capture, shared: true do
|
||||
it "replaces \\k named backreferences with the regexp's corresponding capture" do
|
||||
str = "hello"
|
||||
|
||||
str.gsub(/(?<foo>[aeiou])/, '<\k<foo>>').should == "h<e>ll<o>"
|
||||
str.gsub(/(?<foo>.)/, '\k<foo>\k<foo>').should == "hheelllloo"
|
||||
end
|
||||
end
|
||||
|
||||
describe "String#gsub with pattern and replacement" do
|
||||
it "inserts the replacement around every character when the pattern collapses" do
|
||||
"hello".gsub(//, ".").should == ".h.e.l.l.o."
|
||||
end
|
||||
|
||||
it "respects unicode when the pattern collapses" do
|
||||
str = "こにちわ"
|
||||
reg = %r!!
|
||||
|
||||
str.gsub(reg, ".").should == ".こ.に.ち.わ."
|
||||
end
|
||||
|
||||
it "doesn't freak out when replacing ^" do
|
||||
"Text\n".gsub(/^/, ' ').should == " Text\n"
|
||||
"Text\nFoo".gsub(/^/, ' ').should == " Text\n Foo"
|
||||
end
|
||||
|
||||
it "returns a copy of self with all occurrences of pattern replaced with replacement" do
|
||||
"hello".gsub(/[aeiou]/, '*').should == "h*ll*"
|
||||
|
||||
str = "hello homely world. hah!"
|
||||
str.gsub(/\Ah\S+\s*/, "huh? ").should == "huh? homely world. hah!"
|
||||
|
||||
str = "¿por qué?"
|
||||
str.gsub(/([a-z\d]*)/, "*").should == "*¿** **é*?*"
|
||||
end
|
||||
|
||||
it "ignores a block if supplied" do
|
||||
"food".gsub(/f/, "g") { "w" }.should == "good"
|
||||
end
|
||||
|
||||
it "supports \\G which matches at the beginning of the remaining (non-matched) string" do
|
||||
str = "hello homely world. hah!"
|
||||
str.gsub(/\Gh\S+\s*/, "huh? ").should == "huh? huh? world. hah!"
|
||||
end
|
||||
|
||||
it "supports /i for ignoring case" do
|
||||
str = "Hello. How happy are you?"
|
||||
str.gsub(/h/i, "j").should == "jello. jow jappy are you?"
|
||||
str.gsub(/H/i, "j").should == "jello. jow jappy are you?"
|
||||
end
|
||||
|
||||
it "doesn't interpret regexp metacharacters if pattern is a string" do
|
||||
"12345".gsub('\d', 'a').should == "12345"
|
||||
'\d'.gsub('\d', 'a').should == "a"
|
||||
end
|
||||
|
||||
it "replaces \\1 sequences with the regexp's corresponding capture" do
|
||||
str = "hello"
|
||||
|
||||
str.gsub(/([aeiou])/, '<\1>').should == "h<e>ll<o>"
|
||||
str.gsub(/(.)/, '\1\1').should == "hheelllloo"
|
||||
|
||||
str.gsub(/.(.?)/, '<\0>(\1)').should == "<he>(e)<ll>(l)<o>()"
|
||||
|
||||
str.gsub(/.(.)+/, '\1').should == "o"
|
||||
|
||||
str = "ABCDEFGHIJKLabcdefghijkl"
|
||||
re = /#{"(.)" * 12}/
|
||||
str.gsub(re, '\1').should == "Aa"
|
||||
str.gsub(re, '\9').should == "Ii"
|
||||
# Only the first 9 captures can be accessed in MRI
|
||||
str.gsub(re, '\10').should == "A0a0"
|
||||
end
|
||||
|
||||
it "treats \\1 sequences without corresponding captures as empty strings" do
|
||||
str = "hello!"
|
||||
|
||||
str.gsub("", '<\1>').should == "<>h<>e<>l<>l<>o<>!<>"
|
||||
str.gsub("h", '<\1>').should == "<>ello!"
|
||||
|
||||
str.gsub(//, '<\1>').should == "<>h<>e<>l<>l<>o<>!<>"
|
||||
str.gsub(/./, '\1\2\3').should == ""
|
||||
str.gsub(/.(.{20})?/, '\1').should == ""
|
||||
end
|
||||
|
||||
it "replaces \\& and \\0 with the complete match" do
|
||||
str = "hello!"
|
||||
|
||||
str.gsub("", '<\0>').should == "<>h<>e<>l<>l<>o<>!<>"
|
||||
str.gsub("", '<\&>').should == "<>h<>e<>l<>l<>o<>!<>"
|
||||
str.gsub("he", '<\0>').should == "<he>llo!"
|
||||
str.gsub("he", '<\&>').should == "<he>llo!"
|
||||
str.gsub("l", '<\0>').should == "he<l><l>o!"
|
||||
str.gsub("l", '<\&>').should == "he<l><l>o!"
|
||||
|
||||
str.gsub(//, '<\0>').should == "<>h<>e<>l<>l<>o<>!<>"
|
||||
str.gsub(//, '<\&>').should == "<>h<>e<>l<>l<>o<>!<>"
|
||||
str.gsub(/../, '<\0>').should == "<he><ll><o!>"
|
||||
str.gsub(/../, '<\&>').should == "<he><ll><o!>"
|
||||
str.gsub(/(.)./, '<\0>').should == "<he><ll><o!>"
|
||||
end
|
||||
|
||||
it "replaces \\` with everything before the current match" do
|
||||
str = "hello!"
|
||||
|
||||
str.gsub("", '<\`>').should == "<>h<h>e<he>l<hel>l<hell>o<hello>!<hello!>"
|
||||
str.gsub("h", '<\`>').should == "<>ello!"
|
||||
str.gsub("l", '<\`>').should == "he<he><hel>o!"
|
||||
str.gsub("!", '<\`>').should == "hello<hello>"
|
||||
|
||||
str.gsub(//, '<\`>').should == "<>h<h>e<he>l<hel>l<hell>o<hello>!<hello!>"
|
||||
str.gsub(/../, '<\`>').should == "<><he><hell>"
|
||||
end
|
||||
|
||||
it "replaces \\' with everything after the current match" do
|
||||
str = "hello!"
|
||||
|
||||
str.gsub("", '<\\\'>').should == "<hello!>h<ello!>e<llo!>l<lo!>l<o!>o<!>!<>"
|
||||
str.gsub("h", '<\\\'>').should == "<ello!>ello!"
|
||||
str.gsub("ll", '<\\\'>').should == "he<o!>o!"
|
||||
str.gsub("!", '<\\\'>').should == "hello<>"
|
||||
|
||||
str.gsub(//, '<\\\'>').should == "<hello!>h<ello!>e<llo!>l<lo!>l<o!>o<!>!<>"
|
||||
str.gsub(/../, '<\\\'>').should == "<llo!><o!><>"
|
||||
end
|
||||
|
||||
it "replaces \\+ with the last paren that actually matched" do
|
||||
str = "hello!"
|
||||
|
||||
str.gsub(/(.)(.)/, '\+').should == "el!"
|
||||
str.gsub(/(.)(.)+/, '\+').should == "!"
|
||||
str.gsub(/(.)()/, '\+').should == ""
|
||||
str.gsub(/(.)(.{20})?/, '<\+>').should == "<h><e><l><l><o><!>"
|
||||
|
||||
str = "ABCDEFGHIJKLabcdefghijkl"
|
||||
re = /#{"(.)" * 12}/
|
||||
str.gsub(re, '\+').should == "Ll"
|
||||
end
|
||||
|
||||
it "treats \\+ as an empty string if there was no captures" do
|
||||
"hello!".gsub(/./, '\+').should == ""
|
||||
end
|
||||
|
||||
it "maps \\\\ in replacement to \\" do
|
||||
"hello".gsub(/./, '\\\\').should == '\\' * 5
|
||||
end
|
||||
|
||||
it "leaves unknown \\x escapes in replacement untouched" do
|
||||
"hello".gsub(/./, '\\x').should == '\\x' * 5
|
||||
"hello".gsub(/./, '\\y').should == '\\y' * 5
|
||||
end
|
||||
|
||||
it "leaves \\ at the end of replacement untouched" do
|
||||
"hello".gsub(/./, 'hah\\').should == 'hah\\' * 5
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
"hello.".gsub(pattern, "!").should == "hello!"
|
||||
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)
|
||||
end
|
||||
|
||||
it "tries to convert replacement to a string using to_str" do
|
||||
replacement = mock('hello_replacement')
|
||||
def replacement.to_str() "hello_replacement" end
|
||||
|
||||
"hello".gsub(/hello/, replacement).should == "hello_replacement"
|
||||
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)
|
||||
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)
|
||||
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'
|
||||
|
||||
'hello.'.gsub('not', 'x')
|
||||
$~.should == nil
|
||||
|
||||
'hello.'.gsub(/.(.)/, 'x')
|
||||
$~[0].should == 'o.'
|
||||
|
||||
'hello.'.gsub(/not/, 'x')
|
||||
$~.should == nil
|
||||
end
|
||||
end
|
||||
|
||||
describe "String#gsub with pattern and Hash" do
|
||||
it "returns a copy of self with all occurrences of pattern replaced with the value of the corresponding hash key" do
|
||||
"hello".gsub(/./, 'l' => 'L').should == "LL"
|
||||
"hello!".gsub(/(.)(.)/, 'he' => 'she ', 'll' => 'said').should == 'she said'
|
||||
"hello".gsub('l', 'l' => 'el').should == 'heelelo'
|
||||
end
|
||||
|
||||
it "ignores keys that don't correspond to matches" do
|
||||
"hello".gsub(/./, 'z' => 'L', 'h' => 'b', 'o' => 'ow').should == "bow"
|
||||
end
|
||||
|
||||
it "returns an empty string if the pattern matches but the hash specifies no replacements" do
|
||||
"hello".gsub(/./, 'z' => 'L').should == ""
|
||||
end
|
||||
|
||||
it "ignores non-String keys" do
|
||||
"tattoo".gsub(/(tt)/, 'tt' => 'b', tt: 'z').should == "taboo"
|
||||
end
|
||||
|
||||
it "uses a key's value as many times as needed" do
|
||||
"food".gsub(/o/, 'o' => '0').should == "f00d"
|
||||
end
|
||||
|
||||
it "uses the hash's default value for missing keys" do
|
||||
hsh = {}
|
||||
hsh.default='?'
|
||||
hsh['o'] = '0'
|
||||
"food".gsub(/./, hsh).should == "?00?"
|
||||
end
|
||||
|
||||
it "coerces the hash values with #to_s" do
|
||||
hsh = {}
|
||||
hsh.default=[]
|
||||
hsh['o'] = 0
|
||||
obj = mock('!')
|
||||
obj.should_receive(:to_s).and_return('!')
|
||||
hsh['!'] = obj
|
||||
"food!".gsub(/./, hsh).should == "[]00[]!"
|
||||
end
|
||||
|
||||
it "uses the hash's value set from default_proc for missing keys" do
|
||||
hsh = {}
|
||||
hsh.default_proc = lambda { |k,v| 'lamb' }
|
||||
"food!".gsub(/./, hsh).should == "lamblamblamblamblamb"
|
||||
end
|
||||
|
||||
it "sets $~ to MatchData of last match and nil when there's none for access from outside" do
|
||||
'hello.'.gsub('l', 'l' => 'L')
|
||||
$~.begin(0).should == 3
|
||||
$~[0].should == 'l'
|
||||
|
||||
'hello.'.gsub('not', 'ot' => 'to')
|
||||
$~.should == nil
|
||||
|
||||
'hello.'.gsub(/.(.)/, 'o' => ' hole')
|
||||
$~[0].should == 'o.'
|
||||
|
||||
'hello.'.gsub(/not/, 'z' => 'glark')
|
||||
$~.should == nil
|
||||
end
|
||||
|
||||
it "doesn't interpolate special sequences like \\1 for the block's return value" 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
|
||||
|
||||
it "returns self with all occurrences of pattern replaced with the value of the corresponding hash key" do
|
||||
"hello".gsub!(/./, 'l' => 'L').should == "LL"
|
||||
"hello!".gsub!(/(.)(.)/, 'he' => 'she ', 'll' => 'said').should == 'she said'
|
||||
"hello".gsub!('l', 'l' => 'el').should == 'heelelo'
|
||||
end
|
||||
|
||||
it "ignores keys that don't correspond to matches" do
|
||||
"hello".gsub!(/./, 'z' => 'L', 'h' => 'b', 'o' => 'ow').should == "bow"
|
||||
end
|
||||
|
||||
it "replaces self with an empty string if the pattern matches but the hash specifies no replacements" do
|
||||
"hello".gsub!(/./, 'z' => 'L').should == ""
|
||||
end
|
||||
|
||||
it "ignores non-String keys" do
|
||||
"hello".gsub!(/(ll)/, 'll' => 'r', ll: 'z').should == "hero"
|
||||
end
|
||||
|
||||
it "uses a key's value as many times as needed" do
|
||||
"food".gsub!(/o/, 'o' => '0').should == "f00d"
|
||||
end
|
||||
|
||||
it "uses the hash's default value for missing keys" do
|
||||
hsh = {}
|
||||
hsh.default='?'
|
||||
hsh['o'] = '0'
|
||||
"food".gsub!(/./, hsh).should == "?00?"
|
||||
end
|
||||
|
||||
it "coerces the hash values with #to_s" do
|
||||
hsh = {}
|
||||
hsh.default=[]
|
||||
hsh['o'] = 0
|
||||
obj = mock('!')
|
||||
obj.should_receive(:to_s).and_return('!')
|
||||
hsh['!'] = obj
|
||||
"food!".gsub!(/./, hsh).should == "[]00[]!"
|
||||
end
|
||||
|
||||
it "uses the hash's value set from default_proc for missing keys" do
|
||||
hsh = {}
|
||||
hsh.default_proc = lambda { |k,v| 'lamb' }
|
||||
"food!".gsub!(/./, hsh).should == "lamblamblamblamblamb"
|
||||
end
|
||||
|
||||
it "sets $~ to MatchData of last match and nil when there's none for access from outside" do
|
||||
'hello.'.gsub!('l', 'l' => 'L')
|
||||
$~.begin(0).should == 3
|
||||
$~[0].should == 'l'
|
||||
|
||||
'hello.'.gsub!('not', 'ot' => 'to')
|
||||
$~.should == nil
|
||||
|
||||
'hello.'.gsub!(/.(.)/, 'o' => ' hole')
|
||||
$~[0].should == 'o.'
|
||||
|
||||
'hello.'.gsub!(/not/, 'z' => 'glark')
|
||||
$~.should == nil
|
||||
end
|
||||
|
||||
it "doesn't interpolate special sequences like \\1 for the block's return value" 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
|
||||
it "returns a copy of self with all occurrences of pattern replaced with the block's return value" do
|
||||
"hello".gsub(/./) { |s| s.succ + ' ' }.should == "i f m m p "
|
||||
"hello!".gsub(/(.)(.)/) { |*a| a.inspect }.should == '["he"]["ll"]["o!"]'
|
||||
"hello".gsub('l') { 'x'}.should == 'hexxo'
|
||||
end
|
||||
|
||||
it "sets $~ for access from the block" do
|
||||
str = "hello"
|
||||
str.gsub(/([aeiou])/) { "<#{$~[1]}>" }.should == "h<e>ll<o>"
|
||||
str.gsub(/([aeiou])/) { "<#{$1}>" }.should == "h<e>ll<o>"
|
||||
str.gsub("l") { "<#{$~[0]}>" }.should == "he<l><l>o"
|
||||
|
||||
offsets = []
|
||||
|
||||
str.gsub(/([aeiou])/) do
|
||||
md = $~
|
||||
md.string.should == str
|
||||
offsets << md.offset(0)
|
||||
str
|
||||
end.should == "hhellollhello"
|
||||
|
||||
offsets.should == [[1, 2], [4, 5]]
|
||||
end
|
||||
|
||||
it "restores $~ after leaving the block" do
|
||||
[/./, "l"].each do |pattern|
|
||||
old_md = nil
|
||||
"hello".gsub(pattern) do
|
||||
old_md = $~
|
||||
"ok".match(/./)
|
||||
"x"
|
||||
end
|
||||
|
||||
$~[0].should == old_md[0]
|
||||
$~.string.should == "hello"
|
||||
end
|
||||
end
|
||||
|
||||
it "sets $~ to MatchData of last match and nil when there's none for access from outside" do
|
||||
'hello.'.gsub('l') { 'x' }
|
||||
$~.begin(0).should == 3
|
||||
$~[0].should == 'l'
|
||||
|
||||
'hello.'.gsub('not') { 'x' }
|
||||
$~.should == nil
|
||||
|
||||
'hello.'.gsub(/.(.)/) { 'x' }
|
||||
$~[0].should == 'o.'
|
||||
|
||||
'hello.'.gsub(/not/) { 'x' }
|
||||
$~.should == nil
|
||||
end
|
||||
|
||||
it "doesn't interpolate special sequences like \\1 for the block's return value" do
|
||||
repl = '\& \0 \1 \` \\\' \+ \\\\ foo'
|
||||
"hello".gsub(/(.+)/) { repl }.should == repl
|
||||
end
|
||||
|
||||
it "converts the block's return value to a string using to_s" do
|
||||
replacement = mock('hello_replacement')
|
||||
def replacement.to_s() "hello_replacement" end
|
||||
|
||||
"hello".gsub(/hello/) { replacement }.should == "hello_replacement"
|
||||
|
||||
obj = mock('ok')
|
||||
def obj.to_s() "ok" end
|
||||
|
||||
"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
|
||||
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)
|
||||
end
|
||||
|
||||
it "replaces the incompatible part properly even if the encodings are not compatible" do
|
||||
s = "hllëllo"
|
||||
|
||||
s.gsub(/ë/) { |bar| "Русский".force_encoding("iso-8859-5") }.encoding.should == Encoding::ISO_8859_5
|
||||
end
|
||||
|
||||
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)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "String#gsub with pattern and without replacement and block" do
|
||||
it "returns an enumerator" do
|
||||
enum = "abca".gsub(/a/)
|
||||
enum.should be_an_instance_of(Enumerator)
|
||||
enum.to_a.should == ["a", "a"]
|
||||
end
|
||||
|
||||
describe "returned Enumerator" do
|
||||
describe "size" do
|
||||
it "should return nil" do
|
||||
"abca".gsub(/a/).size.should == nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "String#gsub! with pattern and replacement" do
|
||||
it "modifies self in place and returns self" do
|
||||
a = "hello"
|
||||
a.gsub!(/[aeiou]/, '*').should equal(a)
|
||||
a.should == "h*ll*"
|
||||
end
|
||||
|
||||
it "modifies self in place with multi-byte characters and returns self" do
|
||||
a = "¿por qué?"
|
||||
a.gsub!(/([a-z\d]*)/, "*").should equal(a)
|
||||
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
|
||||
a.gsub!(/z/, 'z').should == nil
|
||||
a.should == "hello"
|
||||
end
|
||||
|
||||
# See [ruby-core:23666]
|
||||
it "raises a RuntimeError 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)
|
||||
end
|
||||
end
|
||||
|
||||
describe "String#gsub! with pattern and block" do
|
||||
it "modifies self in place and returns self" do
|
||||
a = "hello"
|
||||
a.gsub!(/[aeiou]/) { '*' }.should equal(a)
|
||||
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
|
||||
a.gsub!(/z/) { 'z' }.should == nil
|
||||
a.should == "hello"
|
||||
end
|
||||
|
||||
# See [ruby-core:23663]
|
||||
it "raises a RuntimeError 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)
|
||||
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
|
||||
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)
|
||||
end
|
||||
|
||||
it "replaces the incompatible part properly even if the encodings are not compatible" do
|
||||
s = "hllëllo"
|
||||
|
||||
s.gsub!(/ë/) { |bar| "Русский".force_encoding("iso-8859-5") }.encoding.should == Encoding::ISO_8859_5
|
||||
end
|
||||
|
||||
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)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "String#gsub! with pattern and without replacement and block" do
|
||||
it "returns an enumerator" do
|
||||
enum = "abca".gsub!(/a/)
|
||||
enum.should be_an_instance_of(Enumerator)
|
||||
enum.to_a.should == ["a", "a"]
|
||||
end
|
||||
|
||||
describe "returned Enumerator" do
|
||||
describe "size" do
|
||||
it "should return nil" do
|
||||
"abca".gsub!(/a/).size.should == nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
9
spec/ruby/core/string/hash_spec.rb
Normal file
9
spec/ruby/core/string/hash_spec.rb
Normal file
|
@ -0,0 +1,9 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
describe "String#hash" do
|
||||
it "returns a hash based on a string's length and content" do
|
||||
"abc".hash.should == "abc".hash
|
||||
"abc".hash.should_not == "cba".hash
|
||||
end
|
||||
end
|
49
spec/ruby/core/string/hex_spec.rb
Normal file
49
spec/ruby/core/string/hex_spec.rb
Normal file
|
@ -0,0 +1,49 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
# TODO: Move actual results to String#to_int() and spec in terms of it
|
||||
describe "String#hex" do
|
||||
it "treats leading characters of self as a string of hex digits" do
|
||||
"0a".hex.should == 10
|
||||
"0o".hex.should == 0
|
||||
"0x".hex.should == 0
|
||||
"A_BAD_BABE".hex.should == 0xABADBABE
|
||||
"0b1010".hex.should == "b1010".hex
|
||||
"0d500".hex.should == "d500".hex
|
||||
"abcdefG".hex.should == 0xabcdef
|
||||
end
|
||||
|
||||
it "does not accept a sequence of underscores as part of a number" do
|
||||
"a__b".hex.should == 0xa
|
||||
"a____b".hex.should == 0xa
|
||||
"a___f".hex.should == 0xa
|
||||
end
|
||||
|
||||
it "takes an optional sign" do
|
||||
"-1234".hex.should == -4660
|
||||
"+1234".hex.should == 4660
|
||||
end
|
||||
|
||||
it "takes an optional 0x" do
|
||||
"0x0a".hex.should == 10
|
||||
"0a".hex.should == 10
|
||||
end
|
||||
|
||||
it "requires that the sign is in front of the 0x if present" do
|
||||
"-0x1".hex.should == -1
|
||||
"0x-1".hex.should == 0
|
||||
end
|
||||
|
||||
it "returns 0 on error" do
|
||||
"".hex.should == 0
|
||||
"+-5".hex.should == 0
|
||||
"wombat".hex.should == 0
|
||||
"0x0x42".hex.should == 0
|
||||
end
|
||||
|
||||
it "returns 0 if sequence begins with underscore" do
|
||||
"_a".hex.should == 0
|
||||
"___b".hex.should == 0
|
||||
"___0xc".hex.should == 0
|
||||
end
|
||||
end
|
28
spec/ruby/core/string/include_spec.rb
Normal file
28
spec/ruby/core/string/include_spec.rb
Normal file
|
@ -0,0 +1,28 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
describe "String#include? with String" do
|
||||
it "returns true if self contains other_str" do
|
||||
"hello".include?("lo").should == true
|
||||
"hello".include?("ol").should == false
|
||||
end
|
||||
|
||||
it "ignores subclass differences" do
|
||||
"hello".include?(StringSpecs::MyString.new("lo")).should == true
|
||||
StringSpecs::MyString.new("hello").include?("lo").should == true
|
||||
StringSpecs::MyString.new("hello").include?(StringSpecs::MyString.new("lo")).should == true
|
||||
end
|
||||
|
||||
it "tries to convert other to string using to_str" do
|
||||
other = mock('lo')
|
||||
other.should_receive(:to_str).and_return("lo")
|
||||
|
||||
"hello".include?(other).should == true
|
||||
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)
|
||||
end
|
||||
end
|
315
spec/ruby/core/string/index_spec.rb
Normal file
315
spec/ruby/core/string/index_spec.rb
Normal file
|
@ -0,0 +1,315 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
describe "String#index" do
|
||||
it "raises a TypeError if passed nil" do
|
||||
lambda { "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)
|
||||
end
|
||||
|
||||
it "raises a TypeError if passed a Symbol" do
|
||||
lambda { "abc".index :a }.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "calls #to_str to convert the first argument" do
|
||||
char = mock("string index char")
|
||||
char.should_receive(:to_str).and_return("b")
|
||||
"abc".index(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".index("c", offset).should == 2
|
||||
end
|
||||
|
||||
it "raises a TypeError if passed a Fixnum" do
|
||||
lambda { "abc".index 97 }.should raise_error(TypeError)
|
||||
end
|
||||
end
|
||||
|
||||
describe "String#index with String" do
|
||||
it "behaves the same as String#index(char) for one-character strings" do
|
||||
"blablabla hello cruel world...!".split("").uniq.each do |str|
|
||||
chr = str[0]
|
||||
str.index(str).should == str.index(chr)
|
||||
|
||||
0.upto(str.size + 1) do |start|
|
||||
str.index(str, start).should == str.index(chr, start)
|
||||
end
|
||||
|
||||
(-str.size - 1).upto(-1) do |start|
|
||||
str.index(str, start).should == str.index(chr, start)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "returns the index of the first occurrence of the given substring" do
|
||||
"blablabla".index("").should == 0
|
||||
"blablabla".index("b").should == 0
|
||||
"blablabla".index("bla").should == 0
|
||||
"blablabla".index("blabla").should == 0
|
||||
"blablabla".index("blablabla").should == 0
|
||||
|
||||
"blablabla".index("l").should == 1
|
||||
"blablabla".index("la").should == 1
|
||||
"blablabla".index("labla").should == 1
|
||||
"blablabla".index("lablabla").should == 1
|
||||
|
||||
"blablabla".index("a").should == 2
|
||||
"blablabla".index("abla").should == 2
|
||||
"blablabla".index("ablabla").should == 2
|
||||
end
|
||||
|
||||
it "doesn't set $~" do
|
||||
$~ = nil
|
||||
|
||||
'hello.'.index('ll')
|
||||
$~.should == nil
|
||||
end
|
||||
|
||||
it "ignores string subclasses" do
|
||||
"blablabla".index(StringSpecs::MyString.new("bla")).should == 0
|
||||
StringSpecs::MyString.new("blablabla").index("bla").should == 0
|
||||
StringSpecs::MyString.new("blablabla").index(StringSpecs::MyString.new("bla")).should == 0
|
||||
end
|
||||
|
||||
it "starts the search at the given offset" do
|
||||
"blablabla".index("bl", 0).should == 0
|
||||
"blablabla".index("bl", 1).should == 3
|
||||
"blablabla".index("bl", 2).should == 3
|
||||
"blablabla".index("bl", 3).should == 3
|
||||
|
||||
"blablabla".index("bla", 0).should == 0
|
||||
"blablabla".index("bla", 1).should == 3
|
||||
"blablabla".index("bla", 2).should == 3
|
||||
"blablabla".index("bla", 3).should == 3
|
||||
|
||||
"blablabla".index("blab", 0).should == 0
|
||||
"blablabla".index("blab", 1).should == 3
|
||||
"blablabla".index("blab", 2).should == 3
|
||||
"blablabla".index("blab", 3).should == 3
|
||||
|
||||
"blablabla".index("la", 1).should == 1
|
||||
"blablabla".index("la", 2).should == 4
|
||||
"blablabla".index("la", 3).should == 4
|
||||
"blablabla".index("la", 4).should == 4
|
||||
|
||||
"blablabla".index("lab", 1).should == 1
|
||||
"blablabla".index("lab", 2).should == 4
|
||||
"blablabla".index("lab", 3).should == 4
|
||||
"blablabla".index("lab", 4).should == 4
|
||||
|
||||
"blablabla".index("ab", 2).should == 2
|
||||
"blablabla".index("ab", 3).should == 5
|
||||
"blablabla".index("ab", 4).should == 5
|
||||
"blablabla".index("ab", 5).should == 5
|
||||
|
||||
"blablabla".index("", 0).should == 0
|
||||
"blablabla".index("", 1).should == 1
|
||||
"blablabla".index("", 2).should == 2
|
||||
"blablabla".index("", 7).should == 7
|
||||
"blablabla".index("", 8).should == 8
|
||||
"blablabla".index("", 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.index(needle, offset).should ==
|
||||
str.index(needle, offset + str.length)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "returns nil if the substring isn't found" do
|
||||
"blablabla".index("B").should == nil
|
||||
"blablabla".index("z").should == nil
|
||||
"blablabla".index("BLA").should == nil
|
||||
"blablabla".index("blablablabla").should == nil
|
||||
"blablabla".index("", 10).should == nil
|
||||
|
||||
"hello".index("he", 1).should == nil
|
||||
"hello".index("he", 2).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 after offset" do
|
||||
"われわれ".index("わ", 1).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
|
||||
end
|
||||
end
|
||||
|
||||
describe "String#index with Regexp" do
|
||||
it "behaves the same as String#index(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.index(regexp).should == str.index(needle)
|
||||
|
||||
0.upto(str.size + 1) do |start|
|
||||
str.index(regexp, start).should == str.index(needle, start)
|
||||
end
|
||||
|
||||
(-str.size - 1).upto(-1) do |start|
|
||||
str.index(regexp, start).should == str.index(needle, start)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "returns the index of the first match of regexp" do
|
||||
"blablabla".index(/bla/).should == 0
|
||||
"blablabla".index(/BLA/i).should == 0
|
||||
|
||||
"blablabla".index(/.{0}/).should == 0
|
||||
"blablabla".index(/.{6}/).should == 0
|
||||
"blablabla".index(/.{9}/).should == 0
|
||||
|
||||
"blablabla".index(/.*/).should == 0
|
||||
"blablabla".index(/.+/).should == 0
|
||||
|
||||
"blablabla".index(/lab|b/).should == 0
|
||||
|
||||
not_supported_on :opal do
|
||||
"blablabla".index(/\A/).should == 0
|
||||
"blablabla".index(/\Z/).should == 9
|
||||
"blablabla".index(/\z/).should == 9
|
||||
"blablabla\n".index(/\Z/).should == 9
|
||||
"blablabla\n".index(/\z/).should == 10
|
||||
end
|
||||
|
||||
"blablabla".index(/^/).should == 0
|
||||
"\nblablabla".index(/^/).should == 0
|
||||
"b\nablabla".index(/$/).should == 1
|
||||
"bl\nablabla".index(/$/).should == 2
|
||||
|
||||
"blablabla".index(/.l./).should == 0
|
||||
end
|
||||
|
||||
it "sets $~ to MatchData of match and nil when there's none" do
|
||||
'hello.'.index(/.(.)/)
|
||||
$~[0].should == 'he'
|
||||
|
||||
'hello.'.index(/not/)
|
||||
$~.should == nil
|
||||
end
|
||||
|
||||
it "starts the search at the given offset" do
|
||||
"blablabla".index(/.{0}/, 5).should == 5
|
||||
"blablabla".index(/.{1}/, 5).should == 5
|
||||
"blablabla".index(/.{2}/, 5).should == 5
|
||||
"blablabla".index(/.{3}/, 5).should == 5
|
||||
"blablabla".index(/.{4}/, 5).should == 5
|
||||
|
||||
"blablabla".index(/.{0}/, 3).should == 3
|
||||
"blablabla".index(/.{1}/, 3).should == 3
|
||||
"blablabla".index(/.{2}/, 3).should == 3
|
||||
"blablabla".index(/.{5}/, 3).should == 3
|
||||
"blablabla".index(/.{6}/, 3).should == 3
|
||||
|
||||
"blablabla".index(/.l./, 0).should == 0
|
||||
"blablabla".index(/.l./, 1).should == 3
|
||||
"blablabla".index(/.l./, 2).should == 3
|
||||
"blablabla".index(/.l./, 3).should == 3
|
||||
|
||||
"xblaxbla".index(/x./, 0).should == 0
|
||||
"xblaxbla".index(/x./, 1).should == 4
|
||||
"xblaxbla".index(/x./, 2).should == 4
|
||||
|
||||
not_supported_on :opal do
|
||||
"blablabla\n".index(/\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.index(needle, offset).should ==
|
||||
str.index(needle, offset + str.length)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "returns nil if the substring isn't found" do
|
||||
"blablabla".index(/BLA/).should == nil
|
||||
|
||||
"blablabla".index(/.{10}/).should == nil
|
||||
"blaxbla".index(/.x/, 3).should == nil
|
||||
"blaxbla".index(/..x/, 2).should == nil
|
||||
end
|
||||
|
||||
it "returns nil if the Regexp matches the empty string and the offset is out of range" do
|
||||
"ruby".index(//,12).should be_nil
|
||||
end
|
||||
|
||||
it "supports \\G which matches at the given start offset" do
|
||||
"helloYOU.".index(/\GYOU/, 5).should == 5
|
||||
"helloYOU.".index(/\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].index("#")
|
||||
str = spec[0].delete("#")
|
||||
|
||||
str.index(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".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 after offset" do
|
||||
"われわれ".index(/わ/, 1).should == 2
|
||||
end
|
||||
|
||||
it "treats the offset as a character index" do
|
||||
"われわわれ".index(/わ/, 3).should == 3
|
||||
end
|
||||
|
||||
it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
|
||||
re = Regexp.new "れ".encode(Encoding::EUC_JP)
|
||||
lambda do
|
||||
"あれ".index re
|
||||
end.should raise_error(Encoding::CompatibilityError)
|
||||
end
|
||||
end
|
||||
end
|
26
spec/ruby/core/string/initialize_spec.rb
Normal file
26
spec/ruby/core/string/initialize_spec.rb
Normal file
|
@ -0,0 +1,26 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
require File.expand_path('../shared/replace', __FILE__)
|
||||
|
||||
describe "String#initialize" do
|
||||
it "is a private method" do
|
||||
String.should have_private_instance_method(:initialize)
|
||||
end
|
||||
|
||||
describe "with no arguments" do
|
||||
it "does not change self" do
|
||||
s = "some string"
|
||||
s.send :initialize
|
||||
s.should == "some string"
|
||||
end
|
||||
|
||||
it "does not raise an exception when frozen" do
|
||||
a = "hello".freeze
|
||||
a.send(:initialize).should equal(a)
|
||||
end
|
||||
end
|
||||
|
||||
describe "with an argument" do
|
||||
it_behaves_like :string_replace, :initialize
|
||||
end
|
||||
end
|
84
spec/ruby/core/string/insert_spec.rb
Normal file
84
spec/ruby/core/string/insert_spec.rb
Normal file
|
@ -0,0 +1,84 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
|
||||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
describe "String#insert with index, other" do
|
||||
it "inserts other before the character at the given index" do
|
||||
"abcd".insert(0, 'X').should == "Xabcd"
|
||||
"abcd".insert(3, 'X').should == "abcXd"
|
||||
"abcd".insert(4, 'X').should == "abcdX"
|
||||
end
|
||||
|
||||
it "modifies self in place" do
|
||||
a = "abcd"
|
||||
a.insert(4, 'X').should == "abcdX"
|
||||
a.should == "abcdX"
|
||||
end
|
||||
|
||||
it "inserts after the given character on an negative count" do
|
||||
"abcd".insert(-5, 'X').should == "Xabcd"
|
||||
"abcd".insert(-3, 'X').should == "abXcd"
|
||||
"abcd".insert(-1, 'X').should == "abcdX"
|
||||
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)
|
||||
end
|
||||
|
||||
it "converts index to an integer using to_int" do
|
||||
other = mock('-3')
|
||||
other.should_receive(:to_int).and_return(-3)
|
||||
|
||||
"abcd".insert(other, "XYZ").should == "abXYZcd"
|
||||
end
|
||||
|
||||
it "converts other to a string using to_str" do
|
||||
other = mock('XYZ')
|
||||
other.should_receive(:to_str).and_return("XYZ")
|
||||
|
||||
"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)
|
||||
end
|
||||
|
||||
it "raises a RuntimeError 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)
|
||||
end
|
||||
|
||||
with_feature :encoding do
|
||||
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 "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)
|
||||
end
|
||||
end
|
||||
end
|
492
spec/ruby/core/string/inspect_spec.rb
Normal file
492
spec/ruby/core/string/inspect_spec.rb
Normal file
|
@ -0,0 +1,492 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
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
|
||||
|
||||
it "returns a string with special characters replaced with \\<char> notation" do
|
||||
[ ["\a", '"\\a"'],
|
||||
["\b", '"\\b"'],
|
||||
["\t", '"\\t"'],
|
||||
["\n", '"\\n"'],
|
||||
["\v", '"\\v"'],
|
||||
["\f", '"\\f"'],
|
||||
["\r", '"\\r"'],
|
||||
["\e", '"\\e"']
|
||||
].should be_computed_by(:inspect)
|
||||
end
|
||||
|
||||
it "returns a string with \" and \\ escaped with a backslash" do
|
||||
[ ["\"", '"\\""'],
|
||||
["\\", '"\\\\"']
|
||||
].should be_computed_by(:inspect)
|
||||
end
|
||||
|
||||
it "returns a string with \\#<char> when # is followed by $, @, {" do
|
||||
[ ["\#$", '"\\#$"'],
|
||||
["\#@", '"\\#@"'],
|
||||
["\#{", '"\\#{"']
|
||||
].should be_computed_by(:inspect)
|
||||
end
|
||||
|
||||
it "returns a string with # not escaped when followed by any other character" do
|
||||
[ ["#", '"#"'],
|
||||
["#1", '"#1"']
|
||||
].should be_computed_by(:inspect)
|
||||
end
|
||||
|
||||
it "returns a string with printable non-alphanumeric characters unescaped" do
|
||||
[ [" ", '" "'],
|
||||
["!", '"!"'],
|
||||
["$", '"$"'],
|
||||
["%", '"%"'],
|
||||
["&", '"&"'],
|
||||
["'", '"\'"'],
|
||||
["(", '"("'],
|
||||
[")", '")"'],
|
||||
["*", '"*"'],
|
||||
["+", '"+"'],
|
||||
[",", '","'],
|
||||
["-", '"-"'],
|
||||
[".", '"."'],
|
||||
["/", '"/"'],
|
||||
[":", '":"'],
|
||||
[";", '";"'],
|
||||
["<", '"<"'],
|
||||
["=", '"="'],
|
||||
[">", '">"'],
|
||||
["?", '"?"'],
|
||||
["@", '"@"'],
|
||||
["[", '"["'],
|
||||
["]", '"]"'],
|
||||
["^", '"^"'],
|
||||
["_", '"_"'],
|
||||
["`", '"`"'],
|
||||
["{", '"{"'],
|
||||
["|", '"|"'],
|
||||
["}", '"}"'],
|
||||
["~", '"~"']
|
||||
].should be_computed_by(:inspect)
|
||||
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(:inspect)
|
||||
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(:inspect)
|
||||
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(:inspect)
|
||||
end
|
||||
|
||||
it "returns a string with non-printing characters replaced by \\x notation" do
|
||||
# Avoid the file encoding by computing the string with #chr.
|
||||
[ [0001.chr, '"\\x01"'],
|
||||
[0002.chr, '"\\x02"'],
|
||||
[0003.chr, '"\\x03"'],
|
||||
[0004.chr, '"\\x04"'],
|
||||
[0005.chr, '"\\x05"'],
|
||||
[0006.chr, '"\\x06"'],
|
||||
[0016.chr, '"\\x0E"'],
|
||||
[0017.chr, '"\\x0F"'],
|
||||
[0020.chr, '"\\x10"'],
|
||||
[0021.chr, '"\\x11"'],
|
||||
[0022.chr, '"\\x12"'],
|
||||
[0023.chr, '"\\x13"'],
|
||||
[0024.chr, '"\\x14"'],
|
||||
[0025.chr, '"\\x15"'],
|
||||
[0026.chr, '"\\x16"'],
|
||||
[0027.chr, '"\\x17"'],
|
||||
[0030.chr, '"\\x18"'],
|
||||
[0031.chr, '"\\x19"'],
|
||||
[0032.chr, '"\\x1A"'],
|
||||
[0034.chr, '"\\x1C"'],
|
||||
[0035.chr, '"\\x1D"'],
|
||||
[0036.chr, '"\\x1E"'],
|
||||
[0037.chr, '"\\x1F"'],
|
||||
[0177.chr, '"\\x7F"'],
|
||||
[0200.chr, '"\\x80"'],
|
||||
[0201.chr, '"\\x81"'],
|
||||
[0202.chr, '"\\x82"'],
|
||||
[0203.chr, '"\\x83"'],
|
||||
[0204.chr, '"\\x84"'],
|
||||
[0205.chr, '"\\x85"'],
|
||||
[0206.chr, '"\\x86"'],
|
||||
[0207.chr, '"\\x87"'],
|
||||
[0210.chr, '"\\x88"'],
|
||||
[0211.chr, '"\\x89"'],
|
||||
[0212.chr, '"\\x8A"'],
|
||||
[0213.chr, '"\\x8B"'],
|
||||
[0214.chr, '"\\x8C"'],
|
||||
[0215.chr, '"\\x8D"'],
|
||||
[0216.chr, '"\\x8E"'],
|
||||
[0217.chr, '"\\x8F"'],
|
||||
[0220.chr, '"\\x90"'],
|
||||
[0221.chr, '"\\x91"'],
|
||||
[0222.chr, '"\\x92"'],
|
||||
[0223.chr, '"\\x93"'],
|
||||
[0224.chr, '"\\x94"'],
|
||||
[0225.chr, '"\\x95"'],
|
||||
[0226.chr, '"\\x96"'],
|
||||
[0227.chr, '"\\x97"'],
|
||||
[0230.chr, '"\\x98"'],
|
||||
[0231.chr, '"\\x99"'],
|
||||
[0232.chr, '"\\x9A"'],
|
||||
[0233.chr, '"\\x9B"'],
|
||||
[0234.chr, '"\\x9C"'],
|
||||
[0235.chr, '"\\x9D"'],
|
||||
[0236.chr, '"\\x9E"'],
|
||||
[0237.chr, '"\\x9F"'],
|
||||
[0240.chr, '"\\xA0"'],
|
||||
[0241.chr, '"\\xA1"'],
|
||||
[0242.chr, '"\\xA2"'],
|
||||
[0243.chr, '"\\xA3"'],
|
||||
[0244.chr, '"\\xA4"'],
|
||||
[0245.chr, '"\\xA5"'],
|
||||
[0246.chr, '"\\xA6"'],
|
||||
[0247.chr, '"\\xA7"'],
|
||||
[0250.chr, '"\\xA8"'],
|
||||
[0251.chr, '"\\xA9"'],
|
||||
[0252.chr, '"\\xAA"'],
|
||||
[0253.chr, '"\\xAB"'],
|
||||
[0254.chr, '"\\xAC"'],
|
||||
[0255.chr, '"\\xAD"'],
|
||||
[0256.chr, '"\\xAE"'],
|
||||
[0257.chr, '"\\xAF"'],
|
||||
[0260.chr, '"\\xB0"'],
|
||||
[0261.chr, '"\\xB1"'],
|
||||
[0262.chr, '"\\xB2"'],
|
||||
[0263.chr, '"\\xB3"'],
|
||||
[0264.chr, '"\\xB4"'],
|
||||
[0265.chr, '"\\xB5"'],
|
||||
[0266.chr, '"\\xB6"'],
|
||||
[0267.chr, '"\\xB7"'],
|
||||
[0270.chr, '"\\xB8"'],
|
||||
[0271.chr, '"\\xB9"'],
|
||||
[0272.chr, '"\\xBA"'],
|
||||
[0273.chr, '"\\xBB"'],
|
||||
[0274.chr, '"\\xBC"'],
|
||||
[0275.chr, '"\\xBD"'],
|
||||
[0276.chr, '"\\xBE"'],
|
||||
[0277.chr, '"\\xBF"'],
|
||||
[0300.chr, '"\\xC0"'],
|
||||
[0301.chr, '"\\xC1"'],
|
||||
[0302.chr, '"\\xC2"'],
|
||||
[0303.chr, '"\\xC3"'],
|
||||
[0304.chr, '"\\xC4"'],
|
||||
[0305.chr, '"\\xC5"'],
|
||||
[0306.chr, '"\\xC6"'],
|
||||
[0307.chr, '"\\xC7"'],
|
||||
[0310.chr, '"\\xC8"'],
|
||||
[0311.chr, '"\\xC9"'],
|
||||
[0312.chr, '"\\xCA"'],
|
||||
[0313.chr, '"\\xCB"'],
|
||||
[0314.chr, '"\\xCC"'],
|
||||
[0315.chr, '"\\xCD"'],
|
||||
[0316.chr, '"\\xCE"'],
|
||||
[0317.chr, '"\\xCF"'],
|
||||
[0320.chr, '"\\xD0"'],
|
||||
[0321.chr, '"\\xD1"'],
|
||||
[0322.chr, '"\\xD2"'],
|
||||
[0323.chr, '"\\xD3"'],
|
||||
[0324.chr, '"\\xD4"'],
|
||||
[0325.chr, '"\\xD5"'],
|
||||
[0326.chr, '"\\xD6"'],
|
||||
[0327.chr, '"\\xD7"'],
|
||||
[0330.chr, '"\\xD8"'],
|
||||
[0331.chr, '"\\xD9"'],
|
||||
[0332.chr, '"\\xDA"'],
|
||||
[0333.chr, '"\\xDB"'],
|
||||
[0334.chr, '"\\xDC"'],
|
||||
[0335.chr, '"\\xDD"'],
|
||||
[0336.chr, '"\\xDE"'],
|
||||
[0337.chr, '"\\xDF"'],
|
||||
[0340.chr, '"\\xE0"'],
|
||||
[0341.chr, '"\\xE1"'],
|
||||
[0342.chr, '"\\xE2"'],
|
||||
[0343.chr, '"\\xE3"'],
|
||||
[0344.chr, '"\\xE4"'],
|
||||
[0345.chr, '"\\xE5"'],
|
||||
[0346.chr, '"\\xE6"'],
|
||||
[0347.chr, '"\\xE7"'],
|
||||
[0350.chr, '"\\xE8"'],
|
||||
[0351.chr, '"\\xE9"'],
|
||||
[0352.chr, '"\\xEA"'],
|
||||
[0353.chr, '"\\xEB"'],
|
||||
[0354.chr, '"\\xEC"'],
|
||||
[0355.chr, '"\\xED"'],
|
||||
[0356.chr, '"\\xEE"'],
|
||||
[0357.chr, '"\\xEF"'],
|
||||
[0360.chr, '"\\xF0"'],
|
||||
[0361.chr, '"\\xF1"'],
|
||||
[0362.chr, '"\\xF2"'],
|
||||
[0363.chr, '"\\xF3"'],
|
||||
[0364.chr, '"\\xF4"'],
|
||||
[0365.chr, '"\\xF5"'],
|
||||
[0366.chr, '"\\xF6"'],
|
||||
[0367.chr, '"\\xF7"'],
|
||||
[0370.chr, '"\\xF8"'],
|
||||
[0371.chr, '"\\xF9"'],
|
||||
[0372.chr, '"\\xFA"'],
|
||||
[0373.chr, '"\\xFB"'],
|
||||
[0374.chr, '"\\xFC"'],
|
||||
[0375.chr, '"\\xFD"'],
|
||||
[0376.chr, '"\\xFE"'],
|
||||
[0377.chr, '"\\xFF"']
|
||||
].should be_computed_by(:inspect)
|
||||
end
|
||||
|
||||
it "returns a string with a NUL character replaced by \\x notation" do
|
||||
0.chr.inspect.should == '"\\x00"'
|
||||
end
|
||||
|
||||
describe "when default external is UTF-8" do
|
||||
before :each do
|
||||
@extenc, Encoding.default_external = Encoding.default_external, Encoding::UTF_8
|
||||
end
|
||||
|
||||
after :each do
|
||||
Encoding.default_external = @extenc
|
||||
end
|
||||
|
||||
it "returns a string with non-printing characters replaced by \\u notation for Unicode strings" do
|
||||
[ [0001.chr('utf-8'), '"\u0001"'],
|
||||
[0002.chr('utf-8'), '"\u0002"'],
|
||||
[0003.chr('utf-8'), '"\u0003"'],
|
||||
[0004.chr('utf-8'), '"\u0004"'],
|
||||
[0005.chr('utf-8'), '"\u0005"'],
|
||||
[0006.chr('utf-8'), '"\u0006"'],
|
||||
[0016.chr('utf-8'), '"\u000E"'],
|
||||
[0017.chr('utf-8'), '"\u000F"'],
|
||||
[0020.chr('utf-8'), '"\u0010"'],
|
||||
[0021.chr('utf-8'), '"\u0011"'],
|
||||
[0022.chr('utf-8'), '"\u0012"'],
|
||||
[0023.chr('utf-8'), '"\u0013"'],
|
||||
[0024.chr('utf-8'), '"\u0014"'],
|
||||
[0025.chr('utf-8'), '"\u0015"'],
|
||||
[0026.chr('utf-8'), '"\u0016"'],
|
||||
[0027.chr('utf-8'), '"\u0017"'],
|
||||
[0030.chr('utf-8'), '"\u0018"'],
|
||||
[0031.chr('utf-8'), '"\u0019"'],
|
||||
[0032.chr('utf-8'), '"\u001A"'],
|
||||
[0034.chr('utf-8'), '"\u001C"'],
|
||||
[0035.chr('utf-8'), '"\u001D"'],
|
||||
[0036.chr('utf-8'), '"\u001E"'],
|
||||
[0037.chr('utf-8'), '"\u001F"'],
|
||||
[0177.chr('utf-8'), '"\u007F"'],
|
||||
[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(:inspect)
|
||||
end
|
||||
|
||||
it "returns a string with a NUL character replaced by \\u notation" do
|
||||
0.chr('utf-8').inspect.should == '"\\u0000"'
|
||||
end
|
||||
|
||||
it "returns a string with extended characters for Unicode strings" do
|
||||
[ [0240.chr('utf-8'), '" "'],
|
||||
[0241.chr('utf-8'), '"¡"'],
|
||||
[0242.chr('utf-8'), '"¢"'],
|
||||
[0243.chr('utf-8'), '"£"'],
|
||||
[0244.chr('utf-8'), '"¤"'],
|
||||
[0245.chr('utf-8'), '"¥"'],
|
||||
[0246.chr('utf-8'), '"¦"'],
|
||||
[0247.chr('utf-8'), '"§"'],
|
||||
[0250.chr('utf-8'), '"¨"'],
|
||||
[0251.chr('utf-8'), '"©"'],
|
||||
[0252.chr('utf-8'), '"ª"'],
|
||||
[0253.chr('utf-8'), '"«"'],
|
||||
[0254.chr('utf-8'), '"¬"'],
|
||||
[0255.chr('utf-8'), '""'],
|
||||
[0256.chr('utf-8'), '"®"'],
|
||||
[0257.chr('utf-8'), '"¯"'],
|
||||
[0260.chr('utf-8'), '"°"'],
|
||||
[0261.chr('utf-8'), '"±"'],
|
||||
[0262.chr('utf-8'), '"²"'],
|
||||
[0263.chr('utf-8'), '"³"'],
|
||||
[0264.chr('utf-8'), '"´"'],
|
||||
[0265.chr('utf-8'), '"µ"'],
|
||||
[0266.chr('utf-8'), '"¶"'],
|
||||
[0267.chr('utf-8'), '"·"'],
|
||||
[0270.chr('utf-8'), '"¸"'],
|
||||
[0271.chr('utf-8'), '"¹"'],
|
||||
[0272.chr('utf-8'), '"º"'],
|
||||
[0273.chr('utf-8'), '"»"'],
|
||||
[0274.chr('utf-8'), '"¼"'],
|
||||
[0275.chr('utf-8'), '"½"'],
|
||||
[0276.chr('utf-8'), '"¾"'],
|
||||
[0277.chr('utf-8'), '"¿"'],
|
||||
[0300.chr('utf-8'), '"À"'],
|
||||
[0301.chr('utf-8'), '"Á"'],
|
||||
[0302.chr('utf-8'), '"Â"'],
|
||||
[0303.chr('utf-8'), '"Ã"'],
|
||||
[0304.chr('utf-8'), '"Ä"'],
|
||||
[0305.chr('utf-8'), '"Å"'],
|
||||
[0306.chr('utf-8'), '"Æ"'],
|
||||
[0307.chr('utf-8'), '"Ç"'],
|
||||
[0310.chr('utf-8'), '"È"'],
|
||||
[0311.chr('utf-8'), '"É"'],
|
||||
[0312.chr('utf-8'), '"Ê"'],
|
||||
[0313.chr('utf-8'), '"Ë"'],
|
||||
[0314.chr('utf-8'), '"Ì"'],
|
||||
[0315.chr('utf-8'), '"Í"'],
|
||||
[0316.chr('utf-8'), '"Î"'],
|
||||
[0317.chr('utf-8'), '"Ï"'],
|
||||
[0320.chr('utf-8'), '"Ð"'],
|
||||
[0321.chr('utf-8'), '"Ñ"'],
|
||||
[0322.chr('utf-8'), '"Ò"'],
|
||||
[0323.chr('utf-8'), '"Ó"'],
|
||||
[0324.chr('utf-8'), '"Ô"'],
|
||||
[0325.chr('utf-8'), '"Õ"'],
|
||||
[0326.chr('utf-8'), '"Ö"'],
|
||||
[0327.chr('utf-8'), '"×"'],
|
||||
[0330.chr('utf-8'), '"Ø"'],
|
||||
[0331.chr('utf-8'), '"Ù"'],
|
||||
[0332.chr('utf-8'), '"Ú"'],
|
||||
[0333.chr('utf-8'), '"Û"'],
|
||||
[0334.chr('utf-8'), '"Ü"'],
|
||||
[0335.chr('utf-8'), '"Ý"'],
|
||||
[0336.chr('utf-8'), '"Þ"'],
|
||||
[0337.chr('utf-8'), '"ß"'],
|
||||
[0340.chr('utf-8'), '"à"'],
|
||||
[0341.chr('utf-8'), '"á"'],
|
||||
[0342.chr('utf-8'), '"â"'],
|
||||
[0343.chr('utf-8'), '"ã"'],
|
||||
[0344.chr('utf-8'), '"ä"'],
|
||||
[0345.chr('utf-8'), '"å"'],
|
||||
[0346.chr('utf-8'), '"æ"'],
|
||||
[0347.chr('utf-8'), '"ç"'],
|
||||
[0350.chr('utf-8'), '"è"'],
|
||||
[0351.chr('utf-8'), '"é"'],
|
||||
[0352.chr('utf-8'), '"ê"'],
|
||||
[0353.chr('utf-8'), '"ë"'],
|
||||
[0354.chr('utf-8'), '"ì"'],
|
||||
[0355.chr('utf-8'), '"í"'],
|
||||
[0356.chr('utf-8'), '"î"'],
|
||||
[0357.chr('utf-8'), '"ï"'],
|
||||
[0360.chr('utf-8'), '"ð"'],
|
||||
[0361.chr('utf-8'), '"ñ"'],
|
||||
[0362.chr('utf-8'), '"ò"'],
|
||||
[0363.chr('utf-8'), '"ó"'],
|
||||
[0364.chr('utf-8'), '"ô"'],
|
||||
[0365.chr('utf-8'), '"õ"'],
|
||||
[0366.chr('utf-8'), '"ö"'],
|
||||
[0367.chr('utf-8'), '"÷"'],
|
||||
[0370.chr('utf-8'), '"ø"'],
|
||||
[0371.chr('utf-8'), '"ù"'],
|
||||
[0372.chr('utf-8'), '"ú"'],
|
||||
[0373.chr('utf-8'), '"û"'],
|
||||
[0374.chr('utf-8'), '"ü"'],
|
||||
[0375.chr('utf-8'), '"ý"'],
|
||||
[0376.chr('utf-8'), '"þ"'],
|
||||
[0377.chr('utf-8'), '"ÿ"']
|
||||
].should be_computed_by(:inspect)
|
||||
end
|
||||
end
|
||||
end
|
7
spec/ruby/core/string/intern_spec.rb
Normal file
7
spec/ruby/core/string/intern_spec.rb
Normal file
|
@ -0,0 +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__)
|
||||
|
||||
describe "String#intern" do
|
||||
it_behaves_like(:string_to_sym, :intern)
|
||||
end
|
7
spec/ruby/core/string/length_spec.rb
Normal file
7
spec/ruby/core/string/length_spec.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
require File.expand_path('../shared/length', __FILE__)
|
||||
|
||||
describe "String#length" do
|
||||
it_behaves_like(:string_length, :length)
|
||||
end
|
13
spec/ruby/core/string/lines_spec.rb
Normal file
13
spec/ruby/core/string/lines_spec.rb
Normal file
|
@ -0,0 +1,13 @@
|
|||
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__)
|
||||
|
||||
describe "String#lines" do
|
||||
it_behaves_like(:string_each_line, :lines)
|
||||
|
||||
it "returns an array when no block given" do
|
||||
ary = "hello world".send(@method, ' ')
|
||||
ary.should == ["hello ", "world"]
|
||||
end
|
||||
end
|
116
spec/ruby/core/string/ljust_spec.rb
Normal file
116
spec/ruby/core/string/ljust_spec.rb
Normal file
|
@ -0,0 +1,116 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
describe "String#ljust with length, padding" do
|
||||
it "returns a new string of specified length with self left justified and padded with padstr" do
|
||||
"hello".ljust(20, '1234').should == "hello123412341234123"
|
||||
|
||||
"".ljust(1, "abcd").should == "a"
|
||||
"".ljust(2, "abcd").should == "ab"
|
||||
"".ljust(3, "abcd").should == "abc"
|
||||
"".ljust(4, "abcd").should == "abcd"
|
||||
"".ljust(6, "abcd").should == "abcdab"
|
||||
|
||||
"OK".ljust(3, "abcd").should == "OKa"
|
||||
"OK".ljust(4, "abcd").should == "OKab"
|
||||
"OK".ljust(6, "abcd").should == "OKabcd"
|
||||
"OK".ljust(8, "abcd").should == "OKabcdab"
|
||||
end
|
||||
|
||||
it "pads with whitespace if no padstr is given" do
|
||||
"hello".ljust(20).should == "hello "
|
||||
end
|
||||
|
||||
it "returns self if it's longer than or as long as the specified length" do
|
||||
"".ljust(0).should == ""
|
||||
"".ljust(-1).should == ""
|
||||
"hello".ljust(4).should == "hello"
|
||||
"hello".ljust(-1).should == "hello"
|
||||
"this".ljust(3).should == "this"
|
||||
"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 == "^_^"
|
||||
|
||||
obj = mock('3')
|
||||
obj.should_receive(:to_int).and_return(3)
|
||||
|
||||
"o".ljust(obj, "_o").should == "o_o"
|
||||
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)
|
||||
end
|
||||
|
||||
it "tries to convert padstr to a string using to_str" do
|
||||
padstr = mock('123')
|
||||
padstr.should_receive(:to_str).and_return("123")
|
||||
|
||||
"hello".ljust(10, padstr).should == "hello12312"
|
||||
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)
|
||||
end
|
||||
|
||||
it "raises an ArgumentError when padstr is empty" do
|
||||
lambda { "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)
|
||||
|
||||
"".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
|
||||
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
|
||||
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
|
||||
end
|
||||
end
|
||||
end
|
50
spec/ruby/core/string/lstrip_spec.rb
Normal file
50
spec/ruby/core/string/lstrip_spec.rb
Normal file
|
@ -0,0 +1,50 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
describe "String#lstrip" do
|
||||
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"
|
||||
end
|
||||
|
||||
it "does not strip leading \\0" do
|
||||
"\x00hello".lstrip.should == "\x00hello"
|
||||
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
|
||||
end
|
||||
end
|
||||
|
||||
describe "String#lstrip!" do
|
||||
it "modifies self in place and returns self" 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
|
||||
a = "hello"
|
||||
a.lstrip!.should == nil
|
||||
a.should == "hello"
|
||||
end
|
||||
|
||||
it "raises a RuntimeError on a frozen instance that is modified" do
|
||||
lambda { " hello ".freeze.lstrip! }.should raise_error(RuntimeError)
|
||||
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)
|
||||
end
|
||||
end
|
175
spec/ruby/core/string/match_spec.rb
Normal file
175
spec/ruby/core/string/match_spec.rb
Normal file
|
@ -0,0 +1,175 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
describe :string_match_escaped_literal, shared: true do
|
||||
not_supported_on :opal do
|
||||
it "matches a literal Regexp that uses ASCII-only UTF-8 escape sequences" do
|
||||
"a b".match(/([\u{20}-\u{7e}])/)[0].should == "a"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "String#=~" do
|
||||
it "behaves the same way as index() when given a regexp" do
|
||||
("rudder" =~ /udder/).should == "rudder".index(/udder/)
|
||||
("boat" =~ /[^fl]oat/).should == "boat".index(/[^fl]oat/)
|
||||
("bean" =~ /bag/).should == "bean".index(/bag/)
|
||||
("true" =~ /false/).should == "true".index(/false/)
|
||||
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)
|
||||
end
|
||||
|
||||
it "invokes obj.=~ with self if obj is neither a string nor regexp" do
|
||||
str = "w00t"
|
||||
obj = mock('x')
|
||||
|
||||
obj.should_receive(:=~).with(str).any_number_of_times.and_return(true)
|
||||
str.should =~ obj
|
||||
|
||||
obj = mock('y')
|
||||
obj.should_receive(:=~).with(str).any_number_of_times.and_return(false)
|
||||
str.should_not =~ obj
|
||||
end
|
||||
|
||||
it "sets $~ to MatchData when there is a match and nil when there's none" do
|
||||
'hello' =~ /./
|
||||
$~[0].should == 'h'
|
||||
|
||||
'hello' =~ /not/
|
||||
$~.should == nil
|
||||
end
|
||||
|
||||
with_feature :encoding do
|
||||
it "returns the character index of a found match" do
|
||||
("こにちわ" =~ /に/).should == 1
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe "String#match" do
|
||||
it "matches the pattern against self" do
|
||||
'hello'.match(/(.)\1/)[0].should == 'll'
|
||||
end
|
||||
|
||||
it_behaves_like :string_match_escaped_literal, :match
|
||||
|
||||
describe "with [pattern, position]" do
|
||||
describe "when given a positive position" do
|
||||
it "matches the pattern against self starting at an optional index" 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
|
||||
end
|
||||
end
|
||||
|
||||
describe "when given a negative position" do
|
||||
it "matches the pattern against self starting at an optional index" 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
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "when passed a block" do
|
||||
it "yields the MatchData" do
|
||||
"abc".match(/./) {|m| ScratchPad.record m }
|
||||
ScratchPad.recorded.should be_kind_of(MatchData)
|
||||
end
|
||||
|
||||
it "returns the block result" do
|
||||
"abc".match(/./) { :result }.should == :result
|
||||
end
|
||||
|
||||
it "does not yield if there is no match" do
|
||||
ScratchPad.record []
|
||||
"b".match(/a/) {|m| ScratchPad << m }
|
||||
ScratchPad.recorded.should == []
|
||||
end
|
||||
end
|
||||
|
||||
it "tries to convert pattern to a string via to_str" do
|
||||
obj = mock('.')
|
||||
def obj.to_str() "." end
|
||||
"hello".match(obj)[0].should == "h"
|
||||
|
||||
obj = mock('.')
|
||||
def obj.respond_to?(type, *) true end
|
||||
def obj.method_missing(*args) "." end
|
||||
"hello".match(obj)[0].should == "h"
|
||||
end
|
||||
|
||||
it "raises a TypeError if pattern is not a regexp or a string" do
|
||||
lambda { 'hello'.match(10) }.should raise_error(TypeError)
|
||||
not_supported_on :opal do
|
||||
lambda { 'hello'.match(:ell) }.should raise_error(TypeError)
|
||||
end
|
||||
end
|
||||
|
||||
it "converts string patterns to regexps without escaping" do
|
||||
'hello'.match('(.)\1')[0].should == 'll'
|
||||
end
|
||||
|
||||
it "returns nil if there's no match" do
|
||||
'hello'.match('xx').should == nil
|
||||
end
|
||||
|
||||
it "matches \\G at the start of the string" do
|
||||
'hello'.match(/\Gh/)[0].should == 'h'
|
||||
'hello'.match(/\Go/).should == nil
|
||||
end
|
||||
|
||||
it "sets $~ to MatchData of match or nil when there is none" do
|
||||
'hello'.match(/./)
|
||||
$~[0].should == 'h'
|
||||
Regexp.last_match[0].should == 'h'
|
||||
|
||||
'hello'.match(/X/)
|
||||
$~.should == nil
|
||||
Regexp.last_match.should == nil
|
||||
end
|
||||
|
||||
it "calls match on the regular expression" do
|
||||
regexp = /./
|
||||
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
|
||||
|
||||
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 "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
|
||||
end
|
789
spec/ruby/core/string/modulo_spec.rb
Normal file
789
spec/ruby/core/string/modulo_spec.rb
Normal file
|
@ -0,0 +1,789 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
describe "String#%" do
|
||||
it "formats multiple expressions" do
|
||||
("%b %x %d %s" % [10, 10, 10, 10]).should == "1010 a 10 10"
|
||||
end
|
||||
|
||||
it "formats expressions mid string" do
|
||||
("hello %s!" % "world").should == "hello world!"
|
||||
end
|
||||
|
||||
it "formats %% into %" 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%"
|
||||
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)
|
||||
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"
|
||||
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"
|
||||
end
|
||||
|
||||
it "raises an error if single % appears anywhere else" do
|
||||
lambda { (" % " % []) }.should raise_error(ArgumentError)
|
||||
lambda { ("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
|
||||
|
||||
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
|
||||
end
|
||||
end
|
||||
|
||||
it "ignores unused arguments when $DEBUG is false" do
|
||||
begin
|
||||
old_debug = $DEBUG
|
||||
$DEBUG = false
|
||||
|
||||
("" % [1, 2, 3]).should == ""
|
||||
("%s" % [1, 2, 3]).should == "1"
|
||||
ensure
|
||||
$DEBUG = old_debug
|
||||
end
|
||||
end
|
||||
|
||||
it "raises an ArgumentError for unused arguments when $DEBUG is true" do
|
||||
begin
|
||||
old_debug = $DEBUG
|
||||
$DEBUG = true
|
||||
s = $stderr
|
||||
$stderr = IOStub.new
|
||||
|
||||
lambda { "" % [1, 2, 3] }.should raise_error(ArgumentError)
|
||||
lambda { "%s" % [1, 2, 3] }.should raise_error(ArgumentError)
|
||||
ensure
|
||||
$DEBUG = old_debug
|
||||
$stderr = s
|
||||
end
|
||||
end
|
||||
|
||||
it "always allows unused arguments when positional argument style is used" do
|
||||
begin
|
||||
old_debug = $DEBUG
|
||||
$DEBUG = false
|
||||
|
||||
("%2$s" % [1, 2, 3]).should == "2"
|
||||
$DEBUG = true
|
||||
("%2$s" % [1, 2, 3]).should == "2"
|
||||
ensure
|
||||
$DEBUG = old_debug
|
||||
end
|
||||
end
|
||||
|
||||
it "replaces trailing absolute argument specifier without type with percent sign" do
|
||||
("hello %1$" % "foo").should == "hello %"
|
||||
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)
|
||||
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)
|
||||
end
|
||||
|
||||
it "respects positional arguments and precision tokens given for one format specifier" do
|
||||
("%2$1d" % [1, 0]).should == "0"
|
||||
("%2$1d" % [0, 1]).should == "1"
|
||||
|
||||
("%2$.2f" % [1, 0]).should == "0.00"
|
||||
("%2$.2f" % [0, 1]).should == "1.00"
|
||||
end
|
||||
|
||||
it "allows more than one digit of position" do
|
||||
("%50$d" % (0..100).to_a).should == "49"
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
|
||||
lambda { "%s %2$s" % ["foo", "bar"] }.should raise_error(ArgumentError)
|
||||
lambda { "%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)
|
||||
end
|
||||
|
||||
it "allows reuse of the one argument multiple via absolute argument numbers" do
|
||||
("%1$s %1$s" % "foo").should == "foo foo"
|
||||
("%1$s %2$s %1$s %2$s" % ["foo", "bar"]).should == "foo bar foo bar"
|
||||
end
|
||||
|
||||
it "always interprets an array argument as a list of argument parameters" do
|
||||
lambda { "%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[1]).should == "1"
|
||||
("%p %p" % StringSpecs::MyArray[1, 2]).should == "1 2"
|
||||
end
|
||||
|
||||
it "allows positional arguments for width star and precision star arguments" do
|
||||
("%*1$.*2$3$d" % [10, 5, 1]).should == " 00001"
|
||||
end
|
||||
|
||||
it "allows negative width to imply '-' flag" do
|
||||
("%*1$.*2$3$d" % [-10, 5, 1]).should == "00001 "
|
||||
("%-*1$.*2$3$d" % [10, 5, 1]).should == "00001 "
|
||||
("%-*1$.*2$3$d" % [-10, 5, 1]).should == "00001 "
|
||||
end
|
||||
|
||||
it "ignores negative precision" do
|
||||
("%*1$.*2$3$d" % [10, -5, 1]).should == " 1"
|
||||
end
|
||||
|
||||
it "allows a star to take an argument number to use as the width" do
|
||||
("%1$*2$s" % ["a", 8]).should == " a"
|
||||
("%1$*10$s" % ["a",0,0,0,0,0,0,0,0,8]).should == " a"
|
||||
end
|
||||
|
||||
it "calls to_int on width star and precision star tokens" do
|
||||
w = mock('10')
|
||||
w.should_receive(:to_int).and_return(10)
|
||||
|
||||
p = mock('5')
|
||||
p.should_receive(:to_int).and_return(5)
|
||||
|
||||
("%*.*f" % [w, p, 1]).should == " 1.00000"
|
||||
|
||||
|
||||
w = mock('10')
|
||||
w.should_receive(:to_int).and_return(10)
|
||||
|
||||
p = mock('5')
|
||||
p.should_receive(:to_int).and_return(5)
|
||||
|
||||
("%*.*d" % [w, p, 1]).should == " 00001"
|
||||
end
|
||||
|
||||
it "does not call #to_a to convert the argument" do
|
||||
x = mock("string modulo to_a")
|
||||
x.should_not_receive(:to_a)
|
||||
x.should_receive(:to_s).and_return("x")
|
||||
|
||||
("%s" % x).should == "x"
|
||||
end
|
||||
|
||||
it "calls #to_ary to convert the argument" do
|
||||
x = mock("string modulo to_ary")
|
||||
x.should_not_receive(:to_s)
|
||||
x.should_receive(:to_ary).and_return(["x"])
|
||||
|
||||
("%s" % x).should == "x"
|
||||
end
|
||||
|
||||
it "wraps the object in an Array if #to_ary returns nil" do
|
||||
x = mock("string modulo to_ary")
|
||||
x.should_receive(:to_ary).and_return(nil)
|
||||
x.should_receive(:to_s).and_return("x")
|
||||
|
||||
("%s" % x).should == "x"
|
||||
end
|
||||
|
||||
it "raises a TypeError if #to_ary does not return an Array" do
|
||||
x = mock("string modulo to_ary")
|
||||
x.should_receive(:to_ary).and_return("x")
|
||||
|
||||
lambda { "%s" % x }.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "tries to convert the argument to Array by calling #to_ary" do
|
||||
obj = mock('[1,2]')
|
||||
def obj.to_ary() [1, 2] end
|
||||
def obj.to_s() "obj" end
|
||||
("%s %s" % obj).should == "1 2"
|
||||
("%s" % obj).should == "1"
|
||||
end
|
||||
|
||||
it "doesn't return subclass instances when called on a subclass" 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|
|
||||
(StringSpecs::MyString.new(format) % universal).should be_an_instance_of(String)
|
||||
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"
|
||||
("%1$b" % [10, 20]).should == "1010"
|
||||
("%#b" % 10).should == "0b1010"
|
||||
("%+b" % 10).should == "+1010"
|
||||
("%-9b" % 10).should == "1010 "
|
||||
("%05b" % 10).should == "01010"
|
||||
("%*b" % [10, 6]).should == " 110"
|
||||
("%*b" % [-10, 6]).should == "110 "
|
||||
("%.4b" % 2).should == "0010"
|
||||
("%.32b" % 2147483648).should == "10000000000000000000000000000000"
|
||||
end
|
||||
|
||||
it "supports binary formats using %b for negative numbers" do
|
||||
("%b" % -5).should == "..1011"
|
||||
("%0b" % -5).should == "..1011"
|
||||
("%.1b" % -5).should == "..1011"
|
||||
("%.7b" % -5).should == "..11011"
|
||||
("%.10b" % -5).should == "..11111011"
|
||||
("% b" % -5).should == "-101"
|
||||
("%+b" % -5).should == "-101"
|
||||
not_supported_on :opal do
|
||||
("%b" % -(2 ** 64 + 5)).should ==
|
||||
"..101111111111111111111111111111111111111111111111111111111111111011"
|
||||
end
|
||||
end
|
||||
|
||||
it "supports binary formats using %B with same behaviour as %b except for using 0B instead of 0b for #" do
|
||||
("%B" % 10).should == ("%b" % 10)
|
||||
("% B" % 10).should == ("% b" % 10)
|
||||
("%1$B" % [10, 20]).should == ("%1$b" % [10, 20])
|
||||
("%+B" % 10).should == ("%+b" % 10)
|
||||
("%-9B" % 10).should == ("%-9b" % 10)
|
||||
("%05B" % 10).should == ("%05b" % 10)
|
||||
("%*B" % [10, 6]).should == ("%*b" % [10, 6])
|
||||
("%*B" % [-10, 6]).should == ("%*b" % [-10, 6])
|
||||
|
||||
("%B" % -5).should == ("%b" % -5)
|
||||
("%0B" % -5).should == ("%0b" % -5)
|
||||
("%.1B" % -5).should == ("%.1b" % -5)
|
||||
("%.7B" % -5).should == ("%.7b" % -5)
|
||||
("%.10B" % -5).should == ("%.10b" % -5)
|
||||
("% B" % -5).should == ("% b" % -5)
|
||||
("%+B" % -5).should == ("%+b" % -5)
|
||||
not_supported_on :opal do
|
||||
("%B" % -(2 ** 64 + 5)).should == ("%b" % -(2 ** 64 + 5))
|
||||
end
|
||||
|
||||
("%#B" % 10).should == "0B1010"
|
||||
end
|
||||
|
||||
it "supports character formats using %c" do
|
||||
("%c" % 10).should == "\n"
|
||||
("%2$c" % [10, 11, 14]).should == "\v"
|
||||
("%-4c" % 10).should == "\n "
|
||||
("%*c" % [10, 3]).should == " \003"
|
||||
("%c" % 42).should == "*"
|
||||
|
||||
lambda { "%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)
|
||||
end
|
||||
|
||||
it "calls to_str on argument for %c formats" do
|
||||
obj = mock('A')
|
||||
obj.should_receive(:to_str).and_return('A')
|
||||
|
||||
("%c" % obj).should == "A"
|
||||
end
|
||||
|
||||
it "calls #to_ary on argument for %c formats" do
|
||||
obj = mock('65')
|
||||
obj.should_receive(:to_ary).and_return([65])
|
||||
("%c" % obj).should == ("%c" % [65])
|
||||
end
|
||||
|
||||
it "calls #to_int on argument for %c formats, if the argument does not respond to #to_ary" do
|
||||
obj = mock('65')
|
||||
obj.should_receive(:to_int).and_return(65)
|
||||
|
||||
("%c" % obj).should == ("%c" % 65)
|
||||
end
|
||||
|
||||
%w(d i).each do |f|
|
||||
format = "%" + f
|
||||
|
||||
it "supports integer formats using #{format}" do
|
||||
("%#{f}" % 10).should == "10"
|
||||
("% #{f}" % 10).should == " 10"
|
||||
("%1$#{f}" % [10, 20]).should == "10"
|
||||
("%+#{f}" % 10).should == "+10"
|
||||
("%-7#{f}" % 10).should == "10 "
|
||||
("%04#{f}" % 10).should == "0010"
|
||||
("%*#{f}" % [10, 4]).should == " 4"
|
||||
("%6.4#{f}" % 123).should == " 0123"
|
||||
end
|
||||
|
||||
it "supports negative integers using #{format}" do
|
||||
("%#{f}" % -5).should == "-5"
|
||||
("%3#{f}" % -5).should == " -5"
|
||||
("%03#{f}" % -5).should == "-05"
|
||||
("%+03#{f}" % -5).should == "-05"
|
||||
("%+.2#{f}" % -5).should == "-05"
|
||||
("%-3#{f}" % -5).should == "-5 "
|
||||
("%6.4#{f}" % -123).should == " -0123"
|
||||
end
|
||||
|
||||
it "supports negative integers using #{format}, giving priority to `-`" do
|
||||
("%-03#{f}" % -5).should == "-5 "
|
||||
("%+-03#{f}" % -5).should == "-5 "
|
||||
end
|
||||
end
|
||||
|
||||
it "supports float formats using %e" do
|
||||
("%e" % 10).should == "1.000000e+01"
|
||||
("% e" % 10).should == " 1.000000e+01"
|
||||
("%1$e" % 10).should == "1.000000e+01"
|
||||
("%#e" % 10).should == "1.000000e+01"
|
||||
("%+e" % 10).should == "+1.000000e+01"
|
||||
("%-7e" % 10).should == "1.000000e+01"
|
||||
("%05e" % 10).should == "1.000000e+01"
|
||||
("%*e" % [10, 9]).should == "9.000000e+00"
|
||||
end
|
||||
|
||||
it "supports float formats using %e, but Inf, -Inf, and NaN are not floats" do
|
||||
("%e" % 1e1020).should == "Inf"
|
||||
("%e" % -1e1020).should == "-Inf"
|
||||
("%e" % -Float::NAN).should == "NaN"
|
||||
("%e" % Float::NAN).should == "NaN"
|
||||
end
|
||||
|
||||
it "supports float formats using %E, but Inf, -Inf, and NaN are not floats" do
|
||||
("%E" % 1e1020).should == "Inf"
|
||||
("%E" % -1e1020).should == "-Inf"
|
||||
("%-10E" % 1e1020).should == "Inf "
|
||||
("%10E" % 1e1020).should == " Inf"
|
||||
("%+E" % 1e1020).should == "+Inf"
|
||||
("% E" % 1e1020).should == " Inf"
|
||||
("%E" % Float::NAN).should == "NaN"
|
||||
("%E" % -Float::NAN).should == "NaN"
|
||||
end
|
||||
|
||||
it "supports float formats using %E" do
|
||||
("%E" % 10).should == "1.000000E+01"
|
||||
("% E" % 10).should == " 1.000000E+01"
|
||||
("%1$E" % 10).should == "1.000000E+01"
|
||||
("%#E" % 10).should == "1.000000E+01"
|
||||
("%+E" % 10).should == "+1.000000E+01"
|
||||
("%-7E" % 10).should == "1.000000E+01"
|
||||
("%05E" % 10).should == "1.000000E+01"
|
||||
("%*E" % [10, 9]).should == "9.000000E+00"
|
||||
end
|
||||
|
||||
it "pads with spaces for %E with Inf, -Inf, and NaN" do
|
||||
("%010E" % -1e1020).should == " -Inf"
|
||||
("%010E" % 1e1020).should == " Inf"
|
||||
("%010E" % Float::NAN).should == " NaN"
|
||||
end
|
||||
|
||||
it "supports float formats using %f" do
|
||||
("%f" % 10).should == "10.000000"
|
||||
("% f" % 10).should == " 10.000000"
|
||||
("%1$f" % 10).should == "10.000000"
|
||||
("%#f" % 10).should == "10.000000"
|
||||
("%#0.3f" % 10).should == "10.000"
|
||||
("%+f" % 10).should == "+10.000000"
|
||||
("%-7f" % 10).should == "10.000000"
|
||||
("%05f" % 10).should == "10.000000"
|
||||
("%0.5f" % 10).should == "10.00000"
|
||||
("%*f" % [10, 9]).should == " 9.000000"
|
||||
end
|
||||
|
||||
it "supports float formats using %g" do
|
||||
("%g" % 10).should == "10"
|
||||
("% g" % 10).should == " 10"
|
||||
("%1$g" % 10).should == "10"
|
||||
("%#g" % 10).should == "10.0000"
|
||||
("%#.3g" % 10).should == "10.0"
|
||||
("%+g" % 10).should == "+10"
|
||||
("%-7g" % 10).should == "10 "
|
||||
("%05g" % 10).should == "00010"
|
||||
("%g" % 10**10).should == "1e+10"
|
||||
("%*g" % [10, 9]).should == " 9"
|
||||
end
|
||||
|
||||
it "supports float formats using %G" do
|
||||
("%G" % 10).should == "10"
|
||||
("% G" % 10).should == " 10"
|
||||
("%1$G" % 10).should == "10"
|
||||
("%#G" % 10).should == "10.0000"
|
||||
("%#.3G" % 10).should == "10.0"
|
||||
("%+G" % 10).should == "+10"
|
||||
("%-7G" % 10).should == "10 "
|
||||
("%05G" % 10).should == "00010"
|
||||
("%G" % 10**10).should == "1E+10"
|
||||
("%*G" % [10, 9]).should == " 9"
|
||||
end
|
||||
|
||||
it "supports octal formats using %o for positive numbers" do
|
||||
("%o" % 10).should == "12"
|
||||
("% o" % 10).should == " 12"
|
||||
("%1$o" % [10, 20]).should == "12"
|
||||
("%#o" % 10).should == "012"
|
||||
("%+o" % 10).should == "+12"
|
||||
("%-9o" % 10).should == "12 "
|
||||
("%05o" % 10).should == "00012"
|
||||
("%*o" % [10, 6]).should == " 6"
|
||||
end
|
||||
|
||||
it "supports octal formats using %o for negative numbers" do
|
||||
# These are incredibly wrong. -05 == -5, not 7177777...whatever
|
||||
("%o" % -5).should == "..73"
|
||||
("%0o" % -5).should == "..73"
|
||||
("%.4o" % 20).should == "0024"
|
||||
("%.1o" % -5).should == "..73"
|
||||
("%.7o" % -5).should == "..77773"
|
||||
("%.10o" % -5).should == "..77777773"
|
||||
|
||||
("% o" % -26).should == "-32"
|
||||
("%+o" % -26).should == "-32"
|
||||
not_supported_on :opal do
|
||||
("%o" % -(2 ** 64 + 5)).should == "..75777777777777777777773"
|
||||
end
|
||||
end
|
||||
|
||||
it "supports inspect formats using %p" do
|
||||
("%p" % 10).should == "10"
|
||||
("%1$p" % [10, 5]).should == "10"
|
||||
("%-22p" % 10).should == "10 "
|
||||
("%*p" % [10, 10]).should == " 10"
|
||||
("%p" % {capture: 1}).should == "{:capture=>1}"
|
||||
("%p" % "str").should == "\"str\""
|
||||
end
|
||||
|
||||
it "calls inspect on arguments for %p format" do
|
||||
obj = mock('obj')
|
||||
def obj.inspect() "obj" end
|
||||
("%p" % obj).should == "obj"
|
||||
|
||||
# undef is not working
|
||||
# obj = mock('obj')
|
||||
# class << obj; undef :inspect; end
|
||||
# def obj.method_missing(*args) "obj" end
|
||||
# ("%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 == ""
|
||||
("%s" % 10).should == "10"
|
||||
("%1$s" % [10, 8]).should == "10"
|
||||
("%-5s" % 10).should == "10 "
|
||||
("%*s" % [10, 9]).should == " 9"
|
||||
end
|
||||
|
||||
it "respects a space padding request not as part of the width" do
|
||||
x = "% -5s" % ["foo"]
|
||||
x.should == "foo "
|
||||
end
|
||||
|
||||
it "calls to_s on non-String arguments for %s format" do
|
||||
obj = mock('obj')
|
||||
def obj.to_s() "obj" end
|
||||
|
||||
("%s" % obj).should == "obj"
|
||||
|
||||
# undef doesn't work
|
||||
# obj = mock('obj')
|
||||
# class << obj; undef :to_s; end
|
||||
# def obj.method_missing(*args) "obj" end
|
||||
#
|
||||
# ("%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.should raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
# Note: %u has been changed to an alias for %d in 1.9.
|
||||
it "supports unsigned formats using %u" do
|
||||
("%u" % 10).should == "10"
|
||||
("% u" % 10).should == " 10"
|
||||
("%1$u" % [10, 20]).should == "10"
|
||||
("%+u" % 10).should == "+10"
|
||||
("%-7u" % 10).should == "10 "
|
||||
("%04u" % 10).should == "0010"
|
||||
("%*u" % [10, 4]).should == " 4"
|
||||
end
|
||||
|
||||
it "formats negative values with a leading sign using %u" do
|
||||
("% u" % -26).should == "-26"
|
||||
("%+u" % -26).should == "-26"
|
||||
end
|
||||
|
||||
it "supports negative bignums with %u or %d" do
|
||||
("%u" % -(2 ** 64 + 5)).should == "-18446744073709551621"
|
||||
("%d" % -(2 ** 64 + 5)).should == "-18446744073709551621"
|
||||
end
|
||||
|
||||
it "supports hex formats using %x for positive numbers" do
|
||||
("%x" % 10).should == "a"
|
||||
("% x" % 10).should == " a"
|
||||
("%1$x" % [10, 20]).should == "a"
|
||||
("%#x" % 10).should == "0xa"
|
||||
("%+x" % 10).should == "+a"
|
||||
("%-9x" % 10).should == "a "
|
||||
("%05x" % 10).should == "0000a"
|
||||
("%*x" % [10, 6]).should == " 6"
|
||||
("%.4x" % 20).should == "0014"
|
||||
("%x" % 0xFFFFFFFF).should == "ffffffff"
|
||||
end
|
||||
|
||||
it "supports hex formats using %x for negative numbers" do
|
||||
("%x" % -5).should == "..fb"
|
||||
("%0x" % -5).should == "..fb"
|
||||
("%.1x" % -5).should == "..fb"
|
||||
("%.7x" % -5).should == "..ffffb"
|
||||
("%.10x" % -5).should == "..fffffffb"
|
||||
("% x" % -26).should == "-1a"
|
||||
("%+x" % -26).should == "-1a"
|
||||
not_supported_on :opal do
|
||||
("%x" % -(2 ** 64 + 5)).should == "..fefffffffffffffffb"
|
||||
end
|
||||
end
|
||||
|
||||
it "supports hex formats using %X for positive numbers" do
|
||||
("%X" % 10).should == "A"
|
||||
("% X" % 10).should == " A"
|
||||
("%1$X" % [10, 20]).should == "A"
|
||||
("%#X" % 10).should == "0XA"
|
||||
("%+X" % 10).should == "+A"
|
||||
("%-9X" % 10).should == "A "
|
||||
("%05X" % 10).should == "0000A"
|
||||
("%*X" % [10, 6]).should == " 6"
|
||||
("%X" % 0xFFFFFFFF).should == "FFFFFFFF"
|
||||
end
|
||||
|
||||
it "supports hex formats using %X for negative numbers" do
|
||||
("%X" % -5).should == "..FB"
|
||||
("%0X" % -5).should == "..FB"
|
||||
("%.1X" % -5).should == "..FB"
|
||||
("%.7X" % -5).should == "..FFFFB"
|
||||
("%.10X" % -5).should == "..FFFFFFFB"
|
||||
("% X" % -26).should == "-1A"
|
||||
("%+X" % -26).should == "-1A"
|
||||
not_supported_on :opal do
|
||||
("%X" % -(2 ** 64 + 5)).should == "..FEFFFFFFFFFFFFFFFB"
|
||||
end
|
||||
end
|
||||
|
||||
it "formats zero without prefix using %#x" do
|
||||
("%#x" % 0).should == "0"
|
||||
end
|
||||
|
||||
it "formats zero without prefix using %#X" do
|
||||
("%#X" % 0).should == "0"
|
||||
end
|
||||
|
||||
%w(b d i o u x X).each do |f|
|
||||
format = "%" + f
|
||||
|
||||
it "behaves as if calling Kernel#Integer for #{format} argument, if it does not respond to #to_ary" do
|
||||
(format % "10").should == (format % Kernel.Integer("10"))
|
||||
(format % "0x42").should == (format % Kernel.Integer("0x42"))
|
||||
(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)
|
||||
|
||||
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)
|
||||
|
||||
obj = mock('5')
|
||||
obj.should_receive(:to_i).and_return(5)
|
||||
(format % obj).should == (format % 5)
|
||||
|
||||
obj = mock('6')
|
||||
obj.stub!(:to_i).and_return(5)
|
||||
obj.should_receive(:to_int).and_return(6)
|
||||
(format % obj).should == (format % 6)
|
||||
end
|
||||
end
|
||||
|
||||
%w(e E f g G).each do |f|
|
||||
format = "%" + f
|
||||
|
||||
it "tries to convert the passed argument to an Array using #to_ary" do
|
||||
obj = mock('3.14')
|
||||
obj.should_receive(:to_ary).and_return([3.14])
|
||||
(format % obj).should == (format % [3.14])
|
||||
end
|
||||
|
||||
it "behaves as if calling Kernel#Float for #{format} arguments, when the passed argument does not respond to #to_ary" do
|
||||
(format % 10).should == (format % 10.0)
|
||||
(format % "-10.4e-20").should == (format % -10.4e-20)
|
||||
(format % ".5").should == (format % 0.5)
|
||||
(format % "-.5").should == (format % -0.5)
|
||||
# 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)
|
||||
|
||||
obj = mock('5.0')
|
||||
obj.should_receive(:to_f).and_return(5.0)
|
||||
(format % obj).should == (format % 5.0)
|
||||
end
|
||||
|
||||
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
|
||||
it "replaces %{} sections with values from passed-in hash" 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)
|
||||
end
|
||||
end
|
||||
|
||||
describe "when format string contains %<> formats" do
|
||||
it "uses the named argument for the format's value" do
|
||||
("%<foo>d" % {foo: 1}).should == "1"
|
||||
end
|
||||
|
||||
it "raises KeyError if key is missing from passed-in hash" do
|
||||
lambda {"%<foo>d" % {}}.should raise_error(KeyError)
|
||||
end
|
||||
|
||||
it "should raise ArgumentError if no hash given" do
|
||||
lambda {"%<foo>" % []}.should raise_error(ArgumentError)
|
||||
end
|
||||
end
|
||||
end
|
7
spec/ruby/core/string/multiply_spec.rb
Normal file
7
spec/ruby/core/string/multiply_spec.rb
Normal file
|
@ -0,0 +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__)
|
||||
|
||||
describe "String#*" do
|
||||
it_behaves_like :string_times, :*, ->(str, times) { str * times }
|
||||
end
|
58
spec/ruby/core/string/new_spec.rb
Normal file
58
spec/ruby/core/string/new_spec.rb
Normal file
|
@ -0,0 +1,58 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
|
||||
describe "String.new" do
|
||||
it "returns an instance of String" do
|
||||
str = String.new
|
||||
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
|
||||
end
|
||||
|
||||
it "returns a fully-formed String" do
|
||||
str = String.new
|
||||
str.size.should == 0
|
||||
str << "more"
|
||||
str.should == "more"
|
||||
end
|
||||
|
||||
it "returns a new string given a string argument" do
|
||||
str1 = "test"
|
||||
str = String.new(str1)
|
||||
str.should be_an_instance_of(String)
|
||||
str.should == str1
|
||||
str << "more"
|
||||
str.should == "testmore"
|
||||
end
|
||||
|
||||
it "returns an instance of a subclass" do
|
||||
a = StringSpecs::MyString.new("blah")
|
||||
a.should be_an_instance_of(StringSpecs::MyString)
|
||||
a.should == "blah"
|
||||
end
|
||||
|
||||
it "is called on subclasses" do
|
||||
s = StringSpecs::SubString.new
|
||||
s.special.should == nil
|
||||
s.should == ""
|
||||
|
||||
s = StringSpecs::SubString.new "subclass"
|
||||
s.special.should == "subclass"
|
||||
s.should == ""
|
||||
end
|
||||
|
||||
it "raises TypeError on inconvertible object" do
|
||||
lambda { String.new 5 }.should raise_error(TypeError)
|
||||
lambda { String.new nil }.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "returns a binary String" do
|
||||
String.new.encoding.should == Encoding::BINARY
|
||||
end
|
||||
end
|
11
spec/ruby/core/string/next_spec.rb
Normal file
11
spec/ruby/core/string/next_spec.rb
Normal file
|
@ -0,0 +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__)
|
||||
|
||||
describe "String#next" do
|
||||
it_behaves_like(:string_succ, :next)
|
||||
end
|
||||
|
||||
describe "String#next!" do
|
||||
it_behaves_like(:string_succ_bang, :"next!")
|
||||
end
|
88
spec/ruby/core/string/oct_spec.rb
Normal file
88
spec/ruby/core/string/oct_spec.rb
Normal file
|
@ -0,0 +1,88 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
# 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.
|
||||
# See http://groups.google.com/group/ruby-core-google/browse_frm/thread/b53e9c2003425703
|
||||
describe "String#oct" do
|
||||
it "treats numeric digits as base-8 digits by default" do
|
||||
"0".oct.should == 0
|
||||
"77".oct.should == 077
|
||||
"077".oct.should == 077
|
||||
end
|
||||
|
||||
it "accepts numbers formatted as binary" do
|
||||
"0b1010".oct.should == 0b1010
|
||||
end
|
||||
|
||||
it "accepts numbers formatted as hexadecimal" do
|
||||
"0xFF".oct.should == 0xFF
|
||||
end
|
||||
|
||||
it "accepts numbers formatted as decimal" do
|
||||
"0d500".oct.should == 500
|
||||
end
|
||||
|
||||
describe "with a leading minus sign" do
|
||||
it "treats numeric digits as base-8 digits by default" do
|
||||
"-12348".oct.should == -01234
|
||||
end
|
||||
|
||||
it "accepts numbers formatted as binary" do
|
||||
"-0b0101".oct.should == -0b0101
|
||||
end
|
||||
|
||||
it "accepts numbers formatted as hexadecimal" do
|
||||
"-0xEE".oct.should == -0xEE
|
||||
end
|
||||
|
||||
it "accepts numbers formatted as decimal" do
|
||||
"-0d500".oct.should == -500
|
||||
end
|
||||
end
|
||||
|
||||
describe "with a leading plus sign" do
|
||||
it "treats numeric digits as base-8 digits by default" do
|
||||
"+12348".oct.should == 01234
|
||||
end
|
||||
|
||||
it "accepts numbers formatted as binary" do
|
||||
"+0b1010".oct.should == 0b1010
|
||||
end
|
||||
|
||||
it "accepts numbers formatted as hexadecimal" do
|
||||
"+0xFF".oct.should == 0xFF
|
||||
end
|
||||
|
||||
it "accepts numbers formatted as decimal" do
|
||||
"+0d500".oct.should == 500
|
||||
end
|
||||
end
|
||||
|
||||
it "accepts a single underscore separating digits" do
|
||||
"755_333".oct.should == 0755_333
|
||||
end
|
||||
|
||||
it "does not accept a sequence of underscores as part of a number" do
|
||||
"7__3".oct.should == 07
|
||||
"7___3".oct.should == 07
|
||||
"7__5".oct.should == 07
|
||||
end
|
||||
|
||||
it "ignores characters that are incorrect for the base-8 digits" do
|
||||
"0o".oct.should == 0
|
||||
"5678".oct.should == 0567
|
||||
end
|
||||
|
||||
it "returns 0 if no characters can be interpreted as a base-8 number" do
|
||||
"".oct.should == 0
|
||||
"+-5".oct.should == 0
|
||||
"wombat".oct.should == 0
|
||||
end
|
||||
|
||||
it "returns 0 for strings with leading underscores" do
|
||||
"_7".oct.should == 0
|
||||
"_07".oct.should == 0
|
||||
" _7".oct.should == 0
|
||||
end
|
||||
end
|
30
spec/ruby/core/string/ord_spec.rb
Normal file
30
spec/ruby/core/string/ord_spec.rb
Normal file
|
@ -0,0 +1,30 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
|
||||
with_feature :encoding do
|
||||
describe "String#ord" do
|
||||
it "returns a Fixnum" do
|
||||
'a'.ord.should be_an_instance_of(Fixnum)
|
||||
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 "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 "raises an ArgumentError if called on an empty String" do
|
||||
lambda { ''.ord }.should raise_error(ArgumentError)
|
||||
end
|
||||
end
|
||||
end
|
38
spec/ruby/core/string/partition_spec.rb
Normal file
38
spec/ruby/core/string/partition_spec.rb
Normal file
|
@ -0,0 +1,38 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
describe "String#partition with String" do
|
||||
it "returns an array of substrings based on splitting on the given string" do
|
||||
"hello world".partition("o").should == ["hell", "o", " world"]
|
||||
end
|
||||
|
||||
it "always returns 3 elements" do
|
||||
"hello".partition("x").should == ["hello", "", ""]
|
||||
"hello".partition("hello").should == ["", "hello", ""]
|
||||
end
|
||||
|
||||
it "accepts regexp" do
|
||||
"hello!".partition(/l./).should == ["he", "ll", "o!"]
|
||||
end
|
||||
|
||||
it "sets global vars if regexp used" do
|
||||
"hello!".partition(/(.l)(.o)/)
|
||||
$1.should == "el"
|
||||
$2.should == "lo"
|
||||
end
|
||||
|
||||
it "converts its argument using :to_str" do
|
||||
find = mock('l')
|
||||
find.should_receive(:to_str).and_return("l")
|
||||
"hello".partition(find).should == ["he","l","lo"]
|
||||
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)
|
||||
end
|
||||
|
||||
it "takes precedence over a given block" do
|
||||
"hello world".partition("o") { true }.should == ["hell", "o", " world"]
|
||||
end
|
||||
end
|
47
spec/ruby/core/string/plus_spec.rb
Normal file
47
spec/ruby/core/string/plus_spec.rb
Normal file
|
@ -0,0 +1,47 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
require File.expand_path('../shared/concat', __FILE__)
|
||||
|
||||
describe "String#+" do
|
||||
it "returns a new string containing the given string concatenated to self" do
|
||||
("" + "").should == ""
|
||||
("" + "Hello").should == "Hello"
|
||||
("Hello" + "").should == "Hello"
|
||||
("Ruby !" + "= Rubinius").should == "Ruby != Rubinius"
|
||||
end
|
||||
|
||||
it "converts any non-String argument with #to_str" do
|
||||
c = mock 'str'
|
||||
c.should_receive(:to_str).any_number_of_times.and_return(' + 1 = 2')
|
||||
|
||||
("1" + c).should == '1 + 1 = 2'
|
||||
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)
|
||||
end
|
||||
|
||||
it "doesn't return subclass instances" do
|
||||
(StringSpecs::MyString.new("hello") + "").should be_an_instance_of(String)
|
||||
(StringSpecs::MyString.new("hello") + "foo").should be_an_instance_of(String)
|
||||
(StringSpecs::MyString.new("hello") + StringSpecs::MyString.new("foo")).should be_an_instance_of(String)
|
||||
(StringSpecs::MyString.new("hello") + StringSpecs::MyString.new("")).should be_an_instance_of(String)
|
||||
(StringSpecs::MyString.new("") + StringSpecs::MyString.new("")).should be_an_instance_of(String)
|
||||
("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
|
64
spec/ruby/core/string/prepend_spec.rb
Normal file
64
spec/ruby/core/string/prepend_spec.rb
Normal file
|
@ -0,0 +1,64 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
describe "String#prepend" do
|
||||
it "prepends the given argument to self and returns self" do
|
||||
str = "world"
|
||||
str.prepend("hello ").should equal(str)
|
||||
str.should == "hello world"
|
||||
end
|
||||
|
||||
it "converts the given argument to a String using to_str" do
|
||||
obj = mock("hello")
|
||||
obj.should_receive(:to_str).and_return("hello")
|
||||
a = " world!".prepend(obj)
|
||||
a.should == "hello world!"
|
||||
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)
|
||||
end
|
||||
|
||||
it "raises a RuntimeError when self is frozen" do
|
||||
a = "hello"
|
||||
a.freeze
|
||||
|
||||
lambda { a.prepend "" }.should raise_error(RuntimeError)
|
||||
lambda { a.prepend "test" }.should raise_error(RuntimeError)
|
||||
end
|
||||
|
||||
it "works when given a subclass instance" do
|
||||
a = " world"
|
||||
a.prepend StringSpecs::MyString.new("hello")
|
||||
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
|
||||
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 "returns self when given no arguments" do
|
||||
str = "hello"
|
||||
str.prepend.should equal(str)
|
||||
str.should == "hello"
|
||||
end
|
||||
end
|
||||
end
|
7
spec/ruby/core/string/replace_spec.rb
Normal file
7
spec/ruby/core/string/replace_spec.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes', __FILE__)
|
||||
require File.expand_path('../shared/replace', __FILE__)
|
||||
|
||||
describe "String#replace" do
|
||||
it_behaves_like :string_replace, :replace
|
||||
end
|
52
spec/ruby/core/string/reverse_spec.rb
Normal file
52
spec/ruby/core/string/reverse_spec.rb
Normal file
|
@ -0,0 +1,52 @@
|
|||
# encoding: utf-8
|
||||
|
||||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
describe "String#reverse" do
|
||||
it "returns a new string with the characters of self in reverse order" do
|
||||
"stressed".reverse.should == "desserts"
|
||||
"m".reverse.should == "m"
|
||||
"".reverse.should == ""
|
||||
end
|
||||
|
||||
it "taints the result if self is tainted" do
|
||||
"".taint.reverse.tainted?.should == true
|
||||
"m".taint.reverse.tainted?.should == true
|
||||
end
|
||||
|
||||
with_feature :encoding do
|
||||
it "reverses a string with multi byte characters" do
|
||||
"微軟正黑體".reverse.should == "體黑正軟微"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe "String#reverse!" do
|
||||
it "reverses self in place and always returns self" do
|
||||
a = "stressed"
|
||||
a.reverse!.should equal(a)
|
||||
a.should == "desserts"
|
||||
|
||||
"".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)
|
||||
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)
|
||||
end
|
||||
|
||||
with_feature :encoding do
|
||||
it "reverses a string with multi byte characters" do
|
||||
str = "微軟正黑體"
|
||||
str.reverse!
|
||||
str.should == "體黑正軟微"
|
||||
end
|
||||
end
|
||||
end
|
368
spec/ruby/core/string/rindex_spec.rb
Normal file
368
spec/ruby/core/string/rindex_spec.rb
Normal file
|
@ -0,0 +1,368 @@
|
|||
# -*- 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__)
|
||||
|
||||
describe "String#rindex with object" do
|
||||
it "raises a TypeError if obj isn't a String, Fixnum or Regexp" do
|
||||
not_supported_on :opal do
|
||||
lambda { "hello".rindex(:sym) }.should raise_error(TypeError)
|
||||
end
|
||||
lambda { "hello".rindex(mock('x')) }.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)
|
||||
end
|
||||
|
||||
it "tries to convert obj to a string via to_str" do
|
||||
obj = mock('lo')
|
||||
def obj.to_str() "lo" end
|
||||
"hello".rindex(obj).should == "hello".rindex("lo")
|
||||
|
||||
obj = mock('o')
|
||||
def obj.respond_to?(arg, *) true end
|
||||
def obj.method_missing(*args) "o" end
|
||||
"hello".rindex(obj).should == "hello".rindex("o")
|
||||
end
|
||||
end
|
||||
|
||||
describe "String#rindex with String" do
|
||||
it "behaves the same as String#rindex(char) for one-character strings" do
|
||||
"blablabla hello cruel world...!".split("").uniq.each do |str|
|
||||
chr = str[0]
|
||||
str.rindex(str).should == str.rindex(chr)
|
||||
|
||||
0.upto(str.size + 1) do |start|
|
||||
str.rindex(str, start).should == str.rindex(chr, start)
|
||||
end
|
||||
|
||||
(-str.size - 1).upto(-1) do |start|
|
||||
str.rindex(str, start).should == str.rindex(chr, start)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "behaves the same as String#rindex(?char) for one-character strings" do
|
||||
"blablabla hello cruel world...!".split("").uniq.each do |str|
|
||||
chr = str[0] =~ / / ? str[0] : eval("?#{str[0]}")
|
||||
str.rindex(str).should == str.rindex(chr)
|
||||
|
||||
0.upto(str.size + 1) do |start|
|
||||
str.rindex(str, start).should == str.rindex(chr, start)
|
||||
end
|
||||
|
||||
(-str.size - 1).upto(-1) do |start|
|
||||
str.rindex(str, start).should == str.rindex(chr, start)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "returns the index of the last occurrence of the given substring" do
|
||||
"blablabla".rindex("").should == 9
|
||||
"blablabla".rindex("a").should == 8
|
||||
"blablabla".rindex("la").should == 7
|
||||
"blablabla".rindex("bla").should == 6
|
||||
"blablabla".rindex("abla").should == 5
|
||||
"blablabla".rindex("labla").should == 4
|
||||
"blablabla".rindex("blabla").should == 3
|
||||
"blablabla".rindex("ablabla").should == 2
|
||||
"blablabla".rindex("lablabla").should == 1
|
||||
"blablabla".rindex("blablabla").should == 0
|
||||
|
||||
"blablabla".rindex("l").should == 7
|
||||
"blablabla".rindex("bl").should == 6
|
||||
"blablabla".rindex("abl").should == 5
|
||||
"blablabla".rindex("labl").should == 4
|
||||
"blablabla".rindex("blabl").should == 3
|
||||
"blablabla".rindex("ablabl").should == 2
|
||||
"blablabla".rindex("lablabl").should == 1
|
||||
"blablabla".rindex("blablabl").should == 0
|
||||
|
||||
"blablabla".rindex("b").should == 6
|
||||
"blablabla".rindex("ab").should == 5
|
||||
"blablabla".rindex("lab").should == 4
|
||||
"blablabla".rindex("blab").should == 3
|
||||
"blablabla".rindex("ablab").should == 2
|
||||
"blablabla".rindex("lablab").should == 1
|
||||
"blablabla".rindex("blablab").should == 0
|
||||
end
|
||||
|
||||
it "doesn't set $~" do
|
||||
$~ = nil
|
||||
|
||||
'hello.'.rindex('ll')
|
||||
$~.should == nil
|
||||
end
|
||||
|
||||
it "ignores string subclasses" do
|
||||
"blablabla".rindex(StringSpecs::MyString.new("bla")).should == 6
|
||||
StringSpecs::MyString.new("blablabla").rindex("bla").should == 6
|
||||
StringSpecs::MyString.new("blablabla").rindex(StringSpecs::MyString.new("bla")).should == 6
|
||||
end
|
||||
|
||||
it "starts the search at the given offset" do
|
||||
"blablabla".rindex("bl", 0).should == 0
|
||||
"blablabla".rindex("bl", 1).should == 0
|
||||
"blablabla".rindex("bl", 2).should == 0
|
||||
"blablabla".rindex("bl", 3).should == 3
|
||||
|
||||
"blablabla".rindex("bla", 0).should == 0
|
||||
"blablabla".rindex("bla", 1).should == 0
|
||||
"blablabla".rindex("bla", 2).should == 0
|
||||
"blablabla".rindex("bla", 3).should == 3
|
||||
|
||||
"blablabla".rindex("blab", 0).should == 0
|
||||
"blablabla".rindex("blab", 1).should == 0
|
||||
"blablabla".rindex("blab", 2).should == 0
|
||||
"blablabla".rindex("blab", 3).should == 3
|
||||
"blablabla".rindex("blab", 6).should == 3
|
||||
"blablablax".rindex("blab", 6).should == 3
|
||||
|
||||
"blablabla".rindex("la", 1).should == 1
|
||||
"blablabla".rindex("la", 2).should == 1
|
||||
"blablabla".rindex("la", 3).should == 1
|
||||
"blablabla".rindex("la", 4).should == 4
|
||||
|
||||
"blablabla".rindex("lab", 1).should == 1
|
||||
"blablabla".rindex("lab", 2).should == 1
|
||||
"blablabla".rindex("lab", 3).should == 1
|
||||
"blablabla".rindex("lab", 4).should == 4
|
||||
|
||||
"blablabla".rindex("ab", 2).should == 2
|
||||
"blablabla".rindex("ab", 3).should == 2
|
||||
"blablabla".rindex("ab", 4).should == 2
|
||||
"blablabla".rindex("ab", 5).should == 5
|
||||
|
||||
"blablabla".rindex("", 0).should == 0
|
||||
"blablabla".rindex("", 1).should == 1
|
||||
"blablabla".rindex("", 2).should == 2
|
||||
"blablabla".rindex("", 7).should == 7
|
||||
"blablabla".rindex("", 8).should == 8
|
||||
"blablabla".rindex("", 9).should == 9
|
||||
"blablabla".rindex("", 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.rindex(needle, offset).should ==
|
||||
str.rindex(needle, offset + str.length)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "returns nil if the substring isn't found" do
|
||||
"blablabla".rindex("B").should == nil
|
||||
"blablabla".rindex("z").should == nil
|
||||
"blablabla".rindex("BLA").should == nil
|
||||
"blablabla".rindex("blablablabla").should == nil
|
||||
|
||||
"hello".rindex("lo", 0).should == nil
|
||||
"hello".rindex("lo", 1).should == nil
|
||||
"hello".rindex("lo", 2).should == nil
|
||||
|
||||
"hello".rindex("llo", 0).should == nil
|
||||
"hello".rindex("llo", 1).should == nil
|
||||
|
||||
"hello".rindex("el", 0).should == nil
|
||||
"hello".rindex("ello", 0).should == nil
|
||||
|
||||
"hello".rindex("", -6).should == nil
|
||||
"hello".rindex("", -7).should == nil
|
||||
|
||||
"hello".rindex("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".rindex("st", obj).should == 0
|
||||
|
||||
obj = mock('5')
|
||||
def obj.respond_to?(arg, *) true end
|
||||
def obj.method_missing(*args) 5 end
|
||||
"str".rindex("st", obj).should == 0
|
||||
end
|
||||
|
||||
it "raises a TypeError when given offset is nil" do
|
||||
lambda { "str".rindex("st", nil) }.should raise_error(TypeError)
|
||||
end
|
||||
end
|
||||
|
||||
describe "String#rindex with Regexp" do
|
||||
it "behaves the same as String#rindex(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.rindex(regexp).should == str.rindex(needle)
|
||||
|
||||
0.upto(str.size + 1) do |start|
|
||||
str.rindex(regexp, start).should == str.rindex(needle, start)
|
||||
end
|
||||
|
||||
(-str.size - 1).upto(-1) do |start|
|
||||
str.rindex(regexp, start).should == str.rindex(needle, start)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "returns the index of the first match from the end of string of regexp" do
|
||||
"blablabla".rindex(/bla/).should == 6
|
||||
"blablabla".rindex(/BLA/i).should == 6
|
||||
|
||||
"blablabla".rindex(/.{0}/).should == 9
|
||||
"blablabla".rindex(/.{1}/).should == 8
|
||||
"blablabla".rindex(/.{2}/).should == 7
|
||||
"blablabla".rindex(/.{6}/).should == 3
|
||||
"blablabla".rindex(/.{9}/).should == 0
|
||||
|
||||
"blablabla".rindex(/.*/).should == 9
|
||||
"blablabla".rindex(/.+/).should == 8
|
||||
|
||||
"blablabla".rindex(/bla|a/).should == 8
|
||||
|
||||
not_supported_on :opal do
|
||||
"blablabla".rindex(/\A/).should == 0
|
||||
"blablabla".rindex(/\Z/).should == 9
|
||||
"blablabla".rindex(/\z/).should == 9
|
||||
"blablabla\n".rindex(/\Z/).should == 10
|
||||
"blablabla\n".rindex(/\z/).should == 10
|
||||
end
|
||||
|
||||
"blablabla".rindex(/^/).should == 0
|
||||
not_supported_on :opal do
|
||||
"\nblablabla".rindex(/^/).should == 1
|
||||
"b\nlablabla".rindex(/^/).should == 2
|
||||
end
|
||||
"blablabla".rindex(/$/).should == 9
|
||||
|
||||
"blablabla".rindex(/.l./).should == 6
|
||||
end
|
||||
|
||||
it "sets $~ to MatchData of match and nil when there's none" do
|
||||
'hello.'.rindex(/.(.)/)
|
||||
$~[0].should == 'o.'
|
||||
|
||||
'hello.'.rindex(/not/)
|
||||
$~.should == nil
|
||||
end
|
||||
|
||||
it "starts the search at the given offset" do
|
||||
"blablabla".rindex(/.{0}/, 5).should == 5
|
||||
"blablabla".rindex(/.{1}/, 5).should == 5
|
||||
"blablabla".rindex(/.{2}/, 5).should == 5
|
||||
"blablabla".rindex(/.{3}/, 5).should == 5
|
||||
"blablabla".rindex(/.{4}/, 5).should == 5
|
||||
|
||||
"blablabla".rindex(/.{0}/, 3).should == 3
|
||||
"blablabla".rindex(/.{1}/, 3).should == 3
|
||||
"blablabla".rindex(/.{2}/, 3).should == 3
|
||||
"blablabla".rindex(/.{5}/, 3).should == 3
|
||||
"blablabla".rindex(/.{6}/, 3).should == 3
|
||||
|
||||
"blablabla".rindex(/.l./, 0).should == 0
|
||||
"blablabla".rindex(/.l./, 1).should == 0
|
||||
"blablabla".rindex(/.l./, 2).should == 0
|
||||
"blablabla".rindex(/.l./, 3).should == 3
|
||||
|
||||
"blablablax".rindex(/.x/, 10).should == 8
|
||||
"blablablax".rindex(/.x/, 9).should == 8
|
||||
"blablablax".rindex(/.x/, 8).should == 8
|
||||
|
||||
"blablablax".rindex(/..x/, 10).should == 7
|
||||
"blablablax".rindex(/..x/, 9).should == 7
|
||||
"blablablax".rindex(/..x/, 8).should == 7
|
||||
"blablablax".rindex(/..x/, 7).should == 7
|
||||
|
||||
not_supported_on :opal do
|
||||
"blablabla\n".rindex(/\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.rindex(needle, offset).should ==
|
||||
str.rindex(needle, offset + str.length)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "returns nil if the substring isn't found" do
|
||||
"blablabla".rindex(/BLA/).should == nil
|
||||
"blablabla".rindex(/.{10}/).should == nil
|
||||
"blablablax".rindex(/.x/, 7).should == nil
|
||||
"blablablax".rindex(/..x/, 6).should == nil
|
||||
|
||||
not_supported_on :opal do
|
||||
"blablabla".rindex(/\Z/, 5).should == nil
|
||||
"blablabla".rindex(/\z/, 5).should == nil
|
||||
"blablabla\n".rindex(/\z/, 9).should == nil
|
||||
end
|
||||
end
|
||||
|
||||
not_supported_on :opal do
|
||||
it "supports \\G which matches at the given start offset" do
|
||||
"helloYOU.".rindex(/YOU\G/, 8).should == 5
|
||||
"helloYOU.".rindex(/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.rindex(re, start).should == i[1]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "tries to convert start_offset to an integer via to_int" do
|
||||
obj = mock('5')
|
||||
def obj.to_int() 5 end
|
||||
"str".rindex(/../, obj).should == 1
|
||||
|
||||
obj = mock('5')
|
||||
def obj.respond_to?(arg, *) true end
|
||||
def obj.method_missing(*args); 5; end
|
||||
"str".rindex(/../, obj).should == 1
|
||||
end
|
||||
|
||||
it "raises a TypeError when given offset is nil" do
|
||||
lambda { "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 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
|
||||
end
|
||||
end
|
116
spec/ruby/core/string/rjust_spec.rb
Normal file
116
spec/ruby/core/string/rjust_spec.rb
Normal file
|
@ -0,0 +1,116 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
describe "String#rjust with length, padding" do
|
||||
it "returns a new string of specified length with self right justified and padded with padstr" do
|
||||
"hello".rjust(20, '1234').should == "123412341234123hello"
|
||||
|
||||
"".rjust(1, "abcd").should == "a"
|
||||
"".rjust(2, "abcd").should == "ab"
|
||||
"".rjust(3, "abcd").should == "abc"
|
||||
"".rjust(4, "abcd").should == "abcd"
|
||||
"".rjust(6, "abcd").should == "abcdab"
|
||||
|
||||
"OK".rjust(3, "abcd").should == "aOK"
|
||||
"OK".rjust(4, "abcd").should == "abOK"
|
||||
"OK".rjust(6, "abcd").should == "abcdOK"
|
||||
"OK".rjust(8, "abcd").should == "abcdabOK"
|
||||
end
|
||||
|
||||
it "pads with whitespace if no padstr is given" do
|
||||
"hello".rjust(20).should == " hello"
|
||||
end
|
||||
|
||||
it "returns self if it's longer than or as long as the specified length" do
|
||||
"".rjust(0).should == ""
|
||||
"".rjust(-1).should == ""
|
||||
"hello".rjust(4).should == "hello"
|
||||
"hello".rjust(-1).should == "hello"
|
||||
"this".rjust(3).should == "this"
|
||||
"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 == "^_^"
|
||||
|
||||
obj = mock('3')
|
||||
obj.should_receive(:to_int).and_return(3)
|
||||
|
||||
"o".rjust(obj, "o_").should == "o_o"
|
||||
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)
|
||||
end
|
||||
|
||||
it "tries to convert padstr to a string using to_str" do
|
||||
padstr = mock('123')
|
||||
padstr.should_receive(:to_str).and_return("123")
|
||||
|
||||
"hello".rjust(10, padstr).should == "12312hello"
|
||||
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)
|
||||
end
|
||||
|
||||
it "raises an ArgumentError when padstr is empty" do
|
||||
lambda { "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)
|
||||
|
||||
"".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
|
||||
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
|
||||
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
|
||||
end
|
||||
end
|
||||
end
|
33
spec/ruby/core/string/rpartition_spec.rb
Normal file
33
spec/ruby/core/string/rpartition_spec.rb
Normal file
|
@ -0,0 +1,33 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
describe "String#rpartition with String" do
|
||||
it "returns an array of substrings based on splitting on the given string" do
|
||||
"hello world".rpartition("o").should == ["hello w", "o", "rld"]
|
||||
end
|
||||
|
||||
it "always returns 3 elements" do
|
||||
"hello".rpartition("x").should == ["", "", "hello"]
|
||||
"hello".rpartition("hello").should == ["", "hello", ""]
|
||||
end
|
||||
|
||||
it "accepts regexp" do
|
||||
"hello!".rpartition(/l./).should == ["hel", "lo", "!"]
|
||||
end
|
||||
|
||||
it "affects $~" do
|
||||
matched_string = "hello!".rpartition(/l./)[1]
|
||||
matched_string.should == $~[0]
|
||||
end
|
||||
|
||||
it "converts its argument using :to_str" do
|
||||
find = mock('l')
|
||||
find.should_receive(:to_str).and_return("l")
|
||||
"hello".rpartition(find).should == ["hel","l","o"]
|
||||
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)
|
||||
end
|
||||
end
|
52
spec/ruby/core/string/rstrip_spec.rb
Normal file
52
spec/ruby/core/string/rstrip_spec.rb
Normal file
|
@ -0,0 +1,52 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
describe "String#rstrip" do
|
||||
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"
|
||||
end
|
||||
|
||||
it "returns a copy of self with all trailing whitespace and NULL bytes removed" do
|
||||
"\x00 \x00hello\x00 \x00".rstrip.should == "\x00 \x00hello"
|
||||
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
|
||||
end
|
||||
end
|
||||
|
||||
describe "String#rstrip!" do
|
||||
it "modifies self in place and returns self" do
|
||||
a = " hello "
|
||||
a.rstrip!.should equal(a)
|
||||
a.should == " hello"
|
||||
end
|
||||
|
||||
it "modifies self removing trailing NULL bytes and whitespace" do
|
||||
a = "\x00 \x00hello\x00 \x00"
|
||||
a.rstrip!
|
||||
a.should == "\x00 \x00hello"
|
||||
end
|
||||
|
||||
it "returns nil if no modifications were made" do
|
||||
a = "hello"
|
||||
a.rstrip!.should == nil
|
||||
a.should == "hello"
|
||||
end
|
||||
|
||||
it "raises a RuntimeError on a frozen instance that is modified" do
|
||||
lambda { " hello ".freeze.rstrip! }.should raise_error(RuntimeError)
|
||||
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)
|
||||
end
|
||||
end
|
192
spec/ruby/core/string/scan_spec.rb
Normal file
192
spec/ruby/core/string/scan_spec.rb
Normal file
|
@ -0,0 +1,192 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
describe "String#scan" do
|
||||
it "returns an array containing all matches" do
|
||||
"cruel world".scan(/\w+/).should == ["cruel", "world"]
|
||||
"cruel world".scan(/.../).should == ["cru", "el ", "wor"]
|
||||
|
||||
# Edge case
|
||||
"hello".scan(//).should == ["", "", "", "", "", ""]
|
||||
"".scan(//).should == [""]
|
||||
end
|
||||
|
||||
it "respects unicode when the pattern collapses to nothing" do
|
||||
str = "こにちわ"
|
||||
reg = %r!!
|
||||
str.scan(reg).should == ["", "", "", "", ""]
|
||||
end
|
||||
|
||||
it "stores groups as arrays in the returned arrays" do
|
||||
"hello".scan(/()/).should == [[""]] * 6
|
||||
"hello".scan(/()()/).should == [["", ""]] * 6
|
||||
"cruel world".scan(/(...)/).should == [["cru"], ["el "], ["wor"]]
|
||||
"cruel world".scan(/(..)(..)/).should == [["cr", "ue"], ["l ", "wo"]]
|
||||
end
|
||||
|
||||
it "scans for occurrences of the string if pattern is a string" do
|
||||
"one two one two".scan('one').should == ["one", "one"]
|
||||
"hello.".scan('.').should == ['.']
|
||||
end
|
||||
|
||||
it "sets $~ to MatchData of last match and nil when there's none" do
|
||||
'hello.'.scan(/.(.)/)
|
||||
$~[0].should == 'o.'
|
||||
|
||||
'hello.'.scan(/not/)
|
||||
$~.should == nil
|
||||
|
||||
'hello.'.scan('l')
|
||||
$~.begin(0).should == 3
|
||||
$~[0].should == 'l'
|
||||
|
||||
'hello.'.scan('not')
|
||||
$~.should == nil
|
||||
end
|
||||
|
||||
it "supports \\G which matches the end of the previous match / string start for first match" do
|
||||
"one two one two".scan(/\G\w+/).should == ["one"]
|
||||
"one two one two".scan(/\G\w+\s*/).should == ["one ", "two ", "one ", "two"]
|
||||
"one two one two".scan(/\G\s*\w+/).should == ["one", " two", " one", " two"]
|
||||
end
|
||||
|
||||
it "tries to convert pattern to a string via to_str" do
|
||||
obj = mock('o')
|
||||
obj.should_receive(:to_str).and_return("o")
|
||||
"o_o".scan(obj).should == ["o", "o"]
|
||||
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)
|
||||
not_supported_on :opal do
|
||||
lambda { "cruel world".scan(:test) }.should raise_error(TypeError)
|
||||
end
|
||||
lambda { "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 }
|
||||
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 }
|
||||
end
|
||||
end
|
||||
|
||||
describe "String#scan with pattern and block" do
|
||||
it "returns self" do
|
||||
s = "foo"
|
||||
s.scan(/./) {}.should equal(s)
|
||||
s.scan(/roar/) {}.should equal(s)
|
||||
end
|
||||
|
||||
it "passes each match to the block as one argument: an array" do
|
||||
a = []
|
||||
"cruel world".scan(/\w+/) { |*w| a << w }
|
||||
a.should == [["cruel"], ["world"]]
|
||||
end
|
||||
|
||||
it "passes groups to the block as one argument: an array" do
|
||||
a = []
|
||||
"cruel world".scan(/(..)(..)/) { |w| a << w }
|
||||
a.should == [["cr", "ue"], ["l ", "wo"]]
|
||||
end
|
||||
|
||||
it "sets $~ for access from the block" do
|
||||
str = "hello"
|
||||
|
||||
matches = []
|
||||
offsets = []
|
||||
|
||||
str.scan(/([aeiou])/) do
|
||||
md = $~
|
||||
md.string.should == str
|
||||
matches << md.to_a
|
||||
offsets << md.offset(0)
|
||||
str
|
||||
end
|
||||
|
||||
matches.should == [["e", "e"], ["o", "o"]]
|
||||
offsets.should == [[1, 2], [4, 5]]
|
||||
|
||||
matches = []
|
||||
offsets = []
|
||||
|
||||
str.scan("l") do
|
||||
md = $~
|
||||
md.string.should == str
|
||||
matches << md.to_a
|
||||
offsets << md.offset(0)
|
||||
str
|
||||
end
|
||||
|
||||
matches.should == [["l"], ["l"]]
|
||||
offsets.should == [[2, 3], [3, 4]]
|
||||
end
|
||||
|
||||
it "restores $~ after leaving the block" do
|
||||
[/./, "l"].each do |pattern|
|
||||
old_md = nil
|
||||
"hello".scan(pattern) do
|
||||
old_md = $~
|
||||
"ok".match(/./)
|
||||
"x"
|
||||
end
|
||||
|
||||
$~[0].should == old_md[0]
|
||||
$~.string.should == "hello"
|
||||
end
|
||||
end
|
||||
|
||||
it "sets $~ to MatchData of last match and nil when there's none for access from outside" do
|
||||
'hello.'.scan('l') { 'x' }
|
||||
$~.begin(0).should == 3
|
||||
$~[0].should == 'l'
|
||||
|
||||
'hello.'.scan('not') { 'x' }
|
||||
$~.should == nil
|
||||
|
||||
'hello.'.scan(/.(.)/) { 'x' }
|
||||
$~[0].should == 'o.'
|
||||
|
||||
'hello.'.scan(/not/) { 'x' }
|
||||
$~.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';
|
||||
second.should == 'b';
|
||||
third.should == 'c';
|
||||
end
|
||||
end
|
||||
end
|
101
spec/ruby/core/string/scrub_spec.rb
Normal file
101
spec/ruby/core/string/scrub_spec.rb
Normal file
|
@ -0,0 +1,101 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
require File.expand_path("../../../spec_helper", __FILE__)
|
||||
|
||||
describe "String#scrub with a default replacement" do
|
||||
it "returns self for valid strings" do
|
||||
input = "foo"
|
||||
|
||||
input.scrub.should == input
|
||||
end
|
||||
|
||||
it "replaces invalid byte sequences" do
|
||||
x81 = [0x81].pack('C').force_encoding('utf-8')
|
||||
"abc\u3042#{x81}".scrub.should == "abc\u3042\uFFFD"
|
||||
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
|
||||
end
|
||||
|
||||
describe "String#scrub with a custom replacement" do
|
||||
it "returns self for valid strings" do
|
||||
input = "foo"
|
||||
|
||||
input.scrub("*").should == input
|
||||
end
|
||||
|
||||
it "replaces invalid byte sequences" do
|
||||
x81 = [0x81].pack('C').force_encoding('utf-8')
|
||||
"abc\u3042#{x81}".scrub("*").should == "abc\u3042*"
|
||||
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 == "*"
|
||||
end
|
||||
|
||||
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.should raise_error(ArgumentError)
|
||||
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.should raise_error(TypeError)
|
||||
end
|
||||
end
|
||||
|
||||
describe "String#scrub with a block" do
|
||||
it "returns self for valid strings" do
|
||||
input = "foo"
|
||||
|
||||
input.scrub { |b| "*" }.should == input
|
||||
end
|
||||
|
||||
it "replaces invalid byte sequences" do
|
||||
xE3x80 = [0xE3, 0x80].pack('CC').force_encoding 'utf-8'
|
||||
replaced = "abc\u3042#{xE3x80}".scrub { |b| "<#{b.unpack("H*")[0]}>" }
|
||||
|
||||
replaced.should == "abc\u3042<e380>"
|
||||
end
|
||||
|
||||
it "replaces invalid byte sequences using a custom encoding" do
|
||||
x80x80 = [0x80, 0x80].pack('CC').force_encoding 'utf-8'
|
||||
replaced = x80x80.scrub do |bad|
|
||||
bad.encode(Encoding::UTF_8, Encoding::Windows_1252)
|
||||
end
|
||||
|
||||
replaced.should == "€€"
|
||||
end
|
||||
end
|
||||
|
||||
describe "String#scrub!" do
|
||||
it "modifies self for valid strings" do
|
||||
x81 = [0x81].pack('C').force_encoding('utf-8')
|
||||
input = "a#{x81}"
|
||||
input.scrub!
|
||||
input.should == "a\uFFFD"
|
||||
end
|
||||
|
||||
it "accepts blocks" do
|
||||
x81 = [0x81].pack('C').force_encoding('utf-8')
|
||||
input = "a#{x81}"
|
||||
input.scrub! { |b| "<?>" }
|
||||
input.should == "a<?>"
|
||||
end
|
||||
end
|
105
spec/ruby/core/string/setbyte_spec.rb
Normal file
105
spec/ruby/core/string/setbyte_spec.rb
Normal file
|
@ -0,0 +1,105 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
|
||||
describe "String#setbyte" do
|
||||
it "returns an Integer" do
|
||||
"a".setbyte(0,1).should be_kind_of(Integer)
|
||||
end
|
||||
|
||||
it "modifies the receiver" do
|
||||
str = "glark"
|
||||
old_id = str.object_id
|
||||
str.setbyte(0,88)
|
||||
str.object_id.should == old_id
|
||||
end
|
||||
|
||||
it "changes the byte at the given index to the new byte" do
|
||||
str = "a"
|
||||
str.setbyte(0,98)
|
||||
str.should == 'b'
|
||||
|
||||
# copy-on-write case
|
||||
str1, str2 = "fooXbar".split("X")
|
||||
str2.setbyte(0, 50)
|
||||
str2.should == "2ar"
|
||||
str1.should == "foo"
|
||||
end
|
||||
|
||||
it "allows changing bytes in multi-byte characters" do
|
||||
str = "\u{915}"
|
||||
str.setbyte(1,254)
|
||||
str.getbyte(1).should == 254
|
||||
end
|
||||
|
||||
it "can invalidate a String's encoding" do
|
||||
str = "glark"
|
||||
str.valid_encoding?.should be_true
|
||||
str.setbyte(2,253)
|
||||
str.valid_encoding?.should be_false
|
||||
end
|
||||
|
||||
it "regards a negative index as counting from the end of the String" do
|
||||
str = "hedgehog"
|
||||
str.setbyte(-3, 108)
|
||||
str.should == "hedgelog"
|
||||
|
||||
# copy-on-write case
|
||||
str1, str2 = "fooXbar".split("X")
|
||||
str2.setbyte(-1, 50)
|
||||
str2.should == "ba2"
|
||||
str1.should == "foo"
|
||||
end
|
||||
|
||||
it "raises an IndexError if the index is greater than the String bytesize" do
|
||||
lambda { "?".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)
|
||||
end
|
||||
|
||||
it "sets a byte at an index greater than String size" do
|
||||
chr = "\u{998}"
|
||||
chr.bytesize.should == 3
|
||||
chr.setbyte(2, 150)
|
||||
chr.should == "\xe0\xa6\x96"
|
||||
end
|
||||
|
||||
it "does not modify the original string when using String.new" do
|
||||
str1 = "hedgehog"
|
||||
str2 = String.new(str1)
|
||||
str2.setbyte(0, 108)
|
||||
str2.should == "ledgehog"
|
||||
str2.should_not == "hedgehog"
|
||||
str1.should == "hedgehog"
|
||||
str1.should_not == "ledgehog"
|
||||
end
|
||||
|
||||
it "raises a RuntimeError if self is frozen" do
|
||||
str = "cold".freeze
|
||||
str.frozen?.should be_true
|
||||
lambda { str.setbyte(3,96) }.should raise_error(RuntimeError)
|
||||
end
|
||||
|
||||
it "raises a TypeError unless the second argument is an Integer" do
|
||||
lambda { "a".setbyte(0,'a') }.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "calls #to_int to convert the index" do
|
||||
index = mock("setbyte index")
|
||||
index.should_receive(:to_int).and_return(1)
|
||||
|
||||
str = "hat"
|
||||
str.setbyte(index, "i".ord)
|
||||
str.should == "hit"
|
||||
end
|
||||
|
||||
it "calls to_int to convert the value" do
|
||||
value = mock("setbyte value")
|
||||
value.should_receive(:to_int).and_return("i".ord)
|
||||
|
||||
str = "hat"
|
||||
str.setbyte(1, value)
|
||||
str.should == "hit"
|
||||
end
|
||||
end
|
82
spec/ruby/core/string/shared/chars.rb
Normal file
82
spec/ruby/core/string/shared/chars.rb
Normal file
|
@ -0,0 +1,82 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
require File.expand_path('../../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../../fixtures/classes', __FILE__)
|
||||
|
||||
describe :string_chars, shared: true do
|
||||
it "passes each char in self to the given block" do
|
||||
a = []
|
||||
"hello".send(@method) { |c| a << c }
|
||||
a.should == ['h', 'e', 'l', 'l', 'o']
|
||||
end
|
||||
|
||||
it "returns self" do
|
||||
s = StringSpecs::MyString.new "hello"
|
||||
s.send(@method){}.should equal(s)
|
||||
end
|
||||
|
||||
|
||||
it "is unicode aware" do
|
||||
"\303\207\342\210\202\303\251\306\222g".send(@method).to_a.should ==
|
||||
["\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 "uses the String's encoding to determine what characters it contains" do
|
||||
s = "\u{24B62}"
|
||||
|
||||
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 "taints resulting strings when self is tainted" do
|
||||
str = "hello"
|
||||
|
||||
str.send(@method) do |x|
|
||||
x.tainted?.should == false
|
||||
end
|
||||
|
||||
str.dup.taint.send(@method) do |x|
|
||||
x.tainted?.should == true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
56
spec/ruby/core/string/shared/codepoints.rb
Normal file
56
spec/ruby/core/string/shared/codepoints.rb
Normal file
|
@ -0,0 +1,56 @@
|
|||
# -*- encoding: binary -*-
|
||||
describe :string_codepoints, shared: true do
|
||||
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.valid_encoding?.should be_false
|
||||
lambda { s.send(@method).to_a }.should raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it "yields each codepoint to the block if one is given" do
|
||||
codepoints = []
|
||||
"abcd".send(@method) do |codepoint|
|
||||
codepoints << codepoint
|
||||
end
|
||||
codepoints.should == [97, 98, 99, 100]
|
||||
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.valid_encoding?.should be_false
|
||||
lambda { s.send(@method) { } }.should raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it "returns codepoints as Fixnums" do
|
||||
"glark\u{20}".send(@method).to_a.each do |codepoint|
|
||||
codepoint.should be_an_instance_of(Fixnum)
|
||||
end
|
||||
end
|
||||
|
||||
it "returns 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
|
||||
|
||||
it "works for multibyte characters" do
|
||||
s = "\u{9819}"
|
||||
s.bytesize.should == 3
|
||||
s.send(@method).to_a.should == [38937]
|
||||
end
|
||||
|
||||
it "returns the codepoint 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 = ""
|
||||
s.send(@method) {|n| s2 << n.chr(Encoding::UTF_8)}
|
||||
s.should == s2
|
||||
end
|
||||
|
||||
it "is synonomous with #bytes for Strings which are single-byte optimisable" do
|
||||
s = "(){}".encode('ascii')
|
||||
s.ascii_only?.should be_true
|
||||
s.send(@method).to_a.should == s.bytes.to_a
|
||||
end
|
||||
end
|
160
spec/ruby/core/string/shared/concat.rb
Normal file
160
spec/ruby/core/string/shared/concat.rb
Normal file
|
@ -0,0 +1,160 @@
|
|||
describe :string_concat, shared: true do
|
||||
it "concatenates the given argument to self and returns self" do
|
||||
str = 'hello '
|
||||
str.send(@method, 'world').should equal(str)
|
||||
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
|
||||
a = "hello"
|
||||
a.freeze
|
||||
|
||||
lambda { a.send(@method, "") }.should raise_error(RuntimeError)
|
||||
lambda { a.send(@method, "test") }.should raise_error(RuntimeError)
|
||||
end
|
||||
|
||||
it "returns a String when given a subclass instance" do
|
||||
a = "hello"
|
||||
a.send(@method, StringSpecs::MyString.new(" world"))
|
||||
a.should == "hello world"
|
||||
a.should be_an_instance_of(String)
|
||||
end
|
||||
|
||||
it "returns an instance of same class when called on a subclass" do
|
||||
str = StringSpecs::MyString.new("hello")
|
||||
str.send(@method, " world")
|
||||
str.should == "hello world"
|
||||
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
|
||||
b = "".send(@method, 33)
|
||||
b.should == "!"
|
||||
|
||||
b.encode!(Encoding::UTF_8)
|
||||
b.send(@method, 0x203D)
|
||||
b.should == "!\u203D"
|
||||
end
|
||||
|
||||
# #5855
|
||||
it "returns a ASCII-8BIT 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.should == 128.chr
|
||||
|
||||
a = ("".encode(Encoding::US_ASCII).send(@method, 255))
|
||||
a.encoding.should == Encoding::ASCII_8BIT
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
end
|
||||
|
||||
it "raises a RuntimeError 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)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe :string_concat_encoding, shared: true do
|
||||
describe "when self is in an ASCII-incompatible encoding incompatible with the argument's encoding" do
|
||||
it "uses self's encoding if both are empty" do
|
||||
"".encode("UTF-16LE").send(@method, "").encoding.should == Encoding::UTF_16LE
|
||||
end
|
||||
|
||||
it "uses self's encoding if the argument is empty" do
|
||||
"x".encode("UTF-16LE").send(@method, "").encoding.should == Encoding::UTF_16LE
|
||||
end
|
||||
|
||||
it "uses the argument's encoding if self is empty" do
|
||||
"".encode("UTF-16LE").send(@method, "x".encode("UTF-8")).encoding.should == Encoding::UTF_8
|
||||
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)
|
||||
end
|
||||
end
|
||||
|
||||
describe "when the argument is in an ASCII-incompatible encoding incompatible with self's encoding" do
|
||||
it "uses self's encoding if both are empty" do
|
||||
"".encode("UTF-8").send(@method, "".encode("UTF-16LE")).encoding.should == Encoding::UTF_8
|
||||
end
|
||||
|
||||
it "uses self's encoding if the argument is empty" do
|
||||
"x".encode("UTF-8").send(@method, "".encode("UTF-16LE")).encoding.should == Encoding::UTF_8
|
||||
end
|
||||
|
||||
it "uses the argument's encoding if self is empty" do
|
||||
"".encode("UTF-8").send(@method, "x".encode("UTF-16LE")).encoding.should == Encoding::UTF_16LE
|
||||
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)
|
||||
end
|
||||
end
|
||||
|
||||
describe "when self and the argument are in different ASCII-compatible encodings" do
|
||||
it "uses self's encoding if both are ASCII-only" do
|
||||
"abc".encode("UTF-8").send(@method, "123".encode("SHIFT_JIS")).encoding.should == Encoding::UTF_8
|
||||
end
|
||||
|
||||
it "uses self's encoding if the argument is ASCII-only" do
|
||||
"\u00E9".encode("UTF-8").send(@method, "123".encode("ISO-8859-1")).encoding.should == Encoding::UTF_8
|
||||
end
|
||||
|
||||
it "uses the argument's encoding if self is ASCII-only" do
|
||||
"abc".encode("UTF-8").send(@method, "\u00E9".encode("ISO-8859-1")).encoding.should == Encoding::ISO_8859_1
|
||||
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)
|
||||
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
|
||||
end
|
||||
end
|
||||
end
|
26
spec/ruby/core/string/shared/each_char_without_block.rb
Normal file
26
spec/ruby/core/string/shared/each_char_without_block.rb
Normal file
|
@ -0,0 +1,26 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
require File.expand_path('../../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../../fixtures/classes', __FILE__)
|
||||
|
||||
describe :string_each_char_without_block, shared: true do
|
||||
describe "when no block is given" do
|
||||
it "returns an enumerator" do
|
||||
enum = "hello".send(@method)
|
||||
enum.should be_an_instance_of(Enumerator)
|
||||
enum.to_a.should == ['h', 'e', 'l', 'l', 'o']
|
||||
end
|
||||
|
||||
describe "returned enumerator" do
|
||||
describe "size" do
|
||||
it "should return the size of the string" do
|
||||
str = "hello"
|
||||
str.send(@method).size.should == str.size
|
||||
str = "ola"
|
||||
str.send(@method).size.should == str.size
|
||||
str = "\303\207\342\210\202\303\251\306\222g"
|
||||
str.send(@method).size.should == str.size
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
33
spec/ruby/core/string/shared/each_codepoint_without_block.rb
Normal file
33
spec/ruby/core/string/shared/each_codepoint_without_block.rb
Normal file
|
@ -0,0 +1,33 @@
|
|||
# -*- encoding: binary -*-
|
||||
describe :string_each_codepoint_without_block, shared: true do
|
||||
describe "when no block is given" do
|
||||
it "returns an Enumerator" do
|
||||
"".send(@method).should be_an_instance_of(Enumerator)
|
||||
end
|
||||
|
||||
it "returns an Enumerator even when self has an invalid encoding" do
|
||||
s = "\xDF".force_encoding(Encoding::UTF_8)
|
||||
s.valid_encoding?.should be_false
|
||||
s.send(@method).should be_an_instance_of(Enumerator)
|
||||
end
|
||||
|
||||
describe "returned Enumerator" do
|
||||
describe "size" do
|
||||
it "should return the size of the string" do
|
||||
str = "hello"
|
||||
str.send(@method).size.should == str.size
|
||||
str = "ola"
|
||||
str.send(@method).size.should == str.size
|
||||
str = "\303\207\342\210\202\303\251\306\222g"
|
||||
str.send(@method).size.should == str.size
|
||||
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.valid_encoding?.should be_false
|
||||
s.send(@method).size.should == 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
136
spec/ruby/core/string/shared/each_line.rb
Normal file
136
spec/ruby/core/string/shared/each_line.rb
Normal file
|
@ -0,0 +1,136 @@
|
|||
describe :string_each_line, shared: true do
|
||||
it "splits using default newline separator when none is specified" do
|
||||
a = []
|
||||
"one\ntwo\r\nthree".send(@method) { |s| a << s }
|
||||
a.should == ["one\n", "two\r\n", "three"]
|
||||
|
||||
b = []
|
||||
"hello\n\n\nworld".send(@method) { |s| b << s }
|
||||
b.should == ["hello\n", "\n", "\n", "world"]
|
||||
|
||||
c = []
|
||||
"\n\n\n\n\n".send(@method) {|s| c << s}
|
||||
c.should == ["\n", "\n", "\n", "\n", "\n"]
|
||||
end
|
||||
|
||||
it "splits self using the supplied record separator and passes each substring to the block" do
|
||||
a = []
|
||||
"one\ntwo\r\nthree".send(@method, "\n") { |s| a << s }
|
||||
a.should == ["one\n", "two\r\n", "three"]
|
||||
|
||||
b = []
|
||||
"hello\nworld".send(@method, 'l') { |s| b << s }
|
||||
b.should == [ "hel", "l", "o\nworl", "d" ]
|
||||
|
||||
c = []
|
||||
"hello\n\n\nworld".send(@method, "\n") { |s| c << s }
|
||||
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 }
|
||||
|
||||
"x.y.".send(@method, ".".taint) { |s| s.tainted?.should == false }
|
||||
end
|
||||
|
||||
it "passes self as a whole to the block if the separator is nil" do
|
||||
a = []
|
||||
"one\ntwo\r\nthree".send(@method, nil) { |s| a << s }
|
||||
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"]
|
||||
|
||||
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
|
||||
end
|
||||
|
||||
describe "uses $/" do
|
||||
before :each do
|
||||
@before_separator = $/
|
||||
end
|
||||
|
||||
after :each do
|
||||
$/ = @before_separator
|
||||
end
|
||||
|
||||
it "as the separator when none is given" do
|
||||
[
|
||||
"", "x", "x\ny", "x\ry", "x\r\ny", "x\n\r\r\ny",
|
||||
"hello hullo bello"
|
||||
].each do |str|
|
||||
["", "llo", "\n", "\r", nil].each do |sep|
|
||||
expected = []
|
||||
str.send(@method, sep) { |x| expected << x }
|
||||
|
||||
$/ = sep
|
||||
|
||||
actual = []
|
||||
str.send(@method) { |x| actual << x }
|
||||
|
||||
actual.should == expected
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "yields subclass instances for subclasses" do
|
||||
a = []
|
||||
StringSpecs::MyString.new("hello\nworld").send(@method) { |s| a << s.class }
|
||||
a.should == [StringSpecs::MyString, StringSpecs::MyString]
|
||||
end
|
||||
|
||||
it "returns self" do
|
||||
s = "hello\nworld"
|
||||
(s.send(@method) {}).should equal(s)
|
||||
end
|
||||
|
||||
it "tries to convert the separator to a string using to_str" do
|
||||
separator = mock('l')
|
||||
separator.should_receive(:to_str).and_return("l")
|
||||
|
||||
a = []
|
||||
"hello\nworld".send(@method, separator) { |s| a << s }
|
||||
a.should == [ "hel", "l", "o\nworl", "d" ]
|
||||
end
|
||||
|
||||
it "does not care if the string is modified while substituting" do
|
||||
str = "hello\nworld."
|
||||
out = []
|
||||
str.send(@method){|x| out << x; str[-1] = '!' }.should == "hello\nworld!"
|
||||
out.should == ["hello\n", "world."]
|
||||
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)
|
||||
end
|
||||
|
||||
it "accepts a string separator" do
|
||||
"hello world".send(@method, ?o).to_a.should == ["hello", " wo", "rld"]
|
||||
end
|
||||
|
||||
it "raises a TypeError when the separator is a symbol" do
|
||||
lambda { "hello world".send(@method, :o).to_a }.should raise_error(TypeError)
|
||||
end
|
||||
end
|
17
spec/ruby/core/string/shared/each_line_without_block.rb
Normal file
17
spec/ruby/core/string/shared/each_line_without_block.rb
Normal file
|
@ -0,0 +1,17 @@
|
|||
describe :string_each_line_without_block, shared: true do
|
||||
describe "when no block is given" do
|
||||
it "returns an enumerator" do
|
||||
enum = "hello world".send(@method, ' ')
|
||||
enum.should be_an_instance_of(Enumerator)
|
||||
enum.to_a.should == ["hello ", "world"]
|
||||
end
|
||||
|
||||
describe "returned Enumerator" do
|
||||
describe "size" do
|
||||
it "should return nil" do
|
||||
"hello world".send(@method, ' ').size.should == nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
247
spec/ruby/core/string/shared/encode.rb
Normal file
247
spec/ruby/core/string/shared/encode.rb
Normal file
|
@ -0,0 +1,247 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
describe :string_encode, shared: true do
|
||||
describe "when passed no options" do
|
||||
it "transcodes to Encoding.default_internal when set" do
|
||||
Encoding.default_internal = Encoding::UTF_8
|
||||
str = [0xA4, 0xA2].pack('CC').force_encoding Encoding::EUC_JP
|
||||
str.send(@method).should == "あ"
|
||||
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
|
||||
end.should raise_error(Encoding::ConverterNotFoundError)
|
||||
|
||||
Encoding.default_internal = Encoding::Emacs_Mule
|
||||
str = "\x79".force_encoding Encoding::ASCII_8BIT
|
||||
|
||||
str.send(@method).should == "y".force_encoding(Encoding::ASCII_8BIT)
|
||||
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)
|
||||
end
|
||||
end
|
||||
|
||||
describe "when passed to encoding" do
|
||||
it "accepts a String argument" do
|
||||
str = [0xA4, 0xA2].pack('CC').force_encoding Encoding::EUC_JP
|
||||
str.send(@method, "utf-8").should == "あ"
|
||||
end
|
||||
|
||||
it "calls #to_str to convert the object to an Encoding" do
|
||||
enc = mock("string encode encoding")
|
||||
enc.should_receive(:to_str).and_return("utf-8")
|
||||
|
||||
str = [0xA4, 0xA2].pack('CC').force_encoding Encoding::EUC_JP
|
||||
str.send(@method, enc).should == "あ"
|
||||
end
|
||||
|
||||
it "transcodes to the passed encoding" do
|
||||
str = [0xA4, 0xA2].pack('CC').force_encoding Encoding::EUC_JP
|
||||
str.send(@method, Encoding::UTF_8).should == "あ"
|
||||
end
|
||||
|
||||
it "transcodes Japanese multibyte characters" do
|
||||
str = "あいうえお"
|
||||
str.send(@method, Encoding::ISO_2022_JP).should ==
|
||||
"\e\x24\x42\x24\x22\x24\x24\x24\x26\x24\x28\x24\x2A\e\x28\x42".force_encoding(Encoding::ISO_2022_JP)
|
||||
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
|
||||
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)
|
||||
end
|
||||
|
||||
it "raises an Encoding::ConverterNotFoundError when no conversion is possible" do
|
||||
str = [0x80].pack('C').force_encoding Encoding::ASCII_8BIT
|
||||
lambda 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
|
||||
"abc".send(@method, "xyz")
|
||||
end.should raise_error(Encoding::ConverterNotFoundError)
|
||||
end
|
||||
end
|
||||
|
||||
describe "when passed options" do
|
||||
it "does not process transcoding options if not transcoding" do
|
||||
result = "あ\ufffdあ".send(@method, undef: :replace)
|
||||
result.should == "あ\ufffdあ"
|
||||
end
|
||||
|
||||
it "calls #to_hash to convert the object" do
|
||||
options = mock("string encode options")
|
||||
options.should_receive(:to_hash).and_return({ undef: :replace })
|
||||
|
||||
result = "あ\ufffdあ".send(@method, options)
|
||||
result.should == "あ\ufffdあ"
|
||||
end
|
||||
|
||||
it "transcodes to Encoding.default_internal when set" do
|
||||
Encoding.default_internal = Encoding::UTF_8
|
||||
str = [0xA4, 0xA2].pack('CC').force_encoding Encoding::EUC_JP
|
||||
str.send(@method, invalid: :replace).should == "あ"
|
||||
end
|
||||
|
||||
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.send(@method, invalid: :replace, undef: :replace)
|
||||
end.should raise_error(Encoding::ConverterNotFoundError)
|
||||
end
|
||||
|
||||
it "replaces invalid characters when replacing Emacs-Mule encoded strings" do
|
||||
got = [0x80].pack('C').force_encoding('Emacs-Mule').send(@method, invalid: :replace)
|
||||
|
||||
got.should == "?".encode('Emacs-Mule')
|
||||
end
|
||||
end
|
||||
|
||||
describe "when passed to, from" do
|
||||
it "transcodes between the encodings ignoring the String encoding" do
|
||||
str = "あ"
|
||||
result = [0xA6, 0xD0, 0x8F, 0xAB, 0xE4, 0x8F, 0xAB, 0xB1].pack('C8')
|
||||
result.force_encoding Encoding::EUC_JP
|
||||
str.send(@method, "euc-jp", "ibm437").should == result
|
||||
end
|
||||
|
||||
it "calls #to_str to convert the from object to an Encoding" do
|
||||
enc = mock("string encode encoding")
|
||||
enc.should_receive(:to_str).and_return("ibm437")
|
||||
|
||||
str = "あ"
|
||||
result = [0xA6, 0xD0, 0x8F, 0xAB, 0xE4, 0x8F, 0xAB, 0xB1].pack('C8')
|
||||
result.force_encoding Encoding::EUC_JP
|
||||
|
||||
str.send(@method, "euc-jp", enc).should == result
|
||||
end
|
||||
end
|
||||
|
||||
describe "when passed to, options" do
|
||||
it "replaces undefined characters in the destination encoding" do
|
||||
result = "あ?あ".send(@method, Encoding::EUC_JP, undef: :replace)
|
||||
# testing for: "\xA4\xA2?\xA4\xA2"
|
||||
xA4xA2 = [0xA4, 0xA2].pack('CC')
|
||||
result.should == "#{xA4xA2}?#{xA4xA2}".force_encoding("euc-jp")
|
||||
end
|
||||
|
||||
it "replaces invalid characters in the destination encoding" do
|
||||
xFF = [0xFF].pack('C').force_encoding('utf-8')
|
||||
"ab#{xFF}c".send(@method, Encoding::ISO_8859_1, invalid: :replace).should == "ab?c"
|
||||
end
|
||||
|
||||
it "calls #to_hash to convert the options object" do
|
||||
options = mock("string encode options")
|
||||
options.should_receive(:to_hash).and_return({ undef: :replace })
|
||||
|
||||
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
|
||||
end
|
||||
|
||||
describe "when passed to, from, options" do
|
||||
it "replaces undefined characters in the destination encoding" do
|
||||
str = "あ?あ".force_encoding Encoding::ASCII_8BIT
|
||||
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")
|
||||
end
|
||||
|
||||
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.send(@method, "iso-8859-1", "utf-8", invalid: :replace).should == "ab?c"
|
||||
end
|
||||
|
||||
it "calls #to_str to convert the to object to an encoding" do
|
||||
to = mock("string encode to encoding")
|
||||
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.send(@method, to, "utf-8", invalid: :replace).should == "ab?c"
|
||||
end
|
||||
|
||||
it "calls #to_str to convert the from object to an encoding" do
|
||||
from = mock("string encode to encoding")
|
||||
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.send(@method, "iso-8859-1", from, invalid: :replace).should == "ab?c"
|
||||
end
|
||||
|
||||
it "calls #to_hash to convert the options object" do
|
||||
options = mock("string encode options")
|
||||
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"
|
||||
end
|
||||
end
|
||||
|
||||
describe "given the xml: :text option" do
|
||||
it "replaces all instances of '&' with '&'" do
|
||||
'& and &'.send(@method, "UTF-8", xml: :text).should == '& and &'
|
||||
end
|
||||
|
||||
it "replaces all instances of '<' with '<'" do
|
||||
'< and <'.send(@method, "UTF-8", xml: :text).should == '< and <'
|
||||
end
|
||||
|
||||
it "replaces all instances of '>' with '>'" do
|
||||
'> and >'.send(@method, "UTF-8", xml: :text).should == '> and >'
|
||||
end
|
||||
|
||||
it "does not replace '\"'" do
|
||||
'" and "'.send(@method, "UTF-8", xml: :text).should == '" and "'
|
||||
end
|
||||
|
||||
it "replaces undefined characters with their upper-case hexadecimal numeric character references" do
|
||||
'ürst'.send(@method, Encoding::US_ASCII, xml: :text).should == 'ürst'
|
||||
end
|
||||
end
|
||||
|
||||
describe "given the xml: :attr option" do
|
||||
it "surrounds the encoded text with double-quotes" do
|
||||
'abc'.send(@method, "UTF-8", xml: :attr).should == '"abc"'
|
||||
end
|
||||
|
||||
it "replaces all instances of '&' with '&'" do
|
||||
'& and &'.send(@method, "UTF-8", xml: :attr).should == '"& and &"'
|
||||
end
|
||||
|
||||
it "replaces all instances of '<' with '<'" do
|
||||
'< and <'.send(@method, "UTF-8", xml: :attr).should == '"< and <"'
|
||||
end
|
||||
|
||||
it "replaces all instances of '>' with '>'" do
|
||||
'> and >'.send(@method, "UTF-8", xml: :attr).should == '"> and >"'
|
||||
end
|
||||
|
||||
it "replaces all instances of '\"' with '"'" do
|
||||
'" and "'.send(@method, "UTF-8", xml: :attr).should == '"" and ""'
|
||||
end
|
||||
|
||||
it "replaces undefined characters with their upper-case hexadecimal numeric character references" do
|
||||
'ürst'.send(@method, Encoding::US_ASCII, xml: :attr).should == '"ürst"'
|
||||
end
|
||||
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)
|
||||
end
|
||||
end
|
34
spec/ruby/core/string/shared/eql.rb
Normal file
34
spec/ruby/core/string/shared/eql.rb
Normal file
|
@ -0,0 +1,34 @@
|
|||
# -*- encoding: binary -*-
|
||||
require File.expand_path('../../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../../fixtures/classes', __FILE__)
|
||||
|
||||
describe :string_eql_value, shared: true do
|
||||
it "returns true if self <=> string returns 0" do
|
||||
'hello'.send(@method, 'hello').should be_true
|
||||
end
|
||||
|
||||
it "returns false if self <=> string does not return 0" do
|
||||
"more".send(@method, "MORE").should be_false
|
||||
"less".send(@method, "greater").should be_false
|
||||
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
|
||||
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
|
||||
end
|
||||
|
||||
it "considers encoding compatibility" do
|
||||
"hello".force_encoding("utf-8").send(@method, "hello".force_encoding("utf-32le")).should be_false
|
||||
end
|
||||
|
||||
it "ignores subclass differences" do
|
||||
a = "hello"
|
||||
b = StringSpecs::MyString.new("hello")
|
||||
|
||||
a.send(@method, b).should be_true
|
||||
b.send(@method, a).should be_true
|
||||
end
|
||||
end
|
29
spec/ruby/core/string/shared/equal_value.rb
Normal file
29
spec/ruby/core/string/shared/equal_value.rb
Normal file
|
@ -0,0 +1,29 @@
|
|||
require File.expand_path('../../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../../fixtures/classes', __FILE__)
|
||||
|
||||
describe :string_equal_value, shared: true do
|
||||
it "returns false if obj does not respond to to_str" do
|
||||
'hello'.send(@method, 5).should be_false
|
||||
not_supported_on :opal do
|
||||
'hello'.send(@method, :hello).should be_false
|
||||
end
|
||||
'hello'.send(@method, mock('x')).should be_false
|
||||
end
|
||||
|
||||
it "returns obj == self if obj responds to to_str" do
|
||||
obj = Object.new
|
||||
|
||||
# String#== merely checks if #to_str is defined. It does
|
||||
# not call it.
|
||||
obj.stub!(:to_str)
|
||||
|
||||
# Don't use @method for :== in `obj.should_recerive(:==)`
|
||||
obj.should_receive(:==).and_return(true)
|
||||
|
||||
'hello'.send(@method, obj).should be_true
|
||||
end
|
||||
|
||||
it "is not fooled by NUL characters" do
|
||||
"abc\0def".send(@method, "abc\0xyz").should be_false
|
||||
end
|
||||
end
|
28
spec/ruby/core/string/shared/length.rb
Normal file
28
spec/ruby/core/string/shared/length.rb
Normal file
|
@ -0,0 +1,28 @@
|
|||
# encoding: utf-8
|
||||
|
||||
describe :string_length, shared: true do
|
||||
it "returns the length of self" do
|
||||
"".send(@method).should == 0
|
||||
"\x00".send(@method).should == 1
|
||||
"one".send(@method).should == 3
|
||||
"two".send(@method).should == 3
|
||||
"three".send(@method).should == 5
|
||||
"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
|
||||
end
|
||||
end
|
75
spec/ruby/core/string/shared/replace.rb
Normal file
75
spec/ruby/core/string/shared/replace.rb
Normal file
|
@ -0,0 +1,75 @@
|
|||
describe :string_replace, shared: true do
|
||||
it "returns self" do
|
||||
a = "a"
|
||||
a.send(@method, "b").should equal(a)
|
||||
end
|
||||
|
||||
it "replaces the content of self with other" do
|
||||
a = "some string"
|
||||
a.send(@method, "another string")
|
||||
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")
|
||||
a.send(@method, b)
|
||||
a.encoding.should == Encoding::UTF_8
|
||||
end
|
||||
|
||||
it "carries over the encoding invalidity" do
|
||||
a = "\u{8765}".force_encoding('ascii')
|
||||
"".send(@method, a).valid_encoding?.should be_false
|
||||
end
|
||||
|
||||
it "tries to convert other to string using to_str" do
|
||||
other = mock('x')
|
||||
other.should_receive(:to_str).and_return("converted to a string")
|
||||
"hello".send(@method, other).should == "converted to a string"
|
||||
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)
|
||||
end
|
||||
|
||||
it "raises a RuntimeError on a frozen instance that is modified" do
|
||||
a = "hello".freeze
|
||||
lambda { a.send(@method, "world") }.should raise_error(RuntimeError)
|
||||
end
|
||||
|
||||
# see [ruby-core:23666]
|
||||
it "raises a RuntimeError on a frozen instance when self-replacing" do
|
||||
a = "hello".freeze
|
||||
lambda { a.send(@method, a) }.should raise_error(RuntimeError)
|
||||
end
|
||||
end
|
557
spec/ruby/core/string/shared/slice.rb
Normal file
557
spec/ruby/core/string/shared/slice.rb
Normal file
|
@ -0,0 +1,557 @@
|
|||
describe :string_slice, shared: true do
|
||||
it "returns the character code of the character at the given index" do
|
||||
"hello".send(@method, 0).should == ?h
|
||||
"hello".send(@method, -1).should == ?o
|
||||
end
|
||||
|
||||
it "returns nil if index is outside of self" do
|
||||
"hello".send(@method, 20).should == nil
|
||||
"hello".send(@method, -20).should == nil
|
||||
|
||||
"".send(@method, 0).should == nil
|
||||
"".send(@method, -1).should == nil
|
||||
end
|
||||
|
||||
it "calls to_int on the given index" do
|
||||
"hello".send(@method, 0.5).should == ?h
|
||||
|
||||
obj = mock('1')
|
||||
obj.should_receive(:to_int).and_return(1)
|
||||
"hello".send(@method, obj).should == ?e
|
||||
end
|
||||
|
||||
it "raises a TypeError if the given index is nil" do
|
||||
lambda { "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)
|
||||
end
|
||||
|
||||
it "raises a RangeError if the index is too big" do
|
||||
lambda { "hello".send(@method, bignum_value) }.should raise_error(RangeError)
|
||||
end
|
||||
end
|
||||
|
||||
describe :string_slice_index_length, shared: true do
|
||||
it "returns the substring starting at the given index with the given length" do
|
||||
"hello there".send(@method, 0,0).should == ""
|
||||
"hello there".send(@method, 0,1).should == "h"
|
||||
"hello there".send(@method, 0,3).should == "hel"
|
||||
"hello there".send(@method, 0,6).should == "hello "
|
||||
"hello there".send(@method, 0,9).should == "hello the"
|
||||
"hello there".send(@method, 0,12).should == "hello there"
|
||||
|
||||
"hello there".send(@method, 1,0).should == ""
|
||||
"hello there".send(@method, 1,1).should == "e"
|
||||
"hello there".send(@method, 1,3).should == "ell"
|
||||
"hello there".send(@method, 1,6).should == "ello t"
|
||||
"hello there".send(@method, 1,9).should == "ello ther"
|
||||
"hello there".send(@method, 1,12).should == "ello there"
|
||||
|
||||
"hello there".send(@method, 3,0).should == ""
|
||||
"hello there".send(@method, 3,1).should == "l"
|
||||
"hello there".send(@method, 3,3).should == "lo "
|
||||
"hello there".send(@method, 3,6).should == "lo the"
|
||||
"hello there".send(@method, 3,9).should == "lo there"
|
||||
|
||||
"hello there".send(@method, 4,0).should == ""
|
||||
"hello there".send(@method, 4,3).should == "o t"
|
||||
"hello there".send(@method, 4,6).should == "o ther"
|
||||
"hello there".send(@method, 4,9).should == "o there"
|
||||
|
||||
"foo".send(@method, 2,1).should == "o"
|
||||
"foo".send(@method, 3,0).should == ""
|
||||
"foo".send(@method, 3,1).should == ""
|
||||
|
||||
"".send(@method, 0,0).should == ""
|
||||
"".send(@method, 0,1).should == ""
|
||||
|
||||
"x".send(@method, 0,0).should == ""
|
||||
"x".send(@method, 0,1).should == "x"
|
||||
"x".send(@method, 1,0).should == ""
|
||||
"x".send(@method, 1,1).should == ""
|
||||
|
||||
"x".send(@method, -1,0).should == ""
|
||||
"x".send(@method, -1,1).should == "x"
|
||||
|
||||
"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
|
||||
s = "hello there"
|
||||
s.send(@method, 1, 9).encoding.should == s.encoding
|
||||
|
||||
a = "hello".force_encoding("binary")
|
||||
b = " there".force_encoding("ISO-8859-1")
|
||||
c = (a + b).force_encoding(Encoding::US_ASCII)
|
||||
|
||||
c.send(@method, 0, 5).encoding.should == Encoding::US_ASCII
|
||||
c.send(@method, 5, 6).encoding.should == Encoding::US_ASCII
|
||||
c.send(@method, 1, 3).encoding.should == Encoding::US_ASCII
|
||||
c.send(@method, 8, 2).encoding.should == Encoding::US_ASCII
|
||||
c.send(@method, 1, 10).encoding.should == Encoding::US_ASCII
|
||||
end
|
||||
|
||||
it "returns nil if the offset falls outside of self" do
|
||||
"hello there".send(@method, 20,3).should == nil
|
||||
"hello there".send(@method, -20,3).should == nil
|
||||
|
||||
"".send(@method, 1,0).should == nil
|
||||
"".send(@method, 1,1).should == nil
|
||||
|
||||
"".send(@method, -1,0).should == nil
|
||||
"".send(@method, -1,1).should == nil
|
||||
|
||||
"x".send(@method, 2,0).should == nil
|
||||
"x".send(@method, 2,1).should == nil
|
||||
|
||||
"x".send(@method, -2,0).should == nil
|
||||
"x".send(@method, -2,1).should == nil
|
||||
end
|
||||
|
||||
it "returns nil if the length is negative" do
|
||||
"hello there".send(@method, 4,-3).should == nil
|
||||
"hello there".send(@method, -4,-3).should == nil
|
||||
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"
|
||||
"hello".send(@method, 1, 2.5).should == "el"
|
||||
|
||||
obj = mock('2')
|
||||
obj.should_receive(:to_int).exactly(4).times.and_return(2)
|
||||
|
||||
"hello".send(@method, obj, 1).should == "l"
|
||||
"hello".send(@method, obj, obj).should == "ll"
|
||||
"hello".send(@method, 0, obj).should == "he"
|
||||
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)
|
||||
|
||||
# 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)
|
||||
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)
|
||||
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)
|
||||
end
|
||||
|
||||
it "returns subclass 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)
|
||||
end
|
||||
|
||||
it "handles repeated application" do
|
||||
"hello world".send(@method, 6, 5).send(@method, 0, 1).should == 'w'
|
||||
"hello world".send(@method, 6, 5).send(@method, 0, 5).should == 'world'
|
||||
|
||||
"hello world".send(@method, 6, 5).send(@method, 1, 1).should == 'o'
|
||||
"hello world".send(@method, 6, 5).send(@method, 1, 4).should == 'orld'
|
||||
|
||||
"hello world".send(@method, 6, 5).send(@method, 4, 1).should == 'd'
|
||||
"hello world".send(@method, 6, 5).send(@method, 5, 0).should == ''
|
||||
|
||||
"hello world".send(@method, 6, 0).send(@method, -1, 0).should == nil
|
||||
"hello world".send(@method, 6, 0).send(@method, 1, 1).should == nil
|
||||
end
|
||||
end
|
||||
|
||||
describe :string_slice_range, shared: true do
|
||||
it "returns the substring given by the offsets of the range" do
|
||||
"hello there".send(@method, 1..1).should == "e"
|
||||
"hello there".send(@method, 1..3).should == "ell"
|
||||
"hello there".send(@method, 1...3).should == "el"
|
||||
"hello there".send(@method, -4..-2).should == "her"
|
||||
"hello there".send(@method, -4...-2).should == "he"
|
||||
"hello there".send(@method, 5..-1).should == " there"
|
||||
"hello there".send(@method, 5...-1).should == " ther"
|
||||
|
||||
"".send(@method, 0..0).should == ""
|
||||
|
||||
"x".send(@method, 0..0).should == "x"
|
||||
"x".send(@method, 0..1).should == "x"
|
||||
"x".send(@method, 0...1).should == "x"
|
||||
"x".send(@method, 0..-1).should == "x"
|
||||
|
||||
"x".send(@method, 1..1).should == ""
|
||||
"x".send(@method, 1..-1).should == ""
|
||||
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
|
||||
"hello there".send(@method, 20..1).should == nil
|
||||
"hello there".send(@method, -20..1).should == nil
|
||||
"hello there".send(@method, -20..-1).should == nil
|
||||
|
||||
"".send(@method, -1..-1).should == nil
|
||||
"".send(@method, -1...-1).should == nil
|
||||
"".send(@method, -1..0).should == nil
|
||||
"".send(@method, -1...0).should == nil
|
||||
end
|
||||
|
||||
it "returns an empty string if range.begin is inside self and > real end" do
|
||||
"hello there".send(@method, 1...1).should == ""
|
||||
"hello there".send(@method, 4..2).should == ""
|
||||
"hello".send(@method, 4..-4).should == ""
|
||||
"hello there".send(@method, -5..-6).should == ""
|
||||
"hello there".send(@method, -2..-4).should == ""
|
||||
"hello there".send(@method, -5..-6).should == ""
|
||||
"hello there".send(@method, -5..2).should == ""
|
||||
|
||||
"".send(@method, 0...0).should == ""
|
||||
"".send(@method, 0..-1).should == ""
|
||||
"".send(@method, 0...-1).should == ""
|
||||
|
||||
"x".send(@method, 0...0).should == ""
|
||||
"x".send(@method, 0...-1).should == ""
|
||||
"x".send(@method, 1...1).should == ""
|
||||
"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
|
||||
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)
|
||||
end
|
||||
|
||||
it "calls to_int on range arguments" do
|
||||
from = mock('from')
|
||||
to = mock('to')
|
||||
|
||||
# So we can construct a range out of them...
|
||||
from.should_receive(:<=>).twice.and_return(0)
|
||||
|
||||
from.should_receive(:to_int).twice.and_return(1)
|
||||
to.should_receive(:to_int).twice.and_return(-2)
|
||||
|
||||
"hello there".send(@method, from..to).should == "ello ther"
|
||||
"hello there".send(@method, from...to).should == "ello the"
|
||||
end
|
||||
|
||||
it "works with Range subclasses" do
|
||||
a = "GOOD"
|
||||
range_incl = StringSpecs::MyRange.new(1, 2)
|
||||
range_excl = StringSpecs::MyRange.new(-3, -1, true)
|
||||
|
||||
a.send(@method, range_incl).should == "OO"
|
||||
a.send(@method, range_excl).should == "OO"
|
||||
end
|
||||
|
||||
it "handles repeated application" do
|
||||
"hello world".send(@method, 6..11).send(@method, 0..0).should == 'w'
|
||||
"hello world".send(@method, 6..11).send(@method, 0..4).should == 'world'
|
||||
|
||||
"hello world".send(@method, 6..11).send(@method, 1..1).should == 'o'
|
||||
"hello world".send(@method, 6..11).send(@method, 1..4).should == 'orld'
|
||||
|
||||
"hello world".send(@method, 6..11).send(@method, 4..4).should == 'd'
|
||||
"hello world".send(@method, 6..11).send(@method, 5..4).should == ''
|
||||
|
||||
"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
|
||||
end
|
||||
|
||||
describe :string_slice_regexp, shared: true do
|
||||
it "returns the matching portion of self" do
|
||||
"hello there".send(@method, /[aeiou](.)\1/).should == "ell"
|
||||
"".send(@method, //).should == ""
|
||||
end
|
||||
|
||||
it "returns nil if there is no match" 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
|
||||
end
|
||||
|
||||
it "returns subclass 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)
|
||||
end
|
||||
|
||||
it "sets $~ to MatchData when there is a match and nil when there's none" do
|
||||
'hello'.send(@method, /./)
|
||||
$~[0].should == 'h'
|
||||
|
||||
'hello'.send(@method, /not/)
|
||||
$~.should == nil
|
||||
end
|
||||
end
|
||||
|
||||
describe :string_slice_regexp_index, shared: true do
|
||||
it "returns the capture for the given index" do
|
||||
"hello there".send(@method, /[aeiou](.)\1/, 0).should == "ell"
|
||||
"hello there".send(@method, /[aeiou](.)\1/, 1).should == "l"
|
||||
"hello there".send(@method, /[aeiou](.)\1/, -1).should == "l"
|
||||
|
||||
"har".send(@method, /(.)(.)(.)/, 0).should == "har"
|
||||
"har".send(@method, /(.)(.)(.)/, 1).should == "h"
|
||||
"har".send(@method, /(.)(.)(.)/, 2).should == "a"
|
||||
"har".send(@method, /(.)(.)(.)/, 3).should == "r"
|
||||
"har".send(@method, /(.)(.)(.)/, -1).should == "r"
|
||||
"har".send(@method, /(.)(.)(.)/, -2).should == "a"
|
||||
"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
|
||||
|
||||
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
|
||||
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
|
||||
end
|
||||
|
||||
it "returns nil if there is no match" do
|
||||
"hello there".send(@method, /(what?)/, 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
|
||||
end
|
||||
|
||||
it "calls to_int on the given index" do
|
||||
obj = mock('2')
|
||||
obj.should_receive(:to_int).and_return(2)
|
||||
|
||||
"har".send(@method, /(.)(.)(.)/, 1.5).should == "h"
|
||||
"har".send(@method, /(.)(.)(.)/, obj).should == "a"
|
||||
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)
|
||||
end
|
||||
|
||||
it "raises a TypeError when the given index is nil" do
|
||||
lambda { "hello".send(@method, /(.)(.)(.)/, nil) }.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "returns subclass 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)
|
||||
end
|
||||
|
||||
it "sets $~ to MatchData when there is a match and nil when there's none" do
|
||||
'hello'.send(@method, /.(.)/, 0)
|
||||
$~[0].should == 'he'
|
||||
|
||||
'hello'.send(@method, /.(.)/, 1)
|
||||
$~[1].should == 'e'
|
||||
|
||||
'hello'.send(@method, /not/, 0)
|
||||
$~.should == nil
|
||||
end
|
||||
end
|
||||
|
||||
describe :string_slice_string, shared: true do
|
||||
it "returns other_str if it occurs in self" do
|
||||
s = "lo"
|
||||
"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
|
||||
|
||||
'hello'.send(@method, 'll')
|
||||
$~.should == nil
|
||||
end
|
||||
|
||||
it "returns nil if there is no match" do
|
||||
"hello there".send(@method, "bye").should == nil
|
||||
end
|
||||
|
||||
it "doesn't call to_str on its argument" do
|
||||
o = mock('x')
|
||||
o.should_not_receive(:to_str)
|
||||
|
||||
lambda { "hello".send(@method, o) }.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "returns a subclass 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)
|
||||
end
|
||||
end
|
||||
|
||||
describe :string_slice_regexp_group, shared: true do
|
||||
not_supported_on :opal do
|
||||
it "returns the capture for the given name" do
|
||||
"hello there".send(@method, /(?<g>[aeiou](.))/, 'g').should == "el"
|
||||
"hello there".send(@method, /[aeiou](?<g>.)/, 'g').should == "l"
|
||||
|
||||
"har".send(@method, /(?<g>(.)(.)(.))/, 'g').should == "har"
|
||||
"har".send(@method, /(?<h>.)(.)(.)/, 'h').should == "h"
|
||||
"har".send(@method, /(.)(?<a>.)(.)/, 'a').should == "a"
|
||||
"har".send(@method, /(.)(.)(?<r>.)/, 'r').should == "r"
|
||||
"har".send(@method, /(?<h>.)(?<a>.)(?<r>.)/, 'r').should == "r"
|
||||
end
|
||||
|
||||
it "returns the last capture for duplicate names" do
|
||||
"hello there".send(@method, /(?<g>h)(?<g>.)/, 'g').should == "e"
|
||||
"hello there".send(@method, /(?<g>h)(?<g>.)(?<f>.)/, 'g').should == "e"
|
||||
end
|
||||
|
||||
it "returns the innermost capture for nested duplicate names" 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
|
||||
"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)
|
||||
end
|
||||
|
||||
it "raises an IndexError when given the empty String as a group name" do
|
||||
lambda { "hello".send(@method, /(?<q>)/, '') }.should raise_error(IndexError)
|
||||
end
|
||||
|
||||
it "returns subclass instances" do
|
||||
s = StringSpecs::MyString.new("hello")
|
||||
s.send(@method, /(?<q>.)/, 'q').should be_an_instance_of(StringSpecs::MyString)
|
||||
end
|
||||
|
||||
it "sets $~ to MatchData when there is a match and nil when there's none" do
|
||||
'hello'.send(@method, /(?<hi>.(.))/, 'hi')
|
||||
$~[0].should == 'he'
|
||||
|
||||
'hello'.send(@method, /(?<non>not)/, 'non')
|
||||
$~.should be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe :string_slice_symbol, shared: true do
|
||||
it "raises TypeError" do
|
||||
lambda { 'hello'.send(@method, :hello) }.should raise_error(TypeError)
|
||||
end
|
||||
end
|
88
spec/ruby/core/string/shared/succ.rb
Normal file
88
spec/ruby/core/string/shared/succ.rb
Normal file
|
@ -0,0 +1,88 @@
|
|||
# -*- encoding: binary -*-
|
||||
describe :string_succ, shared: true do
|
||||
it "returns an empty string for empty strings" do
|
||||
"".send(@method).should == ""
|
||||
end
|
||||
|
||||
it "returns the successor by increasing the rightmost alphanumeric (digit => digit, letter => letter with same case)" do
|
||||
"abcd".send(@method).should == "abce"
|
||||
"THX1138".send(@method).should == "THX1139"
|
||||
|
||||
"<<koala>>".send(@method).should == "<<koalb>>"
|
||||
"==A??".send(@method).should == "==B??"
|
||||
end
|
||||
|
||||
it "increases non-alphanumerics (via ascii rules) if there are no alphanumerics" do
|
||||
"***".send(@method).should == "**+"
|
||||
"**`".send(@method).should == "**a"
|
||||
end
|
||||
|
||||
it "increases the next best alphanumeric (jumping over non-alphanumerics) if there is a carry" do
|
||||
"dz".send(@method).should == "ea"
|
||||
"HZ".send(@method).should == "IA"
|
||||
"49".send(@method).should == "50"
|
||||
|
||||
"izz".send(@method).should == "jaa"
|
||||
"IZZ".send(@method).should == "JAA"
|
||||
"699".send(@method).should == "700"
|
||||
|
||||
"6Z99z99Z".send(@method).should == "7A00a00A"
|
||||
|
||||
"1999zzz".send(@method).should == "2000aaa"
|
||||
"NZ/[]ZZZ9999".send(@method).should == "OA/[]AAA0000"
|
||||
end
|
||||
|
||||
it "increases the next best character if there is a carry for non-alphanumerics" do
|
||||
"(\xFF".send(@method).should == ")\x00"
|
||||
"`\xFF".send(@method).should == "a\x00"
|
||||
"<\xFF\xFF".send(@method).should == "=\x00\x00"
|
||||
end
|
||||
|
||||
it "adds an additional character (just left to the last increased one) if there is a carry and no character left to increase" do
|
||||
"z".send(@method).should == "aa"
|
||||
"Z".send(@method).should == "AA"
|
||||
"9".send(@method).should == "10"
|
||||
|
||||
"zz".send(@method).should == "aaa"
|
||||
"ZZ".send(@method).should == "AAA"
|
||||
"99".send(@method).should == "100"
|
||||
|
||||
"9Z99z99Z".send(@method).should == "10A00a00A"
|
||||
|
||||
"ZZZ9999".send(@method).should == "AAAA0000"
|
||||
"/[]9999".send(@method).should == "/[]10000"
|
||||
"/[]ZZZ9999".send(@method).should == "/[]AAAA0000"
|
||||
"Z/[]ZZZ9999".send(@method).should == "AA/[]AAA0000"
|
||||
|
||||
# non-alphanumeric cases
|
||||
"\xFF".send(@method).should == "\x01\x00"
|
||||
"\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)
|
||||
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
|
||||
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|
|
||||
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)
|
||||
end
|
||||
end
|
9
spec/ruby/core/string/shared/to_a.rb
Normal file
9
spec/ruby/core/string/shared/to_a.rb
Normal file
|
@ -0,0 +1,9 @@
|
|||
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
|
18
spec/ruby/core/string/shared/to_s.rb
Normal file
18
spec/ruby/core/string/shared/to_s.rb
Normal file
|
@ -0,0 +1,18 @@
|
|||
describe :string_to_s, shared: true do
|
||||
it "returns self when self.class == String" do
|
||||
a = "a string"
|
||||
a.should equal(a.send(@method))
|
||||
end
|
||||
|
||||
it "returns a new instance of String when called on a subclass" do
|
||||
a = StringSpecs::MyString.new("a string")
|
||||
s = a.send(@method)
|
||||
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
|
24
spec/ruby/core/string/shared/to_sym.rb
Normal file
24
spec/ruby/core/string/shared/to_sym.rb
Normal file
|
@ -0,0 +1,24 @@
|
|||
describe :string_to_sym, shared: true do
|
||||
it "returns the symbol corresponding to self" do
|
||||
"Koala".send(@method).should == :Koala
|
||||
'cat'.send(@method).should == :cat
|
||||
'@cat'.send(@method).should == :@cat
|
||||
'cat and dog'.send(@method).should == :"cat and dog"
|
||||
"abc=".send(@method).should == :abc=
|
||||
end
|
||||
|
||||
it "does not special case +(binary) and -(binary)" do
|
||||
"+(binary)".send(@method).should == :"+(binary)"
|
||||
"-(binary)".send(@method).should == :"-(binary)"
|
||||
end
|
||||
|
||||
it "does not special case certain operators" do
|
||||
[ ["!@", :"!@"],
|
||||
["~@", :"~@"],
|
||||
["!(unary)", :"!(unary)"],
|
||||
["~(unary)", :"~(unary)"],
|
||||
["+(unary)", :"+(unary)"],
|
||||
["-(unary)", :"-(unary)"]
|
||||
].should be_computed_by(@method)
|
||||
end
|
||||
end
|
7
spec/ruby/core/string/size_spec.rb
Normal file
7
spec/ruby/core/string/size_spec.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
require File.expand_path('../shared/length', __FILE__)
|
||||
|
||||
describe "String#size" do
|
||||
it_behaves_like(:string_length, :size)
|
||||
end
|
476
spec/ruby/core/string/slice_spec.rb
Normal file
476
spec/ruby/core/string/slice_spec.rb
Normal file
|
@ -0,0 +1,476 @@
|
|||
# -*- 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__)
|
||||
|
||||
describe "String#slice" do
|
||||
it_behaves_like :string_slice, :slice
|
||||
end
|
||||
|
||||
describe "String#slice with index, length" do
|
||||
it_behaves_like :string_slice_index_length, :slice
|
||||
end
|
||||
|
||||
describe "String#slice with Range" do
|
||||
it_behaves_like :string_slice_range, :slice
|
||||
end
|
||||
|
||||
describe "String#slice with Regexp" do
|
||||
it_behaves_like :string_slice_regexp, :slice
|
||||
end
|
||||
|
||||
describe "String#slice with Regexp, index" do
|
||||
it_behaves_like :string_slice_regexp_index, :slice
|
||||
end
|
||||
|
||||
describe "String#slice with Regexp, group" do
|
||||
it_behaves_like :string_slice_regexp_group, :slice
|
||||
end
|
||||
|
||||
describe "String#slice with String" do
|
||||
it_behaves_like :string_slice_string, :slice
|
||||
end
|
||||
|
||||
describe "String#slice with Symbol" do
|
||||
it_behaves_like :string_slice_symbol, :slice
|
||||
end
|
||||
|
||||
describe "String#slice! with index" do
|
||||
it "deletes and return the char at the given position" do
|
||||
a = "hello"
|
||||
a.slice!(1).should == ?e
|
||||
a.should == "hllo"
|
||||
a.slice!(-1).should == ?o
|
||||
a.should == "hll"
|
||||
end
|
||||
|
||||
it "returns nil if idx is outside of self" do
|
||||
a = "hello"
|
||||
a.slice!(20).should == nil
|
||||
a.should == "hello"
|
||||
a.slice!(-20).should == nil
|
||||
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)
|
||||
end
|
||||
|
||||
it "calls to_int on index" do
|
||||
"hello".slice!(0.5).should == ?h
|
||||
|
||||
obj = mock('1')
|
||||
obj.should_receive(:to_int).at_least(1).and_return(1)
|
||||
"hello".slice!(obj).should == ?e
|
||||
|
||||
obj = mock('1')
|
||||
obj.should_receive(:respond_to?).at_least(1).with(:to_int, true).and_return(true)
|
||||
obj.should_receive(:method_missing).at_least(1).with(:to_int).and_return(1)
|
||||
"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
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
describe "String#slice! with index, length" do
|
||||
it "deletes and returns the substring at idx and the given length" do
|
||||
a = "hello"
|
||||
a.slice!(1, 2).should == "el"
|
||||
a.should == "hlo"
|
||||
|
||||
a.slice!(1, 0).should == ""
|
||||
a.should == "hlo"
|
||||
|
||||
a.slice!(-2, 4).should == "lo"
|
||||
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
|
||||
a.should == "hello"
|
||||
|
||||
a.slice(-10, 20).should == nil
|
||||
a.should == "hello"
|
||||
end
|
||||
|
||||
it "returns nil if the length is negative" do
|
||||
a = "hello"
|
||||
a.slice(4, -3).should == nil
|
||||
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)
|
||||
end
|
||||
|
||||
it "calls to_int on idx and length" do
|
||||
"hello".slice!(0.5, 2.5).should == "he"
|
||||
|
||||
obj = mock('2')
|
||||
def obj.to_int() 2 end
|
||||
"hello".slice!(obj, obj).should == "ll"
|
||||
|
||||
obj = mock('2')
|
||||
def obj.respond_to?(name, *) name == :to_int; end
|
||||
def obj.method_missing(name, *) name == :to_int ? 2 : super; end
|
||||
"hello".slice!(obj, obj).should == "ll"
|
||||
end
|
||||
|
||||
it "returns subclass 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)
|
||||
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 "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
|
||||
end
|
||||
end
|
||||
|
||||
describe "String#slice! Range" do
|
||||
it "deletes and return the substring given by the offsets of the range" do
|
||||
a = "hello"
|
||||
a.slice!(1..3).should == "ell"
|
||||
a.should == "ho"
|
||||
a.slice!(0..0).should == "h"
|
||||
a.should == "o"
|
||||
a.slice!(0...0).should == ""
|
||||
a.should == "o"
|
||||
|
||||
# Edge Case?
|
||||
"hello".slice!(-3..-9).should == ""
|
||||
end
|
||||
|
||||
it "returns nil if the given range is out of self" do
|
||||
a = "hello"
|
||||
a.slice!(-6..-9).should == nil
|
||||
a.should == "hello"
|
||||
|
||||
b = "hello"
|
||||
b.slice!(10..20).should == nil
|
||||
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
|
||||
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)
|
||||
end
|
||||
|
||||
it "calls to_int on range arguments" do
|
||||
from = mock('from')
|
||||
to = mock('to')
|
||||
|
||||
# So we can construct a range out of them...
|
||||
def from.<=>(o) 0 end
|
||||
def to.<=>(o) 0 end
|
||||
|
||||
def from.to_int() 1 end
|
||||
def to.to_int() -2 end
|
||||
|
||||
"hello there".slice!(from..to).should == "ello ther"
|
||||
|
||||
from = mock('from')
|
||||
to = mock('to')
|
||||
|
||||
def from.<=>(o) 0 end
|
||||
def to.<=>(o) 0 end
|
||||
|
||||
def from.respond_to?(name, *) name == :to_int; end
|
||||
def from.method_missing(name) name == :to_int ? 1 : super; end
|
||||
def to.respond_to?(name, *) name == :to_int; end
|
||||
def to.method_missing(name) name == :to_int ? -2 : super; end
|
||||
|
||||
"hello there".slice!(from..to).should == "ello ther"
|
||||
end
|
||||
|
||||
it "works with Range subclasses" do
|
||||
a = "GOOD"
|
||||
range_incl = StringSpecs::MyRange.new(1, 2)
|
||||
|
||||
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
|
||||
|
||||
end
|
||||
|
||||
it "raises a RuntimeError on a frozen instance that is modified" do
|
||||
lambda { "hello".freeze.slice!(1..3) }.should raise_error(RuntimeError)
|
||||
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)
|
||||
end
|
||||
end
|
||||
|
||||
describe "String#slice! with Regexp" do
|
||||
it "deletes and returns the first match from self" do
|
||||
s = "this is a string"
|
||||
s.slice!(/s.*t/).should == 's is a st'
|
||||
s.should == 'thiring'
|
||||
|
||||
c = "hello hello"
|
||||
c.slice!(/llo/).should == "llo"
|
||||
c.should == "he hello"
|
||||
end
|
||||
|
||||
it "returns nil if there was no match" do
|
||||
s = "this is a string"
|
||||
s.slice!(/zzz/).should == nil
|
||||
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
|
||||
s = StringSpecs::MyString.new("hello")
|
||||
s.slice!(//).should be_an_instance_of(StringSpecs::MyString)
|
||||
s.slice!(/../).should be_an_instance_of(StringSpecs::MyString)
|
||||
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
|
||||
end
|
||||
|
||||
it "sets $~ to MatchData when there is a match and nil when there's none" do
|
||||
'hello'.slice!(/./)
|
||||
$~[0].should == 'h'
|
||||
|
||||
'hello'.slice!(/not/)
|
||||
$~.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)
|
||||
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)
|
||||
end
|
||||
end
|
||||
|
||||
describe "String#slice! with Regexp, index" do
|
||||
it "deletes and returns the capture for idx from self" do
|
||||
str = "hello there"
|
||||
str.slice!(/[aeiou](.)\1/, 0).should == "ell"
|
||||
str.should == "ho there"
|
||||
str.slice!(/(t)h/, 1).should == "t"
|
||||
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
|
||||
s.should == "this is a string"
|
||||
end
|
||||
|
||||
it "returns nil if there is no capture for idx" do
|
||||
"hello there".slice!(/[aeiou](.)\1/, 2).should == nil
|
||||
# You can't refer to 0 using negative indices
|
||||
"hello there".slice!(/[aeiou](.)\1/, -2).should == nil
|
||||
end
|
||||
|
||||
it "accepts a Float for capture index" do
|
||||
"har".slice!(/(.)(.)(.)/, 1.5).should == "h"
|
||||
end
|
||||
|
||||
it "calls #to_int to convert an Object to capture index" do
|
||||
obj = mock('2')
|
||||
obj.should_receive(:to_int).at_least(1).times.and_return(2)
|
||||
|
||||
"har".slice!(/(.)(.)(.)/, obj).should == "a"
|
||||
end
|
||||
|
||||
it "returns subclass 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)
|
||||
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
|
||||
end
|
||||
|
||||
it "sets $~ to MatchData when there is a match and nil when there's none" do
|
||||
'hello'[/.(.)/, 0]
|
||||
$~[0].should == 'he'
|
||||
|
||||
'hello'[/.(.)/, 1]
|
||||
$~[1].should == 'e'
|
||||
|
||||
'hello'[/not/, 0]
|
||||
$~.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)
|
||||
end
|
||||
end
|
||||
|
||||
describe "String#slice! with String" do
|
||||
it "removes and returns the first occurrence of other_str from self" do
|
||||
c = "hello hello"
|
||||
c.slice!('llo').should == "llo"
|
||||
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
|
||||
|
||||
'hello'.slice!('ll')
|
||||
$~.should == nil
|
||||
end
|
||||
|
||||
it "returns nil if self does not contain other" do
|
||||
a = "hello"
|
||||
a.slice!('zzz').should == nil
|
||||
a.should == "hello"
|
||||
end
|
||||
|
||||
it "doesn't call to_str on its argument" do
|
||||
o = mock('x')
|
||||
o.should_not_receive(:to_str)
|
||||
|
||||
lambda { "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)
|
||||
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)
|
||||
end
|
||||
end
|
405
spec/ruby/core/string/split_spec.rb
Normal file
405
spec/ruby/core/string/split_spec.rb
Normal file
|
@ -0,0 +1,405 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
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 "splits on multibyte characters" do
|
||||
"ありがりがとう".split("が").should == ["あり", "り", "とう"]
|
||||
end
|
||||
end
|
||||
|
||||
it "returns an array of substrings based on splitting on the given string" do
|
||||
"mellow yellow".split("ello").should == ["m", "w y", "w"]
|
||||
end
|
||||
|
||||
it "suppresses trailing empty fields when limit isn't given or 0" 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"]
|
||||
"hai".split("hai").should == []
|
||||
",".split(",").should == []
|
||||
",".split(",", 0).should == []
|
||||
end
|
||||
|
||||
it "returns an array with one entry if limit is 1: the original string" do
|
||||
"hai".split("hai", 1).should == ["hai"]
|
||||
"x.y.z".split(".", 1).should == ["x.y.z"]
|
||||
"hello world ".split(" ", 1).should == ["hello world "]
|
||||
"hi!".split("", 1).should == ["hi!"]
|
||||
end
|
||||
|
||||
it "returns at most limit fields when limit > 1" do
|
||||
"hai".split("hai", 2).should == ["", ""]
|
||||
|
||||
"1,2".split(",", 3).should == ["1", "2"]
|
||||
|
||||
"1,2,,3,4,,".split(',', 2).should == ["1", "2,,3,4,,"]
|
||||
"1,2,,3,4,,".split(',', 3).should == ["1", "2", ",3,4,,"]
|
||||
"1,2,,3,4,,".split(',', 4).should == ["1", "2", "", "3,4,,"]
|
||||
"1,2,,3,4,,".split(',', 5).should == ["1", "2", "", "3", "4,,"]
|
||||
"1,2,,3,4,,".split(',', 6).should == ["1", "2", "", "3", "4", ","]
|
||||
|
||||
"x".split('x', 2).should == ["", ""]
|
||||
"xx".split('x', 2).should == ["", "x"]
|
||||
"xx".split('x', 3).should == ["", "", ""]
|
||||
"xxx".split('x', 2).should == ["", "xx"]
|
||||
"xxx".split('x', 3).should == ["", "", "x"]
|
||||
"xxx".split('x', 4).should == ["", "", "", ""]
|
||||
end
|
||||
|
||||
it "doesn't suppress or limit fields when limit is negative" do
|
||||
"1,2,,3,4,,".split(',', -1).should == ["1", "2", "", "3", "4", "", ""]
|
||||
"1,2,,3,4,,".split(',', -5).should == ["1", "2", "", "3", "4", "", ""]
|
||||
" a b c\nd ".split(" ", -1).should == ["", "a", "b", "c\nd", ""]
|
||||
",".split(",", -1).should == ["", ""]
|
||||
end
|
||||
|
||||
it "defaults to $; when string isn't given or nil" do
|
||||
begin
|
||||
old_fs = $;
|
||||
|
||||
[",", ":", "", "XY", nil].each do |fs|
|
||||
$; = 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, -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
|
||||
|
||||
it "ignores leading and continuous whitespace when string is a single space" do
|
||||
" now's the time ".split(' ').should == ["now's", "the", "time"]
|
||||
" now's the time ".split(' ', -1).should == ["now's", "the", "time", ""]
|
||||
" now's the time ".split(' ', 3).should == ["now's", "the", "time "]
|
||||
|
||||
"\t\n a\t\tb \n\r\r\nc\v\vd\v ".split(' ').should == ["a", "b", "c", "d"]
|
||||
"a\x00a b".split(' ').should == ["a\x00a", "b"]
|
||||
end
|
||||
|
||||
describe "when limit is zero" do
|
||||
it "ignores leading and continuous whitespace when string is a single space" do
|
||||
" now's the time ".split(' ', 0).should == ["now's", "the", "time"]
|
||||
end
|
||||
end
|
||||
|
||||
it "splits between characters when its argument is an empty string" do
|
||||
"hi!".split("").should == ["h", "i", "!"]
|
||||
"hi!".split("", -1).should == ["h", "i", "!", ""]
|
||||
"hi!".split("", 0).should == ["h", "i", "!"]
|
||||
"hi!".split("", 1).should == ["hi!"]
|
||||
"hi!".split("", 2).should == ["h", "i!"]
|
||||
"hi!".split("", 3).should == ["h", "i", "!"]
|
||||
"hi!".split("", 4).should == ["h", "i", "!", ""]
|
||||
"hi!".split("", 5).should == ["h", "i", "!", ""]
|
||||
end
|
||||
|
||||
it "tries converting its pattern argument to a string via to_str" do
|
||||
obj = mock('::')
|
||||
obj.should_receive(:to_str).and_return("::")
|
||||
|
||||
"hello::world".split(obj).should == ["hello", "world"]
|
||||
end
|
||||
|
||||
it "tries converting limit to an integer via to_int" do
|
||||
obj = mock('2')
|
||||
obj.should_receive(:to_int).and_return(2)
|
||||
|
||||
"1.2.3.4".split(".", obj).should == ["1", "2.3.4"]
|
||||
end
|
||||
|
||||
it "doesn't set $~" do
|
||||
$~ = nil
|
||||
"x.y.z".split(".")
|
||||
$~.should == nil
|
||||
end
|
||||
|
||||
it "returns the original string if no matches are found" do
|
||||
"foo".split("bar").should == ["foo"]
|
||||
"foo".split("bar", -1).should == ["foo"]
|
||||
"foo".split("bar", 0).should == ["foo"]
|
||||
"foo".split("bar", 1).should == ["foo"]
|
||||
"foo".split("bar", 2).should == ["foo"]
|
||||
"foo".split("bar", 3).should == ["foo"]
|
||||
end
|
||||
|
||||
it "returns subclass 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)
|
||||
end
|
||||
|
||||
str.split(StringSpecs::MyString.new(pat), limit).each do |x|
|
||||
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
|
||||
|
||||
s = StringSpecs::StringWithRaisingConstructor.new('silly:string')
|
||||
s.split(':').first.should == 'silly'
|
||||
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
|
||||
|
||||
str.split(pat.dup.taint).each do |x|
|
||||
x.tainted?.should == false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "String#split with Regexp" do
|
||||
it "divides self on regexp matches" do
|
||||
" now's the time".split(/ /).should == ["", "now's", "", "the", "time"]
|
||||
" x\ny ".split(/ /).should == ["", "x\ny"]
|
||||
"1, 2.34,56, 7".split(/,\s*/).should == ["1", "2.34", "56", "7"]
|
||||
"1x2X3".split(/x/i).should == ["1", "2", "3"]
|
||||
end
|
||||
|
||||
it "treats negative limits as no limit" do
|
||||
"".split(%r!/+!, -1).should == []
|
||||
end
|
||||
|
||||
it "suppresses trailing empty fields when limit isn't given or 0" 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(/\s+/).should == ["", "a", "b", "c", "d"]
|
||||
"hai".split(/hai/).should == []
|
||||
",".split(/,/).should == []
|
||||
",".split(/,/, 0).should == []
|
||||
end
|
||||
|
||||
it "returns an array with one entry if limit is 1: the original string" do
|
||||
"hai".split(/hai/, 1).should == ["hai"]
|
||||
"xAyBzC".split(/[A-Z]/, 1).should == ["xAyBzC"]
|
||||
"hello world ".split(/\s+/, 1).should == ["hello world "]
|
||||
"hi!".split(//, 1).should == ["hi!"]
|
||||
end
|
||||
|
||||
it "returns at most limit fields when limit > 1" do
|
||||
"hai".split(/hai/, 2).should == ["", ""]
|
||||
|
||||
"1,2".split(/,/, 3).should == ["1", "2"]
|
||||
|
||||
"1,2,,3,4,,".split(/,/, 2).should == ["1", "2,,3,4,,"]
|
||||
"1,2,,3,4,,".split(/,/, 3).should == ["1", "2", ",3,4,,"]
|
||||
"1,2,,3,4,,".split(/,/, 4).should == ["1", "2", "", "3,4,,"]
|
||||
"1,2,,3,4,,".split(/,/, 5).should == ["1", "2", "", "3", "4,,"]
|
||||
"1,2,,3,4,,".split(/,/, 6).should == ["1", "2", "", "3", "4", ","]
|
||||
|
||||
"x".split(/x/, 2).should == ["", ""]
|
||||
"xx".split(/x/, 2).should == ["", "x"]
|
||||
"xx".split(/x/, 3).should == ["", "", ""]
|
||||
"xxx".split(/x/, 2).should == ["", "xx"]
|
||||
"xxx".split(/x/, 3).should == ["", "", "x"]
|
||||
"xxx".split(/x/, 4).should == ["", "", "", ""]
|
||||
end
|
||||
|
||||
it "doesn't suppress or limit fields when limit is negative" do
|
||||
"1,2,,3,4,,".split(/,/, -1).should == ["1", "2", "", "3", "4", "", ""]
|
||||
"1,2,,3,4,,".split(/,/, -5).should == ["1", "2", "", "3", "4", "", ""]
|
||||
" a b c\nd ".split(/\s+/, -1).should == ["", "a", "b", "c", "d", ""]
|
||||
",".split(/,/, -1).should == ["", ""]
|
||||
end
|
||||
|
||||
it "defaults to $; when regexp isn't given or nil" do
|
||||
begin
|
||||
old_fs = $;
|
||||
|
||||
[/,/, /:/, //, /XY/, /./].each do |fs|
|
||||
$; = 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, -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
|
||||
|
||||
it "splits between characters when regexp matches a zero-length string" do
|
||||
"hello".split(//).should == ["h", "e", "l", "l", "o"]
|
||||
"hello".split(//, -1).should == ["h", "e", "l", "l", "o", ""]
|
||||
"hello".split(//, 0).should == ["h", "e", "l", "l", "o"]
|
||||
"hello".split(//, 1).should == ["hello"]
|
||||
"hello".split(//, 2).should == ["h", "ello"]
|
||||
"hello".split(//, 5).should == ["h", "e", "l", "l", "o"]
|
||||
"hello".split(//, 6).should == ["h", "e", "l", "l", "o", ""]
|
||||
"hello".split(//, 7).should == ["h", "e", "l", "l", "o", ""]
|
||||
|
||||
"hi mom".split(/\s*/).should == ["h", "i", "m", "o", "m"]
|
||||
|
||||
"AABCCBAA".split(/(?=B)/).should == ["AA", "BCC", "BAA"]
|
||||
"AABCCBAA".split(/(?=B)/, -1).should == ["AA", "BCC", "BAA"]
|
||||
"AABCCBAA".split(/(?=B)/, 2).should == ["AA", "BCCBAA"]
|
||||
end
|
||||
|
||||
it "respects unicode when splitting between characters" do
|
||||
str = "こにちわ"
|
||||
reg = %r!!
|
||||
ary = str.split(reg)
|
||||
ary.size.should == 4
|
||||
ary.should == ["こ", "に", "ち", "わ"]
|
||||
end
|
||||
|
||||
it "respects the encoding of the regexp when splitting between characters" do
|
||||
str = "\303\202"
|
||||
ary = str.split(//u)
|
||||
ary.size.should == 1
|
||||
ary.should == ["\303\202"]
|
||||
end
|
||||
|
||||
it "includes all captures in the result array" do
|
||||
"hello".split(/(el)/).should == ["h", "el", "lo"]
|
||||
"hi!".split(/()/).should == ["h", "", "i", "", "!"]
|
||||
"hi!".split(/()/, -1).should == ["h", "", "i", "", "!", "", ""]
|
||||
"hello".split(/((el))()/).should == ["h", "el", "el", "", "lo"]
|
||||
"AabB".split(/([a-z])+/).should == ["A", "b", "B"]
|
||||
end
|
||||
|
||||
it "applies the limit to the number of split substrings, without counting captures" do
|
||||
"aBaBa".split(/(B)()()/, 2).should == ["a", "B", "", "", "aBa"]
|
||||
end
|
||||
|
||||
it "does not include non-matching captures in the result array" do
|
||||
"hello".split(/(el)|(xx)/).should == ["h", "el", "lo"]
|
||||
end
|
||||
|
||||
it "tries converting limit to an integer via to_int" do
|
||||
obj = mock('2')
|
||||
obj.should_receive(:to_int).and_return(2)
|
||||
|
||||
"1.2.3.4".split(".", obj).should == ["1", "2.3.4"]
|
||||
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)
|
||||
end
|
||||
|
||||
it "doesn't set $~" do
|
||||
$~ = nil
|
||||
"x:y:z".split(/:/)
|
||||
$~.should == nil
|
||||
end
|
||||
|
||||
it "returns the original string if no matches are found" do
|
||||
"foo".split(/bar/).should == ["foo"]
|
||||
"foo".split(/bar/, -1).should == ["foo"]
|
||||
"foo".split(/bar/, 0).should == ["foo"]
|
||||
"foo".split(/bar/, 1).should == ["foo"]
|
||||
"foo".split(/bar/, 2).should == ["foo"]
|
||||
"foo".split(/bar/, 3).should == ["foo"]
|
||||
end
|
||||
|
||||
it "returns subclass 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)
|
||||
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
|
||||
|
||||
s = StringSpecs::StringWithRaisingConstructor.new('silly:string')
|
||||
s.split(/:/).first.should == 'silly'
|
||||
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
|
||||
end
|
||||
|
||||
it "taints an empty string if self is tainted" do
|
||||
":".taint.split(//, -1).last.tainted?.should be_true
|
||||
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
|
||||
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]
|
||||
end
|
||||
|
||||
|
||||
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 "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)
|
||||
end
|
||||
end
|
113
spec/ruby/core/string/squeeze_spec.rb
Normal file
113
spec/ruby/core/string/squeeze_spec.rb
Normal file
|
@ -0,0 +1,113 @@
|
|||
# -*- encoding: binary -*-
|
||||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
# TODO: rewrite all these specs
|
||||
|
||||
describe "String#squeeze" do
|
||||
it "returns new string where runs of the same character are replaced by a single character when no args are given" do
|
||||
"yellow moon".squeeze.should == "yelow mon"
|
||||
end
|
||||
|
||||
it "only squeezes chars that are in the intersection of all sets given" do
|
||||
"woot squeeze cheese".squeeze("eost", "queo").should == "wot squeze chese"
|
||||
" now is the".squeeze(" ").should == " now is the"
|
||||
end
|
||||
|
||||
it "negates sets starting with ^" do
|
||||
s = "<<subbookkeeper!!!>>"
|
||||
s.squeeze("beko", "^e").should == s.squeeze("bko")
|
||||
s.squeeze("^<bek!>").should == s.squeeze("o")
|
||||
s.squeeze("^o").should == s.squeeze("<bek!>")
|
||||
s.squeeze("^").should == s
|
||||
"^__^".squeeze("^^").should == "^_^"
|
||||
"((^^__^^))".squeeze("_^").should == "((^_^))"
|
||||
end
|
||||
|
||||
it "squeezes all chars in a sequence" do
|
||||
s = "--subbookkeeper--"
|
||||
s.squeeze("\x00-\xFF").should == s.squeeze
|
||||
s.squeeze("bk-o").should == s.squeeze("bklmno")
|
||||
s.squeeze("b-e").should == s.squeeze("bcde")
|
||||
s.squeeze("e-").should == "-subbookkeper-"
|
||||
s.squeeze("-e").should == "-subbookkeper-"
|
||||
s.squeeze("---").should == "-subbookkeeper-"
|
||||
"ook--001122".squeeze("--2").should == "ook-012"
|
||||
"ook--(())".squeeze("(--").should == "ook-()"
|
||||
s.squeeze("^b-e").should == "-subbokeeper-"
|
||||
"^^__^^".squeeze("^^-^").should == "^^_^^"
|
||||
"^^--^^".squeeze("^---").should == "^--^"
|
||||
|
||||
s.squeeze("b-dk-o-").should == "-subokeeper-"
|
||||
s.squeeze("-b-dk-o").should == "-subokeeper-"
|
||||
s.squeeze("b-d-k-o").should == "-subokeeper-"
|
||||
|
||||
s.squeeze("bc-e").should == "--subookkeper--"
|
||||
s.squeeze("^bc-e").should == "-subbokeeper-"
|
||||
|
||||
"AABBCCaabbcc[[]]".squeeze("A-a").should == "ABCabbcc[]"
|
||||
end
|
||||
|
||||
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
|
||||
end
|
||||
|
||||
it "tries to convert each set arg to a string using to_str" do
|
||||
other_string = mock('lo')
|
||||
other_string.should_receive(:to_str).and_return("lo")
|
||||
|
||||
other_string2 = mock('o')
|
||||
other_string2.should_receive(:to_str).and_return("o")
|
||||
|
||||
"hello room".squeeze(other_string, other_string2).should == "hello rom"
|
||||
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)
|
||||
end
|
||||
|
||||
it "returns subclass instances when called on a subclass" do
|
||||
StringSpecs::MyString.new("oh no!!!").squeeze("!").should be_an_instance_of(StringSpecs::MyString)
|
||||
end
|
||||
end
|
||||
|
||||
describe "String#squeeze!" do
|
||||
it "modifies self in place and returns self" do
|
||||
a = "yellow moon"
|
||||
a.squeeze!.should equal(a)
|
||||
a.should == "yelow mon"
|
||||
end
|
||||
|
||||
it "returns nil if no modifications were made" do
|
||||
a = "squeeze"
|
||||
a.squeeze!("u", "sq").should == nil
|
||||
a.squeeze!("q").should == nil
|
||||
a.should == "squeeze"
|
||||
end
|
||||
|
||||
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 "raises a RuntimeError when self is frozen" do
|
||||
a = "yellow moon"
|
||||
a.freeze
|
||||
|
||||
lambda { a.squeeze!("") }.should raise_error(RuntimeError)
|
||||
lambda { a.squeeze! }.should raise_error(RuntimeError)
|
||||
end
|
||||
end
|
45
spec/ruby/core/string/start_with_spec.rb
Normal file
45
spec/ruby/core/string/start_with_spec.rb
Normal file
|
@ -0,0 +1,45 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
require File.expand_path('../fixtures/classes.rb', __FILE__)
|
||||
|
||||
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 "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 }.should raise_error(TypeError)
|
||||
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
|
||||
end
|
||||
|
||||
it "works for multibyte strings" do
|
||||
"céréale".start_with?("cér").should be_true
|
||||
end
|
||||
end
|
7
spec/ruby/core/string/string_spec.rb
Normal file
7
spec/ruby/core/string/string_spec.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
require File.expand_path('../../../spec_helper', __FILE__)
|
||||
|
||||
describe "String" do
|
||||
it "includes Comparable" do
|
||||
String.include?(Comparable).should == true
|
||||
end
|
||||
end
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue