mcmire-shoulda-matchers 2.5.0 → 2.6.1.docs.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +9 -0
  4. data/.yardopts +2 -1
  5. data/Appraisals +62 -22
  6. data/Gemfile +1 -1
  7. data/Gemfile.lock +3 -3
  8. data/NEWS.md +87 -4
  9. data/README.md +2 -2
  10. data/Rakefile +18 -0
  11. data/features/activemodel_integration.feature +15 -0
  12. data/features/rails_integration.feature +1 -1
  13. data/features/step_definitions/activemodel_steps.rb +21 -0
  14. data/features/step_definitions/rails_steps.rb +5 -4
  15. data/gemfiles/3.0.gemfile +6 -3
  16. data/gemfiles/3.0.gemfile.lock +14 -4
  17. data/gemfiles/3.1.gemfile +10 -4
  18. data/gemfiles/3.1.gemfile.lock +32 -5
  19. data/gemfiles/3.1_1.9.2.gemfile +21 -0
  20. data/gemfiles/3.1_1.9.2.gemfile.lock +191 -0
  21. data/gemfiles/3.2.gemfile +9 -4
  22. data/gemfiles/3.2.gemfile.lock +28 -5
  23. data/gemfiles/4.0.0.gemfile +11 -3
  24. data/gemfiles/4.0.0.gemfile.lock +42 -5
  25. data/gemfiles/4.0.1.gemfile +11 -3
  26. data/gemfiles/4.0.1.gemfile.lock +42 -5
  27. data/gemfiles/4.1.gemfile +37 -0
  28. data/gemfiles/4.1.gemfile.lock +216 -0
  29. data/lib/shoulda/matchers/action_controller/callback_matcher.rb +202 -0
  30. data/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb +1 -1
  31. data/lib/shoulda/matchers/action_controller/set_the_flash_matcher.rb +2 -1
  32. data/lib/shoulda/matchers/action_controller/strong_parameters_matcher.rb +165 -0
  33. data/lib/shoulda/matchers/action_controller.rb +2 -0
  34. data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +26 -4
  35. data/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +6 -0
  36. data/lib/shoulda/matchers/active_model/ensure_exclusion_of_matcher.rb +2 -0
  37. data/lib/shoulda/matchers/active_model/ensure_inclusion_of_matcher.rb +60 -18
  38. data/lib/shoulda/matchers/active_model/errors.rb +43 -1
  39. data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +14 -3
  40. data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +2 -1
  41. data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +100 -45
  42. data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +38 -5
  43. data/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb +27 -20
  44. data/lib/shoulda/matchers/active_record/association_matcher.rb +12 -2
  45. data/lib/shoulda/matchers/active_record/association_matchers/inverse_of_matcher.rb +41 -0
  46. data/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb +24 -1
  47. data/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb +1 -1
  48. data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +1 -1
  49. data/lib/shoulda/matchers/active_record.rb +1 -0
  50. data/lib/shoulda/matchers/assertion_error.rb +8 -3
  51. data/lib/shoulda/matchers/doublespeak/double.rb +75 -0
  52. data/lib/shoulda/matchers/doublespeak/double_collection.rb +55 -0
  53. data/lib/shoulda/matchers/doublespeak/double_implementation_registry.rb +28 -0
  54. data/lib/shoulda/matchers/doublespeak/object_double.rb +33 -0
  55. data/lib/shoulda/matchers/doublespeak/proxy_implementation.rb +31 -0
  56. data/lib/shoulda/matchers/doublespeak/structs.rb +10 -0
  57. data/lib/shoulda/matchers/doublespeak/stub_implementation.rb +35 -0
  58. data/lib/shoulda/matchers/doublespeak/world.rb +39 -0
  59. data/lib/shoulda/matchers/doublespeak.rb +28 -0
  60. data/lib/shoulda/matchers/error.rb +20 -1
  61. data/lib/shoulda/matchers/independent/delegate_matcher/stubbed_target.rb +35 -0
  62. data/lib/shoulda/matchers/independent/delegate_matcher.rb +293 -0
  63. data/lib/shoulda/matchers/independent.rb +10 -0
  64. data/lib/shoulda/matchers/integrations/nunit_test_case_detection.rb +38 -0
  65. data/lib/shoulda/matchers/integrations/rspec.rb +13 -14
  66. data/lib/shoulda/matchers/integrations/test_unit.rb +19 -15
  67. data/lib/shoulda/matchers/integrations.rb +13 -0
  68. data/lib/shoulda/matchers/rails_shim.rb +16 -0
  69. data/lib/shoulda/matchers/version.rb +1 -1
  70. data/lib/shoulda/matchers.rb +15 -3
  71. data/spec/shoulda/matchers/action_controller/callback_matcher_spec.rb +82 -0
  72. data/spec/shoulda/matchers/action_controller/redirect_to_matcher_spec.rb +2 -2
  73. data/spec/shoulda/matchers/action_controller/render_template_matcher_spec.rb +5 -5
  74. data/spec/shoulda/matchers/action_controller/render_with_layout_matcher_spec.rb +4 -4
  75. data/spec/shoulda/matchers/action_controller/rescue_from_matcher_spec.rb +38 -11
  76. data/spec/shoulda/matchers/action_controller/respond_with_matcher_spec.rb +1 -1
  77. data/spec/shoulda/matchers/action_controller/set_session_matcher_spec.rb +1 -1
  78. data/spec/shoulda/matchers/action_controller/set_the_flash_matcher_spec.rb +6 -6
  79. data/spec/shoulda/matchers/action_controller/strong_parameters_matcher_spec.rb +314 -0
  80. data/spec/shoulda/matchers/active_model/allow_value_matcher_spec.rb +32 -0
  81. data/spec/shoulda/matchers/active_model/ensure_inclusion_of_matcher_spec.rb +553 -211
  82. data/spec/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +22 -0
  83. data/spec/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +38 -0
  84. data/spec/shoulda/matchers/active_model/validate_uniqueness_of_matcher_spec.rb +42 -36
  85. data/spec/shoulda/matchers/active_record/association_matcher_spec.rb +15 -1
  86. data/spec/shoulda/matchers/active_record/association_matchers/model_reflection_spec.rb +4 -0
  87. data/spec/shoulda/matchers/active_record/have_db_index_matcher_spec.rb +4 -0
  88. data/spec/shoulda/matchers/doublespeak/double_collection_spec.rb +102 -0
  89. data/spec/shoulda/matchers/doublespeak/double_implementation_registry_spec.rb +21 -0
  90. data/spec/shoulda/matchers/doublespeak/double_spec.rb +144 -0
  91. data/spec/shoulda/matchers/doublespeak/object_double_spec.rb +77 -0
  92. data/spec/shoulda/matchers/doublespeak/proxy_implementation_spec.rb +40 -0
  93. data/spec/shoulda/matchers/doublespeak/stub_implementation_spec.rb +88 -0
  94. data/spec/shoulda/matchers/doublespeak/world_spec.rb +88 -0
  95. data/spec/shoulda/matchers/doublespeak_spec.rb +19 -0
  96. data/spec/shoulda/matchers/independent/delegate_matcher/stubbed_target_spec.rb +43 -0
  97. data/spec/shoulda/matchers/independent/delegate_matcher_spec.rb +250 -0
  98. data/spec/spec_helper.rb +15 -0
  99. data/spec/support/activemodel_helpers.rb +6 -2
  100. data/spec/support/controller_builder.rb +29 -1
  101. data/spec/support/rails_versions.rb +4 -0
  102. data/spec/support/test_application.rb +1 -1
  103. metadata +59 -10
@@ -0,0 +1,75 @@
1
+ module Shoulda
2
+ module Matchers
3
+ module Doublespeak
4
+ # @private
5
+ class Double
6
+ attr_reader :calls
7
+
8
+ def initialize(klass, method_name, implementation)
9
+ @klass = klass
10
+ @method_name = method_name
11
+ @implementation = implementation
12
+ @activated = false
13
+ @calls = []
14
+ end
15
+
16
+ def to_return(value = nil, &block)
17
+ if block
18
+ implementation.returns(&block)
19
+ else
20
+ implementation.returns(value)
21
+ end
22
+ end
23
+
24
+ def activate
25
+ unless @activated
26
+ store_original_method
27
+ replace_method_with_double
28
+ @activated = true
29
+ end
30
+ end
31
+
32
+ def deactivate
33
+ if @activated
34
+ restore_original_method
35
+ @activated = false
36
+ end
37
+ end
38
+
39
+ def record_call(args, block)
40
+ calls << MethodCall.new(args, block)
41
+ end
42
+
43
+ def call_original_method(object, args, block)
44
+ if original_method
45
+ original_method.bind(object).call(*args, &block)
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ attr_reader :klass, :method_name, :implementation, :original_method
52
+
53
+ def store_original_method
54
+ @original_method = klass.instance_method(method_name)
55
+ end
56
+
57
+ def replace_method_with_double
58
+ implementation = @implementation
59
+ double = self
60
+
61
+ klass.__send__(:define_method, method_name) do |*args, &block|
62
+ implementation.call(double, self, args, block)
63
+ end
64
+ end
65
+
66
+ def restore_original_method
67
+ original_method = @original_method
68
+ klass.__send__(:define_method, method_name) do |*args, &block|
69
+ original_method.bind(self).call(*args, &block)
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,55 @@
1
+ module Shoulda
2
+ module Matchers
3
+ module Doublespeak
4
+ # @private
5
+ class DoubleCollection
6
+ def initialize(klass)
7
+ @klass = klass
8
+ @doubles_by_method_name = {}
9
+ end
10
+
11
+ def register_stub(method_name)
12
+ register_double(method_name, :stub)
13
+ end
14
+
15
+ def register_proxy(method_name)
16
+ register_double(method_name, :proxy)
17
+ end
18
+
19
+ def activate
20
+ doubles_by_method_name.each do |method_name, double|
21
+ double.activate
22
+ end
23
+ end
24
+
25
+ def deactivate
26
+ doubles_by_method_name.each do |method_name, double|
27
+ double.deactivate
28
+ end
29
+ end
30
+
31
+ def calls_to(method_name)
32
+ double = doubles_by_method_name[method_name]
33
+
34
+ if double
35
+ double.calls
36
+ else
37
+ []
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ attr_reader :klass, :doubles_by_method_name
44
+
45
+ def register_double(method_name, implementation_type)
46
+ implementation =
47
+ DoubleImplementationRegistry.find(implementation_type)
48
+ double = Double.new(klass, method_name, implementation)
49
+ doubles_by_method_name[method_name] = double
50
+ double
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,28 @@
1
+ module Shoulda
2
+ module Matchers
3
+ module Doublespeak
4
+ # @private
5
+ module DoubleImplementationRegistry
6
+ class << self
7
+ REGISTRY = {}
8
+
9
+ def find(type)
10
+ find_class!(type).create
11
+ end
12
+
13
+ def register(klass, type)
14
+ REGISTRY[type] = klass
15
+ end
16
+
17
+ private
18
+
19
+ def find_class!(type)
20
+ REGISTRY.fetch(type) do
21
+ raise ArgumentError, "No double implementation class found for '#{type}'"
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,33 @@
1
+ module Shoulda
2
+ module Matchers
3
+ module Doublespeak
4
+ # @private
5
+ class ObjectDouble < BasicObject
6
+ attr_reader :calls
7
+
8
+ def initialize
9
+ @calls = []
10
+ @calls_by_method_name = {}
11
+ end
12
+
13
+ def calls_to(method_name)
14
+ @calls_by_method_name[method_name] || []
15
+ end
16
+
17
+ def respond_to?(name, include_private = nil)
18
+ true
19
+ end
20
+
21
+ def method_missing(method_name, *args, &block)
22
+ calls << MethodCallWithName.new(method_name, args, block)
23
+ (calls_by_method_name[method_name] ||= []) << MethodCall.new(args, block)
24
+ nil
25
+ end
26
+
27
+ private
28
+
29
+ attr_reader :calls_by_method_name
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,31 @@
1
+ module Shoulda
2
+ module Matchers
3
+ module Doublespeak
4
+ # @private
5
+ class ProxyImplementation
6
+ extend Forwardable
7
+
8
+ DoubleImplementationRegistry.register(self, :proxy)
9
+
10
+ def_delegators :stub_implementation, :returns
11
+
12
+ def self.create
13
+ new(StubImplementation.new)
14
+ end
15
+
16
+ def initialize(stub_implementation)
17
+ @stub_implementation = stub_implementation
18
+ end
19
+
20
+ def call(double, object, args, block)
21
+ stub_implementation.call(double, object, args, block)
22
+ double.call_original_method(object, args, block)
23
+ end
24
+
25
+ private
26
+
27
+ attr_reader :stub_implementation
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,10 @@
1
+ module Shoulda
2
+ module Matchers
3
+ module Doublespeak
4
+ # @private
5
+ MethodCall = Struct.new(:args, :block)
6
+ # @private
7
+ MethodCallWithName = Struct.new(:method_name, :args, :block)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,35 @@
1
+ module Shoulda
2
+ module Matchers
3
+ module Doublespeak
4
+ # @private
5
+ class StubImplementation
6
+ DoubleImplementationRegistry.register(self, :stub)
7
+
8
+ def self.create
9
+ new
10
+ end
11
+
12
+ def initialize
13
+ @implementation = proc { nil }
14
+ end
15
+
16
+ def returns(value = nil, &block)
17
+ if block
18
+ @implementation = block
19
+ else
20
+ @implementation = proc { value }
21
+ end
22
+ end
23
+
24
+ def call(double, object, args, block)
25
+ double.record_call(args, block)
26
+ implementation.call(object, args, block)
27
+ end
28
+
29
+ private
30
+
31
+ attr_reader :implementation
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,39 @@
1
+ module Shoulda
2
+ module Matchers
3
+ module Doublespeak
4
+ # @private
5
+ class World
6
+ def register_double_collection(klass)
7
+ double_collection = DoubleCollection.new(klass)
8
+ double_collections_by_class[klass] = double_collection
9
+ double_collection
10
+ end
11
+
12
+ def with_doubles_activated
13
+ activate
14
+ yield
15
+ ensure
16
+ deactivate
17
+ end
18
+
19
+ private
20
+
21
+ def activate
22
+ double_collections_by_class.each do |klass, double_collection|
23
+ double_collection.activate
24
+ end
25
+ end
26
+
27
+ def deactivate
28
+ double_collections_by_class.each do |klass, double_collection|
29
+ double_collection.deactivate
30
+ end
31
+ end
32
+
33
+ def double_collections_by_class
34
+ @_double_collections_by_class ||= {}
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,28 @@
1
+ require 'forwardable'
2
+
3
+ module Shoulda
4
+ module Matchers
5
+ # @private
6
+ module Doublespeak
7
+ class << self
8
+ extend Forwardable
9
+
10
+ def_delegators :world, :register_double_collection,
11
+ :with_doubles_activated
12
+
13
+ def world
14
+ @_world ||= World.new
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ require 'shoulda/matchers/doublespeak/double'
22
+ require 'shoulda/matchers/doublespeak/double_collection'
23
+ require 'shoulda/matchers/doublespeak/double_implementation_registry'
24
+ require 'shoulda/matchers/doublespeak/object_double'
25
+ require 'shoulda/matchers/doublespeak/proxy_implementation'
26
+ require 'shoulda/matchers/doublespeak/structs'
27
+ require 'shoulda/matchers/doublespeak/stub_implementation'
28
+ require 'shoulda/matchers/doublespeak/world'
@@ -1,6 +1,25 @@
1
1
  module Shoulda
2
2
  module Matchers
3
3
  # @private
4
- class Error < StandardError; end
4
+ class Error < StandardError
5
+ def self.create(attributes)
6
+ allocate.tap do |error|
7
+ attributes.each do |name, value|
8
+ error.__send__("#{name}=", value)
9
+ end
10
+
11
+ error.__send__(:initialize)
12
+ end
13
+ end
14
+
15
+ def initialize(*args)
16
+ super
17
+ @message = message
18
+ end
19
+
20
+ def message
21
+ ""
22
+ end
23
+ end
5
24
  end
6
25
  end
@@ -0,0 +1,35 @@
1
+ module Shoulda
2
+ module Matchers
3
+ module Independent
4
+ # @private
5
+ class DelegateMatcher::StubbedTarget
6
+ def initialize(method)
7
+ @received_method = false
8
+ @received_arguments = []
9
+ stub_method(method)
10
+ end
11
+
12
+ def has_received_method?
13
+ received_method
14
+ end
15
+
16
+ def has_received_arguments?(*args)
17
+ args == received_arguments
18
+ end
19
+
20
+ private
21
+
22
+ def stub_method(method)
23
+ class_eval do
24
+ define_method method do |*args|
25
+ @received_method = true
26
+ @received_arguments = args
27
+ end
28
+ end
29
+ end
30
+
31
+ attr_reader :received_method, :received_arguments
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,293 @@
1
+ module Shoulda
2
+ module Matchers
3
+ module Independent
4
+ # The `delegate_method` matcher is used for testing that methods are
5
+ # delegated properly.
6
+ #
7
+ # class TestRunner
8
+ # extend Forwardable
9
+ #
10
+ # def_delegators :suite_runner, :configuration
11
+ #
12
+ # def initialize(suite_runner)
13
+ # @suite_runner = suite_runner
14
+ # end
15
+ #
16
+ # private
17
+ #
18
+ # attr_reader :suite_runner
19
+ # end
20
+ #
21
+ # # RSpec
22
+ # describe TestRunner do
23
+ # it { should delegate_method(:configuration).to(:suite_runner) }
24
+ # end
25
+ #
26
+ # # Test::Unit
27
+ # class TestRunnerTest < ActiveSupport::TestCase
28
+ # should delegate_method(:configuration).to(:suite_runner)
29
+ # end
30
+ #
31
+ # #### Qualifiers
32
+ #
33
+ # ##### as
34
+ #
35
+ # Use `as` to specify the name of the method on the delegate object.
36
+ #
37
+ # class User
38
+ # def initialize(company)
39
+ # @company = company
40
+ # end
41
+ #
42
+ # def company_name
43
+ # company.name
44
+ # end
45
+ #
46
+ # private
47
+ #
48
+ # attr_reader :company
49
+ # end
50
+ #
51
+ # # RSpec
52
+ # describe User do
53
+ # it { should delegate(:company_name).to(:company).as(:name) }
54
+ # end
55
+ #
56
+ # # Test::Unit
57
+ # class UserTest < ActiveSupport::TestCase
58
+ # should delegate(:company_name).to(:company).as(:name)
59
+ # end
60
+ #
61
+ # ##### with_arguments
62
+ #
63
+ # Use `with_arguments` to specify that the target method should be called
64
+ # with the given arguments.
65
+ #
66
+ # class Address
67
+ # def initialize(geocoding_service)
68
+ # @geocoding_service = geocoding_service
69
+ # end
70
+ #
71
+ # def geocode
72
+ # geocoding_service.geocode(to_s)
73
+ # end
74
+ #
75
+ # def to_s
76
+ # [street, city, state, zip].join(' ')
77
+ # end
78
+ #
79
+ # private
80
+ #
81
+ # attr_reader :geocoding_service
82
+ # end
83
+ #
84
+ # # RSpec
85
+ # describe Address do
86
+ # it 'delegates #geocode to the GeocodingService' do
87
+ # address = Address.new(:geocoding_service)
88
+ # address.stubs(:to_s).returns('the address')
89
+ # expect(address).to delegate(:geocode).
90
+ # to(:geocoding_service).
91
+ # with_arguments('the address')
92
+ # end
93
+ # end
94
+ #
95
+ # # Test::Unit
96
+ # class AddressTest < ActiveSupport::TestCase
97
+ # should 'delegate #geocode to the GeocodingService' do
98
+ # address = Address.new(:geocoding_service)
99
+ # address.stubs(:to_s).returns('the address')
100
+ # matcher = delegate(:geocode).
101
+ # to(:geocoding_service).
102
+ # with_arguments('the address')
103
+ # assert_accepts matcher, address
104
+ # end
105
+ # end
106
+ #
107
+ def delegate_method(delegating_method)
108
+ DelegateMatcher.new(delegating_method)
109
+ end
110
+
111
+ # @private
112
+ class DelegateMatcher
113
+ def initialize(delegating_method)
114
+ @delegating_method = delegating_method
115
+ @method_on_target = @delegating_method
116
+ @target_double = Doublespeak::ObjectDouble.new
117
+
118
+ @delegated_arguments = []
119
+ @target_method = nil
120
+ @subject = nil
121
+ @subject_double_collection = nil
122
+ end
123
+
124
+ def matches?(subject)
125
+ @subject = subject
126
+
127
+ ensure_target_method_is_present!
128
+
129
+ subject_has_delegating_method? &&
130
+ subject_has_target_method? &&
131
+ subject_delegates_to_target_correctly?
132
+ end
133
+
134
+ def description
135
+ add_clarifications_to(
136
+ "delegate method ##{delegating_method} to :#{target_method}"
137
+ )
138
+ end
139
+
140
+ def to(target_method)
141
+ @target_method = target_method
142
+ self
143
+ end
144
+
145
+ def as(method_on_target)
146
+ @method_on_target = method_on_target
147
+ self
148
+ end
149
+
150
+ def with_arguments(*arguments)
151
+ @delegated_arguments = arguments
152
+ self
153
+ end
154
+
155
+ def failure_message
156
+ base = "Expected #{formatted_delegating_method_name} to delegate to #{formatted_target_method_name}"
157
+ add_clarifications_to(base)
158
+ base << "\nCalls on #{formatted_target_method_name}:"
159
+ base << formatted_calls_on_target
160
+ base.strip
161
+ end
162
+ alias failure_message_for_should failure_message
163
+
164
+ def failure_message_when_negated
165
+ base = "Expected #{formatted_delegating_method_name} not to delegate to #{formatted_target_method_name}"
166
+ add_clarifications_to(base)
167
+ base << ', but it did'
168
+ end
169
+ alias failure_message_for_should_not failure_message_when_negated
170
+
171
+ private
172
+
173
+ attr_reader \
174
+ :delegated_arguments,
175
+ :delegating_method,
176
+ :method,
177
+ :method_on_target,
178
+ :subject,
179
+ :subject_double_collection,
180
+ :target_double,
181
+ :target_method
182
+
183
+ def add_clarifications_to(message)
184
+ if delegated_arguments.any?
185
+ message << " with arguments: #{delegated_arguments.inspect}"
186
+ end
187
+
188
+ if method_on_target != delegating_method
189
+ message << " as ##{method_on_target}"
190
+ end
191
+
192
+ message
193
+ end
194
+
195
+ def formatted_delegating_method_name
196
+ formatted_method_name_for(delegating_method)
197
+ end
198
+
199
+ def formatted_target_method_name
200
+ formatted_method_name_for(target_method)
201
+ end
202
+
203
+ def formatted_method_name_for(method_name)
204
+ if subject.is_a?(Class)
205
+ subject.name + '.' + method_name.to_s
206
+ else
207
+ subject.class.name + '#' + method_name.to_s
208
+ end
209
+ end
210
+
211
+ def target_received_method?
212
+ calls_to_method_on_target.any?
213
+ end
214
+
215
+ def target_received_method_with_delegated_arguments?
216
+ calls_to_method_on_target.any? do |call|
217
+ call.args == delegated_arguments
218
+ end
219
+ end
220
+
221
+ def subject_has_delegating_method?
222
+ subject.respond_to?(delegating_method)
223
+ end
224
+
225
+ def subject_has_target_method?
226
+ subject.respond_to?(target_method)
227
+ end
228
+
229
+ def ensure_target_method_is_present!
230
+ if target_method.blank?
231
+ raise TargetNotDefinedError
232
+ end
233
+ end
234
+
235
+ def subject_delegates_to_target_correctly?
236
+ register_subject_double_collection
237
+
238
+ Doublespeak.with_doubles_activated do
239
+ subject.public_send(delegating_method, *delegated_arguments)
240
+ end
241
+
242
+ if delegated_arguments.any?
243
+ target_received_method_with_delegated_arguments?
244
+ else
245
+ target_received_method?
246
+ end
247
+ end
248
+
249
+ def register_subject_double_collection
250
+ double_collection =
251
+ Doublespeak.register_double_collection(subject.singleton_class)
252
+ double_collection.register_stub(target_method).
253
+ to_return(target_double)
254
+
255
+ @subject_double_collection = double_collection
256
+ end
257
+
258
+ def calls_to_method_on_target
259
+ target_double.calls_to(method_on_target)
260
+ end
261
+
262
+ def calls_on_target
263
+ target_double.calls
264
+ end
265
+
266
+ def formatted_calls_on_target
267
+ string = ""
268
+
269
+ if calls_on_target.any?
270
+ string << "\n"
271
+ calls_on_target.each_with_index do |call, i|
272
+ name = call.method_name
273
+ args = call.args.map { |arg| arg.inspect }.join(', ')
274
+ string << "#{i+1}) #{name}(#{args})\n"
275
+ end
276
+ else
277
+ string << " (none)"
278
+ end
279
+
280
+ string
281
+ end
282
+
283
+ # @private
284
+ class TargetNotDefinedError < StandardError
285
+ def message
286
+ 'Delegation needs a target. Use the #to method to define one, e.g.
287
+ `post_office.should delegate(:deliver_mail).to(:mailman)`'.squish
288
+ end
289
+ end
290
+ end
291
+ end
292
+ end
293
+ end
@@ -0,0 +1,10 @@
1
+ require 'shoulda/matchers/independent/delegate_matcher'
2
+ require 'shoulda/matchers/independent/delegate_matcher/stubbed_target'
3
+
4
+ module Shoulda
5
+ module Matchers
6
+ # Matchers for non-Rails-dependent code.
7
+ module Independent
8
+ end
9
+ end
10
+ end