Initial support for 'if', 'then' and 'else' subschemas

This commit is contained in:
Tristan Penman 2019-08-29 10:31:37 +10:00
parent dac4cff42f
commit 925ff8ff68
4 changed files with 115 additions and 4 deletions

View File

@ -118,7 +118,51 @@ private:
class ConditionalConstraint: public BasicConstraint<ConditionalConstraint>
{
public:
ConditionalConstraint() { }
ConditionalConstraint()
: ifSubschema(NULL),
thenSubschema(NULL),
elseSubschema(NULL) { }
ConditionalConstraint(CustomAlloc allocFn, CustomFree freeFn)
: BasicConstraint(allocFn, freeFn),
ifSubschema(NULL),
thenSubschema(NULL),
elseSubschema(NULL) { }
const Subschema * getIfSubschema() const
{
return ifSubschema;
}
const Subschema * getThenSubschema() const
{
return thenSubschema;
}
const Subschema * getElseSubschema() const
{
return elseSubschema;
}
void setIfSubschema(const Subschema *subschema)
{
ifSubschema = subschema;
}
void setThenSubschema(const Subschema *subschema)
{
thenSubschema = subschema;
}
void setElseSubschema(const Subschema *subschema)
{
elseSubschema = subschema;
}
private:
const Subschema *ifSubschema;
const Subschema *thenSubschema;
const Subschema *elseSubschema;
};
/**

View File

@ -37,7 +37,8 @@ public:
/// Supported versions of JSON Schema
enum Version {
kDraft3, ///< @deprecated JSON Schema v3 has been superseded by v4
kDraft4
kDraft4,
kDraft7
};
/// Version of JSON Schema that should be expected when parsing
@ -710,6 +711,25 @@ private:
}
}
{
const typename AdapterType::Object::const_iterator ifItr = object.find("if");
const typename AdapterType::Object::const_iterator thenItr = object.find("then");
const typename AdapterType::Object::const_iterator elseItr = object.find("end");
if (object.end() != ifItr && object.end() != thenItr) {
if (version == kDraft7) {
rootSchema.addConstraintToSubschema(
makeConditionalConstraint(rootSchema, rootNode,
ifItr->second, thenItr->second,
elseItr == object.end() ? NULL : &elseItr->second,
updatedScope, nodePath, fetchDoc, docCache, schemaCache),
&subschema);
} else {
throw std::runtime_error("Not supported");
}
}
}
if ((itr = object.find("maximum")) != object.end()) {
typename AdapterType::Object::const_iterator exclusiveMaximumItr =
object.find("exclusiveMaximum");
@ -1138,6 +1158,24 @@ private:
{
constraints::ConditionalConstraint constraint;
const Subschema *ifSubschema = makeOrReuseSchema<AdapterType>(
rootSchema, rootNode, ifNode, currentScope,
nodePath, fetchDoc, NULL, NULL, docCache,
schemaCache);
constraint.setIfSubschema(ifSubschema);
const Subschema *thenSubschema = makeOrReuseSchema<AdapterType>(
rootSchema, rootNode, thenNode, currentScope, nodePath, fetchDoc, NULL, NULL,
docCache, schemaCache);
constraint.setThenSubschema(thenSubschema);
if (elseNode) {
const Subschema *elseSubschema = makeOrReuseSchema<AdapterType>(
rootSchema, rootNode, *elseNode, currentScope, nodePath, fetchDoc, NULL, NULL,
docCache, schemaCache);
constraint.setElseSubschema(elseSubschema);
}
return constraint;
}

View File

@ -158,9 +158,28 @@ public:
return numValidated > 0;
}
/**
* @brief Validate current node using a set of 'if', 'then' and 'else' subschemas
*
* A conditional constraint allows a document to validated against one of two additional
* subschemas (specified via 'then' or 'else' properties) depending on whether the document
* satifies an optional subschema (specified via the 'if' property).
*
* @param constraint ConditionalConstraint that the current node must validate against
*
* @return \c true if validation passes; \c false otherwise
*/
virtual bool visit(const ConditionalConstraint &constraint)
{
return false;
// Create a validator to evaluate the conditional
ValidationVisitor ifValidator(target, context, strictTypes, NULL);
ValidationVisitor thenElseValidator(target, context, strictTypes, NULL);
if (ifValidator.validateSchema(*constraint.getIfSubschema())) {
return thenElseValidator.validateSchema(*constraint.getThenSubschema());
} else {
return thenElseValidator.validateSchema(*constraint.getElseSubschema());
}
}
/**

View File

@ -183,6 +183,11 @@ protected:
{
return processTestFile(testFile, SchemaParser::kDraft4);
}
void processDraft7TestFile(const std::string &testFile)
{
return processTestFile(testFile, SchemaParser::kDraft7);
}
};
TEST_F(TestValidator, Draft3_AdditionalItems)
@ -414,3 +419,8 @@ TEST_F(TestValidator, Draft4_UniqueItems)
{
processDraft4TestFile(TEST_SUITE_DIR "draft4/uniqueItems.json");
}
TEST_F(TestValidator, Draft7_IfThenElse)
{
processDraft7TestFile(TEST_SUITE_DIR "draft7/if-then-else.json");
}