rr 0.3.11 → 0.4.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 (150) hide show
  1. data/CHANGES +8 -3
  2. data/README +130 -39
  3. data/Rakefile +6 -5
  4. data/lib/rr.rb +8 -8
  5. data/lib/rr/adapters/rr_methods.rb +228 -0
  6. data/lib/rr/adapters/rspec.rb +1 -1
  7. data/lib/rr/adapters/test_unit.rb +1 -1
  8. data/lib/rr/double.rb +294 -89
  9. data/lib/rr/{scenario_creator.rb → double_creator.rb} +65 -66
  10. data/lib/rr/{scenario_definition.rb → double_definition.rb} +36 -36
  11. data/lib/rr/{scenario_definition_builder.rb → double_definition_builder.rb} +3 -3
  12. data/lib/rr/double_insertion.rb +132 -0
  13. data/lib/rr/{scenario_matches.rb → double_matches.rb} +2 -2
  14. data/lib/rr/{scenario_method_proxy.rb → double_method_proxy.rb} +2 -2
  15. data/lib/rr/errors/argument_equality_error.rb +3 -3
  16. data/lib/rr/errors/rr_error.rb +13 -13
  17. data/lib/rr/errors/scenario_definition_error.rb +3 -3
  18. data/lib/rr/errors/scenario_not_found_error.rb +3 -3
  19. data/lib/rr/errors/scenario_order_error.rb +3 -3
  20. data/lib/rr/errors/times_called_error.rb +3 -3
  21. data/lib/rr/expectations/any_argument_expectation.rb +1 -1
  22. data/lib/rr/expectations/argument_equality_expectation.rb +1 -1
  23. data/lib/rr/expectations/times_called_expectation.rb +1 -1
  24. data/lib/rr/hash_with_object_id_key.rb +1 -1
  25. data/lib/rr/space.rb +40 -40
  26. data/lib/rr/times_called_matchers/any_times_matcher.rb +13 -13
  27. data/lib/rr/times_called_matchers/at_least_matcher.rb +11 -11
  28. data/lib/rr/times_called_matchers/at_most_matcher.rb +16 -16
  29. data/lib/rr/times_called_matchers/integer_matcher.rb +13 -13
  30. data/lib/rr/times_called_matchers/non_terminal.rb +21 -21
  31. data/lib/rr/times_called_matchers/proc_matcher.rb +7 -7
  32. data/lib/rr/times_called_matchers/range_matcher.rb +14 -14
  33. data/lib/rr/times_called_matchers/terminal.rb +16 -16
  34. data/lib/rr/times_called_matchers/times_called_matcher.rb +32 -32
  35. data/spec/core_spec_suite.rb +18 -0
  36. data/{examples → spec}/environment_fixture_setup.rb +0 -1
  37. data/{examples/high_level_example.rb → spec/high_level_spec.rb} +11 -11
  38. data/spec/rr/adapters/rr_methods_argument_matcher_spec.rb +67 -0
  39. data/spec/rr/adapters/rr_methods_creator_spec.rb +365 -0
  40. data/spec/rr/adapters/rr_methods_space_spec.rb +134 -0
  41. data/spec/rr/adapters/rr_methods_spec_helper.rb +11 -0
  42. data/{examples/rr/extensions/instance_methods_times_matcher_example.rb → spec/rr/adapters/rr_methods_times_matcher_spec.rb} +4 -4
  43. data/spec/rr/double/double_insertion_bind_spec.rb +78 -0
  44. data/spec/rr/double/double_insertion_dispatching_spec.rb +221 -0
  45. data/spec/rr/double/double_insertion_has_original_method_spec.rb +56 -0
  46. data/spec/rr/double/double_insertion_register_scenario_spec.rb +24 -0
  47. data/spec/rr/double/double_insertion_reset_spec.rb +89 -0
  48. data/spec/rr/double/double_insertion_spec.rb +66 -0
  49. data/spec/rr/double/double_insertion_verify_spec.rb +23 -0
  50. data/spec/rr/double_creator_spec.rb +454 -0
  51. data/{examples/rr/scenario_definition_example.rb → spec/rr/double_definition_spec.rb} +143 -143
  52. data/spec/rr/double_method_proxy_spec.rb +71 -0
  53. data/spec/rr/double_spec.rb +654 -0
  54. data/spec/rr/errors/rr_error_spec.rb +65 -0
  55. data/spec/rr/expectations/any_argument_expectation_spec.rb +47 -0
  56. data/spec/rr/expectations/anything_argument_equality_expectation_spec.rb +38 -0
  57. data/spec/rr/expectations/argument_equality_expectation_spec.rb +58 -0
  58. data/spec/rr/expectations/boolean_argument_equality_expectation_spec.rb +53 -0
  59. data/spec/rr/expectations/duck_type_argument_equality_expectation_spec.rb +71 -0
  60. data/spec/rr/expectations/is_a_argument_equality_expectation_spec.rb +51 -0
  61. data/spec/rr/expectations/numeric_argument_equality_expectation_spec.rb +47 -0
  62. data/spec/rr/expectations/range_argument_equality_expectation_spec.rb +59 -0
  63. data/spec/rr/expectations/regexp_argument_equality_expectation_spec.rb +72 -0
  64. data/spec/rr/expectations/times_called_expectation/times_called_expectation_any_times_spec.rb +43 -0
  65. data/spec/rr/expectations/times_called_expectation/times_called_expectation_at_least_spec.rb +67 -0
  66. data/spec/rr/expectations/times_called_expectation/times_called_expectation_at_most_spec.rb +71 -0
  67. data/spec/rr/expectations/times_called_expectation/times_called_expectation_helper.rb +21 -0
  68. data/spec/rr/expectations/times_called_expectation/times_called_expectation_integer_spec.rb +103 -0
  69. data/spec/rr/expectations/times_called_expectation/times_called_expectation_proc_spec.rb +79 -0
  70. data/spec/rr/expectations/times_called_expectation/times_called_expectation_range_spec.rb +81 -0
  71. data/spec/rr/expectations/times_called_expectation/times_called_expectation_spec.rb +40 -0
  72. data/spec/rr/rspec/rspec_adapter_spec.rb +65 -0
  73. data/spec/rr/rspec/rspec_backtrace_tweaking_spec.rb +52 -0
  74. data/spec/rr/rspec/rspec_usage_spec.rb +67 -0
  75. data/spec/rr/space/hash_with_object_id_key_spec.rb +88 -0
  76. data/spec/rr/space/space_create_spec.rb +278 -0
  77. data/spec/rr/space/space_helper.rb +7 -0
  78. data/spec/rr/space/space_register_spec.rb +32 -0
  79. data/spec/rr/space/space_reset_spec.rb +131 -0
  80. data/spec/rr/space/space_spec.rb +32 -0
  81. data/spec/rr/space/space_verify_spec.rb +181 -0
  82. data/{examples → spec}/rr/test_unit/test_helper.rb +1 -1
  83. data/{examples → spec}/rr/test_unit/test_unit_backtrace_test.rb +0 -0
  84. data/{examples → spec}/rr/test_unit/test_unit_integration_test.rb +4 -4
  85. data/spec/rr/times_called_matchers/any_times_matcher_spec.rb +47 -0
  86. data/spec/rr/times_called_matchers/at_least_matcher_spec.rb +55 -0
  87. data/spec/rr/times_called_matchers/at_most_matcher_spec.rb +70 -0
  88. data/spec/rr/times_called_matchers/integer_matcher_spec.rb +70 -0
  89. data/spec/rr/times_called_matchers/proc_matcher_spec.rb +55 -0
  90. data/spec/rr/times_called_matchers/range_matcher_spec.rb +76 -0
  91. data/spec/rr/times_called_matchers/times_called_matcher_spec.rb +118 -0
  92. data/spec/rspec_spec_suite.rb +16 -0
  93. data/spec/spec_helper.rb +9 -0
  94. data/{examples/example_suite.rb → spec/spec_suite.rb} +3 -3
  95. data/{examples/test_unit_example_suite.rb → spec/test_unit_spec_suite.rb} +0 -0
  96. metadata +93 -93
  97. data/examples/core_example_suite.rb +0 -31
  98. data/examples/example_helper.rb +0 -9
  99. data/examples/rr/double/double_bind_example.rb +0 -70
  100. data/examples/rr/double/double_dispatching_example.rb +0 -236
  101. data/examples/rr/double/double_example.rb +0 -66
  102. data/examples/rr/double/double_has_original_method_example.rb +0 -56
  103. data/examples/rr/double/double_register_scenario_example.rb +0 -24
  104. data/examples/rr/double/double_reset_example.rb +0 -89
  105. data/examples/rr/double/double_verify_example.rb +0 -23
  106. data/examples/rr/errors/rr_error_example.rb +0 -65
  107. data/examples/rr/expectations/any_argument_expectation_example.rb +0 -52
  108. data/examples/rr/expectations/anything_argument_equality_expectation_example.rb +0 -38
  109. data/examples/rr/expectations/argument_equality_expectation_example.rb +0 -62
  110. data/examples/rr/expectations/boolean_argument_equality_expectation_example.rb +0 -48
  111. data/examples/rr/expectations/duck_type_argument_equality_expectation_example.rb +0 -67
  112. data/examples/rr/expectations/is_a_argument_equality_expectation_example.rb +0 -50
  113. data/examples/rr/expectations/numeric_argument_equality_expectation_example.rb +0 -46
  114. data/examples/rr/expectations/range_argument_equality_expectation_example.rb +0 -59
  115. data/examples/rr/expectations/regexp_argument_equality_expectation_example.rb +0 -67
  116. data/examples/rr/expectations/times_called_expectation/times_called_expectation_any_times_example.rb +0 -50
  117. data/examples/rr/expectations/times_called_expectation/times_called_expectation_at_least_example.rb +0 -73
  118. data/examples/rr/expectations/times_called_expectation/times_called_expectation_at_most_example.rb +0 -77
  119. data/examples/rr/expectations/times_called_expectation/times_called_expectation_example.rb +0 -42
  120. data/examples/rr/expectations/times_called_expectation/times_called_expectation_helper.rb +0 -20
  121. data/examples/rr/expectations/times_called_expectation/times_called_expectation_integer_example.rb +0 -111
  122. data/examples/rr/expectations/times_called_expectation/times_called_expectation_proc_example.rb +0 -88
  123. data/examples/rr/expectations/times_called_expectation/times_called_expectation_range_example.rb +0 -90
  124. data/examples/rr/extensions/instance_methods_argument_matcher_example.rb +0 -65
  125. data/examples/rr/extensions/instance_methods_creator_example.rb +0 -363
  126. data/examples/rr/extensions/instance_methods_example_helper.rb +0 -11
  127. data/examples/rr/extensions/instance_methods_space_example.rb +0 -122
  128. data/examples/rr/rspec/rspec_adapter_example.rb +0 -63
  129. data/examples/rr/rspec/rspec_backtrace_tweaking_example.rb +0 -36
  130. data/examples/rr/rspec/rspec_usage_example.rb +0 -65
  131. data/examples/rr/scenario_creator_example.rb +0 -459
  132. data/examples/rr/scenario_example.rb +0 -701
  133. data/examples/rr/scenario_method_proxy_example.rb +0 -71
  134. data/examples/rr/space/hash_with_object_id_key_example.rb +0 -86
  135. data/examples/rr/space/space_create_example.rb +0 -278
  136. data/examples/rr/space/space_example.rb +0 -29
  137. data/examples/rr/space/space_helper.rb +0 -7
  138. data/examples/rr/space/space_register_example.rb +0 -32
  139. data/examples/rr/space/space_reset_example.rb +0 -120
  140. data/examples/rr/space/space_verify_example.rb +0 -169
  141. data/examples/rr/times_called_matchers/any_times_matcher_example.rb +0 -63
  142. data/examples/rr/times_called_matchers/at_least_matcher_example.rb +0 -70
  143. data/examples/rr/times_called_matchers/at_most_matcher_example.rb +0 -85
  144. data/examples/rr/times_called_matchers/integer_matcher_example.rb +0 -91
  145. data/examples/rr/times_called_matchers/proc_matcher_example.rb +0 -77
  146. data/examples/rr/times_called_matchers/range_matcher_example.rb +0 -97
  147. data/examples/rr/times_called_matchers/times_called_matcher_example.rb +0 -53
  148. data/examples/rspec_example_suite.rb +0 -25
  149. data/lib/rr/extensions/instance_methods.rb +0 -228
  150. data/lib/rr/scenario.rb +0 -337
@@ -8,7 +8,7 @@ module RR
8
8
  end
9
9
  end
10
10
 
11
- include RR::Extensions::InstanceMethods
11
+ include RRMethods
12
12
  def setup_mocks_for_rspec
13
13
  rr_reset
14
14
  end
@@ -1,7 +1,7 @@
1
1
  module RR
2
2
  module Adapters
3
3
  module TestUnit
4
- include RR::Extensions::InstanceMethods
4
+ include RRMethods
5
5
  def self.included(mod)
6
6
  RR::Space.trim_backtrace = true
7
7
  mod.class_eval do
@@ -1,132 +1,337 @@
1
1
  module RR
2
- # RR::Double is the binding of an object and a method.
3
- # A double has 0 to many Scenario objects. Each Scenario
4
- # has Argument Expectations and Times called Expectations.
2
+ # RR::Double is the use case for a method call.
3
+ # It has the ArgumentEqualityExpectation, TimesCalledExpectation,
4
+ # and the implementation.
5
5
  class Double
6
- MethodArguments = Struct.new(:arguments, :block)
7
- attr_reader :space, :object, :method_name, :scenarios
6
+ class << self
7
+ def formatted_name(method_name, args)
8
+ formatted_errors = args.collect {|arg| arg.inspect}.join(', ')
9
+ "#{method_name}(#{formatted_errors})"
10
+ end
8
11
 
9
- def initialize(space, object, method_name)
10
- @space = space
11
- @object = object
12
- @method_name = method_name.to_sym
13
- if object_has_method?(method_name)
14
- meta.send(:alias_method, original_method_name, method_name)
12
+ def list_message_part(scenarios)
13
+ scenarios.collect do |scenario|
14
+ "- #{formatted_name(scenario.method_name, scenario.expected_arguments)}"
15
+ end.join("\n")
15
16
  end
16
- @scenarios = []
17
17
  end
18
18
 
19
- # RR::Double#register_scenario adds the passed in Scenario
20
- # into this Double's list of Scenario objects.
21
- def register_scenario(scenario)
22
- @scenarios << scenario
19
+ attr_reader :times_called, :double_insertion, :definition
20
+
21
+ def initialize(space, double_insertion, definition)
22
+ @space = space
23
+ @double_insertion = double_insertion
24
+ @definition = definition
25
+ @times_called = 0
26
+ @times_called_expectation = Expectations::TimesCalledExpectation.new(self)
23
27
  end
24
28
 
25
- # RR::Double#bind injects a method that acts as a dispatcher
26
- # that dispatches to the matching Scenario when the method
27
- # is called.
28
- def bind
29
- define_implementation_placeholder
30
- returns_method = <<-METHOD
31
- def #{@method_name}(*args, &block)
32
- arguments = MethodArguments.new(args, block)
33
- #{placeholder_name}(arguments)
34
- end
35
- METHOD
36
- meta.class_eval(returns_method, __FILE__, __LINE__ - 5)
29
+ # Double#with sets the expectation that the Double will receive
30
+ # the passed in arguments.
31
+ #
32
+ # Passing in a block sets the return value.
33
+ #
34
+ # mock(subject).method_name.with(1, 2) {:return_value}
35
+ def with(*args, &returns)
36
+ definition.with(*args, &returns)
37
37
  end
38
38
 
39
- # RR::Double#verify verifies each Scenario
40
- # TimesCalledExpectation are met.
41
- def verify
42
- @scenarios.each do |scenario|
43
- scenario.verify
44
- end
39
+ # Double#with_any_args sets the expectation that the Double can receive
40
+ # any arguments.
41
+ #
42
+ # Passing in a block sets the return value.
43
+ #
44
+ # mock(subject).method_name.with_any_args {:return_value}
45
+ def with_any_args(&returns)
46
+ definition.with_any_args(&returns)
45
47
  end
46
48
 
47
- # RR::Double#reset removes the injected dispatcher method.
48
- # It binds the original method implementation on the object
49
- # if one exists.
50
- def reset
51
- meta.send(:remove_method, placeholder_name)
52
- if object_has_original_method?
53
- meta.send(:alias_method, @method_name, original_method_name)
54
- meta.send(:remove_method, original_method_name)
55
- else
56
- meta.send(:remove_method, @method_name)
57
- end
49
+ # Double#with_no_args sets the expectation that the Double will receive
50
+ # no arguments.
51
+ #
52
+ # Passing in a block sets the return value.
53
+ #
54
+ # mock(subject).method_name.with_no_args {:return_value}
55
+ def with_no_args(&returns)
56
+ definition.with_no_args(&returns)
58
57
  end
59
58
 
60
- def call_original_method(*args, &block)
61
- @object.__send__(original_method_name, *args, &block)
59
+ # Double#never sets the expectation that the Double will never be
60
+ # called.
61
+ #
62
+ # This method does not accept a block because it will never be called.
63
+ #
64
+ # mock(subject).method_name.never
65
+ def never
66
+ definition.never
62
67
  end
63
68
 
64
- def object_has_original_method?
65
- object_has_method?(original_method_name)
69
+ # Double#once sets the expectation that the Double will be called
70
+ # 1 time.
71
+ #
72
+ # Passing in a block sets the return value.
73
+ #
74
+ # mock(subject).method_name.once {:return_value}
75
+ def once(&returns)
76
+ definition.once(&returns)
66
77
  end
67
78
 
68
- protected
69
- def define_implementation_placeholder
70
- me = self
71
- meta.send(:define_method, placeholder_name) do |arguments|
72
- me.send(:call_method, arguments.arguments, arguments.block)
73
- end
79
+ # Double#twice sets the expectation that the Double will be called
80
+ # 2 times.
81
+ #
82
+ # Passing in a block sets the return value.
83
+ #
84
+ # mock(subject).method_name.twice {:return_value}
85
+ def twice(&returns)
86
+ definition.twice(&returns)
74
87
  end
75
88
 
76
- def call_method(args, block)
77
- if scenario = find_scenario_to_attempt(args)
78
- return scenario.call(self, *args, &block)
79
- end
80
- scenario_not_found_error(*args)
89
+ # Double#at_least sets the expectation that the Double
90
+ # will be called at least n times.
91
+ # It works by creating a TimesCalledExpectation.
92
+ #
93
+ # Passing in a block sets the return value.
94
+ #
95
+ # mock(subject).method_name.at_least(4) {:return_value}
96
+ def at_least(number, &returns)
97
+ definition.at_least(number, &returns)
81
98
  end
82
99
 
83
- def find_scenario_to_attempt(args)
84
- matches = ScenarioMatches.new(@scenarios).find_all_matches!(args)
100
+ # Double#at_most allows sets the expectation that the Double
101
+ # will be called at most n times.
102
+ # It works by creating a TimesCalledExpectation.
103
+ #
104
+ # Passing in a block sets the return value.
105
+ #
106
+ # mock(subject).method_name.at_most(4) {:return_value}
107
+ def at_most(number, &returns)
108
+ definition.at_most(number, &returns)
109
+ end
85
110
 
86
- unless matches.exact_terminal_scenarios_to_attempt.empty?
87
- return matches.exact_terminal_scenarios_to_attempt.first
88
- end
111
+ # Double#any_number_of_times sets an that the Double will be called
112
+ # any number of times. This effectively removes the times called expectation
113
+ # from the Doublen
114
+ #
115
+ # Passing in a block sets the return value.
116
+ #
117
+ # mock(subject).method_name.any_number_of_times
118
+ def any_number_of_times(&returns)
119
+ definition.any_number_of_times(&returns)
120
+ end
89
121
 
90
- unless matches.exact_non_terminal_scenarios_to_attempt.empty?
91
- return matches.exact_non_terminal_scenarios_to_attempt.last
92
- end
122
+ # Double#times creates an TimesCalledExpectation of the passed
123
+ # in number.
124
+ #
125
+ # Passing in a block sets the return value.
126
+ #
127
+ # mock(subject).method_name.times(4) {:return_value}
128
+ def times(number, &returns)
129
+ definition.times(number, &returns)
130
+ end
131
+
132
+ # Double#ordered sets the Double to have an ordered
133
+ # expectation.
134
+ #
135
+ # Passing in a block sets the return value.
136
+ #
137
+ # mock(subject).method_name.ordered {return_value}
138
+ def ordered(&returns)
139
+ definition.ordered(&returns)
140
+ end
93
141
 
94
- unless matches.wildcard_terminal_scenarios_to_attempt.empty?
95
- return matches.wildcard_terminal_scenarios_to_attempt.first
142
+ # Double#ordered? returns true when the Double is ordered.
143
+ #
144
+ # mock(subject).method_name.ordered?
145
+ def ordered?
146
+ definition.ordered?
147
+ end
148
+
149
+ # Double#yields sets the Double to invoke a passed in block when
150
+ # the Double is called.
151
+ # An Expection will be raised if no block is passed in when the
152
+ # Double is called.
153
+ #
154
+ # Passing in a block sets the return value.
155
+ #
156
+ # mock(subject).method_name.yields(yield_arg1, yield_arg2) {return_value}
157
+ # subject.method_name {|yield_arg1, yield_arg2|}
158
+ def yields(*args, &returns)
159
+ definition.yields(*args, &returns)
160
+ end
161
+
162
+ # Double#after_call creates a callback that occurs after call
163
+ # is called. The passed in block receives the return value of
164
+ # the Double being called.
165
+ # An Expection will be raised if no block is passed in.
166
+ #
167
+ # mock(subject).method_name {return_value}.after_call {|return_value|}
168
+ # subject.method_name # return_value
169
+ #
170
+ # This feature is built into proxies.
171
+ # mock.proxy(User).find('1') {|user| mock(user).valid? {false}}
172
+ def after_call(&block)
173
+ definition.after_call &block
174
+ end
175
+
176
+ # Double#returns accepts an argument value or a block.
177
+ # It will raise an ArgumentError if both are passed in.
178
+ #
179
+ # Passing in a block causes Double to return the return value of
180
+ # the passed in block.
181
+ #
182
+ # Passing in an argument causes Double to return the argument.
183
+ def returns(value=nil, &implementation)
184
+ definition.returns(value, &implementation)
185
+ end
186
+
187
+ # Double#implemented_by sets the implementation of the Double.
188
+ # This method takes a Proc or a Method. Passing in a Method allows
189
+ # the Double to accept blocks.
190
+ #
191
+ # obj = Object.new
192
+ # def obj.foobar
193
+ # yield(1)
194
+ # end
195
+ # mock(obj).method_name.implemented_by(obj.method(:foobar))
196
+ def implemented_by(implementation)
197
+ definition.implemented_by implementation
198
+ end
199
+
200
+ # Double#implemented_by_original_method sets the implementation
201
+ # of the Double to be the original method.
202
+ # This is primarily used with proxy.
203
+ #
204
+ # obj = Object.new
205
+ # def obj.foobar
206
+ # yield(1)
207
+ # end
208
+ # mock(obj).method_name.implemented_by_original_method
209
+ # obj.foobar {|arg| puts arg} # puts 1
210
+ def implemented_by_original_method
211
+ definition.implemented_by_original_method
212
+ end
213
+
214
+ # Double#call calls the Double's implementation. The return
215
+ # value of the implementation is returned.
216
+ #
217
+ # A TimesCalledError is raised when the times called
218
+ # exceeds the expected TimesCalledExpectation.
219
+ def call(double_insertion, *args, &block)
220
+ self.times_called_expectation.attempt! if definition.times_matcher
221
+ @space.verify_ordered_scenario(self) if ordered?
222
+ yields!(block)
223
+ return_value = call_implementation(double_insertion, *args, &block)
224
+ return return_value unless definition.after_call_value
225
+ definition.after_call_value.call(return_value)
226
+ end
227
+
228
+ def yields!(block)
229
+ if definition.yields_value
230
+ unless block
231
+ raise ArgumentError, "A Block must be passed into the method call when using yields"
232
+ end
233
+ block.call(*definition.yields_value)
96
234
  end
235
+ end
236
+ protected :yields!
97
237
 
98
- unless matches.wildcard_non_terminal_scenarios_to_attempt.empty?
99
- return matches.wildcard_non_terminal_scenarios_to_attempt.last
238
+ def call_implementation(double_insertion, *args, &block)
239
+ return nil unless implementation
240
+
241
+ if implementation === DoubleDefinition::ORIGINAL_METHOD
242
+ if double_insertion.object_has_original_method?
243
+ return double_insertion.call_original_method(*args, &block)
244
+ else
245
+ return double_insertion.object.__send__(
246
+ :method_missing,
247
+ method_name,
248
+ *args,
249
+ &block
250
+ )
251
+ end
100
252
  end
101
253
 
102
- unless matches.matching_scenarios.empty?
103
- # This will raise a TimesCalledError
104
- return matches.matching_scenarios.first
254
+ if implementation.is_a?(Method)
255
+ return implementation.call(*args, &block)
256
+ else
257
+ args << block if block
258
+ return implementation.call(*args)
105
259
  end
260
+ end
261
+ protected :call_implementation
262
+
263
+ # Double#exact_match? returns true when the passed in arguments
264
+ # exactly match the ArgumentEqualityExpectation arguments.
265
+ def exact_match?(*arguments)
266
+ definition.exact_match?(*arguments)
267
+ end
106
268
 
107
- return nil
269
+ # Double#wildcard_match? returns true when the passed in arguments
270
+ # wildcard match the ArgumentEqualityExpectation arguments.
271
+ def wildcard_match?(*arguments)
272
+ definition.wildcard_match?(*arguments)
108
273
  end
109
274
 
110
- def scenario_not_found_error(*args)
111
- message = "No scenario for #{Scenario.formatted_name(@method_name, args)} in\n"
112
- message << Scenario.list_message_part(@scenarios)
113
- raise Errors::ScenarioNotFoundError, message
275
+ # Double#attempt? returns true when the
276
+ # TimesCalledExpectation is satisfied.
277
+ def attempt?
278
+ return true unless definition.times_matcher
279
+ times_called_expectation.attempt?
114
280
  end
115
281
 
116
- def placeholder_name
117
- "__rr__#{@method_name}"
282
+ # Double#verify verifies the the TimesCalledExpectation
283
+ # is satisfied for this scenario. A TimesCalledError
284
+ # is raised if the TimesCalledExpectation is not met.
285
+ def verify
286
+ return true unless definition.times_matcher
287
+ times_called_expectation.verify!
288
+ true
289
+ end
290
+
291
+ def terminal?
292
+ return false unless definition.times_matcher
293
+ times_called_expectation.terminal?
294
+ end
295
+
296
+ # The method name that this Double is attatched to
297
+ def method_name
298
+ double_insertion.method_name
299
+ end
300
+
301
+ # The Arguments that this Double expects
302
+ def expected_arguments
303
+ return [] unless argument_expectation
304
+ argument_expectation.expected_arguments
118
305
  end
119
306
 
120
- def original_method_name
121
- "__rr__original_#{@method_name}"
307
+ # The TimesCalledMatcher for the TimesCalledExpectation
308
+ def times_matcher
309
+ times_called_expectation.matcher
122
310
  end
123
311
 
124
- def object_has_method?(method_name)
125
- @object.methods.include?(method_name.to_s) || @object.respond_to?(method_name)
312
+ def times_called_expectation
313
+ @times_called_expectation.matcher = definition.times_matcher
314
+ @times_called_expectation
315
+ end
316
+
317
+ def implementation
318
+ definition.implementation
319
+ end
320
+ def implementation=(value)
321
+ definition.implementation = value
322
+ end
323
+ protected :implementation=
324
+
325
+ def argument_expectation
326
+ definition.argument_expectation
327
+ end
328
+ def argument_expectation=(value)
329
+ definition.argument_expectation = value
126
330
  end
331
+ protected :argument_expectation=
127
332
 
128
- def meta
129
- (class << @object; self; end)
333
+ def formatted_name
334
+ self.class.formatted_name(method_name, expected_arguments)
130
335
  end
131
336
  end
132
- end
337
+ end
@@ -1,12 +1,11 @@
1
1
  module RR
2
- # RR::ScenarioCreator provides a strategies to create a Scenario.
2
+ # RR::DoubleCreator provides a strategies to create a Double.
3
3
  # The strategies are:
4
4
  # * mock
5
5
  # * stub
6
- # * do_not_call
7
- #
8
- # Probing can also be added.
9
- class ScenarioCreator
6
+ # * proxy
7
+ # * dont_allow
8
+ class DoubleCreator
10
9
  NO_SUBJECT_ARG = Object.new
11
10
 
12
11
  attr_reader :space
@@ -15,29 +14,29 @@ module RR
15
14
  def initialize(space)
16
15
  @space = space
17
16
  @strategy = nil
18
- @probe = false
17
+ @proxy = false
19
18
  @instance_of = nil
20
19
  @instance_of_method_name = nil
21
20
  end
22
21
 
23
- # This method sets the Scenario to have a mock strategy. A mock strategy
24
- # sets the default state of the Scenario to expect the method call
25
- # with arguments exactly one time. The Scenario's expectations can be
22
+ # This method sets the Double to have a mock strategy. A mock strategy
23
+ # sets the default state of the Double to expect the method call
24
+ # with arguments exactly one time. The Double's expectations can be
26
25
  # changed.
27
26
  #
28
- # This method can be chained with probe.
29
- # mock.probe(subject).method_name_1
27
+ # This method can be chained with proxy.
28
+ # mock.proxy(subject).method_name_1
30
29
  # or
31
- # probe.mock(subject).method_name_1
30
+ # proxy.mock(subject).method_name_1
32
31
  #
33
- # When passed the subject, a ScenarioMethodProxy is returned. Passing
32
+ # When passed the subject, a DoubleMethodProxy is returned. Passing
34
33
  # a method with arguments to the proxy will set up expectations that
35
34
  # the a call to the subject's method with the arguments will happen.
36
35
  # mock(subject).method_name_1 {return_value_1}
37
36
  # mock(subject).method_name_2(arg1, arg2) {return_value_2}
38
37
  #
39
38
  # When passed the subject and the method_name, this method returns
40
- # a mock Scenario with the method already set.
39
+ # a mock Double with the method already set.
41
40
  #
42
41
  # mock(subject, :method_name_1) {return_value_1}
43
42
  # mock(subject, :method_name_2).with(arg1, arg2) {return_value_2}
@@ -54,17 +53,17 @@ module RR
54
53
  RR::Space.scenario_method_proxy(self, subject, method_name, &definition)
55
54
  end
56
55
 
57
- # This method sets the Scenario to have a stub strategy. A stub strategy
58
- # sets the default state of the Scenario to expect the method call
59
- # with any arguments any number of times. The Scenario's
56
+ # This method sets the Double to have a stub strategy. A stub strategy
57
+ # sets the default state of the Double to expect the method call
58
+ # with any arguments any number of times. The Double's
60
59
  # expectations can be changed.
61
60
  #
62
- # This method can be chained with probe.
63
- # stub.probe(subject).method_name_1
61
+ # This method can be chained with proxy.
62
+ # stub.proxy(subject).method_name_1
64
63
  # or
65
- # probe.stub(subject).method_name_1
64
+ # proxy.stub(subject).method_name_1
66
65
  #
67
- # When passed the subject, a ScenarioMethodProxy is returned. Passing
66
+ # When passed the subject, a DoubleMethodProxy is returned. Passing
68
67
  # a method with arguments to the proxy will set up expectations that
69
68
  # the a call to the subject's method with the arguments will happen,
70
69
  # and return the prescribed value.
@@ -72,7 +71,7 @@ module RR
72
71
  # stub(subject).method_name_2(arg_1, arg_2) {return_value_2}
73
72
  #
74
73
  # When passed the subject and the method_name, this method returns
75
- # a stub Scenario with the method already set.
74
+ # a stub Double with the method already set.
76
75
  #
77
76
  # mock(subject, :method_name_1) {return_value_1}
78
77
  # mock(subject, :method_name_2).with(arg1, arg2) {return_value_2}
@@ -89,50 +88,50 @@ module RR
89
88
  RR::Space.scenario_method_proxy(self, subject, method_name, &definition)
90
89
  end
91
90
 
92
- # This method sets the Scenario to have a do_not_call strategy.
93
- # A do_not_call strategy sets the default state of the Scenario
94
- # to expect never to be called. The Scenario's expectations can be
91
+ # This method sets the Double to have a dont_allow strategy.
92
+ # A dont_allow strategy sets the default state of the Double
93
+ # to expect never to be called. The Double's expectations can be
95
94
  # changed.
96
95
  #
97
96
  # The following example sets the expectation that subject.method_name
98
97
  # will never be called with arg1 and arg2.
99
98
  #
100
- # do_not_allow(subject).method_name(arg1, arg2)
99
+ # dont_allow(subject).method_name(arg1, arg2)
101
100
  #
102
- # do_not_call also supports a block sytnax.
103
- # do_not_call(subject) do |m|
101
+ # dont_allow also supports a block sytnax.
102
+ # dont_allow(subject) do |m|
104
103
  # m.method1 # Do not allow method1 with any arguments
105
104
  # m.method2(arg1, arg2) # Do not allow method2 with arguments arg1 and arg2
106
105
  # m.method3.with_no_args # Do not allow method3 with no arguments
107
106
  # end
108
- def do_not_call(subject=NO_SUBJECT_ARG, method_name=nil, &definition)
107
+ def dont_allow(subject=NO_SUBJECT_ARG, method_name=nil, &definition)
109
108
  strategy_error! if @strategy
110
- probe_when_do_not_call_error! if @probe
111
- @strategy = :do_not_call
109
+ proxy_when_dont_allow_error! if @proxy
110
+ @strategy = :dont_allow
112
111
  return self if subject.__id__ === NO_SUBJECT_ARG.__id__
113
112
  RR::Space.scenario_method_proxy(self, subject, method_name, &definition)
114
113
  end
115
- alias_method :dont_call, :do_not_call
116
- alias_method :do_not_allow, :do_not_call
117
- alias_method :dont_allow, :do_not_call
114
+ alias_method :do_not_allow, :dont_allow
115
+ alias_method :dont_call, :dont_allow
116
+ alias_method :do_not_call, :dont_allow
118
117
 
119
- # This method add probe capabilities to the Scenario. probe can be called
118
+ # This method add proxy capabilities to the Double. proxy can be called
120
119
  # with mock or stub.
121
120
  #
122
- # mock.probe(controller.template).render(:partial => "my/socks")
121
+ # mock.proxy(controller.template).render(:partial => "my/socks")
123
122
  #
124
- # stub.probe(controller.template).render(:partial => "my/socks") do |html|
123
+ # stub.proxy(controller.template).render(:partial => "my/socks") do |html|
125
124
  # html.should include("My socks are wet")
126
125
  # html
127
126
  # end
128
127
  #
129
- # mock.probe(controller.template).render(:partial => "my/socks") do |html|
128
+ # mock.proxy(controller.template).render(:partial => "my/socks") do |html|
130
129
  # html.should include("My socks are wet")
131
130
  # "My new return value"
132
131
  # end
133
132
  #
134
- # mock.probe also takes a block for definitions.
135
- # mock.probe(subject) do
133
+ # mock.proxy also takes a block for definitions.
134
+ # mock.proxy(subject) do
136
135
  # render(:partial => "my/socks")
137
136
  #
138
137
  # render(:partial => "my/socks") do |html|
@@ -151,31 +150,31 @@ module RR
151
150
  # end
152
151
  # end
153
152
  #
154
- # Passing a block to the Scenario (after the method name and arguments)
153
+ # Passing a block to the Double (after the method name and arguments)
155
154
  # allows you to intercept the return value.
156
155
  # The return value can be modified, validated, and/or overridden by
157
156
  # passing in a block. The return value of the block will replace
158
157
  # the actual return value.
159
158
  #
160
- # mock.probe(controller.template).render(:partial => "my/socks") do |html|
159
+ # mock.proxy(controller.template).render(:partial => "my/socks") do |html|
161
160
  # html.should include("My socks are wet")
162
161
  # "My new return value"
163
162
  # end
164
- def probe(subject=NO_SUBJECT_ARG, method_name=nil, &definition)
165
- probe_when_do_not_call_error! if @strategy == :do_not_call
166
- @probe = true
163
+ def proxy(subject=NO_SUBJECT_ARG, method_name=nil, &definition)
164
+ proxy_when_dont_allow_error! if @strategy == :dont_allow
165
+ @proxy = true
167
166
  return self if subject.__id__ === NO_SUBJECT_ARG.__id__
168
167
  RR::Space.scenario_method_proxy(self, subject, method_name, &definition)
169
168
  end
170
- alias_method :proxy, :probe
169
+ alias_method :probe, :proxy
171
170
 
172
171
  # Calling instance_of will cause all instances of the passed in Class
173
- # to have the Scenario defined.
172
+ # to have the Double defined.
174
173
  #
175
174
  # The following example mocks all User's valid? method and return false.
176
175
  # mock.instance_of(User).valid? {false}
177
176
  #
178
- # The following example mocks and probes User#projects and returns the
177
+ # The following example mocks and proxies User#projects and returns the
179
178
  # first 3 projects.
180
179
  # mock.instance_of(User).projects do |projects|
181
180
  # projects[0..2]
@@ -201,45 +200,45 @@ module RR
201
200
 
202
201
  protected
203
202
  def setup_scenario(subject, method_name)
204
- @double = @space.double(subject, method_name)
205
- @scenario = @space.scenario(@double)
203
+ @double_insertion = @space.double_insertion(subject, method_name)
204
+ @scenario = @space.scenario(@double_insertion)
206
205
  @definition = @scenario.definition
207
206
  end
208
207
 
209
208
  def setup_class_probing_instances(subject, method_name)
210
- class_double = @space.double(subject, :new)
209
+ class_double = @space.double_insertion(subject, :new)
211
210
  class_scenario = @space.scenario(class_double)
212
211
 
213
212
  instance_method_name = method_name
214
213
 
215
214
  @definition = @space.scenario_definition
216
215
  class_handler = proc do |return_value|
217
- double = @space.double(return_value, instance_method_name)
218
- @space.scenario(double, @definition)
216
+ double_insertion = @space.double_insertion(return_value, instance_method_name)
217
+ @space.scenario(double_insertion, @definition)
219
218
  return_value
220
219
  end
221
220
 
222
- builder = ScenarioDefinitionBuilder.new(
221
+ builder = DoubleDefinitionBuilder.new(
223
222
  class_scenario.definition,
224
223
  [],
225
224
  class_handler
226
225
  )
227
226
  builder.stub!
228
- builder.probe!
227
+ builder.proxy!
229
228
  end
230
229
 
231
230
  def transform!
232
- builder = ScenarioDefinitionBuilder.new(@definition, @args, @handler)
231
+ builder = DoubleDefinitionBuilder.new(@definition, @args, @handler)
233
232
 
234
233
  case @strategy
235
234
  when :mock; builder.mock!
236
235
  when :stub; builder.stub!
237
- when :do_not_call; builder.do_not_call!
236
+ when :dont_allow; builder.dont_allow!
238
237
  else no_strategy_error!
239
238
  end
240
239
 
241
- if @probe
242
- builder.probe!
240
+ if @proxy
241
+ builder.proxy!
243
242
  else
244
243
  builder.reimplementation!
245
244
  end
@@ -247,22 +246,22 @@ module RR
247
246
 
248
247
  def strategy_error!
249
248
  raise(
250
- ScenarioDefinitionError,
251
- "This Scenario already has a #{@strategy} strategy"
249
+ DoubleDefinitionError,
250
+ "This Double already has a #{@strategy} strategy"
252
251
  )
253
252
  end
254
253
 
255
254
  def no_strategy_error!
256
255
  raise(
257
- ScenarioDefinitionError,
258
- "This Scenario has no strategy"
256
+ DoubleDefinitionError,
257
+ "This Double has no strategy"
259
258
  )
260
259
  end
261
260
 
262
- def probe_when_do_not_call_error!
261
+ def proxy_when_dont_allow_error!
263
262
  raise(
264
- ScenarioDefinitionError,
265
- "Scenarios cannot be probed when using do_not_call strategy"
263
+ DoubleDefinitionError,
264
+ "Doubles cannot be proxied when using dont_allow strategy"
266
265
  )
267
266
  end
268
267
  end