mocha 1.8.0 → 1.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (274) hide show
  1. checksums.yaml +4 -4
  2. data/.github/FUNDING.yml +1 -0
  3. data/.rubocop.yml +3 -0
  4. data/.rubocop_todo.yml +7 -30
  5. data/.yardopts +1 -0
  6. data/CONTRIBUTING.md +1 -1
  7. data/README.md +56 -31
  8. data/RELEASE.md +166 -0
  9. data/Rakefile +15 -7
  10. data/init.rb +1 -3
  11. data/lib/mocha/any_instance_method.rb +11 -53
  12. data/lib/mocha/api.rb +119 -56
  13. data/lib/mocha/block_matcher.rb +31 -0
  14. data/lib/mocha/cardinality.rb +52 -34
  15. data/lib/mocha/class_methods.rb +17 -15
  16. data/lib/mocha/configuration.rb +351 -67
  17. data/lib/mocha/deprecation.rb +2 -1
  18. data/lib/mocha/detection/test_unit.rb +1 -3
  19. data/lib/mocha/exception_raiser.rb +2 -1
  20. data/lib/mocha/expectation.rb +120 -81
  21. data/lib/mocha/expectation_error.rb +1 -3
  22. data/lib/mocha/expectation_list.rb +6 -6
  23. data/lib/mocha/inspect.rb +30 -26
  24. data/lib/mocha/instance_method.rb +19 -2
  25. data/lib/mocha/integration/mini_test.rb +7 -0
  26. data/lib/mocha/integration/test_unit.rb +7 -0
  27. data/lib/mocha/integration.rb +1 -3
  28. data/lib/mocha/invocation.rb +77 -0
  29. data/lib/mocha/macos_version.rb +5 -0
  30. data/lib/mocha/minitest.rb +6 -1
  31. data/lib/mocha/mock.rb +80 -39
  32. data/lib/mocha/mockery.rb +34 -80
  33. data/lib/mocha/names.rb +1 -1
  34. data/lib/mocha/object_methods.rb +13 -19
  35. data/lib/mocha/parameter_matchers/all_of.rb +1 -1
  36. data/lib/mocha/parameter_matchers/any_of.rb +1 -1
  37. data/lib/mocha/parameter_matchers/equivalent_uri.rb +0 -9
  38. data/lib/mocha/parameter_matchers/has_entries.rb +2 -3
  39. data/lib/mocha/parameter_matchers/has_entry.rb +24 -16
  40. data/lib/mocha/parameter_matchers/has_key.rb +2 -3
  41. data/lib/mocha/parameter_matchers/has_keys.rb +53 -0
  42. data/lib/mocha/parameter_matchers/has_value.rb +2 -3
  43. data/lib/mocha/parameter_matchers/includes.rb +2 -0
  44. data/lib/mocha/parameter_matchers/instance_methods.rb +18 -0
  45. data/lib/mocha/parameter_matchers/is_a.rb +2 -3
  46. data/lib/mocha/parameter_matchers/not.rb +2 -3
  47. data/lib/mocha/parameter_matchers.rb +2 -1
  48. data/lib/mocha/raised_exception.rb +11 -0
  49. data/lib/mocha/return_values.rb +3 -3
  50. data/lib/mocha/setup.rb +5 -0
  51. data/lib/mocha/single_return_value.rb +2 -1
  52. data/lib/mocha/singleton_class.rb +9 -0
  53. data/lib/mocha/state_machine.rb +31 -40
  54. data/lib/mocha/stubbed_method.rb +125 -0
  55. data/lib/mocha/test_unit.rb +6 -1
  56. data/lib/mocha/thrower.rb +2 -1
  57. data/lib/mocha/thrown_object.rb +12 -0
  58. data/lib/mocha/version.rb +1 -1
  59. data/lib/mocha/yield_parameters.rb +5 -11
  60. data/lib/mocha.rb +8 -0
  61. data/mocha.gemspec +14 -10
  62. metadata +16 -233
  63. data/bin/build-matrix +0 -83
  64. data/docs/CNAME +0 -1
  65. data/docs/Mocha/API.html +0 -1056
  66. data/docs/Mocha/ClassMethods.html +0 -267
  67. data/docs/Mocha/Configuration.html +0 -626
  68. data/docs/Mocha/Expectation.html +0 -2709
  69. data/docs/Mocha/ExpectationError.html +0 -157
  70. data/docs/Mocha/ExpectationErrorFactory.html +0 -269
  71. data/docs/Mocha/Hooks.html +0 -385
  72. data/docs/Mocha/Integration/MiniTest/Adapter.html +0 -165
  73. data/docs/Mocha/Integration/MiniTest.html +0 -123
  74. data/docs/Mocha/Integration/TestUnit/Adapter.html +0 -165
  75. data/docs/Mocha/Integration/TestUnit.html +0 -123
  76. data/docs/Mocha/Integration.html +0 -125
  77. data/docs/Mocha/Mock.html +0 -1197
  78. data/docs/Mocha/ObjectMethods.html +0 -712
  79. data/docs/Mocha/ParameterMatchers/AllOf.html +0 -154
  80. data/docs/Mocha/ParameterMatchers/AnyOf.html +0 -154
  81. data/docs/Mocha/ParameterMatchers/AnyParameters.html +0 -153
  82. data/docs/Mocha/ParameterMatchers/Anything.html +0 -153
  83. data/docs/Mocha/ParameterMatchers/Base.html +0 -448
  84. data/docs/Mocha/ParameterMatchers/Equals.html +0 -154
  85. data/docs/Mocha/ParameterMatchers/EquivalentUri.html +0 -153
  86. data/docs/Mocha/ParameterMatchers/HasEntries.html +0 -154
  87. data/docs/Mocha/ParameterMatchers/HasEntry.html +0 -154
  88. data/docs/Mocha/ParameterMatchers/HasKey.html +0 -154
  89. data/docs/Mocha/ParameterMatchers/HasValue.html +0 -154
  90. data/docs/Mocha/ParameterMatchers/Includes.html +0 -154
  91. data/docs/Mocha/ParameterMatchers/InstanceOf.html +0 -154
  92. data/docs/Mocha/ParameterMatchers/IsA.html +0 -153
  93. data/docs/Mocha/ParameterMatchers/KindOf.html +0 -154
  94. data/docs/Mocha/ParameterMatchers/Not.html +0 -154
  95. data/docs/Mocha/ParameterMatchers/Optionally.html +0 -153
  96. data/docs/Mocha/ParameterMatchers/RegexpMatches.html +0 -154
  97. data/docs/Mocha/ParameterMatchers/RespondsWith.html +0 -154
  98. data/docs/Mocha/ParameterMatchers/YamlEquivalent.html +0 -154
  99. data/docs/Mocha/ParameterMatchers.html +0 -3049
  100. data/docs/Mocha/Sequence.html +0 -149
  101. data/docs/Mocha/StateMachine/State.html +0 -141
  102. data/docs/Mocha/StateMachine/StatePredicate.html +0 -141
  103. data/docs/Mocha/StateMachine.html +0 -539
  104. data/docs/Mocha/StubbingError.html +0 -150
  105. data/docs/Mocha/UnexpectedInvocation.html +0 -140
  106. data/docs/Mocha.html +0 -127
  107. data/docs/_index.html +0 -537
  108. data/docs/class_list.html +0 -51
  109. data/docs/css/common.css +0 -1
  110. data/docs/css/full_list.css +0 -58
  111. data/docs/css/style.css +0 -496
  112. data/docs/file.COPYING.html +0 -81
  113. data/docs/file.MIT-LICENSE.html +0 -85
  114. data/docs/file.README.html +0 -418
  115. data/docs/file.RELEASE.html +0 -875
  116. data/docs/file_list.html +0 -71
  117. data/docs/frames.html +0 -17
  118. data/docs/index.html +0 -418
  119. data/docs/js/app.js +0 -292
  120. data/docs/js/full_list.js +0 -216
  121. data/docs/js/jquery.js +0 -4
  122. data/docs/method_list.html +0 -571
  123. data/docs/top-level-namespace.html +0 -118
  124. data/gemfiles/Gemfile.minitest.1.3.0 +0 -7
  125. data/gemfiles/Gemfile.minitest.1.4.0 +0 -7
  126. data/gemfiles/Gemfile.minitest.1.4.1 +0 -7
  127. data/gemfiles/Gemfile.minitest.1.4.2 +0 -7
  128. data/gemfiles/Gemfile.minitest.2.0.0 +0 -7
  129. data/gemfiles/Gemfile.minitest.2.0.1 +0 -7
  130. data/gemfiles/Gemfile.minitest.2.11.0 +0 -7
  131. data/gemfiles/Gemfile.minitest.2.11.2 +0 -7
  132. data/gemfiles/Gemfile.minitest.2.3.0 +0 -7
  133. data/gemfiles/Gemfile.test-unit.2.0.0 +0 -7
  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 -113
  137. data/lib/mocha/mini_test.rb +0 -5
  138. data/lib/mocha/module_method.rb +0 -6
  139. data/lib/mocha/module_methods.rb +0 -10
  140. data/lib/mocha/multiple_yields.rb +0 -15
  141. data/lib/mocha/no_yields.rb +0 -5
  142. data/lib/mocha/parameter_matchers/object.rb +0 -15
  143. data/lib/mocha/pretty_parameters.rb +0 -24
  144. data/lib/mocha/single_yield.rb +0 -13
  145. data/lib/mocha/standalone.rb +0 -4
  146. data/lib/mocha/unexpected_invocation.rb +0 -24
  147. data/lib/mocha_standalone.rb +0 -4
  148. data/test/acceptance/acceptance_test_helper.rb +0 -35
  149. data/test/acceptance/bug_18914_test.rb +0 -38
  150. data/test/acceptance/bug_21465_test.rb +0 -32
  151. data/test/acceptance/bug_21563_test.rb +0 -23
  152. data/test/acceptance/exception_rescue_test.rb +0 -54
  153. data/test/acceptance/expectations_on_multiple_methods_test.rb +0 -56
  154. data/test/acceptance/expected_invocation_count_test.rb +0 -230
  155. data/test/acceptance/failure_messages_test.rb +0 -62
  156. data/test/acceptance/issue_272_test.rb +0 -51
  157. data/test/acceptance/issue_65_test.rb +0 -65
  158. data/test/acceptance/issue_70_test.rb +0 -54
  159. data/test/acceptance/mocha_example_test.rb +0 -97
  160. data/test/acceptance/mocha_test_result_test.rb +0 -84
  161. data/test/acceptance/mock_test.rb +0 -98
  162. data/test/acceptance/mock_with_initializer_block_test.rb +0 -56
  163. data/test/acceptance/mocked_methods_dispatch_test.rb +0 -76
  164. data/test/acceptance/multiple_expectations_failure_message_test.rb +0 -67
  165. data/test/acceptance/optional_parameters_test.rb +0 -68
  166. data/test/acceptance/parameter_matcher_test.rb +0 -300
  167. data/test/acceptance/partial_mocks_test.rb +0 -45
  168. data/test/acceptance/prepend_test.rb +0 -87
  169. data/test/acceptance/prevent_use_of_mocha_outside_test_test.rb +0 -77
  170. data/test/acceptance/raise_exception_test.rb +0 -37
  171. data/test/acceptance/return_value_test.rb +0 -50
  172. data/test/acceptance/sequence_test.rb +0 -190
  173. data/test/acceptance/states_test.rb +0 -72
  174. data/test/acceptance/stub_any_instance_method_defined_on_superclass_test.rb +0 -65
  175. data/test/acceptance/stub_any_instance_method_test.rb +0 -282
  176. data/test/acceptance/stub_class_method_defined_on_active_record_association_proxy_test.rb +0 -106
  177. data/test/acceptance/stub_class_method_defined_on_class_test.rb +0 -79
  178. data/test/acceptance/stub_class_method_defined_on_module_test.rb +0 -74
  179. data/test/acceptance/stub_class_method_defined_on_superclass_test.rb +0 -145
  180. data/test/acceptance/stub_everything_test.rb +0 -54
  181. data/test/acceptance/stub_instance_method_defined_on_active_record_association_proxy_test.rb +0 -92
  182. data/test/acceptance/stub_instance_method_defined_on_class_and_aliased_test.rb +0 -68
  183. data/test/acceptance/stub_instance_method_defined_on_class_test.rb +0 -68
  184. data/test/acceptance/stub_instance_method_defined_on_kernel_module_test.rb +0 -137
  185. data/test/acceptance/stub_instance_method_defined_on_module_test.rb +0 -77
  186. data/test/acceptance/stub_instance_method_defined_on_object_class_test.rb +0 -76
  187. data/test/acceptance/stub_instance_method_defined_on_singleton_class_test.rb +0 -68
  188. data/test/acceptance/stub_instance_method_defined_on_superclass_test.rb +0 -71
  189. data/test/acceptance/stub_method_defined_on_module_and_aliased_test.rb +0 -39
  190. data/test/acceptance/stub_module_method_test.rb +0 -201
  191. data/test/acceptance/stub_test.rb +0 -50
  192. data/test/acceptance/stubba_example_test.rb +0 -94
  193. data/test/acceptance/stubba_test_result_test.rb +0 -72
  194. data/test/acceptance/stubbing_error_backtrace_test.rb +0 -64
  195. data/test/acceptance/stubbing_frozen_object_test.rb +0 -89
  196. data/test/acceptance/stubbing_method_accepting_block_parameter_test.rb +0 -53
  197. data/test/acceptance/stubbing_method_unnecessarily_test.rb +0 -63
  198. data/test/acceptance/stubbing_nil_test.rb +0 -60
  199. data/test/acceptance/stubbing_non_existent_any_instance_method_test.rb +0 -141
  200. data/test/acceptance/stubbing_non_existent_class_method_test.rb +0 -157
  201. data/test/acceptance/stubbing_non_existent_instance_method_test.rb +0 -145
  202. data/test/acceptance/stubbing_non_public_any_instance_method_test.rb +0 -128
  203. data/test/acceptance/stubbing_non_public_class_method_test.rb +0 -163
  204. data/test/acceptance/stubbing_non_public_instance_method_test.rb +0 -141
  205. data/test/acceptance/stubbing_on_non_mock_object_test.rb +0 -70
  206. data/test/acceptance/stubbing_same_class_method_on_parent_and_child_classes_test.rb +0 -34
  207. data/test/acceptance/throw_test.rb +0 -43
  208. data/test/acceptance/unexpected_invocation_test.rb +0 -24
  209. data/test/acceptance/unstubbing_test.rb +0 -195
  210. data/test/assertions.rb +0 -8
  211. data/test/deprecation_disabler.rb +0 -15
  212. data/test/execution_point.rb +0 -36
  213. data/test/integration/mini_test_test.rb +0 -8
  214. data/test/integration/shared_tests.rb +0 -176
  215. data/test/integration/test_unit_test.rb +0 -8
  216. data/test/method_definer.rb +0 -22
  217. data/test/mini_test_result.rb +0 -96
  218. data/test/minitest_result.rb +0 -48
  219. data/test/simple_counter.rb +0 -11
  220. data/test/test_helper.rb +0 -58
  221. data/test/test_runner.rb +0 -56
  222. data/test/test_unit_result.rb +0 -22
  223. data/test/unit/any_instance_method_test.rb +0 -150
  224. data/test/unit/array_inspect_test.rb +0 -14
  225. data/test/unit/backtrace_filter_test.rb +0 -17
  226. data/test/unit/cardinality_test.rb +0 -54
  227. data/test/unit/central_test.rb +0 -99
  228. data/test/unit/change_state_side_effect_test.rb +0 -37
  229. data/test/unit/class_method_test.rb +0 -254
  230. data/test/unit/class_methods_test.rb +0 -69
  231. data/test/unit/configuration_test.rb +0 -37
  232. data/test/unit/date_time_inspect_test.rb +0 -19
  233. data/test/unit/exception_raiser_test.rb +0 -40
  234. data/test/unit/expectation_list_test.rb +0 -80
  235. data/test/unit/expectation_test.rb +0 -492
  236. data/test/unit/hash_inspect_test.rb +0 -14
  237. data/test/unit/hooks_test.rb +0 -35
  238. data/test/unit/in_state_ordering_constraint_test.rb +0 -39
  239. data/test/unit/method_matcher_test.rb +0 -26
  240. data/test/unit/mock_test.rb +0 -363
  241. data/test/unit/mockery_test.rb +0 -174
  242. data/test/unit/module_methods_test.rb +0 -17
  243. data/test/unit/multiple_yields_test.rb +0 -16
  244. data/test/unit/no_yields_test.rb +0 -16
  245. data/test/unit/object_inspect_test.rb +0 -58
  246. data/test/unit/object_methods_test.rb +0 -62
  247. data/test/unit/parameter_matchers/all_of_test.rb +0 -24
  248. data/test/unit/parameter_matchers/any_of_test.rb +0 -24
  249. data/test/unit/parameter_matchers/anything_test.rb +0 -19
  250. data/test/unit/parameter_matchers/equals_test.rb +0 -23
  251. data/test/unit/parameter_matchers/equivalent_uri_test.rb +0 -50
  252. data/test/unit/parameter_matchers/has_entries_test.rb +0 -51
  253. data/test/unit/parameter_matchers/has_entry_test.rb +0 -128
  254. data/test/unit/parameter_matchers/has_key_test.rb +0 -54
  255. data/test/unit/parameter_matchers/has_value_test.rb +0 -55
  256. data/test/unit/parameter_matchers/includes_test.rb +0 -106
  257. data/test/unit/parameter_matchers/instance_of_test.rb +0 -23
  258. data/test/unit/parameter_matchers/is_a_test.rb +0 -23
  259. data/test/unit/parameter_matchers/kind_of_test.rb +0 -23
  260. data/test/unit/parameter_matchers/not_test.rb +0 -24
  261. data/test/unit/parameter_matchers/regexp_matches_test.rb +0 -45
  262. data/test/unit/parameter_matchers/responds_with_test.rb +0 -38
  263. data/test/unit/parameter_matchers/stub_matcher.rb +0 -23
  264. data/test/unit/parameter_matchers/yaml_equivalent_test.rb +0 -23
  265. data/test/unit/parameters_matcher_test.rb +0 -119
  266. data/test/unit/receivers_test.rb +0 -96
  267. data/test/unit/return_values_test.rb +0 -61
  268. data/test/unit/sequence_test.rb +0 -100
  269. data/test/unit/single_return_value_test.rb +0 -12
  270. data/test/unit/single_yield_test.rb +0 -16
  271. data/test/unit/state_machine_test.rb +0 -96
  272. data/test/unit/string_inspect_test.rb +0 -9
  273. data/test/unit/thrower_test.rb +0 -18
  274. data/test/unit/yield_parameters_test.rb +0 -91
@@ -1,3 +1,8 @@
1
1
  require 'mocha/integration/mini_test'
2
+ require 'mocha/deprecation'
2
3
 
3
- Mocha::Integration::MiniTest.activate
4
+ unless Mocha::Integration::MiniTest.activate
5
+ Mocha::Deprecation.warning(
6
+ "MiniTest must be loaded *before* `require 'mocha/minitest'`."
7
+ )
8
+ end
data/lib/mocha/mock.rb CHANGED
@@ -1,21 +1,27 @@
1
- require 'metaclass'
1
+ require 'mocha/singleton_class'
2
2
  require 'mocha/expectation'
3
3
  require 'mocha/expectation_list'
4
+ require 'mocha/invocation'
4
5
  require 'mocha/names'
5
6
  require 'mocha/receivers'
6
7
  require 'mocha/method_matcher'
7
8
  require 'mocha/parameters_matcher'
8
- require 'mocha/unexpected_invocation'
9
9
  require 'mocha/argument_iterator'
10
10
  require 'mocha/expectation_error_factory'
11
- require 'mocha/deprecation'
12
11
  require 'mocha/ruby_version'
13
12
 
14
13
  module Mocha
15
14
  # Traditional mock object.
16
15
  #
17
- # All methods return an {Expectation} which can be further modified by
18
- # methods on {Expectation}.
16
+ # {expects} and {stubs} return an {Expectation} which can be further modified
17
+ # by methods on {Expectation}.
18
+ #
19
+ # {responds_like} and {responds_like_instance_of} both return a {Mock}, and
20
+ # can therefore, be chained to the original creation methods in {API}.
21
+ # They force the mock to indicate what it is supposed to be mocking, thus
22
+ # making it a safer verifying mock. They check that the underlying +responder+
23
+ # will actually respond to the methods being stubbed, throwing a
24
+ # +NoMethodError+ upon invocation otherwise.
19
25
  #
20
26
  # Stubs and expectations are basically the same thing. A stub is just an
21
27
  # expectation of zero or more invocations. The {#stubs} method is syntactic
@@ -70,12 +76,12 @@ module Mocha
70
76
  class Mock
71
77
  # Adds an expectation that the specified method must be called exactly once with any parameters.
72
78
  #
73
- # @param [Symbol,String] method_name name of expected method
74
- # @param [Hash] expected_methods_vs_return_values expected method name symbols as keys and corresponding return values as values - these expectations are setup as if {#expects} were called multiple times.
79
+ # @return [Expectation] last-built expectation which can be further modified by methods on {Expectation}.
75
80
  #
76
81
  # @overload def expects(method_name)
82
+ # @param [Symbol,String] method_name name of expected method
77
83
  # @overload def expects(expected_methods_vs_return_values)
78
- # @return [Expectation] last-built expectation which can be further modified by methods on {Expectation}.
84
+ # @param [Hash] expected_methods_vs_return_values expected method name symbols as keys and corresponding return values as values - these expectations are setup as if {#expects} were called multiple times.
79
85
  #
80
86
  # @example Expected method invoked once so no error raised
81
87
  # object = mock()
@@ -115,12 +121,12 @@ module Mocha
115
121
 
116
122
  # Adds an expectation that the specified method may be called any number of times with any parameters.
117
123
  #
118
- # @param [Symbol,String] method_name name of stubbed method
119
- # @param [Hash] stubbed_methods_vs_return_values stubbed method name symbols as keys and corresponding return values as values - these stubbed methods are setup as if {#stubs} were called multiple times.
124
+ # @return [Expectation] last-built expectation which can be further modified by methods on {Expectation}.
120
125
  #
121
126
  # @overload def stubs(method_name)
127
+ # @param [Symbol,String] method_name name of stubbed method
122
128
  # @overload def stubs(stubbed_methods_vs_return_values)
123
- # @return [Expectation] last-built expectation which can be further modified by methods on {Expectation}.
129
+ # @param [Hash] stubbed_methods_vs_return_values stubbed method name symbols as keys and corresponding return values as values - these stubbed methods are setup as if {#stubs} were called multiple times.
124
130
  #
125
131
  # @example No error raised however many times stubbed method is invoked
126
132
  # object = mock()
@@ -150,9 +156,9 @@ module Mocha
150
156
  end
151
157
  end
152
158
 
153
- # Removes the specified stubbed method (added by calls to {#expects} or {#stubs}) and all expectations associated with it.
159
+ # Removes the specified stubbed methods (added by calls to {#expects} or {#stubs}) and all expectations associated with them.
154
160
  #
155
- # @param [Symbol] method_name name of method to unstub.
161
+ # @param [Array<Symbol>] method_names names of methods to unstub.
156
162
  #
157
163
  # @example Invoking an unstubbed method causes error to be raised
158
164
  # object = mock('mock') do
@@ -160,8 +166,18 @@ module Mocha
160
166
  # object.stubbed_method # => :result_one
161
167
  # object.unstub(:stubbed_method)
162
168
  # object.stubbed_method # => unexpected invocation: #<Mock:mock>.stubbed_method()
163
- def unstub(method_name)
164
- @expectations.remove_all_matching_method(method_name)
169
+ #
170
+ # @example Unstubbing multiple methods.
171
+ # multiplier.unstub(:double, :triple)
172
+ #
173
+ # # exactly equivalent to
174
+ #
175
+ # multiplier.unstub(:double)
176
+ # multiplier.unstub(:triple)
177
+ def unstub(*method_names)
178
+ method_names.each do |method_name|
179
+ @expectations.remove_all_matching_method(method_name)
180
+ end
165
181
  end
166
182
 
167
183
  # Constrains the {Mock} instance so that it can only expect or stub methods to which +responder+ responds. The constraint is only applied at method invocation time.
@@ -251,7 +267,7 @@ module Mocha
251
267
  end
252
268
 
253
269
  # @private
254
- def initialize(mockery, name = nil, receiver = nil, &block)
270
+ def initialize(mockery, name = nil, receiver = nil)
255
271
  @mockery = mockery
256
272
  @name = name || DefaultName.new(self)
257
273
  @receiver = receiver || DefaultReceiver.new(self)
@@ -259,9 +275,7 @@ module Mocha
259
275
  @everything_stubbed = false
260
276
  @responder = nil
261
277
  @unexpected_invocation = nil
262
- return unless block
263
- Deprecation.warning('Passing a block is deprecated. Use Object#tap or define stubs/expectations with an explicit receiver instead.')
264
- instance_eval(&block)
278
+ @expired = false
265
279
  end
266
280
 
267
281
  # @private
@@ -271,6 +285,8 @@ module Mocha
271
285
 
272
286
  alias_method :__stubs__, :stubs
273
287
 
288
+ alias_method :__singleton_class__, :singleton_class
289
+
274
290
  alias_method :quacks_like, :responds_like
275
291
  alias_method :quacks_like_instance_of, :responds_like_instance_of
276
292
 
@@ -290,26 +306,16 @@ module Mocha
290
306
  end
291
307
 
292
308
  # @private
293
- # rubocop:disable Style/MethodMissingSuper
294
- def method_missing(symbol, *arguments, &block)
295
- if @responder && !@responder.respond_to?(symbol)
296
- raise NoMethodError, "undefined method `#{symbol}' for #{mocha_inspect} which responds like #{@responder.mocha_inspect}"
297
- end
298
- if (matching_expectation_allowing_invocation = all_expectations.match_allowing_invocation(symbol, *arguments))
299
- matching_expectation_allowing_invocation.invoke(&block)
300
- elsif (matching_expectation = all_expectations.match(symbol, *arguments)) || (!matching_expectation && !@everything_stubbed)
301
- if @unexpected_invocation.nil?
302
- @unexpected_invocation = UnexpectedInvocation.new(self, symbol, *arguments)
303
- matching_expectation.invoke(&block) if matching_expectation
304
- message = @unexpected_invocation.full_description
305
- message << @mockery.mocha_inspect
306
- else
307
- message = @unexpected_invocation.short_description
308
- end
309
- raise ExpectationErrorFactory.build(message, caller)
309
+ def method_missing(symbol, *arguments, &block) # rubocop:disable Style/MethodMissingSuper
310
+ check_expiry
311
+ check_responder_responds_to(symbol)
312
+ invocation = Invocation.new(self, symbol, *arguments, &block)
313
+ if (matching_expectation_allowing_invocation = all_expectations.match_allowing_invocation(invocation))
314
+ matching_expectation_allowing_invocation.invoke(invocation)
315
+ elsif (matching_expectation = all_expectations.match(invocation)) || (!matching_expectation && !@everything_stubbed)
316
+ raise_unexpected_invocation_error(invocation, matching_expectation)
310
317
  end
311
318
  end
312
- # rubocop:enable Style/MethodMissingSuper
313
319
 
314
320
  # @private
315
321
  def respond_to_missing?(symbol, include_private = false)
@@ -324,8 +330,8 @@ module Mocha
324
330
  end
325
331
  end
326
332
 
327
- # @private
328
333
  if PRE_RUBY_V19
334
+ # @private
329
335
  def respond_to?(symbol, include_private = false)
330
336
  respond_to_missing?(symbol, include_private)
331
337
  end
@@ -336,6 +342,11 @@ module Mocha
336
342
  @expectations.verified?(assertion_counter)
337
343
  end
338
344
 
345
+ # @private
346
+ def __expire__
347
+ @expired = true
348
+ end
349
+
339
350
  # @private
340
351
  def mocha_inspect
341
352
  @name.mocha_inspect
@@ -348,12 +359,42 @@ module Mocha
348
359
 
349
360
  # @private
350
361
  def ensure_method_not_already_defined(method_name)
351
- __metaclass__.send(:undef_method, method_name) if __metaclass__.method_defined?(method_name) || __metaclass__.private_method_defined?(method_name)
362
+ __singleton_class__.send(:undef_method, method_name) if __singleton_class__.method_defined?(method_name) || __singleton_class__.private_method_defined?(method_name)
352
363
  end
353
364
 
354
365
  # @private
355
366
  def any_expectations?
356
367
  @expectations.any?
357
368
  end
369
+
370
+ private
371
+
372
+ def raise_unexpected_invocation_error(invocation, matching_expectation)
373
+ if @unexpected_invocation.nil?
374
+ @unexpected_invocation = invocation
375
+ matching_expectation.invoke(invocation) if matching_expectation
376
+ message = "#{@unexpected_invocation.call_description}\n#{@mockery.mocha_inspect}"
377
+ else
378
+ message = @unexpected_invocation.short_call_description
379
+ end
380
+ raise ExpectationErrorFactory.build("unexpected invocation: #{message}", caller)
381
+ end
382
+
383
+ def check_responder_responds_to(symbol)
384
+ if @responder && !@responder.respond_to?(symbol) # rubocop:disable Style/GuardClause
385
+ raise NoMethodError, "undefined method `#{symbol}' for #{mocha_inspect} which responds like #{@responder.mocha_inspect}"
386
+ end
387
+ end
388
+
389
+ def check_expiry
390
+ if @expired # rubocop:disable Style/GuardClause
391
+ Deprecation.warning(
392
+ "#{mocha_inspect} was instantiated in one test but it is receiving invocations within another test.",
393
+ ' This can lead to unintended interactions between tests and hence unexpected test failures.',
394
+ ' Ensure that every test correctly cleans up any state that it introduces.',
395
+ ' A Mocha::StubbingError will be raised in this scenario in the future.'
396
+ )
397
+ end
398
+ end
358
399
  end
359
400
  end
data/lib/mocha/mockery.rb CHANGED
@@ -35,12 +35,13 @@ module Mocha
35
35
 
36
36
  class << self
37
37
  def instance
38
- instances.last || Null.new
38
+ @instances.last || Null.new
39
39
  end
40
40
 
41
41
  def setup
42
+ @instances ||= []
42
43
  mockery = new
43
- mockery.logger = instance.logger unless instances.empty?
44
+ mockery.logger = instance.logger unless @instances.empty?
44
45
  @instances.push(mockery)
45
46
  end
46
47
 
@@ -52,30 +53,23 @@ module Mocha
52
53
  instance.teardown
53
54
  ensure
54
55
  @instances.pop
55
- @instances = nil if instances.empty?
56
- end
57
-
58
- private
59
-
60
- def instances
61
- @instances ||= []
62
56
  end
63
57
  end
64
58
 
65
- def named_mock(name, &block)
66
- add_mock(Mock.new(self, Name.new(name), &block))
59
+ def named_mock(name)
60
+ add_mock(Mock.new(self, Name.new(name)))
67
61
  end
68
62
 
69
- def unnamed_mock(&block)
70
- add_mock(Mock.new(self, &block))
63
+ def unnamed_mock
64
+ add_mock(Mock.new(self))
71
65
  end
72
66
 
73
- def mock_impersonating(object, &block)
74
- add_mock(Mock.new(self, ImpersonatingName.new(object), ObjectReceiver.new(object), &block))
67
+ def mock_impersonating(object)
68
+ add_mock(Mock.new(self, ImpersonatingName.new(object), ObjectReceiver.new(object)))
75
69
  end
76
70
 
77
- def mock_impersonating_any_instance_of(klass, &block)
78
- add_mock(Mock.new(self, ImpersonatingAnyInstanceName.new(klass), AnyInstanceReceiver.new(klass), &block))
71
+ def mock_impersonating_any_instance_of(klass)
72
+ add_mock(Mock.new(self, ImpersonatingAnyInstanceName.new(klass), AnyInstanceReceiver.new(klass)))
79
73
  end
80
74
 
81
75
  def new_state_machine(name)
@@ -92,16 +86,15 @@ module Mocha
92
86
  end
93
87
  raise ExpectationErrorFactory.build(message, backtrace)
94
88
  end
95
- expectations.each do |e|
96
- unless Mocha::Configuration.allow?(:stubbing_method_unnecessarily)
97
- next if e.used?
98
- on_stubbing_method_unnecessarily(e)
99
- end
89
+ expectations.reject(&:used?).each do |expectation|
90
+ signature_proc = lambda { expectation.method_signature }
91
+ check(:stubbing_method_unnecessarily, 'method unnecessarily', signature_proc, expectation.backtrace)
100
92
  end
101
93
  end
102
94
 
103
95
  def teardown
104
96
  stubba.unstub_all
97
+ mocks.each(&:__expire__)
105
98
  reset
106
99
  end
107
100
 
@@ -119,71 +112,23 @@ module Mocha
119
112
 
120
113
  def mocha_inspect
121
114
  message = ''
122
- message << "unsatisfied expectations:\n- #{unsatisfied_expectations.map(&:mocha_inspect).join("\n- ")}\n" unless unsatisfied_expectations.empty?
123
- message << "satisfied expectations:\n- #{satisfied_expectations.map(&:mocha_inspect).join("\n- ")}\n" unless satisfied_expectations.empty?
124
- message << "states:\n- #{state_machines.map(&:mocha_inspect).join("\n- ")}" unless state_machines.empty?
115
+ message << "unsatisfied expectations:\n- #{unsatisfied_expectations.map(&:mocha_inspect).join("\n- ")}\n" if unsatisfied_expectations.any?
116
+ message << "satisfied expectations:\n- #{satisfied_expectations.map(&:mocha_inspect).join("\n- ")}\n" if satisfied_expectations.any?
117
+ message << "states:\n- #{state_machines.map(&:mocha_inspect).join("\n- ")}\n" if state_machines.any?
125
118
  message
126
119
  end
127
120
 
128
121
  def on_stubbing(object, method)
129
122
  method = PRE_RUBY_V19 ? method.to_s : method.to_sym
130
- unless Mocha::Configuration.allow?(:stubbing_non_existent_method)
131
- unless object.method_exists?(method, true)
132
- on_stubbing_non_existent_method(object, method)
133
- end
134
- end
135
- unless Mocha::Configuration.allow?(:stubbing_non_public_method)
136
- if object.method_exists?(method, false)
137
- on_stubbing_non_public_method(object, method)
138
- end
139
- end
140
- unless Mocha::Configuration.allow?(:stubbing_method_on_nil)
141
- if object.nil?
142
- on_stubbing_method_on_nil(object, method)
143
- end
144
- end
145
- return if Mocha::Configuration.allow?(:stubbing_method_on_non_mock_object)
146
- on_stubbing_method_on_non_mock_object(object, method)
147
- end
148
-
149
- def on_stubbing_non_existent_method(object, method)
150
- if Mocha::Configuration.prevent?(:stubbing_non_existent_method)
151
- raise StubbingError.new("stubbing non-existent method: #{object.mocha_inspect}.#{method}", caller)
152
- end
153
- return unless Mocha::Configuration.warn_when?(:stubbing_non_existent_method)
154
- logger.warn "stubbing non-existent method: #{object.mocha_inspect}.#{method}"
155
- end
156
-
157
- def on_stubbing_non_public_method(object, method)
158
- if Mocha::Configuration.prevent?(:stubbing_non_public_method)
159
- raise StubbingError.new("stubbing non-public method: #{object.mocha_inspect}.#{method}", caller)
160
- end
161
- return unless Mocha::Configuration.warn_when?(:stubbing_non_public_method)
162
- logger.warn "stubbing non-public method: #{object.mocha_inspect}.#{method}"
163
- end
164
-
165
- def on_stubbing_method_on_nil(object, method)
166
- if Mocha::Configuration.prevent?(:stubbing_method_on_nil)
167
- raise StubbingError.new("stubbing method on nil: #{object.mocha_inspect}.#{method}", caller)
168
- end
169
- return unless Mocha::Configuration.warn_when?(:stubbing_method_on_nil)
170
- logger.warn "stubbing method on nil: #{object.mocha_inspect}.#{method}"
171
- end
172
-
173
- def on_stubbing_method_on_non_mock_object(object, method)
174
- if Mocha::Configuration.prevent?(:stubbing_method_on_non_mock_object)
175
- raise StubbingError.new("stubbing method on non-mock object: #{object.mocha_inspect}.#{method}", caller)
123
+ signature_proc = lambda { "#{object.mocha_inspect}.#{method}" }
124
+ check(:stubbing_non_existent_method, 'non-existent method', signature_proc) do
125
+ !(object.stubba_class.__method_exists__?(method, true) || object.respond_to?(method.to_sym))
176
126
  end
177
- return unless Mocha::Configuration.warn_when?(:stubbing_method_on_non_mock_object)
178
- logger.warn "stubbing method on non-mock object: #{object.mocha_inspect}.#{method}"
179
- end
180
-
181
- def on_stubbing_method_unnecessarily(expectation)
182
- if Mocha::Configuration.prevent?(:stubbing_method_unnecessarily)
183
- raise StubbingError.new("stubbing method unnecessarily: #{expectation.method_signature}", expectation.backtrace)
127
+ check(:stubbing_non_public_method, 'non-public method', signature_proc) do
128
+ object.stubba_class.__method_exists__?(method, false)
184
129
  end
185
- return unless Mocha::Configuration.warn_when?(:stubbing_method_unnecessarily)
186
- logger.warn "stubbing method unnecessarily: #{expectation.method_signature}"
130
+ check(:stubbing_method_on_nil, 'method on nil', signature_proc) { object.nil? }
131
+ check(:stubbing_method_on_non_mock_object, 'method on non-mock object', signature_proc)
187
132
  end
188
133
 
189
134
  attr_writer :logger
@@ -194,6 +139,15 @@ module Mocha
194
139
 
195
140
  private
196
141
 
142
+ def check(action, description, signature_proc, backtrace = caller)
143
+ treatment = Mocha.configuration.send(action)
144
+ return if (treatment == :allow) || (block_given? && !yield)
145
+ method_signature = signature_proc.call
146
+ message = "stubbing #{description}: #{method_signature}"
147
+ raise StubbingError.new(message, backtrace) if treatment == :prevent
148
+ logger.warn(message) if treatment == :warn
149
+ end
150
+
197
151
  def expectations
198
152
  mocks.map { |mock| mock.__expectations__.to_a }.flatten
199
153
  end
data/lib/mocha/names.rb CHANGED
@@ -21,7 +21,7 @@ module Mocha
21
21
 
22
22
  class Name
23
23
  def initialize(name)
24
- @name = name
24
+ @name = name.to_s
25
25
  end
26
26
 
27
27
  def mocha_inspect
@@ -35,17 +35,22 @@ module Mocha
35
35
  self
36
36
  end
37
37
 
38
+ # @private
39
+ def stubba_class
40
+ singleton_class
41
+ end
42
+
38
43
  # Adds an expectation that the specified method must be called exactly once with any parameters.
39
44
  #
40
45
  # The original implementation of the method is replaced during the test and then restored at the end of the test. The temporary replacement method has the same visibility as the original method.
41
46
  #
42
- # @param [Symbol,String] method_name name of expected method
43
- # @param [Hash] expected_methods_vs_return_values expected method name symbols as keys and corresponding return values as values - these expectations are setup as if {#expects} were called multiple times.
47
+ # @return [Expectation] last-built expectation which can be further modified by methods on {Expectation}.
48
+ # @raise [StubbingError] if attempting to stub method which is not allowed.
44
49
  #
45
50
  # @overload def expects(method_name)
51
+ # @param [Symbol,String] method_name name of expected method
46
52
  # @overload def expects(expected_methods_vs_return_values)
47
- # @return [Expectation] last-built expectation which can be further modified by methods on {Expectation}.
48
- # @raise [StubbingError] if attempting to stub method which is not allowed.
53
+ # @param [Hash] expected_methods_vs_return_values expected method name symbols as keys and corresponding return values as values - these expectations are setup as if {#expects} were called multiple times.
49
54
  #
50
55
  # @example Setting up an expectation on a non-mock object.
51
56
  # product = Product.new
@@ -88,13 +93,13 @@ module Mocha
88
93
  #
89
94
  # The original implementation of the method is replaced during the test and then restored at the end of the test. The temporary replacement method has the same visibility as the original method.
90
95
  #
91
- # @param [Symbol,String] method_name name of stubbed method
92
- # @param [Hash] stubbed_methods_vs_return_values stubbed method name symbols as keys and corresponding return values as values - these stubbed methods are setup as if {#stubs} were called multiple times.
96
+ # @return [Expectation] last-built expectation which can be further modified by methods on {Expectation}.
97
+ # @raise [StubbingError] if attempting to stub method which is not allowed.
93
98
  #
94
99
  # @overload def stubs(method_name)
100
+ # @param [Symbol,String] method_name name of stubbed method
95
101
  # @overload def stubs(stubbed_methods_vs_return_values)
96
- # @return [Expectation] last-built expectation which can be further modified by methods on {Expectation}.
97
- # @raise [StubbingError] if attempting to stub method which is not allowed.
102
+ # @param [Hash] stubbed_methods_vs_return_values stubbed method name symbols as keys and corresponding return values as values - these stubbed methods are setup as if {#stubs} were called multiple times.
98
103
  #
99
104
  # @example Setting up a stubbed methods on a non-mock object.
100
105
  # product = Product.new
@@ -160,16 +165,5 @@ module Mocha
160
165
  mockery.stubba.unstub(method)
161
166
  end
162
167
  end
163
-
164
- # @private
165
- def method_exists?(method, include_public_methods = true)
166
- if include_public_methods
167
- return true if public_methods(true).include?(method)
168
- return true if respond_to?(method.to_sym)
169
- end
170
- return true if protected_methods(true).include?(method)
171
- return true if private_methods(true).include?(method)
172
- false
173
- end
174
168
  end
175
169
  end
@@ -4,7 +4,7 @@ module Mocha
4
4
  module ParameterMatchers
5
5
  # Matches if all +matchers+ match.
6
6
  #
7
- # @param [*Array<Base>] parameter_matchers parameter matchers.
7
+ # @param [*Array<Base>] matchers parameter matchers.
8
8
  # @return [AllOf] parameter matcher.
9
9
  #
10
10
  # @see Expectation#with
@@ -4,7 +4,7 @@ module Mocha
4
4
  module ParameterMatchers
5
5
  # Matches if any +matchers+ match.
6
6
  #
7
- # @param [*Array<Base>] parameter_matchers parameter matchers.
7
+ # @param [*Array<Base>] matchers parameter matchers.
8
8
  # @return [AnyOf] parameter matcher.
9
9
  #
10
10
  # @see Expectation#with
@@ -27,15 +27,6 @@ module Mocha
27
27
  EquivalentUri.new(uri)
28
28
  end
29
29
 
30
- # @deprecated Use {#equivalent_uri} instead.
31
- # rubocop:disable Naming/PredicateName
32
- def has_equivalent_query_string(uri)
33
- Mocha::Deprecation.warning('`has_equivalent_query_string` is deprecated. Please use `equivalent_uri` instead.')
34
-
35
- equivalent_uri(uri)
36
- end
37
- # rubocop:enable Naming/PredicateName
38
-
39
30
  # Parameter matcher which matches URIs with equivalent query strings.
40
31
  class EquivalentUri < Base
41
32
  # @private
@@ -22,11 +22,10 @@ module Mocha
22
22
  # object.expects(:method_1).with(has_entries('key_1' => 1, 'key_2' => 2))
23
23
  # object.method_1('key_1' => 1, 'key_2' => 99)
24
24
  # # error raised, because method_1 was not called with Hash containing entries: 'key_1' => 1, 'key_2' => 2
25
- # rubocop:disable Naming/PredicateName
26
- def has_entries(entries)
25
+ #
26
+ def has_entries(entries) # rubocop:disable Naming/PredicateName
27
27
  HasEntries.new(entries)
28
28
  end
29
- # rubocop:enable Naming/PredicateName
30
29
 
31
30
  # Parameter matcher which matches when actual parameter contains all expected +Hash+ entries.
32
31
  class HasEntries < Base
@@ -39,23 +39,13 @@ module Mocha
39
39
  # object.expects(:method_1).with(has_entry('key_1' => 1))
40
40
  # object.method_1('key_1' => 2, 'key_2' => 1)
41
41
  # # error raised, because method_1 was not called with Hash containing entry: 'key_1' => 1
42
- # rubocop:disable Naming/PredicateName
43
- def has_entry(*options)
42
+ #
43
+ def has_entry(*options) # rubocop:disable Naming/PredicateName
44
44
  case options.length
45
+ when 0
46
+ raise ArgumentError, 'No arguments. Expecting at least one.'
45
47
  when 1
46
- case options[0]
47
- when Hash
48
- case options[0].length
49
- when 0
50
- raise ArgumentError, 'Argument has no entries.'
51
- when 1
52
- key, value = options[0].first
53
- else
54
- raise ArgumentError, 'Argument has multiple entries. Use Mocha::ParameterMatchers#has_entries instead.'
55
- end
56
- else
57
- raise ArgumentError, 'Argument is not a Hash.'
58
- end
48
+ key, value = parse_option(options[0])
59
49
  when 2
60
50
  key, value = options
61
51
  else
@@ -63,7 +53,6 @@ module Mocha
63
53
  end
64
54
  HasEntry.new(key, value)
65
55
  end
66
- # rubocop:enable Naming/PredicateName
67
56
 
68
57
  # Parameter matcher which matches when actual parameter contains expected +Hash+ entry.
69
58
  class HasEntry < Base
@@ -86,5 +75,24 @@ module Mocha
86
75
  "has_entry(#{@key.mocha_inspect} => #{@value.mocha_inspect})"
87
76
  end
88
77
  end
78
+
79
+ private
80
+
81
+ # @private
82
+ def parse_option(option)
83
+ case option
84
+ when Hash
85
+ case option.length
86
+ when 0
87
+ raise ArgumentError, 'Argument has no entries.'
88
+ when 1
89
+ option.first
90
+ else
91
+ raise ArgumentError, 'Argument has multiple entries. Use Mocha::ParameterMatchers#has_entries instead.'
92
+ end
93
+ else
94
+ raise ArgumentError, 'Argument is not a Hash.'
95
+ end
96
+ end
89
97
  end
90
98
  end
@@ -20,11 +20,10 @@ module Mocha
20
20
  # object.expects(:method_1).with(has_key('key_1'))
21
21
  # object.method_1('key_2' => 2)
22
22
  # # error raised, because method_1 was not called with Hash containing key: 'key_1'
23
- # rubocop:disable Naming/PredicateName
24
- def has_key(key)
23
+ #
24
+ def has_key(key) # rubocop:disable Naming/PredicateName
25
25
  HasKey.new(key)
26
26
  end
27
- # rubocop:enable Naming/PredicateName
28
27
 
29
28
  # Parameter matcher which matches when actual parameter contains +Hash+ entry with expected key.
30
29
  class HasKey < Base
@@ -0,0 +1,53 @@
1
+ require 'mocha/parameter_matchers/base'
2
+
3
+ module Mocha
4
+ module ParameterMatchers
5
+ # Matches +Hash+ containing +keys+.
6
+ #
7
+ # @param [*Array<Object>] keys expected keys.
8
+ # @return [HasKeys] parameter matcher.
9
+ #
10
+ # @see Expectation#with
11
+ #
12
+ # @example Actual parameter contains entry with expected keys.
13
+ # object = mock()
14
+ # object.expects(:method_1).with(has_keys(:key_1, :key_2))
15
+ # object.method_1(:key_1 => 1, :key_2 => 2, :key_3 => 3)
16
+ # # no error raised
17
+ #
18
+ # @example Actual parameter does not contain all expected keys.
19
+ # object = mock()
20
+ # object.expects(:method_1).with(has_keys(:key_1, :key_2))
21
+ # object.method_1(:key_2 => 2)
22
+ # # error raised, because method_1 was not called with Hash containing key: :key_1
23
+ #
24
+ def has_keys(*keys) # rubocop:disable Naming/PredicateName
25
+ HasKeys.new(*keys)
26
+ end
27
+
28
+ # Parameter matcher which matches when actual parameter contains +Hash+ with all expected keys.
29
+ class HasKeys < Base
30
+ # @private
31
+ def initialize(*keys)
32
+ raise ArgumentError, 'No arguments. Expecting at least one.' if keys.empty?
33
+
34
+ @keys = keys
35
+ end
36
+
37
+ # @private
38
+ def matches?(available_parameters)
39
+ parameter = available_parameters.shift
40
+ return false unless parameter.respond_to?(:keys)
41
+
42
+ @keys.map(&:to_matcher).all? do |matcher|
43
+ parameter.keys.any? { |key| matcher.matches?([key]) }
44
+ end
45
+ end
46
+
47
+ # @private
48
+ def mocha_inspect
49
+ "has_keys(#{@keys.mocha_inspect(false)})"
50
+ end
51
+ end
52
+ end
53
+ end