mocha 1.0.0.alpha → 1.10.0.alpha

Sign up to get free protection for your applications and to get access to all the features.
Files changed (313) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop.yml +61 -0
  3. data/.rubocop_todo.yml +27 -0
  4. data/CONTRIBUTING.md +7 -0
  5. data/README.md +136 -42
  6. data/RELEASE.md +166 -16
  7. data/Rakefile +52 -36
  8. data/bin/build-matrix +32 -21
  9. data/docs/CNAME +1 -0
  10. data/docs/Mocha.html +254 -0
  11. data/docs/Mocha/API.html +1129 -0
  12. data/docs/Mocha/ClassMethods.html +339 -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 +429 -0
  59. data/docs/file.RELEASE.html +942 -0
  60. data/docs/file_list.html +71 -0
  61. data/docs/frames.html +17 -0
  62. data/docs/index.html +429 -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 +635 -0
  67. data/docs/top-level-namespace.html +118 -0
  68. data/gemfiles/Gemfile.minitest.5.11.3 +7 -0
  69. data/gemfiles/Gemfile.test-unit.latest +5 -1
  70. data/init.rb +1 -3
  71. data/lib/mocha.rb +8 -0
  72. data/lib/mocha/any_instance_method.rb +12 -50
  73. data/lib/mocha/api.rb +63 -65
  74. data/lib/mocha/argument_iterator.rb +4 -8
  75. data/lib/mocha/backtrace_filter.rb +1 -5
  76. data/lib/mocha/cardinality.rb +43 -35
  77. data/lib/mocha/central.rb +21 -12
  78. data/lib/mocha/change_state_side_effect.rb +0 -4
  79. data/lib/mocha/class_methods.rb +18 -20
  80. data/lib/mocha/configuration.rb +305 -18
  81. data/lib/mocha/debug.rb +3 -2
  82. data/lib/mocha/deprecation.rb +6 -10
  83. data/lib/mocha/detection/mini_test.rb +0 -2
  84. data/lib/mocha/detection/test_unit.rb +3 -5
  85. data/lib/mocha/error_with_filtered_backtrace.rb +13 -0
  86. data/lib/mocha/exception_raiser.rb +4 -6
  87. data/lib/mocha/expectation.rb +62 -67
  88. data/lib/mocha/expectation_error.rb +1 -1
  89. data/lib/mocha/expectation_error_factory.rb +0 -1
  90. data/lib/mocha/expectation_list.rb +7 -11
  91. data/lib/mocha/hooks.rb +1 -3
  92. data/lib/mocha/in_state_ordering_constraint.rb +0 -4
  93. data/lib/mocha/inspect.rb +28 -38
  94. data/lib/mocha/instance_method.rb +15 -8
  95. data/lib/mocha/integration.rb +2 -5
  96. data/lib/mocha/integration/mini_test.rb +7 -0
  97. data/lib/mocha/integration/mini_test/adapter.rb +2 -4
  98. data/lib/mocha/integration/mini_test/exception_translation.rb +1 -1
  99. data/lib/mocha/integration/mini_test/nothing.rb +4 -4
  100. data/lib/mocha/integration/mini_test/version_13.rb +4 -1
  101. data/lib/mocha/integration/mini_test/version_140.rb +4 -1
  102. data/lib/mocha/integration/mini_test/version_141.rb +4 -1
  103. data/lib/mocha/integration/mini_test/version_142_to_172.rb +4 -1
  104. data/lib/mocha/integration/mini_test/version_200.rb +4 -1
  105. data/lib/mocha/integration/mini_test/version_201_to_222.rb +4 -1
  106. data/lib/mocha/integration/mini_test/version_2110_to_2111.rb +4 -1
  107. data/lib/mocha/integration/mini_test/version_2112_to_320.rb +4 -1
  108. data/lib/mocha/integration/mini_test/version_230_to_2101.rb +4 -1
  109. data/lib/mocha/integration/monkey_patcher.rb +8 -2
  110. data/lib/mocha/integration/test_unit.rb +7 -0
  111. data/lib/mocha/integration/test_unit/adapter.rb +5 -6
  112. data/lib/mocha/integration/test_unit/gem_version_200.rb +5 -2
  113. data/lib/mocha/integration/test_unit/gem_version_201_to_202.rb +5 -2
  114. data/lib/mocha/integration/test_unit/gem_version_203_to_220.rb +5 -2
  115. data/lib/mocha/integration/test_unit/gem_version_230_to_250.rb +5 -2
  116. data/lib/mocha/integration/test_unit/nothing.rb +4 -4
  117. data/lib/mocha/integration/test_unit/ruby_version_185_and_below.rb +4 -1
  118. data/lib/mocha/integration/test_unit/ruby_version_186_and_above.rb +4 -1
  119. data/lib/mocha/invocation.rb +61 -0
  120. data/lib/mocha/is_a.rb +0 -2
  121. data/lib/mocha/logger.rb +0 -4
  122. data/lib/mocha/macos_version.rb +5 -0
  123. data/lib/mocha/method_matcher.rb +1 -5
  124. data/lib/mocha/minitest.rb +8 -0
  125. data/lib/mocha/mock.rb +70 -44
  126. data/lib/mocha/mockery.rb +78 -91
  127. data/lib/mocha/multiple_yields.rb +0 -5
  128. data/lib/mocha/names.rb +2 -12
  129. data/lib/mocha/no_yields.rb +1 -7
  130. data/lib/mocha/not_initialized_error.rb +7 -0
  131. data/lib/mocha/object_methods.rb +27 -33
  132. data/lib/mocha/parameter_matchers.rb +2 -4
  133. data/lib/mocha/parameter_matchers/all_of.rb +2 -8
  134. data/lib/mocha/parameter_matchers/any_of.rb +2 -8
  135. data/lib/mocha/parameter_matchers/any_parameters.rb +3 -9
  136. data/lib/mocha/parameter_matchers/anything.rb +2 -8
  137. data/lib/mocha/parameter_matchers/base.rb +6 -12
  138. data/lib/mocha/parameter_matchers/equals.rb +1 -7
  139. data/lib/mocha/parameter_matchers/{query_string.rb → equivalent_uri.rb} +15 -15
  140. data/lib/mocha/parameter_matchers/has_entries.rb +2 -6
  141. data/lib/mocha/parameter_matchers/has_entry.rb +8 -11
  142. data/lib/mocha/parameter_matchers/has_key.rb +2 -6
  143. data/lib/mocha/parameter_matchers/has_value.rb +2 -6
  144. data/lib/mocha/parameter_matchers/includes.rb +50 -8
  145. data/lib/mocha/parameter_matchers/instance_methods.rb +18 -0
  146. data/lib/mocha/parameter_matchers/instance_of.rb +0 -6
  147. data/lib/mocha/parameter_matchers/is_a.rb +2 -6
  148. data/lib/mocha/parameter_matchers/kind_of.rb +2 -6
  149. data/lib/mocha/parameter_matchers/not.rb +2 -6
  150. data/lib/mocha/parameter_matchers/optionally.rb +4 -10
  151. data/lib/mocha/parameter_matchers/regexp_matches.rb +0 -6
  152. data/lib/mocha/parameter_matchers/responds_with.rb +3 -8
  153. data/lib/mocha/parameter_matchers/yaml_equivalent.rb +2 -6
  154. data/lib/mocha/parameters_matcher.rb +6 -9
  155. data/lib/mocha/pretty_parameters.rb +0 -4
  156. data/lib/mocha/raised_exception.rb +11 -0
  157. data/lib/mocha/receivers.rb +10 -14
  158. data/lib/mocha/return_values.rb +4 -8
  159. data/lib/mocha/ruby_version.rb +4 -0
  160. data/lib/mocha/sequence.rb +4 -9
  161. data/lib/mocha/setup.rb +5 -0
  162. data/lib/mocha/single_return_value.rb +2 -5
  163. data/lib/mocha/single_yield.rb +0 -5
  164. data/lib/mocha/singleton_class.rb +9 -0
  165. data/lib/mocha/state_machine.rb +6 -10
  166. data/lib/mocha/stubbed_method.rb +127 -0
  167. data/lib/mocha/stubbing_error.rb +2 -13
  168. data/lib/mocha/test_unit.rb +7 -2
  169. data/lib/mocha/thrower.rb +4 -6
  170. data/lib/mocha/thrown_object.rb +12 -0
  171. data/lib/mocha/version.rb +1 -1
  172. data/lib/mocha/yield_parameters.rb +3 -7
  173. data/mocha.gemspec +35 -39
  174. data/test/acceptance/acceptance_test_helper.rb +6 -6
  175. data/test/acceptance/bug_18914_test.rb +7 -13
  176. data/test/acceptance/bug_21465_test.rb +0 -3
  177. data/test/acceptance/bug_21563_test.rb +0 -3
  178. data/test/acceptance/display_matching_invocations_alongside_expectations_test.rb +69 -0
  179. data/test/acceptance/exception_rescue_test.rb +7 -9
  180. data/test/acceptance/expectations_on_multiple_methods_test.rb +2 -2
  181. data/test/acceptance/expected_invocation_count_test.rb +27 -30
  182. data/test/acceptance/failure_messages_test.rb +3 -6
  183. data/test/acceptance/issue_272_test.rb +50 -0
  184. data/test/acceptance/issue_65_test.rb +15 -14
  185. data/test/acceptance/issue_70_test.rb +0 -2
  186. data/test/acceptance/mocha_example_test.rb +5 -7
  187. data/test/acceptance/mocha_test_result_test.rb +7 -8
  188. data/test/acceptance/mock_test.rb +48 -9
  189. data/test/acceptance/mocked_methods_dispatch_test.rb +0 -3
  190. data/test/acceptance/multiple_expectations_failure_message_test.rb +16 -18
  191. data/test/acceptance/optional_parameters_test.rb +0 -3
  192. data/test/acceptance/parameter_matcher_test.rb +6 -44
  193. data/test/acceptance/partial_mocks_test.rb +4 -7
  194. data/test/acceptance/prepend_test.rb +86 -0
  195. data/test/acceptance/prevent_use_of_mocha_outside_test_test.rb +76 -0
  196. data/test/acceptance/raise_exception_test.rb +2 -5
  197. data/test/acceptance/return_value_test.rb +0 -3
  198. data/test/acceptance/sequence_test.rb +9 -12
  199. data/test/acceptance/states_test.rb +6 -5
  200. data/test/acceptance/stub_any_instance_method_defined_on_superclass_test.rb +33 -3
  201. data/test/acceptance/stub_any_instance_method_test.rb +119 -21
  202. data/test/acceptance/stub_class_method_defined_on_active_record_association_proxy_test.rb +8 -9
  203. data/test/acceptance/stub_class_method_defined_on_class_test.rb +5 -5
  204. data/test/acceptance/stub_class_method_defined_on_module_test.rb +0 -2
  205. data/test/acceptance/stub_class_method_defined_on_superclass_test.rb +34 -2
  206. data/test/acceptance/stub_everything_test.rb +1 -4
  207. data/test/acceptance/stub_instance_method_defined_on_active_record_association_proxy_test.rb +6 -8
  208. data/test/acceptance/stub_instance_method_defined_on_class_and_aliased_test.rb +0 -2
  209. data/test/acceptance/stub_instance_method_defined_on_class_test.rb +3 -5
  210. data/test/acceptance/stub_instance_method_defined_on_kernel_module_test.rb +63 -2
  211. data/test/acceptance/stub_instance_method_defined_on_module_test.rb +3 -2
  212. data/test/acceptance/stub_instance_method_defined_on_object_class_test.rb +2 -2
  213. data/test/acceptance/stub_instance_method_defined_on_singleton_class_test.rb +0 -3
  214. data/test/acceptance/stub_instance_method_defined_on_superclass_test.rb +0 -2
  215. data/test/acceptance/stub_method_defined_on_module_and_aliased_test.rb +38 -0
  216. data/test/acceptance/stub_module_method_test.rb +58 -21
  217. data/test/acceptance/stub_test.rb +1 -4
  218. data/test/acceptance/stubba_example_test.rb +6 -15
  219. data/test/acceptance/stubba_test_result_test.rb +11 -6
  220. data/test/acceptance/stubbing_error_backtrace_test.rb +6 -7
  221. data/test/acceptance/stubbing_frozen_object_test.rb +2 -2
  222. data/test/acceptance/stubbing_method_accepting_block_parameter_test.rb +12 -8
  223. data/test/acceptance/stubbing_method_unnecessarily_test.rb +5 -7
  224. data/test/acceptance/stubbing_nil_test.rb +36 -35
  225. data/test/acceptance/stubbing_non_existent_any_instance_method_test.rb +23 -12
  226. data/test/acceptance/stubbing_non_existent_class_method_test.rb +14 -14
  227. data/test/acceptance/stubbing_non_existent_instance_method_test.rb +12 -14
  228. data/test/acceptance/stubbing_non_public_any_instance_method_test.rb +8 -10
  229. data/test/acceptance/stubbing_non_public_class_method_test.rb +12 -12
  230. data/test/acceptance/stubbing_non_public_instance_method_test.rb +10 -12
  231. data/test/acceptance/stubbing_on_non_mock_object_test.rb +17 -11
  232. data/test/acceptance/stubbing_same_class_method_on_parent_and_child_classes_test.rb +3 -5
  233. data/test/acceptance/throw_test.rb +0 -3
  234. data/test/acceptance/unexpected_invocation_test.rb +2 -4
  235. data/test/acceptance/unstubbing_test.rb +41 -15
  236. data/test/assertions.rb +6 -4
  237. data/test/deprecation_disabler.rb +1 -1
  238. data/test/execution_point.rb +7 -7
  239. data/test/integration/mini_test_test.rb +2 -2
  240. data/test/integration/shared_tests.rb +27 -23
  241. data/test/integration/test_unit_test.rb +2 -2
  242. data/test/method_definer.rb +11 -19
  243. data/test/mini_test_result.rb +17 -11
  244. data/test/minitest_result.rb +2 -3
  245. data/test/simple_counter.rb +0 -2
  246. data/test/test_helper.rb +13 -5
  247. data/test/test_runner.rb +5 -5
  248. data/test/test_unit_result.rb +4 -2
  249. data/test/unit/any_instance_method_test.rb +74 -31
  250. data/test/unit/array_inspect_test.rb +2 -4
  251. data/test/unit/backtrace_filter_test.rb +3 -5
  252. data/test/unit/cardinality_test.rb +41 -25
  253. data/test/unit/central_test.rb +26 -28
  254. data/test/unit/change_state_side_effect_test.rb +0 -4
  255. data/test/unit/class_methods_test.rb +35 -6
  256. data/test/unit/configuration_test.rb +13 -14
  257. data/test/unit/date_time_inspect_test.rb +1 -3
  258. data/test/unit/exception_raiser_test.rb +10 -7
  259. data/test/unit/expectation_list_test.rb +13 -13
  260. data/test/unit/expectation_test.rb +111 -131
  261. data/test/unit/hash_inspect_test.rb +3 -5
  262. data/test/unit/hooks_test.rb +14 -8
  263. data/test/unit/in_state_ordering_constraint_test.rb +0 -4
  264. data/test/unit/instance_method_test.rb +282 -0
  265. data/test/unit/method_matcher_test.rb +1 -3
  266. data/test/unit/mock_test.rb +56 -25
  267. data/test/unit/mockery_test.rb +49 -29
  268. data/test/unit/module_methods_test.rb +2 -5
  269. data/test/unit/multiple_yields_test.rb +0 -2
  270. data/test/unit/no_yields_test.rb +0 -2
  271. data/test/unit/object_inspect_test.rb +27 -5
  272. data/test/unit/object_methods_test.rb +25 -8
  273. data/test/unit/parameter_matchers/all_of_test.rb +0 -2
  274. data/test/unit/parameter_matchers/any_of_test.rb +0 -2
  275. data/test/unit/parameter_matchers/anything_test.rb +2 -4
  276. data/test/unit/parameter_matchers/equals_test.rb +1 -3
  277. data/test/unit/parameter_matchers/equivalent_uri_test.rb +41 -0
  278. data/test/unit/parameter_matchers/has_entries_test.rb +3 -3
  279. data/test/unit/parameter_matchers/has_entry_test.rb +16 -17
  280. data/test/unit/parameter_matchers/has_key_test.rb +1 -2
  281. data/test/unit/parameter_matchers/has_value_test.rb +2 -4
  282. data/test/unit/parameter_matchers/includes_test.rb +50 -3
  283. data/test/unit/parameter_matchers/instance_of_test.rb +1 -3
  284. data/test/unit/parameter_matchers/is_a_test.rb +1 -3
  285. data/test/unit/parameter_matchers/kind_of_test.rb +1 -3
  286. data/test/unit/parameter_matchers/not_test.rb +0 -2
  287. data/test/unit/parameter_matchers/regexp_matches_test.rb +1 -2
  288. data/test/unit/parameter_matchers/responds_with_test.rb +10 -4
  289. data/test/unit/parameter_matchers/stub_matcher.rb +0 -4
  290. data/test/unit/parameter_matchers/yaml_equivalent_test.rb +1 -3
  291. data/test/unit/parameters_matcher_test.rb +2 -4
  292. data/test/unit/receivers_test.rb +35 -5
  293. data/test/unit/return_values_test.rb +28 -25
  294. data/test/unit/sequence_test.rb +1 -5
  295. data/test/unit/single_return_value_test.rb +6 -3
  296. data/test/unit/single_yield_test.rb +0 -2
  297. data/test/unit/state_machine_test.rb +1 -3
  298. data/test/unit/string_inspect_test.rb +3 -5
  299. data/test/unit/thrower_test.rb +7 -4
  300. data/test/unit/yield_parameters_test.rb +0 -2
  301. data/yard-templates/default/layout/html/google_analytics.erb +6 -9
  302. data/yard-templates/default/layout/html/setup.rb +2 -3
  303. metadata +99 -42
  304. data/lib/mocha/class_method.rb +0 -106
  305. data/lib/mocha/mini_test.rb +0 -3
  306. data/lib/mocha/module_method.rb +0 -16
  307. data/lib/mocha/module_methods.rb +0 -14
  308. data/lib/mocha/parameter_matchers/object.rb +0 -17
  309. data/lib/mocha/standalone.rb +0 -4
  310. data/lib/mocha/unexpected_invocation.rb +0 -26
  311. data/lib/mocha_standalone.rb +0 -4
  312. data/test/acceptance/mock_with_initializer_block_test.rb +0 -51
  313. data/test/unit/class_method_test.rb +0 -223
@@ -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,6 +1,19 @@
1
1
  module Mocha
2
-
3
2
  class Central
3
+ class Null < self
4
+ def initialize(&block)
5
+ super
6
+ @raise_not_initialized_error = block
7
+ end
8
+
9
+ def stub(*)
10
+ @raise_not_initialized_error.call
11
+ end
12
+
13
+ def unstub(*)
14
+ @raise_not_initialized_error.call
15
+ end
16
+ end
4
17
 
5
18
  attr_accessor :stubba_methods
6
19
 
@@ -9,25 +22,21 @@ module Mocha
9
22
  end
10
23
 
11
24
  def stub(method)
12
- unless stubba_methods.detect { |m| m.matches?(method) }
13
- method.stub
14
- stubba_methods.push(method)
15
- end
25
+ return if stubba_methods.detect { |m| m.matches?(method) }
26
+ method.stub
27
+ stubba_methods.push(method)
16
28
  end
17
29
 
18
30
  def unstub(method)
19
- if existing = stubba_methods.detect { |m| m.matches?(method) }
20
- existing.unstub
21
- stubba_methods.delete(existing)
22
- end
31
+ return unless (existing = stubba_methods.detect { |m| m.matches?(method) })
32
+ existing.unstub
33
+ stubba_methods.delete(existing)
23
34
  end
24
35
 
25
36
  def unstub_all
26
- while stubba_methods.any? do
37
+ while stubba_methods.any?
27
38
  unstub(stubba_methods.first)
28
39
  end
29
40
  end
30
-
31
41
  end
32
-
33
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,45 +1,36 @@
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
21
12
 
22
- def mocha
23
- @mocha ||= Mocha::Mockery.instance.mock_impersonating_any_instance_of(@stubba_object)
13
+ def mocha(instantiate = true)
14
+ if instantiate
15
+ @mocha ||= Mocha::Mockery.instance.mock_impersonating_any_instance_of(@stubba_object)
16
+ else
17
+ defined?(@mocha) ? @mocha : nil
18
+ end
24
19
  end
25
20
 
26
21
  def stubba_method
27
22
  Mocha::AnyInstanceMethod
28
23
  end
29
24
 
30
- def stubba_object
25
+ def stubba_class
31
26
  @stubba_object
32
27
  end
33
28
 
34
- def method_exists?(method, include_public_methods = true)
35
- if include_public_methods
36
- return true if @stubba_object.public_instance_methods(include_superclass_methods = true).include?(method)
37
- end
38
- return true if @stubba_object.protected_instance_methods(include_superclass_methods = true).include?(method)
39
- return true if @stubba_object.private_instance_methods(include_superclass_methods = true).include?(method)
40
- return false
29
+ def respond_to?(method)
30
+ @stubba_object.allocate.respond_to?(method.to_sym)
41
31
  end
42
32
 
33
+ attr_reader :stubba_object
43
34
  end
44
35
 
45
36
  # @return [Mock] a mock object which will detect calls to any instance of this class.
@@ -58,6 +49,13 @@ module Mocha
58
49
  @any_instance ||= AnyInstance.new(self)
59
50
  end
60
51
 
52
+ # rubocop:disable Metrics/CyclomaticComplexity
53
+ def method_visibility(method, include_public_methods = true)
54
+ (include_public_methods && public_method_defined?(method) && :public) ||
55
+ (protected_method_defined?(method) && :protected) ||
56
+ (private_method_defined?(method) && :private)
57
+ end
58
+ # rubocop:enable Metrics/CyclomaticComplexity
59
+ alias_method :method_exists?, :method_visibility
61
60
  end
62
-
63
61
  end
@@ -1,55 +1,323 @@
1
1
  module Mocha
2
+ # Allows setting of configuration options. See {Configuration} for the available options.
3
+ #
4
+ # Typically the configuration is set globally in a +test_helper.rb+ or +spec_helper.rb+ file.
5
+ #
6
+ # @see Configuration
7
+ #
8
+ # @yieldparam configuration [Configuration] the configuration for modification
9
+ #
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
15
+ # end
16
+ #
17
+ def self.configure
18
+ yield configuration
19
+ end
2
20
 
3
- # Configuration settings.
4
- class Configuration
21
+ # @private
22
+ def self.configuration
23
+ Configuration.configuration
24
+ end
5
25
 
26
+ # This class provides a number of ways to configure the library.
27
+ #
28
+ # Typically the configuration is set globally in a +test_helper.rb+ or +spec_helper.rb+ file.
29
+ #
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
35
+ # end
36
+ #
37
+ class Configuration
38
+ # @private
6
39
  DEFAULTS = {
7
40
  :stubbing_method_unnecessarily => :allow,
8
41
  :stubbing_method_on_non_mock_object => :allow,
9
42
  :stubbing_non_existent_method => :allow,
10
43
  :stubbing_non_public_method => :allow,
11
44
  :stubbing_method_on_nil => :prevent,
12
- }
45
+ :display_matching_invocations_on_failure => false
46
+ }.freeze
13
47
 
14
- 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
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
15
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
16
251
  # Allow the specified +action+.
17
252
  #
18
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+.
19
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=}
20
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
21
267
  change_config action, :allow, &block
22
268
  end
23
269
 
24
270
  # @private
25
271
  def allow?(action)
26
- configuration[action] == :allow
272
+ configuration.allow?(action)
27
273
  end
28
274
 
29
275
  # Warn if the specified +action+ is attempted.
30
276
  #
31
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+.
32
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=}
33
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
34
291
  change_config action, :warn, &block
35
292
  end
36
293
 
37
294
  # @private
38
295
  def warn_when?(action)
39
- configuration[action] == :warn
296
+ configuration.warn_when?(action)
40
297
  end
41
298
 
42
- # Raise a {StubbingError} if if the specified +action+ is attempted.
299
+ # Raise a {StubbingError} if the specified +action+ is attempted.
43
300
  #
44
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+.
45
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=}
46
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
47
315
  change_config action, :prevent, &block
48
316
  end
49
317
 
50
318
  # @private
51
319
  def prevent?(action)
52
- configuration[action] == :prevent
320
+ configuration.prevent?(action)
53
321
  end
54
322
 
55
323
  # @private
@@ -57,33 +325,52 @@ module Mocha
57
325
  @configuration = nil
58
326
  end
59
327
 
60
- 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
61
347
 
62
348
  # @private
63
349
  def configuration
64
- @configuration ||= DEFAULTS.dup
350
+ @configuration ||= new
65
351
  end
66
352
 
353
+ private
354
+
67
355
  # @private
68
356
  def change_config(action, new_value, &block)
69
357
  if block_given?
70
358
  temporarily_change_config action, new_value, &block
71
359
  else
72
- configuration[action] = new_value
360
+ configuration.send("#{action}=".to_sym, new_value)
73
361
  end
74
362
  end
75
363
 
76
364
  # @private
77
- def temporarily_change_config(action, new_value, &block)
78
- original_value = configuration[action]
79
- 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
80
370
  yield
81
371
  ensure
82
- configuration[action] = original_value
372
+ @configuration = original_configuration
83
373
  end
84
-
85
374
  end
86
-
87
375
  end
88
-
89
376
  end