summaryrefslogtreecommitdiff
path: root/spec/ruby/language
diff options
context:
space:
mode:
Diffstat (limited to 'spec/ruby/language')
-rw-r--r--spec/ruby/language/constants_spec.rb22
-rw-r--r--spec/ruby/language/ensure_spec.rb229
-rw-r--r--spec/ruby/language/fixtures/ensure.rb7
-rw-r--r--spec/ruby/language/rescue_spec.rb154
4 files changed, 374 insertions, 38 deletions
diff --git a/spec/ruby/language/constants_spec.rb b/spec/ruby/language/constants_spec.rb
index 45d87ce52f..1f1e254fb8 100644
--- a/spec/ruby/language/constants_spec.rb
+++ b/spec/ruby/language/constants_spec.rb
@@ -425,6 +425,28 @@ describe "Constant resolution within a singleton class (class << obj)" do
end
end
+describe "top-level constant lookup" do
+ context "on a class" do
+ ruby_version_is "" ... "2.5" do
+ it "searches Object successfully after searching other scopes" do
+ ->() {
+ String::Hash.should == Hash
+ }.should complain(/toplevel constant Hash referenced by/)
+ end
+ end
+
+ ruby_version_is "2.5" do
+ it "does not search Object after searching other scopes" do
+ ->() { String::Hash }.should raise_error(NameError)
+ end
+ end
+ end
+
+ it "searches Object unsuccessfully when searches on a module" do
+ ->() { Enumerable::Hash }.should raise_error(NameError)
+ end
+end
+
describe "Module#private_constant marked constants" do
it "remain private even when updated" do
diff --git a/spec/ruby/language/ensure_spec.rb b/spec/ruby/language/ensure_spec.rb
index ae04feb739..1d99dcf5f2 100644
--- a/spec/ruby/language/ensure_spec.rb
+++ b/spec/ruby/language/ensure_spec.rb
@@ -7,50 +7,44 @@ describe "An ensure block inside a begin block" do
end
it "is executed when an exception is raised in it's corresponding begin block" do
- begin
- lambda {
- begin
- ScratchPad << :begin
- raise "An exception occurred!"
- ensure
- ScratchPad << :ensure
- end
- }.should raise_error(RuntimeError)
+ lambda {
+ begin
+ ScratchPad << :begin
+ raise EnsureSpec::Error
+ ensure
+ ScratchPad << :ensure
+ end
+ }.should raise_error(EnsureSpec::Error)
- ScratchPad.recorded.should == [:begin, :ensure]
- end
+ ScratchPad.recorded.should == [:begin, :ensure]
end
it "is executed when an exception is raised and rescued in it's corresponding begin block" do
begin
+ ScratchPad << :begin
+ raise "An exception occurred!"
+ rescue
+ ScratchPad << :rescue
+ ensure
+ ScratchPad << :ensure
+ end
+
+ ScratchPad.recorded.should == [:begin, :rescue, :ensure]
+ end
+
+ it "is executed even when a symbol is thrown in it's corresponding begin block" do
+ catch(:symbol) do
begin
ScratchPad << :begin
- raise "An exception occurred!"
+ throw(:symbol)
rescue
ScratchPad << :rescue
ensure
ScratchPad << :ensure
end
-
- ScratchPad.recorded.should == [:begin, :rescue, :ensure]
end
- end
-
- it "is executed even when a symbol is thrown in it's corresponding begin block" do
- begin
- catch(:symbol) do
- begin
- ScratchPad << :begin
- throw(:symbol)
- rescue
- ScratchPad << :rescue
- ensure
- ScratchPad << :ensure
- end
- end
- ScratchPad.recorded.should == [:begin, :ensure]
- end
+ ScratchPad.recorded.should == [:begin, :ensure]
end
it "is executed when nothing is raised or thrown in it's corresponding begin block" do
@@ -102,7 +96,7 @@ describe "An ensure block inside a method" do
end
it "is executed when an exception is raised in the method" do
- lambda { @obj.raise_in_method_with_ensure }.should raise_error(RuntimeError)
+ lambda { @obj.raise_in_method_with_ensure }.should raise_error(EnsureSpec::Error)
@obj.executed.should == [:method, :ensure]
end
@@ -124,3 +118,176 @@ describe "An ensure block inside a method" do
@obj.explicit_return_in_method_with_ensure.should == :ensure
end
end
+
+describe "An ensure block inside a class" do
+ before :each do
+ ScratchPad.record []
+ end
+
+ it "is executed when an exception is raised" do
+ lambda {
+ eval <<-ruby
+ class EnsureInClassExample
+ ScratchPad << :class
+ raise EnsureSpec::Error
+ ensure
+ ScratchPad << :ensure
+ end
+ ruby
+ }.should raise_error(EnsureSpec::Error)
+
+ ScratchPad.recorded.should == [:class, :ensure]
+ end
+
+ it "is executed when an exception is raised and rescued" do
+ eval <<-ruby
+ class EnsureInClassExample
+ ScratchPad << :class
+ raise
+ rescue
+ ScratchPad << :rescue
+ ensure
+ ScratchPad << :ensure
+ end
+ ruby
+
+ ScratchPad.recorded.should == [:class, :rescue, :ensure]
+ end
+
+ it "is executed even when a symbol is thrown" do
+ catch(:symbol) do
+ eval <<-ruby
+ class EnsureInClassExample
+ ScratchPad << :class
+ throw(:symbol)
+ rescue
+ ScratchPad << :rescue
+ ensure
+ ScratchPad << :ensure
+ end
+ ruby
+ end
+
+ ScratchPad.recorded.should == [:class, :ensure]
+ end
+
+ it "is executed when nothing is raised or thrown" do
+ eval <<-ruby
+ class EnsureInClassExample
+ ScratchPad << :class
+ rescue
+ ScratchPad << :rescue
+ ensure
+ ScratchPad << :ensure
+ end
+ ruby
+
+ ScratchPad.recorded.should == [:class, :ensure]
+ end
+
+ it "has no return value" do
+ result = eval <<-ruby
+ class EnsureInClassExample
+ :class
+ ensure
+ :ensure
+ end
+ ruby
+
+ result.should == :class
+ end
+end
+
+describe "An ensure block inside {} block" do
+ it "is not allowed" do
+ lambda {
+ eval <<-ruby
+ lambda {
+ raise
+ ensure
+ }
+ ruby
+ }.should raise_error(SyntaxError)
+ end
+end
+
+ruby_version_is "2.5" do
+ describe "An ensure block inside 'do end' block" do
+ before :each do
+ ScratchPad.record []
+ end
+
+ it "is executed when an exception is raised in it's corresponding begin block" do
+ lambda {
+ eval(<<-ruby).call
+ lambda do
+ ScratchPad << :begin
+ raise EnsureSpec::Error
+ ensure
+ ScratchPad << :ensure
+ end
+ ruby
+ }.should raise_error(EnsureSpec::Error)
+
+ ScratchPad.recorded.should == [:begin, :ensure]
+ end
+
+ it "is executed when an exception is raised and rescued in it's corresponding begin block" do
+ eval(<<-ruby).call
+ lambda do
+ ScratchPad << :begin
+ raise "An exception occurred!"
+ rescue
+ ScratchPad << :rescue
+ ensure
+ ScratchPad << :ensure
+ end
+ ruby
+
+ ScratchPad.recorded.should == [:begin, :rescue, :ensure]
+ end
+
+ it "is executed even when a symbol is thrown in it's corresponding begin block" do
+ catch(:symbol) do
+ eval(<<-ruby).call
+ lambda do
+ ScratchPad << :begin
+ throw(:symbol)
+ rescue
+ ScratchPad << :rescue
+ ensure
+ ScratchPad << :ensure
+ end
+ ruby
+ end
+
+ ScratchPad.recorded.should == [:begin, :ensure]
+ end
+
+ it "is executed when nothing is raised or thrown in it's corresponding begin block" do
+ eval(<<-ruby).call
+ lambda do
+ ScratchPad << :begin
+ rescue
+ ScratchPad << :rescue
+ ensure
+ ScratchPad << :ensure
+ end
+ ruby
+
+ ScratchPad.recorded.should == [:begin, :ensure]
+ end
+
+ it "has no return value" do
+ result = eval(<<-ruby).call
+ lambda do
+ :begin
+ ensure
+ :ensure
+ end
+ ruby
+
+ result.should == :begin
+ end
+ end
+end
diff --git a/spec/ruby/language/fixtures/ensure.rb b/spec/ruby/language/fixtures/ensure.rb
index 0dad7d8401..d1a9da37b8 100644
--- a/spec/ruby/language/fixtures/ensure.rb
+++ b/spec/ruby/language/fixtures/ensure.rb
@@ -8,7 +8,7 @@ module EnsureSpec
def raise_in_method_with_ensure
@executed << :method
- raise "An Exception"
+ raise EnsureSpec::Error
ensure
@executed << :ensure
end
@@ -70,3 +70,8 @@ module EnsureSpec
end
end
end
+
+module EnsureSpec
+ class Error < RuntimeError
+ end
+end
diff --git a/spec/ruby/language/rescue_spec.rb b/spec/ruby/language/rescue_spec.rb
index d7042b7973..0dc8894740 100644
--- a/spec/ruby/language/rescue_spec.rb
+++ b/spec/ruby/language/rescue_spec.rb
@@ -31,6 +31,28 @@ describe "The rescue keyword" do
end
end
+ it "returns value from `rescue` if an exception was raised" do
+ begin
+ raise
+ rescue
+ :caught
+ end.should == :caught
+ end
+
+ it "returns value from `else` section if no exceptions were raised" do
+ result = begin
+ :begin
+ rescue
+ :rescue
+ else
+ :else
+ ensure
+ :ensure
+ end
+
+ result.should == :else
+ end
+
it "can rescue multiple raised exceptions with a single rescue block" do
[lambda{raise ArbitraryException}, lambda{raise SpecificExampleException}].map do |block|
begin
@@ -94,6 +116,32 @@ describe "The rescue keyword" do
end.should raise_error(OtherCustomException)
end
+ it "can rescue different types of exceptions in different ways" do
+ begin
+ raise Exception
+ rescue RuntimeError
+ rescue StandardError
+ rescue Exception
+ ScratchPad << :exception
+ end
+
+ ScratchPad.recorded.should == [:exception]
+ end
+
+ it "rescues exception within the first suitable section in order of declaration" do
+ begin
+ raise StandardError
+ rescue RuntimeError
+ ScratchPad << :runtime_error
+ rescue StandardError
+ ScratchPad << :standard_error
+ rescue Exception
+ ScratchPad << :exception
+ end
+
+ ScratchPad.recorded.should == [:standard_error]
+ end
+
it "will execute an else block only if no exceptions were raised" do
result = begin
ScratchPad << :one
@@ -147,6 +195,20 @@ describe "The rescue keyword" do
ScratchPad.recorded.should == [:one, :else_ran, :ensure_ran, :outside_begin]
end
+ it "will execute an else block even without rescue and ensure" do
+ lambda {
+ eval <<-ruby
+ begin
+ ScratchPad << :begin
+ else
+ ScratchPad << :else
+ end
+ ruby
+ }.should complain(/else without rescue is useless/)
+
+ ScratchPad.recorded.should == [:begin, :else]
+ end
+
it "will not execute an else block if an exception was raised" do
result = begin
ScratchPad << :one
@@ -223,14 +285,31 @@ describe "The rescue keyword" do
a.should == 'ac'
end
- it "without classes will not rescue Exception" do
- lambda do
+ context "without rescue expression" do
+ it "will rescue only StandardError and its subclasses" do
begin
- raise Exception
+ raise StandardError
rescue
- 'Exception wrongly rescued'
+ ScratchPad << :caught
+ end
+
+ ScratchPad.recorded.should == [:caught]
+ end
+
+ it "will not rescue exceptions except StandardError" do
+ [ Exception.new, NoMemoryError.new, ScriptError.new, SecurityError.new,
+ SignalException.new('INT'), SystemExit.new, SystemStackError.new
+ ].each do |exception|
+ lambda {
+ begin
+ raise exception
+ rescue
+ ScratchPad << :caught
+ end
+ }.should raise_error(exception.class)
end
- end.should raise_error(Exception)
+ ScratchPad.recorded.should == []
+ end
end
it "uses === to compare against rescued classes" do
@@ -279,7 +358,7 @@ describe "The rescue keyword" do
invalid_rescuer = Object.new
begin
:foo
- rescue rescuer
+ rescue invalid_rescuer
end.should == :foo
end
@@ -291,6 +370,44 @@ describe "The rescue keyword" do
end.should == :expected
end
+ it "allows rescue in class" do
+ eval <<-ruby
+ class RescueInClassExample
+ raise SpecificExampleException
+ rescue SpecificExampleException
+ ScratchPad << :caught
+ end
+ ruby
+
+ ScratchPad.recorded.should == [:caught]
+ end
+
+ it "does not allow rescue in {} block" do
+ lambda {
+ eval <<-ruby
+ lambda {
+ raise SpecificExampleException
+ rescue SpecificExampleException
+ :caught
+ }
+ ruby
+ }.should raise_error(SyntaxError)
+ end
+
+ ruby_version_is "2.5" do
+ it "allows rescue in 'do end' block" do
+ lambda = eval <<-ruby
+ lambda do
+ raise SpecificExampleException
+ rescue SpecificExampleException
+ ScratchPad << :caught
+ end.call
+ ruby
+
+ ScratchPad.recorded.should == [:caught]
+ end
+ end
+
ruby_version_is ""..."2.4" do
it "fails when using 'rescue' in method arguments" do
lambda { eval '1.+ (1 rescue 1)' }.should raise_error(SyntaxError)
@@ -305,6 +422,31 @@ describe "The rescue keyword" do
it "requires the 'rescue' in method arguments to be wrapped in parens" do
lambda { eval '1.+(1 rescue 1)' }.should raise_error(SyntaxError)
+ eval('1.+((1 rescue 1))').should == 2
+ end
+ end
+
+ describe "inline form" do
+ it "can be inlined" do
+ a = 1/0 rescue 1
+ a.should == 1
+ end
+
+ it "doesn't except rescue expression" do
+ lambda {
+ eval <<-ruby
+ a = 1 rescue RuntimeError 2
+ ruby
+ }.should raise_error(SyntaxError)
+ end
+
+ it "rescues only StandardError and its subclasses" do
+ a = raise(StandardError) rescue 1
+ a.should == 1
+
+ lambda {
+ a = raise(Exception) rescue 1
+ }.should raise_error(Exception)
end
end
end