mirror of
https://github.com/tristanpenman/valijson.git
synced 2024-12-13 18:45:11 +01:00
Merge branch 'add-poly-constraint'
This commit is contained in:
commit
28bcbcbbb2
20
Authors
Normal file
20
Authors
Normal 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
|
@ -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)
|
||||
|
1
LICENSE
1
LICENSE
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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
|
||||
*
|
||||
|
97
tests/test_poly_constraint.cpp
Normal file
97
tests/test_poly_constraint.cpp
Normal 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());
|
||||
}
|
@ -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 */,
|
||||
|
Loading…
Reference in New Issue
Block a user