Skip to content

Commit

Permalink
preventing negative usage of receive_messages
Browse files Browse the repository at this point in the history
  • Loading branch information
JonRowe committed Aug 19, 2013
1 parent b7e3ada commit d01dc11
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 8 deletions.
7 changes: 7 additions & 0 deletions lib/rspec/mocks/matchers/receive_messages.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ def setup_expectation(subject, &block)
end
alias matches? setup_expectation

def setup_negative_expectation(subject, &block)
raise NegationUnsupportedError,
"`expect(...).to_not receive_messages` is not supported since it " +
"doesn't really make sense. What would it even mean?"
end
alias does_not_match? setup_negative_expectation

def setup_allowance(subject)
each_message_on( proxy_on(subject) ) do |host, message, return_value|
host.add_simple_stub(message, return_value)
Expand Down
30 changes: 22 additions & 8 deletions lib/rspec/mocks/targets.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,24 @@ def initialize(target)
@target = target
end

def self.delegate_to(matcher_method, options = {})
method_name = options.fetch(:from) { :to }
define_method(method_name) do |matcher, &block|
def self.delegate_to(matcher_method)
define_method(:to) do |matcher, &block|
unless Matchers::Receive === matcher || Matchers::ReceiveMessages === matcher
raise_unsupported_matcher(:to, matcher)
end
define_matcher(matcher, matcher_method, &block)
end
end

matcher.__send__(matcher_method, @target, &block)
def self.delegate_not_to(matcher_method, options = {})
method_name = options.fetch(:from)
define_method(method_name) do |matcher, &block|
case matcher
when Matchers::Receive then define_matcher(matcher, matcher_method, &block)
when Matchers::ReceiveMessages then raise_negation_unsupported(method_name, matcher)
else
raise_unsupported_matcher(method_name, matcher)
end
end
end

Expand All @@ -27,6 +37,10 @@ def self.disallow_negation(method_name)

private

def define_matcher(matcher, name, &block)
matcher.__send__(name, @target, &block)
end

def raise_unsupported_matcher(method_name, matcher)
raise UnsupportedMatcherError,
"only the `receive` or `receive_messages` matchers are supported " +
Expand Down Expand Up @@ -54,8 +68,8 @@ class AllowanceTarget < TargetBase
class ExpectationTarget < TargetBase
EXPRESSION = :expect
delegate_to :setup_expectation
delegate_to :setup_negative_expectation, :from => :not_to
delegate_to :setup_negative_expectation, :from => :to_not
delegate_not_to :setup_negative_expectation, :from => :not_to
delegate_not_to :setup_negative_expectation, :from => :to_not
end

class AnyInstanceAllowanceTarget < TargetBase
Expand All @@ -68,8 +82,8 @@ class AnyInstanceAllowanceTarget < TargetBase
class AnyInstanceExpectationTarget < TargetBase
EXPRESSION = :expect_any_instance_of
delegate_to :setup_any_instance_expectation
delegate_to :setup_any_instance_negative_expectation, :from => :not_to
delegate_to :setup_any_instance_negative_expectation, :from => :to_not
delegate_not_to :setup_any_instance_negative_expectation, :from => :not_to
delegate_not_to :setup_any_instance_negative_expectation, :from => :to_not
end
end
end
Expand Down
29 changes: 29 additions & 0 deletions spec/rspec/mocks/matchers/receive_messages_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -87,5 +87,34 @@ module Mocks
}.to raise_error "Implementation blocks aren't supported with `receive_messages`"
end
end

describe "negative expectation failure" do
let(:obj) { Object.new }

specify "allow(...).to_not receive_messages(:a => 1, :b => 2)" do
expect { allow(obj).to_not receive_messages(:a => 1, :b => 2) }.to(
raise_error "`allow(...).to_not receive_messages` is not supported "+
"since it doesn't really make sense. What would it even mean?"
)
end
specify "allow_any_instance_of(...).to_not receive_messages(:a => 1, :b => 2)" do
expect { allow_any_instance_of(obj).to_not receive_messages(:a => 1, :b => 2) }.to(
raise_error "`allow_any_instance_of(...).to_not receive_messages` is not supported "+
"since it doesn't really make sense. What would it even mean?"
)
end
specify "expect(...).to_not receive_messages(:a => 1, :b => 2)" do
expect { expect(obj).to_not receive_messages(:a => 1, :b => 2) }.to(
raise_error "`expect(...).to_not receive_messages` is not supported "+
"since it doesn't really make sense. What would it even mean?"
)
end
specify "expect_any_instance_of(...).to_not receive_messages(:a => 1, :b => 2)" do
expect { expect_any_instance_of(obj).to_not receive_messages(:a => 1, :b => 2) }.to(
raise_error "`expect_any_instance_of(...).to_not receive_messages` is not supported "+
"since it doesn't really make sense. What would it even mean?"
)
end
end
end
end

0 comments on commit d01dc11

Please sign in to comment.