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,2376 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ class CoreParametersTest < Minitest::Test
6
+ def setup
7
+ # Ensure no action on unpermitted parameters for testing
8
+ StrongParameters::Core::Parameters.action_on_unpermitted_parameters = nil
9
+
10
+ @params = StrongParameters::Core::Parameters.new(
11
+ name: 'John',
12
+ email: 'john@example.com',
13
+ age: 30,
14
+ admin: true,
15
+ profile: {
16
+ bio: 'Developer',
17
+ location: 'NYC'
18
+ },
19
+ tags: ['ruby', 'rails'],
20
+ scores: [95, 87, 92]
21
+ )
22
+ end
23
+
24
+ # Test initialization
25
+ def test_initialization_with_nil
26
+ params = StrongParameters::Core::Parameters.new(nil)
27
+ assert_equal({}, params.to_h)
28
+ assert !params.permitted?
29
+ end
30
+
31
+ def test_initialization_with_empty_hash
32
+ params = StrongParameters::Core::Parameters.new({})
33
+ assert_equal({}, params.to_h)
34
+ assert !params.permitted?
35
+ end
36
+
37
+ def test_initialization_with_hash
38
+ params = StrongParameters::Core::Parameters.new(key: 'value')
39
+ assert_equal 'value', params[:key]
40
+ assert !params.permitted?
41
+ end
42
+
43
+ def test_initialization_normalizes_keys
44
+ params = StrongParameters::Core::Parameters.new('name' => 'John', :email => 'test@example.com')
45
+ assert_equal 'John', params[:name]
46
+ assert_equal 'test@example.com', params[:email]
47
+ assert_equal ['name', 'email'], params.keys
48
+ end
49
+
50
+ def test_initialization_with_nested_hashes
51
+ params = StrongParameters::Core::Parameters.new(
52
+ user: { profile: { name: 'John' } }
53
+ )
54
+ assert params[:user].is_a?(StrongParameters::Core::Parameters)
55
+ assert params[:user][:profile].is_a?(StrongParameters::Core::Parameters)
56
+ assert_equal 'John', params[:user][:profile][:name]
57
+ end
58
+
59
+ def test_initialization_with_arrays_of_hashes
60
+ params = StrongParameters::Core::Parameters.new(
61
+ users: [{ name: 'John' }, { name: 'Jane' }]
62
+ )
63
+ assert params[:users].is_a?(Array)
64
+ assert params[:users][0].is_a?(StrongParameters::Core::Parameters)
65
+ assert params[:users][1].is_a?(StrongParameters::Core::Parameters)
66
+ assert_equal 'John', params[:users][0][:name]
67
+ assert_equal 'Jane', params[:users][1][:name]
68
+ end
69
+
70
+ def test_initialization_with_deeply_nested_structure
71
+ params = StrongParameters::Core::Parameters.new(
72
+ user: {
73
+ profile: {
74
+ settings: {
75
+ notifications: {
76
+ email: true,
77
+ sms: false
78
+ }
79
+ }
80
+ }
81
+ }
82
+ )
83
+
84
+ assert params[:user].is_a?(StrongParameters::Core::Parameters)
85
+ assert params[:user][:profile].is_a?(StrongParameters::Core::Parameters)
86
+ assert params[:user][:profile][:settings].is_a?(StrongParameters::Core::Parameters)
87
+ assert params[:user][:profile][:settings][:notifications].is_a?(StrongParameters::Core::Parameters)
88
+ assert_equal true, params[:user][:profile][:settings][:notifications][:email]
89
+ assert_equal false, params[:user][:profile][:settings][:notifications][:sms]
90
+ end
91
+
92
+ def test_initialization_with_large_hash
93
+ large_hash = {}
94
+ 1000.times { |i| large_hash["key#{i}"] = "value#{i}" }
95
+
96
+ params = StrongParameters::Core::Parameters.new(large_hash)
97
+ assert_equal 1000, params.size
98
+ assert_equal 'value0', params[:key0]
99
+ assert_equal 'value999', params[:key999]
100
+ end
101
+
102
+ def test_initialization_with_mixed_key_types
103
+ params = StrongParameters::Core::Parameters.new(
104
+ 'string_key' => 'string_value',
105
+ :symbol_key => 'symbol_value',
106
+ 123 => 'numeric_key_value'
107
+ )
108
+
109
+ assert_equal 'string_value', params['string_key']
110
+ assert_equal 'symbol_value', params[:symbol_key]
111
+ assert_equal 'numeric_key_value', params['123']
112
+ end
113
+
114
+ def test_initialization_with_frozen_hash
115
+ frozen_hash = { name: 'John', age: 30 }.freeze
116
+ params = StrongParameters::Core::Parameters.new(frozen_hash)
117
+
118
+ assert_equal 'John', params[:name]
119
+ assert_equal 30, params[:age]
120
+ end
121
+
122
+ def test_initialization_with_empty_nested_hashes
123
+ params = StrongParameters::Core::Parameters.new(
124
+ user: {},
125
+ profile: { settings: {} }
126
+ )
127
+
128
+ assert params[:user].is_a?(StrongParameters::Core::Parameters)
129
+ assert params[:user].empty?
130
+ assert params[:profile][:settings].is_a?(StrongParameters::Core::Parameters)
131
+ assert params[:profile][:settings].empty?
132
+ end
133
+
134
+ # Test permitted flag
135
+ def test_permitted_starts_false
136
+ assert !@params.permitted?
137
+ end
138
+
139
+ def test_permit_bang_sets_permitted_true
140
+ @params.permit!
141
+ assert @params.permitted?
142
+ end
143
+
144
+ def test_permit_bang_returns_self
145
+ result = @params.permit!
146
+ assert_equal @params.object_id, result.object_id
147
+ end
148
+
149
+ def test_permit_bang_on_nested_parameters
150
+ @params.permit!
151
+ assert @params[:profile].permitted?
152
+ end
153
+
154
+ def test_permit_bang_on_array_of_parameters
155
+ params = StrongParameters::Core::Parameters.new(
156
+ users: [{ name: 'John' }, { name: 'Jane' }]
157
+ )
158
+ params.permit!
159
+ assert params[:users][0].permitted?
160
+ assert params[:users][1].permitted?
161
+ end
162
+
163
+ # Test require method
164
+ def test_require_returns_value_when_present
165
+ params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
166
+ result = params.require(:user)
167
+ assert_equal 'John', result[:name]
168
+ end
169
+
170
+ def test_require_raises_when_key_missing
171
+ error = assert_raises(StrongParameters::Core::ParameterMissing) do
172
+ @params.require(:nonexistent)
173
+ end
174
+ assert_equal 'nonexistent', error.param
175
+ assert_match(/param is missing or the value is empty: nonexistent/, error.message)
176
+ assert_match(/Available keys: name, email, age, admin, profile, tags, scores/, error.message)
177
+ end
178
+
179
+ def test_require_raises_with_suggestions
180
+ params = StrongParameters::Core::Parameters.new(usr: { name: 'John' }, usrname: 'test')
181
+ error = assert_raises(StrongParameters::Core::ParameterMissing) do
182
+ params.require(:user)
183
+ end
184
+ assert_match(/Did you mean\? usr, usrname/, error.message)
185
+ end
186
+
187
+ def test_parameter_missing_with_no_similar_keys
188
+ params = StrongParameters::Core::Parameters.new(xyz: 'value', abc: 'other')
189
+ error = assert_raises(StrongParameters::Core::ParameterMissing) do
190
+ params.require(:user)
191
+ end
192
+ assert_match(/param is missing or the value is empty: user/, error.message)
193
+ assert_match(/Available keys: xyz, abc/, error.message)
194
+ refute_match(/Did you mean\?/, error.message)
195
+ end
196
+
197
+ def test_parameter_missing_with_many_similar_keys
198
+ params = StrongParameters::Core::Parameters.new(
199
+ usr: 'value',
200
+ user_name: 'value',
201
+ user_email: 'value',
202
+ username: 'value',
203
+ usr_profile: 'value'
204
+ )
205
+ error = assert_raises(StrongParameters::Core::ParameterMissing) do
206
+ params.require(:user)
207
+ end
208
+ # Should limit to 3 suggestions
209
+ assert_match(/Did you mean\? usr, user_name, user_email/, error.message)
210
+ end
211
+
212
+ def test_require_raises_when_value_empty
213
+ params = StrongParameters::Core::Parameters.new(user: nil)
214
+ assert_raises(StrongParameters::Core::ParameterMissing) do
215
+ params.require(:user)
216
+ end
217
+ end
218
+
219
+ def test_require_raises_when_value_empty_string
220
+ params = StrongParameters::Core::Parameters.new(user: '')
221
+ assert_raises(StrongParameters::Core::ParameterMissing) do
222
+ params.require(:user)
223
+ end
224
+ end
225
+
226
+ def test_require_raises_when_value_empty_array
227
+ params = StrongParameters::Core::Parameters.new(user: [])
228
+ assert_raises(StrongParameters::Core::ParameterMissing) do
229
+ params.require(:user)
230
+ end
231
+ end
232
+
233
+ def test_require_returns_false_when_present
234
+ params = StrongParameters::Core::Parameters.new(active: false)
235
+ assert_equal false, params.require(:active)
236
+ end
237
+
238
+ def test_require_returns_zero_when_present
239
+ params = StrongParameters::Core::Parameters.new(count: 0)
240
+ assert_equal 0, params.require(:count)
241
+ end
242
+
243
+ def test_require_raises_when_value_empty_hash
244
+ params = StrongParameters::Core::Parameters.new(user: {})
245
+ assert_raises(StrongParameters::Core::ParameterMissing) do
246
+ params.require(:user)
247
+ end
248
+ end
249
+
250
+ def test_require_accepts_string_key
251
+ params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
252
+ result = params.require('user')
253
+ assert_equal 'John', result[:name]
254
+ end
255
+
256
+ def test_require_sets_required_key_on_result
257
+ params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
258
+ result = params.require(:user)
259
+ assert_equal :user, result.required_key
260
+ end
261
+
262
+ def test_required_alias_works
263
+ params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
264
+ result = params.required(:user)
265
+ assert_equal 'John', result[:name]
266
+ end
267
+
268
+ def test_require_with_numeric_key
269
+ params = StrongParameters::Core::Parameters.new('123' => { name: 'John' })
270
+ result = params.require(123)
271
+ assert_equal 'John', result[:name]
272
+ end
273
+
274
+ def test_require_with_false_value
275
+ params = StrongParameters::Core::Parameters.new(active: false)
276
+ result = params.require(:active)
277
+ assert_equal false, result
278
+ end
279
+
280
+ def test_require_with_zero_value
281
+ params = StrongParameters::Core::Parameters.new(count: 0)
282
+ result = params.require(:count)
283
+ assert_equal 0, result
284
+ end
285
+
286
+ def test_require_with_nested_require
287
+ params = StrongParameters::Core::Parameters.new(
288
+ company: {
289
+ employees: [
290
+ { name: 'Alice' },
291
+ { name: 'Bob' }
292
+ ]
293
+ }
294
+ )
295
+
296
+ company = params.require(:company)
297
+ employees = company.require(:employees)
298
+ assert employees.is_a?(Array)
299
+ assert_equal 'Alice', employees[0][:name]
300
+ assert_equal 'Bob', employees[1][:name]
301
+ end
302
+
303
+ def test_require_preserves_required_key_through_multiple_calls
304
+ params = StrongParameters::Core::Parameters.new(
305
+ organization: {
306
+ department: {
307
+ team: { name: 'Dev Team' }
308
+ }
309
+ }
310
+ )
311
+
312
+ org = params.require(:organization)
313
+ dept = org.require(:department)
314
+ team = dept.require(:team)
315
+
316
+ assert_equal :organization, org.required_key
317
+ assert_equal :organization, dept.required_key # Inherits from parent
318
+ assert_equal :organization, team.required_key
319
+ end
320
+
321
+ def test_require_with_array_value
322
+ params = StrongParameters::Core::Parameters.new(tags: ['ruby', 'rails'])
323
+ result = params.require(:tags)
324
+ assert_equal ['ruby', 'rails'], result
325
+ end
326
+
327
+ def test_require_with_empty_array
328
+ params = StrongParameters::Core::Parameters.new(items: [])
329
+ assert_raises(StrongParameters::Core::ParameterMissing) do
330
+ params.require(:items)
331
+ end
332
+ end
333
+
334
+ # Test permit method
335
+ def test_permit_with_single_key
336
+ permitted = @params.permit(:name)
337
+ assert_equal 'John', permitted[:name]
338
+ assert_nil permitted[:email]
339
+ assert permitted.permitted?
340
+ end
341
+
342
+ def test_permit_with_multiple_keys
343
+ permitted = @params.permit(:name, :email, :age)
344
+ assert_equal 'John', permitted[:name]
345
+ assert_equal 'john@example.com', permitted[:email]
346
+ assert_equal 30, permitted[:age]
347
+ assert_nil permitted[:admin]
348
+ assert permitted.permitted?
349
+ end
350
+
351
+ def test_permit_with_string_keys
352
+ permitted = @params.permit('name', 'email')
353
+ assert_equal 'John', permitted[:name]
354
+ assert_equal 'john@example.com', permitted[:email]
355
+ assert permitted.permitted?
356
+ end
357
+
358
+ def test_permit_returns_new_instance
359
+ permitted = @params.permit(:name)
360
+ refute_equal @params.object_id, permitted.object_id
361
+ end
362
+
363
+ def test_permit_doesnt_modify_original
364
+ permitted = @params.permit(:name)
365
+ assert !@params.permitted?
366
+ assert permitted.permitted?
367
+ end
368
+
369
+ def test_permit_with_nested_hash
370
+ permitted = @params.permit(profile: [:bio, :location])
371
+ assert_equal 'Developer', permitted[:profile][:bio]
372
+ assert_equal 'NYC', permitted[:profile][:location]
373
+ assert permitted[:profile].permitted?
374
+ end
375
+
376
+ def test_permit_with_array_of_scalars
377
+ permitted = @params.permit(tags: [])
378
+ assert_equal ['ruby', 'rails'], permitted[:tags]
379
+ assert permitted.permitted?
380
+ end
381
+
382
+ def test_permit_with_array_of_scalars_explicit
383
+ permitted = @params.permit(scores: [])
384
+ assert_equal [95, 87, 92], permitted[:scores]
385
+ assert permitted.permitted?
386
+ end
387
+
388
+ def test_permit_with_complex_nested_structure
389
+ params = StrongParameters::Core::Parameters.new(
390
+ user: {
391
+ name: 'John',
392
+ profile: {
393
+ bio: 'Developer',
394
+ skills: ['ruby', 'rails']
395
+ },
396
+ addresses: [
397
+ { city: 'NYC', zip: '10001' },
398
+ { city: 'LA', zip: '90210' }
399
+ ]
400
+ }
401
+ )
402
+
403
+ permitted = params.permit(
404
+ user: [
405
+ :name,
406
+ profile: [:bio, skills: []],
407
+ addresses: [:city, :zip]
408
+ ]
409
+ )
410
+
411
+ assert_equal 'John', permitted[:user][:name]
412
+ assert_equal 'Developer', permitted[:user][:profile][:bio]
413
+ assert_equal ['ruby', 'rails'], permitted[:user][:profile][:skills]
414
+ assert_equal 'NYC', permitted[:user][:addresses][0][:city]
415
+ assert_equal '10001', permitted[:user][:addresses][0][:zip]
416
+ assert_equal 'LA', permitted[:user][:addresses][1][:city]
417
+ assert_equal '90210', permitted[:user][:addresses][1][:zip]
418
+ end
419
+
420
+ def test_permit_with_extremely_nested_structure
421
+ params = StrongParameters::Core::Parameters.new(
422
+ organization: {
423
+ departments: [
424
+ {
425
+ name: 'Engineering',
426
+ teams: [
427
+ {
428
+ name: 'Backend',
429
+ members: [
430
+ { name: 'Alice', role: 'senior' },
431
+ { name: 'Bob', role: 'junior' }
432
+ ]
433
+ },
434
+ {
435
+ name: 'Frontend',
436
+ members: [
437
+ { name: 'Charlie', role: 'lead' }
438
+ ]
439
+ }
440
+ ]
441
+ },
442
+ {
443
+ name: 'Sales',
444
+ teams: []
445
+ }
446
+ ]
447
+ }
448
+ )
449
+
450
+ permitted = params.permit(
451
+ organization: {
452
+ departments: [
453
+ :name,
454
+ teams: [
455
+ :name,
456
+ members: [:name, :role]
457
+ ]
458
+ ]
459
+ }
460
+ )
461
+
462
+ assert_equal 'Engineering', permitted[:organization][:departments][0][:name]
463
+ assert_equal 'Backend', permitted[:organization][:departments][0][:teams][0][:name]
464
+ assert_equal 'Alice', permitted[:organization][:departments][0][:teams][0][:members][0][:name]
465
+ assert_equal 'senior', permitted[:organization][:departments][0][:teams][0][:members][0][:role]
466
+ assert_equal 'Sales', permitted[:organization][:departments][1][:name]
467
+ assert_equal [], permitted[:organization][:departments][1][:teams]
468
+ end
469
+
470
+ def test_permit_with_mixed_array_and_hash_filters
471
+ params = StrongParameters::Core::Parameters.new(
472
+ posts: [
473
+ { title: 'Post 1', tags: ['ruby', 'rails'], metadata: { published: true } },
474
+ { title: 'Post 2', tags: ['js'], metadata: { published: false } }
475
+ ],
476
+ categories: ['tech', 'news']
477
+ )
478
+
479
+ permitted = params.permit(
480
+ posts: [:title, tags: [], metadata: [:published]],
481
+ categories: []
482
+ )
483
+
484
+ assert_equal 'Post 1', permitted[:posts][0][:title]
485
+ assert_equal ['ruby', 'rails'], permitted[:posts][0][:tags]
486
+ assert_equal true, permitted[:posts][0][:metadata][:published]
487
+ assert_equal 'Post 2', permitted[:posts][1][:title]
488
+ assert_equal ['js'], permitted[:posts][1][:tags]
489
+ assert_equal false, permitted[:posts][1][:metadata][:published]
490
+ assert_equal ['tech', 'news'], permitted[:categories]
491
+ end
492
+
493
+ def test_permit_with_fields_for_style_arrays
494
+ params = StrongParameters::Core::Parameters.new(
495
+ '0' => { name: 'John', age: '30', secret: 'hidden' },
496
+ '1' => { name: 'Jane', age: '25', secret: 'also_hidden' },
497
+ '2' => { name: 'Bob', age: '35' }
498
+ )
499
+
500
+ permitted = params.permit(
501
+ '0' => [:name, :age],
502
+ '1' => [:name, :age],
503
+ '2' => [:name, :age]
504
+ )
505
+
506
+ assert_equal 'John', permitted['0'][:name]
507
+ assert_equal '30', permitted['0'][:age]
508
+ assert_nil permitted['0'][:secret]
509
+ assert_equal 'Jane', permitted['1'][:name]
510
+ assert_equal '25', permitted['1'][:age]
511
+ assert_nil permitted['1'][:secret]
512
+ assert_equal 'Bob', permitted['2'][:name]
513
+ assert_equal '35', permitted['2'][:age]
514
+ end
515
+
516
+ def test_permit_with_negative_indexed_fields_for
517
+ params = StrongParameters::Core::Parameters.new(
518
+ '-1' => { name: 'John' },
519
+ '0' => { name: 'Jane' }
520
+ )
521
+
522
+ permitted = params.permit(
523
+ '-1' => [:name],
524
+ '0' => [:name]
525
+ )
526
+
527
+ assert_equal 'John', permitted['-1'][:name]
528
+ assert_equal 'Jane', permitted['0'][:name]
529
+ end
530
+
531
+ def test_permit_with_nil_values
532
+ params = StrongParameters::Core::Parameters.new(name: 'John', age: nil, active: false)
533
+ permitted = params.permit(:name, :age, :active)
534
+ assert_equal 'John', permitted[:name]
535
+ assert_nil permitted[:age]
536
+ assert_equal false, permitted[:active]
537
+ end
538
+
539
+ def test_permit_with_empty_arrays
540
+ params = StrongParameters::Core::Parameters.new(tags: [], scores: [1, 2, 3])
541
+ permitted = params.permit(tags: [], scores: [])
542
+ assert_equal [], permitted[:tags]
543
+ assert_equal [1, 2, 3], permitted[:scores]
544
+ end
545
+
546
+ def test_permit_with_mixed_array_types
547
+ params = StrongParameters::Core::Parameters.new(items: ['string', 42, true, nil])
548
+ permitted = params.permit(items: [])
549
+ assert_equal ['string', 42, true, nil], permitted[:items]
550
+ end
551
+
552
+ def test_permit_with_invalid_array_elements
553
+ params = StrongParameters::Core::Parameters.new(items: ['valid', {}])
554
+ permitted = params.permit(items: [])
555
+ # Should not permit array with invalid elements
556
+ assert_nil permitted[:items]
557
+ end
558
+
559
+ def test_permit_with_deeply_nested_empty_hashes
560
+ params = StrongParameters::Core::Parameters.new(user: { profile: {} })
561
+ permitted = params.permit(user: { profile: {} })
562
+ assert_equal({}, permitted[:user][:profile].to_h)
563
+ end
564
+
565
+ def test_permit_with_duplicate_keys_in_filters
566
+ params = StrongParameters::Core::Parameters.new(name: 'John', age: 30)
567
+ permitted = params.permit(:name, :name, :age)
568
+ assert_equal 'John', permitted[:name]
569
+ assert_equal 30, permitted[:age]
570
+ end
571
+
572
+ def test_permit_with_mixed_filters_and_unpermitted_keys
573
+ StrongParameters::Core::Parameters.action_on_unpermitted_parameters = :raise
574
+
575
+ params = StrongParameters::Core::Parameters.new(
576
+ user: {
577
+ name: 'John',
578
+ email: 'john@example.com',
579
+ admin: true,
580
+ profile: {
581
+ bio: 'Developer',
582
+ secret: 'hidden'
583
+ }
584
+ },
585
+ extra: 'value'
586
+ )
587
+
588
+ assert_raises(StrongParameters::Core::UnpermittedParameters) do
589
+ params.permit(
590
+ user: [:name, :email, profile: [:bio]], # admin and secret not permitted
591
+ extra: [] # extra not permitted
592
+ )
593
+ end
594
+ end
595
+
596
+ def test_permit_with_fields_for_style_and_multi_param
597
+ params = StrongParameters::Core::Parameters.new(
598
+ 'posts' => {
599
+ '0' => { title: 'First Post', content: 'Content 1' },
600
+ '1' => { title: 'Second Post', content: 'Content 2' }
601
+ },
602
+ 'event_date(1i)' => '2023',
603
+ 'event_date(2i)' => '12',
604
+ 'event_date(3i)' => '25'
605
+ )
606
+
607
+ permitted = params.permit(
608
+ {posts: [:title, :content]},
609
+ :event_date
610
+ )
611
+
612
+ assert_equal 'First Post', permitted[:posts]['0'][:title]
613
+ assert_equal 'Content 2', permitted[:posts]['1'][:content]
614
+ assert_equal '2023', permitted['event_date(1i)']
615
+ assert_equal '12', permitted['event_date(2i)']
616
+ assert_equal '25', permitted['event_date(3i)']
617
+ end
618
+
619
+ # Test transform_params method
620
+ def test_transform_params_with_inference
621
+ # Mock the ParamsRegistry
622
+ StrongParameters::Core::ParamsRegistry.register(:user, Class.new(StrongParameters::Core::ApplicationParams) do
623
+ def self.permitted_attributes(action: nil)
624
+ [:name, :email]
625
+ end
626
+ end)
627
+
628
+ params = StrongParameters::Core::Parameters.new(user: { name: 'John', email: 'john@example.com', admin: true })
629
+ user_params = params.require(:user)
630
+ permitted = user_params.transform_params
631
+
632
+ assert_equal 'John', permitted[:name]
633
+ assert_equal 'john@example.com', permitted[:email]
634
+ assert_nil permitted[:admin]
635
+ assert permitted.permitted?
636
+ end
637
+
638
+ def test_transform_params_with_explicit_class
639
+ user_params_class = Class.new(StrongParameters::Core::ApplicationParams) do
640
+ def self.permitted_attributes(action: nil)
641
+ [:name, :age]
642
+ end
643
+ end
644
+
645
+ params = StrongParameters::Core::Parameters.new(user: { name: 'John', age: 30, admin: true })
646
+ user_params = params.require(:user)
647
+ permitted = user_params.transform_params(user_params_class)
648
+
649
+ assert_equal 'John', permitted[:name]
650
+ assert_equal 30, permitted[:age]
651
+ assert_nil permitted[:admin]
652
+ end
653
+
654
+ def test_transform_params_with_action
655
+ user_params_class = Class.new(StrongParameters::Core::ApplicationParams) do
656
+ def self.permitted_attributes(action: nil)
657
+ case action
658
+ when :create
659
+ [:name, :email]
660
+ when :update
661
+ [:name, :age]
662
+ else
663
+ []
664
+ end
665
+ end
666
+ end
667
+
668
+ params = StrongParameters::Core::Parameters.new(user: { name: 'John', email: 'john@example.com', age: 30 })
669
+ user_params = params.require(:user)
670
+
671
+ create_permitted = user_params.transform_params(user_params_class, action: :create)
672
+ assert_equal 'John', create_permitted[:name]
673
+ assert_equal 'john@example.com', create_permitted[:email]
674
+ assert_nil create_permitted[:age]
675
+
676
+ update_permitted = user_params.transform_params(user_params_class, action: :update)
677
+ assert_equal 'John', update_permitted[:name]
678
+ assert_equal 30, update_permitted[:age]
679
+ assert_nil update_permitted[:email]
680
+ end
681
+
682
+ def test_transform_params_with_additional_attrs
683
+ user_params_class = Class.new(StrongParameters::Core::ApplicationParams) do
684
+ def self.permitted_attributes(action: nil)
685
+ [:name]
686
+ end
687
+ end
688
+
689
+ params = StrongParameters::Core::Parameters.new(user: { name: 'John', token: 'abc123', admin: true })
690
+ user_params = params.require(:user)
691
+ permitted = user_params.transform_params(user_params_class, additional_attrs: [:token])
692
+
693
+ assert_equal 'John', permitted[:name]
694
+ assert_equal 'abc123', permitted[:token]
695
+ assert_nil permitted[:admin]
696
+ end
697
+
698
+ def test_transform_params_with_metadata
699
+ user_params_class = Class.new(StrongParameters::Core::ApplicationParams) do
700
+ allow :name
701
+ allow :admin_override
702
+ metadata :current_user
703
+
704
+ def self.apply_transformations(params, options)
705
+ current_user = options[:current_user]
706
+ if current_user&.admin?
707
+ params.merge('admin_override' => true)
708
+ else
709
+ params
710
+ end
711
+ end
712
+ end
713
+
714
+ params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
715
+ user_params = params.require(:user)
716
+
717
+ # Mock current_user
718
+ current_user = Object.new
719
+ def current_user.admin?; true; end
720
+
721
+ permitted = user_params.transform_params(user_params_class, current_user: current_user)
722
+ assert_equal 'John', permitted[:name]
723
+ assert_equal true, permitted[:admin_override]
724
+ end
725
+
726
+ def test_transform_params_with_invalid_metadata
727
+ user_params_class = Class.new(StrongParameters::Core::ApplicationParams) do
728
+ def self.metadata_allowed?(key)
729
+ false
730
+ end
731
+ end
732
+
733
+ params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
734
+ user_params = params.require(:user)
735
+
736
+ assert_raises(ArgumentError) do
737
+ user_params.transform_params(user_params_class, invalid_key: 'value')
738
+ end
739
+ end
740
+
741
+ def test_transform_params_with_nil_class
742
+ params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
743
+ user_params = params.require(:user)
744
+ permitted = user_params.transform_params(nil)
745
+
746
+ assert_equal({}, permitted.to_h)
747
+ assert permitted.permitted?
748
+ end
749
+
750
+ def test_transform_params_without_required_key
751
+ params = StrongParameters::Core::Parameters.new(name: 'John')
752
+ permitted = params.transform_params
753
+
754
+ assert_equal({}, permitted.to_h)
755
+ assert permitted.permitted?
756
+ end
757
+
758
+ def test_transform_params_with_unregistered_params_class
759
+ # Ensure no registration for :user
760
+ StrongParameters::Core::ParamsRegistry.clear!
761
+
762
+ params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
763
+ user_params = params.require(:user)
764
+ permitted = user_params.transform_params
765
+
766
+ assert_equal({}, permitted.to_h)
767
+ assert permitted.permitted?
768
+ end
769
+
770
+ def test_transform_params_with_nil_params_class
771
+ params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
772
+ user_params = params.require(:user)
773
+ permitted = user_params.transform_params(nil)
774
+
775
+ assert_equal({}, permitted.to_h)
776
+ assert permitted.permitted?
777
+ end
778
+
779
+ # Test hash access methods
780
+ def test_bracket_accessor_with_symbol
781
+ assert_equal 'John', @params[:name]
782
+ end
783
+
784
+ def test_bracket_accessor_with_string
785
+ assert_equal 'John', @params['name']
786
+ end
787
+
788
+ def test_bracket_accessor_returns_nil_for_missing_key
789
+ assert_nil @params[:nonexistent]
790
+ end
791
+
792
+ def test_bracket_accessor_converts_hash_to_parameters
793
+ profile = @params[:profile]
794
+ assert profile.is_a?(StrongParameters::Core::Parameters)
795
+ assert_equal 'Developer', profile[:bio]
796
+ end
797
+
798
+ def test_bracket_equals_sets_value
799
+ @params[:new_key] = 'new_value'
800
+ assert_equal 'new_value', @params[:new_key]
801
+ end
802
+
803
+ def test_bracket_equals_normalizes_key
804
+ @params['new_key'] = 'new_value'
805
+ assert_equal 'new_value', @params[:new_key]
806
+ end
807
+
808
+ def test_fetch_returns_value_when_present
809
+ assert_equal 'John', @params.fetch(:name)
810
+ end
811
+
812
+ def test_fetch_raises_when_key_missing
813
+ assert_raises(StrongParameters::Core::ParameterMissing) do
814
+ @params.fetch(:nonexistent)
815
+ end
816
+ end
817
+
818
+ def test_fetch_with_default_value
819
+ result = @params.fetch(:nonexistent, 'default')
820
+ assert_equal 'default', result
821
+ end
822
+
823
+ def test_fetch_with_block
824
+ result = @params.fetch(:nonexistent) { 'from block' }
825
+ assert_equal 'from block', result
826
+ end
827
+
828
+ def test_fetch_converts_hash_to_parameters
829
+ profile = @params.fetch(:profile)
830
+ assert profile.is_a?(StrongParameters::Core::Parameters)
831
+ end
832
+
833
+ def test_has_key_with_symbol
834
+ assert @params.has_key?(:name)
835
+ end
836
+
837
+ def test_has_key_with_string
838
+ assert @params.has_key?('name')
839
+ end
840
+
841
+ def test_has_key_returns_false_for_missing
842
+ assert !@params.has_key?(:nonexistent)
843
+ end
844
+
845
+ def test_key_alias_works
846
+ assert @params.key?(:name)
847
+ end
848
+
849
+ def test_include_alias_works
850
+ assert @params.include?(:name)
851
+ end
852
+
853
+ def test_delete_removes_key
854
+ @params.delete(:name)
855
+ assert_nil @params[:name]
856
+ end
857
+
858
+ def test_delete_returns_value
859
+ result = @params.delete(:name)
860
+ assert_equal 'John', result
861
+ end
862
+
863
+ def test_delete_normalizes_key
864
+ result = @params.delete('name')
865
+ assert_equal 'John', result
866
+ end
867
+
868
+ def test_bracket_accessor_with_numeric_key
869
+ params = StrongParameters::Core::Parameters.new('123' => 'numeric')
870
+ assert_equal 'numeric', params[123]
871
+ assert_equal 'numeric', params['123']
872
+ end
873
+
874
+ def test_bracket_accessor_with_nil_key
875
+ params = StrongParameters::Core::Parameters.new(nil => 'nil_value')
876
+ assert_equal 'nil_value', params[nil]
877
+ assert_equal 'nil_value', params['']
878
+ end
879
+
880
+ def test_bracket_accessor_with_boolean_key
881
+ params = StrongParameters::Core::Parameters.new(true => 'true_value', false => 'false_value')
882
+ assert_equal 'true_value', params[true]
883
+ assert_equal 'false_value', params[false]
884
+ end
885
+
886
+ def test_bracket_equals_with_numeric_key
887
+ params = StrongParameters::Core::Parameters.new
888
+ params[123] = 'numeric_value'
889
+ assert_equal 'numeric_value', params['123']
890
+ assert_equal 'numeric_value', params[123]
891
+ end
892
+
893
+ def test_bracket_equals_with_nil_key
894
+ params = StrongParameters::Core::Parameters.new
895
+ params[nil] = 'nil_value'
896
+ assert_equal 'nil_value', params['']
897
+ end
898
+
899
+ def test_fetch_with_numeric_key
900
+ params = StrongParameters::Core::Parameters.new('42' => 'answer')
901
+ assert_equal 'answer', params.fetch(42)
902
+ end
903
+
904
+ def test_fetch_with_default_proc
905
+ params = StrongParameters::Core::Parameters.new
906
+ result = params.fetch(:missing) { |key| "default_for_#{key}" }
907
+ assert_equal 'default_for_missing', result
908
+ end
909
+
910
+ def test_has_key_with_numeric_key
911
+ params = StrongParameters::Core::Parameters.new('42' => 'answer')
912
+ assert params.has_key?(42)
913
+ assert params.has_key?('42')
914
+ end
915
+
916
+ def test_has_key_with_nil_key
917
+ params = StrongParameters::Core::Parameters.new(nil => 'value')
918
+ assert params.has_key?(nil)
919
+ assert params.has_key?('')
920
+ end
921
+
922
+ def test_delete_with_numeric_key
923
+ params = StrongParameters::Core::Parameters.new('42' => 'answer')
924
+ result = params.delete(42)
925
+ assert_equal 'answer', result
926
+ assert_nil params['42']
927
+ end
928
+
929
+ def test_delete_with_block
930
+ params = StrongParameters::Core::Parameters.new(name: 'John')
931
+ result = params.delete(:missing) { 'not found' }
932
+ assert_equal 'not found', result
933
+ end
934
+
935
+ def test_bracket_accessor_converts_nested_arrays
936
+ params = StrongParameters::Core::Parameters.new(
937
+ items: [
938
+ { name: 'item1' },
939
+ { name: 'item2' }
940
+ ]
941
+ )
942
+
943
+ items = params[:items]
944
+ assert items.is_a?(Array)
945
+ assert items[0].is_a?(StrongParameters::Core::Parameters)
946
+ assert_equal 'item1', items[0][:name]
947
+ end
948
+
949
+ def test_fetch_converts_nested_arrays
950
+ params = StrongParameters::Core::Parameters.new(
951
+ items: [
952
+ { name: 'item1' }
953
+ ]
954
+ )
955
+
956
+ items = params.fetch(:items)
957
+ assert items.is_a?(Array)
958
+ assert items[0].is_a?(StrongParameters::Core::Parameters)
959
+ end
960
+
961
+ def test_slice_returns_subset
962
+ sliced = @params.slice(:name, :email)
963
+ assert_equal 'John', sliced[:name]
964
+ assert_equal 'john@example.com', sliced[:email]
965
+ assert_nil sliced[:age]
966
+ end
967
+
968
+ def test_slice_preserves_permitted_flag
969
+ @params.permit!
970
+ sliced = @params.slice(:name)
971
+ assert sliced.permitted?
972
+ end
973
+
974
+ def test_slice_preserves_required_key
975
+ params = StrongParameters::Core::Parameters.new(user: { name: 'John', email: 'john@example.com' })
976
+ user_params = params.require(:user)
977
+ sliced = user_params.slice(:name)
978
+ assert_equal :user, sliced.required_key
979
+ end
980
+
981
+ def test_slice_returns_new_instance
982
+ sliced = @params.slice(:name)
983
+ refute_equal @params.object_id, sliced.object_id
984
+ end
985
+
986
+ def test_except_excludes_keys
987
+ excepted = @params.except(:name, :email)
988
+ assert_nil excepted[:name]
989
+ assert_nil excepted[:email]
990
+ assert_equal 30, excepted[:age]
991
+ end
992
+
993
+ def test_except_returns_new_instance
994
+ excepted = @params.except(:name)
995
+ refute_equal @params.object_id, excepted.object_id
996
+ end
997
+
998
+ def test_dup_creates_new_instance
999
+ duped = @params.dup
1000
+ refute_equal @params.object_id, duped.object_id
1001
+ end
1002
+
1003
+ def test_dup_preserves_data
1004
+ duped = @params.dup
1005
+ assert_equal 'John', duped[:name]
1006
+ assert_equal 'john@example.com', duped[:email]
1007
+ assert_equal 30, duped[:age]
1008
+ end
1009
+
1010
+ def test_dup_preserves_permitted_flag
1011
+ @params.permit!
1012
+ duped = @params.dup
1013
+ assert duped.permitted?
1014
+ end
1015
+
1016
+ def test_dup_preserves_required_key
1017
+ params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
1018
+ user_params = params.require(:user)
1019
+ duped = user_params.dup
1020
+ assert_equal :user, duped.required_key
1021
+ end
1022
+
1023
+ def test_dup_creates_shallow_copy
1024
+ duped = @params.dup
1025
+ duped[:new_key] = 'new_value'
1026
+ assert_nil @params[:new_key]
1027
+ end
1028
+
1029
+ def test_dup_with_nested_parameters
1030
+ duped = @params.dup
1031
+ duped[:profile][:new_field] = 'new_value'
1032
+ assert_nil @params[:profile][:new_field]
1033
+ end
1034
+
1035
+ def test_slice_with_nonexistent_keys
1036
+ sliced = @params.slice(:name, :nonexistent)
1037
+ assert_equal 'John', sliced[:name]
1038
+ assert_nil sliced[:nonexistent]
1039
+ end
1040
+
1041
+ def test_slice_with_empty_keys
1042
+ sliced = @params.slice
1043
+ assert_equal({}, sliced.to_h)
1044
+ assert !sliced.permitted?
1045
+ end
1046
+
1047
+ def test_slice_with_mixed_key_types
1048
+ params = StrongParameters::Core::Parameters.new('name' => 'John', :age => 30, 'email' => 'test@example.com')
1049
+ sliced = params.slice('name', :age)
1050
+ assert_equal 'John', sliced[:name]
1051
+ assert_equal 30, sliced[:age]
1052
+ assert_nil sliced[:email]
1053
+ end
1054
+
1055
+ def test_except_with_no_keys
1056
+ excepted = @params.except
1057
+ assert_equal @params.to_h, excepted.to_h
1058
+ end
1059
+
1060
+ def test_except_with_all_keys
1061
+ excepted = @params.except(*@params.keys)
1062
+ assert_equal({}, excepted.to_h)
1063
+ end
1064
+
1065
+ def test_except_preserves_permitted_flag
1066
+ @params.permit!
1067
+ excepted = @params.except(:name)
1068
+ assert excepted.permitted?
1069
+ end
1070
+
1071
+ def test_slice_with_nested_parameters
1072
+ params = StrongParameters::Core::Parameters.new(
1073
+ user: { name: 'John', email: 'john@example.com', profile: { bio: 'Developer' } },
1074
+ admin: true
1075
+ )
1076
+
1077
+ sliced = params.slice(:user)
1078
+ assert_equal 'John', sliced[:user][:name]
1079
+ assert_equal 'john@example.com', sliced[:user][:email]
1080
+ assert_equal 'Developer', sliced[:user][:profile][:bio]
1081
+ assert_nil sliced[:admin]
1082
+ end
1083
+
1084
+ def test_except_with_nested_parameters
1085
+ params = StrongParameters::Core::Parameters.new(
1086
+ user: { name: 'John', email: 'john@example.com', profile: { bio: 'Developer' } },
1087
+ admin: true
1088
+ )
1089
+
1090
+ excepted = params.except(:admin)
1091
+ assert_equal 'John', excepted[:user][:name]
1092
+ assert_equal 'john@example.com', excepted[:user][:email]
1093
+ assert_equal 'Developer', excepted[:user][:profile][:bio]
1094
+ assert_nil excepted[:admin]
1095
+ end
1096
+
1097
+ def test_slice_with_array_of_parameters
1098
+ params = StrongParameters::Core::Parameters.new(
1099
+ users: [
1100
+ { name: 'John', age: 30 },
1101
+ { name: 'Jane', age: 25 }
1102
+ ],
1103
+ total: 2
1104
+ )
1105
+
1106
+ sliced = params.slice(:users)
1107
+ assert_equal 'John', sliced[:users][0][:name]
1108
+ assert_equal 30, sliced[:users][0][:age]
1109
+ assert_equal 'Jane', sliced[:users][1][:name]
1110
+ assert_equal 25, sliced[:users][1][:age]
1111
+ assert_nil sliced[:total]
1112
+ end
1113
+
1114
+ def test_except_with_array_of_parameters
1115
+ params = StrongParameters::Core::Parameters.new(
1116
+ users: [
1117
+ { name: 'John', age: 30 },
1118
+ { name: 'Jane', age: 25 }
1119
+ ],
1120
+ total: 2
1121
+ )
1122
+
1123
+ excepted = params.except(:total)
1124
+ assert_equal 'John', excepted[:users][0][:name]
1125
+ assert_equal 30, excepted[:users][0][:age]
1126
+ assert_equal 'Jane', excepted[:users][1][:name]
1127
+ assert_equal 25, excepted[:users][1][:age]
1128
+ assert_nil excepted[:total]
1129
+ end
1130
+
1131
+ def test_slice_preserves_required_key_on_nested
1132
+ params = StrongParameters::Core::Parameters.new(
1133
+ company: {
1134
+ employees: [
1135
+ { name: 'Alice' },
1136
+ { name: 'Bob' }
1137
+ ]
1138
+ }
1139
+ )
1140
+
1141
+ company = params.require(:company)
1142
+ sliced = company.slice(:employees)
1143
+ assert_equal :company, sliced.required_key
1144
+ end
1145
+
1146
+ def test_except_preserves_required_key
1147
+ params = StrongParameters::Core::Parameters.new(user: { name: 'John', email: 'john@example.com', admin: true })
1148
+ user_params = params.require(:user)
1149
+ excepted = user_params.except(:admin)
1150
+ assert_equal :user, excepted.required_key
1151
+ end
1152
+
1153
+ def test_slice_with_duplicate_keys
1154
+ params = StrongParameters::Core::Parameters.new(name: 'John', age: 30, name_dup: 'Jane')
1155
+ sliced = params.slice(:name, :name_dup)
1156
+ assert_equal 'John', sliced[:name]
1157
+ assert_equal 'Jane', sliced[:name_dup]
1158
+ end
1159
+
1160
+ def test_except_with_duplicate_keys
1161
+ params = StrongParameters::Core::Parameters.new(name: 'John', age: 30, name_dup: 'Jane')
1162
+ excepted = params.except(:age)
1163
+ assert_equal 'John', excepted[:name]
1164
+ assert_equal 'Jane', excepted[:name_dup]
1165
+ end
1166
+
1167
+ def test_dup_with_empty_params
1168
+ params = StrongParameters::Core::Parameters.new
1169
+ duped = params.dup
1170
+ assert_equal({}, duped.to_h)
1171
+ assert !duped.permitted?
1172
+ end
1173
+
1174
+ def test_dup_independence_after_modification
1175
+ duped = @params.dup
1176
+ duped[:new_key] = 'new_value'
1177
+ duped.delete(:name)
1178
+ assert_nil @params[:new_key]
1179
+ assert_equal 'John', @params[:name]
1180
+ end
1181
+
1182
+ # Test conversion methods
1183
+ def test_to_h_returns_hash
1184
+ hash = @params.to_h
1185
+ assert hash.is_a?(Hash)
1186
+ end
1187
+
1188
+ def test_to_h_with_permitted_params
1189
+ permitted = @params.permit(:name, :email)
1190
+ hash = permitted.to_h
1191
+ assert_equal 'John', hash['name']
1192
+ assert_equal 'john@example.com', hash['email']
1193
+ end
1194
+
1195
+ def test_to_h_converts_nested_parameters
1196
+ hash = @params.to_h
1197
+ assert hash['profile'].is_a?(Hash)
1198
+ assert_equal 'Developer', hash['profile']['bio']
1199
+ end
1200
+
1201
+ def test_to_unsafe_h_alias
1202
+ assert_equal @params.to_h, @params.to_unsafe_h
1203
+ end
1204
+
1205
+ def test_to_hash_alias
1206
+ assert_equal @params.to_h, @params.to_hash
1207
+ end
1208
+
1209
+ def test_to_h_with_deeply_nested_parameters
1210
+ params = StrongParameters::Core::Parameters.new(
1211
+ user: {
1212
+ profile: {
1213
+ settings: {
1214
+ theme: 'dark',
1215
+ notifications: {
1216
+ email: true,
1217
+ sms: false
1218
+ }
1219
+ }
1220
+ }
1221
+ }
1222
+ )
1223
+ hash = params.to_h
1224
+ assert hash.is_a?(Hash)
1225
+ assert_equal 'dark', hash['user']['profile']['settings']['theme']
1226
+ assert_equal true, hash['user']['profile']['settings']['notifications']['email']
1227
+ end
1228
+
1229
+ def test_to_h_with_arrays_of_parameters
1230
+ params = StrongParameters::Core::Parameters.new(
1231
+ users: [
1232
+ { name: 'John', age: 30 },
1233
+ { name: 'Jane', age: 25 }
1234
+ ]
1235
+ )
1236
+ hash = params.to_h
1237
+ assert hash['users'].is_a?(Array)
1238
+ assert hash['users'][0].is_a?(Hash)
1239
+ assert_equal 'John', hash['users'][0]['name']
1240
+ assert_equal 25, hash['users'][1]['age']
1241
+ end
1242
+
1243
+ def test_to_h_with_mixed_types
1244
+ params = StrongParameters::Core::Parameters.new(
1245
+ name: 'John',
1246
+ age: 30,
1247
+ active: true,
1248
+ score: 95.5,
1249
+ tags: ['ruby', 'rails'],
1250
+ metadata: { created_at: Time.now }
1251
+ )
1252
+ hash = params.to_h
1253
+ assert_equal 'John', hash['name']
1254
+ assert_equal 30, hash['age']
1255
+ assert_equal true, hash['active']
1256
+ assert_equal 95.5, hash['score']
1257
+ assert_equal ['ruby', 'rails'], hash['tags']
1258
+ assert hash['metadata'].is_a?(Hash)
1259
+ end
1260
+
1261
+ def test_to_h_with_file_objects
1262
+ file = StringIO.new('content')
1263
+ params = StrongParameters::Core::Parameters.new(
1264
+ name: 'John',
1265
+ avatar: file
1266
+ )
1267
+ hash = params.to_h
1268
+ assert_equal 'John', hash['name']
1269
+ assert_equal file, hash['avatar']
1270
+ end
1271
+
1272
+ def test_to_h_with_big_decimal
1273
+ bd = BigDecimal('1.23')
1274
+ params = StrongParameters::Core::Parameters.new(price: bd)
1275
+ hash = params.to_h
1276
+ assert_equal bd, hash['price']
1277
+ end
1278
+
1279
+ def test_to_h_with_date_objects
1280
+ date = Date.today
1281
+ time = Time.now
1282
+ datetime = DateTime.now
1283
+
1284
+ params = StrongParameters::Core::Parameters.new(
1285
+ birth_date: date,
1286
+ created_at: time,
1287
+ updated_at: datetime
1288
+ )
1289
+
1290
+ hash = params.to_h
1291
+ assert_equal date, hash['birth_date']
1292
+ assert_equal time, hash['created_at']
1293
+ assert_equal datetime, hash['updated_at']
1294
+ end
1295
+
1296
+ def test_to_h_with_permitted_nested_parameters
1297
+ params = StrongParameters::Core::Parameters.new(
1298
+ user: { name: 'John', email: 'john@example.com', admin: true }
1299
+ )
1300
+
1301
+ permitted = params.permit(user: [:name, :email])
1302
+ hash = permitted.to_h
1303
+
1304
+ assert hash['user'].is_a?(Hash)
1305
+ assert_equal 'John', hash['user']['name']
1306
+ assert_equal 'john@example.com', hash['user']['email']
1307
+ assert_nil hash['user']['admin']
1308
+ end
1309
+
1310
+ def test_to_h_with_complex_mixed_structure
1311
+ params = StrongParameters::Core::Parameters.new(
1312
+ company: {
1313
+ name: 'ACME Corp',
1314
+ founded: Date.new(2000, 1, 1),
1315
+ employees: [
1316
+ { name: 'Alice', salary: BigDecimal('50000.00'), active: true },
1317
+ { name: 'Bob', salary: BigDecimal('60000.00'), active: false }
1318
+ ],
1319
+ metadata: {
1320
+ industry: 'Tech',
1321
+ locations: ['NYC', 'LA', 'London']
1322
+ }
1323
+ },
1324
+ report_generated_at: Time.now
1325
+ )
1326
+
1327
+ hash = params.to_h
1328
+
1329
+ assert_equal 'ACME Corp', hash['company']['name']
1330
+ assert hash['company']['founded'].is_a?(Date)
1331
+ assert hash['company']['employees'].is_a?(Array)
1332
+ assert hash['company']['employees'][0].is_a?(Hash)
1333
+ assert_equal 'Alice', hash['company']['employees'][0]['name']
1334
+ assert hash['company']['employees'][0]['salary'].is_a?(BigDecimal)
1335
+ assert_equal true, hash['company']['employees'][0]['active']
1336
+ assert_equal 'Tech', hash['company']['metadata']['industry']
1337
+ assert_equal ['NYC', 'LA', 'London'], hash['company']['metadata']['locations']
1338
+ assert hash['report_generated_at'].is_a?(Time)
1339
+ end
1340
+
1341
+ def test_to_h_preserves_array_structure
1342
+ params = StrongParameters::Core::Parameters.new(
1343
+ matrix: [
1344
+ [1, 2, 3],
1345
+ [4, 5, 6],
1346
+ [7, 8, 9]
1347
+ ]
1348
+ )
1349
+
1350
+ hash = params.to_h
1351
+ assert_equal [[1, 2, 3], [4, 5, 6], [7, 8, 9]], hash['matrix']
1352
+ end
1353
+
1354
+ def test_to_h_with_empty_parameters
1355
+ params = StrongParameters::Core::Parameters.new
1356
+ hash = params.to_h
1357
+ assert_equal({}, hash)
1358
+ end
1359
+
1360
+ def test_to_unsafe_h_with_permitted_params
1361
+ permitted = @params.permit(:name, :email)
1362
+ assert_equal permitted.to_h, permitted.to_unsafe_h
1363
+ end
1364
+
1365
+ def test_to_h_preserves_key_types
1366
+ params = StrongParameters::Core::Parameters.new('name' => 'John', :age => 30)
1367
+ hash = params.to_h
1368
+ assert_equal 'John', hash['name']
1369
+ assert_equal 30, hash['age']
1370
+ end
1371
+
1372
+ # Test filtering logic
1373
+ def test_permitted_scalar_with_string
1374
+ assert @params.send(:permitted_scalar?, 'test')
1375
+ end
1376
+
1377
+ def test_permitted_scalar_with_symbol
1378
+ assert @params.send(:permitted_scalar?, :test)
1379
+ end
1380
+
1381
+ def test_permitted_scalar_with_nil
1382
+ assert @params.send(:permitted_scalar?, nil)
1383
+ end
1384
+
1385
+ def test_permitted_scalar_with_numeric
1386
+ assert @params.send(:permitted_scalar?, 42)
1387
+ assert @params.send(:permitted_scalar?, 3.14)
1388
+ assert @params.send(:permitted_scalar?, BigDecimal('1.0'))
1389
+ end
1390
+
1391
+ def test_permitted_scalar_with_boolean
1392
+ assert @params.send(:permitted_scalar?, true)
1393
+ assert @params.send(:permitted_scalar?, false)
1394
+ end
1395
+
1396
+ def test_permitted_scalar_with_date_time
1397
+ assert @params.send(:permitted_scalar?, Date.today)
1398
+ assert @params.send(:permitted_scalar?, Time.now)
1399
+ assert @params.send(:permitted_scalar?, DateTime.now)
1400
+ end
1401
+
1402
+ def test_permitted_scalar_with_file
1403
+ file = StringIO.new('content')
1404
+ assert @params.send(:permitted_scalar?, file)
1405
+ assert @params.send(:permitted_scalar?, File.open('/dev/null'))
1406
+ end
1407
+
1408
+ def test_permitted_scalar_with_non_permitted
1409
+ assert !@params.send(:permitted_scalar?, [])
1410
+ assert !@params.send(:permitted_scalar?, {})
1411
+ assert !@params.send(:permitted_scalar?, Object.new)
1412
+ end
1413
+
1414
+ def test_array_of_permitted_scalars_with_valid_array
1415
+ assert @params.send(:array_of_permitted_scalars?, ['a', 'b', 1, 2])
1416
+ end
1417
+
1418
+ def test_array_of_permitted_scalars_with_invalid_array
1419
+ assert !@params.send(:array_of_permitted_scalars?, ['a', {}])
1420
+ end
1421
+
1422
+ def test_array_of_permitted_scalars_with_non_array
1423
+ assert_nil @params.send(:array_of_permitted_scalars?, 'not array')
1424
+ end
1425
+
1426
+ # Test private methods
1427
+ def test_normalize_key
1428
+ params = StrongParameters::Core::Parameters.new
1429
+ assert_equal 'test_key', params.send(:normalize_key, :test_key)
1430
+ assert_equal 'test_key', params.send(:normalize_key, 'test_key')
1431
+ end
1432
+
1433
+ def test_deep_normalize_keys
1434
+ params = StrongParameters::Core::Parameters.new
1435
+ hash = { 'key1' => 'value1', :key2 => { 'nested' => 'value2' } }
1436
+ normalized = params.send(:deep_normalize_keys, hash)
1437
+ assert_equal 'value1', normalized['key1']
1438
+ assert_equal 'value2', normalized['key2']['nested']
1439
+ end
1440
+
1441
+ def test_convert_value_with_hash
1442
+ params = StrongParameters::Core::Parameters.new
1443
+ hash = { a: 1 }
1444
+ converted = params.send(:convert_value, hash)
1445
+ assert converted.is_a?(StrongParameters::Core::Parameters)
1446
+ assert_equal 1, converted[:a]
1447
+ end
1448
+
1449
+ def test_convert_value_with_array
1450
+ params = StrongParameters::Core::Parameters.new
1451
+ array = [{ a: 1 }, { b: 2 }]
1452
+ converted = params.send(:convert_value, array)
1453
+ assert converted[0].is_a?(StrongParameters::Core::Parameters)
1454
+ assert_equal 1, converted[0][:a]
1455
+ end
1456
+
1457
+ def test_wrap_array
1458
+ params = StrongParameters::Core::Parameters.new
1459
+ assert_equal [1], params.send(:wrap_array, 1)
1460
+ assert_equal [1, 2], params.send(:wrap_array, [1, 2])
1461
+ end
1462
+
1463
+ def test_fields_for_style?
1464
+ params = StrongParameters::Core::Parameters.new
1465
+ assert params.send(:fields_for_style?, { '0' => { name: 'John' }, '1' => { name: 'Jane' } })
1466
+ assert !params.send(:fields_for_style?, { name: 'John', age: 30 })
1467
+ end
1468
+
1469
+ def test_fields_for_style_with_negative_indices
1470
+ params = StrongParameters::Core::Parameters.new
1471
+ assert params.send(:fields_for_style?, { '-1' => { name: 'John' }, '0' => { name: 'Jane' } })
1472
+ end
1473
+
1474
+ def test_fields_for_style_with_non_numeric_keys
1475
+ params = StrongParameters::Core::Parameters.new
1476
+ assert !params.send(:fields_for_style?, { 'a' => { name: 'John' }, 'b' => { name: 'Jane' } })
1477
+ end
1478
+
1479
+ def test_fields_for_style_with_mixed_keys
1480
+ params = StrongParameters::Core::Parameters.new
1481
+ assert !params.send(:fields_for_style?, { '0' => { name: 'John' }, 'name' => 'Jane' })
1482
+ end
1483
+
1484
+ def test_convert_value_with_nil
1485
+ params = StrongParameters::Core::Parameters.new
1486
+ assert_nil params.send(:convert_value, nil)
1487
+ end
1488
+
1489
+ def test_convert_value_with_scalar
1490
+ params = StrongParameters::Core::Parameters.new
1491
+ assert_equal 'string', params.send(:convert_value, 'string')
1492
+ assert_equal 42, params.send(:convert_value, 42)
1493
+ end
1494
+
1495
+ def test_convert_value_with_nested_array
1496
+ params = StrongParameters::Core::Parameters.new
1497
+ array = [{ a: 1 }, { b: 2 }]
1498
+ converted = params.send(:convert_value, array)
1499
+ assert converted[0].is_a?(StrongParameters::Core::Parameters)
1500
+ assert_equal 1, converted[0][:a]
1501
+ end
1502
+
1503
+ def test_wrap_array_with_array
1504
+ params = StrongParameters::Core::Parameters.new
1505
+ assert_equal [1, 2, 3], params.send(:wrap_array, [1, 2, 3])
1506
+ end
1507
+
1508
+ def test_wrap_array_with_non_array
1509
+ params = StrongParameters::Core::Parameters.new
1510
+ assert_equal ['string'], params.send(:wrap_array, 'string')
1511
+ assert_equal [42], params.send(:wrap_array, 42)
1512
+ end
1513
+
1514
+ def test_unpermitted_keys_excludes_never_unpermitted
1515
+ params = StrongParameters::Core::Parameters.new(name: 'John', controller: 'users', action: 'create', admin: true)
1516
+ permitted_params = StrongParameters::Core::Parameters.new(name: 'John')
1517
+ unpermitted = params.send(:unpermitted_keys, permitted_params)
1518
+ assert_equal ['admin'], unpermitted
1519
+ assert !unpermitted.include?('controller')
1520
+ assert !unpermitted.include?('action')
1521
+ end
1522
+
1523
+ def test_unpermitted_keys_with_no_permitted
1524
+ params = StrongParameters::Core::Parameters.new(name: 'John', admin: true)
1525
+ permitted_params = StrongParameters::Core::Parameters.new
1526
+ unpermitted = params.send(:unpermitted_keys, permitted_params)
1527
+ assert_equal ['name', 'admin'], unpermitted
1528
+ end
1529
+
1530
+ def test_normalize_key_with_various_types
1531
+ params = StrongParameters::Core::Parameters.new
1532
+ assert_equal '123', params.send(:normalize_key, 123)
1533
+ assert_equal 'true', params.send(:normalize_key, true)
1534
+ assert_equal 'false', params.send(:normalize_key, false)
1535
+ assert_equal '', params.send(:normalize_key, nil)
1536
+ assert_equal 'symbol', params.send(:normalize_key, :symbol)
1537
+ assert_equal 'string', params.send(:normalize_key, 'string')
1538
+ end
1539
+
1540
+ def test_deep_normalize_keys_with_mixed_types
1541
+ params = StrongParameters::Core::Parameters.new
1542
+ hash = {
1543
+ 'string' => 'value',
1544
+ :symbol => 'value',
1545
+ 123 => 'value',
1546
+ nil => 'value',
1547
+ nested: {
1548
+ 'inner_string' => 'value',
1549
+ :inner_symbol => 'value'
1550
+ }
1551
+ }
1552
+
1553
+ normalized = params.send(:deep_normalize_keys, hash)
1554
+ assert_equal 'value', normalized['string']
1555
+ assert_equal 'value', normalized['symbol']
1556
+ assert_equal 'value', normalized['123']
1557
+ assert_equal 'value', normalized['']
1558
+ assert_equal 'value', normalized['nested']['inner_string']
1559
+ assert_equal 'value', normalized['nested']['inner_symbol']
1560
+ end
1561
+
1562
+ def test_convert_value_with_deeply_nested_hash
1563
+ params = StrongParameters::Core::Parameters.new
1564
+ hash = { a: { b: { c: 'value' } } }
1565
+ converted = params.send(:convert_value, hash)
1566
+
1567
+ assert converted.is_a?(StrongParameters::Core::Parameters)
1568
+ assert converted[:a].is_a?(StrongParameters::Core::Parameters)
1569
+ assert converted[:a][:b].is_a?(StrongParameters::Core::Parameters)
1570
+ assert_equal 'value', converted[:a][:b][:c]
1571
+ end
1572
+
1573
+ def test_convert_value_with_mixed_array_and_hash
1574
+ params = StrongParameters::Core::Parameters.new
1575
+ mixed = [
1576
+ { name: 'John' },
1577
+ 'string',
1578
+ 42,
1579
+ { nested: { value: true } }
1580
+ ]
1581
+
1582
+ converted = params.send(:convert_value, mixed)
1583
+ assert converted[0].is_a?(StrongParameters::Core::Parameters)
1584
+ assert_equal 'John', converted[0][:name]
1585
+ assert_equal 'string', converted[1]
1586
+ assert_equal 42, converted[2]
1587
+ assert converted[3].is_a?(StrongParameters::Core::Parameters)
1588
+ assert_equal true, converted[3][:nested][:value]
1589
+ end
1590
+
1591
+ def test_wrap_array_with_various_inputs
1592
+ params = StrongParameters::Core::Parameters.new
1593
+ assert_equal [nil], params.send(:wrap_array, nil)
1594
+ assert_equal ['string'], params.send(:wrap_array, 'string')
1595
+ assert_equal [42], params.send(:wrap_array, 42)
1596
+ assert_equal [true], params.send(:wrap_array, true)
1597
+ assert_equal [:symbol], params.send(:wrap_array, :symbol)
1598
+ assert_equal([1, 2, 3], params.send(:wrap_array, [1, 2, 3]))
1599
+ end
1600
+
1601
+ def test_fields_for_style_with_various_patterns
1602
+ params = StrongParameters::Core::Parameters.new
1603
+
1604
+ # Valid fields_for patterns
1605
+ assert params.send(:fields_for_style?, { '0' => {}, '1' => {} })
1606
+ assert params.send(:fields_for_style?, { '-1' => {}, '0' => {}, '1' => {} })
1607
+ assert params.send(:fields_for_style?, { '10' => {}, '20' => {} })
1608
+
1609
+ # Invalid patterns
1610
+ assert !params.send(:fields_for_style?, { name: 'John' })
1611
+ assert !params.send(:fields_for_style?, { '0' => {}, name: 'John' })
1612
+ assert !params.send(:fields_for_style?, { 'a' => {}, 'b' => {} })
1613
+ assert !params.send(:fields_for_style?, { '0' => 'not_hash' })
1614
+ assert !params.send(:fields_for_style?, {})
1615
+ end
1616
+
1617
+ def test_unpermitted_keys_with_controller_action
1618
+ params = StrongParameters::Core::Parameters.new(
1619
+ name: 'John',
1620
+ admin: true,
1621
+ controller: 'users',
1622
+ action: 'create'
1623
+ )
1624
+
1625
+ permitted_params = StrongParameters::Core::Parameters.new(name: 'John')
1626
+ unpermitted = params.send(:unpermitted_keys, permitted_params)
1627
+
1628
+ assert_equal ['admin'], unpermitted
1629
+ assert !unpermitted.include?('controller')
1630
+ assert !unpermitted.include?('action')
1631
+ end
1632
+
1633
+ def test_validate_metadata_keys_with_empty_metadata
1634
+ params_class = Class.new(StrongParameters::Core::ApplicationParams)
1635
+ params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
1636
+ user_params = params.require(:user)
1637
+
1638
+ # Should not raise
1639
+ user_params.send(:validate_metadata_keys!, params_class, [])
1640
+ end
1641
+
1642
+ def test_validate_metadata_keys_allows_current_user_always
1643
+ params_class = Class.new(StrongParameters::Core::ApplicationParams) do
1644
+ def self.metadata_allowed?(key)
1645
+ false # Explicitly disallow everything
1646
+ end
1647
+ end
1648
+
1649
+ params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
1650
+ user_params = params.require(:user)
1651
+
1652
+ # Should not raise because :current_user is always allowed
1653
+ user_params.send(:validate_metadata_keys!, params_class, [:current_user])
1654
+ end
1655
+
1656
+ # Test unpermitted parameters handling
1657
+ def test_unpermitted_parameters_with_log_action
1658
+ StrongParameters::Core::Parameters.action_on_unpermitted_parameters = :log
1659
+ StrongParameters::Core::Parameters.unpermitted_notification_handler = proc { |keys| @logged_keys = keys }
1660
+
1661
+ params = StrongParameters::Core::Parameters.new(name: 'John', admin: true)
1662
+ params.permit(:name)
1663
+
1664
+ assert_equal ['admin'], @logged_keys
1665
+ end
1666
+
1667
+ def test_unpermitted_parameters_with_raise_action
1668
+ StrongParameters::Core::Parameters.action_on_unpermitted_parameters = :raise
1669
+
1670
+ params = StrongParameters::Core::Parameters.new(name: 'John', admin: true)
1671
+
1672
+ assert_raises(StrongParameters::Core::UnpermittedParameters) do
1673
+ params.permit(:name)
1674
+ end
1675
+ end
1676
+
1677
+ def test_unpermitted_parameters_with_nil_action
1678
+ StrongParameters::Core::Parameters.action_on_unpermitted_parameters = nil
1679
+
1680
+ params = StrongParameters::Core::Parameters.new(name: 'John', admin: true)
1681
+ permitted = params.permit(:name)
1682
+
1683
+ assert_equal 'John', permitted[:name]
1684
+ end
1685
+
1686
+ def test_unpermitted_notification_handler_called_with_correct_keys
1687
+ called_with = nil
1688
+ StrongParameters::Core::Parameters.action_on_unpermitted_parameters = :log
1689
+ StrongParameters::Core::Parameters.unpermitted_notification_handler = proc { |keys| called_with = keys }
1690
+
1691
+ params = StrongParameters::Core::Parameters.new(name: 'John', admin: true, secret: 'hidden')
1692
+ params.permit(:name)
1693
+
1694
+ assert_equal ['admin', 'secret'], called_with
1695
+ end
1696
+
1697
+ def test_unpermitted_notification_handler_not_called_when_no_unpermitted
1698
+ called = false
1699
+ StrongParameters::Core::Parameters.action_on_unpermitted_parameters = :log
1700
+ StrongParameters::Core::Parameters.unpermitted_notification_handler = proc { called = true }
1701
+
1702
+ params = StrongParameters::Core::Parameters.new(name: 'John')
1703
+ params.permit(:name)
1704
+
1705
+ assert !called
1706
+ end
1707
+
1708
+ def test_unpermitted_notification_handler_with_nil_handler
1709
+ StrongParameters::Core::Parameters.action_on_unpermitted_parameters = :log
1710
+ StrongParameters::Core::Parameters.unpermitted_notification_handler = nil
1711
+
1712
+ params = StrongParameters::Core::Parameters.new(name: 'John', admin: true)
1713
+ # Should not raise or error
1714
+ permitted = params.permit(:name)
1715
+ assert_equal 'John', permitted[:name]
1716
+ end
1717
+
1718
+ def test_class_attributes_initially_nil
1719
+ original_action = StrongParameters::Core::Parameters.action_on_unpermitted_parameters
1720
+ original_handler = StrongParameters::Core::Parameters.unpermitted_notification_handler
1721
+
1722
+ begin
1723
+ StrongParameters::Core::Parameters.action_on_unpermitted_parameters = nil
1724
+ StrongParameters::Core::Parameters.unpermitted_notification_handler = nil
1725
+
1726
+ assert_nil StrongParameters::Core::Parameters.action_on_unpermitted_parameters
1727
+ assert_nil StrongParameters::Core::Parameters.unpermitted_notification_handler
1728
+ ensure
1729
+ StrongParameters::Core::Parameters.action_on_unpermitted_parameters = original_action
1730
+ StrongParameters::Core::Parameters.unpermitted_notification_handler = original_handler
1731
+ end
1732
+ end
1733
+
1734
+ def test_unpermitted_parameters_ignores_controller_and_action
1735
+ StrongParameters::Core::Parameters.action_on_unpermitted_parameters = :raise
1736
+
1737
+ params = StrongParameters::Core::Parameters.new(
1738
+ name: 'John',
1739
+ controller: 'users',
1740
+ action: 'create'
1741
+ )
1742
+
1743
+ # Should not raise because controller and action are never unpermitted
1744
+ permitted = params.permit(:name)
1745
+ assert_equal 'John', permitted[:name]
1746
+ end
1747
+
1748
+ def test_unpermitted_parameters_with_nested_unpermitted
1749
+ StrongParameters::Core::Parameters.action_on_unpermitted_parameters = :raise
1750
+
1751
+ params = StrongParameters::Core::Parameters.new(
1752
+ user: {
1753
+ name: 'John',
1754
+ profile: {
1755
+ bio: 'Developer',
1756
+ secret: 'hidden'
1757
+ }
1758
+ },
1759
+ admin: true
1760
+ )
1761
+
1762
+ assert_raises(StrongParameters::Core::UnpermittedParameters) do
1763
+ params.permit(user: [profile: [:bio]]) # secret and admin not permitted
1764
+ end
1765
+ end
1766
+
1767
+ def test_unpermitted_parameters_log_with_custom_handler
1768
+ logged_keys = nil
1769
+ StrongParameters::Core::Parameters.action_on_unpermitted_parameters = :log
1770
+ StrongParameters::Core::Parameters.unpermitted_notification_handler = proc { |keys| logged_keys = keys }
1771
+
1772
+ params = StrongParameters::Core::Parameters.new(
1773
+ name: 'John',
1774
+ admin: true,
1775
+ controller: 'users', # Should be ignored
1776
+ action: 'create' # Should be ignored
1777
+ )
1778
+
1779
+ permitted = params.permit(:name)
1780
+ assert_equal 'John', permitted[:name]
1781
+ assert_equal ['admin'], logged_keys
1782
+ end
1783
+
1784
+ def test_unpermitted_parameters_with_multiple_unpermitted_keys
1785
+ StrongParameters::Core::Parameters.action_on_unpermitted_parameters = :log
1786
+ logged_keys = nil
1787
+ StrongParameters::Core::Parameters.unpermitted_notification_handler = proc { |keys| logged_keys = keys }
1788
+
1789
+ params = StrongParameters::Core::Parameters.new(
1790
+ name: 'John',
1791
+ admin: true,
1792
+ super_admin: true,
1793
+ secret_token: 'abc123'
1794
+ )
1795
+
1796
+ permitted = params.permit(:name)
1797
+ assert_equal ['admin', 'super_admin', 'secret_token'], logged_keys
1798
+ end
1799
+
1800
+ def test_unpermitted_parameters_with_no_unpermitted_keys
1801
+ called = false
1802
+ StrongParameters::Core::Parameters.action_on_unpermitted_parameters = :log
1803
+ StrongParameters::Core::Parameters.unpermitted_notification_handler = proc { called = true }
1804
+
1805
+ params = StrongParameters::Core::Parameters.new(
1806
+ name: 'John',
1807
+ controller: 'users',
1808
+ action: 'create'
1809
+ )
1810
+
1811
+ permitted = params.permit(:name, :controller, :action)
1812
+ assert_equal 'John', permitted[:name]
1813
+ assert !called # Handler should not be called
1814
+ end
1815
+
1816
+ def test_unpermitted_parameters_handler_exception_does_not_prevent_permit
1817
+ StrongParameters::Core::Parameters.action_on_unpermitted_parameters = :log
1818
+ StrongParameters::Core::Parameters.unpermitted_notification_handler = proc { raise 'Handler error' }
1819
+
1820
+ params = StrongParameters::Core::Parameters.new(name: 'John', admin: true)
1821
+
1822
+ # Even if handler raises, permit should still work
1823
+ permitted = params.permit(:name)
1824
+ assert_equal 'John', permitted[:name]
1825
+ end
1826
+
1827
+ def test_unpermitted_parameters_with_permitted_but_unpermitted_in_nested
1828
+ StrongParameters::Core::Parameters.action_on_unpermitted_parameters = :raise
1829
+
1830
+ params = StrongParameters::Core::Parameters.new(
1831
+ user: {
1832
+ name: 'John',
1833
+ emails: [
1834
+ { address: 'john@example.com', primary: true },
1835
+ { address: 'john@work.com', primary: false, secret: 'hidden' }
1836
+ ]
1837
+ }
1838
+ )
1839
+
1840
+ assert_raises(StrongParameters::Core::UnpermittedParameters) do
1841
+ params.permit(user: [emails: [:address, :primary]]) # secret not permitted
1842
+ end
1843
+ end
1844
+
1845
+ # Test exceptions
1846
+ def test_parameter_missing_exception_stores_param
1847
+ error = assert_raises(StrongParameters::Core::ParameterMissing) do
1848
+ @params.require(:missing)
1849
+ end
1850
+
1851
+ assert_equal 'missing', error.param
1852
+ end
1853
+
1854
+ def test_unpermitted_parameters_exception_stores_params
1855
+ error = StrongParameters::Core::UnpermittedParameters.new(['field1', 'field2'])
1856
+ assert_equal ['field1', 'field2'], error.params
1857
+ end
1858
+
1859
+ def test_parameter_missing_with_empty_available_keys
1860
+ params = StrongParameters::Core::Parameters.new({})
1861
+ error = assert_raises(StrongParameters::Core::ParameterMissing) do
1862
+ params.require(:missing)
1863
+ end
1864
+ assert_equal 'missing', error.param
1865
+ assert_match(/param is missing or the value is empty: missing/, error.message)
1866
+ refute_match(/Available keys:/, error.message)
1867
+ refute_match(/Did you mean\?/, error.message)
1868
+ end
1869
+
1870
+ def test_parameter_missing_with_numeric_keys
1871
+ params = StrongParameters::Core::Parameters.new('0' => 'first', '1' => 'second')
1872
+ error = assert_raises(StrongParameters::Core::ParameterMissing) do
1873
+ params.require(:missing)
1874
+ end
1875
+ assert_match(/Available keys: 0, 1/, error.message)
1876
+ end
1877
+
1878
+ def test_parameter_missing_with_special_characters_in_keys
1879
+ params = StrongParameters::Core::Parameters.new('user-name' => 'John', 'user_name' => 'Jane')
1880
+ error = assert_raises(StrongParameters::Core::ParameterMissing) do
1881
+ params.require(:user)
1882
+ end
1883
+ assert_match(/Did you mean\? user-name, user_name/, error.message)
1884
+ end
1885
+
1886
+ def test_parameter_missing_find_similar_keys_case_insensitive
1887
+ params = StrongParameters::Core::Parameters.new('User' => 'John', 'USER' => 'Jane')
1888
+ error = assert_raises(StrongParameters::Core::ParameterMissing) do
1889
+ params.require(:user)
1890
+ end
1891
+ assert_match(/Did you mean\? User, USER/, error.message)
1892
+ end
1893
+
1894
+ def test_unpermitted_parameters_with_empty_keys
1895
+ error = StrongParameters::Core::UnpermittedParameters.new([])
1896
+ assert_equal [], error.params
1897
+ assert_equal "found unpermitted parameters: ", error.message
1898
+ end
1899
+
1900
+ def test_unpermitted_parameters_with_single_key
1901
+ error = StrongParameters::Core::UnpermittedParameters.new(['admin'])
1902
+ assert_equal ['admin'], error.params
1903
+ assert_equal "found unpermitted parameters: admin", error.message
1904
+ end
1905
+
1906
+ def test_parameter_missing_with_no_available_keys
1907
+ params = StrongParameters::Core::Parameters.new({})
1908
+ error = assert_raises(StrongParameters::Core::ParameterMissing) do
1909
+ params.require(:user)
1910
+ end
1911
+
1912
+ assert_equal 'user', error.param
1913
+ assert_match(/param is missing or the value is empty: user/, error.message)
1914
+ refute_match(/Available keys:/, error.message)
1915
+ refute_match(/Did you mean\?/, error.message)
1916
+ end
1917
+
1918
+ def test_parameter_missing_with_many_available_keys
1919
+ params = StrongParameters::Core::Parameters.new(
1920
+ usr: 'value',
1921
+ user_name: 'value',
1922
+ user_email: 'value',
1923
+ username: 'value',
1924
+ usr_profile: 'value',
1925
+ other_key: 'value',
1926
+ another_key: 'value'
1927
+ )
1928
+
1929
+ error = assert_raises(StrongParameters::Core::ParameterMissing) do
1930
+ params.require(:user)
1931
+ end
1932
+
1933
+ assert_match(/Available keys: usr, user_name, user_email, username, usr_profile, other_key, another_key/, error.message)
1934
+ # Should suggest up to 3 similar keys
1935
+ assert_match(/Did you mean\? usr, user_name, user_email/, error.message)
1936
+ end
1937
+
1938
+ def test_parameter_missing_with_exact_match_suggestion
1939
+ params = StrongParameters::Core::Parameters.new(userr: 'value', usr: 'value')
1940
+ error = assert_raises(StrongParameters::Core::ParameterMissing) do
1941
+ params.require(:user)
1942
+ end
1943
+
1944
+ assert_match(/Did you mean\? userr, usr/, error.message)
1945
+ end
1946
+
1947
+ def test_parameter_missing_with_case_insensitive_suggestions
1948
+ params = StrongParameters::Core::Parameters.new(User: 'value', USER: 'value', user_name: 'value')
1949
+ error = assert_raises(StrongParameters::Core::ParameterMissing) do
1950
+ params.require(:user)
1951
+ end
1952
+
1953
+ assert_match(/Did you mean\? User, USER, user_name/, error.message)
1954
+ end
1955
+
1956
+ def test_parameter_missing_with_numeric_keys_only
1957
+ params = StrongParameters::Core::Parameters.new('0' => 'first', '1' => 'second', '2' => 'third')
1958
+ error = assert_raises(StrongParameters::Core::ParameterMissing) do
1959
+ params.require(:user)
1960
+ end
1961
+
1962
+ assert_match(/Available keys: 0, 1, 2/, error.message)
1963
+ refute_match(/Did you mean\?/, error.message) # Numeric keys shouldn't suggest
1964
+ end
1965
+
1966
+ def test_parameter_missing_with_mixed_key_types
1967
+ params = StrongParameters::Core::Parameters.new(
1968
+ 'string_key' => 'value',
1969
+ :symbol_key => 'value',
1970
+ 42 => 'value'
1971
+ )
1972
+
1973
+ error = assert_raises(StrongParameters::Core::ParameterMissing) do
1974
+ params.require(:user)
1975
+ end
1976
+
1977
+ # Keys are normalized to strings
1978
+ assert_match(/Available keys: string_key, symbol_key, 42/, error.message)
1979
+ end
1980
+
1981
+ def test_parameter_missing_with_very_long_key_list
1982
+ # Create many keys to test display
1983
+ keys = {}
1984
+ 20.times { |i| keys["key#{i}"] = "value#{i}" }
1985
+ params = StrongParameters::Core::Parameters.new(keys)
1986
+
1987
+ error = assert_raises(StrongParameters::Core::ParameterMissing) do
1988
+ params.require(:user)
1989
+ end
1990
+
1991
+ assert_match(/Available keys: key0, key1, key2, key3, key4, key5, key6, key7, key8, key9, key10, key11, key12, key13, key14, key15, key16, key17, key18, key19/, error.message)
1992
+ end
1993
+
1994
+ def test_unpermitted_parameters_with_multiple_keys_sorted
1995
+ error = StrongParameters::Core::UnpermittedParameters.new(['zebra', 'alpha', 'beta'])
1996
+ assert_equal ['zebra', 'alpha', 'beta'], error.params
1997
+ assert_equal "found unpermitted parameters: zebra, alpha, beta", error.message
1998
+ end
1999
+
2000
+ def test_unpermitted_parameters_with_special_characters
2001
+ error = StrongParameters::Core::UnpermittedParameters.new(['user-name', 'user_name', 'user.name'])
2002
+ assert_equal ['user-name', 'user_name', 'user.name'], error.params
2003
+ assert_equal "found unpermitted parameters: user-name, user_name, user.name", error.message
2004
+ end
2005
+
2006
+ # Test metadata validation
2007
+ def test_validate_metadata_keys_with_allowed_keys
2008
+ params_class = Class.new(StrongParameters::Core::ApplicationParams) do
2009
+ def self.metadata_allowed?(key)
2010
+ key == :current_user
2011
+ end
2012
+ end
2013
+
2014
+ params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
2015
+ user_params = params.require(:user)
2016
+
2017
+ # Should not raise
2018
+ user_params.send(:validate_metadata_keys!, params_class, [:current_user])
2019
+ end
2020
+
2021
+ def test_validate_metadata_keys_with_disallowed_keys
2022
+ params_class = Class.new(StrongParameters::Core::ApplicationParams) do
2023
+ def self.metadata_allowed?(key)
2024
+ false
2025
+ end
2026
+ end
2027
+
2028
+ params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
2029
+ user_params = params.require(:user)
2030
+
2031
+ error = assert_raises(ArgumentError) do
2032
+ user_params.send(:validate_metadata_keys!, params_class, [:invalid_key])
2033
+ end
2034
+
2035
+ assert_match(/Metadata key\(s\) :invalid_key not allowed/, error.message)
2036
+ assert_match(/To fix this, declare them in your params class/, error.message)
2037
+ end
2038
+
2039
+ def test_validate_metadata_keys_allows_current_user_implicitly
2040
+ params_class = Class.new(StrongParameters::Core::ApplicationParams) do
2041
+ def self.metadata_allowed?(key)
2042
+ false # Even if metadata_allowed? returns false for current_user
2043
+ end
2044
+ end
2045
+
2046
+ params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
2047
+ user_params = params.require(:user)
2048
+
2049
+ # Should not raise because :current_user is always allowed
2050
+ user_params.send(:validate_metadata_keys!, params_class, [:current_user])
2051
+ end
2052
+
2053
+ # Test required_key initialization
2054
+ def test_required_key_initially_nil
2055
+ params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
2056
+ assert_nil params.required_key
2057
+ end
2058
+
2059
+ # Test multi-parameter attributes (like Rails date/time selects)
2060
+ def test_permit_multi_parameter_attributes
2061
+ params = StrongParameters::Core::Parameters.new(
2062
+ 'birth_date(1i)' => '1990',
2063
+ 'birth_date(2i)' => '01',
2064
+ 'birth_date(3i)' => '15'
2065
+ )
2066
+
2067
+ permitted = params.permit(:birth_date)
2068
+ assert_equal '1990', permitted['birth_date(1i)']
2069
+ assert_equal '01', permitted['birth_date(2i)']
2070
+ assert_equal '15', permitted['birth_date(3i)']
2071
+ end
2072
+
2073
+ # Test fields_for style parameters (numeric keys for arrays)
2074
+ def test_permit_fields_for_style_parameters
2075
+ params = StrongParameters::Core::Parameters.new(
2076
+ '0' => { name: 'John', age: '30' },
2077
+ '1' => { name: 'Jane', age: '25' }
2078
+ )
2079
+
2080
+ permitted = params.permit('0' => [:name, :age], '1' => [:name, :age])
2081
+ assert_equal 'John', permitted['0'][:name]
2082
+ assert_equal '30', permitted['0'][:age]
2083
+ assert_equal 'Jane', permitted['1'][:name]
2084
+ assert_equal '25', permitted['1'][:age]
2085
+ end
2086
+
2087
+ # Test edge cases
2088
+ def test_permit_with_empty_filters
2089
+ permitted = @params.permit
2090
+ assert_equal({}, permitted.to_h)
2091
+ assert permitted.permitted?
2092
+ end
2093
+
2094
+ def test_permit_with_nonexistent_keys
2095
+ permitted = @params.permit(:nonexistent)
2096
+ assert_equal({}, permitted.to_h)
2097
+ assert permitted.permitted?
2098
+ end
2099
+
2100
+ def test_require_with_nonexistent_key_in_nested_params
2101
+ params = StrongParameters::Core::Parameters.new(user: { profile: { name: 'John' } })
2102
+ user_params = params.require(:user)
2103
+ profile_params = user_params.require(:profile)
2104
+
2105
+ assert_equal 'John', profile_params[:name]
2106
+ end
2107
+
2108
+ def test_require_with_complex_nested_structure
2109
+ params = StrongParameters::Core::Parameters.new(
2110
+ company: {
2111
+ employees: [
2112
+ { name: 'Alice', role: 'dev' },
2113
+ { name: 'Bob', role: 'qa' }
2114
+ ],
2115
+ address: {
2116
+ street: '123 Main St',
2117
+ city: 'NYC'
2118
+ }
2119
+ }
2120
+ )
2121
+
2122
+ company_params = params.require(:company)
2123
+ assert company_params.is_a?(StrongParameters::Core::Parameters)
2124
+
2125
+ employees = company_params[:employees]
2126
+ assert employees.is_a?(Array)
2127
+ assert employees[0].is_a?(StrongParameters::Core::Parameters)
2128
+ assert_equal 'Alice', employees[0][:name]
2129
+
2130
+ address = company_params.require(:address)
2131
+ assert_equal '123 Main St', address[:street]
2132
+ end
2133
+
2134
+ def test_require_preserves_required_key_through_nesting
2135
+ params = StrongParameters::Core::Parameters.new(user: { profile: { settings: { theme: 'dark' } } })
2136
+ user_params = params.require(:user)
2137
+ profile_params = user_params.require(:profile)
2138
+ settings_params = profile_params.require(:settings)
2139
+
2140
+ assert_equal :user, user_params.required_key
2141
+ assert_equal :user, profile_params.required_key # Should inherit from parent
2142
+ assert_equal :user, settings_params.required_key
2143
+ end
2144
+
2145
+ def test_transform_params_with_empty_transformations
2146
+ params_class = Class.new(StrongParameters::Core::ApplicationParams) do
2147
+ def self.permitted_attributes(action: nil)
2148
+ [:name]
2149
+ end
2150
+
2151
+ def self.apply_transformations(params, options)
2152
+ params
2153
+ end
2154
+ end
2155
+
2156
+ params = StrongParameters::Core::Parameters.new(user: { name: 'John', extra: 'value' })
2157
+ user_params = params.require(:user)
2158
+ permitted = user_params.transform_params(params_class)
2159
+
2160
+ assert_equal 'John', permitted[:name]
2161
+ assert_nil permitted[:extra]
2162
+ end
2163
+
2164
+ def test_transform_params_with_nil_permitted_attributes
2165
+ params_class = Class.new(StrongParameters::Core::ApplicationParams) do
2166
+ def self.permitted_attributes(action: nil)
2167
+ nil
2168
+ end
2169
+ end
2170
+
2171
+ params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
2172
+ user_params = params.require(:user)
2173
+ permitted = user_params.transform_params(params_class)
2174
+
2175
+ assert_equal({}, permitted.to_h)
2176
+ assert permitted.permitted?
2177
+ end
2178
+
2179
+ def test_transform_params_with_empty_permitted_attributes
2180
+ params_class = Class.new(StrongParameters::Core::ApplicationParams) do
2181
+ def self.permitted_attributes(action: nil)
2182
+ []
2183
+ end
2184
+ end
2185
+
2186
+ params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
2187
+ user_params = params.require(:user)
2188
+ permitted = user_params.transform_params(params_class)
2189
+
2190
+ assert_equal({}, permitted.to_h)
2191
+ assert permitted.permitted?
2192
+ end
2193
+
2194
+ def test_transform_params_with_transformation_returning_nil
2195
+ params_class = Class.new(StrongParameters::Core::ApplicationParams) do
2196
+ def self.permitted_attributes(action: nil)
2197
+ [:name]
2198
+ end
2199
+
2200
+ def self.apply_transformations(params, options)
2201
+ nil
2202
+ end
2203
+ end
2204
+
2205
+ params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
2206
+ user_params = params.require(:user)
2207
+
2208
+ permitted = user_params.transform_params(params_class)
2209
+ assert_equal({}, permitted.to_h)
2210
+ assert permitted.permitted?
2211
+ end
2212
+
2213
+ def test_transform_params_with_transformation_returning_non_hash
2214
+ params_class = Class.new(StrongParameters::Core::ApplicationParams) do
2215
+ def self.permitted_attributes(action: nil)
2216
+ [:name]
2217
+ end
2218
+
2219
+ def self.apply_transformations(params, options)
2220
+ 'not a hash'
2221
+ end
2222
+ end
2223
+
2224
+ params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
2225
+ user_params = params.require(:user)
2226
+
2227
+ assert_raises(TypeError) do
2228
+ user_params.transform_params(params_class)
2229
+ end
2230
+ end
2231
+
2232
+ def test_transform_params_with_additional_attrs_empty
2233
+ user_params_class = Class.new(StrongParameters::Core::ApplicationParams) do
2234
+ def self.permitted_attributes(action: nil)
2235
+ [:name]
2236
+ end
2237
+ end
2238
+
2239
+ params = StrongParameters::Core::Parameters.new(user: { name: 'John', token: 'abc123' })
2240
+ user_params = params.require(:user)
2241
+ permitted = user_params.transform_params(user_params_class, additional_attrs: [])
2242
+
2243
+ assert_equal 'John', permitted[:name]
2244
+ assert_nil permitted[:token]
2245
+ end
2246
+
2247
+ def test_transform_params_with_additional_attrs_overriding
2248
+ user_params_class = Class.new(StrongParameters::Core::ApplicationParams) do
2249
+ def self.permitted_attributes(action: nil)
2250
+ [:name]
2251
+ end
2252
+ end
2253
+
2254
+ params = StrongParameters::Core::Parameters.new(user: { name: 'John', token: 'abc123' })
2255
+ user_params = params.require(:user)
2256
+ permitted = user_params.transform_params(user_params_class, additional_attrs: [:name, :token])
2257
+
2258
+ assert_equal 'John', permitted[:name]
2259
+ assert_equal 'abc123', permitted[:token]
2260
+ end
2261
+
2262
+ def test_transform_params_with_unknown_action
2263
+ user_params_class = Class.new(StrongParameters::Core::ApplicationParams) do
2264
+ def self.permitted_attributes(action: nil)
2265
+ case action
2266
+ when :create
2267
+ [:name, :email]
2268
+ when :update
2269
+ [:name]
2270
+ else
2271
+ [] # Unknown action returns empty
2272
+ end
2273
+ end
2274
+ end
2275
+
2276
+ params = StrongParameters::Core::Parameters.new(user: { name: 'John', email: 'john@example.com' })
2277
+ user_params = params.require(:user)
2278
+ permitted = user_params.transform_params(user_params_class, action: :unknown)
2279
+
2280
+ assert_equal({}, permitted.to_h)
2281
+ assert permitted.permitted?
2282
+ end
2283
+
2284
+ def test_transform_params_with_nil_action
2285
+ user_params_class = Class.new(StrongParameters::Core::ApplicationParams) do
2286
+ def self.permitted_attributes(action: nil)
2287
+ if action.nil?
2288
+ [:name]
2289
+ else
2290
+ [:email]
2291
+ end
2292
+ end
2293
+ end
2294
+
2295
+ params = StrongParameters::Core::Parameters.new(user: { name: 'John', email: 'john@example.com' })
2296
+ user_params = params.require(:user)
2297
+
2298
+ # With nil action
2299
+ permitted_nil = user_params.transform_params(user_params_class, action: nil)
2300
+ assert_equal 'John', permitted_nil[:name]
2301
+ assert_nil permitted_nil[:email]
2302
+
2303
+ # With unspecified action (defaults to nil)
2304
+ permitted_default = user_params.transform_params(user_params_class)
2305
+ assert_equal 'John', permitted_default[:name]
2306
+ assert_nil permitted_default[:email]
2307
+ end
2308
+
2309
+ def test_transform_params_with_complex_transformations
2310
+ user_params_class = Class.new(StrongParameters::Core::ApplicationParams) do
2311
+ allow :name
2312
+ allow :email
2313
+ allow :age
2314
+ allow :full_name
2315
+
2316
+ def self.apply_transformations(params, options)
2317
+ # Normalize email to lowercase
2318
+ if params['email']
2319
+ params = params.merge('email' => params['email'].downcase)
2320
+ end
2321
+
2322
+ # Add computed field
2323
+ full_name = "#{params['name']} (#{params['age']})"
2324
+ params.merge('full_name' => full_name)
2325
+ end
2326
+ end
2327
+
2328
+ params = StrongParameters::Core::Parameters.new(user: { name: 'John', email: 'JOHN@EXAMPLE.COM', age: 30, admin: true })
2329
+ user_params = params.require(:user)
2330
+ permitted = user_params.transform_params(user_params_class)
2331
+
2332
+ assert_equal 'John', permitted[:name]
2333
+ assert_equal 'john@example.com', permitted[:email]
2334
+ assert_equal 30, permitted[:age]
2335
+ assert_equal 'John (30)', permitted[:full_name]
2336
+ assert_nil permitted[:admin]
2337
+ end
2338
+
2339
+ def test_transform_params_with_transformation_error
2340
+ user_params_class = Class.new(StrongParameters::Core::ApplicationParams) do
2341
+ def self.permitted_attributes(action: nil)
2342
+ [:name]
2343
+ end
2344
+
2345
+ def self.apply_transformations(params, options)
2346
+ raise StandardError, 'Transformation failed'
2347
+ end
2348
+ end
2349
+
2350
+ params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
2351
+ user_params = params.require(:user)
2352
+
2353
+ assert_raises(StandardError, 'Transformation failed') do
2354
+ user_params.transform_params(user_params_class)
2355
+ end
2356
+ end
2357
+
2358
+ def test_transform_params_with_empty_params_class
2359
+ empty_params_class = Class.new(StrongParameters::Core::ApplicationParams) do
2360
+ def self.permitted_attributes(action: nil)
2361
+ []
2362
+ end
2363
+
2364
+ def self.apply_transformations(params, options)
2365
+ {}
2366
+ end
2367
+ end
2368
+
2369
+ params = StrongParameters::Core::Parameters.new(user: { name: 'John', email: 'john@example.com' })
2370
+ user_params = params.require(:user)
2371
+ permitted = user_params.transform_params(empty_params_class)
2372
+
2373
+ assert_equal({}, permitted.to_h)
2374
+ assert permitted.permitted?
2375
+ end
2376
+ end