rr 0.2.5 → 0.3.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 (40) hide show
  1. data/CHANGES +5 -0
  2. data/README +20 -9
  3. data/Rakefile +1 -1
  4. data/examples/example_suite.rb +1 -1
  5. data/examples/high_level_example.rb +4 -4
  6. data/examples/rr/double/double_dispatching_example.rb +41 -41
  7. data/examples/rr/double/double_verify_example.rb +1 -1
  8. data/examples/rr/expectations/times_called_expectation/times_called_expectation_helper.rb +2 -2
  9. data/examples/rr/extensions/instance_methods_creator_example.rb +48 -38
  10. data/examples/rr/extensions/instance_methods_space_example.rb +8 -8
  11. data/examples/rr/rspec/rspec_adapter_example.rb +9 -9
  12. data/examples/rr/rspec/rspec_usage_example.rb +16 -2
  13. data/examples/rr/scenario_creator_example.rb +400 -0
  14. data/examples/rr/scenario_example.rb +19 -4
  15. data/examples/rr/scenario_method_proxy_example.rb +71 -0
  16. data/examples/rr/space/space_create_example.rb +93 -106
  17. data/examples/rr/space/space_example.rb +2 -2
  18. data/examples/rr/space/space_register_example.rb +3 -3
  19. data/examples/rr/space/space_reset_example.rb +11 -11
  20. data/examples/rr/space/space_verify_example.rb +12 -12
  21. data/examples/rr/test_unit/test_unit_integration_test.rb +11 -2
  22. data/lib/rr.rb +10 -12
  23. data/lib/rr/errors/scenario_definition_error.rb +6 -0
  24. data/lib/rr/extensions/instance_methods.rb +84 -84
  25. data/lib/rr/scenario.rb +18 -3
  26. data/lib/rr/scenario_creator.rb +233 -0
  27. data/lib/rr/scenario_method_proxy.rb +19 -0
  28. data/lib/rr/space.rb +12 -32
  29. metadata +7 -13
  30. data/examples/rr/do_not_allow_creator_example.rb +0 -111
  31. data/examples/rr/mock_creator_example.rb +0 -87
  32. data/examples/rr/mock_probe_creator_example.rb +0 -120
  33. data/examples/rr/stub_creator_example.rb +0 -96
  34. data/examples/rr/stub_probe_creator_example.rb +0 -127
  35. data/lib/rr/creator.rb +0 -16
  36. data/lib/rr/do_not_allow_creator.rb +0 -33
  37. data/lib/rr/mock_creator.rb +0 -26
  38. data/lib/rr/mock_probe_creator.rb +0 -36
  39. data/lib/rr/stub_creator.rb +0 -30
  40. data/lib/rr/stub_probe_creator.rb +0 -42
@@ -20,12 +20,12 @@ module RR
20
20
 
21
21
  def initialize(space, double)
22
22
  @space = space
23
+ @double = double
23
24
  @implementation = nil
24
25
  @argument_expectation = nil
25
26
  @times_called_expectation = nil
26
27
  @times_called = 0
27
28
  @after_call = nil
28
- @double = double
29
29
  @yields = nil
30
30
  end
31
31
 
@@ -203,7 +203,7 @@ module RR
203
203
  @after_call = block
204
204
  self
205
205
  end
206
-
206
+
207
207
  # Scenario#returns accepts an argument value or a block.
208
208
  # It will raise an ArgumentError if both are passed in.
209
209
  #
@@ -236,6 +236,21 @@ module RR
236
236
  self
237
237
  end
238
238
 
239
+ # Scenario#implemented_by_original_method sets the implementation
240
+ # of the Scenario to be the original method.
241
+ # This is primarily used with probes.
242
+ #
243
+ # obj = Object.new
244
+ # def obj.foobar
245
+ # yield(1)
246
+ # end
247
+ # mock(obj).method_name.implemented_by_original_method
248
+ # obj.foobar {|arg| puts arg} # puts 1
249
+ def implemented_by_original_method
250
+ implemented_by @double.original_method
251
+ self
252
+ end
253
+
239
254
  # Scenario#call calls the Scenario's implementation. The return
240
255
  # value of the implementation is returned.
241
256
  #
@@ -270,7 +285,7 @@ module RR
270
285
  # Scenario#exact_match? returns true when the passed in arguments
271
286
  # exactly match the ArgumentEqualityExpectation arguments.
272
287
  def exact_match?(*arguments)
273
- return false unless @argument_expectation
288
+ return false unless @argument_expectation
274
289
  @argument_expectation.exact_match?(*arguments)
275
290
  end
276
291
 
@@ -0,0 +1,233 @@
1
+ module RR
2
+ # RR::ScenarioCreator provides a strategies to create a Scenario.
3
+ # The strategies are:
4
+ # * mock
5
+ # * stub
6
+ # * do_not_call
7
+ #
8
+ # Probing can also be added.
9
+ class ScenarioCreator
10
+ NO_SUBJECT_ARG = Object.new
11
+
12
+ attr_reader :space, :subject
13
+ include Errors
14
+
15
+ def initialize(space)
16
+ @space = space
17
+ @strategy = nil
18
+ @probe = false
19
+ end
20
+
21
+ def create!(subject, method_name, *args, &handler)
22
+ @subject = subject
23
+ @method_name = method_name
24
+ @args = args
25
+ @handler = handler
26
+ @double = @space.double(@subject, method_name)
27
+ @scenario = @space.scenario(@double)
28
+ transform!
29
+ @scenario
30
+ end
31
+
32
+ # This method sets the Scenario to have a mock strategy. A mock strategy
33
+ # sets the default state of the Scenario to expect the method call
34
+ # with arguments exactly one time. The Scenario's expectations can be
35
+ # changed.
36
+ #
37
+ # This method can be chained with probe.
38
+ # mock.probe(subject).method_name_1
39
+ # or
40
+ # probe.mock(subject).method_name_1
41
+ #
42
+ # When passed the subject, a ScenarioMethodProxy is returned. Passing
43
+ # a method with arguments to the proxy will set up expectations that
44
+ # the a call to the subject's method with the arguments will happen.
45
+ # mock(subject).method_name_1 {return_value_1}
46
+ # mock(subject).method_name_2(arg1, arg2) {return_value_2}
47
+ #
48
+ # When passed the subject and the method_name, this method returns
49
+ # a mock Scenario with the method already set.
50
+ #
51
+ # mock(subject, :method_name_1) {return_value_1}
52
+ # mock(subject, :method_name_2).with(arg1, arg2) {return_value_2}
53
+ #
54
+ # mock also takes a block for definitions.
55
+ # mock(subject) do
56
+ # method_name_1 {return_value_1}
57
+ # method_name_2(arg_1, arg_2) {return_value_2}
58
+ # end
59
+ def mock(subject=NO_SUBJECT_ARG, method_name=nil, &definition)
60
+ strategy_error! if @strategy
61
+ @strategy = :mock
62
+ return self if subject === NO_SUBJECT_ARG
63
+ RR::Space.scenario_method_proxy(self, subject, method_name, &definition)
64
+ end
65
+
66
+ # This method sets the Scenario to have a stub strategy. A stub strategy
67
+ # sets the default state of the Scenario to expect the method call
68
+ # with any arguments any number of times. The Scenario's
69
+ # expectations can be changed.
70
+ #
71
+ # This method can be chained with probe.
72
+ # stub.probe(subject).method_name_1
73
+ # or
74
+ # probe.stub(subject).method_name_1
75
+ #
76
+ # When passed the subject, a ScenarioMethodProxy is returned. Passing
77
+ # a method with arguments to the proxy will set up expectations that
78
+ # the a call to the subject's method with the arguments will happen,
79
+ # and return the prescribed value.
80
+ # stub(subject).method_name_1 {return_value_1}
81
+ # stub(subject).method_name_2(arg_1, arg_2) {return_value_2}
82
+ #
83
+ # When passed the subject and the method_name, this method returns
84
+ # a stub Scenario with the method already set.
85
+ #
86
+ # mock(subject, :method_name_1) {return_value_1}
87
+ # mock(subject, :method_name_2).with(arg1, arg2) {return_value_2}
88
+ #
89
+ # stub also takes a block for definitions.
90
+ # stub(subject) do
91
+ # method_name_1 {return_value_1}
92
+ # method_name_2(arg_1, arg_2) {return_value_2}
93
+ # end
94
+ def stub(subject=NO_SUBJECT_ARG, method_name=nil, &definition)
95
+ strategy_error! if @strategy
96
+ @strategy = :stub
97
+ return self if subject === NO_SUBJECT_ARG
98
+ RR::Space.scenario_method_proxy(self, subject, method_name, &definition)
99
+ end
100
+
101
+ def do_not_call(subject=NO_SUBJECT_ARG, method_name=nil, &definition)
102
+ strategy_error! if @strategy
103
+ probe_when_do_not_call_error! if @probe
104
+ @strategy = :do_not_call
105
+ return self if subject === NO_SUBJECT_ARG
106
+ RR::Space.scenario_method_proxy(self, subject, method_name, &definition)
107
+ end
108
+ alias_method :dont_call, :do_not_call
109
+ alias_method :do_not_allow, :do_not_call
110
+ alias_method :dont_allow, :do_not_call
111
+
112
+ # This method add probe capabilities to the Scenario. probe can be called
113
+ # with mock or stub.
114
+ #
115
+ # mock.probe(controller.template).render(:partial => "my/socks")
116
+ #
117
+ # stub.probe(controller.template).render(:partial => "my/socks") do |html|
118
+ # html.should include("My socks are wet")
119
+ # html
120
+ # end
121
+ #
122
+ # mock.probe(controller.template).render(:partial => "my/socks") do |html|
123
+ # html.should include("My socks are wet")
124
+ # "My new return value"
125
+ # end
126
+ #
127
+ # mock.probe also takes a block for definitions.
128
+ # mock.probe(subject) do
129
+ # render(:partial => "my/socks")
130
+ #
131
+ # render(:partial => "my/socks") do |html|
132
+ # html.should include("My socks are wet")
133
+ # html
134
+ # end
135
+ #
136
+ # render(:partial => "my/socks") do |html|
137
+ # html.should include("My socks are wet")
138
+ # html
139
+ # end
140
+ #
141
+ # render(:partial => "my/socks") do |html|
142
+ # html.should include("My socks are wet")
143
+ # "My new return value"
144
+ # end
145
+ # end
146
+ #
147
+ # Passing a block to the Scenario (after the method name and arguments)
148
+ # allows you to intercept the return value.
149
+ # The return value can be modified, validated, and/or overridden by
150
+ # passing in a block. The return value of the block will replace
151
+ # the actual return value.
152
+ #
153
+ # mock.probe(controller.template).render(:partial => "my/socks") do |html|
154
+ # html.should include("My socks are wet")
155
+ # "My new return value"
156
+ # end
157
+ def probe(subject=NO_SUBJECT_ARG, method_name=nil, &definition)
158
+ probe_when_do_not_call_error! if @strategy == :do_not_call
159
+ @probe = true
160
+ return self if subject === NO_SUBJECT_ARG
161
+ RR::Space.scenario_method_proxy(self, subject, method_name, &definition)
162
+ end
163
+
164
+ protected
165
+ def transform!
166
+ case @strategy
167
+ when :mock; mock!
168
+ when :stub; stub!
169
+ when :do_not_call; do_not_call!
170
+ else no_strategy_error!
171
+ end
172
+
173
+ if @probe
174
+ probe!
175
+ else
176
+ reimplementation!
177
+ end
178
+ end
179
+
180
+ def mock!
181
+ @scenario.with(*@args).once
182
+ end
183
+
184
+ def stub!
185
+ @scenario.any_number_of_times
186
+ permissive_argument!
187
+ end
188
+
189
+ def do_not_call!
190
+ @scenario.never
191
+ permissive_argument!
192
+ reimplementation!
193
+ end
194
+
195
+ def permissive_argument!
196
+ if @args.empty?
197
+ @scenario.with_any_args
198
+ else
199
+ @scenario.with(*@args)
200
+ end
201
+ end
202
+
203
+ def reimplementation!
204
+ @scenario.returns(&@handler)
205
+ end
206
+
207
+ def probe!
208
+ @scenario.implemented_by_original_method
209
+ @scenario.after_call(&@handler) if @handler
210
+ end
211
+
212
+ def strategy_error!
213
+ raise(
214
+ ScenarioDefinitionError,
215
+ "This Scenario already has a #{@strategy} strategy"
216
+ )
217
+ end
218
+
219
+ def no_strategy_error!
220
+ raise(
221
+ ScenarioDefinitionError,
222
+ "This Scenario has no strategy"
223
+ )
224
+ end
225
+
226
+ def probe_when_do_not_call_error!
227
+ raise(
228
+ ScenarioDefinitionError,
229
+ "Scenarios cannot be probed when using do_not_call strategy"
230
+ )
231
+ end
232
+ end
233
+ end
@@ -0,0 +1,19 @@
1
+ module RR
2
+ class ScenarioMethodProxy
3
+ def initialize(space, creator, object, &block)
4
+ @space = space
5
+ @creator = creator
6
+ @object = object
7
+ class << self
8
+ instance_methods.each do |m|
9
+ undef_method m unless m =~ /^__/
10
+ end
11
+
12
+ def method_missing(method_name, *args, &block)
13
+ @creator.create!(@object, method_name, *args, &block)
14
+ end
15
+ end
16
+ yield(self) if block_given?
17
+ end
18
+ end
19
+ end
@@ -25,33 +25,22 @@ module RR
25
25
  @trim_backtrace = false
26
26
  end
27
27
 
28
- # Creates a MockCreator.
29
- def mock_creator(subject, method_name=nil, &definition)
30
- setup_creator MockCreator, subject, method_name, definition
31
- end
32
-
33
- # Creates a StubCreator.
34
- def stub_creator(subject, method_name=nil, &definition)
35
- setup_creator StubCreator, subject, method_name, definition
36
- end
37
-
38
- # Creates a MockProbeCreator.
39
- def mock_probe_creator(subject, method_name=nil, &definition)
40
- setup_creator MockProbeCreator, subject, method_name, definition
41
- end
42
-
43
- # Creates a StubProbeCreator.
44
- def stub_probe_creator(subject, method_name=nil, &definition)
45
- setup_creator StubProbeCreator, subject, method_name, definition
28
+ def scenario_method_proxy(creator, object, method_name=nil, &definition)
29
+ if method_name && definition
30
+ raise ArgumentError, "Cannot pass in a method name and a block"
31
+ end
32
+ proxy = ScenarioMethodProxy.new(self, creator, object, &definition)
33
+ return proxy unless method_name
34
+ proxy.__send__(method_name)
46
35
  end
47
36
 
48
- # Creates a DoNotAllowCreator.
49
- def do_not_allow_creator(subject, method_name=nil, &definition)
50
- setup_creator DoNotAllowCreator, subject, method_name, definition
37
+ # Creates a ScenarioCreator.
38
+ def scenario_creator
39
+ ScenarioCreator.new(self)
51
40
  end
52
41
 
53
42
  # Creates and registers a Scenario to be verified.
54
- def create_scenario(double)
43
+ def scenario(double)
55
44
  scenario = Scenario.new(self, double)
56
45
  double.register_scenario scenario
57
46
  scenario
@@ -61,7 +50,7 @@ module RR
61
50
  # in object and method_name.
62
51
  # When a Double is created, it binds the dispatcher to the
63
52
  # object.
64
- def create_double(object, method_name)
53
+ def double(object, method_name)
65
54
  double = @doubles[object][method_name.to_sym]
66
55
  return double if double
67
56
 
@@ -124,15 +113,6 @@ module RR
124
113
  end
125
114
 
126
115
  protected
127
- def setup_creator(klass, subject, method_name, definition)
128
- if method_name && definition
129
- raise ArgumentError, "Cannot pass in a method name and a block"
130
- end
131
- creator = klass.new(self, subject, &definition)
132
- return creator unless method_name
133
- creator.__send__(method_name)
134
- end
135
-
136
116
  # Removes the ordered Scenarios from the list
137
117
  def reset_ordered_scenarios
138
118
  @ordered_scenarios.clear
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.3
3
3
  specification_version: 1
4
4
  name: rr
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.2.5
7
- date: 2007-07-21 00:00:00 -07:00
6
+ version: 0.3.0
7
+ date: 2007-07-22 00:00:00 -07:00
8
8
  summary: RR (Double Ruby) is a double framework that features a rich selection of double techniques and a terse syntax. http://xunitpatterns.com/Test%20Double.html
9
9
  require_paths:
10
10
  - lib
@@ -33,17 +33,13 @@ files:
33
33
  - CHANGES
34
34
  - README
35
35
  - lib/rr.rb
36
- - lib/rr/mock_probe_creator.rb
36
+ - lib/rr/scenario_method_proxy.rb
37
37
  - lib/rr/scenario.rb
38
38
  - lib/rr/hash_with_object_id_key.rb
39
- - lib/rr/creator.rb
40
- - lib/rr/stub_probe_creator.rb
41
39
  - lib/rr/scenario_matches.rb
42
- - lib/rr/stub_creator.rb
43
40
  - lib/rr/space.rb
44
41
  - lib/rr/double.rb
45
- - lib/rr/do_not_allow_creator.rb
46
- - lib/rr/mock_creator.rb
42
+ - lib/rr/scenario_creator.rb
47
43
  - lib/rr/times_called_matchers/any_times_matcher.rb
48
44
  - lib/rr/times_called_matchers/at_most_matcher.rb
49
45
  - lib/rr/times_called_matchers/times_called_matcher.rb
@@ -61,6 +57,7 @@ files:
61
57
  - lib/rr/errors/scenario_order_error.rb
62
58
  - lib/rr/errors/rr_error.rb
63
59
  - lib/rr/errors/times_called_error.rb
60
+ - lib/rr/errors/scenario_definition_error.rb
64
61
  - lib/rr/adapters/test_unit.rb
65
62
  - lib/rr/adapters/rspec.rb
66
63
  - lib/rr/wildcard_matchers/boolean.rb
@@ -77,12 +74,9 @@ files:
77
74
  - examples/example_helper.rb
78
75
  - examples/test_unit_example_suite.rb
79
76
  - examples/high_level_example.rb
80
- - examples/rr/stub_probe_creator_example.rb
81
- - examples/rr/mock_creator_example.rb
82
- - examples/rr/stub_creator_example.rb
77
+ - examples/rr/scenario_method_proxy_example.rb
83
78
  - examples/rr/scenario_example.rb
84
- - examples/rr/do_not_allow_creator_example.rb
85
- - examples/rr/mock_probe_creator_example.rb
79
+ - examples/rr/scenario_creator_example.rb
86
80
  - examples/rr/rspec/rspec_backtrace_tweaking_example.rb
87
81
  - examples/rr/rspec/rspec_adapter_example.rb
88
82
  - examples/rr/rspec/rspec_usage_example.rb
@@ -1,111 +0,0 @@
1
- require "examples/example_helper"
2
-
3
- module RR
4
- describe DoNotAllowCreator, :shared => true do
5
- before(:each) do
6
- @space = Space.new
7
- @subject = Object.new
8
- end
9
-
10
- it "initializes creator with passed in object" do
11
- class << @creator
12
- attr_reader :subject
13
- end
14
- @creator.subject.should === @subject
15
- end
16
- end
17
-
18
- describe DoNotAllowCreator, ".new" do
19
- it_should_behave_like "RR::DoNotAllowCreator"
20
-
21
- before do
22
- @creator = DoNotAllowCreator.new(@space, @subject)
23
- end
24
-
25
- it "clears out all methods from creator" do
26
- creator_subclass = Class.new(DoNotAllowCreator) do
27
- def i_should_be_a_scenario
28
- end
29
- end
30
- creator_subclass.instance_methods.should include('i_should_be_a_scenario')
31
-
32
- creator = creator_subclass.new(@space, @subject)
33
- creator.i_should_be_a_scenario.should be_instance_of(Scenario)
34
- end
35
- end
36
-
37
- describe DoNotAllowCreator, ".new with block" do
38
- it_should_behave_like "RR::DoNotAllowCreator"
39
-
40
- before do
41
- @creator = DoNotAllowCreator.new(@space, @subject) do |c|
42
- c.any_args
43
- c.no_args.with_no_args
44
- c.with_args(1, 2)
45
- end
46
- end
47
-
48
- it "raises TimesCalledError when any_args is called with no arguments" do
49
- proc {@subject.any_args}.should raise_error(Errors::TimesCalledError)
50
- end
51
-
52
- it "raises TimesCalledError when any_args is called with arguments" do
53
- proc {@subject.any_args(1, 2)}.should raise_error(Errors::TimesCalledError)
54
- end
55
-
56
- it "raises TimesCalledError when no_args is called with no arguments" do
57
- proc {@subject.no_args}.should raise_error(Errors::TimesCalledError)
58
- end
59
-
60
- it "does not raise TimesCalledError when no_args is called with arguments" do
61
- proc {@subject.no_args(1, 2)}.should raise_error(Errors::ScenarioNotFoundError)
62
- end
63
-
64
- it "raises TimesCalledError when any_args is called with no arguments" do
65
- proc {@subject.with_args}.should raise_error(Errors::ScenarioNotFoundError)
66
- end
67
-
68
- it "raises TimesCalledError when any_args is called with arguments" do
69
- proc {@subject.any_args(1, 2)}.should raise_error(Errors::TimesCalledError)
70
- end
71
-
72
- it "clears out all methods from creator" do
73
- creator_subclass = Class.new(DoNotAllowCreator) do
74
- def i_should_be_a_scenario
75
- end
76
- end
77
- creator_subclass.instance_methods.should include('i_should_be_a_scenario')
78
-
79
- creator = creator_subclass.new(@space, @subject)
80
- creator.i_should_be_a_scenario.should be_instance_of(Scenario)
81
- end
82
- end
83
-
84
- describe DoNotAllowCreator, "#method_missing" do
85
- it_should_behave_like "RR::DoNotAllowCreator"
86
-
87
- before do
88
- @subject = Object.new
89
- @creator = DoNotAllowCreator.new(@space, @subject)
90
- end
91
-
92
- it "sets expectation for method to never be called with any arguments when on arguments passed in" do
93
- @creator.foobar
94
- proc {@subject.foobar}.should raise_error(Errors::TimesCalledError)
95
- proc {@subject.foobar(1, 2)}.should raise_error(Errors::TimesCalledError)
96
- end
97
-
98
- it "sets expectation for method to never be called with passed in arguments" do
99
- @creator.foobar(1, 2)
100
- proc {@subject.foobar}.should raise_error(Errors::ScenarioNotFoundError)
101
- proc {@subject.foobar(1, 2)}.should raise_error(Errors::TimesCalledError)
102
- end
103
-
104
- it "sets expectation for method to never be called with no arguments when with_no_args is set" do
105
- @creator.foobar.with_no_args
106
- proc {@subject.foobar}.should raise_error(Errors::TimesCalledError)
107
- proc {@subject.foobar(1, 2)}.should raise_error(Errors::ScenarioNotFoundError)
108
- end
109
- end
110
-
111
- end