Update AllOfConstraint and AnyOfConstraint to support draft 7

This commit is contained in:
Tristan Penman 2019-08-30 10:33:56 +10:00
parent a285ed0fbe
commit c210d07c61
4 changed files with 72 additions and 13 deletions

View File

@ -40,11 +40,13 @@ class AllOfConstraint: public BasicConstraint<AllOfConstraint>
{ {
public: public:
AllOfConstraint() AllOfConstraint()
: subschemas(Allocator::rebind<const Subschema *>::other(allocator)) { } : subschemas(Allocator::rebind<const Subschema *>::other(allocator)),
alwaysInvalid(false) { }
AllOfConstraint(CustomAlloc allocFn, CustomFree freeFn) AllOfConstraint(CustomAlloc allocFn, CustomFree freeFn)
: BasicConstraint(allocFn, freeFn), : BasicConstraint(allocFn, freeFn),
subschemas(Allocator::rebind<const Subschema *>::other(allocator)) { } subschemas(Allocator::rebind<const Subschema *>::other(allocator)),
alwaysInvalid(false) { }
void addSubschema(const Subschema *subschema) void addSubschema(const Subschema *subschema)
{ {
@ -64,12 +66,24 @@ public:
} }
} }
bool getAlwaysInvalid() const
{
return alwaysInvalid;
}
void setAlwaysInvalid()
{
alwaysInvalid = true;
}
private: private:
typedef std::vector<const Subschema *, typedef std::vector<const Subschema *,
internal::CustomAllocator<const Subschema *> > Subschemas; internal::CustomAllocator<const Subschema *> > Subschemas;
/// Collection of sub-schemas, all of which must be satisfied /// Collection of sub-schemas, all of which must be satisfied
Subschemas subschemas; Subschemas subschemas;
bool alwaysInvalid;
}; };
/** /**
@ -83,7 +97,8 @@ class AnyOfConstraint: public BasicConstraint<AnyOfConstraint>
{ {
public: public:
AnyOfConstraint() AnyOfConstraint()
: subschemas(Allocator::rebind<const Subschema *>::other(allocator)) { } : subschemas(Allocator::rebind<const Subschema *>::other(allocator)),
alwaysValid(false) { }
AnyOfConstraint(CustomAlloc allocFn, CustomFree freeFn) AnyOfConstraint(CustomAlloc allocFn, CustomFree freeFn)
: BasicConstraint(allocFn, freeFn), : BasicConstraint(allocFn, freeFn),
@ -107,12 +122,24 @@ public:
} }
} }
bool getAlwaysValid() const
{
return alwaysValid;
}
void setAlwaysValid()
{
alwaysValid = true;
}
private: private:
typedef std::vector<const Subschema *, typedef std::vector<const Subschema *,
internal::CustomAllocator<const Subschema *> > Subschemas; internal::CustomAllocator<const Subschema *> > Subschemas;
/// Collection of sub-schemas, at least one of which must be satisfied /// Collection of sub-schemas, at least one of which must be satisfied
Subschemas subschemas; Subschemas subschemas;
bool alwaysValid;
}; };
class ConditionalConstraint: public BasicConstraint<ConditionalConstraint> class ConditionalConstraint: public BasicConstraint<ConditionalConstraint>

View File

@ -1096,17 +1096,25 @@ private:
int index = 0; int index = 0;
for (const AdapterType schemaNode : node.asArray()) { for (const AdapterType schemaNode : node.asArray()) {
if (schemaNode.maybeObject()) { if (schemaNode.maybeObject()) {
const std::string childPath = nodePath + "/" + const std::string childPath = nodePath + "/" + std::to_string(index);
std::to_string(index);
const Subschema *subschema = makeOrReuseSchema<AdapterType>( const Subschema *subschema = makeOrReuseSchema<AdapterType>(
rootSchema, rootNode, schemaNode, currentScope, rootSchema, rootNode, schemaNode, currentScope,
childPath, fetchDoc, NULL, NULL, docCache, schemaCache); childPath, fetchDoc, NULL, NULL, docCache, schemaCache);
constraint.addSubschema(subschema); constraint.addSubschema(subschema);
index++; index++;
} else if (version == kDraft7) {
if (schemaNode.maybeBool()) {
if (!schemaNode.asBool()) {
// Schema that always fails
constraint.setAlwaysInvalid();
}
} else {
throw std::runtime_error(
"Expected element to be an object or boolean value in 'allOf' constraint");
}
} else { } else {
throw std::runtime_error( throw std::runtime_error(
"Expected array element to be an object value in " "Expected element to be an object value in 'allOf' constraint.");
"'allOf' constraint.");
} }
} }
@ -1152,17 +1160,24 @@ private:
int index = 0; int index = 0;
for (const AdapterType schemaNode : node.asArray()) { for (const AdapterType schemaNode : node.asArray()) {
if (schemaNode.maybeObject()) { if (schemaNode.maybeObject()) {
const std::string childPath = nodePath + "/" + const std::string childPath = nodePath + "/" + std::to_string(index);
std::to_string(index);
const Subschema *subschema = makeOrReuseSchema<AdapterType>( const Subschema *subschema = makeOrReuseSchema<AdapterType>(
rootSchema, rootNode, schemaNode, currentScope, rootSchema, rootNode, schemaNode, currentScope,
childPath, fetchDoc, NULL, NULL, docCache, schemaCache); childPath, fetchDoc, NULL, NULL, docCache, schemaCache);
constraint.addSubschema(subschema); constraint.addSubschema(subschema);
index++; index++;
} else if (version == kDraft7) {
if (schemaNode.maybeBool()) {
if (schemaNode.asBool()) {
constraint.setAlwaysValid();
}
} else {
throw std::runtime_error(
"Expected element to be an object or boolean value in 'allOf' constraint");
}
} else { } else {
throw std::runtime_error( throw std::runtime_error(
"Expected array element to be an object value in " "Expected array element to be an object value in 'anyOf' constraint.");
"'anyOf' constraint.");
} }
} }

View File

@ -108,8 +108,11 @@ public:
*/ */
virtual bool visit(const AllOfConstraint &constraint) virtual bool visit(const AllOfConstraint &constraint)
{ {
bool validated = true; if (constraint.getAlwaysInvalid()) {
return false;
}
bool validated = true;
constraint.applyToSubschemas(ValidateSubschemas(target, context, constraint.applyToSubschemas(ValidateSubschemas(target, context,
true, false, *this, results, NULL, &validated)); true, false, *this, results, NULL, &validated));
@ -135,6 +138,10 @@ public:
*/ */
virtual bool visit(const AnyOfConstraint &constraint) virtual bool visit(const AnyOfConstraint &constraint)
{ {
if (constraint.getAlwaysValid()) {
return true;
}
unsigned int numValidated = 0; unsigned int numValidated = 0;
ValidationResults newResults; ValidationResults newResults;

View File

@ -190,6 +190,11 @@ protected:
} }
}; };
//
// draft 3
// ------------------------------------------------------------------------------------------------
//
TEST_F(TestValidator, Draft3_AdditionalItems) TEST_F(TestValidator, Draft3_AdditionalItems)
{ {
processDraft3TestFile(TEST_SUITE_DIR "draft3/additionalItems.json"); processDraft3TestFile(TEST_SUITE_DIR "draft3/additionalItems.json");
@ -290,6 +295,11 @@ TEST_F(TestValidator, Draft3_UniqueItems)
processDraft3TestFile(TEST_SUITE_DIR "draft3/uniqueItems.json"); processDraft3TestFile(TEST_SUITE_DIR "draft3/uniqueItems.json");
} }
//
// draft 4
// ------------------------------------------------------------------------------------------------
//
TEST_F(TestValidator, Draft4_AdditionalItems) TEST_F(TestValidator, Draft4_AdditionalItems)
{ {
processDraft4TestFile(TEST_SUITE_DIR "draft4/additionalItems.json"); processDraft4TestFile(TEST_SUITE_DIR "draft4/additionalItems.json");