scimitar 1.0.3 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -363,78 +363,94 @@ RSpec.describe Scimitar::Resources::Mixin do
363
363
  # =========================================================================
364
364
 
365
365
  context '#from_scim!' do
366
- context 'writes instance attribute values from a SCIM representation' do
367
- it 'ignoring read-only lists' do
368
- hash = {
369
- 'userName' => 'foo',
370
- 'name' => {'givenName'=>'Foo', 'familyName'=>'Bar'},
371
- 'active' => true,
372
- 'emails' => [{'type'=>'work', 'primary'=>true, 'value'=>'foo.bar@test.com'}],
373
- 'phoneNumbers'=> [{'type'=>'work', 'primary'=>false, 'value'=>'+642201234567' }],
374
- 'groups' => [{'type'=>'Group', 'value'=>'1'}, {'type'=>'Group', 'value'=>'2'}],
375
- 'id' => '42', # Note, String
376
- 'externalId' => 'AA02984',
377
- 'meta' => {'location'=>'https://test.com/mock_users/42', 'resourceType'=>'User'},
378
- 'schemas' => ['urn:ietf:params:scim:schemas:core:2.0:User']
379
- }
366
+ shared_examples 'a creator' do | force_upper_case: |
367
+ context 'which writes instance attribute values from a SCIM representation while' do
368
+ it 'ignoring read-only lists' do
369
+ hash = {
370
+ 'userName' => 'foo',
371
+ 'name' => {'givenName' => 'Foo', 'familyName' => 'Bar'},
372
+ 'active' => true,
373
+ 'emails' => [{'type' => 'work', 'primary' => true, 'value' => 'foo.bar@test.com'}],
374
+ 'phoneNumbers' => [{'type' => 'work', 'primary' => false, 'value' => '+642201234567' }],
375
+ 'groups' => [{'type' => 'Group', 'value' => '1'}, {'type' => 'Group', 'value' => '2'}],
376
+ 'id' => '42', # Note, String
377
+ 'externalId' => 'AA02984',
378
+ 'meta' => {'location' => 'https://test.com/mock_users/42', 'resourceType' => 'User'},
379
+ 'schemas' => ['urn:ietf:params:scim:schemas:core:2.0:User']
380
+ }
380
381
 
381
- instance = MockUser.new
382
- instance.home_email_address = 'home@test.com' # Should be cleared as no home e-mail specified in SCIM hash above
383
- instance.from_scim!(scim_hash: hash)
384
-
385
- expect(instance.scim_uid ).to eql('AA02984')
386
- expect(instance.username ).to eql('foo')
387
- expect(instance.first_name ).to eql('Foo')
388
- expect(instance.last_name ).to eql('Bar')
389
- expect(instance.work_email_address).to eql('foo.bar@test.com')
390
- expect(instance.home_email_address).to be_nil
391
- expect(instance.work_phone_number ).to eql('+642201234567')
392
- end
382
+ hash = spec_helper_hupcase(hash) if force_upper_case
393
383
 
394
- it 'honouring read-write lists' do
395
- g1 = MockGroup.create!(display_name: 'Nested group')
396
-
397
- u1 = MockUser.create!(username: '1', first_name: 'Member 1')
398
- u2 = MockUser.create!(username: '2', first_name: 'Member 2')
399
- u3 = MockUser.create!(username: '3', first_name: 'Member 3')
400
-
401
- hash = {
402
- 'displayName' => 'Foo Group',
403
- 'members' => [
404
- {'type'=>'Group', 'value'=>g1.id.to_s},
405
- {'type'=>'User', 'value'=>u1.id.to_s},
406
- {'type'=>'User', 'value'=>u3.id.to_s}
407
- ],
408
- 'externalId' => 'GG01536',
409
- 'meta' => {'location'=>'https://test.com/mock_groups/1', 'resourceType'=>'Group'},
410
- 'schemas' => ['urn:ietf:params:scim:schemas:core:2.0:Group']
411
- }
384
+ instance = MockUser.new
385
+ instance.home_email_address = 'home@test.com' # Should be cleared as no home e-mail specified in SCIM hash above
386
+ instance.from_scim!(scim_hash: hash)
412
387
 
413
- instance = MockGroup.new
414
- instance.from_scim!(scim_hash: hash)
388
+ expect(instance.scim_uid ).to eql('AA02984')
389
+ expect(instance.username ).to eql('foo')
390
+ expect(instance.first_name ).to eql('Foo')
391
+ expect(instance.last_name ).to eql('Bar')
392
+ expect(instance.work_email_address).to eql('foo.bar@test.com')
393
+ expect(instance.home_email_address).to be_nil
394
+ expect(instance.work_phone_number ).to eql('+642201234567')
395
+ end
415
396
 
416
- expect(instance.scim_uid ).to eql('GG01536')
417
- expect(instance.display_name ).to eql('Foo Group')
418
- expect(instance.mock_users ).to match_array([u1, u3])
419
- expect(instance.child_mock_groups).to match_array([g1])
397
+ it 'honouring read-write lists' do
398
+ g1 = MockGroup.create!(display_name: 'Nested group')
420
399
 
421
- instance.save!
422
- expect(g1.reload.parent_id).to eql(instance.id)
423
- end
400
+ u1 = MockUser.create!(username: '1', first_name: 'Member 1')
401
+ u2 = MockUser.create!(username: '2', first_name: 'Member 2')
402
+ u3 = MockUser.create!(username: '3', first_name: 'Member 3')
424
403
 
425
- it 'handles missing inbound lists' do
426
- hash = {
427
- 'displayName' => 'Foo Group'
428
- }
404
+ hash = {
405
+ 'displayName' => 'Foo Group',
406
+ 'members' => [
407
+ {'type' => 'Group', 'value' => g1.id.to_s},
408
+ {'type' => 'User', 'value' => u1.id.to_s},
409
+ {'type' => 'User', 'value' => u3.id.to_s}
410
+ ],
411
+ 'externalId' => 'GG01536',
412
+ 'meta' => {'location'=>'https://test.com/mock_groups/1', 'resourceType'=>'Group'},
413
+ 'schemas' => ['urn:ietf:params:scim:schemas:core:2.0:Group']
414
+ }
429
415
 
430
- instance = MockGroup.new
431
- instance.from_scim!(scim_hash: hash)
416
+ hash = spec_helper_hupcase(hash) if force_upper_case
432
417
 
433
- expect(instance.display_name ).to eql('Foo Group')
434
- expect(instance.mock_users ).to be_empty
435
- expect(instance.child_mock_groups).to be_empty
436
- end
437
- end # "context 'writes instance attribute values from a SCIM representation' do"
418
+ instance = MockGroup.new
419
+ instance.from_scim!(scim_hash: hash)
420
+
421
+ expect(instance.scim_uid ).to eql('GG01536')
422
+ expect(instance.display_name ).to eql('Foo Group')
423
+ expect(instance.mock_users ).to match_array([u1, u3])
424
+ expect(instance.child_mock_groups).to match_array([g1])
425
+
426
+ instance.save!
427
+ expect(g1.reload.parent_id).to eql(instance.id)
428
+ end
429
+
430
+ it 'handling missing inbound lists' do
431
+ hash = {
432
+ 'displayName' => 'Foo Group'
433
+ }
434
+
435
+ hash = spec_helper_hupcase(hash) if force_upper_case
436
+
437
+ instance = MockGroup.new
438
+ instance.from_scim!(scim_hash: hash)
439
+
440
+ expect(instance.display_name ).to eql('Foo Group')
441
+ expect(instance.mock_users ).to be_empty
442
+ expect(instance.child_mock_groups).to be_empty
443
+ end
444
+ end # "context 'which writes instance attribute values from a SCIM representation while' do"
445
+ end # "shared_examples 'a creator' do | force_upper_case: |"
446
+
447
+ context 'using schema-matched case' do
448
+ it_behaves_like 'a creator', force_upper_case: false
449
+ end # "context 'using schema-matched case' do"
450
+
451
+ context 'using upper case' do
452
+ it_behaves_like 'a creator', force_upper_case: true
453
+ end # "context 'using upper case' do"
438
454
 
439
455
  it 'clears things not present in input' do
440
456
  instance = MockUser.new
@@ -631,7 +647,7 @@ RSpec.describe Scimitar::Resources::Mixin do
631
647
  context 'when prior value already exists' do
632
648
  it 'simple value: overwrites' do
633
649
  path = [ 'userName' ]
634
- scim_hash = { 'userName' => 'bar' }
650
+ scim_hash = { 'userName' => 'bar' }.with_indifferent_case_insensitive_access()
635
651
 
636
652
  @instance.send(
637
653
  :from_patch_backend!,
@@ -646,7 +662,7 @@ RSpec.describe Scimitar::Resources::Mixin do
646
662
 
647
663
  it 'nested simple value: overwrites' do
648
664
  path = [ 'name', 'givenName' ]
649
- scim_hash = { 'name' => { 'givenName' => 'Foo', 'familyName' => 'Bar' } }
665
+ scim_hash = { 'name' => { 'givenName' => 'Foo', 'familyName' => 'Bar' } }.with_indifferent_case_insensitive_access()
650
666
 
651
667
  @instance.send(
652
668
  :from_patch_backend!,
@@ -677,18 +693,18 @@ RSpec.describe Scimitar::Resources::Mixin do
677
693
  'value' => 'work@test.com'
678
694
  }
679
695
  ]
680
- }
696
+ }.with_indifferent_case_insensitive_access()
681
697
 
682
698
  @instance.send(
683
699
  :from_patch_backend!,
684
700
  nature: 'add',
685
701
  path: path,
686
- value: 'added_over_origina@test.com',
702
+ value: 'added_over_original@test.com',
687
703
  altering_hash: scim_hash
688
704
  )
689
705
 
690
706
  expect(scim_hash['emails'][0]['value']).to eql('home@test.com')
691
- expect(scim_hash['emails'][1]['value']).to eql('added_over_origina@test.com')
707
+ expect(scim_hash['emails'][1]['value']).to eql('added_over_original@test.com')
692
708
  end
693
709
 
694
710
  it 'by boolean match: overwrites' do
@@ -703,18 +719,18 @@ RSpec.describe Scimitar::Resources::Mixin do
703
719
  'primary' => true
704
720
  }
705
721
  ]
706
- }
722
+ }.with_indifferent_case_insensitive_access()
707
723
 
708
724
  @instance.send(
709
725
  :from_patch_backend!,
710
726
  nature: 'add',
711
727
  path: path,
712
- value: 'added_over_origina@test.com',
728
+ value: 'added_over_original@test.com',
713
729
  altering_hash: scim_hash
714
730
  )
715
731
 
716
732
  expect(scim_hash['emails'][0]['value']).to eql('home@test.com')
717
- expect(scim_hash['emails'][1]['value']).to eql('added_over_origina@test.com')
733
+ expect(scim_hash['emails'][1]['value']).to eql('added_over_original@test.com')
718
734
  end
719
735
 
720
736
  it 'multiple matches: overwrites all' do
@@ -730,18 +746,18 @@ RSpec.describe Scimitar::Resources::Mixin do
730
746
  'value' => 'work_2@test.com'
731
747
  }
732
748
  ]
733
- }
749
+ }.with_indifferent_case_insensitive_access()
734
750
 
735
751
  @instance.send(
736
752
  :from_patch_backend!,
737
753
  nature: 'add',
738
754
  path: path,
739
- value: 'added_over_origina@test.com',
755
+ value: 'added_over_original@test.com',
740
756
  altering_hash: scim_hash
741
757
  )
742
758
 
743
- expect(scim_hash['emails'][0]['value']).to eql('added_over_origina@test.com')
744
- expect(scim_hash['emails'][1]['value']).to eql('added_over_origina@test.com')
759
+ expect(scim_hash['emails'][0]['value']).to eql('added_over_original@test.com')
760
+ expect(scim_hash['emails'][1]['value']).to eql('added_over_original@test.com')
745
761
  end
746
762
  end # "context 'with filter mid-path' do"
747
763
 
@@ -754,7 +770,7 @@ RSpec.describe Scimitar::Resources::Mixin do
754
770
  'value' => 'home@test.com'
755
771
  }
756
772
  ]
757
- }
773
+ }.with_indifferent_case_insensitive_access()
758
774
 
759
775
  @instance.send(
760
776
  :from_patch_backend!,
@@ -778,7 +794,7 @@ RSpec.describe Scimitar::Resources::Mixin do
778
794
  {'value' => '2'}
779
795
  ]
780
796
  }
781
- }
797
+ }.with_indifferent_case_insensitive_access()
782
798
 
783
799
  # Example seen at:
784
800
  #
@@ -820,7 +836,7 @@ RSpec.describe Scimitar::Resources::Mixin do
820
836
  context 'when value is not present' do
821
837
  it 'simple value: adds' do
822
838
  path = [ 'userName' ]
823
- scim_hash = {}
839
+ scim_hash = {}.with_indifferent_case_insensitive_access()
824
840
 
825
841
  @instance.send(
826
842
  :from_patch_backend!,
@@ -835,7 +851,7 @@ RSpec.describe Scimitar::Resources::Mixin do
835
851
 
836
852
  it 'nested simple value: adds' do
837
853
  path = [ 'name', 'givenName' ]
838
- scim_hash = {}
854
+ scim_hash = {}.with_indifferent_case_insensitive_access()
839
855
 
840
856
  @instance.send(
841
857
  :from_patch_backend!,
@@ -861,7 +877,7 @@ RSpec.describe Scimitar::Resources::Mixin do
861
877
  'type' => 'work'
862
878
  }
863
879
  ]
864
- }
880
+ }.with_indifferent_case_insensitive_access()
865
881
 
866
882
  @instance.send(
867
883
  :from_patch_backend!,
@@ -886,7 +902,7 @@ RSpec.describe Scimitar::Resources::Mixin do
886
902
  'primary' => true
887
903
  }
888
904
  ]
889
- }
905
+ }.with_indifferent_case_insensitive_access()
890
906
 
891
907
  @instance.send(
892
908
  :from_patch_backend!,
@@ -902,7 +918,7 @@ RSpec.describe Scimitar::Resources::Mixin do
902
918
 
903
919
  it 'with no match: still adds' do
904
920
  path = [ 'emails[type eq "work"]', 'value' ]
905
- scim_hash = {}
921
+ scim_hash = {}.with_indifferent_case_insensitive_access()
906
922
 
907
923
  @instance.send(
908
924
  :from_patch_backend!,
@@ -926,7 +942,7 @@ RSpec.describe Scimitar::Resources::Mixin do
926
942
  'type' => 'work'
927
943
  }
928
944
  ]
929
- }
945
+ }.with_indifferent_case_insensitive_access()
930
946
 
931
947
  @instance.send(
932
948
  :from_patch_backend!,
@@ -943,7 +959,7 @@ RSpec.describe Scimitar::Resources::Mixin do
943
959
 
944
960
  it 'with arrays: appends' do
945
961
  path = [ 'emails' ]
946
- scim_hash = {}
962
+ scim_hash = {}.with_indifferent_case_insensitive_access()
947
963
 
948
964
  @instance.send(
949
965
  :from_patch_backend!,
@@ -968,7 +984,7 @@ RSpec.describe Scimitar::Resources::Mixin do
968
984
  context 'when prior value already exists' do
969
985
  it 'simple value: removes' do
970
986
  path = [ 'userName' ]
971
- scim_hash = { 'userName' => 'bar' }
987
+ scim_hash = { 'userName' => 'bar' }.with_indifferent_case_insensitive_access()
972
988
 
973
989
  @instance.send(
974
990
  :from_patch_backend!,
@@ -983,7 +999,7 @@ RSpec.describe Scimitar::Resources::Mixin do
983
999
 
984
1000
  it 'nested simple value: removes' do
985
1001
  path = [ 'name', 'givenName' ]
986
- scim_hash = { 'name' => { 'givenName' => 'Foo', 'familyName' => 'Bar' } }
1002
+ scim_hash = { 'name' => { 'givenName' => 'Foo', 'familyName' => 'Bar' } }.with_indifferent_case_insensitive_access()
987
1003
 
988
1004
  @instance.send(
989
1005
  :from_patch_backend!,
@@ -1011,7 +1027,7 @@ RSpec.describe Scimitar::Resources::Mixin do
1011
1027
  'value' => 'work@test.com'
1012
1028
  }
1013
1029
  ]
1014
- }
1030
+ }.with_indifferent_case_insensitive_access()
1015
1031
 
1016
1032
  @instance.send(
1017
1033
  :from_patch_backend!,
@@ -1037,7 +1053,7 @@ RSpec.describe Scimitar::Resources::Mixin do
1037
1053
  'primary' => true
1038
1054
  }
1039
1055
  ]
1040
- }
1056
+ }.with_indifferent_case_insensitive_access()
1041
1057
 
1042
1058
  @instance.send(
1043
1059
  :from_patch_backend!,
@@ -1064,7 +1080,7 @@ RSpec.describe Scimitar::Resources::Mixin do
1064
1080
  'value' => 'work_2@test.com'
1065
1081
  }
1066
1082
  ]
1067
- }
1083
+ }.with_indifferent_case_insensitive_access()
1068
1084
 
1069
1085
  @instance.send(
1070
1086
  :from_patch_backend!,
@@ -1093,7 +1109,7 @@ RSpec.describe Scimitar::Resources::Mixin do
1093
1109
  'value' => 'work@test.com'
1094
1110
  }
1095
1111
  ]
1096
- }
1112
+ }.with_indifferent_case_insensitive_access()
1097
1113
 
1098
1114
  @instance.send(
1099
1115
  :from_patch_backend!,
@@ -1119,7 +1135,7 @@ RSpec.describe Scimitar::Resources::Mixin do
1119
1135
  'primary' => true
1120
1136
  }
1121
1137
  ]
1122
- }
1138
+ }.with_indifferent_case_insensitive_access()
1123
1139
 
1124
1140
  @instance.send(
1125
1141
  :from_patch_backend!,
@@ -1150,7 +1166,7 @@ RSpec.describe Scimitar::Resources::Mixin do
1150
1166
  'value' => 'home@test.com'
1151
1167
  },
1152
1168
  ]
1153
- }
1169
+ }.with_indifferent_case_insensitive_access()
1154
1170
 
1155
1171
  @instance.send(
1156
1172
  :from_patch_backend!,
@@ -1174,7 +1190,7 @@ RSpec.describe Scimitar::Resources::Mixin do
1174
1190
  'value' => 'home@test.com'
1175
1191
  }
1176
1192
  ]
1177
- }
1193
+ }.with_indifferent_case_insensitive_access()
1178
1194
 
1179
1195
  @instance.send(
1180
1196
  :from_patch_backend!,
@@ -1191,7 +1207,7 @@ RSpec.describe Scimitar::Resources::Mixin do
1191
1207
  context 'when value is not present' do
1192
1208
  it 'simple value: does nothing' do
1193
1209
  path = [ 'userName' ]
1194
- scim_hash = {}
1210
+ scim_hash = {}.with_indifferent_case_insensitive_access()
1195
1211
 
1196
1212
  @instance.send(
1197
1213
  :from_patch_backend!,
@@ -1206,7 +1222,7 @@ RSpec.describe Scimitar::Resources::Mixin do
1206
1222
 
1207
1223
  it 'nested simple value: does nothing' do
1208
1224
  path = [ 'name', 'givenName' ]
1209
- scim_hash = { 'name' => {'familyName' => 'Bar' } }
1225
+ scim_hash = { 'name' => {'familyName' => 'Bar' } }.with_indifferent_case_insensitive_access()
1210
1226
 
1211
1227
  @instance.send(
1212
1228
  :from_patch_backend!,
@@ -1230,7 +1246,7 @@ RSpec.describe Scimitar::Resources::Mixin do
1230
1246
  'value' => 'home@test.com'
1231
1247
  }
1232
1248
  ]
1233
- }
1249
+ }.with_indifferent_case_insensitive_access()
1234
1250
 
1235
1251
  @instance.send(
1236
1252
  :from_patch_backend!,
@@ -1252,7 +1268,7 @@ RSpec.describe Scimitar::Resources::Mixin do
1252
1268
  'value' => 'home@test.com'
1253
1269
  }
1254
1270
  ]
1255
- }
1271
+ }.with_indifferent_case_insensitive_access()
1256
1272
 
1257
1273
  @instance.send(
1258
1274
  :from_patch_backend!,
@@ -1275,7 +1291,7 @@ RSpec.describe Scimitar::Resources::Mixin do
1275
1291
  'value' => 'home@test.com'
1276
1292
  }
1277
1293
  ]
1278
- }
1294
+ }.with_indifferent_case_insensitive_access()
1279
1295
 
1280
1296
  @instance.send(
1281
1297
  :from_patch_backend!,
@@ -1293,7 +1309,7 @@ RSpec.describe Scimitar::Resources::Mixin do
1293
1309
  context 'with filter at end of path' do
1294
1310
  it 'by string match: does nothing' do
1295
1311
  path = [ 'emails[type eq "work"]' ]
1296
- scim_hash = {}
1312
+ scim_hash = {}.with_indifferent_case_insensitive_access()
1297
1313
 
1298
1314
  @instance.send(
1299
1315
  :from_patch_backend!,
@@ -1315,7 +1331,7 @@ RSpec.describe Scimitar::Resources::Mixin do
1315
1331
  'primary' => false
1316
1332
  }
1317
1333
  ]
1318
- }
1334
+ }.with_indifferent_case_insensitive_access()
1319
1335
 
1320
1336
  @instance.send(
1321
1337
  :from_patch_backend!,
@@ -1332,7 +1348,7 @@ RSpec.describe Scimitar::Resources::Mixin do
1332
1348
 
1333
1349
  it 'remove whole array: does nothing' do
1334
1350
  path = [ 'emails' ]
1335
- scim_hash = {}
1351
+ scim_hash = {}.with_indifferent_case_insensitive_access()
1336
1352
 
1337
1353
  @instance.send(
1338
1354
  :from_patch_backend!,
@@ -1358,7 +1374,7 @@ RSpec.describe Scimitar::Resources::Mixin do
1358
1374
  context 'when prior value already exists' do
1359
1375
  it 'simple value: overwrites' do
1360
1376
  path = [ 'userName' ]
1361
- scim_hash = { 'userName' => 'bar' }
1377
+ scim_hash = { 'userName' => 'bar' }.with_indifferent_case_insensitive_access()
1362
1378
 
1363
1379
  @instance.send(
1364
1380
  :from_patch_backend!,
@@ -1373,7 +1389,7 @@ RSpec.describe Scimitar::Resources::Mixin do
1373
1389
 
1374
1390
  it 'nested simple value: overwrites' do
1375
1391
  path = [ 'name', 'givenName' ]
1376
- scim_hash = { 'name' => { 'givenName' => 'Foo', 'familyName' => 'Bar' } }
1392
+ scim_hash = { 'name' => { 'givenName' => 'Foo', 'familyName' => 'Bar' } }.with_indifferent_case_insensitive_access()
1377
1393
 
1378
1394
  @instance.send(
1379
1395
  :from_patch_backend!,
@@ -1401,18 +1417,18 @@ RSpec.describe Scimitar::Resources::Mixin do
1401
1417
  'value' => 'work@test.com'
1402
1418
  }
1403
1419
  ]
1404
- }
1420
+ }.with_indifferent_case_insensitive_access()
1405
1421
 
1406
1422
  @instance.send(
1407
1423
  :from_patch_backend!,
1408
1424
  nature: 'replace',
1409
1425
  path: path,
1410
- value: 'added_over_origina@test.com',
1426
+ value: 'added_over_original@test.com',
1411
1427
  altering_hash: scim_hash
1412
1428
  )
1413
1429
 
1414
1430
  expect(scim_hash['emails'][0]['value']).to eql('home@test.com')
1415
- expect(scim_hash['emails'][1]['value']).to eql('added_over_origina@test.com')
1431
+ expect(scim_hash['emails'][1]['value']).to eql('added_over_original@test.com')
1416
1432
  end
1417
1433
 
1418
1434
  it 'by boolean match: overwrites' do
@@ -1427,18 +1443,18 @@ RSpec.describe Scimitar::Resources::Mixin do
1427
1443
  'primary' => true
1428
1444
  }
1429
1445
  ]
1430
- }
1446
+ }.with_indifferent_case_insensitive_access()
1431
1447
 
1432
1448
  @instance.send(
1433
1449
  :from_patch_backend!,
1434
1450
  nature: 'replace',
1435
1451
  path: path,
1436
- value: 'added_over_origina@test.com',
1452
+ value: 'added_over_original@test.com',
1437
1453
  altering_hash: scim_hash
1438
1454
  )
1439
1455
 
1440
1456
  expect(scim_hash['emails'][0]['value']).to eql('home@test.com')
1441
- expect(scim_hash['emails'][1]['value']).to eql('added_over_origina@test.com')
1457
+ expect(scim_hash['emails'][1]['value']).to eql('added_over_original@test.com')
1442
1458
  end
1443
1459
 
1444
1460
  it 'multiple matches: overwrites all' do
@@ -1454,18 +1470,18 @@ RSpec.describe Scimitar::Resources::Mixin do
1454
1470
  'value' => 'work_2@test.com'
1455
1471
  }
1456
1472
  ]
1457
- }
1473
+ }.with_indifferent_case_insensitive_access()
1458
1474
 
1459
1475
  @instance.send(
1460
1476
  :from_patch_backend!,
1461
1477
  nature: 'replace',
1462
1478
  path: path,
1463
- value: 'added_over_origina@test.com',
1479
+ value: 'added_over_original@test.com',
1464
1480
  altering_hash: scim_hash
1465
1481
  )
1466
1482
 
1467
- expect(scim_hash['emails'][0]['value']).to eql('added_over_origina@test.com')
1468
- expect(scim_hash['emails'][1]['value']).to eql('added_over_origina@test.com')
1483
+ expect(scim_hash['emails'][0]['value']).to eql('added_over_original@test.com')
1484
+ expect(scim_hash['emails'][1]['value']).to eql('added_over_original@test.com')
1469
1485
  end
1470
1486
  end # "context 'with filter mid-path' do"
1471
1487
 
@@ -1483,7 +1499,7 @@ RSpec.describe Scimitar::Resources::Mixin do
1483
1499
  'value' => 'work@test.com'
1484
1500
  }
1485
1501
  ]
1486
- }
1502
+ }.with_indifferent_case_insensitive_access()
1487
1503
 
1488
1504
  @instance.send(
1489
1505
  :from_patch_backend!,
@@ -1517,7 +1533,7 @@ RSpec.describe Scimitar::Resources::Mixin do
1517
1533
  'value' => 'home@test.com'
1518
1534
  },
1519
1535
  ]
1520
- }
1536
+ }.with_indifferent_case_insensitive_access()
1521
1537
 
1522
1538
  @instance.send(
1523
1539
  :from_patch_backend!,
@@ -1546,7 +1562,7 @@ RSpec.describe Scimitar::Resources::Mixin do
1546
1562
  'value' => 'home@test.com'
1547
1563
  }
1548
1564
  ]
1549
- }
1565
+ }.with_indifferent_case_insensitive_access()
1550
1566
 
1551
1567
  @instance.send(
1552
1568
  :from_patch_backend!,
@@ -1565,7 +1581,7 @@ RSpec.describe Scimitar::Resources::Mixin do
1565
1581
  context 'when value is not present' do
1566
1582
  it 'simple value: adds' do
1567
1583
  path = [ 'userName' ]
1568
- scim_hash = {}
1584
+ scim_hash = {}.with_indifferent_case_insensitive_access()
1569
1585
 
1570
1586
  @instance.send(
1571
1587
  :from_patch_backend!,
@@ -1580,7 +1596,7 @@ RSpec.describe Scimitar::Resources::Mixin do
1580
1596
 
1581
1597
  it 'nested simple value: adds' do
1582
1598
  path = [ 'name', 'givenName' ]
1583
- scim_hash = {}
1599
+ scim_hash = {}.with_indifferent_case_insensitive_access()
1584
1600
 
1585
1601
  @instance.send(
1586
1602
  :from_patch_backend!,
@@ -1606,7 +1622,7 @@ RSpec.describe Scimitar::Resources::Mixin do
1606
1622
  'type' => 'work'
1607
1623
  }
1608
1624
  ]
1609
- }
1625
+ }.with_indifferent_case_insensitive_access()
1610
1626
 
1611
1627
  @instance.send(
1612
1628
  :from_patch_backend!,
@@ -1631,7 +1647,7 @@ RSpec.describe Scimitar::Resources::Mixin do
1631
1647
  'primary' => true
1632
1648
  }
1633
1649
  ]
1634
- }
1650
+ }.with_indifferent_case_insensitive_access()
1635
1651
 
1636
1652
  @instance.send(
1637
1653
  :from_patch_backend!,
@@ -1656,7 +1672,7 @@ RSpec.describe Scimitar::Resources::Mixin do
1656
1672
  'type' => 'work'
1657
1673
  }
1658
1674
  ]
1659
- }
1675
+ }.with_indifferent_case_insensitive_access()
1660
1676
 
1661
1677
  @instance.send(
1662
1678
  :from_patch_backend!,
@@ -1674,7 +1690,7 @@ RSpec.describe Scimitar::Resources::Mixin do
1674
1690
  context 'with filter at end of path' do
1675
1691
  it 'by string match: adds item' do
1676
1692
  path = [ 'emails[type eq "work"]' ]
1677
- scim_hash = {}
1693
+ scim_hash = {}.with_indifferent_case_insensitive_access()
1678
1694
 
1679
1695
  @instance.send(
1680
1696
  :from_patch_backend!,
@@ -1698,7 +1714,7 @@ RSpec.describe Scimitar::Resources::Mixin do
1698
1714
  'primary' => false
1699
1715
  }
1700
1716
  ]
1701
- }
1717
+ }.with_indifferent_case_insensitive_access()
1702
1718
 
1703
1719
  @instance.send(
1704
1720
  :from_patch_backend!,
@@ -1717,7 +1733,7 @@ RSpec.describe Scimitar::Resources::Mixin do
1717
1733
 
1718
1734
  it 'with arrays: replaces' do
1719
1735
  path = [ 'emails' ]
1720
- scim_hash = {}
1736
+ scim_hash = {}.with_indifferent_case_insensitive_access()
1721
1737
 
1722
1738
  @instance.send(
1723
1739
  :from_patch_backend!,
@@ -1838,7 +1854,7 @@ RSpec.describe Scimitar::Resources::Mixin do
1838
1854
  end
1839
1855
 
1840
1856
  it 'adds across multiple deep matching points' do
1841
- scim_hash = @original_hash.deep_dup()
1857
+ scim_hash = @original_hash.deep_dup().with_indifferent_case_insensitive_access()
1842
1858
  contrived_instance = @contrived_class.new
1843
1859
  contrived_instance.send(
1844
1860
  :from_patch_backend!,
@@ -1861,7 +1877,7 @@ RSpec.describe Scimitar::Resources::Mixin do
1861
1877
  end
1862
1878
 
1863
1879
  it 'replaces across multiple deep matching points' do
1864
- scim_hash = @original_hash.deep_dup()
1880
+ scim_hash = @original_hash.deep_dup().with_indifferent_case_insensitive_access()
1865
1881
  contrived_instance = @contrived_class.new
1866
1882
  contrived_instance.send(
1867
1883
  :from_patch_backend!,
@@ -1886,7 +1902,7 @@ RSpec.describe Scimitar::Resources::Mixin do
1886
1902
  end
1887
1903
 
1888
1904
  it 'removes across multiple deep matching points' do
1889
- scim_hash = @original_hash.deep_dup()
1905
+ scim_hash = @original_hash.deep_dup().with_indifferent_case_insensitive_access()
1890
1906
  contrived_instance = @contrived_class.new
1891
1907
  contrived_instance.send(
1892
1908
  :from_patch_backend!,
@@ -1928,7 +1944,7 @@ RSpec.describe Scimitar::Resources::Mixin do
1928
1944
  'value' => 'work_2@test.com'
1929
1945
  }
1930
1946
  ]
1931
- }
1947
+ }.with_indifferent_case_insensitive_access()
1932
1948
 
1933
1949
  expect do
1934
1950
  @instance.send(
@@ -1945,7 +1961,7 @@ RSpec.describe Scimitar::Resources::Mixin do
1945
1961
  path = [ 'userName[type eq "work"]', 'value' ]
1946
1962
  scim_hash = {
1947
1963
  'userName' => '1234'
1948
- }
1964
+ }.with_indifferent_case_insensitive_access()
1949
1965
 
1950
1966
  expect do
1951
1967
  @instance.send(
@@ -1965,7 +1981,7 @@ RSpec.describe Scimitar::Resources::Mixin do
1965
1981
  'work_1@test.com',
1966
1982
  'work_2@test.com',
1967
1983
  ]
1968
- }
1984
+ }.with_indifferent_case_insensitive_access()
1969
1985
 
1970
1986
  expect do
1971
1987
  @instance.send(
@@ -1986,166 +2002,202 @@ RSpec.describe Scimitar::Resources::Mixin do
1986
2002
  # -------------------------------------------------------------------
1987
2003
  #
1988
2004
  context 'public interface' do
1989
- it 'updates simple values' do
1990
- @instance.update!(username: 'foo')
2005
+ shared_examples 'a patcher' do | force_upper_case: |
2006
+ it 'which updates simple values' do
2007
+ @instance.update!(username: 'foo')
2008
+
2009
+ path = 'userName'
2010
+ path = path.upcase if force_upper_case
2011
+
2012
+ patch = {
2013
+ 'schemas' => ['urn:ietf:params:scim:api:messages:2.0:PatchOp'],
2014
+ 'Operations' => [
2015
+ {
2016
+ 'op' => 'replace',
2017
+ 'path' => path,
2018
+ 'value' => '1234'
2019
+ }
2020
+ ]
2021
+ }
1991
2022
 
1992
- patch = {
1993
- 'schemas' => ['urn:ietf:params:scim:api:messages:2.0:PatchOp'],
1994
- 'Operations' => [
1995
- {
1996
- 'op' => 'replace',
1997
- 'path' => 'userName',
1998
- 'value' => '1234'
1999
- }
2000
- ]
2001
- }
2023
+ @instance.from_scim_patch!(patch_hash: patch)
2024
+ expect(@instance.username).to eql('1234')
2025
+ end
2002
2026
 
2003
- @instance.from_scim_patch!(patch_hash: patch)
2004
- expect(@instance.username).to eql('1234')
2005
- end
2027
+ it 'which updates nested values' do
2028
+ @instance.update!(first_name: 'Foo', last_name: 'Bar')
2006
2029
 
2007
- it 'updates nested values' do
2008
- @instance.update!(first_name: 'Foo', last_name: 'Bar')
2030
+ path = 'name.givenName'
2031
+ path = path.upcase if force_upper_case
2009
2032
 
2010
- patch = {
2011
- 'schemas' => ['urn:ietf:params:scim:api:messages:2.0:PatchOp'],
2012
- 'Operations' => [
2013
- {
2014
- 'op' => 'replace',
2015
- 'path' => 'name.givenName',
2016
- 'value' => 'Baz'
2017
- }
2018
- ]
2019
- }
2033
+ patch = {
2034
+ 'schemas' => ['urn:ietf:params:scim:api:messages:2.0:PatchOp'],
2035
+ 'Operations' => [
2036
+ {
2037
+ 'op' => 'replace',
2038
+ 'path' => path,
2039
+ 'value' => 'Baz'
2040
+ }
2041
+ ]
2042
+ }
2020
2043
 
2021
- @instance.from_scim_patch!(patch_hash: patch)
2022
- expect(@instance.first_name).to eql('Baz')
2023
- end
2044
+ @instance.from_scim_patch!(patch_hash: patch)
2045
+ expect(@instance.first_name).to eql('Baz')
2046
+ end
2024
2047
 
2025
- it 'updates with filter match' do
2026
- @instance.update!(work_email_address: 'work@test.com', home_email_address: 'home@test.com')
2048
+ it 'which updates with filter match' do
2049
+ @instance.update!(work_email_address: 'work@test.com', home_email_address: 'home@test.com')
2027
2050
 
2028
- patch = {
2029
- 'schemas' => ['urn:ietf:params:scim:api:messages:2.0:PatchOp'],
2030
- 'Operations' => [
2031
- {
2032
- 'op' => 'replace',
2033
- 'path' => 'emails[type eq "work"].value',
2034
- 'value' => 'replaced@test.com'
2035
- }
2036
- ]
2037
- }
2051
+ filter_prefix = 'emails[type'
2052
+ filter_prefix = filter_prefix.upcase if force_upper_case
2038
2053
 
2039
- @instance.from_scim_patch!(patch_hash: patch)
2040
- expect(@instance.work_email_address).to eql('replaced@test.com')
2041
- expect(@instance.home_email_address).to eql('home@test.com')
2042
- end
2054
+ patch = {
2055
+ 'schemas' => ['urn:ietf:params:scim:api:messages:2.0:PatchOp'],
2056
+ 'Operations' => [
2057
+ {
2058
+ 'op' => 'replace',
2059
+ 'path' => filter_prefix + ' eq "work"].value',
2060
+ 'value' => 'replaced@test.com'
2061
+ }
2062
+ ]
2063
+ }
2043
2064
 
2044
- it 'appends e-mails' do
2045
- @instance.update!(work_email_address: 'work@test.com')
2065
+ @instance.from_scim_patch!(patch_hash: patch)
2066
+ expect(@instance.work_email_address).to eql('replaced@test.com')
2067
+ expect(@instance.home_email_address).to eql('home@test.com')
2068
+ end
2046
2069
 
2047
- patch = {
2048
- 'schemas' => ['urn:ietf:params:scim:api:messages:2.0:PatchOp'],
2049
- 'Operations' => [
2050
- {
2051
- 'op' => 'add',
2052
- 'path' => 'emails[type eq "home"].value',
2053
- 'value' => 'home@test.com'
2054
- }
2055
- ]
2056
- }
2070
+ it 'which appends e-mails' do
2071
+ @instance.update!(work_email_address: 'work@test.com')
2057
2072
 
2058
- @instance.from_scim_patch!(patch_hash: patch)
2059
- expect(@instance.work_email_address).to eql('work@test.com')
2060
- expect(@instance.home_email_address).to eql('home@test.com')
2061
- end
2073
+ filter_prefix = 'emails[type'
2074
+ filter_prefix = filter_prefix.upcase if force_upper_case
2062
2075
 
2063
- it 'removes e-mails' do
2064
- @instance.update!(work_email_address: 'work@test.com', home_email_address: 'home@test.com')
2076
+ patch = {
2077
+ 'schemas' => ['urn:ietf:params:scim:api:messages:2.0:PatchOp'],
2078
+ 'Operations' => [
2079
+ {
2080
+ 'op' => 'add',
2081
+ 'path' => filter_prefix + ' eq "home"].value',
2082
+ 'value' => 'home@test.com'
2083
+ }
2084
+ ]
2085
+ }
2065
2086
 
2066
- patch = {
2067
- 'schemas' => ['urn:ietf:params:scim:api:messages:2.0:PatchOp'],
2068
- 'Operations' => [
2069
- {
2070
- 'op' => 'remove',
2071
- 'path' => 'emails[type eq "home"]'
2072
- }
2073
- ]
2074
- }
2087
+ @instance.from_scim_patch!(patch_hash: patch)
2088
+ expect(@instance.work_email_address).to eql('work@test.com')
2089
+ expect(@instance.home_email_address).to eql('home@test.com')
2090
+ end
2075
2091
 
2076
- @instance.from_scim_patch!(patch_hash: patch)
2077
- expect(@instance.work_email_address).to eql('work@test.com')
2078
- expect(@instance.home_email_address).to be_nil
2079
- end
2092
+ it 'which removes e-mails' do
2093
+ @instance.update!(work_email_address: 'work@test.com', home_email_address: 'home@test.com')
2080
2094
 
2081
- it 'can patch the whole object' do
2082
- @instance.update!(username: 'foo')
2095
+ filter_prefix = 'emails[type'
2096
+ filter_prefix = filter_prefix.upcase if force_upper_case
2083
2097
 
2084
- patch = {
2085
- 'schemas' => ['urn:ietf:params:scim:api:messages:2.0:PatchOp'],
2086
- 'Operations' => [
2087
- {
2088
- 'op' => 'replace',
2089
- 'value' => {'userName' => '1234', 'name' => {'givenName' => 'Bar'}}
2090
- }
2091
- ]
2092
- }
2098
+ patch = {
2099
+ 'schemas' => ['urn:ietf:params:scim:api:messages:2.0:PatchOp'],
2100
+ 'Operations' => [
2101
+ {
2102
+ 'op' => 'remove',
2103
+ 'path' => filter_prefix + ' eq "home"].value',
2104
+ }
2105
+ ]
2106
+ }
2093
2107
 
2094
- @instance.from_scim_patch!(patch_hash: patch)
2095
- expect(@instance.username).to eql('1234')
2096
- expect(@instance.first_name).to eql('Bar')
2097
- end
2108
+ @instance.from_scim_patch!(patch_hash: patch)
2109
+ expect(@instance.work_email_address).to eql('work@test.com')
2110
+ expect(@instance.home_email_address).to be_nil
2111
+ end
2098
2112
 
2099
- it 'treats operation types as case-insensitive' do
2100
- @instance.update!(username: 'foo')
2113
+ it 'which can patch the whole object' do
2114
+ @instance.update!(username: 'foo')
2101
2115
 
2102
- patch = {
2103
- 'schemas' => ['urn:ietf:params:scim:api:messages:2.0:PatchOp'],
2104
- 'Operations' => [
2105
- {
2106
- 'op' => 'REPLACE', # Note upper case
2107
- 'path' => 'userName',
2108
- 'value' => '1234'
2116
+ hash = {
2117
+ 'userName' => '1234',
2118
+ 'name' => {
2119
+ 'givenName' => 'Bar'
2109
2120
  }
2110
- ]
2111
- }
2121
+ }
2112
2122
 
2113
- @instance.from_scim_patch!(patch_hash: patch)
2114
- expect(@instance.username).to eql('1234')
2115
- end
2123
+ hash = spec_helper_hupcase(hash) if force_upper_case
2116
2124
 
2117
- it 'complains about bad operation types' do
2118
- patch = {
2119
- 'schemas' => ['urn:ietf:params:scim:api:messages:2.0:PatchOp'],
2120
- 'Operations' => [
2121
- {
2122
- 'op' => 'invalidop',
2123
- 'path' => 'userName',
2124
- 'value' => '1234'
2125
- }
2126
- ]
2127
- }
2125
+ patch = {
2126
+ 'schemas' => ['urn:ietf:params:scim:api:messages:2.0:PatchOp'],
2127
+ 'Operations' => [
2128
+ {
2129
+ 'op' => 'replace',
2130
+ 'value' => hash
2131
+ }
2132
+ ]
2133
+ }
2128
2134
 
2129
- expect { @instance.from_scim_patch!(patch_hash: patch) }.to raise_error(Scimitar::ErrorResponse) do |e|
2130
- expect(e.as_json['scimType']).to eql('invalidSyntax')
2131
- expect(e.as_json[:detail ]).to include('invalidop')
2135
+ @instance.from_scim_patch!(patch_hash: patch)
2136
+ expect(@instance.username).to eql('1234')
2137
+ expect(@instance.first_name).to eql('Bar')
2132
2138
  end
2133
- end
2139
+ end # "shared_examples 'a patcher' do | force_upper_case: |"
2134
2140
 
2135
- it 'complains about a missing target for "remove" operations' do
2136
- patch = {
2137
- 'schemas' => ['urn:ietf:params:scim:api:messages:2.0:PatchOp'],
2138
- 'Operations' => [
2139
- {
2140
- 'op' => 'remove'
2141
- }
2142
- ]
2143
- }
2141
+ context 'using schema-matched case' do
2142
+ it_behaves_like 'a patcher', force_upper_case: false
2143
+ end # "context 'using schema-matched case' do"
2144
+
2145
+ context 'using upper case' do
2146
+ it_behaves_like 'a patcher', force_upper_case: true
2144
2147
 
2145
- expect { @instance.from_scim_patch!(patch_hash: patch) }.to raise_error(Scimitar::ErrorResponse) do |e|
2146
- expect(e.as_json['scimType']).to eql('noTarget')
2148
+ it 'treats operation types as case-insensitive' do
2149
+ @instance.update!(username: 'foo')
2150
+
2151
+ patch = {
2152
+ 'schemas' => ['urn:ietf:params:scim:api:messages:2.0:PatchOp'],
2153
+ 'Operations' => [
2154
+ {
2155
+ 'op' => 'REPLACE', # Note upper case
2156
+ 'path' => 'userName',
2157
+ 'value' => '1234'
2158
+ }
2159
+ ]
2160
+ }
2161
+
2162
+ @instance.from_scim_patch!(patch_hash: patch)
2163
+ expect(@instance.username).to eql('1234')
2147
2164
  end
2148
- end
2165
+ end # "context 'using upper case' do"
2166
+
2167
+ context 'with errors' do
2168
+ it 'complains about bad operation types' do
2169
+ patch = {
2170
+ 'schemas' => ['urn:ietf:params:scim:api:messages:2.0:PatchOp'],
2171
+ 'Operations' => [
2172
+ {
2173
+ 'op' => 'invalidop',
2174
+ 'path' => 'userName',
2175
+ 'value' => '1234'
2176
+ }
2177
+ ]
2178
+ }
2179
+
2180
+ expect { @instance.from_scim_patch!(patch_hash: patch) }.to raise_error(Scimitar::ErrorResponse) do |e|
2181
+ expect(e.as_json['scimType']).to eql('invalidSyntax')
2182
+ expect(e.as_json[:detail ]).to include('invalidop')
2183
+ end
2184
+ end
2185
+
2186
+ it 'complains about a missing target for "remove" operations' do
2187
+ patch = {
2188
+ 'schemas' => ['urn:ietf:params:scim:api:messages:2.0:PatchOp'],
2189
+ 'Operations' => [
2190
+ {
2191
+ 'op' => 'remove'
2192
+ }
2193
+ ]
2194
+ }
2195
+
2196
+ expect { @instance.from_scim_patch!(patch_hash: patch) }.to raise_error(Scimitar::ErrorResponse) do |e|
2197
+ expect(e.as_json['scimType']).to eql('noTarget')
2198
+ end
2199
+ end
2200
+ end # "context 'with errors' do"
2149
2201
  end # "context 'public interface' do"
2150
2202
  end # "context '#from_scim_patch!' do"
2151
2203
  end # "context 'with good class definitons' do"