mocha 0.5.6 → 0.9.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 (120) hide show
  1. data/README +4 -4
  2. data/RELEASE +45 -0
  3. data/Rakefile +55 -33
  4. data/lib/mocha.rb +1 -0
  5. data/lib/mocha/any_instance_method.rb +24 -4
  6. data/lib/mocha/backtrace_filter.rb +17 -0
  7. data/lib/mocha/cardinality.rb +92 -0
  8. data/lib/mocha/central.rb +1 -9
  9. data/lib/mocha/change_state_side_effect.rb +19 -0
  10. data/lib/mocha/class_method.rb +25 -5
  11. data/lib/mocha/configuration.rb +60 -0
  12. data/lib/mocha/exception_raiser.rb +1 -1
  13. data/lib/mocha/expectation.rb +109 -48
  14. data/lib/mocha/expectation_error.rb +6 -6
  15. data/lib/mocha/expectation_list.rb +10 -14
  16. data/lib/mocha/in_state_ordering_constraint.rb +19 -0
  17. data/lib/mocha/instance_method.rb +9 -0
  18. data/lib/mocha/logger.rb +15 -0
  19. data/lib/mocha/mock.rb +19 -14
  20. data/lib/mocha/mockery.rb +166 -0
  21. data/lib/mocha/module_method.rb +17 -0
  22. data/lib/mocha/names.rb +53 -0
  23. data/lib/mocha/object.rb +26 -9
  24. data/lib/mocha/parameter_matchers.rb +2 -1
  25. data/lib/mocha/parameter_matchers/all_of.rb +3 -3
  26. data/lib/mocha/parameter_matchers/any_of.rb +3 -3
  27. data/lib/mocha/parameter_matchers/anything.rb +1 -1
  28. data/lib/mocha/parameter_matchers/has_entries.rb +4 -1
  29. data/lib/mocha/parameter_matchers/has_entry.rb +3 -2
  30. data/lib/mocha/parameter_matchers/has_key.rb +1 -1
  31. data/lib/mocha/parameter_matchers/has_value.rb +1 -1
  32. data/lib/mocha/parameter_matchers/not.rb +2 -2
  33. data/lib/mocha/parameter_matchers/object.rb +1 -1
  34. data/lib/mocha/parameter_matchers/optionally.rb +22 -0
  35. data/lib/mocha/parameter_matchers/regexp_matches.rb +2 -2
  36. data/lib/mocha/parameter_matchers/responds_with.rb +43 -0
  37. data/lib/mocha/parameter_matchers/yaml_equivalent.rb +43 -0
  38. data/lib/mocha/single_return_value.rb +2 -9
  39. data/lib/mocha/standalone.rb +151 -17
  40. data/lib/mocha/state_machine.rb +91 -0
  41. data/lib/mocha/stubbing_error.rb +16 -0
  42. data/lib/mocha/test_case_adapter.rb +76 -22
  43. data/lib/stubba.rb +2 -1
  44. data/test/acceptance/acceptance_test_helper.rb +38 -0
  45. data/test/acceptance/bug_18914_test.rb +43 -0
  46. data/test/acceptance/{expected_invocation_count_acceptance_test.rb → expected_invocation_count_test.rb} +29 -20
  47. data/test/acceptance/failure_messages_test.rb +64 -0
  48. data/test/acceptance/{mocha_acceptance_test.rb → mocha_example_test.rb} +5 -5
  49. data/test/{integration/mocha_test_result_integration_test.rb → acceptance/mocha_test_result_test.rb} +19 -40
  50. data/test/acceptance/mock_test.rb +100 -0
  51. data/test/acceptance/{mock_with_initializer_block_acceptance_test.rb → mock_with_initializer_block_test.rb} +12 -5
  52. data/test/acceptance/{mocked_methods_dispatch_acceptance_test.rb → mocked_methods_dispatch_test.rb} +12 -5
  53. data/test/acceptance/{optional_parameters_acceptance_test.rb → optional_parameters_test.rb} +11 -4
  54. data/test/acceptance/{parameter_matcher_acceptance_test.rb → parameter_matcher_test.rb} +67 -5
  55. data/test/acceptance/{partial_mocks_acceptance_test.rb → partial_mocks_test.rb} +12 -5
  56. data/test/acceptance/return_value_test.rb +52 -0
  57. data/test/acceptance/{sequence_acceptance_test.rb → sequence_test.rb} +13 -6
  58. data/test/acceptance/{standalone_acceptance_test.rb → standalone_test.rb} +19 -11
  59. data/test/acceptance/states_test.rb +70 -0
  60. data/test/acceptance/stub_any_instance_method_test.rb +195 -0
  61. data/test/acceptance/stub_class_method_test.rb +203 -0
  62. data/test/acceptance/stub_everything_test.rb +56 -0
  63. data/test/acceptance/stub_instance_method_test.rb +165 -0
  64. data/test/acceptance/stub_module_method_test.rb +163 -0
  65. data/test/acceptance/stub_test.rb +52 -0
  66. data/test/acceptance/{stubba_acceptance_test.rb → stubba_example_test.rb} +1 -1
  67. data/test/{integration/stubba_test_result_integration_test.rb → acceptance/stubba_test_result_test.rb} +17 -36
  68. data/test/acceptance/stubbing_error_backtrace_test.rb +64 -0
  69. data/test/acceptance/stubbing_method_unnecessarily_test.rb +65 -0
  70. data/test/acceptance/stubbing_non_existent_any_instance_method_test.rb +130 -0
  71. data/test/acceptance/stubbing_non_existent_class_method_test.rb +155 -0
  72. data/test/acceptance/stubbing_non_existent_instance_method_test.rb +145 -0
  73. data/test/acceptance/stubbing_non_public_any_instance_method_test.rb +130 -0
  74. data/test/acceptance/stubbing_non_public_class_method_test.rb +161 -0
  75. data/test/acceptance/stubbing_non_public_instance_method_test.rb +141 -0
  76. data/test/acceptance/stubbing_on_non_mock_object_test.rb +64 -0
  77. data/test/execution_point.rb +3 -1
  78. data/test/simple_counter.rb +13 -0
  79. data/test/test_helper.rb +0 -1
  80. data/test/test_runner.rb +6 -4
  81. data/test/unit/any_instance_method_test.rb +1 -1
  82. data/test/unit/array_inspect_test.rb +1 -1
  83. data/test/unit/backtrace_filter_test.rb +19 -0
  84. data/test/unit/cardinality_test.rb +56 -0
  85. data/test/unit/central_test.rb +4 -63
  86. data/test/unit/change_state_side_effect_test.rb +41 -0
  87. data/test/unit/class_method_test.rb +38 -1
  88. data/test/unit/date_time_inspect_test.rb +1 -1
  89. data/test/unit/{expectation_raiser_test.rb → exception_raiser_test.rb} +14 -0
  90. data/test/unit/expectation_list_test.rb +4 -22
  91. data/test/unit/expectation_test.rb +70 -94
  92. data/test/unit/in_state_ordering_constraint_test.rb +43 -0
  93. data/test/unit/mock_test.rb +16 -37
  94. data/test/unit/mockery_test.rb +149 -0
  95. data/test/unit/{no_yield_test.rb → no_yields_test.rb} +0 -0
  96. data/test/unit/object_test.rb +6 -89
  97. data/test/unit/parameter_matchers/equals_test.rb +25 -0
  98. data/test/unit/parameter_matchers/has_entries_test.rb +22 -1
  99. data/test/unit/parameter_matchers/has_entry_test.rb +24 -2
  100. data/test/unit/parameter_matchers/has_key_test.rb +11 -0
  101. data/test/unit/parameter_matchers/has_value_test.rb +12 -0
  102. data/test/unit/parameter_matchers/regexp_matches_test.rb +1 -1
  103. data/test/unit/parameter_matchers/responds_with_test.rb +25 -0
  104. data/test/unit/parameter_matchers/stub_matcher.rb +4 -0
  105. data/test/unit/parameter_matchers/yaml_equivalent_test.rb +25 -0
  106. data/test/unit/single_return_value_test.rb +0 -19
  107. data/test/unit/state_machine_test.rb +98 -0
  108. metadata +108 -69
  109. data/lib/mocha/auto_verify.rb +0 -118
  110. data/lib/mocha/infinite_range.rb +0 -25
  111. data/lib/mocha/missing_expectation.rb +0 -17
  112. data/lib/mocha/setup_and_teardown.rb +0 -23
  113. data/lib/mocha/stub.rb +0 -18
  114. data/test/integration/stubba_integration_test.rb +0 -89
  115. data/test/unit/auto_verify_test.rb +0 -129
  116. data/test/unit/expectation_error_test.rb +0 -24
  117. data/test/unit/infinite_range_test.rb +0 -53
  118. data/test/unit/missing_expectation_test.rb +0 -42
  119. data/test/unit/setup_and_teardown_test.rb +0 -76
  120. data/test/unit/stub_test.rb +0 -24
@@ -0,0 +1,60 @@
1
+ module Mocha # :nodoc:
2
+
3
+ # Configuration settings
4
+ class Configuration
5
+
6
+ DEFAULTS = { :stubbing_method_unnecessarily => :allow, :stubbing_method_on_non_mock_object => :allow, :stubbing_non_existent_method => :allow, :stubbing_non_public_method => :allow }
7
+
8
+ class << self
9
+
10
+ # :call-seq: allow(action)
11
+ #
12
+ # Allow the specified <tt>action</tt> (as a symbol).
13
+ # The <tt>actions</tt> currently available are <tt>:stubbing_method_unnecessarily, :stubbing_method_on_non_mock_object, :stubbing_non_existent_method, :stubbing_non_public_method</tt>.
14
+ def allow(action)
15
+ configuration[action] = :allow
16
+ end
17
+
18
+ def allow?(action) # :nodoc:
19
+ configuration[action] == :allow
20
+ end
21
+
22
+ # :call-seq: warn_when(action)
23
+ #
24
+ # Warn if the specified <tt>action</tt> (as a symbol) is attempted.
25
+ # The <tt>actions</tt> currently available are <tt>:stubbing_method_unnecessarily, :stubbing_method_on_non_mock_object, :stubbing_non_existent_method, :stubbing_non_public_method</tt>.
26
+ def warn_when(action)
27
+ configuration[action] = :warn
28
+ end
29
+
30
+ def warn_when?(action) # :nodoc:
31
+ configuration[action] == :warn
32
+ end
33
+
34
+ # :call-seq: prevent(action)
35
+ #
36
+ # Raise a StubbingError if the specified <tt>action</tt> (as a symbol) is attempted.
37
+ # The <tt>actions</tt> currently available are <tt>:stubbing_method_unnecessarily, :stubbing_method_on_non_mock_object, :stubbing_non_existent_method, :stubbing_non_public_method</tt>.
38
+ def prevent(action)
39
+ configuration[action] = :prevent
40
+ end
41
+
42
+ def prevent?(action) # :nodoc:
43
+ configuration[action] == :prevent
44
+ end
45
+
46
+ def reset_configuration # :nodoc:
47
+ @configuration = nil
48
+ end
49
+
50
+ private
51
+
52
+ def configuration # :nodoc:
53
+ @configuration ||= DEFAULTS.dup
54
+ end
55
+
56
+ end
57
+
58
+ end
59
+
60
+ end
@@ -7,7 +7,7 @@ module Mocha # :nodoc:
7
7
  end
8
8
 
9
9
  def evaluate
10
- raise @exception, @exception.to_s if @exception == Interrupt
10
+ raise @exception, @exception.to_s if @exception.is_a?(Module) && @exception.ancestors.include?(Interrupt)
11
11
  raise @exception, @message if @message
12
12
  raise @exception
13
13
  end
@@ -1,4 +1,3 @@
1
- require 'mocha/infinite_range'
2
1
  require 'mocha/method_matcher'
3
2
  require 'mocha/parameters_matcher'
4
3
  require 'mocha/expectation_error'
@@ -6,6 +5,9 @@ require 'mocha/return_values'
6
5
  require 'mocha/exception_raiser'
7
6
  require 'mocha/yield_parameters'
8
7
  require 'mocha/is_a'
8
+ require 'mocha/in_state_ordering_constraint'
9
+ require 'mocha/change_state_side_effect'
10
+ require 'mocha/cardinality'
9
11
 
10
12
  module Mocha # :nodoc:
11
13
 
@@ -37,7 +39,7 @@ module Mocha # :nodoc:
37
39
  # object.expected_method
38
40
  # # => verify fails
39
41
  def times(range)
40
- @expected_count = range
42
+ @cardinality = Cardinality.times(range)
41
43
  self
42
44
  end
43
45
 
@@ -59,8 +61,8 @@ module Mocha # :nodoc:
59
61
  # object = mock()
60
62
  # object.expects(:expected_method).once
61
63
  # # => verify fails
62
- def once()
63
- times(1)
64
+ def once
65
+ @cardinality = Cardinality.exactly(1)
64
66
  self
65
67
  end
66
68
 
@@ -77,7 +79,7 @@ module Mocha # :nodoc:
77
79
  # object.expected_method
78
80
  # # => verify succeeds
79
81
  def never
80
- times(0)
82
+ @cardinality = Cardinality.exactly(0)
81
83
  self
82
84
  end
83
85
 
@@ -94,7 +96,7 @@ module Mocha # :nodoc:
94
96
  # object.expected_method
95
97
  # # => verify fails
96
98
  def at_least(minimum_number_of_times)
97
- times(Range.at_least(minimum_number_of_times))
99
+ @cardinality = Cardinality.at_least(minimum_number_of_times)
98
100
  self
99
101
  end
100
102
 
@@ -109,7 +111,7 @@ module Mocha # :nodoc:
109
111
  # object = mock()
110
112
  # object.expects(:expected_method).at_least_once
111
113
  # # => verify fails
112
- def at_least_once()
114
+ def at_least_once
113
115
  at_least(1)
114
116
  self
115
117
  end
@@ -127,7 +129,7 @@ module Mocha # :nodoc:
127
129
  # 3.times { object.expected_method }
128
130
  # # => verify fails
129
131
  def at_most(maximum_number_of_times)
130
- times(Range.at_most(maximum_number_of_times))
132
+ @cardinality = Cardinality.at_most(maximum_number_of_times)
131
133
  self
132
134
  end
133
135
 
@@ -247,16 +249,6 @@ module Mocha # :nodoc:
247
249
  # object.expected_method # => 1
248
250
  # object.expected_method # => 2
249
251
  # object.expected_method # => raises exception of class Exception1
250
- # If +value+ is a +Proc+, then the expected method will return the result of calling <tt>Proc#call</tt>.
251
- #
252
- # This usage is _deprecated_.
253
- # Use explicit multiple return values and/or multiple expectations instead.
254
- #
255
- # A +Proc+ instance will be treated the same as any other value in a future release.
256
- # object = mock()
257
- # object.stubs(:stubbed_method).returns(lambda { rand(100) })
258
- # object.stubbed_method # => 41
259
- # object.stubbed_method # => 77
260
252
  def returns(*values)
261
253
  @return_values += ReturnValues.build(*values)
262
254
  self
@@ -285,25 +277,79 @@ module Mocha # :nodoc:
285
277
  end
286
278
 
287
279
  # :call-seq: then() -> expectation
280
+ # then(state_machine.is(state)) -> expectation
288
281
  #
289
- # Syntactic sugar to improve readability. Has no effect on state of the expectation.
282
+ # <tt>then()</tt> is used as syntactic sugar to improve readability. It has no effect on state of the expectation.
290
283
  # object = mock()
291
284
  # object.stubs(:expected_method).returns(1, 2).then.raises(Exception).then.returns(4)
292
285
  # object.expected_method # => 1
293
286
  # object.expected_method # => 2
294
287
  # object.expected_method # => raises exception of class Exception
295
288
  # object.expected_method # => 4
296
- def then
289
+ #
290
+ # <tt>then(state_machine.is(state))</tt> is used to change the +state_machine+ to the specified +state+ when the invocation occurs.
291
+ #
292
+ # See also Standalone#states, StateMachine and Expectation#when.
293
+ # power = states('power').starts_as('off')
294
+ #
295
+ # radio = mock('radio')
296
+ # radio.expects(:switch_on).then(power.is('on'))
297
+ # radio.expects(:select_channel).with('BBC Radio 4').when(power.is('on'))
298
+ # radio.expects(:adjust_volume).with(+5).when(power.is('on'))
299
+ # radio.expects(:select_channel).with('BBC World Service').when(power.is('on'))
300
+ # radio.expects(:adjust_volume).with(-5).when(power.is('on'))
301
+ # radio.expects(:switch_off).then(power.is('off'))
302
+ def then(*parameters)
303
+ if parameters.length == 1
304
+ state = parameters.first
305
+ add_side_effect(ChangeStateSideEffect.new(state))
306
+ end
297
307
  self
298
308
  end
299
309
 
300
- # :stopdoc:
310
+ # :call-seq: when(state_machine.is(state)) -> exception
311
+ #
312
+ # Constrains the expectation to occur only when the +state_machine+ is in the named +state+.
313
+ #
314
+ # See also Standalone#states, StateMachine#starts_as and Expectation#then.
315
+ # power = states('power').starts_as('off')
316
+ #
317
+ # radio = mock('radio')
318
+ # radio.expects(:switch_on).then(power.is('on'))
319
+ # radio.expects(:select_channel).with('BBC Radio 4').when(power.is('on'))
320
+ # radio.expects(:adjust_volume).with(+5).when(power.is('on'))
321
+ # radio.expects(:select_channel).with('BBC World Service').when(power.is('on'))
322
+ # radio.expects(:adjust_volume).with(-5).when(power.is('on'))
323
+ # radio.expects(:switch_off).then(power.is('off'))
324
+ def when(state_predicate)
325
+ add_ordering_constraint(InStateOrderingConstraint.new(state_predicate))
326
+ self
327
+ end
301
328
 
329
+ # :call-seq: in_sequence(*sequences) -> expectation
330
+ #
331
+ # Constrains this expectation so that it must be invoked at the current point in the sequence.
332
+ #
333
+ # To expect a sequence of invocations, write the expectations in order and add the in_sequence(sequence) clause to each one.
334
+ #
335
+ # Expectations in a sequence can have any invocation count.
336
+ #
337
+ # If an expectation in a sequence is stubbed, rather than expected, it can be skipped in the sequence.
338
+ #
339
+ # See also Standalone#sequence.
340
+ # breakfast = sequence('breakfast')
341
+ #
342
+ # egg = mock('egg')
343
+ # egg.expects(:crack).in_sequence(breakfast)
344
+ # egg.expects(:fry).in_sequence(breakfast)
345
+ # egg.expects(:eat).in_sequence(breakfast)
302
346
  def in_sequence(*sequences)
303
- sequences.each { |sequence| sequence.constrain_as_next_in_sequence(self) }
347
+ sequences.each { |sequence| add_in_sequence_ordering_constraint(sequence) }
304
348
  self
305
349
  end
306
350
 
351
+ # :stopdoc:
352
+
307
353
  attr_reader :backtrace
308
354
 
309
355
  def initialize(mock, expected_method_name, backtrace = nil)
@@ -311,7 +357,8 @@ module Mocha # :nodoc:
311
357
  @method_matcher = MethodMatcher.new(expected_method_name)
312
358
  @parameters_matcher = ParametersMatcher.new
313
359
  @ordering_constraints = []
314
- @expected_count, @invoked_count = 1, 0
360
+ @side_effects = []
361
+ @cardinality, @invocation_count = Cardinality.exactly(1), 0
315
362
  @return_values = ReturnValues.new
316
363
  @yield_parameters = YieldParameters.new
317
364
  @backtrace = backtrace || caller
@@ -321,6 +368,18 @@ module Mocha # :nodoc:
321
368
  @ordering_constraints << ordering_constraint
322
369
  end
323
370
 
371
+ def add_in_sequence_ordering_constraint(sequence)
372
+ sequence.constrain_as_next_in_sequence(self)
373
+ end
374
+
375
+ def add_side_effect(side_effect)
376
+ @side_effects << side_effect
377
+ end
378
+
379
+ def perform_side_effects
380
+ @side_effects.each { |side_effect| side_effect.perform }
381
+ end
382
+
324
383
  def in_correct_order?
325
384
  @ordering_constraints.all? { |ordering_constraint| ordering_constraint.allows_invocation_now? }
326
385
  end
@@ -334,23 +393,16 @@ module Mocha # :nodoc:
334
393
  end
335
394
 
336
395
  def invocations_allowed?
337
- if @expected_count.is_a?(Range) then
338
- @invoked_count < @expected_count.last
339
- else
340
- @invoked_count < @expected_count
341
- end
396
+ @cardinality.invocations_allowed?(@invocation_count)
342
397
  end
343
398
 
344
399
  def satisfied?
345
- if @expected_count.is_a?(Range) then
346
- @invoked_count >= @expected_count.first
347
- else
348
- @invoked_count >= @expected_count
349
- end
400
+ @cardinality.satisfied?(@invocation_count)
350
401
  end
351
402
 
352
403
  def invoke
353
- @invoked_count += 1
404
+ @invocation_count += 1
405
+ perform_side_effects()
354
406
  if block_given? then
355
407
  @yield_parameters.next_invocation.each do |yield_parameters|
356
408
  yield(*yield_parameters)
@@ -359,26 +411,35 @@ module Mocha # :nodoc:
359
411
  @return_values.next
360
412
  end
361
413
 
362
- def verify
363
- yield(self) if block_given?
364
- unless (@expected_count === @invoked_count) then
365
- error = ExpectationError.new(error_message(@expected_count, @invoked_count), backtrace)
366
- raise error
367
- end
414
+ def verified?(assertion_counter = nil)
415
+ assertion_counter.increment if assertion_counter && @cardinality.needs_verifying?
416
+ @cardinality.verified?(@invocation_count)
368
417
  end
369
418
 
370
- def method_signature
371
- signature = "#{@mock.mocha_inspect}.#{@method_matcher.mocha_inspect}#{@parameters_matcher.mocha_inspect}"
372
- signature << "; #{@ordering_constraints.map { |oc| oc.mocha_inspect }.join("; ")}" unless @ordering_constraints.empty?
373
- signature
419
+ def used?
420
+ @cardinality.used?(@invocation_count)
374
421
  end
375
422
 
376
- def error_message(expected_count, actual_count)
377
- "#{method_signature} - expected calls: #{expected_count.mocha_inspect}, actual calls: #{actual_count}"
423
+ def mocha_inspect
424
+ message = "#{@cardinality.mocha_inspect}, "
425
+ if @invocation_count > 0
426
+ message << "already invoked #{@invocation_count} time"
427
+ message << "s" if @invocation_count > 1
428
+ else
429
+ message << "never invoked"
430
+ end
431
+ message << ": "
432
+ message << method_signature
433
+ message << "; #{@ordering_constraints.map { |oc| oc.mocha_inspect }.join("; ")}" unless @ordering_constraints.empty?
434
+ message
378
435
  end
379
-
436
+
437
+ def method_signature
438
+ "#{@mock.mocha_inspect}.#{@method_matcher.mocha_inspect}#{@parameters_matcher.mocha_inspect}"
439
+ end
440
+
380
441
  # :startdoc:
381
442
 
382
443
  end
383
444
 
384
- end
445
+ end
@@ -1,15 +1,15 @@
1
+ require 'mocha/backtrace_filter'
2
+
1
3
  module Mocha
2
4
 
3
5
  class ExpectationError < StandardError
4
6
 
5
- LIB_DIRECTORY = File.expand_path(File.join(File.dirname(__FILE__), "..")) + File::SEPARATOR
6
-
7
- def initialize(message = nil, backtrace = [], lib_directory = LIB_DIRECTORY)
7
+ def initialize(message = nil, backtrace = [])
8
8
  super(message)
9
- filtered_backtrace = backtrace.reject { |location| Regexp.new(lib_directory).match(File.expand_path(location)) }
10
- set_backtrace(filtered_backtrace)
9
+ filter = BacktraceFilter.new
10
+ set_backtrace(filter.filtered(backtrace))
11
11
  end
12
12
 
13
13
  end
14
14
 
15
- end
15
+ end
@@ -5,42 +5,38 @@ module Mocha # :nodoc:
5
5
  def initialize
6
6
  @expectations = []
7
7
  end
8
-
8
+
9
9
  def add(expectation)
10
10
  @expectations << expectation
11
11
  expectation
12
12
  end
13
-
13
+
14
14
  def matches_method?(method_name)
15
15
  @expectations.any? { |expectation| expectation.matches_method?(method_name) }
16
16
  end
17
-
18
- def similar(method_name)
19
- @expectations.select { |expectation| expectation.matches_method?(method_name) }
20
- end
21
-
17
+
22
18
  def detect(method_name, *arguments)
23
19
  expectations = @expectations.reverse.select { |e| e.match?(method_name, *arguments) }
24
20
  expectation = expectations.detect { |e| e.invocations_allowed? }
25
21
  expectation || expectations.first
26
22
  end
27
-
28
- def verify(&block)
29
- @expectations.each { |expectation| expectation.verify(&block) }
23
+
24
+ def verified?(assertion_counter = nil)
25
+ @expectations.all? { |expectation| expectation.verified?(assertion_counter) }
30
26
  end
31
-
27
+
32
28
  def to_a
33
29
  @expectations
34
30
  end
35
-
31
+
36
32
  def to_set
37
33
  @expectations.to_set
38
34
  end
39
-
35
+
40
36
  def length
41
37
  @expectations.length
42
38
  end
43
-
39
+
44
40
  end
45
41
 
46
42
  end
@@ -0,0 +1,19 @@
1
+ module Mocha
2
+
3
+ class InStateOrderingConstraint
4
+
5
+ def initialize(state_predicate)
6
+ @state_predicate = state_predicate
7
+ end
8
+
9
+ def allows_invocation_now?
10
+ @state_predicate.active?
11
+ end
12
+
13
+ def mocha_inspect
14
+ "when #{@state_predicate.mocha_inspect}"
15
+ end
16
+
17
+ end
18
+
19
+ end
@@ -3,6 +3,15 @@ require 'mocha/class_method'
3
3
  module Mocha
4
4
 
5
5
  class InstanceMethod < ClassMethod
6
+
7
+ def method_exists?(method)
8
+ existing_methods = []
9
+ existing_methods += stubbee.public_methods(false)
10
+ existing_methods += stubbee.protected_methods(false)
11
+ existing_methods += stubbee.private_methods(false)
12
+ existing_methods.any? { |m| m.to_s == method.to_s }
13
+ end
14
+
6
15
  end
7
16
 
8
17
  end