Skip to content

Commit

Permalink
Fix requireValidation for oneOf/anyOf/allOf
Browse files Browse the repository at this point in the history
Fixes: #64
  • Loading branch information
ChALkeR committed Jun 24, 2020
1 parent 33363b2 commit 471dd3b
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 4 deletions.
12 changes: 8 additions & 4 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,8 @@ const compile = (schema, root, opts, scope, basePathRoot) => {

/* Preparation and methods, post-$ref validation will begin at the end of the function */

const hasSubValidation = ['allOf', 'anyOf', 'oneOf'].some((key) => Array.isArray(node[key]))

const { type } = node
if (!type) enforceValidation('type is required')
if (type !== undefined && typeof type !== 'string' && !Array.isArray(type))
Expand Down Expand Up @@ -688,7 +690,9 @@ const compile = (schema, root, opts, scope, basePathRoot) => {
})
})
consume('additionalProperties', 'object', 'boolean')
} else if (typeApplicable('object')) {
} else if (typeApplicable('object') && !hasSubValidation) {
// If subvalidation rules (allOf/anyOf/oneOf) all have additionalProperties, all is good
// If some doesn't -- we'll fail there
enforceValidation('additionalProperties rule must be specified')
}
}
Expand Down Expand Up @@ -737,15 +741,15 @@ const compile = (schema, root, opts, scope, basePathRoot) => {
consume('if', 'object', 'boolean')
}

if (node.allOf) {
if (node.allOf !== undefined) {
enforce(Array.isArray(node.allOf), 'Invalid allOf')
node.allOf.forEach((sch, key) => {
rule(current, sch, subPath('allOf', key))
})
consume('allOf', 'array')
}

if (node.anyOf && node.anyOf.length) {
if (node.anyOf !== undefined) {
enforce(Array.isArray(node.anyOf), 'Invalid anyOf')
const prev = gensym('prev')

Expand All @@ -768,7 +772,7 @@ const compile = (schema, root, opts, scope, basePathRoot) => {
consume('anyOf', 'array')
}

if (node.oneOf && node.oneOf.length) {
if (node.oneOf !== undefined) {
enforce(Array.isArray(node.oneOf), 'Invalid oneOf')
const prev = gensym('prev')
const passes = gensym('passes')
Expand Down
47 changes: 47 additions & 0 deletions test/regressions/require-additional-of.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
'use strict'

const tape = require('tape')
const { validator } = require('../../')

const fail = (t, schema, msg) => t.throws(() => validator(schema, { mode: 'strong' }), msg)
const pass = (t, schema, msg) => t.doesNotThrow(() => validator(schema, { mode: 'strong' }), msg)

tape('requireValidation works with allOf/anyOf/oneOf', (t) => {
fail(t, {}, 'no validation done fails')
pass(t, { type: 'boolean' }, 'non-object type passes')
fail(t, { type: 'object' }, 'object with no additionalProperties fails')

pass(t, { type: 'object', additionalProperties: false }, 'object with additionalProperties')

pass(t, { type: 'object', anyOf: [{ type: 'object', additionalProperties: false }] }, 'allOf')
pass(t, { anyOf: [{ type: 'object', additionalProperties: false }] }, 'allOf with no type')
fail(t, { anyOf: [{ additionalProperties: false }] }, 'oneOf with no type in allOf')

pass(t, { type: 'object', oneOf: [{ type: 'object', additionalProperties: false }] }, 'oneOf')
pass(t, { oneOf: [{ type: 'object', additionalProperties: false }] }, 'oneOf with no type')
fail(t, { oneOf: [{ additionalProperties: false }] }, 'oneOf with no type in oneOf')

pass(t, { type: 'object', anyOf: [{ type: 'object', additionalProperties: false }] }, 'anyOf')
pass(t, { anyOf: [{ type: 'object', additionalProperties: false }] }, 'anyOf with no type')
fail(t, { anyOf: [{ additionalProperties: false }] }, 'oneOf with no type in anyOf')

fail(t, { anyOf: [{ type: 'object', additionalProperties: false }, {}] }, 'anyOf with one empty')

t.end()
})

tape('requireValidation works with $ref', (t) => {
const good = { type: 'object', additionalProperties: false }
const bad0 = {}
const bad1 = { type: 'object' }
const bad2 = { additionalProperties: false }
const $defs = { good, bad0, bad1, bad2 }

fail(t, { $defs }, 'no validation done fails')
fail(t, { $defs, $ref: '#/defs/bad0' }, 'ref to empty fails')
fail(t, { $defs, $ref: '#/defs/bad1' }, 'ref to only type fails')
fail(t, { $defs, $ref: '#/defs/bad2' }, 'ref to only additionalProperties fails')
fail(t, { $defs, $ref: '#/defs/good' }, 'ref to only type + additionalProperties passes')

t.end()
})

0 comments on commit 471dd3b

Please sign in to comment.