mocha 1.2.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (266) hide show
  1. checksums.yaml +5 -5
  2. data/.github/FUNDING.yml +1 -0
  3. data/.rubocop.yml +65 -0
  4. data/.rubocop_todo.yml +27 -0
  5. data/.yardopts +1 -0
  6. data/CONTRIBUTING.md +4 -9
  7. data/Gemfile +29 -0
  8. data/README.md +110 -106
  9. data/RELEASE.md +306 -1
  10. data/Rakefile +52 -45
  11. data/gemfiles/Gemfile.minitest.latest +1 -0
  12. data/gemfiles/Gemfile.test-unit.latest +2 -5
  13. data/lib/mocha/any_instance_method.rb +9 -62
  14. data/lib/mocha/api.rb +84 -68
  15. data/lib/mocha/argument_iterator.rb +4 -8
  16. data/lib/mocha/backtrace_filter.rb +1 -5
  17. data/lib/mocha/block_matcher.rb +31 -0
  18. data/lib/mocha/cardinality.rb +60 -49
  19. data/lib/mocha/central.rb +21 -12
  20. data/lib/mocha/change_state_side_effect.rb +0 -4
  21. data/lib/mocha/class_methods.rb +19 -21
  22. data/lib/mocha/configuration.rb +312 -47
  23. data/lib/mocha/debug.rb +3 -2
  24. data/lib/mocha/deprecation.rb +8 -11
  25. data/lib/mocha/detection/mini_test.rb +0 -2
  26. data/lib/mocha/detection/test_unit.rb +3 -5
  27. data/lib/mocha/error_with_filtered_backtrace.rb +13 -0
  28. data/lib/mocha/exception_raiser.rb +4 -6
  29. data/lib/mocha/expectation.rb +186 -95
  30. data/lib/mocha/expectation_error.rb +1 -1
  31. data/lib/mocha/expectation_error_factory.rb +0 -1
  32. data/lib/mocha/expectation_list.rb +7 -11
  33. data/lib/mocha/hooks.rb +1 -3
  34. data/lib/mocha/in_state_ordering_constraint.rb +0 -4
  35. data/lib/mocha/inspect.rb +30 -38
  36. data/lib/mocha/instance_method.rb +11 -8
  37. data/lib/mocha/integration/mini_test/adapter.rb +2 -4
  38. data/lib/mocha/integration/mini_test/exception_translation.rb +1 -1
  39. data/lib/mocha/integration/mini_test.rb +10 -31
  40. data/lib/mocha/integration/monkey_patcher.rb +5 -7
  41. data/lib/mocha/integration/test_unit/adapter.rb +5 -6
  42. data/lib/mocha/integration/test_unit.rb +10 -26
  43. data/lib/mocha/invocation.rb +73 -0
  44. data/lib/mocha/is_a.rb +0 -2
  45. data/lib/mocha/logger.rb +0 -4
  46. data/lib/mocha/macos_version.rb +5 -0
  47. data/lib/mocha/method_matcher.rb +1 -5
  48. data/lib/mocha/minitest.rb +6 -0
  49. data/lib/mocha/mock.rb +99 -51
  50. data/lib/mocha/mockery.rb +70 -99
  51. data/lib/mocha/names.rb +2 -12
  52. data/lib/mocha/not_initialized_error.rb +7 -0
  53. data/lib/mocha/object_methods.rb +25 -31
  54. data/lib/mocha/parameter_matchers/all_of.rb +2 -8
  55. data/lib/mocha/parameter_matchers/any_of.rb +2 -8
  56. data/lib/mocha/parameter_matchers/any_parameters.rb +3 -9
  57. data/lib/mocha/parameter_matchers/anything.rb +2 -8
  58. data/lib/mocha/parameter_matchers/base.rb +7 -13
  59. data/lib/mocha/parameter_matchers/equals.rb +0 -6
  60. data/lib/mocha/parameter_matchers/{query_string.rb → equivalent_uri.rb} +14 -15
  61. data/lib/mocha/parameter_matchers/has_entries.rb +2 -7
  62. data/lib/mocha/parameter_matchers/has_entry.rb +26 -21
  63. data/lib/mocha/parameter_matchers/has_key.rb +2 -7
  64. data/lib/mocha/parameter_matchers/has_keys.rb +53 -0
  65. data/lib/mocha/parameter_matchers/has_value.rb +2 -7
  66. data/lib/mocha/parameter_matchers/includes.rb +6 -7
  67. data/lib/mocha/parameter_matchers/instance_methods.rb +27 -0
  68. data/lib/mocha/parameter_matchers/instance_of.rb +0 -6
  69. data/lib/mocha/parameter_matchers/is_a.rb +2 -7
  70. data/lib/mocha/parameter_matchers/kind_of.rb +2 -6
  71. data/lib/mocha/parameter_matchers/not.rb +2 -7
  72. data/lib/mocha/parameter_matchers/optionally.rb +4 -10
  73. data/lib/mocha/parameter_matchers/positional_or_keyword_hash.rb +64 -0
  74. data/lib/mocha/parameter_matchers/regexp_matches.rb +0 -6
  75. data/lib/mocha/parameter_matchers/responds_with.rb +3 -8
  76. data/lib/mocha/parameter_matchers/yaml_equivalent.rb +2 -6
  77. data/lib/mocha/parameter_matchers.rb +3 -4
  78. data/lib/mocha/parameters_matcher.rb +8 -11
  79. data/lib/mocha/raised_exception.rb +11 -0
  80. data/lib/mocha/receivers.rb +10 -14
  81. data/lib/mocha/return_values.rb +4 -8
  82. data/lib/mocha/ruby_version.rb +1 -2
  83. data/lib/mocha/sequence.rb +4 -9
  84. data/lib/mocha/single_return_value.rb +2 -5
  85. data/lib/mocha/state_machine.rb +33 -46
  86. data/lib/mocha/stubbed_method.rb +88 -0
  87. data/lib/mocha/stubbing_error.rb +2 -13
  88. data/lib/mocha/test_unit.rb +5 -2
  89. data/lib/mocha/thrower.rb +4 -6
  90. data/lib/mocha/thrown_object.rb +12 -0
  91. data/lib/mocha/version.rb +1 -1
  92. data/lib/mocha/yield_parameters.rb +7 -17
  93. data/mocha.gemspec +14 -65
  94. data/yard-templates/default/layout/html/google_analytics.erb +6 -9
  95. data/yard-templates/default/layout/html/setup.rb +2 -3
  96. metadata +26 -266
  97. data/bin/build-matrix +0 -70
  98. data/gemfiles/Gemfile.minitest.1.3.0 +0 -7
  99. data/gemfiles/Gemfile.minitest.1.4.0 +0 -7
  100. data/gemfiles/Gemfile.minitest.1.4.1 +0 -7
  101. data/gemfiles/Gemfile.minitest.1.4.2 +0 -7
  102. data/gemfiles/Gemfile.minitest.2.0.0 +0 -7
  103. data/gemfiles/Gemfile.minitest.2.0.1 +0 -7
  104. data/gemfiles/Gemfile.minitest.2.11.0 +0 -7
  105. data/gemfiles/Gemfile.minitest.2.11.2 +0 -7
  106. data/gemfiles/Gemfile.minitest.2.3.0 +0 -7
  107. data/gemfiles/Gemfile.test-unit.2.0.0 +0 -7
  108. data/gemfiles/Gemfile.test-unit.2.0.1 +0 -7
  109. data/gemfiles/Gemfile.test-unit.2.0.3 +0 -7
  110. data/init.rb +0 -3
  111. data/lib/mocha/class_method.rb +0 -119
  112. data/lib/mocha/integration/mini_test/nothing.rb +0 -19
  113. data/lib/mocha/integration/mini_test/version_13.rb +0 -51
  114. data/lib/mocha/integration/mini_test/version_140.rb +0 -51
  115. data/lib/mocha/integration/mini_test/version_141.rb +0 -62
  116. data/lib/mocha/integration/mini_test/version_142_to_172.rb +0 -62
  117. data/lib/mocha/integration/mini_test/version_200.rb +0 -63
  118. data/lib/mocha/integration/mini_test/version_201_to_222.rb +0 -63
  119. data/lib/mocha/integration/mini_test/version_2110_to_2111.rb +0 -67
  120. data/lib/mocha/integration/mini_test/version_2112_to_320.rb +0 -70
  121. data/lib/mocha/integration/mini_test/version_230_to_2101.rb +0 -65
  122. data/lib/mocha/integration/test_unit/gem_version_200.rb +0 -59
  123. data/lib/mocha/integration/test_unit/gem_version_201_to_202.rb +0 -59
  124. data/lib/mocha/integration/test_unit/gem_version_203_to_220.rb +0 -59
  125. data/lib/mocha/integration/test_unit/gem_version_230_to_250.rb +0 -65
  126. data/lib/mocha/integration/test_unit/nothing.rb +0 -19
  127. data/lib/mocha/integration/test_unit/ruby_version_185_and_below.rb +0 -58
  128. data/lib/mocha/integration/test_unit/ruby_version_186_and_above.rb +0 -60
  129. data/lib/mocha/integration.rb +0 -14
  130. data/lib/mocha/mini_test.rb +0 -3
  131. data/lib/mocha/module_method.rb +0 -16
  132. data/lib/mocha/module_methods.rb +0 -14
  133. data/lib/mocha/multiple_yields.rb +0 -20
  134. data/lib/mocha/no_yields.rb +0 -11
  135. data/lib/mocha/parameter_matchers/object.rb +0 -17
  136. data/lib/mocha/pretty_parameters.rb +0 -28
  137. data/lib/mocha/setup.rb +0 -9
  138. data/lib/mocha/single_yield.rb +0 -18
  139. data/lib/mocha/standalone.rb +0 -4
  140. data/lib/mocha/unexpected_invocation.rb +0 -26
  141. data/lib/mocha_standalone.rb +0 -4
  142. data/test/acceptance/acceptance_test_helper.rb +0 -41
  143. data/test/acceptance/bug_18914_test.rb +0 -43
  144. data/test/acceptance/bug_21465_test.rb +0 -34
  145. data/test/acceptance/bug_21563_test.rb +0 -25
  146. data/test/acceptance/exception_rescue_test.rb +0 -55
  147. data/test/acceptance/expectations_on_multiple_methods_test.rb +0 -55
  148. data/test/acceptance/expected_invocation_count_test.rb +0 -232
  149. data/test/acceptance/failure_messages_test.rb +0 -64
  150. data/test/acceptance/issue_272_test.rb +0 -52
  151. data/test/acceptance/issue_65_test.rb +0 -63
  152. data/test/acceptance/issue_70_test.rb +0 -55
  153. data/test/acceptance/mocha_example_test.rb +0 -98
  154. data/test/acceptance/mocha_test_result_test.rb +0 -84
  155. data/test/acceptance/mock_test.rb +0 -100
  156. data/test/acceptance/mock_with_initializer_block_test.rb +0 -51
  157. data/test/acceptance/mocked_methods_dispatch_test.rb +0 -78
  158. data/test/acceptance/multiple_expectations_failure_message_test.rb +0 -68
  159. data/test/acceptance/optional_parameters_test.rb +0 -70
  160. data/test/acceptance/parameter_matcher_test.rb +0 -337
  161. data/test/acceptance/partial_mocks_test.rb +0 -47
  162. data/test/acceptance/prepend_test.rb +0 -89
  163. data/test/acceptance/raise_exception_test.rb +0 -39
  164. data/test/acceptance/return_value_test.rb +0 -52
  165. data/test/acceptance/sequence_test.rb +0 -192
  166. data/test/acceptance/states_test.rb +0 -70
  167. data/test/acceptance/stub_any_instance_method_defined_on_superclass_test.rb +0 -34
  168. data/test/acceptance/stub_any_instance_method_test.rb +0 -280
  169. data/test/acceptance/stub_class_method_defined_on_active_record_association_proxy_test.rb +0 -106
  170. data/test/acceptance/stub_class_method_defined_on_class_test.rb +0 -78
  171. data/test/acceptance/stub_class_method_defined_on_module_test.rb +0 -75
  172. data/test/acceptance/stub_class_method_defined_on_superclass_test.rb +0 -112
  173. data/test/acceptance/stub_everything_test.rb +0 -56
  174. data/test/acceptance/stub_instance_method_defined_on_active_record_association_proxy_test.rb +0 -93
  175. data/test/acceptance/stub_instance_method_defined_on_class_and_aliased_test.rb +0 -69
  176. data/test/acceptance/stub_instance_method_defined_on_class_test.rb +0 -69
  177. data/test/acceptance/stub_instance_method_defined_on_kernel_module_test.rb +0 -75
  178. data/test/acceptance/stub_instance_method_defined_on_module_test.rb +0 -78
  179. data/test/acceptance/stub_instance_method_defined_on_object_class_test.rb +0 -75
  180. data/test/acceptance/stub_instance_method_defined_on_singleton_class_test.rb +0 -70
  181. data/test/acceptance/stub_instance_method_defined_on_superclass_test.rb +0 -72
  182. data/test/acceptance/stub_method_defined_on_module_and_aliased_test.rb +0 -39
  183. data/test/acceptance/stub_module_method_test.rb +0 -163
  184. data/test/acceptance/stub_test.rb +0 -52
  185. data/test/acceptance/stubba_example_test.rb +0 -102
  186. data/test/acceptance/stubba_test_result_test.rb +0 -66
  187. data/test/acceptance/stubbing_error_backtrace_test.rb +0 -64
  188. data/test/acceptance/stubbing_frozen_object_test.rb +0 -88
  189. data/test/acceptance/stubbing_method_accepting_block_parameter_test.rb +0 -48
  190. data/test/acceptance/stubbing_method_unnecessarily_test.rb +0 -65
  191. data/test/acceptance/stubbing_nil_test.rb +0 -61
  192. data/test/acceptance/stubbing_non_existent_any_instance_method_test.rb +0 -143
  193. data/test/acceptance/stubbing_non_existent_class_method_test.rb +0 -157
  194. data/test/acceptance/stubbing_non_existent_instance_method_test.rb +0 -147
  195. data/test/acceptance/stubbing_non_public_any_instance_method_test.rb +0 -130
  196. data/test/acceptance/stubbing_non_public_class_method_test.rb +0 -163
  197. data/test/acceptance/stubbing_non_public_instance_method_test.rb +0 -143
  198. data/test/acceptance/stubbing_on_non_mock_object_test.rb +0 -64
  199. data/test/acceptance/stubbing_same_class_method_on_parent_and_child_classes_test.rb +0 -35
  200. data/test/acceptance/throw_test.rb +0 -45
  201. data/test/acceptance/unexpected_invocation_test.rb +0 -25
  202. data/test/acceptance/unstubbing_test.rb +0 -168
  203. data/test/assertions.rb +0 -8
  204. data/test/deprecation_disabler.rb +0 -15
  205. data/test/execution_point.rb +0 -36
  206. data/test/integration/mini_test_test.rb +0 -8
  207. data/test/integration/shared_tests.rb +0 -174
  208. data/test/integration/test_unit_test.rb +0 -8
  209. data/test/method_definer.rb +0 -24
  210. data/test/mini_test_result.rb +0 -90
  211. data/test/minitest_result.rb +0 -49
  212. data/test/simple_counter.rb +0 -13
  213. data/test/test_helper.rb +0 -50
  214. data/test/test_runner.rb +0 -58
  215. data/test/test_unit_result.rb +0 -20
  216. data/test/unit/any_instance_method_test.rb +0 -134
  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 -225
  223. data/test/unit/class_methods_test.rb +0 -40
  224. data/test/unit/configuration_test.rb +0 -38
  225. data/test/unit/date_time_inspect_test.rb +0 -21
  226. data/test/unit/exception_raiser_test.rb +0 -42
  227. data/test/unit/expectation_list_test.rb +0 -82
  228. data/test/unit/expectation_test.rb +0 -497
  229. data/test/unit/hash_inspect_test.rb +0 -16
  230. data/test/unit/hooks_test.rb +0 -29
  231. data/test/unit/in_state_ordering_constraint_test.rb +0 -43
  232. data/test/unit/method_matcher_test.rb +0 -28
  233. data/test/unit/mock_test.rb +0 -342
  234. data/test/unit/mockery_test.rb +0 -151
  235. data/test/unit/module_methods_test.rb +0 -19
  236. data/test/unit/multiple_yields_test.rb +0 -18
  237. data/test/unit/no_yields_test.rb +0 -18
  238. data/test/unit/object_inspect_test.rb +0 -39
  239. data/test/unit/object_methods_test.rb +0 -46
  240. data/test/unit/parameter_matchers/all_of_test.rb +0 -26
  241. data/test/unit/parameter_matchers/any_of_test.rb +0 -26
  242. data/test/unit/parameter_matchers/anything_test.rb +0 -21
  243. data/test/unit/parameter_matchers/equals_test.rb +0 -25
  244. data/test/unit/parameter_matchers/has_entries_test.rb +0 -51
  245. data/test/unit/parameter_matchers/has_entry_test.rb +0 -129
  246. data/test/unit/parameter_matchers/has_key_test.rb +0 -55
  247. data/test/unit/parameter_matchers/has_value_test.rb +0 -57
  248. data/test/unit/parameter_matchers/includes_test.rb +0 -102
  249. data/test/unit/parameter_matchers/instance_of_test.rb +0 -25
  250. data/test/unit/parameter_matchers/is_a_test.rb +0 -25
  251. data/test/unit/parameter_matchers/kind_of_test.rb +0 -25
  252. data/test/unit/parameter_matchers/not_test.rb +0 -26
  253. data/test/unit/parameter_matchers/regexp_matches_test.rb +0 -46
  254. data/test/unit/parameter_matchers/responds_with_test.rb +0 -32
  255. data/test/unit/parameter_matchers/stub_matcher.rb +0 -27
  256. data/test/unit/parameter_matchers/yaml_equivalent_test.rb +0 -25
  257. data/test/unit/parameters_matcher_test.rb +0 -121
  258. data/test/unit/receivers_test.rb +0 -66
  259. data/test/unit/return_values_test.rb +0 -63
  260. data/test/unit/sequence_test.rb +0 -104
  261. data/test/unit/single_return_value_test.rb +0 -14
  262. data/test/unit/single_yield_test.rb +0 -18
  263. data/test/unit/state_machine_test.rb +0 -98
  264. data/test/unit/string_inspect_test.rb +0 -11
  265. data/test/unit/thrower_test.rb +0 -20
  266. data/test/unit/yield_parameters_test.rb +0 -93
@@ -1,3 +1,4 @@
1
+ require 'ruby2_keywords'
1
2
  require 'mocha/method_matcher'
2
3
  require 'mocha/parameters_matcher'
3
4
  require 'mocha/expectation_error'
@@ -9,12 +10,13 @@ require 'mocha/is_a'
9
10
  require 'mocha/in_state_ordering_constraint'
10
11
  require 'mocha/change_state_side_effect'
11
12
  require 'mocha/cardinality'
13
+ require 'mocha/configuration'
14
+ require 'mocha/block_matcher'
15
+ require 'mocha/backtrace_filter'
12
16
 
13
17
  module Mocha
14
-
15
18
  # Methods on expectations returned from {Mock#expects}, {Mock#stubs}, {ObjectMethods#expects} and {ObjectMethods#stubs}.
16
19
  class Expectation
17
-
18
20
  # Modifies expectation so that the number of calls to the expected method must be within a specific +range+.
19
21
  #
20
22
  # @param [Range,Integer] range specifies the allowable range in the number of expected invocations.
@@ -42,7 +44,7 @@ module Mocha
42
44
  # object.expected_method
43
45
  # # => verify fails
44
46
  def times(range)
45
- @cardinality = Cardinality.times(range)
47
+ @cardinality.times(range)
46
48
  self
47
49
  end
48
50
 
@@ -68,7 +70,7 @@ module Mocha
68
70
  # object.expected_method
69
71
  # # => verify fails
70
72
  def twice
71
- @cardinality = Cardinality.exactly(2)
73
+ @cardinality.exactly(2)
72
74
  self
73
75
  end
74
76
 
@@ -93,7 +95,7 @@ module Mocha
93
95
  # object.expects(:expected_method).once
94
96
  # # => verify fails
95
97
  def once
96
- @cardinality = Cardinality.exactly(1)
98
+ @cardinality.exactly(1)
97
99
  self
98
100
  end
99
101
 
@@ -110,7 +112,7 @@ module Mocha
110
112
  # object.expects(:expected_method).never
111
113
  # # => verify succeeds
112
114
  def never
113
- @cardinality = Cardinality.exactly(0)
115
+ @cardinality.exactly(0)
114
116
  self
115
117
  end
116
118
 
@@ -130,7 +132,7 @@ module Mocha
130
132
  # object.expected_method
131
133
  # # => verify fails
132
134
  def at_least(minimum_number_of_times)
133
- @cardinality = Cardinality.at_least(minimum_number_of_times)
135
+ @cardinality.at_least(minimum_number_of_times)
134
136
  self
135
137
  end
136
138
 
@@ -149,7 +151,6 @@ module Mocha
149
151
  # # => verify fails
150
152
  def at_least_once
151
153
  at_least(1)
152
- self
153
154
  end
154
155
 
155
156
  # Modifies expectation so that the expected method must be called at most a +maximum_number_of_times+.
@@ -167,7 +168,7 @@ module Mocha
167
168
  # object.expects(:expected_method).at_most(2)
168
169
  # 3.times { object.expected_method } # => unexpected invocation
169
170
  def at_most(maximum_number_of_times)
170
- @cardinality = Cardinality.at_most(maximum_number_of_times)
171
+ @cardinality.at_most(maximum_number_of_times)
171
172
  self
172
173
  end
173
174
 
@@ -184,22 +185,30 @@ module Mocha
184
185
  # object = mock()
185
186
  # object.expects(:expected_method).at_most_once
186
187
  # 2.times { object.expected_method } # => unexpected invocation
187
- def at_most_once()
188
+ def at_most_once
188
189
  at_most(1)
189
- self
190
190
  end
191
191
 
192
- # Modifies expectation so that the expected method must be called with +expected_parameters+.
192
+ # Modifies expectation so that the expected method must be called with +expected_parameters_or_matchers+.
193
+ #
194
+ # May be used with Ruby literals or variables for exact matching or with parameter matchers for less-specific matching, e.g. {ParameterMatchers#includes}, {ParameterMatchers#has_key}, etc. See {ParameterMatchers} for a list of all available parameter matchers.
195
+ #
196
+ # Positional arguments were separated from keyword arguments in Ruby v3 (see {https://www.ruby-lang.org/en/news/2019/12/12/separation-of-positional-and-keyword-arguments-in-ruby-3-0 this article}). In relation to this a new configuration option ({Configuration#strict_keyword_argument_matching=}) is available in Ruby >= 2.7.
197
+ #
198
+ # When {Configuration#strict_keyword_argument_matching=} is set to +false+ (which is currently the default), a positional +Hash+ and a set of keyword arguments passed to {#with} are treated the same for the purposes of parameter matching. However, a deprecation warning will be displayed if a positional +Hash+ matches a set of keyword arguments or vice versa. This is because {Configuration#strict_keyword_argument_matching=} will default to +true+ in the future.
199
+ #
200
+ # When {Configuration#strict_keyword_argument_matching=} is set to +true+, an actual positional +Hash+ will not match an expected set of keyword arguments; and vice versa, an actual set of keyword arguments will not match an expected positional +Hash+, i.e. the parameter matching is stricter.
193
201
  #
194
- # May be used with parameter matchers in {ParameterMatchers}.
202
+ # @see ParameterMatchers
203
+ # @see Configuration#strict_keyword_argument_matching=
195
204
  #
196
- # @param [*Array] expected_parameters parameters expected.
205
+ # @param [*Array<Object,ParameterMatchers::Base>] expected_parameters_or_matchers expected parameter values or parameter matchers.
197
206
  # @yield optional block specifying custom matching.
198
- # @yieldparam [*Array] actual_parameters parameters with which expected method was invoked.
207
+ # @yieldparam [*Array<Object>] actual_parameters parameters with which expected method was invoked.
199
208
  # @yieldreturn [Boolean] +true+ if +actual_parameters+ are acceptable.
200
209
  # @return [Expectation] the same expectation, thereby allowing invocations of other {Expectation} methods to be chained.
201
210
  #
202
- # @example Expected method must be called with expected parameters.
211
+ # @example Expected method must be called with exact parameter values.
203
212
  # object = mock()
204
213
  # object.expects(:expected_method).with(:param1, :param2)
205
214
  # object.expected_method(:param1, :param2)
@@ -210,6 +219,43 @@ module Mocha
210
219
  # object.expected_method(:param3)
211
220
  # # => verify fails
212
221
  #
222
+ # @example Expected method must be called with parameters matching parameter matchers.
223
+ # object = mock()
224
+ # object.expects(:expected_method).with(includes('string2'), anything)
225
+ # object.expected_method(['string1', 'string2'], 'any-old-value')
226
+ # # => verify succeeds
227
+ #
228
+ # object = mock()
229
+ # object.expects(:expected_method).with(includes('string2'), anything)
230
+ # object.expected_method(['string1'], 'any-old-value')
231
+ # # => verify fails
232
+ #
233
+ # @example Loose keyword argument matching (default)
234
+ #
235
+ # class Example
236
+ # def foo(a, bar:); end
237
+ # end
238
+ #
239
+ # example = Example.new
240
+ # example.expects(:foo).with('a', bar: 'b')
241
+ # example.foo('a', { bar: 'b' })
242
+ # # This passes the test, but would result in an ArgumentError in practice
243
+ #
244
+ # @example Strict keyword argument matching
245
+ #
246
+ # Mocha.configure do |c|
247
+ # c.strict_keyword_argument_matching = true
248
+ # end
249
+ #
250
+ # class Example
251
+ # def foo(a, bar:); end
252
+ # end
253
+ #
254
+ # example = Example.new
255
+ # example.expects(:foo).with('a', bar: 'b')
256
+ # example.foo('a', { bar: 'b' })
257
+ # # This now fails as expected
258
+ #
213
259
  # @example Expected method must be called with a value divisible by 4.
214
260
  # object = mock()
215
261
  # object.expects(:expected_method).with() { |value| value % 4 == 0 }
@@ -220,12 +266,55 @@ module Mocha
220
266
  # object.expects(:expected_method).with() { |value| value % 4 == 0 }
221
267
  # object.expected_method(17)
222
268
  # # => verify fails
223
- def with(*expected_parameters, &matching_block)
224
- @parameters_matcher = ParametersMatcher.new(expected_parameters, &matching_block)
269
+ def with(*expected_parameters_or_matchers, &matching_block)
270
+ @parameters_matcher = ParametersMatcher.new(expected_parameters_or_matchers, self, &matching_block)
271
+ self
272
+ end
273
+ ruby2_keywords(:with)
274
+
275
+ # Modifies expectation so that the expected method must be called with a block.
276
+ #
277
+ # @return [Expectation] the same expectation, thereby allowing invocations of other {Expectation} methods to be chained.
278
+ #
279
+ # @example Expected method must be called with a block.
280
+ # object = mock()
281
+ # object.expects(:expected_method).with_block_given
282
+ # object.expected_method { 1 + 1 }
283
+ # # => verify succeeds
284
+ #
285
+ # object = mock()
286
+ # object.expects(:expected_method).with_block_given
287
+ # object.expected_method
288
+ # # => verify fails
289
+ def with_block_given
290
+ @block_matcher = BlockMatchers::BlockGiven.new
291
+ self
292
+ end
293
+
294
+ # Modifies expectation so that the expected method must be called without a block.
295
+ #
296
+ # @return [Expectation] the same expectation, thereby allowing invocations of other {Expectation} methods to be chained.
297
+ #
298
+ # @example Expected method must be called without a block.
299
+ # object = mock()
300
+ # object.expects(:expected_method).with_no_block_given
301
+ # object.expected_method
302
+ # # => verify succeeds
303
+ #
304
+ # object = mock()
305
+ # object.expects(:expected_method).with_block_given
306
+ # object.expected_method { 1 + 1 }
307
+ # # => verify fails
308
+ def with_no_block_given
309
+ @block_matcher = BlockMatchers::NoBlockGiven.new
225
310
  self
226
311
  end
227
312
 
228
- # Modifies expectation so that when the expected method is called, it yields with the specified +parameters+.
313
+ # Modifies expectation so that when the expected method is called, it yields to the block with the specified +parameters+.
314
+ #
315
+ # If no +parameters+ are specified, it yields to the block without any parameters.
316
+ #
317
+ # If no block is provided, the method will still attempt to yield resulting in a +LocalJumpError+. Note that this is what would happen if a "real" (non-mock) method implementation tried to yield to a non-existent block.
229
318
  #
230
319
  # May be called multiple times on the same expectation for consecutive invocations.
231
320
  #
@@ -233,51 +322,58 @@ module Mocha
233
322
  # @return [Expectation] the same expectation, thereby allowing invocations of other {Expectation} methods to be chained.
234
323
  # @see #then
235
324
  #
325
+ # @example Yield when expected method is invoked.
326
+ # benchmark = mock()
327
+ # benchmark.expects(:measure).yields
328
+ # yielded = false
329
+ # benchmark.measure { yielded = true }
330
+ # yielded # => true
331
+ #
236
332
  # @example Yield parameters when expected method is invoked.
237
- # object = mock()
238
- # object.expects(:expected_method).yields('result')
239
- # yielded_value = nil
240
- # object.expected_method { |value| yielded_value = value }
241
- # yielded_value # => 'result'
333
+ # fibonacci = mock()
334
+ # fibonacci.expects(:next_pair).yields(0, 1)
335
+ # sum = 0
336
+ # fibonacci.next_pair { |first, second| sum = first + second }
337
+ # sum # => 1
242
338
  #
243
339
  # @example Yield different parameters on different invocations of the expected method.
244
- # object = mock()
245
- # object.stubs(:expected_method).yields(1).then.yields(2)
246
- # yielded_values_from_first_invocation = []
247
- # yielded_values_from_second_invocation = []
248
- # object.expected_method { |value| yielded_values_from_first_invocation << value } # first invocation
249
- # object.expected_method { |value| yielded_values_from_second_invocation << value } # second invocation
250
- # yielded_values_from_first_invocation # => [1]
251
- # yielded_values_from_second_invocation # => [2]
340
+ # fibonacci = mock()
341
+ # fibonacci.expects(:next_pair).yields(0, 1).then.yields(1, 1)
342
+ # sum = 0
343
+ # fibonacci.next_pair { |first, second| sum = first + second }
344
+ # sum # => 1
345
+ # fibonacci.next_pair { |first, second| sum = first + second }
346
+ # sum # => 2
252
347
  def yields(*parameters)
253
- @yield_parameters.add(*parameters)
254
- self
348
+ multiple_yields(parameters)
255
349
  end
256
350
 
257
351
  # Modifies expectation so that when the expected method is called, it yields multiple times per invocation with the specified +parameter_groups+.
258
352
  #
259
- # @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.
353
+ # If no block is provided, the method will still attempt to yield resulting in a +LocalJumpError+. Note that this is what would happen if a "real" (non-mock) method implementation tried to yield to a non-existent block.
354
+ #
355
+ # @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. Any element of +parameter_groups+ that is not an +Array+ is wrapped in an +Array+.
260
356
  # @return [Expectation] the same expectation, thereby allowing invocations of other {Expectation} methods to be chained.
261
357
  # @see #then
262
358
  #
263
- # @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.
264
- # object = mock()
265
- # object.expects(:expected_method).multiple_yields(['result_1', 'result_2'], ['result_3'])
266
- # yielded_values = []
267
- # object.expected_method { |*values| yielded_values << values }
268
- # yielded_values # => [['result_1', 'result_2'], ['result_3]]
269
- #
270
- # @example Yield different groups of parameters on different invocations of the expected method.
271
- # object = mock()
272
- # object.stubs(:expected_method).multiple_yields([1, 2], [3]).then.multiple_yields([4], [5, 6])
273
- # yielded_values_from_first_invocation = []
274
- # yielded_values_from_second_invocation = []
275
- # object.expected_method { |*values| yielded_values_from_first_invocation << values } # first invocation
276
- # object.expected_method { |*values| yielded_values_from_second_invocation << values } # second invocation
277
- # yielded_values_from_first_invocation # => [[1, 2], [3]]
278
- # yielded_values_from_second_invocation # => [[4], [5, 6]]
359
+ # @example When +foreach+ is called, the stub will invoke the block twice, the first time it passes ['row1_col1', 'row1_col2'] as the parameters, and the second time it passes ['row2_col1', ''] as the parameters.
360
+ # csv = mock()
361
+ # csv.expects(:foreach).with("path/to/file.csv").multiple_yields(['row1_col1', 'row1_col2'], ['row2_col1', ''])
362
+ # rows = []
363
+ # csv.foreach { |row| rows << row }
364
+ # rows # => [['row1_col1', 'row1_col2'], ['row2_col1', '']]
365
+ #
366
+ # @example Yield different groups of parameters on different invocations of the expected method. Simulating a situation where the CSV file at 'path/to/file.csv' has been modified between the two calls to +foreach+.
367
+ # csv = mock()
368
+ # csv.stubs(:foreach).with("path/to/file.csv").multiple_yields(['old_row1_col1', 'old_row1_col2'], ['old_row2_col1', '']).then.multiple_yields(['new_row1_col1', ''], ['new_row2_col1', 'new_row2_col2'])
369
+ # rows_from_first_invocation = []
370
+ # rows_from_second_invocation = []
371
+ # csv.foreach { |row| rows_from_first_invocation << row } # first invocation
372
+ # csv.foreach { |row| rows_from_second_invocation << row } # second invocation
373
+ # rows_from_first_invocation # => [['old_row1_col1', 'old_row1_col2'], ['old_row2_col1', '']]
374
+ # rows_from_second_invocation # => [['new_row1_col1', ''], ['new_row2_col1', 'new_row2_col2']]
279
375
  def multiple_yields(*parameter_groups)
280
- @yield_parameters.multiple_add(*parameter_groups)
376
+ @yield_parameters.add(*parameter_groups)
281
377
  self
282
378
  end
283
379
 
@@ -409,9 +505,9 @@ module Mocha
409
505
 
410
506
  # @overload def then
411
507
  # Used as syntactic sugar to improve readability. It has no effect on state of the expectation.
412
- # @overload def then(state_machine.is(state_name))
413
- # Used to change the +state_machine+ to the state specified by +state_name+ when the expected invocation occurs.
414
- # @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.
508
+ # @overload def then(state)
509
+ # Used to change the +state_machine+ to the specified state when the expected invocation occurs.
510
+ # @param [StateMachine::State] 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.
415
511
  #
416
512
  # @see API#states
417
513
  # @see StateMachine
@@ -437,17 +533,14 @@ module Mocha
437
533
  # radio.expects(:select_channel).with('BBC World Service').when(power.is('on'))
438
534
  # radio.expects(:adjust_volume).with(-5).when(power.is('on'))
439
535
  # radio.expects(:switch_off).then(power.is('off'))
440
- def then(*parameters)
441
- if parameters.length == 1
442
- state = parameters.first
443
- add_side_effect(ChangeStateSideEffect.new(state))
444
- end
536
+ def then(state = nil)
537
+ add_side_effect(ChangeStateSideEffect.new(state)) if state
445
538
  self
446
539
  end
447
540
 
448
- # Constrains the expectation to occur only when the +state_machine+ is in the state specified by +state_name+.
541
+ # Constrains the expectation to occur only when the +state_machine+ is in the state specified by +state_predicate+.
449
542
  #
450
- # @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.
543
+ # @param [StateMachine::StatePredicate] state_predicate +state_machine.is(state_name)+ provides a mechanism to determine whether the +state_machine+ is in the state specified by +state_predicate+ when the expected method is invoked.
451
544
  # @return [Expectation] the same expectation, thereby allowing invocations of other {Expectation} methods to be chained.
452
545
  #
453
546
  # @see API#states
@@ -479,7 +572,8 @@ module Mocha
479
572
  #
480
573
  # An expected method can appear in multiple sequences.
481
574
  #
482
- # @param [*Array<Sequence>] sequences sequences in which expected method should appear.
575
+ # @param [Sequence] sequence sequence in which expected method should appear.
576
+ # @param [*Array<Sequence>] sequences more sequences in which expected method should appear.
483
577
  # @return [Expectation] the same expectation, thereby allowing invocations of other {Expectation} methods to be chained.
484
578
  #
485
579
  # @see API#sequence
@@ -491,8 +585,8 @@ module Mocha
491
585
  # egg.expects(:crack).in_sequence(breakfast)
492
586
  # egg.expects(:fry).in_sequence(breakfast)
493
587
  # egg.expects(:eat).in_sequence(breakfast)
494
- def in_sequence(*sequences)
495
- sequences.each { |sequence| add_in_sequence_ordering_constraint(sequence) }
588
+ def in_sequence(sequence, *sequences)
589
+ sequences.unshift(sequence).each { |seq| add_in_sequence_ordering_constraint(seq) }
496
590
  self
497
591
  end
498
592
 
@@ -504,9 +598,10 @@ module Mocha
504
598
  @mock = mock
505
599
  @method_matcher = MethodMatcher.new(expected_method_name.to_sym)
506
600
  @parameters_matcher = ParametersMatcher.new
601
+ @block_matcher = BlockMatchers::OptionalBlock.new
507
602
  @ordering_constraints = []
508
603
  @side_effects = []
509
- @cardinality, @invocation_count = Cardinality.exactly(1), 0
604
+ @cardinality = Cardinality.new.exactly(1)
510
605
  @return_values = ReturnValues.new
511
606
  @yield_parameters = YieldParameters.new
512
607
  @backtrace = backtrace || caller
@@ -529,12 +624,12 @@ module Mocha
529
624
 
530
625
  # @private
531
626
  def perform_side_effects
532
- @side_effects.each { |side_effect| side_effect.perform }
627
+ @side_effects.each(&:perform)
533
628
  end
534
629
 
535
630
  # @private
536
631
  def in_correct_order?
537
- @ordering_constraints.all? { |ordering_constraint| ordering_constraint.allows_invocation_now? }
632
+ @ordering_constraints.all?(&:allows_invocation_now?)
538
633
  end
539
634
 
540
635
  # @private
@@ -543,70 +638,66 @@ module Mocha
543
638
  end
544
639
 
545
640
  # @private
546
- def match?(actual_method_name, *actual_parameters)
547
- @method_matcher.match?(actual_method_name) && @parameters_matcher.match?(actual_parameters) && in_correct_order?
641
+ def match?(invocation)
642
+ @method_matcher.match?(invocation.method_name) && @parameters_matcher.match?(invocation.arguments) && @block_matcher.match?(invocation.block) && in_correct_order?
548
643
  end
549
644
 
550
645
  # @private
551
646
  def invocations_allowed?
552
- @cardinality.invocations_allowed?(@invocation_count)
647
+ @cardinality.invocations_allowed?
553
648
  end
554
649
 
555
650
  # @private
556
651
  def satisfied?
557
- @cardinality.satisfied?(@invocation_count)
652
+ @cardinality.satisfied?
558
653
  end
559
654
 
560
655
  # @private
561
- def invoke
562
- @invocation_count += 1
563
- perform_side_effects()
564
- if block_given? then
565
- @yield_parameters.next_invocation.each do |yield_parameters|
566
- yield(*yield_parameters)
567
- end
568
- end
569
- @return_values.next
656
+ def invoke(invocation)
657
+ perform_side_effects
658
+ @cardinality << invocation
659
+ invocation.call(@yield_parameters, @return_values)
570
660
  end
571
661
 
572
662
  # @private
573
663
  def verified?(assertion_counter = nil)
574
664
  assertion_counter.increment if assertion_counter && @cardinality.needs_verifying?
575
- @cardinality.verified?(@invocation_count)
665
+ @cardinality.verified?
576
666
  end
577
667
 
578
668
  # @private
579
669
  def used?
580
- @cardinality.used?(@invocation_count)
670
+ @cardinality.used?
581
671
  end
582
672
 
583
673
  # @private
584
674
  def inspect
585
675
  address = __id__ * 2
586
676
  address += 0x100000000 if address < 0
587
- "#<Expectation:0x#{'%x' % address} #{mocha_inspect} >"
677
+ "#<Expectation:0x#{format('%x', address)} #{mocha_inspect} >"
588
678
  end
589
679
 
590
680
  # @private
591
681
  def mocha_inspect
592
- message = "#{@cardinality.mocha_inspect}, "
593
- message << case @invocation_count
594
- when 0 then "not yet invoked"
595
- when 1 then "invoked once"
596
- when 2 then "invoked twice"
597
- else "invoked #{@invocation_count} times"
682
+ message = "#{@cardinality.anticipated_times}, #{@cardinality.invoked_times}: #{method_signature}"
683
+ message << "; #{@ordering_constraints.map(&:mocha_inspect).join('; ')}" unless @ordering_constraints.empty?
684
+ if Mocha.configuration.display_matching_invocations_on_failure?
685
+ message << @cardinality.actual_invocations
598
686
  end
599
- message << ": "
600
- message << method_signature
601
- message << "; #{@ordering_constraints.map { |oc| oc.mocha_inspect }.join("; ")}" unless @ordering_constraints.empty?
602
687
  message
603
688
  end
604
689
 
605
690
  # @private
606
691
  def method_signature
607
- "#{@mock.mocha_inspect}.#{@method_matcher.mocha_inspect}#{@parameters_matcher.mocha_inspect}"
692
+ signature = "#{@mock.mocha_inspect}.#{@method_matcher.mocha_inspect}#{@parameters_matcher.mocha_inspect}"
693
+ signature << " #{@block_matcher.mocha_inspect}" if @block_matcher.mocha_inspect
694
+ signature
608
695
  end
609
696
 
697
+ # @private
698
+ def definition_location
699
+ filter = BacktraceFilter.new
700
+ filter.filtered(backtrace)[0]
701
+ end
610
702
  end
611
-
612
703
  end
@@ -4,5 +4,5 @@ module Mocha
4
4
  # Authors of test libraries may use +Mocha::ExpectationErrorFactory+ to have Mocha raise a different exception.
5
5
  #
6
6
  # @see Mocha::ExpectationErrorFactory
7
- class ExpectationError < Exception; end
7
+ class ExpectationError < Exception; end # rubocop:disable Lint/InheritException
8
8
  end
@@ -2,7 +2,6 @@ require 'mocha/backtrace_filter'
2
2
  require 'mocha/expectation_error'
3
3
 
4
4
  module Mocha
5
-
6
5
  # This factory determines what class of exception should be raised when Mocha detects a test failure.
7
6
  #
8
7
  # This class should only be used by authors of test libraries and not by typical "users" of Mocha.
@@ -1,7 +1,5 @@
1
1
  module Mocha
2
-
3
2
  class ExpectationList
4
-
5
3
  def initialize(expectations = [])
6
4
  @expectations = expectations
7
5
  end
@@ -19,12 +17,12 @@ module Mocha
19
17
  @expectations.any? { |expectation| expectation.matches_method?(method_name) }
20
18
  end
21
19
 
22
- def match(method_name, *arguments)
23
- matching_expectations(method_name, *arguments).first
20
+ def match(invocation)
21
+ matching_expectations(invocation).first
24
22
  end
25
23
 
26
- def match_allowing_invocation(method_name, *arguments)
27
- matching_expectations(method_name, *arguments).detect { |e| e.invocations_allowed? }
24
+ def match_allowing_invocation(invocation)
25
+ matching_expectations(invocation).detect(&:invocations_allowed?)
28
26
  end
29
27
 
30
28
  def verified?(assertion_counter = nil)
@@ -48,15 +46,13 @@ module Mocha
48
46
  end
49
47
 
50
48
  def +(other)
51
- self.class.new(self.to_a + other.to_a)
49
+ self.class.new(to_a + other.to_a)
52
50
  end
53
51
 
54
52
  private
55
53
 
56
- def matching_expectations(method_name, *arguments)
57
- @expectations.select { |e| e.match?(method_name, *arguments) }
54
+ def matching_expectations(invocation)
55
+ @expectations.select { |e| e.match?(invocation) }
58
56
  end
59
-
60
57
  end
61
-
62
58
  end
data/lib/mocha/hooks.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  require 'mocha/mockery'
2
2
 
3
3
  module Mocha
4
-
5
4
  # Integration hooks for test library authors.
6
5
  #
7
6
  # The methods in this module should be called from test libraries wishing to integrate with Mocha.
@@ -21,6 +20,7 @@ module Mocha
21
20
  #
22
21
  # This method should be called before each individual test starts (including before any "setup" code).
23
22
  def mocha_setup
23
+ Mockery.setup
24
24
  end
25
25
 
26
26
  # Verifies that all mock expectations have been met (only for use by authors of test libraries).
@@ -37,8 +37,6 @@ module Mocha
37
37
  # This method should be called after each individual test has finished (including after any "teardown" code).
38
38
  def mocha_teardown
39
39
  Mockery.teardown
40
- ensure
41
- Mockery.reset_instance
42
40
  end
43
41
  end
44
42
  end
@@ -1,7 +1,5 @@
1
1
  module Mocha
2
-
3
2
  class InStateOrderingConstraint
4
-
5
3
  def initialize(state_predicate)
6
4
  @state_predicate = state_predicate
7
5
  end
@@ -13,7 +11,5 @@ module Mocha
13
11
  def mocha_inspect
14
12
  "when #{@state_predicate.mocha_inspect}"
15
13
  end
16
-
17
14
  end
18
-
19
15
  end