summaryrefslogtreecommitdiff
path: root/spec/ruby/core/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'spec/ruby/core/kernel')
-rw-r--r--spec/ruby/core/kernel/Complex_spec.rb93
-rw-r--r--spec/ruby/core/kernel/Float_spec.rb2
-rw-r--r--spec/ruby/core/kernel/Integer_spec.rb38
-rw-r--r--spec/ruby/core/kernel/String_spec.rb2
-rw-r--r--spec/ruby/core/kernel/__dir___spec.rb16
-rw-r--r--spec/ruby/core/kernel/at_exit_spec.rb61
-rw-r--r--spec/ruby/core/kernel/caller_locations_spec.rb40
-rw-r--r--spec/ruby/core/kernel/caller_spec.rb20
-rw-r--r--spec/ruby/core/kernel/catch_spec.rb2
-rw-r--r--spec/ruby/core/kernel/class_spec.rb2
-rw-r--r--spec/ruby/core/kernel/clone_spec.rb99
-rw-r--r--spec/ruby/core/kernel/define_singleton_method_spec.rb21
-rw-r--r--spec/ruby/core/kernel/eval_spec.rb84
-rw-r--r--spec/ruby/core/kernel/exec_spec.rb4
-rw-r--r--spec/ruby/core/kernel/exit_spec.rb10
-rw-r--r--spec/ruby/core/kernel/fixtures/Complex.rb5
-rw-r--r--spec/ruby/core/kernel/fixtures/at_exit.rb3
-rw-r--r--spec/ruby/core/kernel/fixtures/classes.rb15
-rw-r--r--spec/ruby/core/kernel/fixtures/warn_core_method.rb2
-rw-r--r--spec/ruby/core/kernel/initialize_clone_spec.rb26
-rw-r--r--spec/ruby/core/kernel/initialize_copy_spec.rb9
-rw-r--r--spec/ruby/core/kernel/initialize_dup_spec.rb20
-rw-r--r--spec/ruby/core/kernel/inspect_spec.rb10
-rw-r--r--spec/ruby/core/kernel/instance_variable_get_spec.rb6
-rw-r--r--spec/ruby/core/kernel/instance_variable_set_spec.rb12
-rw-r--r--spec/ruby/core/kernel/instance_variables_spec.rb11
-rw-r--r--spec/ruby/core/kernel/iterator_spec.rb14
-rw-r--r--spec/ruby/core/kernel/lambda_spec.rb78
-rw-r--r--spec/ruby/core/kernel/match_spec.rb34
-rw-r--r--spec/ruby/core/kernel/method_spec.rb45
-rw-r--r--spec/ruby/core/kernel/not_match_spec.rb14
-rw-r--r--spec/ruby/core/kernel/open_spec.rb77
-rw-r--r--spec/ruby/core/kernel/p_spec.rb6
-rw-r--r--spec/ruby/core/kernel/print_spec.rb12
-rw-r--r--spec/ruby/core/kernel/printf_spec.rb7
-rw-r--r--spec/ruby/core/kernel/proc_spec.rb26
-rw-r--r--spec/ruby/core/kernel/public_send_spec.rb4
-rw-r--r--spec/ruby/core/kernel/rand_spec.rb4
-rw-r--r--spec/ruby/core/kernel/remove_instance_variable_spec.rb13
-rw-r--r--spec/ruby/core/kernel/require_relative_spec.rb10
-rw-r--r--spec/ruby/core/kernel/require_spec.rb20
-rw-r--r--spec/ruby/core/kernel/shared/dup_clone.rb24
-rw-r--r--spec/ruby/core/kernel/shared/load.rb83
-rw-r--r--spec/ruby/core/kernel/shared/require.rb84
-rw-r--r--spec/ruby/core/kernel/shared/sprintf.rb85
-rw-r--r--spec/ruby/core/kernel/shared/sprintf_encoding.rb39
-rw-r--r--spec/ruby/core/kernel/singleton_class_spec.rb51
-rw-r--r--spec/ruby/core/kernel/sleep_spec.rb28
-rw-r--r--spec/ruby/core/kernel/sprintf_spec.rb16
-rw-r--r--spec/ruby/core/kernel/srand_spec.rb16
-rw-r--r--spec/ruby/core/kernel/system_spec.rb17
-rw-r--r--spec/ruby/core/kernel/taint_spec.rb59
-rw-r--r--spec/ruby/core/kernel/tainted_spec.rb30
-rw-r--r--spec/ruby/core/kernel/test_spec.rb4
-rw-r--r--spec/ruby/core/kernel/to_s_spec.rb10
-rw-r--r--spec/ruby/core/kernel/trust_spec.rb41
-rw-r--r--spec/ruby/core/kernel/untaint_spec.rb41
-rw-r--r--spec/ruby/core/kernel/untrust_spec.rb39
-rw-r--r--spec/ruby/core/kernel/untrusted_spec.rb44
-rw-r--r--spec/ruby/core/kernel/warn_spec.rb101
60 files changed, 1188 insertions, 601 deletions
diff --git a/spec/ruby/core/kernel/Complex_spec.rb b/spec/ruby/core/kernel/Complex_spec.rb
index 4f043526b8..346d50ab5e 100644
--- a/spec/ruby/core/kernel/Complex_spec.rb
+++ b/spec/ruby/core/kernel/Complex_spec.rb
@@ -1,4 +1,6 @@
require_relative '../../spec_helper'
+require_relative '../../shared/kernel/complex'
+require_relative 'fixtures/Complex'
describe "Kernel.Complex()" do
describe "when passed [Complex, Complex]" do
@@ -58,7 +60,92 @@ describe "Kernel.Complex()" do
end
end
- describe "when passed a String" do
+ describe "when passed [String]" do
+ it_behaves_like :kernel_complex, :Complex_method, KernelSpecs
+
+ context "invalid argument" do
+ it "raises Encoding::CompatibilityError if String is in not ASCII-compatible encoding" do
+ -> {
+ Complex("79+4i".encode("UTF-16"))
+ }.should raise_error(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16")
+ end
+
+ it "raises ArgumentError for unrecognised Strings" do
+ -> {
+ Complex("ruby")
+ }.should raise_error(ArgumentError, 'invalid value for convert(): "ruby"')
+ end
+
+ it "raises ArgumentError for trailing garbage" do
+ -> {
+ Complex("79+4iruby")
+ }.should raise_error(ArgumentError, 'invalid value for convert(): "79+4iruby"')
+ end
+
+ it "does not understand Float::INFINITY" do
+ -> {
+ Complex("Infinity")
+ }.should raise_error(ArgumentError, 'invalid value for convert(): "Infinity"')
+
+ -> {
+ Complex("-Infinity")
+ }.should raise_error(ArgumentError, 'invalid value for convert(): "-Infinity"')
+ end
+
+ it "does not understand Float::NAN" do
+ -> {
+ Complex("NaN")
+ }.should raise_error(ArgumentError, 'invalid value for convert(): "NaN"')
+ end
+
+ it "does not understand a sequence of _" do
+ -> {
+ Complex("7__9+4__0i")
+ }.should raise_error(ArgumentError, 'invalid value for convert(): "7__9+4__0i"')
+ end
+
+ it "does not allow null-byte" do
+ -> {
+ Complex("1-2i\0")
+ }.should raise_error(ArgumentError, "string contains null byte")
+ end
+ end
+
+ context "invalid argument and exception: false passed" do
+ it "raises Encoding::CompatibilityError if String is in not ASCII-compatible encoding" do
+ -> {
+ Complex("79+4i".encode("UTF-16"), exception: false)
+ }.should raise_error(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16")
+ end
+
+ it "returns nil for unrecognised Strings" do
+ Complex("ruby", exception: false).should == nil
+ end
+
+ it "returns nil when trailing garbage" do
+ Complex("79+4iruby", exception: false).should == nil
+ end
+
+ it "returns nil for Float::INFINITY" do
+ Complex("Infinity", exception: false).should == nil
+ Complex("-Infinity", exception: false).should == nil
+ end
+
+ it "returns nil for Float::NAN" do
+ Complex("NaN", exception: false).should == nil
+ end
+
+ it "returns nil when there is a sequence of _" do
+ Complex("7__9+4__0i", exception: false).should == nil
+ end
+
+ it "returns nil when String contains null-byte" do
+ Complex("1-2i\0", exception: false).should == nil
+ end
+ end
+ end
+
+ describe "when passes [String, String]" do
it "needs to be reviewed for spec completeness"
end
@@ -182,4 +269,8 @@ describe "Kernel.Complex()" do
end
end
end
+
+ it "freezes its result" do
+ Complex(1).frozen?.should == true
+ end
end
diff --git a/spec/ruby/core/kernel/Float_spec.rb b/spec/ruby/core/kernel/Float_spec.rb
index 015bcb33d6..0f83cb5824 100644
--- a/spec/ruby/core/kernel/Float_spec.rb
+++ b/spec/ruby/core/kernel/Float_spec.rb
@@ -41,7 +41,7 @@ describe :kernel_float, shared: true do
end
it "converts Strings to floats without calling #to_f" do
- string = "10"
+ string = +"10"
string.should_not_receive(:to_f)
@object.send(:Float, string).should == 10.0
end
diff --git a/spec/ruby/core/kernel/Integer_spec.rb b/spec/ruby/core/kernel/Integer_spec.rb
index 2c78e27428..74dd3e0dd2 100644
--- a/spec/ruby/core/kernel/Integer_spec.rb
+++ b/spec/ruby/core/kernel/Integer_spec.rb
@@ -145,7 +145,7 @@ describe :kernel_integer, shared: true do
end
end
-describe "Integer() given a String", shared: true do
+describe :kernel_integer_string, shared: true do
it "raises an ArgumentError if the String is a null byte" do
-> { Integer("\0") }.should raise_error(ArgumentError)
end
@@ -348,7 +348,7 @@ describe "Integer() given a String", shared: true do
end
end
-describe "Integer() given a String and base", shared: true do
+describe :kernel_integer_string_base, shared: true do
it "raises an ArgumentError if the String is a null byte" do
-> { Integer("\0", 2) }.should raise_error(ArgumentError)
end
@@ -573,9 +573,31 @@ describe "Integer() given a String and base", shared: true do
-> { Integer("0#{d}1", base) }.should raise_error(ArgumentError)
end
end
+ end
+
+ it "raises an ArgumentError if a base is given for a non-String value" do
+ -> { Integer(98, 15) }.should raise_error(ArgumentError)
+ end
+
+ it "tries to convert the base to an integer using to_int" do
+ obj = mock('8')
+ obj.should_receive(:to_int).and_return(8)
+
+ Integer("777", obj).should == 0777
+ end
+
+ # https://bugs.ruby-lang.org/issues/19349
+ ruby_version_is ''...'3.3' do
+ it "ignores the base if it is not an integer and does not respond to #to_i" do
+ Integer("777", "8").should == 777
+ end
+ end
- it "raises an ArgumentError if a base is given for a non-String value" do
- -> { Integer(98, 15) }.should raise_error(ArgumentError)
+ ruby_version_is '3.3' do
+ it "raises a TypeError if it is not an integer and does not respond to #to_i" do
+ -> {
+ Integer("777", "8")
+ }.should raise_error(TypeError, "no implicit conversion of String into Integer")
end
end
@@ -777,9 +799,9 @@ describe "Kernel.Integer" do
# TODO: fix these specs
it_behaves_like :kernel_integer, :Integer, Kernel
- it_behaves_like "Integer() given a String", :Integer
+ it_behaves_like :kernel_integer_string, :Integer
- it_behaves_like "Integer() given a String and base", :Integer
+ it_behaves_like :kernel_integer_string_base, :Integer
it "is a public method" do
Kernel.Integer(10).should == 10
@@ -791,9 +813,9 @@ describe "Kernel#Integer" do
# TODO: fix these specs
it_behaves_like :kernel_integer, :Integer, Object.new
- it_behaves_like "Integer() given a String", :Integer
+ it_behaves_like :kernel_integer_string, :Integer
- it_behaves_like "Integer() given a String and base", :Integer
+ it_behaves_like :kernel_integer_string_base, :Integer
it "is a private method" do
Kernel.should have_private_instance_method(:Integer)
diff --git a/spec/ruby/core/kernel/String_spec.rb b/spec/ruby/core/kernel/String_spec.rb
index 47ee797be5..7caec6eda5 100644
--- a/spec/ruby/core/kernel/String_spec.rb
+++ b/spec/ruby/core/kernel/String_spec.rb
@@ -78,7 +78,7 @@ describe :kernel_String, shared: true do
end
it "returns the same object if it is already a String" do
- string = "Hello"
+ string = +"Hello"
string.should_not_receive(:to_s)
string2 = @object.send(@method, string)
string.should equal(string2)
diff --git a/spec/ruby/core/kernel/__dir___spec.rb b/spec/ruby/core/kernel/__dir___spec.rb
index 324792a408..242adbf48b 100644
--- a/spec/ruby/core/kernel/__dir___spec.rb
+++ b/spec/ruby/core/kernel/__dir___spec.rb
@@ -19,19 +19,9 @@ describe "Kernel#__dir__" do
end
end
- ruby_version_is ""..."3.0" do
- context "when used in eval with top level binding" do
- it "returns the real name of the directory containing the currently-executing file" do
- eval("__dir__", binding).should == File.realpath(File.dirname(__FILE__))
- end
- end
- end
-
- ruby_version_is "3.0" do
- context "when used in eval with top level binding" do
- it "returns nil" do
- eval("__dir__", binding).should == nil
- end
+ context "when used in eval with top level binding" do
+ it "returns nil" do
+ eval("__dir__", binding).should == nil
end
end
end
diff --git a/spec/ruby/core/kernel/at_exit_spec.rb b/spec/ruby/core/kernel/at_exit_spec.rb
index a784c1ae17..ebd9a71d15 100644
--- a/spec/ruby/core/kernel/at_exit_spec.rb
+++ b/spec/ruby/core/kernel/at_exit_spec.rb
@@ -1,67 +1,16 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
+require_relative '../../shared/kernel/at_exit'
describe "Kernel.at_exit" do
+ it_behaves_like :kernel_at_exit, :at_exit
+
it "is a private method" do
Kernel.should have_private_instance_method(:at_exit)
end
- it "runs after all other code" do
- ruby_exe("at_exit {print 5}; print 6").should == "65"
- end
-
- it "runs in reverse order of registration" do
- code = "at_exit {print 4};at_exit {print 5}; print 6; at_exit {print 7}"
- ruby_exe(code).should == "6754"
- end
-
- it "allows calling exit inside at_exit handler" do
- code = "at_exit {print 3}; at_exit {print 4; exit; print 5}; at_exit {print 6}"
- ruby_exe(code).should == "643"
- end
-
- it "gives access to the last raised exception" do
- code = <<-EOC
- at_exit do
- puts "The exception matches: \#{$! == $exception} (message=\#{$!.message})"
- end
-
- begin
- raise "foo"
- rescue => $exception
- raise
- end
- EOC
-
- result = ruby_exe(code, args: "2>&1", exit_status: 1)
- result.lines.should.include?("The exception matches: true (message=foo)\n")
- end
-
- it "both exceptions in at_exit and in the main script are printed" do
- code = 'at_exit { raise "at_exit_error" }; raise "main_script_error"'
- result = ruby_exe(code, args: "2>&1", exit_status: 1)
- result.should.include?('at_exit_error (RuntimeError)')
- result.should.include?('main_script_error (RuntimeError)')
- end
-
- it "decides the exit status if both at_exit and the main script raise SystemExit" do
- ruby_exe('at_exit { exit 43 }; exit 42', args: "2>&1", exit_status: 43)
- $?.exitstatus.should == 43
- end
-
- it "runs all at_exit even if some raise exceptions" do
- code = 'at_exit { STDERR.puts "last" }; at_exit { exit 43 }; at_exit { STDERR.puts "first" }; exit 42'
- result = ruby_exe(code, args: "2>&1", exit_status: 43)
- result.should == "first\nlast\n"
- $?.exitstatus.should == 43
- end
-
- it "runs at_exit handlers even if the main script fails to parse" do
- script = fixture(__FILE__, "at_exit.rb")
- result = ruby_exe('{', options: "-r#{script}", args: "2>&1", exit_status: 1)
- $?.should_not.success?
- result.should.include?("at_exit ran\n")
- result.should.include?("syntax error")
+ it "raises ArgumentError if called without a block" do
+ -> { at_exit }.should raise_error(ArgumentError, "called without a block")
end
end
diff --git a/spec/ruby/core/kernel/caller_locations_spec.rb b/spec/ruby/core/kernel/caller_locations_spec.rb
index 3ec8f0f432..aaacd9a910 100644
--- a/spec/ruby/core/kernel/caller_locations_spec.rb
+++ b/spec/ruby/core/kernel/caller_locations_spec.rb
@@ -34,12 +34,10 @@ describe 'Kernel#caller_locations' do
locations2.map(&:to_s).should == locations1[2..-1].map(&:to_s)
end
- ruby_version_is "2.7" do
- it "works with beginless ranges" do
- locations1 = caller_locations(0)
- locations2 = caller_locations(eval("(...5)"))
- locations2.map(&:to_s)[eval("(2..)")].should == locations1[eval("(...5)")].map(&:to_s)[eval("(2..)")]
- end
+ it "works with beginless ranges" do
+ locations1 = caller_locations(0)
+ locations2 = caller_locations((...5))
+ locations2.map(&:to_s)[eval("(2..)")].should == locations1[(...5)].map(&:to_s)[eval("(2..)")]
end
it "can be called with a range whose end is negative" do
@@ -73,14 +71,28 @@ describe 'Kernel#caller_locations' do
end
guard -> { Kernel.instance_method(:tap).source_location } do
- it "includes core library methods defined in Ruby" do
- file, line = Kernel.instance_method(:tap).source_location
- file.should.start_with?('<internal:')
-
- loc = nil
- tap { loc = caller_locations(1, 1)[0] }
- loc.label.should == "tap"
- loc.path.should.start_with? "<internal:"
+ ruby_version_is ""..."3.4" do
+ it "includes core library methods defined in Ruby" do
+ file, line = Kernel.instance_method(:tap).source_location
+ file.should.start_with?('<internal:')
+
+ loc = nil
+ tap { loc = caller_locations(1, 1)[0] }
+ loc.label.should == "tap"
+ loc.path.should.start_with? "<internal:"
+ end
+ end
+
+ ruby_version_is "3.4" do
+ it "includes core library methods defined in Ruby" do
+ file, line = Kernel.instance_method(:tap).source_location
+ file.should.start_with?('<internal:')
+
+ loc = nil
+ tap { loc = caller_locations(1, 1)[0] }
+ loc.label.should == "Kernel#tap"
+ loc.path.should.start_with? "<internal:"
+ end
end
end
end
diff --git a/spec/ruby/core/kernel/caller_spec.rb b/spec/ruby/core/kernel/caller_spec.rb
index dba65ddcb0..c3d63ccb00 100644
--- a/spec/ruby/core/kernel/caller_spec.rb
+++ b/spec/ruby/core/kernel/caller_spec.rb
@@ -38,10 +38,9 @@ describe 'Kernel#caller' do
it "returns an Array with the block given to #at_exit at the base of the stack" do
path = fixture(__FILE__, "caller_at_exit.rb")
lines = ruby_exe(path).lines
- lines.should == [
- "#{path}:6:in `foo'\n",
- "#{path}:2:in `block in <main>'\n"
- ]
+ lines.size.should == 2
+ lines[0].should =~ /\A#{path}:6:in [`'](?:Object#)?foo'\n\z/
+ lines[1].should =~ /\A#{path}:2:in [`']block in <main>'\n\z/
end
it "works with endless ranges" do
@@ -50,12 +49,10 @@ describe 'Kernel#caller' do
locations2.map(&:to_s).should == locations1[2..-1].map(&:to_s)
end
- ruby_version_is "2.7" do
- it "works with beginless ranges" do
- locations1 = KernelSpecs::CallerTest.locations(0)
- locations2 = KernelSpecs::CallerTest.locations(eval("(..5)"))
- locations2.map(&:to_s)[eval("(2..)")].should == locations1[eval("(..5)")].map(&:to_s)[eval("(2..)")]
- end
+ it "works with beginless ranges" do
+ locations1 = KernelSpecs::CallerTest.locations(0)
+ locations2 = KernelSpecs::CallerTest.locations((..5))
+ locations2.map(&:to_s)[eval("(2..)")].should == locations1[(..5)].map(&:to_s)[eval("(2..)")]
end
guard -> { Kernel.instance_method(:tap).source_location } do
@@ -65,8 +62,7 @@ describe 'Kernel#caller' do
loc = nil
tap { loc = caller(1, 1)[0] }
- loc.should.end_with? "in `tap'"
- loc.should.start_with? "<internal:"
+ loc.should =~ /\A<internal:.*in [`'](?:Kernel#)?tap'\z/
end
end
end
diff --git a/spec/ruby/core/kernel/catch_spec.rb b/spec/ruby/core/kernel/catch_spec.rb
index 4060172429..9f59d3b384 100644
--- a/spec/ruby/core/kernel/catch_spec.rb
+++ b/spec/ruby/core/kernel/catch_spec.rb
@@ -35,7 +35,7 @@ describe "Kernel.catch" do
end
it "raises an ArgumentError if a String with different identity is thrown" do
- -> { catch("exit") { throw "exit" } }.should raise_error(ArgumentError)
+ -> { catch("exit".dup) { throw "exit".dup } }.should raise_error(ArgumentError)
end
it "catches a Symbol when thrown a matching Symbol" do
diff --git a/spec/ruby/core/kernel/class_spec.rb b/spec/ruby/core/kernel/class_spec.rb
index 2725bde19b..b1d9df1671 100644
--- a/spec/ruby/core/kernel/class_spec.rb
+++ b/spec/ruby/core/kernel/class_spec.rb
@@ -19,7 +19,7 @@ describe "Kernel#class" do
end
it "returns the first non-singleton class" do
- a = "hello"
+ a = +"hello"
def a.my_singleton_method; end
a.class.should equal(String)
end
diff --git a/spec/ruby/core/kernel/clone_spec.rb b/spec/ruby/core/kernel/clone_spec.rb
index c18af4a490..5adcbbe603 100644
--- a/spec/ruby/core/kernel/clone_spec.rb
+++ b/spec/ruby/core/kernel/clone_spec.rb
@@ -28,27 +28,88 @@ describe "Kernel#clone" do
clone.class.should equal klass
end
- it "copies frozen state from the original" do
- o2 = @obj.clone
- @obj.freeze
- o3 = @obj.clone
+ describe "with no arguments" do
+ it "copies frozen state from the original" do
+ o2 = @obj.clone
+ o2.should_not.frozen?
- o2.should_not.frozen?
- o3.should.frozen?
+ @obj.freeze
+ o3 = @obj.clone
+ o3.should.frozen?
+ end
+
+ it 'copies frozen?' do
+ o = ''.freeze.clone
+ o.frozen?.should be_true
+ end
end
- ruby_version_is '3.0' do
- it 'takes an freeze: true option to frozen copy' do
- @obj.clone(freeze: true).should.frozen?
+ describe "with freeze: nil" do
+ it "copies frozen state from the original, like #clone without arguments" do
+ o2 = @obj.clone(freeze: nil)
+ o2.should_not.frozen?
+
+ @obj.freeze
+ o3 = @obj.clone(freeze: nil)
+ o3.should.frozen?
+ end
+
+ it "copies frozen?" do
+ o = "".freeze.clone(freeze: nil)
+ o.frozen?.should be_true
+ end
+ end
+
+ describe "with freeze: true" do
+ it 'makes a frozen copy if the original is frozen' do
@obj.freeze
@obj.clone(freeze: true).should.frozen?
end
+
+ it 'freezes the copy even if the original was not frozen' do
+ @obj.clone(freeze: true).should.frozen?
+ end
+
+ it "calls #initialize_clone with kwargs freeze: true" do
+ obj = KernelSpecs::CloneFreeze.new
+ obj.clone(freeze: true)
+ ScratchPad.recorded.should == [obj, { freeze: true }]
+ end
+
+ it "calls #initialize_clone with kwargs freeze: true even if #initialize_clone only takes a single argument" do
+ obj = KernelSpecs::Clone.new
+ -> { obj.clone(freeze: true) }.should raise_error(ArgumentError, 'wrong number of arguments (given 2, expected 1)')
+ end
end
- it 'takes an freeze: false option to not return frozen copy' do
- @obj.clone(freeze: false).should_not.frozen?
- @obj.freeze
- @obj.clone(freeze: false).should_not.frozen?
+ describe "with freeze: false" do
+ it 'does not freeze the copy if the original is frozen' do
+ @obj.freeze
+ @obj.clone(freeze: false).should_not.frozen?
+ end
+
+ it 'does not freeze the copy if the original is not frozen' do
+ @obj.clone(freeze: false).should_not.frozen?
+ end
+
+ it "calls #initialize_clone with kwargs freeze: false" do
+ obj = KernelSpecs::CloneFreeze.new
+ obj.clone(freeze: false)
+ ScratchPad.recorded.should == [obj, { freeze: false }]
+ end
+
+ it "calls #initialize_clone with kwargs freeze: false even if #initialize_clone only takes a single argument" do
+ obj = KernelSpecs::Clone.new
+ -> { obj.clone(freeze: false) }.should raise_error(ArgumentError, 'wrong number of arguments (given 2, expected 1)')
+ end
+ end
+
+ describe "with freeze: anything else" do
+ it 'raises ArgumentError when passed not true/false/nil' do
+ -> { @obj.clone(freeze: 1) }.should raise_error(ArgumentError, /unexpected value for freeze: Integer/)
+ -> { @obj.clone(freeze: "") }.should raise_error(ArgumentError, /unexpected value for freeze: String/)
+ -> { @obj.clone(freeze: Object.new) }.should raise_error(ArgumentError, /unexpected value for freeze: Object/)
+ end
end
it "copies instance variables" do
@@ -113,16 +174,4 @@ describe "Kernel#clone" do
cloned.bar.should == ['a']
end
-
- it 'copies frozen?' do
- o = ''.freeze.clone
- o.frozen?.should be_true
- end
-
- ruby_version_is ''...'2.7' do
- it 'copies tainted?' do
- o = ''.taint.clone
- o.tainted?.should be_true
- end
- end
end
diff --git a/spec/ruby/core/kernel/define_singleton_method_spec.rb b/spec/ruby/core/kernel/define_singleton_method_spec.rb
index dc77c3e6f8..24acec84f5 100644
--- a/spec/ruby/core/kernel/define_singleton_method_spec.rb
+++ b/spec/ruby/core/kernel/define_singleton_method_spec.rb
@@ -96,4 +96,25 @@ describe "Kernel#define_singleton_method" do
o.define(:foo) { raise "not used" }
}.should raise_error(ArgumentError)
end
+
+ it "always defines the method with public visibility" do
+ cls = Class.new
+ def cls.define(name, &block)
+ private
+ define_singleton_method(name, &block)
+ end
+
+ -> {
+ suppress_warning do
+ cls.define(:foo) { :ok }
+ end
+ cls.foo.should == :ok
+ }.should_not raise_error(NoMethodError)
+ end
+
+ it "cannot define a singleton method with a frozen singleton class" do
+ o = Object.new
+ o.freeze
+ -> { o.define_singleton_method(:foo) { 1 } }.should raise_error(FrozenError)
+ end
end
diff --git a/spec/ruby/core/kernel/eval_spec.rb b/spec/ruby/core/kernel/eval_spec.rb
index 1e2764a4de..454bc4a58e 100644
--- a/spec/ruby/core/kernel/eval_spec.rb
+++ b/spec/ruby/core/kernel/eval_spec.rb
@@ -135,7 +135,7 @@ describe "Kernel#eval" do
it "includes file and line information in syntax error" do
expected = 'speccing.rb'
-> {
- eval('if true',TOPLEVEL_BINDING, expected)
+ eval('if true', TOPLEVEL_BINDING, expected)
}.should raise_error(SyntaxError) { |e|
e.message.should =~ /#{expected}:1:.+/
}
@@ -144,7 +144,7 @@ describe "Kernel#eval" do
it "evaluates string with given filename and negative linenumber" do
expected_file = 'speccing.rb'
-> {
- eval('if true',TOPLEVEL_BINDING, expected_file, -100)
+ eval('if true', TOPLEVEL_BINDING, expected_file, -100)
}.should raise_error(SyntaxError) { |e|
e.message.should =~ /#{expected_file}:-100:.+/
}
@@ -159,18 +159,7 @@ describe "Kernel#eval" do
end
end
- ruby_version_is ""..."3.0" do
- it "uses the filename of the binding if none is provided" do
- eval("__FILE__").should == "(eval)"
- suppress_warning {eval("__FILE__", binding)}.should == __FILE__
- eval("__FILE__", binding, "success").should == "success"
- suppress_warning {eval("eval '__FILE__', binding")}.should == "(eval)"
- suppress_warning {eval("eval '__FILE__', binding", binding)}.should == __FILE__
- suppress_warning {eval("eval '__FILE__', binding", binding, 'success')}.should == 'success'
- end
- end
-
- ruby_version_is "3.0" do
+ ruby_version_is ""..."3.3" do
it "uses (eval) filename if none is provided" do
eval("__FILE__").should == "(eval)"
eval("__FILE__", binding).should == "(eval)"
@@ -180,8 +169,27 @@ describe "Kernel#eval" do
eval("eval '__FILE__', binding", binding, 'success').should == '(eval)'
eval("eval '__FILE__', binding, 'success'", binding).should == 'success'
end
+
+ it 'uses (eval) for __FILE__ and 1 for __LINE__ with a binding argument' do
+ eval("[__FILE__, __LINE__]", binding).should == ["(eval)", 1]
+ end
end
+ ruby_version_is "3.3" do
+ it "uses (eval at __FILE__:__LINE__) if none is provided" do
+ eval("__FILE__").should == "(eval at #{__FILE__}:#{__LINE__})"
+ eval("__FILE__", binding).should == "(eval at #{__FILE__}:#{__LINE__})"
+ eval("__FILE__", binding, "success").should == "success"
+ eval("eval '__FILE__', binding").should == "(eval at (eval at #{__FILE__}:#{__LINE__}):1)"
+ eval("eval '__FILE__', binding", binding).should == "(eval at (eval at #{__FILE__}:#{__LINE__}):1)"
+ eval("eval '__FILE__', binding", binding, 'success').should == "(eval at success:1)"
+ eval("eval '__FILE__', binding, 'success'", binding).should == 'success'
+ end
+
+ it 'uses (eval at __FILE__:__LINE__) for __FILE__ and 1 for __LINE__ with a binding argument' do
+ eval("[__FILE__, __LINE__]", binding).should == ["(eval at #{__FILE__}:#{__LINE__})", 1]
+ end
+ end
# Found via Rubinius bug github:#149
it "does not alter the value of __FILE__ in the binding" do
first_time = EvalSpecs.call_eval
@@ -218,6 +226,20 @@ describe "Kernel#eval" do
-> { eval("return :eval") }.call.should == :eval
end
+ it "returns from the method calling #eval when evaluating 'return'" do
+ def eval_return(n)
+ eval("return n*2")
+ end
+ -> { eval_return(3) }.call.should == 6
+ end
+
+ it "returns from the method calling #eval when evaluating 'return' in BEGIN" do
+ def eval_return(n)
+ eval("BEGIN {return n*3}")
+ end
+ -> { eval_return(4) }.call.should == 12
+ end
+
it "unwinds through a Proc-style closure and returns from a lambda-style closure in the closure chain" do
code = fixture __FILE__, "eval_return_with_lambda.rb"
ruby_exe(code).chomp.should == "a,b,c,eval,f"
@@ -239,6 +261,19 @@ describe "Kernel#eval" do
end
end
+ it "makes flip-flop operator work correctly" do
+ ScratchPad.record []
+
+ eval "10.times { |i| ScratchPad << i if (i == 4)...(i == 4) }"
+ ScratchPad.recorded.should == [4, 5, 6, 7, 8, 9]
+
+ ScratchPad.clear
+ end
+
+ it "returns nil if given an empty string" do
+ eval("").should == nil
+ end
+
# See language/magic_comment_spec.rb for more magic comments specs
describe "with a magic encoding comment" do
it "uses the magic comment encoding for the encoding of literal strings" do
@@ -315,12 +350,11 @@ CODE
end
it "allows a magic encoding comment and a subsequent frozen_string_literal magic comment" do
- # Make sure frozen_string_literal is not default true
- eval("'foo'".b).frozen?.should be_false
+ frozen_string_default = "test".frozen?
code = <<CODE.b
# encoding: UTF-8
-# frozen_string_literal: true
+# frozen_string_literal: #{!frozen_string_default}
class EvalSpecs
Vπstring = "frozen"
end
@@ -330,7 +364,7 @@ CODE
EvalSpecs.constants(false).should include(:"Vπstring")
EvalSpecs::Vπstring.should == "frozen"
EvalSpecs::Vπstring.encoding.should == Encoding::UTF_8
- EvalSpecs::Vπstring.frozen?.should be_true
+ EvalSpecs::Vπstring.frozen?.should == !frozen_string_default
end
it "allows a magic encoding comment and a frozen_string_literal magic comment on the same line in emacs style" do
@@ -349,8 +383,9 @@ CODE
end
it "ignores the magic encoding comment if it is after a frozen_string_literal magic comment" do
+ frozen_string_default = "test".frozen?
code = <<CODE.b
-# frozen_string_literal: true
+# frozen_string_literal: #{!frozen_string_default}
# encoding: UTF-8
class EvalSpecs
Vπfrozen_first = "frozen"
@@ -364,23 +399,24 @@ CODE
value = EvalSpecs.const_get(binary_constant)
value.should == "frozen"
value.encoding.should == Encoding::BINARY
- value.frozen?.should be_true
+ value.frozen?.should == !frozen_string_default
end
it "ignores the frozen_string_literal magic comment if it appears after a token and warns if $VERBOSE is true" do
+ frozen_string_default = "test".frozen?
code = <<CODE
some_token_before_magic_comment = :anything
-# frozen_string_literal: true
+# frozen_string_literal: #{!frozen_string_default}
class EvalSpecs
Vπstring_not_frozen = "not frozen"
end
CODE
- -> { eval(code) }.should complain(/warning: `frozen_string_literal' is ignored after any tokens/, verbose: true)
- EvalSpecs::Vπstring_not_frozen.frozen?.should be_false
+ -> { eval(code) }.should complain(/warning: [`']frozen_string_literal' is ignored after any tokens/, verbose: true)
+ EvalSpecs::Vπstring_not_frozen.frozen?.should == frozen_string_default
EvalSpecs.send :remove_const, :Vπstring_not_frozen
-> { eval(code) }.should_not complain(verbose: false)
- EvalSpecs::Vπstring_not_frozen.frozen?.should be_false
+ EvalSpecs::Vπstring_not_frozen.frozen?.should == frozen_string_default
EvalSpecs.send :remove_const, :Vπstring_not_frozen
end
end
diff --git a/spec/ruby/core/kernel/exec_spec.rb b/spec/ruby/core/kernel/exec_spec.rb
index 1b4a7ae6f4..3d9520ad67 100644
--- a/spec/ruby/core/kernel/exec_spec.rb
+++ b/spec/ruby/core/kernel/exec_spec.rb
@@ -7,12 +7,12 @@ describe "Kernel#exec" do
end
it "runs the specified command, replacing current process" do
- ruby_exe('exec "echo hello"; puts "fail"', escape: true).should == "hello\n"
+ ruby_exe('exec "echo hello"; puts "fail"').should == "hello\n"
end
end
describe "Kernel.exec" do
it "runs the specified command, replacing current process" do
- ruby_exe('Kernel.exec "echo hello"; puts "fail"', escape: true).should == "hello\n"
+ ruby_exe('Kernel.exec "echo hello"; puts "fail"').should == "hello\n"
end
end
diff --git a/spec/ruby/core/kernel/exit_spec.rb b/spec/ruby/core/kernel/exit_spec.rb
index f168cb375e..93cec3fee5 100644
--- a/spec/ruby/core/kernel/exit_spec.rb
+++ b/spec/ruby/core/kernel/exit_spec.rb
@@ -10,6 +10,10 @@ describe "Kernel#exit" do
it_behaves_like :process_exit, :exit, KernelSpecs::Method.new
end
+describe "Kernel.exit" do
+ it_behaves_like :process_exit, :exit, Kernel
+end
+
describe "Kernel#exit!" do
it "is a private method" do
Kernel.should have_private_instance_method(:exit!)
@@ -18,10 +22,6 @@ describe "Kernel#exit!" do
it_behaves_like :process_exit!, :exit!, "self"
end
-describe "Kernel.exit" do
- it_behaves_like :process_exit, :exit, Kernel
-end
-
describe "Kernel.exit!" do
- it_behaves_like :process_exit!, :exit!, Kernel
+ it_behaves_like :process_exit!, :exit!, "Kernel"
end
diff --git a/spec/ruby/core/kernel/fixtures/Complex.rb b/spec/ruby/core/kernel/fixtures/Complex.rb
new file mode 100644
index 0000000000..bf14d55ad5
--- /dev/null
+++ b/spec/ruby/core/kernel/fixtures/Complex.rb
@@ -0,0 +1,5 @@
+module KernelSpecs
+ def self.Complex_method(string)
+ Complex(string)
+ end
+end
diff --git a/spec/ruby/core/kernel/fixtures/at_exit.rb b/spec/ruby/core/kernel/fixtures/at_exit.rb
deleted file mode 100644
index 9c11a7ad6c..0000000000
--- a/spec/ruby/core/kernel/fixtures/at_exit.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-at_exit do
- STDERR.puts "at_exit ran"
-end
diff --git a/spec/ruby/core/kernel/fixtures/classes.rb b/spec/ruby/core/kernel/fixtures/classes.rb
index 1bf5715c50..541a4c075e 100644
--- a/spec/ruby/core/kernel/fixtures/classes.rb
+++ b/spec/ruby/core/kernel/fixtures/classes.rb
@@ -281,14 +281,25 @@ module KernelSpecs
@two = two
end
- def initialize_copy(other)
+ def initialize_copy(other, **kw)
ScratchPad.record object_id
end
+
+ # define to support calling #clone with optional :freeze keyword argument
+ def initialize_clone(other, **kw)
+ super(other) # to call #initialize_copy
+ end
end
class Clone
def initialize_clone(other)
- ScratchPad.record other.object_id
+ ScratchPad.record other
+ end
+ end
+
+ class CloneFreeze
+ def initialize_clone(other, **kwargs)
+ ScratchPad.record([other, kwargs])
end
end
diff --git a/spec/ruby/core/kernel/fixtures/warn_core_method.rb b/spec/ruby/core/kernel/fixtures/warn_core_method.rb
index f5dee6b668..fd82562404 100644
--- a/spec/ruby/core/kernel/fixtures/warn_core_method.rb
+++ b/spec/ruby/core/kernel/fixtures/warn_core_method.rb
@@ -1,6 +1,6 @@
raise 'should be run without RubyGems' if defined?(Gem)
-def deprecated(n=1)
+public def deprecated(n=1)
# puts nil, caller(0), nil
warn "use X instead", uplevel: n
end
diff --git a/spec/ruby/core/kernel/initialize_clone_spec.rb b/spec/ruby/core/kernel/initialize_clone_spec.rb
new file mode 100644
index 0000000000..21a90c19f0
--- /dev/null
+++ b/spec/ruby/core/kernel/initialize_clone_spec.rb
@@ -0,0 +1,26 @@
+require_relative '../../spec_helper'
+
+describe "Kernel#initialize_clone" do
+ it "is a private instance method" do
+ Kernel.should have_private_instance_method(:initialize_clone)
+ end
+
+ it "returns the receiver" do
+ a = Object.new
+ b = Object.new
+ a.send(:initialize_clone, b).should == a
+ end
+
+ it "calls #initialize_copy" do
+ a = Object.new
+ b = Object.new
+ a.should_receive(:initialize_copy).with(b)
+ a.send(:initialize_clone, b)
+ end
+
+ it "accepts a :freeze keyword argument for obj.clone(freeze: value)" do
+ a = Object.new
+ b = Object.new
+ a.send(:initialize_clone, b, freeze: true).should == a
+ end
+end
diff --git a/spec/ruby/core/kernel/initialize_copy_spec.rb b/spec/ruby/core/kernel/initialize_copy_spec.rb
index fe08d184ad..d71ca9f60f 100644
--- a/spec/ruby/core/kernel/initialize_copy_spec.rb
+++ b/spec/ruby/core/kernel/initialize_copy_spec.rb
@@ -1,11 +1,18 @@
require_relative '../../spec_helper'
describe "Kernel#initialize_copy" do
+ it "returns self" do
+ obj = Object.new
+ obj.send(:initialize_copy, obj).should.equal?(obj)
+ end
+
it "does nothing if the argument is the same as the receiver" do
obj = Object.new
obj.send(:initialize_copy, obj).should.equal?(obj)
- obj.freeze
+
+ obj = Object.new.freeze
obj.send(:initialize_copy, obj).should.equal?(obj)
+
1.send(:initialize_copy, 1).should.equal?(1)
end
diff --git a/spec/ruby/core/kernel/initialize_dup_spec.rb b/spec/ruby/core/kernel/initialize_dup_spec.rb
new file mode 100644
index 0000000000..6dff34b7ad
--- /dev/null
+++ b/spec/ruby/core/kernel/initialize_dup_spec.rb
@@ -0,0 +1,20 @@
+require_relative '../../spec_helper'
+
+describe "Kernel#initialize_dup" do
+ it "is a private instance method" do
+ Kernel.should have_private_instance_method(:initialize_dup)
+ end
+
+ it "returns the receiver" do
+ a = Object.new
+ b = Object.new
+ a.send(:initialize_dup, b).should == a
+ end
+
+ it "calls #initialize_copy" do
+ a = Object.new
+ b = Object.new
+ a.should_receive(:initialize_copy).with(b)
+ a.send(:initialize_dup, b)
+ end
+end
diff --git a/spec/ruby/core/kernel/inspect_spec.rb b/spec/ruby/core/kernel/inspect_spec.rb
index e6fca8bf6f..1f9ce834ab 100644
--- a/spec/ruby/core/kernel/inspect_spec.rb
+++ b/spec/ruby/core/kernel/inspect_spec.rb
@@ -6,16 +6,6 @@ describe "Kernel#inspect" do
Object.new.inspect.should be_an_instance_of(String)
end
- ruby_version_is ''...'2.7' do
- it "returns a tainted string if self is tainted" do
- Object.new.taint.inspect.tainted?.should be_true
- end
-
- it "returns an untrusted string if self is untrusted" do
- Object.new.untrust.inspect.untrusted?.should be_true
- end
- end
-
it "does not call #to_s if it is defined" do
# We must use a bare Object here
obj = Object.new
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 7fda30f72c..2c25f4366f 100644
--- a/spec/ruby/core/kernel/instance_variable_set_spec.rb
+++ b/spec/ruby/core/kernel/instance_variable_set_spec.rb
@@ -89,5 +89,17 @@ describe "Kernel#instance_variable_set" do
it "raises a FrozenError when passed replacement is different from stored object" do
-> { @frozen.instance_variable_set(:@ivar, :replacement) }.should raise_error(FrozenError)
end
+
+ it "accepts unicode instance variable names" do
+ o = Object.new
+ 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/instance_variables_spec.rb b/spec/ruby/core/kernel/instance_variables_spec.rb
index 831f0662a2..677d8bb7b2 100644
--- a/spec/ruby/core/kernel/instance_variables_spec.rb
+++ b/spec/ruby/core/kernel/instance_variables_spec.rb
@@ -25,5 +25,16 @@ describe "Kernel#instance_variables" do
a.instance_variable_set("@test", 1)
a.instance_variables.should == [:@test]
end
+
+ it "returns the instances variables in the order declared" do
+ c = Class.new do
+ def initialize
+ @c = 1
+ @a = 2
+ @b = 3
+ end
+ end
+ c.new.instance_variables.should == [:@c, :@a, :@b]
+ end
end
end
diff --git a/spec/ruby/core/kernel/iterator_spec.rb b/spec/ruby/core/kernel/iterator_spec.rb
deleted file mode 100644
index 3fe8317f26..0000000000
--- a/spec/ruby/core/kernel/iterator_spec.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-
-ruby_version_is ""..."3.0" do
- describe "Kernel#iterator?" do
- it "is a private method" do
- Kernel.should have_private_instance_method(:iterator?)
- end
- end
-
- describe "Kernel.iterator?" do
- it "needs to be reviewed for spec completeness"
- end
-end
diff --git a/spec/ruby/core/kernel/lambda_spec.rb b/spec/ruby/core/kernel/lambda_spec.rb
index 9a960f3589..565536ac0d 100644
--- a/spec/ruby/core/kernel/lambda_spec.rb
+++ b/spec/ruby/core/kernel/lambda_spec.rb
@@ -26,42 +26,44 @@ describe "Kernel.lambda" do
l.lambda?.should be_true
end
- it "creates a lambda-style Proc if given a literal block via Kernel.public_send" do
- suppress_warning do
- l = Kernel.public_send(:lambda) { 42 }
- l.lambda?.should be_true
+ ruby_version_is ""..."3.3" do
+ it "creates a lambda-style Proc if given a literal block via Kernel.public_send" do
+ suppress_warning do
+ l = Kernel.public_send(:lambda) { 42 }
+ l.lambda?.should be_true
+ end
end
- end
- it "returns the passed Proc if given an existing Proc" do
- some_proc = proc {}
- l = suppress_warning {lambda(&some_proc)}
- l.should equal(some_proc)
- l.lambda?.should be_false
- end
+ it "returns the passed Proc if given an existing Proc" do
+ some_proc = proc {}
+ l = suppress_warning {lambda(&some_proc)}
+ l.should equal(some_proc)
+ l.lambda?.should be_false
+ end
- it "creates a lambda-style Proc when called with zsuper" do
- suppress_warning do
- l = KernelSpecs::LambdaSpecs::ForwardBlockWithZSuper.new.lambda { 42 }
- l.lambda?.should be_true
- l.call.should == 42
+ it "creates a lambda-style Proc when called with zsuper" do
+ suppress_warning do
+ l = KernelSpecs::LambdaSpecs::ForwardBlockWithZSuper.new.lambda { 42 }
+ l.lambda?.should be_true
+ l.call.should == 42
- lambda { l.call(:extra) }.should raise_error(ArgumentError)
+ lambda { l.call(:extra) }.should raise_error(ArgumentError)
+ end
end
- end
- it "returns the passed Proc if given an existing Proc through super" do
- some_proc = proc { }
- l = KernelSpecs::LambdaSpecs::SuperAmpersand.new.lambda(&some_proc)
- l.should equal(some_proc)
- l.lambda?.should be_false
- end
+ it "returns the passed Proc if given an existing Proc through super" do
+ some_proc = proc { }
+ l = KernelSpecs::LambdaSpecs::SuperAmpersand.new.lambda(&some_proc)
+ l.should equal(some_proc)
+ l.lambda?.should be_false
+ end
- it "does not create lambda-style Procs when captured with #method" do
- kernel_lambda = method(:lambda)
- l = suppress_warning {kernel_lambda.call { 42 }}
- l.lambda?.should be_false
- l.call(:extra).should == 42
+ it "does not create lambda-style Procs when captured with #method" do
+ kernel_lambda = method(:lambda)
+ l = suppress_warning {kernel_lambda.call { 42 }}
+ l.lambda?.should be_false
+ l.call(:extra).should == 42
+ end
end
it "checks the arity of the call when no args are specified" do
@@ -135,4 +137,22 @@ describe "Kernel.lambda" do
klass.new.lambda { 42 }.should be_an_instance_of Proc
klass.new.ret.should == 1
end
+
+ context "when called without a literal block" do
+ ruby_version_is ""..."3.3" do
+ it "warns when proc isn't a lambda" do
+ -> { lambda(&proc{}) }.should complain("#{__FILE__}:#{__LINE__}: warning: lambda without a literal block is deprecated; use the proc without lambda instead\n")
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raises when proc isn't a lambda" do
+ -> { lambda(&proc{}) }.should raise_error(ArgumentError, /the lambda method requires a literal block/)
+ end
+ end
+
+ it "doesn't warn when proc is lambda" do
+ -> { lambda(&lambda{}) }.should_not complain(verbose: true)
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/match_spec.rb b/spec/ruby/core/kernel/match_spec.rb
index fbfc77f959..aa25006163 100644
--- a/spec/ruby/core/kernel/match_spec.rb
+++ b/spec/ruby/core/kernel/match_spec.rb
@@ -1,22 +1,30 @@
require_relative '../../spec_helper'
describe "Kernel#=~" do
- it "returns nil matching any object" do
- o = Object.new
+ ruby_version_is ''...'3.2' do
+ it "returns nil matching any object" do
+ o = Object.new
- suppress_warning do
- (o =~ /Object/).should be_nil
- (o =~ 'Object').should be_nil
- (o =~ Object).should be_nil
- (o =~ Object.new).should be_nil
- (o =~ nil).should be_nil
- (o =~ true).should be_nil
+ suppress_warning do
+ (o =~ /Object/).should be_nil
+ (o =~ 'Object').should be_nil
+ (o =~ Object).should be_nil
+ (o =~ Object.new).should be_nil
+ (o =~ nil).should be_nil
+ (o =~ true).should be_nil
+ end
+ end
+
+ it "is deprecated" do
+ -> do
+ Object.new =~ /regexp/
+ end.should complain(/deprecated Object#=~ is called on Object/, verbose: true)
end
end
- it "is deprecated" do
- -> do
- Object.new =~ /regexp/
- end.should complain(/deprecated Object#=~ is called on Object/, verbose: true)
+ ruby_version_is '3.2' do
+ it "is no longer defined" do
+ Object.new.should_not.respond_to?(:=~)
+ end
end
end
diff --git a/spec/ruby/core/kernel/method_spec.rb b/spec/ruby/core/kernel/method_spec.rb
index 25c6691e10..3fc566d6a6 100644
--- a/spec/ruby/core/kernel/method_spec.rb
+++ b/spec/ruby/core/kernel/method_spec.rb
@@ -29,9 +29,52 @@ describe "Kernel#method" do
m.call.should == :defined
end
- it "can be called even if we only repond_to_missing? method, true" do
+ it "can be called even if we only respond_to_missing? method, true" do
m = KernelSpecs::RespondViaMissing.new.method(:handled_privately)
m.should be_an_instance_of(Method)
m.call(1, 2, 3).should == "Done handled_privately([1, 2, 3])"
end
+
+ it "can call a #method_missing accepting zero or one arguments" do
+ cls = Class.new do
+ def respond_to_missing?(name, *)
+ name == :foo or super
+ end
+ def method_missing
+ :no_args
+ end
+ end
+ m = cls.new.method(:foo)
+ -> { m.call }.should raise_error(ArgumentError)
+
+ cls = Class.new do
+ def respond_to_missing?(name, *)
+ name == :bar or super
+ end
+ def method_missing(m)
+ m
+ end
+ end
+ m = cls.new.method(:bar)
+ m.call.should == :bar
+ end
+
+ describe "converts the given name to a String using #to_str" do
+ it "calls #to_str to convert the given name to a String" do
+ name = mock("method-name")
+ name.should_receive(:to_str).and_return("hash")
+ Object.method(name).should == Object.method(:hash)
+ end
+
+ it "raises a TypeError if the given name can't be converted to a String" do
+ -> { Object.method(nil) }.should raise_error(TypeError)
+ -> { Object.method([]) }.should raise_error(TypeError)
+ end
+
+ it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to a String" do
+ name = mock("method-name")
+ name.should_receive(:to_str).and_raise(NoMethodError)
+ -> { Object.method(name) }.should raise_error(NoMethodError)
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/not_match_spec.rb b/spec/ruby/core/kernel/not_match_spec.rb
index 906f18df2c..f8dd82fad8 100644
--- a/spec/ruby/core/kernel/not_match_spec.rb
+++ b/spec/ruby/core/kernel/not_match_spec.rb
@@ -14,6 +14,20 @@ describe "Kernel#!~" do
(obj !~ :foo).should == false
end
+ ruby_version_is ""..."3.2" do
+ it "returns true if self does not respond to #=~" do
+ suppress_warning do
+ (Object.new !~ :foo).should == true
+ end
+ end
+ end
+
+ ruby_version_is "3.2" do
+ it "raises NoMethodError if self does not respond to #=~" do
+ -> { Object.new !~ :foo }.should raise_error(NoMethodError)
+ end
+ end
+
it 'can be overridden in subclasses' do
obj = KernelSpecs::NotMatch.new
(obj !~ :bar).should == :foo
diff --git a/spec/ruby/core/kernel/open_spec.rb b/spec/ruby/core/kernel/open_spec.rb
index 8d936d8ca0..bb42c31f31 100644
--- a/spec/ruby/core/kernel/open_spec.rb
+++ b/spec/ruby/core/kernel/open_spec.rb
@@ -27,9 +27,11 @@ describe "Kernel#open" do
open(@name, "r") { |f| f.gets }.should == @content
end
- platform_is_not :windows do
+ platform_is_not :windows, :wasi do
it "opens an io when path starts with a pipe" do
- @io = open("|date")
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ @io = open("|date")
+ end
begin
@io.should be_kind_of(IO)
@io.read
@@ -39,21 +41,27 @@ describe "Kernel#open" do
end
it "opens an io when called with a block" do
- @output = open("|date") { |f| f.read }
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ @output = open("|date") { |f| f.read }
+ end
@output.should_not == ''
end
it "opens an io for writing" do
- -> do
- bytes = open("|cat", "w") { |io| io.write(".") }
- bytes.should == 1
- end.should output_to_fd(".")
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ -> {
+ bytes = open("|cat", "w") { |io| io.write(".") }
+ bytes.should == 1
+ }.should output_to_fd(".")
+ end
end
end
platform_is :windows do
it "opens an io when path starts with a pipe" do
- @io = open("|date /t")
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ @io = open("|date /t")
+ end
begin
@io.should be_kind_of(IO)
@io.read
@@ -63,15 +71,36 @@ describe "Kernel#open" do
end
it "opens an io when called with a block" do
- @output = open("|date /t") { |f| f.read }
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ @output = open("|date /t") { |f| f.read }
+ end
@output.should_not == ''
end
end
+ ruby_version_is "3.3" do
+ # https://bugs.ruby-lang.org/issues/19630
+ it "warns about deprecation given a path with a pipe" do
+ cmd = "|echo ok"
+ -> {
+ open(cmd) { |f| f.read }
+ }.should complain(/Kernel#open with a leading '\|'/)
+ end
+ end
+
it "raises an ArgumentError if not passed one argument" do
-> { open }.should raise_error(ArgumentError)
end
+ it "accepts options as keyword arguments" do
+ @file = open(@name, "r", 0666, flags: File::CREAT)
+ @file.should be_kind_of(File)
+
+ -> {
+ open(@name, "r", 0666, {flags: File::CREAT})
+ }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 1..3)")
+ end
+
describe "when given an object that responds to to_open" do
before :each do
ScratchPad.clear
@@ -109,11 +138,21 @@ describe "Kernel#open" do
it "passes its arguments onto #to_open" do
obj = mock('to_open')
- obj.should_receive(:to_open).with(1,2,3)
-
+ obj.should_receive(:to_open).with(1, 2, 3)
open(obj, 1, 2, 3)
end
+ it "passes keyword arguments onto #to_open as keyword arguments if to_open accepts them" do
+ obj = Object.new
+ def obj.to_open(*args, **kw)
+ ScratchPad << {args: args, kw: kw}
+ end
+
+ ScratchPad.record []
+ open(obj, 1, 2, 3, a: "b")
+ ScratchPad.recorded.should == [args: [1, 2, 3], kw: {a: "b"}]
+ end
+
it "passes the return value from #to_open to a block" do
obj = mock('to_open')
obj.should_receive(:to_open).and_return(:value)
@@ -137,16 +176,14 @@ describe "Kernel#open" do
open(@name, nil, nil) { |f| f.gets }.should == @content
end
- ruby_version_is ""..."3.0" do
- it "works correctly when redefined by open-uri" do
- code = <<~RUBY
+ it "is not redefined by open-uri" do
+ code = <<~RUBY
+ before = Kernel.instance_method(:open)
require 'open-uri'
- obj = Object.new
- def obj.to_open; self; end
- p open(obj) == obj
- RUBY
- ruby_exe(code, args: "2>&1").should == "true\n"
- end
+ after = Kernel.instance_method(:open)
+ p before == after
+ RUBY
+ ruby_exe(code, args: "2>&1").should == "true\n"
end
end
diff --git a/spec/ruby/core/kernel/p_spec.rb b/spec/ruby/core/kernel/p_spec.rb
index 1bdd1740ca..eae191aa54 100644
--- a/spec/ruby/core/kernel/p_spec.rb
+++ b/spec/ruby/core/kernel/p_spec.rb
@@ -76,10 +76,8 @@ describe "Kernel#p" do
-> { p(*[]) }.should output("")
end
-=begin Not sure how to spec this, but wanted to note the behavior here
- it "does not flush if receiver is not a TTY or a File" do
- end
-=end
+ # Not sure how to spec this, but wanted to note the behavior here
+ it "does not flush if receiver is not a TTY or a File"
end
describe "Kernel.p" do
diff --git a/spec/ruby/core/kernel/print_spec.rb b/spec/ruby/core/kernel/print_spec.rb
index c8c4453d1e..7e7c9b822d 100644
--- a/spec/ruby/core/kernel/print_spec.rb
+++ b/spec/ruby/core/kernel/print_spec.rb
@@ -5,6 +5,18 @@ describe "Kernel#print" do
it "is a private method" do
Kernel.should have_private_instance_method(:print)
end
+
+ it "delegates to $stdout" do
+ -> { print :arg }.should output("arg")
+ end
+
+ it "prints $_ when no arguments are given" do
+ orig_value = $_
+ $_ = 'foo'
+ -> { print }.should output("foo")
+ ensure
+ $_ = orig_value
+ end
end
describe "Kernel.print" do
diff --git a/spec/ruby/core/kernel/printf_spec.rb b/spec/ruby/core/kernel/printf_spec.rb
index d8f93ce429..61bf955c25 100644
--- a/spec/ruby/core/kernel/printf_spec.rb
+++ b/spec/ruby/core/kernel/printf_spec.rb
@@ -31,6 +31,13 @@ describe "Kernel.printf" do
object.should_receive(:write).with("string")
Kernel.printf(object, "%s", "string")
end
+
+ it "calls #to_str to convert the format object to a String" do
+ object = mock('format string')
+ object.should_receive(:to_str).and_return("to_str: %i")
+ $stdout.should_receive(:write).with("to_str: 42")
+ Kernel.printf($stdout, object, 42)
+ end
end
describe "Kernel.printf" do
diff --git a/spec/ruby/core/kernel/proc_spec.rb b/spec/ruby/core/kernel/proc_spec.rb
index dfe178420b..6553b8fd04 100644
--- a/spec/ruby/core/kernel/proc_spec.rb
+++ b/spec/ruby/core/kernel/proc_spec.rb
@@ -40,27 +40,9 @@ describe "Kernel#proc" do
proc
end
- ruby_version_is ""..."2.7" do
- it "uses the implicit block from an enclosing method" do
- prc = some_method { "hello" }
-
- prc.call.should == "hello"
- end
- end
-
- ruby_version_is "2.7"..."3.0" do
- it "can be created when called with no block" do
- -> {
- some_method { "hello" }
- }.should complain(/Capturing the given block using Kernel#proc is deprecated/)
- end
- end
-
- ruby_version_is "3.0" do
- it "raises an ArgumentError when passed no block" do
- -> {
- some_method { "hello" }
- }.should raise_error(ArgumentError, 'tried to create Proc object without a block')
- end
+ it "raises an ArgumentError when passed no block" do
+ -> {
+ some_method { "hello" }
+ }.should raise_error(ArgumentError, 'tried to create Proc object without a block')
end
end
diff --git a/spec/ruby/core/kernel/public_send_spec.rb b/spec/ruby/core/kernel/public_send_spec.rb
index 4dae419ff9..b684b1729c 100644
--- a/spec/ruby/core/kernel/public_send_spec.rb
+++ b/spec/ruby/core/kernel/public_send_spec.rb
@@ -105,11 +105,11 @@ describe "Kernel#public_send" do
end
it "includes `public_send` in the backtrace when passed not enough arguments" do
- -> { public_send() }.should raise_error(ArgumentError) { |e| e.backtrace[0].should.include?("`public_send'") }
+ -> { public_send() }.should raise_error(ArgumentError) { |e| e.backtrace[0].should =~ /[`'](?:Kernel#)?public_send'/ }
end
it "includes `public_send` in the backtrace when passed a single incorrect argument" do
- -> { public_send(Object.new) }.should raise_error(TypeError) { |e| e.backtrace[0].should.include?("`public_send'") }
+ -> { public_send(Object.new) }.should raise_error(TypeError) { |e| e.backtrace[0].should =~ /[`'](?:Kernel#)?public_send'/ }
end
it_behaves_like :basicobject_send, :public_send
diff --git a/spec/ruby/core/kernel/rand_spec.rb b/spec/ruby/core/kernel/rand_spec.rb
index c52faee2c4..355e425792 100644
--- a/spec/ruby/core/kernel/rand_spec.rb
+++ b/spec/ruby/core/kernel/rand_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-describe "Kernel.rand" do
+describe "Kernel#rand" do
it "is a private method" do
Kernel.should have_private_instance_method(:rand)
end
@@ -192,6 +192,6 @@ describe "Kernel.rand" do
end
end
-describe "Kernel#rand" do
+describe "Kernel.rand" do
it "needs to be reviewed for spec completeness"
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/require_relative_spec.rb b/spec/ruby/core/kernel/require_relative_spec.rb
index d4146eb3c8..6188d13a4e 100644
--- a/spec/ruby/core/kernel/require_relative_spec.rb
+++ b/spec/ruby/core/kernel/require_relative_spec.rb
@@ -5,9 +5,9 @@ describe "Kernel#require_relative with a relative path" do
before :each do
CodeLoadingSpecs.spec_setup
@dir = "../../fixtures/code"
- @abs_dir = File.realpath(@dir, File.dirname(__FILE__))
+ @abs_dir = File.realpath(@dir, __dir__)
@path = "#{@dir}/load_fixture.rb"
- @abs_path = File.realpath(@path, File.dirname(__FILE__))
+ @abs_path = File.realpath(@path, __dir__)
end
after :each do
@@ -92,7 +92,7 @@ describe "Kernel#require_relative with a relative path" do
it "raises a LoadError that includes the missing path" do
missing_path = "#{@dir}/nonexistent.rb"
- expanded_missing_path = File.expand_path(missing_path, File.dirname(__FILE__))
+ expanded_missing_path = File.expand_path(missing_path, __dir__)
-> { require_relative(missing_path) }.should raise_error(LoadError) { |e|
e.message.should include(expanded_missing_path)
e.path.should == expanded_missing_path
@@ -207,7 +207,7 @@ describe "Kernel#require_relative with a relative path" do
$LOADED_FEATURES.should include(@abs_path)
end
- platform_is_not :windows do
+ platform_is_not :windows, :wasi do
describe "with symlinks" do
before :each do
@symlink_to_code_dir = tmp("codesymlink")
@@ -277,7 +277,7 @@ end
describe "Kernel#require_relative with an absolute path" do
before :each do
CodeLoadingSpecs.spec_setup
- @dir = File.expand_path "../../fixtures/code", File.dirname(__FILE__)
+ @dir = File.expand_path "../../fixtures/code", __dir__
@abs_dir = @dir
@path = File.join @dir, "load_fixture.rb"
@abs_path = @path
diff --git a/spec/ruby/core/kernel/require_spec.rb b/spec/ruby/core/kernel/require_spec.rb
index dc3da4b7e6..4029e68725 100644
--- a/spec/ruby/core/kernel/require_spec.rb
+++ b/spec/ruby/core/kernel/require_spec.rb
@@ -16,6 +16,26 @@ describe "Kernel#require" do
Kernel.should have_private_instance_method(:require)
end
+ provided = %w[complex enumerator rational thread ruby2_keywords]
+ ruby_version_is "3.1" do
+ provided << "fiber"
+ end
+
+ it "#{provided.join(', ')} are already required" do
+ out = ruby_exe("puts $LOADED_FEATURES", options: '--disable-gems --disable-did-you-mean')
+ features = out.lines.map { |line| File.basename(line.chomp, '.*') }
+
+ # Ignore CRuby internals
+ features -= %w[encdb transdb windows_1252 windows_31j]
+ features.reject! { |feature| feature.end_with?('-fake') }
+
+ features.sort.should == provided.sort
+
+ code = provided.map { |f| "puts require #{f.inspect}\n" }.join
+ required = ruby_exe(code, options: '--disable-gems')
+ required.should == "false\n" * provided.size
+ end
+
it_behaves_like :kernel_require_basic, :require, CodeLoadingSpecs::Method.new
it_behaves_like :kernel_require, :require, CodeLoadingSpecs::Method.new
end
diff --git a/spec/ruby/core/kernel/shared/dup_clone.rb b/spec/ruby/core/kernel/shared/dup_clone.rb
index 84ad49cbde..4fac6006e1 100644
--- a/spec/ruby/core/kernel/shared/dup_clone.rb
+++ b/spec/ruby/core/kernel/shared/dup_clone.rb
@@ -52,18 +52,6 @@ describe :kernel_dup_clone, shared: true do
o2.original.should equal(o)
end
- ruby_version_is ''...'2.7' do
- it "preserves tainted state from the original" do
- o = ObjectSpecDupInitCopy.new
- o2 = o.send(@method)
- o.taint
- o3 = o.send(@method)
-
- o2.should_not.tainted?
- o3.should.tainted?
- end
- end
-
it "does not preserve the object_id" do
o1 = ObjectSpecDupInitCopy.new
old_object_id = o1.object_id
@@ -71,18 +59,6 @@ describe :kernel_dup_clone, shared: true do
o2.object_id.should_not == old_object_id
end
- ruby_version_is ''...'2.7' do
- it "preserves untrusted state from the original" do
- o = ObjectSpecDupInitCopy.new
- o2 = o.send(@method)
- o.untrust
- o3 = o.send(@method)
-
- o2.should_not.untrusted?
- o3.should.untrusted?
- end
- end
-
it "returns nil for NilClass" do
nil.send(@method).should == nil
end
diff --git a/spec/ruby/core/kernel/shared/load.rb b/spec/ruby/core/kernel/shared/load.rb
index 120619abef..0fe2d5ce16 100644
--- a/spec/ruby/core/kernel/shared/load.rb
+++ b/spec/ruby/core/kernel/shared/load.rb
@@ -1,5 +1,6 @@
main = self
+# The big difference is Kernel#load does not attempt to add an extension to the passed path, unlike Kernel#require
describe :kernel_load, shared: true do
before :each do
CodeLoadingSpecs.spec_setup
@@ -10,22 +11,31 @@ describe :kernel_load, shared: true do
CodeLoadingSpecs.spec_cleanup
end
- it "loads a non-extensioned file as a Ruby source file" do
- path = File.expand_path "load_fixture", CODE_LOADING_DIR
- @object.load(path).should be_true
- ScratchPad.recorded.should == [:no_ext]
- end
+ describe "(path resolution)" do
+ # This behavior is specific to Kernel#load, it differs for Kernel#require
+ it "loads a non-extensioned file as a Ruby source file" do
+ path = File.expand_path "load_fixture", CODE_LOADING_DIR
+ @object.load(path).should be_true
+ ScratchPad.recorded.should == [:no_ext]
+ end
- it "loads a non .rb extensioned file as a Ruby source file" do
- path = File.expand_path "load_fixture.ext", CODE_LOADING_DIR
- @object.load(path).should be_true
- ScratchPad.recorded.should == [:no_rb_ext]
- end
+ it "loads a non .rb extensioned file as a Ruby source file" do
+ path = File.expand_path "load_fixture.ext", CODE_LOADING_DIR
+ @object.load(path).should be_true
+ ScratchPad.recorded.should == [:no_rb_ext]
+ end
- it "loads from the current working directory" do
- Dir.chdir CODE_LOADING_DIR do
- @object.load("load_fixture.rb").should be_true
- ScratchPad.recorded.should == [:loaded]
+ it "loads from the current working directory" do
+ Dir.chdir CODE_LOADING_DIR do
+ @object.load("load_fixture.rb").should be_true
+ ScratchPad.recorded.should == [:loaded]
+ end
+ end
+
+ # This behavior is specific to Kernel#load, it differs for Kernel#require
+ it "does not look for a c-extension file when passed a path without extension (when no .rb is present)" do
+ path = File.join CODE_LOADING_DIR, "a", "load_fixture"
+ -> { @object.send(@method, path) }.should raise_error(LoadError)
end
end
@@ -88,12 +98,12 @@ describe :kernel_load, shared: true do
describe "when passed true for 'wrap'" do
it "loads from an existing path" do
- path = File.expand_path "wrap_fixture.rb", CODE_LOADING_DIR
+ path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
@object.load(path, true).should be_true
end
it "sets the enclosing scope to an anonymous module" do
- path = File.expand_path "wrap_fixture.rb", CODE_LOADING_DIR
+ path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
@object.load(path, true)
Object.const_defined?(:LoadSpecWrap).should be_false
@@ -103,14 +113,14 @@ describe :kernel_load, shared: true do
end
it "allows referencing outside namespaces" do
- path = File.expand_path "wrap_fixture.rb", CODE_LOADING_DIR
+ path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
@object.load(path, true)
ScratchPad.recorded[0].should equal(String)
end
it "sets self as a copy of the top-level main" do
- path = File.expand_path "wrap_fixture.rb", CODE_LOADING_DIR
+ path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
@object.load(path, true)
top_level = ScratchPad.recorded[2]
@@ -127,7 +137,7 @@ describe :kernel_load, shared: true do
main_ancestors = main.singleton_class.ancestors[1..-1]
main_ancestors.first.should == mod
- path = File.expand_path "wrap_fixture.rb", CODE_LOADING_DIR
+ path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
@object.load(path, true)
top_level = ScratchPad.recorded[2]
@@ -154,6 +164,41 @@ describe :kernel_load, shared: true do
end
end
+ describe "when passed a module for 'wrap'" do
+ ruby_version_is "3.1" do
+ it "sets the enclosing scope to the supplied module" do
+ path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
+ mod = Module.new
+ @object.load(path, mod)
+
+ Object.const_defined?(:LoadSpecWrap).should be_false
+ mod.const_defined?(:LoadSpecWrap).should be_true
+
+ wrap_module = ScratchPad.recorded[1]
+ wrap_module.should == mod
+ end
+
+ it "makes constants and instance methods in the source file reachable with the supplied module" do
+ path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
+ mod = Module.new
+ @object.load(path, mod)
+
+ mod::LOAD_WRAP_SPECS_TOP_LEVEL_CONSTANT.should == 1
+ obj = Object.new
+ obj.extend(mod)
+ obj.send(:load_wrap_specs_top_level_method).should == :load_wrap_specs_top_level_method
+ end
+
+ it "makes instance methods in the source file private" do
+ path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
+ mod = Module.new
+ @object.load(path, mod)
+
+ mod.private_instance_methods.include?(:load_wrap_specs_top_level_method).should == true
+ end
+ end
+ end
+
describe "(shell expansion)" do
before :each do
@env_home = ENV["HOME"]
diff --git a/spec/ruby/core/kernel/shared/require.rb b/spec/ruby/core/kernel/shared/require.rb
index 9a2c38be1a..250813191b 100644
--- a/spec/ruby/core/kernel/shared/require.rb
+++ b/spec/ruby/core/kernel/shared/require.rb
@@ -212,6 +212,34 @@ end
describe :kernel_require, shared: true do
describe "(path resolution)" do
+ it "loads .rb file when passed absolute path without extension" do
+ path = File.expand_path "load_fixture", CODE_LOADING_DIR
+ @object.send(@method, path).should be_true
+ # This should _not_ be [:no_ext]
+ ScratchPad.recorded.should == [:loaded]
+ end
+
+ platform_is :linux, :darwin do
+ it "loads c-extension file when passed absolute path without extension when no .rb is present" do
+ # the error message is specific to what dlerror() returns
+ path = File.join CODE_LOADING_DIR, "a", "load_fixture"
+ -> { @object.send(@method, path) }.should raise_error(Exception, /file too short|not a mach-o file/)
+ end
+ end
+
+ platform_is :darwin do
+ it "loads .bundle file when passed absolute path with .so" do
+ # the error message is specific to what dlerror() returns
+ path = File.join CODE_LOADING_DIR, "a", "load_fixture.so"
+ -> { @object.send(@method, path) }.should raise_error(Exception, /load_fixture\.bundle.+(file too short|not a mach-o file)/)
+ end
+ end
+
+ it "does not try an extra .rb if the path already ends in .rb" do
+ path = File.join CODE_LOADING_DIR, "d", "load_fixture.rb"
+ -> { @object.send(@method, path) }.should raise_error(LoadError)
+ end
+
# For reference see [ruby-core:24155] in which matz confirms this feature is
# intentional for security reasons.
it "does not load a bare filename unless the current working directory is in $LOAD_PATH" do
@@ -237,6 +265,17 @@ describe :kernel_require, shared: true do
}.should complain(/circular require considered harmful/, verbose: true)
ScratchPad.recorded.should == [:loaded]
end
+
+ ruby_bug "#17340", ''...'3.3' do
+ it "loads a file concurrently" do
+ path = File.expand_path "concurrent_require_fixture.rb", CODE_LOADING_DIR
+ ScratchPad.record(@object)
+ -> {
+ @object.require(path)
+ }.should_not complain(/circular require considered harmful/, verbose: true)
+ ScratchPad.recorded.join
+ end
+ end
end
describe "(non-extensioned path)" do
@@ -251,13 +290,11 @@ describe :kernel_require, shared: true do
ScratchPad.recorded.should == [:loaded]
end
- ruby_bug "#16926", "2.7"..."3.0" do
- it "does not load a feature twice when $LOAD_PATH has been modified" do
- $LOAD_PATH.replace [CODE_LOADING_DIR]
- @object.require("load_fixture").should be_true
- $LOAD_PATH.replace [File.expand_path("b", CODE_LOADING_DIR), CODE_LOADING_DIR]
- @object.require("load_fixture").should be_false
- end
+ it "does not load a feature twice when $LOAD_PATH has been modified" do
+ $LOAD_PATH.replace [CODE_LOADING_DIR]
+ @object.require("load_fixture").should be_true
+ $LOAD_PATH.replace [File.expand_path("b", CODE_LOADING_DIR), CODE_LOADING_DIR]
+ @object.require("load_fixture").should be_false
end
end
@@ -546,22 +583,6 @@ describe :kernel_require, shared: true do
ScratchPad.recorded.should == []
end
- provided = %w[complex enumerator rational thread]
- ruby_version_is "2.7" do
- provided << 'ruby2_keywords'
- end
-
- it "#{provided.join(', ')} are already required" do
- features = ruby_exe("puts $LOADED_FEATURES", options: '--disable-gems')
- provided.each { |feature|
- features.should =~ /\b#{feature}\.(rb|so|jar)$/
- }
-
- code = provided.map { |f| "puts require #{f.inspect}\n" }.join
- required = ruby_exe(code, options: '--disable-gems')
- required.should == "false\n" * provided.size
- end
-
it "unicode_normalize is part of core and not $LOADED_FEATURES" do
features = ruby_exe("puts $LOADED_FEATURES", options: '--disable-gems')
features.lines.each { |feature|
@@ -570,6 +591,23 @@ describe :kernel_require, shared: true do
-> { @object.require("unicode_normalize") }.should raise_error(LoadError)
end
+
+ 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
describe "(shell expansion)" do
diff --git a/spec/ruby/core/kernel/shared/sprintf.rb b/spec/ruby/core/kernel/shared/sprintf.rb
index 84d472b0d1..13dc6e97f0 100644
--- a/spec/ruby/core/kernel/shared/sprintf.rb
+++ b/spec/ruby/core/kernel/shared/sprintf.rb
@@ -289,21 +289,80 @@ describe :kernel_sprintf, shared: true do
@method.call("%c", "a").should == "a"
end
- it "raises ArgumentError if argument is a string of several characters" do
+ ruby_version_is ""..."3.2" do
+ it "raises ArgumentError if argument is a string of several characters" do
+ -> {
+ @method.call("%c", "abc")
+ }.should raise_error(ArgumentError, /%c requires a character/)
+ end
+
+ it "raises ArgumentError if argument is an empty string" do
+ -> {
+ @method.call("%c", "")
+ }.should raise_error(ArgumentError, /%c requires a character/)
+ end
+ end
+
+ ruby_version_is "3.2" do
+ it "displays only the first character if argument is a string of several characters" do
+ @method.call("%c", "abc").should == "a"
+ end
+
+ it "displays no characters if argument is an empty string" do
+ @method.call("%c", "").should == ""
+ end
+ end
+
+ it "raises TypeError if argument is not String or Integer and cannot be converted to them" do
-> {
- @method.call("%c", "abc")
- }.should raise_error(ArgumentError)
+ @method.call("%c", [])
+ }.should raise_error(TypeError, /no implicit conversion of Array into Integer/)
end
- it "raises ArgumentError if argument is an empty string" do
+ it "raises TypeError if argument is nil" do
-> {
- @method.call("%c", "")
- }.should raise_error(ArgumentError)
+ @method.call("%c", nil)
+ }.should raise_error(TypeError, /no implicit conversion from nil to integer/)
+ end
+
+ it "tries to convert argument to String with to_str" do
+ obj = BasicObject.new
+ def obj.to_str
+ "a"
+ end
+
+ @method.call("%c", obj).should == "a"
end
- it "supports Unicode characters" do
- @method.call("%c", 1286).should == "Ԇ"
- @method.call("%c", "ش").should == "ش"
+ it "tries to convert argument to Integer with to_int" do
+ obj = BasicObject.new
+ def obj.to_int
+ 90
+ end
+
+ @method.call("%c", obj).should == "Z"
+ end
+
+ it "raises TypeError if converting to String with to_str returns non-String" do
+ obj = BasicObject.new
+ def obj.to_str
+ :foo
+ end
+
+ -> {
+ @method.call("%c", obj)
+ }.should raise_error(TypeError, /can't convert BasicObject to String/)
+ end
+
+ it "raises TypeError if converting to Integer with to_int returns non-Integer" do
+ obj = BasicObject.new
+ def obj.to_int
+ :foo
+ end
+
+ -> {
+ @method.call("%c", obj)
+ }.should raise_error(TypeError, /can't convert BasicObject to Integer/)
end
end
@@ -362,11 +421,11 @@ describe :kernel_sprintf, shared: true do
@method.call("%4.6s", "abcdefg").should == "abcdef"
end
- it "formats nli with width" do
+ it "formats nil with width" do
@method.call("%6s", nil).should == " "
end
- it "formats nli with precision" do
+ it "formats nil with precision" do
@method.call("%.6s", nil).should == ""
end
@@ -927,4 +986,8 @@ describe :kernel_sprintf, shared: true do
}
end
end
+
+ it "does not raise error when passed more arguments than needed" do
+ sprintf("%s %d %c", "string", 2, "c", []).should == "string 2 c"
+ end
end
diff --git a/spec/ruby/core/kernel/shared/sprintf_encoding.rb b/spec/ruby/core/kernel/shared/sprintf_encoding.rb
index 5ca66b9083..7ec0fe4c48 100644
--- a/spec/ruby/core/kernel/shared/sprintf_encoding.rb
+++ b/spec/ruby/core/kernel/shared/sprintf_encoding.rb
@@ -1,3 +1,5 @@
+# Keep encoding-related specs in a separate shared example to be able to skip them in IO/File/StringIO specs.
+# It's difficult to check result's encoding in the test after writing to a file/io buffer.
describe :kernel_sprintf_encoding, shared: true do
it "can produce a string with valid encoding" do
string = @method.call("good day %{valid}", valid: "e")
@@ -12,20 +14,20 @@ describe :kernel_sprintf_encoding, shared: true do
end
it "returns a String in the same encoding as the format String if compatible" do
- string = "%s".force_encoding(Encoding::KOI8_U)
+ string = "%s".dup.force_encoding(Encoding::KOI8_U)
result = @method.call(string, "dogs")
result.encoding.should equal(Encoding::KOI8_U)
end
it "returns a String in the argument's encoding if format encoding is more restrictive" do
- string = "foo %s".force_encoding(Encoding::US_ASCII)
- argument = "b\303\274r".force_encoding(Encoding::UTF_8)
+ string = "foo %s".dup.force_encoding(Encoding::US_ASCII)
+ argument = "b\303\274r".dup.force_encoding(Encoding::UTF_8)
result = @method.call(string, argument)
result.encoding.should equal(Encoding::UTF_8)
end
- it "raises Encoding::CompatibilityError if both encodings are ASCII compatible and there ano not ASCII characters" do
+ it "raises Encoding::CompatibilityError if both encodings are ASCII compatible and there are not ASCII characters" do
string = "Ä %s".encode('windows-1252')
argument = "Ђ".encode('windows-1251')
@@ -33,4 +35,33 @@ describe :kernel_sprintf_encoding, shared: true do
@method.call(string, argument)
}.should raise_error(Encoding::CompatibilityError)
end
+
+ describe "%c" do
+ it "supports Unicode characters" do
+ result = @method.call("%c", 1286)
+ result.should == "Ԇ"
+ result.bytes.should == [212, 134]
+
+ result = @method.call("%c", "ش")
+ result.should == "ش"
+ result.bytes.should == [216, 180]
+ end
+
+ it "raises error when a codepoint isn't representable in an encoding of a format string" do
+ format = "%c".encode("ASCII")
+
+ -> {
+ @method.call(format, 1286)
+ }.should raise_error(RangeError, /out of char range/)
+ end
+
+ it "uses the encoding of the format string to interpret codepoints" do
+ format = "%c".dup.force_encoding("euc-jp")
+ result = @method.call(format, 9415601)
+
+ result.encoding.should == Encoding::EUC_JP
+ result.should == "é".encode(Encoding::EUC_JP)
+ result.bytes.should == [143, 171, 177]
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/singleton_class_spec.rb b/spec/ruby/core/kernel/singleton_class_spec.rb
index a8bcd916d1..23c400f9bd 100644
--- a/spec/ruby/core/kernel/singleton_class_spec.rb
+++ b/spec/ruby/core/kernel/singleton_class_spec.rb
@@ -1,3 +1,6 @@
+# truffleruby_primitives: true
+require_relative '../../spec_helper'
+
describe "Kernel#singleton_class" do
it "returns class extended from an object" do
x = Object.new
@@ -18,10 +21,54 @@ describe "Kernel#singleton_class" do
end
it "raises TypeError for Integer" do
- -> { 123.singleton_class }.should raise_error(TypeError)
+ -> { 123.singleton_class }.should raise_error(TypeError, "can't define singleton")
+ end
+
+ it "raises TypeError for Float" do
+ -> { 3.14.singleton_class }.should raise_error(TypeError, "can't define singleton")
end
it "raises TypeError for Symbol" do
- -> { :foo.singleton_class }.should raise_error(TypeError)
+ -> { :foo.singleton_class }.should raise_error(TypeError, "can't define singleton")
+ end
+
+ it "raises TypeError for a frozen deduplicated String" do
+ -> { (-"string").singleton_class }.should raise_error(TypeError, "can't define singleton")
+ -> { a = -"string"; a.singleton_class }.should raise_error(TypeError, "can't define singleton")
+ -> { a = "string"; (-a).singleton_class }.should raise_error(TypeError, "can't define singleton")
+ end
+
+ it "returns a frozen singleton class if object is frozen" do
+ obj = Object.new
+ obj.freeze
+ obj.singleton_class.frozen?.should be_true
+ end
+
+ context "for an IO object with a replaced singleton class" do
+ it "looks up singleton methods from the fresh singleton class after an object instance got a new one" do
+ proxy = -> io { io.foo }
+ if RUBY_ENGINE == 'truffleruby'
+ # We need an inline cache with only this object seen, the best way to do that is to use a Primitive
+ sclass = -> io { Primitive.singleton_class(io) }
+ else
+ sclass = -> io { io.singleton_class }
+ end
+
+ io = File.new(__FILE__)
+ io.define_singleton_method(:foo) { "old" }
+ sclass1 = sclass.call(io)
+ proxy.call(io).should == "old"
+
+ # IO#reopen is the only method which can replace an object's singleton class
+ io2 = File.new(__FILE__)
+ io.reopen(io2)
+ io.define_singleton_method(:foo) { "new" }
+ sclass2 = sclass.call(io)
+ sclass2.should_not.equal?(sclass1)
+ proxy.call(io).should == "new"
+ ensure
+ io2.close
+ io.close
+ end
end
end
diff --git a/spec/ruby/core/kernel/sleep_spec.rb b/spec/ruby/core/kernel/sleep_spec.rb
index 32da6344c1..0570629723 100644
--- a/spec/ruby/core/kernel/sleep_spec.rb
+++ b/spec/ruby/core/kernel/sleep_spec.rb
@@ -1,5 +1,4 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
describe "Kernel#sleep" do
it "is a private method" do
@@ -33,10 +32,6 @@ describe "Kernel#sleep" do
-> { sleep(-1) }.should raise_error(ArgumentError)
end
- it "raises a TypeError when passed nil" do
- -> { sleep(nil) }.should raise_error(TypeError)
- end
-
it "raises a TypeError when passed a String" do
-> { sleep('2') }.should raise_error(TypeError)
end
@@ -55,6 +50,29 @@ describe "Kernel#sleep" do
t.wakeup
t.value.should == 5
end
+
+ ruby_version_is ""..."3.3" do
+ it "raises a TypeError when passed nil" do
+ -> { sleep(nil) }.should raise_error(TypeError)
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "accepts a nil duration" do
+ running = false
+ t = Thread.new do
+ running = true
+ sleep(nil)
+ 5
+ end
+
+ Thread.pass until running
+ Thread.pass while t.status and t.status != "sleep"
+
+ t.wakeup
+ t.value.should == 5
+ end
+ end
end
describe "Kernel.sleep" do
diff --git a/spec/ruby/core/kernel/sprintf_spec.rb b/spec/ruby/core/kernel/sprintf_spec.rb
index 7adf71be76..9ef7f86f16 100644
--- a/spec/ruby/core/kernel/sprintf_spec.rb
+++ b/spec/ruby/core/kernel/sprintf_spec.rb
@@ -3,6 +3,14 @@ require_relative 'fixtures/classes'
require_relative 'shared/sprintf'
require_relative 'shared/sprintf_encoding'
+describe :kernel_sprintf_to_str, shared: true do
+ it "calls #to_str to convert the format object to a String" do
+ obj = mock('format string')
+ obj.should_receive(:to_str).and_return("to_str: %i")
+ @method.call(obj, 42).should == "to_str: 42"
+ end
+end
+
describe "Kernel#sprintf" do
it_behaves_like :kernel_sprintf, -> format, *args {
sprintf(format, *args)
@@ -11,6 +19,10 @@ describe "Kernel#sprintf" do
it_behaves_like :kernel_sprintf_encoding, -> format, *args {
sprintf(format, *args)
}
+
+ it_behaves_like :kernel_sprintf_to_str, -> format, *args {
+ sprintf(format, *args)
+ }
end
describe "Kernel.sprintf" do
@@ -21,4 +33,8 @@ describe "Kernel.sprintf" do
it_behaves_like :kernel_sprintf_encoding, -> format, *args {
Kernel.sprintf(format, *args)
}
+
+ it_behaves_like :kernel_sprintf_to_str, -> format, *args {
+ Kernel.sprintf(format, *args)
+ }
end
diff --git a/spec/ruby/core/kernel/srand_spec.rb b/spec/ruby/core/kernel/srand_spec.rb
index 6774d19284..95bb406f46 100644
--- a/spec/ruby/core/kernel/srand_spec.rb
+++ b/spec/ruby/core/kernel/srand_spec.rb
@@ -1,7 +1,15 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-describe "Kernel.srand" do
+describe "Kernel#srand" do
+ before :each do
+ @seed = srand
+ end
+
+ after :each do
+ srand(@seed)
+ end
+
it "is a private method" do
Kernel.should have_private_instance_method(:srand)
end
@@ -11,8 +19,8 @@ describe "Kernel.srand" do
srand(20).should == 10
end
- it "returns the previous seed value on the first call" do
- ruby_exe('p srand(10)', options: '--disable-gems').chomp.should =~ /\A\d+\z/
+ it "returns the system-initialized seed value on the first call" do
+ ruby_exe('print srand(10)', options: '--disable-gems').should =~ /\A\d+\z/
end
it "seeds the RNG correctly and repeatably" do
@@ -60,6 +68,6 @@ describe "Kernel.srand" do
end
end
-describe "Kernel#srand" do
+describe "Kernel.srand" do
it "needs to be reviewed for spec completeness"
end
diff --git a/spec/ruby/core/kernel/system_spec.rb b/spec/ruby/core/kernel/system_spec.rb
index 9671a650cc..9bc03924dd 100644
--- a/spec/ruby/core/kernel/system_spec.rb
+++ b/spec/ruby/core/kernel/system_spec.rb
@@ -64,6 +64,23 @@ describe :kernel_system, shared: true do
end
end
+ platform_is_not :windows do
+ before :each do
+ require 'tmpdir'
+ @shell_command = File.join(Dir.mktmpdir, "noshebang.cmd")
+ File.write(@shell_command, %[echo "$PATH"\n], perm: 0o700)
+ end
+
+ after :each do
+ File.unlink(@shell_command)
+ Dir.rmdir(File.dirname(@shell_command))
+ end
+
+ it "executes with `sh` if the command is executable but not binary and there is no shebang" do
+ -> { @object.system(@shell_command) }.should output_to_fd(ENV['PATH'] + "\n")
+ end
+ end
+
before :each do
ENV['TEST_SH_EXPANSION'] = 'foo'
@shell_var = '$TEST_SH_EXPANSION'
diff --git a/spec/ruby/core/kernel/taint_spec.rb b/spec/ruby/core/kernel/taint_spec.rb
index 8ba9869af2..0c16b1dbbf 100644
--- a/spec/ruby/core/kernel/taint_spec.rb
+++ b/spec/ruby/core/kernel/taint_spec.rb
@@ -2,54 +2,13 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Kernel#taint" do
- ruby_version_is ''...'2.7' do
- it "returns self" do
- o = Object.new
- o.taint.should equal(o)
- end
-
- it "sets the tainted bit" do
- o = Object.new
- o.taint
- o.should.tainted?
- end
-
- it "raises FrozenError on an untainted, frozen object" do
- o = Object.new.freeze
- -> { o.taint }.should raise_error(FrozenError)
- end
-
- it "does not raise an error on a tainted, frozen object" do
- o = Object.new.taint.freeze
- o.taint.should equal(o)
- end
-
- it "has no effect on immediate values" do
- [nil, true, false].each do |v|
- v.taint
- v.should_not.tainted?
- end
- end
-
- it "no raises a RuntimeError on symbols" do
- v = :sym
- -> { v.taint }.should_not raise_error(RuntimeError)
- v.should_not.tainted?
- end
-
- it "no raises error on integer values" do
- [1].each do |v|
- -> { v.taint }.should_not raise_error(RuntimeError)
- v.should_not.tainted?
- end
- end
- end
-
- ruby_version_is "2.7"..."3.0" do
+ ruby_version_is ""..."3.2" do
it "is a no-op" do
- o = Object.new
- o.taint
- o.should_not.tainted?
+ suppress_warning do
+ o = Object.new
+ o.taint
+ o.should_not.tainted?
+ end
end
it "warns in verbose mode" do
@@ -59,4 +18,10 @@ describe "Kernel#taint" do
}.should complain(/Object#taint is deprecated and will be removed in Ruby 3.2/, verbose: true)
end
end
+
+ ruby_version_is "3.2" do
+ it "has been removed" do
+ Object.new.should_not.respond_to?(:taint)
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/tainted_spec.rb b/spec/ruby/core/kernel/tainted_spec.rb
index 022938bfc1..fcae433069 100644
--- a/spec/ruby/core/kernel/tainted_spec.rb
+++ b/spec/ruby/core/kernel/tainted_spec.rb
@@ -2,23 +2,15 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Kernel#tainted?" do
- ruby_version_is ''...'2.7' do
- it "returns true if Object is tainted" do
- o = mock('o')
- p = mock('p')
- p.taint
- o.should_not.tainted?
- p.should.tainted?
- end
- end
-
- ruby_version_is "2.7"..."3.0" do
+ ruby_version_is ""..."3.2" do
it "is a no-op" do
- o = mock('o')
- p = mock('p')
- p.taint
- o.should_not.tainted?
- p.should_not.tainted?
+ suppress_warning do
+ o = mock('o')
+ p = mock('p')
+ p.taint
+ o.should_not.tainted?
+ p.should_not.tainted?
+ end
end
it "warns in verbose mode" do
@@ -28,4 +20,10 @@ describe "Kernel#tainted?" do
}.should complain(/Object#tainted\? is deprecated and will be removed in Ruby 3.2/, verbose: true)
end
end
+
+ ruby_version_is "3.2" do
+ it "has been removed" do
+ Object.new.should_not.respond_to?(:tainted?)
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/test_spec.rb b/spec/ruby/core/kernel/test_spec.rb
index abb365aed2..d26dc06361 100644
--- a/spec/ruby/core/kernel/test_spec.rb
+++ b/spec/ruby/core/kernel/test_spec.rb
@@ -3,8 +3,8 @@ require_relative 'fixtures/classes'
describe "Kernel#test" do
before :all do
- @file = File.dirname(__FILE__) + '/fixtures/classes.rb'
- @dir = File.dirname(__FILE__) + '/fixtures'
+ @file = __dir__ + '/fixtures/classes.rb'
+ @dir = __dir__ + '/fixtures'
end
it "is a private method" do
diff --git a/spec/ruby/core/kernel/to_s_spec.rb b/spec/ruby/core/kernel/to_s_spec.rb
index 64b40f46e5..ea4b00151e 100644
--- a/spec/ruby/core/kernel/to_s_spec.rb
+++ b/spec/ruby/core/kernel/to_s_spec.rb
@@ -5,14 +5,4 @@ describe "Kernel#to_s" do
it "returns a String containing the name of self's class" do
Object.new.to_s.should =~ /Object/
end
-
- ruby_version_is ''...'2.7' do
- it "returns a tainted result if self is tainted" do
- Object.new.taint.to_s.tainted?.should be_true
- end
-
- it "returns an untrusted result if self is untrusted" do
- Object.new.untrust.to_s.untrusted?.should be_true
- end
- end
end
diff --git a/spec/ruby/core/kernel/trust_spec.rb b/spec/ruby/core/kernel/trust_spec.rb
index 399983f74d..db6f17e0fb 100644
--- a/spec/ruby/core/kernel/trust_spec.rb
+++ b/spec/ruby/core/kernel/trust_spec.rb
@@ -2,35 +2,14 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Kernel#trust" do
- ruby_version_is ''...'2.7' do
- it "returns self" do
- o = Object.new
- o.trust.should equal(o)
- end
-
- it "clears the untrusted bit" do
- o = Object.new.untrust
- o.trust
- o.should_not.untrusted?
- end
-
- it "raises FrozenError on an untrusted, frozen object" do
- o = Object.new.untrust.freeze
- -> { o.trust }.should raise_error(FrozenError)
- end
-
- it "does not raise an error on a trusted, frozen object" do
- o = Object.new.freeze
- o.trust.should equal(o)
- end
- end
-
- ruby_version_is "2.7"..."3.0" do
+ ruby_version_is ""..."3.2" do
it "is a no-op" do
- o = Object.new.untrust
- o.should_not.untrusted?
- o.trust
- o.should_not.untrusted?
+ suppress_warning do
+ o = Object.new.untrust
+ o.should_not.untrusted?
+ o.trust
+ o.should_not.untrusted?
+ end
end
it "warns in verbose mode" do
@@ -40,4 +19,10 @@ describe "Kernel#trust" do
}.should complain(/Object#trust is deprecated and will be removed in Ruby 3.2/, verbose: true)
end
end
+
+ ruby_version_is "3.2" do
+ it "has been removed" do
+ Object.new.should_not.respond_to?(:trust)
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/untaint_spec.rb b/spec/ruby/core/kernel/untaint_spec.rb
index 44d87da5d5..26b2aabbe9 100644
--- a/spec/ruby/core/kernel/untaint_spec.rb
+++ b/spec/ruby/core/kernel/untaint_spec.rb
@@ -2,35 +2,14 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Kernel#untaint" do
- ruby_version_is ''...'2.7' do
- it "returns self" do
- o = Object.new
- o.untaint.should equal(o)
- end
-
- it "clears the tainted bit" do
- o = Object.new.taint
- o.untaint
- o.should_not.tainted?
- end
-
- it "raises FrozenError on a tainted, frozen object" do
- o = Object.new.taint.freeze
- -> { o.untaint }.should raise_error(FrozenError)
- end
-
- it "does not raise an error on an untainted, frozen object" do
- o = Object.new.freeze
- o.untaint.should equal(o)
- end
- end
-
- ruby_version_is "2.7"..."3.0" do
+ ruby_version_is ""..."3.2" do
it "is a no-op" do
- o = Object.new.taint
- o.should_not.tainted?
- o.untaint
- o.should_not.tainted?
+ suppress_warning do
+ o = Object.new.taint
+ o.should_not.tainted?
+ o.untaint
+ o.should_not.tainted?
+ end
end
it "warns in verbose mode" do
@@ -40,4 +19,10 @@ describe "Kernel#untaint" do
}.should complain(/Object#untaint is deprecated and will be removed in Ruby 3.2/, verbose: true)
end
end
+
+ ruby_version_is "3.2" do
+ it "has been removed" do
+ Object.new.should_not.respond_to?(:untaint)
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/untrust_spec.rb b/spec/ruby/core/kernel/untrust_spec.rb
index aff0fec57b..5310cd8eb4 100644
--- a/spec/ruby/core/kernel/untrust_spec.rb
+++ b/spec/ruby/core/kernel/untrust_spec.rb
@@ -2,34 +2,13 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Kernel#untrust" do
- ruby_version_is ''...'2.7' do
- it "returns self" do
- o = Object.new
- o.untrust.should equal(o)
- end
-
- it "sets the untrusted bit" do
- o = Object.new
- o.untrust
- o.should.untrusted?
- end
-
- it "raises FrozenError on a trusted, frozen object" do
- o = Object.new.freeze
- -> { o.untrust }.should raise_error(FrozenError)
- end
-
- it "does not raise an error on an untrusted, frozen object" do
- o = Object.new.untrust.freeze
- o.untrust.should equal(o)
- end
- end
-
- ruby_version_is "2.7"..."3.0" do
+ ruby_version_is ""..."3.2" do
it "is a no-op" do
- o = Object.new
- o.untrust
- o.should_not.untrusted?
+ suppress_warning do
+ o = Object.new
+ o.untrust
+ o.should_not.untrusted?
+ end
end
it "warns in verbose mode" do
@@ -39,4 +18,10 @@ describe "Kernel#untrust" do
}.should complain(/Object#untrust is deprecated and will be removed in Ruby 3.2/, verbose: true)
end
end
+
+ ruby_version_is "3.2" do
+ it "has been removed" do
+ Object.new.should_not.respond_to?(:untrust)
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/untrusted_spec.rb b/spec/ruby/core/kernel/untrusted_spec.rb
index 5347c90093..ea36d6c98c 100644
--- a/spec/ruby/core/kernel/untrusted_spec.rb
+++ b/spec/ruby/core/kernel/untrusted_spec.rb
@@ -2,38 +2,14 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Kernel#untrusted?" do
- ruby_version_is ''...'2.7' do
- it "returns the untrusted status of an object" do
- o = mock('o')
- o.should_not.untrusted?
- o.untrust
- o.should.untrusted?
- end
-
- it "has no effect on immediate values" do
- a = nil
- b = true
- c = false
- a.untrust
- b.untrust
- c.untrust
- a.should_not.untrusted?
- b.should_not.untrusted?
- c.should_not.untrusted?
- end
-
- it "has effect on immediate values" do
- d = 1
- -> { d.untrust }.should_not raise_error(RuntimeError)
- end
- end
-
- ruby_version_is "2.7"..."3.0" do
+ ruby_version_is ""..."3.2" do
it "is a no-op" do
- o = mock('o')
- o.should_not.untrusted?
- o.untrust
- o.should_not.untrusted?
+ suppress_warning do
+ o = mock('o')
+ o.should_not.untrusted?
+ o.untrust
+ o.should_not.untrusted?
+ end
end
it "warns in verbose mode" do
@@ -43,4 +19,10 @@ describe "Kernel#untrusted?" do
}.should complain(/Object#untrusted\? is deprecated and will be removed in Ruby 3.2/, verbose: true)
end
end
+
+ ruby_version_is "3.2" do
+ it "has been removed" do
+ Object.new.should_not.respond_to?(:untrusted?)
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/warn_spec.rb b/spec/ruby/core/kernel/warn_spec.rb
index 511e741f32..00164ad90b 100644
--- a/spec/ruby/core/kernel/warn_spec.rb
+++ b/spec/ruby/core/kernel/warn_spec.rb
@@ -128,36 +128,34 @@ describe "Kernel#warn" do
end
end
- ruby_version_is "3.0" do
- it "accepts :category keyword with a symbol" do
- -> {
- $VERBOSE = true
- warn("message", category: :deprecated)
- }.should output(nil, "message\n")
- end
+ it "accepts :category keyword with a symbol" do
+ -> {
+ $VERBOSE = true
+ warn("message", category: :deprecated)
+ }.should output(nil, "message\n")
+ end
- it "accepts :category keyword with nil" do
- -> {
- $VERBOSE = true
- warn("message", category: nil)
- }.should output(nil, "message\n")
- end
+ it "accepts :category keyword with nil" do
+ -> {
+ $VERBOSE = true
+ warn("message", category: nil)
+ }.should output(nil, "message\n")
+ end
- it "accepts :category keyword with object convertible to symbol" do
- o = Object.new
- def o.to_sym; :deprecated; end
- -> {
- $VERBOSE = true
- warn("message", category: o)
- }.should output(nil, "message\n")
- end
+ it "accepts :category keyword with object convertible to symbol" do
+ o = Object.new
+ def o.to_sym; :deprecated; end
+ -> {
+ $VERBOSE = true
+ warn("message", category: o)
+ }.should output(nil, "message\n")
+ end
- it "raises if :category keyword is not nil and not convertible to symbol" do
- -> {
- $VERBOSE = true
- warn("message", category: Object.new)
- }.should raise_error(TypeError)
- end
+ it "raises if :category keyword is not nil and not convertible to symbol" do
+ -> {
+ $VERBOSE = true
+ warn("message", category: Object.new)
+ }.should raise_error(TypeError)
end
it "converts first arg using to_s" do
@@ -212,6 +210,55 @@ describe "Kernel#warn" do
-> { warn('foo', **h) }.should complain("foo\n")
end
+ it "calls Warning.warn without keyword arguments if Warning.warn does not accept keyword arguments" do
+ verbose = $VERBOSE
+ $VERBOSE = false
+ class << Warning
+ alias_method :_warn, :warn
+ def warn(message)
+ ScratchPad.record(message)
+ end
+ end
+
+ begin
+ ScratchPad.clear
+ Kernel.warn("Chunky bacon!")
+ ScratchPad.recorded.should == "Chunky bacon!\n"
+
+ Kernel.warn("Deprecated bacon!", category: :deprecated)
+ ScratchPad.recorded.should == "Deprecated bacon!\n"
+ ensure
+ class << Warning
+ remove_method :warn
+ alias_method :warn, :_warn
+ remove_method :_warn
+ end
+ $VERBOSE = verbose
+ end
+ end
+
+ it "calls Warning.warn with category: nil if Warning.warn accepts keyword arguments" do
+ Warning.should_receive(:warn).with("Chunky bacon!\n", category: nil)
+ verbose = $VERBOSE
+ $VERBOSE = false
+ begin
+ Kernel.warn("Chunky bacon!")
+ ensure
+ $VERBOSE = verbose
+ end
+ end
+
+ it "calls Warning.warn with given category keyword converted to a symbol" do
+ Warning.should_receive(:warn).with("Chunky bacon!\n", category: :deprecated)
+ verbose = $VERBOSE
+ $VERBOSE = false
+ begin
+ Kernel.warn("Chunky bacon!", category: 'deprecated')
+ ensure
+ $VERBOSE = verbose
+ end
+ end
+
it "does not call Warning.warn if self is the Warning module" do
# RubyGems redefines Kernel#warn so we need to use a subprocess and disable RubyGems here
code = <<-RUBY