rr 0.10.10 → 0.10.11

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 (50) hide show
  1. data/CHANGES +4 -0
  2. data/VERSION.yml +1 -1
  3. data/lib/rr.rb +5 -3
  4. data/lib/rr/adapters/rr_methods.rb +5 -5
  5. data/lib/rr/blank_slate.rb +17 -0
  6. data/lib/rr/double_definitions/{child_double_definition_creator.rb → child_double_definition_create.rb} +1 -1
  7. data/lib/rr/double_definitions/double_definition.rb +13 -11
  8. data/lib/rr/double_definitions/{double_definition_creator.rb → double_definition_create.rb} +52 -43
  9. data/lib/rr/double_definitions/double_definition_create_blank_slate.rb +26 -0
  10. data/lib/rr/double_definitions/strategies/implementation/implementation_strategy.rb +2 -2
  11. data/lib/rr/double_definitions/strategies/scope/instance.rb +1 -1
  12. data/lib/rr/double_definitions/strategies/scope/instance_of_class.rb +6 -6
  13. data/lib/rr/double_definitions/strategies/scope/scope_strategy.rb +2 -2
  14. data/lib/rr/double_definitions/strategies/strategy.rb +15 -16
  15. data/lib/rr/double_definitions/strategies/verification/mock.rb +1 -1
  16. data/lib/rr/double_definitions/strategies/verification/stub.rb +1 -1
  17. data/lib/rr/double_definitions/strategies/verification/verification_strategy.rb +2 -2
  18. data/lib/rr/injections/double_injection.rb +59 -4
  19. data/lib/rr/injections/injection.rb +6 -0
  20. data/lib/rr/injections/method_missing_injection.rb +13 -1
  21. data/lib/rr/injections/singleton_method_added_injection.rb +14 -3
  22. data/lib/rr/method_dispatches/base_method_dispatch.rb +2 -2
  23. data/lib/rr/method_dispatches/method_missing_dispatch.rb +2 -2
  24. data/lib/rr/recorded_calls.rb +1 -1
  25. data/lib/rr/space.rb +17 -68
  26. data/lib/rr/spy_verification_proxy.rb +1 -6
  27. data/spec/rr/adapters/rr_methods_creator_spec.rb +9 -21
  28. data/spec/rr/adapters/rr_methods_space_spec.rb +10 -25
  29. data/spec/rr/double_definitions/child_double_definition_creator_spec.rb +16 -16
  30. data/spec/rr/double_definitions/double_definition_create_blank_slate_spec.rb +87 -0
  31. data/spec/rr/double_definitions/{double_definition_creator_spec.rb → double_definition_create_spec.rb} +64 -72
  32. data/spec/rr/double_injection/double_injection_verify_spec.rb +2 -2
  33. data/spec/rr/expectations/times_called_expectation/times_called_expectation_any_times_spec.rb +5 -29
  34. data/spec/rr/expectations/times_called_expectation/times_called_expectation_at_least_spec.rb +7 -39
  35. data/spec/rr/expectations/times_called_expectation/times_called_expectation_at_most_spec.rb +19 -47
  36. data/spec/rr/expectations/times_called_expectation/times_called_expectation_helper.rb +1 -9
  37. data/spec/rr/expectations/times_called_expectation/times_called_expectation_integer_spec.rb +18 -64
  38. data/spec/rr/expectations/times_called_expectation/times_called_expectation_proc_spec.rb +7 -53
  39. data/spec/rr/expectations/times_called_expectation/times_called_expectation_range_spec.rb +12 -56
  40. data/spec/rr/rspec/rspec_adapter_spec.rb +8 -11
  41. data/spec/rr/space/space_spec.rb +72 -212
  42. data/spec/spec_helper.rb +0 -76
  43. data/spec/spy_verification_spec.rb +1 -1
  44. metadata +8 -11
  45. data/lib/rr/double_definitions/double_definition_creator_proxy.rb +0 -37
  46. data/ruby_19_spec.rb +0 -12
  47. data/spec/rr/double_definitions/double_definition_creator_proxy_spec.rb +0 -124
  48. data/spec/rr/double_definitions/double_definition_spec.rb +0 -1168
  49. data/spec/rr/double_spec.rb +0 -361
  50. data/spec/rr/expectations/times_called_expectation/times_called_expectation_spec.rb +0 -38
@@ -12,7 +12,7 @@ module RR
12
12
  # or
13
13
  # proxy.mock(subject).method_name_1
14
14
  #
15
- # When passed the subject, a DoubleDefinitionCreatorProxy is returned. Passing
15
+ # When passed the subject, a DoubleDefinitionCreateBlankSlate is returned. Passing
16
16
  # a method with arguments to the proxy will set up expectations that
17
17
  # the a call to the subject's method with the arguments will happen,
18
18
  # and return the prescribed value.
@@ -12,7 +12,7 @@ module RR
12
12
  # or
13
13
  # proxy.stub(subject).method_name_1
14
14
  #
15
- # When passed the subject, a DoubleDefinitionCreatorProxy is returned. Passing
15
+ # When passed the subject, a DoubleDefinitionCreateBlankSlate is returned. Passing
16
16
  # a method with arguments to the proxy will set up expectations that
17
17
  # the a call to the subject's method with the arguments will happen,
18
18
  # and return the prescribed value.
@@ -4,8 +4,8 @@ module RR
4
4
  module Verification
5
5
  class VerificationStrategy < Strategy
6
6
  class << self
7
- def register_self_at_double_definition_creator(domain_name)
8
- DoubleDefinitionCreator.register_verification_strategy_class(self, domain_name)
7
+ def register_self_at_double_definition_create(strategy_method_name)
8
+ DoubleDefinitionCreate.register_verification_strategy_class(self, strategy_method_name)
9
9
  end
10
10
  end
11
11
  end
@@ -4,6 +4,57 @@ module RR
4
4
  # A double_injection has 0 to many Double objects. Each Double
5
5
  # has Argument Expectations and Times called Expectations.
6
6
  class DoubleInjection < Injection
7
+ class << self
8
+ def create(subject, method_name)
9
+ instances[subject][method_name.to_sym] ||= begin
10
+ new(subject, method_name.to_sym, (class << subject; self; end)).bind
11
+ end
12
+ end
13
+
14
+ def exists?(subject, method_name)
15
+ instances.include?(subject) && instances[subject].include?(method_name.to_sym)
16
+ end
17
+
18
+ def reset
19
+ instances.each do |subject, method_double_map|
20
+ method_double_map.keys.each do |method_name|
21
+ reset_double(subject, method_name)
22
+ end
23
+ end
24
+ end
25
+
26
+ def verify(*subjects)
27
+ subjects = Injections::DoubleInjection.instances.keys if subjects.empty?
28
+ subjects.each do |subject|
29
+ instances.include?(subject) &&
30
+ instances[subject].keys.each do |method_name|
31
+ verify_double(subject, method_name)
32
+ end &&
33
+ instances.delete(subject)
34
+ end
35
+ end
36
+
37
+ # Verifies the DoubleInjection for the passed in subject and method_name.
38
+ def verify_double(subject, method_name)
39
+ Injections::DoubleInjection.instances[subject][method_name].verify
40
+ ensure
41
+ reset_double subject, method_name
42
+ end
43
+
44
+ # Resets the DoubleInjection for the passed in subject and method_name.
45
+ def reset_double(subject, method_name)
46
+ double_injection = Injections::DoubleInjection.instances[subject].delete(method_name)
47
+ Injections::DoubleInjection.instances.delete(subject) if Injections::DoubleInjection.instances[subject].empty?
48
+ double_injection.reset
49
+ end
50
+
51
+ def instances
52
+ @instances ||= HashWithObjectIdKey.new do |hash, subject_object|
53
+ hash.set_with_object_id(subject_object, {})
54
+ end
55
+ end
56
+ end
57
+
7
58
  attr_reader :subject_class, :method_name, :doubles
8
59
 
9
60
  MethodArguments = Struct.new(:arguments, :block)
@@ -34,8 +85,8 @@ module RR
34
85
  bind_method_with_alias
35
86
  end
36
87
  else
37
- space.method_missing_injection(subject)
38
- space.singleton_method_added_injection(subject)
88
+ Injections::MethodMissingInjection.create(subject)
89
+ Injections::SingletonMethodAddedInjection.create(subject)
39
90
  end
40
91
  else
41
92
  bind_method
@@ -50,6 +101,7 @@ module RR
50
101
  double.verify
51
102
  end
52
103
  end
104
+
53
105
  # RR::DoubleInjection#reset removes the injected dispatcher method.
54
106
 
55
107
  # It binds the original method implementation on the subject
@@ -100,7 +152,10 @@ module RR
100
152
 
101
153
  protected
102
154
  def subject_is_proxy_for_method?(method_name_in_question)
103
- !(class << @subject; self; end).
155
+ !(
156
+ class << @subject;
157
+ self;
158
+ end).
104
159
  instance_methods.
105
160
  detect {|method_name| method_name.to_sym == method_name_in_question.to_sym}
106
161
  end
@@ -122,7 +177,7 @@ module RR
122
177
  subject_class.class_eval(<<-METHOD, __FILE__, __LINE__ + 1)
123
178
  def #{@method_name}(*args, &block)
124
179
  arguments = MethodArguments.new(args, block)
125
- RR::Space.double_injection(#{subject}, :#{@method_name}).dispatch_method(arguments.arguments, arguments.block)
180
+ RR::Injections::DoubleInjection.create(#{subject}, :#{@method_name}).dispatch_method(arguments.arguments, arguments.block)
126
181
  end
127
182
  METHOD
128
183
  end
@@ -1,6 +1,12 @@
1
1
  module RR
2
2
  module Injections
3
3
  class Injection
4
+ class << self
5
+ def instances
6
+ @instances ||= HashWithObjectIdKey.new
7
+ end
8
+ end
9
+
4
10
  include Space::Reader
5
11
 
6
12
  attr_reader :subject
@@ -1,6 +1,18 @@
1
1
  module RR
2
2
  module Injections
3
3
  class MethodMissingInjection < Injection
4
+ class << self
5
+ def create(subject)
6
+ instances[subject] ||= begin
7
+ new(subject).bind
8
+ end
9
+ end
10
+
11
+ def exists?(subject)
12
+ instances.include?(subject)
13
+ end
14
+ end
15
+
4
16
  def initialize(subject)
5
17
  @subject = subject
6
18
  @placeholder_method_defined = false
@@ -48,7 +60,7 @@ module RR
48
60
  def bind_method
49
61
  returns_method = <<-METHOD
50
62
  def method_missing(method_name, *args, &block)
51
- RR::Space.method_missing_injection(self).dispatch_method(method_name, args, block)
63
+ RR::Injections::MethodMissingInjection.create(self).dispatch_method(method_name, args, block)
52
64
  end
53
65
  METHOD
54
66
  subject_class.class_eval(returns_method, __FILE__, __LINE__ - 4)
@@ -1,6 +1,18 @@
1
1
  module RR
2
2
  module Injections
3
3
  class SingletonMethodAddedInjection < Injection
4
+ class << self
5
+ def create(subject)
6
+ instances[subject] ||= begin
7
+ new(subject).bind
8
+ end
9
+ end
10
+
11
+ def exists?(subject)
12
+ instances.include?(subject)
13
+ end
14
+ end
15
+
4
16
  def initialize(subject)
5
17
  @subject = subject
6
18
  @placeholder_method_defined = false
@@ -18,12 +30,11 @@ module RR
18
30
  end
19
31
 
20
32
  memoized_subject = subject
21
- memoized_space = space
22
33
  memoized_original_method_alias_name = original_method_alias_name
23
34
  subject_class.__send__(:alias_method, original_method_alias_name, :singleton_method_added)
24
35
  subject_class.__send__(:define_method, :singleton_method_added) do |method_name_arg|
25
- if memoized_space.double_injection_exists?(memoized_subject, method_name_arg)
26
- memoized_space.double_injection(memoized_subject, method_name_arg).send(:deferred_bind_method)
36
+ if Injections::DoubleInjection.exists?(memoized_subject, method_name_arg)
37
+ Injections::DoubleInjection.create(memoized_subject, method_name_arg).send(:deferred_bind_method)
27
38
  end
28
39
  send(memoized_original_method_alias_name, method_name_arg)
29
40
  end
@@ -59,8 +59,8 @@ module RR
59
59
  case return_value
60
60
  when DoubleDefinitions::DoubleDefinition
61
61
  return_value.root_subject
62
- when DoubleDefinitions::DoubleDefinitionCreatorProxy
63
- return_value.__creator__.root_subject
62
+ when DoubleDefinitions::DoubleDefinitionCreateBlankSlate
63
+ return_value.__double_definition_create__.root_subject
64
64
  else
65
65
  return_value
66
66
  end
@@ -13,7 +13,7 @@ module RR
13
13
  end
14
14
 
15
15
  def call
16
- if space.double_injection_exists?(subject, method_name)
16
+ if Injections::DoubleInjection.exists?(subject, method_name)
17
17
  space.record_call(subject, method_name, args, block)
18
18
  @double = find_double_to_attempt
19
19
 
@@ -50,7 +50,7 @@ module RR
50
50
  end
51
51
 
52
52
  def double_injection
53
- space.double_injection(subject, method_name)
53
+ Injections::DoubleInjection.create(subject, method_name)
54
54
  end
55
55
 
56
56
  def_delegators 'self.class', :original_method_missing_alias_name
@@ -40,7 +40,7 @@ module RR
40
40
  attr_accessor :ordered_index
41
41
 
42
42
  def double_injection_exists_error(spy_verification)
43
- unless space.double_injection_exists?(spy_verification.subject, spy_verification.method_name)
43
+ unless Injections::DoubleInjection.exists?(spy_verification.subject, spy_verification.method_name)
44
44
  RR::Errors::SpyVerificationErrors::DoubleInjectionNotFoundError.new(
45
45
  "A Double Injection for the subject and method call:\n" <<
46
46
  "#{spy_verification.subject.inspect}\n" <<
data/lib/rr/space.rb CHANGED
@@ -19,53 +19,14 @@ module RR
19
19
  end
20
20
  end
21
21
 
22
- attr_reader :double_injections, :method_missing_injections, :ordered_doubles, :recorded_calls
22
+ attr_reader :ordered_doubles, :recorded_calls
23
23
  attr_accessor :trim_backtrace
24
24
  def initialize
25
- @double_injections = HashWithObjectIdKey.new do |hash, subject_object|
26
- hash.set_with_object_id(subject_object, {})
27
- end
28
- @method_missing_injections = HashWithObjectIdKey.new
29
- @singleton_method_added_injections = HashWithObjectIdKey.new
30
25
  @ordered_doubles = []
31
26
  @trim_backtrace = false
32
27
  @recorded_calls = RR::RecordedCalls.new
33
28
  end
34
29
 
35
- # Reuses or creates, if none exists, a DoubleInjection for the passed
36
- # in subject and method_name.
37
- # When a DoubleInjection is created, it binds the dispatcher to the
38
- # subject.
39
- def double_injection(subject, method_name)
40
- @double_injections[subject][method_name.to_sym] ||= begin
41
- Injections::DoubleInjection.new(subject, method_name.to_sym, (class << subject; self; end)).bind
42
- end
43
- end
44
-
45
- def double_injection_exists?(subject, method_name)
46
- @double_injections.include?(subject) && @double_injections[subject].include?(method_name.to_sym)
47
- end
48
-
49
- def method_missing_injection(subject)
50
- @method_missing_injections[subject] ||= begin
51
- Injections::MethodMissingInjection.new(subject).bind
52
- end
53
- end
54
-
55
- def method_missing_injection_exists?(subject)
56
- @method_missing_injections.include?(subject)
57
- end
58
-
59
- def singleton_method_added_injection(subject)
60
- @singleton_method_added_injections[subject] ||= begin
61
- Injections::SingletonMethodAddedInjection.new(subject).bind
62
- end
63
- end
64
-
65
- def singleton_method_added_injection_exists?(subject)
66
- @singleton_method_added_injections.include?(subject)
67
- end
68
-
69
30
  # Registers the ordered Double to be verified.
70
31
  def register_ordered_double(double)
71
32
  @ordered_doubles << double unless ordered_doubles.include?(double)
@@ -90,20 +51,15 @@ module RR
90
51
 
91
52
  # Verifies all the DoubleInjection objects have met their
92
53
  # TimesCalledExpectations.
93
- def verify_doubles(*objects)
94
- objects = @double_injections.keys if objects.empty?
95
- objects.each do |subject|
96
- @double_injections[subject].keys.each do |method_name|
97
- verify_double(subject, method_name)
98
- end
99
- end
54
+ def verify_doubles(*subjects)
55
+ Injections::DoubleInjection.verify(*subjects)
100
56
  end
101
57
  alias_method :verify, :verify_doubles
102
58
 
103
59
  # Resets the registered Doubles and ordered Doubles
104
60
  def reset
105
61
  reset_ordered_doubles
106
- reset_double_injections
62
+ Injections::DoubleInjection.reset
107
63
  reset_method_missing_injections
108
64
  reset_singleton_method_added_injections
109
65
  reset_recorded_calls
@@ -111,49 +67,42 @@ module RR
111
67
 
112
68
  # Verifies the DoubleInjection for the passed in subject and method_name.
113
69
  def verify_double(subject, method_name)
114
- @double_injections[subject][method_name].verify
115
- ensure
116
- reset_double subject, method_name
70
+ Injections::DoubleInjection.verify_double(subject, method_name)
117
71
  end
118
72
 
119
73
  # Resets the DoubleInjection for the passed in subject and method_name.
120
74
  def reset_double(subject, method_name)
121
- double_injection = @double_injections[subject].delete(method_name)
122
- @double_injections.delete(subject) if @double_injections[subject].empty?
123
- double_injection.reset
75
+ Injections::DoubleInjection.reset_double(subject, method_name)
124
76
  end
125
-
77
+
126
78
  def record_call(subject, method_name, arguments, block)
127
79
  @recorded_calls << [subject, method_name, arguments, block]
128
80
  end
129
81
 
82
+ def blank_slate_whitelist
83
+ @blank_slate_whitelist ||= [
84
+ "object_id", "respond_to?", "method_missing", "instance_eval", "instance_exec", "class_eval"
85
+ ]
86
+ end
87
+
130
88
  protected
131
89
  # Removes the ordered Doubles from the list
132
90
  def reset_ordered_doubles
133
91
  @ordered_doubles.clear
134
92
  end
135
93
 
136
- # Resets the registered Doubles for the next test run.
137
- def reset_double_injections
138
- @double_injections.each do |subject, method_double_map|
139
- method_double_map.keys.each do |method_name|
140
- reset_double(subject, method_name)
141
- end
142
- end
143
- end
144
-
145
94
  def reset_method_missing_injections
146
- @method_missing_injections.each do |subject, injection|
95
+ Injections::MethodMissingInjection.instances.each do |subject, injection|
147
96
  injection.reset
148
97
  end
149
- @method_missing_injections.clear
98
+ Injections::MethodMissingInjection.instances.clear
150
99
  end
151
100
 
152
101
  def reset_singleton_method_added_injections
153
- @singleton_method_added_injections.each do |subject, injection|
102
+ Injections::SingletonMethodAddedInjection.instances.each do |subject, injection|
154
103
  injection.reset
155
104
  end
156
- @singleton_method_added_injections.clear
105
+ Injections::SingletonMethodAddedInjection.instances.clear
157
106
  end
158
107
 
159
108
  def reset_recorded_calls
@@ -1,11 +1,6 @@
1
1
  module RR
2
2
  class SpyVerificationProxy
3
- instance_methods.each do |m|
4
- unless m =~ /^_/ || m.to_s == 'object_id' || m.to_s == "instance_eval" || m.to_s == "instance_exec" || m.to_s == 'respond_to?'
5
- alias_method "__blank_slated_#{m}", m
6
- undef_method m
7
- end
8
- end
3
+ BlankSlate.call(self)
9
4
 
10
5
  def initialize(subject)
11
6
  @subject = subject
@@ -23,11 +23,9 @@ module RR
23
23
  @strategy_method_name = :mock
24
24
  end
25
25
 
26
- send("normal strategy definition")
27
-
28
26
  context "when passing no args" do
29
- it "returns a DoubleDefinitionCreator" do
30
- call_strategy.class.should == RR::DoubleDefinitions::DoubleDefinitionCreator
27
+ it "returns a DoubleDefinitionCreate" do
28
+ call_strategy.class.should == RR::DoubleDefinitions::DoubleDefinitionCreate
31
29
  end
32
30
  end
33
31
 
@@ -47,11 +45,9 @@ module RR
47
45
  @strategy_method_name = :stub
48
46
  end
49
47
 
50
- send("normal strategy definition")
51
-
52
48
  context "when passing no args" do
53
- it "returns a DoubleDefinitionCreator" do
54
- call_strategy.class.should == RR::DoubleDefinitions::DoubleDefinitionCreator
49
+ it "returns a DoubleDefinitionCreate" do
50
+ call_strategy.class.should == RR::DoubleDefinitions::DoubleDefinitionCreate
55
51
  end
56
52
  end
57
53
 
@@ -70,11 +66,9 @@ module RR
70
66
  @strategy_method_name = :dont_allow
71
67
  end
72
68
 
73
- send("normal strategy definition")
74
-
75
69
  context "when passing no args" do
76
- it "returns a DoubleDefinitionCreator" do
77
- call_strategy.class.should == RR::DoubleDefinitions::DoubleDefinitionCreator
70
+ it "returns a DoubleDefinitionCreate" do
71
+ call_strategy.class.should == RR::DoubleDefinitions::DoubleDefinitionCreate
78
72
  end
79
73
  end
80
74
 
@@ -104,12 +98,10 @@ module RR
104
98
  @strategy_method_name = :mock!
105
99
  end
106
100
 
107
- send("! strategy definition")
108
-
109
101
  context "when passed a method_name argument" do
110
102
  it "sets #verification_strategy to Mock" do
111
103
  proxy = mock!(:foobar)
112
- proxy.double_definition_creator.verification_strategy.class.should == RR::DoubleDefinitions::Strategies::Verification::Mock
104
+ proxy.double_definition_create.verification_strategy.class.should == RR::DoubleDefinitions::Strategies::Verification::Mock
113
105
  end
114
106
  end
115
107
  end
@@ -119,12 +111,10 @@ module RR
119
111
  @strategy_method_name = :stub!
120
112
  end
121
113
 
122
- send("! strategy definition")
123
-
124
114
  context "when passed a method_name argument" do
125
115
  it "sets #verification_strategy to Stub" do
126
116
  proxy = stub!(:foobar)
127
- proxy.double_definition_creator.verification_strategy.class.should == RR::DoubleDefinitions::Strategies::Verification::Stub
117
+ proxy.double_definition_create.verification_strategy.class.should == RR::DoubleDefinitions::Strategies::Verification::Stub
128
118
  end
129
119
  end
130
120
  end
@@ -134,12 +124,10 @@ module RR
134
124
  @strategy_method_name = :dont_allow!
135
125
  end
136
126
 
137
- send("! strategy definition")
138
-
139
127
  context "when passed a method_name argument" do
140
128
  it "sets #verification_strategy to DontAllow" do
141
129
  proxy = dont_allow!(:foobar)
142
- proxy.double_definition_creator.verification_strategy.class.should == RR::DoubleDefinitions::Strategies::Verification::DontAllow
130
+ proxy.double_definition_create.verification_strategy.class.should == RR::DoubleDefinitions::Strategies::Verification::DontAllow
143
131
  end
144
132
  end
145
133
  end