mocha 0.5.6 → 3.0.2

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 (192) hide show
  1. checksums.yaml +7 -0
  2. data/.gemtest +0 -0
  3. data/.github/FUNDING.yml +1 -0
  4. data/.rubocop.yml +92 -0
  5. data/.rubocop_todo.yml +39 -0
  6. data/.yardopts +25 -0
  7. data/CONTRIBUTING.md +7 -0
  8. data/COPYING.md +3 -0
  9. data/Gemfile +17 -0
  10. data/{MIT-LICENSE → MIT-LICENSE.md} +2 -2
  11. data/README.md +361 -0
  12. data/RELEASE.md +1235 -0
  13. data/Rakefile +165 -123
  14. data/gemfiles/Gemfile.minitest.latest +8 -0
  15. data/gemfiles/Gemfile.rubocop +9 -0
  16. data/gemfiles/Gemfile.test-unit.latest +8 -0
  17. data/lib/mocha/any_instance_method.rb +12 -26
  18. data/lib/mocha/any_instance_receiver.rb +20 -0
  19. data/lib/mocha/api.rb +213 -0
  20. data/lib/mocha/argument_iterator.rb +17 -0
  21. data/lib/mocha/backtrace_filter.rb +15 -0
  22. data/lib/mocha/block_matchers.rb +33 -0
  23. data/lib/mocha/cardinality.rb +110 -0
  24. data/lib/mocha/central.rb +33 -22
  25. data/lib/mocha/change_state_side_effect.rb +17 -0
  26. data/lib/mocha/class_methods.rb +67 -0
  27. data/lib/mocha/configuration.rb +338 -0
  28. data/lib/mocha/default_name.rb +15 -0
  29. data/lib/mocha/default_receiver.rb +13 -0
  30. data/lib/mocha/deprecation.rb +19 -14
  31. data/lib/mocha/detection/minitest.rb +25 -0
  32. data/lib/mocha/detection/test_unit.rb +30 -0
  33. data/lib/mocha/error_with_filtered_backtrace.rb +15 -0
  34. data/lib/mocha/exception_raiser.rb +11 -10
  35. data/lib/mocha/expectation.rb +553 -168
  36. data/lib/mocha/expectation_error.rb +9 -14
  37. data/lib/mocha/expectation_error_factory.rb +37 -0
  38. data/lib/mocha/expectation_list.rb +30 -14
  39. data/lib/mocha/hooks.rb +55 -0
  40. data/lib/mocha/ignoring_warning.rb +20 -0
  41. data/lib/mocha/impersonating_any_instance_name.rb +13 -0
  42. data/lib/mocha/impersonating_name.rb +13 -0
  43. data/lib/mocha/in_state_ordering_constraint.rb +17 -0
  44. data/lib/mocha/inspect.rb +56 -22
  45. data/lib/mocha/instance_method.rb +17 -4
  46. data/lib/mocha/integration/assertion_counter.rb +15 -0
  47. data/lib/mocha/integration/minitest/adapter.rb +71 -0
  48. data/lib/mocha/integration/minitest.rb +29 -0
  49. data/lib/mocha/integration/monkey_patcher.rb +26 -0
  50. data/lib/mocha/integration/test_unit/adapter.rb +61 -0
  51. data/lib/mocha/integration/test_unit.rb +29 -0
  52. data/lib/mocha/integration.rb +5 -0
  53. data/lib/mocha/invocation.rb +76 -0
  54. data/lib/mocha/logger.rb +13 -0
  55. data/lib/mocha/macos_version.rb +7 -0
  56. data/lib/mocha/method_matcher.rb +8 -10
  57. data/lib/mocha/minitest.rb +7 -0
  58. data/lib/mocha/mock.rb +333 -108
  59. data/lib/mocha/mockery.rb +199 -0
  60. data/lib/mocha/name.rb +13 -0
  61. data/lib/mocha/not_initialized_error.rb +9 -0
  62. data/lib/mocha/object_methods.rb +183 -0
  63. data/lib/mocha/object_receiver.rb +20 -0
  64. data/lib/mocha/parameter_matchers/all_of.rb +38 -28
  65. data/lib/mocha/parameter_matchers/any_of.rb +44 -33
  66. data/lib/mocha/parameter_matchers/any_parameters.rb +33 -26
  67. data/lib/mocha/parameter_matchers/anything.rb +31 -22
  68. data/lib/mocha/parameter_matchers/base_methods.rb +64 -0
  69. data/lib/mocha/parameter_matchers/equals.rb +36 -25
  70. data/lib/mocha/parameter_matchers/equivalent_uri.rb +65 -0
  71. data/lib/mocha/parameter_matchers/has_entries.rb +48 -29
  72. data/lib/mocha/parameter_matchers/has_entry.rb +90 -42
  73. data/lib/mocha/parameter_matchers/has_key.rb +39 -26
  74. data/lib/mocha/parameter_matchers/has_keys.rb +59 -0
  75. data/lib/mocha/parameter_matchers/has_value.rb +39 -26
  76. data/lib/mocha/parameter_matchers/includes.rb +88 -23
  77. data/lib/mocha/parameter_matchers/instance_methods.rb +28 -0
  78. data/lib/mocha/parameter_matchers/instance_of.rb +37 -26
  79. data/lib/mocha/parameter_matchers/is_a.rb +38 -26
  80. data/lib/mocha/parameter_matchers/kind_of.rb +39 -26
  81. data/lib/mocha/parameter_matchers/not.rb +37 -26
  82. data/lib/mocha/parameter_matchers/optionally.rb +52 -17
  83. data/lib/mocha/parameter_matchers/positional_or_keyword_hash.rb +91 -0
  84. data/lib/mocha/parameter_matchers/regexp_matches.rb +37 -25
  85. data/lib/mocha/parameter_matchers/responds_with.rb +82 -0
  86. data/lib/mocha/parameter_matchers/yaml_equivalent.rb +55 -0
  87. data/lib/mocha/parameter_matchers.rb +12 -5
  88. data/lib/mocha/parameters_matcher.rb +28 -19
  89. data/lib/mocha/raised_exception.rb +13 -0
  90. data/lib/mocha/return_values.rb +13 -18
  91. data/lib/mocha/ruby_version.rb +7 -0
  92. data/lib/mocha/sequence.rb +23 -17
  93. data/lib/mocha/single_return_value.rb +8 -18
  94. data/lib/mocha/state_machine.rb +95 -0
  95. data/lib/mocha/stubbed_method.rb +96 -0
  96. data/lib/mocha/stubbing_error.rb +10 -0
  97. data/lib/mocha/test_unit.rb +7 -0
  98. data/lib/mocha/thrower.rb +15 -0
  99. data/lib/mocha/thrown_object.rb +14 -0
  100. data/lib/mocha/version.rb +5 -0
  101. data/lib/mocha/yield_parameters.rb +12 -20
  102. data/lib/mocha.rb +19 -17
  103. data/mise.toml +2 -0
  104. data/mocha.gemspec +40 -0
  105. metadata +130 -145
  106. data/COPYING +0 -3
  107. data/README +0 -35
  108. data/RELEASE +0 -188
  109. data/examples/misc.rb +0 -44
  110. data/examples/mocha.rb +0 -26
  111. data/examples/stubba.rb +0 -65
  112. data/lib/mocha/auto_verify.rb +0 -118
  113. data/lib/mocha/class_method.rb +0 -66
  114. data/lib/mocha/infinite_range.rb +0 -25
  115. data/lib/mocha/is_a.rb +0 -9
  116. data/lib/mocha/metaclass.rb +0 -7
  117. data/lib/mocha/missing_expectation.rb +0 -17
  118. data/lib/mocha/multiple_yields.rb +0 -20
  119. data/lib/mocha/no_yields.rb +0 -11
  120. data/lib/mocha/object.rb +0 -110
  121. data/lib/mocha/parameter_matchers/base.rb +0 -15
  122. data/lib/mocha/parameter_matchers/object.rb +0 -9
  123. data/lib/mocha/pretty_parameters.rb +0 -28
  124. data/lib/mocha/setup_and_teardown.rb +0 -23
  125. data/lib/mocha/single_yield.rb +0 -18
  126. data/lib/mocha/standalone.rb +0 -32
  127. data/lib/mocha/stub.rb +0 -18
  128. data/lib/mocha/test_case_adapter.rb +0 -49
  129. data/lib/mocha_standalone.rb +0 -2
  130. data/lib/stubba.rb +0 -2
  131. data/test/acceptance/expected_invocation_count_acceptance_test.rb +0 -187
  132. data/test/acceptance/mocha_acceptance_test.rb +0 -98
  133. data/test/acceptance/mock_with_initializer_block_acceptance_test.rb +0 -44
  134. data/test/acceptance/mocked_methods_dispatch_acceptance_test.rb +0 -71
  135. data/test/acceptance/optional_parameters_acceptance_test.rb +0 -63
  136. data/test/acceptance/parameter_matcher_acceptance_test.rb +0 -117
  137. data/test/acceptance/partial_mocks_acceptance_test.rb +0 -40
  138. data/test/acceptance/sequence_acceptance_test.rb +0 -179
  139. data/test/acceptance/standalone_acceptance_test.rb +0 -131
  140. data/test/acceptance/stubba_acceptance_test.rb +0 -102
  141. data/test/active_record_test_case.rb +0 -36
  142. data/test/deprecation_disabler.rb +0 -15
  143. data/test/execution_point.rb +0 -34
  144. data/test/integration/mocha_test_result_integration_test.rb +0 -105
  145. data/test/integration/stubba_integration_test.rb +0 -89
  146. data/test/integration/stubba_test_result_integration_test.rb +0 -85
  147. data/test/method_definer.rb +0 -18
  148. data/test/test_helper.rb +0 -12
  149. data/test/test_runner.rb +0 -31
  150. data/test/unit/any_instance_method_test.rb +0 -126
  151. data/test/unit/array_inspect_test.rb +0 -16
  152. data/test/unit/auto_verify_test.rb +0 -129
  153. data/test/unit/central_test.rb +0 -124
  154. data/test/unit/class_method_test.rb +0 -200
  155. data/test/unit/date_time_inspect_test.rb +0 -21
  156. data/test/unit/expectation_error_test.rb +0 -24
  157. data/test/unit/expectation_list_test.rb +0 -75
  158. data/test/unit/expectation_raiser_test.rb +0 -28
  159. data/test/unit/expectation_test.rb +0 -483
  160. data/test/unit/hash_inspect_test.rb +0 -16
  161. data/test/unit/infinite_range_test.rb +0 -53
  162. data/test/unit/metaclass_test.rb +0 -22
  163. data/test/unit/method_matcher_test.rb +0 -23
  164. data/test/unit/missing_expectation_test.rb +0 -42
  165. data/test/unit/mock_test.rb +0 -323
  166. data/test/unit/multiple_yields_test.rb +0 -18
  167. data/test/unit/no_yield_test.rb +0 -18
  168. data/test/unit/object_inspect_test.rb +0 -37
  169. data/test/unit/object_test.rb +0 -165
  170. data/test/unit/parameter_matchers/all_of_test.rb +0 -26
  171. data/test/unit/parameter_matchers/any_of_test.rb +0 -26
  172. data/test/unit/parameter_matchers/anything_test.rb +0 -21
  173. data/test/unit/parameter_matchers/has_entries_test.rb +0 -30
  174. data/test/unit/parameter_matchers/has_entry_test.rb +0 -40
  175. data/test/unit/parameter_matchers/has_key_test.rb +0 -25
  176. data/test/unit/parameter_matchers/has_value_test.rb +0 -25
  177. data/test/unit/parameter_matchers/includes_test.rb +0 -25
  178. data/test/unit/parameter_matchers/instance_of_test.rb +0 -25
  179. data/test/unit/parameter_matchers/is_a_test.rb +0 -25
  180. data/test/unit/parameter_matchers/kind_of_test.rb +0 -25
  181. data/test/unit/parameter_matchers/not_test.rb +0 -26
  182. data/test/unit/parameter_matchers/regexp_matches_test.rb +0 -25
  183. data/test/unit/parameter_matchers/stub_matcher.rb +0 -23
  184. data/test/unit/parameters_matcher_test.rb +0 -121
  185. data/test/unit/return_values_test.rb +0 -63
  186. data/test/unit/sequence_test.rb +0 -104
  187. data/test/unit/setup_and_teardown_test.rb +0 -76
  188. data/test/unit/single_return_value_test.rb +0 -33
  189. data/test/unit/single_yield_test.rb +0 -18
  190. data/test/unit/string_inspect_test.rb +0 -11
  191. data/test/unit/stub_test.rb +0 -24
  192. data/test/unit/yield_parameters_test.rb +0 -93
@@ -0,0 +1,199 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mocha/central'
4
+ require 'mocha/mock'
5
+ require 'mocha/name'
6
+ require 'mocha/impersonating_name'
7
+ require 'mocha/impersonating_any_instance_name'
8
+ require 'mocha/object_receiver'
9
+ require 'mocha/any_instance_receiver'
10
+ require 'mocha/state_machine'
11
+ require 'mocha/logger'
12
+ require 'mocha/configuration'
13
+ require 'mocha/stubbing_error'
14
+ require 'mocha/not_initialized_error'
15
+ require 'mocha/expectation_error_factory'
16
+
17
+ module Mocha
18
+ class Mockery
19
+ class Null < self
20
+ def self.build
21
+ new(nil)
22
+ end
23
+
24
+ def add_mock(*)
25
+ raise_not_initialized_error
26
+ end
27
+
28
+ def add_state_machine(*)
29
+ raise_not_initialized_error
30
+ end
31
+
32
+ def stubba
33
+ Central::Null.new(&method(:raise_not_initialized_error))
34
+ end
35
+
36
+ private
37
+
38
+ def raise_not_initialized_error
39
+ message = 'Mocha methods cannot be used outside the context of a test'
40
+ raise NotInitializedError.new(message, caller)
41
+ end
42
+ end
43
+
44
+ class << self
45
+ def instance
46
+ @instances.last || Null.build
47
+ end
48
+
49
+ def setup(assertion_counter)
50
+ @instances ||= []
51
+ mockery = new(assertion_counter)
52
+ mockery.logger = instance.logger unless @instances.empty?
53
+ @instances.push(mockery)
54
+ end
55
+
56
+ def verify
57
+ instance.verify
58
+ end
59
+
60
+ def teardown(origin = nil)
61
+ if @instances.nil?
62
+ raise NotInitializedError, 'Mocha::Mockery.teardown called before Mocha::Mockery.setup'
63
+ end
64
+
65
+ instance.teardown(origin)
66
+ ensure
67
+ @instances.pop unless @instances.nil?
68
+ end
69
+ end
70
+
71
+ def initialize(assertion_counter)
72
+ @assertion_counter = assertion_counter
73
+ end
74
+
75
+ def named_mock(name)
76
+ add_mock(Mock.new(self, @assertion_counter, Name.new(name)))
77
+ end
78
+
79
+ def unnamed_mock
80
+ add_mock(Mock.new(self, @assertion_counter))
81
+ end
82
+
83
+ def mock_impersonating(object)
84
+ add_mock(Mock.new(self, @assertion_counter, ImpersonatingName.new(object), ObjectReceiver.new(object)))
85
+ end
86
+
87
+ def mock_impersonating_any_instance_of(klass)
88
+ add_mock(Mock.new(self, @assertion_counter, ImpersonatingAnyInstanceName.new(klass), AnyInstanceReceiver.new(klass)))
89
+ end
90
+
91
+ def new_state_machine(name)
92
+ add_state_machine(StateMachine.new(name))
93
+ end
94
+
95
+ def verify
96
+ unless mocks.all?(&:__verified__?)
97
+ message = "not all expectations were satisfied\n#{mocha_inspect}"
98
+ backtrace = if unsatisfied_expectations.empty?
99
+ caller
100
+ else
101
+ unsatisfied_expectations[0].backtrace
102
+ end
103
+ raise ExpectationErrorFactory.build(message, backtrace)
104
+ end
105
+ expectations.reject(&:used?).each do |expectation|
106
+ signature_proc = lambda { expectation.method_signature }
107
+ check(:stubbing_method_unnecessarily, 'method unnecessarily', signature_proc, expectation.backtrace)
108
+ end
109
+ end
110
+
111
+ def teardown(origin = nil)
112
+ stubba.unstub_all
113
+ mocks.each { |m| m.__expire__(origin) }
114
+ reset
115
+ end
116
+
117
+ def stubba
118
+ @stubba ||= Central.new
119
+ end
120
+
121
+ def mocks
122
+ @mocks ||= []
123
+ end
124
+
125
+ def state_machines
126
+ @state_machines ||= []
127
+ end
128
+
129
+ def sequences
130
+ @sequences ||= []
131
+ end
132
+
133
+ def mocha_inspect
134
+ lines = []
135
+ lines << "unsatisfied expectations:\n- #{unsatisfied_expectations.map(&:mocha_inspect).join("\n- ")}\n" if unsatisfied_expectations.any?
136
+ lines << "satisfied expectations:\n- #{satisfied_expectations.map(&:mocha_inspect).join("\n- ")}\n" if satisfied_expectations.any?
137
+ lines << "states:\n- #{state_machines.map(&:mocha_inspect).join("\n- ")}\n" if state_machines.any?
138
+ lines.join
139
+ end
140
+
141
+ def on_stubbing(object, method)
142
+ signature_proc = lambda { "#{object.mocha_inspect}.#{method}" }
143
+ check(:stubbing_non_existent_method, 'non-existent method', signature_proc) do
144
+ !(object.stubba_class.__method_exists__?(method) || object.stubba_respond_to?(method))
145
+ end
146
+ check(:stubbing_non_public_method, 'non-public method', signature_proc) do
147
+ object.stubba_class.__method_exists__?(method, include_public_methods: false)
148
+ end
149
+ check(:stubbing_method_on_non_mock_object, 'method on non-mock object', signature_proc)
150
+ end
151
+
152
+ attr_writer :logger
153
+
154
+ def logger
155
+ @logger ||= Logger.new($stderr)
156
+ end
157
+
158
+ private
159
+
160
+ def check(action, description, signature_proc, backtrace = caller)
161
+ treatment = Mocha.configuration.send(action)
162
+ return if (treatment == :allow) || (block_given? && !yield)
163
+
164
+ method_signature = signature_proc.call
165
+ message = "stubbing #{description}: #{method_signature}"
166
+ raise StubbingError.new(message, backtrace) if treatment == :prevent
167
+
168
+ logger.warn(message) if treatment == :warn
169
+ end
170
+
171
+ def expectations
172
+ mocks.map { |mock| mock.__expectations__.to_a }.flatten
173
+ end
174
+
175
+ def unsatisfied_expectations
176
+ expectations.reject(&:verified?)
177
+ end
178
+
179
+ def satisfied_expectations
180
+ expectations.select(&:verified?)
181
+ end
182
+
183
+ def add_mock(mock)
184
+ mocks << mock
185
+ mock
186
+ end
187
+
188
+ def add_state_machine(state_machine)
189
+ state_machines << state_machine
190
+ state_machine
191
+ end
192
+
193
+ def reset
194
+ @stubba = nil
195
+ @mocks = nil
196
+ @state_machines = nil
197
+ end
198
+ end
199
+ end
data/lib/mocha/name.rb ADDED
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mocha
4
+ class Name
5
+ def initialize(name)
6
+ @name = name.to_s
7
+ end
8
+
9
+ def mocha_inspect
10
+ "#<Mock:#{@name}>"
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mocha/error_with_filtered_backtrace'
4
+
5
+ module Mocha
6
+ # Exception raised when Mocha has not been initialized, e.g. outside the
7
+ # context of a test.
8
+ class NotInitializedError < ErrorWithFilteredBacktrace; end
9
+ end
@@ -0,0 +1,183 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mocha/mockery'
4
+ require 'mocha/instance_method'
5
+ require 'mocha/argument_iterator'
6
+ require 'mocha/expectation_error_factory'
7
+ require 'mocha/ignoring_warning'
8
+
9
+ module Mocha
10
+ # Methods added to all objects to allow mocking and stubbing on real (i.e. non-mock) objects.
11
+ #
12
+ # Both {#expects} and {#stubs} return an {Expectation} which can be further modified by methods on {Expectation}.
13
+ module ObjectMethods
14
+ extend IgnoringWarning
15
+
16
+ # @private
17
+ JRUBY_ALIAS_SPECIAL_METHODS_WARNING = /accesses caller method's state and should not be aliased/.freeze
18
+
19
+ ignoring_warning(JRUBY_ALIAS_SPECIAL_METHODS_WARNING, if_: RUBY_ENGINE == 'jruby') do
20
+ alias_method :_method, :method
21
+ end
22
+
23
+ # @private
24
+ def mocha(instantiate: true)
25
+ if instantiate
26
+ @mocha ||= Mocha::Mockery.instance.mock_impersonating(self)
27
+ else
28
+ defined?(@mocha) ? @mocha : nil
29
+ end
30
+ end
31
+
32
+ # @private
33
+ def reset_mocha
34
+ @mocha = nil
35
+ end
36
+
37
+ # @private
38
+ def stubba_method
39
+ Mocha::InstanceMethod
40
+ end
41
+
42
+ # @private
43
+ def stubba_object
44
+ self
45
+ end
46
+
47
+ # @private
48
+ def stubba_class
49
+ singleton_class
50
+ end
51
+
52
+ # @private
53
+ def stubba_respond_to?(symbol)
54
+ respond_to?(symbol)
55
+ end
56
+
57
+ # Adds an expectation that the specified method must be called exactly once with any parameters.
58
+ #
59
+ # The original implementation of the method is replaced during the test and then restored at the end of the test. The temporary replacement method has the same visibility as the original method.
60
+ #
61
+ # @return [Expectation] last-built expectation which can be further modified by methods on {Expectation}.
62
+ # @raise [StubbingError] if attempting to stub method which is not allowed.
63
+ #
64
+ # @overload def expects(method_name)
65
+ # @param [Symbol,String] method_name name of expected method
66
+ # @overload def expects(expected_methods_vs_return_values)
67
+ # @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.
68
+ #
69
+ # @example Setting up an expectation on a non-mock object.
70
+ # product = Product.new
71
+ # product.expects(:save).returns(true)
72
+ # assert_equal true, product.save
73
+ #
74
+ # @example Setting up multiple expectations on a non-mock object.
75
+ # product = Product.new
76
+ # product.expects(valid?: true, save: true)
77
+ #
78
+ # # exactly equivalent to
79
+ #
80
+ # product = Product.new
81
+ # product.expects(:valid?).returns(true)
82
+ # product.expects(:save).returns(true)
83
+ #
84
+ # @see Mock#expects
85
+ def expects(expected_methods_vs_return_values)
86
+ if expected_methods_vs_return_values.to_s =~ /the[^a-z]*spanish[^a-z]*inquisition/i
87
+ raise ExpectationErrorFactory.build('NOBODY EXPECTS THE SPANISH INQUISITION!')
88
+ end
89
+ if frozen?
90
+ raise StubbingError.new("can't stub method on frozen object: #{mocha_inspect}", caller)
91
+ end
92
+
93
+ expectation = nil
94
+ mockery = Mocha::Mockery.instance
95
+ iterator = ArgumentIterator.new(expected_methods_vs_return_values)
96
+ iterator.each do |method_name, *args|
97
+ mockery.on_stubbing(self, method_name)
98
+ method = stubba_method.new(stubba_object, method_name)
99
+ mockery.stubba.stub(method)
100
+ expectation = mocha.expects(method_name, caller)
101
+ expectation.returns(args.shift) unless args.empty?
102
+ end
103
+ expectation
104
+ end
105
+
106
+ # Adds an expectation that the specified method may be called any number of times with any parameters.
107
+ #
108
+ # The original implementation of the method is replaced during the test and then restored at the end of the test. The temporary replacement method has the same visibility as the original method.
109
+ #
110
+ # @return [Expectation] last-built expectation which can be further modified by methods on {Expectation}.
111
+ # @raise [StubbingError] if attempting to stub method which is not allowed.
112
+ #
113
+ # @overload def stubs(method_name)
114
+ # @param [Symbol,String] method_name name of stubbed method
115
+ # @overload def stubs(stubbed_methods_vs_return_values)
116
+ # @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.
117
+ #
118
+ # @example Setting up a stubbed methods on a non-mock object.
119
+ # product = Product.new
120
+ # product.stubs(:save).returns(true)
121
+ # assert_equal true, product.save
122
+ #
123
+ # @example Setting up multiple stubbed methods on a non-mock object.
124
+ # product = Product.new
125
+ # product.stubs(valid?: true, save: true)
126
+ #
127
+ # # exactly equivalent to
128
+ #
129
+ # product = Product.new
130
+ # product.stubs(:valid?).returns(true)
131
+ # product.stubs(:save).returns(true)
132
+ #
133
+ # @see Mock#stubs
134
+ def stubs(stubbed_methods_vs_return_values)
135
+ if frozen?
136
+ raise StubbingError.new("can't stub method on frozen object: #{mocha_inspect}", caller)
137
+ end
138
+
139
+ expectation = nil
140
+ mockery = Mocha::Mockery.instance
141
+ iterator = ArgumentIterator.new(stubbed_methods_vs_return_values)
142
+ iterator.each do |method_name, *args|
143
+ mockery.on_stubbing(self, method_name)
144
+ method = stubba_method.new(stubba_object, method_name)
145
+ mockery.stubba.stub(method)
146
+ expectation = mocha.stubs(method_name, caller)
147
+ expectation.returns(args.shift) unless args.empty?
148
+ end
149
+ expectation
150
+ end
151
+
152
+ # Removes the specified stubbed methods (added by calls to {#expects} or {#stubs}) and all expectations associated with them.
153
+ #
154
+ # Restores the original behaviour of the methods before they were stubbed. This is normally done automatically at the end of each test, but in some circumstances you may want to do it *before* the end of the test.
155
+ #
156
+ # WARNING: If you {#unstub} a method which still has unsatisfied expectations, you may be removing the only way those expectations can be satisfied. Use {#unstub} with care.
157
+ #
158
+ # @param [Array<Symbol>] method_names names of methods to unstub.
159
+ #
160
+ # @example Stubbing and unstubbing a method on a real (non-mock) object.
161
+ # multiplier = Multiplier.new
162
+ # multiplier.double(2) # => 4
163
+ # multiplier.stubs(:double).raises # new behaviour defined
164
+ # multiplier.double(2) # => raises exception
165
+ # multiplier.unstub(:double) # original behaviour restored
166
+ # multiplier.double(2) # => 4
167
+ #
168
+ # @example Unstubbing multiple methods on a real (non-mock) object.
169
+ # multiplier.unstub(:double, :triple)
170
+ #
171
+ # # exactly equivalent to
172
+ #
173
+ # multiplier.unstub(:double)
174
+ # multiplier.unstub(:triple)
175
+ def unstub(*method_names)
176
+ mockery = Mocha::Mockery.instance
177
+ method_names.each do |method_name|
178
+ method = stubba_method.new(stubba_object, method_name)
179
+ mockery.stubba.unstub(method)
180
+ end
181
+ end
182
+ end
183
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mocha
4
+ class ObjectReceiver
5
+ def initialize(object)
6
+ @object = object
7
+ end
8
+
9
+ def mocks
10
+ object = @object
11
+ mocks = []
12
+ while object
13
+ mocha = object.mocha(instantiate: false)
14
+ mocks << mocha if mocha
15
+ object = object.is_a?(Class) ? object.superclass : nil
16
+ end
17
+ mocks
18
+ end
19
+ end
20
+ end
@@ -1,42 +1,52 @@
1
- require 'mocha/parameter_matchers/base'
1
+ # frozen_string_literal: true
2
+
3
+ require 'mocha/parameter_matchers/base_methods'
2
4
 
3
5
  module Mocha
4
-
5
6
  module ParameterMatchers
6
-
7
- # :call-seq: all_of -> parameter_matcher
8
- #
9
- # Matches if all +matchers+ match.
10
- # object = mock()
11
- # object.expects(:method_1).with(all_of(includes(1), includes(3)))
12
- # object.method_1([1, 3])
13
- # # no error raised
14
- #
15
- # object = mock()
16
- # object.expects(:method_1).with(all_of(includes(1), includes(3)))
17
- # object.method_1([1, 2])
18
- # # error raised, because method_1 was not called with object including 1 and 3
19
- def all_of(*matchers)
20
- AllOf.new(*matchers)
7
+ module Methods
8
+ # Matches if all +matchers+ match.
9
+ #
10
+ # @param [*Array<BaseMethods>] matchers parameter matchers.
11
+ # @return [AllOf] parameter matcher.
12
+ #
13
+ # @see Expectation#with
14
+ #
15
+ # @example All parameter matchers match.
16
+ # object = mock()
17
+ # object.expects(:method_1).with(all_of(includes(1), includes(3)))
18
+ # object.method_1([1, 3])
19
+ # # no error raised
20
+ #
21
+ # @example One of the parameter matchers does not match.
22
+ # object = mock()
23
+ # object.expects(:method_1).with(all_of(includes(1), includes(3)))
24
+ # object.method_1([1, 2])
25
+ # # error raised, because method_1 was not called with object including 1 and 3
26
+ def all_of(*matchers)
27
+ AllOf.new(*matchers)
28
+ end
21
29
  end
22
-
23
- class AllOf < Base # :nodoc:
24
-
30
+
31
+ # Parameter matcher which combines a number of other matchers using a logical AND.
32
+ class AllOf
33
+ include BaseMethods
34
+
35
+ # @private
25
36
  def initialize(*matchers)
26
37
  @matchers = matchers
27
38
  end
28
-
39
+
40
+ # @private
29
41
  def matches?(available_parameters)
30
42
  parameter = available_parameters.shift
31
- @matchers.all? { |matcher| matcher.matches?([parameter]) }
43
+ @matchers.all? { |matcher| matcher.to_matcher.matches?([parameter]) }
32
44
  end
33
-
45
+
46
+ # @private
34
47
  def mocha_inspect
35
- "all_of(#{@matchers.map { |matcher| matcher.mocha_inspect }.join(", ") })"
48
+ "all_of(#{@matchers.map(&:mocha_inspect).join(', ')})"
36
49
  end
37
-
38
50
  end
39
-
40
51
  end
41
-
42
- end
52
+ end
@@ -1,47 +1,58 @@
1
- require 'mocha/parameter_matchers/base'
1
+ # frozen_string_literal: true
2
+
3
+ require 'mocha/parameter_matchers/base_methods'
2
4
 
3
5
  module Mocha
4
-
5
6
  module ParameterMatchers
6
-
7
- # :call-seq: any_of -> parameter_matcher
8
- #
9
- # Matches if any +matchers+ match.
10
- # object = mock()
11
- # object.expects(:method_1).with(any_of(1, 3))
12
- # object.method_1(1)
13
- # # no error raised
14
- #
15
- # object = mock()
16
- # object.expects(:method_1).with(any_of(1, 3))
17
- # object.method_1(3)
18
- # # no error raised
19
- #
20
- # object = mock()
21
- # object.expects(:method_1).with(any_of(1, 3))
22
- # object.method_1(2)
23
- # # error raised, because method_1 was not called with 1 or 3
24
- def any_of(*matchers)
25
- AnyOf.new(*matchers)
7
+ module Methods
8
+ # Matches if any +matchers+ match.
9
+ #
10
+ # @param [*Array<BaseMethods>] matchers parameter matchers.
11
+ # @return [AnyOf] parameter matcher.
12
+ #
13
+ # @see Expectation#with
14
+ #
15
+ # @example One parameter matcher matches.
16
+ # object = mock()
17
+ # object.expects(:method_1).with(any_of(1, 3))
18
+ # object.method_1(1)
19
+ # # no error raised
20
+ #
21
+ # @example The other parameter matcher matches.
22
+ # object = mock()
23
+ # object.expects(:method_1).with(any_of(1, 3))
24
+ # object.method_1(3)
25
+ # # no error raised
26
+ #
27
+ # @example Neither parameter matcher matches.
28
+ # object = mock()
29
+ # object.expects(:method_1).with(any_of(1, 3))
30
+ # object.method_1(2)
31
+ # # error raised, because method_1 was not called with 1 or 3
32
+ def any_of(*matchers)
33
+ AnyOf.new(*matchers)
34
+ end
26
35
  end
27
-
28
- class AnyOf < Base # :nodoc:
29
-
36
+
37
+ # Parameter matcher which combines a number of other matchers using a logical OR.
38
+ class AnyOf
39
+ include BaseMethods
40
+
41
+ # @private
30
42
  def initialize(*matchers)
31
43
  @matchers = matchers
32
44
  end
33
-
45
+
46
+ # @private
34
47
  def matches?(available_parameters)
35
48
  parameter = available_parameters.shift
36
- @matchers.any? { |matcher| matcher.matches?([parameter]) }
49
+ @matchers.any? { |matcher| matcher.to_matcher.matches?([parameter]) }
37
50
  end
38
-
51
+
52
+ # @private
39
53
  def mocha_inspect
40
- "any_of(#{@matchers.map { |matcher| matcher.mocha_inspect }.join(", ") })"
54
+ "any_of(#{@matchers.map(&:mocha_inspect).join(', ')})"
41
55
  end
42
-
43
56
  end
44
-
45
57
  end
46
-
47
- end
58
+ end
@@ -1,40 +1,47 @@
1
- require 'mocha/parameter_matchers/base'
1
+ # frozen_string_literal: true
2
+
3
+ require 'mocha/parameter_matchers/base_methods'
2
4
 
3
5
  module Mocha
4
-
5
6
  module ParameterMatchers
6
-
7
- # :call-seq: any_parameters() -> parameter_matcher
8
- #
9
- # Matches any parameters.
10
- # object = mock()
11
- # object.expects(:method_1).with(any_parameters)
12
- # object.method_1(1, 2, 3, 4)
13
- # # no error raised
14
- #
15
- # object = mock()
16
- # object.expects(:method_1).with(any_parameters)
17
- # object.method_1(5, 6, 7, 8, 9, 0)
18
- # # no error raised
19
- def any_parameters
20
- AnyParameters.new
7
+ module Methods
8
+ # Matches any parameters. This is used as the default for a newly built expectation.
9
+ #
10
+ # @return [AnyParameters] parameter matcher.
11
+ #
12
+ # @see Expectation#with
13
+ #
14
+ # @example Any parameters will match.
15
+ # object = mock()
16
+ # object.expects(:method_1).with(any_parameters)
17
+ # object.method_1(1, 2, 3, 4)
18
+ # # no error raised
19
+ #
20
+ # object = mock()
21
+ # object.expects(:method_1).with(any_parameters)
22
+ # object.method_1(5, 6, 7, 8, 9, 0)
23
+ # # no error raised
24
+ def any_parameters
25
+ AnyParameters.new
26
+ end
21
27
  end
22
28
 
23
- class AnyParameters < Base # :nodoc:
24
-
29
+ # Parameter matcher which always matches whatever the parameters.
30
+ class AnyParameters
31
+ include BaseMethods
32
+
33
+ # @private
25
34
  def matches?(available_parameters)
26
- while available_parameters.length > 0 do
35
+ until available_parameters.empty?
27
36
  available_parameters.shift
28
37
  end
29
- return true
38
+ true
30
39
  end
31
40
 
41
+ # @private
32
42
  def mocha_inspect
33
- "any_parameters"
43
+ 'any_parameters'
34
44
  end
35
-
36
45
  end
37
-
38
46
  end
39
-
40
- end
47
+ end