redinger-rr 0.10.3

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 (133) hide show
  1. data/CHANGES +221 -0
  2. data/README.rdoc +343 -0
  3. data/Rakefile +88 -0
  4. data/VERSION.yml +4 -0
  5. data/lib/rr.rb +88 -0
  6. data/lib/rr/adapters/rr_methods.rb +122 -0
  7. data/lib/rr/adapters/rspec.rb +59 -0
  8. data/lib/rr/adapters/test_unit.rb +29 -0
  9. data/lib/rr/double.rb +152 -0
  10. data/lib/rr/double_definitions/child_double_definition_creator.rb +27 -0
  11. data/lib/rr/double_definitions/double_definition.rb +348 -0
  12. data/lib/rr/double_definitions/double_definition_creator.rb +167 -0
  13. data/lib/rr/double_definitions/double_definition_creator_proxy.rb +37 -0
  14. data/lib/rr/double_definitions/strategies/implementation/implementation_strategy.rb +15 -0
  15. data/lib/rr/double_definitions/strategies/implementation/proxy.rb +62 -0
  16. data/lib/rr/double_definitions/strategies/implementation/reimplementation.rb +14 -0
  17. data/lib/rr/double_definitions/strategies/implementation/strongly_typed_reimplementation.rb +17 -0
  18. data/lib/rr/double_definitions/strategies/scope/instance.rb +15 -0
  19. data/lib/rr/double_definitions/strategies/scope/instance_of_class.rb +50 -0
  20. data/lib/rr/double_definitions/strategies/scope/scope_strategy.rb +15 -0
  21. data/lib/rr/double_definitions/strategies/strategy.rb +70 -0
  22. data/lib/rr/double_definitions/strategies/verification/dont_allow.rb +34 -0
  23. data/lib/rr/double_definitions/strategies/verification/mock.rb +44 -0
  24. data/lib/rr/double_definitions/strategies/verification/stub.rb +45 -0
  25. data/lib/rr/double_definitions/strategies/verification/verification_strategy.rb +15 -0
  26. data/lib/rr/double_injection.rb +180 -0
  27. data/lib/rr/double_matches.rb +51 -0
  28. data/lib/rr/errors/argument_equality_error.rb +6 -0
  29. data/lib/rr/errors/double_definition_error.rb +6 -0
  30. data/lib/rr/errors/double_not_found_error.rb +6 -0
  31. data/lib/rr/errors/double_order_error.rb +6 -0
  32. data/lib/rr/errors/rr_error.rb +20 -0
  33. data/lib/rr/errors/spy_verification_errors/double_injection_not_found_error.rb +8 -0
  34. data/lib/rr/errors/spy_verification_errors/invocation_count_error.rb +8 -0
  35. data/lib/rr/errors/spy_verification_errors/spy_verification_error.rb +8 -0
  36. data/lib/rr/errors/subject_does_not_implement_method_error.rb +6 -0
  37. data/lib/rr/errors/subject_has_different_arity_error.rb +6 -0
  38. data/lib/rr/errors/times_called_error.rb +6 -0
  39. data/lib/rr/expectations/any_argument_expectation.rb +21 -0
  40. data/lib/rr/expectations/argument_equality_expectation.rb +41 -0
  41. data/lib/rr/expectations/times_called_expectation.rb +57 -0
  42. data/lib/rr/hash_with_object_id_key.rb +44 -0
  43. data/lib/rr/method_dispatches/base_method_dispatch.rb +108 -0
  44. data/lib/rr/method_dispatches/method_dispatch.rb +61 -0
  45. data/lib/rr/method_dispatches/method_missing_dispatch.rb +49 -0
  46. data/lib/rr/proc_from_block.rb +7 -0
  47. data/lib/rr/recorded_calls.rb +103 -0
  48. data/lib/rr/space.rb +123 -0
  49. data/lib/rr/spy_verification.rb +48 -0
  50. data/lib/rr/spy_verification_proxy.rb +18 -0
  51. data/lib/rr/times_called_matchers/any_times_matcher.rb +18 -0
  52. data/lib/rr/times_called_matchers/at_least_matcher.rb +15 -0
  53. data/lib/rr/times_called_matchers/at_most_matcher.rb +23 -0
  54. data/lib/rr/times_called_matchers/integer_matcher.rb +19 -0
  55. data/lib/rr/times_called_matchers/non_terminal.rb +27 -0
  56. data/lib/rr/times_called_matchers/proc_matcher.rb +11 -0
  57. data/lib/rr/times_called_matchers/range_matcher.rb +21 -0
  58. data/lib/rr/times_called_matchers/terminal.rb +20 -0
  59. data/lib/rr/times_called_matchers/times_called_matcher.rb +44 -0
  60. data/lib/rr/wildcard_matchers.rb +158 -0
  61. data/lib/rr/wildcard_matchers/anything.rb +18 -0
  62. data/lib/rr/wildcard_matchers/boolean.rb +23 -0
  63. data/lib/rr/wildcard_matchers/duck_type.rb +32 -0
  64. data/lib/rr/wildcard_matchers/hash_including.rb +29 -0
  65. data/lib/rr/wildcard_matchers/is_a.rb +25 -0
  66. data/lib/rr/wildcard_matchers/numeric.rb +13 -0
  67. data/lib/rr/wildcard_matchers/range.rb +7 -0
  68. data/lib/rr/wildcard_matchers/regexp.rb +7 -0
  69. data/lib/rr/wildcard_matchers/satisfy.rb +26 -0
  70. data/spec/core_spec_suite.rb +19 -0
  71. data/spec/environment_fixture_setup.rb +7 -0
  72. data/spec/high_level_spec.rb +398 -0
  73. data/spec/proc_from_block_spec.rb +14 -0
  74. data/spec/rr/adapters/rr_methods_argument_matcher_spec.rb +67 -0
  75. data/spec/rr/adapters/rr_methods_creator_spec.rb +149 -0
  76. data/spec/rr/adapters/rr_methods_space_spec.rb +115 -0
  77. data/spec/rr/adapters/rr_methods_spec_helper.rb +11 -0
  78. data/spec/rr/adapters/rr_methods_times_matcher_spec.rb +17 -0
  79. data/spec/rr/double_definitions/child_double_definition_creator_spec.rb +112 -0
  80. data/spec/rr/double_definitions/double_definition_creator_proxy_spec.rb +155 -0
  81. data/spec/rr/double_definitions/double_definition_creator_spec.rb +502 -0
  82. data/spec/rr/double_definitions/double_definition_spec.rb +1165 -0
  83. data/spec/rr/double_injection/double_injection_spec.rb +339 -0
  84. data/spec/rr/double_injection/double_injection_verify_spec.rb +29 -0
  85. data/spec/rr/double_spec.rb +352 -0
  86. data/spec/rr/errors/rr_error_spec.rb +67 -0
  87. data/spec/rr/expectations/any_argument_expectation_spec.rb +47 -0
  88. data/spec/rr/expectations/anything_argument_equality_expectation_spec.rb +14 -0
  89. data/spec/rr/expectations/argument_equality_expectation_spec.rb +135 -0
  90. data/spec/rr/expectations/boolean_argument_equality_expectation_spec.rb +34 -0
  91. data/spec/rr/expectations/hash_including_argument_equality_expectation_spec.rb +82 -0
  92. data/spec/rr/expectations/hash_including_spec.rb +17 -0
  93. data/spec/rr/expectations/satisfy_argument_equality_expectation_spec.rb +59 -0
  94. data/spec/rr/expectations/satisfy_spec.rb +14 -0
  95. data/spec/rr/expectations/times_called_expectation/times_called_expectation_any_times_spec.rb +46 -0
  96. data/spec/rr/expectations/times_called_expectation/times_called_expectation_at_least_spec.rb +69 -0
  97. data/spec/rr/expectations/times_called_expectation/times_called_expectation_at_most_spec.rb +71 -0
  98. data/spec/rr/expectations/times_called_expectation/times_called_expectation_helper.rb +23 -0
  99. data/spec/rr/expectations/times_called_expectation/times_called_expectation_integer_spec.rb +104 -0
  100. data/spec/rr/expectations/times_called_expectation/times_called_expectation_proc_spec.rb +81 -0
  101. data/spec/rr/expectations/times_called_expectation/times_called_expectation_range_spec.rb +83 -0
  102. data/spec/rr/expectations/times_called_expectation/times_called_expectation_spec.rb +38 -0
  103. data/spec/rr/rspec/invocation_matcher_spec.rb +279 -0
  104. data/spec/rr/rspec/rspec_adapter_spec.rb +66 -0
  105. data/spec/rr/rspec/rspec_backtrace_tweaking_spec.rb +31 -0
  106. data/spec/rr/rspec/rspec_backtrace_tweaking_spec_fixture.rb +11 -0
  107. data/spec/rr/rspec/rspec_usage_spec.rb +86 -0
  108. data/spec/rr/space/hash_with_object_id_key_spec.rb +88 -0
  109. data/spec/rr/space/space_spec.rb +550 -0
  110. data/spec/rr/test_unit/test_helper.rb +7 -0
  111. data/spec/rr/test_unit/test_unit_backtrace_test.rb +36 -0
  112. data/spec/rr/test_unit/test_unit_integration_test.rb +57 -0
  113. data/spec/rr/times_called_matchers/any_times_matcher_spec.rb +47 -0
  114. data/spec/rr/times_called_matchers/at_least_matcher_spec.rb +55 -0
  115. data/spec/rr/times_called_matchers/at_most_matcher_spec.rb +70 -0
  116. data/spec/rr/times_called_matchers/integer_matcher_spec.rb +70 -0
  117. data/spec/rr/times_called_matchers/proc_matcher_spec.rb +55 -0
  118. data/spec/rr/times_called_matchers/range_matcher_spec.rb +76 -0
  119. data/spec/rr/times_called_matchers/times_called_matcher_spec.rb +118 -0
  120. data/spec/rr/wildcard_matchers/anything_spec.rb +24 -0
  121. data/spec/rr/wildcard_matchers/boolean_spec.rb +36 -0
  122. data/spec/rr/wildcard_matchers/duck_type_spec.rb +52 -0
  123. data/spec/rr/wildcard_matchers/is_a_spec.rb +32 -0
  124. data/spec/rr/wildcard_matchers/numeric_spec.rb +32 -0
  125. data/spec/rr/wildcard_matchers/range_spec.rb +35 -0
  126. data/spec/rr/wildcard_matchers/regexp_spec.rb +43 -0
  127. data/spec/rr_spec.rb +28 -0
  128. data/spec/rspec_spec_suite.rb +17 -0
  129. data/spec/spec_helper.rb +109 -0
  130. data/spec/spec_suite.rb +31 -0
  131. data/spec/spy_verification_spec.rb +129 -0
  132. data/spec/test_unit_spec_suite.rb +21 -0
  133. metadata +193 -0
@@ -0,0 +1,44 @@
1
+ module RR
2
+ # TODO: Refactor to a side-effect-free strategy.
3
+ class HashWithObjectIdKey < ::Hash #:nodoc:
4
+ def initialize
5
+ @keys = {}
6
+ super do |hash, subject_object|
7
+ hash.set_with_object_id(subject_object, {})
8
+ end
9
+ end
10
+
11
+ alias_method :get_with_object_id, :[]
12
+
13
+ def [](key)
14
+ @keys[key.__id__] = key
15
+ super(key.__id__)
16
+ end
17
+
18
+ alias_method :set_with_object_id, :[]=
19
+
20
+ def []=(key, value)
21
+ @keys[key.__id__] = key
22
+ super(key.__id__, value)
23
+ end
24
+
25
+ def each
26
+ super do |object_id, value|
27
+ yield @keys[object_id], value
28
+ end
29
+ end
30
+
31
+ def delete(key)
32
+ @keys.delete(key.__id__)
33
+ super(key.__id__)
34
+ end
35
+
36
+ def keys
37
+ @keys.values
38
+ end
39
+
40
+ def include?(key)
41
+ super(key.__id__)
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,108 @@
1
+ module RR
2
+ module MethodDispatches
3
+ class BaseMethodDispatch
4
+ include Space::Reader
5
+
6
+ attr_reader :double_injection, :args, :block, :double
7
+
8
+ def call
9
+ raise NotImplementedError
10
+ end
11
+
12
+ protected
13
+ def find_double_to_attempt
14
+ matches = DoubleMatches.new(doubles).find_all_matches(args)
15
+
16
+ unless matches.exact_terminal_doubles_to_attempt.empty?
17
+ return matches.exact_terminal_doubles_to_attempt.first
18
+ end
19
+
20
+ unless matches.exact_non_terminal_doubles_to_attempt.empty?
21
+ return matches.exact_non_terminal_doubles_to_attempt.last
22
+ end
23
+
24
+ unless matches.wildcard_terminal_doubles_to_attempt.empty?
25
+ return matches.wildcard_terminal_doubles_to_attempt.first
26
+ end
27
+
28
+ unless matches.wildcard_non_terminal_doubles_to_attempt.empty?
29
+ return matches.wildcard_non_terminal_doubles_to_attempt.last
30
+ end
31
+
32
+ unless matches.matching_doubles.empty?
33
+ return matches.matching_doubles.first # This will raise a TimesCalledError
34
+ end
35
+
36
+ return nil
37
+ end
38
+
39
+ def call_yields
40
+ if definition.yields_value
41
+ if block
42
+ block.call(*definition.yields_value)
43
+ else
44
+ raise ArgumentError, "A Block must be passed into the method call when using yields"
45
+ end
46
+ end
47
+ end
48
+
49
+ def call_implementation
50
+ if implementation_is_original_method?
51
+ call_original_method
52
+ else
53
+ if implementation
54
+ if implementation.is_a?(Method)
55
+ implementation.call(*args, &block)
56
+ else
57
+ call_args = block ? args + [ProcFromBlock.new(&block)] : args
58
+ implementation.call(*call_args)
59
+ end
60
+ else
61
+ nil
62
+ end
63
+ end
64
+ end
65
+
66
+ def call_original_method_missing
67
+ subject.__send__(original_method_missing_alias_name, method_name, *args, &block)
68
+ end
69
+
70
+ def implementation_is_original_method?
71
+ double.implementation_is_original_method?
72
+ end
73
+
74
+ def extract_subject_from_return_value(return_value)
75
+ case return_value
76
+ when DoubleDefinitions::DoubleDefinition
77
+ return_value.root_subject
78
+ when DoubleDefinitions::DoubleDefinitionCreatorProxy
79
+ return_value.__creator__.root_subject
80
+ else
81
+ return_value
82
+ end
83
+ end
84
+
85
+ def double_not_found_error
86
+ message =
87
+ "On subject #{subject},\n" <<
88
+ "unexpected method invocation:\n" <<
89
+ " #{Double.formatted_name(method_name, args)}\n" <<
90
+ "expected invocations:\n" <<
91
+ Double.list_message_part(doubles)
92
+ raise Errors::DoubleNotFoundError, message
93
+ end
94
+
95
+ def after_call_proc
96
+ definition.after_call_proc
97
+ end
98
+
99
+ def definition
100
+ double.definition
101
+ end
102
+
103
+ def doubles
104
+ double_injection.doubles
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,61 @@
1
+ module RR
2
+ module MethodDispatches
3
+ class MethodDispatch < BaseMethodDispatch
4
+ def initialize(double_injection, args, block)
5
+ @double_injection, @args, @block = double_injection, args, block
6
+ @double = find_double_to_attempt
7
+ end
8
+
9
+ def call
10
+ space.record_call(subject, method_name, args, block)
11
+ if double
12
+ double.method_call(args)
13
+ call_yields
14
+ return_value = extract_subject_from_return_value(call_implementation)
15
+ if after_call_proc
16
+ extract_subject_from_return_value(after_call_proc.call(return_value))
17
+ else
18
+ return_value
19
+ end
20
+ else
21
+ double_not_found_error
22
+ end
23
+ end
24
+
25
+ def call_original_method
26
+ if subject_has_original_method?
27
+ subject.__send__(original_method_alias_name, *args, &block)
28
+ elsif subject_has_original_method_missing?
29
+ call_original_method_missing
30
+ else
31
+ subject.__send__(:method_missing, method_name, *args, &block)
32
+ end
33
+ end
34
+
35
+ protected
36
+ def implementation
37
+ definition.implementation
38
+ end
39
+
40
+ def subject_has_original_method?
41
+ double_injection.subject_has_original_method?
42
+ end
43
+
44
+ def subject_has_original_method_missing?
45
+ double_injection.subject_has_original_method_missing?
46
+ end
47
+
48
+ def subject
49
+ double_injection.subject
50
+ end
51
+
52
+ def method_name
53
+ double_injection.method_name
54
+ end
55
+
56
+ def original_method_alias_name
57
+ double_injection.original_method_alias_name
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,49 @@
1
+ module RR
2
+ module MethodDispatches
3
+ class MethodMissingDispatch < BaseMethodDispatch
4
+ attr_reader :method_name
5
+ def initialize(double_injection, method_name, args, block)
6
+ @double_injection, @args, @block = double_injection, args, block
7
+ @method_name = method_name
8
+ end
9
+
10
+ def call
11
+ if double_injection.method_name == method_name
12
+ space.record_call(subject, method_name, args, block)
13
+ @double = find_double_to_attempt
14
+
15
+ if double
16
+ double.method_call(args)
17
+ call_yields
18
+ return_value = extract_subject_from_return_value(call_implementation)
19
+ if after_call_proc
20
+ extract_subject_from_return_value(after_call_proc.call(return_value))
21
+ else
22
+ return_value
23
+ end
24
+ else
25
+ double_not_found_error
26
+ end
27
+ else
28
+ call_original_method
29
+ end
30
+ end
31
+
32
+ def call_original_method
33
+ double_injection.bypass_bound_method do
34
+ call_original_method_missing
35
+ end
36
+ end
37
+
38
+ protected
39
+
40
+ def original_method_missing_alias_name
41
+ double_injection.original_method_missing_alias_name
42
+ end
43
+
44
+ def subject
45
+ double_injection.subject
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,7 @@
1
+ module RR
2
+ class ProcFromBlock < Proc
3
+ def ==(other)
4
+ Proc.new(&self) == other
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,103 @@
1
+ module RR
2
+ class RecordedCalls
3
+ include RR::Space::Reader
4
+
5
+ def initialize(recorded_calls=[])
6
+ @recorded_calls = recorded_calls
7
+ @ordered_index = 0
8
+ end
9
+
10
+ attr_reader :recorded_calls
11
+
12
+ def clear
13
+ self.ordered_index = 0
14
+ recorded_calls.clear
15
+ end
16
+
17
+ def <<(recorded_call)
18
+ recorded_calls << recorded_call
19
+ end
20
+
21
+ def any?(&block)
22
+ recorded_calls.any?(&block)
23
+ end
24
+
25
+ def ==(other)
26
+ recorded_calls == other.recorded_calls
27
+ end
28
+
29
+ def match_error(spy_verification)
30
+ double_injection_exists_error(spy_verification) || begin
31
+ if spy_verification.ordered?
32
+ ordered_match_error(spy_verification)
33
+ else
34
+ unordered_match_error(spy_verification)
35
+ end
36
+ end
37
+ end
38
+
39
+ protected
40
+ attr_accessor :ordered_index
41
+
42
+ def double_injection_exists_error(spy_verification)
43
+ unless space.double_injection_exists?(spy_verification.subject, spy_verification.method_name)
44
+ RR::Errors::SpyVerificationErrors::DoubleInjectionNotFoundError.new(
45
+ "A Double Injection for the subject and method call:\n" <<
46
+ "#{spy_verification.subject.inspect}\n" <<
47
+ "#{spy_verification.method_name}\ndoes not exist in:\n" <<
48
+ "\t#{recorded_calls.map {|call| call.inspect}.join("\n\t")}"
49
+ )
50
+ end
51
+ end
52
+
53
+ def ordered_match_error(spy_verification)
54
+ memoized_matching_recorded_calls = matching_recorded_calls(spy_verification)
55
+
56
+ if memoized_matching_recorded_calls.last
57
+ self.ordered_index = recorded_calls.index(memoized_matching_recorded_calls.last)
58
+ end
59
+ (0..memoized_matching_recorded_calls.size).to_a.any? do |i|
60
+ spy_verification.times_matcher.matches?(i)
61
+ end ? nil : invocation_count_error(spy_verification, memoized_matching_recorded_calls)
62
+ end
63
+
64
+ def unordered_match_error(spy_verification)
65
+ memoized_matching_recorded_calls = matching_recorded_calls(spy_verification)
66
+
67
+ spy_verification.times_matcher.matches?(
68
+ memoized_matching_recorded_calls.size
69
+ ) ? nil : invocation_count_error(spy_verification, memoized_matching_recorded_calls)
70
+ end
71
+
72
+ def matching_recorded_calls(spy_verification)
73
+ recorded_calls[ordered_index..-1].
74
+ select(&match_double_injection(spy_verification)).
75
+ select(&match_argument_expectation(spy_verification))
76
+ end
77
+
78
+ def match_double_injection(spy_verification)
79
+ lambda do |recorded_call|
80
+ recorded_call[0] == spy_verification.subject &&
81
+ recorded_call[1] == spy_verification.method_name
82
+ end
83
+ end
84
+
85
+ def match_argument_expectation(spy_verification)
86
+ lambda do |recorded_call|
87
+ spy_verification.argument_expectation.exact_match?(*recorded_call[2]) ||
88
+ spy_verification.argument_expectation.wildcard_match?(*recorded_call[2])
89
+ end
90
+ end
91
+
92
+ def invocation_count_error(spy_verification, matching_recorded_calls)
93
+ RR::Errors::SpyVerificationErrors::InvocationCountError.new(
94
+ "On subject #{spy_verification.subject.inspect}\n" <<
95
+ "Expected #{Double.formatted_name(spy_verification.method_name, spy_verification.argument_expectation.expected_arguments)}\n" <<
96
+ "to be called #{spy_verification.times_matcher.expected_times_message},\n" <<
97
+ "but was called #{matching_recorded_calls.size} times.\n" <<
98
+ "All of the method calls related to Doubles are:\n" <<
99
+ "\t#{recorded_calls.map {|call| call.inspect}.join("\n\t")}"
100
+ )
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,123 @@
1
+ module RR
2
+ # RR::Space.instance is the global state subject for the RR framework.
3
+ class Space
4
+ module Reader
5
+ def space
6
+ RR::Space.instance
7
+ end
8
+ end
9
+
10
+ class << self
11
+ def instance
12
+ @instance ||= new
13
+ end
14
+ attr_writer :instance
15
+
16
+ protected
17
+ def method_missing(method_name, *args, &block)
18
+ instance.__send__(method_name, *args, &block)
19
+ end
20
+ end
21
+
22
+ attr_reader :double_injections, :ordered_doubles, :recorded_calls
23
+ attr_accessor :trim_backtrace
24
+ def initialize
25
+ @double_injections = HashWithObjectIdKey.new
26
+ @ordered_doubles = []
27
+ @trim_backtrace = false
28
+ @recorded_calls = RR::RecordedCalls.new
29
+ end
30
+
31
+ # Reuses or creates, if none exists, a DoubleInjection for the passed
32
+ # in subject and method_name.
33
+ # When a DoubleInjection is created, it binds the dispatcher to the
34
+ # subject.
35
+ def double_injection(subject, method_name)
36
+ @double_injections[subject][method_name.to_sym] ||= begin
37
+ DoubleInjection.new(subject, method_name.to_sym, (class << subject; self; end)).bind
38
+ end
39
+ end
40
+
41
+ def double_injection_exists?(subject, method_name)
42
+ @double_injections.include?(subject) && @double_injections[subject].include?(method_name.to_sym)
43
+ end
44
+
45
+ # Registers the ordered Double to be verified.
46
+ def register_ordered_double(double)
47
+ @ordered_doubles << double unless ordered_doubles.include?(double)
48
+ end
49
+
50
+ # Verifies that the passed in ordered Double is being called
51
+ # in the correct position.
52
+ def verify_ordered_double(double)
53
+ unless double.terminal?
54
+ raise Errors::DoubleOrderError,
55
+ "Ordered Doubles cannot have a NonTerminal TimesCalledExpectation"
56
+ end
57
+ unless @ordered_doubles.first == double
58
+ message = Double.formatted_name(double.method_name, double.expected_arguments)
59
+ message << " called out of order in list\n"
60
+ message << Double.list_message_part(@ordered_doubles)
61
+ raise Errors::DoubleOrderError, message
62
+ end
63
+ @ordered_doubles.shift unless double.attempt?
64
+ double
65
+ end
66
+
67
+ # Verifies all the DoubleInjection objects have met their
68
+ # TimesCalledExpectations.
69
+ def verify_doubles(*objects)
70
+ objects = @double_injections.keys if objects.empty?
71
+ objects.each do |subject|
72
+ @double_injections[subject].keys.each do |method_name|
73
+ verify_double(subject, method_name)
74
+ end
75
+ end
76
+ end
77
+ alias_method :verify, :verify_doubles
78
+
79
+ # Resets the registered Doubles and ordered Doubles
80
+ def reset
81
+ reset_ordered_doubles
82
+ reset_double_injections
83
+ reset_recorded_calls
84
+ end
85
+
86
+ # Verifies the DoubleInjection for the passed in subject and method_name.
87
+ def verify_double(subject, method_name)
88
+ @double_injections[subject][method_name].verify
89
+ ensure
90
+ reset_double subject, method_name
91
+ end
92
+
93
+ # Resets the DoubleInjection for the passed in subject and method_name.
94
+ def reset_double(subject, method_name)
95
+ double_injection = @double_injections[subject].delete(method_name)
96
+ @double_injections.delete(subject) if @double_injections[subject].empty?
97
+ double_injection.reset
98
+ end
99
+
100
+ def record_call(subject, method_name, arguments, block)
101
+ @recorded_calls << [subject, method_name, arguments, block]
102
+ end
103
+
104
+ protected
105
+ # Removes the ordered Doubles from the list
106
+ def reset_ordered_doubles
107
+ @ordered_doubles.clear
108
+ end
109
+
110
+ # Resets the registered Doubles for the next test run.
111
+ def reset_double_injections
112
+ @double_injections.each do |subject, method_double_map|
113
+ method_double_map.keys.each do |method_name|
114
+ reset_double(subject, method_name)
115
+ end
116
+ end
117
+ end
118
+
119
+ def reset_recorded_calls
120
+ @recorded_calls.clear
121
+ end
122
+ end
123
+ end