Skip to content

Commit

Permalink
Merge pull request #5 from ShiftForward/enum_and_one_of
Browse files Browse the repository at this point in the history
Add support for enums and multiple possible schemas in Validator
  • Loading branch information
JD557 authored Aug 17, 2017
2 parents d0c5aad + 3b0fe56 commit abe2691
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 4 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
### 0.2.0 (unreleased)

- New features
- New schema types `$enum` and `$one_of` for specifying enumerations and values with multiple
possible schemas ([#5](https://github.com/ShiftForward/frise/pull/5)).
- Bug fixes
- Deal correctly with non-existing schema files in the load path
([#4](https://github.com/ShiftForward/frise/pull/4)).

### 0.1.0 (August 10, 2017)

Initial version.
28 changes: 27 additions & 1 deletion lib/frise/validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ def add_validation_error(path, msg)

def get_full_schema(schema)
case schema
when Hash then schema
when Hash then
default_type = schema[:enum] || schema[:one_of] ? 'Object' : 'Hash'
{ type: default_type }.merge(schema)
when Symbol then { type: 'Object', validate: schema }
when Array then
if schema.size == 1
Expand Down Expand Up @@ -87,6 +89,28 @@ def validate_custom(full_schema, obj, path)
true
end

def validate_enum(full_schema, obj, path)
if full_schema[:enum] && !full_schema[:enum].include?(obj)
add_validation_error(path, "invalid value #{obj.inspect}. " \
"Accepted values are #{full_schema[:enum].map(&:inspect).join(', ')}")
return false
end
true
end

def validate_one_of(full_schema, obj, path)
if full_schema[:one_of]
full_schema[:one_of].each do |schema_opt|
opt_validator = Validator.new(@root, @validators)
opt_validator.validate_object(path, obj, schema_opt)
return true if opt_validator.errors.empty?
end
add_validation_error(path, "#{obj.inspect} does not match any of the possible schemas")
return false
end
true
end

def validate_spec_keys(full_schema, obj, path, processed_keys)
full_schema.each do |spec_key, spec_value|
next if spec_key.is_a?(Symbol)
Expand Down Expand Up @@ -122,6 +146,8 @@ def validate_object(path, obj, schema)
return unless validate_optional(full_schema, obj, path)
return unless validate_type(full_schema, obj, path)
return unless validate_custom(full_schema, obj, path)
return unless validate_enum(full_schema, obj, path)
return unless validate_one_of(full_schema, obj, path)

processed_keys = Set.new
return unless validate_spec_keys(full_schema, obj, path, processed_keys)
Expand Down
50 changes: 47 additions & 3 deletions spec/frise/validator_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,44 @@ def validators.short_string(_, str)
expect(errors).to eq ['At obj: expected a short key, found "objkey0"']
end

it 'should validate correctly enumerations' do
schema = { 'color' => { '$enum' => %w[red green blue] } }

conf = { 'color' => 'green' }
errors = validate(conf, schema)
expect(errors).to eq []

conf = { 'color' => 'car' }
errors = validate(conf, schema)
expect(errors).to eq [
'At color: invalid value "car". Accepted values are "red", "green", "blue"'
]
end

it 'should validate correctly $one_of choices of schemas' do
schema = {
'key' => {
'$one_of' => ['String', { 'c' => 'Integer' }]
}
}

conf = { 'key' => 'abc' }
errors = validate(conf, schema)
expect(errors).to eq []

conf = { 'key' => { 'c' => 4 } }
errors = validate(conf, schema)
expect(errors).to eq []

conf = { 'key' => 42 }
errors = validate(conf, schema)
expect(errors).to eq ['At key: 42 does not match any of the possible schemas']

conf = { 'key' => { 'c' => 'abc' } }
errors = validate(conf, schema)
expect(errors).to eq ['At key: {"c"=>"abc"} does not match any of the possible schemas']
end

it 'should be able to use complex schemas in their full form' do
validators = Object.new
def validators.short_string(_, str)
Expand All @@ -180,7 +218,9 @@ def validators.short_string(_, str)
'opt_int_map' => { '$all_keys' => '$short_string', '$all' => 'Integer', '$optional' => true },
'opt_sstr' => { '$type' => 'String', '$validate' => '$short_string', '$optional' => true },
'opt_sstr_arr' => { '$type' => 'Array', '$all' => '$short_string', '$optional' => true },
'sstr_arr' => ['$short_string']
'sstr_arr' => ['$short_string'],
'opt_enum' => { '$enum' => %w[a b c], '$optional' => true },
'opt_one_of' => { '$one_of' => %w[String Integer], '$optional' => true }
}

conf = { 'sstr_arr' => ['val'] }
Expand All @@ -191,7 +231,9 @@ def validators.short_string(_, str)
'opt_int_map' => { 'k0' => 1, 'k1' => 'a', 'mapkey1' => 2 },
'opt_sstr' => 'abcde',
'opt_sstr_arr' => ['v1', 'v1234', true],
'sstr_arr' => %w[value val]
'sstr_arr' => %w[value val],
'opt_enum' => 'd',
'opt_one_of' => 4.5
}
errors = validate(conf, schema, validators: validators)
expect(errors).to eq [
Expand All @@ -200,7 +242,9 @@ def validators.short_string(_, str)
'At opt_sstr: expected a short string, found "abcde"',
'At opt_sstr_arr.1: expected a short string, found "v1234"',
'At opt_sstr_arr.2: expected a short string, found true',
'At sstr_arr.0: expected a short string, found "value"'
'At sstr_arr.0: expected a short string, found "value"',
'At opt_enum: invalid value "d". Accepted values are "a", "b", "c"',
'At opt_one_of: 4.5 does not match any of the possible schemas'
]
end

Expand Down

0 comments on commit abe2691

Please sign in to comment.