Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

Bug with expectation's on Class methods caught by method missing [Critical] #17

Closed
aselder opened this Issue Mar 3, 2011 · 5 comments

Comments

Projects
None yet
2 participants

aselder commented Mar 3, 2011

In the proxy.rb file, Rspec 1.3.1 added a stanza to the it/else stack

    elsif @target.is_a?(Class)
      @target.superclass.send(sym, *args, &block)

This just seems wrong to me and I'm pretty sure it's causing catastrophic errors in my build.

Consider the following example:

require 'spec_helper'

class Foo

    def self.singleton
      @singleton ||= new
    end

    # Redirect all missing class methods to the singleton instance for backwards compatible API
    def self.method_missing(name,*args,&block)
      self.singleton.send(name,*args,&block)
    end

    def bar
      "abc"
    end
end

describe Foo do

  it "should mock correctly" do
    Foo.should_receive(:bar).and_return(123)
    Foo.bar.should == 123
  end

  it "should call successfully after a mock" do
    Foo.bar.should == "abc"
  end

end

The first example creates a message_expectation for the Foo class object, which defines the :bar method on Foo, since as written Foo.respond_to?(:bar) returns false. This method send the name of the method to the __mock_proxy which delegates it to message received.

As we move to the second example, the method defined by define_expected_method remains, which sends the message to the mock_proxy's message_received methods. Since there are no expectations defined, we drop to the suspect code. Since the @target of the proxy is Foo, and Foo is a Class, the message tries to get sent to Foo's superclass, namely Object, which doesn't define #bar and blows up.

- should mock correctly
- should call successfully after a mock (FAILED - 1)

1)
NoMethodError in 'Foo should call successfully after a mock'
undefined method `bar' for Object:Class
spec/models/test_spec.rb:27:in `block (2 levels) in <top (required)>'

aselder commented Mar 3, 2011

I know the example above is slightly contrived, but given the amount of meta-programming in Ruby, this pattern is probably quite common.

Any expectation set on a class method not explicitly defined will cause any future calls to the method to blow up.

aselder commented Mar 3, 2011

A solution that seems to work for me is to change line 114 of proxy.rb to:

elsif @target.is_a?(Class) && @target.superclass.respond_to?(sym, true)
Owner

dchelimsky commented Mar 4, 2011

Do you want to submit a proper patch?

aselder commented Mar 4, 2011

Dave,

Will do. I'll get to it tonight.

Andrew

Owner

dchelimsky commented Mar 4, 2011

Closed by c723627

mrkn pushed a commit to mrkn/rspec that referenced this issue Apr 20, 2011

Only try to pass messages to the superclass if the superclass respond…
…s to the method

Fixes LH Bug #1049 and GH Bug #15 and #17

This issue was closed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment