* Regression introduced by a727464. * The cause: - Test code requests a method be stubbed - Since the method was not defined on the object's singleton class, it did not need to be stashed - Proxied method is defined on the object's singleton class - Test code requests a method to be stubbed (again) - Since the proxied method is defined on the object's singleton class, it is stashed (bug here!) - Later, the proxied method is restored in the reset step; future calls to that method are broken * The fix: - Do not stash methods if a method has already been proxied by TestDouble * Test written by @myronmarston (thanks!)
* Instances stubbed with `#any_instance` would not be usable after the test finished because `MethodDouble` would stash the implementation of the method already overridden by `AnyInstance::Recorder`. When the test finished, that implementation would be restored on the object's singleton class, and any future calls to it would blow up with a stack overflow. * This fix only stashes methods if they are defined on the object's singleton class to begin with; `AnyInstance::Recorder` defines a method on the object's class so that method will not be stashed. * If there is no method on the object's singleton class, RSpec can safely define one there without stashing the original implementation. At the end of the test, the method is simply removed entirely from the singleton class. Any original implementation defined in the object's ancestor chain will show through again. * This issue cannot be fixed on MRI 1.8.6 because it does not support `Method#owner`. However, `#any_instance` itself is not supported on 1.8.6 for the same reason. The fix should not negatively affect 1.8.6, though, because the fallback behavior is to stash the method in all cases (which was the original behavior). * This commit also refactors the stashing behavior out into its own object. While not explicitly necessary, it helped me reason about the fix much easier than when all the responsibility was in `MethodDouble` (which also has other responsibilities). * Fixes #167 * Closes #182
- was using Object.new - Fixes #587
My changes in deec990 caused it to blow up in the face of inherited constants.
…ants. I didn't realize this previously, but these methods can pick up a top-level constant when you don't intend it (e.g. ::Hash when checking MyGem.const_defined?("Hash")).
Previously, the recorder implementation created a SystemStackError. Closes #152.
- lib/rspec/mocks/error_generator.rb:32: warning: assigned but unused variable - expected_args - lib/rspec/mocks/error_generator.rb:33: warning: assigned but unused variable - actual_args - lib/rspec/mocks/stub_const.rb:8: warning: shadowing outer local variable - name - lib/rspec/mocks/stub_const.rb:12: warning: shadowing outer local variable - name - spec/rspec/mocks/stub_const_spec.rb:60: warning: assigned but unused variable - orig_value - lib/rspec/mocks/stub_const.rb:233: warning: instance variable @registered_with_mocks_space not initialized Closes #162.
…revious stub. In a case like: double = stub.as_null_object double.stub(:foo => "bar") double.should_receive(:foo) double.foo ..it used to return "bar", but due to my changes in a5f296e it was returning `self`.
Given a case like: double = mock.as_null_object double.should_receive(:bar) ...`double.bar` was returning nil when it should return the double itself, since that's the expected null object behavior and no implementation was provided for the mock expectation. Closes #155.
…into a string. Closes #154.
Also extract base ExpectationChain.
…nts. This needs to be documented, but I want to get feedback from others before spending effort on that.
This allows chaining: stub_const("Foo", double).stub(:foo)
… with default behavior.
…en if x is already stubbed widget.stub(:count => 1) widget.should_receive(:count).at_least(:once).and_return(2) widget.count #=> 2 widget.count #=> 2 If there is no return value set, it will fall back to the stub value: widget.stub(:count => 1) widget.should_receive(:count).at_least(:once) widget.count #=> 1 widget.count #=> 1 - Fixes #142