rr 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/CHANGES +1 -0
  2. data/README +45 -0
  3. data/Rakefile +60 -0
  4. data/examples/environment_fixture_setup.rb +7 -0
  5. data/examples/example_helper.rb +8 -0
  6. data/examples/example_suite.rb +45 -0
  7. data/examples/high_level_example.rb +132 -0
  8. data/examples/rr/do_not_allow_creator_example.rb +90 -0
  9. data/examples/rr/double_bind_example.rb +32 -0
  10. data/examples/rr/double_dispatching_example.rb +167 -0
  11. data/examples/rr/double_example.rb +67 -0
  12. data/examples/rr/double_register_scenario_example.rb +25 -0
  13. data/examples/rr/double_reset_example.rb +60 -0
  14. data/examples/rr/double_verify_example.rb +24 -0
  15. data/examples/rr/expectations/any_argument_expectation_example.rb +43 -0
  16. data/examples/rr/expectations/anything_argument_equality_expectation_example.rb +39 -0
  17. data/examples/rr/expectations/argument_equality_expectation_example.rb +53 -0
  18. data/examples/rr/expectations/boolean_argument_equality_expectation_example.rb +49 -0
  19. data/examples/rr/expectations/duck_type_argument_equality_expectation_example.rb +68 -0
  20. data/examples/rr/expectations/is_a_argument_equality_expectation_example.rb +51 -0
  21. data/examples/rr/expectations/numeric_argument_equality_expectation_example.rb +47 -0
  22. data/examples/rr/expectations/range_argument_equality_expectation_example.rb +60 -0
  23. data/examples/rr/expectations/regexp_argument_equality_expectation_example.rb +68 -0
  24. data/examples/rr/expectations/times_called_expectation_example.rb +176 -0
  25. data/examples/rr/extensions/double_methods_example.rb +130 -0
  26. data/examples/rr/mock_creator_example.rb +65 -0
  27. data/examples/rr/probe_creator_example.rb +83 -0
  28. data/examples/rr/rspec/rspec_adapter_example.rb +64 -0
  29. data/examples/rr/rspec/rspec_usage_example.rb +38 -0
  30. data/examples/rr/scenario_example.rb +399 -0
  31. data/examples/rr/space_create_example.rb +185 -0
  32. data/examples/rr/space_example.rb +30 -0
  33. data/examples/rr/space_helper.rb +7 -0
  34. data/examples/rr/space_register_example.rb +33 -0
  35. data/examples/rr/space_reset_example.rb +73 -0
  36. data/examples/rr/space_verify_example.rb +146 -0
  37. data/examples/rr/stub_creator_example.rb +74 -0
  38. data/examples/rr/test_unit/test_helper.rb +9 -0
  39. data/examples/rr/test_unit/test_unit_integration_test.rb +39 -0
  40. data/examples/rspec_example_suite.rb +25 -0
  41. data/examples/test_unit_example_suite.rb +21 -0
  42. data/lib/rr.rb +27 -0
  43. data/lib/rr/adapters/rspec.rb +19 -0
  44. data/lib/rr/adapters/test_unit.rb +27 -0
  45. data/lib/rr/do_not_allow_creator.rb +39 -0
  46. data/lib/rr/double.rb +91 -0
  47. data/lib/rr/expectations/any_argument_expectation.rb +17 -0
  48. data/lib/rr/expectations/argument_equality_expectation.rb +35 -0
  49. data/lib/rr/expectations/times_called_expectation.rb +39 -0
  50. data/lib/rr/expectations/wildcard_matchers/anything.rb +15 -0
  51. data/lib/rr/expectations/wildcard_matchers/boolean.rb +20 -0
  52. data/lib/rr/expectations/wildcard_matchers/duck_type.rb +26 -0
  53. data/lib/rr/expectations/wildcard_matchers/is_a.rb +22 -0
  54. data/lib/rr/expectations/wildcard_matchers/numeric.rb +11 -0
  55. data/lib/rr/expectations/wildcard_matchers/range.rb +7 -0
  56. data/lib/rr/expectations/wildcard_matchers/regexp.rb +7 -0
  57. data/lib/rr/extensions/double_methods.rb +81 -0
  58. data/lib/rr/mock_creator.rb +32 -0
  59. data/lib/rr/probe_creator.rb +31 -0
  60. data/lib/rr/scenario.rb +184 -0
  61. data/lib/rr/scenario_not_found_error.rb +4 -0
  62. data/lib/rr/scenario_order_error.rb +4 -0
  63. data/lib/rr/space.rb +111 -0
  64. data/lib/rr/stub_creator.rb +36 -0
  65. metadata +113 -0
@@ -0,0 +1,15 @@
1
+ module RR
2
+ module Expectations
3
+ module WildcardMatchers
4
+ class Anything
5
+ def wildcard_match?(other)
6
+ true
7
+ end
8
+
9
+ def ==(other)
10
+ other.is_a?(self.class)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,20 @@
1
+ module RR
2
+ module Expectations
3
+ module WildcardMatchers
4
+ class Boolean
5
+ def wildcard_match?(other)
6
+ self == other || is_a_boolean?(other)
7
+ end
8
+
9
+ def ==(other)
10
+ other.is_a?(self.class)
11
+ end
12
+
13
+ protected
14
+ def is_a_boolean?(subject)
15
+ subject.is_a?(TrueClass) || subject.is_a?(FalseClass)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,26 @@
1
+ module RR
2
+ module Expectations
3
+ module WildcardMatchers
4
+ class DuckType
5
+ attr_accessor :required_methods
6
+
7
+ def initialize(*required_methods)
8
+ @required_methods = required_methods
9
+ end
10
+
11
+ def wildcard_match?(other)
12
+ return true if self == other
13
+ required_methods.each do |m|
14
+ return false unless other.respond_to?(m)
15
+ end
16
+ return true
17
+ end
18
+
19
+ def ==(other)
20
+ return false unless other.is_a?(self.class)
21
+ self.required_methods == other.required_methods
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,22 @@
1
+ module RR
2
+ module Expectations
3
+ module WildcardMatchers
4
+ class IsA
5
+ attr_reader :klass
6
+
7
+ def initialize(klass)
8
+ @klass = klass
9
+ end
10
+
11
+ def wildcard_match?(other)
12
+ self == other || other.is_a?(klass)
13
+ end
14
+
15
+ def ==(other)
16
+ return false unless other.is_a?(self.class)
17
+ self.klass == other.klass
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,11 @@
1
+ module RR
2
+ module Expectations
3
+ module WildcardMatchers
4
+ class Numeric < IsA
5
+ def initialize
6
+ @klass = ::Numeric
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,7 @@
1
+ class Range
2
+ def wildcard_match?(other)
3
+ return true if self == other
4
+ return false unless other.is_a?(Numeric)
5
+ self.include?(other)
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ class Regexp
2
+ def wildcard_match?(other)
3
+ return true if self == other
4
+ return false unless other.is_a?(String)
5
+ (other =~ self) ? true : false
6
+ end
7
+ end
@@ -0,0 +1,81 @@
1
+ module RR
2
+ module Extensions
3
+ module DoubleMethods
4
+ # Sets up a MockCreator that generates a Double Scenario that
5
+ # acts like a mock.
6
+ # mock(object).method_name(arg1, arg2) {return_value}
7
+ def mock(subject, &definition)
8
+ RR::Space.instance.create_mock_creator(subject, &definition)
9
+ end
10
+
11
+ # Sets up a StubCreator that generates a Double Scenario that
12
+ # acts like a stub.
13
+ # stub(object).method_name {return_value}
14
+ def stub(subject, &definition)
15
+ RR::Space.instance.create_stub_creator(subject, &definition)
16
+ end
17
+
18
+ # Sets up a ProbeCreator that generates a Double Scenario that
19
+ # acts like a probe.
20
+ # probe(controller.template).render(:partial => "my/socks")
21
+ def probe(subject, &definition)
22
+ RR::Space.instance.create_probe_creator(subject, &definition)
23
+ end
24
+
25
+ # Sets up a DoNotAllowCreator that generates a Double Scenario that
26
+ # expects never to be called.
27
+ # do_not_allow(object).method_name
28
+ def do_not_allow(subject, &definition)
29
+ RR::Space.instance.create_do_not_allow_creator(subject, &definition)
30
+ end
31
+ alias_method :dont_allow, :do_not_allow
32
+
33
+ # Sets up an Anything wildcard ArgumentEqualityExpectation
34
+ # that succeeds when passed any argument.
35
+ # mock(object).method_name(anything) {return_value}
36
+ # object.method_name("an arbitrary value") # passes
37
+ def anything
38
+ RR::Expectations::WildcardMatchers::Anything.new
39
+ end
40
+
41
+ # Sets up an IsA wildcard ArgumentEqualityExpectation
42
+ # that succeeds when passed an argument of a certain type.
43
+ # mock(object).method_name(is_a(String)) {return_value}
44
+ # object.method_name("A String") # passes
45
+ def is_a(klass)
46
+ RR::Expectations::WildcardMatchers::IsA.new(klass)
47
+ end
48
+
49
+ # Sets up an Numeric wildcard ArgumentEqualityExpectation
50
+ # that succeeds when passed an argument that is ::Numeric.
51
+ # mock(object).method_name(numeric) {return_value}
52
+ # object.method_name(99) # passes
53
+ def numeric
54
+ RR::Expectations::WildcardMatchers::Numeric.new
55
+ end
56
+
57
+ # Sets up an Boolean wildcard ArgumentEqualityExpectation
58
+ # that succeeds when passed an argument that is a ::Boolean.
59
+ # mock(object).method_name(boolean) {return_value}
60
+ # object.method_name(false) # passes
61
+ def boolean
62
+ RR::Expectations::WildcardMatchers::Boolean.new
63
+ end
64
+
65
+ # Sets up a DuckType wildcard ArgumentEqualityExpectation
66
+ # that succeeds when passed the argument implements the methods.
67
+ # arg = Object.new
68
+ # def arg.foo; end
69
+ # def arg.bar; end
70
+ # mock(object).method_name(duck_type(:foo, :bar)) {return_value}
71
+ # object.method_name(arg) # passes
72
+ def duck_type(*args)
73
+ RR::Expectations::WildcardMatchers::DuckType.new(*args)
74
+ end
75
+
76
+ instance_methods.each do |name|
77
+ alias_method "rr_#{name}", name
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,32 @@
1
+ module RR
2
+ # RR::MockCreator uses RR::MockCreator#method_missing to create
3
+ # a Scenario that acts like a mock.
4
+ #
5
+ # The following example mocks method_name with arg1 and arg2
6
+ # returning return_value.
7
+ #
8
+ # mock(subject).method_name(arg1, arg2) { return_value }
9
+ #
10
+ # The MockCreator also supports a block sytnax.
11
+ #
12
+ # mock(subject) do |m|
13
+ # m.method_name(arg1, arg2) { return_value }
14
+ # end
15
+ class MockCreator
16
+ instance_methods.each { |m| undef_method m unless m =~ /^__/ }
17
+
18
+ def initialize(space, subject)
19
+ @space = space
20
+ @subject = subject
21
+ yield(self) if block_given?
22
+ end
23
+
24
+ protected
25
+ def method_missing(method_name, *args, &returns)
26
+ double = @space.create_double(@subject, method_name)
27
+ scenario = @space.create_scenario(double)
28
+ scenario.with(*args).once.returns(&returns)
29
+ scenario
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,31 @@
1
+ module RR
2
+ # RR::ProbeCreator uses RR::ProbeCreator#method_missing to create
3
+ # a Scenario that acts like a probe.
4
+ #
5
+ # The following example probes method_name with arg1 and arg2
6
+ # returning return_value.
7
+ #
8
+ # probe(subject).method_name(arg1, arg2) { return_value }
9
+ #
10
+ # The ProbeCreator also supports a block sytnax.
11
+ #
12
+ # probe(subject) do |m|
13
+ # m.method_name(arg1, arg2) { return_value }
14
+ # end
15
+ class ProbeCreator
16
+ instance_methods.each { |m| undef_method m unless m =~ /^__/ }
17
+
18
+ def initialize(space, subject)
19
+ @space = space
20
+ @subject = subject
21
+ yield(self) if block_given?
22
+ end
23
+
24
+ protected
25
+ def method_missing(method_name, *args, &returns)
26
+ double = @space.create_double(@subject, method_name)
27
+ scenario = @space.create_scenario(double)
28
+ scenario.with(*args).once.implemented_by(double.original_method)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,184 @@
1
+ module RR
2
+ # RR::Scenario is the use case for a method call.
3
+ # It has the ArgumentEqualityExpectation, TimesCalledExpectation,
4
+ # and the implementation.
5
+ class Scenario
6
+ attr_reader :times_called, :argument_expectation, :times_called_expectation
7
+
8
+ def initialize(space)
9
+ @space = space
10
+ @implementation = nil
11
+ @argument_expectation = nil
12
+ @times_called_expectation = nil
13
+ @times_called = 0
14
+ end
15
+
16
+ # Scenario#with creates an ArgumentEqualityExpectation for the
17
+ # Scenario. it takes a list of expected arguments.
18
+ #
19
+ # Passing in a block sets the return value.
20
+ #
21
+ # mock(subject).method_name.with(1, 2) {:return_value}
22
+ def with(*args, &returns)
23
+ @argument_expectation = Expectations::ArgumentEqualityExpectation.new(*args)
24
+ returns(&returns) if returns
25
+ self
26
+ end
27
+
28
+ # Scenario#with_any_args creates an AnyArgumentEqualityExpectation
29
+ # for the Scenario.
30
+ #
31
+ # Passing in a block sets the return value.
32
+ #
33
+ # mock(subject).method_name.with_any_args {:return_value}
34
+ def with_any_args(&returns)
35
+ @argument_expectation = Expectations::AnyArgumentExpectation.new
36
+ returns(&returns) if returns
37
+ self
38
+ end
39
+
40
+ # Scenario#with_no_args creates an ArgumentEqualityExpectation with
41
+ # no arguments for the Scenario.
42
+ #
43
+ # Passing in a block sets the return value.
44
+ #
45
+ # mock(subject).method_name.with_no_args {:return_value}
46
+ def with_no_args(&returns)
47
+ @argument_expectation = Expectations::ArgumentEqualityExpectation.new()
48
+ returns(&returns) if returns
49
+ self
50
+ end
51
+
52
+ # Scenario#never creates an TimesCalledExpectation of 0.
53
+ #
54
+ # This method does not accept a block because it will never be called.
55
+ #
56
+ # mock(subject).method_name.never
57
+ def never
58
+ @times_called_expectation = Expectations::TimesCalledExpectation.new(0)
59
+ self
60
+ end
61
+
62
+ # Scenario#once creates an TimesCalledExpectation of 1.
63
+ #
64
+ # Passing in a block sets the return value.
65
+ #
66
+ # mock(subject).method_name.once {:return_value}
67
+ def once(&returns)
68
+ @times_called_expectation = Expectations::TimesCalledExpectation.new(1)
69
+ returns(&returns) if returns
70
+ self
71
+ end
72
+
73
+ # Scenario#twice creates an TimesCalledExpectation of 2.
74
+ #
75
+ # Passing in a block sets the return value.
76
+ #
77
+ # mock(subject).method_name.twice {:return_value}
78
+ def twice(&returns)
79
+ @times_called_expectation = Expectations::TimesCalledExpectation.new(2)
80
+ returns(&returns) if returns
81
+ self
82
+ end
83
+
84
+ # Scenario#twice creates an TimesCalledExpectation of the passed
85
+ # in number.
86
+ #
87
+ # Passing in a block sets the return value.
88
+ #
89
+ # mock(subject).method_name.times(4) {:return_value}
90
+ def times(number, &returns)
91
+ @times_called_expectation = Expectations::TimesCalledExpectation.new(number)
92
+ returns(&returns) if returns
93
+ self
94
+ end
95
+
96
+ # Scenario#ordered sets the Scenario to have an ordered
97
+ # expectation.
98
+ #
99
+ # Passing in a block sets the return value.
100
+ #
101
+ # mock(subject).method_name.ordered {return_value}
102
+ def ordered(&returns)
103
+ @ordered = true
104
+ @space.ordered_scenarios << self unless @space.ordered_scenarios.include?(self)
105
+ returns(&returns) if returns
106
+ self
107
+ end
108
+
109
+ # Scenario#ordered? returns true when the Scenario is ordered.
110
+ #
111
+ # mock(subject).method_name.ordered?
112
+ def ordered?
113
+ @ordered
114
+ end
115
+
116
+ # Scenario#returns causes Scenario to return the return value of
117
+ # the passed in block.
118
+ def returns(&implementation)
119
+ implemented_by implementation
120
+ end
121
+
122
+ # Scenario#implemented_by sets the implementation of the Scenario.
123
+ # This method takes a Proc or a Method. Passing in a Method allows
124
+ # the Scenario to accept blocks.
125
+ #
126
+ # obj = Object.new
127
+ # def obj.foobar
128
+ # yield(1)
129
+ # end
130
+ # mock(obj).method_name.implemented_by(obj.method(:foobar))
131
+ def implemented_by(implementation)
132
+ @implementation = implementation
133
+ self
134
+ end
135
+
136
+ # Scenario#call calls the Scenario's implementation. The return
137
+ # value of the implementation is returned.
138
+ #
139
+ # A TimesCalledExpectationError is raised when the times called
140
+ # exceeds the expected TimesCalledExpectation.
141
+ def call(*args, &block)
142
+ @times_called_expectation.verify_input if @times_called_expectation
143
+ @space.verify_ordered_scenario(self) if ordered?
144
+ return nil unless @implementation
145
+
146
+ if @implementation.is_a?(Method)
147
+ return @implementation.call(*args, &block)
148
+ else
149
+ args << block if block
150
+ return @implementation.call(*args)
151
+ end
152
+ end
153
+
154
+ # Scenario#exact_match? returns true when the passed in arguments
155
+ # exactly match the ArgumentEqualityExpectation arguments.
156
+ def exact_match?(*arguments)
157
+ return false unless @argument_expectation
158
+ @argument_expectation.exact_match?(*arguments)
159
+ end
160
+
161
+ # Scenario#wildcard_match? returns true when the passed in arguments
162
+ # wildcard match the ArgumentEqualityExpectation arguments.
163
+ def wildcard_match?(*arguments)
164
+ return false unless @argument_expectation
165
+ @argument_expectation.wildcard_match?(*arguments)
166
+ end
167
+
168
+ # Scenario#times_called_verified? returns true when the
169
+ # TimesCalledExpectation is satisfied.
170
+ def times_called_verified?
171
+ return false unless @times_called_expectation
172
+ @times_called_expectation.verify
173
+ end
174
+
175
+ # Scenario#verify verifies the the TimesCalledExpectation
176
+ # is satisfied for this scenario. A TimesCalledExpectationError
177
+ # is raised if the TimesCalledExpectation is not met.
178
+ def verify
179
+ return true unless @times_called_expectation
180
+ @times_called_expectation.verify!
181
+ true
182
+ end
183
+ end
184
+ end