diff options
Diffstat (limited to 'spec/ruby/language')
-rw-r--r-- | spec/ruby/language/constants_spec.rb | 22 | ||||
-rw-r--r-- | spec/ruby/language/ensure_spec.rb | 229 | ||||
-rw-r--r-- | spec/ruby/language/fixtures/ensure.rb | 7 | ||||
-rw-r--r-- | spec/ruby/language/rescue_spec.rb | 154 |
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 |