Skip to content

Commit

Permalink
Add missing specs for NoMethodError#message
Browse files Browse the repository at this point in the history
  • Loading branch information
andrykonchin committed Dec 19, 2024
1 parent 8d0133f commit 4cdd52d
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 40 deletions.
3 changes: 3 additions & 0 deletions spec/ruby/core/exception/fixtures/common.rb
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ class NoMethodErrorD; end

class InstanceException < Exception
end

class AClass; end
module AModule; end
end

class NameErrorSpecs
Expand Down
174 changes: 134 additions & 40 deletions spec/ruby/core/exception/no_method_error_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
end

ruby_version_is ""..."3.3" do
it "calls receiver.inspect only when calling Exception#message" do
it "calls #inspect when calling Exception#message" do
ScratchPad.record []
test_class = Class.new do
def inspect
Expand All @@ -76,68 +76,162 @@ def inspect
end
end
instance = test_class.new

begin
instance.bar
rescue Exception => e
e.name.should == :bar
ScratchPad.recorded.should == []
e.message.should =~ /undefined method.+\bbar\b/
rescue NoMethodError => error
error.message.should =~ /\Aundefined method [`']bar' for <inspect>:#<Class:0x\h+>$/
ScratchPad.recorded.should == [:inspect_called]
end
end
end

ruby_version_is "3.3" do
it "does not call receiver.inspect even when calling Exception#message" do
ScratchPad.record []
it "fallbacks to a simpler representation of the receiver when receiver.inspect raises an exception" do
test_class = Class.new do
def inspect
ScratchPad << :inspect_called
"<inspect>"
raise NoMethodErrorSpecs::InstanceException
end
end
instance = test_class.new

begin
instance.bar
rescue Exception => e
e.name.should == :bar
ScratchPad.recorded.should == []
e.message.should =~ /undefined method.+\bbar\b/
ScratchPad.recorded.should == []
rescue NoMethodError => error
message = error.message
message.should =~ /undefined method.+\bbar\b/
message.should include test_class.inspect
end
end
end

it "fallbacks to a simpler representation of the receiver when receiver.inspect raises an exception" do
test_class = Class.new do
def inspect
raise NoMethodErrorSpecs::InstanceException
it "uses #name to display the receiver if it is a class" do
klass = Class.new { def self.name; "MyClass"; end }

begin
klass.foo
rescue NoMethodError => error
error.message.should =~ /\Aundefined method [`']foo' for MyClass:Class$/
end
end
instance = test_class.new
begin
instance.bar
rescue Exception => e
e.name.should == :bar
message = e.message
message.should =~ /undefined method.+\bbar\b/
message.should include test_class.inspect

it "uses #name to display the receiver if it is a module" do
mod = Module.new { def self.name; "MyModule"; end }

begin
mod.foo
rescue NoMethodError => error
error.message.should =~ /\Aundefined method [`']foo' for MyModule:Module$/
end
end
end

it "uses #name to display the receiver if it is a class or a module" do
klass = Class.new { def self.name; "MyClass"; end }
begin
klass.foo
rescue NoMethodError => error
error.message.lines.first.chomp.should =~ /^undefined method [`']foo' for /
ruby_version_is "3.3" do
it "uses a literal name when receiver is nil" do
begin
nil.foo
rescue NoMethodError => error
error.message.should =~ /\Aundefined method [`']foo' for nil\Z/
end
end

mod = Module.new { def self.name; "MyModule"; end }
begin
mod.foo
rescue NoMethodError => error
error.message.lines.first.chomp.should =~ /^undefined method [`']foo' for /
it "uses a literal name when receiver is true" do
begin
true.foo
rescue NoMethodError => error
error.message.should =~ /\Aundefined method [`']foo' for true\Z/
end
end

it "uses a literal name when receiver is false" do
begin
false.foo
rescue NoMethodError => error
error.message.should =~ /\Aundefined method [`']foo' for false\Z/
end
end

it "uses #name when receiver is a class" do
begin
NoMethodErrorSpecs::AClass.foo
rescue NoMethodError => error
error.message.should =~ /\Aundefined method [`']foo' for class NoMethodErrorSpecs::AClass\Z/
end
end

it "uses class' string representation when receiver is an anonymous class" do
klass = Class.new

begin
klass.foo
rescue NoMethodError => error
error.message.should =~ /\Aundefined method [`']foo' for class #<Class:0x\h+>\Z/
end
end

it "uses #name when receiver is a module" do
begin
NoMethodErrorSpecs::AModule.foo
rescue NoMethodError => error
error.message.should =~ /\Aundefined method [`']foo' for module NoMethodErrorSpecs::AModule\Z/
end
end

it "uses module's string representation when receiver is an anonymous module" do
m = Module.new

begin
m.foo
rescue NoMethodError => error
error.message.should =~ /\Aundefined method [`']foo' for module #<Module:0x\h+>\Z/
end
end

it "uses class name when receiver is an ordinary object" do
instance = NoMethodErrorSpecs::NoMethodErrorA.new

begin
instance.bar
rescue NoMethodError => error
error.message.should =~ /\Aundefined method [`']bar' for an instance of NoMethodErrorSpecs::NoMethodErrorA\Z/
end
end

it "uses class string representation when receiver is an instance of anonymous class" do
klass = Class.new
instance = klass.new

begin
instance.bar
rescue NoMethodError => error
error.message.should =~ /\Aundefined method [`']bar' for an instance of #<Class:0x\h+>\Z/
end
end

it "uses class name when receiver has a singleton class" do
instance = NoMethodErrorSpecs::NoMethodErrorA.new
def instance.foo; end

begin
instance.bar
rescue NoMethodError => error
error.message.should =~ /\Aundefined method [`']bar' for #<NoMethodErrorSpecs::NoMethodErrorA:0x\h+>\Z/
end
end

it "does not call #inspect when calling Exception#message" do
ScratchPad.record []
test_class = Class.new do
def inspect
ScratchPad << :inspect_called
"<inspect>"
end
end
instance = test_class.new

begin
instance.bar
rescue NoMethodError => error
error.message.should =~ /\Aundefined method [`']bar' for an instance of #<Class:0x\h+>\Z/
ScratchPad.recorded.should == []
end
end
end
end
Expand Down
2 changes: 2 additions & 0 deletions spec/tags/core/exception/no_method_error_tags.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
fails:NoMethodError#message uses class string representation when receiver is an instance of anonymous class
fails:NoMethodError#message does not call #inspect when calling Exception#message

0 comments on commit 4cdd52d

Please sign in to comment.