mirror of
https://github.com/tristanpenman/valijson.git
synced 2025-09-27 16:29:33 +02:00
Update OneOfConstraint to use custom allocator, with better encapsulation
This commit is contained in:
parent
d534c49393
commit
c53268ba77
@ -434,15 +434,40 @@ struct NotConstraint: BasicConstraint<NotConstraint>
|
||||
/**
|
||||
* @brief Represents a 'oneOf' constraint.
|
||||
*/
|
||||
struct OneOfConstraint: BasicConstraint<OneOfConstraint>
|
||||
class OneOfConstraint: public BasicConstraint<OneOfConstraint>
|
||||
{
|
||||
typedef std::vector<const Subschema *> Schemas;
|
||||
public:
|
||||
OneOfConstraint()
|
||||
: subschemas(Allocator::rebind<const Subschema *>::other(allocator)) { }
|
||||
|
||||
OneOfConstraint(const Schemas &schemas)
|
||||
: schemas(schemas) { }
|
||||
OneOfConstraint(CustomAlloc allocFn, CustomFree freeFn)
|
||||
: BasicConstraint(allocFn, freeFn),
|
||||
subschemas(Allocator::rebind<const Subschema *>::other(allocator)) { }
|
||||
|
||||
/// Collection of schemas that must all be satisfied
|
||||
const Schemas schemas;
|
||||
void addSubschema(const Subschema *subschema)
|
||||
{
|
||||
subschemas.push_back(subschema);
|
||||
}
|
||||
|
||||
template<typename FunctorType>
|
||||
void applyToSubschemas(const FunctorType &fn) const
|
||||
{
|
||||
unsigned int index = 0;
|
||||
BOOST_FOREACH( const Subschema *subschema, subschemas ) {
|
||||
if (!fn(index, subschema)) {
|
||||
return;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
typedef std::vector<const Subschema *,
|
||||
internal::CustomAllocator<const Subschema *> > Subschemas;
|
||||
|
||||
/// Collection of sub-schemas, exactly one of which must be satisfied
|
||||
Subschemas subschemas;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -5,8 +5,6 @@
|
||||
namespace valijson {
|
||||
namespace constraints {
|
||||
|
||||
struct AllOfConstraint;
|
||||
struct AnyOfConstraint;
|
||||
struct EnumConstraint;
|
||||
struct ItemsConstraint;
|
||||
struct FormatConstraint;
|
||||
@ -20,14 +18,16 @@ struct MinLengthConstraint;
|
||||
struct MinPropertiesConstraint;
|
||||
struct MultipleOfConstraint;
|
||||
struct NotConstraint;
|
||||
struct OneOfConstraint;
|
||||
struct PatternConstraint;
|
||||
struct PropertiesConstraint;
|
||||
struct RequiredConstraint;
|
||||
struct TypeConstraint;
|
||||
struct UniqueItemsConstraint;
|
||||
|
||||
class AllOfConstraint;
|
||||
class AnyOfConstraint;
|
||||
class DependenciesConstraint;
|
||||
class OneOfConstraint;
|
||||
|
||||
/// Interface to allow usage of the visitor pattern with Constraints
|
||||
class ConstraintVisitor
|
||||
|
@ -1152,18 +1152,20 @@ private:
|
||||
const boost::optional<
|
||||
typename FetchDocumentFunction<AdapterType>::Type > fetchDoc)
|
||||
{
|
||||
constraints::OneOfConstraint::Schemas childSchemas;
|
||||
constraints::OneOfConstraint constraint;
|
||||
|
||||
int index = 0;
|
||||
BOOST_FOREACH ( const AdapterType schemaNode, node.getArray() ) {
|
||||
const std::string childPath = nodePath + "/" +
|
||||
boost::lexical_cast<std::string>(index);
|
||||
childSchemas.push_back(rootSchema.createSubschema());
|
||||
const Subschema *subschema = rootSchema.createSubschema();
|
||||
constraint.addSubschema(subschema);
|
||||
populateSchema<AdapterType>(rootSchema, rootNode, schemaNode,
|
||||
*childSchemas.back(), currentScope, childPath, fetchDoc);
|
||||
*subschema, currentScope, childPath, fetchDoc);
|
||||
index++;
|
||||
}
|
||||
|
||||
return constraints::OneOfConstraint(childSchemas);
|
||||
return constraint;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -114,8 +114,8 @@ public:
|
||||
{
|
||||
bool validated = true;
|
||||
|
||||
constraint.applyToSubschemas(ValidateAllSubschemas(target, context,
|
||||
*this, results, &validated));
|
||||
constraint.applyToSubschemas(ValidateSubschemas(target, context,
|
||||
false, *this, results, NULL, &validated));
|
||||
|
||||
return validated;
|
||||
}
|
||||
@ -739,15 +739,12 @@ public:
|
||||
virtual bool visit(const OneOfConstraint &constraint)
|
||||
{
|
||||
unsigned int numValidated = 0;
|
||||
|
||||
ValidationResults newResults;
|
||||
ValidationResults *childResults = (results) ? &newResults : NULL;
|
||||
|
||||
BOOST_FOREACH( const Subschema *subschema, constraint.schemas ) {
|
||||
ValidationVisitor<AdapterType> v(target, context, strictTypes, childResults);
|
||||
if (v.validateSchema(*subschema)) {
|
||||
numValidated++;
|
||||
}
|
||||
}
|
||||
constraint.applyToSubschemas(ValidateSubschemas(target, context,
|
||||
true, *this, childResults, &numValidated, NULL));
|
||||
|
||||
if (numValidated == 0) {
|
||||
if (results) {
|
||||
@ -1044,47 +1041,6 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
struct ValidateAllSubschemas
|
||||
{
|
||||
ValidateAllSubschemas(
|
||||
const AdapterType &adapter,
|
||||
const std::vector<std::string> &context,
|
||||
ValidationVisitor &validationVisitor,
|
||||
ValidationResults *results,
|
||||
bool *validated)
|
||||
: adapter(adapter),
|
||||
context(context),
|
||||
validationVisitor(validationVisitor),
|
||||
results(results),
|
||||
validated(validated) { }
|
||||
|
||||
bool operator()(unsigned int index, const Subschema *subschema) const
|
||||
{
|
||||
if (!validationVisitor.validateSchema(*subschema)) {
|
||||
if (validated) {
|
||||
*validated = false;
|
||||
}
|
||||
if (results) {
|
||||
results->pushError(context,
|
||||
"Failed to validate against child schema #" +
|
||||
boost::lexical_cast<std::string>(index) +
|
||||
" of allOf constraint.");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
const AdapterType &adapter;
|
||||
const std::vector<std::string> &context;
|
||||
ValidationVisitor &validationVisitor;
|
||||
ValidationResults * const results;
|
||||
bool * const validated;
|
||||
};
|
||||
|
||||
struct ValidateAtLeastOneSubschema
|
||||
{
|
||||
ValidateAtLeastOneSubschema(
|
||||
@ -1215,6 +1171,57 @@ private:
|
||||
bool * const validated;
|
||||
};
|
||||
|
||||
struct ValidateSubschemas
|
||||
{
|
||||
ValidateSubschemas(
|
||||
const AdapterType &adapter,
|
||||
const std::vector<std::string> &context,
|
||||
bool continueOnFailure,
|
||||
ValidationVisitor &validationVisitor,
|
||||
ValidationResults *results,
|
||||
unsigned int *numValidated,
|
||||
bool *validated)
|
||||
: adapter(adapter),
|
||||
context(context),
|
||||
continueOnFailure(continueOnFailure),
|
||||
validationVisitor(validationVisitor),
|
||||
results(results),
|
||||
numValidated(numValidated),
|
||||
validated(validated) { }
|
||||
|
||||
bool operator()(unsigned int index, const Subschema *subschema) const
|
||||
{
|
||||
if (validationVisitor.validateSchema(*subschema)) {
|
||||
if (numValidated) {
|
||||
(*numValidated)++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (validated) {
|
||||
*validated = false;
|
||||
}
|
||||
|
||||
if (results) {
|
||||
results->pushError(context,
|
||||
"Failed to validate against child schema #" +
|
||||
boost::lexical_cast<std::string>(index) + ".");
|
||||
}
|
||||
|
||||
return continueOnFailure;
|
||||
}
|
||||
|
||||
private:
|
||||
const AdapterType &adapter;
|
||||
const std::vector<std::string> &context;
|
||||
bool continueOnFailure;
|
||||
ValidationVisitor &validationVisitor;
|
||||
ValidationResults * const results;
|
||||
unsigned int * const numValidated;
|
||||
bool * const validated;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Callback function that passes a visitor to a constraint.
|
||||
*
|
||||
|
@ -88,7 +88,7 @@ TEST_F(TestValidationErrors, AllOfConstraintFailure)
|
||||
EXPECT_TRUE( results.popError(error) );
|
||||
EXPECT_EQ( 1, error.context.size() );
|
||||
EXPECT_EQ( "<root>", error.context[0] );
|
||||
EXPECT_EQ( "Failed to validate against child schema #0 of allOf constraint.", error.description );
|
||||
EXPECT_EQ( "Failed to validate against child schema #0.", error.description );
|
||||
|
||||
EXPECT_FALSE( results.popError(error) );
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user