summaryrefslogtreecommitdiff
path: root/spec/ruby/core/exception/no_method_error_spec.rb
blob: 8428ba03826ee5f4bd8c753136da4f6a0c50771c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
require_relative '../../spec_helper'
require_relative 'fixtures/common'

describe "NoMethodError.new" do
  it "allows passing method args" do
    NoMethodError.new("msg", "name", ["args"]).args.should == ["args"]
  end

  it "does not require a name" do
    NoMethodError.new("msg").message.should == "msg"
  end

  it "accepts a :receiver keyword argument" do
    receiver = mock("receiver")

    error = NoMethodError.new("msg", :name, receiver: receiver)

    error.receiver.should == receiver
    error.name.should == :name
  end
end

describe "NoMethodError#args" do
  it "returns an empty array if the caller method had no arguments" do
    begin
      NoMethodErrorSpecs::NoMethodErrorB.new.foo
    rescue Exception => e
      e.args.should == []
    end
  end

  it "returns an array with the same elements as passed to the method" do
    begin
      a = NoMethodErrorSpecs::NoMethodErrorA.new
      NoMethodErrorSpecs::NoMethodErrorB.new.foo(1,a)
    rescue Exception => e
      e.args.should == [1,a]
      e.args[1].should equal a
    end
  end
end

describe "NoMethodError#message" do
  it "for an undefined method match /undefined method/" do
    begin
      NoMethodErrorSpecs::NoMethodErrorD.new.foo
    rescue Exception => e
      e.should be_kind_of(NoMethodError)
    end
  end

  it "for an protected method match /protected method/" do
    begin
      NoMethodErrorSpecs::NoMethodErrorC.new.a_protected_method
    rescue Exception => e
      e.should be_kind_of(NoMethodError)
    end
  end

  it "for private method match /private method/" do
    begin
      NoMethodErrorSpecs::NoMethodErrorC.new.a_private_method
    rescue Exception => e
      e.should be_kind_of(NoMethodError)
      e.message.lines[0].should =~ /private method `a_private_method' called for #<NoMethodErrorSpecs::NoMethodErrorC:0x[\h]+>/
    end
  end

  it "calls receiver.inspect only 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 Exception => e
      e.name.should == :bar
      ScratchPad.recorded.should == []
      e.message.should =~ /undefined method.+\bbar\b/
      ScratchPad.recorded.should == [:inspect_called]
    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
      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
    end
  end

  ruby_version_is "3.0" do
    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 MyClass:Class"
      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 MyModule:Module"
      end
    end
  end
end

describe "NoMethodError#dup" do
  it "copies the name, arguments and receiver" do
    begin
      receiver = Object.new
      receiver.foo(:one, :two)
    rescue NoMethodError => nme
      no_method_error_dup = nme.dup
      no_method_error_dup.name.should == :foo
      no_method_error_dup.receiver.should == receiver
      no_method_error_dup.args.should == [:one, :two]
    end
  end
end