shoulda-matchers 2.8.0 → 3.0.0.rc1

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 (171) hide show
  1. checksums.yaml +4 -4
  2. data/.hound_config/ruby.yml +7 -0
  3. data/.travis.yml +11 -54
  4. data/Appraisals +45 -100
  5. data/CONTRIBUTING.md +51 -7
  6. data/Gemfile +7 -19
  7. data/Gemfile.lock +60 -134
  8. data/Guardfile +5 -0
  9. data/NEWS.md +203 -0
  10. data/README.md +95 -50
  11. data/Rakefile +1 -0
  12. data/doc_config/yard/templates/default/layout/html/setup.rb +1 -1
  13. data/gemfiles/4.0.0.gemfile +10 -7
  14. data/gemfiles/4.0.0.gemfile.lock +103 -79
  15. data/gemfiles/4.0.1.gemfile +10 -7
  16. data/gemfiles/4.0.1.gemfile.lock +109 -83
  17. data/gemfiles/4.1.gemfile +10 -7
  18. data/gemfiles/4.1.gemfile.lock +109 -85
  19. data/gemfiles/4.2.gemfile +10 -9
  20. data/gemfiles/4.2.gemfile.lock +86 -78
  21. data/lib/shoulda/matchers.rb +13 -18
  22. data/lib/shoulda/matchers/action_controller.rb +4 -1
  23. data/lib/shoulda/matchers/action_controller/flash_store.rb +95 -0
  24. data/lib/shoulda/matchers/action_controller/{strong_parameters_matcher.rb → permit_matcher.rb} +147 -30
  25. data/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +1 -1
  26. data/lib/shoulda/matchers/action_controller/render_template_matcher.rb +1 -1
  27. data/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb +1 -1
  28. data/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb +1 -1
  29. data/lib/shoulda/matchers/action_controller/route_matcher.rb +5 -1
  30. data/lib/shoulda/matchers/action_controller/route_params.rb +15 -6
  31. data/lib/shoulda/matchers/action_controller/session_store.rb +34 -0
  32. data/lib/shoulda/matchers/action_controller/set_flash_matcher.rb +30 -136
  33. data/lib/shoulda/matchers/action_controller/set_session_matcher.rb +28 -109
  34. data/lib/shoulda/matchers/action_controller/set_session_or_flash_matcher.rb +103 -0
  35. data/lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb +1 -12
  36. data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +79 -10
  37. data/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +10 -0
  38. data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +21 -0
  39. data/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb +24 -0
  40. data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +22 -5
  41. data/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb +29 -10
  42. data/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +27 -10
  43. data/lib/shoulda/matchers/active_model/validate_length_of_matcher.rb +27 -12
  44. data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +56 -20
  45. data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +3 -11
  46. data/lib/shoulda/matchers/active_model/validation_message_finder.rb +65 -0
  47. data/lib/shoulda/matchers/active_record/association_matcher.rb +40 -6
  48. data/lib/shoulda/matchers/active_record/association_matchers/join_table_matcher.rb +21 -7
  49. data/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb +11 -40
  50. data/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb +1 -1
  51. data/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb +2 -6
  52. data/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +137 -22
  53. data/lib/shoulda/matchers/configuration.rb +20 -0
  54. data/lib/shoulda/matchers/doublespeak.rb +11 -1
  55. data/lib/shoulda/matchers/doublespeak/double.rb +29 -11
  56. data/lib/shoulda/matchers/doublespeak/double_collection.rb +4 -3
  57. data/lib/shoulda/matchers/doublespeak/method_call.rb +35 -0
  58. data/lib/shoulda/matchers/doublespeak/object_double.rb +7 -2
  59. data/lib/shoulda/matchers/doublespeak/proxy_implementation.rb +4 -3
  60. data/lib/shoulda/matchers/doublespeak/stub_implementation.rb +3 -3
  61. data/lib/shoulda/matchers/doublespeak/world.rb +21 -1
  62. data/lib/shoulda/matchers/integrations.rb +43 -0
  63. data/lib/shoulda/matchers/integrations/configuration.rb +68 -0
  64. data/lib/shoulda/matchers/integrations/configuration_error.rb +9 -0
  65. data/lib/shoulda/matchers/integrations/inclusion.rb +20 -0
  66. data/lib/shoulda/matchers/integrations/libraries.rb +15 -0
  67. data/lib/shoulda/matchers/integrations/libraries/action_controller.rb +31 -0
  68. data/lib/shoulda/matchers/integrations/libraries/active_model.rb +26 -0
  69. data/lib/shoulda/matchers/integrations/libraries/active_record.rb +26 -0
  70. data/lib/shoulda/matchers/integrations/libraries/missing_library.rb +19 -0
  71. data/lib/shoulda/matchers/integrations/libraries/rails.rb +30 -0
  72. data/lib/shoulda/matchers/integrations/rails.rb +12 -0
  73. data/lib/shoulda/matchers/integrations/registry.rb +28 -0
  74. data/lib/shoulda/matchers/integrations/test_frameworks.rb +16 -0
  75. data/lib/shoulda/matchers/integrations/test_frameworks/active_support_test_case.rb +37 -0
  76. data/lib/shoulda/matchers/integrations/test_frameworks/minitest_4.rb +36 -0
  77. data/lib/shoulda/matchers/integrations/test_frameworks/minitest_5.rb +37 -0
  78. data/lib/shoulda/matchers/integrations/test_frameworks/missing_test_framework.rb +40 -0
  79. data/lib/shoulda/matchers/integrations/test_frameworks/rspec.rb +29 -0
  80. data/lib/shoulda/matchers/integrations/test_frameworks/test_unit.rb +36 -0
  81. data/lib/shoulda/matchers/rails_shim.rb +0 -40
  82. data/lib/shoulda/matchers/version.rb +1 -1
  83. data/script/SUPPORTED_VERSIONS +1 -1
  84. data/script/update_gems_in_all_appraisals +14 -0
  85. data/shoulda-matchers.gemspec +2 -2
  86. data/spec/acceptance/active_model_integration_spec.rb +4 -1
  87. data/spec/acceptance/independent_matchers_spec.rb +6 -6
  88. data/spec/acceptance/multiple_libraries_integration_spec.rb +52 -0
  89. data/spec/acceptance/rails_integration_spec.rb +15 -5
  90. data/spec/acceptance_spec_helper.rb +8 -0
  91. data/spec/doublespeak_spec_helper.rb +14 -0
  92. data/spec/support/acceptance/adds_shoulda_matchers_to_project.rb +110 -0
  93. data/spec/support/acceptance/helpers.rb +2 -0
  94. data/spec/support/acceptance/helpers/base_helpers.rb +6 -1
  95. data/spec/support/acceptance/helpers/command_helpers.rb +6 -2
  96. data/spec/support/acceptance/helpers/minitest_helpers.rb +0 -8
  97. data/spec/support/acceptance/helpers/n_unit_helpers.rb +25 -0
  98. data/spec/support/acceptance/helpers/rspec_helpers.rb +2 -0
  99. data/spec/support/acceptance/helpers/step_helpers.rb +13 -19
  100. data/spec/support/acceptance/matchers/have_output.rb +1 -1
  101. data/spec/support/tests/bundle.rb +1 -1
  102. data/spec/support/tests/command_runner.rb +25 -13
  103. data/spec/support/tests/current_bundle.rb +47 -0
  104. data/spec/support/tests/database.rb +28 -0
  105. data/spec/support/tests/database_adapters/postgresql.rb +25 -0
  106. data/spec/support/tests/database_adapters/sqlite3.rb +26 -0
  107. data/spec/support/tests/database_configuration.rb +33 -0
  108. data/spec/support/tests/database_configuration_registry.rb +28 -0
  109. data/spec/support/tests/filesystem.rb +25 -2
  110. data/spec/support/unit/helpers/active_record_versions.rb +12 -0
  111. data/spec/support/unit/helpers/class_builder.rb +6 -2
  112. data/spec/support/unit/helpers/column_type_helpers.rb +26 -0
  113. data/spec/support/unit/helpers/controller_builder.rb +0 -28
  114. data/spec/support/unit/helpers/database_helpers.rb +18 -0
  115. data/spec/support/unit/helpers/model_builder.rb +38 -6
  116. data/spec/support/unit/helpers/rails_versions.rb +2 -2
  117. data/spec/support/unit/matchers/fail_with_message_including_matcher.rb +9 -8
  118. data/spec/support/unit/matchers/fail_with_message_matcher.rb +1 -1
  119. data/spec/support/unit/rails_application.rb +29 -13
  120. data/spec/support/unit/record_validating_confirmation_builder.rb +1 -2
  121. data/spec/support/unit/shared_examples/set_session_or_flash.rb +355 -0
  122. data/spec/unit/shoulda/matchers/action_controller/permit_matcher_spec.rb +433 -0
  123. data/spec/unit/shoulda/matchers/action_controller/render_with_layout_matcher_spec.rb +1 -5
  124. data/spec/unit/shoulda/matchers/action_controller/route_matcher_spec.rb +37 -0
  125. data/spec/unit/shoulda/matchers/action_controller/set_flash_matcher_spec.rb +23 -147
  126. data/spec/unit/shoulda/matchers/action_controller/set_session_matcher_spec.rb +8 -285
  127. data/spec/unit/shoulda/matchers/action_controller/set_session_or_flash_matcher_spec.rb +562 -0
  128. data/spec/unit/shoulda/matchers/active_model/allow_value_matcher_spec.rb +81 -14
  129. data/spec/unit/shoulda/matchers/active_model/disallow_value_matcher_spec.rb +16 -8
  130. data/spec/unit/shoulda/matchers/active_model/numericality_matchers/comparison_matcher_spec.rb +101 -9
  131. data/spec/unit/shoulda/matchers/active_model/numericality_matchers/even_number_matcher_spec.rb +39 -1
  132. data/spec/unit/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher_spec.rb +39 -1
  133. data/spec/unit/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher_spec.rb +39 -0
  134. data/spec/unit/shoulda/matchers/active_model/validate_exclusion_of_matcher_spec.rb +0 -17
  135. data/spec/unit/shoulda/matchers/active_model/validate_inclusion_of_matcher_spec.rb +0 -17
  136. data/spec/unit/shoulda/matchers/active_model/validate_length_of_matcher_spec.rb +0 -17
  137. data/spec/unit/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +838 -271
  138. data/spec/unit/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +0 -19
  139. data/spec/unit/shoulda/matchers/active_record/association_matcher_spec.rb +93 -0
  140. data/spec/unit/shoulda/matchers/active_record/association_matchers/model_reflection_spec.rb +3 -3
  141. data/spec/unit/shoulda/matchers/active_record/define_enum_for_matcher_spec.rb +25 -0
  142. data/spec/unit/shoulda/matchers/active_record/validate_uniqueness_of_matcher_spec.rb +905 -0
  143. data/spec/unit/shoulda/matchers/doublespeak/double_collection_spec.rb +17 -11
  144. data/spec/unit/shoulda/matchers/doublespeak/double_implementation_registry_spec.rb +1 -1
  145. data/spec/unit/shoulda/matchers/doublespeak/double_spec.rb +144 -43
  146. data/spec/unit/shoulda/matchers/doublespeak/object_double_spec.rb +1 -1
  147. data/spec/unit/shoulda/matchers/doublespeak/proxy_implementation_spec.rb +36 -11
  148. data/spec/unit/shoulda/matchers/doublespeak/stub_implementation_spec.rb +29 -16
  149. data/spec/unit/shoulda/matchers/doublespeak/world_spec.rb +8 -5
  150. data/spec/unit/shoulda/matchers/doublespeak_spec.rb +1 -1
  151. data/spec/unit_spec_helper.rb +15 -14
  152. data/spec/warnings_spy.rb +1 -1
  153. metadata +68 -29
  154. data/docs.watchr +0 -5
  155. data/gemfiles/3.0.gemfile +0 -26
  156. data/gemfiles/3.0.gemfile.lock +0 -173
  157. data/gemfiles/3.1.gemfile +0 -32
  158. data/gemfiles/3.1.gemfile.lock +0 -212
  159. data/gemfiles/3.1_1.9.2.gemfile +0 -32
  160. data/gemfiles/3.1_1.9.2.gemfile.lock +0 -212
  161. data/gemfiles/3.2.gemfile +0 -33
  162. data/gemfiles/3.2.gemfile.lock +0 -212
  163. data/gemfiles/3.2_1.9.2.gemfile +0 -31
  164. data/gemfiles/3.2_1.9.2.gemfile.lock +0 -207
  165. data/lib/shoulda/matchers/assertion_error.rb +0 -27
  166. data/lib/shoulda/matchers/doublespeak/structs.rb +0 -10
  167. data/lib/shoulda/matchers/integrations/nunit_test_case_detection.rb +0 -39
  168. data/lib/shoulda/matchers/integrations/rspec.rb +0 -19
  169. data/lib/shoulda/matchers/integrations/test_unit.rb +0 -34
  170. data/spec/unit/shoulda/matchers/action_controller/strong_parameters_matcher_spec.rb +0 -331
  171. data/spec/unit/shoulda/matchers/active_model/validate_uniqueness_of_matcher_spec.rb +0 -564
@@ -1,28 +1,23 @@
1
- require 'shoulda/matchers/assertion_error'
1
+ require 'shoulda/matchers/configuration'
2
2
  require 'shoulda/matchers/doublespeak'
3
3
  require 'shoulda/matchers/error'
4
+ require 'shoulda/matchers/independent'
5
+ require 'shoulda/matchers/integrations'
4
6
  require 'shoulda/matchers/matcher_context'
5
7
  require 'shoulda/matchers/rails_shim'
6
8
  require 'shoulda/matchers/util'
7
9
  require 'shoulda/matchers/version'
8
10
  require 'shoulda/matchers/warn'
9
11
 
10
- require 'shoulda/matchers/independent'
12
+ require 'shoulda/matchers/action_controller'
13
+ require 'shoulda/matchers/active_model'
14
+ require 'shoulda/matchers/active_record'
11
15
 
12
- if defined?(ActiveModel)
13
- require 'shoulda/matchers/active_model'
16
+ module Shoulda
17
+ module Matchers
18
+ class << self
19
+ # @private
20
+ attr_accessor :assertion_exception_class
21
+ end
22
+ end
14
23
  end
15
-
16
- if defined?(ActiveRecord)
17
- require 'shoulda/matchers/active_record'
18
- end
19
-
20
- if defined?(ActionController)
21
- require 'shoulda/matchers/action_controller'
22
- end
23
-
24
- if defined?(RSpec)
25
- require 'shoulda/matchers/integrations/rspec'
26
- end
27
-
28
- require 'shoulda/matchers/integrations/test_unit'
@@ -9,7 +9,10 @@ require 'shoulda/matchers/action_controller/redirect_to_matcher'
9
9
  require 'shoulda/matchers/action_controller/render_template_matcher'
10
10
  require 'shoulda/matchers/action_controller/rescue_from_matcher'
11
11
  require 'shoulda/matchers/action_controller/callback_matcher'
12
- require 'shoulda/matchers/action_controller/strong_parameters_matcher'
12
+ require 'shoulda/matchers/action_controller/permit_matcher'
13
+ require 'shoulda/matchers/action_controller/set_session_or_flash_matcher'
14
+ require 'shoulda/matchers/action_controller/flash_store'
15
+ require 'shoulda/matchers/action_controller/session_store'
13
16
 
14
17
  module Shoulda
15
18
  module Matchers
@@ -0,0 +1,95 @@
1
+ module Shoulda
2
+ module Matchers
3
+ module ActionController
4
+ # @private
5
+ class FlashStore
6
+ def self.future
7
+ new
8
+ end
9
+
10
+ def self.now
11
+ new.use_now!
12
+ end
13
+
14
+ attr_accessor :controller
15
+
16
+ def initialize
17
+ @use_now = false
18
+ end
19
+
20
+ def name
21
+ if @use_now
22
+ 'flash.now'
23
+ else
24
+ 'flash'
25
+ end
26
+ end
27
+
28
+ def has_key?(key)
29
+ values_to_check.include?(key)
30
+ end
31
+
32
+ def has_value?(expected_value)
33
+ values_to_check.values.any? do |actual_value|
34
+ expected_value === actual_value
35
+ end
36
+ end
37
+
38
+ def empty?
39
+ flash.empty?
40
+ end
41
+
42
+ def use_now!
43
+ @use_now = true
44
+ self
45
+ end
46
+
47
+ private
48
+
49
+ def flash
50
+ @_flash ||= copy_of_flash_from_controller
51
+ end
52
+
53
+ def copy_of_flash_from_controller
54
+ controller.flash.dup.tap do |flash|
55
+ copy_flashes(controller.flash, flash)
56
+ copy_discard_if_necessary(controller.flash, flash)
57
+ # sweep_flash_if_necessary(flash)
58
+ end
59
+ end
60
+
61
+ def copy_flashes(original_flash, new_flash)
62
+ flashes = original_flash.instance_variable_get('@flashes').dup
63
+ new_flash.instance_variable_set('@flashes', flashes)
64
+ end
65
+
66
+ def copy_discard_if_necessary(original_flash, new_flash)
67
+ discard = original_flash.instance_variable_get('@discard').dup
68
+ new_flash.instance_variable_set('@discard', discard)
69
+ end
70
+
71
+ def sweep_flash_if_necessary(flash)
72
+ unless @use_now
73
+ flash.sweep
74
+ end
75
+ end
76
+
77
+ def set_values
78
+ flash.instance_variable_get('@flashes')
79
+ end
80
+
81
+ def keys_to_discard
82
+ flash.instance_variable_get('@discard')
83
+ end
84
+
85
+ def values_to_check
86
+ if @use_now
87
+ set_values.slice(*keys_to_discard.to_a)
88
+ else
89
+ set_values.except(*keys_to_discard.to_a)
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -38,14 +38,16 @@ module Shoulda
38
38
  # describe UsersController do
39
39
  # it do
40
40
  # should permit(:first_name, :last_name, :email, :password).
41
- # for(:create)
41
+ # for(:create).
42
+ # on(:user)
42
43
  # end
43
44
  # end
44
45
  #
45
46
  # # Test::Unit
46
47
  # class UsersControllerTest < ActionController::TestCase
47
48
  # should permit(:first_name, :last_name, :email, :password).
48
- # for(:create)
49
+ # for(:create).
50
+ # on(:user)
49
51
  # end
50
52
  #
51
53
  # If your action requires query parameters in order to work, then you'll
@@ -82,7 +84,8 @@ module Shoulda
82
84
  #
83
85
  # it do
84
86
  # should permit(:first_name, :last_name, :email, :password).
85
- # for(:update, params: { id: 1 })
87
+ # for(:update, params: { id: 1 }).
88
+ # on(:user)
86
89
  # end
87
90
  # end
88
91
  #
@@ -93,7 +96,8 @@ module Shoulda
93
96
  # end
94
97
  #
95
98
  # should permit(:first_name, :last_name, :email, :password).
96
- # for(:update, params: { id: 1 })
99
+ # for(:update, params: { id: 1 }).
100
+ # on(:user)
97
101
  # end
98
102
  #
99
103
  # Finally, if you have an action that isn't one of the seven resourceful
@@ -132,10 +136,9 @@ module Shoulda
132
136
  # end
133
137
  #
134
138
  # it do
135
- # should permit(:activated).for(:toggle,
136
- # params: { id: 1 },
137
- # verb: :put
138
- # )
139
+ # should permit(:activated).
140
+ # for(:toggle, params: { id: 1 }, verb: :put).
141
+ # on(:user)
139
142
  # end
140
143
  # end
141
144
  #
@@ -145,28 +148,28 @@ module Shoulda
145
148
  # create(:user, id: 1)
146
149
  # end
147
150
  #
148
- # should permit(:activated).for(:toggle,
149
- # params: { id: 1 },
150
- # verb: :put
151
- # )
151
+ # should permit(:activated).
152
+ # for(:toggle, params: { id: 1 }, verb: :put).
153
+ # on(:user)
152
154
  # end
153
155
  #
154
- # @return [StrongParametersMatcher]
156
+ # @return [PermitMatcher]
155
157
  #
156
158
  def permit(*params)
157
- StrongParametersMatcher.new(params).in_context(self)
159
+ PermitMatcher.new(params).in_context(self)
158
160
  end
159
161
 
160
162
  # @private
161
- class StrongParametersMatcher
163
+ class PermitMatcher
162
164
  attr_writer :stubbed_params
163
165
 
164
166
  def initialize(expected_permitted_params)
167
+ @expected_permitted_params = expected_permitted_params
165
168
  @action = nil
166
169
  @verb = nil
167
170
  @request_params = {}
168
- @expected_permitted_params = expected_permitted_params
169
- set_double_collection
171
+ @subparameter = nil
172
+ @parameters_doubles = ParametersDoubles.new
170
173
  end
171
174
 
172
175
  def for(action, options = {})
@@ -176,19 +179,32 @@ module Shoulda
176
179
  self
177
180
  end
178
181
 
182
+ def add_params(params)
183
+ request_params.merge!(params)
184
+ self
185
+ end
186
+
187
+ def on(subparameter)
188
+ @subparameter = subparameter
189
+ @parameters_doubles = SliceOfParametersDoubles.new(subparameter)
190
+ self
191
+ end
192
+
179
193
  def in_context(context)
180
194
  @context = context
181
195
  self
182
196
  end
183
197
 
184
198
  def description
185
- "permit #{verb.upcase} ##{action} to receive parameters #{param_names_as_sentence}"
199
+ "(on #{verb.upcase} ##{action}) " + expectation
186
200
  end
187
201
 
188
202
  def matches?(controller)
189
203
  @controller = controller
190
204
  ensure_action_and_verb_present!
191
205
 
206
+ parameters_doubles.register
207
+
192
208
  Doublespeak.with_doubles_activated do
193
209
  context.__send__(verb, action, request_params)
194
210
  end
@@ -197,32 +213,49 @@ module Shoulda
197
213
  end
198
214
 
199
215
  def failure_message
200
- "Expected controller to permit #{unpermitted_params.to_sentence}, but it did not."
216
+ "Expected #{verb.upcase} ##{action} to #{expectation},\nbut #{reality}."
201
217
  end
202
218
  alias failure_message_for_should failure_message
203
219
 
204
220
  def failure_message_when_negated
205
- "Expected controller not to permit #{verified_permitted_params.to_sentence}, but it did."
221
+ "Expected #{verb.upcase} ##{action} not to #{expectation},\nbut it did."
206
222
  end
207
223
  alias failure_message_for_should_not failure_message_when_negated
208
224
 
209
225
  protected
210
226
 
211
- attr_reader :controller, :double_collection, :action, :verb,
212
- :request_params, :expected_permitted_params, :context
227
+ attr_reader :controller, :double_collections_by_param, :action, :verb,
228
+ :request_params, :expected_permitted_params, :context, :subparameter,
229
+ :parameters_doubles
230
+
231
+ def expectation
232
+ message = 'restrict parameters '
233
+
234
+ if subparameter
235
+ message << " for #{subparameter.inspect}"
236
+ end
237
+
238
+ message << 'to ' + format_param_names(expected_permitted_params)
213
239
 
214
- def set_double_collection
215
- @double_collection =
216
- Doublespeak.double_collection_for(::ActionController::Parameters)
240
+ message
241
+ end
217
242
 
218
- @double_collection.register_stub(:require).to_return { |params| params }
219
- @double_collection.register_proxy(:permit)
243
+ def reality
244
+ if actual_permitted_params.empty?
245
+ 'it did not restrict any parameters'
246
+ else
247
+ 'the restricted parameters were ' +
248
+ format_param_names(actual_permitted_params) +
249
+ ' instead'
250
+ end
251
+ end
252
+
253
+ def format_param_names(param_names)
254
+ param_names.map(&:inspect).to_sentence
220
255
  end
221
256
 
222
257
  def actual_permitted_params
223
- double_collection.calls_to(:permit).inject([]) do |all_param_names, call|
224
- all_param_names + call.args
225
- end.flatten
258
+ parameters_doubles.permitted_params
226
259
  end
227
260
 
228
261
  def permit_called?
@@ -258,6 +291,90 @@ module Shoulda
258
291
  expected_permitted_params.map(&:inspect).to_sentence
259
292
  end
260
293
 
294
+ # @private
295
+ class ParametersDoubles
296
+ def self.permitted_params_within(double_collection)
297
+ double_collection.calls_to(:permit).map(&:args).flatten
298
+ end
299
+
300
+ def initialize
301
+ klass = ::ActionController::Parameters
302
+ @double_collection = Doublespeak.double_collection_for(klass)
303
+ end
304
+
305
+ def register
306
+ double_collection.register_proxy(:permit)
307
+ end
308
+
309
+ def permitted_params
310
+ ParametersDoubles.permitted_params_within(double_collection)
311
+ end
312
+
313
+ protected
314
+
315
+ attr_reader :double_collection
316
+ end
317
+
318
+ # @private
319
+ class SliceOfParametersDoubles
320
+ TOP_LEVEL = Object.new
321
+
322
+ def initialize(subparameter)
323
+ klass = ::ActionController::Parameters
324
+
325
+ @subparameter = subparameter
326
+ @double_collections_by_param = {
327
+ TOP_LEVEL => Doublespeak.double_collection_for(klass)
328
+ }
329
+ end
330
+
331
+ def register
332
+ top_level_collection = double_collections_by_param[TOP_LEVEL]
333
+ double_permit_on(top_level_collection)
334
+ double_require_on(top_level_collection)
335
+ end
336
+
337
+ def permitted_params
338
+ if double_collections_by_param.key?(subparameter)
339
+ ParametersDoubles.permitted_params_within(
340
+ double_collections_by_param[subparameter]
341
+ )
342
+ else
343
+ []
344
+ end
345
+ end
346
+
347
+ protected
348
+
349
+ attr_reader :subparameter, :double_collections_by_param
350
+
351
+ private
352
+
353
+ def double_permit_on(double_collection)
354
+ double_collection.register_proxy(:permit)
355
+ end
356
+
357
+ def double_require_on(double_collection)
358
+ double_collections_by_param = @double_collections_by_param
359
+ require_double = double_collection.register_proxy(:require)
360
+
361
+ require_double.to_return do |call|
362
+ param_name = call.args.first
363
+ params = call.return_value
364
+ double_collections_by_param[param_name] ||=
365
+ double_permit_against(params)
366
+ end
367
+ end
368
+
369
+ def double_permit_against(params)
370
+ klass = params.singleton_class
371
+
372
+ Doublespeak.double_collection_for(klass).tap do |double_collection|
373
+ double_permit_on(double_collection)
374
+ end
375
+ end
376
+ end
377
+
261
378
  # @private
262
379
  class ActionNotDefinedError < StandardError
263
380
  def message
@@ -82,7 +82,7 @@ module Shoulda
82
82
  @context.__send__(:assert_redirected_to, url)
83
83
  @failure_message_when_negated = "Didn't expect to redirect to #{url}"
84
84
  true
85
- rescue Shoulda::Matchers::AssertionError => error
85
+ rescue Shoulda::Matchers.assertion_exception_class => error
86
86
  @failure_message = error.message
87
87
  false
88
88
  end
@@ -80,7 +80,7 @@ module Shoulda
80
80
  @context.__send__(:assert_template, @options, @message)
81
81
  @failure_message_when_negated = "Didn't expect to render #{@template}"
82
82
  true
83
- rescue Shoulda::Matchers::AssertionError => error
83
+ rescue Shoulda::Matchers.assertion_exception_class => error
84
84
  @failure_message = error.message
85
85
  false
86
86
  end
@@ -125,7 +125,7 @@ module Shoulda
125
125
 
126
126
  def recorded_layouts
127
127
  if @context
128
- @context.instance_variable_get(Shoulda::Matchers::RailsShim.layouts_ivar)
128
+ @context.instance_variable_get('@_layouts')
129
129
  else
130
130
  {}
131
131
  end