Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Generate documentation using YARD instead of RDoc.

- YARD allows for much richer documentation.
- It looks prettier too.
- I hope to remove the dependencies on rdoc & coderay.
  • Loading branch information...
commit 4e28497a0df59b86537cdc689ef3cd11ea6c7c3e 1 parent 5753a8a
@floehopper authored
Showing with 1,070 additions and 663 deletions.
  1. +1 −1  COPYING.rdoc
  2. +4 −4 README.rdoc
  3. +22 −21 Rakefile
  4. +120 −106 lib/mocha/api.rb
  5. +46 −37 lib/mocha/configuration.rb
  6. +173 −77 lib/mocha/expectation.rb
  7. +84 −55 lib/mocha/mock.rb
  8. +92 −75 lib/mocha/object.rb
  9. +3 −3 lib/mocha/parameter_matchers.rb
  10. +22 −12 lib/mocha/parameter_matchers/all_of.rb
  11. +23 −12 lib/mocha/parameter_matchers/any_of.rb
  12. +15 −8 lib/mocha/parameter_matchers/any_parameters.rb
  13. +20 −11 lib/mocha/parameter_matchers/anything.rb
  14. +34 −26 lib/mocha/parameter_matchers/base.rb
  15. +23 −12 lib/mocha/parameter_matchers/equals.rb
  16. +22 −12 lib/mocha/parameter_matchers/has_entries.rb
  17. +31 −13 lib/mocha/parameter_matchers/has_entry.rb
  18. +21 −11 lib/mocha/parameter_matchers/has_key.rb
  19. +21 −11 lib/mocha/parameter_matchers/has_value.rb
  20. +14 −4 lib/mocha/parameter_matchers/includes.rb
  21. +23 −12 lib/mocha/parameter_matchers/instance_of.rb
  22. +23 −12 lib/mocha/parameter_matchers/is_a.rb
  23. +23 −12 lib/mocha/parameter_matchers/kind_of.rb
  24. +22 −12 lib/mocha/parameter_matchers/not.rb
  25. +5 −3 lib/mocha/parameter_matchers/object.rb
  26. +24 −12 lib/mocha/parameter_matchers/optionally.rb
  27. +14 −3 lib/mocha/parameter_matchers/query_string.rb
  28. +20 −10 lib/mocha/parameter_matchers/regexp_matches.rb
  29. +17 −6 lib/mocha/parameter_matchers/responds_with.rb
  30. +16 −6 lib/mocha/parameter_matchers/yaml_equivalent.rb
  31. +23 −14 lib/mocha/sequence.rb
  32. +61 −46 lib/mocha/state_machine.rb
  33. +5 −4 lib/mocha/stubbing_error.rb
  34. +3 −0  mocha.gemspec
View
2  COPYING.rdoc
@@ -1,3 +1,3 @@
Copyright Revieworld Ltd. 2006
-You may use, copy and redistribute this library under the same terms as {Ruby itself}[http://www.ruby-lang.org/en/LICENSE.txt] or under the {MIT license}[/files/MIT-LICENSE.rdoc.html].
+You may use, copy and redistribute this library under the same terms as {Ruby itself}[http://www.ruby-lang.org/en/LICENSE.txt] or under the {file:MIT-LICENSE.rdoc MIT license}.
View
8 README.rdoc
@@ -36,9 +36,9 @@ Note that versions 0.9.6 & 0.9.7 of the Rails plugin were broken. As of version
== Examples
-* Quick Start - {Usage Examples}[/examples/misc.html]
-* Traditional mocking - {Star Trek Example}[/examples/mocha.html]
-* Setting expectations on real classes - {Order Example}[/examples/stubba.html]
+* Quick Start - {file:misc.rb Usage Examples}
+* Traditional mocking - {file:mocha.rb Star Trek Example}
+* Setting expectations on real classes - {file:stubba.rb Order Example}
* More examples on {James Mead's Blog}[http://jamesmead.org/blog/]
* {Mailing List Archives}[http://groups.google.com/group/mocha-developer]
@@ -51,4 +51,4 @@ Note that versions 0.9.6 & 0.9.7 of the Rails plugin were broken. As of version
Copyright Revieworld Ltd. 2006
-You may use, copy and redistribute this library under the same terms as {Ruby itself}[http://www.ruby-lang.org/en/LICENSE.txt] or under the {MIT license}[/files/MIT-LICENSE.rdoc.html].
+You may use, copy and redistribute this library under the same terms as {Ruby itself}[http://www.ruby-lang.org/en/LICENSE.txt] or under the {file:MIT-LICENSE.rdoc MIT license}.
View
43 Rakefile
@@ -2,7 +2,7 @@ require "bundler"
Bundler::GemHelper.install_tasks
require "bundler/setup"
-require 'rdoc/task'
+require 'yard'
require 'rake/testtask'
desc "Run all tests"
@@ -81,23 +81,15 @@ def benchmark_test_case(klass, iterations)
end
end
-desc 'Generate RDoc'
-Rake::RDocTask.new('rdoc') do |task|
- task.generator = 'hanna'
- task.main = 'README.rdoc'
- task.title = "Mocha #{Mocha::VERSION}"
- task.rdoc_dir = 'doc'
- template = File.expand_path(File.join(File.dirname(__FILE__), "templates", "html_with_google_analytics.rb"))
- if File.exist?(template)
- puts "*** Using RDoc template incorporating Google Analytics"
- task.template = template
- end
- task.rdoc_files.include(
- 'README.rdoc',
- 'RELEASE.rdoc',
- 'COPYING.rdoc',
- 'MIT-LICENSE.rdoc',
- 'agiledox.txt',
+desc 'Remove generated documentation'
+task 'clobber_yardoc' do
+ `rm -rf ./doc`
+end
+
+desc 'Generate documentation'
+YARD::Rake::YardocTask.new('yardoc') do |task|
+ task.options = ["--title", "Mocha #{Mocha::VERSION}", "--no-private"]
+ task.files = [
'lib/mocha/api.rb',
'lib/mocha/mock.rb',
'lib/mocha/expectation.rb',
@@ -105,13 +97,22 @@ Rake::RDocTask.new('rdoc') do |task|
'lib/mocha/parameter_matchers.rb',
'lib/mocha/parameter_matchers',
'lib/mocha/state_machine.rb',
+ 'lib/mocha/sequence.rb',
'lib/mocha/configuration.rb',
- 'lib/mocha/stubbing_error.rb'
- )
+ 'lib/mocha/stubbing_error.rb',
+ '-',
+ 'RELEASE.rdoc',
+ 'COPYING.rdoc',
+ 'MIT-LICENSE.rdoc',
+ 'agiledox.txt',
+ 'examples/mocha.rb',
+ 'examples/stubba.rb',
+ 'examples/misc.rb',
+ ]
end
desc "Generate documentation"
-task 'generate_docs' => ['clobber_rdoc', 'rdoc', 'examples', 'agiledox.txt']
+task 'generate_docs' => ['clobber_yardoc', 'agiledox.txt', 'yardoc']
desc "Publish docs to Github (relies on running 'generate_docs' task and committing changes to master branch)"
task 'publish_docs' do
View
226 lib/mocha/api.rb
@@ -2,40 +2,40 @@
require 'mocha/mockery'
require 'mocha/sequence'
-module Mocha # :nodoc:
-
- # Methods added to Test::Unit::TestCase or equivalent.
+module Mocha
+
+ # Methods added to +Test::Unit::TestCase+ or equivalent.
module API
-
+
include ParameterMatchers
-
- # :call-seq: mock(name, &block) -> mock object
- # mock(expected_methods = {}, &block) -> mock object
- # mock(name, expected_methods = {}, &block) -> mock object
- #
- # Creates a mock object.
- #
- # +name+ is a +String+ identifier for the mock object.
- #
- # +expected_methods+ is a +Hash+ with expected method name symbols as keys and corresponding return values as values.
- #
- # Note that (contrary to expectations set up by #stub) these expectations <b>must</b> be fulfilled during the test.
- # def test_product
- # product = mock('ipod_product', :manufacturer => 'ipod', :price => 100)
- # assert_equal 'ipod', product.manufacturer
- # assert_equal 100, product.price
- # # an error will be raised unless both Product#manufacturer and Product#price have been called
- # end
- #
- # +block+ is an optional block to be evaluated against the mock object instance, giving an alernative way to set up expectations & stubs.
- # def test_product
- # product = mock('ipod_product') do
- # expects(:manufacturer).returns('ipod')
- # expects(:price).returns(100)
+
+ # Builds a new mock object
+ #
+ # @param [String] name identifies mock object in error messages.
+ # @param [Hash] expected_methods_vs_return_values expected method name symbols as keys and corresponding return values as values - these expectations are setup as if {Mock#expects} were called multiple times.
+ # @yield optional block to be evaluated against the mock object instance, giving an alternative way to setup expectations.
+ # @return [Mock] a new mock object
+ #
+ # @overload def mock(name, &block)
+ # @overload def mock(expected_methods_vs_return_values = {}, &block)
+ # @overload def mock(name, expected_methods_vs_return_values = {}, &block)
+ #
+ # @example Using expected_methods_vs_return_values Hash to setup expectations.
+ # def test_motor_starts_and_stops
+ # motor = mock('motor', :start => true, :stop => true)
+ # assert motor.start
+ # assert motor.stop
+ # # an error will be raised unless both Motor#start and Motor#stop have been called
+ # end
+ # @example Using the optional block to setup expectations & stubbed methods.
+ # def test_motor_starts_and_stops
+ # motor = mock('motor') do
+ # expects(:start).with(100.rpm).returns(true)
+ # stubs(:stop).returns(true)
# end
- # assert_equal 'ipod', product.manufacturer
- # assert_equal 100, product.price
- # # an error will be raised unless both Product#manufacturer and Product#price have been called
+ # assert motor.start(100.rpm)
+ # assert motor.stop
+ # # an error will only be raised if Motor#start(100.rpm) has not been called
# end
def mock(*arguments, &block)
name = arguments.shift if arguments.first.is_a?(String)
@@ -44,34 +44,36 @@ def mock(*arguments, &block)
mock.expects(expectations)
mock
end
-
- # :call-seq: stub(name, &block) -> mock object
- # stub(stubbed_methods = {}, &block) -> mock object
- # stub(name, stubbed_methods = {}, &block) -> mock object
- #
- # Creates a mock object.
- #
- # +name+ is a +String+ identifier for the mock object.
- #
- # +stubbed_methods+ is a +Hash+ with stubbed method name symbols as keys and corresponding return values as values.
- # Note that (contrary to expectations set up by #mock) these expectations <b>need not</b> be fulfilled during the test.
- # def test_product
- # product = stub('ipod_product', :manufacturer => 'ipod', :price => 100)
- # assert_equal 'ipod', product.manufacturer
- # assert_equal 100, product.price
- # # an error will not be raised even if Product#manufacturer and Product#price have not been called
+
+ # Builds a new mock object
+ #
+ # @param [String] name identifies mock object in error messages.
+ # @param [Hash] stubbed_methods_vs_return_values stubbed method name symbols as keys and corresponding return values as values - these stubbed methods are setup as if {Mock#stubs} were called multiple times.
+ # @yield optional block to be evaluated against the mock object instance, giving an alternative way to setup stubbed methods.
+ # @return [Mock] a new mock object
+ #
+ # @overload def stub(name, &block)
+ # @overload def stub(stubbed_methods_vs_return_values = {}, &block)
+ # @overload def stub(name, stubbed_methods_vs_return_values = {}, &block)
+ #
+ # @example Using stubbed_methods_vs_return_values Hash to setup stubbed methods.
+ # def test_motor_starts_and_stops
+ # motor = mock('motor', :start => true, :stop => true)
+ # assert motor.start
+ # assert motor.stop
+ # # an error will not be raised even if either Motor#start or Motor#stop has not been called
# end
#
- # +block+ is an optional block to be evaluated against the mock object instance, giving an alernative way to set up expectations & stubs.
- # def test_product
- # product = stub('ipod_product') do
- # stubs(:manufacturer).returns('ipod')
- # stubs(:price).returns(100)
+ # @example Using the optional block to setup expectations & stubbed methods.
+ # def test_motor_starts_and_stops
+ # motor = mock('motor') do
+ # expects(:start).with(100.rpm).returns(true)
+ # stubs(:stop).returns(true)
# end
- # assert_equal 'ipod', product.manufacturer
- # assert_equal 100, product.price
- # # an error will not be raised even if Product#manufacturer and Product#price have not been called
- # end
+ # assert motor.start(100.rpm)
+ # assert motor.stop
+ # # an error will only be raised if Motor#start(100.rpm) has not been called
+ # end
def stub(*arguments, &block)
name = arguments.shift if arguments.first.is_a?(String)
expectations = arguments.shift || {}
@@ -79,23 +81,24 @@ def stub(*arguments, &block)
stub.stubs(expectations)
stub
end
-
- # :call-seq: stub_everything(name, &block) -> mock object
- # stub_everything(stubbed_methods = {}, &block) -> mock object
- # stub_everything(name, stubbed_methods = {}, &block) -> mock object
- #
- # Creates a mock object that accepts calls to any method.
- #
- # By default it will return +nil+ for any method call.
- #
- # +block+ is a block to be evaluated against the mock object instance, giving an alernative way to set up expectations & stubs.
- #
- # +name+ and +stubbed_methods+ work in the same way as for #stub.
- # def test_product
- # product = stub_everything('ipod_product', :price => 100)
- # assert_nil product.manufacturer
- # assert_nil product.any_old_method
- # assert_equal 100, product.price
+
+ # Builds a mock object that accepts calls to any method. By default it will return +nil+ for any method call.
+ #
+ # @param [String] name identifies mock object in error messages.
+ # @param [Hash] stubbed_methods_vs_return_values stubbed method name symbols as keys and corresponding return values as values - these stubbed methods are setup as if {Mock#stubs} were called multiple times.
+ # @yield optional block to be evaluated against the mock object instance, giving an alternative way to setup stubbed methods.
+ # @return [Mock] a new mock object
+ #
+ # @overload def stub_everything(name, &block)
+ # @overload def stub_everything(stubbed_methods_vs_return_values = {}, &block)
+ # @overload def stub_everything(name, stubbed_methods_vs_return_values = {}, &block)
+ #
+ # @example Ignore invocations of irrelevant methods.
+ # def test_motor_stops
+ # motor = stub_everything('motor', :stop => true)
+ # assert_nil motor.irrelevant_method_1 # => no error raised
+ # assert_nil motor.irrelevant_method_2 # => no error raised
+ # assert motor.stop
# end
def stub_everything(*arguments, &block)
name = arguments.shift if arguments.first.is_a?(String)
@@ -105,69 +108,80 @@ def stub_everything(*arguments, &block)
stub.stubs(expectations)
stub
end
-
- # :call-seq: sequence(name) -> sequence
+
+ # Builds a new sequence which can be used to constrain the order in which expectations can occur.
#
- # Returns a new sequence that is used to constrain the order in which expectations can occur.
+ # Specify that an expected invocation must occur within a named {Sequence} by using {Expectation#in_sequence}.
#
- # Specify that an expected invocation must occur in within a named +sequence+ by using Expectation#in_sequence.
+ # @return [Sequence] a new sequence
#
- # See also Expectation#in_sequence.
+ # @see Expectation#in_sequence
+ #
+ # @example Ensure methods on egg are invoked in correct order.
# breakfast = sequence('breakfast')
#
- # egg = mock('egg')
- # egg.expects(:crack).in_sequence(breakfast)
- # egg.expects(:fry).in_sequence(breakfast)
- # egg.expects(:eat).in_sequence(breakfast)
+ # egg = mock('egg') do
+ # expects(:crack).in_sequence(breakfast)
+ # expects(:fry).in_sequence(breakfast)
+ # expects(:eat).in_sequence(breakfast)
+ # end
def sequence(name)
Sequence.new(name)
end
-
- # :call-seq: states(name) -> state_machine
+
+ # Builds a new state machine which can be used to constrain the order in which expectations can occur.
#
- # Returns a new +state_machine+ that is used to constrain the order in which expectations can occur.
+ # Specify the initial state of the state machine by using {StateMachine#starts_as}.
#
- # Specify the initial +state+ of the +state_machine+ by using StateMachine#starts_as.
+ # Specify that an expected invocation should change the state of the state machine by using {Expectation#then}.
#
- # Specify that an expected invocation should change the +state+ of the +state_machine+ by using Expectation#then.
+ # Specify that an expected invocation should be constrained to occur within a particular +state+ by using {Expectation#when}.
#
- # Specify that an expected invocation should be constrained to occur within a particular +state+ by using Expectation#when.
+ # A test can contain multiple state machines.
#
- # A test can contain multiple +state_machines+.
+ # @return [StateMachine] a new state machine
#
- # See also Expectation#then, Expectation#when and StateMachine.
+ # @see Expectation#then
+ # @see Expectation#when
+ # @see StateMachine
+ # @example Constrain expected invocations to occur in particular states.
# power = states('power').starts_as('off')
#
- # radio = mock('radio')
- # radio.expects(:switch_on).then(power.is('on'))
- # radio.expects(:select_channel).with('BBC Radio 4').when(power.is('on'))
- # radio.expects(:adjust_volume).with(+5).when(power.is('on'))
- # radio.expects(:select_channel).with('BBC World Service').when(power.is('on'))
- # radio.expects(:adjust_volume).with(-5).when(power.is('on'))
- # radio.expects(:switch_off).then(power.is('off'))
+ # radio = mock('radio') do
+ # expects(:switch_on).then(power.is('on'))
+ # expects(:select_channel).with('BBC Radio 4').when(power.is('on'))
+ # expects(:adjust_volume).with(+5).when(power.is('on'))
+ # expects(:select_channel).with('BBC World Service').when(power.is('on'))
+ # expects(:adjust_volume).with(-5).when(power.is('on'))
+ # expects(:switch_off).then(power.is('off'))
+ # end
def states(name)
Mockery.instance.new_state_machine(name)
end
-
- def mocha_setup # :nodoc:
+
+ # @private
+ def mocha_setup
end
-
- def mocha_verify(assertion_counter = nil) # :nodoc:
+
+ # @private
+ def mocha_verify(assertion_counter = nil)
Mockery.instance.verify(assertion_counter)
end
-
- def mocha_teardown # :nodoc:
+
+ # @private
+ def mocha_teardown
Mockery.instance.teardown
Mockery.reset_instance
end
-
+
end
-
+
+ # @private
def self.const_missing(name)
return super unless name == :Standalone
require 'mocha/deprecation'
Deprecation.warning "Mocha::Standalone has been renamed to Mocha::API"
return API
end
-
+
end
View
83 lib/mocha/configuration.rb
@@ -1,62 +1,70 @@
-module Mocha # :nodoc:
-
- # Configuration settings
+module Mocha
+
+ # Configuration settings.
class Configuration
-
- DEFAULTS = { :stubbing_method_unnecessarily => :allow, :stubbing_method_on_non_mock_object => :allow, :stubbing_non_existent_method => :allow, :stubbing_non_public_method => :allow }
-
+
+ DEFAULTS = {
+ :stubbing_method_unnecessarily => :allow,
+ :stubbing_method_on_non_mock_object => :allow,
+ :stubbing_non_existent_method => :allow,
+ :stubbing_non_public_method => :allow
+ }
+
class << self
-
- # :call-seq: allow(action, &block)
+
+ # Allow the specified +action+.
#
- # Allow the specified <tt>action</tt> (as a symbol).
- # The <tt>actions</tt> currently available are <tt>:stubbing_method_unnecessarily, :stubbing_method_on_non_mock_object, :stubbing_non_existent_method, :stubbing_non_public_method</tt>.
- # If given a block, the configuration for the action will only be changed for the duration of the block, and will then be restored to the previous value.
+ # @param [Symbol] action one of +:stubbing_method_unnecessarily+, +:stubbing_method_on_non_mock_object+, +:stubbing_non_existent_method+, +:stubbing_non_public_method+.
+ # @yield optional block during which the configuration change will be changed before being returned to its original value at the end of the block.
def allow(action, &block)
change_config action, :allow, &block
end
-
- def allow?(action) # :nodoc:
+
+ # @private
+ def allow?(action)
configuration[action] == :allow
end
-
- # :call-seq: warn_when(action, &block)
+
+ # Warn if the specified +action+ is attempted.
#
- # Warn if the specified <tt>action</tt> (as a symbol) is attempted.
- # The <tt>actions</tt> currently available are <tt>:stubbing_method_unnecessarily, :stubbing_method_on_non_mock_object, :stubbing_non_existent_method, :stubbing_non_public_method</tt>.
- # If given a block, the configuration for the action will only be changed for the duration of the block, and will then be restored to the previous value.
+ # @param [Symbol] action one of +:stubbing_method_unnecessarily+, +:stubbing_method_on_non_mock_object+, +:stubbing_non_existent_method+, +:stubbing_non_public_method+.
+ # @yield optional block during which the configuration change will be changed before being returned to its original value at the end of the block.
def warn_when(action, &block)
change_config action, :warn, &block
end
-
- def warn_when?(action) # :nodoc:
+
+ # @private
+ def warn_when?(action)
configuration[action] == :warn
end
-
- # :call-seq: prevent(action, &block)
+
+ # Raise a {StubbingError} if if the specified +action+ is attempted.
#
- # Raise a StubbingError if the specified <tt>action</tt> (as a symbol) is attempted.
- # The <tt>actions</tt> currently available are <tt>:stubbing_method_unnecessarily, :stubbing_method_on_non_mock_object, :stubbing_non_existent_method, :stubbing_non_public_method</tt>.
- # If given a block, the configuration for the action will only be changed for the duration of the block, and will then be restored to the previous value.
+ # @param [Symbol] action one of +:stubbing_method_unnecessarily+, +:stubbing_method_on_non_mock_object+, +:stubbing_non_existent_method+, +:stubbing_non_public_method+.
+ # @yield optional block during which the configuration change will be changed before being returned to its original value at the end of the block.
def prevent(action, &block)
change_config action, :prevent, &block
end
-
- def prevent?(action) # :nodoc:
+
+ # @private
+ def prevent?(action)
configuration[action] == :prevent
end
-
- def reset_configuration # :nodoc:
+
+ # @private
+ def reset_configuration
@configuration = nil
end
-
+
private
-
- def configuration # :nodoc:
+
+ # @private
+ def configuration
@configuration ||= DEFAULTS.dup
end
- def change_config(action, new_value, &block) # :nodoc:
+ # @private
+ def change_config(action, new_value, &block)
if block_given?
temporarily_change_config action, new_value, &block
else
@@ -64,16 +72,17 @@ def change_config(action, new_value, &block) # :nodoc:
end
end
- def temporarily_change_config(action, new_value, &block) # :nodoc:
+ # @private
+ def temporarily_change_config(action, new_value, &block)
original_value = configuration[action]
configuration[action] = new_value
yield
ensure
configuration[action] = original_value
end
-
+
end
-
+
end
-
+
end
View
250 lib/mocha/expectation.rb
@@ -10,16 +10,17 @@
require 'mocha/change_state_side_effect'
require 'mocha/cardinality'
-module Mocha # :nodoc:
+module Mocha
- # Methods on expectations returned from Mock#expects, Mock#stubs, Object#expects and Object#stubs.
+ # Methods on expectations returned from {Mock#expects}, {Mock#stubs}, {ObjectMethods#expects} and {ObjectMethods#stubs}.
class Expectation
- # :call-seq: times(range) -> expectation
- #
# Modifies expectation so that the number of calls to the expected method must be within a specific +range+.
#
- # +range+ can be specified as an exact integer or as a range of integers
+ # @param [Range,Integer] range specifies the allowable range in the number of expected invocations.
+ # @return [Expectation] the same expectation, thereby allowing invocations of other {Expectation} methods to be chained.
+ #
+ # @example Specifying a specific number of expected invocations.
# object = mock()
# object.expects(:expected_method).times(3)
# 3.times { object.expected_method }
@@ -30,6 +31,7 @@ class Expectation
# 2.times { object.expected_method }
# # => verify fails
#
+ # @example Specifying a range in the number of expected invocations.
# object = mock()
# object.expects(:expected_method).times(2..4)
# 3.times { object.expected_method }
@@ -44,9 +46,11 @@ def times(range)
self
end
- # :call-seq: twice() -> expectation
- #
# Modifies expectation so that the expected method must be called exactly twice.
+ #
+ # @return [Expectation] the same expectation, thereby allowing invocations of other {Expectation} methods to be chained.
+ #
+ # @example Expected method must be invoked exactly twice.
# object = mock()
# object.expects(:expected_method).twice
# object.expected_method
@@ -57,8 +61,7 @@ def times(range)
# object.expects(:expected_method).twice
# object.expected_method
# object.expected_method
- # object.expected_method
- # # => verify fails
+ # object.expected_method # => unexpected invocation
#
# object = mock()
# object.expects(:expected_method).twice
@@ -69,10 +72,13 @@ def twice
self
end
- # :call-seq: once() -> expectation
- #
# Modifies expectation so that the expected method must be called exactly once.
+ #
# Note that this is the default behaviour for an expectation, but you may wish to use it for clarity/emphasis.
+ #
+ # @return [Expectation] the same expectation, thereby allowing invocations of other {Expectation} methods to be chained.
+ #
+ # @example Expected method must be invoked exactly once.
# object = mock()
# object.expects(:expected_method).once
# object.expected_method
@@ -81,8 +87,7 @@ def twice
# object = mock()
# object.expects(:expected_method).once
# object.expected_method
- # object.expected_method
- # # => verify fails
+ # object.expected_method # => unexpected invocation
#
# object = mock()
# object.expects(:expected_method).once
@@ -92,13 +97,14 @@ def once
self
end
- # :call-seq: never() -> expectation
- #
# Modifies expectation so that the expected method must never be called.
+ #
+ # @return [Expectation] the same expectation, thereby allowing invocations of other {Expectation} methods to be chained.
+ #
+ # @example Expected method must never be called.
# object = mock()
# object.expects(:expected_method).never
- # object.expected_method
- # # => verify fails
+ # object.expected_method # => unexpected invocation
#
# object = mock()
# object.expects(:expected_method).never
@@ -108,9 +114,12 @@ def never
self
end
- # :call-seq: at_least(minimum_number_of_times) -> expectation
- #
# Modifies expectation so that the expected method must be called at least a +minimum_number_of_times+.
+ #
+ # @param [Integer] minimum_number_of_times minimum number of expected invocations.
+ # @return [Expectation] the same expectation, thereby allowing invocations of other {Expectation} methods to be chained.
+ #
+ # @example Expected method must be called at least twice.
# object = mock()
# object.expects(:expected_method).at_least(2)
# 3.times { object.expected_method }
@@ -125,9 +134,11 @@ def at_least(minimum_number_of_times)
self
end
- # :call-seq: at_least_once() -> expectation
- #
# Modifies expectation so that the expected method must be called at least once.
+ #
+ # @return [Expectation] the same expectation, thereby allowing invocations of other {Expectation} methods to be chained.
+ #
+ # @example Expected method must be called at least once.
# object = mock()
# object.expects(:expected_method).at_least_once
# object.expected_method
@@ -141,9 +152,12 @@ def at_least_once
self
end
- # :call-seq: at_most(maximum_number_of_times) -> expectation
- #
# Modifies expectation so that the expected method must be called at most a +maximum_number_of_times+.
+ #
+ # @param [Integer] maximum_number_of_times maximum number of expected invocations.
+ # @return [Expectation] the same expectation, thereby allowing invocations of other {Expectation} methods to be chained.
+ #
+ # @example Expected method must be called at most twice.
# object = mock()
# object.expects(:expected_method).at_most(2)
# 2.times { object.expected_method }
@@ -151,16 +165,17 @@ def at_least_once
#
# object = mock()
# object.expects(:expected_method).at_most(2)
- # 3.times { object.expected_method }
- # # => verify fails
+ # 3.times { object.expected_method } # => unexpected invocation
def at_most(maximum_number_of_times)
@cardinality = Cardinality.at_most(maximum_number_of_times)
self
end
- # :call-seq: at_most_once() -> expectation
- #
# Modifies expectation so that the expected method must be called at most once.
+ #
+ # @return [Expectation] the same expectation, thereby allowing invocations of other {Expectation} methods to be chained.
+ #
+ # @example Expected method must be called at most once.
# object = mock()
# object.expects(:expected_method).at_most_once
# object.expected_method
@@ -168,16 +183,23 @@ def at_most(maximum_number_of_times)
#
# object = mock()
# object.expects(:expected_method).at_most_once
- # 2.times { object.expected_method }
- # # => verify fails
+ # 2.times { object.expected_method } # => unexpected invocation
def at_most_once()
at_most(1)
self
end
- # :call-seq: with(*expected_parameters, &matching_block) -> expectation
- #
# Modifies expectation so that the expected method must be called with +expected_parameters+.
+ #
+ # May be used with parameter matchers in {ParameterMatchers}.
+ #
+ # @param [*Array] expected_parameters parameters expected.
+ # @yield optional block specifying custom matching.
+ # @yieldparam [*Array] actual_parameters parameters with which expected method was invoked.
+ # @yieldreturn [Boolean] +true+ if +actual_parameters+ are acceptable.
+ # @return [Expectation] the same expectation, thereby allowing invocations of other {Expectation} methods to be chained.
+ #
+ # @example Expected method must be called with expected parameters.
# object = mock()
# object.expects(:expected_method).with(:param1, :param2)
# object.expected_method(:param1, :param2)
@@ -187,10 +209,8 @@ def at_most_once()
# object.expects(:expected_method).with(:param1, :param2)
# object.expected_method(:param3)
# # => verify fails
- # May be used with parameter matchers in Mocha::ParameterMatchers.
#
- # If a +matching_block+ is given, the block is called with the parameters passed to the expected method.
- # The expectation is matched if the block evaluates to +true+.
+ # @example Expected method must be called with a value divisible by 4.
# object = mock()
# object.expects(:expected_method).with() { |value| value % 4 == 0 }
# object.expected_method(16)
@@ -205,15 +225,22 @@ def with(*expected_parameters, &matching_block)
self
end
- # :call-seq: yields(*parameters) -> expectation
- #
# Modifies expectation so that when the expected method is called, it yields with the specified +parameters+.
+ #
+ # May be called multiple times on the same expectation for consecutive invocations.
+ #
+ # @param [*Array] parameters parameters to be yielded.
+ # @return [Expectation] the same expectation, thereby allowing invocations of other {Expectation} methods to be chained.
+ # @see #then
+ #
+ # @example Yield parameters when expected method is invoked.
# object = mock()
# object.expects(:expected_method).yields('result')
# yielded_value = nil
# object.expected_method { |value| yielded_value = value }
# yielded_value # => 'result'
- # May be called multiple times on the same expectation for consecutive invocations. Also see Expectation#then.
+ #
+ # @example Yield different parameters on different invocations of the expected method.
# object = mock()
# object.stubs(:expected_method).yields(1).then.yields(2)
# yielded_values_from_first_invocation = []
@@ -227,18 +254,20 @@ def yields(*parameters)
self
end
- # :call-seq: multiple_yields(*parameter_groups) -> expectation
- #
# Modifies expectation so that when the expected method is called, it yields multiple times per invocation with the specified +parameter_groups+.
#
- # Note that each +parameter_group+ should be an Array representing the parameters to be passed to the block for a single yield. In the following example when the expected_method is called, the stub will invoke the block twice, the first time it passes 'result_1', 'result_2' as the parameters, and the second time it passes 'result_3' as the parameters.
+ # @param [*Array<Array>] parameter_groups each element of +parameter_groups+ should iself be an +Array+ representing the parameters to be passed to the block for a single yield.
+ # @return [Expectation] the same expectation, thereby allowing invocations of other {Expectation} methods to be chained.
+ # @see #then
#
+ # @example When the +expected_method+ is called, the stub will invoke the block twice, the first time it passes +'result_1'+, +'result_2'+ as the parameters, and the second time it passes 'result_3' as the parameters.
# object = mock()
# object.expects(:expected_method).multiple_yields(['result_1', 'result_2'], ['result_3'])
# yielded_values = []
# object.expected_method { |*values| yielded_values << values }
# yielded_values # => [['result_1', 'result_2'], ['result_3]]
- # May be called multiple times on the same expectation for consecutive invocations. Also see Expectation#then.
+ #
+ # @example Yield different groups of parameters on different invocations of the expected method.
# object = mock()
# object.stubs(:expected_method).multiple_yields([1, 2], [3]).then.multiple_yields([4], [5, 6])
# yielded_values_from_first_invocation = []
@@ -252,32 +281,43 @@ def multiple_yields(*parameter_groups)
self
end
- # :call-seq: returns(value) -> expectation
- # returns(*values) -> expectation
- #
# Modifies expectation so that when the expected method is called, it returns the specified +value+.
+ #
+ # @return [Expectation] the same expectation, thereby allowing invocations of other {Expectation} methods to be chained.
+ # @see #then
+ #
+ # @overload def returns(value)
+ # @param [Object] value value to return on invocation of expected method.
+ # @overload def returns(*values)
+ # @param [*Array] values values to return on consecutive invocations of expected method.
+ #
+ # @example Return the same value on every invocation.
# object = mock()
# object.stubs(:stubbed_method).returns('result')
# object.stubbed_method # => 'result'
# object.stubbed_method # => 'result'
- # If multiple +values+ are given, these are returned in turn on consecutive calls to the method.
+ #
+ # @example Return a different value on consecutive invocations.
# object = mock()
# object.stubs(:stubbed_method).returns(1, 2)
# object.stubbed_method # => 1
# object.stubbed_method # => 2
- # May be called multiple times on the same expectation. Also see Expectation#then.
+ #
+ # @example Alternative way to return a different value on consecutive invocations.
# object = mock()
# object.stubs(:expected_method).returns(1, 2).then.returns(3)
# object.expected_method # => 1
# object.expected_method # => 2
# object.expected_method # => 3
- # May be called in conjunction with Expectation#raises on the same expectation.
+ #
+ # @example May be called in conjunction with {#raises} on the same expectation.
# object = mock()
# object.stubs(:expected_method).returns(1, 2).then.raises(Exception)
# object.expected_method # => 1
# object.expected_method # => 2
# object.expected_method # => raises exception of class Exception1
- # Note that in Ruby a method returning multiple values is exactly equivalent to a method returning an Array of those values.
+ #
+ # @example Note that in Ruby a method returning multiple values is exactly equivalent to a method returning an +Array+ of those values.
# object = mock()
# object.stubs(:expected_method).returns([1, 2])
# x, y = object.expected_method
@@ -288,22 +328,36 @@ def returns(*values)
self
end
- # :call-seq: raises(exception = RuntimeError, message = nil) -> expectation
+ # Modifies expectation so that when the expected method is called, it raises the specified +exception+ with the specified +message+ i.e. calls +Kernel#raise(exception, message)+.
+ #
+ # @param [Class,Exception,String,#exception] exception exception to be raised or message to be passed to RuntimeError.
+ # @param [String] message exception message.
+ # @return [Expectation] the same expectation, thereby allowing invocations of other {Expectation} methods to be chained.
+ #
+ # @see Kernel#raise
+ # @see #then
#
- # Modifies expectation so that when the expected method is called, it raises the specified +exception+ with the specified +message+ i.e. calls Kernel#raise(exception, message).
+ # @overload def raises
+ # @overload def raises(exception)
+ # @overload def raises(exception, message)
+ #
+ # @example Raise specified exception if expected method is invoked.
# object = stub()
# object.stubs(:expected_method).raises(Exception, 'message')
# object.expected_method # => raises exception of class Exception and with message 'message'
- # Note that if you have a custom exception class with extra constructor parameters, you can pass in an instance of the exception (just as you can for Kernel#raise).
+ #
+ # @example Raise custom exception with extra constructor parameters by passing in an instance of the exception.
# object = stub()
# object.stubs(:expected_method).raises(MyException.new('message', 1, 2, 3))
# object.expected_method # => raises the specified instance of MyException
- # May be called multiple times on the same expectation. Also see Expectation#then.
+ #
+ # @example Raise different exceptions on consecutive invocations of the expected method.
# object = stub()
# object.stubs(:expected_method).raises(Exception1).then.raises(Exception2)
# object.expected_method # => raises exception of class Exception1
# object.expected_method # => raises exception of class Exception2
- # May be called in conjunction with Expectation#returns on the same expectation.
+ #
+ # @example Raise an exception on first invocation of expected method and then return values on subsequent invocations.
# object = stub()
# object.stubs(:expected_method).raises(Exception).then.returns(2, 3)
# object.expected_method # => raises exception of class Exception1
@@ -314,22 +368,35 @@ def raises(exception = RuntimeError, message = nil)
self
end
- # :call-seq: throws(tag, object = nil) -> expectation
+ # Modifies expectation so that when the expected method is called, it throws the specified +tag+ with the specific return value +object+ i.e. calls +Kernel#throw(tag, object)+.
+ #
+ # @param [Symbol,String] tag tag to throw to transfer control to the active catch block.
+ # @param [Object] object return value for the catch block.
+ # @return [Expectation] the same expectation, thereby allowing invocations of other {Expectation} methods to be chained.
#
- # Modifies expectation so that when the expected method is called, it throws the specified +tag+ with the specific return value +object+ i.e. calls Kernel#throw(tag, object).
+ # @see Kernel#throw
+ # @see #then
+ #
+ # @overload def throw(tag)
+ # @overload def throw(tag, object)
+ #
+ # @example Throw tag when expected method is invoked.
# object = stub()
# object.stubs(:expected_method).throws(:done)
# object.expected_method # => throws tag :done
- # Note you can also pass in an optional return value +object+ (just as you can for Kernel#throw).
+ #
+ # @example Throw tag with return value +object+ c.f. +Kernel#throw+.
# object = stub()
# object.stubs(:expected_method).throws(:done, 'result')
# object.expected_method # => throws tag :done and causes catch block to return 'result'
- # May be called multiple times on the same expectation. Also see Expectation#then.
+ #
+ # @example Throw different tags on consecutive invocations of the expected method.
# object = stub()
# object.stubs(:expected_method).throws(:done).then.throws(:continue)
# object.expected_method # => throws :done
# object.expected_method # => throws :continue
- # May be called in conjunction with Expectation#returns on the same expectation.
+ #
+ # @example Throw tag on first invocation of expected method and then return values for subsequent invocations.
# object = stub()
# object.stubs(:expected_method).throws(:done).then.returns(2, 3)
# object.expected_method # => throws :done
@@ -340,10 +407,19 @@ def throws(tag, object = nil)
self
end
- # :call-seq: then() -> expectation
- # then(state_machine.is(state)) -> expectation
+ # @overload def then
+ # Used as syntactic sugar to improve readability. It has no effect on state of the expectation.
+ # @overload def then(state_machine.is(state_name))
+ # Used to change the +state_machine+ to the state specified by +state_name+ when the expected invocation occurs.
+ # @param [StateMachine::State] state_machine.is(state_name) provides a mechanism to change the +state_machine+ into the state specified by +state_name+ when the expected method is invoked.
+ #
+ # @see API#states
+ # @see StateMachine
+ # @see #when
+ #
+ # @return [Expectation] the same expectation, thereby allowing invocations of other {Expectation} methods to be chained.
#
- # <tt>then()</tt> is used as syntactic sugar to improve readability. It has no effect on state of the expectation.
+ # @example Using {#then} as syntactic sugar when specifying values to be returned and exceptions to be raised on consecutive invocations of the expected method.
# object = mock()
# object.stubs(:expected_method).returns(1, 2).then.raises(Exception).then.returns(4)
# object.expected_method # => 1
@@ -351,9 +427,7 @@ def throws(tag, object = nil)
# object.expected_method # => raises exception of class Exception
# object.expected_method # => 4
#
- # <tt>then(state_machine.is(state))</tt> is used to change the +state_machine+ to the specified +state+ when the invocation occurs.
- #
- # See also API#states, StateMachine and Expectation#when.
+ # @example Using {#then} to change the +state+ of a +state_machine+ on the invocation of an expected method.
# power = states('power').starts_as('off')
#
# radio = mock('radio')
@@ -371,11 +445,16 @@ def then(*parameters)
self
end
- # :call-seq: when(state_machine.is(state)) -> exception
+ # Constrains the expectation to occur only when the +state_machine+ is in the state specified by +state_name+.
+ #
+ # @param [StateMachine::StatePredicate] state_machine.is(state_name) provides a mechanism to determine whether the +state_machine+ is in the state specified by +state_name+ when the expected method is invoked.
+ # @return [Expectation] the same expectation, thereby allowing invocations of other {Expectation} methods to be chained.
#
- # Constrains the expectation to occur only when the +state_machine+ is in the named +state+.
+ # @see API#states
+ # @see StateMachine
+ # @see #then
#
- # See also API#states, StateMachine#starts_as and Expectation#then.
+ # @example Using {#when} to only allow invocation of methods when "power" state machine is in the "on" state.
# power = states('power').starts_as('off')
#
# radio = mock('radio')
@@ -390,17 +469,22 @@ def when(state_predicate)
self
end
- # :call-seq: in_sequence(*sequences) -> expectation
+ # Constrains the expectation so that it must be invoked at the current point in the +sequence+.
#
- # Constrains this expectation so that it must be invoked at the current point in the sequence.
+ # To expect a sequence of invocations, write the expectations in order and add the +in_sequence(sequence)+ clause to each one.
#
- # To expect a sequence of invocations, write the expectations in order and add the in_sequence(sequence) clause to each one.
+ # Expectations in a +sequence+ can have any invocation count.
#
- # Expectations in a sequence can have any invocation count.
+ # If an expectation in a sequence is stubbed, rather than expected, it can be skipped in the +sequence+.
#
- # If an expectation in a sequence is stubbed, rather than expected, it can be skipped in the sequence.
+ # An expected method can appear in multiple sequences.
#
- # See also API#sequence.
+ # @param [*Array<Sequence>] sequences sequences in which expected method should appear.
+ # @return [Expectation] the same expectation, thereby allowing invocations of other {Expectation} methods to be chained.
+ #
+ # @see API#sequence
+ #
+ # @example Ensure methods are invoked in a specified order.
# breakfast = sequence('breakfast')
#
# egg = mock('egg')
@@ -412,10 +496,10 @@ def in_sequence(*sequences)
self
end
- # :stopdoc:
-
+ # @private
attr_reader :backtrace
+ # @private
def initialize(mock, expected_method_name, backtrace = nil)
@mock = mock
@method_matcher = MethodMatcher.new(expected_method_name.to_sym)
@@ -428,42 +512,52 @@ def initialize(mock, expected_method_name, backtrace = nil)
@backtrace = backtrace || caller
end
+ # @private
def add_ordering_constraint(ordering_constraint)
@ordering_constraints << ordering_constraint
end
+ # @private
def add_in_sequence_ordering_constraint(sequence)
sequence.constrain_as_next_in_sequence(self)
end
+ # @private
def add_side_effect(side_effect)
@side_effects << side_effect
end
+ # @private
def perform_side_effects
@side_effects.each { |side_effect| side_effect.perform }
end
+ # @private
def in_correct_order?
@ordering_constraints.all? { |ordering_constraint| ordering_constraint.allows_invocation_now? }
end
+ # @private
def matches_method?(method_name)
@method_matcher.match?(method_name)
end
+ # @private
def match?(actual_method_name, *actual_parameters)
@method_matcher.match?(actual_method_name) && @parameters_matcher.match?(actual_parameters) && in_correct_order?
end
+ # @private
def invocations_allowed?
@cardinality.invocations_allowed?(@invocation_count)
end
+ # @private
def satisfied?
@cardinality.satisfied?(@invocation_count)
end
+ # @private
def invoke
@invocation_count += 1
perform_side_effects()
@@ -475,15 +569,18 @@ def invoke
@return_values.next
end
+ # @private
def verified?(assertion_counter = nil)
assertion_counter.increment if assertion_counter && @cardinality.needs_verifying?
@cardinality.verified?(@invocation_count)
end
+ # @private
def used?
@cardinality.used?(@invocation_count)
end
+ # @private
def mocha_inspect
message = "#{@cardinality.mocha_inspect}, "
message << case @invocation_count
@@ -498,12 +595,11 @@ def mocha_inspect
message
end
+ # @private
def method_signature
"#{@mock.mocha_inspect}.#{@method_matcher.mocha_inspect}#{@parameters_matcher.mocha_inspect}"
end
- # :startdoc:
-
end
end
View
139 lib/mocha/mock.rb
@@ -7,37 +7,47 @@
require 'mocha/unexpected_invocation'
require 'mocha/argument_iterator'
-module Mocha # :nodoc:
+module Mocha
# Traditional mock object.
#
- # Methods return an Expectation which can be further modified by methods on Expectation.
+ # All methods return an {Expectation} which can be further modified by methods on {Expectation}.
class Mock
- # :call-seq: expects(method_name) -> expectation
- # expects(method_names_vs_return_values) -> last expectation
+ # Adds an expectation that the specified method must be called exactly once with any parameters.
#
- # Adds an expectation that a method identified by +method_name+ Symbol/String must be called exactly once with any parameters.
- # Returns the new expectation which can be further modified by methods on Expectation.
- # object = mock()
- # object.expects(:method1)
- # object.method1
- # # no error raised
+ # @param [Symbol,String] method_name name of expected method
+ # @param [Hash] expected_methods_vs_return_values expected method name symbols as keys and corresponding return values as values - these expectations are setup as if {#expects} were called multiple times.
#
+ # @overload def expects(method_name)
+ # @overload def expects(expected_methods_vs_return_values)
+ # @return [Expectation] last-built expectation which can be further modified by methods on {Expectation}.
+ #
+ # @example Expected method invoked once so no error raised
# object = mock()
- # object.expects(:method1)
- # # error raised, because method1 not called exactly once
- # If +method_names_vs_return_values+ is a +Hash+, an expectation will be set up for each entry using the key as +method_name+ and value as +return_value+.
+ # object.expects(:expected_method)
+ # object.expected_method
+ #
+ # @example Expected method not invoked so error raised
# object = mock()
- # object.expects(:method1 => :result1, :method2 => :result2)
+ # object.expects(:expected_method)
+ # # error raised when test completes, because expected_method not called exactly once
#
- # # exactly equivalent to
+ # @example Expected method invoked twice so error raised
+ # object = mock()
+ # object.expects(:expected_method)
+ # object.expected_method
+ # object.expected_method # => error raised when expected method invoked second time
#
+ # @example Setup multiple expectations using +expected_methods_vs_return_values+.
# object = mock()
- # object.expects(:method1).returns(:result1)
- # object.expects(:method2).returns(:result2)
+ # object.expects(:expected_method_one => :result_one, :expected_method_two => :result_two)
+ #
+ # # is exactly equivalent to
#
- # Aliased by <tt>\_\_expects\_\_</tt>
+ # object = mock()
+ # object.expects(:expected_method_one).returns(:result_one)
+ # object.expects(:expected_method_two).returns(:result_two)
def expects(method_name_or_hash, backtrace = nil)
iterator = ArgumentIterator.new(method_name_or_hash)
iterator.each { |*args|
@@ -49,27 +59,31 @@ def expects(method_name_or_hash, backtrace = nil)
}
end
- # :call-seq: stubs(method_name) -> expectation
- # stubs(method_names_vs_return_values) -> last expectation
+ # Adds an expectation that the specified method may be called any number of times with any parameters.
#
- # Adds an expectation that a method identified by +method_name+ Symbol/String may be called any number of times with any parameters.
- # Returns the new expectation which can be further modified by methods on Expectation.
+ # @param [Symbol,String] method_name name of stubbed method
+ # @param [Hash] stubbed_methods_vs_return_values stubbed method name symbols as keys and corresponding return values as values - these stubbed methods are setup as if {#stubs} were called multiple times.
+ #
+ # @overload def stubs(method_name)
+ # @overload def stubs(stubbed_methods_vs_return_values)
+ # @return [Expectation] last-built expectation which can be further modified by methods on {Expectation}.
+ #
+ # @example No error raised however many times stubbed method is invoked
# object = mock()
- # object.stubs(:method1)
- # object.method1
- # object.method1
+ # object.stubs(:stubbed_method)
+ # object.stubbed_method
+ # object.stubbed_method
# # no error raised
- # If +method_names_vs_return_values+ is a +Hash+, an expectation will be set up for each entry using the key as +method_name+ and value as +return_value+.
+ #
+ # @example Setup multiple expectations using +stubbed_methods_vs_return_values+.
# object = mock()
- # object.stubs(:method1 => :result1, :method2 => :result2)
+ # object.stubs(:stubbed_method_one => :result_one, :stubbed_method_two => :result_two)
#
- # # exactly equivalent to
+ # # is exactly equivalent to
#
# object = mock()
- # object.stubs(:method1).returns(:result1)
- # object.stubs(:method2).returns(:result2)
- #
- # Aliased by <tt>\_\_stubs\_\_</tt>
+ # object.stubs(:stubbed_method_one).returns(:result_one)
+ # object.stubs(:stubbed_method_two).returns(:result_two)
def stubs(method_name_or_hash, backtrace = nil)
iterator = ArgumentIterator.new(method_name_or_hash)
iterator.each { |*args|
@@ -82,30 +96,30 @@ def stubs(method_name_or_hash, backtrace = nil)
}
end
- # :call-seq: unstub(method_name)
+ # Removes the specified stubbed method (added by calls to {#expects} or {#stubs}) and all expectations associated with it.
#
- # Removes all expectations for method identified by +method_name+.
- # object = mock('mock')
- # object.stubs(:method1).returns(:result1)
- # object.method1 # => :result1
- # object.unstub(:method1)
- # object.method1 # => unexpected invocation: #<Mock:mock>.method1()
+ # @param [Symbol] method_name name of method to unstub.
+ #
+ # @example Invoking an unstubbed method causes error to be raised
+ # object = mock('mock') do
+ # object.stubs(:stubbed_method).returns(:result_one)
+ # object.stubbed_method # => :result_one
+ # object.unstub(:stubbed_method)
+ # object.stubbed_method # => unexpected invocation: #<Mock:mock>.stubbed_method()
def unstub(method_name)
@expectations.remove_all_matching_method(method_name)
end
- # :call-seq: responds_like(responder) -> mock
+ # Constrains the {Mock} instance so that it can only expect or stub methods to which +responder+ responds. The constraint is only applied at method invocation time.
#
- # Constrains the +mock+ so that it can only expect or stub methods to which +responder+ responds. The constraint is only applied at method invocation time.
+ # A +NoMethodError+ will be raised if the +responder+ does not +#respond_to?+ a method invocation (even if the method has been expected or stubbed).
#
- # A +NoMethodError+ will be raised if the +responder+ does not <tt>respond_to?</tt> a method invocation (even if the method has been expected or stubbed).
+ # The {Mock} instance will delegate its +#respond_to?+ method to the +responder+.
#
- # The +mock+ will delegate its <tt>respond_to?</tt> method to the +responder+.
- # class Sheep
- # def chew(grass); end
- # def self.number_of_legs; end
- # end
+ # @param [Object, #respond_to?] responder an object used to determine whether {Mock} instance should +#respond_to?+ to an invocation.
+ # @return [Mock] the same {Mock} instance, thereby allowing invocations of other {Mock} methods to be chained.
#
+ # @example Normal mocking
# sheep = mock('sheep')
# sheep.expects(:chew)
# sheep.expects(:foo)
@@ -115,6 +129,11 @@ def unstub(method_name)
# sheep.foo
# # no error raised
#
+ # @example Using {#responds_like} with an instance method
+ # class Sheep
+ # def chew(grass); end
+ # end
+ #
# sheep = mock('sheep')
# sheep.responds_like(Sheep.new)
# sheep.expects(:chew)
@@ -124,6 +143,11 @@ def unstub(method_name)
# sheep.chew
# sheep.foo # => raises NoMethodError exception
#
+ # @example Using {#responds_like} with a class method
+ # class Sheep
+ # def self.number_of_legs; end
+ # end
+ #
# sheep_class = mock('sheep_class')
# sheep_class.responds_like(Sheep)
# sheep_class.stubs(:number_of_legs).returns(4)
@@ -132,15 +156,12 @@ def unstub(method_name)
# sheep_class.respond_to?(:foo) # => false
# assert_equal 4, sheep_class.number_of_legs
# sheep_class.foo # => raises NoMethodError exception
- #
- # Aliased by +quacks_like+
- def responds_like(object)
- @responder = object
+ def responds_like(responder)
+ @responder = responder
self
end
- # :stopdoc:
-
+ # @private
def initialize(mockery, name = nil, &block)
@mockery = mockery
@name = name || DefaultName.new(self)
@@ -150,6 +171,7 @@ def initialize(mockery, name = nil, &block)
instance_eval(&block) if block
end
+ # @private
attr_reader :everything_stubbed
alias_method :__expects__, :expects
@@ -158,14 +180,17 @@ def initialize(mockery, name = nil, &block)
alias_method :quacks_like, :responds_like
+ # @private
def __expectations__
@expectations
end
+ # @private
def stub_everything
@everything_stubbed = true
end
+ # @private
def method_missing(symbol, *arguments, &block)
if @responder and not @responder.respond_to?(symbol)
raise NoMethodError, "undefined method `#{symbol}' for #{self.mocha_inspect} which responds like #{@responder.mocha_inspect}"
@@ -182,6 +207,7 @@ def method_missing(symbol, *arguments, &block)
end
end
+ # @private
def respond_to?(symbol, include_private = false)
if @responder then
if @responder.method(:respond_to?).arity > 1
@@ -194,28 +220,31 @@ def respond_to?(symbol, include_private = false)
end
end
+ # @private
def __verified__?(assertion_counter = nil)
@expectations.verified?(assertion_counter)
end
+ # @private
def mocha_inspect
@name.mocha_inspect
end
+ # @private
def inspect
mocha_inspect
end
+ # @private
def ensure_method_not_already_defined(method_name)
self.__metaclass__.send(:undef_method, method_name) if self.__metaclass__.method_defined?(method_name)
end
+ # @private
def any_expectations?
@expectations.any?
end
- # :startdoc:
-
end
end
View
167 lib/mocha/object.rb
@@ -6,42 +6,49 @@
require 'mocha/argument_iterator'
module Mocha
-
- # Methods added to all objects to allow mocking and stubbing on real objects.
+
+ # Methods added to all objects to allow mocking and stubbing on real (i.e. non-mock) objects.
#
- # Methods return a Mocha::Expectation which can be further modified by methods on Mocha::Expectation.
+ # Both {#expects} and {#stubs} return an {Expectation} which can be further modified by methods on {Expectation}.
module ObjectMethods
-
- def mocha # :nodoc:
+
+ # @private
+ def mocha
@mocha ||= Mocha::Mockery.instance.mock_impersonating(self)
end
-
- def reset_mocha # :nodoc:
+
+ # @private
+ def reset_mocha
@mocha = nil
end
-
- def stubba_method # :nodoc:
+
+ # @private
+ def stubba_method
Mocha::InstanceMethod
end
-
- def stubba_object # :nodoc:
+
+ # @private
+ def stubba_object
self
end
-
- # :call-seq: expects(method_name) -> expectation
- # expects(method_names_vs_return_values) -> last expectation
+
+ # Adds an expectation that the specified method must be called exactly once with any parameters.
+ #
+ # The original implementation of the method is replaced during the test and then restored at the end of the test.
+ #
+ # @param [Symbol,String] method_name name of expected method
+ # @param [Hash] expected_methods_vs_return_values expected method name symbols as keys and corresponding return values as values - these expectations are setup as if {#expects} were called multiple times.
#
- # Adds an expectation that a method identified by +method_name+ Symbol must be called exactly once with any parameters.
- # Returns the new expectation which can be further modified by methods on Mocha::Expectation.
+ # @overload def expects(method_name)
+ # @overload def expects(expected_methods_vs_return_values)
+ # @return [Expectation] last-built expectation which can be further modified by methods on {Expectation}.
+ #
+ # @example Setting up an expectation on a non-mock object.
# product = Product.new
# product.expects(:save).returns(true)
# assert_equal true, product.save
#
- # The original implementation of <tt>Product#save</tt> is replaced temporarily.
- #
- # The original implementation of <tt>Product#save</tt> is restored at the end of the test.
- #
- # If +method_names_vs_return_values+ is a +Hash+, an expectation will be set up for each entry using the key as +method_name+ and value as +return_value+.
+ # @example Setting up multiple expectations on a non-mock object.
# product = Product.new
# product.expects(:valid? => true, :save => true)
#
@@ -50,13 +57,15 @@ def stubba_object # :nodoc:
# product = Product.new
# product.expects(:valid?).returns(true)
# product.expects(:save).returns(true)
- def expects(method_name_or_hash)
- if method_name_or_hash.to_s =~ /the[^a-z]*spanish[^a-z]*inquisition/i
+ #
+ # @see Mock#expects
+ def expects(expected_methods_vs_return_values)
+ if expected_methods_vs_return_values.to_s =~ /the[^a-z]*spanish[^a-z]*inquisition/i
raise Mocha::ExpectationError.new('NOBODY EXPECTS THE SPANISH INQUISITION!')
end
expectation = nil
mockery = Mocha::Mockery.instance
- iterator = ArgumentIterator.new(method_name_or_hash)
+ iterator = ArgumentIterator.new(expected_methods_vs_return_values)
iterator.each { |*args|
method_name = args.shift
mockery.on_stubbing(self, method_name)
@@ -67,21 +76,22 @@ def expects(method_name_or_hash)
}
expectation
end
-
- # :call-seq: stubs(method_name) -> expectation
- # stubs(method_names_vs_return_values) -> last expectation
+
+ # Adds an expectation that the specified method may be called any number of times with any parameters.
#
- # Adds an expectation that a method identified by +method_name+ Symbol may be called any number of times with any parameters.
- # Returns the new expectation which can be further modified by methods on Mocha::Expectation.
+ # @param [Symbol,String] method_name name of stubbed method
+ # @param [Hash] stubbed_methods_vs_return_values stubbed method name symbols as keys and corresponding return values as values - these stubbed methods are setup as if {#stubs} were called multiple times.
+ #
+ # @overload def stubs(method_name)
+ # @overload def stubs(stubbed_methods_vs_return_values)
+ # @return [Expectation] last-built expectation which can be further modified by methods on {Expectation}.
+ #
+ # @example Setting up a stubbed methods on a non-mock object.
# product = Product.new
# product.stubs(:save).returns(true)
# assert_equal true, product.save
#
- # The original implementation of <tt>Product#save</tt> is replaced temporarily.
- #
- # The original implementation of <tt>Product#save</tt> is restored at the end of the test.
- #
- # If +method_names_vs_return_values+ is a +Hash+, an expectation will be set up for each entry using the key as +method_name+ and value as +return_value+.
+ # @example Setting up multiple stubbed methods on a non-mock object.
# product = Product.new
# product.stubs(:valid? => true, :save => true)
#
@@ -90,10 +100,12 @@ def expects(method_name_or_hash)
# product = Product.new
# product.stubs(:valid?).returns(true)
# product.stubs(:save).returns(true)
- def stubs(method_name_or_hash)
+ #
+ # @see Mock#stubs
+ def stubs(stubbed_methods_vs_return_values)
expectation = nil
mockery = Mocha::Mockery.instance
- iterator = ArgumentIterator.new(method_name_or_hash)
+ iterator = ArgumentIterator.new(stubbed_methods_vs_return_values)
iterator.each { |*args|
method_name = args.shift
mockery.on_stubbing(self, method_name)
@@ -104,26 +116,24 @@ def stubs(method_name_or_hash)
}
expectation
end
-
- # :call-seq: unstub(*method_names)
+
+ # Removes the specified stubbed methods (added by calls to {#expects} or {#stubs}) and all expectations associated with them.
+ #
+ # Restores the original behaviour of the methods before they were stubbed.
+ #
+ # WARNING: If you {#unstub} a method which still has unsatisfied expectations, you may be removing the only way those expectations can be satisfied. Use {#unstub} with care.
#
- # Removes the method stub added by calls to #expects or #stubs.
- # Restores the original behaviour of the method before it was stubbed.
+ # @param [Array<Symbol>] method_names names of methods to unstub.
+ #
+ # @example Stubbing and unstubbing a method on a real (non-mock) object.
# multiplier = Multiplier.new
# multiplier.double(2) # => 4
- # multiplier.stubs(:double).raises
+ # multiplier.stubs(:double).raises # new behaviour defined
# multiplier.double(2) # => raises exception
- # multiplier.unstub(:double)
+ # multiplier.unstub(:double) # original behaviour restored
# multiplier.double(2) # => 4
#
- # The original implementation of <tt>Multiplier#double</tt> is replaced temporarily.
- #
- # The original implementation of <tt>Multiplier#double</tt> is restored when #unstub is called.
- #
- # WARNING: If you #unstub a method which still has unsatisfied expectations, you may be removing
- # the only way those expectations can be satisfied. Use #unstub with care.
- #
- # If multiple +method_names+ are supplied, each method is unstubbed.
+ # @example Unstubbing multiple methods on a real (non-mock) object.
# multiplier.unstub(:double, :triple)
#
# # exactly equivalent to
@@ -137,8 +147,9 @@ def unstub(*method_names)
mockery.stubba.unstub(method)
end
end
-
- def method_exists?(method, include_public_methods = true) # :nodoc:
+
+ # @private
+ def method_exists?(method, include_public_methods = true)
if include_public_methods
return true if public_methods(include_superclass_methods = true).include?(method)
return true if respond_to?(method.to_sym)
@@ -147,30 +158,33 @@ def method_exists?(method, include_public_methods = true) # :nodoc:
return true if private_methods(include_superclass_methods = true).include?(method)
return false
end
-
+
end
-
- module ModuleMethods # :nodoc:
-
+
+ # @private
+ module ModuleMethods
+
def stubba_method
Mocha::ModuleMethod
end
-
+
end
-
- # Methods added all classes to allow mocking and stubbing on real objects.
+
+ # Methods added to all classes to allow mocking and stubbing on real (i.e. non-mock) objects.
module ClassMethods
-
- def stubba_method # :nodoc:
+
+ # @private
+ def stubba_method
Mocha::ClassMethod
end
- class AnyInstance # :nodoc:
-
+ # @private
+ class AnyInstance
+
def initialize(klass)
@stubba_object = klass
end
-
+
def mocha
@mocha ||= Mocha::Mockery.instance.mock_impersonating_any_instance_of(@stubba_object)
end
@@ -178,11 +192,11 @@ def mocha
def stubba_method
Mocha::AnyInstanceMethod
end
-
+
def stubba_object
@stubba_object
end
-
+
def method_exists?(method, include_public_methods = true)
if include_public_methods
return true if @stubba_object.public_instance_methods(include_superclass_methods = true).include?(method)
@@ -191,12 +205,12 @@ def method_exists?(method, include_public_methods = true)
return true if @stubba_object.private_instance_methods(include_superclass_methods = true).include?(method)
return false
end
-
+
end
-
- # :call-seq: any_instance -> mock object
+
+ # @return [Mock] a mock object which will detect calls to any instance of this class.
#
- # Returns a mock object which will detect calls to any instance of this class.
+ # @example Return false to invocation of +Product#save+ for any instance of +Product+.
# Product.any_instance.stubs(:save).returns(false)
# product_1 = Product.new
# assert_equal false, product_1.save
@@ -205,19 +219,22 @@ def method_exists?(method, include_public_methods = true)
def any_instance
@any_instance ||= AnyInstance.new(self)
end
-
+
end
-
+
end
-class Object # :nodoc:
+# @private
+class Object
include Mocha::ObjectMethods
end
-class Module # :nodoc:
+# @private
+class Module
include Mocha::ModuleMethods
end
-class Class # :nodoc:
+# @private
+class Class
include Mocha::ClassMethods
end
View
6 lib/mocha/parameter_matchers.rb
@@ -1,8 +1,8 @@
module Mocha
-
- # Used as parameters for Expectation#with to restrict the parameter values which will match the expectation. Can be nested.
+
+ # Used as parameters for {Expectation#with} to restrict the parameter values which will match the expectation. Can be nested.
module ParameterMatchers; end
-
+
end
require 'mocha/parameter_matchers/object'
View
34 lib/mocha/parameter_matchers/all_of.rb
@@ -1,17 +1,23 @@
require 'mocha/parameter_matchers/base'
module Mocha
-
+
module ParameterMatchers
- # :call-seq: all_of(*parameter_matchers) -> parameter_matcher
+ # Matches if all +matchers+ match.
+ #
+ # @param [*Array<Base>] parameter_matchers parameter matchers.
+ # @return [AllOf] parameter matcher.
+ #
+ # @see Expectation#with
#
- # Matches if all +parameter_matchers+ match.
+ # @example All parameter matchers match.
# object = mock()
# object.expects(:method_1).with(all_of(includes(1), includes(3)))
# object.method_1([1, 3])
# # no error raised
#
+ # @example One of the parameter matchers does not match.
# object = mock()
# object.expects(:method_1).with(all_of(includes(1), includes(3)))
# object.method_1([1, 2])
@@ -19,24 +25,28 @@ module ParameterMatchers
def all_of(*matchers)
AllOf.new(*matchers)
end
-
- class AllOf < Base # :nodoc:
-
+
+ # Parameter matcher which combines a number of other matchers using a logical AND.
+ class AllOf < Base
+
+ # @private
def initialize(*matchers)
@matchers = matchers
end
-
+
+ # @private
def matches?(available_parameters)
parameter = available_parameters.shift
@matchers.all? { |matcher| matcher.to_matcher.matches?([parameter]) }
end
-
+
+ # @private
def mocha_inspect
"all_of(#{@matchers.map { |matcher| matcher.mocha_inspect }.join(", ") })"
end
-
+
end
-
+
end
-
-end
+
+end
View
35 lib/mocha/parameter_matchers/any_of.rb
@@ -1,22 +1,29 @@
require 'mocha/parameter_matchers/base'
module Mocha
-
+
module ParameterMatchers
- # :call-seq: any_of(*parameter_matchers) -> parameter_matcher
+ # Matches if any +matchers+ match.
+ #
+ # @param [*Array<Base>] parameter_matchers parameter matchers.
+ # @return [AnyOf] parameter matcher.
+ #
+ # @see Expectation#with
#
- # Matches if any +parameter_matchers+ match.
+ # @example One parameter matcher matches.
# object = mock()
# object.expects(:method_1).with(any_of(1, 3))
# object.method_1(1)
# # no error raised
#
+ # @example The other parameter matcher matches.
# object = mock()
# object.expects(:method_1).with(any_of(1, 3))
# object.method_1(3)
# # no error raised
#
+ # @example Neither parameter matcher matches.
# object = mock()
# object.expects(:method_1).with(any_of(1, 3))
# object.method_1(2)
@@ -24,24 +31,28 @@ module ParameterMatchers
def any_of(*matchers)
AnyOf.new(*matchers)
end
-
- class AnyOf < Base # :nodoc:
-
+
+ # Parameter matcher which combines a number of other matchers using a logical OR.
+ class AnyOf < Base
+
+ # @private
def initialize(*matchers)
@matchers = matchers
end
-
+
+ # @private
def matches?(available_parameters)
parameter = available_parameters.shift
@matchers.any? { |matcher| matcher.to_matcher.matches?([parameter]) }
end
-
+
+ # @private
def mocha_inspect
"any_of(#{@matchers.map { |matcher| matcher.mocha_inspect }.join(", ") })"
end
-
+
end
-
+
end
-
-end
+
+end
View
23 lib/mocha/parameter_matchers/any_parameters.rb
@@ -1,12 +1,16 @@
require 'mocha/parameter_matchers/base'
module Mocha
-
+
module ParameterMatchers
- # :call-seq: any_parameters() -> parameter_matcher
+ # Matches any parameters. This is used as the default for a newly built expectation.
+ #
+ # @return [AnyParameters] parameter matcher.
+ #
+ # @see Expectation#with
#
- # Matches any parameters.
+ # @example Any parameters will match.
# object = mock()
# object.expects(:method_1).with(any_parameters)
# object.method_1(1, 2, 3, 4)
@@ -20,8 +24,10 @@ def any_parameters
AnyParameters.new
end
- class AnyParameters < Base # :nodoc:
-
+ # Parameter matcher which always matches whatever the parameters.
+ class AnyParameters < Base
+
+ # @private
def matches?(available_parameters)
while available_parameters.length > 0 do
available_parameters.shift
@@ -29,12 +35,13 @@ def matches?(available_parameters)
return true
end
+ # @private
def mocha_inspect
"any_parameters"
end
end
-
+
end
-
-end
+
+end
View
31 lib/mocha/parameter_matchers/anything.rb
@@ -1,33 +1,42 @@
require 'mocha/parameter_matchers/base'
module Mocha
-
+
module ParameterMatchers
- # :call-seq: anything() -> parameter_matcher
- #
# Matches any object.
+ #
+ # @return [Anything] parameter matcher.
+ #
+ # @see Expectation#with
+ #
+ # @example Any object will match.
# object = mock()
# object.expects(:method_1).with(anything)
# object.method_1('foo')
+ # object.method_1(789)
+ # object.method_1(:bar)
# # no error raised
def anything
Anything.new
end
-
- class Anything < Base # :nodoc:
-
+
+ # Parameter matcher which always matches a single parameter.
+ class Anything < Base
+
+ # @private
def matches?(available_parameters)
available_parameters.shift
return true
end
-
+
+ # @private
def mocha_inspect
"anything"
end
-
+
end
-
+
end
-
-end
+
+end
View
60 lib/mocha/parameter_matchers/base.rb
@@ -1,53 +1,61 @@
module Mocha
-
+
module ParameterMatchers
-
+
+ # @abstract Subclass and implement +#matches?+ and +#mocha_inspect+ to define a custom matcher. Also add a suitably named instance method to {ParameterMatchers} to build an instance of the new matcher c.f. {#equals}.
class Base
-
- def to_matcher # :nodoc:
+
+ # @private
+ def to_matcher
self
end
-
- # :call-seq: &(matcher) -> parameter_matcher
+
+ # A shorthand way of combining two matchers when both must match.
#
- # A short hand way of specifying multiple matchers that should
- # all match.
+ # Returns a new {AllOf} parameter matcher combining two matchers using a logical AND.
#
- # Returns a new +AllOf+ parameter matcher combining the
- # given matcher and the receiver.
+ # This shorthand will not work with an implicit equals match. Instead, an explicit {Equals} matcher should be used.
#
- # The following statements are equivalent:
+ # @param [Base] matcher parameter matcher.
+ # @return [AllOf] parameter matcher.
+ #
+ # @see Expectation#with
+ #
+ # @example Alternative ways to combine matchers with a logical AND.
# object = mock()
# object.expects(:run).with(all_of(has_key(:foo), has_key(:bar)))
# object.run(:foo => 'foovalue', :bar => 'barvalue')
#
- # # with the shorthand
+ # # is exactly equivalent to
+ #
# object.expects(:run).with(has_key(:foo) & has_key(:bar))
# object.run(:foo => 'foovalue', :bar => 'barvalue)
def &(matcher)
AllOf.new(self, matcher)
end
-
- # :call-seq: |(matcher) -> parameter_matcher
+
+ # A shorthand way of combining two matchers when at least one must match.
+ #
+ # Returns a new +AnyOf+ parameter matcher combining two matchers using a logical OR.
#
- # A short hand way of specifying multiple matchers, only at least
- # one of which should pass.
+ # This shorthand will not work with an implicit equals match. Instead, an explicit {Equals} matcher should be used.
#
- # Returns a new +AnyOf+ parameter matcher combining the
- # given matcher and the receiver.
+ # @param [Base] matcher parameter matcher.
+ # @return [AnyOf] parameter matcher.
#
- # The following statements are equivalent:
+ # @see Expectation#with
+ #
+ # @example Alternative ways to combine matchers with a logical OR.
# object = mock()
# object.expects(:run).with(any_of(has_key(:foo), has_key(:bar)))
# object.run(:foo => 'foovalue')
#
- # # with the shorthand
+ # # is exactly equivalent to
+ #
# object.expects(:run).with(has_key(:foo) | has_key(:bar))
# object.run(:foo => 'foovalue')
#
- # This shorthand will not work with an implicit equals match. Instead,
- # an explicit equals matcher should be used:
- #
+ # @example Using an explicit {Equals} matcher in combination with {#|}.
# object.expects(:run).with(equals(1) | equals(2))
# object.run(1) # passes
# object.run(2) # passes
@@ -55,9 +63,9 @@ def &(matcher)
def |(matcher)
AnyOf.new(self, matcher)
end
-
+
end
-
+
end
-
+
end
View
35 lib/mocha/parameter_matchers/equals.rb
@@ -1,42 +1,53 @@
require 'mocha/parameter_matchers/base'
module Mocha
-
+
module ParameterMatchers
- # :call-seq: equals(value) -> parameter_matcher
+ # Matches any +Object+ equalling +value+.
+ #
+ # @param [Object] value expected value.
+ # @return [Equals] parameter matcher.
+ #
+ # @see Expectation#with
+ # @see Object#==
#
- # Matches +Object+ equalling +value+.
+ # @example Actual parameter equals expected parameter.
# object = mock()
# object.expects(:method_1).with(equals(2))
# object.method_1(2)
# # no error raised
#
+ # @example Actual parameter does not equal expected parameter.
# object = mock()
# object.expects(:method_1).with(equals(2))
# object.method_1(3)
- # # error raised, because method_1 was not called with Object equalling 3
+ # # error raised, because method_1 was not called with an +Object+ that equals 3
def equals(value)
Equals.new(value)
end
- class Equals < Base # :nodoc:
-
+ # Parameter matcher which matches when actual parameter equals expected value.
+ class Equals < Base
+
+ # @private
def initialize(value)
@value = value
end
-
+
+ # @private
def matches?(available_parameters)
parameter = available_parameters.shift
parameter == @value
end
-
+
+ # @private
def mocha_inspect
@value.mocha_inspect
end
-
+
end
-
+
end
-
-end
+
+end
View
34 lib/mocha/parameter_matchers/has_entries.rb
@@ -3,17 +3,23 @@
require 'mocha/parameter_matchers/has_entry'
module Mocha
-
+
module ParameterMatchers
- # :call-seq: has_entries(entries) -> parameter_matcher
- #
# Matches +Hash+ containing all +entries+.
+ #
+ # @param [Hash] entries expected +Hash+ entries.
+ # @return [HasEntries] parameter matcher.
+ #
+ # @see Expectation#with
+ #
+ # @example Actual parameter contains all expected entries.
# object = mock()
# object.expects(:method_1).with(has_entries('key_1' => 1, 'key_2' => 2))
# object.method_1('key_1' => 1, 'key_2' => 2, 'key_3' => 3)
# # no error raised
#
+ # @example Actual parameter does not contain all expected entries.
# object = mock()
# object.expects(:method_1).with(has_entries('key_1' => 1, 'key_2' => 2))
# object.method_1('key_1' => 1, 'key_2' => 99)
@@ -21,25 +27,29 @@ module ParameterMatchers
def has_entries(entries)
HasEntries.new(entries)
end
-
- class HasEntries < Base # :nodoc:
-
+
+ # Parameter matcher which matches when actual parameter contains all expected +Hash+ entries.
+ class HasEntries < Base
+
+ # @private
def initialize(entries)
@entries = entries
end
-
+
+ # @private
def matches?(available_parameters)
parameter = available_parameters.shift
has_entry_matchers = @entries.map { |key, value| HasEntry.new(key, value) }
AllOf.new(*has_entry_matchers).matches?([parameter])
end
-
+
+ # @private
def mocha_inspect
"has_entries(#{@entries.mocha_inspect})"
end
-
+
end
-
+
end
-
-end
+
+end
View
44 lib/mocha/parameter_matchers/has_entry.rb
@@ -1,28 +1,42 @@
require 'mocha/parameter_matchers/base'
module Mocha
-
+
module ParameterMatchers
- # :call-seq: has_entry(key, value) -> parameter_matcher
- # has_entry(key => value) -> parameter_matcher
- #
# Matches +Hash+ containing entry with +key+ and +value+.
+ #
+ # @overload def has_entry(key, value)
+ # @param [Object] key key for entry.
+ # @param [Object] value value for entry.
+ # @overload def has_entry(single_entry_hash)
+ # @param [Hash] single_entry_hash +Hash+ with single entry.
+ # @raise [ArgumentError] if +single_entry_hash+ does not contain exactly one entry.