summaryrefslogtreecommitdiff
path: root/spec/ruby/core
diff options
context:
space:
mode:
authorBenoit Daloze <eregontp@gmail.com>2022-06-26 14:50:14 +0200
committerBenoit Daloze <eregontp@gmail.com>2022-06-26 14:50:14 +0200
commitd3d5ef0cca160fca538c7f556c5a6e08df5847e6 (patch)
tree57358b4b9cdd6f429d0383005ac393cb74dd3bff /spec/ruby/core
parentf616e816372d14e605879d2e43c7fbdda29ef837 (diff)
Update to ruby/spec@ab32a1a
Diffstat (limited to 'spec/ruby/core')
-rw-r--r--spec/ruby/core/array/fill_spec.rb6
-rw-r--r--spec/ruby/core/array/fixtures/classes.rb62
-rw-r--r--spec/ruby/core/array/sample_spec.rb18
-rw-r--r--spec/ruby/core/dir/foreach_spec.rb10
-rw-r--r--spec/ruby/core/exception/signal_exception_spec.rb6
-rw-r--r--spec/ruby/core/file/open_spec.rb8
-rw-r--r--spec/ruby/core/float/divide_spec.rb4
-rw-r--r--spec/ruby/core/float/round_spec.rb64
-rw-r--r--spec/ruby/core/integer/chr_spec.rb39
-rw-r--r--spec/ruby/core/integer/fdiv_spec.rb5
-rw-r--r--spec/ruby/core/io/advise_spec.rb14
-rw-r--r--spec/ruby/core/io/fixtures/classes.rb14
-rw-r--r--spec/ruby/core/io/gets_spec.rb14
-rw-r--r--spec/ruby/core/io/readline_spec.rb31
-rw-r--r--spec/ruby/core/io/readlines_spec.rb22
-rw-r--r--spec/ruby/core/io/shared/each.rb48
-rw-r--r--spec/ruby/core/io/shared/readlines.rb133
-rw-r--r--spec/ruby/core/kernel/instance_variable_get_spec.rb6
-rw-r--r--spec/ruby/core/kernel/instance_variable_set_spec.rb6
-rw-r--r--spec/ruby/core/kernel/remove_instance_variable_spec.rb13
-rw-r--r--spec/ruby/core/kernel/shared/require.rb19
-rw-r--r--spec/ruby/core/math/ldexp_spec.rb6
-rw-r--r--spec/ruby/core/module/class_variables_spec.rb8
-rw-r--r--spec/ruby/core/module/fixtures/classes.rb4
-rw-r--r--spec/ruby/core/process/clock_gettime_spec.rb99
-rw-r--r--spec/ruby/core/process/egid_spec.rb41
-rw-r--r--spec/ruby/core/process/euid_spec.rb12
-rw-r--r--spec/ruby/core/process/spawn_spec.rb2
-rw-r--r--spec/ruby/core/process/status/equal_value_spec.rb2
-rw-r--r--spec/ruby/core/process/status/exited_spec.rb2
-rw-r--r--spec/ruby/core/process/status/exitstatus_spec.rb2
-rw-r--r--spec/ruby/core/process/status/signaled_spec.rb2
-rw-r--r--spec/ruby/core/process/status/success_spec.rb2
-rw-r--r--spec/ruby/core/process/status/termsig_spec.rb4
-rw-r--r--spec/ruby/core/process/status/to_i_spec.rb2
-rw-r--r--spec/ruby/core/regexp/shared/quote.rb5
-rw-r--r--spec/ruby/core/signal/trap_spec.rb4
-rw-r--r--spec/ruby/core/string/capitalize_spec.rb4
-rw-r--r--spec/ruby/core/string/dup_spec.rb9
-rw-r--r--spec/ruby/core/string/insert_spec.rb9
-rw-r--r--spec/ruby/core/string/lstrip_spec.rb6
-rw-r--r--spec/ruby/core/string/rstrip_spec.rb6
-rw-r--r--spec/ruby/core/string/scrub_spec.rb5
-rw-r--r--spec/ruby/core/string/shared/slice.rb14
-rw-r--r--spec/ruby/core/string/split_spec.rb19
-rw-r--r--spec/ruby/core/string/unpack/z_spec.rb5
-rw-r--r--spec/ruby/core/thread/raise_spec.rb24
47 files changed, 683 insertions, 157 deletions
diff --git a/spec/ruby/core/array/fill_spec.rb b/spec/ruby/core/array/fill_spec.rb
index 6369f23544..23728414be 100644
--- a/spec/ruby/core/array/fill_spec.rb
+++ b/spec/ruby/core/array/fill_spec.rb
@@ -205,6 +205,12 @@ describe "Array#fill with (filler, index, length)" do
-> { [].fill('a', obj) }.should raise_error(TypeError)
end
+ it "raises a TypeError when the length is not numeric" do
+ -> { [1, 2, 3].fill("x", 1, "foo") }.should raise_error(TypeError, /no implicit conversion of String into Integer/)
+ -> { [1, 2, 3].fill("x", 1, :"foo") }.should raise_error(TypeError, /no implicit conversion of Symbol into Integer/)
+ -> { [1, 2, 3].fill("x", 1, Object.new) }.should raise_error(TypeError, /no implicit conversion of Object into Integer/)
+ end
+
not_supported_on :opal do
it "raises an ArgumentError or RangeError for too-large sizes" do
error_types = [RangeError, ArgumentError]
diff --git a/spec/ruby/core/array/fixtures/classes.rb b/spec/ruby/core/array/fixtures/classes.rb
index affb3b49e6..aa5fecd96b 100644
--- a/spec/ruby/core/array/fixtures/classes.rb
+++ b/spec/ruby/core/array/fixtures/classes.rb
@@ -40,6 +40,68 @@ module ArraySpecs
a
end
+ # Chi squared critical values for tests with n degrees of freedom at 99% confidence.
+ # Values obtained from NIST Engineering Statistic Handbook at
+ # https://www.itl.nist.gov/div898/handbook/eda/section3/eda3674.htm
+
+ CHI_SQUARED_CRITICAL_VALUES = [
+ 0,
+ 6.635, 9.210, 11.345, 13.277, 15.086, 16.812, 18.475, 20.090, 21.666, 23.209,
+ 24.725, 26.217, 27.688, 29.141, 30.578, 32.000, 33.409, 34.805, 36.191, 37.566,
+ 38.932, 40.289, 41.638, 42.980, 44.314, 45.642, 46.963, 48.278, 49.588, 50.892,
+ 52.191, 53.486, 54.776, 56.061, 57.342, 58.619, 59.893, 61.162, 62.428, 63.691,
+ 64.950, 66.206, 67.459, 68.710, 69.957, 71.201, 72.443, 73.683, 74.919, 76.154,
+ 77.386, 78.616, 79.843, 81.069, 82.292, 83.513, 84.733, 85.950, 87.166, 88.379,
+ 89.591, 90.802, 92.010, 93.217, 94.422, 95.626, 96.828, 98.028, 99.228, 100.425,
+ 101.621, 102.816, 104.010, 105.202, 106.393, 107.583, 108.771, 109.958, 111.144, 112.329,
+ 113.512, 114.695, 115.876, 117.057, 118.236, 119.414, 120.591, 121.767, 122.942, 124.116,
+ 125.289, 126.462, 127.633, 128.803, 129.973, 131.141, 132.309, 133.476, 134.642, 135.807,
+ ]
+
+ def self.measure_sample_fairness(size, samples, iters)
+ ary = Array.new(size) { |x| x }
+ (samples).times do |i|
+ chi_results = []
+ 3.times do
+ counts = Array.new(size) { 0 }
+ expected = iters / size
+ iters.times do
+ x = ary.sample(samples)[i]
+ counts[x] += 1
+ end
+ chi_squared = 0.0
+ counts.each do |count|
+ chi_squared += (((count - expected) ** 2) * 1.0 / expected)
+ end
+ chi_results << chi_squared
+ break if chi_squared <= CHI_SQUARED_CRITICAL_VALUES[size]
+ end
+
+ chi_results.min.should <= CHI_SQUARED_CRITICAL_VALUES[size]
+ end
+ end
+
+ def self.measure_sample_fairness_large_sample_size(size, samples, iters)
+ ary = Array.new(size) { |x| x }
+ counts = Array.new(size) { 0 }
+ expected = iters * samples / size
+ iters.times do
+ ary.sample(samples).each do |sample|
+ counts[sample] += 1
+ end
+ end
+ chi_squared = 0.0
+ counts.each do |count|
+ chi_squared += (((count - expected) ** 2) * 1.0 / expected)
+ end
+
+ # Chi squared critical values for tests with 4 degrees of freedom
+ # Values obtained from NIST Engineering Statistic Handbook at
+ # https://www.itl.nist.gov/div898/handbook/eda/section3/eda3674.htm
+
+ chi_squared.should <= CHI_SQUARED_CRITICAL_VALUES[size]
+ end
+
class MyArray < Array
# The #initialize method has a different signature than Array to help
# catch places in the specs that do not assert the #initialize is not
diff --git a/spec/ruby/core/array/sample_spec.rb b/spec/ruby/core/array/sample_spec.rb
index 755b46f126..5b3aac9aed 100644
--- a/spec/ruby/core/array/sample_spec.rb
+++ b/spec/ruby/core/array/sample_spec.rb
@@ -3,16 +3,14 @@ require_relative 'fixtures/classes'
describe "Array#sample" do
it "samples evenly" do
- ary = [0, 1, 2, 3]
- 3.times do |i|
- counts = [0, 0, 0, 0]
- 4000.times do
- counts[ary.sample(3)[i]] += 1
- end
- counts.each do |count|
- (800..1200).should include(count)
- end
- end
+ ArraySpecs.measure_sample_fairness(4, 1, 400)
+ ArraySpecs.measure_sample_fairness(4, 2, 400)
+ ArraySpecs.measure_sample_fairness(4, 3, 400)
+ ArraySpecs.measure_sample_fairness(40, 3, 400)
+ ArraySpecs.measure_sample_fairness(40, 4, 400)
+ ArraySpecs.measure_sample_fairness(40, 8, 400)
+ ArraySpecs.measure_sample_fairness(40, 16, 400)
+ ArraySpecs.measure_sample_fairness_large_sample_size(100, 80, 4000)
end
it "returns nil for an empty Array" do
diff --git a/spec/ruby/core/dir/foreach_spec.rb b/spec/ruby/core/dir/foreach_spec.rb
index b0e18afeb5..9cf34b1d71 100644
--- a/spec/ruby/core/dir/foreach_spec.rb
+++ b/spec/ruby/core/dir/foreach_spec.rb
@@ -41,13 +41,13 @@ describe "Dir.foreach" do
it "accepts an encoding keyword for the encoding of the entries" do
dirs = Dir.foreach("#{DirSpecs.mock_dir}/deeply/nested", encoding: "utf-8").to_a.sort
- dirs.each {|dir| dir.encoding.should == Encoding::UTF_8}
+ dirs.each { |dir| dir.encoding.should == Encoding::UTF_8 }
- dirs = Dir.foreach("#{DirSpecs.mock_dir}/deeply/nested", encoding: Encoding::UTF_16LE).to_a.sort
- dirs.each {|dir| dir.encoding.should == Encoding::UTF_16LE}
+ dirs = Dir.foreach("#{DirSpecs.mock_dir}/deeply/nested", encoding: Encoding::ISO_8859_1).to_a.sort
+ dirs.each { |dir| dir.encoding.should == Encoding::ISO_8859_1 }
- Dir.foreach("#{DirSpecs.mock_dir}/deeply/nested", encoding: Encoding::UTF_16LE) do |f|
- f.encoding.should == Encoding::UTF_16LE
+ Dir.foreach("#{DirSpecs.mock_dir}/deeply/nested", encoding: Encoding::ISO_8859_1) do |f|
+ f.encoding.should == Encoding::ISO_8859_1
end
end
diff --git a/spec/ruby/core/exception/signal_exception_spec.rb b/spec/ruby/core/exception/signal_exception_spec.rb
index 566bcb4672..1a0940743f 100644
--- a/spec/ruby/core/exception/signal_exception_spec.rb
+++ b/spec/ruby/core/exception/signal_exception_spec.rb
@@ -93,7 +93,7 @@ describe "SignalException" do
platform_is_not :windows do
it "runs after at_exit" do
- output = ruby_exe(<<-RUBY, exit_status: nil)
+ output = ruby_exe(<<-RUBY, exit_status: :SIGKILL)
at_exit do
puts "hello"
$stdout.flush
@@ -107,7 +107,7 @@ describe "SignalException" do
end
it "cannot be trapped with Signal.trap" do
- ruby_exe(<<-RUBY, exit_status: nil)
+ ruby_exe(<<-RUBY, exit_status: :SIGPROF)
Signal.trap("PROF") {}
raise(SignalException, "PROF")
RUBY
@@ -116,7 +116,7 @@ describe "SignalException" do
end
it "self-signals for USR1" do
- ruby_exe("raise(SignalException, 'USR1')", exit_status: nil)
+ ruby_exe("raise(SignalException, 'USR1')", exit_status: :SIGUSR1)
$?.termsig.should == Signal.list.fetch('USR1')
end
end
diff --git a/spec/ruby/core/file/open_spec.rb b/spec/ruby/core/file/open_spec.rb
index c7dd34d5c6..1729780570 100644
--- a/spec/ruby/core/file/open_spec.rb
+++ b/spec/ruby/core/file/open_spec.rb
@@ -494,6 +494,14 @@ describe "File.open" do
File.open(@file, "w") { |f| f.puts "testing" }
File.size(@file).should > 0
File.open(@file, "rb+") do |f|
+ f.binmode?.should == true
+ f.external_encoding.should == Encoding::ASCII_8BIT
+ f.pos.should == 0
+ f.should_not.eof?
+ end
+ File.open(@file, "r+b") do |f|
+ f.binmode?.should == true
+ f.external_encoding.should == Encoding::ASCII_8BIT
f.pos.should == 0
f.should_not.eof?
end
diff --git a/spec/ruby/core/float/divide_spec.rb b/spec/ruby/core/float/divide_spec.rb
index d8f71a6b98..72ab7527bd 100644
--- a/spec/ruby/core/float/divide_spec.rb
+++ b/spec/ruby/core/float/divide_spec.rb
@@ -36,4 +36,8 @@ describe "Float#/" do
-> { 13.0 / "10" }.should raise_error(TypeError)
-> { 13.0 / :symbol }.should raise_error(TypeError)
end
+
+ it "divides correctly by Rational numbers" do
+ (1.2345678901234567 / Rational(1, 10000000000000000000)).should == 1.2345678901234567e+19
+ end
end
diff --git a/spec/ruby/core/float/round_spec.rb b/spec/ruby/core/float/round_spec.rb
index 4bd2dc460c..e5a8f534e7 100644
--- a/spec/ruby/core/float/round_spec.rb
+++ b/spec/ruby/core/float/round_spec.rb
@@ -103,6 +103,70 @@ describe "Float#round" do
5.55.round(1, half: :up).should eql(5.6)
5.55.round(1, half: :down).should eql(5.5)
5.55.round(1, half: :even).should eql(5.6)
+ -5.55.round(1, half: nil).should eql(-5.6)
+ -5.55.round(1, half: :up).should eql(-5.6)
+ -5.55.round(1, half: :down).should eql(-5.5)
+ -5.55.round(1, half: :even).should eql(-5.6)
+ end
+
+ it "preserves cases where neighbouring floating pointer number increase the decimal places" do
+ 4.8100000000000005.round(5, half: nil).should eql(4.81)
+ 4.8100000000000005.round(5, half: :up).should eql(4.81)
+ 4.8100000000000005.round(5, half: :down).should eql(4.81)
+ 4.8100000000000005.round(5, half: :even).should eql(4.81)
+ -4.8100000000000005.round(5, half: nil).should eql(-4.81)
+ -4.8100000000000005.round(5, half: :up).should eql(-4.81)
+ -4.8100000000000005.round(5, half: :down).should eql(-4.81)
+ -4.8100000000000005.round(5, half: :even).should eql(-4.81)
+ 4.81.round(5, half: nil).should eql(4.81)
+ 4.81.round(5, half: :up).should eql(4.81)
+ 4.81.round(5, half: :down).should eql(4.81)
+ 4.81.round(5, half: :even).should eql(4.81)
+ -4.81.round(5, half: nil).should eql(-4.81)
+ -4.81.round(5, half: :up).should eql(-4.81)
+ -4.81.round(5, half: :down).should eql(-4.81)
+ -4.81.round(5, half: :even).should eql(-4.81)
+ 4.809999999999999.round(5, half: nil).should eql(4.81)
+ 4.809999999999999.round(5, half: :up).should eql(4.81)
+ 4.809999999999999.round(5, half: :down).should eql(4.81)
+ 4.809999999999999.round(5, half: :even).should eql(4.81)
+ -4.809999999999999.round(5, half: nil).should eql(-4.81)
+ -4.809999999999999.round(5, half: :up).should eql(-4.81)
+ -4.809999999999999.round(5, half: :down).should eql(-4.81)
+ -4.809999999999999.round(5, half: :even).should eql(-4.81)
+ end
+
+ ruby_bug "", ""..."3.3" do
+ # These numbers are neighbouring floating point numbers round a
+ # precise value. They test that the rounding modes work correctly
+ # round that value and precision is not lost which might cause
+ # incorrect results.
+ it "does not lose precision during the rounding process" do
+ 767573.1875850001.round(5, half: nil).should eql(767573.18759)
+ 767573.1875850001.round(5, half: :up).should eql(767573.18759)
+ 767573.1875850001.round(5, half: :down).should eql(767573.18759)
+ 767573.1875850001.round(5, half: :even).should eql(767573.18759)
+ -767573.1875850001.round(5, half: nil).should eql(-767573.18759)
+ -767573.1875850001.round(5, half: :up).should eql(-767573.18759)
+ -767573.1875850001.round(5, half: :down).should eql(-767573.18759)
+ -767573.1875850001.round(5, half: :even).should eql(-767573.18759)
+ 767573.187585.round(5, half: nil).should eql(767573.18759)
+ 767573.187585.round(5, half: :up).should eql(767573.18759)
+ 767573.187585.round(5, half: :down).should eql(767573.18758)
+ 767573.187585.round(5, half: :even).should eql(767573.18758)
+ -767573.187585.round(5, half: nil).should eql(-767573.18759)
+ -767573.187585.round(5, half: :up).should eql(-767573.18759)
+ -767573.187585.round(5, half: :down).should eql(-767573.18758)
+ -767573.187585.round(5, half: :even).should eql(-767573.18758)
+ 767573.1875849998.round(5, half: nil).should eql(767573.18758)
+ 767573.1875849998.round(5, half: :up).should eql(767573.18758)
+ 767573.1875849998.round(5, half: :down).should eql(767573.18758)
+ 767573.1875849998.round(5, half: :even).should eql(767573.18758)
+ -767573.1875849998.round(5, half: nil).should eql(-767573.18758)
+ -767573.1875849998.round(5, half: :up).should eql(-767573.18758)
+ -767573.1875849998.round(5, half: :down).should eql(-767573.18758)
+ -767573.1875849998.round(5, half: :even).should eql(-767573.18758)
+ end
end
it "raises FloatDomainError for exceptional values with a half option" do
diff --git a/spec/ruby/core/integer/chr_spec.rb b/spec/ruby/core/integer/chr_spec.rb
index 3e13f45480..8fe20ff812 100644
--- a/spec/ruby/core/integer/chr_spec.rb
+++ b/spec/ruby/core/integer/chr_spec.rb
@@ -223,26 +223,25 @@ describe "Integer#chr with an encoding argument" do
# #5864
it "raises RangeError if self is invalid as a codepoint in the specified encoding" do
- [ [0x80, "US-ASCII"],
- [0x0100, "BINARY"],
- [0x0100, "EUC-JP"],
- [0xA1A0, "EUC-JP"],
- [0xA1, "EUC-JP"],
- [0x80, "SHIFT_JIS"],
- [0xE0, "SHIFT_JIS"],
- [0x0100, "ISO-8859-9"],
- [620, "TIS-620"],
- [0xD800, "UTF-8"],
- [0xDBFF, "UTF-8"],
- [0xDC00, "UTF-8"],
- [0xDFFF, "UTF-8"],
- [0xD800, "UTF-16"],
- [0xDBFF, "UTF-16"],
- [0xDC00, "UTF-16"],
- [0xDFFF, "UTF-16"],
- ].each do |integer, encoding_name|
- -> { integer.chr(encoding_name) }.should raise_error(RangeError)
- end
+ -> { 0x80.chr("US-ASCII") }.should raise_error(RangeError)
+ -> { 0x0100.chr("BINARY") }.should raise_error(RangeError)
+ -> { 0x0100.chr("EUC-JP") }.should raise_error(RangeError)
+ -> { 0xA1A0.chr("EUC-JP") }.should raise_error(RangeError)
+ -> { 0xA1.chr("EUC-JP") }.should raise_error(RangeError)
+ -> { 0x80.chr("SHIFT_JIS") }.should raise_error(RangeError)
+ -> { 0xE0.chr("SHIFT_JIS") }.should raise_error(RangeError)
+ -> { 0x0100.chr("ISO-8859-9") }.should raise_error(RangeError)
+ -> { 620.chr("TIS-620") }.should raise_error(RangeError)
+ # UTF-16 surrogate range
+ -> { 0xD800.chr("UTF-8") }.should raise_error(RangeError)
+ -> { 0xDBFF.chr("UTF-8") }.should raise_error(RangeError)
+ -> { 0xDC00.chr("UTF-8") }.should raise_error(RangeError)
+ -> { 0xDFFF.chr("UTF-8") }.should raise_error(RangeError)
+ # UTF-16 surrogate range
+ -> { 0xD800.chr("UTF-16") }.should raise_error(RangeError)
+ -> { 0xDBFF.chr("UTF-16") }.should raise_error(RangeError)
+ -> { 0xDC00.chr("UTF-16") }.should raise_error(RangeError)
+ -> { 0xDFFF.chr("UTF-16") }.should raise_error(RangeError)
end
it 'returns a String encoding self interpreted as a codepoint in the CESU-8 encoding' do
diff --git a/spec/ruby/core/integer/fdiv_spec.rb b/spec/ruby/core/integer/fdiv_spec.rb
index d99a19eb0f..d9ea2fdf8d 100644
--- a/spec/ruby/core/integer/fdiv_spec.rb
+++ b/spec/ruby/core/integer/fdiv_spec.rb
@@ -55,6 +55,11 @@ describe "Integer#fdiv" do
num.fdiv(den).should == -0.5555555555555556
end
+ it "rounds to the correct float for bignum denominators" do
+ 1.fdiv(10**324).should == 0.0
+ 1.fdiv(10**323).should == 1.0e-323
+ end
+
it "performs floating-point division between self and a Float" do
8.fdiv(9.0).should be_close(0.888888888888889, TOLERANCE)
end
diff --git a/spec/ruby/core/io/advise_spec.rb b/spec/ruby/core/io/advise_spec.rb
index 0a845487e2..651fc52378 100644
--- a/spec/ruby/core/io/advise_spec.rb
+++ b/spec/ruby/core/io/advise_spec.rb
@@ -73,19 +73,9 @@ describe "IO#advise" do
end
end
- platform_is :linux do
+ guard -> { platform_is :linux and kernel_version_is '3.6' } do # [ruby-core:65355] tmpfs is not supported
it "supports the willneed advice type" do
- require 'etc'
- uname = if Etc.respond_to?(:uname)
- Etc.uname[:release]
- else
- `uname -r`.chomp
- end
- if (uname.split('.').map(&:to_i) <=> [3,6]) < 0
- skip "[ruby-core:65355] tmpfs is not supported"
- else
- @io.advise(:willneed).should be_nil
- end
+ @io.advise(:willneed).should be_nil
end
end
diff --git a/spec/ruby/core/io/fixtures/classes.rb b/spec/ruby/core/io/fixtures/classes.rb
index 5d81d5fcd9..067ab59d93 100644
--- a/spec/ruby/core/io/fixtures/classes.rb
+++ b/spec/ruby/core/io/fixtures/classes.rb
@@ -108,6 +108,14 @@ module IOSpecs
"linha ", "cinco.\nHere ", "is ", "line ", "six.\n" ]
end
+ def self.lines_space_separator_without_trailing_spaces
+ [ "Voici", "la", "ligne", "une.\nQui",
+ "\303\250", "la", "linea", "due.\n\n\nAqu\303\255",
+ "est\303\241", "la", "l\303\255nea", "tres.\nHier",
+ "ist", "Zeile", "vier.\n\nEst\303\241", "aqui", "a",
+ "linha", "cinco.\nHere", "is", "line", "six.\n" ]
+ end
+
def self.lines_arbitrary_separator
[ "Voici la ligne une.\nQui \303\250",
" la linea due.\n\n\nAqu\303\255 est\303\241 la l\303\255nea tres.\nHier ist Zeile vier.\n\nEst\303\241 aqui a linha cinco.\nHere is line six.\n" ]
@@ -119,6 +127,12 @@ module IOSpecs
"Est\303\241 aqui a linha cinco.\nHere is line six.\n" ]
end
+ def self.paragraphs_without_trailing_new_line_characters
+ [ "Voici la ligne une.\nQui \303\250 la linea due.",
+ "Aqu\303\255 est\303\241 la l\303\255nea tres.\nHier ist Zeile vier.",
+ "Est\303\241 aqui a linha cinco.\nHere is line six.\n" ]
+ end
+
# Creates an IO instance for an existing fixture file. The
# file should obviously not be deleted.
def self.io_fixture(name, mode = "r:utf-8")
diff --git a/spec/ruby/core/io/gets_spec.rb b/spec/ruby/core/io/gets_spec.rb
index 42238f6201..b9f82f8133 100644
--- a/spec/ruby/core/io/gets_spec.rb
+++ b/spec/ruby/core/io/gets_spec.rb
@@ -119,6 +119,16 @@ describe "IO#gets" do
it "returns the first line without a trailing newline character" do
@io.gets(chomp: true).should == IOSpecs.lines_without_newline_characters[0]
end
+
+ ruby_version_is "3.0" do
+ it "raises exception when options passed as Hash" do
+ -> { @io.gets({ chomp: true }) }.should raise_error(TypeError)
+
+ -> {
+ @io.gets("\n", 1, { chomp: true })
+ }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 0..2)")
+ end
+ end
end
end
@@ -200,6 +210,10 @@ describe "IO#gets" do
it "reads all bytes when pass a separator and reading more than all bytes" do
@io.gets("\t", 100).should == "one\n\ntwo\n\nthree\nfour\n"
end
+
+ it "returns empty string when 0 passed as a limit" do
+ @io.gets(0).should == ""
+ end
end
describe "IO#gets" do
diff --git a/spec/ruby/core/io/readline_spec.rb b/spec/ruby/core/io/readline_spec.rb
index 7cb1601816..ca30f31e39 100644
--- a/spec/ruby/core/io/readline_spec.rb
+++ b/spec/ruby/core/io/readline_spec.rb
@@ -43,9 +43,40 @@ describe "IO#readline" do
end
end
+ describe "when passed limit" do
+ it "reads limit bytes" do
+ @io.readline(3).should == "Voi"
+ end
+
+ it "returns an empty string when passed 0 as a limit" do
+ @io.readline(0).should == ""
+ end
+ end
+
+ describe "when passed separator and limit" do
+ it "reads limit bytes till the separator" do
+ # Voici la ligne une.\
+ @io.readline(" ", 4).should == "Voic"
+ @io.readline(" ", 4).should == "i "
+ @io.readline(" ", 4).should == "la "
+ @io.readline(" ", 4).should == "lign"
+ @io.readline(" ", 4).should == "e "
+ end
+ end
+
describe "when passed chomp" do
it "returns the first line without a trailing newline character" do
@io.readline(chomp: true).should == IOSpecs.lines_without_newline_characters[0]
end
+
+ ruby_version_is "3.0" do
+ it "raises exception when options passed as Hash" do
+ -> { @io.readline({ chomp: true }) }.should raise_error(TypeError)
+
+ -> {
+ @io.readline("\n", 1, { chomp: true })
+ }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 0..2)")
+ end
+ end
end
end
diff --git a/spec/ruby/core/io/readlines_spec.rb b/spec/ruby/core/io/readlines_spec.rb
index 254f2927b5..15af6debbe 100644
--- a/spec/ruby/core/io/readlines_spec.rb
+++ b/spec/ruby/core/io/readlines_spec.rb
@@ -101,6 +101,28 @@ describe "IO#readlines" do
@io.readlines(obj).should == IOSpecs.lines_r_separator
end
end
+
+ describe "when passed limit" do
+ it "raises ArgumentError when passed 0 as a limit" do
+ -> { @io.readlines(0) }.should raise_error(ArgumentError)
+ end
+ end
+
+ describe "when passed chomp" do
+ it "returns the first line without a trailing newline character" do
+ @io.readlines(chomp: true).should == IOSpecs.lines_without_newline_characters
+ end
+
+ ruby_version_is "3.0" do
+ it "raises exception when options passed as Hash" do
+ -> { @io.readlines({ chomp: true }) }.should raise_error(TypeError)
+
+ -> {
+ @io.readlines("\n", 1, { chomp: true })
+ }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 0..2)")
+ end
+ end
+ end
end
describe "IO#readlines" do
diff --git a/spec/ruby/core/io/shared/each.rb b/spec/ruby/core/io/shared/each.rb
index 91766fbe03..badf8985e0 100644
--- a/spec/ruby/core/io/shared/each.rb
+++ b/spec/ruby/core/io/shared/each.rb
@@ -161,6 +161,54 @@ describe :io_each, shared: true do
@io.send(@method, chomp: true) { |s| ScratchPad << s }
ScratchPad.recorded.should == IOSpecs.lines_without_newline_characters
end
+
+ ruby_version_is "3.0" do
+ it "raises exception when options passed as Hash" do
+ -> {
+ @io.send(@method, { chomp: true }) { |s| }
+ }.should raise_error(TypeError)
+
+ -> {
+ @io.send(@method, "\n", 1, { chomp: true }) { |s| }
+ }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 0..2)")
+ end
+ end
+ end
+
+ describe "when passed chomp and a separator" do
+ it "yields each line without separator to the passed block" do
+ @io.send(@method, " ", chomp: true) { |s| ScratchPad << s }
+ ScratchPad.recorded.should == IOSpecs.lines_space_separator_without_trailing_spaces
+ end
+ end
+
+ describe "when passed chomp and empty line as a separator" do
+ it "yields each paragraph without trailing new line characters" do
+ @io.send(@method, "", 1024, chomp: true) { |s| ScratchPad << s }
+ ScratchPad.recorded.should == IOSpecs.paragraphs_without_trailing_new_line_characters
+ end
+ end
+
+ describe "when passed chomp and nil as a separator" do
+ it "yields self's content without trailing new line character" do
+ @io.pos = 100
+ @io.send(@method, nil, chomp: true) { |s| ScratchPad << s }
+ ScratchPad.recorded.should == ["qui a linha cinco.\nHere is line six."]
+ end
+ end
+
+ describe "when passed chomp, nil as a separator, and a limit" do
+ it "yields each line of limit size without truncating trailing new line character" do
+ # 43 - is a size of the 1st paragraph in the file
+ @io.send(@method, nil, 43, chomp: true) { |s| ScratchPad << s }
+
+ ScratchPad.recorded.should == [
+ "Voici la ligne une.\nQui è la linea due.\n\n\n",
+ "Aquí está la línea tres.\n" + "Hier ist Zeile ",
+ "vier.\n\nEstá aqui a linha cinco.\nHere is li",
+ "ne six.\n"
+ ]
+ end
end
end
diff --git a/spec/ruby/core/io/shared/readlines.rb b/spec/ruby/core/io/shared/readlines.rb
index 52b20364ef..479452b71c 100644
--- a/spec/ruby/core/io/shared/readlines.rb
+++ b/spec/ruby/core/io/shared/readlines.rb
@@ -78,6 +78,14 @@ describe :io_readlines_options_19, shared: true do
result = IO.send(@method, @name, -2, &@object)
(result ? result : ScratchPad.recorded).should == IOSpecs.lines
end
+
+ ruby_bug "#18767", ""..."3.3" do
+ describe "when passed limit" do
+ it "raises ArgumentError when passed 0 as a limit" do
+ -> { IO.send(@method, @name, 0, &@object) }.should raise_error(ArgumentError)
+ end
+ end
+ end
end
describe "when the object is a String" do
@@ -92,31 +100,35 @@ describe :io_readlines_options_19, shared: true do
end
end
- describe "when the object is a Hash" do
- it "uses the value as the options hash" do
- result = IO.send(@method, @name, mode: "r", &@object)
- (result ? result : ScratchPad.recorded).should == IOSpecs.lines
+ describe "when the object is an options Hash" do
+ ruby_version_is "3.0" do
+ it "raises TypeError exception" do
+ -> {
+ IO.send(@method, @name, { chomp: true }, &@object)
+ }.should raise_error(TypeError)
+ end
end
end
- end
- describe "when passed name, object, object" do
- describe "when the first object is an Integer" do
- it "uses the second object as an options Hash" do
- -> do
- IO.send(@method, @filename, 10, mode: "w", &@object)
- end.should raise_error(IOError)
- end
+ describe "when the object is neither Integer nor String" do
+ it "raises TypeError exception" do
+ obj = mock("not io readlines limit")
- it "calls #to_hash to convert the second object to a Hash" do
- options = mock("io readlines options Hash")
- options.should_receive(:to_hash).and_return({ mode: "w" })
- -> do
- IO.send(@method, @filename, 10, **options, &@object)
- end.should raise_error(IOError)
+ -> {
+ IO.send(@method, @name, obj, &@object)
+ }.should raise_error(TypeError)
end
end
+ end
+ describe "when passed name, keyword arguments" do
+ it "uses the keyword arguments as options" do
+ result = IO.send(@method, @name, mode: "r", &@object)
+ (result ? result : ScratchPad.recorded).should == IOSpecs.lines
+ end
+ end
+
+ describe "when passed name, object, object" do
describe "when the first object is a String" do
it "uses the second object as a limit if it is an Integer" do
result = IO.send(@method, @name, " ", 10, &@object)
@@ -129,32 +141,18 @@ describe :io_readlines_options_19, shared: true do
result = IO.send(@method, @name, " ", limit, &@object)
(result ? result : ScratchPad.recorded).should == IOSpecs.lines_space_separator_limit
end
-
- it "uses the second object as an options Hash" do
- -> do
- IO.send(@method, @filename, " ", mode: "w", &@object)
- end.should raise_error(IOError)
- end
-
- it "calls #to_hash to convert the second object to a Hash" do
- options = mock("io readlines options Hash")
- options.should_receive(:to_hash).and_return({ mode: "w" })
- -> do
- IO.send(@method, @filename, " ", **options, &@object)
- end.should raise_error(IOError)
- end
end
describe "when the first object is not a String or Integer" do
it "calls #to_str to convert the object to a String" do
sep = mock("io readlines separator")
sep.should_receive(:to_str).at_least(1).and_return(" ")
- result = IO.send(@method, @name, sep, 10, mode: "r", &@object)
+ result = IO.send(@method, @name, sep, 10, &@object)
(result ? result : ScratchPad.recorded).should == IOSpecs.lines_space_separator_limit
end
it "uses the second object as a limit if it is an Integer" do
- result = IO.send(@method, @name, " ", 10, mode: "r", &@object)
+ result = IO.send(@method, @name, " ", 10, &@object)
(result ? result : ScratchPad.recorded).should == IOSpecs.lines_space_separator_limit
end
@@ -164,24 +162,59 @@ describe :io_readlines_options_19, shared: true do
result = IO.send(@method, @name, " ", limit, &@object)
(result ? result : ScratchPad.recorded).should == IOSpecs.lines_space_separator_limit
end
+ end
+
+ describe "when the second object is neither Integer nor String" do
+ it "raises TypeError exception" do
+ obj = mock("not io readlines limit")
+
+ -> {
+ IO.send(@method, @name, " ", obj, &@object)
+ }.should raise_error(TypeError)
+ end
+ end
+
+ describe "when the second object is an options Hash" do
+ ruby_version_is "3.0" do
+ it "raises TypeError exception" do
+ -> {
+ IO.send(@method, @name, "", { chomp: true }, &@object)
+ }.should raise_error(TypeError)
+ end
+ end
+ end
+ end
+
+ describe "when passed name, object, keyword arguments" do
+ describe "when the first object is an Integer" do
+ it "uses the keyword arguments as options" do
+ -> do
+ IO.send(@method, @filename, 10, mode: "w", &@object)
+ end.should raise_error(IOError)
+ end
+ end
- it "uses the second object as an options Hash" do
+ describe "when the first object is a String" do
+ it "uses the keyword arguments as options" do
-> do
IO.send(@method, @filename, " ", mode: "w", &@object)
end.should raise_error(IOError)
end
+ end
+
+ describe "when the first object is not a String or Integer" do
+ it "uses the keyword arguments as options" do
+ sep = mock("io readlines separator")
+ sep.should_receive(:to_str).at_least(1).and_return(" ")
- it "calls #to_hash to convert the second object to a Hash" do
- options = mock("io readlines options Hash")
- options.should_receive(:to_hash).and_return({ mode: "w" })
-> do
- IO.send(@method, @filename, " ", **options, &@object)
+ IO.send(@method, @filename, sep, mode: "w", &@object)
end.should raise_error(IOError)
end
end
end
- describe "when passed name, separator, limit, options" do
+ describe "when passed name, separator, limit, keyword arguments" do
it "calls #to_path to convert the name object" do
name = mock("io name to_path")
name.should_receive(:to_path).and_return(@name)
@@ -203,12 +236,24 @@ describe :io_readlines_options_19, shared: true do
(result ? result : ScratchPad.recorded).should == IOSpecs.lines_space_separator_limit
end
- it "calls #to_hash to convert the options object" do
- options = mock("io readlines options Hash")
- options.should_receive(:to_hash).and_return({ mode: "w" })
+ it "uses the keyword arguments as options" do
-> do
- IO.send(@method, @filename, " ", 10, **options, &@object)
+ IO.send(@method, @filename, " ", 10, mode: "w", &@object)
end.should raise_error(IOError)
end
+
+ describe "when passed chomp, nil as a separator, and a limit" do
+ it "yields each line of limit size without truncating trailing new line character" do
+ # 43 - is a size of the 1st paragraph in the file
+ result = IO.send(@method, @name, nil, 43, chomp: true, &@object)
+
+ (result ? result : ScratchPad.recorded).should == [
+ "Voici la ligne une.\nQui è la linea due.\n\n\n",
+ "Aquí está la línea tres.\n" + "Hier ist Zeile ",
+ "vier.\n\nEstá aqui a linha cinco.\nHere is li",
+ "ne six.\n"
+ ]
+ end
+ end
end
end
diff --git a/spec/ruby/core/kernel/instance_variable_get_spec.rb b/spec/ruby/core/kernel/instance_variable_get_spec.rb
index bb6f03d3bf..f1d2a45df8 100644
--- a/spec/ruby/core/kernel/instance_variable_get_spec.rb
+++ b/spec/ruby/core/kernel/instance_variable_get_spec.rb
@@ -67,6 +67,12 @@ describe "Kernel#instance_variable_get when passed Symbol" do
it "raises a NameError when the passed Symbol is an invalid instance variable name" do
-> { @obj.instance_variable_get(:"@0") }.should raise_error(NameError)
end
+
+ it "returns nil or raises for frozen objects" do
+ nil.instance_variable_get(:@foo).should == nil
+ -> { nil.instance_variable_get(:foo) }.should raise_error(NameError)
+ :foo.instance_variable_get(:@foo).should == nil
+ end
end
describe "Kernel#instance_variable_get when passed String" do
diff --git a/spec/ruby/core/kernel/instance_variable_set_spec.rb b/spec/ruby/core/kernel/instance_variable_set_spec.rb
index dbd257f7b9..2c25f4366f 100644
--- a/spec/ruby/core/kernel/instance_variable_set_spec.rb
+++ b/spec/ruby/core/kernel/instance_variable_set_spec.rb
@@ -95,5 +95,11 @@ describe "Kernel#instance_variable_set" do
o.instance_variable_set(:@💙, 42)
o.instance_variable_get(:@💙).should == 42
end
+
+ it "raises for frozen objects" do
+ -> { nil.instance_variable_set(:@foo, 42) }.should raise_error(FrozenError)
+ -> { nil.instance_variable_set(:foo, 42) }.should raise_error(NameError)
+ -> { :foo.instance_variable_set(:@foo, 42) }.should raise_error(FrozenError)
+ end
end
end
diff --git a/spec/ruby/core/kernel/remove_instance_variable_spec.rb b/spec/ruby/core/kernel/remove_instance_variable_spec.rb
index e90efc8aed..4e5ba5e018 100644
--- a/spec/ruby/core/kernel/remove_instance_variable_spec.rb
+++ b/spec/ruby/core/kernel/remove_instance_variable_spec.rb
@@ -41,6 +41,19 @@ describe "Kernel#remove_instance_variable" do
end.should raise_error(TypeError)
end
+ it "raises a FrozenError if self is frozen" do
+ o = Object.new
+ o.freeze
+ -> { o.remove_instance_variable(:@foo) }.should raise_error(FrozenError)
+ -> { o.remove_instance_variable(:foo) }.should raise_error(NameError)
+ end
+
+ it "raises for frozen objects" do
+ -> { nil.remove_instance_variable(:@foo) }.should raise_error(FrozenError)
+ -> { nil.remove_instance_variable(:foo) }.should raise_error(NameError)
+ -> { :foo.remove_instance_variable(:@foo) }.should raise_error(FrozenError)
+ end
+
describe "when passed a String" do
it_behaves_like :kernel_remove_instance_variable, nil, "@greeting"
end
diff --git a/spec/ruby/core/kernel/shared/require.rb b/spec/ruby/core/kernel/shared/require.rb
index cf01b9dc52..666ca15e11 100644
--- a/spec/ruby/core/kernel/shared/require.rb
+++ b/spec/ruby/core/kernel/shared/require.rb
@@ -568,6 +568,25 @@ describe :kernel_require, shared: true do
-> { @object.require("unicode_normalize") }.should raise_error(LoadError)
end
+
+ ruby_version_is "3.0" do
+ it "does not load a file earlier on the $LOAD_PATH when other similar features were already loaded" do
+ Dir.chdir CODE_LOADING_DIR do
+ @object.send(@method, "../code/load_fixture").should be_true
+ end
+ ScratchPad.recorded.should == [:loaded]
+
+ $LOAD_PATH.unshift "#{CODE_LOADING_DIR}/b"
+ # This loads because the above load was not on the $LOAD_PATH
+ @object.send(@method, "load_fixture").should be_true
+ ScratchPad.recorded.should == [:loaded, :loaded]
+
+ $LOAD_PATH.unshift "#{CODE_LOADING_DIR}/c"
+ # This does not load because the above load was on the $LOAD_PATH
+ @object.send(@method, "load_fixture").should be_false
+ ScratchPad.recorded.should == [:loaded, :loaded]
+ end
+ end
end
describe "(shell expansion)" do
diff --git a/spec/ruby/core/math/ldexp_spec.rb b/spec/ruby/core/math/ldexp_spec.rb
index fb7799cf26..6dcf94a663 100644
--- a/spec/ruby/core/math/ldexp_spec.rb
+++ b/spec/ruby/core/math/ldexp_spec.rb
@@ -45,6 +45,12 @@ describe "Math.ldexp" do
it "accepts any second argument that can be coerced with Integer()" do
Math.ldexp(3.23, MathSpecs::Integer.new).should be_close(12.92, TOLERANCE)
end
+
+ it "returns correct value that closes to the max value of double type" do
+ Math.ldexp(0.5122058490966879, 1024).should == 9.207889385574391e+307
+ Math.ldexp(0.9999999999999999, 1024).should == 1.7976931348623157e+308
+ Math.ldexp(0.99999999999999999, 1024).should == Float::INFINITY
+ end
end
describe "Math#ldexp" do
diff --git a/spec/ruby/core/module/class_variables_spec.rb b/spec/ruby/core/module/class_variables_spec.rb
index fd7aa93aa8..e155f1deac 100644
--- a/spec/ruby/core/module/class_variables_spec.rb
+++ b/spec/ruby/core/module/class_variables_spec.rb
@@ -23,4 +23,12 @@ describe "Module#class_variables" do
c.extend ModuleSpecs::MVars
c.class_variables.should_not include(:@@mvar)
end
+
+ it "returns the correct class variables when inherit is given" do
+ ModuleSpecs::SubCVars.class_variables(false).should == [:@@sub]
+ ModuleSpecs::SubCVars.new.singleton_class.class_variables(false).should == []
+
+ ModuleSpecs::SubCVars.class_variables(true).should == [:@@sub, :@@cls, :@@meta]
+ ModuleSpecs::SubCVars.new.singleton_class.class_variables(true).should == [:@@sub, :@@cls, :@@meta]
+ end
end
diff --git a/spec/ruby/core/module/fixtures/classes.rb b/spec/ruby/core/module/fixtures/classes.rb
index 40777cdbbd..a64f672b2f 100644
--- a/spec/ruby/core/module/fixtures/classes.rb
+++ b/spec/ruby/core/module/fixtures/classes.rb
@@ -352,6 +352,10 @@ module ModuleSpecs
end
end
+ class SubCVars < CVars
+ @@sub = :sub
+ end
+
module MVars
@@mvar = :mvar
end
diff --git a/spec/ruby/core/process/clock_gettime_spec.rb b/spec/ruby/core/process/clock_gettime_spec.rb
index 59e1406e02..f00b8db043 100644
--- a/spec/ruby/core/process/clock_gettime_spec.rb
+++ b/spec/ruby/core/process/clock_gettime_spec.rb
@@ -52,7 +52,7 @@ describe "Process.clock_gettime" do
end
# These specs need macOS 10.12+ / darwin 16+
- guard_not -> { platform_is_not(:darwin) or RUBY_PLATFORM[/darwin\d+/].to_i >= 16 } do
+ guard -> { platform_is_not(:darwin) or kernel_version_is '16' } do
platform_is :linux, :openbsd, :darwin do
it "CLOCK_PROCESS_CPUTIME_ID" do
Process.clock_gettime(Process::CLOCK_PROCESS_CPUTIME_ID).should be_an_instance_of(Float)
@@ -65,20 +65,6 @@ describe "Process.clock_gettime" do
end
end
- platform_is :freebsd, :openbsd do
- it "CLOCK_VIRTUAL" do
- Process.clock_gettime(Process::CLOCK_VIRTUAL).should be_an_instance_of(Float)
- end
-
- it "CLOCK_PROF" do
- Process.clock_gettime(Process::CLOCK_PROF).should be_an_instance_of(Float)
- end
-
- it "CLOCK_UPTIME" do
- Process.clock_gettime(Process::CLOCK_UPTIME).should be_an_instance_of(Float)
- end
- end
-
platform_is :linux, :darwin do
it "CLOCK_MONOTONIC_RAW" do
Process.clock_gettime(Process::CLOCK_MONOTONIC_RAW).should be_an_instance_of(Float)
@@ -95,42 +81,69 @@ describe "Process.clock_gettime" do
Process.clock_gettime(Process::CLOCK_UPTIME_RAW_APPROX).should be_an_instance_of(Float)
end
end
+ end
- platform_is :freebsd do
- it "CLOCK_REALTIME_FAST and CLOCK_REALTIME_PRECISE" do
- Process.clock_gettime(Process::CLOCK_REALTIME_FAST).should be_an_instance_of(Float)
- Process.clock_gettime(Process::CLOCK_REALTIME_PRECISE).should be_an_instance_of(Float)
- end
+ platform_is :freebsd, :openbsd do
+ it "CLOCK_VIRTUAL" do
+ Process.clock_gettime(Process::CLOCK_VIRTUAL).should be_an_instance_of(Float)
+ end
- it "CLOCK_MONOTONIC_FAST and CLOCK_MONOTONIC_PRECISE" do
- Process.clock_gettime(Process::CLOCK_MONOTONIC_FAST).should be_an_instance_of(Float)
- Process.clock_gettime(Process::CLOCK_MONOTONIC_PRECISE).should be_an_instance_of(Float)
- end
+ it "CLOCK_PROF" do
+ Process.clock_gettime(Process::CLOCK_PROF).should be_an_instance_of(Float)
+ end
- it "CLOCK_UPTIME_FAST and CLOCK_UPTIME_PRECISE" do
- Process.clock_gettime(Process::CLOCK_UPTIME_FAST).should be_an_instance_of(Float)
- Process.clock_gettime(Process::CLOCK_UPTIME_PRECISE).should be_an_instance_of(Float)
- end
+ it "CLOCK_UPTIME" do
+ Process.clock_gettime(Process::CLOCK_UPTIME).should be_an_instance_of(Float)
+ end
+ end
- it "CLOCK_SECOND" do
- Process.clock_gettime(Process::CLOCK_SECOND).should be_an_instance_of(Float)
- end
+ platform_is :freebsd do
+ it "CLOCK_REALTIME_FAST and CLOCK_REALTIME_PRECISE" do
+ Process.clock_gettime(Process::CLOCK_REALTIME_FAST).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_REALTIME_PRECISE).should be_an_instance_of(Float)
end
- platform_is :linux do
- it "CLOCK_REALTIME_COARSE and CLOCK_REALTIME_ALARM" do
- Process.clock_gettime(Process::CLOCK_REALTIME_COARSE).should be_an_instance_of(Float)
- Process.clock_gettime(Process::CLOCK_REALTIME_ALARM).should be_an_instance_of(Float)
- end
+ it "CLOCK_MONOTONIC_FAST and CLOCK_MONOTONIC_PRECISE" do
+ Process.clock_gettime(Process::CLOCK_MONOTONIC_FAST).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_MONOTONIC_PRECISE).should be_an_instance_of(Float)
+ end
- it "CLOCK_MONOTONIC_COARSE" do
- Process.clock_gettime(Process::CLOCK_MONOTONIC_COARSE).should be_an_instance_of(Float)
- end
+ it "CLOCK_UPTIME_FAST and CLOCK_UPTIME_PRECISE" do
+ Process.clock_gettime(Process::CLOCK_UPTIME_FAST).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_UPTIME_PRECISE).should be_an_instance_of(Float)
+ end
- it "CLOCK_BOOTTIME and CLOCK_BOOTTIME_ALARM" do
- Process.clock_gettime(Process::CLOCK_BOOTTIME).should be_an_instance_of(Float)
- Process.clock_gettime(Process::CLOCK_BOOTTIME_ALARM).should be_an_instance_of(Float)
- end
+ it "CLOCK_SECOND" do
+ Process.clock_gettime(Process::CLOCK_SECOND).should be_an_instance_of(Float)
+ end
+ end
+
+ guard -> { platform_is :linux and kernel_version_is '2.6.32' } do
+ it "CLOCK_REALTIME_COARSE" do
+ Process.clock_gettime(Process::CLOCK_REALTIME_COARSE).should be_an_instance_of(Float)
+ end
+
+ it "CLOCK_MONOTONIC_COARSE" do
+ Process.clock_gettime(Process::CLOCK_MONOTONIC_COARSE).should be_an_instance_of(Float)
+ end
+ end
+
+ guard -> { platform_is :linux and kernel_version_is '2.6.39' } do
+ it "CLOCK_BOOTTIME" do
+ skip "No Process::CLOCK_BOOTTIME" unless defined?(Process::CLOCK_BOOTTIME)
+ Process.clock_gettime(Process::CLOCK_BOOTTIME).should be_an_instance_of(Float)
+ end
+ end
+
+ guard -> { platform_is "x86_64-linux" and kernel_version_is '3.0' } do
+ it "CLOCK_REALTIME_ALARM" do
+ skip "No Process::CLOCK_REALTIME_ALARM" unless defined?(Process::CLOCK_REALTIME_ALARM)
+ Process.clock_gettime(Process::CLOCK_REALTIME_ALARM).should be_an_instance_of(Float)
+ end
+
+ it "CLOCK_BOOTTIME_ALARM" do
+ skip "No Process::CLOCK_BOOTTIME_ALARM" unless defined?(Process::CLOCK_BOOTTIME_ALARM)
+ Process.clock_gettime(Process::CLOCK_BOOTTIME_ALARM).should be_an_instance_of(Float)
end
end
end
diff --git a/spec/ruby/core/process/egid_spec.rb b/spec/ruby/core/process/egid_spec.rb
index 24dda43804..a67b623d5c 100644
--- a/spec/ruby/core/process/egid_spec.rb
+++ b/spec/ruby/core/process/egid_spec.rb
@@ -15,5 +15,44 @@ describe "Process.egid" do
end
describe "Process.egid=" do
- it "needs to be reviewed for spec completeness"
+
+ platform_is_not :windows do
+ it "raises TypeError if not passed an Integer or String" do
+ -> { Process.egid = Object.new }.should raise_error(TypeError)
+ end
+
+ it "sets the effective group id to its own gid if given the username corresponding to its own gid" do
+ raise unless Process.gid == Process.egid
+
+ require "etc"
+ group = Etc.getgrgid(Process.gid).name
+
+ Process.egid = group
+ Process.egid.should == Process.gid
+ end
+
+ as_user do
+ it "raises Errno::ERPERM if run by a non superuser trying to set the root group id" do
+ -> { Process.egid = 0 }.should raise_error(Errno::EPERM)
+ end
+
+ platform_is :linux do
+ it "raises Errno::ERPERM if run by a non superuser trying to set the group id from group name" do
+ -> { Process.egid = "root" }.should raise_error(Errno::EPERM)
+ end
+ end
+ end
+
+ as_superuser do
+ context "when ran by a superuser" do
+ it "sets the effective group id for the current process if run by a superuser" do
+ code = <<-RUBY
+ Process.egid = 1
+ puts Process.egid
+ RUBY
+ ruby_exe(code).should == "1\n"
+ end
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/process/euid_spec.rb b/spec/ruby/core/process/euid_spec.rb
index a2f1bbf42e..c1ec4171d0 100644
--- a/spec/ruby/core/process/euid_spec.rb
+++ b/spec/ruby/core/process/euid_spec.rb
@@ -21,9 +21,19 @@ describe "Process.euid=" do
-> { Process.euid = Object.new }.should raise_error(TypeError)
end
+ it "sets the effective user id to its own uid if given the username corresponding to its own uid" do
+ raise unless Process.uid == Process.euid
+
+ require "etc"
+ user = Etc.getpwuid(Process.uid).name
+
+ Process.euid = user
+ Process.euid.should == Process.uid
+ end
+
as_user do
it "raises Errno::ERPERM if run by a non superuser trying to set the superuser id" do
- -> { (Process.euid = 0)}.should raise_error(Errno::EPERM)
+ -> { Process.euid = 0 }.should raise_error(Errno::EPERM)
end
it "raises Errno::ERPERM if run by a non superuser trying to set the superuser id from username" do
diff --git a/spec/ruby/core/process/spawn_spec.rb b/spec/ruby/core/process/spawn_spec.rb
index 6be3f41a87..9aa8da8125 100644
--- a/spec/ruby/core/process/spawn_spec.rb
+++ b/spec/ruby/core/process/spawn_spec.rb
@@ -349,7 +349,7 @@ describe "Process.spawn" do
pgid = Process.getpgid(Process.pid)
# The process group is not available on all platforms.
# See "man proc" - /proc/[pid]/stat - (5) pgrp
- # In Travis arm64 environment, the value is 0.
+ # In Travis aarch64 environment, the value is 0.
#
# $ cat /proc/[pid]/stat
# 19179 (ruby) S 19160 0 0 ...
diff --git a/spec/ruby/core/process/status/equal_value_spec.rb b/spec/ruby/core/process/status/equal_value_spec.rb
index d85bb22214..d8a2be26b8 100644
--- a/spec/ruby/core/process/status/equal_value_spec.rb
+++ b/spec/ruby/core/process/status/equal_value_spec.rb
@@ -8,7 +8,7 @@ describe "Process::Status#==" do
end
it "returns true when compared to the integer status of a terminated child" do
- ruby_exe("Process.kill(:KILL, $$); exit(29)", exit_status: platform_is(:windows) ? 0 : nil)
+ ruby_exe("Process.kill(:KILL, $$); exit(29)", exit_status: platform_is(:windows) ? 0 : :SIGKILL)
$?.to_i.should == $?
$?.should == $?.to_i
end
diff --git a/spec/ruby/core/process/status/exited_spec.rb b/spec/ruby/core/process/status/exited_spec.rb
index 059cd5b1aa..a61292b146 100644
--- a/spec/ruby/core/process/status/exited_spec.rb
+++ b/spec/ruby/core/process/status/exited_spec.rb
@@ -14,7 +14,7 @@ describe "Process::Status#exited?" do
describe "for a terminated child" do
before :each do
- ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : nil)
+ ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : :SIGKILL)
end
platform_is_not :windows do
diff --git a/spec/ruby/core/process/status/exitstatus_spec.rb b/spec/ruby/core/process/status/exitstatus_spec.rb
index 3087bd619e..5c86c2b3c8 100644
--- a/spec/ruby/core/process/status/exitstatus_spec.rb
+++ b/spec/ruby/core/process/status/exitstatus_spec.rb
@@ -11,7 +11,7 @@ describe "Process::Status#exitstatus" do
describe "for a child that raised SignalException" do
before :each do
- ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : nil)
+ ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : :SIGKILL)
end
platform_is_not :windows do
diff --git a/spec/ruby/core/process/status/signaled_spec.rb b/spec/ruby/core/process/status/signaled_spec.rb
index 389092a533..c0de7b8006 100644
--- a/spec/ruby/core/process/status/signaled_spec.rb
+++ b/spec/ruby/core/process/status/signaled_spec.rb
@@ -13,7 +13,7 @@ describe "Process::Status#signaled?" do
describe "for a terminated child" do
before :each do
- ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : nil)
+ ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : :SIGKILL)
end
platform_is_not :windows do
diff --git a/spec/ruby/core/process/status/success_spec.rb b/spec/ruby/core/process/status/success_spec.rb
index c531121f08..3589cc611f 100644
--- a/spec/ruby/core/process/status/success_spec.rb
+++ b/spec/ruby/core/process/status/success_spec.rb
@@ -23,7 +23,7 @@ describe "Process::Status#success?" do
describe "for a child that was terminated" do
before :each do
- ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : nil)
+ ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : :SIGKILL)
end
platform_is_not :windows do
diff --git a/spec/ruby/core/process/status/termsig_spec.rb b/spec/ruby/core/process/status/termsig_spec.rb
index 1c87a6f455..5d286950f8 100644
--- a/spec/ruby/core/process/status/termsig_spec.rb
+++ b/spec/ruby/core/process/status/termsig_spec.rb
@@ -13,7 +13,7 @@ describe "Process::Status#termsig" do
describe "for a child that raised SignalException" do
before :each do
- ruby_exe("raise SignalException, 'SIGTERM'", exit_status: nil)
+ ruby_exe("raise SignalException, 'SIGTERM'", exit_status: :SIGTERM)
end
platform_is_not :windows do
@@ -25,7 +25,7 @@ describe "Process::Status#termsig" do
describe "for a child that was sent a signal" do
before :each do
- ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : nil)
+ ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : :SIGKILL)
end
platform_is_not :windows do
diff --git a/spec/ruby/core/process/status/to_i_spec.rb b/spec/ruby/core/process/status/to_i_spec.rb
index 7cde9b915b..39f8e2d84c 100644
--- a/spec/ruby/core/process/status/to_i_spec.rb
+++ b/spec/ruby/core/process/status/to_i_spec.rb
@@ -7,7 +7,7 @@ describe "Process::Status#to_i" do
end
it "returns an integer when the child is signaled" do
- ruby_exe('raise SignalException, "TERM"', exit_status: platform_is(:windows) ? 3 : nil)
+ ruby_exe('raise SignalException, "TERM"', exit_status: platform_is(:windows) ? 3 : :SIGTERM)
$?.to_i.should be_an_instance_of(Integer)
end
end
diff --git a/spec/ruby/core/regexp/shared/quote.rb b/spec/ruby/core/regexp/shared/quote.rb
index a55adb5bf2..33bdfd9979 100644
--- a/spec/ruby/core/regexp/shared/quote.rb
+++ b/spec/ruby/core/regexp/shared/quote.rb
@@ -12,6 +12,11 @@ describe :regexp_quote, shared: true do
Regexp.send(@method, :symbol).should == 'symbol'
end
+ it "works with substrings" do
+ str = ".+[]()"[1...-1]
+ Regexp.send(@method, str).should == '\+\[\]\('
+ end
+
it "sets the encoding of the result to US-ASCII if there are only US-ASCII characters present in the input String" do
str = "abc".force_encoding("euc-jp")
Regexp.send(@method, str).encoding.should == Encoding::US_ASCII
diff --git a/spec/ruby/core/signal/trap_spec.rb b/spec/ruby/core/signal/trap_spec.rb
index 3c78922694..2a94a81634 100644
--- a/spec/ruby/core/signal/trap_spec.rb
+++ b/spec/ruby/core/signal/trap_spec.rb
@@ -254,12 +254,10 @@ describe "Signal.trap" do
r.close
loop { w.write("a"*1024) }
RUBY
- out = ruby_exe(code, exit_status: nil)
+ out = ruby_exe(code, exit_status: :SIGPIPE)
status = $?
out.should == "nil\n"
status.should.signaled?
- status.termsig.should be_kind_of(Integer)
- Signal.signame(status.termsig).should == "PIPE"
end
end
diff --git a/spec/ruby/core/string/capitalize_spec.rb b/spec/ruby/core/string/capitalize_spec.rb
index ca8df88fec..8afaefc021 100644
--- a/spec/ruby/core/string/capitalize_spec.rb
+++ b/spec/ruby/core/string/capitalize_spec.rb
@@ -35,6 +35,10 @@ describe "String#capitalize" do
it "does not capitalize non-ASCII characters" do
"ßet".capitalize(:ascii).should == "ßet"
end
+
+ it "handles non-ASCII substrings properly" do
+ "garçon"[1..-1].capitalize(:ascii).should == "Arçon"
+ end
end
describe "full Unicode case mapping adapted for Turkic languages" do
diff --git a/spec/ruby/core/string/dup_spec.rb b/spec/ruby/core/string/dup_spec.rb
index d650788210..eec3cf0a70 100644
--- a/spec/ruby/core/string/dup_spec.rb
+++ b/spec/ruby/core/string/dup_spec.rb
@@ -49,4 +49,13 @@ describe "String#dup" do
orig.should == "xtring"
dup.should == "string"
end
+
+ it "does not modify the original setbyte-mutated string when changing dupped string" do
+ orig = "a"
+ orig.setbyte 0, "b".ord
+ copy = orig.dup
+ orig.setbyte 0, "c".ord
+ orig.should == "c"
+ copy.should == "b"
+ end
end
diff --git a/spec/ruby/core/string/insert_spec.rb b/spec/ruby/core/string/insert_spec.rb
index db42a37941..0c87df3a95 100644
--- a/spec/ruby/core/string/insert_spec.rb
+++ b/spec/ruby/core/string/insert_spec.rb
@@ -69,4 +69,13 @@ describe "String#insert with index, other" do
"あれ".insert 0, pat
end.should raise_error(Encoding::CompatibilityError)
end
+
+ it "should not call subclassed string methods" do
+ cls = Class.new(String) do
+ def replace(arg)
+ raise "should not call replace"
+ end
+ end
+ cls.new("abcd").insert(0, 'X').should == "Xabcd"
+ end
end
diff --git a/spec/ruby/core/string/lstrip_spec.rb b/spec/ruby/core/string/lstrip_spec.rb
index 6e868eac4f..02bc6b4322 100644
--- a/spec/ruby/core/string/lstrip_spec.rb
+++ b/spec/ruby/core/string/lstrip_spec.rb
@@ -50,4 +50,10 @@ describe "String#lstrip!" do
-> { "hello".freeze.lstrip! }.should raise_error(FrozenError)
-> { "".freeze.lstrip! }.should raise_error(FrozenError)
end
+
+ it "raises an ArgumentError if the first codepoint is invalid" do
+ s = "\xDFabc".force_encoding(Encoding::UTF_8)
+ s.valid_encoding?.should be_false
+ -> { s.lstrip! }.should raise_error(ArgumentError)
+ end
end
diff --git a/spec/ruby/core/string/rstrip_spec.rb b/spec/ruby/core/string/rstrip_spec.rb
index 2dc55182ae..dc34b12719 100644
--- a/spec/ruby/core/string/rstrip_spec.rb
+++ b/spec/ruby/core/string/rstrip_spec.rb
@@ -46,4 +46,10 @@ describe "String#rstrip!" do
-> { "hello".freeze.rstrip! }.should raise_error(FrozenError)
-> { "".freeze.rstrip! }.should raise_error(FrozenError)
end
+
+ it "raises an ArgumentError if the last codepoint is invalid" do
+ s = "abc\xDF".force_encoding(Encoding::UTF_8)
+ s.valid_encoding?.should be_false
+ -> { s.rstrip! }.should raise_error(ArgumentError)
+ end
end
diff --git a/spec/ruby/core/string/scrub_spec.rb b/spec/ruby/core/string/scrub_spec.rb
index 3137399291..66755bcc7b 100644
--- a/spec/ruby/core/string/scrub_spec.rb
+++ b/spec/ruby/core/string/scrub_spec.rb
@@ -14,6 +14,11 @@ describe "String#scrub with a default replacement" do
"abc\u3042#{x81}".scrub.should == "abc\u3042\uFFFD"
end
+ it "replaces invalid byte sequences in lazy substrings" do
+ x81 = [0x81].pack('C').force_encoding('utf-8')
+ "abc\u3042#{x81}def"[1...-1].scrub.should == "bc\u3042\uFFFDde"
+ end
+
it "returns a copy of self when the input encoding is BINARY" do
input = "foo".encode('BINARY')
diff --git a/spec/ruby/core/string/shared/slice.rb b/spec/ruby/core/string/shared/slice.rb
index 228af5f824..713234fffd 100644
--- a/spec/ruby/core/string/shared/slice.rb
+++ b/spec/ruby/core/string/shared/slice.rb
@@ -375,10 +375,20 @@ describe :string_slice_regexp_index, shared: true do
"hello there".send(@method, /(what?)/, 1).should == nil
end
+ it "returns nil if the index is larger than the number of captures" do
+ "hello there".send(@method, /hello (.)/, 2).should == nil
+ # You can't refer to 0 using negative indices
+ "hello there".send(@method, /hello (.)/, -2).should == nil
+ end
+
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 "returns nil if the given capture group was not matched but still sets $~" do
+ "test".send(@method, /te(z)?/, 1).should == nil
+ $~[0].should == "te"
+ $~[1].should == nil
end
it "calls to_int on the given index" do
diff --git a/spec/ruby/core/string/split_spec.rb b/spec/ruby/core/string/split_spec.rb
index 82911ef50b..7ef34c65da 100644
--- a/spec/ruby/core/string/split_spec.rb
+++ b/spec/ruby/core/string/split_spec.rb
@@ -3,12 +3,17 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "String#split with String" do
+ it "throws an ArgumentError if the string is not a valid" do
+ s = "\xDF".force_encoding(Encoding::UTF_8)
+
+ -> { s.split }.should raise_error(ArgumentError)
+ -> { s.split(':') }.should raise_error(ArgumentError)
+ end
+
it "throws an ArgumentError if the pattern is not a valid string" do
str = 'проверка'
- broken_str = 'проверка'
- broken_str.force_encoding('binary')
- broken_str.chop!
- broken_str.force_encoding('utf-8')
+ broken_str = "\xDF".force_encoding(Encoding::UTF_8)
+
-> { str.split(broken_str) }.should raise_error(ArgumentError)
end
@@ -218,6 +223,12 @@ describe "String#split with String" do
end
describe "String#split with Regexp" do
+ it "throws an ArgumentError if the string is not a valid" do
+ s = "\xDF".force_encoding(Encoding::UTF_8)
+
+ -> { s.split(/./) }.should raise_error(ArgumentError)
+ end
+
it "divides self on regexp matches" do
" now's the time".split(/ /).should == ["", "now's", "", "the", "time"]
" x\ny ".split(/ /).should == ["", "x\ny"]
diff --git a/spec/ruby/core/string/unpack/z_spec.rb b/spec/ruby/core/string/unpack/z_spec.rb
index 552851ce04..ce8da4b29e 100644
--- a/spec/ruby/core/string/unpack/z_spec.rb
+++ b/spec/ruby/core/string/unpack/z_spec.rb
@@ -20,4 +20,9 @@ describe "String#unpack with format 'Z'" do
["\x00a\x00 bc \x00", ["", "c"]]
].should be_computed_by(:unpack, "Z5Z")
end
+
+ it "does not advance past the null byte when given a 'Z' format specifier" do
+ "a\x00\x0f".unpack('Zxc').should == ['a', 15]
+ "a\x00\x0f".unpack('Zcc').should == ['a', 0, 15]
+ end
end
diff --git a/spec/ruby/core/thread/raise_spec.rb b/spec/ruby/core/thread/raise_spec.rb
index 27de3cc627..49323cf270 100644
--- a/spec/ruby/core/thread/raise_spec.rb
+++ b/spec/ruby/core/thread/raise_spec.rb
@@ -102,6 +102,30 @@ describe "Thread#raise on a sleeping thread" do
raised_again.backtrace.first.should_not include("#{__FILE__}:#{raise_again_line}:")
end
end
+
+ it "calls #exception in both the caller and in the target thread" do
+ cls = Class.new(Exception) do
+ attr_accessor :log
+ def initialize(*args)
+ @log = [] # This is shared because the super #exception uses a shallow clone
+ super
+ end
+
+ def exception(*args)
+ @log << [self, Thread.current, args]
+ super
+ end
+ end
+ exc = cls.new
+
+ @thr.raise exc, "Thread#raise #exception spec"
+ @thr.join
+ ScratchPad.recorded.should.is_a?(cls)
+ exc.log.should == [
+ [exc, Thread.current, ["Thread#raise #exception spec"]],
+ [ScratchPad.recorded, @thr, []]
+ ]
+ end
end
describe "Thread#raise on a running thread" do