mocha 1.9.0 → 1.10.0.alpha

Sign up to get free protection for your applications and to get access to all the features.
Files changed (200) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/.rubocop_todo.yml +7 -30
  4. data/README.md +10 -11
  5. data/RELEASE.md +48 -0
  6. data/Rakefile +9 -3
  7. data/docs/CNAME +1 -0
  8. data/docs/Mocha.html +132 -5
  9. data/docs/Mocha/API.html +289 -216
  10. data/docs/Mocha/ClassMethods.html +88 -16
  11. data/docs/Mocha/Configuration.html +931 -174
  12. data/docs/Mocha/Expectation.html +200 -255
  13. data/docs/Mocha/ExpectationError.html +5 -10
  14. data/docs/Mocha/ExpectationErrorFactory.html +9 -18
  15. data/docs/Mocha/Hooks.html +12 -27
  16. data/docs/Mocha/Integration.html +3 -3
  17. data/docs/Mocha/Integration/MiniTest.html +3 -3
  18. data/docs/Mocha/Integration/MiniTest/Adapter.html +5 -6
  19. data/docs/Mocha/Integration/TestUnit.html +3 -3
  20. data/docs/Mocha/Integration/TestUnit/Adapter.html +5 -6
  21. data/docs/Mocha/Mock.html +202 -162
  22. data/docs/Mocha/ObjectMethods.html +121 -68
  23. data/docs/Mocha/ParameterMatchers.html +21 -109
  24. data/docs/Mocha/ParameterMatchers/AllOf.html +4 -5
  25. data/docs/Mocha/ParameterMatchers/AnyOf.html +4 -5
  26. data/docs/Mocha/ParameterMatchers/AnyParameters.html +3 -3
  27. data/docs/Mocha/ParameterMatchers/Anything.html +3 -3
  28. data/docs/Mocha/ParameterMatchers/Base.html +8 -15
  29. data/docs/Mocha/ParameterMatchers/Equals.html +4 -5
  30. data/docs/Mocha/ParameterMatchers/EquivalentUri.html +3 -3
  31. data/docs/Mocha/ParameterMatchers/HasEntries.html +4 -5
  32. data/docs/Mocha/ParameterMatchers/HasEntry.html +4 -5
  33. data/docs/Mocha/ParameterMatchers/HasKey.html +4 -5
  34. data/docs/Mocha/ParameterMatchers/HasValue.html +4 -5
  35. data/docs/Mocha/ParameterMatchers/Includes.html +4 -5
  36. data/docs/Mocha/ParameterMatchers/InstanceOf.html +4 -5
  37. data/docs/Mocha/ParameterMatchers/IsA.html +3 -3
  38. data/docs/Mocha/ParameterMatchers/KindOf.html +4 -5
  39. data/docs/Mocha/ParameterMatchers/Not.html +4 -5
  40. data/docs/Mocha/ParameterMatchers/Optionally.html +3 -3
  41. data/docs/Mocha/ParameterMatchers/RegexpMatches.html +4 -5
  42. data/docs/Mocha/ParameterMatchers/RespondsWith.html +4 -5
  43. data/docs/Mocha/ParameterMatchers/YamlEquivalent.html +4 -5
  44. data/docs/Mocha/Sequence.html +3 -3
  45. data/docs/Mocha/StateMachine.html +13 -25
  46. data/docs/Mocha/StateMachine/State.html +4 -5
  47. data/docs/Mocha/StateMachine/StatePredicate.html +4 -5
  48. data/docs/Mocha/StubbingError.html +3 -3
  49. data/docs/_index.html +4 -22
  50. data/docs/class_list.html +1 -1
  51. data/docs/file.COPYING.html +3 -3
  52. data/docs/file.MIT-LICENSE.html +3 -3
  53. data/docs/file.README.html +18 -15
  54. data/docs/file.RELEASE.html +58 -3
  55. data/docs/frames.html +1 -1
  56. data/docs/index.html +18 -15
  57. data/docs/method_list.html +103 -39
  58. data/docs/top-level-namespace.html +3 -3
  59. data/gemfiles/Gemfile.minitest.5.11.3 +7 -0
  60. data/init.rb +1 -3
  61. data/lib/mocha.rb +8 -0
  62. data/lib/mocha/any_instance_method.rb +9 -25
  63. data/lib/mocha/api.rb +62 -66
  64. data/lib/mocha/cardinality.rb +26 -11
  65. data/lib/mocha/class_methods.rb +16 -15
  66. data/lib/mocha/configuration.rb +295 -67
  67. data/lib/mocha/detection/test_unit.rb +1 -3
  68. data/lib/mocha/exception_raiser.rb +2 -1
  69. data/lib/mocha/expectation.rb +56 -58
  70. data/lib/mocha/expectation_error.rb +1 -3
  71. data/lib/mocha/expectation_list.rb +6 -6
  72. data/lib/mocha/inspect.rb +28 -26
  73. data/lib/mocha/instance_method.rb +19 -2
  74. data/lib/mocha/integration.rb +1 -3
  75. data/lib/mocha/integration/mini_test.rb +7 -0
  76. data/lib/mocha/integration/test_unit.rb +7 -0
  77. data/lib/mocha/invocation.rb +61 -0
  78. data/lib/mocha/macos_version.rb +5 -0
  79. data/lib/mocha/minitest.rb +6 -1
  80. data/lib/mocha/mock.rb +46 -31
  81. data/lib/mocha/mockery.rb +28 -61
  82. data/lib/mocha/names.rb +1 -1
  83. data/lib/mocha/object_methods.rb +13 -19
  84. data/lib/mocha/parameter_matchers.rb +1 -1
  85. data/lib/mocha/parameter_matchers/all_of.rb +1 -1
  86. data/lib/mocha/parameter_matchers/any_of.rb +1 -1
  87. data/lib/mocha/parameter_matchers/equivalent_uri.rb +0 -9
  88. data/lib/mocha/parameter_matchers/includes.rb +2 -0
  89. data/lib/mocha/parameter_matchers/instance_methods.rb +18 -0
  90. data/lib/mocha/raised_exception.rb +11 -0
  91. data/lib/mocha/return_values.rb +3 -3
  92. data/lib/mocha/setup.rb +5 -0
  93. data/lib/mocha/single_return_value.rb +2 -1
  94. data/lib/mocha/singleton_class.rb +9 -0
  95. data/lib/mocha/{class_method.rb → stubbed_method.rb} +23 -43
  96. data/lib/mocha/test_unit.rb +6 -1
  97. data/lib/mocha/thrower.rb +2 -1
  98. data/lib/mocha/thrown_object.rb +12 -0
  99. data/lib/mocha/version.rb +1 -1
  100. data/mocha.gemspec +1 -3
  101. data/test/acceptance/acceptance_test_helper.rb +6 -0
  102. data/test/acceptance/bug_18914_test.rb +0 -1
  103. data/test/acceptance/bug_21465_test.rb +0 -1
  104. data/test/acceptance/bug_21563_test.rb +0 -1
  105. data/test/acceptance/display_matching_invocations_alongside_expectations_test.rb +69 -0
  106. data/test/acceptance/exception_rescue_test.rb +1 -2
  107. data/test/acceptance/expectations_on_multiple_methods_test.rb +0 -1
  108. data/test/acceptance/expected_invocation_count_test.rb +2 -3
  109. data/test/acceptance/failure_messages_test.rb +0 -1
  110. data/test/acceptance/issue_272_test.rb +1 -2
  111. data/test/acceptance/issue_65_test.rb +0 -1
  112. data/test/acceptance/issue_70_test.rb +0 -1
  113. data/test/acceptance/mocha_example_test.rb +0 -1
  114. data/test/acceptance/mocha_test_result_test.rb +0 -1
  115. data/test/acceptance/mock_test.rb +47 -6
  116. data/test/acceptance/mocked_methods_dispatch_test.rb +0 -1
  117. data/test/acceptance/multiple_expectations_failure_message_test.rb +0 -1
  118. data/test/acceptance/optional_parameters_test.rb +0 -1
  119. data/test/acceptance/parameter_matcher_test.rb +0 -1
  120. data/test/acceptance/partial_mocks_test.rb +0 -1
  121. data/test/acceptance/prepend_test.rb +0 -1
  122. data/test/acceptance/prevent_use_of_mocha_outside_test_test.rb +0 -1
  123. data/test/acceptance/raise_exception_test.rb +0 -1
  124. data/test/acceptance/return_value_test.rb +0 -1
  125. data/test/acceptance/sequence_test.rb +0 -1
  126. data/test/acceptance/states_test.rb +0 -1
  127. data/test/acceptance/stub_any_instance_method_defined_on_superclass_test.rb +1 -2
  128. data/test/acceptance/stub_any_instance_method_test.rb +20 -1
  129. data/test/acceptance/stub_class_method_defined_on_active_record_association_proxy_test.rb +0 -1
  130. data/test/acceptance/stub_class_method_defined_on_class_test.rb +0 -1
  131. data/test/acceptance/stub_class_method_defined_on_module_test.rb +0 -1
  132. data/test/acceptance/stub_class_method_defined_on_superclass_test.rb +1 -2
  133. data/test/acceptance/stub_everything_test.rb +0 -1
  134. data/test/acceptance/stub_instance_method_defined_on_active_record_association_proxy_test.rb +0 -1
  135. data/test/acceptance/stub_instance_method_defined_on_class_and_aliased_test.rb +0 -1
  136. data/test/acceptance/stub_instance_method_defined_on_class_test.rb +0 -1
  137. data/test/acceptance/stub_instance_method_defined_on_kernel_module_test.rb +0 -1
  138. data/test/acceptance/stub_instance_method_defined_on_module_test.rb +0 -1
  139. data/test/acceptance/stub_instance_method_defined_on_object_class_test.rb +0 -1
  140. data/test/acceptance/stub_instance_method_defined_on_singleton_class_test.rb +0 -1
  141. data/test/acceptance/stub_instance_method_defined_on_superclass_test.rb +0 -1
  142. data/test/acceptance/stub_method_defined_on_module_and_aliased_test.rb +0 -1
  143. data/test/acceptance/stub_module_method_test.rb +0 -1
  144. data/test/acceptance/stub_test.rb +0 -1
  145. data/test/acceptance/stubba_example_test.rb +0 -1
  146. data/test/acceptance/stubba_test_result_test.rb +0 -1
  147. data/test/acceptance/stubbing_error_backtrace_test.rb +4 -5
  148. data/test/acceptance/stubbing_frozen_object_test.rb +0 -1
  149. data/test/acceptance/stubbing_method_accepting_block_parameter_test.rb +0 -1
  150. data/test/acceptance/stubbing_method_unnecessarily_test.rb +5 -5
  151. data/test/acceptance/stubbing_nil_test.rb +5 -5
  152. data/test/acceptance/stubbing_non_existent_any_instance_method_test.rb +11 -11
  153. data/test/acceptance/stubbing_non_existent_class_method_test.rb +11 -11
  154. data/test/acceptance/stubbing_non_existent_instance_method_test.rb +11 -11
  155. data/test/acceptance/stubbing_non_public_any_instance_method_test.rb +8 -8
  156. data/test/acceptance/stubbing_non_public_class_method_test.rb +9 -9
  157. data/test/acceptance/stubbing_non_public_instance_method_test.rb +9 -9
  158. data/test/acceptance/stubbing_on_non_mock_object_test.rb +5 -5
  159. data/test/acceptance/stubbing_same_class_method_on_parent_and_child_classes_test.rb +0 -1
  160. data/test/acceptance/throw_test.rb +0 -1
  161. data/test/acceptance/unexpected_invocation_test.rb +0 -1
  162. data/test/acceptance/unstubbing_test.rb +0 -1
  163. data/test/integration/shared_tests.rb +5 -3
  164. data/test/method_definer.rb +11 -17
  165. data/test/test_runner.rb +2 -0
  166. data/test/unit/any_instance_method_test.rb +41 -40
  167. data/test/unit/cardinality_test.rb +41 -23
  168. data/test/unit/central_test.rb +0 -1
  169. data/test/unit/class_methods_test.rb +1 -1
  170. data/test/unit/configuration_test.rb +12 -12
  171. data/test/unit/exception_raiser_test.rb +10 -5
  172. data/test/unit/expectation_list_test.rb +13 -11
  173. data/test/unit/expectation_test.rb +88 -103
  174. data/test/unit/instance_method_test.rb +282 -0
  175. data/test/unit/mock_test.rb +28 -19
  176. data/test/unit/mockery_test.rb +8 -11
  177. data/test/unit/module_methods_test.rb +2 -3
  178. data/test/unit/object_inspect_test.rb +6 -4
  179. data/test/unit/object_methods_test.rb +3 -2
  180. data/test/unit/parameter_matchers/equivalent_uri_test.rb +0 -9
  181. data/test/unit/parameter_matchers/has_entries_test.rb +1 -1
  182. data/test/unit/parameter_matchers/has_entry_test.rb +1 -1
  183. data/test/unit/parameter_matchers/has_key_test.rb +1 -1
  184. data/test/unit/parameter_matchers/has_value_test.rb +1 -1
  185. data/test/unit/parameter_matchers/includes_test.rb +1 -1
  186. data/test/unit/parameter_matchers/responds_with_test.rb +1 -1
  187. data/test/unit/return_values_test.rb +25 -20
  188. data/test/unit/single_return_value_test.rb +6 -1
  189. data/test/unit/thrower_test.rb +7 -2
  190. metadata +16 -30
  191. data/docs/Mocha/UnexpectedInvocation.html +0 -140
  192. data/lib/mocha/mini_test.rb +0 -5
  193. data/lib/mocha/module_method.rb +0 -6
  194. data/lib/mocha/module_methods.rb +0 -10
  195. data/lib/mocha/parameter_matchers/object.rb +0 -15
  196. data/lib/mocha/standalone.rb +0 -4
  197. data/lib/mocha/unexpected_invocation.rb +0 -24
  198. data/lib/mocha_standalone.rb +0 -4
  199. data/test/acceptance/mock_with_initializer_block_test.rb +0 -56
  200. data/test/unit/class_method_test.rb +0 -276
@@ -6,7 +6,7 @@
6
6
  <title>
7
7
  Top Level Namespace
8
8
 
9
- &mdash; Mocha 1.9.0
9
+ &mdash; Mocha 1.10.0.alpha
10
10
 
11
11
  </title>
12
12
 
@@ -108,9 +108,9 @@
108
108
  </div>
109
109
 
110
110
  <div id="footer">
111
- Generated on Mon Jun 17 18:38:43 2019 by
111
+ Generated on Sun Nov 24 15:26:48 2019 by
112
112
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
113
- 0.9.19 (ruby-2.5.3).
113
+ 0.9.20 (ruby-2.6.5).
114
114
  </div>
115
115
 
116
116
  </div>
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec :path=>"../"
4
+
5
+ group :development do
6
+ gem "minitest", "5.11.3"
7
+ end
data/init.rb CHANGED
@@ -1,3 +1 @@
1
- # Mocha should no longer be loaded at plugin load time
2
- # You should explicitly load Mocha *after* Test::Unit or MiniTest have been loaded
3
- # e.g. by adding "require 'mocha'" at the bottom of test/test_helper.rb
1
+ warn 'Mocha deprecation warning: The old-style Rails plugin will not be supported in future versions of Mocha.'
@@ -1 +1,9 @@
1
1
  require 'mocha/version'
2
+ require 'mocha/ruby_version'
3
+ require 'mocha/deprecation'
4
+
5
+ if Mocha::PRE_RUBY_V19
6
+ Mocha::Deprecation.warning(
7
+ 'Versions of Ruby earlier than v1.9 will not be supported in future versions of Mocha.'
8
+ )
9
+ end
@@ -1,36 +1,20 @@
1
1
  require 'mocha/ruby_version'
2
- require 'mocha/class_method'
2
+ require 'mocha/stubbed_method'
3
3
 
4
4
  module Mocha
5
- class AnyInstanceMethod < ClassMethod
6
- def mock
7
- stubbee.any_instance.mocha
8
- end
9
-
10
- def reset_mocha
11
- stubbee.any_instance.reset_mocha
12
- end
5
+ class AnyInstanceMethod < StubbedMethod
6
+ private
13
7
 
14
- def restore_original_method
15
- return if use_prepended_module_for_stub_method?
16
- return unless stub_method_overwrites_original_method?
17
- original_method_owner.send(:define_method, method_name, original_method)
18
- Module.instance_method(original_visibility).bind(original_method_owner).call(method_name)
8
+ def mock_owner
9
+ stubbee.any_instance
19
10
  end
20
11
 
21
- private
22
-
23
- def store_original_method
24
- @original_method = original_method_owner.instance_method(method_name)
12
+ def method_body(method)
13
+ method
25
14
  end
26
15
 
27
- def stub_method_definition
28
- method_implementation = <<-CODE
29
- def #{method_name}(*args, &block)
30
- self.class.any_instance.mocha.method_missing(:#{method_name}, *args, &block)
31
- end
32
- CODE
33
- [method_implementation, __FILE__, __LINE__ - 4]
16
+ def stubbee_method(method_name)
17
+ stubbee.instance_method(method_name)
34
18
  end
35
19
 
36
20
  def original_method_owner
@@ -3,11 +3,33 @@ require 'mocha/hooks'
3
3
  require 'mocha/mockery'
4
4
  require 'mocha/sequence'
5
5
  require 'mocha/object_methods'
6
- require 'mocha/module_methods'
7
6
  require 'mocha/class_methods'
8
7
 
9
8
  module Mocha
10
9
  # Methods added to +Test::Unit::TestCase+, +MiniTest::Unit::TestCase+ or equivalent.
10
+ # The mock creation methods are {#mock}, {#stub} and {#stub_everything}, all of which return a #{Mock}
11
+ # which can be further modified by {Mock#responds_like} and {Mock#responds_like_instance_of} methods,
12
+ # both of which return a {Mock}, too, and can therefore, be chained to the original creation methods.
13
+ #
14
+ # {Mock#responds_like} and {Mock#responds_like_instance_of} force the mock to indicate what it is
15
+ # supposed to be mocking, thus making it a safer verifying mock. They check that the underlying +responder+
16
+ # will actually respond to the methods being stubbed, throwing a +NoMethodError+ upon invocation otherwise.
17
+ #
18
+ # @example Verifying mock using {Mock#responds_like_instance_of}
19
+ # class Sheep
20
+ # def initialize
21
+ # raise "some awkward code we don't want to call"
22
+ # end
23
+ # def chew(grass); end
24
+ # end
25
+ #
26
+ # sheep = mock('sheep').responds_like_instance_of(Sheep)
27
+ # sheep.expects(:chew)
28
+ # sheep.expects(:foo)
29
+ # sheep.respond_to?(:chew) # => true
30
+ # sheep.respond_to?(:foo) # => false
31
+ # sheep.chew
32
+ # sheep.foo # => raises NoMethodError exception
11
33
  module API
12
34
  include ParameterMatchers
13
35
  include Hooks
@@ -15,22 +37,20 @@ module Mocha
15
37
  # @private
16
38
  def self.included(_mod)
17
39
  Object.send(:include, Mocha::ObjectMethods)
18
- Module.send(:include, Mocha::ModuleMethods)
19
40
  Class.send(:include, Mocha::ClassMethods)
20
41
  end
21
42
 
22
43
  # Builds a new mock object
23
44
  #
24
- # @param [String] name identifies mock object in error messages.
25
- # @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 {Mock#expects} were called multiple times.
26
- # @yield optional block to be evaluated in the context of the mock object instance, giving an alternative way to setup stubbed methods.
27
- # @yield note that the block is evaulated by calling Mock#instance_eval and so things like instance variables declared in the test will not be available within the block.
28
- # @yield deprecated: use Object#tap or define stubs/expectations with an explicit receiver instead.
29
45
  # @return [Mock] a new mock object
30
46
  #
31
- # @overload def mock(name, &block)
32
- # @overload def mock(expected_methods_vs_return_values = {}, &block)
33
- # @overload def mock(name, expected_methods_vs_return_values = {}, &block)
47
+ # @overload def mock(name)
48
+ # @param [String, Symbol] name identifies mock object in error messages.
49
+ # @overload def mock(expected_methods_vs_return_values = {})
50
+ # @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 {Mock#expects} were called multiple times.
51
+ # @overload def mock(name, expected_methods_vs_return_values = {})
52
+ # @param [String, Symbol] name identifies mock object in error messages.
53
+ # @param [Hash] expected_methods_vs_return_values expected method name symbols as keys and corresponding return values as values - these expectations are setup as if {Mock#expects} were called multiple times.
34
54
  #
35
55
  # @example Using expected_methods_vs_return_values Hash to setup expectations.
36
56
  # def test_motor_starts_and_stops
@@ -39,36 +59,20 @@ module Mocha
39
59
  # assert motor.stop
40
60
  # # an error will be raised unless both Motor#start and Motor#stop have been called
41
61
  # end
42
- # @example Using the optional block to setup expectations & stubbed methods [deprecated].
43
- # def test_motor_starts_and_stops
44
- # motor = mock('motor') do
45
- # expects(:start).with(100.rpm).returns(true)
46
- # stubs(:stop).returns(true)
47
- # end
48
- # assert motor.start(100.rpm)
49
- # assert motor.stop
50
- # # an error will only be raised if Motor#start(100.rpm) has not been called
51
- # end
52
- def mock(*arguments, &block)
53
- name = arguments.shift if arguments.first.is_a?(String)
54
- expectations = arguments.shift || {}
55
- mock = name ? Mockery.instance.named_mock(name, &block) : Mockery.instance.unnamed_mock(&block)
56
- mock.expects(expectations)
57
- mock
62
+ def mock(*arguments)
63
+ create_mock(arguments) { |mock, expectations| mock.expects(expectations) }
58
64
  end
59
65
 
60
66
  # Builds a new mock object
61
67
  #
62
- # @param [String] name identifies mock object in error messages.
63
- # @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 {Mock#stubs} were called multiple times.
64
- # @yield optional block to be evaluated in the context of the mock object instance, giving an alternative way to setup stubbed methods.
65
- # @yield note that the block is evaulated by calling Mock#instance_eval and so things like instance variables declared in the test will not be available within the block.
66
- # @yield deprecated: use Object#tap or define stubs/expectations with an explicit receiver instead.
67
68
  # @return [Mock] a new mock object
68
69
  #
69
- # @overload def stub(name, &block)
70
- # @overload def stub(stubbed_methods_vs_return_values = {}, &block)
71
- # @overload def stub(name, stubbed_methods_vs_return_values = {}, &block)
70
+ # @overload def stub(name)
71
+ # @param [String, Symbol] name identifies mock object in error messages.
72
+ # @overload def stub(stubbed_methods_vs_return_values = {})
73
+ # @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 {Mock#stubs} were called multiple times.
74
+ # @overload def stub(name, stubbed_methods_vs_return_values = {})
75
+ # @param [String, Symbol] name identifies mock object in error messages.
72
76
  #
73
77
  # @example Using stubbed_methods_vs_return_values Hash to setup stubbed methods.
74
78
  # def test_motor_starts_and_stops
@@ -77,37 +81,21 @@ module Mocha
77
81
  # assert motor.stop
78
82
  # # an error will not be raised even if either Motor#start or Motor#stop has not been called
79
83
  # end
80
- #
81
- # @example Using the optional block to setup expectations & stubbed methods [deprecated].
82
- # def test_motor_starts_and_stops
83
- # motor = stub('motor') do
84
- # expects(:start).with(100.rpm).returns(true)
85
- # stubs(:stop).returns(true)
86
- # end
87
- # assert motor.start(100.rpm)
88
- # assert motor.stop
89
- # # an error will only be raised if Motor#start(100.rpm) has not been called
90
- # end
91
- def stub(*arguments, &block)
92
- name = arguments.shift if arguments.first.is_a?(String)
93
- expectations = arguments.shift || {}
94
- stub = name ? Mockery.instance.named_mock(name, &block) : Mockery.instance.unnamed_mock(&block)
95
- stub.stubs(expectations)
96
- stub
84
+ def stub(*arguments)
85
+ create_mock(arguments) { |stub, expectations| stub.stubs(expectations) }
97
86
  end
98
87
 
99
88
  # Builds a mock object that accepts calls to any method. By default it will return +nil+ for any method call.
100
89
  #
101
- # @param [String] name identifies mock object in error messages.
102
- # @param [Hash] stubbed_methods_vs_return_values stubbed method name symbols as keys and corresponding return values as values - these stubbed methods are setup as if {Mock#stubs} were called multiple times.
103
- # @yield optional block to be evaluated in the context of the mock object instance, giving an alternative way to setup stubbed methods.
104
- # @yield note that the block is evaulated by calling Mock#instance_eval and so things like instance variables declared in the test will not be available within the block.
105
- # @yield deprecated: use Object#tap or define stubs/expectations with an explicit receiver instead.
106
90
  # @return [Mock] a new mock object
107
91
  #
108
- # @overload def stub_everything(name, &block)
109
- # @overload def stub_everything(stubbed_methods_vs_return_values = {}, &block)
110
- # @overload def stub_everything(name, stubbed_methods_vs_return_values = {}, &block)
92
+ # @overload def stub_everything(name)
93
+ # @param [String, Symbol] name identifies mock object in error messages.
94
+ # @overload def stub_everything(stubbed_methods_vs_return_values = {})
95
+ # @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 {Mock#stubs} were called multiple times.
96
+ # @overload def stub_everything(name, stubbed_methods_vs_return_values = {})
97
+ # @param [String, Symbol] name identifies mock object in error messages.
98
+ # @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 {Mock#stubs} were called multiple times.
111
99
  #
112
100
  # @example Ignore invocations of irrelevant methods.
113
101
  # def test_motor_stops
@@ -116,13 +104,11 @@ module Mocha
116
104
  # assert_nil motor.irrelevant_method_2 # => no error raised
117
105
  # assert motor.stop
118
106
  # end
119
- def stub_everything(*arguments, &block)
120
- name = arguments.shift if arguments.first.is_a?(String)
121
- expectations = arguments.shift || {}
122
- stub = name ? Mockery.instance.named_mock(name, &block) : Mockery.instance.unnamed_mock(&block)
123
- stub.stub_everything
124
- stub.stubs(expectations)
125
- stub
107
+ def stub_everything(*arguments)
108
+ create_mock(arguments) do |stub, expectations|
109
+ stub.stub_everything
110
+ stub.stubs(expectations)
111
+ end
126
112
  end
127
113
 
128
114
  # Builds a new sequence which can be used to constrain the order in which expectations can occur.
@@ -174,5 +160,15 @@ module Mocha
174
160
  def states(name)
175
161
  Mockery.instance.new_state_machine(name)
176
162
  end
163
+
164
+ private
165
+
166
+ def create_mock(arguments)
167
+ name = arguments.shift.to_s if arguments.first.is_a?(String) || arguments.first.is_a?(Symbol)
168
+ expectations = arguments.shift || {}
169
+ mock = name ? Mockery.instance.named_mock(name) : Mockery.instance.unnamed_mock
170
+ yield mock, expectations
171
+ mock
172
+ end
177
173
  end
178
174
  end
@@ -26,37 +26,43 @@ module Mocha
26
26
  def initialize(required, maximum)
27
27
  @required = required
28
28
  @maximum = maximum
29
+ @invocations = []
29
30
  end
30
31
 
31
- def invocations_allowed?(invocation_count)
32
- invocation_count < maximum
32
+ def <<(invocation)
33
+ @invocations << invocation
33
34
  end
34
35
 
35
- def satisfied?(invocations_so_far)
36
- invocations_so_far >= required
36
+ def invocations_allowed?
37
+ @invocations.size < maximum
38
+ end
39
+
40
+ def satisfied?
41
+ @invocations.size >= required
37
42
  end
38
43
 
39
44
  def needs_verifying?
40
45
  !allowed_any_number_of_times?
41
46
  end
42
47
 
43
- def verified?(invocation_count)
44
- (invocation_count >= required) && (invocation_count <= maximum)
48
+ def verified?
49
+ (@invocations.size >= required) && (@invocations.size <= maximum)
45
50
  end
46
51
 
47
52
  def allowed_any_number_of_times?
48
53
  required.zero? && infinite?(maximum)
49
54
  end
50
55
 
51
- def used?(invocation_count)
52
- (invocation_count > 0) || maximum.zero?
56
+ def used?
57
+ @invocations.any? || maximum.zero?
53
58
  end
54
59
 
55
- def mocha_inspect
60
+ # rubocop:disable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
61
+ def anticipated_times
56
62
  if allowed_any_number_of_times?
57
63
  'allowed any number of times'
58
64
  elsif required.zero? && maximum.zero?
59
- 'expected never'
65
+ "expected #{times(maximum)}"
60
66
  elsif required == maximum
61
67
  "expected exactly #{times(required)}"
62
68
  elsif infinite?(maximum)
@@ -67,6 +73,15 @@ module Mocha
67
73
  "expected between #{required} and #{times(maximum)}"
68
74
  end
69
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
70
85
 
71
86
  protected
72
87
 
@@ -74,7 +89,7 @@ module Mocha
74
89
 
75
90
  def times(number)
76
91
  case number
77
- when 0 then 'no times'
92
+ when 0 then 'never'
78
93
  when 1 then 'once'
79
94
  when 2 then 'twice'
80
95
  else "#{number} times"
@@ -1,15 +1,9 @@
1
1
  require 'mocha/mockery'
2
- require 'mocha/class_method'
3
2
  require 'mocha/any_instance_method'
4
3
 
5
4
  module Mocha
6
5
  # Methods added to all classes to allow mocking and stubbing on real (i.e. non-mock) objects.
7
6
  module ClassMethods
8
- # @private
9
- def stubba_method
10
- Mocha::ClassMethod
11
- end
12
-
13
7
  # @private
14
8
  class AnyInstance
15
9
  def initialize(klass)
@@ -28,17 +22,15 @@ module Mocha
28
22
  Mocha::AnyInstanceMethod
29
23
  end
30
24
 
31
- attr_reader :stubba_object
25
+ def stubba_class
26
+ @stubba_object
27
+ end
32
28
 
33
- def method_exists?(method, include_public_methods = true)
34
- if include_public_methods
35
- return true if @stubba_object.public_instance_methods(true).include?(method)
36
- return true if @stubba_object.allocate.respond_to?(method.to_sym)
37
- end
38
- return true if @stubba_object.protected_instance_methods(true).include?(method)
39
- return true if @stubba_object.private_instance_methods(true).include?(method)
40
- false
29
+ def respond_to?(method)
30
+ @stubba_object.allocate.respond_to?(method.to_sym)
41
31
  end
32
+
33
+ attr_reader :stubba_object
42
34
  end
43
35
 
44
36
  # @return [Mock] a mock object which will detect calls to any instance of this class.
@@ -56,5 +48,14 @@ module Mocha
56
48
  end
57
49
  @any_instance ||= AnyInstance.new(self)
58
50
  end
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
59
60
  end
60
61
  end
@@ -1,117 +1,323 @@
1
1
  module Mocha
2
- # 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:
2
+ # Allows setting of configuration options. See {Configuration} for the available options.
3
3
  #
4
- # * +: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.
5
- # * +: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.
6
- # * +: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.
7
- # * +: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.
8
- # * +:stubbing_method_on_nil+ - This is usually done accidentally, but there might be rare cases where it is intended. Prevented by default.
4
+ # Typically the configuration is set globally in a +test_helper.rb+ or +spec_helper.rb+ file.
9
5
  #
10
- # @example Preventing unnecessary stubbing of a method
11
- # Mocha::Configuration.prevent(:stubbing_method_unnecessarily)
6
+ # @see Configuration
12
7
  #
13
- # example = mock('example')
14
- # example.stubs(:unused_stub)
15
- # # => Mocha::StubbingError: stubbing method unnecessarily:
16
- # # => #<Mock:example>.unused_stub(any_parameters)
8
+ # @yieldparam configuration [Configuration] the configuration for modification
17
9
  #
18
- # @example Preventing stubbing of a method on a non-mock object
19
- # Mocha::Configuration.prevent(:stubbing_method_on_non_mock_object)
20
- #
21
- # class Example
22
- # def example_method; end
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
23
15
  # end
24
16
  #
25
- # example = Example.new
26
- # example.stubs(:example_method)
27
- # # => Mocha::StubbingError: stubbing method on non-mock object:
28
- # # => #<Example:0x593620>.example_method
29
- #
30
- # @example Preventing stubbing of a non-existent method
31
- #
32
- # Mocha::Configuration.prevent(:stubbing_non_existent_method)
33
- #
34
- # class Example
35
- # end
36
- #
37
- # example = Example.new
38
- # example.stubs(:method_that_doesnt_exist)
39
- # # => Mocha::StubbingError: stubbing non-existent method:
40
- # # => #<Example:0x593760>.method_that_doesnt_exist
41
- #
42
- # @example Preventing stubbing of a non-public method
43
- # Mocha::Configuration.prevent(:stubbing_non_public_method)
44
- #
45
- # class Example
46
- # def internal_method; end
47
- # private :internal_method
48
- # end
49
- #
50
- # example = Example.new
51
- # example.stubs(:internal_method)
52
- # # => Mocha::StubbingError: stubbing non-public method:
53
- # # => #<Example:0x593530>.internal_method
54
- #
55
- # 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.
56
27
  #
57
- # @example Temporarily allowing stubbing of a non-existent method
58
- # Mocha::Configuration.prevent(:stubbing_non_public_method)
28
+ # Typically the configuration is set globally in a +test_helper.rb+ or +spec_helper.rb+ file.
59
29
  #
60
- # 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
61
35
  # end
62
36
  #
63
- # Mocha::Configuration.allow(:stubbing_non_existent_method) do
64
- # example = Example.new
65
- # example.stubs(:method_that_doesnt_exist)
66
- # # => no exception raised
67
- # end
68
37
  class Configuration
38
+ # @private
69
39
  DEFAULTS = {
70
40
  :stubbing_method_unnecessarily => :allow,
71
41
  :stubbing_method_on_non_mock_object => :allow,
72
42
  :stubbing_non_existent_method => :allow,
73
43
  :stubbing_non_public_method => :allow,
74
- :stubbing_method_on_nil => :prevent
44
+ :stubbing_method_on_nil => :prevent,
45
+ :display_matching_invocations_on_failure => false
75
46
  }.freeze
76
47
 
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
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
+
77
250
  class << self
78
251
  # Allow the specified +action+.
79
252
  #
80
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+.
81
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=}
82
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
83
267
  change_config action, :allow, &block
84
268
  end
85
269
 
86
270
  # @private
87
271
  def allow?(action)
88
- configuration[action] == :allow
272
+ configuration.allow?(action)
89
273
  end
90
274
 
91
275
  # Warn if the specified +action+ is attempted.
92
276
  #
93
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+.
94
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=}
95
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
96
291
  change_config action, :warn, &block
97
292
  end
98
293
 
99
294
  # @private
100
295
  def warn_when?(action)
101
- configuration[action] == :warn
296
+ configuration.warn_when?(action)
102
297
  end
103
298
 
104
- # Raise a {StubbingError} if if the specified +action+ is attempted.
299
+ # Raise a {StubbingError} if the specified +action+ is attempted.
105
300
  #
106
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+.
107
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=}
108
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
109
315
  change_config action, :prevent, &block
110
316
  end
111
317
 
112
318
  # @private
113
319
  def prevent?(action)
114
- configuration[action] == :prevent
320
+ configuration.prevent?(action)
115
321
  end
116
322
 
117
323
  # @private
@@ -119,29 +325,51 @@ module Mocha
119
325
  @configuration = nil
120
326
  end
121
327
 
122
- 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
123
347
 
124
348
  # @private
125
349
  def configuration
126
- @configuration ||= DEFAULTS.dup
350
+ @configuration ||= new
127
351
  end
128
352
 
353
+ private
354
+
129
355
  # @private
130
356
  def change_config(action, new_value, &block)
131
357
  if block_given?
132
358
  temporarily_change_config action, new_value, &block
133
359
  else
134
- configuration[action] = new_value
360
+ configuration.send("#{action}=".to_sym, new_value)
135
361
  end
136
362
  end
137
363
 
138
364
  # @private
139
365
  def temporarily_change_config(action, new_value)
140
- original_value = configuration[action]
141
- configuration[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
142
370
  yield
143
371
  ensure
144
- configuration[action] = original_value
372
+ @configuration = original_configuration
145
373
  end
146
374
  end
147
375
  end