mocha 1.6.0 → 1.10.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (310) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop.yml +61 -0
  3. data/.rubocop_todo.yml +27 -0
  4. data/CONTRIBUTING.md +4 -9
  5. data/README.md +55 -27
  6. data/RELEASE.md +90 -0
  7. data/Rakefile +44 -38
  8. data/bin/build-matrix +32 -20
  9. data/docs/CNAME +1 -0
  10. data/docs/Mocha.html +254 -0
  11. data/docs/Mocha/API.html +1153 -0
  12. data/docs/Mocha/ClassMethods.html +264 -0
  13. data/docs/Mocha/Configuration.html +1383 -0
  14. data/docs/Mocha/Expectation.html +2654 -0
  15. data/docs/Mocha/ExpectationError.html +152 -0
  16. data/docs/Mocha/ExpectationErrorFactory.html +260 -0
  17. data/docs/Mocha/Hooks.html +370 -0
  18. data/docs/Mocha/Integration.html +125 -0
  19. data/docs/Mocha/Integration/MiniTest.html +123 -0
  20. data/docs/Mocha/Integration/MiniTest/Adapter.html +164 -0
  21. data/docs/Mocha/Integration/TestUnit.html +123 -0
  22. data/docs/Mocha/Integration/TestUnit/Adapter.html +164 -0
  23. data/docs/Mocha/Mock.html +1237 -0
  24. data/docs/Mocha/ObjectMethods.html +765 -0
  25. data/docs/Mocha/ParameterMatchers.html +2961 -0
  26. data/docs/Mocha/ParameterMatchers/AllOf.html +153 -0
  27. data/docs/Mocha/ParameterMatchers/AnyOf.html +153 -0
  28. data/docs/Mocha/ParameterMatchers/AnyParameters.html +153 -0
  29. data/docs/Mocha/ParameterMatchers/Anything.html +153 -0
  30. data/docs/Mocha/ParameterMatchers/Base.html +441 -0
  31. data/docs/Mocha/ParameterMatchers/Equals.html +153 -0
  32. data/docs/Mocha/ParameterMatchers/EquivalentUri.html +153 -0
  33. data/docs/Mocha/ParameterMatchers/HasEntries.html +153 -0
  34. data/docs/Mocha/ParameterMatchers/HasEntry.html +153 -0
  35. data/docs/Mocha/ParameterMatchers/HasKey.html +153 -0
  36. data/docs/Mocha/ParameterMatchers/HasValue.html +153 -0
  37. data/docs/Mocha/ParameterMatchers/Includes.html +153 -0
  38. data/docs/Mocha/ParameterMatchers/InstanceOf.html +153 -0
  39. data/docs/Mocha/ParameterMatchers/IsA.html +153 -0
  40. data/docs/Mocha/ParameterMatchers/KindOf.html +153 -0
  41. data/docs/Mocha/ParameterMatchers/Not.html +153 -0
  42. data/docs/Mocha/ParameterMatchers/Optionally.html +153 -0
  43. data/docs/Mocha/ParameterMatchers/RegexpMatches.html +153 -0
  44. data/docs/Mocha/ParameterMatchers/RespondsWith.html +153 -0
  45. data/docs/Mocha/ParameterMatchers/YamlEquivalent.html +153 -0
  46. data/docs/Mocha/Sequence.html +149 -0
  47. data/docs/Mocha/StateMachine.html +527 -0
  48. data/docs/Mocha/StateMachine/State.html +140 -0
  49. data/docs/Mocha/StateMachine/StatePredicate.html +140 -0
  50. data/docs/Mocha/StubbingError.html +150 -0
  51. data/docs/_index.html +519 -0
  52. data/docs/class_list.html +51 -0
  53. data/docs/css/common.css +1 -0
  54. data/docs/css/full_list.css +58 -0
  55. data/docs/css/style.css +496 -0
  56. data/docs/file.COPYING.html +81 -0
  57. data/docs/file.MIT-LICENSE.html +85 -0
  58. data/docs/file.README.html +448 -0
  59. data/docs/file.RELEASE.html +963 -0
  60. data/docs/file_list.html +71 -0
  61. data/docs/frames.html +17 -0
  62. data/docs/index.html +448 -0
  63. data/docs/js/app.js +303 -0
  64. data/docs/js/full_list.js +216 -0
  65. data/docs/js/jquery.js +4 -0
  66. data/docs/method_list.html +627 -0
  67. data/docs/top-level-namespace.html +118 -0
  68. data/gemfiles/Gemfile.minitest.5.11.3 +7 -0
  69. data/init.rb +1 -3
  70. data/lib/mocha.rb +8 -0
  71. data/lib/mocha/any_instance_method.rb +11 -59
  72. data/lib/mocha/api.rb +70 -70
  73. data/lib/mocha/argument_iterator.rb +4 -8
  74. data/lib/mocha/backtrace_filter.rb +1 -5
  75. data/lib/mocha/cardinality.rb +43 -35
  76. data/lib/mocha/central.rb +7 -15
  77. data/lib/mocha/change_state_side_effect.rb +0 -4
  78. data/lib/mocha/class_methods.rb +13 -19
  79. data/lib/mocha/configuration.rb +296 -74
  80. data/lib/mocha/debug.rb +3 -2
  81. data/lib/mocha/deprecation.rb +4 -11
  82. data/lib/mocha/detection/mini_test.rb +0 -2
  83. data/lib/mocha/detection/test_unit.rb +3 -5
  84. data/lib/mocha/error_with_filtered_backtrace.rb +0 -4
  85. data/lib/mocha/exception_raiser.rb +4 -6
  86. data/lib/mocha/expectation.rb +62 -67
  87. data/lib/mocha/expectation_error.rb +1 -1
  88. data/lib/mocha/expectation_error_factory.rb +0 -1
  89. data/lib/mocha/expectation_list.rb +7 -11
  90. data/lib/mocha/hooks.rb +0 -1
  91. data/lib/mocha/in_state_ordering_constraint.rb +0 -4
  92. data/lib/mocha/inspect.rb +28 -28
  93. data/lib/mocha/instance_method.rb +18 -3
  94. data/lib/mocha/integration.rb +2 -5
  95. data/lib/mocha/integration/mini_test.rb +7 -0
  96. data/lib/mocha/integration/mini_test/adapter.rb +2 -4
  97. data/lib/mocha/integration/mini_test/exception_translation.rb +1 -1
  98. data/lib/mocha/integration/mini_test/nothing.rb +4 -4
  99. data/lib/mocha/integration/mini_test/version_13.rb +3 -1
  100. data/lib/mocha/integration/mini_test/version_140.rb +3 -1
  101. data/lib/mocha/integration/mini_test/version_141.rb +3 -1
  102. data/lib/mocha/integration/mini_test/version_142_to_172.rb +3 -1
  103. data/lib/mocha/integration/mini_test/version_200.rb +3 -1
  104. data/lib/mocha/integration/mini_test/version_201_to_222.rb +3 -1
  105. data/lib/mocha/integration/mini_test/version_2110_to_2111.rb +3 -1
  106. data/lib/mocha/integration/mini_test/version_2112_to_320.rb +3 -1
  107. data/lib/mocha/integration/mini_test/version_230_to_2101.rb +3 -1
  108. data/lib/mocha/integration/monkey_patcher.rb +5 -7
  109. data/lib/mocha/integration/test_unit.rb +7 -0
  110. data/lib/mocha/integration/test_unit/adapter.rb +5 -6
  111. data/lib/mocha/integration/test_unit/gem_version_200.rb +4 -2
  112. data/lib/mocha/integration/test_unit/gem_version_201_to_202.rb +4 -2
  113. data/lib/mocha/integration/test_unit/gem_version_203_to_220.rb +4 -2
  114. data/lib/mocha/integration/test_unit/gem_version_230_to_250.rb +4 -2
  115. data/lib/mocha/integration/test_unit/nothing.rb +4 -4
  116. data/lib/mocha/integration/test_unit/ruby_version_185_and_below.rb +3 -1
  117. data/lib/mocha/integration/test_unit/ruby_version_186_and_above.rb +3 -1
  118. data/lib/mocha/invocation.rb +61 -0
  119. data/lib/mocha/is_a.rb +0 -2
  120. data/lib/mocha/logger.rb +0 -4
  121. data/lib/mocha/macos_version.rb +5 -0
  122. data/lib/mocha/method_matcher.rb +1 -5
  123. data/lib/mocha/minitest.rb +7 -2
  124. data/lib/mocha/mock.rb +57 -47
  125. data/lib/mocha/mockery.rb +38 -90
  126. data/lib/mocha/multiple_yields.rb +0 -5
  127. data/lib/mocha/names.rb +2 -12
  128. data/lib/mocha/no_yields.rb +1 -7
  129. data/lib/mocha/not_initialized_error.rb +0 -2
  130. data/lib/mocha/object_methods.rb +19 -29
  131. data/lib/mocha/parameter_matchers.rb +1 -3
  132. data/lib/mocha/parameter_matchers/all_of.rb +2 -8
  133. data/lib/mocha/parameter_matchers/any_of.rb +2 -8
  134. data/lib/mocha/parameter_matchers/any_parameters.rb +3 -9
  135. data/lib/mocha/parameter_matchers/anything.rb +2 -8
  136. data/lib/mocha/parameter_matchers/base.rb +6 -12
  137. data/lib/mocha/parameter_matchers/equals.rb +0 -6
  138. data/lib/mocha/parameter_matchers/equivalent_uri.rb +3 -12
  139. data/lib/mocha/parameter_matchers/has_entries.rb +2 -6
  140. data/lib/mocha/parameter_matchers/has_entry.rb +8 -11
  141. data/lib/mocha/parameter_matchers/has_key.rb +2 -6
  142. data/lib/mocha/parameter_matchers/has_value.rb +2 -6
  143. data/lib/mocha/parameter_matchers/includes.rb +4 -6
  144. data/lib/mocha/parameter_matchers/instance_methods.rb +18 -0
  145. data/lib/mocha/parameter_matchers/instance_of.rb +0 -6
  146. data/lib/mocha/parameter_matchers/is_a.rb +2 -6
  147. data/lib/mocha/parameter_matchers/kind_of.rb +2 -6
  148. data/lib/mocha/parameter_matchers/not.rb +2 -6
  149. data/lib/mocha/parameter_matchers/optionally.rb +4 -10
  150. data/lib/mocha/parameter_matchers/regexp_matches.rb +0 -6
  151. data/lib/mocha/parameter_matchers/responds_with.rb +3 -8
  152. data/lib/mocha/parameter_matchers/yaml_equivalent.rb +2 -6
  153. data/lib/mocha/parameters_matcher.rb +6 -9
  154. data/lib/mocha/pretty_parameters.rb +0 -4
  155. data/lib/mocha/raised_exception.rb +11 -0
  156. data/lib/mocha/receivers.rb +6 -12
  157. data/lib/mocha/return_values.rb +4 -8
  158. data/lib/mocha/sequence.rb +4 -9
  159. data/lib/mocha/setup.rb +5 -0
  160. data/lib/mocha/single_return_value.rb +2 -5
  161. data/lib/mocha/single_yield.rb +0 -5
  162. data/lib/mocha/singleton_class.rb +9 -0
  163. data/lib/mocha/state_machine.rb +6 -10
  164. data/lib/mocha/stubbed_method.rb +127 -0
  165. data/lib/mocha/stubbing_error.rb +0 -2
  166. data/lib/mocha/test_unit.rb +7 -2
  167. data/lib/mocha/thrower.rb +4 -6
  168. data/lib/mocha/thrown_object.rb +12 -0
  169. data/lib/mocha/version.rb +1 -1
  170. data/lib/mocha/yield_parameters.rb +3 -7
  171. data/mocha.gemspec +33 -60
  172. data/test/acceptance/acceptance_test_helper.rb +6 -4
  173. data/test/acceptance/bug_18914_test.rb +7 -13
  174. data/test/acceptance/bug_21465_test.rb +0 -3
  175. data/test/acceptance/bug_21563_test.rb +0 -3
  176. data/test/acceptance/display_matching_invocations_alongside_expectations_test.rb +69 -0
  177. data/test/acceptance/exception_rescue_test.rb +7 -9
  178. data/test/acceptance/expectations_on_multiple_methods_test.rb +2 -2
  179. data/test/acceptance/expected_invocation_count_test.rb +27 -30
  180. data/test/acceptance/failure_messages_test.rb +3 -6
  181. data/test/acceptance/issue_272_test.rb +1 -3
  182. data/test/acceptance/issue_65_test.rb +15 -14
  183. data/test/acceptance/issue_70_test.rb +0 -2
  184. data/test/acceptance/mocha_example_test.rb +5 -7
  185. data/test/acceptance/mocha_test_result_test.rb +7 -8
  186. data/test/acceptance/mock_test.rb +48 -9
  187. data/test/acceptance/mocked_methods_dispatch_test.rb +0 -3
  188. data/test/acceptance/multiple_expectations_failure_message_test.rb +16 -18
  189. data/test/acceptance/optional_parameters_test.rb +0 -3
  190. data/test/acceptance/parameter_matcher_test.rb +2 -4
  191. data/test/acceptance/partial_mocks_test.rb +4 -7
  192. data/test/acceptance/prepend_test.rb +14 -17
  193. data/test/acceptance/prevent_use_of_mocha_outside_test_test.rb +0 -3
  194. data/test/acceptance/raise_exception_test.rb +2 -5
  195. data/test/acceptance/return_value_test.rb +0 -3
  196. data/test/acceptance/sequence_test.rb +9 -12
  197. data/test/acceptance/states_test.rb +6 -5
  198. data/test/acceptance/stub_any_instance_method_defined_on_superclass_test.rb +5 -5
  199. data/test/acceptance/stub_any_instance_method_test.rb +39 -18
  200. data/test/acceptance/stub_class_method_defined_on_active_record_association_proxy_test.rb +8 -9
  201. data/test/acceptance/stub_class_method_defined_on_class_test.rb +2 -2
  202. data/test/acceptance/stub_class_method_defined_on_module_test.rb +0 -2
  203. data/test/acceptance/stub_class_method_defined_on_superclass_test.rb +7 -5
  204. data/test/acceptance/stub_everything_test.rb +1 -4
  205. data/test/acceptance/stub_instance_method_defined_on_active_record_association_proxy_test.rb +6 -8
  206. data/test/acceptance/stub_instance_method_defined_on_class_and_aliased_test.rb +0 -2
  207. data/test/acceptance/stub_instance_method_defined_on_class_test.rb +0 -2
  208. data/test/acceptance/stub_instance_method_defined_on_kernel_module_test.rb +0 -2
  209. data/test/acceptance/stub_instance_method_defined_on_module_test.rb +0 -2
  210. data/test/acceptance/stub_instance_method_defined_on_object_class_test.rb +2 -2
  211. data/test/acceptance/stub_instance_method_defined_on_singleton_class_test.rb +0 -3
  212. data/test/acceptance/stub_instance_method_defined_on_superclass_test.rb +0 -2
  213. data/test/acceptance/stub_method_defined_on_module_and_aliased_test.rb +0 -1
  214. data/test/acceptance/stub_module_method_test.rb +13 -14
  215. data/test/acceptance/stub_test.rb +1 -4
  216. data/test/acceptance/stubba_example_test.rb +6 -15
  217. data/test/acceptance/stubba_test_result_test.rb +5 -9
  218. data/test/acceptance/stubbing_error_backtrace_test.rb +6 -7
  219. data/test/acceptance/stubbing_frozen_object_test.rb +2 -2
  220. data/test/acceptance/stubbing_method_accepting_block_parameter_test.rb +12 -8
  221. data/test/acceptance/stubbing_method_unnecessarily_test.rb +5 -7
  222. data/test/acceptance/stubbing_nil_test.rb +9 -10
  223. data/test/acceptance/stubbing_non_existent_any_instance_method_test.rb +28 -14
  224. data/test/acceptance/stubbing_non_existent_class_method_test.rb +14 -14
  225. data/test/acceptance/stubbing_non_existent_instance_method_test.rb +12 -14
  226. data/test/acceptance/stubbing_non_public_any_instance_method_test.rb +8 -10
  227. data/test/acceptance/stubbing_non_public_class_method_test.rb +12 -12
  228. data/test/acceptance/stubbing_non_public_instance_method_test.rb +10 -12
  229. data/test/acceptance/stubbing_on_non_mock_object_test.rb +9 -15
  230. data/test/acceptance/stubbing_same_class_method_on_parent_and_child_classes_test.rb +3 -5
  231. data/test/acceptance/throw_test.rb +0 -3
  232. data/test/acceptance/unexpected_invocation_test.rb +2 -4
  233. data/test/acceptance/unstubbing_test.rb +41 -15
  234. data/test/deprecation_disabler.rb +0 -1
  235. data/test/execution_point.rb +2 -4
  236. data/test/integration/mini_test_test.rb +2 -2
  237. data/test/integration/shared_tests.rb +27 -23
  238. data/test/integration/test_unit_test.rb +2 -2
  239. data/test/method_definer.rb +11 -19
  240. data/test/mini_test_result.rb +17 -11
  241. data/test/minitest_result.rb +0 -1
  242. data/test/simple_counter.rb +0 -2
  243. data/test/test_helper.rb +13 -5
  244. data/test/test_runner.rb +4 -4
  245. data/test/test_unit_result.rb +4 -2
  246. data/test/unit/any_instance_method_test.rb +74 -35
  247. data/test/unit/array_inspect_test.rb +2 -4
  248. data/test/unit/backtrace_filter_test.rb +3 -5
  249. data/test/unit/cardinality_test.rb +41 -25
  250. data/test/unit/central_test.rb +26 -28
  251. data/test/unit/change_state_side_effect_test.rb +0 -4
  252. data/test/unit/class_methods_test.rb +10 -12
  253. data/test/unit/configuration_test.rb +13 -14
  254. data/test/unit/date_time_inspect_test.rb +1 -3
  255. data/test/unit/exception_raiser_test.rb +10 -7
  256. data/test/unit/expectation_list_test.rb +13 -13
  257. data/test/unit/expectation_test.rb +110 -130
  258. data/test/unit/hash_inspect_test.rb +3 -5
  259. data/test/unit/hooks_test.rb +9 -4
  260. data/test/unit/in_state_ordering_constraint_test.rb +0 -4
  261. data/test/unit/instance_method_test.rb +282 -0
  262. data/test/unit/method_matcher_test.rb +1 -3
  263. data/test/unit/mock_test.rb +47 -25
  264. data/test/unit/mockery_test.rb +32 -33
  265. data/test/unit/module_methods_test.rb +2 -5
  266. data/test/unit/multiple_yields_test.rb +0 -2
  267. data/test/unit/no_yields_test.rb +0 -2
  268. data/test/unit/object_inspect_test.rb +26 -5
  269. data/test/unit/object_methods_test.rb +9 -10
  270. data/test/unit/parameter_matchers/all_of_test.rb +0 -2
  271. data/test/unit/parameter_matchers/any_of_test.rb +0 -2
  272. data/test/unit/parameter_matchers/anything_test.rb +2 -4
  273. data/test/unit/parameter_matchers/equals_test.rb +1 -3
  274. data/test/unit/parameter_matchers/equivalent_uri_test.rb +0 -10
  275. data/test/unit/parameter_matchers/has_entries_test.rb +3 -3
  276. data/test/unit/parameter_matchers/has_entry_test.rb +14 -15
  277. data/test/unit/parameter_matchers/has_key_test.rb +1 -2
  278. data/test/unit/parameter_matchers/has_value_test.rb +1 -3
  279. data/test/unit/parameter_matchers/includes_test.rb +9 -10
  280. data/test/unit/parameter_matchers/instance_of_test.rb +1 -3
  281. data/test/unit/parameter_matchers/is_a_test.rb +1 -3
  282. data/test/unit/parameter_matchers/kind_of_test.rb +1 -3
  283. data/test/unit/parameter_matchers/not_test.rb +0 -2
  284. data/test/unit/parameter_matchers/regexp_matches_test.rb +1 -2
  285. data/test/unit/parameter_matchers/responds_with_test.rb +10 -4
  286. data/test/unit/parameter_matchers/stub_matcher.rb +0 -4
  287. data/test/unit/parameter_matchers/yaml_equivalent_test.rb +1 -3
  288. data/test/unit/parameters_matcher_test.rb +2 -4
  289. data/test/unit/receivers_test.rb +8 -6
  290. data/test/unit/return_values_test.rb +28 -25
  291. data/test/unit/sequence_test.rb +1 -5
  292. data/test/unit/single_return_value_test.rb +6 -3
  293. data/test/unit/single_yield_test.rb +0 -2
  294. data/test/unit/state_machine_test.rb +1 -3
  295. data/test/unit/string_inspect_test.rb +2 -4
  296. data/test/unit/thrower_test.rb +7 -4
  297. data/test/unit/yield_parameters_test.rb +0 -2
  298. data/yard-templates/default/layout/html/google_analytics.erb +6 -9
  299. data/yard-templates/default/layout/html/setup.rb +2 -3
  300. metadata +81 -49
  301. data/lib/mocha/class_method.rb +0 -119
  302. data/lib/mocha/mini_test.rb +0 -5
  303. data/lib/mocha/module_method.rb +0 -8
  304. data/lib/mocha/module_methods.rb +0 -14
  305. data/lib/mocha/parameter_matchers/object.rb +0 -17
  306. data/lib/mocha/standalone.rb +0 -4
  307. data/lib/mocha/unexpected_invocation.rb +0 -26
  308. data/lib/mocha_standalone.rb +0 -4
  309. data/test/acceptance/mock_with_initializer_block_test.rb +0 -58
  310. data/test/unit/class_method_test.rb +0 -229
@@ -1,8 +1,6 @@
1
1
  module Mocha
2
-
3
2
  class BacktraceFilter
4
-
5
- LIB_DIRECTORY = File.expand_path(File.join(File.dirname(__FILE__), "..")) + File::SEPARATOR
3
+ LIB_DIRECTORY = File.expand_path(File.join(File.dirname(__FILE__), '..')) + File::SEPARATOR
6
4
 
7
5
  def initialize(lib_directory = LIB_DIRECTORY)
8
6
  @path_pattern = Regexp.new(lib_directory)
@@ -11,7 +9,5 @@ module Mocha
11
9
  def filtered(backtrace)
12
10
  backtrace.reject { |location| @path_pattern.match(File.expand_path(location)) }
13
11
  end
14
-
15
12
  end
16
-
17
13
  end
@@ -1,11 +1,8 @@
1
1
  module Mocha
2
-
3
2
  class Cardinality
4
-
5
3
  INFINITY = 1 / 0.0
6
4
 
7
5
  class << self
8
-
9
6
  def exactly(count)
10
7
  new(count, count)
11
8
  end
@@ -20,58 +17,71 @@ module Mocha
20
17
 
21
18
  def times(range_or_count)
22
19
  case range_or_count
23
- when Range then new(range_or_count.first, range_or_count.last)
24
- else new(range_or_count, range_or_count)
20
+ when Range then new(range_or_count.first, range_or_count.last)
21
+ else new(range_or_count, range_or_count)
25
22
  end
26
23
  end
27
-
28
24
  end
29
25
 
30
26
  def initialize(required, maximum)
31
- @required, @maximum = required, maximum
27
+ @required = required
28
+ @maximum = maximum
29
+ @invocations = []
32
30
  end
33
31
 
34
- def invocations_allowed?(invocation_count)
35
- invocation_count < maximum
32
+ def <<(invocation)
33
+ @invocations << invocation
36
34
  end
37
35
 
38
- def satisfied?(invocations_so_far)
39
- invocations_so_far >= required
36
+ def invocations_allowed?
37
+ @invocations.size < maximum
38
+ end
39
+
40
+ def satisfied?
41
+ @invocations.size >= required
40
42
  end
41
43
 
42
44
  def needs_verifying?
43
45
  !allowed_any_number_of_times?
44
46
  end
45
47
 
46
- def verified?(invocation_count)
47
- (invocation_count >= required) && (invocation_count <= maximum)
48
+ def verified?
49
+ (@invocations.size >= required) && (@invocations.size <= maximum)
48
50
  end
49
51
 
50
52
  def allowed_any_number_of_times?
51
- required == 0 && infinite?(maximum)
53
+ required.zero? && infinite?(maximum)
52
54
  end
53
55
 
54
- def used?(invocation_count)
55
- (invocation_count > 0) || (maximum == 0)
56
+ def used?
57
+ @invocations.any? || maximum.zero?
56
58
  end
57
59
 
58
- def mocha_inspect
60
+ # rubocop:disable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
61
+ def anticipated_times
59
62
  if allowed_any_number_of_times?
60
- "allowed any number of times"
63
+ 'allowed any number of times'
64
+ elsif required.zero? && maximum.zero?
65
+ "expected #{times(maximum)}"
66
+ elsif required == maximum
67
+ "expected exactly #{times(required)}"
68
+ elsif infinite?(maximum)
69
+ "expected at least #{times(required)}"
70
+ elsif required.zero?
71
+ "expected at most #{times(maximum)}"
61
72
  else
62
- if required == 0 && maximum == 0
63
- "expected never"
64
- elsif required == maximum
65
- "expected exactly #{times(required)}"
66
- elsif infinite?(maximum)
67
- "expected at least #{times(required)}"
68
- elsif required == 0
69
- "expected at most #{times(maximum)}"
70
- else
71
- "expected between #{required} and #{times(maximum)}"
72
- end
73
+ "expected between #{required} and #{times(maximum)}"
73
74
  end
74
75
  end
76
+ # rubocop:enable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
77
+
78
+ def invoked_times
79
+ "invoked #{times(@invocations.size)}"
80
+ end
81
+
82
+ def actual_invocations
83
+ @invocations.map(&:full_description).join
84
+ end
75
85
 
76
86
  protected
77
87
 
@@ -79,17 +89,15 @@ module Mocha
79
89
 
80
90
  def times(number)
81
91
  case number
82
- when 0 then "no times"
83
- when 1 then "once"
84
- when 2 then "twice"
85
- else "#{number} times"
92
+ when 0 then 'never'
93
+ when 1 then 'once'
94
+ when 2 then 'twice'
95
+ else "#{number} times"
86
96
  end
87
97
  end
88
98
 
89
99
  def infinite?(number)
90
100
  number.respond_to?(:infinite?) && number.infinite?
91
101
  end
92
-
93
102
  end
94
-
95
103
  end
@@ -1,9 +1,6 @@
1
1
  module Mocha
2
-
3
2
  class Central
4
-
5
3
  class Null < self
6
-
7
4
  def initialize(&block)
8
5
  super
9
6
  @raise_not_initialized_error = block
@@ -16,7 +13,6 @@ module Mocha
16
13
  def unstub(*)
17
14
  @raise_not_initialized_error.call
18
15
  end
19
-
20
16
  end
21
17
 
22
18
  attr_accessor :stubba_methods
@@ -26,25 +22,21 @@ module Mocha
26
22
  end
27
23
 
28
24
  def stub(method)
29
- unless stubba_methods.detect { |m| m.matches?(method) }
30
- method.stub
31
- stubba_methods.push(method)
32
- end
25
+ return if stubba_methods.detect { |m| m.matches?(method) }
26
+ method.stub
27
+ stubba_methods.push(method)
33
28
  end
34
29
 
35
30
  def unstub(method)
36
- if existing = stubba_methods.detect { |m| m.matches?(method) }
37
- existing.unstub
38
- stubba_methods.delete(existing)
39
- end
31
+ return unless (existing = stubba_methods.detect { |m| m.matches?(method) })
32
+ existing.unstub
33
+ stubba_methods.delete(existing)
40
34
  end
41
35
 
42
36
  def unstub_all
43
- while stubba_methods.any? do
37
+ while stubba_methods.any?
44
38
  unstub(stubba_methods.first)
45
39
  end
46
40
  end
47
-
48
41
  end
49
-
50
42
  end
@@ -1,7 +1,5 @@
1
1
  module Mocha
2
-
3
2
  class ChangeStateSideEffect
4
-
5
3
  def initialize(state)
6
4
  @state = state
7
5
  end
@@ -13,7 +11,5 @@ module Mocha
13
11
  def mocha_inspect
14
12
  "then #{@state.mocha_inspect}"
15
13
  end
16
-
17
14
  end
18
-
19
15
  end
@@ -1,20 +1,11 @@
1
1
  require 'mocha/mockery'
2
- require 'mocha/class_method'
3
2
  require 'mocha/any_instance_method'
4
3
 
5
4
  module Mocha
6
-
7
5
  # Methods added to all classes to allow mocking and stubbing on real (i.e. non-mock) objects.
8
6
  module ClassMethods
9
-
10
- # @private
11
- def stubba_method
12
- Mocha::ClassMethod
13
- end
14
-
15
7
  # @private
16
8
  class AnyInstance
17
-
18
9
  def initialize(klass)
19
10
  @stubba_object = klass
20
11
  end
@@ -31,20 +22,15 @@ module Mocha
31
22
  Mocha::AnyInstanceMethod
32
23
  end
33
24
 
34
- def stubba_object
25
+ def stubba_class
35
26
  @stubba_object
36
27
  end
37
28
 
38
- def method_exists?(method, include_public_methods = true)
39
- if include_public_methods
40
- return true if @stubba_object.public_instance_methods(include_superclass_methods = true).include?(method)
41
- return true if @stubba_object.allocate.respond_to?(method.to_sym)
42
- end
43
- return true if @stubba_object.protected_instance_methods(include_superclass_methods = true).include?(method)
44
- return true if @stubba_object.private_instance_methods(include_superclass_methods = true).include?(method)
45
- return false
29
+ def respond_to?(method)
30
+ @stubba_object.allocate.respond_to?(method.to_sym)
46
31
  end
47
32
 
33
+ attr_reader :stubba_object
48
34
  end
49
35
 
50
36
  # @return [Mock] a mock object which will detect calls to any instance of this class.
@@ -63,6 +49,14 @@ module Mocha
63
49
  @any_instance ||= AnyInstance.new(self)
64
50
  end
65
51
 
52
+ # @private
53
+ # rubocop:disable Metrics/CyclomaticComplexity
54
+ def __method_visibility__(method, include_public_methods = true)
55
+ (include_public_methods && public_method_defined?(method) && :public) ||
56
+ (protected_method_defined?(method) && :protected) ||
57
+ (private_method_defined?(method) && :private)
58
+ end
59
+ # rubocop:enable Metrics/CyclomaticComplexity
60
+ alias_method :__method_exists__?, :__method_visibility__
66
61
  end
67
-
68
62
  end
@@ -1,120 +1,323 @@
1
1
  module Mocha
2
-
3
- # This class allows you to determine what should happen under certain circumstances. In each scenario, Mocha can be configured to {.allow do nothing}, {.warn_when display a warning message}, or {.prevent raise an exception}. The relevant scenario is identified using one of the following symbols:
4
- #
5
- # * +:stubbing_method_unnecessarily+ This is useful for identifying unused stubs. Unused stubs are often accidentally introduced when code is {http://martinfowler.com/bliki/DefinitionOfRefactoring.html refactored}. Allowed by default.
6
- # * +:stubbing_non_existent_method+ - This is useful if you want to ensure that methods you're mocking really exist. A common criticism of unit tests with mock objects is that such a test may (incorrectly) pass when an equivalent non-mocking test would (correctly) fail. While you should always have some integration tests, particularly for critical business functionality, this Mocha configuration setting should catch scenarios when mocked methods and real methods have become misaligned. Allowed by default.
7
- # * +:stubbing_non_public_method+ - Many people think that it's good practice only to mock public methods. This is one way to prevent your tests being too tightly coupled to the internal implementation of a class. Such tests tend to be very brittle and not much use when refactoring. Allowed by default.
8
- # * +:stubbing_method_on_non_mock_object+ - If you like the idea of {http://www.jmock.org/oopsla2004.pdf mocking roles not objects} and {http://www.mockobjects.com/2007/04/test-smell-mocking-concrete-classes.html you don't like stubbing concrete classes}, this is the setting for you. However, while this restriction makes a lot of sense in Java with its {http://java.sun.com/docs/books/tutorial/java/concepts/interface.html explicit interfaces}, it may be moot in Ruby where roles are probably best represented as Modules. Allowed by default.
9
- # * +:stubbing_method_on_nil+ - This is usually done accidentally, but there might be rare cases where it is intended. Prevented by default.
10
- #
11
- # @example Preventing unnecessary stubbing of a method
12
- # Mocha::Configuration.prevent(:stubbing_method_unnecessarily)
13
- #
14
- # example = mock('example')
15
- # example.stubs(:unused_stub)
16
- # # => Mocha::StubbingError: stubbing method unnecessarily:
17
- # # => #<Mock:example>.unused_stub(any_parameters)
18
- #
19
- # @example Preventing stubbing of a method on a non-mock object
20
- # Mocha::Configuration.prevent(:stubbing_method_on_non_mock_object)
21
- #
22
- # class Example
23
- # def example_method; end
24
- # end
25
- #
26
- # example = Example.new
27
- # example.stubs(:example_method)
28
- # # => Mocha::StubbingError: stubbing method on non-mock object:
29
- # # => #<Example:0x593620>.example_method
30
- #
31
- # @example Preventing stubbing of a non-existent method
2
+ # Allows setting of configuration options. See {Configuration} for the available options.
32
3
  #
33
- # Mocha::Configuration.prevent(:stubbing_non_existent_method)
4
+ # Typically the configuration is set globally in a +test_helper.rb+ or +spec_helper.rb+ file.
34
5
  #
35
- # class Example
36
- # end
37
- #
38
- # example = Example.new
39
- # example.stubs(:method_that_doesnt_exist)
40
- # # => Mocha::StubbingError: stubbing non-existent method:
41
- # # => #<Example:0x593760>.method_that_doesnt_exist
6
+ # @see Configuration
42
7
  #
43
- # @example Preventing stubbing of a non-public method
44
- # Mocha::Configuration.prevent(:stubbing_non_public_method)
8
+ # @yieldparam configuration [Configuration] the configuration for modification
45
9
  #
46
- # class Example
47
- # def internal_method; end
48
- # private :internal_method
10
+ # @example Setting multiple configuration options
11
+ # Mocha.configure do |c|
12
+ # c.stubbing_method_unnecessarily = :prevent
13
+ # c.stubbing_method_on_non_mock_object = :warn
14
+ # c.stubbing_method_on_nil = :allow
49
15
  # end
50
16
  #
51
- # example = Example.new
52
- # example.stubs(:internal_method)
53
- # # => Mocha::StubbingError: stubbing non-public method:
54
- # # => #<Example:0x593530>.internal_method
55
- #
56
- # Typically the configuration would be set globally in a +test_helper.rb+ or +spec_helper.rb+ file. However, it can also be temporarily overridden locally using the block syntax of the relevant method. In the latter case, the original configuration settings are restored when the block is exited.
17
+ def self.configure
18
+ yield configuration
19
+ end
20
+
21
+ # @private
22
+ def self.configuration
23
+ Configuration.configuration
24
+ end
25
+
26
+ # This class provides a number of ways to configure the library.
57
27
  #
58
- # @example Temporarily allowing stubbing of a non-existent method
59
- # Mocha::Configuration.prevent(:stubbing_non_public_method)
28
+ # Typically the configuration is set globally in a +test_helper.rb+ or +spec_helper.rb+ file.
60
29
  #
61
- # class Example
30
+ # @example Setting multiple configuration options
31
+ # Mocha.configure do |c|
32
+ # c.stubbing_method_unnecessarily = :prevent
33
+ # c.stubbing_method_on_non_mock_object = :warn
34
+ # c.stubbing_method_on_nil = :allow
62
35
  # end
63
36
  #
64
- # Mocha::Configuration.allow(:stubbing_non_existent_method) do
65
- # example = Example.new
66
- # example.stubs(:method_that_doesnt_exist)
67
- # # => no exception raised
68
- # end
69
37
  class Configuration
70
-
38
+ # @private
71
39
  DEFAULTS = {
72
40
  :stubbing_method_unnecessarily => :allow,
73
41
  :stubbing_method_on_non_mock_object => :allow,
74
42
  :stubbing_non_existent_method => :allow,
75
43
  :stubbing_non_public_method => :allow,
76
44
  :stubbing_method_on_nil => :prevent,
77
- }
45
+ :display_matching_invocations_on_failure => false
46
+ }.freeze
78
47
 
79
- class << self
48
+ attr_reader :options
49
+ protected :options
50
+
51
+ # @private
52
+ def initialize(options = {})
53
+ @options = DEFAULTS.merge(options)
54
+ end
55
+
56
+ # @private
57
+ def initialize_copy(other)
58
+ @options = other.options.dup
59
+ end
60
+
61
+ # @private
62
+ def merge(other)
63
+ self.class.new(@options.merge(other.options))
64
+ end
65
+
66
+ # Configure whether stubbing methods unnecessarily is allowed.
67
+ #
68
+ # This is useful for identifying unused stubs. Unused stubs are often accidentally introduced when code is {http://martinfowler.com/bliki/DefinitionOfRefactoring.html refactored}.
69
+ #
70
+ # When +value+ is +:allow+, do nothing. This is the default.
71
+ # When +value+ is +:warn+, display a warning.
72
+ # When +value+ is +:prevent+, raise a {StubbingError}.
73
+ #
74
+ # @param [Symbol] value one of +:allow+, +:warn+, +:prevent+.
75
+ #
76
+ # @example Preventing unnecessary stubbing of a method
77
+ # Mocha.configure do |c|
78
+ # c.stubbing_method_unnecessarily = :prevent
79
+ # end
80
+ #
81
+ # example = mock('example')
82
+ # example.stubs(:unused_stub)
83
+ # # => Mocha::StubbingError: stubbing method unnecessarily:
84
+ # # => #<Mock:example>.unused_stub(any_parameters)
85
+ #
86
+ def stubbing_method_unnecessarily=(value)
87
+ @options[:stubbing_method_unnecessarily] = value
88
+ end
80
89
 
90
+ # @private
91
+ def stubbing_method_unnecessarily
92
+ @options[:stubbing_method_unnecessarily]
93
+ end
94
+
95
+ # Configure whether stubbing methods on non-mock objects is allowed.
96
+ #
97
+ # If you like the idea of {http://www.jmock.org/oopsla2004.pdf mocking roles not objects} and {http://www.mockobjects.com/2007/04/test-smell-mocking-concrete-classes.html you don't like stubbing concrete classes}, this is the setting for you. However, while this restriction makes a lot of sense in Java with its {http://java.sun.com/docs/books/tutorial/java/concepts/interface.html explicit interfaces}, it may be moot in Ruby where roles are probably best represented as Modules.
98
+ #
99
+ # When +value+ is +:allow+, do nothing. This is the default.
100
+ # When +value+ is +:warn+, display a warning.
101
+ # When +value+ is +:prevent+, raise a {StubbingError}.
102
+ #
103
+ # @param [Symbol] value one of +:allow+, +:warn+, +:prevent+.
104
+ #
105
+ # @example Preventing stubbing of a method on a non-mock object
106
+ # Mocha.configure do |c|
107
+ # c.stubbing_method_on_non_mock_object = :prevent
108
+ # end
109
+ #
110
+ # class Example
111
+ # def example_method; end
112
+ # end
113
+ #
114
+ # example = Example.new
115
+ # example.stubs(:example_method)
116
+ # # => Mocha::StubbingError: stubbing method on non-mock object:
117
+ # # => #<Example:0x593620>.example_method
118
+ #
119
+ def stubbing_method_on_non_mock_object=(value)
120
+ @options[:stubbing_method_on_non_mock_object] = value
121
+ end
122
+
123
+ # @private
124
+ def stubbing_method_on_non_mock_object
125
+ @options[:stubbing_method_on_non_mock_object]
126
+ end
127
+
128
+ # Configure whether stubbing of non-existent methods is allowed.
129
+ #
130
+ # This is useful if you want to ensure that methods you're mocking really exist. A common criticism of unit tests with mock objects is that such a test may (incorrectly) pass when an equivalent non-mocking test would (correctly) fail. While you should always have some integration tests, particularly for critical business functionality, this Mocha configuration setting should catch scenarios when mocked methods and real methods have become misaligned.
131
+ #
132
+ # When +value+ is +:allow+, do nothing. This is the default.
133
+ # When +value+ is +:warn+, display a warning.
134
+ # When +value+ is +:prevent+, raise a {StubbingError}.
135
+ #
136
+ # @param [Symbol] value one of +:allow+, +:warn+, +:prevent+.
137
+ #
138
+ # @example Preventing stubbing of a non-existent method
139
+ #
140
+ # Mocha.configure do |c|
141
+ # c.stubbing_non_existent_method = :prevent
142
+ # end
143
+ #
144
+ # class Example
145
+ # end
146
+ #
147
+ # example = Example.new
148
+ # example.stubs(:method_that_doesnt_exist)
149
+ # # => Mocha::StubbingError: stubbing non-existent method:
150
+ # # => #<Example:0x593760>.method_that_doesnt_exist
151
+ #
152
+ def stubbing_non_existent_method=(value)
153
+ @options[:stubbing_non_existent_method] = value
154
+ end
155
+
156
+ # @private
157
+ def stubbing_non_existent_method
158
+ @options[:stubbing_non_existent_method]
159
+ end
160
+
161
+ # Configure whether stubbing of non-public methods is allowed.
162
+ #
163
+ # Many people think that it's good practice only to mock public methods. This is one way to prevent your tests being too tightly coupled to the internal implementation of a class. Such tests tend to be very brittle and not much use when refactoring.
164
+ #
165
+ # When +value+ is +:allow+, do nothing. This is the default.
166
+ # When +value+ is +:warn+, display a warning.
167
+ # When +value+ is +:prevent+, raise a {StubbingError}.
168
+ #
169
+ # @param [Symbol] value one of +:allow+, +:warn+, +:prevent+.
170
+ #
171
+ # @example Preventing stubbing of a non-public method
172
+ # Mocha.configure do |c|
173
+ # c.stubbing_non_public_method = :prevent
174
+ # end
175
+ #
176
+ # class Example
177
+ # def internal_method; end
178
+ # private :internal_method
179
+ # end
180
+ #
181
+ # example = Example.new
182
+ # example.stubs(:internal_method)
183
+ # # => Mocha::StubbingError: stubbing non-public method:
184
+ # # => #<Example:0x593530>.internal_method
185
+ #
186
+ def stubbing_non_public_method=(value)
187
+ @options[:stubbing_non_public_method] = value
188
+ end
189
+
190
+ # @private
191
+ def stubbing_non_public_method
192
+ @options[:stubbing_non_public_method]
193
+ end
194
+
195
+ # Configure whether stubbing methods on the +nil+ object is allowed.
196
+ #
197
+ # This is usually done accidentally, but there might be rare cases where it is intended.
198
+ #
199
+ # This option only works for Ruby < v2.2.0. In later versions of Ruby +nil+ is frozen and so a {StubbingError} will be raised if you attempt to stub a method on +nil+.
200
+ #
201
+ # When +value+ is +:allow+, do nothing.
202
+ # When +value+ is +:warn+, display a warning.
203
+ # When +value+ is +:prevent+, raise a {StubbingError}. This is the default.
204
+ #
205
+ # @param [Symbol] value one of +:allow+, +:warn+, +:prevent+.
206
+ #
207
+ def stubbing_method_on_nil=(value)
208
+ @options[:stubbing_method_on_nil] = value
209
+ end
210
+
211
+ # @private
212
+ def stubbing_method_on_nil
213
+ @options[:stubbing_method_on_nil]
214
+ end
215
+
216
+ # Display matching invocations alongside expectations on Mocha-related test failure.
217
+ #
218
+ # @param [Boolean] value +true+ to enable display of matching invocations; disabled by default.
219
+ #
220
+ # @example Enable display of matching invocations
221
+ # Mocha.configure do |c|
222
+ # c.display_matching_invocations_on_failure = true
223
+ # end
224
+ #
225
+ # foo = mock('foo')
226
+ # foo.expects(:bar)
227
+ # foo.stubs(:baz).returns('baz').raises(RuntimeError).throws(:tag, 'value')
228
+ #
229
+ # foo.baz(1, 2)
230
+ # assert_raises(RuntimeError) { foo.baz(3, 4) }
231
+ # assert_throws(:tag) { foo.baz(5, 6) }
232
+ #
233
+ # not all expectations were satisfied
234
+ # unsatisfied expectations:
235
+ # - expected exactly once, invoked never: #<Mock:foo>.bar
236
+ # satisfied expectations:
237
+ # - allowed any number of times, invoked 3 times: #<Mock:foo>.baz(any_parameters)
238
+ # - #<Mock:foo>.baz(1, 2) # => "baz"
239
+ # - #<Mock:foo>.baz(3, 4) # => raised RuntimeError
240
+ # - #<Mock:foo>.baz(5, 6) # => threw (:tag, "value")
241
+ def display_matching_invocations_on_failure=(value)
242
+ @options[:display_matching_invocations_on_failure] = value
243
+ end
244
+
245
+ # @private
246
+ def display_matching_invocations_on_failure?
247
+ @options[:display_matching_invocations_on_failure]
248
+ end
249
+
250
+ class << self
81
251
  # Allow the specified +action+.
82
252
  #
83
253
  # @param [Symbol] action one of +:stubbing_method_unnecessarily+, +:stubbing_method_on_non_mock_object+, +:stubbing_non_existent_method+, +:stubbing_non_public_method+, +:stubbing_method_on_nil+.
84
254
  # @yield optional block during which the configuration change will be changed before being returned to its original value at the end of the block.
255
+ # @deprecated If a block is supplied, call {.override} with a +Hash+ containing an entry with the +action+ as the key and +:allow+ as the value. If no block is supplied, call the appropriate +action+ writer method with +value+ set to +:allow+ via {Mocha.configure}. The writer method will be the one of the following corresponding to the +action+:
256
+ # * {#stubbing_method_unnecessarily=}
257
+ # * {#stubbing_method_on_non_mock_object=}
258
+ # * {#stubbing_non_existent_method=}
259
+ # * {#stubbing_non_public_method=}
260
+ # * {#stubbing_method_on_nil=}
85
261
  def allow(action, &block)
262
+ if block_given?
263
+ Deprecation.warning("Use Mocha::Configuration.override(#{action}: :allow) with the same block")
264
+ else
265
+ Deprecation.warning("Use Mocha.configure { |c| c.#{action} = :allow }")
266
+ end
86
267
  change_config action, :allow, &block
87
268
  end
88
269
 
89
270
  # @private
90
271
  def allow?(action)
91
- configuration[action] == :allow
272
+ configuration.allow?(action)
92
273
  end
93
274
 
94
275
  # Warn if the specified +action+ is attempted.
95
276
  #
96
277
  # @param [Symbol] action one of +:stubbing_method_unnecessarily+, +:stubbing_method_on_non_mock_object+, +:stubbing_non_existent_method+, +:stubbing_non_public_method+, +:stubbing_method_on_nil+.
97
278
  # @yield optional block during which the configuration change will be changed before being returned to its original value at the end of the block.
279
+ # @deprecated If a block is supplied, call {.override} with a +Hash+ containing an entry with the +action+ as the key and +:warn+ as the value. If no block is supplied, call the appropriate +action+ writer method with +value+ set to +:warn+ via {Mocha.configure}. The writer method will be the one of the following corresponding to the +action+:
280
+ # * {#stubbing_method_unnecessarily=}
281
+ # * {#stubbing_method_on_non_mock_object=}
282
+ # * {#stubbing_non_existent_method=}
283
+ # * {#stubbing_non_public_method=}
284
+ # * {#stubbing_method_on_nil=}
98
285
  def warn_when(action, &block)
286
+ if block_given?
287
+ Deprecation.warning("Use Mocha::Configuration.override(#{action}: :warn) with the same block")
288
+ else
289
+ Deprecation.warning("Use Mocha.configure { |c| c.#{action} = :warn }")
290
+ end
99
291
  change_config action, :warn, &block
100
292
  end
101
293
 
102
294
  # @private
103
295
  def warn_when?(action)
104
- configuration[action] == :warn
296
+ configuration.warn_when?(action)
105
297
  end
106
298
 
107
- # Raise a {StubbingError} if if the specified +action+ is attempted.
299
+ # Raise a {StubbingError} if the specified +action+ is attempted.
108
300
  #
109
301
  # @param [Symbol] action one of +:stubbing_method_unnecessarily+, +:stubbing_method_on_non_mock_object+, +:stubbing_non_existent_method+, +:stubbing_non_public_method+, +:stubbing_method_on_nil+.
110
302
  # @yield optional block during which the configuration change will be changed before being returned to its original value at the end of the block.
303
+ # @deprecated If a block is supplied, call {.override} with a +Hash+ containing an entry with the +action+ as the key and +:prevent+ as the value. If no block is supplied, call the appropriate +action+ writer method with +value+ set to +:prevent+ via {Mocha.configure}. The writer method will be the one of the following corresponding to the +action+:
304
+ # * {#stubbing_method_unnecessarily=}
305
+ # * {#stubbing_method_on_non_mock_object=}
306
+ # * {#stubbing_non_existent_method=}
307
+ # * {#stubbing_non_public_method=}
308
+ # * {#stubbing_method_on_nil=}
111
309
  def prevent(action, &block)
310
+ if block_given?
311
+ Deprecation.warning("Use Mocha::Configuration.override(#{action}: :prevent) with the same block")
312
+ else
313
+ Deprecation.warning("Use Mocha.configure { |c| c.#{action} = :prevent }")
314
+ end
112
315
  change_config action, :prevent, &block
113
316
  end
114
317
 
115
318
  # @private
116
319
  def prevent?(action)
117
- configuration[action] == :prevent
320
+ configuration.prevent?(action)
118
321
  end
119
322
 
120
323
  # @private
@@ -122,33 +325,52 @@ module Mocha
122
325
  @configuration = nil
123
326
  end
124
327
 
125
- private
328
+ # Temporarily modify {Configuration} options.
329
+ #
330
+ # The supplied +temporary_options+ will override the current configuration for the duration of the supplied block.
331
+ # The configuration will be returned to its original state when the block returns.
332
+ #
333
+ # @param [Hash] temporary_options the configuration options to apply for the duration of the block.
334
+ # @yield block during which the configuration change will be in force.
335
+ #
336
+ # @example Temporarily allow stubbing of +nil+
337
+ # Mocha::Configuration.override(stubbing_method_on_nil: :allow) do
338
+ # nil.stubs(:foo)
339
+ # end
340
+ def override(temporary_options)
341
+ original_configuration = configuration
342
+ @configuration = configuration.merge(new(temporary_options))
343
+ yield
344
+ ensure
345
+ @configuration = original_configuration
346
+ end
126
347
 
127
348
  # @private
128
349
  def configuration
129
- @configuration ||= DEFAULTS.dup
350
+ @configuration ||= new
130
351
  end
131
352
 
353
+ private
354
+
132
355
  # @private
133
356
  def change_config(action, new_value, &block)
134
357
  if block_given?
135
358
  temporarily_change_config action, new_value, &block
136
359
  else
137
- configuration[action] = new_value
360
+ configuration.send("#{action}=".to_sym, new_value)
138
361
  end
139
362
  end
140
363
 
141
364
  # @private
142
- def temporarily_change_config(action, new_value, &block)
143
- original_value = configuration[action]
144
- configuration[action] = new_value
365
+ def temporarily_change_config(action, new_value)
366
+ original_configuration = configuration
367
+ new_configuration = configuration.dup
368
+ new_configuration.send("#{action}=".to_sym, new_value)
369
+ @configuration = new_configuration
145
370
  yield
146
371
  ensure
147
- configuration[action] = original_value
372
+ @configuration = original_configuration
148
373
  end
149
-
150
374
  end
151
-
152
375
  end
153
-
154
376
  end