Merge branch 'add-poly-constraint'

This commit is contained in:
Tristan Penman 2016-04-07 10:07:20 +10:00
commit 28bcbcbbb2
9 changed files with 214 additions and 4 deletions

20
Authors Normal file
View File

@ -0,0 +1,20 @@
Tristan Penman, tristan@tristanpenman.com
Core library development
James Jensen, jjensen@akamai.com, changes Copyright (c) 2016 Akamai Technologies
Polymorphic constraint support
Tengiz Sharafiev, btolfa+github@gmail.com
Adapter for nlohmann/json parser library
hotwatermorning (github username), hotwatermorning@gmail.com
Adapter for json11 parser library
shsfre09 (github username), <email address unknown>
Adapter for picojson parser library
Michael Smith, michael.smith@puppetlabs.com
Memory management improvements for RapidJson parser library
Richard Clamp, richardc@unixbeard.net
Boost-related fixes

View File

@ -44,16 +44,18 @@ add_subdirectory(thirdparty/gtest-1.7.0)
# Include path
include_directories(
include
)
include_directories(SYSTEM
${Boost_INCLUDE_DIRS}
thirdparty/gtest-1.7.0/include
thirdparty/jsoncpp-0.9.4/include
thirdparty/rapidjson-1.0.2/include
thirdparty/picojson-1.3.0
thirdparty/nlohmann-json-1.1.0
${Boost_INCLUDE_DIRS}
)
if(VALIJSON_CXX11_ADAPTERS_ARE_ENABLED)
include_directories(
include_directories(SYSTEM
thirdparty/json11-2016-01-26
)
endif()
@ -78,6 +80,7 @@ set(TEST_SOURCES
tests/test_picojson_adapter.cpp
tests/test_validation_errors.cpp
tests/test_validator.cpp
tests/test_poly_constraint.cpp
)
if(VALIJSON_CXX11_ADAPTERS_ARE_ENABLED)

View File

@ -1,4 +1,5 @@
Copyright (c) 2016, Tristan Penman
Copyright (c) 2016, Akamai Technolgies, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@ -31,6 +31,7 @@
#include <valijson/schema.hpp>
namespace valijson {
class ValidationResults;
namespace constraints {
/**
@ -783,6 +784,40 @@ private:
String pattern;
};
class PolyConstraint : public Constraint
{
public:
virtual bool accept(ConstraintVisitor &visitor) const
{
return visitor.visit(*static_cast<const PolyConstraint*>(this));
}
virtual Constraint * clone(CustomAlloc allocFn, CustomFree freeFn) const
{
void *ptr = allocFn(sizeOf());
if (!ptr) {
throw std::runtime_error(
"Failed to allocate memory for cloned constraint");
}
try {
return cloneInto(ptr);
} catch (...) {
freeFn(ptr);
throw;
}
}
virtual bool validate(const adapters::Adapter &target,
const std::vector<std::string>& context,
valijson::ValidationResults *results) const = 0;
protected:
virtual Constraint * cloneInto(void *) const = 0;
virtual size_t sizeOf() const = 0;
};
/**
* @brief Represents a combination of 'properties', 'patternProperties' and
* 'additionalProperties' constraints

View File

@ -23,6 +23,7 @@ class MultipleOfIntConstraint;
class NotConstraint;
class OneOfConstraint;
class PatternConstraint;
class PolyConstraint;
class PropertiesConstraint;
class RequiredConstraint;
class SingularItemsConstraint;
@ -53,6 +54,7 @@ protected:
typedef constraints::NotConstraint NotConstraint;
typedef constraints::OneOfConstraint OneOfConstraint;
typedef constraints::PatternConstraint PatternConstraint;
typedef constraints::PolyConstraint PolyConstraint;
typedef constraints::PropertiesConstraint PropertiesConstraint;
typedef constraints::RequiredConstraint RequiredConstraint;
typedef constraints::SingularItemsConstraint SingularItemsConstraint;
@ -79,12 +81,12 @@ public:
virtual bool visit(const NotConstraint &) = 0;
virtual bool visit(const OneOfConstraint &) = 0;
virtual bool visit(const PatternConstraint &) = 0;
virtual bool visit(const PolyConstraint &) = 0;
virtual bool visit(const PropertiesConstraint &) = 0;
virtual bool visit(const RequiredConstraint &) = 0;
virtual bool visit(const SingularItemsConstraint &) = 0;
virtual bool visit(const TypeConstraint &) = 0;
virtual bool visit(const UniqueItemsConstraint &) = 0;
};
} // namespace constraints

View File

@ -7,6 +7,7 @@
#include <boost/foreach.hpp>
#include <boost/function.hpp>
#include <boost/optional.hpp>
#include <memory>
#include <valijson/constraints/constraint.hpp>
@ -93,6 +94,39 @@ public:
constraints.push_back(constraint.clone(allocFn, freeFn));
}
/**
* @brief move a constraint to this sub-schema
*
* The constraint will be added to the list of constraints for this
* Subschema.
*
* @param constraint pointer to the constraint to be added. Ownership
* assumed.
*/
void addConstraint(const Constraint *constraint)
{
constraints.push_back(constraint);
}
//#if _cplusplus >=201103L
#if 0
/**
* @brief Add a constraint to this sub-schema
*
* The constraint will be copied before being added to the list of
* constraints for this Subschema. Note that constraints will be copied
* only as deep as references to other Subschemas - e.g. copies of
* constraints that refer to sub-schemas, will continue to refer to the
* same Subschema instances.
*
* @param constraint Reference to the constraint to copy
*/
void addConstraint(std::unique_ptr<Constraint>constraint)
{
constraints.push_back(constraint.release());
}
#endif
/**
* @brief Invoke a function on each child Constraint
*

View File

@ -794,6 +794,18 @@ public:
return true;
}
/**
* @brief Validate a value against a PatternConstraint
*
* @param constraint Constraint that the target must validate against
*
* @return \c true if the constraint is satisfied; \c false otherwise
*/
virtual bool visit(const constraints::PolyConstraint &constraint)
{
return constraint.validate(target, context, results);
}
/**
* @brief Validate a value against a PropertiesConstraint
*

View File

@ -0,0 +1,97 @@
#include <gtest/gtest.h>
#include <iostream>
#include <valijson/adapters/rapidjson_adapter.hpp>
#include <valijson/schema.hpp>
#include <valijson/validation_results.hpp>
#include <valijson/validator.hpp>
namespace {
using valijson::adapters::Adapter;
using valijson::Schema;
using valijson::Validator;
using valijson::ValidationResults;
using valijson::adapters::RapidJsonAdapter;
class StubPolyConstraint : public valijson::constraints::PolyConstraint
{
bool shouldValidate;
public:
StubPolyConstraint(bool shouldValidate)
: shouldValidate(shouldValidate) { }
virtual Constraint * cloneInto(void *ptr) const
{
return new (ptr) StubPolyConstraint(shouldValidate);
}
virtual size_t sizeOf() const
{
return sizeof(StubPolyConstraint);
}
virtual bool validate(const Adapter &target,
const std::vector<std::string> &context,
ValidationResults *results) const
{
if (shouldValidate) {
return true;
}
if (results) {
results->pushError(context,
"StubPolyConstraint intentionally failed validation");
}
return false;
}
};
} // end anonymous namespace
class TestPolyConstraint : public testing::Test
{
};
TEST_F(TestPolyConstraint, ValidationCanPass)
{
StubPolyConstraint stubPolyConstraint(true);
Schema schema;
schema.addConstraintToSubschema(stubPolyConstraint, schema.root());
rapidjson::Document document;
RapidJsonAdapter adapter(document);
ValidationResults results;
Validator validator;
EXPECT_TRUE(validator.validate(schema, adapter, &results));
EXPECT_EQ(size_t(0), results.numErrors());
}
TEST_F(TestPolyConstraint, ValidationCanFail)
{
StubPolyConstraint stubPolyConstraint(false);
Schema schema;
schema.addConstraintToSubschema(stubPolyConstraint, schema.root());
rapidjson::Document document;
RapidJsonAdapter adapter(document);
ValidationResults results;
Validator validator;
EXPECT_FALSE(validator.validate(schema, adapter, &results));
EXPECT_EQ(size_t(1), results.numErrors());
ValidationResults::Error error;
EXPECT_TRUE(results.popError(error));
EXPECT_STREQ("StubPolyConstraint intentionally failed validation",
error.description.c_str());
}

View File

@ -19,6 +19,7 @@
6A725F4817F6404100D6B2FF /* test_property_tree_adapter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6AB8FEC417E92B100028E147 /* test_property_tree_adapter.cpp */; };
6A725F4917F6404100D6B2FF /* test_rapidjson_adapter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6AC18D3917CC874100FE0EC9 /* test_rapidjson_adapter.cpp */; };
6A725F4A17F6404100D6B2FF /* test_validator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6AC18D3517CC86E000FE0EC9 /* test_validator.cpp */; };
6A773AAF1CB5CA8C007D66FA /* test_poly_constraint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6A773AAE1CB5CA8C007D66FA /* test_poly_constraint.cpp */; };
6A9E1856194DC44B003F1C4C /* test_fetch_document_callback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6AA8A5DA17F8BDCA002728A0 /* test_fetch_document_callback.cpp */; };
6AA822FF1C3F38D4007103A7 /* test_picojson_adapter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6AA822FE1C3F38D4007103A7 /* test_picojson_adapter.cpp */; };
6AB2D0EF1C610ACB007F0EFF /* test_nlohmann_json_adapter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6AB2D0EE1C610ACB007F0EFF /* test_nlohmann_json_adapter.cpp */; };
@ -111,6 +112,8 @@
6A725F7917F89CD500D6B2FF /* read_stream.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = read_stream.hpp; sourceTree = "<group>"; };
6A725F7A17F89CD500D6B2FF /* url.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = url.hpp; sourceTree = "<group>"; };
6A725F7F17F89CD500D6B2FF /* urdl.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = urdl.cpp; sourceTree = "<group>"; };
6A773AAD1CB5CA1F007D66FA /* Authors */ = {isa = PBXFileReference; lastKnownFileType = text; name = Authors; path = ../Authors; sourceTree = "<group>"; };
6A773AAE1CB5CA8C007D66FA /* test_poly_constraint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = test_poly_constraint.cpp; sourceTree = "<group>"; };
6A8699EC17CD8641006864FA /* additionalItems.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = additionalItems.json; sourceTree = "<group>"; };
6A8699ED17CD8641006864FA /* additionalProperties.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = additionalProperties.json; sourceTree = "<group>"; };
6A8699EE17CD8641006864FA /* dependencies.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = dependencies.json; sourceTree = "<group>"; };
@ -791,6 +794,7 @@
6AB8FE9217E6BE770028E147 /* test_jsoncpp_adapter.cpp */,
6AB2D0EE1C610ACB007F0EFF /* test_nlohmann_json_adapter.cpp */,
6AA822FE1C3F38D4007103A7 /* test_picojson_adapter.cpp */,
6A773AAE1CB5CA8C007D66FA /* test_poly_constraint.cpp */,
6AB8FEC417E92B100028E147 /* test_property_tree_adapter.cpp */,
6AC18D3917CC874100FE0EC9 /* test_rapidjson_adapter.cpp */,
6A725F4317F61B5100D6B2FF /* test_validation_errors.cpp */,
@ -803,6 +807,7 @@
6AC78AC417C5FBBC00674114 = {
isa = PBXGroup;
children = (
6A773AAD1CB5CA1F007D66FA /* Authors */,
6AD030F51B03FD9900B957E5 /* LICENSE */,
6AD030F41B03FD9000B957E5 /* README.md */,
6A506D101AF884D700C2C818 /* doc */,
@ -1132,6 +1137,7 @@
6A725F4617F6404100D6B2FF /* test_adapter_comparison.cpp in Sources */,
6A725F4717F6404100D6B2FF /* test_jsoncpp_adapter.cpp in Sources */,
6A725F4817F6404100D6B2FF /* test_property_tree_adapter.cpp in Sources */,
6A773AAF1CB5CA8C007D66FA /* test_poly_constraint.cpp in Sources */,
6AD3490118FF56FB004BDEE7 /* gtest_main.cc in Sources */,
6AB2D0EF1C610ACB007F0EFF /* test_nlohmann_json_adapter.cpp in Sources */,
6A5C5D2A1C5B13D4004F40ED /* test_json11_adapter.cpp in Sources */,