scimitar 1.0.1 → 1.2.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.
- checksums.yaml +4 -4
- data/app/controllers/scimitar/active_record_backed_resources_controller.rb +2 -2
- data/app/models/scimitar/complex_types/base.rb +43 -1
- data/app/models/scimitar/resources/base.rb +22 -4
- data/app/models/scimitar/resources/mixin.rb +52 -29
- data/app/models/scimitar/schema/base.rb +3 -1
- data/lib/scimitar/support/hash_with_indifferent_case_insensitive_access.rb +86 -0
- data/lib/scimitar/version.rb +2 -2
- data/lib/scimitar.rb +1 -0
- data/spec/models/scimitar/resources/base_spec.rb +108 -58
- data/spec/models/scimitar/resources/mixin_spec.rb +342 -265
- data/spec/models/scimitar/resources/user_spec.rb +13 -0
- data/spec/requests/active_record_backed_resources_controller_spec.rb +172 -127
- data/spec/requests/engine_spec.rb +26 -1
- data/spec/spec_helper.rb +27 -0
- data/spec/spec_helper_spec.rb +30 -0
- data/spec/support/hash_with_indifferent_case_insensitive_access_spec.rb +61 -0
- metadata +22 -28
| @@ -363,78 +363,94 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 363 363 | 
             
                # =========================================================================
         | 
| 364 364 |  | 
| 365 365 | 
             
                context '#from_scim!' do
         | 
| 366 | 
            -
                   | 
| 367 | 
            -
                     | 
| 368 | 
            -
                       | 
| 369 | 
            -
                         | 
| 370 | 
            -
             | 
| 371 | 
            -
             | 
| 372 | 
            -
             | 
| 373 | 
            -
             | 
| 374 | 
            -
             | 
| 375 | 
            -
             | 
| 376 | 
            -
             | 
| 377 | 
            -
             | 
| 378 | 
            -
             | 
| 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 | 
            -
             | 
| 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 | 
            -
             | 
| 395 | 
            -
             | 
| 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 | 
            -
                       | 
| 414 | 
            -
             | 
| 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 | 
            -
                       | 
| 417 | 
            -
             | 
| 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 | 
            -
             | 
| 422 | 
            -
             | 
| 423 | 
            -
             | 
| 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 | 
            -
             | 
| 426 | 
            -
             | 
| 427 | 
            -
             | 
| 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 | 
            -
             | 
| 431 | 
            -
                      instance.from_scim!(scim_hash: hash)
         | 
| 416 | 
            +
                        hash = spec_helper_hupcase(hash) if force_upper_case
         | 
| 432 417 |  | 
| 433 | 
            -
             | 
| 434 | 
            -
             | 
| 435 | 
            -
             | 
| 436 | 
            -
             | 
| 437 | 
            -
             | 
| 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
         | 
| @@ -522,6 +538,22 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 522 538 | 
             
                        end.to raise_error(RuntimeError)
         | 
| 523 539 | 
             
                      end
         | 
| 524 540 |  | 
| 541 | 
            +
                      it 'complaints about unsupported multiple operators, handling value spaces' do
         | 
| 542 | 
            +
                        expect do
         | 
| 543 | 
            +
                          @instance.send(:all_matching_filter, filter: 'type eq "work with spaces" and primary pr', within_array: []) do
         | 
| 544 | 
            +
                            fail # Block should never be called!
         | 
| 545 | 
            +
                          end
         | 
| 546 | 
            +
                        end.to raise_error(RuntimeError)
         | 
| 547 | 
            +
                      end
         | 
| 548 | 
            +
             | 
| 549 | 
            +
                      it 'complaints about unquoted values with spaces' do
         | 
| 550 | 
            +
                        expect do
         | 
| 551 | 
            +
                          @instance.send(:all_matching_filter, filter: 'type eq work with spaces', within_array: []) do
         | 
| 552 | 
            +
                            fail # Block should never be called!
         | 
| 553 | 
            +
                          end
         | 
| 554 | 
            +
                        end.to raise_error(RuntimeError)
         | 
| 555 | 
            +
                      end
         | 
| 556 | 
            +
             | 
| 525 557 | 
             
                      it 'calls block with matches' do
         | 
| 526 558 | 
             
                        array = [
         | 
| 527 559 | 
             
                          {
         | 
| @@ -565,6 +597,10 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 565 597 | 
             
                          {
         | 
| 566 598 | 
             
                            'type'  => 'work"',
         | 
| 567 599 | 
             
                            'value' => 'work_trailing_dquote@test.com'
         | 
| 600 | 
            +
                          },
         | 
| 601 | 
            +
                          {
         | 
| 602 | 
            +
                            'type'  => 'spaced',
         | 
| 603 | 
            +
                            'value' => 'value with spaces'
         | 
| 568 604 | 
             
                          }
         | 
| 569 605 | 
             
                        ]
         | 
| 570 606 |  | 
| @@ -585,7 +621,12 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 585 621 | 
             
                          expect(matched_hash['value']).to eql('boolean@test.com')
         | 
| 586 622 | 
             
                        end
         | 
| 587 623 |  | 
| 588 | 
            -
                         | 
| 624 | 
            +
                        @instance.send(:all_matching_filter, filter: 'value eq "value with spaces"', within_array: array) do |matched_hash, index|
         | 
| 625 | 
            +
                          call_count += 1
         | 
| 626 | 
            +
                          expect(matched_hash['type']).to eql('spaced')
         | 
| 627 | 
            +
                        end
         | 
| 628 | 
            +
             | 
| 629 | 
            +
                        expect(call_count).to eql(4)
         | 
| 589 630 | 
             
                      end
         | 
| 590 631 | 
             
                    end # "context '#all_matching_filter' do"
         | 
| 591 632 |  | 
| @@ -606,7 +647,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 606 647 | 
             
                        context 'when prior value already exists' do
         | 
| 607 648 | 
             
                          it 'simple value: overwrites' do
         | 
| 608 649 | 
             
                            path      = [ 'userName' ]
         | 
| 609 | 
            -
                            scim_hash = { 'userName' => 'bar' }
         | 
| 650 | 
            +
                            scim_hash = { 'userName' => 'bar' }.with_indifferent_case_insensitive_access()
         | 
| 610 651 |  | 
| 611 652 | 
             
                            @instance.send(
         | 
| 612 653 | 
             
                              :from_patch_backend!,
         | 
| @@ -621,7 +662,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 621 662 |  | 
| 622 663 | 
             
                          it 'nested simple value: overwrites' do
         | 
| 623 664 | 
             
                            path      = [ 'name', 'givenName' ]
         | 
| 624 | 
            -
                            scim_hash = { 'name' => { 'givenName' => 'Foo', 'familyName' => 'Bar' } }
         | 
| 665 | 
            +
                            scim_hash = { 'name' => { 'givenName' => 'Foo', 'familyName' => 'Bar' } }.with_indifferent_case_insensitive_access()
         | 
| 625 666 |  | 
| 626 667 | 
             
                            @instance.send(
         | 
| 627 668 | 
             
                              :from_patch_backend!,
         | 
| @@ -652,18 +693,18 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 652 693 | 
             
                                    'value' => 'work@test.com'
         | 
| 653 694 | 
             
                                  }
         | 
| 654 695 | 
             
                                ]
         | 
| 655 | 
            -
                              }
         | 
| 696 | 
            +
                              }.with_indifferent_case_insensitive_access()
         | 
| 656 697 |  | 
| 657 698 | 
             
                              @instance.send(
         | 
| 658 699 | 
             
                                :from_patch_backend!,
         | 
| 659 700 | 
             
                                nature:        'add',
         | 
| 660 701 | 
             
                                path:          path,
         | 
| 661 | 
            -
                                value:         ' | 
| 702 | 
            +
                                value:         'added_over_original@test.com',
         | 
| 662 703 | 
             
                                altering_hash: scim_hash
         | 
| 663 704 | 
             
                              )
         | 
| 664 705 |  | 
| 665 706 | 
             
                              expect(scim_hash['emails'][0]['value']).to eql('home@test.com')
         | 
| 666 | 
            -
                              expect(scim_hash['emails'][1]['value']).to eql(' | 
| 707 | 
            +
                              expect(scim_hash['emails'][1]['value']).to eql('added_over_original@test.com')
         | 
| 667 708 | 
             
                            end
         | 
| 668 709 |  | 
| 669 710 | 
             
                            it 'by boolean match: overwrites' do
         | 
| @@ -678,18 +719,18 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 678 719 | 
             
                                    'primary' => true
         | 
| 679 720 | 
             
                                  }
         | 
| 680 721 | 
             
                                ]
         | 
| 681 | 
            -
                              }
         | 
| 722 | 
            +
                              }.with_indifferent_case_insensitive_access()
         | 
| 682 723 |  | 
| 683 724 | 
             
                              @instance.send(
         | 
| 684 725 | 
             
                                :from_patch_backend!,
         | 
| 685 726 | 
             
                                nature:        'add',
         | 
| 686 727 | 
             
                                path:          path,
         | 
| 687 | 
            -
                                value:         ' | 
| 728 | 
            +
                                value:         'added_over_original@test.com',
         | 
| 688 729 | 
             
                                altering_hash: scim_hash
         | 
| 689 730 | 
             
                              )
         | 
| 690 731 |  | 
| 691 732 | 
             
                              expect(scim_hash['emails'][0]['value']).to eql('home@test.com')
         | 
| 692 | 
            -
                              expect(scim_hash['emails'][1]['value']).to eql(' | 
| 733 | 
            +
                              expect(scim_hash['emails'][1]['value']).to eql('added_over_original@test.com')
         | 
| 693 734 | 
             
                            end
         | 
| 694 735 |  | 
| 695 736 | 
             
                            it 'multiple matches: overwrites all' do
         | 
| @@ -705,18 +746,18 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 705 746 | 
             
                                    'value' => 'work_2@test.com'
         | 
| 706 747 | 
             
                                  }
         | 
| 707 748 | 
             
                                ]
         | 
| 708 | 
            -
                              }
         | 
| 749 | 
            +
                              }.with_indifferent_case_insensitive_access()
         | 
| 709 750 |  | 
| 710 751 | 
             
                              @instance.send(
         | 
| 711 752 | 
             
                                :from_patch_backend!,
         | 
| 712 753 | 
             
                                nature:        'add',
         | 
| 713 754 | 
             
                                path:          path,
         | 
| 714 | 
            -
                                value:         ' | 
| 755 | 
            +
                                value:         'added_over_original@test.com',
         | 
| 715 756 | 
             
                                altering_hash: scim_hash
         | 
| 716 757 | 
             
                              )
         | 
| 717 758 |  | 
| 718 | 
            -
                              expect(scim_hash['emails'][0]['value']).to eql(' | 
| 719 | 
            -
                              expect(scim_hash['emails'][1]['value']).to eql(' | 
| 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')
         | 
| 720 761 | 
             
                            end
         | 
| 721 762 | 
             
                          end # "context 'with filter mid-path' do"
         | 
| 722 763 |  | 
| @@ -729,7 +770,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 729 770 | 
             
                                  'value' => 'home@test.com'
         | 
| 730 771 | 
             
                                }
         | 
| 731 772 | 
             
                              ]
         | 
| 732 | 
            -
                            }
         | 
| 773 | 
            +
                            }.with_indifferent_case_insensitive_access()
         | 
| 733 774 |  | 
| 734 775 | 
             
                            @instance.send(
         | 
| 735 776 | 
             
                              :from_patch_backend!,
         | 
| @@ -753,7 +794,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 753 794 | 
             
                                    {'value' => '2'}
         | 
| 754 795 | 
             
                                  ]
         | 
| 755 796 | 
             
                                }
         | 
| 756 | 
            -
                              }
         | 
| 797 | 
            +
                              }.with_indifferent_case_insensitive_access()
         | 
| 757 798 |  | 
| 758 799 | 
             
                              # Example seen at:
         | 
| 759 800 | 
             
                              #
         | 
| @@ -795,7 +836,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 795 836 | 
             
                        context 'when value is not present' do
         | 
| 796 837 | 
             
                          it 'simple value: adds' do
         | 
| 797 838 | 
             
                            path      = [ 'userName' ]
         | 
| 798 | 
            -
                            scim_hash = {}
         | 
| 839 | 
            +
                            scim_hash = {}.with_indifferent_case_insensitive_access()
         | 
| 799 840 |  | 
| 800 841 | 
             
                            @instance.send(
         | 
| 801 842 | 
             
                              :from_patch_backend!,
         | 
| @@ -810,7 +851,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 810 851 |  | 
| 811 852 | 
             
                          it 'nested simple value: adds' do
         | 
| 812 853 | 
             
                            path      = [ 'name', 'givenName' ]
         | 
| 813 | 
            -
                            scim_hash = {}
         | 
| 854 | 
            +
                            scim_hash = {}.with_indifferent_case_insensitive_access()
         | 
| 814 855 |  | 
| 815 856 | 
             
                            @instance.send(
         | 
| 816 857 | 
             
                              :from_patch_backend!,
         | 
| @@ -836,7 +877,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 836 877 | 
             
                                    'type' => 'work'
         | 
| 837 878 | 
             
                                  }
         | 
| 838 879 | 
             
                                ]
         | 
| 839 | 
            -
                              }
         | 
| 880 | 
            +
                              }.with_indifferent_case_insensitive_access()
         | 
| 840 881 |  | 
| 841 882 | 
             
                              @instance.send(
         | 
| 842 883 | 
             
                                :from_patch_backend!,
         | 
| @@ -861,7 +902,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 861 902 | 
             
                                    'primary' => true
         | 
| 862 903 | 
             
                                  }
         | 
| 863 904 | 
             
                                ]
         | 
| 864 | 
            -
                              }
         | 
| 905 | 
            +
                              }.with_indifferent_case_insensitive_access()
         | 
| 865 906 |  | 
| 866 907 | 
             
                              @instance.send(
         | 
| 867 908 | 
             
                                :from_patch_backend!,
         | 
| @@ -877,7 +918,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 877 918 |  | 
| 878 919 | 
             
                            it 'with no match: still adds' do
         | 
| 879 920 | 
             
                              path      = [ 'emails[type eq "work"]', 'value' ]
         | 
| 880 | 
            -
                              scim_hash = {}
         | 
| 921 | 
            +
                              scim_hash = {}.with_indifferent_case_insensitive_access()
         | 
| 881 922 |  | 
| 882 923 | 
             
                              @instance.send(
         | 
| 883 924 | 
             
                                :from_patch_backend!,
         | 
| @@ -901,7 +942,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 901 942 | 
             
                                    'type' => 'work'
         | 
| 902 943 | 
             
                                  }
         | 
| 903 944 | 
             
                                ]
         | 
| 904 | 
            -
                              }
         | 
| 945 | 
            +
                              }.with_indifferent_case_insensitive_access()
         | 
| 905 946 |  | 
| 906 947 | 
             
                              @instance.send(
         | 
| 907 948 | 
             
                                :from_patch_backend!,
         | 
| @@ -918,7 +959,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 918 959 |  | 
| 919 960 | 
             
                          it 'with arrays: appends' do
         | 
| 920 961 | 
             
                            path      = [ 'emails' ]
         | 
| 921 | 
            -
                            scim_hash = {}
         | 
| 962 | 
            +
                            scim_hash = {}.with_indifferent_case_insensitive_access()
         | 
| 922 963 |  | 
| 923 964 | 
             
                            @instance.send(
         | 
| 924 965 | 
             
                              :from_patch_backend!,
         | 
| @@ -943,7 +984,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 943 984 | 
             
                        context 'when prior value already exists' do
         | 
| 944 985 | 
             
                          it 'simple value: removes' do
         | 
| 945 986 | 
             
                            path      = [ 'userName' ]
         | 
| 946 | 
            -
                            scim_hash = { 'userName' => 'bar' }
         | 
| 987 | 
            +
                            scim_hash = { 'userName' => 'bar' }.with_indifferent_case_insensitive_access()
         | 
| 947 988 |  | 
| 948 989 | 
             
                            @instance.send(
         | 
| 949 990 | 
             
                              :from_patch_backend!,
         | 
| @@ -958,7 +999,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 958 999 |  | 
| 959 1000 | 
             
                          it 'nested simple value: removes' do
         | 
| 960 1001 | 
             
                            path      = [ 'name', 'givenName' ]
         | 
| 961 | 
            -
                            scim_hash = { 'name' => { 'givenName' => 'Foo', 'familyName' => 'Bar' } }
         | 
| 1002 | 
            +
                            scim_hash = { 'name' => { 'givenName' => 'Foo', 'familyName' => 'Bar' } }.with_indifferent_case_insensitive_access()
         | 
| 962 1003 |  | 
| 963 1004 | 
             
                            @instance.send(
         | 
| 964 1005 | 
             
                              :from_patch_backend!,
         | 
| @@ -986,7 +1027,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 986 1027 | 
             
                                    'value' => 'work@test.com'
         | 
| 987 1028 | 
             
                                  }
         | 
| 988 1029 | 
             
                                ]
         | 
| 989 | 
            -
                              }
         | 
| 1030 | 
            +
                              }.with_indifferent_case_insensitive_access()
         | 
| 990 1031 |  | 
| 991 1032 | 
             
                              @instance.send(
         | 
| 992 1033 | 
             
                                :from_patch_backend!,
         | 
| @@ -1012,7 +1053,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 1012 1053 | 
             
                                    'primary' => true
         | 
| 1013 1054 | 
             
                                  }
         | 
| 1014 1055 | 
             
                                ]
         | 
| 1015 | 
            -
                              }
         | 
| 1056 | 
            +
                              }.with_indifferent_case_insensitive_access()
         | 
| 1016 1057 |  | 
| 1017 1058 | 
             
                              @instance.send(
         | 
| 1018 1059 | 
             
                                :from_patch_backend!,
         | 
| @@ -1039,7 +1080,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 1039 1080 | 
             
                                    'value' => 'work_2@test.com'
         | 
| 1040 1081 | 
             
                                  }
         | 
| 1041 1082 | 
             
                                ]
         | 
| 1042 | 
            -
                              }
         | 
| 1083 | 
            +
                              }.with_indifferent_case_insensitive_access()
         | 
| 1043 1084 |  | 
| 1044 1085 | 
             
                              @instance.send(
         | 
| 1045 1086 | 
             
                                :from_patch_backend!,
         | 
| @@ -1068,7 +1109,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 1068 1109 | 
             
                                    'value' => 'work@test.com'
         | 
| 1069 1110 | 
             
                                  }
         | 
| 1070 1111 | 
             
                                ]
         | 
| 1071 | 
            -
                              }
         | 
| 1112 | 
            +
                              }.with_indifferent_case_insensitive_access()
         | 
| 1072 1113 |  | 
| 1073 1114 | 
             
                              @instance.send(
         | 
| 1074 1115 | 
             
                                :from_patch_backend!,
         | 
| @@ -1094,7 +1135,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 1094 1135 | 
             
                                    'primary' => true
         | 
| 1095 1136 | 
             
                                  }
         | 
| 1096 1137 | 
             
                                ]
         | 
| 1097 | 
            -
                              }
         | 
| 1138 | 
            +
                              }.with_indifferent_case_insensitive_access()
         | 
| 1098 1139 |  | 
| 1099 1140 | 
             
                              @instance.send(
         | 
| 1100 1141 | 
             
                                :from_patch_backend!,
         | 
| @@ -1125,7 +1166,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 1125 1166 | 
             
                                    'value' => 'home@test.com'
         | 
| 1126 1167 | 
             
                                  },
         | 
| 1127 1168 | 
             
                                ]
         | 
| 1128 | 
            -
                              }
         | 
| 1169 | 
            +
                              }.with_indifferent_case_insensitive_access()
         | 
| 1129 1170 |  | 
| 1130 1171 | 
             
                              @instance.send(
         | 
| 1131 1172 | 
             
                                :from_patch_backend!,
         | 
| @@ -1149,7 +1190,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 1149 1190 | 
             
                                  'value' => 'home@test.com'
         | 
| 1150 1191 | 
             
                                }
         | 
| 1151 1192 | 
             
                              ]
         | 
| 1152 | 
            -
                            }
         | 
| 1193 | 
            +
                            }.with_indifferent_case_insensitive_access()
         | 
| 1153 1194 |  | 
| 1154 1195 | 
             
                            @instance.send(
         | 
| 1155 1196 | 
             
                              :from_patch_backend!,
         | 
| @@ -1166,7 +1207,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 1166 1207 | 
             
                        context 'when value is not present' do
         | 
| 1167 1208 | 
             
                          it 'simple value: does nothing' do
         | 
| 1168 1209 | 
             
                            path      = [ 'userName' ]
         | 
| 1169 | 
            -
                            scim_hash = {}
         | 
| 1210 | 
            +
                            scim_hash = {}.with_indifferent_case_insensitive_access()
         | 
| 1170 1211 |  | 
| 1171 1212 | 
             
                            @instance.send(
         | 
| 1172 1213 | 
             
                              :from_patch_backend!,
         | 
| @@ -1181,7 +1222,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 1181 1222 |  | 
| 1182 1223 | 
             
                          it 'nested simple value: does nothing' do
         | 
| 1183 1224 | 
             
                            path      = [ 'name', 'givenName' ]
         | 
| 1184 | 
            -
                            scim_hash = { 'name' => {'familyName' => 'Bar' } }
         | 
| 1225 | 
            +
                            scim_hash = { 'name' => {'familyName' => 'Bar' } }.with_indifferent_case_insensitive_access()
         | 
| 1185 1226 |  | 
| 1186 1227 | 
             
                            @instance.send(
         | 
| 1187 1228 | 
             
                              :from_patch_backend!,
         | 
| @@ -1205,7 +1246,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 1205 1246 | 
             
                                    'value' => 'home@test.com'
         | 
| 1206 1247 | 
             
                                  }
         | 
| 1207 1248 | 
             
                                ]
         | 
| 1208 | 
            -
                              }
         | 
| 1249 | 
            +
                              }.with_indifferent_case_insensitive_access()
         | 
| 1209 1250 |  | 
| 1210 1251 | 
             
                              @instance.send(
         | 
| 1211 1252 | 
             
                                :from_patch_backend!,
         | 
| @@ -1227,7 +1268,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 1227 1268 | 
             
                                    'value' => 'home@test.com'
         | 
| 1228 1269 | 
             
                                  }
         | 
| 1229 1270 | 
             
                                ]
         | 
| 1230 | 
            -
                              }
         | 
| 1271 | 
            +
                              }.with_indifferent_case_insensitive_access()
         | 
| 1231 1272 |  | 
| 1232 1273 | 
             
                              @instance.send(
         | 
| 1233 1274 | 
             
                                :from_patch_backend!,
         | 
| @@ -1250,7 +1291,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 1250 1291 | 
             
                                    'value' => 'home@test.com'
         | 
| 1251 1292 | 
             
                                  }
         | 
| 1252 1293 | 
             
                                ]
         | 
| 1253 | 
            -
                              }
         | 
| 1294 | 
            +
                              }.with_indifferent_case_insensitive_access()
         | 
| 1254 1295 |  | 
| 1255 1296 | 
             
                              @instance.send(
         | 
| 1256 1297 | 
             
                                :from_patch_backend!,
         | 
| @@ -1268,7 +1309,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 1268 1309 | 
             
                          context 'with filter at end of path' do
         | 
| 1269 1310 | 
             
                            it 'by string match: does nothing' do
         | 
| 1270 1311 | 
             
                              path      = [ 'emails[type eq "work"]' ]
         | 
| 1271 | 
            -
                              scim_hash = {}
         | 
| 1312 | 
            +
                              scim_hash = {}.with_indifferent_case_insensitive_access()
         | 
| 1272 1313 |  | 
| 1273 1314 | 
             
                              @instance.send(
         | 
| 1274 1315 | 
             
                                :from_patch_backend!,
         | 
| @@ -1290,7 +1331,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 1290 1331 | 
             
                                    'primary' => false
         | 
| 1291 1332 | 
             
                                  }
         | 
| 1292 1333 | 
             
                                ]
         | 
| 1293 | 
            -
                              }
         | 
| 1334 | 
            +
                              }.with_indifferent_case_insensitive_access()
         | 
| 1294 1335 |  | 
| 1295 1336 | 
             
                              @instance.send(
         | 
| 1296 1337 | 
             
                                :from_patch_backend!,
         | 
| @@ -1307,7 +1348,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 1307 1348 |  | 
| 1308 1349 | 
             
                          it 'remove whole array: does nothing' do
         | 
| 1309 1350 | 
             
                            path      = [ 'emails' ]
         | 
| 1310 | 
            -
                            scim_hash = {}
         | 
| 1351 | 
            +
                            scim_hash = {}.with_indifferent_case_insensitive_access()
         | 
| 1311 1352 |  | 
| 1312 1353 | 
             
                            @instance.send(
         | 
| 1313 1354 | 
             
                              :from_patch_backend!,
         | 
| @@ -1333,7 +1374,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 1333 1374 | 
             
                        context 'when prior value already exists' do
         | 
| 1334 1375 | 
             
                          it 'simple value: overwrites' do
         | 
| 1335 1376 | 
             
                            path      = [ 'userName' ]
         | 
| 1336 | 
            -
                            scim_hash = { 'userName' => 'bar' }
         | 
| 1377 | 
            +
                            scim_hash = { 'userName' => 'bar' }.with_indifferent_case_insensitive_access()
         | 
| 1337 1378 |  | 
| 1338 1379 | 
             
                            @instance.send(
         | 
| 1339 1380 | 
             
                              :from_patch_backend!,
         | 
| @@ -1348,7 +1389,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 1348 1389 |  | 
| 1349 1390 | 
             
                          it 'nested simple value: overwrites' do
         | 
| 1350 1391 | 
             
                            path      = [ 'name', 'givenName' ]
         | 
| 1351 | 
            -
                            scim_hash = { 'name' => { 'givenName' => 'Foo', 'familyName' => 'Bar' } }
         | 
| 1392 | 
            +
                            scim_hash = { 'name' => { 'givenName' => 'Foo', 'familyName' => 'Bar' } }.with_indifferent_case_insensitive_access()
         | 
| 1352 1393 |  | 
| 1353 1394 | 
             
                            @instance.send(
         | 
| 1354 1395 | 
             
                              :from_patch_backend!,
         | 
| @@ -1376,18 +1417,18 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 1376 1417 | 
             
                                    'value' => 'work@test.com'
         | 
| 1377 1418 | 
             
                                  }
         | 
| 1378 1419 | 
             
                                ]
         | 
| 1379 | 
            -
                              }
         | 
| 1420 | 
            +
                              }.with_indifferent_case_insensitive_access()
         | 
| 1380 1421 |  | 
| 1381 1422 | 
             
                              @instance.send(
         | 
| 1382 1423 | 
             
                                :from_patch_backend!,
         | 
| 1383 1424 | 
             
                                nature:        'replace',
         | 
| 1384 1425 | 
             
                                path:          path,
         | 
| 1385 | 
            -
                                value:         ' | 
| 1426 | 
            +
                                value:         'added_over_original@test.com',
         | 
| 1386 1427 | 
             
                                altering_hash: scim_hash
         | 
| 1387 1428 | 
             
                              )
         | 
| 1388 1429 |  | 
| 1389 1430 | 
             
                              expect(scim_hash['emails'][0]['value']).to eql('home@test.com')
         | 
| 1390 | 
            -
                              expect(scim_hash['emails'][1]['value']).to eql(' | 
| 1431 | 
            +
                              expect(scim_hash['emails'][1]['value']).to eql('added_over_original@test.com')
         | 
| 1391 1432 | 
             
                            end
         | 
| 1392 1433 |  | 
| 1393 1434 | 
             
                            it 'by boolean match: overwrites' do
         | 
| @@ -1402,18 +1443,18 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 1402 1443 | 
             
                                    'primary' => true
         | 
| 1403 1444 | 
             
                                  }
         | 
| 1404 1445 | 
             
                                ]
         | 
| 1405 | 
            -
                              }
         | 
| 1446 | 
            +
                              }.with_indifferent_case_insensitive_access()
         | 
| 1406 1447 |  | 
| 1407 1448 | 
             
                              @instance.send(
         | 
| 1408 1449 | 
             
                                :from_patch_backend!,
         | 
| 1409 1450 | 
             
                                nature:        'replace',
         | 
| 1410 1451 | 
             
                                path:          path,
         | 
| 1411 | 
            -
                                value:         ' | 
| 1452 | 
            +
                                value:         'added_over_original@test.com',
         | 
| 1412 1453 | 
             
                                altering_hash: scim_hash
         | 
| 1413 1454 | 
             
                              )
         | 
| 1414 1455 |  | 
| 1415 1456 | 
             
                              expect(scim_hash['emails'][0]['value']).to eql('home@test.com')
         | 
| 1416 | 
            -
                              expect(scim_hash['emails'][1]['value']).to eql(' | 
| 1457 | 
            +
                              expect(scim_hash['emails'][1]['value']).to eql('added_over_original@test.com')
         | 
| 1417 1458 | 
             
                            end
         | 
| 1418 1459 |  | 
| 1419 1460 | 
             
                            it 'multiple matches: overwrites all' do
         | 
| @@ -1429,18 +1470,18 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 1429 1470 | 
             
                                    'value' => 'work_2@test.com'
         | 
| 1430 1471 | 
             
                                  }
         | 
| 1431 1472 | 
             
                                ]
         | 
| 1432 | 
            -
                              }
         | 
| 1473 | 
            +
                              }.with_indifferent_case_insensitive_access()
         | 
| 1433 1474 |  | 
| 1434 1475 | 
             
                              @instance.send(
         | 
| 1435 1476 | 
             
                                :from_patch_backend!,
         | 
| 1436 1477 | 
             
                                nature:        'replace',
         | 
| 1437 1478 | 
             
                                path:          path,
         | 
| 1438 | 
            -
                                value:         ' | 
| 1479 | 
            +
                                value:         'added_over_original@test.com',
         | 
| 1439 1480 | 
             
                                altering_hash: scim_hash
         | 
| 1440 1481 | 
             
                              )
         | 
| 1441 1482 |  | 
| 1442 | 
            -
                              expect(scim_hash['emails'][0]['value']).to eql(' | 
| 1443 | 
            -
                              expect(scim_hash['emails'][1]['value']).to eql(' | 
| 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')
         | 
| 1444 1485 | 
             
                            end
         | 
| 1445 1486 | 
             
                          end # "context 'with filter mid-path' do"
         | 
| 1446 1487 |  | 
| @@ -1458,7 +1499,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 1458 1499 | 
             
                                    'value' => 'work@test.com'
         | 
| 1459 1500 | 
             
                                  }
         | 
| 1460 1501 | 
             
                                ]
         | 
| 1461 | 
            -
                              }
         | 
| 1502 | 
            +
                              }.with_indifferent_case_insensitive_access()
         | 
| 1462 1503 |  | 
| 1463 1504 | 
             
                              @instance.send(
         | 
| 1464 1505 | 
             
                                :from_patch_backend!,
         | 
| @@ -1492,7 +1533,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 1492 1533 | 
             
                                    'value' => 'home@test.com'
         | 
| 1493 1534 | 
             
                                  },
         | 
| 1494 1535 | 
             
                                ]
         | 
| 1495 | 
            -
                              }
         | 
| 1536 | 
            +
                              }.with_indifferent_case_insensitive_access()
         | 
| 1496 1537 |  | 
| 1497 1538 | 
             
                              @instance.send(
         | 
| 1498 1539 | 
             
                                :from_patch_backend!,
         | 
| @@ -1521,7 +1562,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 1521 1562 | 
             
                                  'value' => 'home@test.com'
         | 
| 1522 1563 | 
             
                                }
         | 
| 1523 1564 | 
             
                              ]
         | 
| 1524 | 
            -
                            }
         | 
| 1565 | 
            +
                            }.with_indifferent_case_insensitive_access()
         | 
| 1525 1566 |  | 
| 1526 1567 | 
             
                            @instance.send(
         | 
| 1527 1568 | 
             
                              :from_patch_backend!,
         | 
| @@ -1540,7 +1581,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 1540 1581 | 
             
                        context 'when value is not present' do
         | 
| 1541 1582 | 
             
                          it 'simple value: adds' do
         | 
| 1542 1583 | 
             
                            path      = [ 'userName' ]
         | 
| 1543 | 
            -
                            scim_hash = {}
         | 
| 1584 | 
            +
                            scim_hash = {}.with_indifferent_case_insensitive_access()
         | 
| 1544 1585 |  | 
| 1545 1586 | 
             
                            @instance.send(
         | 
| 1546 1587 | 
             
                              :from_patch_backend!,
         | 
| @@ -1555,7 +1596,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 1555 1596 |  | 
| 1556 1597 | 
             
                          it 'nested simple value: adds' do
         | 
| 1557 1598 | 
             
                            path      = [ 'name', 'givenName' ]
         | 
| 1558 | 
            -
                            scim_hash = {}
         | 
| 1599 | 
            +
                            scim_hash = {}.with_indifferent_case_insensitive_access()
         | 
| 1559 1600 |  | 
| 1560 1601 | 
             
                            @instance.send(
         | 
| 1561 1602 | 
             
                              :from_patch_backend!,
         | 
| @@ -1581,7 +1622,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 1581 1622 | 
             
                                    'type' => 'work'
         | 
| 1582 1623 | 
             
                                  }
         | 
| 1583 1624 | 
             
                                ]
         | 
| 1584 | 
            -
                              }
         | 
| 1625 | 
            +
                              }.with_indifferent_case_insensitive_access()
         | 
| 1585 1626 |  | 
| 1586 1627 | 
             
                              @instance.send(
         | 
| 1587 1628 | 
             
                                :from_patch_backend!,
         | 
| @@ -1606,7 +1647,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 1606 1647 | 
             
                                    'primary' => true
         | 
| 1607 1648 | 
             
                                  }
         | 
| 1608 1649 | 
             
                                ]
         | 
| 1609 | 
            -
                              }
         | 
| 1650 | 
            +
                              }.with_indifferent_case_insensitive_access()
         | 
| 1610 1651 |  | 
| 1611 1652 | 
             
                              @instance.send(
         | 
| 1612 1653 | 
             
                                :from_patch_backend!,
         | 
| @@ -1631,7 +1672,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 1631 1672 | 
             
                                    'type' => 'work'
         | 
| 1632 1673 | 
             
                                  }
         | 
| 1633 1674 | 
             
                                ]
         | 
| 1634 | 
            -
                              }
         | 
| 1675 | 
            +
                              }.with_indifferent_case_insensitive_access()
         | 
| 1635 1676 |  | 
| 1636 1677 | 
             
                              @instance.send(
         | 
| 1637 1678 | 
             
                                :from_patch_backend!,
         | 
| @@ -1649,7 +1690,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 1649 1690 | 
             
                          context 'with filter at end of path' do
         | 
| 1650 1691 | 
             
                            it 'by string match: adds item' do
         | 
| 1651 1692 | 
             
                              path      = [ 'emails[type eq "work"]' ]
         | 
| 1652 | 
            -
                              scim_hash = {}
         | 
| 1693 | 
            +
                              scim_hash = {}.with_indifferent_case_insensitive_access()
         | 
| 1653 1694 |  | 
| 1654 1695 | 
             
                              @instance.send(
         | 
| 1655 1696 | 
             
                                :from_patch_backend!,
         | 
| @@ -1673,7 +1714,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 1673 1714 | 
             
                                    'primary' => false
         | 
| 1674 1715 | 
             
                                  }
         | 
| 1675 1716 | 
             
                                ]
         | 
| 1676 | 
            -
                              }
         | 
| 1717 | 
            +
                              }.with_indifferent_case_insensitive_access()
         | 
| 1677 1718 |  | 
| 1678 1719 | 
             
                              @instance.send(
         | 
| 1679 1720 | 
             
                                :from_patch_backend!,
         | 
| @@ -1692,7 +1733,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 1692 1733 |  | 
| 1693 1734 | 
             
                          it 'with arrays: replaces' do
         | 
| 1694 1735 | 
             
                            path      = [ 'emails' ]
         | 
| 1695 | 
            -
                            scim_hash = {}
         | 
| 1736 | 
            +
                            scim_hash = {}.with_indifferent_case_insensitive_access()
         | 
| 1696 1737 |  | 
| 1697 1738 | 
             
                            @instance.send(
         | 
| 1698 1739 | 
             
                              :from_patch_backend!,
         | 
| @@ -1813,7 +1854,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 1813 1854 | 
             
                        end
         | 
| 1814 1855 |  | 
| 1815 1856 | 
             
                        it 'adds across multiple deep matching points' do
         | 
| 1816 | 
            -
                          scim_hash          = @original_hash.deep_dup()
         | 
| 1857 | 
            +
                          scim_hash          = @original_hash.deep_dup().with_indifferent_case_insensitive_access()
         | 
| 1817 1858 | 
             
                          contrived_instance = @contrived_class.new
         | 
| 1818 1859 | 
             
                          contrived_instance.send(
         | 
| 1819 1860 | 
             
                            :from_patch_backend!,
         | 
| @@ -1836,7 +1877,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 1836 1877 | 
             
                        end
         | 
| 1837 1878 |  | 
| 1838 1879 | 
             
                        it 'replaces across multiple deep matching points' do
         | 
| 1839 | 
            -
                          scim_hash          = @original_hash.deep_dup()
         | 
| 1880 | 
            +
                          scim_hash          = @original_hash.deep_dup().with_indifferent_case_insensitive_access()
         | 
| 1840 1881 | 
             
                          contrived_instance = @contrived_class.new
         | 
| 1841 1882 | 
             
                          contrived_instance.send(
         | 
| 1842 1883 | 
             
                            :from_patch_backend!,
         | 
| @@ -1861,7 +1902,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 1861 1902 | 
             
                        end
         | 
| 1862 1903 |  | 
| 1863 1904 | 
             
                        it 'removes across multiple deep matching points' do
         | 
| 1864 | 
            -
                          scim_hash          = @original_hash.deep_dup()
         | 
| 1905 | 
            +
                          scim_hash          = @original_hash.deep_dup().with_indifferent_case_insensitive_access()
         | 
| 1865 1906 | 
             
                          contrived_instance = @contrived_class.new
         | 
| 1866 1907 | 
             
                          contrived_instance.send(
         | 
| 1867 1908 | 
             
                            :from_patch_backend!,
         | 
| @@ -1903,7 +1944,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 1903 1944 | 
             
                                'value' => 'work_2@test.com'
         | 
| 1904 1945 | 
             
                              }
         | 
| 1905 1946 | 
             
                            ]
         | 
| 1906 | 
            -
                          }
         | 
| 1947 | 
            +
                          }.with_indifferent_case_insensitive_access()
         | 
| 1907 1948 |  | 
| 1908 1949 | 
             
                          expect do
         | 
| 1909 1950 | 
             
                            @instance.send(
         | 
| @@ -1920,7 +1961,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 1920 1961 | 
             
                          path      = [ 'userName[type eq "work"]', 'value' ]
         | 
| 1921 1962 | 
             
                          scim_hash = {
         | 
| 1922 1963 | 
             
                            'userName' => '1234'
         | 
| 1923 | 
            -
                          }
         | 
| 1964 | 
            +
                          }.with_indifferent_case_insensitive_access()
         | 
| 1924 1965 |  | 
| 1925 1966 | 
             
                          expect do
         | 
| 1926 1967 | 
             
                            @instance.send(
         | 
| @@ -1940,7 +1981,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 1940 1981 | 
             
                              'work_1@test.com',
         | 
| 1941 1982 | 
             
                              'work_2@test.com',
         | 
| 1942 1983 | 
             
                            ]
         | 
| 1943 | 
            -
                          }
         | 
| 1984 | 
            +
                          }.with_indifferent_case_insensitive_access()
         | 
| 1944 1985 |  | 
| 1945 1986 | 
             
                          expect do
         | 
| 1946 1987 | 
             
                            @instance.send(
         | 
| @@ -1961,166 +2002,202 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 1961 2002 | 
             
                  # -------------------------------------------------------------------
         | 
| 1962 2003 | 
             
                  #
         | 
| 1963 2004 | 
             
                  context 'public interface' do
         | 
| 1964 | 
            -
                     | 
| 1965 | 
            -
                       | 
| 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 | 
            +
                        }
         | 
| 1966 2022 |  | 
| 1967 | 
            -
             | 
| 1968 | 
            -
                         | 
| 1969 | 
            -
             | 
| 1970 | 
            -
                          {
         | 
| 1971 | 
            -
                            'op'    => 'replace',
         | 
| 1972 | 
            -
                            'path'  => 'userName',
         | 
| 1973 | 
            -
                            'value' => '1234'
         | 
| 1974 | 
            -
                          }
         | 
| 1975 | 
            -
                        ]
         | 
| 1976 | 
            -
                      }
         | 
| 2023 | 
            +
                        @instance.from_scim_patch!(patch_hash: patch)
         | 
| 2024 | 
            +
                        expect(@instance.username).to eql('1234')
         | 
| 2025 | 
            +
                      end
         | 
| 1977 2026 |  | 
| 1978 | 
            -
                       | 
| 1979 | 
            -
             | 
| 1980 | 
            -
                    end
         | 
| 2027 | 
            +
                      it 'which updates nested values' do
         | 
| 2028 | 
            +
                        @instance.update!(first_name: 'Foo', last_name: 'Bar')
         | 
| 1981 2029 |  | 
| 1982 | 
            -
             | 
| 1983 | 
            -
             | 
| 2030 | 
            +
                        path = 'name.givenName'
         | 
| 2031 | 
            +
                        path = path.upcase if force_upper_case
         | 
| 1984 2032 |  | 
| 1985 | 
            -
             | 
| 1986 | 
            -
             | 
| 1987 | 
            -
             | 
| 1988 | 
            -
             | 
| 1989 | 
            -
             | 
| 1990 | 
            -
             | 
| 1991 | 
            -
             | 
| 1992 | 
            -
             | 
| 1993 | 
            -
             | 
| 1994 | 
            -
             | 
| 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 | 
            +
                        }
         | 
| 1995 2043 |  | 
| 1996 | 
            -
             | 
| 1997 | 
            -
             | 
| 1998 | 
            -
             | 
| 2044 | 
            +
                        @instance.from_scim_patch!(patch_hash: patch)
         | 
| 2045 | 
            +
                        expect(@instance.first_name).to eql('Baz')
         | 
| 2046 | 
            +
                      end
         | 
| 1999 2047 |  | 
| 2000 | 
            -
             | 
| 2001 | 
            -
             | 
| 2048 | 
            +
                      it 'which updates with filter match' do
         | 
| 2049 | 
            +
                        @instance.update!(work_email_address: 'work@test.com', home_email_address: 'home@test.com')
         | 
| 2002 2050 |  | 
| 2003 | 
            -
             | 
| 2004 | 
            -
                         | 
| 2005 | 
            -
                        'Operations' => [
         | 
| 2006 | 
            -
                          {
         | 
| 2007 | 
            -
                            'op'    => 'replace',
         | 
| 2008 | 
            -
                            'path'  => 'emails[type eq "work"].value',
         | 
| 2009 | 
            -
                            'value' => 'replaced@test.com'
         | 
| 2010 | 
            -
                          }
         | 
| 2011 | 
            -
                        ]
         | 
| 2012 | 
            -
                      }
         | 
| 2051 | 
            +
                        filter_prefix = 'emails[type'
         | 
| 2052 | 
            +
                        filter_prefix = filter_prefix.upcase if force_upper_case
         | 
| 2013 2053 |  | 
| 2014 | 
            -
             | 
| 2015 | 
            -
             | 
| 2016 | 
            -
             | 
| 2017 | 
            -
             | 
| 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 | 
            +
                        }
         | 
| 2018 2064 |  | 
| 2019 | 
            -
             | 
| 2020 | 
            -
             | 
| 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
         | 
| 2021 2069 |  | 
| 2022 | 
            -
                       | 
| 2023 | 
            -
                         | 
| 2024 | 
            -
                        'Operations' => [
         | 
| 2025 | 
            -
                          {
         | 
| 2026 | 
            -
                            'op'    => 'add',
         | 
| 2027 | 
            -
                            'path'  => 'emails[type eq "home"].value',
         | 
| 2028 | 
            -
                            'value' => 'home@test.com'
         | 
| 2029 | 
            -
                          }
         | 
| 2030 | 
            -
                        ]
         | 
| 2031 | 
            -
                      }
         | 
| 2070 | 
            +
                      it 'which appends e-mails' do
         | 
| 2071 | 
            +
                        @instance.update!(work_email_address: 'work@test.com')
         | 
| 2032 2072 |  | 
| 2033 | 
            -
             | 
| 2034 | 
            -
             | 
| 2035 | 
            -
                      expect(@instance.home_email_address).to eql('home@test.com')
         | 
| 2036 | 
            -
                    end
         | 
| 2073 | 
            +
                        filter_prefix = 'emails[type'
         | 
| 2074 | 
            +
                        filter_prefix = filter_prefix.upcase if force_upper_case
         | 
| 2037 2075 |  | 
| 2038 | 
            -
             | 
| 2039 | 
            -
             | 
| 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 | 
            +
                        }
         | 
| 2040 2086 |  | 
| 2041 | 
            -
             | 
| 2042 | 
            -
                         | 
| 2043 | 
            -
                        ' | 
| 2044 | 
            -
             | 
| 2045 | 
            -
                            'op'   => 'remove',
         | 
| 2046 | 
            -
                            'path' => 'emails[type eq "home"]'
         | 
| 2047 | 
            -
                          }
         | 
| 2048 | 
            -
                        ]
         | 
| 2049 | 
            -
                      }
         | 
| 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
         | 
| 2050 2091 |  | 
| 2051 | 
            -
                       | 
| 2052 | 
            -
             | 
| 2053 | 
            -
                      expect(@instance.home_email_address).to be_nil
         | 
| 2054 | 
            -
                    end
         | 
| 2092 | 
            +
                      it 'which removes e-mails' do
         | 
| 2093 | 
            +
                        @instance.update!(work_email_address: 'work@test.com', home_email_address: 'home@test.com')
         | 
| 2055 2094 |  | 
| 2056 | 
            -
             | 
| 2057 | 
            -
             | 
| 2095 | 
            +
                        filter_prefix = 'emails[type'
         | 
| 2096 | 
            +
                        filter_prefix = filter_prefix.upcase if force_upper_case
         | 
| 2058 2097 |  | 
| 2059 | 
            -
             | 
| 2060 | 
            -
             | 
| 2061 | 
            -
             | 
| 2062 | 
            -
             | 
| 2063 | 
            -
             | 
| 2064 | 
            -
             | 
| 2065 | 
            -
             | 
| 2066 | 
            -
             | 
| 2067 | 
            -
             | 
| 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 | 
            +
                        }
         | 
| 2068 2107 |  | 
| 2069 | 
            -
             | 
| 2070 | 
            -
             | 
| 2071 | 
            -
             | 
| 2072 | 
            -
             | 
| 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
         | 
| 2073 2112 |  | 
| 2074 | 
            -
             | 
| 2075 | 
            -
             | 
| 2113 | 
            +
                      it 'which can patch the whole object' do
         | 
| 2114 | 
            +
                        @instance.update!(username: 'foo')
         | 
| 2076 2115 |  | 
| 2077 | 
            -
             | 
| 2078 | 
            -
             | 
| 2079 | 
            -
             | 
| 2080 | 
            -
             | 
| 2081 | 
            -
                            'op'    => 'REPLACE', # Note upper case
         | 
| 2082 | 
            -
                            'path'  => 'userName',
         | 
| 2083 | 
            -
                            'value' => '1234'
         | 
| 2116 | 
            +
                        hash = {
         | 
| 2117 | 
            +
                          'userName' => '1234',
         | 
| 2118 | 
            +
                          'name' => {
         | 
| 2119 | 
            +
                            'givenName' => 'Bar'
         | 
| 2084 2120 | 
             
                          }
         | 
| 2085 | 
            -
                         | 
| 2086 | 
            -
                      }
         | 
| 2121 | 
            +
                        }
         | 
| 2087 2122 |  | 
| 2088 | 
            -
             | 
| 2089 | 
            -
                      expect(@instance.username).to eql('1234')
         | 
| 2090 | 
            -
                    end
         | 
| 2123 | 
            +
                        hash = spec_helper_hupcase(hash) if force_upper_case
         | 
| 2091 2124 |  | 
| 2092 | 
            -
             | 
| 2093 | 
            -
             | 
| 2094 | 
            -
             | 
| 2095 | 
            -
             | 
| 2096 | 
            -
             | 
| 2097 | 
            -
             | 
| 2098 | 
            -
                             | 
| 2099 | 
            -
             | 
| 2100 | 
            -
             | 
| 2101 | 
            -
                        ]
         | 
| 2102 | 
            -
                      }
         | 
| 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 | 
            +
                        }
         | 
| 2103 2134 |  | 
| 2104 | 
            -
             | 
| 2105 | 
            -
                        expect( | 
| 2106 | 
            -
                        expect( | 
| 2135 | 
            +
                        @instance.from_scim_patch!(patch_hash: patch)
         | 
| 2136 | 
            +
                        expect(@instance.username).to eql('1234')
         | 
| 2137 | 
            +
                        expect(@instance.first_name).to eql('Bar')
         | 
| 2107 2138 | 
             
                      end
         | 
| 2108 | 
            -
                    end
         | 
| 2139 | 
            +
                    end # "shared_examples 'a patcher' do | force_upper_case: |"
         | 
| 2109 2140 |  | 
| 2110 | 
            -
                     | 
| 2111 | 
            -
                       | 
| 2112 | 
            -
             | 
| 2113 | 
            -
             | 
| 2114 | 
            -
             | 
| 2115 | 
            -
             | 
| 2116 | 
            -
             | 
| 2117 | 
            -
             | 
| 2118 | 
            -
             | 
| 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
         | 
| 2147 | 
            +
             | 
| 2148 | 
            +
                      it 'treats operation types as case-insensitive' do
         | 
| 2149 | 
            +
                        @instance.update!(username: 'foo')
         | 
| 2119 2150 |  | 
| 2120 | 
            -
             | 
| 2121 | 
            -
             | 
| 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')
         | 
| 2122 2164 | 
             
                      end
         | 
| 2123 | 
            -
                    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"
         | 
| 2124 2201 | 
             
                  end # "context 'public interface' do"
         | 
| 2125 2202 | 
             
                end # "context '#from_scim_patch!' do"
         | 
| 2126 2203 | 
             
              end # "context 'with good class definitons' do"
         |