scimitar 1.0.3 → 2.0.0

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.
@@ -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"