Skip to content

Commit

Permalink
Merge pull request #358 from rspec/revisited_bugfix_for_doubles_in_ar…
Browse files Browse the repository at this point in the history
…rays

Ensure null objects behave correctly with to_a and to_ary
  • Loading branch information
JonRowe committed Jul 11, 2013
2 parents c7eb20e + 71f39f7 commit 19d39b7
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 17 deletions.
12 changes: 8 additions & 4 deletions features/method_stubs/to_ary.feature
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@ Feature: double handling to_ary
"""ruby
describe "#to_ary" do
shared_examples "to_ary" do
it "raises a NoMethodError" do
expect { obj.to_ary }.to raise_error(NoMethodError)
end
it "can be overridden with a stub" do
obj.stub(:to_ary) { :non_nil_value }
obj.to_ary.should be(:non_nil_value)
Expand All @@ -35,11 +31,19 @@ Feature: double handling to_ary
context "sent to a double as_null_object" do
let(:obj) { double('obj').as_null_object }
include_examples "to_ary"
it "returns nil" do
expect( obj.to_ary ).to eq nil
end
end
context "sent to a double without as_null_object" do
let(:obj) { double('obj') }
include_examples "to_ary"
it "raises a NoMethodError" do
expect { obj.to_ary }.to raise_error(NoMethodError)
end
end
end
"""
Expand Down
12 changes: 9 additions & 3 deletions lib/rspec/mocks/test_double.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def to_s

# @private
def respond_to?(message, incl_private=false)
__mock_proxy.null_object? && message != :to_ary ? true : super
__mock_proxy.null_object? ? true : super
end

# @private
Expand All @@ -79,13 +79,19 @@ def __initialize_as_test_double(name=nil, stubs_and_options={})
end

def method_missing(message, *args, &block)
raise NoMethodError if message == :to_ary || message == :to_a
return 0 if message == :to_int && __mock_proxy.null_object?
if __mock_proxy.null_object?
case message
when :to_int then return 0
when :to_a, :to_ary then return nil
end
end
__mock_proxy.record_message_received(message, *args, &block)

begin
__mock_proxy.null_object? ? self : super
rescue NameError
# Required wrapping doubles in an Array on Ruby 1.9.2
raise NoMethodError if [:to_a, :to_ary].include? message
__mock_proxy.raise_unexpected_message_error(message, *args)
end
end
Expand Down
16 changes: 16 additions & 0 deletions spec/rspec/mocks/mock_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,22 @@ def @double.method_with_default_argument(arg={}); end
expect( Array(@double) ).to eq([@double])
end

it "is wrappable in an array when a null object" do
expect( Array(@double.as_null_object) ).to eq [@double]
end

it "responds to to_ary as a null object" do
expect(@double.as_null_object.to_ary).to eq nil
end

it "responds to to_a as a null object" do
if RUBY_VERSION.to_f > 1.8
expect(@double.as_null_object.to_a).to eq nil
else
expect(@double.as_null_object.to_a).to eq [@double]
end
end

it "passes proc to expectation block without an argument" do
@double.should_receive(:foo) { |&block| expect(block.call).to eq(:bar) }
@double.foo { :bar }
Expand Down
34 changes: 24 additions & 10 deletions spec/rspec/mocks/to_ary_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,6 @@

describe "a double receiving to_ary" do
shared_examples "to_ary" do
it "returns nil" do
expect do
expect(obj.to_ary).to be_nil
end.to raise_error(NoMethodError)
end

it "doesn't respond" do
expect(obj).not_to respond_to(:to_ary)
end

it "can be overridden with a stub" do
obj.stub(:to_ary) { :non_nil_value }
expect(obj.to_ary).to be(:non_nil_value)
Expand All @@ -31,10 +21,34 @@
context "double as_null_object" do
let(:obj) { double('obj').as_null_object }
include_examples "to_ary"

it "does respond to to_ary" do
expect(obj).to respond_to(:to_ary)
end

it "does respond to to_a" do
expect(obj).to respond_to(:to_a)
end

it "returns nil" do
expect(obj.to_ary).to eq nil
end
end

context "double without as_null_object" do
let(:obj) { double('obj') }
include_examples "to_ary"

it "doesn't respond to to_ary" do
expect(obj).not_to respond_to(:to_ary)
end

it "doesn't respond to to_a", :if => ( RUBY_VERSION.to_f > 1.8 ) do
expect(obj).not_to respond_to(:to_a)
end

it "raises " do
expect { obj.to_ary }.to raise_error(NoMethodError)
end
end
end

0 comments on commit 19d39b7

Please sign in to comment.