mocha 1.2.1 → 1.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (265) hide show
  1. checksums.yaml +5 -5
  2. data/.github/FUNDING.yml +1 -0
  3. data/.rubocop.yml +61 -0
  4. data/.rubocop_todo.yml +27 -0
  5. data/.yardopts +1 -0
  6. data/CONTRIBUTING.md +4 -9
  7. data/Gemfile +29 -0
  8. data/README.md +104 -106
  9. data/RELEASE.md +277 -1
  10. data/Rakefile +46 -44
  11. data/gemfiles/Gemfile.minitest.latest +1 -0
  12. data/gemfiles/Gemfile.test-unit.latest +2 -5
  13. data/init.rb +1 -3
  14. data/lib/mocha/any_instance_method.rb +9 -62
  15. data/lib/mocha/api.rb +144 -68
  16. data/lib/mocha/argument_iterator.rb +4 -8
  17. data/lib/mocha/backtrace_filter.rb +1 -5
  18. data/lib/mocha/block_matcher.rb +31 -0
  19. data/lib/mocha/cardinality.rb +60 -49
  20. data/lib/mocha/central.rb +21 -12
  21. data/lib/mocha/change_state_side_effect.rb +0 -4
  22. data/lib/mocha/class_methods.rb +19 -21
  23. data/lib/mocha/configuration.rb +372 -18
  24. data/lib/mocha/debug.rb +3 -2
  25. data/lib/mocha/deprecation.rb +8 -11
  26. data/lib/mocha/detection/mini_test.rb +0 -2
  27. data/lib/mocha/detection/test_unit.rb +3 -5
  28. data/lib/mocha/error_with_filtered_backtrace.rb +13 -0
  29. data/lib/mocha/exception_raiser.rb +4 -6
  30. data/lib/mocha/expectation.rb +125 -89
  31. data/lib/mocha/expectation_error.rb +1 -1
  32. data/lib/mocha/expectation_error_factory.rb +0 -1
  33. data/lib/mocha/expectation_list.rb +7 -11
  34. data/lib/mocha/hooks.rb +1 -3
  35. data/lib/mocha/in_state_ordering_constraint.rb +0 -4
  36. data/lib/mocha/inspect.rb +30 -38
  37. data/lib/mocha/instance_method.rb +11 -8
  38. data/lib/mocha/integration/mini_test/adapter.rb +2 -4
  39. data/lib/mocha/integration/mini_test/exception_translation.rb +1 -1
  40. data/lib/mocha/integration/mini_test/nothing.rb +4 -4
  41. data/lib/mocha/integration/mini_test/version_13.rb +4 -1
  42. data/lib/mocha/integration/mini_test/version_140.rb +4 -1
  43. data/lib/mocha/integration/mini_test/version_141.rb +4 -1
  44. data/lib/mocha/integration/mini_test/version_142_to_172.rb +4 -1
  45. data/lib/mocha/integration/mini_test/version_200.rb +4 -1
  46. data/lib/mocha/integration/mini_test/version_201_to_222.rb +4 -1
  47. data/lib/mocha/integration/mini_test/version_2110_to_2111.rb +4 -1
  48. data/lib/mocha/integration/mini_test/version_2112_to_320.rb +4 -1
  49. data/lib/mocha/integration/mini_test/version_230_to_2101.rb +4 -1
  50. data/lib/mocha/integration/mini_test.rb +7 -0
  51. data/lib/mocha/integration/monkey_patcher.rb +5 -7
  52. data/lib/mocha/integration/test_unit/adapter.rb +5 -6
  53. data/lib/mocha/integration/test_unit/gem_version_200.rb +5 -2
  54. data/lib/mocha/integration/test_unit/gem_version_201_to_202.rb +5 -2
  55. data/lib/mocha/integration/test_unit/gem_version_203_to_220.rb +5 -2
  56. data/lib/mocha/integration/test_unit/gem_version_230_to_250.rb +5 -2
  57. data/lib/mocha/integration/test_unit/nothing.rb +4 -4
  58. data/lib/mocha/integration/test_unit/ruby_version_186_and_above.rb +4 -1
  59. data/lib/mocha/integration/test_unit.rb +7 -2
  60. data/lib/mocha/integration.rb +2 -5
  61. data/lib/mocha/invocation.rb +86 -0
  62. data/lib/mocha/is_a.rb +0 -2
  63. data/lib/mocha/logger.rb +0 -4
  64. data/lib/mocha/macos_version.rb +5 -0
  65. data/lib/mocha/method_matcher.rb +1 -5
  66. data/lib/mocha/minitest.rb +9 -0
  67. data/lib/mocha/mock.rb +102 -58
  68. data/lib/mocha/mockery.rb +70 -99
  69. data/lib/mocha/names.rb +2 -12
  70. data/lib/mocha/not_initialized_error.rb +7 -0
  71. data/lib/mocha/object_methods.rb +25 -31
  72. data/lib/mocha/parameter_matchers/all_of.rb +2 -8
  73. data/lib/mocha/parameter_matchers/any_of.rb +2 -8
  74. data/lib/mocha/parameter_matchers/any_parameters.rb +3 -9
  75. data/lib/mocha/parameter_matchers/anything.rb +2 -8
  76. data/lib/mocha/parameter_matchers/base.rb +6 -12
  77. data/lib/mocha/parameter_matchers/equals.rb +0 -6
  78. data/lib/mocha/parameter_matchers/{query_string.rb → equivalent_uri.rb} +15 -15
  79. data/lib/mocha/parameter_matchers/has_entries.rb +2 -7
  80. data/lib/mocha/parameter_matchers/has_entry.rb +26 -21
  81. data/lib/mocha/parameter_matchers/has_key.rb +2 -7
  82. data/lib/mocha/parameter_matchers/has_keys.rb +53 -0
  83. data/lib/mocha/parameter_matchers/has_value.rb +2 -7
  84. data/lib/mocha/parameter_matchers/includes.rb +6 -7
  85. data/lib/mocha/parameter_matchers/instance_methods.rb +18 -0
  86. data/lib/mocha/parameter_matchers/instance_of.rb +0 -6
  87. data/lib/mocha/parameter_matchers/is_a.rb +2 -7
  88. data/lib/mocha/parameter_matchers/kind_of.rb +2 -6
  89. data/lib/mocha/parameter_matchers/not.rb +2 -7
  90. data/lib/mocha/parameter_matchers/optionally.rb +4 -10
  91. data/lib/mocha/parameter_matchers/regexp_matches.rb +0 -6
  92. data/lib/mocha/parameter_matchers/responds_with.rb +3 -8
  93. data/lib/mocha/parameter_matchers/yaml_equivalent.rb +2 -6
  94. data/lib/mocha/parameter_matchers.rb +3 -4
  95. data/lib/mocha/parameters_matcher.rb +6 -9
  96. data/lib/mocha/raised_exception.rb +11 -0
  97. data/lib/mocha/receivers.rb +10 -14
  98. data/lib/mocha/return_values.rb +4 -8
  99. data/lib/mocha/ruby_version.rb +8 -1
  100. data/lib/mocha/sequence.rb +4 -9
  101. data/lib/mocha/setup.rb +5 -0
  102. data/lib/mocha/single_return_value.rb +2 -5
  103. data/lib/mocha/state_machine.rb +33 -46
  104. data/lib/mocha/stubbed_method.rb +124 -0
  105. data/lib/mocha/stubbing_error.rb +2 -13
  106. data/lib/mocha/test_unit.rb +8 -2
  107. data/lib/mocha/thrower.rb +4 -6
  108. data/lib/mocha/thrown_object.rb +12 -0
  109. data/lib/mocha/version.rb +1 -1
  110. data/lib/mocha/yield_parameters.rb +7 -17
  111. data/mocha.gemspec +14 -65
  112. data/yard-templates/default/layout/html/google_analytics.erb +6 -9
  113. data/yard-templates/default/layout/html/setup.rb +2 -3
  114. metadata +25 -247
  115. data/bin/build-matrix +0 -70
  116. data/gemfiles/Gemfile.minitest.1.3.0 +0 -7
  117. data/gemfiles/Gemfile.minitest.1.4.0 +0 -7
  118. data/gemfiles/Gemfile.minitest.1.4.1 +0 -7
  119. data/gemfiles/Gemfile.minitest.1.4.2 +0 -7
  120. data/gemfiles/Gemfile.minitest.2.0.0 +0 -7
  121. data/gemfiles/Gemfile.minitest.2.0.1 +0 -7
  122. data/gemfiles/Gemfile.minitest.2.11.0 +0 -7
  123. data/gemfiles/Gemfile.minitest.2.11.2 +0 -7
  124. data/gemfiles/Gemfile.minitest.2.3.0 +0 -7
  125. data/gemfiles/Gemfile.test-unit.2.0.0 +0 -7
  126. data/gemfiles/Gemfile.test-unit.2.0.1 +0 -7
  127. data/gemfiles/Gemfile.test-unit.2.0.3 +0 -7
  128. data/lib/mocha/class_method.rb +0 -119
  129. data/lib/mocha/integration/test_unit/ruby_version_185_and_below.rb +0 -58
  130. data/lib/mocha/mini_test.rb +0 -3
  131. data/lib/mocha/module_method.rb +0 -16
  132. data/lib/mocha/module_methods.rb +0 -14
  133. data/lib/mocha/multiple_yields.rb +0 -20
  134. data/lib/mocha/no_yields.rb +0 -11
  135. data/lib/mocha/parameter_matchers/object.rb +0 -17
  136. data/lib/mocha/pretty_parameters.rb +0 -28
  137. data/lib/mocha/single_yield.rb +0 -18
  138. data/lib/mocha/standalone.rb +0 -4
  139. data/lib/mocha/unexpected_invocation.rb +0 -26
  140. data/lib/mocha_standalone.rb +0 -4
  141. data/test/acceptance/acceptance_test_helper.rb +0 -41
  142. data/test/acceptance/bug_18914_test.rb +0 -43
  143. data/test/acceptance/bug_21465_test.rb +0 -34
  144. data/test/acceptance/bug_21563_test.rb +0 -25
  145. data/test/acceptance/exception_rescue_test.rb +0 -55
  146. data/test/acceptance/expectations_on_multiple_methods_test.rb +0 -55
  147. data/test/acceptance/expected_invocation_count_test.rb +0 -232
  148. data/test/acceptance/failure_messages_test.rb +0 -64
  149. data/test/acceptance/issue_272_test.rb +0 -52
  150. data/test/acceptance/issue_65_test.rb +0 -63
  151. data/test/acceptance/issue_70_test.rb +0 -55
  152. data/test/acceptance/mocha_example_test.rb +0 -98
  153. data/test/acceptance/mocha_test_result_test.rb +0 -84
  154. data/test/acceptance/mock_test.rb +0 -100
  155. data/test/acceptance/mock_with_initializer_block_test.rb +0 -51
  156. data/test/acceptance/mocked_methods_dispatch_test.rb +0 -78
  157. data/test/acceptance/multiple_expectations_failure_message_test.rb +0 -68
  158. data/test/acceptance/optional_parameters_test.rb +0 -70
  159. data/test/acceptance/parameter_matcher_test.rb +0 -337
  160. data/test/acceptance/partial_mocks_test.rb +0 -47
  161. data/test/acceptance/prepend_test.rb +0 -89
  162. data/test/acceptance/raise_exception_test.rb +0 -39
  163. data/test/acceptance/return_value_test.rb +0 -52
  164. data/test/acceptance/sequence_test.rb +0 -192
  165. data/test/acceptance/states_test.rb +0 -70
  166. data/test/acceptance/stub_any_instance_method_defined_on_superclass_test.rb +0 -34
  167. data/test/acceptance/stub_any_instance_method_test.rb +0 -280
  168. data/test/acceptance/stub_class_method_defined_on_active_record_association_proxy_test.rb +0 -106
  169. data/test/acceptance/stub_class_method_defined_on_class_test.rb +0 -78
  170. data/test/acceptance/stub_class_method_defined_on_module_test.rb +0 -75
  171. data/test/acceptance/stub_class_method_defined_on_superclass_test.rb +0 -112
  172. data/test/acceptance/stub_everything_test.rb +0 -56
  173. data/test/acceptance/stub_instance_method_defined_on_active_record_association_proxy_test.rb +0 -93
  174. data/test/acceptance/stub_instance_method_defined_on_class_and_aliased_test.rb +0 -69
  175. data/test/acceptance/stub_instance_method_defined_on_class_test.rb +0 -69
  176. data/test/acceptance/stub_instance_method_defined_on_kernel_module_test.rb +0 -75
  177. data/test/acceptance/stub_instance_method_defined_on_module_test.rb +0 -78
  178. data/test/acceptance/stub_instance_method_defined_on_object_class_test.rb +0 -75
  179. data/test/acceptance/stub_instance_method_defined_on_singleton_class_test.rb +0 -70
  180. data/test/acceptance/stub_instance_method_defined_on_superclass_test.rb +0 -72
  181. data/test/acceptance/stub_method_defined_on_module_and_aliased_test.rb +0 -39
  182. data/test/acceptance/stub_module_method_test.rb +0 -163
  183. data/test/acceptance/stub_test.rb +0 -52
  184. data/test/acceptance/stubba_example_test.rb +0 -102
  185. data/test/acceptance/stubba_test_result_test.rb +0 -66
  186. data/test/acceptance/stubbing_error_backtrace_test.rb +0 -64
  187. data/test/acceptance/stubbing_frozen_object_test.rb +0 -88
  188. data/test/acceptance/stubbing_method_accepting_block_parameter_test.rb +0 -48
  189. data/test/acceptance/stubbing_method_unnecessarily_test.rb +0 -65
  190. data/test/acceptance/stubbing_nil_test.rb +0 -61
  191. data/test/acceptance/stubbing_non_existent_any_instance_method_test.rb +0 -143
  192. data/test/acceptance/stubbing_non_existent_class_method_test.rb +0 -157
  193. data/test/acceptance/stubbing_non_existent_instance_method_test.rb +0 -147
  194. data/test/acceptance/stubbing_non_public_any_instance_method_test.rb +0 -130
  195. data/test/acceptance/stubbing_non_public_class_method_test.rb +0 -163
  196. data/test/acceptance/stubbing_non_public_instance_method_test.rb +0 -143
  197. data/test/acceptance/stubbing_on_non_mock_object_test.rb +0 -64
  198. data/test/acceptance/stubbing_same_class_method_on_parent_and_child_classes_test.rb +0 -35
  199. data/test/acceptance/throw_test.rb +0 -45
  200. data/test/acceptance/unexpected_invocation_test.rb +0 -25
  201. data/test/acceptance/unstubbing_test.rb +0 -168
  202. data/test/assertions.rb +0 -8
  203. data/test/deprecation_disabler.rb +0 -15
  204. data/test/execution_point.rb +0 -36
  205. data/test/integration/mini_test_test.rb +0 -8
  206. data/test/integration/shared_tests.rb +0 -174
  207. data/test/integration/test_unit_test.rb +0 -8
  208. data/test/method_definer.rb +0 -24
  209. data/test/mini_test_result.rb +0 -90
  210. data/test/minitest_result.rb +0 -49
  211. data/test/simple_counter.rb +0 -13
  212. data/test/test_helper.rb +0 -50
  213. data/test/test_runner.rb +0 -58
  214. data/test/test_unit_result.rb +0 -20
  215. data/test/unit/any_instance_method_test.rb +0 -134
  216. data/test/unit/array_inspect_test.rb +0 -16
  217. data/test/unit/backtrace_filter_test.rb +0 -19
  218. data/test/unit/cardinality_test.rb +0 -56
  219. data/test/unit/central_test.rb +0 -100
  220. data/test/unit/change_state_side_effect_test.rb +0 -41
  221. data/test/unit/class_method_test.rb +0 -225
  222. data/test/unit/class_methods_test.rb +0 -40
  223. data/test/unit/configuration_test.rb +0 -38
  224. data/test/unit/date_time_inspect_test.rb +0 -21
  225. data/test/unit/exception_raiser_test.rb +0 -42
  226. data/test/unit/expectation_list_test.rb +0 -82
  227. data/test/unit/expectation_test.rb +0 -497
  228. data/test/unit/hash_inspect_test.rb +0 -16
  229. data/test/unit/hooks_test.rb +0 -29
  230. data/test/unit/in_state_ordering_constraint_test.rb +0 -43
  231. data/test/unit/method_matcher_test.rb +0 -28
  232. data/test/unit/mock_test.rb +0 -342
  233. data/test/unit/mockery_test.rb +0 -151
  234. data/test/unit/module_methods_test.rb +0 -19
  235. data/test/unit/multiple_yields_test.rb +0 -18
  236. data/test/unit/no_yields_test.rb +0 -18
  237. data/test/unit/object_inspect_test.rb +0 -39
  238. data/test/unit/object_methods_test.rb +0 -46
  239. data/test/unit/parameter_matchers/all_of_test.rb +0 -26
  240. data/test/unit/parameter_matchers/any_of_test.rb +0 -26
  241. data/test/unit/parameter_matchers/anything_test.rb +0 -21
  242. data/test/unit/parameter_matchers/equals_test.rb +0 -25
  243. data/test/unit/parameter_matchers/has_entries_test.rb +0 -51
  244. data/test/unit/parameter_matchers/has_entry_test.rb +0 -129
  245. data/test/unit/parameter_matchers/has_key_test.rb +0 -55
  246. data/test/unit/parameter_matchers/has_value_test.rb +0 -57
  247. data/test/unit/parameter_matchers/includes_test.rb +0 -102
  248. data/test/unit/parameter_matchers/instance_of_test.rb +0 -25
  249. data/test/unit/parameter_matchers/is_a_test.rb +0 -25
  250. data/test/unit/parameter_matchers/kind_of_test.rb +0 -25
  251. data/test/unit/parameter_matchers/not_test.rb +0 -26
  252. data/test/unit/parameter_matchers/regexp_matches_test.rb +0 -46
  253. data/test/unit/parameter_matchers/responds_with_test.rb +0 -32
  254. data/test/unit/parameter_matchers/stub_matcher.rb +0 -27
  255. data/test/unit/parameter_matchers/yaml_equivalent_test.rb +0 -25
  256. data/test/unit/parameters_matcher_test.rb +0 -121
  257. data/test/unit/receivers_test.rb +0 -66
  258. data/test/unit/return_values_test.rb +0 -63
  259. data/test/unit/sequence_test.rb +0 -104
  260. data/test/unit/single_return_value_test.rb +0 -14
  261. data/test/unit/single_yield_test.rb +0 -18
  262. data/test/unit/state_machine_test.rb +0 -98
  263. data/test/unit/string_inspect_test.rb +0 -11
  264. data/test/unit/thrower_test.rb +0 -20
  265. data/test/unit/yield_parameters_test.rb +0 -93
@@ -0,0 +1,86 @@
1
+ require 'mocha/parameters_matcher'
2
+ require 'mocha/raised_exception'
3
+ require 'mocha/return_values'
4
+ require 'mocha/thrown_object'
5
+ require 'mocha/yield_parameters'
6
+ require 'mocha/configuration'
7
+ require 'mocha/deprecation'
8
+
9
+ module Mocha
10
+ class Invocation
11
+ attr_reader :method_name, :block
12
+
13
+ def initialize(mock, method_name, arguments = [], block = nil)
14
+ @mock = mock
15
+ @method_name = method_name
16
+ @arguments = arguments
17
+ @block = block
18
+ @yields = []
19
+ @result = nil
20
+ end
21
+
22
+ def call(yield_parameters = YieldParameters.new, return_values = ReturnValues.new)
23
+ yield_parameters.next_invocation.each do |yield_args|
24
+ @yields << ParametersMatcher.new(yield_args)
25
+ if @block
26
+ @block.call(*yield_args)
27
+ else
28
+ raise LocalJumpError unless Mocha.configuration.reinstate_undocumented_behaviour_from_v1_9?
29
+ yield_args_description = ParametersMatcher.new(yield_args).mocha_inspect
30
+ Deprecation.warning(
31
+ "Stubbed method was instructed to yield #{yield_args_description}, but no block was given by invocation: #{call_description}.",
32
+ ' This will raise a LocalJumpError in the future.',
33
+ ' Use Expectation#with_block_given to constrain this expectation to match invocations supplying a block.',
34
+ ' And, if necessary, add another expectation to match invocations not supplying a block.'
35
+ )
36
+ end
37
+ end
38
+ return_values.next(self)
39
+ end
40
+
41
+ def returned(value)
42
+ @result = value
43
+ end
44
+
45
+ def raised(exception)
46
+ @result = RaisedException.new(exception)
47
+ end
48
+
49
+ def threw(tag, value)
50
+ @result = ThrownObject.new(tag, value)
51
+ end
52
+
53
+ def arguments
54
+ @arguments.dup
55
+ end
56
+
57
+ def call_description
58
+ description = "#{@mock.mocha_inspect}.#{@method_name}#{argument_description}"
59
+ description << ' { ... }' unless @block.nil?
60
+ description
61
+ end
62
+
63
+ def short_call_description
64
+ "#{@method_name}(#{@arguments.join(', ')})"
65
+ end
66
+
67
+ def result_description
68
+ desc = "# => #{@result.mocha_inspect}"
69
+ desc << " after yielding #{@yields.map(&:mocha_inspect).join(', then ')}" if @yields.any?
70
+ desc
71
+ end
72
+
73
+ def full_description
74
+ "\n - #{call_description} #{result_description}"
75
+ end
76
+
77
+ private
78
+
79
+ def argument_description
80
+ signature = arguments.mocha_inspect
81
+ signature = signature.gsub(/^\[|\]$/, '')
82
+ signature = signature.gsub(/^\{|\}$/, '') if arguments.length == 1
83
+ "(#{signature})"
84
+ end
85
+ end
86
+ end
data/lib/mocha/is_a.rb CHANGED
@@ -1,9 +1,7 @@
1
1
  class Object
2
-
3
2
  # :stopdoc:
4
3
 
5
4
  alias_method :__is_a__, :is_a?
6
5
 
7
6
  # :startdoc:
8
-
9
7
  end
data/lib/mocha/logger.rb CHANGED
@@ -1,7 +1,5 @@
1
1
  module Mocha
2
-
3
2
  class Logger
4
-
5
3
  def initialize(io)
6
4
  @io = io
7
5
  end
@@ -9,7 +7,5 @@ module Mocha
9
7
  def warn(message)
10
8
  @io.puts "WARNING: #{message}"
11
9
  end
12
-
13
10
  end
14
-
15
11
  end
@@ -0,0 +1,5 @@
1
+ module Mocha
2
+ MACOS = /darwin/.match(RUBY_PLATFORM)
3
+ MACOS_VERSION = MACOS && /darwin(\d+)/.match(RUBY_PLATFORM)[1].to_i
4
+ MACOS_MOJAVE_VERSION = 18
5
+ end
@@ -1,7 +1,5 @@
1
1
  module Mocha
2
-
3
2
  class MethodMatcher
4
-
5
3
  attr_reader :expected_method_name
6
4
 
7
5
  def initialize(expected_method_name)
@@ -13,9 +11,7 @@ module Mocha
13
11
  end
14
12
 
15
13
  def mocha_inspect
16
- "#{@expected_method_name}"
14
+ @expected_method_name.to_s
17
15
  end
18
-
19
16
  end
20
-
21
17
  end
@@ -0,0 +1,9 @@
1
+ require 'mocha/ruby_version'
2
+ require 'mocha/integration/mini_test'
3
+ require 'mocha/deprecation'
4
+
5
+ unless Mocha::Integration::MiniTest.activate
6
+ Mocha::Deprecation.warning(
7
+ "MiniTest must be loaded *before* `require 'mocha/minitest'`."
8
+ )
9
+ end
data/lib/mocha/mock.rb CHANGED
@@ -1,20 +1,25 @@
1
- require 'metaclass'
2
1
  require 'mocha/expectation'
3
2
  require 'mocha/expectation_list'
3
+ require 'mocha/invocation'
4
4
  require 'mocha/names'
5
5
  require 'mocha/receivers'
6
6
  require 'mocha/method_matcher'
7
7
  require 'mocha/parameters_matcher'
8
- require 'mocha/unexpected_invocation'
9
8
  require 'mocha/argument_iterator'
10
9
  require 'mocha/expectation_error_factory'
11
10
 
12
11
  module Mocha
13
-
14
12
  # Traditional mock object.
15
13
  #
16
- # All methods return an {Expectation} which can be further modified by
17
- # methods on {Expectation}.
14
+ # {expects} and {stubs} return an {Expectation} which can be further modified
15
+ # by methods on {Expectation}.
16
+ #
17
+ # {responds_like} and {responds_like_instance_of} both return a {Mock}, and
18
+ # can therefore, be chained to the original creation methods in {API}.
19
+ # They force the mock to indicate what it is supposed to be mocking, thus
20
+ # making it a safer verifying mock. They check that the underlying +responder+
21
+ # will actually respond to the methods being stubbed, throwing a
22
+ # +NoMethodError+ upon invocation otherwise.
18
23
  #
19
24
  # Stubs and expectations are basically the same thing. A stub is just an
20
25
  # expectation of zero or more invocations. The {#stubs} method is syntactic
@@ -67,15 +72,14 @@ module Mocha
67
72
  # different mock objects, use the {Expectation#in_sequence} method to
68
73
  # explicitly define a total or partial ordering of invocations.
69
74
  class Mock
70
-
71
75
  # Adds an expectation that the specified method must be called exactly once with any parameters.
72
76
  #
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.
77
+ # @return [Expectation] last-built expectation which can be further modified by methods on {Expectation}.
75
78
  #
76
79
  # @overload def expects(method_name)
80
+ # @param [Symbol,String] method_name name of expected method
77
81
  # @overload def expects(expected_methods_vs_return_values)
78
- # @return [Expectation] last-built expectation which can be further modified by methods on {Expectation}.
82
+ # @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
83
  #
80
84
  # @example Expected method invoked once so no error raised
81
85
  # object = mock()
@@ -103,24 +107,26 @@ module Mocha
103
107
  # object.expects(:expected_method_one).returns(:result_one)
104
108
  # object.expects(:expected_method_two).returns(:result_two)
105
109
  def expects(method_name_or_hash, backtrace = nil)
110
+ expectation = nil
106
111
  iterator = ArgumentIterator.new(method_name_or_hash)
107
- iterator.each { |*args|
112
+ iterator.each do |*args|
108
113
  method_name = args.shift
109
114
  ensure_method_not_already_defined(method_name)
110
115
  expectation = Expectation.new(self, method_name, backtrace)
111
- expectation.returns(args.shift) if args.length > 0
116
+ expectation.returns(args.shift) unless args.empty?
112
117
  @expectations.add(expectation)
113
- }
118
+ end
119
+ expectation
114
120
  end
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()
@@ -139,36 +145,48 @@ module Mocha
139
145
  # object.stubs(:stubbed_method_one).returns(:result_one)
140
146
  # object.stubs(:stubbed_method_two).returns(:result_two)
141
147
  def stubs(method_name_or_hash, backtrace = nil)
148
+ expectation = nil
142
149
  iterator = ArgumentIterator.new(method_name_or_hash)
143
- iterator.each { |*args|
150
+ iterator.each do |*args|
144
151
  method_name = args.shift
145
152
  ensure_method_not_already_defined(method_name)
146
153
  expectation = Expectation.new(self, method_name, backtrace)
147
154
  expectation.at_least(0)
148
- expectation.returns(args.shift) if args.length > 0
155
+ expectation.returns(args.shift) unless args.empty?
149
156
  @expectations.add(expectation)
150
- }
157
+ end
158
+ expectation
151
159
  end
152
160
 
153
- # Removes the specified stubbed method (added by calls to {#expects} or {#stubs}) and all expectations associated with it.
161
+ # Removes the specified stubbed methods (added by calls to {#expects} or {#stubs}) and all expectations associated with them.
154
162
  #
155
- # @param [Symbol] method_name name of method to unstub.
163
+ # @param [Array<Symbol>] method_names names of methods to unstub.
156
164
  #
157
165
  # @example Invoking an unstubbed method causes error to be raised
158
- # object = mock('mock') do
166
+ # object = mock('mock')
159
167
  # object.stubs(:stubbed_method).returns(:result_one)
160
168
  # object.stubbed_method # => :result_one
161
169
  # object.unstub(:stubbed_method)
162
170
  # object.stubbed_method # => unexpected invocation: #<Mock:mock>.stubbed_method()
163
- def unstub(method_name)
164
- @expectations.remove_all_matching_method(method_name)
171
+ #
172
+ # @example Unstubbing multiple methods.
173
+ # multiplier.unstub(:double, :triple)
174
+ #
175
+ # # exactly equivalent to
176
+ #
177
+ # multiplier.unstub(:double)
178
+ # multiplier.unstub(:triple)
179
+ def unstub(*method_names)
180
+ method_names.each do |method_name|
181
+ @expectations.remove_all_matching_method(method_name)
182
+ end
165
183
  end
166
184
 
167
- # 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.
185
+ # Constrains the {Mock} instance so that it can only expect or stub methods to which +responder+ responds publicly. The constraint is only applied at method invocation time.
168
186
  #
169
- # A +NoMethodError+ will be raised if the +responder+ does not +#respond_to?+ a method invocation (even if the method has been expected or stubbed).
187
+ # A +NoMethodError+ will be raised if the +responder+ does not publicly +#respond_to?+ the invoked method (even if the method has been expected or stubbed).
170
188
  #
171
- # The {Mock} instance will delegate its +#respond_to?+ method to the +responder+.
189
+ # The {Mock} instance will delegate its +#respond_to?+ method to the +responder+. However, the +include_all+ parameter is not passed through, so only public methods on the +responder+ will be considered.
172
190
  #
173
191
  # Note that the methods on +responder+ are never actually invoked.
174
192
  #
@@ -218,11 +236,11 @@ module Mocha
218
236
  self
219
237
  end
220
238
 
221
- # Constrains the {Mock} instance so that it can only expect or stub methods to which an instance of the +responder_class+ responds. The constraint is only applied at method invocation time. Note that the responder instance is instantiated using +Class#allocate+.
239
+ # Constrains the {Mock} instance so that it can only expect or stub methods to which an instance of the +responder_class+ responds publicly. The constraint is only applied at method invocation time. Note that the responder instance is instantiated using +Class#allocate+.
222
240
  #
223
- # A +NoMethodError+ will be raised if the responder instance does not +#respond_to?+ a method invocation (even if the method has been expected or stubbed).
241
+ # A +NoMethodError+ will be raised if the responder instance does not publicly +#respond_to?+ the invoked method (even if the method has been expected or stubbed).
224
242
  #
225
- # The {Mock} instance will delegate its +#respond_to?+ method to the responder instance.
243
+ # The {Mock} instance will delegate its +#respond_to?+ method to the responder instance. However, the +include_all+ parameter is not passed through, so only public methods on the +responder+ will be considered.
226
244
  #
227
245
  # Note that the methods on the responder instance are never actually invoked.
228
246
  #
@@ -251,7 +269,7 @@ module Mocha
251
269
  end
252
270
 
253
271
  # @private
254
- def initialize(mockery, name = nil, receiver = nil, &block)
272
+ def initialize(mockery, name = nil, receiver = nil)
255
273
  @mockery = mockery
256
274
  @name = name || DefaultName.new(self)
257
275
  @receiver = receiver || DefaultReceiver.new(self)
@@ -259,7 +277,7 @@ module Mocha
259
277
  @everything_stubbed = false
260
278
  @responder = nil
261
279
  @unexpected_invocation = nil
262
- instance_eval(&block) if block
280
+ @expired = false
263
281
  end
264
282
 
265
283
  # @private
@@ -269,6 +287,8 @@ module Mocha
269
287
 
270
288
  alias_method :__stubs__, :stubs
271
289
 
290
+ alias_method :__singleton_class__, :singleton_class
291
+
272
292
  alias_method :quacks_like, :responds_like
273
293
  alias_method :quacks_like_instance_of, :responds_like_instance_of
274
294
 
@@ -288,35 +308,26 @@ module Mocha
288
308
  end
289
309
 
290
310
  # @private
291
- def method_missing(symbol, *arguments, &block)
292
- if @responder and not @responder.respond_to?(symbol)
293
- raise NoMethodError, "undefined method `#{symbol}' for #{self.mocha_inspect} which responds like #{@responder.mocha_inspect}"
294
- end
295
- if matching_expectation_allowing_invocation = all_expectations.match_allowing_invocation(symbol, *arguments)
296
- matching_expectation_allowing_invocation.invoke(&block)
297
- else
298
- if (matching_expectation = all_expectations.match(symbol, *arguments)) || (!matching_expectation && !@everything_stubbed)
299
- if @unexpected_invocation.nil?
300
- @unexpected_invocation = UnexpectedInvocation.new(self, symbol, *arguments)
301
- matching_expectation.invoke(&block) if matching_expectation
302
- message = @unexpected_invocation.full_description
303
- message << @mockery.mocha_inspect
304
- else
305
- message = @unexpected_invocation.short_description
306
- end
307
- raise ExpectationErrorFactory.build(message, caller)
308
- end
311
+ def method_missing(symbol, *arguments, &block) # rubocop:disable Style/MethodMissingSuper
312
+ handle_method_call(symbol, arguments, block)
313
+ end
314
+
315
+ # @private
316
+ def handle_method_call(symbol, arguments, block)
317
+ check_expiry
318
+ check_responder_responds_to(symbol)
319
+ invocation = Invocation.new(self, symbol, arguments, block)
320
+ if (matching_expectation_allowing_invocation = all_expectations.match_allowing_invocation(invocation))
321
+ matching_expectation_allowing_invocation.invoke(invocation)
322
+ elsif (matching_expectation = all_expectations.match(invocation)) || (!matching_expectation && !@everything_stubbed)
323
+ raise_unexpected_invocation_error(invocation, matching_expectation)
309
324
  end
310
325
  end
311
326
 
312
327
  # @private
313
- def respond_to?(symbol, include_private = false)
314
- if @responder then
315
- if @responder.method(:respond_to?).arity > 1
316
- @responder.respond_to?(symbol, include_private)
317
- else
318
- @responder.respond_to?(symbol)
319
- end
328
+ def respond_to_missing?(symbol, _include_all)
329
+ if @responder
330
+ @responder.respond_to?(symbol)
320
331
  else
321
332
  @everything_stubbed || all_expectations.matches_method?(symbol)
322
333
  end
@@ -327,6 +338,11 @@ module Mocha
327
338
  @expectations.verified?(assertion_counter)
328
339
  end
329
340
 
341
+ # @private
342
+ def __expire__
343
+ @expired = true
344
+ end
345
+
330
346
  # @private
331
347
  def mocha_inspect
332
348
  @name.mocha_inspect
@@ -339,7 +355,7 @@ module Mocha
339
355
 
340
356
  # @private
341
357
  def ensure_method_not_already_defined(method_name)
342
- self.__metaclass__.send(:undef_method, method_name) if self.__metaclass__.method_defined?(method_name) || self.__metaclass__.private_method_defined?(method_name)
358
+ __singleton_class__.send(:undef_method, method_name) if __singleton_class__.method_defined?(method_name) || __singleton_class__.private_method_defined?(method_name)
343
359
  end
344
360
 
345
361
  # @private
@@ -347,6 +363,34 @@ module Mocha
347
363
  @expectations.any?
348
364
  end
349
365
 
350
- end
366
+ private
367
+
368
+ def raise_unexpected_invocation_error(invocation, matching_expectation)
369
+ if @unexpected_invocation.nil?
370
+ @unexpected_invocation = invocation
371
+ matching_expectation.invoke(invocation) if matching_expectation
372
+ message = "#{@unexpected_invocation.call_description}\n#{@mockery.mocha_inspect}"
373
+ else
374
+ message = @unexpected_invocation.short_call_description
375
+ end
376
+ raise ExpectationErrorFactory.build("unexpected invocation: #{message}", caller)
377
+ end
378
+
379
+ def check_responder_responds_to(symbol)
380
+ if @responder && !@responder.respond_to?(symbol) # rubocop:disable Style/GuardClause
381
+ raise NoMethodError, "undefined method `#{symbol}' for #{mocha_inspect} which responds like #{@responder.mocha_inspect}"
382
+ end
383
+ end
351
384
 
385
+ def check_expiry
386
+ if @expired # rubocop:disable Style/GuardClause
387
+ Deprecation.warning(
388
+ "#{mocha_inspect} was instantiated in one test but it is receiving invocations within another test.",
389
+ ' This can lead to unintended interactions between tests and hence unexpected test failures.',
390
+ ' Ensure that every test correctly cleans up any state that it introduces.',
391
+ ' A Mocha::StubbingError will be raised in this scenario in the future.'
392
+ )
393
+ end
394
+ end
395
+ end
352
396
  end