Browse files

fix bug in which multiple chains with shared messages ending in hashes

failed to return the correct value

- also documented stub_chain(:a, :b => :c) format in feature
  • Loading branch information...
1 parent 5ac6d83 commit ca2d83712fe329affbe4334c8c292c40ae74e5ce @dchelimsky dchelimsky committed Feb 12, 2011
View
7 features/Changelog.md
@@ -1,3 +1,10 @@
+### dev
+
+[full changelog](http://github.com/rspec/rspec-mocks/compare/v2.5.0...master)
+
+* Bug fixes
+ * fix bug in which multiple chains with shared messages ending in hashes failed to return the correct value
+
### 2.5.0 / 2011-02-05
[full changelog](http://github.com/rspec/rspec-mocks/compare/v2.4.0...v2.5.0)
View
17 features/method_stubs/stub_chain.feature
@@ -1,9 +1,9 @@
Feature: stub a chain of methods
- The `stub_chain` method lets you to stub a chain of methods in one statement.
- Method chains are considered a design smell, but it's not really the method
- chain that is the problem - it's the dependency chain represented by a chain
- of messages to different objects:
+ Use the `stub_chain` method to stub a chain of two or more methods in one
+ statement. Method chains are considered a design smell, but it's not really
+ the method chain itself that is the problem - it's the dependency chain
+ represented by a chain of messages to different objects:
foo.get_bar.get_baz
@@ -32,6 +32,13 @@ Feature: stub a chain of methods
end
end
+ context "given a hash at the end" do
+ it "returns the correct value" do
+ subject.stub_chain(:one, :two, :three => :four)
+ subject.one.two.three.should eq(:four)
+ end
+ end
+
context "given a string of methods separated by dots" do
it "returns the correct value" do
subject.stub_chain("one.two.three").and_return(:four)
@@ -41,4 +48,4 @@ Feature: stub a chain of methods
end
"""
When I run "rspec stub_chain_spec.rb"
- Then the output should contain "2 examples, 0 failures"
+ Then the examples should all pass
View
4 features/step_definitions/additional_cli_steps.rb
@@ -0,0 +1,4 @@
+Then /^the example(?:s)? should(?: all)? pass$/ do
+ Then %q{the output should contain "0 failures"}
+ Then %q{the exit status should be 0}
+end
View
2 lib/rspec/mocks/methods.rb
@@ -39,7 +39,7 @@ def stub_chain(*chain, &blk)
if chain.length > 1
if matching_stub = __mock_proxy.__send__(:find_matching_method_stub, chain[0].to_sym)
chain.shift
- matching_stub.invoke.stub_chain(*chain)
+ matching_stub.invoke.stub_chain(*chain, &blk)
else
next_in_chain = Object.new
stub(chain.shift) { next_in_chain }
View
109 spec/rspec/mocks/stub_chain_spec.rb
@@ -3,111 +3,146 @@
module RSpec
module Mocks
describe "A chained method stub" do
- before(:each) do
- @subject = Object.new
- end
-
+ subject { Object.new }
context "with one method in chain" do
context "using and_return" do
it "returns expected value from chaining only one method call" do
- @subject.stub_chain(:msg1).and_return(:return_value)
- @subject.msg1.should equal(:return_value)
+ subject.stub_chain(:msg1).and_return(:return_value)
+ subject.msg1.should equal(:return_value)
end
end
context "using a block" do
it "returns the correct value" do
- @subject.stub_chain(:msg1) { :return_value }
- @subject.msg1.should equal(:return_value)
+ subject.stub_chain(:msg1) { :return_value }
+ subject.msg1.should equal(:return_value)
end
end
context "using a hash" do
it "returns the value of the key/value pair" do
- @subject.stub_chain(:msg1 => :return_value)
- @subject.msg1.should equal(:return_value)
+ subject.stub_chain(:msg1 => :return_value)
+ subject.msg1.should equal(:return_value)
end
end
end
context "with two methods in chain" do
context "using and_return" do
it "returns expected value from chaining two method calls" do
- @subject.stub_chain(:msg1, :msg2).and_return(:return_value)
- @subject.msg1.msg2.should equal(:return_value)
+ subject.stub_chain(:msg1, :msg2).and_return(:return_value)
+ subject.msg1.msg2.should equal(:return_value)
end
end
context "using a block" do
it "returns the correct value" do
- @subject.stub_chain(:msg1, :msg2) { :return_value }
- @subject.msg1.msg2.should equal(:return_value)
+ subject.stub_chain(:msg1, :msg2) { :return_value }
+ subject.msg1.msg2.should equal(:return_value)
end
end
context "using a hash" do
it "returns the value of the key/value pair" do
- @subject.stub_chain(:msg1, :msg2 => :return_value)
- @subject.msg1.msg2.should equal(:return_value)
+ subject.stub_chain(:msg1, :msg2 => :return_value)
+ subject.msg1.msg2.should equal(:return_value)
end
end
end
context "with four methods in chain" do
context "using and_return" do
it "returns expected value from chaining two method calls" do
- @subject.stub_chain(:msg1, :msg2, :msg3, :msg4).and_return(:return_value)
- @subject.msg1.msg2.msg3.msg4.should equal(:return_value)
+ subject.stub_chain(:msg1, :msg2, :msg3, :msg4).and_return(:return_value)
+ subject.msg1.msg2.msg3.msg4.should equal(:return_value)
end
end
context "using a block" do
it "returns the correct value" do
- @subject.stub_chain(:msg1, :msg2, :msg3, :msg4) { :return_value }
- @subject.msg1.msg2.msg3.msg4.should equal(:return_value)
+ subject.stub_chain(:msg1, :msg2, :msg3, :msg4) { :return_value }
+ subject.msg1.msg2.msg3.msg4.should equal(:return_value)
end
end
context "using a hash" do
it "returns the value of the key/value pair" do
- @subject.stub_chain(:msg1, :msg2, :msg3, :msg4 => :return_value)
- @subject.msg1.msg2.msg3.msg4.should equal(:return_value)
+ subject.stub_chain(:msg1, :msg2, :msg3, :msg4 => :return_value)
+ subject.msg1.msg2.msg3.msg4.should equal(:return_value)
end
end
context "using a hash with a string key" do
it "returns the value of the key/value pair" do
- @subject.stub_chain("msg1.msg2.msg3.msg4" => :return_value)
- @subject.msg1.msg2.msg3.msg4.should equal(:return_value)
+ subject.stub_chain("msg1.msg2.msg3.msg4" => :return_value)
+ subject.msg1.msg2.msg3.msg4.should equal(:return_value)
end
end
end
it "returns expected value from chaining four method calls" do
- @subject.stub_chain(:msg1, :msg2, :msg3, :msg4).and_return(:return_value)
- @subject.msg1.msg2.msg3.msg4.should equal(:return_value)
+ subject.stub_chain(:msg1, :msg2, :msg3, :msg4).and_return(:return_value)
+ subject.msg1.msg2.msg3.msg4.should equal(:return_value)
end
- it "returns expected value from chaining four method calls twice with some shared" do
- @subject.stub_chain(:msg1, :msg2, :msg3, :msg4).and_return(:first)
- @subject.stub_chain(:msg5, :msg2, :msg3, :msg4).and_return(:second)
+ context "with messages shared across multiple chains" do
+ context "using and_return" do
+ context "starting with the same message" do
+ it "returns expected value" do
+ subject.stub_chain(:msg1, :msg2, :msg3).and_return(:first)
+ subject.stub_chain(:msg1, :msg2, :msg4).and_return(:second)
+
+ subject.msg1.msg2.msg3.should equal(:first)
+ subject.msg1.msg2.msg4.should equal(:second)
+ end
+ end
+
+ context "starting with the different messages" do
+ it "returns expected value" do
+ subject.stub_chain(:msg1, :msg2, :msg3).and_return(:first)
+ subject.stub_chain(:msg4, :msg2, :msg3).and_return(:second)
+
+ subject.msg1.msg2.msg3.should equal(:first)
+ subject.msg4.msg2.msg3.should equal(:second)
+ end
+ end
+ end
+
+ context "using => value" do
+ context "starting with the same message" do
+ it "returns expected value", :focus => true do
+ subject.stub_chain(:msg1, :msg2, :msg3 => :first)
+ subject.stub_chain(:msg1, :msg2, :msg4 => :second)
+
+ subject.msg1.msg2.msg3.should equal(:first)
+ subject.msg1.msg2.msg4.should equal(:second)
+ end
+ end
- @subject.msg1.msg2.msg3.msg4.should equal(:first)
- @subject.msg5.msg2.msg3.msg4.should equal(:second)
+ context "starting with different messages" do
+ it "returns expected value", :focus => true do
+ subject.stub_chain(:msg1, :msg2, :msg3 => :first)
+ subject.stub_chain(:msg4, :msg2, :msg3 => :second)
+
+ subject.msg1.msg2.msg3.should equal(:first)
+ subject.msg4.msg2.msg3.should equal(:second)
+ end
+ end
+ end
end
it "returns expected value when chain is a dot separated string, like stub_chain('msg1.msg2.msg3')" do
- @subject.stub_chain("msg1.msg2.msg3").and_return(:return_value)
- @subject.msg1.msg2.msg3.should equal(:return_value)
+ subject.stub_chain("msg1.msg2.msg3").and_return(:return_value)
+ subject.msg1.msg2.msg3.should equal(:return_value)
end
it "returns expected value from two chains with shared messages at the beginning" do
- @subject.stub_chain(:msg1, :msg2, :msg3, :msg4).and_return(:first)
- @subject.stub_chain(:msg1, :msg2, :msg3, :msg5).and_return(:second)
+ subject.stub_chain(:msg1, :msg2, :msg3, :msg4).and_return(:first)
+ subject.stub_chain(:msg1, :msg2, :msg3, :msg5).and_return(:second)
- @subject.msg1.msg2.msg3.msg4.should equal(:first)
- @subject.msg1.msg2.msg3.msg5.should equal(:second)
+ subject.msg1.msg2.msg3.msg4.should equal(:first)
+ subject.msg1.msg2.msg3.msg5.should equal(:second)
end
end
end

0 comments on commit ca2d837

Please sign in to comment.