rr 0.1.6 → 0.1.7

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 (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