mocha 1.4.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (269) hide show
  1. checksums.yaml +5 -5
  2. data/.github/FUNDING.yml +1 -0
  3. data/.rubocop.yml +53 -0
  4. data/.rubocop_todo.yml +27 -0
  5. data/.yardopts +1 -1
  6. data/CONTRIBUTING.md +4 -9
  7. data/COPYING.md +2 -2
  8. data/Gemfile +27 -0
  9. data/MIT-LICENSE.md +1 -1
  10. data/README.md +88 -117
  11. data/RELEASE.md +340 -0
  12. data/Rakefile +53 -52
  13. data/gemfiles/Gemfile.minitest.latest +1 -0
  14. data/gemfiles/Gemfile.test-unit.latest +2 -5
  15. data/lib/mocha/any_instance_method.rb +9 -62
  16. data/lib/mocha/api.rb +84 -74
  17. data/lib/mocha/argument_iterator.rb +4 -8
  18. data/lib/mocha/backtrace_filter.rb +3 -7
  19. data/lib/mocha/block_matcher.rb +31 -0
  20. data/lib/mocha/cardinality.rb +60 -49
  21. data/lib/mocha/central.rb +21 -12
  22. data/lib/mocha/change_state_side_effect.rb +0 -4
  23. data/lib/mocha/class_methods.rb +19 -21
  24. data/lib/mocha/configuration.rb +317 -52
  25. data/lib/mocha/debug.rb +2 -4
  26. data/lib/mocha/deprecation.rb +6 -12
  27. data/lib/mocha/detection/mini_test.rb +0 -2
  28. data/lib/mocha/detection/test_unit.rb +3 -5
  29. data/lib/mocha/error_with_filtered_backtrace.rb +13 -0
  30. data/lib/mocha/exception_raiser.rb +4 -6
  31. data/lib/mocha/expectation.rb +186 -95
  32. data/lib/mocha/expectation_error.rb +1 -1
  33. data/lib/mocha/expectation_error_factory.rb +0 -1
  34. data/lib/mocha/expectation_list.rb +7 -11
  35. data/lib/mocha/hooks.rb +1 -3
  36. data/lib/mocha/in_state_ordering_constraint.rb +0 -4
  37. data/lib/mocha/inspect.rb +30 -28
  38. data/lib/mocha/instance_method.rb +14 -3
  39. data/lib/mocha/integration/mini_test/adapter.rb +3 -5
  40. data/lib/mocha/integration/mini_test/exception_translation.rb +1 -1
  41. data/lib/mocha/integration/mini_test.rb +10 -31
  42. data/lib/mocha/integration/monkey_patcher.rb +5 -7
  43. data/lib/mocha/integration/test_unit/adapter.rb +8 -9
  44. data/lib/mocha/integration/test_unit.rb +10 -26
  45. data/lib/mocha/invocation.rb +73 -0
  46. data/lib/mocha/is_a.rb +0 -2
  47. data/lib/mocha/logger.rb +0 -4
  48. data/lib/mocha/macos_version.rb +5 -0
  49. data/lib/mocha/method_matcher.rb +1 -5
  50. data/lib/mocha/minitest.rb +5 -2
  51. data/lib/mocha/mock.rb +104 -68
  52. data/lib/mocha/mockery.rb +70 -99
  53. data/lib/mocha/names.rb +2 -12
  54. data/lib/mocha/not_initialized_error.rb +7 -0
  55. data/lib/mocha/object_methods.rb +25 -31
  56. data/lib/mocha/parameter_matchers/all_of.rb +2 -8
  57. data/lib/mocha/parameter_matchers/any_of.rb +2 -8
  58. data/lib/mocha/parameter_matchers/any_parameters.rb +3 -9
  59. data/lib/mocha/parameter_matchers/anything.rb +2 -8
  60. data/lib/mocha/parameter_matchers/base.rb +7 -13
  61. data/lib/mocha/parameter_matchers/equals.rb +0 -6
  62. data/lib/mocha/parameter_matchers/equivalent_uri.rb +3 -13
  63. data/lib/mocha/parameter_matchers/has_entries.rb +2 -7
  64. data/lib/mocha/parameter_matchers/has_entry.rb +26 -21
  65. data/lib/mocha/parameter_matchers/has_key.rb +2 -7
  66. data/lib/mocha/parameter_matchers/has_keys.rb +53 -0
  67. data/lib/mocha/parameter_matchers/has_value.rb +2 -7
  68. data/lib/mocha/parameter_matchers/includes.rb +4 -6
  69. data/lib/mocha/parameter_matchers/instance_methods.rb +27 -0
  70. data/lib/mocha/parameter_matchers/instance_of.rb +0 -6
  71. data/lib/mocha/parameter_matchers/is_a.rb +2 -7
  72. data/lib/mocha/parameter_matchers/kind_of.rb +2 -6
  73. data/lib/mocha/parameter_matchers/not.rb +2 -7
  74. data/lib/mocha/parameter_matchers/optionally.rb +4 -10
  75. data/lib/mocha/parameter_matchers/positional_or_keyword_hash.rb +64 -0
  76. data/lib/mocha/parameter_matchers/regexp_matches.rb +0 -6
  77. data/lib/mocha/parameter_matchers/responds_with.rb +3 -8
  78. data/lib/mocha/parameter_matchers/yaml_equivalent.rb +2 -6
  79. data/lib/mocha/parameter_matchers.rb +2 -3
  80. data/lib/mocha/parameters_matcher.rb +8 -11
  81. data/lib/mocha/raised_exception.rb +11 -0
  82. data/lib/mocha/receivers.rb +10 -14
  83. data/lib/mocha/return_values.rb +4 -8
  84. data/lib/mocha/ruby_version.rb +1 -2
  85. data/lib/mocha/sequence.rb +4 -9
  86. data/lib/mocha/single_return_value.rb +2 -5
  87. data/lib/mocha/state_machine.rb +33 -46
  88. data/lib/mocha/stubbed_method.rb +88 -0
  89. data/lib/mocha/stubbing_error.rb +2 -13
  90. data/lib/mocha/test_unit.rb +5 -2
  91. data/lib/mocha/thrower.rb +4 -6
  92. data/lib/mocha/thrown_object.rb +12 -0
  93. data/lib/mocha/version.rb +1 -1
  94. data/lib/mocha/yield_parameters.rb +7 -17
  95. data/mocha.gemspec +15 -65
  96. metadata +27 -257
  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 -5
  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 -58
  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 -301
  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 -201
  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 -75
  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 -76
  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 -16
  205. data/test/execution_point.rb +0 -38
  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 -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 -229
  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 -350
  234. data/test/unit/mockery_test.rb +0 -157
  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/equivalent_uri_test.rb +0 -51
  245. data/test/unit/parameter_matchers/has_entries_test.rb +0 -51
  246. data/test/unit/parameter_matchers/has_entry_test.rb +0 -129
  247. data/test/unit/parameter_matchers/has_key_test.rb +0 -55
  248. data/test/unit/parameter_matchers/has_value_test.rb +0 -57
  249. data/test/unit/parameter_matchers/includes_test.rb +0 -107
  250. data/test/unit/parameter_matchers/instance_of_test.rb +0 -25
  251. data/test/unit/parameter_matchers/is_a_test.rb +0 -25
  252. data/test/unit/parameter_matchers/kind_of_test.rb +0 -25
  253. data/test/unit/parameter_matchers/not_test.rb +0 -26
  254. data/test/unit/parameter_matchers/regexp_matches_test.rb +0 -46
  255. data/test/unit/parameter_matchers/responds_with_test.rb +0 -32
  256. data/test/unit/parameter_matchers/stub_matcher.rb +0 -27
  257. data/test/unit/parameter_matchers/yaml_equivalent_test.rb +0 -25
  258. data/test/unit/parameters_matcher_test.rb +0 -121
  259. data/test/unit/receivers_test.rb +0 -66
  260. data/test/unit/return_values_test.rb +0 -63
  261. data/test/unit/sequence_test.rb +0 -104
  262. data/test/unit/single_return_value_test.rb +0 -14
  263. data/test/unit/single_yield_test.rb +0 -18
  264. data/test/unit/state_machine_test.rb +0 -98
  265. data/test/unit/string_inspect_test.rb +0 -11
  266. data/test/unit/thrower_test.rb +0 -20
  267. data/test/unit/yield_parameters_test.rb +0 -93
  268. data/yard-templates/default/layout/html/google_analytics.erb +0 -11
  269. data/yard-templates/default/layout/html/setup.rb +0 -6
@@ -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('%<address>x', address: 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