mocha 0.10.5 → 1.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (262) hide show
  1. checksums.yaml +7 -0
  2. data/.github/FUNDING.yml +1 -0
  3. data/.rubocop.yml +61 -0
  4. data/.rubocop_todo.yml +27 -0
  5. data/.yardopts +24 -0
  6. data/CONTRIBUTING.md +7 -0
  7. data/COPYING.md +3 -0
  8. data/Gemfile +2 -2
  9. data/{MIT-LICENSE.rdoc → MIT-LICENSE.md} +1 -1
  10. data/README.md +363 -0
  11. data/{RELEASE.rdoc → RELEASE.md} +436 -35
  12. data/Rakefile +87 -87
  13. data/gemfiles/Gemfile.minitest.latest +2 -2
  14. data/gemfiles/Gemfile.test-unit.latest +6 -2
  15. data/init.rb +1 -3
  16. data/lib/mocha/any_instance_method.rb +12 -45
  17. data/lib/mocha/api.rb +199 -131
  18. data/lib/mocha/argument_iterator.rb +6 -10
  19. data/lib/mocha/backtrace_filter.rb +1 -5
  20. data/lib/mocha/block_matcher.rb +31 -0
  21. data/lib/mocha/cardinality.rb +77 -66
  22. data/lib/mocha/central.rb +27 -18
  23. data/lib/mocha/change_state_side_effect.rb +3 -7
  24. data/lib/mocha/class_methods.rb +62 -0
  25. data/lib/mocha/configuration.rb +399 -46
  26. data/lib/mocha/debug.rb +12 -0
  27. data/lib/mocha/deprecation.rb +11 -12
  28. data/lib/mocha/detection/mini_test.rb +23 -0
  29. data/lib/mocha/detection/test_unit.rb +27 -0
  30. data/lib/mocha/error_with_filtered_backtrace.rb +13 -0
  31. data/lib/mocha/exception_raiser.rb +8 -10
  32. data/lib/mocha/expectation.rb +290 -151
  33. data/lib/mocha/expectation_error.rb +6 -13
  34. data/lib/mocha/expectation_error_factory.rb +35 -0
  35. data/lib/mocha/expectation_list.rb +22 -22
  36. data/lib/mocha/hooks.rb +42 -0
  37. data/lib/mocha/in_state_ordering_constraint.rb +3 -7
  38. data/lib/mocha/inspect.rb +35 -43
  39. data/lib/mocha/instance_method.rb +12 -21
  40. data/lib/mocha/integration/assertion_counter.rb +13 -0
  41. data/lib/mocha/integration/mini_test/adapter.rb +52 -0
  42. data/lib/mocha/integration/mini_test/exception_translation.rb +1 -7
  43. data/lib/mocha/integration/mini_test/nothing.rb +19 -0
  44. data/lib/mocha/integration/mini_test/version_13.rb +35 -25
  45. data/lib/mocha/integration/mini_test/version_140.rb +35 -26
  46. data/lib/mocha/integration/mini_test/version_141.rb +43 -34
  47. data/lib/mocha/integration/mini_test/version_142_to_172.rb +44 -35
  48. data/lib/mocha/integration/mini_test/version_200.rb +45 -36
  49. data/lib/mocha/integration/mini_test/version_201_to_222.rb +44 -35
  50. data/lib/mocha/integration/mini_test/version_2110_to_2111.rb +70 -0
  51. data/lib/mocha/integration/mini_test/version_2112_to_320.rb +73 -0
  52. data/lib/mocha/integration/mini_test/version_230_to_2101.rb +68 -0
  53. data/lib/mocha/integration/mini_test.rb +51 -49
  54. data/lib/mocha/integration/monkey_patcher.rb +24 -0
  55. data/lib/mocha/integration/test_unit/adapter.rb +50 -0
  56. data/lib/mocha/integration/test_unit/gem_version_200.rb +39 -29
  57. data/lib/mocha/integration/test_unit/gem_version_201_to_202.rb +39 -29
  58. data/lib/mocha/integration/test_unit/gem_version_203_to_220.rb +39 -29
  59. data/lib/mocha/integration/test_unit/gem_version_230_to_250.rb +68 -0
  60. data/lib/mocha/integration/test_unit/nothing.rb +19 -0
  61. data/lib/mocha/integration/test_unit/ruby_version_185_and_below.rb +39 -29
  62. data/lib/mocha/integration/test_unit/ruby_version_186_and_above.rb +40 -30
  63. data/lib/mocha/integration/test_unit.rb +45 -51
  64. data/lib/mocha/integration.rb +6 -33
  65. data/lib/mocha/invocation.rb +77 -0
  66. data/lib/mocha/is_a.rb +0 -2
  67. data/lib/mocha/logger.rb +2 -6
  68. data/lib/mocha/macos_version.rb +5 -0
  69. data/lib/mocha/method_matcher.rb +6 -10
  70. data/lib/mocha/minitest.rb +8 -0
  71. data/lib/mocha/mock.rb +266 -79
  72. data/lib/mocha/mockery.rb +104 -106
  73. data/lib/mocha/names.rb +10 -20
  74. data/lib/mocha/not_initialized_error.rb +7 -0
  75. data/lib/mocha/object_methods.rb +169 -0
  76. data/lib/mocha/parameter_matchers/all_of.rb +18 -14
  77. data/lib/mocha/parameter_matchers/any_of.rb +19 -14
  78. data/lib/mocha/parameter_matchers/any_parameters.rb +14 -13
  79. data/lib/mocha/parameter_matchers/anything.rb +17 -14
  80. data/lib/mocha/parameter_matchers/base.rb +33 -31
  81. data/lib/mocha/parameter_matchers/equals.rb +18 -13
  82. data/lib/mocha/parameter_matchers/equivalent_uri.rb +58 -0
  83. data/lib/mocha/parameter_matchers/has_entries.rb +19 -14
  84. data/lib/mocha/parameter_matchers/has_entry.rb +58 -26
  85. data/lib/mocha/parameter_matchers/has_key.rb +18 -13
  86. data/lib/mocha/parameter_matchers/has_keys.rb +53 -0
  87. data/lib/mocha/parameter_matchers/has_value.rb +18 -13
  88. data/lib/mocha/parameter_matchers/includes.rb +80 -19
  89. data/lib/mocha/parameter_matchers/instance_methods.rb +18 -0
  90. data/lib/mocha/parameter_matchers/instance_of.rb +18 -13
  91. data/lib/mocha/parameter_matchers/is_a.rb +20 -14
  92. data/lib/mocha/parameter_matchers/kind_of.rb +20 -13
  93. data/lib/mocha/parameter_matchers/not.rb +19 -14
  94. data/lib/mocha/parameter_matchers/optionally.rb +23 -17
  95. data/lib/mocha/parameter_matchers/regexp_matches.rb +16 -12
  96. data/lib/mocha/parameter_matchers/responds_with.rb +17 -11
  97. data/lib/mocha/parameter_matchers/yaml_equivalent.rb +15 -9
  98. data/lib/mocha/parameter_matchers.rb +4 -5
  99. data/lib/mocha/parameters_matcher.rb +11 -14
  100. data/lib/mocha/raised_exception.rb +11 -0
  101. data/lib/mocha/receivers.rb +45 -0
  102. data/lib/mocha/return_values.rb +11 -15
  103. data/lib/mocha/ruby_version.rb +4 -0
  104. data/lib/mocha/sequence.rb +21 -17
  105. data/lib/mocha/setup.rb +14 -0
  106. data/lib/mocha/single_return_value.rb +5 -8
  107. data/lib/mocha/singleton_class.rb +9 -0
  108. data/lib/mocha/state_machine.rb +69 -67
  109. data/lib/mocha/stubbed_method.rb +125 -0
  110. data/lib/mocha/stubbing_error.rb +6 -14
  111. data/lib/mocha/test_unit.rb +8 -0
  112. data/lib/mocha/thrower.rb +6 -8
  113. data/lib/mocha/thrown_object.rb +12 -0
  114. data/lib/mocha/version.rb +1 -1
  115. data/lib/mocha/yield_parameters.rb +12 -22
  116. data/lib/mocha.rb +8 -3
  117. data/mocha.gemspec +43 -34
  118. data/yard-templates/default/layout/html/google_analytics.erb +8 -0
  119. data/yard-templates/default/layout/html/setup.rb +5 -0
  120. metadata +123 -268
  121. data/COPYING.rdoc +0 -3
  122. data/README.rdoc +0 -54
  123. data/examples/misc.rb +0 -43
  124. data/examples/mocha.rb +0 -25
  125. data/examples/stubba.rb +0 -64
  126. data/gemfiles/Gemfile.minitest.1.3.0 +0 -7
  127. data/gemfiles/Gemfile.minitest.1.4.0 +0 -7
  128. data/gemfiles/Gemfile.minitest.1.4.1 +0 -7
  129. data/gemfiles/Gemfile.minitest.1.4.2 +0 -7
  130. data/gemfiles/Gemfile.minitest.2.0.0 +0 -7
  131. data/gemfiles/Gemfile.minitest.2.0.1 +0 -7
  132. data/gemfiles/Gemfile.minitest.2.3.0 +0 -7
  133. data/gemfiles/Gemfile.test-unit.2.0.0 +0 -8
  134. data/gemfiles/Gemfile.test-unit.2.0.1 +0 -7
  135. data/gemfiles/Gemfile.test-unit.2.0.3 +0 -7
  136. data/lib/mocha/class_method.rb +0 -98
  137. data/lib/mocha/integration/mini_test/assertion_counter.rb +0 -23
  138. data/lib/mocha/integration/mini_test/version_230_to_262.rb +0 -59
  139. data/lib/mocha/integration/test_unit/assertion_counter.rb +0 -23
  140. data/lib/mocha/integration/test_unit/gem_version_230_to_240.rb +0 -58
  141. data/lib/mocha/module_method.rb +0 -16
  142. data/lib/mocha/multiple_yields.rb +0 -20
  143. data/lib/mocha/no_yields.rb +0 -11
  144. data/lib/mocha/object.rb +0 -223
  145. data/lib/mocha/options.rb +0 -1
  146. data/lib/mocha/parameter_matchers/object.rb +0 -15
  147. data/lib/mocha/parameter_matchers/query_string.rb +0 -47
  148. data/lib/mocha/pretty_parameters.rb +0 -28
  149. data/lib/mocha/single_yield.rb +0 -18
  150. data/lib/mocha/standalone.rb +0 -1
  151. data/lib/mocha/unexpected_invocation.rb +0 -18
  152. data/lib/mocha_standalone.rb +0 -2
  153. data/lib/stubba.rb +0 -4
  154. data/test/acceptance/acceptance_test_helper.rb +0 -41
  155. data/test/acceptance/api_test.rb +0 -139
  156. data/test/acceptance/bug_18914_test.rb +0 -43
  157. data/test/acceptance/bug_21465_test.rb +0 -34
  158. data/test/acceptance/bug_21563_test.rb +0 -25
  159. data/test/acceptance/exception_rescue_test.rb +0 -55
  160. data/test/acceptance/expectations_on_multiple_methods_test.rb +0 -55
  161. data/test/acceptance/expected_invocation_count_test.rb +0 -232
  162. data/test/acceptance/failure_messages_test.rb +0 -64
  163. data/test/acceptance/issue_65_test.rb +0 -63
  164. data/test/acceptance/issue_70_test.rb +0 -55
  165. data/test/acceptance/minitest_test.rb +0 -162
  166. data/test/acceptance/mocha_example_test.rb +0 -98
  167. data/test/acceptance/mocha_test_result_test.rb +0 -84
  168. data/test/acceptance/mock_test.rb +0 -100
  169. data/test/acceptance/mock_with_initializer_block_test.rb +0 -51
  170. data/test/acceptance/mocked_methods_dispatch_test.rb +0 -78
  171. data/test/acceptance/multiple_expectations_failure_message_test.rb +0 -68
  172. data/test/acceptance/optional_parameters_test.rb +0 -70
  173. data/test/acceptance/parameter_matcher_test.rb +0 -300
  174. data/test/acceptance/partial_mocks_test.rb +0 -47
  175. data/test/acceptance/raise_exception_test.rb +0 -39
  176. data/test/acceptance/return_value_test.rb +0 -52
  177. data/test/acceptance/sequence_test.rb +0 -192
  178. data/test/acceptance/states_test.rb +0 -70
  179. data/test/acceptance/stub_any_instance_method_test.rb +0 -198
  180. data/test/acceptance/stub_class_method_defined_on_active_record_association_proxy_test.rb +0 -106
  181. data/test/acceptance/stub_class_method_defined_on_class_test.rb +0 -72
  182. data/test/acceptance/stub_class_method_defined_on_module_test.rb +0 -75
  183. data/test/acceptance/stub_class_method_defined_on_superclass_test.rb +0 -75
  184. data/test/acceptance/stub_everything_test.rb +0 -56
  185. data/test/acceptance/stub_instance_method_defined_on_active_record_association_proxy_test.rb +0 -93
  186. data/test/acceptance/stub_instance_method_defined_on_class_and_aliased_test.rb +0 -69
  187. data/test/acceptance/stub_instance_method_defined_on_class_test.rb +0 -66
  188. data/test/acceptance/stub_instance_method_defined_on_kernel_module_test.rb +0 -75
  189. data/test/acceptance/stub_instance_method_defined_on_module_test.rb +0 -75
  190. data/test/acceptance/stub_instance_method_defined_on_object_class_test.rb +0 -75
  191. data/test/acceptance/stub_instance_method_defined_on_singleton_class_test.rb +0 -70
  192. data/test/acceptance/stub_instance_method_defined_on_superclass_test.rb +0 -72
  193. data/test/acceptance/stub_module_method_test.rb +0 -163
  194. data/test/acceptance/stub_test.rb +0 -52
  195. data/test/acceptance/stubba_example_test.rb +0 -102
  196. data/test/acceptance/stubba_test.rb +0 -15
  197. data/test/acceptance/stubba_test_result_test.rb +0 -66
  198. data/test/acceptance/stubbing_error_backtrace_test.rb +0 -64
  199. data/test/acceptance/stubbing_method_unnecessarily_test.rb +0 -65
  200. data/test/acceptance/stubbing_non_existent_any_instance_method_test.rb +0 -130
  201. data/test/acceptance/stubbing_non_existent_class_method_test.rb +0 -157
  202. data/test/acceptance/stubbing_non_existent_instance_method_test.rb +0 -147
  203. data/test/acceptance/stubbing_non_public_any_instance_method_test.rb +0 -130
  204. data/test/acceptance/stubbing_non_public_class_method_test.rb +0 -163
  205. data/test/acceptance/stubbing_non_public_instance_method_test.rb +0 -143
  206. data/test/acceptance/stubbing_on_non_mock_object_test.rb +0 -64
  207. data/test/acceptance/throw_test.rb +0 -45
  208. data/test/acceptance/unstubbing_test.rb +0 -151
  209. data/test/deprecation_disabler.rb +0 -15
  210. data/test/execution_point.rb +0 -36
  211. data/test/method_definer.rb +0 -24
  212. data/test/mini_test_result.rb +0 -83
  213. data/test/simple_counter.rb +0 -13
  214. data/test/test_helper.rb +0 -11
  215. data/test/test_runner.rb +0 -50
  216. data/test/unit/any_instance_method_test.rb +0 -136
  217. data/test/unit/array_inspect_test.rb +0 -16
  218. data/test/unit/backtrace_filter_test.rb +0 -19
  219. data/test/unit/cardinality_test.rb +0 -56
  220. data/test/unit/central_test.rb +0 -100
  221. data/test/unit/change_state_side_effect_test.rb +0 -41
  222. data/test/unit/class_method_test.rb +0 -260
  223. data/test/unit/configuration_test.rb +0 -38
  224. data/test/unit/date_time_inspect_test.rb +0 -21
  225. data/test/unit/exception_raiser_test.rb +0 -42
  226. data/test/unit/expectation_list_test.rb +0 -71
  227. data/test/unit/expectation_test.rb +0 -480
  228. data/test/unit/hash_inspect_test.rb +0 -16
  229. data/test/unit/in_state_ordering_constraint_test.rb +0 -43
  230. data/test/unit/method_matcher_test.rb +0 -23
  231. data/test/unit/mock_test.rb +0 -312
  232. data/test/unit/mockery_test.rb +0 -150
  233. data/test/unit/multiple_yields_test.rb +0 -18
  234. data/test/unit/no_yields_test.rb +0 -18
  235. data/test/unit/object_inspect_test.rb +0 -38
  236. data/test/unit/object_test.rb +0 -87
  237. data/test/unit/parameter_matchers/all_of_test.rb +0 -26
  238. data/test/unit/parameter_matchers/any_of_test.rb +0 -26
  239. data/test/unit/parameter_matchers/anything_test.rb +0 -21
  240. data/test/unit/parameter_matchers/equals_test.rb +0 -25
  241. data/test/unit/parameter_matchers/has_entries_test.rb +0 -51
  242. data/test/unit/parameter_matchers/has_entry_test.rb +0 -96
  243. data/test/unit/parameter_matchers/has_key_test.rb +0 -55
  244. data/test/unit/parameter_matchers/has_value_test.rb +0 -57
  245. data/test/unit/parameter_matchers/includes_test.rb +0 -44
  246. data/test/unit/parameter_matchers/instance_of_test.rb +0 -25
  247. data/test/unit/parameter_matchers/is_a_test.rb +0 -25
  248. data/test/unit/parameter_matchers/kind_of_test.rb +0 -25
  249. data/test/unit/parameter_matchers/not_test.rb +0 -26
  250. data/test/unit/parameter_matchers/regexp_matches_test.rb +0 -46
  251. data/test/unit/parameter_matchers/responds_with_test.rb +0 -25
  252. data/test/unit/parameter_matchers/stub_matcher.rb +0 -27
  253. data/test/unit/parameter_matchers/yaml_equivalent_test.rb +0 -25
  254. data/test/unit/parameters_matcher_test.rb +0 -121
  255. data/test/unit/return_values_test.rb +0 -63
  256. data/test/unit/sequence_test.rb +0 -104
  257. data/test/unit/single_return_value_test.rb +0 -14
  258. data/test/unit/single_yield_test.rb +0 -18
  259. data/test/unit/state_machine_test.rb +0 -98
  260. data/test/unit/string_inspect_test.rb +0 -11
  261. data/test/unit/thrower_test.rb +0 -20
  262. data/test/unit/yield_parameters_test.rb +0 -93
data/lib/mocha/api.rb CHANGED
@@ -1,173 +1,241 @@
1
1
  require 'mocha/parameter_matchers'
2
+ require 'mocha/hooks'
2
3
  require 'mocha/mockery'
3
4
  require 'mocha/sequence'
5
+ require 'mocha/object_methods'
6
+ require 'mocha/class_methods'
4
7
 
5
- module Mocha # :nodoc:
6
-
7
- # Methods added to Test::Unit::TestCase or equivalent.
8
+ module Mocha
9
+ # Methods added to +Test::Unit::TestCase+, +MiniTest::Unit::TestCase+ or equivalent.
10
+ # The mock creation methods are {#mock}, {#stub} and {#stub_everything}, all of which return a #{Mock}
11
+ # which can be further modified by {Mock#responds_like} and {Mock#responds_like_instance_of} methods,
12
+ # both of which return a {Mock}, too, and can therefore, be chained to the original creation methods.
13
+ #
14
+ # {Mock#responds_like} and {Mock#responds_like_instance_of} force the mock to indicate what it is
15
+ # supposed to be mocking, thus making it a safer verifying mock. They check that the underlying +responder+
16
+ # will actually respond to the methods being stubbed, throwing a +NoMethodError+ upon invocation otherwise.
17
+ #
18
+ # @example Verifying mock using {Mock#responds_like_instance_of}
19
+ # class Sheep
20
+ # def initialize
21
+ # raise "some awkward code we don't want to call"
22
+ # end
23
+ # def chew(grass); end
24
+ # end
25
+ #
26
+ # sheep = mock('sheep').responds_like_instance_of(Sheep)
27
+ # sheep.expects(:chew)
28
+ # sheep.expects(:foo)
29
+ # sheep.respond_to?(:chew) # => true
30
+ # sheep.respond_to?(:foo) # => false
31
+ # sheep.chew
32
+ # sheep.foo # => raises NoMethodError exception
8
33
  module API
9
-
10
34
  include ParameterMatchers
11
-
12
- # :call-seq: mock(name, &block) -> mock object
13
- # mock(expected_methods = {}, &block) -> mock object
14
- # mock(name, expected_methods = {}, &block) -> mock object
15
- #
16
- # Creates a mock object.
17
- #
18
- # +name+ is a +String+ identifier for the mock object.
19
- #
20
- # +expected_methods+ is a +Hash+ with expected method name symbols as keys and corresponding return values as values.
21
- #
22
- # Note that (contrary to expectations set up by #stub) these expectations <b>must</b> be fulfilled during the test.
23
- # def test_product
24
- # product = mock('ipod_product', :manufacturer => 'ipod', :price => 100)
25
- # assert_equal 'ipod', product.manufacturer
26
- # assert_equal 100, product.price
27
- # # an error will be raised unless both Product#manufacturer and Product#price have been called
28
- # end
29
- #
30
- # +block+ is an optional block to be evaluated against the mock object instance, giving an alernative way to set up expectations & stubs.
31
- # def test_product
32
- # product = mock('ipod_product') do
33
- # expects(:manufacturer).returns('ipod')
34
- # expects(:price).returns(100)
35
- # end
36
- # assert_equal 'ipod', product.manufacturer
37
- # assert_equal 100, product.price
38
- # # an error will be raised unless both Product#manufacturer and Product#price have been called
39
- # end
40
- def mock(*arguments, &block)
41
- name = arguments.shift if arguments.first.is_a?(String)
35
+ include Hooks
36
+
37
+ # @private
38
+ def self.included(_mod)
39
+ Object.send(:include, Mocha::ObjectMethods)
40
+ Class.send(:include, Mocha::ClassMethods)
41
+ end
42
+
43
+ # @private
44
+ def self.extended(mod)
45
+ included(mod)
46
+ end
47
+
48
+ # Builds a new mock object
49
+ #
50
+ # @return [Mock] a new mock object
51
+ #
52
+ # @overload def mock(name)
53
+ # @param [String, Symbol] name identifies mock object in error messages.
54
+ # @note Prior to v1.10.0 when +name+ was a +Symbol+, this method returned an unnamed +Mock+ that expected the method identified by +name+. This was undocumented behaviour and it will be removed in the future, but for the moment it can be reinstated using {Configuration#reinstate_undocumented_behaviour_from_v1_9=}.
55
+ # @overload def mock(expected_methods_vs_return_values = {})
56
+ # @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.
57
+ # @overload def mock(name, expected_methods_vs_return_values = {})
58
+ # @param [String, Symbol] name identifies mock object in error messages.
59
+ # @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.
60
+ #
61
+ # @example Using expected_methods_vs_return_values Hash to setup expectations.
62
+ # def test_motor_starts_and_stops
63
+ # motor = mock('motor', :start => true, :stop => true)
64
+ # assert motor.start
65
+ # assert motor.stop
66
+ # # an error will be raised unless both Motor#start and Motor#stop have been called
67
+ # end
68
+ #
69
+ def mock(*arguments) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
70
+ if Mocha.configuration.reinstate_undocumented_behaviour_from_v1_9?
71
+ if arguments.first.is_a?(Symbol)
72
+ method_name = arguments[0]
73
+ Deprecation.warning(
74
+ "Explicitly include `#{method_name}` in Hash of expected methods vs return values,",
75
+ " e.g. `mock(:#{method_name} => nil)`."
76
+ )
77
+ if arguments[1]
78
+ Deprecation.warning(
79
+ "In this case the 2nd argument for `mock(:##{method_name}, ...)` is ignored,",
80
+ ' but in the future a Hash of expected methods vs return values will be respected.'
81
+ )
82
+ end
83
+ elsif arguments.first.is_a?(String)
84
+ name = arguments.shift
85
+ end
86
+ elsif arguments.first.is_a?(String) || arguments.first.is_a?(Symbol)
87
+ name = arguments.shift
88
+ end
42
89
  expectations = arguments.shift || {}
43
- mock = name ? Mockery.instance.named_mock(name, &block) : Mockery.instance.unnamed_mock(&block)
90
+ mock = name ? Mockery.instance.named_mock(name) : Mockery.instance.unnamed_mock
44
91
  mock.expects(expectations)
45
92
  mock
46
93
  end
47
-
48
- # :call-seq: stub(name, &block) -> mock object
49
- # stub(stubbed_methods = {}, &block) -> mock object
50
- # stub(name, stubbed_methods = {}, &block) -> mock object
51
- #
52
- # Creates a mock object.
53
- #
54
- # +name+ is a +String+ identifier for the mock object.
55
- #
56
- # +stubbed_methods+ is a +Hash+ with stubbed method name symbols as keys and corresponding return values as values.
57
- # Note that (contrary to expectations set up by #mock) these expectations <b>need not</b> be fulfilled during the test.
58
- # def test_product
59
- # product = stub('ipod_product', :manufacturer => 'ipod', :price => 100)
60
- # assert_equal 'ipod', product.manufacturer
61
- # assert_equal 100, product.price
62
- # # an error will not be raised even if Product#manufacturer and Product#price have not been called
63
- # end
64
- #
65
- # +block+ is an optional block to be evaluated against the mock object instance, giving an alernative way to set up expectations & stubs.
66
- # def test_product
67
- # product = stub('ipod_product') do
68
- # stubs(:manufacturer).returns('ipod')
69
- # stubs(:price).returns(100)
70
- # end
71
- # assert_equal 'ipod', product.manufacturer
72
- # assert_equal 100, product.price
73
- # # an error will not be raised even if Product#manufacturer and Product#price have not been called
94
+
95
+ # Builds a new mock object
96
+ #
97
+ # @return [Mock] a new mock object
98
+ #
99
+ # @overload def stub(name)
100
+ # @param [String, Symbol] name identifies mock object in error messages.
101
+ # @note Prior to v1.10.0 when +name+ was a +Symbol+, this method returned an unnamed +Mock+ that stubbed the method identified by +name+. This was undocumented behaviour and it will be removed in the future, but for the moment it can be reinstated using {Configuration#reinstate_undocumented_behaviour_from_v1_9=}.
102
+ # @overload def stub(stubbed_methods_vs_return_values = {})
103
+ # @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.
104
+ # @overload def stub(name, stubbed_methods_vs_return_values = {})
105
+ # @param [String, Symbol] name identifies mock object in error messages.
106
+ #
107
+ # @example Using stubbed_methods_vs_return_values Hash to setup stubbed methods.
108
+ # def test_motor_starts_and_stops
109
+ # motor = stub('motor', :start => true, :stop => true)
110
+ # assert motor.start
111
+ # assert motor.stop
112
+ # # an error will not be raised even if either Motor#start or Motor#stop has not been called
74
113
  # end
75
- def stub(*arguments, &block)
76
- name = arguments.shift if arguments.first.is_a?(String)
114
+ # rubocop:disable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
115
+ def stub(*arguments)
116
+ if Mocha.configuration.reinstate_undocumented_behaviour_from_v1_9?
117
+ if arguments.first.is_a?(Symbol)
118
+ method_name = arguments[0]
119
+ Deprecation.warning(
120
+ "Explicitly include `#{method_name}` in Hash of stubbed methods vs return values,",
121
+ " e.g. `stub(:#{method_name} => nil)`."
122
+ )
123
+ if arguments[1]
124
+ Deprecation.warning(
125
+ "In this case the 2nd argument for `stub(:##{method_name}, ...)` is ignored,",
126
+ ' but in the future a Hash of stubbed methods vs return values will be respected.'
127
+ )
128
+ end
129
+ elsif arguments.first.is_a?(String)
130
+ name = arguments.shift
131
+ end
132
+ elsif arguments.first.is_a?(String) || arguments.first.is_a?(Symbol)
133
+ name = arguments.shift
134
+ end
77
135
  expectations = arguments.shift || {}
78
- stub = name ? Mockery.instance.named_mock(name, &block) : Mockery.instance.unnamed_mock(&block)
136
+ stub = name ? Mockery.instance.named_mock(name) : Mockery.instance.unnamed_mock
79
137
  stub.stubs(expectations)
80
138
  stub
81
139
  end
82
-
83
- # :call-seq: stub_everything(name, &block) -> mock object
84
- # stub_everything(stubbed_methods = {}, &block) -> mock object
85
- # stub_everything(name, stubbed_methods = {}, &block) -> mock object
86
- #
87
- # Creates a mock object that accepts calls to any method.
88
- #
89
- # By default it will return +nil+ for any method call.
90
- #
91
- # +block+ is a block to be evaluated against the mock object instance, giving an alernative way to set up expectations & stubs.
92
- #
93
- # +name+ and +stubbed_methods+ work in the same way as for #stub.
94
- # def test_product
95
- # product = stub_everything('ipod_product', :price => 100)
96
- # assert_nil product.manufacturer
97
- # assert_nil product.any_old_method
98
- # assert_equal 100, product.price
140
+ # rubocop:enable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
141
+
142
+ # Builds a mock object that accepts calls to any method. By default it will return +nil+ for any method call.
143
+ #
144
+ # @return [Mock] a new mock object
145
+ #
146
+ # @overload def stub_everything(name)
147
+ # @param [String, Symbol] name identifies mock object in error messages.
148
+ # @note Prior to v1.10.0 when +name+ was a +Symbol+, this method returned an unnamed +Mock+ that stubbed the method identified by +name+. This was undocumented behaviour and it will be removed in the future, but for the moment it can be reinstated using {Configuration#reinstate_undocumented_behaviour_from_v1_9=}.
149
+ # @overload def stub_everything(stubbed_methods_vs_return_values = {})
150
+ # @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.
151
+ # @overload def stub_everything(name, stubbed_methods_vs_return_values = {})
152
+ # @param [String, Symbol] name identifies mock object in error messages.
153
+ # @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.
154
+ #
155
+ # @example Ignore invocations of irrelevant methods.
156
+ # def test_motor_stops
157
+ # motor = stub_everything('motor', :stop => true)
158
+ # assert_nil motor.irrelevant_method_1 # => no error raised
159
+ # assert_nil motor.irrelevant_method_2 # => no error raised
160
+ # assert motor.stop
99
161
  # end
100
- def stub_everything(*arguments, &block)
101
- name = arguments.shift if arguments.first.is_a?(String)
162
+ # rubocop:disable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
163
+ def stub_everything(*arguments)
164
+ if Mocha.configuration.reinstate_undocumented_behaviour_from_v1_9?
165
+ if arguments.first.is_a?(Symbol)
166
+ method_name = arguments[0]
167
+ Deprecation.warning(
168
+ "Explicitly include `#{method_name}` in Hash of stubbed methods vs return values,",
169
+ " e.g. `stub_everything(:#{method_name} => nil)`."
170
+ )
171
+ if arguments[1]
172
+ Deprecation.warning(
173
+ "In this case the 2nd argument for `stub_everything(:##{method_name}, ...)` is ignored,",
174
+ ' but in the future a Hash of stubbed methods vs return values will be respected.'
175
+ )
176
+ end
177
+ elsif arguments.first.is_a?(String)
178
+ name = arguments.shift
179
+ end
180
+ elsif arguments.first.is_a?(String) || arguments.first.is_a?(Symbol)
181
+ name = arguments.shift
182
+ end
102
183
  expectations = arguments.shift || {}
103
- stub = name ? Mockery.instance.named_mock(name, &block) : Mockery.instance.unnamed_mock(&block)
184
+ stub = name ? Mockery.instance.named_mock(name) : Mockery.instance.unnamed_mock
104
185
  stub.stub_everything
105
186
  stub.stubs(expectations)
106
187
  stub
107
188
  end
108
-
109
- # :call-seq: sequence(name) -> sequence
189
+ # rubocop:enable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
190
+
191
+ # Builds a new sequence which can be used to constrain the order in which expectations can occur.
192
+ #
193
+ # Specify that an expected invocation must occur within a named {Sequence} by using {Expectation#in_sequence}.
110
194
  #
111
- # Returns a new sequence that is used to constrain the order in which expectations can occur.
195
+ # @return [Sequence] a new sequence
112
196
  #
113
- # Specify that an expected invocation must occur in within a named +sequence+ by using Expectation#in_sequence.
197
+ # @see Expectation#in_sequence
114
198
  #
115
- # See also Expectation#in_sequence.
199
+ # @example Ensure methods on egg are invoked in correct order.
116
200
  # breakfast = sequence('breakfast')
117
201
  #
118
- # egg = mock('egg')
119
- # egg.expects(:crack).in_sequence(breakfast)
120
- # egg.expects(:fry).in_sequence(breakfast)
121
- # egg.expects(:eat).in_sequence(breakfast)
202
+ # egg = mock('egg') do
203
+ # expects(:crack).in_sequence(breakfast)
204
+ # expects(:fry).in_sequence(breakfast)
205
+ # expects(:eat).in_sequence(breakfast)
206
+ # end
122
207
  def sequence(name)
123
208
  Sequence.new(name)
124
209
  end
125
-
126
- # :call-seq: states(name) -> state_machine
210
+
211
+ # Builds a new state machine which can be used to constrain the order in which expectations can occur.
127
212
  #
128
- # Returns a new +state_machine+ that is used to constrain the order in which expectations can occur.
213
+ # Specify the initial state of the state machine by using {StateMachine#starts_as}.
129
214
  #
130
- # Specify the initial +state+ of the +state_machine+ by using StateMachine#starts_as.
215
+ # Specify that an expected invocation should change the state of the state machine by using {Expectation#then}.
131
216
  #
132
- # Specify that an expected invocation should change the +state+ of the +state_machine+ by using Expectation#then.
217
+ # Specify that an expected invocation should be constrained to occur within a particular +state+ by using {Expectation#when}.
133
218
  #
134
- # Specify that an expected invocation should be constrained to occur within a particular +state+ by using Expectation#when.
219
+ # A test can contain multiple state machines.
135
220
  #
136
- # A test can contain multiple +state_machines+.
221
+ # @return [StateMachine] a new state machine
137
222
  #
138
- # See also Expectation#then, Expectation#when and StateMachine.
223
+ # @see Expectation#then
224
+ # @see Expectation#when
225
+ # @see StateMachine
226
+ # @example Constrain expected invocations to occur in particular states.
139
227
  # power = states('power').starts_as('off')
140
228
  #
141
- # radio = mock('radio')
142
- # radio.expects(:switch_on).then(power.is('on'))
143
- # radio.expects(:select_channel).with('BBC Radio 4').when(power.is('on'))
144
- # radio.expects(:adjust_volume).with(+5).when(power.is('on'))
145
- # radio.expects(:select_channel).with('BBC World Service').when(power.is('on'))
146
- # radio.expects(:adjust_volume).with(-5).when(power.is('on'))
147
- # radio.expects(:switch_off).then(power.is('off'))
229
+ # radio = mock('radio') do
230
+ # expects(:switch_on).then(power.is('on'))
231
+ # expects(:select_channel).with('BBC Radio 4').when(power.is('on'))
232
+ # expects(:adjust_volume).with(+5).when(power.is('on'))
233
+ # expects(:select_channel).with('BBC World Service').when(power.is('on'))
234
+ # expects(:adjust_volume).with(-5).when(power.is('on'))
235
+ # expects(:switch_off).then(power.is('off'))
236
+ # end
148
237
  def states(name)
149
238
  Mockery.instance.new_state_machine(name)
150
239
  end
151
-
152
- def mocha_setup # :nodoc:
153
- end
154
-
155
- def mocha_verify(assertion_counter = nil) # :nodoc:
156
- Mockery.instance.verify(assertion_counter)
157
- end
158
-
159
- def mocha_teardown # :nodoc:
160
- Mockery.instance.teardown
161
- Mockery.reset_instance
162
- end
163
-
164
- end
165
-
166
- def self.const_missing(name)
167
- return super unless name == :Standalone
168
- require 'mocha/deprecation'
169
- Deprecation.warning "Mocha::Standalone has been renamed to Mocha::API"
170
- return API
171
240
  end
172
-
173
241
  end
@@ -1,21 +1,17 @@
1
1
  module Mocha
2
-
3
2
  class ArgumentIterator
4
-
5
3
  def initialize(argument)
6
4
  @argument = argument
7
5
  end
8
-
9
- def each(&block)
10
- if @argument.is_a?(Hash) then
6
+
7
+ def each
8
+ if @argument.is_a?(Hash)
11
9
  @argument.each do |method_name, return_value|
12
- block.call(method_name, return_value)
10
+ yield method_name, return_value
13
11
  end
14
12
  else
15
- block.call(@argument)
13
+ yield @argument
16
14
  end
17
15
  end
18
-
19
16
  end
20
-
21
- end
17
+ end
@@ -1,8 +1,6 @@
1
1
  module Mocha
2
-
3
2
  class BacktraceFilter
4
-
5
- LIB_DIRECTORY = File.expand_path(File.join(File.dirname(__FILE__), "..")) + File::SEPARATOR
3
+ LIB_DIRECTORY = File.expand_path(File.join(File.dirname(__FILE__), '..')) + File::SEPARATOR
6
4
 
7
5
  def initialize(lib_directory = LIB_DIRECTORY)
8
6
  @path_pattern = Regexp.new(lib_directory)
@@ -11,7 +9,5 @@ module Mocha
11
9
  def filtered(backtrace)
12
10
  backtrace.reject { |location| @path_pattern.match(File.expand_path(location)) }
13
11
  end
14
-
15
12
  end
16
-
17
13
  end
@@ -0,0 +1,31 @@
1
+ module Mocha
2
+ module BlockMatchers
3
+ class OptionalBlock
4
+ def match?(_actual_block)
5
+ true
6
+ end
7
+
8
+ def mocha_inspect; end
9
+ end
10
+
11
+ class BlockGiven
12
+ def match?(actual_block)
13
+ !actual_block.nil?
14
+ end
15
+
16
+ def mocha_inspect
17
+ 'with block given'
18
+ end
19
+ end
20
+
21
+ class NoBlockGiven
22
+ def match?(actual_block)
23
+ actual_block.nil?
24
+ end
25
+
26
+ def mocha_inspect
27
+ 'with no block given'
28
+ end
29
+ end
30
+ end
31
+ end
@@ -1,95 +1,106 @@
1
1
  module Mocha
2
-
3
2
  class Cardinality
4
-
5
3
  INFINITY = 1 / 0.0
6
-
7
- class << self
8
-
9
- def exactly(count)
10
- new(count, count)
11
- end
12
-
13
- def at_least(count)
14
- new(count, INFINITY)
15
- end
16
-
17
- def at_most(count)
18
- new(0, count)
19
- end
20
-
21
- def times(range_or_count)
22
- case range_or_count
23
- when Range then new(range_or_count.first, range_or_count.last)
24
- else new(range_or_count, range_or_count)
25
- end
4
+
5
+ def initialize(required = 0, maximum = INFINITY)
6
+ update(required, maximum)
7
+ @invocations = []
8
+ end
9
+
10
+ def exactly(count)
11
+ update(count, count)
12
+ end
13
+
14
+ def at_least(count)
15
+ update(count, INFINITY)
16
+ end
17
+
18
+ def at_most(count)
19
+ update(0, count)
20
+ end
21
+
22
+ def times(range_or_count)
23
+ case range_or_count
24
+ when Range then update(range_or_count.first, range_or_count.last)
25
+ else update(range_or_count, range_or_count)
26
26
  end
27
-
28
27
  end
29
-
30
- def initialize(required, maximum)
31
- @required, @maximum = required, maximum
28
+
29
+ def <<(invocation)
30
+ @invocations << invocation
32
31
  end
33
-
34
- def invocations_allowed?(invocation_count)
35
- invocation_count < maximum
32
+
33
+ def invocations_allowed?
34
+ @invocations.size < maximum
36
35
  end
37
-
38
- def satisfied?(invocations_so_far)
39
- invocations_so_far >= required
36
+
37
+ def satisfied?
38
+ @invocations.size >= required
40
39
  end
41
-
40
+
42
41
  def needs_verifying?
43
42
  !allowed_any_number_of_times?
44
43
  end
45
-
46
- def verified?(invocation_count)
47
- (invocation_count >= required) && (invocation_count <= maximum)
44
+
45
+ def verified?
46
+ (@invocations.size >= required) && (@invocations.size <= maximum)
48
47
  end
49
-
48
+
50
49
  def allowed_any_number_of_times?
51
- required == 0 && infinite?(maximum)
50
+ required.zero? && infinite?(maximum)
52
51
  end
53
-
54
- def used?(invocation_count)
55
- (invocation_count > 0) || (maximum == 0)
52
+
53
+ def used?
54
+ @invocations.any? || maximum.zero?
56
55
  end
57
-
58
- def mocha_inspect
56
+
57
+ # rubocop:disable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
58
+ def anticipated_times
59
59
  if allowed_any_number_of_times?
60
- "allowed any number of times"
60
+ 'allowed any number of times'
61
+ elsif required.zero? && maximum.zero?
62
+ "expected #{count(maximum)}"
63
+ elsif required == maximum
64
+ "expected exactly #{count(required)}"
65
+ elsif infinite?(maximum)
66
+ "expected at least #{count(required)}"
67
+ elsif required.zero?
68
+ "expected at most #{count(maximum)}"
61
69
  else
62
- if required == 0 && maximum == 0
63
- "expected never"
64
- elsif required == maximum
65
- "expected exactly #{times(required)}"
66
- elsif infinite?(maximum)
67
- "expected at least #{times(required)}"
68
- elsif required == 0
69
- "expected at most #{times(maximum)}"
70
- else
71
- "expected between #{required} and #{times(maximum)}"
72
- end
70
+ "expected between #{required} and #{count(maximum)}"
73
71
  end
74
72
  end
75
-
73
+ # rubocop:enable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
74
+
75
+ def invoked_times
76
+ "invoked #{count(@invocations.size)}"
77
+ end
78
+
79
+ def actual_invocations
80
+ @invocations.map(&:full_description).join
81
+ end
82
+
76
83
  protected
77
-
84
+
78
85
  attr_reader :required, :maximum
79
-
80
- def times(number)
86
+
87
+ def count(number)
81
88
  case number
82
- when 0 then "no times"
83
- when 1 then "once"
84
- when 2 then "twice"
85
- else "#{number} times"
89
+ when 0 then 'never'
90
+ when 1 then 'once'
91
+ when 2 then 'twice'
92
+ else "#{number} times"
86
93
  end
87
94
  end
88
-
95
+
96
+ def update(required, maximum)
97
+ @required = required
98
+ @maximum = maximum
99
+ self
100
+ end
101
+
89
102
  def infinite?(number)
90
103
  number.respond_to?(:infinite?) && number.infinite?
91
104
  end
92
-
93
105
  end
94
-
95
106
  end