mcmire-rr 1.0.5.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (155) hide show
  1. data/CHANGES +269 -0
  2. data/Gemfile +16 -0
  3. data/Gemfile.lock +47 -0
  4. data/LICENSE +22 -0
  5. data/README.rdoc +390 -0
  6. data/Rakefile +49 -0
  7. data/VERSION +1 -0
  8. data/lib/rr.rb +101 -0
  9. data/lib/rr/adapters/minitest.rb +31 -0
  10. data/lib/rr/adapters/rr_methods.rb +146 -0
  11. data/lib/rr/adapters/rspec.rb +61 -0
  12. data/lib/rr/adapters/rspec2.rb +22 -0
  13. data/lib/rr/adapters/test_unit.rb +31 -0
  14. data/lib/rr/blank_slate.rb +17 -0
  15. data/lib/rr/class_instance_method_defined.rb +9 -0
  16. data/lib/rr/double.rb +154 -0
  17. data/lib/rr/double_definitions/child_double_definition_create.rb +27 -0
  18. data/lib/rr/double_definitions/double_definition.rb +365 -0
  19. data/lib/rr/double_definitions/double_definition_create.rb +139 -0
  20. data/lib/rr/double_definitions/double_definition_create_blank_slate.rb +26 -0
  21. data/lib/rr/double_definitions/double_injections/any_instance_of.rb +28 -0
  22. data/lib/rr/double_definitions/double_injections/instance.rb +16 -0
  23. data/lib/rr/double_definitions/strategies/double_injection/any_instance_of.rb +30 -0
  24. data/lib/rr/double_definitions/strategies/double_injection/double_injection_strategy.rb +10 -0
  25. data/lib/rr/double_definitions/strategies/double_injection/instance.rb +17 -0
  26. data/lib/rr/double_definitions/strategies/implementation/implementation_strategy.rb +10 -0
  27. data/lib/rr/double_definitions/strategies/implementation/proxy.rb +60 -0
  28. data/lib/rr/double_definitions/strategies/implementation/reimplementation.rb +14 -0
  29. data/lib/rr/double_definitions/strategies/implementation/strongly_typed_reimplementation.rb +15 -0
  30. data/lib/rr/double_definitions/strategies/strategy.rb +43 -0
  31. data/lib/rr/double_definitions/strategies/strategy_methods.rb +53 -0
  32. data/lib/rr/double_definitions/strategies/verification/dont_allow.rb +31 -0
  33. data/lib/rr/double_definitions/strategies/verification/mock.rb +42 -0
  34. data/lib/rr/double_definitions/strategies/verification/stub.rb +43 -0
  35. data/lib/rr/double_definitions/strategies/verification/verification_strategy.rb +10 -0
  36. data/lib/rr/double_matches.rb +42 -0
  37. data/lib/rr/errors/argument_equality_error.rb +6 -0
  38. data/lib/rr/errors/double_definition_error.rb +6 -0
  39. data/lib/rr/errors/double_not_found_error.rb +6 -0
  40. data/lib/rr/errors/double_order_error.rb +6 -0
  41. data/lib/rr/errors/rr_error.rb +20 -0
  42. data/lib/rr/errors/spy_verification_errors/double_injection_not_found_error.rb +8 -0
  43. data/lib/rr/errors/spy_verification_errors/invocation_count_error.rb +8 -0
  44. data/lib/rr/errors/spy_verification_errors/spy_verification_error.rb +8 -0
  45. data/lib/rr/errors/subject_does_not_implement_method_error.rb +6 -0
  46. data/lib/rr/errors/subject_has_different_arity_error.rb +6 -0
  47. data/lib/rr/errors/times_called_error.rb +6 -0
  48. data/lib/rr/expectations/any_argument_expectation.rb +21 -0
  49. data/lib/rr/expectations/argument_equality_expectation.rb +41 -0
  50. data/lib/rr/expectations/times_called_expectation.rb +57 -0
  51. data/lib/rr/hash_with_object_id_key.rb +46 -0
  52. data/lib/rr/injections/double_injection.rb +220 -0
  53. data/lib/rr/injections/injection.rb +33 -0
  54. data/lib/rr/injections/method_missing_injection.rb +73 -0
  55. data/lib/rr/injections/singleton_method_added_injection.rb +72 -0
  56. data/lib/rr/method_dispatches/base_method_dispatch.rb +84 -0
  57. data/lib/rr/method_dispatches/method_dispatch.rb +59 -0
  58. data/lib/rr/method_dispatches/method_missing_dispatch.rb +61 -0
  59. data/lib/rr/proc_from_block.rb +7 -0
  60. data/lib/rr/recorded_calls.rb +103 -0
  61. data/lib/rr/space.rb +119 -0
  62. data/lib/rr/spy_verification.rb +48 -0
  63. data/lib/rr/spy_verification_proxy.rb +13 -0
  64. data/lib/rr/times_called_matchers/any_times_matcher.rb +18 -0
  65. data/lib/rr/times_called_matchers/at_least_matcher.rb +15 -0
  66. data/lib/rr/times_called_matchers/at_most_matcher.rb +23 -0
  67. data/lib/rr/times_called_matchers/integer_matcher.rb +19 -0
  68. data/lib/rr/times_called_matchers/never_matcher.rb +23 -0
  69. data/lib/rr/times_called_matchers/non_terminal.rb +27 -0
  70. data/lib/rr/times_called_matchers/proc_matcher.rb +11 -0
  71. data/lib/rr/times_called_matchers/range_matcher.rb +21 -0
  72. data/lib/rr/times_called_matchers/terminal.rb +20 -0
  73. data/lib/rr/times_called_matchers/times_called_matcher.rb +44 -0
  74. data/lib/rr/wildcard_matchers.rb +158 -0
  75. data/lib/rr/wildcard_matchers/anything.rb +18 -0
  76. data/lib/rr/wildcard_matchers/boolean.rb +23 -0
  77. data/lib/rr/wildcard_matchers/duck_type.rb +32 -0
  78. data/lib/rr/wildcard_matchers/hash_including.rb +29 -0
  79. data/lib/rr/wildcard_matchers/is_a.rb +25 -0
  80. data/lib/rr/wildcard_matchers/numeric.rb +13 -0
  81. data/lib/rr/wildcard_matchers/range.rb +7 -0
  82. data/lib/rr/wildcard_matchers/regexp.rb +7 -0
  83. data/lib/rr/wildcard_matchers/satisfy.rb +26 -0
  84. data/spec/api/any_instance_of/all_instances_of_spec.rb +12 -0
  85. data/spec/api/any_instance_of/any_instance_of_spec.rb +47 -0
  86. data/spec/api/any_instance_of/instance_of_spec.rb +12 -0
  87. data/spec/api/dont_allow/dont_allow_after_stub_spec.rb +14 -0
  88. data/spec/api/mock/mock_spec.rb +193 -0
  89. data/spec/api/proxy/proxy_spec.rb +86 -0
  90. data/spec/api/spy/spy_spec.rb +49 -0
  91. data/spec/api/strong/strong_spec.rb +87 -0
  92. data/spec/api/stub/stub_spec.rb +152 -0
  93. data/spec/core_spec_suite.rb +18 -0
  94. data/spec/environment_fixture_setup.rb +7 -0
  95. data/spec/minitest_spec_suite.rb +21 -0
  96. data/spec/proc_from_block_spec.rb +14 -0
  97. data/spec/rr/adapters/rr_methods_argument_matcher_spec.rb +67 -0
  98. data/spec/rr/adapters/rr_methods_creator_spec.rb +137 -0
  99. data/spec/rr/adapters/rr_methods_space_spec.rb +98 -0
  100. data/spec/rr/adapters/rr_methods_spec_helper.rb +7 -0
  101. data/spec/rr/adapters/rr_methods_times_matcher_spec.rb +13 -0
  102. data/spec/rr/double_definitions/child_double_definition_creator_spec.rb +112 -0
  103. data/spec/rr/double_definitions/double_definition_create_blank_slate_spec.rb +91 -0
  104. data/spec/rr/double_definitions/double_definition_create_spec.rb +443 -0
  105. data/spec/rr/double_injection/double_injection_spec.rb +546 -0
  106. data/spec/rr/double_injection/double_injection_verify_spec.rb +29 -0
  107. data/spec/rr/errors/rr_error_spec.rb +67 -0
  108. data/spec/rr/expectations/any_argument_expectation_spec.rb +47 -0
  109. data/spec/rr/expectations/anything_argument_equality_expectation_spec.rb +14 -0
  110. data/spec/rr/expectations/argument_equality_expectation_spec.rb +135 -0
  111. data/spec/rr/expectations/boolean_argument_equality_expectation_spec.rb +34 -0
  112. data/spec/rr/expectations/hash_including_argument_equality_expectation_spec.rb +82 -0
  113. data/spec/rr/expectations/hash_including_spec.rb +17 -0
  114. data/spec/rr/expectations/satisfy_argument_equality_expectation_spec.rb +59 -0
  115. data/spec/rr/expectations/satisfy_spec.rb +14 -0
  116. data/spec/rr/expectations/times_called_expectation/times_called_expectation_any_times_spec.rb +22 -0
  117. data/spec/rr/expectations/times_called_expectation/times_called_expectation_at_least_spec.rb +37 -0
  118. data/spec/rr/expectations/times_called_expectation/times_called_expectation_at_most_spec.rb +43 -0
  119. data/spec/rr/expectations/times_called_expectation/times_called_expectation_helper.rb +11 -0
  120. data/spec/rr/expectations/times_called_expectation/times_called_expectation_integer_spec.rb +58 -0
  121. data/spec/rr/expectations/times_called_expectation/times_called_expectation_proc_spec.rb +35 -0
  122. data/spec/rr/expectations/times_called_expectation/times_called_expectation_range_spec.rb +39 -0
  123. data/spec/rr/minitest/minitest_integration_test.rb +59 -0
  124. data/spec/rr/minitest/test_helper.rb +7 -0
  125. data/spec/rr/rspec/invocation_matcher_spec.rb +279 -0
  126. data/spec/rr/rspec/rspec_adapter_spec.rb +63 -0
  127. data/spec/rr/rspec/rspec_backtrace_tweaking_spec.rb +21 -0
  128. data/spec/rr/rspec/rspec_backtrace_tweaking_spec_fixture.rb +11 -0
  129. data/spec/rr/rspec/rspec_usage_spec.rb +86 -0
  130. data/spec/rr/space/hash_with_object_id_key_spec.rb +88 -0
  131. data/spec/rr/space/space_spec.rb +596 -0
  132. data/spec/rr/test_unit/test_helper.rb +7 -0
  133. data/spec/rr/test_unit/test_unit_backtrace_test.rb +36 -0
  134. data/spec/rr/test_unit/test_unit_integration_test.rb +59 -0
  135. data/spec/rr/times_called_matchers/any_times_matcher_spec.rb +47 -0
  136. data/spec/rr/times_called_matchers/at_least_matcher_spec.rb +55 -0
  137. data/spec/rr/times_called_matchers/at_most_matcher_spec.rb +70 -0
  138. data/spec/rr/times_called_matchers/integer_matcher_spec.rb +70 -0
  139. data/spec/rr/times_called_matchers/proc_matcher_spec.rb +55 -0
  140. data/spec/rr/times_called_matchers/range_matcher_spec.rb +76 -0
  141. data/spec/rr/times_called_matchers/times_called_matcher_spec.rb +118 -0
  142. data/spec/rr/wildcard_matchers/anything_spec.rb +24 -0
  143. data/spec/rr/wildcard_matchers/boolean_spec.rb +36 -0
  144. data/spec/rr/wildcard_matchers/duck_type_spec.rb +52 -0
  145. data/spec/rr/wildcard_matchers/is_a_spec.rb +32 -0
  146. data/spec/rr/wildcard_matchers/numeric_spec.rb +32 -0
  147. data/spec/rr/wildcard_matchers/range_spec.rb +35 -0
  148. data/spec/rr/wildcard_matchers/regexp_spec.rb +43 -0
  149. data/spec/rr_spec.rb +28 -0
  150. data/spec/rspec_spec_suite.rb +16 -0
  151. data/spec/spec_helper.rb +40 -0
  152. data/spec/spec_suite.rb +50 -0
  153. data/spec/spy_verification_spec.rb +129 -0
  154. data/spec/test_unit_spec_suite.rb +20 -0
  155. metadata +220 -0
@@ -0,0 +1,546 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../../spec_helper")
2
+
3
+ module RR
4
+ module Injections
5
+ describe DoubleInjection do
6
+ attr_reader :subject, :method_name, :double_injection
7
+ macro("sets up subject and method_name") do
8
+ it "sets up subject and method_name" do
9
+ double_injection.subject.should === subject
10
+ double_injection.method_name.should == method_name.to_sym
11
+ end
12
+ end
13
+
14
+ before do
15
+ @subject = Object.new
16
+ end
17
+
18
+ describe "mock/stub" do
19
+ context "when the subject responds to the injected method" do
20
+ before do
21
+ class << subject
22
+ attr_reader :original_foobar_called
23
+
24
+ def foobar
25
+ @original_foobar_called = true
26
+ :original_foobar
27
+ end
28
+ end
29
+
30
+ subject.should respond_to(:foobar)
31
+ (!!subject.methods.detect {|method| method.to_sym == :foobar}).should be_true
32
+ stub(subject).foobar {:new_foobar}
33
+ end
34
+
35
+ describe "being bound" do
36
+ it "sets __rr__original_{method_name} to the original method" do
37
+ subject.__rr__original_foobar.should == :original_foobar
38
+ end
39
+
40
+ describe "being called" do
41
+ it "returns the return value of the block" do
42
+ subject.foobar.should == :new_foobar
43
+ end
44
+
45
+ it "does not call the original method" do
46
+ subject.foobar
47
+ subject.original_foobar_called.should be_nil
48
+ end
49
+ end
50
+
51
+ describe "being reset" do
52
+ before do
53
+ RR::Space.reset_double(subject, :foobar)
54
+ end
55
+
56
+ it "rebinds the original method" do
57
+ subject.foobar.should == :original_foobar
58
+ end
59
+
60
+ it "removes __rr__original_{method_name}" do
61
+ subject.should_not respond_to(:__rr__original_foobar)
62
+ end
63
+ end
64
+ end
65
+ end
66
+
67
+ context "when the subject does not respond to the injected method" do
68
+ before do
69
+ subject.should_not respond_to(:foobar)
70
+ subject.methods.should_not include('foobar')
71
+ stub(subject).foobar {:new_foobar}
72
+ end
73
+
74
+ it "does not set __rr__original_{method_name} to the original method" do
75
+ subject.should_not respond_to(:__rr__original_foobar)
76
+ end
77
+
78
+ describe "being called" do
79
+ it "calls the newly defined method" do
80
+ subject.foobar.should == :new_foobar
81
+ end
82
+ end
83
+
84
+ describe "being reset" do
85
+ before do
86
+ RR::Space.reset_double(subject, :foobar)
87
+ end
88
+
89
+ it "unsets the foobar method" do
90
+ subject.should_not respond_to(:foobar)
91
+ subject.methods.should_not include('foobar')
92
+ end
93
+ end
94
+ end
95
+
96
+ context "when the subject redefines respond_to?" do
97
+ it "does not try to call the implementation" do
98
+ class << subject
99
+ def respond_to?(method_symbol, include_private = false)
100
+ method_symbol == :foobar
101
+ end
102
+ end
103
+ mock(@subject).foobar
104
+ @subject.foobar.should == nil
105
+ end
106
+ end
107
+ end
108
+
109
+ describe "mock/stub + proxy" do
110
+ context "when the subject responds to the injected method" do
111
+ context "when the subject has the method defined" do
112
+ describe "being bound" do
113
+ before do
114
+ def subject.foobar
115
+ :original_foobar
116
+ end
117
+
118
+ subject.should respond_to(:foobar)
119
+ (!!subject.methods.detect {|method| method.to_sym == :foobar}).should be_true
120
+ stub.proxy(subject).foobar {:new_foobar}
121
+ end
122
+
123
+ it "aliases the original method to __rr__original_{method_name}" do
124
+ subject.__rr__original_foobar.should == :original_foobar
125
+ end
126
+
127
+ it "replaces the original method with the new method" do
128
+ subject.foobar.should == :new_foobar
129
+ end
130
+
131
+ describe "being called" do
132
+ it "calls the original method first and sends it into the block" do
133
+ original_return_value = nil
134
+ stub.proxy(subject).foobar {|arg| original_return_value = arg; :new_foobar}
135
+ subject.foobar.should == :new_foobar
136
+ original_return_value.should == :original_foobar
137
+ end
138
+ end
139
+
140
+ describe "being reset" do
141
+ before do
142
+ RR::Space.reset_double(subject, :foobar)
143
+ end
144
+
145
+ it "rebinds the original method" do
146
+ subject.foobar.should == :original_foobar
147
+ end
148
+
149
+ it "removes __rr__original_{method_name}" do
150
+ subject.should_not respond_to(:__rr__original_foobar)
151
+ end
152
+ end
153
+ end
154
+ end
155
+
156
+ context "when the subject does not have the method defined" do
157
+ describe "being bound" do
158
+ context "when the subject has not been previously bound to" do
159
+ before do
160
+ setup_subject
161
+
162
+ subject.should respond_to(:foobar)
163
+ stub.proxy(subject).foobar {:new_foobar}
164
+ end
165
+
166
+ def setup_subject
167
+ def subject.respond_to?(method_name)
168
+ if method_name.to_sym == :foobar
169
+ true
170
+ else
171
+ super
172
+ end
173
+ end
174
+ end
175
+
176
+ it "does not define __rr__original_{method_name}" do
177
+ subject.methods.should_not include("__rr__original_foobar")
178
+ end
179
+
180
+ context "when method is defined after being bound and before being called" do
181
+ def setup_subject
182
+ super
183
+ def subject.foobar
184
+ :original_foobar
185
+ end
186
+ end
187
+
188
+ describe "being called" do
189
+ it "defines __rr__original_{method_name} to be the lazily created method" do
190
+ (!!subject.methods.detect {|method| method.to_sym == :__rr__original_foobar}).should be_true
191
+ subject.__rr__original_foobar.should == :original_foobar
192
+ end
193
+
194
+ it "calls the original method first and sends it into the block" do
195
+ original_return_value = nil
196
+ stub.proxy(subject).foobar {|arg| original_return_value = arg; :new_foobar}
197
+ subject.foobar.should == :new_foobar
198
+ original_return_value.should == :original_foobar
199
+ end
200
+ end
201
+
202
+ describe "being reset" do
203
+ before do
204
+ RR::Space.reset_double(subject, :foobar)
205
+ end
206
+
207
+ it "rebinds the original method" do
208
+ subject.foobar.should == :original_foobar
209
+ end
210
+
211
+ it "removes __rr__original_{method_name}" do
212
+ subject.should_not respond_to(:__rr__original_foobar)
213
+ end
214
+ end
215
+ end
216
+
217
+ context "when method is still not defined" do
218
+ context "when the method is lazily created" do
219
+ def setup_subject
220
+ super
221
+ def subject.method_missing(method_name, *args, &block)
222
+ if method_name.to_sym == :foobar
223
+ def self.foobar
224
+ :original_foobar
225
+ end
226
+
227
+ foobar
228
+ else
229
+ super
230
+ end
231
+ end
232
+ end
233
+
234
+ describe "being called" do
235
+ it "defines __rr__original_{method_name} to be the lazily created method" do
236
+ subject.foobar
237
+ (!!subject.methods.detect {|method| method.to_sym == :__rr__original_foobar}).should be_true
238
+ subject.__rr__original_foobar.should == :original_foobar
239
+ end
240
+
241
+ it "calls the lazily created method and returns the injected method return value" do
242
+ original_return_value = nil
243
+ stub.proxy(subject).foobar {|arg| original_return_value = arg; :new_foobar}
244
+ subject.foobar.should == :new_foobar
245
+ original_return_value.should == :original_foobar
246
+ end
247
+ end
248
+
249
+ describe "being reset" do
250
+ context "when reset before being called" do
251
+ before do
252
+ RR::Space.reset_double(subject, :foobar)
253
+ end
254
+
255
+ it "rebinds the original method" do
256
+ subject.foobar.should == :original_foobar
257
+ end
258
+
259
+ it "removes __rr__original_{method_name}" do
260
+ subject.should_not respond_to(:__rr__original_foobar)
261
+ end
262
+ end
263
+ end
264
+ end
265
+
266
+ context "when the method is not lazily created (handled in method_missing)" do
267
+ def setup_subject
268
+ super
269
+ def subject.method_missing(method_name, *args, &block)
270
+ if method_name.to_sym == :foobar
271
+ :original_foobar
272
+ else
273
+ super
274
+ end
275
+ end
276
+ end
277
+
278
+ describe "being called" do
279
+ it "does not define the __rr__original_{method_name}" do
280
+ subject.foobar
281
+ subject.methods.should_not include("__rr__original_foobar")
282
+ end
283
+
284
+ it "calls the lazily created method and returns the injected method return value" do
285
+ original_return_value = nil
286
+ stub.proxy(subject).foobar {|arg| original_return_value = arg; :new_foobar}
287
+ subject.foobar.should == :new_foobar
288
+ original_return_value.should == :original_foobar
289
+ end
290
+ end
291
+
292
+ describe "being reset" do
293
+ before do
294
+ RR::Space.reset_double(subject, :foobar)
295
+ end
296
+
297
+ it "rebinds the original method" do
298
+ subject.foobar.should == :original_foobar
299
+ end
300
+
301
+ it "removes __rr__original_{method_name}" do
302
+ subject.should_not respond_to(:__rr__original_foobar)
303
+ end
304
+ end
305
+ end
306
+ end
307
+ end
308
+
309
+ context "when the subject has been previously bound to" do
310
+ before do
311
+ setup_subject
312
+
313
+ subject.should respond_to(:foobar)
314
+ stub.proxy(subject).baz {:new_baz}
315
+ stub.proxy(subject).foobar {:new_foobar}
316
+ end
317
+
318
+ def setup_subject
319
+ def subject.respond_to?(method_name)
320
+ if method_name.to_sym == :foobar || method_name.to_sym == :baz
321
+ true
322
+ else
323
+ super
324
+ end
325
+ end
326
+ end
327
+
328
+ it "does not define __rr__original_{method_name}" do
329
+ subject.methods.should_not include("__rr__original_foobar")
330
+ end
331
+
332
+ context "when method is defined after being bound and before being called" do
333
+ def setup_subject
334
+ super
335
+ def subject.foobar
336
+ :original_foobar
337
+ end
338
+ end
339
+
340
+ describe "being called" do
341
+ it "defines __rr__original_{method_name} to be the lazily created method" do
342
+ (!!subject.methods.detect {|method| method.to_sym == :__rr__original_foobar}).should be_true
343
+ subject.__rr__original_foobar.should == :original_foobar
344
+ end
345
+
346
+ it "calls the original method first and sends it into the block" do
347
+ original_return_value = nil
348
+ stub.proxy(subject).foobar {|arg| original_return_value = arg; :new_foobar}
349
+ subject.foobar.should == :new_foobar
350
+ original_return_value.should == :original_foobar
351
+ end
352
+ end
353
+
354
+ describe "being reset" do
355
+ before do
356
+ RR::Space.reset_double(subject, :foobar)
357
+ end
358
+
359
+ it "rebinds the original method" do
360
+ subject.foobar.should == :original_foobar
361
+ end
362
+
363
+ it "removes __rr__original_{method_name}" do
364
+ subject.should_not respond_to(:__rr__original_foobar)
365
+ end
366
+ end
367
+ end
368
+
369
+ context "when method is still not defined" do
370
+ context "when the method is lazily created" do
371
+ def setup_subject
372
+ super
373
+ def subject.method_missing(method_name, *args, &block)
374
+ if method_name.to_sym == :foobar
375
+ def self.foobar
376
+ :original_foobar
377
+ end
378
+
379
+ foobar
380
+ else
381
+ super
382
+ end
383
+ end
384
+ end
385
+
386
+ describe "being called" do
387
+ it "defines __rr__original_{method_name} to be the lazily created method" do
388
+ subject.foobar
389
+ (!!subject.methods.detect {|method| method.to_sym == :__rr__original_foobar}).should be_true
390
+ subject.__rr__original_foobar.should == :original_foobar
391
+ end
392
+
393
+ it "calls the lazily created method and returns the injected method return value" do
394
+ original_return_value = nil
395
+ stub.proxy(subject).foobar {|arg| original_return_value = arg; :new_foobar}
396
+ subject.foobar.should == :new_foobar
397
+ original_return_value.should == :original_foobar
398
+ end
399
+ end
400
+
401
+ describe "being reset" do
402
+ context "when reset before being called" do
403
+ before do
404
+ RR::Space.reset_double(subject, :foobar)
405
+ end
406
+
407
+ it "rebinds the original method" do
408
+ subject.foobar.should == :original_foobar
409
+ end
410
+
411
+ it "removes __rr__original_{method_name}" do
412
+ subject.should_not respond_to(:__rr__original_foobar)
413
+ end
414
+ end
415
+ end
416
+ end
417
+
418
+ context "when the method is not lazily created (handled in method_missing)" do
419
+ def setup_subject
420
+ super
421
+ def subject.method_missing(method_name, *args, &block)
422
+ if method_name.to_sym == :foobar
423
+ :original_foobar
424
+ else
425
+ super
426
+ end
427
+ end
428
+ end
429
+
430
+ describe "being called" do
431
+ it "does not define the __rr__original_{method_name}" do
432
+ subject.foobar
433
+ subject.methods.should_not include("__rr__original_foobar")
434
+ end
435
+
436
+ it "calls the lazily created method and returns the injected method return value" do
437
+ original_return_value = nil
438
+ stub.proxy(subject).foobar {|arg| original_return_value = arg; :new_foobar}
439
+ subject.foobar.should == :new_foobar
440
+ original_return_value.should == :original_foobar
441
+ end
442
+ end
443
+
444
+ describe "being reset" do
445
+ before do
446
+ RR::Space.reset_double(subject, :foobar)
447
+ end
448
+
449
+ it "rebinds the original method" do
450
+ subject.foobar.should == :original_foobar
451
+ end
452
+
453
+ it "removes __rr__original_{method_name}" do
454
+ subject.should_not respond_to(:__rr__original_foobar)
455
+ end
456
+ end
457
+ end
458
+ end
459
+ end
460
+ end
461
+ end
462
+ end
463
+
464
+ context "when the subject does not respond to the injected method" do
465
+ context "when the subject responds to the method via method_missing" do
466
+ describe "being bound" do
467
+ before do
468
+ subject.should_not respond_to(:foobar)
469
+ subject.methods.should_not include('foobar')
470
+ class << subject
471
+ def method_missing(method_name, *args, &block)
472
+ if method_name == :foobar
473
+ :original_foobar
474
+ else
475
+ super
476
+ end
477
+ end
478
+ end
479
+ stub.proxy(subject).foobar {:new_foobar}
480
+ end
481
+
482
+ it "adds the method to the subject" do
483
+ subject.should respond_to(:foobar)
484
+ (!!subject.methods.detect {|method| method.to_sym == :foobar}).should be_true
485
+ end
486
+
487
+ describe "being called" do
488
+ it "calls the original method first and sends it into the block" do
489
+ original_return_value = nil
490
+ stub.proxy(subject).foobar {|arg| original_return_value = arg; :new_foobar}
491
+ subject.foobar.should == :new_foobar
492
+ original_return_value.should == :original_foobar
493
+ end
494
+ end
495
+
496
+ describe "being reset" do
497
+ before do
498
+ RR::Space.reset_double(subject, :foobar)
499
+ end
500
+
501
+ it "unsets the foobar method" do
502
+ subject.should_not respond_to(:foobar)
503
+ subject.methods.should_not include('foobar')
504
+ end
505
+ end
506
+ end
507
+ end
508
+
509
+ context "when the subject would raise a NoMethodError when the method is called" do
510
+ describe "being bound" do
511
+ before do
512
+ subject.should_not respond_to(:foobar)
513
+ subject.methods.should_not include('foobar')
514
+ stub.proxy(subject).foobar {:new_foobar}
515
+ end
516
+
517
+ it "adds the method to the subject" do
518
+ subject.should respond_to(:foobar)
519
+ (!!subject.methods.detect {|method| method.to_sym == :foobar}).should be_true
520
+ end
521
+
522
+ describe "being called" do
523
+ it "raises a NoMethodError" do
524
+ lambda do
525
+ subject.foobar
526
+ end.should raise_error(NoMethodError)
527
+ end
528
+ end
529
+
530
+ describe "being reset" do
531
+ before do
532
+ RR::Space.reset_double(subject, :foobar)
533
+ end
534
+
535
+ it "unsets the foobar method" do
536
+ subject.should_not respond_to(:foobar)
537
+ subject.methods.should_not include('foobar')
538
+ end
539
+ end
540
+ end
541
+ end
542
+ end
543
+ end
544
+ end
545
+ end
546
+ end