aboutsummaryrefslogtreecommitdiffstats
path: root/spec/ruby/core
diff options
context:
space:
mode:
authorBenoit Daloze <eregontp@gmail.com>2020-07-27 21:41:08 +0200
committerBenoit Daloze <eregontp@gmail.com>2020-07-27 21:41:08 +0200
commit126fd5f15cff0d3bf314d90d8c21a3ae25ae8e68 (patch)
tree33350f7170436c32ed4c8e79f0be2c334c7bc8a9 /spec/ruby/core
parent7429841ab6494b849106e6d3b119f147adfee3b7 (diff)
downloadruby-126fd5f15cff0d3bf314d90d8c21a3ae25ae8e68.tar.gz
Update to ruby/spec@07164da
Diffstat (limited to 'spec/ruby/core')
-rw-r--r--spec/ruby/core/array/fill_spec.rb3
-rw-r--r--spec/ruby/core/exception/backtrace_spec.rb2
-rw-r--r--spec/ruby/core/kernel/__dir___spec.rb7
-rw-r--r--spec/ruby/core/kernel/at_exit_spec.rb31
-rw-r--r--spec/ruby/core/kernel/fixtures/__dir__.rb2
-rw-r--r--spec/ruby/core/kernel/fixtures/at_exit.rb3
-rw-r--r--spec/ruby/core/kernel/fixtures/warn_require.rb1
-rw-r--r--spec/ruby/core/kernel/fixtures/warn_require_caller.rb2
-rw-r--r--spec/ruby/core/kernel/raise_spec.rb21
-rw-r--r--spec/ruby/core/kernel/warn_spec.rb13
-rw-r--r--spec/ruby/core/module/fixtures/refine.rb12
-rw-r--r--spec/ruby/core/module/refine_spec.rb300
-rw-r--r--spec/ruby/core/string/split_spec.rb68
-rw-r--r--spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb7
-rw-r--r--spec/ruby/core/thread/backtrace/location/fixtures/absolute_path_main.rb2
-rw-r--r--spec/ruby/core/thread/backtrace/location/lineno_spec.rb10
-rw-r--r--spec/ruby/core/thread/backtrace/location/path_spec.rb12
-rw-r--r--spec/ruby/core/thread/raise_spec.rb2
18 files changed, 480 insertions, 18 deletions
diff --git a/spec/ruby/core/array/fill_spec.rb b/spec/ruby/core/array/fill_spec.rb
index 96c8862208..6745bc8d09 100644
--- a/spec/ruby/core/array/fill_spec.rb
+++ b/spec/ruby/core/array/fill_spec.rb
@@ -207,8 +207,9 @@ describe "Array#fill with (filler, index, length)" do
not_supported_on :opal do
it "raises an ArgumentError or RangeError for too-large sizes" do
+ error_types = [RangeError, ArgumentError]
arr = [1, 2, 3]
- -> { arr.fill(10, 1, fixnum_max) }.should raise_error(ArgumentError)
+ -> { arr.fill(10, 1, fixnum_max) }.should raise_error { |err| error_types.should include(err.class) }
-> { arr.fill(10, 1, bignum_value) }.should raise_error(RangeError)
end
end
diff --git a/spec/ruby/core/exception/backtrace_spec.rb b/spec/ruby/core/exception/backtrace_spec.rb
index 2d6825180a..3f74c4cefe 100644
--- a/spec/ruby/core/exception/backtrace_spec.rb
+++ b/spec/ruby/core/exception/backtrace_spec.rb
@@ -43,7 +43,7 @@ describe "Exception#backtrace" do
# This regexp is deliberately imprecise to account for the need to abstract out
# the paths of the included mspec files and the desire to avoid specifying in any
# detail what the in `...' portion looks like.
- line.should =~ /^[^ ]+\:\d+(:in `[^`]+')?$/
+ line.should =~ /^.+:\d+:in `[^`]+'$/
end
end
diff --git a/spec/ruby/core/kernel/__dir___spec.rb b/spec/ruby/core/kernel/__dir___spec.rb
index 64b439161f..0686b31e97 100644
--- a/spec/ruby/core/kernel/__dir___spec.rb
+++ b/spec/ruby/core/kernel/__dir___spec.rb
@@ -5,6 +5,13 @@ describe "Kernel#__dir__" do
__dir__.should == File.realpath(File.dirname(__FILE__))
end
+ it "returns the expanded path of the directory when used in the main script" do
+ fixtures_dir = File.dirname(fixture(__FILE__, '__dir__.rb'))
+ Dir.chdir(fixtures_dir) do
+ ruby_exe("__dir__.rb").should == "__dir__.rb\n#{fixtures_dir}\n"
+ end
+ end
+
context "when used in eval with a given filename" do
it "returns File.dirname(filename)" do
eval("__dir__", nil, "foo.rb").should == "."
diff --git a/spec/ruby/core/kernel/at_exit_spec.rb b/spec/ruby/core/kernel/at_exit_spec.rb
index 21149f965b..7bdb5391fe 100644
--- a/spec/ruby/core/kernel/at_exit_spec.rb
+++ b/spec/ruby/core/kernel/at_exit_spec.rb
@@ -23,7 +23,7 @@ describe "Kernel.at_exit" do
it "gives access to the last raised exception" do
code = <<-EOC
at_exit do
- puts "The exception matches: \#{$! == $exception}"
+ puts "The exception matches: \#{$! == $exception} (message=\#{$!.message})"
end
begin
@@ -33,10 +33,35 @@ describe "Kernel.at_exit" do
end
EOC
- result = ruby_exe(code, args: "2>&1", escape: true)
- result.should =~ /The exception matches: true/
+ result = ruby_exe(code, args: "2>&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
+ result = ruby_exe('at_exit { raise "at_exit_error" }; raise "main_script_error"', args: "2>&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")
+ $?.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")
+ 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")
+ $?.should_not.success?
+ result.should.include?("at_exit ran\n")
+ result.should.include?("syntax error")
+ end
end
describe "Kernel#at_exit" do
diff --git a/spec/ruby/core/kernel/fixtures/__dir__.rb b/spec/ruby/core/kernel/fixtures/__dir__.rb
new file mode 100644
index 0000000000..bf9a15e3c8
--- /dev/null
+++ b/spec/ruby/core/kernel/fixtures/__dir__.rb
@@ -0,0 +1,2 @@
+puts __FILE__
+puts __dir__
diff --git a/spec/ruby/core/kernel/fixtures/at_exit.rb b/spec/ruby/core/kernel/fixtures/at_exit.rb
new file mode 100644
index 0000000000..9c11a7ad6c
--- /dev/null
+++ b/spec/ruby/core/kernel/fixtures/at_exit.rb
@@ -0,0 +1,3 @@
+at_exit do
+ STDERR.puts "at_exit ran"
+end
diff --git a/spec/ruby/core/kernel/fixtures/warn_require.rb b/spec/ruby/core/kernel/fixtures/warn_require.rb
new file mode 100644
index 0000000000..c4b0733233
--- /dev/null
+++ b/spec/ruby/core/kernel/fixtures/warn_require.rb
@@ -0,0 +1 @@
+warn 'warn-require-warning', uplevel: 1
diff --git a/spec/ruby/core/kernel/fixtures/warn_require_caller.rb b/spec/ruby/core/kernel/fixtures/warn_require_caller.rb
new file mode 100644
index 0000000000..35a0f969f9
--- /dev/null
+++ b/spec/ruby/core/kernel/fixtures/warn_require_caller.rb
@@ -0,0 +1,2 @@
+# Use a different line than just 1
+require "#{__dir__}/warn_require"
diff --git a/spec/ruby/core/kernel/raise_spec.rb b/spec/ruby/core/kernel/raise_spec.rb
index bf26560246..591daa03cf 100644
--- a/spec/ruby/core/kernel/raise_spec.rb
+++ b/spec/ruby/core/kernel/raise_spec.rb
@@ -6,6 +6,27 @@ describe "Kernel#raise" do
it "is a private method" do
Kernel.should have_private_instance_method(:raise)
end
+
+ it "re-raises the previously rescued exception if no exception is specified" do
+ ScratchPad.record nil
+
+ -> do
+ begin
+ raise Exception, "outer"
+ ScratchPad.record :no_abort
+ rescue Exception
+ begin
+ raise StandardError, "inner"
+ rescue StandardError
+ end
+
+ raise
+ ScratchPad.record :no_reraise
+ end
+ end.should raise_error(Exception, "outer")
+
+ ScratchPad.recorded.should be_nil
+ end
end
describe "Kernel#raise" do
diff --git a/spec/ruby/core/kernel/warn_spec.rb b/spec/ruby/core/kernel/warn_spec.rb
index 84cfa78672..79e78dd4a3 100644
--- a/spec/ruby/core/kernel/warn_spec.rb
+++ b/spec/ruby/core/kernel/warn_spec.rb
@@ -101,6 +101,19 @@ describe "Kernel#warn" do
-> { w.f4("foo", 3) }.should output(nil, %r|core/kernel/fixtures/classes.rb:#{w.f3_call_lineno}: warning: foo|)
end
+ # Test both explicitly without and with RubyGems as RubyGems overrides Kernel#warn
+ it "shows the caller of #require and not #require itself without RubyGems" do
+ file = fixture(__FILE__ , "warn_require_caller.rb")
+ ruby_exe(file, options: "--disable-gems", args: "2>&1").should == "#{file}:2: warning: warn-require-warning\n"
+ end
+
+ ruby_version_is "2.6" do
+ it "shows the caller of #require and not #require itself with RubyGems loaded" do
+ file = fixture(__FILE__ , "warn_require_caller.rb")
+ ruby_exe(file, options: "-rrubygems", args: "2>&1").should == "#{file}:2: warning: warn-require-warning\n"
+ end
+ end
+
it "converts first arg using to_s" do
w = KernelSpecs::WarnInNestedCall.new
diff --git a/spec/ruby/core/module/fixtures/refine.rb b/spec/ruby/core/module/fixtures/refine.rb
index 79e2e80197..e8215aa640 100644
--- a/spec/ruby/core/module/fixtures/refine.rb
+++ b/spec/ruby/core/module/fixtures/refine.rb
@@ -3,6 +3,10 @@ module ModuleSpecs
def foo; "foo" end
end
+ class ClassWithSuperFoo
+ def foo; [:C] end
+ end
+
module PrependedModule
def foo; "foo from prepended module"; end
end
@@ -11,7 +15,11 @@ module ModuleSpecs
def foo; "foo from included module"; end
end
- def self.build_refined_class
- Class.new(ClassWithFoo)
+ def self.build_refined_class(for_super: false)
+ if for_super
+ Class.new(ClassWithSuperFoo)
+ else
+ Class.new(ClassWithFoo)
+ end
end
end
diff --git a/spec/ruby/core/module/refine_spec.rb b/spec/ruby/core/module/refine_spec.rb
index ca12d5d13b..ebb7111d82 100644
--- a/spec/ruby/core/module/refine_spec.rb
+++ b/spec/ruby/core/module/refine_spec.rb
@@ -731,16 +731,67 @@ describe "Module#refine" do
result.should == "foo"
end
+ it "looks in the refined class from included module" do
+ refined_class = ModuleSpecs.build_refined_class(for_super: true)
+
+ a = Module.new do
+ def foo
+ [:A] + super
+ end
+ end
+
+ refinement = Module.new do
+ refine refined_class do
+ include a
+ end
+ end
+
+ result = nil
+ Module.new do
+ using refinement
+
+ result = refined_class.new.foo
+ end
+
+ result.should == [:A, :C]
+ end
+
+ it "looks in the refined ancestors from included module" do
+ refined_class = ModuleSpecs.build_refined_class(for_super: true)
+ subclass = Class.new(refined_class)
+
+ a = Module.new do
+ def foo
+ [:A] + super
+ end
+ end
+
+ refinement = Module.new do
+ refine refined_class do
+ include a
+ end
+ end
+
+ result = nil
+ Module.new do
+ using refinement
+
+ result = subclass.new.foo
+ end
+
+ result.should == [:A, :C]
+ end
+
# super in a method of a refinement invokes the method in the refined
# class even if there is another refinement which has been activated
# in the same context.
- it "looks in the refined class even if there is another active refinement" do
- refined_class = ModuleSpecs.build_refined_class
+ it "looks in the refined class first if called from refined method" do
+ refined_class = ModuleSpecs.build_refined_class(for_super: true)
refinement = Module.new do
refine refined_class do
def foo
- "foo from refinement"
+ [:R1]
end
end
end
@@ -748,7 +799,7 @@ describe "Module#refine" do
refinement_with_super = Module.new do
refine refined_class do
def foo
- super
+ [:R2] + super
end
end
end
@@ -760,7 +811,246 @@ describe "Module#refine" do
result = refined_class.new.foo
end
- result.should == "foo"
+ result.should == [:R2, :C]
+ end
+
+ it "looks only in the refined class even if there is another active refinement" do
+ refined_class = ModuleSpecs.build_refined_class(for_super: true)
+
+ refinement = Module.new do
+ refine refined_class do
+ def bar
+ "you cannot see me from super because I belong to another active R"
+ end
+ end
+ end
+
+ refinement_with_super = Module.new do
+ refine refined_class do
+ def bar
+ super
+ end
+ end
+ end
+
+
+ Module.new do
+ using refinement
+ using refinement_with_super
+ -> {
+ refined_class.new.bar
+ }.should raise_error(NoMethodError)
+ end
+ end
+
+ it "does't have access to active refinements for C from included module" do
+ refined_class = ModuleSpecs.build_refined_class
+
+ a = Module.new do
+ def foo
+ super + bar
+ end
+ end
+
+ refinement = Module.new do
+ refine refined_class do
+ include a
+
+ def bar
+ "bar is not seen from A methods"
+ end
+ end
+ end
+
+ Module.new do
+ using refinement
+ -> {
+ refined_class.new.foo
+ }.should raise_error(NameError) { |e| e.name.should == :bar }
+ end
+ end
+
+ it "does't have access to other active refinements from included module" do
+ refined_class = ModuleSpecs.build_refined_class
+
+ refinement_integer = Module.new do
+ refine Integer do
+ def bar
+ "bar is not seen from A methods"
+ end
+ end
+ end
+
+ a = Module.new do
+ def foo
+ super + 1.bar
+ end
+ end
+
+ refinement = Module.new do
+ refine refined_class do
+ include a
+ end
+ end
+
+ Module.new do
+ using refinement
+ using refinement_integer
+ -> {
+ refined_class.new.foo
+ }.should raise_error(NameError) { |e| e.name.should == :bar }
+ end
+ end
+
+ # https://bugs.ruby-lang.org/issues/16977
+ it "looks in the another active refinement if super called from included modules" do
+ refined_class = ModuleSpecs.build_refined_class(for_super: true)
+
+ a = Module.new do
+ def foo
+ [:A] + super
+ end
+ end
+
+ b = Module.new do
+ def foo
+ [:B] + super
+ end
+ end
+
+ refinement_a = Module.new do
+ refine refined_class do
+ include a
+ end
+ end
+
+ refinement_b = Module.new do
+ refine refined_class do
+ include b
+ end
+ end
+
+ result = nil
+ Module.new do
+ using refinement_a
+ using refinement_b
+ result = refined_class.new.foo
+ end
+
+ result.should == [:B, :A, :C]
+ end
+
+ it "looks in the current active refinement from included modules" do
+ refined_class = ModuleSpecs.build_refined_class(for_super: true)
+
+ a = Module.new do
+ def foo
+ [:A] + super
+ end
+ end
+
+ b = Module.new do
+ def foo
+ [:B] + super
+ end
+ end
+
+ refinement = Module.new do
+ refine refined_class do
+ def foo
+ [:LAST] + super
+ end
+ end
+ end
+
+ refinement_a_b = Module.new do
+ refine refined_class do
+ include a
+ include b
+ end
+ end
+
+ result = nil
+ Module.new do
+ using refinement
+ using refinement_a_b
+ result = refined_class.new.foo
+ end
+
+ result.should == [:B, :A, :LAST, :C]
+ end
+
+ ruby_version_is ""..."2.8" do
+ it "looks in the lexical scope refinements before other active refinements" do
+ refined_class = ModuleSpecs.build_refined_class(for_super: true)
+
+ refinement_local = Module.new do
+ refine refined_class do
+ def foo
+ [:LOCAL] + super
+ end
+ end
+ end
+
+ a = Module.new do
+ using refinement_local
+
+ def foo
+ [:A] + super
+ end
+ end
+
+ refinement = Module.new do
+ refine refined_class do
+ include a
+ end
+ end
+
+ result = nil
+ Module.new do
+ using refinement
+ result = refined_class.new.foo
+ end
+
+ result.should == [:A, :LOCAL, :C]
+ end
+ end
+
+ ruby_version_is "2.8" do
+ # https://bugs.ruby-lang.org/issues/17007
+ it "does not look in the lexical scope refinements before other active refinements" do
+ refined_class = ModuleSpecs.build_refined_class(for_super: true)
+
+ refinement_local = Module.new do
+ refine refined_class do
+ def foo
+ [:LOCAL] + super
+ end
+ end
+ end
+
+ a = Module.new do
+ using refinement_local
+
+ def foo
+ [:A] + super
+ end
+ end
+
+ refinement = Module.new do
+ refine refined_class do
+ include a
+ end
+ end
+
+ result = nil
+ Module.new do
+ using refinement
+ result = refined_class.new.foo
+ end
+
+ result.should == [:A, :C]
+ end
end
end
diff --git a/spec/ruby/core/string/split_spec.rb b/spec/ruby/core/string/split_spec.rb
index 34a50a5f13..7ac8d7815c 100644
--- a/spec/ruby/core/string/split_spec.rb
+++ b/spec/ruby/core/string/split_spec.rb
@@ -426,12 +426,70 @@ describe "String#split with Regexp" do
end
ruby_version_is "2.6" do
- it "yields each split substrings if a block is given" do
- a = []
- returned_object = "chunky bacon".split(" ") { |str| a << str.capitalize }
+ context "when a block is given" do
+ it "yields each split substring with default pattern" do
+ a = []
+ returned_object = "chunky bacon".split { |str| a << str.capitalize }
+
+ returned_object.should == "chunky bacon"
+ a.should == ["Chunky", "Bacon"]
+ end
+
+ it "yields the string when limit is 1" do
+ a = []
+ returned_object = "chunky bacon".split("", 1) { |str| a << str.capitalize }
+
+ returned_object.should == "chunky bacon"
+ a.should == ["Chunky bacon"]
+ end
+
+ it "yields each split letter" do
+ a = []
+ returned_object = "chunky".split("", 0) { |str| a << str.capitalize }
+
+ returned_object.should == "chunky"
+ a.should == %w(C H U N K Y)
+ end
+
+ it "yields each split substring with a pattern" do
+ a = []
+ returned_object = "chunky-bacon".split("-", 0) { |str| a << str.capitalize }
+
+ returned_object.should == "chunky-bacon"
+ a.should == ["Chunky", "Bacon"]
+ end
- returned_object.should == "chunky bacon"
- a.should == ["Chunky", "Bacon"]
+ it "yields each split substring with empty regexp pattern" do
+ a = []
+ returned_object = "chunky".split(//) { |str| a << str.capitalize }
+
+ returned_object.should == "chunky"
+ a.should == %w(C H U N K Y)
+ end
+
+ it "yields each split substring with empty regexp pattern and limit" do
+ a = []
+ returned_object = "chunky".split(//, 3) { |str| a << str.capitalize }
+
+ returned_object.should == "chunky"
+ a.should == %w(C H Unky)
+ end
+
+ it "yields each split substring with a regexp pattern" do
+ a = []
+ returned_object = "chunky:bacon".split(/:/) { |str| a << str.capitalize }
+
+ returned_object.should == "chunky:bacon"
+ a.should == ["Chunky", "Bacon"]
+ end
+
+ it "returns a string as is (and doesn't call block) if it is empty" do
+ a = []
+ returned_object = "".split { |str| a << str.capitalize }
+
+ returned_object.should == ""
+ a.should == []
+ end
end
describe "for a String subclass" do
diff --git a/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb b/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb
index 67f9274f32..90839baa0f 100644
--- a/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb
+++ b/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb
@@ -10,6 +10,13 @@ describe 'Thread::Backtrace::Location#absolute_path' do
@frame.absolute_path.should == File.realpath(__FILE__)
end
+ it 'returns an absolute path when using a relative main script path' do
+ script = fixture(__FILE__, 'absolute_path_main.rb')
+ Dir.chdir(File.dirname(script)) do
+ ruby_exe('absolute_path_main.rb').should == "absolute_path_main.rb\n#{script}\n"
+ end
+ end
+
context "when used in eval with a given filename" do
it "returns filename" do
code = "caller_locations(0)[0].absolute_path"
diff --git a/spec/ruby/core/thread/backtrace/location/fixtures/absolute_path_main.rb b/spec/ruby/core/thread/backtrace/location/fixtures/absolute_path_main.rb
new file mode 100644
index 0000000000..d2b23393d4
--- /dev/null
+++ b/spec/ruby/core/thread/backtrace/location/fixtures/absolute_path_main.rb
@@ -0,0 +1,2 @@
+puts __FILE__
+puts caller_locations(0)[0].absolute_path
diff --git a/spec/ruby/core/thread/backtrace/location/lineno_spec.rb b/spec/ruby/core/thread/backtrace/location/lineno_spec.rb
index dc93d32d75..d14cf17514 100644
--- a/spec/ruby/core/thread/backtrace/location/lineno_spec.rb
+++ b/spec/ruby/core/thread/backtrace/location/lineno_spec.rb
@@ -10,4 +10,14 @@ describe 'Thread::Backtrace::Location#lineno' do
it 'returns the absolute path of the call frame' do
@frame.lineno.should == @line
end
+
+ it 'should be the same line number as in #to_s, including for core methods' do
+ # Get the caller_locations from a call made into a core library method
+ locations = [:non_empty].map { caller_locations }[0]
+
+ locations.each do |location|
+ line_number = location.to_s[/:(\d+):/, 1]
+ location.lineno.should == Integer(line_number)
+ end
+ end
end
diff --git a/spec/ruby/core/thread/backtrace/location/path_spec.rb b/spec/ruby/core/thread/backtrace/location/path_spec.rb
index 93eb4982d8..7863c055d3 100644
--- a/spec/ruby/core/thread/backtrace/location/path_spec.rb
+++ b/spec/ruby/core/thread/backtrace/location/path_spec.rb
@@ -87,6 +87,18 @@ describe 'Thread::Backtrace::Location#path' do
end
end
+ it 'should be the same path as in #to_s, including for core methods' do
+ # Get the caller_locations from a call made into a core library method
+ locations = [:non_empty].map { caller_locations }[0]
+
+ locations.each do |location|
+ filename = location.to_s[/^(.+):\d+:/, 1]
+ path = location.path
+
+ path.should == filename
+ end
+ end
+
context "canonicalization" do
platform_is_not :windows do
before :each do
diff --git a/spec/ruby/core/thread/raise_spec.rb b/spec/ruby/core/thread/raise_spec.rb
index 88a96d5f4e..27de3cc627 100644
--- a/spec/ruby/core/thread/raise_spec.rb
+++ b/spec/ruby/core/thread/raise_spec.rb
@@ -203,6 +203,6 @@ describe "Thread#raise on same thread" do
Thread.current.raise
end
end
- -> { t.value }.should raise_error(RuntimeError)
+ -> { t.value }.should raise_error(RuntimeError, '')
end
end