Skip to content

Commit 4cdd52d

Browse files
committed
Add missing specs for NoMethodError#message
1 parent 8d0133f commit 4cdd52d

File tree

3 files changed

+139
-40
lines changed

3 files changed

+139
-40
lines changed

spec/ruby/core/exception/fixtures/common.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ class NoMethodErrorD; end
8484

8585
class InstanceException < Exception
8686
end
87+
88+
class AClass; end
89+
module AModule; end
8790
end
8891

8992
class NameErrorSpecs

spec/ruby/core/exception/no_method_error_spec.rb

Lines changed: 134 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
end
6868

6969
ruby_version_is ""..."3.3" do
70-
it "calls receiver.inspect only when calling Exception#message" do
70+
it "calls #inspect when calling Exception#message" do
7171
ScratchPad.record []
7272
test_class = Class.new do
7373
def inspect
@@ -76,68 +76,162 @@ def inspect
7676
end
7777
end
7878
instance = test_class.new
79+
7980
begin
8081
instance.bar
81-
rescue Exception => e
82-
e.name.should == :bar
83-
ScratchPad.recorded.should == []
84-
e.message.should =~ /undefined method.+\bbar\b/
82+
rescue NoMethodError => error
83+
error.message.should =~ /\Aundefined method [`']bar' for <inspect>:#<Class:0x\h+>$/
8584
ScratchPad.recorded.should == [:inspect_called]
8685
end
8786
end
88-
end
8987

90-
ruby_version_is "3.3" do
91-
it "does not call receiver.inspect even when calling Exception#message" do
92-
ScratchPad.record []
88+
it "fallbacks to a simpler representation of the receiver when receiver.inspect raises an exception" do
9389
test_class = Class.new do
9490
def inspect
95-
ScratchPad << :inspect_called
96-
"<inspect>"
91+
raise NoMethodErrorSpecs::InstanceException
9792
end
9893
end
9994
instance = test_class.new
95+
10096
begin
10197
instance.bar
102-
rescue Exception => e
103-
e.name.should == :bar
104-
ScratchPad.recorded.should == []
105-
e.message.should =~ /undefined method.+\bbar\b/
106-
ScratchPad.recorded.should == []
98+
rescue NoMethodError => error
99+
message = error.message
100+
message.should =~ /undefined method.+\bbar\b/
101+
message.should include test_class.inspect
107102
end
108103
end
109-
end
110104

111-
it "fallbacks to a simpler representation of the receiver when receiver.inspect raises an exception" do
112-
test_class = Class.new do
113-
def inspect
114-
raise NoMethodErrorSpecs::InstanceException
105+
it "uses #name to display the receiver if it is a class" do
106+
klass = Class.new { def self.name; "MyClass"; end }
107+
108+
begin
109+
klass.foo
110+
rescue NoMethodError => error
111+
error.message.should =~ /\Aundefined method [`']foo' for MyClass:Class$/
115112
end
116113
end
117-
instance = test_class.new
118-
begin
119-
instance.bar
120-
rescue Exception => e
121-
e.name.should == :bar
122-
message = e.message
123-
message.should =~ /undefined method.+\bbar\b/
124-
message.should include test_class.inspect
114+
115+
it "uses #name to display the receiver if it is a module" do
116+
mod = Module.new { def self.name; "MyModule"; end }
117+
118+
begin
119+
mod.foo
120+
rescue NoMethodError => error
121+
error.message.should =~ /\Aundefined method [`']foo' for MyModule:Module$/
122+
end
125123
end
126124
end
127125

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

136-
mod = Module.new { def self.name; "MyModule"; end }
137-
begin
138-
mod.foo
139-
rescue NoMethodError => error
140-
error.message.lines.first.chomp.should =~ /^undefined method [`']foo' for /
135+
it "uses a literal name when receiver is true" do
136+
begin
137+
true.foo
138+
rescue NoMethodError => error
139+
error.message.should =~ /\Aundefined method [`']foo' for true\Z/
140+
end
141+
end
142+
143+
it "uses a literal name when receiver is false" do
144+
begin
145+
false.foo
146+
rescue NoMethodError => error
147+
error.message.should =~ /\Aundefined method [`']foo' for false\Z/
148+
end
149+
end
150+
151+
it "uses #name when receiver is a class" do
152+
begin
153+
NoMethodErrorSpecs::AClass.foo
154+
rescue NoMethodError => error
155+
error.message.should =~ /\Aundefined method [`']foo' for class NoMethodErrorSpecs::AClass\Z/
156+
end
157+
end
158+
159+
it "uses class' string representation when receiver is an anonymous class" do
160+
klass = Class.new
161+
162+
begin
163+
klass.foo
164+
rescue NoMethodError => error
165+
error.message.should =~ /\Aundefined method [`']foo' for class #<Class:0x\h+>\Z/
166+
end
167+
end
168+
169+
it "uses #name when receiver is a module" do
170+
begin
171+
NoMethodErrorSpecs::AModule.foo
172+
rescue NoMethodError => error
173+
error.message.should =~ /\Aundefined method [`']foo' for module NoMethodErrorSpecs::AModule\Z/
174+
end
175+
end
176+
177+
it "uses module's string representation when receiver is an anonymous module" do
178+
m = Module.new
179+
180+
begin
181+
m.foo
182+
rescue NoMethodError => error
183+
error.message.should =~ /\Aundefined method [`']foo' for module #<Module:0x\h+>\Z/
184+
end
185+
end
186+
187+
it "uses class name when receiver is an ordinary object" do
188+
instance = NoMethodErrorSpecs::NoMethodErrorA.new
189+
190+
begin
191+
instance.bar
192+
rescue NoMethodError => error
193+
error.message.should =~ /\Aundefined method [`']bar' for an instance of NoMethodErrorSpecs::NoMethodErrorA\Z/
194+
end
195+
end
196+
197+
it "uses class string representation when receiver is an instance of anonymous class" do
198+
klass = Class.new
199+
instance = klass.new
200+
201+
begin
202+
instance.bar
203+
rescue NoMethodError => error
204+
error.message.should =~ /\Aundefined method [`']bar' for an instance of #<Class:0x\h+>\Z/
205+
end
206+
end
207+
208+
it "uses class name when receiver has a singleton class" do
209+
instance = NoMethodErrorSpecs::NoMethodErrorA.new
210+
def instance.foo; end
211+
212+
begin
213+
instance.bar
214+
rescue NoMethodError => error
215+
error.message.should =~ /\Aundefined method [`']bar' for #<NoMethodErrorSpecs::NoMethodErrorA:0x\h+>\Z/
216+
end
217+
end
218+
219+
it "does not call #inspect when calling Exception#message" do
220+
ScratchPad.record []
221+
test_class = Class.new do
222+
def inspect
223+
ScratchPad << :inspect_called
224+
"<inspect>"
225+
end
226+
end
227+
instance = test_class.new
228+
229+
begin
230+
instance.bar
231+
rescue NoMethodError => error
232+
error.message.should =~ /\Aundefined method [`']bar' for an instance of #<Class:0x\h+>\Z/
233+
ScratchPad.recorded.should == []
234+
end
141235
end
142236
end
143237
end
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
fails:NoMethodError#message uses class string representation when receiver is an instance of anonymous class
2+
fails:NoMethodError#message does not call #inspect when calling Exception#message

0 commit comments

Comments
 (0)