mocha 1.10.0 → 1.11.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.
- checksums.yaml +4 -4
- data/.github/FUNDING.yml +1 -0
- data/.yardopts +1 -0
- data/RELEASE.md +49 -0
- data/Rakefile +1 -4
- data/docs/Mocha.html +2 -2
- data/docs/Mocha/API.html +167 -35
- data/docs/Mocha/ClassMethods.html +2 -2
- data/docs/Mocha/Configuration.html +197 -55
- data/docs/Mocha/Expectation.html +284 -76
- data/docs/Mocha/ExpectationError.html +2 -2
- data/docs/Mocha/ExpectationErrorFactory.html +2 -2
- data/docs/Mocha/Hooks.html +2 -2
- data/docs/Mocha/Integration.html +2 -2
- data/docs/Mocha/Integration/MiniTest.html +2 -2
- data/docs/Mocha/Integration/MiniTest/Adapter.html +2 -2
- data/docs/Mocha/Integration/TestUnit.html +2 -2
- data/docs/Mocha/Integration/TestUnit/Adapter.html +2 -2
- data/docs/Mocha/Mock.html +14 -41
- data/docs/Mocha/ObjectMethods.html +2 -2
- data/docs/Mocha/ParameterMatchers.html +14 -26
- data/docs/Mocha/ParameterMatchers/AllOf.html +2 -2
- data/docs/Mocha/ParameterMatchers/AnyOf.html +2 -2
- data/docs/Mocha/ParameterMatchers/AnyParameters.html +2 -2
- data/docs/Mocha/ParameterMatchers/Anything.html +2 -2
- data/docs/Mocha/ParameterMatchers/Base.html +2 -2
- data/docs/Mocha/ParameterMatchers/Equals.html +2 -2
- data/docs/Mocha/ParameterMatchers/EquivalentUri.html +2 -2
- data/docs/Mocha/ParameterMatchers/HasEntries.html +2 -2
- data/docs/Mocha/ParameterMatchers/HasEntry.html +2 -2
- data/docs/Mocha/ParameterMatchers/HasKey.html +2 -2
- data/docs/Mocha/ParameterMatchers/HasValue.html +2 -2
- data/docs/Mocha/ParameterMatchers/Includes.html +2 -2
- data/docs/Mocha/ParameterMatchers/InstanceOf.html +2 -2
- data/docs/Mocha/ParameterMatchers/IsA.html +2 -2
- data/docs/Mocha/ParameterMatchers/KindOf.html +2 -2
- data/docs/Mocha/ParameterMatchers/Not.html +2 -2
- data/docs/Mocha/ParameterMatchers/Optionally.html +2 -2
- data/docs/Mocha/ParameterMatchers/RegexpMatches.html +2 -2
- data/docs/Mocha/ParameterMatchers/RespondsWith.html +2 -2
- data/docs/Mocha/ParameterMatchers/YamlEquivalent.html +2 -2
- data/docs/Mocha/Sequence.html +2 -2
- data/docs/Mocha/StateMachine.html +5 -5
- data/docs/Mocha/StateMachine/State.html +2 -2
- data/docs/Mocha/StateMachine/StatePredicate.html +2 -2
- data/docs/Mocha/StubbingError.html +2 -2
- data/docs/_index.html +3 -3
- data/docs/file.COPYING.html +2 -2
- data/docs/file.MIT-LICENSE.html +2 -2
- data/docs/file.README.html +2 -2
- data/docs/file.RELEASE.html +74 -2
- data/docs/frames.html +1 -1
- data/docs/index.html +2 -2
- data/docs/method_list.html +51 -27
- data/docs/top-level-namespace.html +2 -2
- data/lib/mocha/api.rb +83 -19
- data/lib/mocha/block_matcher.rb +31 -0
- data/lib/mocha/configuration.rb +57 -1
- data/lib/mocha/deprecation.rb +2 -1
- data/lib/mocha/expectation.rb +48 -7
- data/lib/mocha/invocation.rb +20 -4
- data/lib/mocha/mock.rb +42 -16
- data/lib/mocha/mockery.rb +14 -14
- data/lib/mocha/parameter_matchers/has_entries.rb +2 -3
- data/lib/mocha/parameter_matchers/has_entry.rb +2 -3
- data/lib/mocha/parameter_matchers/has_key.rb +2 -3
- data/lib/mocha/parameter_matchers/has_value.rb +2 -3
- data/lib/mocha/parameter_matchers/is_a.rb +2 -3
- data/lib/mocha/parameter_matchers/not.rb +2 -3
- data/lib/mocha/state_machine.rb +2 -3
- data/lib/mocha/stubbed_method.rb +4 -6
- data/lib/mocha/version.rb +1 -1
- data/lib/mocha/yield_parameters.rb +5 -11
- data/test/acceptance/acceptance_test_helper.rb +1 -0
- data/test/acceptance/display_matching_invocations_alongside_expectations_test.rb +5 -5
- data/test/acceptance/failure_messages_test.rb +16 -0
- data/test/acceptance/issue_457_test.rb +31 -0
- data/test/acceptance/mocha_example_test.rb +11 -1
- data/test/acceptance/mock_built_with_first_argument_type_being_string_test.rb +98 -0
- data/test/acceptance/mock_test.rb +64 -12
- data/test/acceptance/multiple_yielding_test.rb +59 -0
- data/test/acceptance/stubba_example_test.rb +11 -1
- data/test/acceptance/stubbing_non_existent_any_instance_method_test.rb +16 -0
- data/test/acceptance/yielding_test.rb +80 -0
- data/test/unit/expectation_test.rb +30 -3
- data/test/unit/yield_parameters_test.rb +35 -53
- metadata +8 -9
- data/lib/mocha/multiple_yields.rb +0 -15
- data/lib/mocha/no_yields.rb +0 -5
- data/lib/mocha/pretty_parameters.rb +0 -24
- data/lib/mocha/single_yield.rb +0 -13
- data/test/unit/multiple_yields_test.rb +0 -16
- data/test/unit/no_yields_test.rb +0 -16
- data/test/unit/single_yield_test.rb +0 -16
@@ -0,0 +1,31 @@
|
|
1
|
+
module Mocha
|
2
|
+
module BlockMatchers
|
3
|
+
class OptionalBlock
|
4
|
+
def match?(_actual_block)
|
5
|
+
true
|
6
|
+
end
|
7
|
+
|
8
|
+
def mocha_inspect; end
|
9
|
+
end
|
10
|
+
|
11
|
+
class BlockGiven
|
12
|
+
def match?(actual_block)
|
13
|
+
!actual_block.nil?
|
14
|
+
end
|
15
|
+
|
16
|
+
def mocha_inspect
|
17
|
+
'with block given'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class NoBlockGiven
|
22
|
+
def match?(actual_block)
|
23
|
+
actual_block.nil?
|
24
|
+
end
|
25
|
+
|
26
|
+
def mocha_inspect
|
27
|
+
'with no block given'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/mocha/configuration.rb
CHANGED
@@ -42,7 +42,8 @@ module Mocha
|
|
42
42
|
:stubbing_non_existent_method => :allow,
|
43
43
|
:stubbing_non_public_method => :allow,
|
44
44
|
:stubbing_method_on_nil => :prevent,
|
45
|
-
:display_matching_invocations_on_failure => false
|
45
|
+
:display_matching_invocations_on_failure => false,
|
46
|
+
:reinstate_undocumented_behaviour_from_v1_9 => true
|
46
47
|
}.freeze
|
47
48
|
|
48
49
|
attr_reader :options
|
@@ -247,6 +248,61 @@ module Mocha
|
|
247
248
|
@options[:display_matching_invocations_on_failure]
|
248
249
|
end
|
249
250
|
|
251
|
+
# Reinstate undocumented behaviour from v1.9
|
252
|
+
#
|
253
|
+
# Previously when {API#mock}, {API#stub}, or {API#stub_everything} were called with the first argument being a symbol, they built an *unnamed* mock object *and* expected or stubbed the method identified by the symbol argument; subsequent arguments were ignored.
|
254
|
+
# Now these methods build a *named* mock with the name specified by the symbol argument; *no* methods are expected or stubbed and subsequent arguments *are* taken into account.
|
255
|
+
#
|
256
|
+
# Previously if {Expectation#yields} or {Expectation#multiple_yields} was called on an expectation, but no block was given when the method was invoked, the instruction to yield was ignored.
|
257
|
+
# Now a +LocalJumpError+ is raised.
|
258
|
+
#
|
259
|
+
# Enabling this configuration option reinstates the previous behaviour, but displays a deprecation warning.
|
260
|
+
#
|
261
|
+
# @param [Boolean] value +true+ to reinstate undocumented behaviour; enabled by default.
|
262
|
+
#
|
263
|
+
# @example Reinstate undocumented behaviour for {API#mock}
|
264
|
+
# Mocha.configure do |c|
|
265
|
+
# c.reinstate_undocumented_behaviour_from_v1_9 = true
|
266
|
+
# end
|
267
|
+
#
|
268
|
+
# foo = mock(:bar)
|
269
|
+
# foo.inspect # => #<Mock>
|
270
|
+
#
|
271
|
+
# not all expectations were satisfied
|
272
|
+
# unsatisfied expectations:
|
273
|
+
# - expected exactly once, invoked never: #<Mock>.foo
|
274
|
+
#
|
275
|
+
# @example Reinstate undocumented behaviour for {API#stub}
|
276
|
+
# Mocha.configure do |c|
|
277
|
+
# c.reinstate_undocumented_behaviour_from_v1_9 = true
|
278
|
+
# end
|
279
|
+
#
|
280
|
+
# foo = stub(:bar)
|
281
|
+
# foo.inspect # => #<Mock>
|
282
|
+
# foo.bar # => nil
|
283
|
+
#
|
284
|
+
# @example Reinstate undocumented behaviour for {Expectation#yields}
|
285
|
+
# foo = mock('foo')
|
286
|
+
# foo.stubs(:my_method).yields(1, 2)
|
287
|
+
# foo.my_method # => raises LocalJumpError when no block is supplied
|
288
|
+
#
|
289
|
+
# Mocha.configure do |c|
|
290
|
+
# c.reinstate_undocumented_behaviour_from_v1_9 = true
|
291
|
+
# end
|
292
|
+
#
|
293
|
+
# foo = mock('foo')
|
294
|
+
# foo.stubs(:my_method).yields(1, 2)
|
295
|
+
# foo.my_method # => does *not* raise LocalJumpError when no block is supplied
|
296
|
+
#
|
297
|
+
def reinstate_undocumented_behaviour_from_v1_9=(value)
|
298
|
+
@options[:reinstate_undocumented_behaviour_from_v1_9] = value
|
299
|
+
end
|
300
|
+
|
301
|
+
# @private
|
302
|
+
def reinstate_undocumented_behaviour_from_v1_9?
|
303
|
+
@options[:reinstate_undocumented_behaviour_from_v1_9]
|
304
|
+
end
|
305
|
+
|
250
306
|
class << self
|
251
307
|
# Allow the specified +action+.
|
252
308
|
#
|
data/lib/mocha/deprecation.rb
CHANGED
data/lib/mocha/expectation.rb
CHANGED
@@ -10,6 +10,7 @@ require 'mocha/in_state_ordering_constraint'
|
|
10
10
|
require 'mocha/change_state_side_effect'
|
11
11
|
require 'mocha/cardinality'
|
12
12
|
require 'mocha/configuration'
|
13
|
+
require 'mocha/block_matcher'
|
13
14
|
|
14
15
|
module Mocha
|
15
16
|
# Methods on expectations returned from {Mock#expects}, {Mock#stubs}, {ObjectMethods#expects} and {ObjectMethods#stubs}.
|
@@ -224,6 +225,44 @@ module Mocha
|
|
224
225
|
self
|
225
226
|
end
|
226
227
|
|
228
|
+
# Modifies expectation so that the expected method must be called with a block.
|
229
|
+
#
|
230
|
+
# @return [Expectation] the same expectation, thereby allowing invocations of other {Expectation} methods to be chained.
|
231
|
+
#
|
232
|
+
# @example Expected method must be called with a block.
|
233
|
+
# object = mock()
|
234
|
+
# object.expects(:expected_method).with_block_given
|
235
|
+
# object.expected_method { 1 + 1 }
|
236
|
+
# # => verify succeeds
|
237
|
+
#
|
238
|
+
# object = mock()
|
239
|
+
# object.expects(:expected_method).with_block_given
|
240
|
+
# object.expected_method
|
241
|
+
# # => verify fails
|
242
|
+
def with_block_given
|
243
|
+
@block_matcher = BlockMatchers::BlockGiven.new
|
244
|
+
self
|
245
|
+
end
|
246
|
+
|
247
|
+
# Modifies expectation so that the expected method must be called without a block.
|
248
|
+
#
|
249
|
+
# @return [Expectation] the same expectation, thereby allowing invocations of other {Expectation} methods to be chained.
|
250
|
+
#
|
251
|
+
# @example Expected method must be called without a block.
|
252
|
+
# object = mock()
|
253
|
+
# object.expects(:expected_method).with_no_block_given
|
254
|
+
# object.expected_method
|
255
|
+
# # => verify succeeds
|
256
|
+
#
|
257
|
+
# object = mock()
|
258
|
+
# object.expects(:expected_method).with_block_given
|
259
|
+
# object.expected_method { 1 + 1 }
|
260
|
+
# # => verify fails
|
261
|
+
def with_no_block_given
|
262
|
+
@block_matcher = BlockMatchers::NoBlockGiven.new
|
263
|
+
self
|
264
|
+
end
|
265
|
+
|
227
266
|
# Modifies expectation so that when the expected method is called, it yields with the specified +parameters+ (even if no block is provided, in which case yielding will result in a +LocalJumpError+).
|
228
267
|
#
|
229
268
|
# May be called multiple times on the same expectation for consecutive invocations.
|
@@ -256,13 +295,12 @@ module Mocha
|
|
256
295
|
# fibonacci.next_pair { |first, second| sum = first + second }
|
257
296
|
# sum # => 2
|
258
297
|
def yields(*parameters)
|
259
|
-
|
260
|
-
self
|
298
|
+
multiple_yields(parameters)
|
261
299
|
end
|
262
300
|
|
263
301
|
# Modifies expectation so that when the expected method is called, it yields multiple times per invocation with the specified +parameter_groups+ (even if no block is provided, in which case yielding will result in a +LocalJumpError+).
|
264
302
|
#
|
265
|
-
# @param [*Array<Array>] parameter_groups each element of +parameter_groups+ should iself be an +Array+ representing the parameters to be passed to the block for a single yield.
|
303
|
+
# @param [*Array<Array>] parameter_groups each element of +parameter_groups+ should iself be an +Array+ representing the parameters to be passed to the block for a single yield. Any element of +parameter_groups+ that is not an +Array+ is wrapped in an +Array+.
|
266
304
|
# @return [Expectation] the same expectation, thereby allowing invocations of other {Expectation} methods to be chained.
|
267
305
|
# @see #then
|
268
306
|
#
|
@@ -283,7 +321,7 @@ module Mocha
|
|
283
321
|
# rows_from_first_invocation # => [['old_row1_col1', 'old_row1_col2'], ['old_row2_col1', '']]
|
284
322
|
# rows_from_second_invocation # => [['new_row1_col1', ''], ['new_row2_col1', 'new_row2_col2']]
|
285
323
|
def multiple_yields(*parameter_groups)
|
286
|
-
@yield_parameters.
|
324
|
+
@yield_parameters.add(*parameter_groups)
|
287
325
|
self
|
288
326
|
end
|
289
327
|
|
@@ -511,6 +549,7 @@ module Mocha
|
|
511
549
|
@mock = mock
|
512
550
|
@method_matcher = MethodMatcher.new(expected_method_name.to_sym)
|
513
551
|
@parameters_matcher = ParametersMatcher.new
|
552
|
+
@block_matcher = BlockMatchers::OptionalBlock.new
|
514
553
|
@ordering_constraints = []
|
515
554
|
@side_effects = []
|
516
555
|
@cardinality = Cardinality.exactly(1)
|
@@ -551,7 +590,7 @@ module Mocha
|
|
551
590
|
|
552
591
|
# @private
|
553
592
|
def match?(invocation)
|
554
|
-
@method_matcher.match?(invocation.method_name) && @parameters_matcher.match?(invocation.arguments) && in_correct_order?
|
593
|
+
@method_matcher.match?(invocation.method_name) && @parameters_matcher.match?(invocation.arguments) && @block_matcher.match?(invocation.block) && in_correct_order?
|
555
594
|
end
|
556
595
|
|
557
596
|
# @private
|
@@ -568,7 +607,7 @@ module Mocha
|
|
568
607
|
def invoke(invocation)
|
569
608
|
perform_side_effects
|
570
609
|
@cardinality << invocation
|
571
|
-
invocation.call(@yield_parameters, @return_values)
|
610
|
+
invocation.call(@yield_parameters, @return_values)
|
572
611
|
end
|
573
612
|
|
574
613
|
# @private
|
@@ -601,7 +640,9 @@ module Mocha
|
|
601
640
|
|
602
641
|
# @private
|
603
642
|
def method_signature
|
604
|
-
"#{@mock.mocha_inspect}.#{@method_matcher.mocha_inspect}#{@parameters_matcher.mocha_inspect}"
|
643
|
+
signature = "#{@mock.mocha_inspect}.#{@method_matcher.mocha_inspect}#{@parameters_matcher.mocha_inspect}"
|
644
|
+
signature << " #{@block_matcher.mocha_inspect}" if @block_matcher.mocha_inspect
|
645
|
+
signature
|
605
646
|
end
|
606
647
|
end
|
607
648
|
end
|
data/lib/mocha/invocation.rb
CHANGED
@@ -3,15 +3,18 @@ require 'mocha/raised_exception'
|
|
3
3
|
require 'mocha/return_values'
|
4
4
|
require 'mocha/thrown_object'
|
5
5
|
require 'mocha/yield_parameters'
|
6
|
+
require 'mocha/configuration'
|
7
|
+
require 'mocha/deprecation'
|
6
8
|
|
7
9
|
module Mocha
|
8
10
|
class Invocation
|
9
|
-
attr_reader :method_name
|
11
|
+
attr_reader :method_name, :block
|
10
12
|
|
11
|
-
def initialize(mock, method_name, *arguments)
|
13
|
+
def initialize(mock, method_name, *arguments, &block)
|
12
14
|
@mock = mock
|
13
15
|
@method_name = method_name
|
14
16
|
@arguments = arguments
|
17
|
+
@block = block
|
15
18
|
@yields = []
|
16
19
|
@result = nil
|
17
20
|
end
|
@@ -19,7 +22,18 @@ module Mocha
|
|
19
22
|
def call(yield_parameters = YieldParameters.new, return_values = ReturnValues.new)
|
20
23
|
yield_parameters.next_invocation.each do |yield_args|
|
21
24
|
@yields << ParametersMatcher.new(yield_args)
|
22
|
-
|
25
|
+
if @block
|
26
|
+
@block.call(*yield_args)
|
27
|
+
else
|
28
|
+
raise LocalJumpError unless Mocha.configuration.reinstate_undocumented_behaviour_from_v1_9?
|
29
|
+
yield_args_description = ParametersMatcher.new(yield_args).mocha_inspect
|
30
|
+
Deprecation.warning(
|
31
|
+
"Stubbed method was instructed to yield #{yield_args_description}, but no block was given by invocation: #{call_description}.",
|
32
|
+
' This will raise a LocalJumpError in the future.',
|
33
|
+
' Use Expectation#with_block_given to constrain this expectation to match invocations supplying a block.',
|
34
|
+
' And, if necessary, add another expectation to match invocations not supplying a block.'
|
35
|
+
)
|
36
|
+
end
|
23
37
|
end
|
24
38
|
return_values.next(self)
|
25
39
|
end
|
@@ -41,7 +55,9 @@ module Mocha
|
|
41
55
|
end
|
42
56
|
|
43
57
|
def call_description
|
44
|
-
"#{@mock.mocha_inspect}.#{@method_name}#{ParametersMatcher.new(@arguments).mocha_inspect}"
|
58
|
+
description = "#{@mock.mocha_inspect}.#{@method_name}#{ParametersMatcher.new(@arguments).mocha_inspect}"
|
59
|
+
description << ' { ... }' unless @block.nil?
|
60
|
+
description
|
45
61
|
end
|
46
62
|
|
47
63
|
def short_call_description
|
data/lib/mocha/mock.rb
CHANGED
@@ -275,6 +275,7 @@ module Mocha
|
|
275
275
|
@everything_stubbed = false
|
276
276
|
@responder = nil
|
277
277
|
@unexpected_invocation = nil
|
278
|
+
@expired = false
|
278
279
|
end
|
279
280
|
|
280
281
|
# @private
|
@@ -305,26 +306,16 @@ module Mocha
|
|
305
306
|
end
|
306
307
|
|
307
308
|
# @private
|
308
|
-
# rubocop:disable Style/MethodMissingSuper
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
end
|
313
|
-
invocation = Invocation.new(self, symbol, *arguments)
|
309
|
+
def method_missing(symbol, *arguments, &block) # rubocop:disable Style/MethodMissingSuper
|
310
|
+
check_expiry
|
311
|
+
check_responder_responds_to(symbol)
|
312
|
+
invocation = Invocation.new(self, symbol, *arguments, &block)
|
314
313
|
if (matching_expectation_allowing_invocation = all_expectations.match_allowing_invocation(invocation))
|
315
|
-
matching_expectation_allowing_invocation.invoke(invocation
|
314
|
+
matching_expectation_allowing_invocation.invoke(invocation)
|
316
315
|
elsif (matching_expectation = all_expectations.match(invocation)) || (!matching_expectation && !@everything_stubbed)
|
317
|
-
|
318
|
-
@unexpected_invocation = invocation
|
319
|
-
matching_expectation.invoke(invocation, &block) if matching_expectation
|
320
|
-
message = "#{@unexpected_invocation.call_description}\n#{@mockery.mocha_inspect}"
|
321
|
-
else
|
322
|
-
message = @unexpected_invocation.short_call_description
|
323
|
-
end
|
324
|
-
raise ExpectationErrorFactory.build("unexpected invocation: #{message}", caller)
|
316
|
+
raise_unexpected_invocation_error(invocation, matching_expectation)
|
325
317
|
end
|
326
318
|
end
|
327
|
-
# rubocop:enable Style/MethodMissingSuper,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
|
328
319
|
|
329
320
|
# @private
|
330
321
|
def respond_to_missing?(symbol, include_private = false)
|
@@ -351,6 +342,11 @@ module Mocha
|
|
351
342
|
@expectations.verified?(assertion_counter)
|
352
343
|
end
|
353
344
|
|
345
|
+
# @private
|
346
|
+
def __expire__
|
347
|
+
@expired = true
|
348
|
+
end
|
349
|
+
|
354
350
|
# @private
|
355
351
|
def mocha_inspect
|
356
352
|
@name.mocha_inspect
|
@@ -370,5 +366,35 @@ module Mocha
|
|
370
366
|
def any_expectations?
|
371
367
|
@expectations.any?
|
372
368
|
end
|
369
|
+
|
370
|
+
private
|
371
|
+
|
372
|
+
def raise_unexpected_invocation_error(invocation, matching_expectation)
|
373
|
+
if @unexpected_invocation.nil?
|
374
|
+
@unexpected_invocation = invocation
|
375
|
+
matching_expectation.invoke(invocation) if matching_expectation
|
376
|
+
message = "#{@unexpected_invocation.call_description}\n#{@mockery.mocha_inspect}"
|
377
|
+
else
|
378
|
+
message = @unexpected_invocation.short_call_description
|
379
|
+
end
|
380
|
+
raise ExpectationErrorFactory.build("unexpected invocation: #{message}", caller)
|
381
|
+
end
|
382
|
+
|
383
|
+
def check_responder_responds_to(symbol)
|
384
|
+
if @responder && !@responder.respond_to?(symbol) # rubocop:disable Style/GuardClause
|
385
|
+
raise NoMethodError, "undefined method `#{symbol}' for #{mocha_inspect} which responds like #{@responder.mocha_inspect}"
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
389
|
+
def check_expiry
|
390
|
+
if @expired # rubocop:disable Style/GuardClause
|
391
|
+
Deprecation.warning(
|
392
|
+
"#{mocha_inspect} was instantiated in one test but it is receiving invocations within another test.",
|
393
|
+
' This can lead to unintended interactions between tests and hence unexpected test failures.',
|
394
|
+
' Ensure that every test correctly cleans up any state that it introduces.',
|
395
|
+
' A Mocha::StubbingError will be raised in this scenario in the future.'
|
396
|
+
)
|
397
|
+
end
|
398
|
+
end
|
373
399
|
end
|
374
400
|
end
|
data/lib/mocha/mockery.rb
CHANGED
@@ -102,6 +102,7 @@ module Mocha
|
|
102
102
|
|
103
103
|
def teardown
|
104
104
|
stubba.unstub_all
|
105
|
+
mocks.each(&:__expire__)
|
105
106
|
reset
|
106
107
|
end
|
107
108
|
|
@@ -127,19 +128,20 @@ module Mocha
|
|
127
128
|
|
128
129
|
def on_stubbing(object, method)
|
129
130
|
method = PRE_RUBY_V19 ? method.to_s : method.to_sym
|
130
|
-
|
131
|
-
check(:stubbing_non_existent_method, 'non-existent method',
|
131
|
+
signature_proc = lambda { "#{object.mocha_inspect}.#{method}" }
|
132
|
+
check(:stubbing_non_existent_method, 'non-existent method', signature_proc) do
|
132
133
|
!(object.stubba_class.__method_exists__?(method, true) || object.respond_to?(method.to_sym))
|
133
134
|
end
|
134
|
-
check(:stubbing_non_public_method, 'non-public method',
|
135
|
+
check(:stubbing_non_public_method, 'non-public method', signature_proc) do
|
135
136
|
object.stubba_class.__method_exists__?(method, false)
|
136
137
|
end
|
137
|
-
check(:stubbing_method_on_nil, 'method on nil',
|
138
|
-
check(:stubbing_method_on_non_mock_object, 'method on non-mock object',
|
138
|
+
check(:stubbing_method_on_nil, 'method on nil', signature_proc) { object.nil? }
|
139
|
+
check(:stubbing_method_on_non_mock_object, 'method on non-mock object', signature_proc)
|
139
140
|
end
|
140
141
|
|
141
142
|
def on_stubbing_method_unnecessarily(expectation)
|
142
|
-
|
143
|
+
signature_proc = lambda { expectation.method_signature }
|
144
|
+
check(:stubbing_method_unnecessarily, 'method unnecessarily', signature_proc, expectation.backtrace)
|
143
145
|
end
|
144
146
|
|
145
147
|
attr_writer :logger
|
@@ -150,15 +152,13 @@ module Mocha
|
|
150
152
|
|
151
153
|
private
|
152
154
|
|
153
|
-
def check(action, description,
|
154
|
-
|
155
|
+
def check(action, description, signature_proc, backtrace = caller)
|
156
|
+
treatment = Mocha.configuration.send(action)
|
157
|
+
return if (treatment == :allow) || (block_given? && !yield)
|
158
|
+
method_signature = signature_proc.call
|
155
159
|
message = "stubbing #{description}: #{method_signature}"
|
156
|
-
|
157
|
-
|
158
|
-
logger.warn(message)
|
159
|
-
when :prevent
|
160
|
-
raise StubbingError.new(message, backtrace)
|
161
|
-
end
|
160
|
+
raise StubbingError.new(message, backtrace) if treatment == :prevent
|
161
|
+
logger.warn(message) if treatment == :warn
|
162
162
|
end
|
163
163
|
|
164
164
|
def expectations
|
@@ -22,11 +22,10 @@ module Mocha
|
|
22
22
|
# object.expects(:method_1).with(has_entries('key_1' => 1, 'key_2' => 2))
|
23
23
|
# object.method_1('key_1' => 1, 'key_2' => 99)
|
24
24
|
# # error raised, because method_1 was not called with Hash containing entries: 'key_1' => 1, 'key_2' => 2
|
25
|
-
#
|
26
|
-
def has_entries(entries)
|
25
|
+
#
|
26
|
+
def has_entries(entries) # rubocop:disable Naming/PredicateName
|
27
27
|
HasEntries.new(entries)
|
28
28
|
end
|
29
|
-
# rubocop:enable Naming/PredicateName
|
30
29
|
|
31
30
|
# Parameter matcher which matches when actual parameter contains all expected +Hash+ entries.
|
32
31
|
class HasEntries < Base
|
@@ -39,8 +39,8 @@ module Mocha
|
|
39
39
|
# object.expects(:method_1).with(has_entry('key_1' => 1))
|
40
40
|
# object.method_1('key_1' => 2, 'key_2' => 1)
|
41
41
|
# # error raised, because method_1 was not called with Hash containing entry: 'key_1' => 1
|
42
|
-
#
|
43
|
-
def has_entry(*options)
|
42
|
+
#
|
43
|
+
def has_entry(*options) # rubocop:disable Naming/PredicateName
|
44
44
|
case options.length
|
45
45
|
when 1
|
46
46
|
case options[0]
|
@@ -63,7 +63,6 @@ module Mocha
|
|
63
63
|
end
|
64
64
|
HasEntry.new(key, value)
|
65
65
|
end
|
66
|
-
# rubocop:enable Naming/PredicateName
|
67
66
|
|
68
67
|
# Parameter matcher which matches when actual parameter contains expected +Hash+ entry.
|
69
68
|
class HasEntry < Base
|