durable_parameters 0.2.3

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 (56) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +853 -0
  4. data/Rakefile +29 -0
  5. data/app/params/account_params.rb.example +38 -0
  6. data/app/params/application_params.rb +16 -0
  7. data/lib/durable_parameters/adapters/hanami.rb +138 -0
  8. data/lib/durable_parameters/adapters/rage.rb +124 -0
  9. data/lib/durable_parameters/adapters/rails.rb +280 -0
  10. data/lib/durable_parameters/adapters/sinatra.rb +91 -0
  11. data/lib/durable_parameters/core/application_params.rb +334 -0
  12. data/lib/durable_parameters/core/configuration.rb +83 -0
  13. data/lib/durable_parameters/core/forbidden_attributes_protection.rb +48 -0
  14. data/lib/durable_parameters/core/parameters.rb +643 -0
  15. data/lib/durable_parameters/core/params_registry.rb +110 -0
  16. data/lib/durable_parameters/core.rb +15 -0
  17. data/lib/durable_parameters/log_subscriber.rb +34 -0
  18. data/lib/durable_parameters/railtie.rb +65 -0
  19. data/lib/durable_parameters/version.rb +7 -0
  20. data/lib/durable_parameters.rb +41 -0
  21. data/lib/generators/rails/USAGE +12 -0
  22. data/lib/generators/rails/durable_parameters_controller_generator.rb +17 -0
  23. data/lib/generators/rails/templates/controller.rb +94 -0
  24. data/lib/legacy/action_controller/application_params.rb +235 -0
  25. data/lib/legacy/action_controller/parameters.rb +524 -0
  26. data/lib/legacy/action_controller/params_registry.rb +108 -0
  27. data/lib/legacy/active_model/forbidden_attributes_protection.rb +40 -0
  28. data/test/action_controller_required_params_test.rb +36 -0
  29. data/test/action_controller_tainted_params_test.rb +29 -0
  30. data/test/active_model_mass_assignment_taint_protection_test.rb +25 -0
  31. data/test/application_params_array_test.rb +245 -0
  32. data/test/application_params_edge_cases_test.rb +361 -0
  33. data/test/application_params_test.rb +893 -0
  34. data/test/controller_generator_test.rb +31 -0
  35. data/test/core_parameters_test.rb +2376 -0
  36. data/test/durable_parameters_test.rb +115 -0
  37. data/test/enhanced_error_messages_test.rb +120 -0
  38. data/test/gemfiles/Gemfile.rails-3.0.x +14 -0
  39. data/test/gemfiles/Gemfile.rails-3.1.x +14 -0
  40. data/test/gemfiles/Gemfile.rails-3.2.x +14 -0
  41. data/test/log_on_unpermitted_params_test.rb +49 -0
  42. data/test/metadata_validation_test.rb +294 -0
  43. data/test/multi_parameter_attributes_test.rb +38 -0
  44. data/test/parameters_core_methods_test.rb +503 -0
  45. data/test/parameters_integration_test.rb +553 -0
  46. data/test/parameters_permit_test.rb +491 -0
  47. data/test/parameters_require_test.rb +9 -0
  48. data/test/parameters_taint_test.rb +98 -0
  49. data/test/params_registry_concurrency_test.rb +422 -0
  50. data/test/params_registry_test.rb +112 -0
  51. data/test/permit_by_model_test.rb +227 -0
  52. data/test/raise_on_unpermitted_params_test.rb +32 -0
  53. data/test/test_helper.rb +38 -0
  54. data/test/transform_params_edge_cases_test.rb +526 -0
  55. data/test/transformation_test.rb +360 -0
  56. metadata +223 -0
@@ -0,0 +1,491 @@
1
+ require 'test_helper'
2
+ require 'action_dispatch/http/upload'
3
+
4
+ class NestedParametersTest < Minitest::Test
5
+ def assert_filtered_out(params, key)
6
+ assert !params.has_key?(key), "key #{key.inspect} has not been filtered out"
7
+ end
8
+
9
+ #
10
+ # --- Basic interface --------------------------------------------------------
11
+ #
12
+
13
+ # --- nothing ----------------------------------------------------------------
14
+
15
+ def test_if_nothing_is_permitted_the_hash_becomes_empty
16
+ params = ActionController::Parameters.new(:id => '1234')
17
+ permitted = params.permit
18
+ assert permitted.permitted?
19
+ assert permitted.empty?
20
+ end
21
+
22
+ # --- key --------------------------------------------------------------------
23
+
24
+ def test_key_permitted_scalar_values
25
+ values = ['a', :a, nil]
26
+ values += [0, 1.0, 2**128, BigDecimal('1')]
27
+ values += [true, false]
28
+ values += [Date.today, Time.now, DateTime.now]
29
+ values += [StringIO.new, STDOUT, ActionDispatch::Http::UploadedFile.new(:tempfile => __FILE__), Rack::Test::UploadedFile.new(__FILE__)]
30
+
31
+ values.each do |value|
32
+ params = ActionController::Parameters.new(:id => value)
33
+ permitted = params.permit(:id)
34
+ if value.nil?
35
+ assert_nil permitted[:id]
36
+ else
37
+ assert_equal value, permitted[:id]
38
+ end
39
+
40
+ %w(i f).each do |suffix|
41
+ params = ActionController::Parameters.new("foo(000#{suffix})" => value)
42
+ permitted = params.permit(:foo)
43
+ if value.nil?
44
+ assert_nil permitted["foo(000#{suffix})"]
45
+ else
46
+ assert_equal value, permitted["foo(000#{suffix})"]
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ def test_key_unknown_keys_are_filtered_out
53
+ params = ActionController::Parameters.new(:id => '1234', :injected => 'injected')
54
+ permitted = params.permit(:id)
55
+ assert_equal '1234', permitted[:id]
56
+ assert_filtered_out permitted, :injected
57
+ end
58
+
59
+ def test_key_arrays_are_filtered_out
60
+ [[], [1], ['1']].each do |array|
61
+ params = ActionController::Parameters.new(:id => array)
62
+ permitted = params.permit(:id)
63
+ assert_filtered_out permitted, :id
64
+
65
+ %w(i f).each do |suffix|
66
+ params = ActionController::Parameters.new("foo(000#{suffix})" => array)
67
+ permitted = params.permit(:foo)
68
+ assert_filtered_out permitted, "foo(000#{suffix})"
69
+ end
70
+ end
71
+ end
72
+
73
+ def test_key_hashes_are_filtered_out
74
+ [{}, {:foo => 1}, {:foo => 'bar'}].each do |hash|
75
+ params = ActionController::Parameters.new(:id => hash)
76
+ permitted = params.permit(:id)
77
+ assert_filtered_out permitted, :id
78
+
79
+ %w(i f).each do |suffix|
80
+ params = ActionController::Parameters.new("foo(000#{suffix})" => hash)
81
+ permitted = params.permit(:foo)
82
+ assert_filtered_out permitted, "foo(000#{suffix})"
83
+ end
84
+ end
85
+ end
86
+
87
+ def test_key_non_permitted_scalar_values_are_filtered_out
88
+ params = ActionController::Parameters.new(:id => Object.new)
89
+ permitted = params.permit(:id)
90
+ assert_filtered_out permitted, :id
91
+
92
+ %w(i f).each do |suffix|
93
+ params = ActionController::Parameters.new("foo(000#{suffix})" => Object.new)
94
+ permitted = params.permit(:foo)
95
+ assert_filtered_out permitted, "foo(000#{suffix})"
96
+ end
97
+ end
98
+
99
+ def test_key_it_is_not_assigned_if_not_present_in_params
100
+ params = ActionController::Parameters.new(:name => 'Joe')
101
+ permitted = params.permit(:id)
102
+ assert !permitted.has_key?(:id)
103
+ end
104
+
105
+ def test_do_not_break_params_filtering_on_nil_values
106
+ params = ActionController::Parameters.new(:a => 1, :b => [1, 2, 3], :c => nil)
107
+
108
+ permitted = params.permit(:a, :c => [], :b => [])
109
+ assert_equal 1, permitted[:a]
110
+ assert_equal [1, 2, 3], permitted[:b]
111
+ assert_nil permitted[:c]
112
+ end
113
+
114
+ def test_permit_parameters_as_an_array
115
+ params = ActionController::Parameters.new(:foo => 'bar')
116
+
117
+ assert_equal 'bar', params.permit([:foo])[:foo]
118
+ end
119
+
120
+ # --- key to empty array -----------------------------------------------------
121
+
122
+ def test_key_to_empty_array_empty_arrays_pass
123
+ params = ActionController::Parameters.new(:id => [])
124
+ permitted = params.permit(:id => [])
125
+ assert_equal [], permitted[:id]
126
+ end
127
+
128
+ def test_key_to_empty_array_arrays_of_permitted_scalars_pass
129
+ [['foo'], [1], ['foo', 'bar'], [1, 2, 3]].each do |array|
130
+ params = ActionController::Parameters.new(:id => array)
131
+ permitted = params.permit(:id => [])
132
+ assert_equal array, permitted[:id]
133
+ end
134
+ end
135
+
136
+ def test_key_to_empty_array_permitted_scalar_values_do_not_pass
137
+ ['foo', 1].each do |permitted_scalar|
138
+ params = ActionController::Parameters.new(:id => permitted_scalar)
139
+ permitted = params.permit(:id => [])
140
+ assert_filtered_out permitted, :id
141
+ end
142
+ end
143
+
144
+ def test_key_to_empty_array_arrays_of_non_permitted_scalar_do_not_pass
145
+ [[Object.new], [[]], [[1]], [{}], [{:id => '1'}]].each do |non_permitted_scalar|
146
+ params = ActionController::Parameters.new(:id => non_permitted_scalar)
147
+ permitted = params.permit(:id => [])
148
+ assert_filtered_out permitted, :id
149
+ end
150
+ end
151
+
152
+ #
153
+ # --- Nesting ----------------------------------------------------------------
154
+ #
155
+
156
+ def test_permitted_nested_parameters
157
+ params = ActionController::Parameters.new({
158
+ :book => {
159
+ :title => "Romeo and Juliet",
160
+ :authors => [{
161
+ :name => "William Shakespeare",
162
+ :born => "1564-04-26"
163
+ }, {
164
+ :name => "Christopher Marlowe"
165
+ }, {
166
+ :name => %w(malicious injected names)
167
+ }],
168
+ :details => {
169
+ :pages => 200,
170
+ :genre => "Tragedy"
171
+ }
172
+ },
173
+ :magazine => "Mjallo!"
174
+ })
175
+
176
+ permitted = params.permit :book => [ :title, { :authors => [ :name ] }, { :details => :pages } ]
177
+
178
+ assert permitted.permitted?
179
+ assert_equal "Romeo and Juliet", permitted[:book][:title]
180
+ assert_equal "William Shakespeare", permitted[:book][:authors][0][:name]
181
+ assert_equal "Christopher Marlowe", permitted[:book][:authors][1][:name]
182
+ assert_equal 200, permitted[:book][:details][:pages]
183
+
184
+ assert_filtered_out permitted[:book][:authors][2], :name
185
+
186
+ assert_filtered_out permitted, :magazine
187
+ assert_filtered_out permitted[:book][:details], :genre
188
+ assert_filtered_out permitted[:book][:authors][0], :born
189
+ end
190
+
191
+ def test_permitted_nested_parameters_with_a_string_or_a_symbol_as_a_key
192
+ params = ActionController::Parameters.new({
193
+ :book => {
194
+ 'authors' => [
195
+ { :name => "William Shakespeare", :born => "1564-04-26" },
196
+ { :name => "Christopher Marlowe" }
197
+ ]
198
+ }
199
+ })
200
+
201
+ permitted = params.permit :book => [ { 'authors' => [ :name ] } ]
202
+
203
+ assert_equal "William Shakespeare", permitted[:book]['authors'][0][:name]
204
+ assert_equal "William Shakespeare", permitted[:book][:authors][0][:name]
205
+ assert_equal "Christopher Marlowe", permitted[:book]['authors'][1][:name]
206
+ assert_equal "Christopher Marlowe", permitted[:book][:authors][1][:name]
207
+
208
+ permitted = params.permit :book => [ { :authors => [ :name ] } ]
209
+
210
+ assert_equal "William Shakespeare", permitted[:book]['authors'][0][:name]
211
+ assert_equal "William Shakespeare", permitted[:book][:authors][0][:name]
212
+ assert_equal "Christopher Marlowe", permitted[:book]['authors'][1][:name]
213
+ assert_equal "Christopher Marlowe", permitted[:book][:authors][1][:name]
214
+ end
215
+
216
+ def test_nested_arrays_with_strings
217
+ params = ActionController::Parameters.new({
218
+ :book => {
219
+ :genres => ["Tragedy"]
220
+ }
221
+ })
222
+
223
+ permitted = params.permit :book => {:genres => []}
224
+ assert_equal ["Tragedy"], permitted[:book][:genres]
225
+ end
226
+
227
+ def test_permit_may_specify_symbols_or_strings
228
+ params = ActionController::Parameters.new({
229
+ :book => {
230
+ :title => "Romeo and Juliet",
231
+ :author => "William Shakespeare"
232
+ },
233
+ :magazine => "Shakespeare Today"
234
+ })
235
+
236
+ permitted = params.permit({ :book => ["title", :author] }, "magazine")
237
+ assert_equal "Romeo and Juliet", permitted[:book][:title]
238
+ assert_equal "William Shakespeare", permitted[:book][:author]
239
+ assert_equal "Shakespeare Today", permitted[:magazine]
240
+ end
241
+
242
+ def test_nested_array_with_strings_that_should_be_hashes
243
+ params = ActionController::Parameters.new({
244
+ :book => {
245
+ :genres => ["Tragedy"]
246
+ }
247
+ })
248
+
249
+ permitted = params.permit :book => { :genres => :type }
250
+ assert permitted[:book][:genres].empty?
251
+ end
252
+
253
+ def test_nested_array_with_strings_that_should_be_hashes_and_additional_values
254
+ params = ActionController::Parameters.new({
255
+ :book => {
256
+ :title => "Romeo and Juliet",
257
+ :genres => ["Tragedy"]
258
+ }
259
+ })
260
+
261
+ permitted = params.permit :book => [ :title, { :genres => :type } ]
262
+ assert_equal "Romeo and Juliet", permitted[:book][:title]
263
+ assert permitted[:book][:genres].empty?
264
+ end
265
+
266
+ def test_nested_string_that_should_be_a_hash
267
+ params = ActionController::Parameters.new({
268
+ :book => {
269
+ :genre => "Tragedy"
270
+ }
271
+ })
272
+
273
+ permitted = params.permit :book => { :genre => :type }
274
+ assert_nil permitted[:book][:genre]
275
+ end
276
+
277
+ def test_fields_for_style_nested_params
278
+ params = ActionController::Parameters.new({
279
+ :book => {
280
+ :authors_attributes => {
281
+ :'0' => { :name => 'William Shakespeare', :age_of_death => '52' },
282
+ :'1' => { :name => 'Unattributed Assistant' },
283
+ :'2' => { :name => %w(injected names)}
284
+ }
285
+ }
286
+ })
287
+ permitted = params.permit :book => { :authors_attributes => [ :name ] }
288
+
289
+ refute_nil permitted[:book][:authors_attributes]['0']
290
+ refute_nil permitted[:book][:authors_attributes]['1']
291
+ assert permitted[:book][:authors_attributes]['2'].empty?
292
+ assert_equal 'William Shakespeare', permitted[:book][:authors_attributes]['0'][:name]
293
+ assert_equal 'Unattributed Assistant', permitted[:book][:authors_attributes]['1'][:name]
294
+
295
+ assert_filtered_out permitted[:book][:authors_attributes]['0'], :age_of_death
296
+ end
297
+
298
+ def test_fields_for_style_nested_params_with_negative_numbers
299
+ params = ActionController::Parameters.new({
300
+ :book => {
301
+ :authors_attributes => {
302
+ :'-1' => { :name => 'William Shakespeare', :age_of_death => '52' },
303
+ :'-2' => { :name => 'Unattributed Assistant' }
304
+ }
305
+ }
306
+ })
307
+ permitted = params.permit :book => { :authors_attributes => [:name] }
308
+
309
+ refute_nil permitted[:book][:authors_attributes]['-1']
310
+ refute_nil permitted[:book][:authors_attributes]['-2']
311
+ assert_equal 'William Shakespeare', permitted[:book][:authors_attributes]['-1'][:name]
312
+ assert_equal 'Unattributed Assistant', permitted[:book][:authors_attributes]['-2'][:name]
313
+
314
+ assert_filtered_out permitted[:book][:authors_attributes]['-1'], :age_of_death
315
+ end
316
+
317
+ def test_fields_for_style_nested_params_with_nested_arrays
318
+ params = ActionController::Parameters.new({
319
+ :book => {
320
+ :authors_attributes => {
321
+ :'0' => ['William Shakespeare', '52'],
322
+ :'1' => ['Unattributed Assistant']
323
+ }
324
+ }
325
+ })
326
+ permitted = params.permit :book => { :authors_attributes => { :'0' => [], :'1' => [] } }
327
+
328
+ refute_nil permitted[:book][:authors_attributes]['0']
329
+ refute_nil permitted[:book][:authors_attributes]['1']
330
+ assert_nil permitted[:book][:authors_attributes]['2']
331
+ assert_equal 'William Shakespeare', permitted[:book][:authors_attributes]['0'][0]
332
+ assert_equal 'Unattributed Assistant', permitted[:book][:authors_attributes]['1'][0]
333
+ end
334
+
335
+ def test_nested_number_as_key
336
+ params = ActionController::Parameters.new({
337
+ :product => {
338
+ :properties => {
339
+ '0' => "prop0",
340
+ '1' => "prop1"
341
+ }
342
+ }
343
+ })
344
+ params = params.require(:product).permit(:properties => ["0"])
345
+ refute_nil params[:properties]["0"]
346
+ assert_nil params[:properties]["1"]
347
+ assert_equal "prop0", params[:properties]["0"]
348
+ end
349
+
350
+ def test_fetch_with_a_default_value_of_a_hash_does_not_mutate_the_object
351
+ params = ActionController::Parameters.new({})
352
+ params.fetch :foo, {}
353
+ assert_nil params[:foo]
354
+ end
355
+
356
+ def test_hashes_in_array_values_get_wrapped
357
+ params = ActionController::Parameters.new(:foo => [{}, {}])
358
+ params[:foo].each do |hash|
359
+ assert !hash.permitted?
360
+ end
361
+ end
362
+
363
+ def test_permit_with_deeply_nested_structures
364
+ params = ActionController::Parameters.new({
365
+ :user => {
366
+ :profile => {
367
+ :settings => {
368
+ :notifications => {
369
+ :email => true,
370
+ :sms => false
371
+ }
372
+ }
373
+ }
374
+ }
375
+ })
376
+
377
+ permitted = params.permit(:user => { :profile => { :settings => { :notifications => [:email, :sms] } } })
378
+
379
+ assert permitted.permitted?
380
+ assert_equal true, permitted[:user][:profile][:settings][:notifications][:email]
381
+ assert_equal false, permitted[:user][:profile][:settings][:notifications][:sms]
382
+ end
383
+
384
+ def test_permit_with_mixed_array_and_hash
385
+ params = ActionController::Parameters.new({
386
+ :posts => [
387
+ { :title => 'Post 1', :tags => ['ruby', 'rails'] },
388
+ { :title => 'Post 2', :tags => ['js', 'react'] }
389
+ ]
390
+ })
391
+
392
+ permitted = params.permit(:posts => [:title, { :tags => [] }])
393
+
394
+ assert permitted.permitted?
395
+ assert_equal 'Post 1', permitted[:posts][0][:title]
396
+ assert_equal ['ruby', 'rails'], permitted[:posts][0][:tags]
397
+ assert_equal 'Post 2', permitted[:posts][1][:title]
398
+ assert_equal ['js', 'react'], permitted[:posts][1][:tags]
399
+ end
400
+
401
+ def test_permit_with_empty_nested_hash
402
+ params = ActionController::Parameters.new({
403
+ :user => {
404
+ :profile => {}
405
+ }
406
+ })
407
+
408
+ permitted = params.permit(:user => { :profile => {} })
409
+
410
+ assert permitted.permitted?
411
+ assert_instance_of ActionController::Parameters, permitted[:user][:profile]
412
+ assert permitted[:user][:profile].permitted?
413
+ assert_empty permitted[:user][:profile]
414
+ end
415
+
416
+ def test_permit_with_symbol_keys_in_nested_structure
417
+ params = ActionController::Parameters.new({
418
+ user: {
419
+ profile: {
420
+ name: 'John',
421
+ 'age' => 30
422
+ }
423
+ }
424
+ })
425
+
426
+ permitted = params.permit(user: { profile: [:name, :age] })
427
+
428
+ assert permitted.permitted?
429
+ assert_equal 'John', permitted[:user][:profile][:name]
430
+ assert_equal 30, permitted[:user][:profile][:age]
431
+ end
432
+
433
+ def test_permit_filters_unknown_nested_keys
434
+ params = ActionController::Parameters.new({
435
+ :user => {
436
+ :name => 'John',
437
+ :secret => 'hidden'
438
+ }
439
+ })
440
+
441
+ permitted = params.permit(:user => [:name])
442
+
443
+ assert permitted.permitted?
444
+ assert_equal 'John', permitted[:user][:name]
445
+ assert_filtered_out permitted[:user], :secret
446
+ end
447
+
448
+ def test_permit_with_multiple_levels_of_arrays
449
+ params = ActionController::Parameters.new({
450
+ :matrix => [
451
+ [1, 2, 3],
452
+ [4, 5, 6]
453
+ ]
454
+ })
455
+
456
+ permitted = params.permit(:matrix => [])
457
+
458
+ assert permitted.permitted?
459
+ # Nested arrays are not permitted by default, so matrix should be filtered out
460
+ assert_filtered_out permitted, :matrix
461
+ end
462
+
463
+ def test_permit_with_complex_mixed_structure
464
+ params = ActionController::Parameters.new({
465
+ :company => {
466
+ :name => 'ACME',
467
+ :employees => [
468
+ { :name => 'Alice', :skills => ['Ruby', 'Rails'] },
469
+ { :name => 'Bob', :skills => ['JS', 'React'] }
470
+ ],
471
+ :offices => {
472
+ :headquarters => { :city => 'NYC', :country => 'USA' },
473
+ :branch => { :city => 'LA', :country => 'USA' }
474
+ }
475
+ }
476
+ })
477
+
478
+ permitted = params.permit(:company => [
479
+ :name,
480
+ { :employees => [:name, { :skills => [] }] },
481
+ { :offices => { :headquarters => [:city, :country], :branch => [:city, :country] } }
482
+ ])
483
+
484
+ assert permitted.permitted?
485
+ assert_equal 'ACME', permitted[:company][:name]
486
+ assert_equal 'Alice', permitted[:company][:employees][0][:name]
487
+ assert_equal ['Ruby', 'Rails'], permitted[:company][:employees][0][:skills]
488
+ assert_equal 'NYC', permitted[:company][:offices][:headquarters][:city]
489
+ assert_equal 'USA', permitted[:company][:offices][:headquarters][:country]
490
+ end
491
+ end
@@ -0,0 +1,9 @@
1
+ require 'test_helper'
2
+
3
+ class ParametersRequireTest < Minitest::Test
4
+ def test_required_parameters_must_be_present_not_merely_not_nil
5
+ assert_raises(ActionController::ParameterMissing) do
6
+ ActionController::Parameters.new(:person => {}).require(:person)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,98 @@
1
+ require 'test_helper'
2
+
3
+ class ParametersTaintTest < Minitest::Test
4
+ def setup
5
+ @params = ActionController::Parameters.new(
6
+ :person => {
7
+ :age => '32',
8
+ :name => {
9
+ :first => 'David',
10
+ :last => 'Heinemeier Hansson'
11
+ },
12
+ :addresses => [{:city => 'Chicago', :state => 'Illinois'}]
13
+ }
14
+ )
15
+ end
16
+
17
+ def test_fetch_raises_parameter_missing_exception
18
+ e = assert_raises(ActionController::ParameterMissing) do
19
+ @params.fetch :foo
20
+ end
21
+ assert_equal :foo, e.param
22
+ end
23
+
24
+ def test_fetch_doesnt_raise_parameter_missing_exception_if_there_is_a_default
25
+ assert_equal "monkey", @params.fetch(:foo, "monkey")
26
+ assert_equal "monkey", @params.fetch(:foo) { "monkey" }
27
+ end
28
+
29
+ def test_not_permitted_is_sticky_on_accessors
30
+ assert !@params.slice(:person).permitted?
31
+ assert !@params[:person][:name].permitted?
32
+ assert !@params[:person].except(:name).permitted?
33
+
34
+ @params.each { |key, value| assert(!value.permitted?) if key == "person" }
35
+
36
+ assert !@params.fetch(:person).permitted?
37
+
38
+ assert !@params.values_at(:person).first.permitted?
39
+ end
40
+
41
+ def test_permitted_is_sticky_on_accessors
42
+ @params.permit!
43
+ assert @params.slice(:person).permitted?
44
+ assert @params[:person][:name].permitted?
45
+ assert @params[:person].except(:name).permitted?
46
+
47
+ @params.each { |key, value| assert(value.permitted?) if key == "person" }
48
+
49
+ assert @params.fetch(:person).permitted?
50
+
51
+ assert @params.values_at(:person).first.permitted?
52
+ end
53
+
54
+ def test_not_permitted_is_sticky_on_mutators
55
+ assert !@params.delete_if { |k, v| k == "person" }.permitted?
56
+ assert !@params.keep_if { |k, v| k == "person" }.permitted? if @params.respond_to?(:keep_if)
57
+ end
58
+
59
+ def test_permitted_is_sticky_on_mutators
60
+ @params.permit!
61
+ assert @params.delete_if { |k, v| k == "person" }.permitted?
62
+ assert @params.keep_if { |k, v| k == "person" }.permitted? if @params.respond_to?(:keep_if)
63
+ end
64
+
65
+ def test_not_permitted_is_sticky_beyond_merges
66
+ assert !@params.merge(:a => "b").permitted?
67
+ end
68
+
69
+ def test_permitted_is_sticky_beyond_merges
70
+ @params.permit!
71
+ assert @params.merge(:a => "b").permitted?
72
+ end
73
+
74
+ def test_modifying_the_parameters
75
+ @params[:person][:hometown] = "Chicago"
76
+ @params[:person][:family] = { :brother => "Jonas" }
77
+
78
+ assert_equal "Chicago", @params[:person][:hometown]
79
+ assert_equal "Jonas", @params[:person][:family][:brother]
80
+ end
81
+
82
+ def test_permitting_parameters_that_are_not_there_should_not_include_the_keys
83
+ assert !@params.permit(:person, :funky).has_key?(:funky)
84
+ end
85
+
86
+ def test_permit_state_is_kept_on_a_dup
87
+ @params.permit!
88
+ assert_equal @params.permitted?, @params.dup.permitted?
89
+ end
90
+
91
+ def test_permit_is_recursive
92
+ @params.permit!
93
+ assert @params.permitted?
94
+ assert @params[:person].permitted?
95
+ assert @params[:person][:name].permitted?
96
+ assert @params[:person][:addresses][0].permitted?
97
+ end
98
+ end