rr 0.1.6 → 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. data/CHANGES +7 -0
  2. data/Rakefile +1 -1
  3. data/examples/environment_fixture_setup.rb +1 -1
  4. data/examples/example_helper.rb +1 -0
  5. data/examples/high_level_example.rb +1 -2
  6. data/examples/rr/do_not_allow_creator_example.rb +1 -2
  7. data/examples/rr/double_bind_example.rb +1 -2
  8. data/examples/rr/double_dispatching_example.rb +2 -3
  9. data/examples/rr/double_example.rb +1 -2
  10. data/examples/rr/double_register_scenario_example.rb +1 -2
  11. data/examples/rr/double_reset_example.rb +1 -2
  12. data/examples/rr/double_verify_example.rb +1 -2
  13. data/examples/rr/errors/rr_error_example.rb +1 -2
  14. data/examples/rr/expectations/any_argument_expectation_example.rb +1 -2
  15. data/examples/rr/expectations/anything_argument_equality_expectation_example.rb +1 -2
  16. data/examples/rr/expectations/argument_equality_expectation_example.rb +1 -2
  17. data/examples/rr/expectations/boolean_argument_equality_expectation_example.rb +1 -2
  18. data/examples/rr/expectations/duck_type_argument_equality_expectation_example.rb +1 -2
  19. data/examples/rr/expectations/is_a_argument_equality_expectation_example.rb +1 -2
  20. data/examples/rr/expectations/numeric_argument_equality_expectation_example.rb +1 -2
  21. data/examples/rr/expectations/range_argument_equality_expectation_example.rb +1 -2
  22. data/examples/rr/expectations/regexp_argument_equality_expectation_example.rb +1 -2
  23. data/examples/rr/expectations/times_called_expectation/times_called_expectation_at_least_example.rb +74 -0
  24. data/examples/rr/expectations/times_called_expectation/times_called_expectation_at_most_example.rb +69 -0
  25. data/examples/rr/expectations/times_called_expectation/times_called_expectation_helper.rb +18 -0
  26. data/examples/rr/expectations/times_called_expectation/times_called_expectation_integer_example.rb +102 -0
  27. data/examples/rr/expectations/times_called_expectation/times_called_expectation_proc_example.rb +80 -0
  28. data/examples/rr/expectations/times_called_expectation/times_called_expectation_range_example.rb +81 -0
  29. data/examples/rr/expectations/times_called_expectation_example.rb +1 -185
  30. data/examples/rr/extensions/double_methods_example.rb +3 -4
  31. data/examples/rr/mock_creator_example.rb +1 -2
  32. data/examples/rr/probe_creator_example.rb +1 -2
  33. data/examples/rr/rspec/rspec_adapter_example.rb +1 -2
  34. data/examples/rr/rspec/rspec_backtrace_tweaking_example.rb +1 -2
  35. data/examples/rr/rspec/rspec_usage_example.rb +1 -2
  36. data/examples/rr/scenario_example.rb +60 -15
  37. data/examples/rr/space_create_example.rb +1 -2
  38. data/examples/rr/space_example.rb +1 -2
  39. data/examples/rr/space_register_example.rb +1 -2
  40. data/examples/rr/space_reset_example.rb +51 -4
  41. data/examples/rr/space_verify_example.rb +4 -5
  42. data/examples/rr/stub_creator_example.rb +1 -2
  43. data/examples/rr/test_unit/test_helper.rb +1 -1
  44. data/examples/rr/times_called_matchers/at_least_matcher_example.rb +74 -0
  45. data/examples/rr/times_called_matchers/at_most_matcher_example.rb +82 -0
  46. data/examples/rr/times_called_matchers/integer_matcher_example.rb +88 -0
  47. data/examples/rr/times_called_matchers/proc_matcher_example.rb +74 -0
  48. data/examples/rr/times_called_matchers/range_matcher_example.rb +94 -0
  49. data/examples/rr/times_called_matchers/times_called_matcher_example.rb +53 -0
  50. data/lib/rr.rb +15 -7
  51. data/lib/rr/adapters/rspec.rb +2 -2
  52. data/lib/rr/adapters/test_unit.rb +1 -1
  53. data/lib/rr/double.rb +2 -2
  54. data/lib/rr/expectations/times_called_expectation.rb +14 -13
  55. data/lib/rr/extensions/double_methods.rb +5 -5
  56. data/lib/rr/scenario.rb +35 -7
  57. data/lib/rr/space.rb +20 -8
  58. data/lib/rr/times_called_matchers/at_least_matcher.rb +22 -0
  59. data/lib/rr/times_called_matchers/at_most_matcher.rb +22 -0
  60. data/lib/rr/times_called_matchers/integer_matcher.rb +17 -0
  61. data/lib/rr/times_called_matchers/proc_matcher.rb +17 -0
  62. data/lib/rr/times_called_matchers/range_matcher.rb +19 -0
  63. data/lib/rr/times_called_matchers/times_called_matcher.rb +44 -0
  64. data/lib/rr/wildcard_matchers/anything.rb +13 -0
  65. data/lib/rr/wildcard_matchers/boolean.rb +18 -0
  66. data/lib/rr/wildcard_matchers/duck_type.rb +24 -0
  67. data/lib/rr/wildcard_matchers/is_a.rb +20 -0
  68. data/lib/rr/wildcard_matchers/numeric.rb +9 -0
  69. data/lib/rr/{expectations/wildcard_matchers → wildcard_matchers}/range.rb +0 -0
  70. data/lib/rr/{expectations/wildcard_matchers → wildcard_matchers}/regexp.rb +0 -0
  71. metadata +27 -9
  72. data/lib/rr/expectations/wildcard_matchers/anything.rb +0 -15
  73. data/lib/rr/expectations/wildcard_matchers/boolean.rb +0 -20
  74. data/lib/rr/expectations/wildcard_matchers/duck_type.rb +0 -26
  75. data/lib/rr/expectations/wildcard_matchers/is_a.rb +0 -22
  76. data/lib/rr/expectations/wildcard_matchers/numeric.rb +0 -11
@@ -0,0 +1,94 @@
1
+ require "examples/example_helper"
2
+
3
+ module RR
4
+ module TimesCalledMatchers
5
+ describe TimesCalledMatcher, ".create when passed a IntegerMatcher" do
6
+ it "returns the passed in argument" do
7
+ matcher = RangeMatcher.new(2..4)
8
+ TimesCalledMatcher.create(matcher).should === matcher
9
+ end
10
+ end
11
+
12
+ describe TimesCalledMatcher, ".create when passed a Integer" do
13
+ it "returns RangeMatcher" do
14
+ TimesCalledMatcher.create(2..4).should == RangeMatcher.new(2..4)
15
+ end
16
+ end
17
+
18
+ describe RangeMatcher, "#possible_match?" do
19
+ before do
20
+ @times = 2..4
21
+ @matcher = RangeMatcher.new(@times)
22
+ end
23
+
24
+ it "returns true when times called < start of range" do
25
+ @matcher.should be_possible_match(1)
26
+ end
27
+
28
+ it "returns true when times called in range" do
29
+ @matcher.should be_possible_match(2)
30
+ @matcher.should be_possible_match(3)
31
+ @matcher.should be_possible_match(4)
32
+ end
33
+
34
+ it "returns false when times called > end of range" do
35
+ @matcher.should_not be_possible_match(5)
36
+ end
37
+ end
38
+
39
+ describe RangeMatcher, "#matches?" do
40
+ before do
41
+ @times = 2..4
42
+ @matcher = RangeMatcher.new(@times)
43
+ end
44
+
45
+ it "returns false when times_called less than start of range" do
46
+ @matcher.should_not be_matches(1)
47
+ end
48
+
49
+ it "returns true when times_called in range" do
50
+ @matcher.should be_matches(2)
51
+ @matcher.should be_matches(3)
52
+ @matcher.should be_matches(4)
53
+ end
54
+
55
+ it "returns false when times_called > end of range" do
56
+ @matcher.should_not be_matches(5)
57
+ end
58
+ end
59
+
60
+ describe RangeMatcher, "#attempt?" do
61
+ before do
62
+ @times = 2..4
63
+ @matcher = RangeMatcher.new(@times)
64
+ end
65
+
66
+ it "returns true when less than start of range" do
67
+ @matcher.should be_attempt(1)
68
+ end
69
+
70
+ it "returns true when in range" do
71
+ @matcher.should be_attempt(2)
72
+ @matcher.should be_attempt(3)
73
+ @matcher.should be_attempt(4)
74
+ end
75
+
76
+ it "returns false when > end of range" do
77
+ @matcher.should_not be_attempt(5)
78
+ end
79
+ end
80
+
81
+ describe RangeMatcher, "#error_message" do
82
+ before do
83
+ @times = 2..4
84
+ @matcher = RangeMatcher.new(@times)
85
+ end
86
+
87
+ it "has an error message" do
88
+ @matcher.error_message(1).should == (
89
+ "Called 1 time. Expected 2..4 times."
90
+ )
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,53 @@
1
+ require "examples/example_helper"
2
+
3
+ module RR
4
+ module TimesCalledMatchers
5
+ describe TimesCalledMatcher, ".create when passed a TimesCalledMatcher" do
6
+ it "returns the passed in argument" do
7
+ matcher = TimesCalledMatcher.new(5)
8
+ TimesCalledMatcher.create(matcher).should === matcher
9
+ end
10
+ end
11
+
12
+ describe TimesCalledMatcher, ".create when passed an unsupported type" do
13
+ it "raises an ArgumentError" do
14
+ matcher = Object.new
15
+ proc do
16
+ TimesCalledMatcher.create(matcher)
17
+ end.should raise_error(ArgumentError, "There is no TimesCalledMatcher for #{matcher.inspect}.")
18
+ end
19
+ end
20
+
21
+ describe TimesCalledMatcher, "#error_message" do
22
+ before do
23
+ @times = 3
24
+ @matcher = TimesCalledMatcher.new(@times)
25
+ end
26
+
27
+ it "has an error message" do
28
+ @matcher.error_message(5).should == (
29
+ "Called 5 times. Expected 3 times."
30
+ )
31
+ end
32
+ end
33
+
34
+ describe TimesCalledMatcher, "#==" do
35
+ before do
36
+ @times = 3
37
+ @matcher = TimesCalledMatcher.new(@times)
38
+ end
39
+
40
+ it "returns true when other is the same class and times are ==" do
41
+ @matcher.should == TimesCalledMatcher.new(@times)
42
+ end
43
+
44
+ it "returns false when other is a different class and times are ==" do
45
+ @matcher.should_not == IntegerMatcher.new(@times)
46
+ end
47
+
48
+ it "returns false when is the same class and times are not ==" do
49
+ @matcher.should_not == TimesCalledMatcher.new(1)
50
+ end
51
+ end
52
+ end
53
+ end
data/lib/rr.rb CHANGED
@@ -19,12 +19,20 @@ require "rr/errors/times_called_error"
19
19
  require "rr/expectations/argument_equality_expectation"
20
20
  require "rr/expectations/any_argument_expectation"
21
21
  require "rr/expectations/times_called_expectation"
22
- require "rr/expectations/wildcard_matchers/anything"
23
- require "rr/expectations/wildcard_matchers/is_a"
24
- require "rr/expectations/wildcard_matchers/numeric"
25
- require "rr/expectations/wildcard_matchers/boolean"
26
- require "rr/expectations/wildcard_matchers/duck_type"
27
- require "rr/expectations/wildcard_matchers/regexp"
28
- require "rr/expectations/wildcard_matchers/range"
22
+
23
+ require "rr/wildcard_matchers/anything"
24
+ require "rr/wildcard_matchers/is_a"
25
+ require "rr/wildcard_matchers/numeric"
26
+ require "rr/wildcard_matchers/boolean"
27
+ require "rr/wildcard_matchers/duck_type"
28
+ require "rr/wildcard_matchers/regexp"
29
+ require "rr/wildcard_matchers/range"
30
+
31
+ require "rr/times_called_matchers/times_called_matcher"
32
+ require "rr/times_called_matchers/integer_matcher"
33
+ require "rr/times_called_matchers/range_matcher"
34
+ require "rr/times_called_matchers/proc_matcher"
35
+ require "rr/times_called_matchers/at_least_matcher"
36
+ require "rr/times_called_matchers/at_most_matcher"
29
37
 
30
38
  require "rr/extensions/double_methods"
@@ -6,13 +6,13 @@ module RR
6
6
  module Rspec
7
7
  include RR::Extensions::DoubleMethods
8
8
  def setup_mocks_for_rspec
9
- RR::Space.instance.reset_doubles
9
+ RR::Space.instance.reset
10
10
  end
11
11
  def verify_mocks_for_rspec
12
12
  RR::Space.instance.verify_doubles
13
13
  end
14
14
  def teardown_mocks_for_rspec
15
- RR::Space.instance.reset_doubles
15
+ RR::Space.instance.reset
16
16
  end
17
17
  end
18
18
  end
@@ -9,7 +9,7 @@ module RR
9
9
  alias_method :setup_without_rr, :setup
10
10
  def setup_with_rr
11
11
  setup_without_rr
12
- RR::Space.instance.reset_doubles
12
+ RR::Space.instance.reset
13
13
  end
14
14
  alias_method :setup, :setup_with_rr
15
15
 
data/lib/rr/double.rb CHANGED
@@ -67,13 +67,13 @@ module RR
67
67
  @scenarios.each do |scenario|
68
68
  if scenario.exact_match?(*args)
69
69
  matching_scenarios << scenario
70
- return scenario.call(*args, &block) unless scenario.times_called_verified?
70
+ return scenario.call(*args, &block) if scenario.attempt?
71
71
  end
72
72
  end
73
73
  @scenarios.each do |scenario|
74
74
  if scenario.wildcard_match?(*args)
75
75
  matching_scenarios << scenario
76
- return scenario.call(*args, &block) unless scenario.times_called_verified?
76
+ return scenario.call(*args, &block) if scenario.attempt?
77
77
  end
78
78
  end
79
79
  matching_scenarios.first.call(*args) unless matching_scenarios.empty?
@@ -1,27 +1,29 @@
1
1
  module RR
2
2
  module Expectations
3
3
  class TimesCalledExpectation
4
- attr_reader :times, :times_called
4
+ attr_reader :matcher, :times_called
5
5
 
6
- def initialize(times=nil, &time_condition_block)
7
- raise ArgumentError, "Cannot pass in both an argument and a block" if times && time_condition_block
8
- @times = times || time_condition_block
6
+ def initialize(matcher=nil, &time_condition_block)
7
+ raise ArgumentError, "Cannot pass in both an argument and a block" if matcher && time_condition_block
8
+ matcher_value = matcher || time_condition_block
9
+ @matcher = TimesCalledMatchers::TimesCalledMatcher.create(matcher_value)
9
10
  @times_called = 0
10
11
  @verify_backtrace = caller[1..-1]
11
12
  end
12
13
 
13
- def verify_input
14
+ def attempt?
15
+ @matcher.attempt?(@times_called)
16
+ end
17
+
18
+ def attempt!
14
19
  @times_called += 1
15
- verify_input_error if @times.is_a?(Integer) && @times_called > @times
16
- verify_input_error if @times.is_a?(Range) && @times_called > @times.end
20
+ verify_input_error unless @matcher.possible_match?(@times_called)
17
21
  return
18
22
  end
19
23
 
20
24
  def verify
21
- return true if @times.is_a?(Integer) && @times == @times_called
22
- return true if @times.is_a?(Proc) && @times.call(@times_called)
23
- return true if @times.is_a?(Range) && @times.include?(@times_called)
24
- return false
25
+ return false unless @matcher.is_a?(TimesCalledMatchers::TimesCalledMatcher)
26
+ return @matcher.matches?(@times_called)
25
27
  end
26
28
 
27
29
  def verify!
@@ -42,8 +44,7 @@ module RR
42
44
  end
43
45
 
44
46
  def error_message
45
- time_casing = (@times_called == 1) ? "time" : "times"
46
- "Called #{@times_called.inspect} #{time_casing}. Expected #{@times.inspect}."
47
+ @matcher.error_message(@times_called)
47
48
  end
48
49
  end
49
50
  end
@@ -35,7 +35,7 @@ module Extensions
35
35
  # mock(object).method_name(anything) {return_value}
36
36
  # object.method_name("an arbitrary value") # passes
37
37
  def anything
38
- RR::Expectations::WildcardMatchers::Anything.new
38
+ RR::WildcardMatchers::Anything.new
39
39
  end
40
40
 
41
41
  # Sets up an IsA wildcard ArgumentEqualityError
@@ -43,7 +43,7 @@ module Extensions
43
43
  # mock(object).method_name(is_a(String)) {return_value}
44
44
  # object.method_name("A String") # passes
45
45
  def is_a(klass)
46
- RR::Expectations::WildcardMatchers::IsA.new(klass)
46
+ RR::WildcardMatchers::IsA.new(klass)
47
47
  end
48
48
 
49
49
  # Sets up an Numeric wildcard ArgumentEqualityError
@@ -51,7 +51,7 @@ module Extensions
51
51
  # mock(object).method_name(numeric) {return_value}
52
52
  # object.method_name(99) # passes
53
53
  def numeric
54
- RR::Expectations::WildcardMatchers::Numeric.new
54
+ RR::WildcardMatchers::Numeric.new
55
55
  end
56
56
 
57
57
  # Sets up an Boolean wildcard ArgumentEqualityError
@@ -59,7 +59,7 @@ module Extensions
59
59
  # mock(object).method_name(boolean) {return_value}
60
60
  # object.method_name(false) # passes
61
61
  def boolean
62
- RR::Expectations::WildcardMatchers::Boolean.new
62
+ RR::WildcardMatchers::Boolean.new
63
63
  end
64
64
 
65
65
  # Sets up a DuckType wildcard ArgumentEqualityError
@@ -70,7 +70,7 @@ module Extensions
70
70
  # mock(object).method_name(duck_type(:foo, :bar)) {return_value}
71
71
  # object.method_name(arg) # passes
72
72
  def duck_type(*args)
73
- RR::Expectations::WildcardMatchers::DuckType.new(*args)
73
+ RR::WildcardMatchers::DuckType.new(*args)
74
74
  end
75
75
 
76
76
  instance_methods.each do |name|
data/lib/rr/scenario.rb CHANGED
@@ -83,7 +83,35 @@ module RR
83
83
  self
84
84
  end
85
85
 
86
- # Scenario#twice creates an TimesCalledExpectation of the passed
86
+ # Scenario#at_least allows you to set an expectation that the Scenario
87
+ # will be called at least n times.
88
+ # It works by creating a TimesCalledExpectation.
89
+ #
90
+ # Passing in a block sets the return value.
91
+ #
92
+ # mock(subject).method_name.at_least(4) {:return_value}
93
+ def at_least(number, &returns)
94
+ matcher = RR::TimesCalledMatchers::AtLeastMatcher.new(number)
95
+ @times_called_expectation = Expectations::TimesCalledExpectation.new(matcher)
96
+ returns(&returns) if returns
97
+ self
98
+ end
99
+
100
+ # Scenario#at_most allows you to set an expectation that the Scenario
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
+ matcher = RR::TimesCalledMatchers::AtMostMatcher.new(number)
109
+ @times_called_expectation = Expectations::TimesCalledExpectation.new(matcher)
110
+ returns(&returns) if returns
111
+ self
112
+ end
113
+
114
+ # Scenario#times creates an TimesCalledExpectation of the passed
87
115
  # in number.
88
116
  #
89
117
  # Passing in a block sets the return value.
@@ -188,7 +216,7 @@ module RR
188
216
  end
189
217
 
190
218
  def call_implementation(*args, &block)
191
- @times_called_expectation.verify_input if @times_called_expectation
219
+ @times_called_expectation.attempt! if @times_called_expectation
192
220
  @space.verify_ordered_scenario(self) if ordered?
193
221
  if @yields
194
222
  unless block
@@ -221,11 +249,11 @@ module RR
221
249
  @argument_expectation.wildcard_match?(*arguments)
222
250
  end
223
251
 
224
- # Scenario#times_called_verified? returns true when the
252
+ # Scenario#attempt? returns true when the
225
253
  # TimesCalledExpectation is satisfied.
226
- def times_called_verified?
227
- return false unless @times_called_expectation
228
- @times_called_expectation.verify
254
+ def attempt?
255
+ return true unless @times_called_expectation
256
+ @times_called_expectation.attempt?
229
257
  end
230
258
 
231
259
  # Scenario#verify verifies the the TimesCalledExpectation
@@ -237,4 +265,4 @@ module RR
237
265
  true
238
266
  end
239
267
  end
240
- end
268
+ end
data/lib/rr/space.rb CHANGED
@@ -73,7 +73,7 @@ module RR
73
73
  # in the correct position.
74
74
  def verify_ordered_scenario(scenario)
75
75
  raise Errors::ScenarioOrderError unless @ordered_scenarios.first == scenario
76
- @ordered_scenarios.shift if scenario.times_called_verified?
76
+ @ordered_scenarios.shift unless scenario.attempt?
77
77
  scenario
78
78
  end
79
79
 
@@ -87,13 +87,10 @@ module RR
87
87
  end
88
88
  end
89
89
 
90
- # Resets the registered Doubles for the next test run.
91
- def reset_doubles
92
- @doubles.each do |object, method_double_map|
93
- method_double_map.keys.each do |method_name|
94
- reset_double(object, method_name)
95
- end
96
- end
90
+ # Resets the registered Doubles and ordered Scenarios
91
+ def reset
92
+ reset_ordered_scenarios
93
+ reset_doubles
97
94
  end
98
95
 
99
96
  # Verifies the Double for the passed in object and method_name.
@@ -109,5 +106,20 @@ module RR
109
106
  @doubles.delete(object) if @doubles[object].empty?
110
107
  double.reset
111
108
  end
109
+
110
+ protected
111
+ # Removes the ordered Scenarios from the list
112
+ def reset_ordered_scenarios
113
+ @ordered_scenarios.clear
114
+ end
115
+
116
+ # Resets the registered Doubles for the next test run.
117
+ def reset_doubles
118
+ @doubles.each do |object, method_double_map|
119
+ method_double_map.keys.each do |method_name|
120
+ reset_double(object, method_name)
121
+ end
122
+ end
123
+ end
112
124
  end
113
125
  end
@@ -0,0 +1,22 @@
1
+ module RR
2
+ module TimesCalledMatchers
3
+ class AtLeastMatcher < TimesCalledMatcher
4
+ def possible_match?(times_called)
5
+ true
6
+ end
7
+
8
+ def matches?(times_called)
9
+ times_called >= @times
10
+ end
11
+
12
+ def attempt?(times_called)
13
+ times_called < @times
14
+ end
15
+
16
+ protected
17
+ def expected_message_part
18
+ "Expected at least #{@times.inspect} times."
19
+ end
20
+ end
21
+ end
22
+ end