cli
  1# frozen_string_literal: true
  2
  3RSpec.describe Scim::Kit::Cli::Validator do
  4  describe '.errors_for' do
  5    let(:schema) do
  6      {
  7        'type' => 'object',
  8        'properties' => { 'userName' => { 'type' => 'string' } },
  9        'required' => ['userName'],
 10        'additionalProperties' => false
 11      }
 12    end
 13
 14    it 'returns an empty array for a valid document' do
 15      errors = described_class.errors_for(schema, { userName: 'bjensen' })
 16
 17      expect(errors).to eql([])
 18    end
 19
 20    it 'returns a readable error for a missing required property' do
 21      errors = described_class.errors_for(schema, {})
 22
 23      expect(errors).to eql(['root is missing required keys: userName'])
 24    end
 25
 26    it 'returns a readable error for a wrong type' do
 27      errors = described_class.errors_for(schema, { userName: 1 })
 28
 29      expect(errors).to eql(["property '/userName' is not of type: string"])
 30    end
 31
 32    context 'with an optional attribute' do
 33      let(:schema) do
 34        {
 35          'type' => 'object',
 36          'properties' => {
 37            'userName' => { 'type' => 'string' },
 38            'externalId' => { 'type' => 'string' }
 39          },
 40          'required' => ['userName']
 41        }
 42      end
 43
 44      it 'accepts null, which RFC 7643 2.5 makes equivalent to unassigned' do
 45        errors = described_class.errors_for(
 46          schema, { userName: 'bjensen', externalId: nil }
 47        )
 48
 49        expect(errors).to eql([])
 50      end
 51
 52      it 'still reports a wrong type' do
 53        errors = described_class.errors_for(
 54          schema, { userName: 'bjensen', externalId: 1 }
 55        )
 56
 57        expect(errors).to eql(["property '/externalId' is not of type: string"])
 58      end
 59    end
 60
 61    it 'reports null for a required attribute as unassigned' do
 62      errors = described_class.errors_for(schema, { userName: nil })
 63
 64      expect(errors).to eql(['root is missing required keys: userName'])
 65    end
 66
 67    context 'with an optional attribute behind a $ref' do
 68      let(:schema) do
 69        {
 70          'type' => 'object',
 71          'properties' => { 'meta' => { '$ref' => '#/$defs/meta' } },
 72          '$defs' => {
 73            'meta' => {
 74              'type' => 'object',
 75              'properties' => { 'version' => { 'type' => 'string' } }
 76            }
 77          }
 78        }
 79      end
 80
 81      it 'reports only the error the server actually made' do
 82        errors = described_class.errors_for(schema, { meta: { version: 1 } })
 83
 84        expect(errors).to eql(
 85          ["property '/meta/version' is not of type: string"]
 86        )
 87      end
 88    end
 89
 90    it 'accepts a declared attribute the server spelled differently' do
 91      errors = described_class.errors_for(schema, { USERNAME: 'bjensen' })
 92
 93      expect(errors).to eql([])
 94    end
 95
 96    it 'reports the canonical name when a differently spelled value is wrong' do
 97      errors = described_class.errors_for(schema, { USERNAME: 1 })
 98
 99      expect(errors).to eql(["property '/userName' is not of type: string"])
100    end
101
102    it 'returns a readable error for an undeclared property' do
103      errors = described_class.errors_for(schema, { userName: 'bjensen', extra: true })
104
105      expect(errors).to eql(["property '/extra' is invalid: error_type=schema"])
106    end
107  end
108end