mocha 0.5.6 → 3.1.0

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 (191) 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 +1247 -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 +25 -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 +6 -15
  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 +562 -171
  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 +54 -30
  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 +26 -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 +192 -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/mocha.gemspec +40 -0
  104. metadata +129 -145
  105. data/COPYING +0 -3
  106. data/README +0 -35
  107. data/RELEASE +0 -188
  108. data/examples/misc.rb +0 -44
  109. data/examples/mocha.rb +0 -26
  110. data/examples/stubba.rb +0 -65
  111. data/lib/mocha/auto_verify.rb +0 -118
  112. data/lib/mocha/class_method.rb +0 -66
  113. data/lib/mocha/infinite_range.rb +0 -25
  114. data/lib/mocha/is_a.rb +0 -9
  115. data/lib/mocha/metaclass.rb +0 -7
  116. data/lib/mocha/missing_expectation.rb +0 -17
  117. data/lib/mocha/multiple_yields.rb +0 -20
  118. data/lib/mocha/no_yields.rb +0 -11
  119. data/lib/mocha/object.rb +0 -110
  120. data/lib/mocha/parameter_matchers/base.rb +0 -15
  121. data/lib/mocha/parameter_matchers/object.rb +0 -9
  122. data/lib/mocha/pretty_parameters.rb +0 -28
  123. data/lib/mocha/setup_and_teardown.rb +0 -23
  124. data/lib/mocha/single_yield.rb +0 -18
  125. data/lib/mocha/standalone.rb +0 -32
  126. data/lib/mocha/stub.rb +0 -18
  127. data/lib/mocha/test_case_adapter.rb +0 -49
  128. data/lib/mocha_standalone.rb +0 -2
  129. data/lib/stubba.rb +0 -2
  130. data/test/acceptance/expected_invocation_count_acceptance_test.rb +0 -187
  131. data/test/acceptance/mocha_acceptance_test.rb +0 -98
  132. data/test/acceptance/mock_with_initializer_block_acceptance_test.rb +0 -44
  133. data/test/acceptance/mocked_methods_dispatch_acceptance_test.rb +0 -71
  134. data/test/acceptance/optional_parameters_acceptance_test.rb +0 -63
  135. data/test/acceptance/parameter_matcher_acceptance_test.rb +0 -117
  136. data/test/acceptance/partial_mocks_acceptance_test.rb +0 -40
  137. data/test/acceptance/sequence_acceptance_test.rb +0 -179
  138. data/test/acceptance/standalone_acceptance_test.rb +0 -131
  139. data/test/acceptance/stubba_acceptance_test.rb +0 -102
  140. data/test/active_record_test_case.rb +0 -36
  141. data/test/deprecation_disabler.rb +0 -15
  142. data/test/execution_point.rb +0 -34
  143. data/test/integration/mocha_test_result_integration_test.rb +0 -105
  144. data/test/integration/stubba_integration_test.rb +0 -89
  145. data/test/integration/stubba_test_result_integration_test.rb +0 -85
  146. data/test/method_definer.rb +0 -18
  147. data/test/test_helper.rb +0 -12
  148. data/test/test_runner.rb +0 -31
  149. data/test/unit/any_instance_method_test.rb +0 -126
  150. data/test/unit/array_inspect_test.rb +0 -16
  151. data/test/unit/auto_verify_test.rb +0 -129
  152. data/test/unit/central_test.rb +0 -124
  153. data/test/unit/class_method_test.rb +0 -200
  154. data/test/unit/date_time_inspect_test.rb +0 -21
  155. data/test/unit/expectation_error_test.rb +0 -24
  156. data/test/unit/expectation_list_test.rb +0 -75
  157. data/test/unit/expectation_raiser_test.rb +0 -28
  158. data/test/unit/expectation_test.rb +0 -483
  159. data/test/unit/hash_inspect_test.rb +0 -16
  160. data/test/unit/infinite_range_test.rb +0 -53
  161. data/test/unit/metaclass_test.rb +0 -22
  162. data/test/unit/method_matcher_test.rb +0 -23
  163. data/test/unit/missing_expectation_test.rb +0 -42
  164. data/test/unit/mock_test.rb +0 -323
  165. data/test/unit/multiple_yields_test.rb +0 -18
  166. data/test/unit/no_yield_test.rb +0 -18
  167. data/test/unit/object_inspect_test.rb +0 -37
  168. data/test/unit/object_test.rb +0 -165
  169. data/test/unit/parameter_matchers/all_of_test.rb +0 -26
  170. data/test/unit/parameter_matchers/any_of_test.rb +0 -26
  171. data/test/unit/parameter_matchers/anything_test.rb +0 -21
  172. data/test/unit/parameter_matchers/has_entries_test.rb +0 -30
  173. data/test/unit/parameter_matchers/has_entry_test.rb +0 -40
  174. data/test/unit/parameter_matchers/has_key_test.rb +0 -25
  175. data/test/unit/parameter_matchers/has_value_test.rb +0 -25
  176. data/test/unit/parameter_matchers/includes_test.rb +0 -25
  177. data/test/unit/parameter_matchers/instance_of_test.rb +0 -25
  178. data/test/unit/parameter_matchers/is_a_test.rb +0 -25
  179. data/test/unit/parameter_matchers/kind_of_test.rb +0 -25
  180. data/test/unit/parameter_matchers/not_test.rb +0 -26
  181. data/test/unit/parameter_matchers/regexp_matches_test.rb +0 -25
  182. data/test/unit/parameter_matchers/stub_matcher.rb +0 -23
  183. data/test/unit/parameters_matcher_test.rb +0 -121
  184. data/test/unit/return_values_test.rb +0 -63
  185. data/test/unit/sequence_test.rb +0 -104
  186. data/test/unit/setup_and_teardown_test.rb +0 -76
  187. data/test/unit/single_return_value_test.rb +0 -33
  188. data/test/unit/single_yield_test.rb +0 -18
  189. data/test/unit/string_inspect_test.rb +0 -11
  190. data/test/unit/stub_test.rb +0 -24
  191. data/test/unit/yield_parameters_test.rb +0 -93
@@ -0,0 +1,192 @@
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
+ @instances.push(mockery)
53
+ end
54
+
55
+ def verify
56
+ instance.verify
57
+ end
58
+
59
+ def teardown(origin = nil)
60
+ if @instances.nil?
61
+ raise NotInitializedError, 'Mocha::Mockery.teardown called before Mocha::Mockery.setup'
62
+ end
63
+
64
+ instance.teardown(origin)
65
+ ensure
66
+ @instances.pop unless @instances.nil?
67
+ end
68
+ end
69
+
70
+ def initialize(assertion_counter)
71
+ @assertion_counter = assertion_counter
72
+ end
73
+
74
+ def named_mock(name)
75
+ add_mock(Mock.new(self, @assertion_counter, Name.new(name)))
76
+ end
77
+
78
+ def unnamed_mock
79
+ add_mock(Mock.new(self, @assertion_counter))
80
+ end
81
+
82
+ def mock_impersonating(object)
83
+ add_mock(Mock.new(self, @assertion_counter, ImpersonatingName.new(object), ObjectReceiver.new(object)))
84
+ end
85
+
86
+ def mock_impersonating_any_instance_of(klass)
87
+ add_mock(Mock.new(self, @assertion_counter, ImpersonatingAnyInstanceName.new(klass), AnyInstanceReceiver.new(klass)))
88
+ end
89
+
90
+ def new_state_machine(name)
91
+ add_state_machine(StateMachine.new(name))
92
+ end
93
+
94
+ def verify
95
+ unless mocks.all?(&:__verified__?)
96
+ message = "not all expectations were satisfied\n#{mocha_inspect}"
97
+ backtrace = if unsatisfied_expectations.empty?
98
+ caller
99
+ else
100
+ unsatisfied_expectations[0].backtrace
101
+ end
102
+ raise ExpectationErrorFactory.build(message, backtrace)
103
+ end
104
+ expectations.reject(&:used?).each do |expectation|
105
+ signature_proc = lambda { expectation.method_signature }
106
+ check(:stubbing_method_unnecessarily, 'method unnecessarily', signature_proc, expectation.backtrace)
107
+ end
108
+ end
109
+
110
+ def teardown(origin = nil)
111
+ stubba.unstub_all
112
+ mocks.each { |m| m.__expire__(origin) }
113
+ reset
114
+ end
115
+
116
+ def stubba
117
+ @stubba ||= Central.new
118
+ end
119
+
120
+ def mocks
121
+ @mocks ||= []
122
+ end
123
+
124
+ def state_machines
125
+ @state_machines ||= []
126
+ end
127
+
128
+ def sequences
129
+ @sequences ||= []
130
+ end
131
+
132
+ def mocha_inspect
133
+ lines = []
134
+ lines << "unsatisfied expectations:\n- #{unsatisfied_expectations.map(&:mocha_inspect).join("\n- ")}\n" if unsatisfied_expectations.any?
135
+ lines << "satisfied expectations:\n- #{satisfied_expectations.map(&:mocha_inspect).join("\n- ")}\n" if satisfied_expectations.any?
136
+ lines << "states:\n- #{state_machines.map(&:mocha_inspect).join("\n- ")}\n" if state_machines.any?
137
+ lines.join
138
+ end
139
+
140
+ def on_stubbing(object, method)
141
+ signature_proc = lambda { "#{object.mocha_inspect}.#{method}" }
142
+ check(:stubbing_non_existent_method, 'non-existent method', signature_proc) do
143
+ !(object.stubba_class.__method_exists__?(method) || object.stubba_respond_to?(method))
144
+ end
145
+ check(:stubbing_non_public_method, 'non-public method', signature_proc) do
146
+ object.stubba_class.__method_exists__?(method, include_public_methods: false)
147
+ end
148
+ check(:stubbing_method_on_non_mock_object, 'method on non-mock object', signature_proc)
149
+ end
150
+
151
+ private
152
+
153
+ def check(action, description, signature_proc, backtrace = caller)
154
+ treatment = Mocha.configuration.send(action)
155
+ return if (treatment == :allow) || (block_given? && !yield)
156
+
157
+ method_signature = signature_proc.call
158
+ message = "stubbing #{description}: #{method_signature}"
159
+ raise StubbingError.new(message, backtrace) if treatment == :prevent
160
+
161
+ Logger.warning(message) if treatment == :warn
162
+ end
163
+
164
+ def expectations
165
+ mocks.map { |mock| mock.__expectations__.to_a }.flatten
166
+ end
167
+
168
+ def unsatisfied_expectations
169
+ expectations.reject(&:verified?)
170
+ end
171
+
172
+ def satisfied_expectations
173
+ expectations.select(&:verified?)
174
+ end
175
+
176
+ def add_mock(mock)
177
+ mocks << mock
178
+ mock
179
+ end
180
+
181
+ def add_state_machine(state_machine)
182
+ state_machines << state_machine
183
+ state_machine
184
+ end
185
+
186
+ def reset
187
+ @stubba = nil
188
+ @mocks = nil
189
+ @state_machines = nil
190
+ end
191
+ end
192
+ 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