mirror of
https://github.com/tristanpenman/valijson.git
synced 2025-01-06 00:31:11 +01:00
Improve contexts for error reporting, and fix unicode bug.
This commit is contained in:
parent
280250dbc8
commit
467368d022
@ -69,8 +69,15 @@ int main(int argc, char *argv[])
|
|||||||
ValidationResults::Error error;
|
ValidationResults::Error error;
|
||||||
unsigned int errorNum = 1;
|
unsigned int errorNum = 1;
|
||||||
while (results.popError(error)) {
|
while (results.popError(error)) {
|
||||||
|
|
||||||
|
std::string context;
|
||||||
|
std::vector<std::string>::iterator itr = error.context.begin();
|
||||||
|
for (; itr != error.context.end(); itr++) {
|
||||||
|
context += *itr;
|
||||||
|
}
|
||||||
|
|
||||||
cerr << "Error #" << errorNum << std::endl
|
cerr << "Error #" << errorNum << std::endl
|
||||||
<< " context: " << error.context << endl
|
<< " context: " << context << endl
|
||||||
<< " desc: " << error.description << endl;
|
<< " desc: " << error.description << endl;
|
||||||
++errorNum;
|
++errorNum;
|
||||||
}
|
}
|
||||||
|
@ -41,8 +41,9 @@ inline int u8_strlen(const char *s)
|
|||||||
int count = 0;
|
int count = 0;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
while (u8_nextchar(s, &i) != 0)
|
while (s[i] != 0 && u8_nextchar(s, &i) != 0) {
|
||||||
count++;
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace valijson {
|
namespace valijson {
|
||||||
|
|
||||||
@ -36,12 +37,12 @@ public:
|
|||||||
* @param context Context string to use
|
* @param context Context string to use
|
||||||
* @param description Description string to use
|
* @param description Description string to use
|
||||||
*/
|
*/
|
||||||
Error(const std::string &context, const std::string &description)
|
Error(const std::vector<std::string> &context, const std::string &description)
|
||||||
: context(context),
|
: context(context),
|
||||||
description(description) { }
|
description(description) { }
|
||||||
|
|
||||||
/// Path to the node that failed validation.
|
/// Path to the node that failed validation.
|
||||||
std::string context;
|
std::vector<std::string> context;
|
||||||
|
|
||||||
/// A detailed description of the validation error.
|
/// A detailed description of the validation error.
|
||||||
std::string description;
|
std::string description;
|
||||||
@ -72,7 +73,7 @@ public:
|
|||||||
* @param description Description of the validation error.
|
* @param description Description of the validation error.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
pushError(const std::string &context, const std::string &description)
|
pushError(const std::vector<std::string> &context, const std::string &description)
|
||||||
{
|
{
|
||||||
errors.push_back(Error(context, description));
|
errors.push_back(Error(context, description));
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ public:
|
|||||||
* stop immediately.
|
* stop immediately.
|
||||||
*/
|
*/
|
||||||
ValidationVisitor(const AdapterType &target,
|
ValidationVisitor(const AdapterType &target,
|
||||||
const std::string &context,
|
const std::vector<std::string> &context,
|
||||||
const bool strictTypes,
|
const bool strictTypes,
|
||||||
ValidationResults *results)
|
ValidationResults *results)
|
||||||
: target(target),
|
: target(target),
|
||||||
@ -120,7 +120,7 @@ public:
|
|||||||
if (results) {
|
if (results) {
|
||||||
validated = false;
|
validated = false;
|
||||||
results->pushError(context,
|
results->pushError(context,
|
||||||
std::string("Failed to validate against child schema at index #") +
|
std::string("Failed to validate against child schema #") +
|
||||||
boost::lexical_cast<std::string>(index) + " of allOf constraint.");
|
boost::lexical_cast<std::string>(index) + " of allOf constraint.");
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
@ -165,7 +165,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (results) {
|
if (results) {
|
||||||
results->pushError(context, "Failed to validate against any child schemas.");
|
results->pushError(context, "Failed to validate against any child schemas allowed by anyOf constraint.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -305,10 +305,10 @@ public:
|
|||||||
// Validate all items against single schema
|
// Validate all items against single schema
|
||||||
unsigned int index = 0;
|
unsigned int index = 0;
|
||||||
BOOST_FOREACH( const AdapterType arrayItem, target.getArray() ) {
|
BOOST_FOREACH( const AdapterType arrayItem, target.getArray() ) {
|
||||||
|
std::vector<std::string> newContext = context;
|
||||||
|
newContext.push_back("[" + boost::lexical_cast<std::string>(index) + "]");
|
||||||
ValidationVisitor<AdapterType> v(arrayItem,
|
ValidationVisitor<AdapterType> v(arrayItem,
|
||||||
context + "[" + boost::lexical_cast<std::string>(index) + "]",
|
newContext, strictTypes, results);
|
||||||
strictTypes,
|
|
||||||
results);
|
|
||||||
if (!v.validateSchema(*constraint.itemSchema)) {
|
if (!v.validateSchema(*constraint.itemSchema)) {
|
||||||
if (results) {
|
if (results) {
|
||||||
results->pushError(context, "Failed to validate item #" + boost::lexical_cast<std::string>(index) + " in array.");
|
results->pushError(context, "Failed to validate item #" + boost::lexical_cast<std::string>(index) + " in array.");
|
||||||
@ -338,10 +338,10 @@ public:
|
|||||||
// additionalItems schema
|
// additionalItems schema
|
||||||
unsigned int index = 0;
|
unsigned int index = 0;
|
||||||
BOOST_FOREACH( const AdapterType arrayItem, target.getArray() ) {
|
BOOST_FOREACH( const AdapterType arrayItem, target.getArray() ) {
|
||||||
|
std::vector<std::string> newContext = context;
|
||||||
|
newContext.push_back("[" + boost::lexical_cast<std::string>(index) + "]");
|
||||||
ValidationVisitor<AdapterType> v(arrayItem,
|
ValidationVisitor<AdapterType> v(arrayItem,
|
||||||
context + "[" + boost::lexical_cast<std::string>(index) + "]",
|
newContext, strictTypes, results);
|
||||||
strictTypes,
|
|
||||||
results);
|
|
||||||
if (index >= constraint.itemSchemas->size()) {
|
if (index >= constraint.itemSchemas->size()) {
|
||||||
if (constraint.additionalItemsSchema) {
|
if (constraint.additionalItemsSchema) {
|
||||||
if (!v.validateSchema(*constraint.additionalItemsSchema)) {
|
if (!v.validateSchema(*constraint.additionalItemsSchema)) {
|
||||||
@ -376,10 +376,10 @@ public:
|
|||||||
// Validate each item against additional items schema
|
// Validate each item against additional items schema
|
||||||
unsigned int index = 0;
|
unsigned int index = 0;
|
||||||
BOOST_FOREACH( const AdapterType arrayItem, target.getArray() ) {
|
BOOST_FOREACH( const AdapterType arrayItem, target.getArray() ) {
|
||||||
|
std::vector<std::string> newContext = context;
|
||||||
|
newContext.push_back("[" + boost::lexical_cast<std::string>(index) + "]");
|
||||||
ValidationVisitor<AdapterType> v(arrayItem,
|
ValidationVisitor<AdapterType> v(arrayItem,
|
||||||
context + "[" + boost::lexical_cast<std::string>(index) + "]",
|
newContext, strictTypes, results);
|
||||||
strictTypes,
|
|
||||||
results);
|
|
||||||
if (!v.validateSchema(*constraint.additionalItemsSchema)) {
|
if (!v.validateSchema(*constraint.additionalItemsSchema)) {
|
||||||
if (results) {
|
if (results) {
|
||||||
results->pushError(context, "Failed to validate item #" +
|
results->pushError(context, "Failed to validate item #" +
|
||||||
@ -729,7 +729,11 @@ public:
|
|||||||
const std::string propertyName = m.first;
|
const std::string propertyName = m.first;
|
||||||
bool propertyNameMatched = false;
|
bool propertyNameMatched = false;
|
||||||
|
|
||||||
ValidationVisitor<AdapterType> v(m.second, context + "." + m.first, strictTypes, results);
|
std::vector<std::string> newContext = context;
|
||||||
|
newContext.push_back("[\"" + m.first + "\"]");
|
||||||
|
|
||||||
|
ValidationVisitor<AdapterType> v(m.second,
|
||||||
|
newContext, strictTypes, results);
|
||||||
|
|
||||||
// Search for matching property name
|
// Search for matching property name
|
||||||
PropertiesConstraint::PropertySchemaMap::const_iterator itr =
|
PropertiesConstraint::PropertySchemaMap::const_iterator itr =
|
||||||
@ -739,8 +743,8 @@ public:
|
|||||||
if (!v.validateSchema(*itr->second)) {
|
if (!v.validateSchema(*itr->second)) {
|
||||||
if (results) {
|
if (results) {
|
||||||
results->pushError(context,
|
results->pushError(context,
|
||||||
"Failed to validate against 'properties' schema associated with property name '" +
|
"Failed to validate against schema associated with property name '" +
|
||||||
propertyName + "'.");
|
propertyName + "' in properties constraint.");
|
||||||
validated = false;
|
validated = false;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
@ -757,8 +761,8 @@ public:
|
|||||||
if (!v.validateSchema(*itr->second)) {
|
if (!v.validateSchema(*itr->second)) {
|
||||||
if (results) {
|
if (results) {
|
||||||
results->pushError(context,
|
results->pushError(context,
|
||||||
"Failed to validate against 'patternProperties' schema associated with regex '" +
|
"Failed to validate against schema associated with regex '" +
|
||||||
itr->first + "'.");
|
itr->first + "' in patternProperties constraint.");
|
||||||
validated = false;
|
validated = false;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
@ -782,7 +786,7 @@ public:
|
|||||||
continue;
|
continue;
|
||||||
} else if (results) {
|
} else if (results) {
|
||||||
results->pushError(context, "Failed to validate property '" +
|
results->pushError(context, "Failed to validate property '" +
|
||||||
propertyName + "' against additionalProperties schema.");
|
propertyName + "' against schema in additionalProperties constraint.");
|
||||||
validated = false;
|
validated = false;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
@ -965,8 +969,8 @@ private:
|
|||||||
/// Reference to the JSON value being validated
|
/// Reference to the JSON value being validated
|
||||||
const AdapterType ⌖
|
const AdapterType ⌖
|
||||||
|
|
||||||
/// String describing the current object context
|
/// Vector of strings describing the current object context
|
||||||
const std::string context;
|
const std::vector<std::string> context;
|
||||||
|
|
||||||
/// Optional pointer to a ValidationResults object to be populated
|
/// Optional pointer to a ValidationResults object to be populated
|
||||||
ValidationResults *results;
|
ValidationResults *results;
|
||||||
|
@ -18,8 +18,8 @@ class ValidationResults;
|
|||||||
* This class wraps a Schema object, and encapsulates the logic required to
|
* This class wraps a Schema object, and encapsulates the logic required to
|
||||||
* validate rapidjson values aginst the schema.
|
* validate rapidjson values aginst the schema.
|
||||||
*/
|
*/
|
||||||
class Validator {
|
class Validator
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -68,7 +68,7 @@ public:
|
|||||||
bool validate(const AdapterType &target, ValidationResults *results)
|
bool validate(const AdapterType &target, ValidationResults *results)
|
||||||
{
|
{
|
||||||
// Construct a ValidationVisitor to perform validation at the root level
|
// Construct a ValidationVisitor to perform validation at the root level
|
||||||
ValidationVisitor<AdapterType> v(target, std::string(),
|
ValidationVisitor<AdapterType> v(target, std::vector<std::string>(1, "<root>"),
|
||||||
strictTypes, results);
|
strictTypes, results);
|
||||||
|
|
||||||
return v.validateSchema(*schema);
|
return v.validateSchema(*schema);
|
||||||
|
@ -53,37 +53,47 @@ TEST_F(TestValidationErrors, AllOfConstraintFailure)
|
|||||||
ValidationResults::Error error;
|
ValidationResults::Error error;
|
||||||
|
|
||||||
EXPECT_TRUE( results.popError(error) );
|
EXPECT_TRUE( results.popError(error) );
|
||||||
EXPECT_EQ( "[0]", error.context );
|
EXPECT_EQ( 2, error.context.size() );
|
||||||
|
EXPECT_EQ( "<root>", error.context[0] );
|
||||||
|
EXPECT_EQ( "[0]", error.context[1] );
|
||||||
EXPECT_EQ( "Value type not permitted by 'type' constraint.", error.description );
|
EXPECT_EQ( "Value type not permitted by 'type' constraint.", error.description );
|
||||||
|
|
||||||
EXPECT_TRUE( results.popError(error) );
|
EXPECT_TRUE( results.popError(error) );
|
||||||
EXPECT_EQ( "", error.context );
|
EXPECT_EQ( 1, error.context.size() );
|
||||||
|
EXPECT_EQ( "<root>", error.context[0] );
|
||||||
EXPECT_EQ( "Failed to validate item #0 in array.", error.description );
|
EXPECT_EQ( "Failed to validate item #0 in array.", error.description );
|
||||||
|
|
||||||
EXPECT_TRUE( results.popError(error) );
|
EXPECT_TRUE( results.popError(error) );
|
||||||
EXPECT_EQ( "[1]", error.context );
|
EXPECT_EQ( 2, error.context.size() );
|
||||||
|
EXPECT_EQ( "<root>", error.context[0] );
|
||||||
|
EXPECT_EQ( "[1]", error.context[1] );
|
||||||
EXPECT_EQ( "Value type not permitted by 'type' constraint.", error.description );
|
EXPECT_EQ( "Value type not permitted by 'type' constraint.", error.description );
|
||||||
|
|
||||||
EXPECT_TRUE( results.popError(error) );
|
EXPECT_TRUE( results.popError(error) );
|
||||||
EXPECT_EQ( "", error.context );
|
EXPECT_EQ( 1, error.context.size() );
|
||||||
|
EXPECT_EQ( "<root>", error.context[0] );
|
||||||
EXPECT_EQ( "Failed to validate item #1 in array.", error.description );
|
EXPECT_EQ( "Failed to validate item #1 in array.", error.description );
|
||||||
|
|
||||||
EXPECT_TRUE( results.popError(error) );
|
EXPECT_TRUE( results.popError(error) );
|
||||||
EXPECT_EQ( "[2]", error.context );
|
EXPECT_EQ( 2, error.context.size() );
|
||||||
|
EXPECT_EQ( "<root>", error.context[0] );
|
||||||
|
EXPECT_EQ( "[2]", error.context[1] );
|
||||||
EXPECT_EQ( "Value type not permitted by 'type' constraint.", error.description );
|
EXPECT_EQ( "Value type not permitted by 'type' constraint.", error.description );
|
||||||
|
|
||||||
EXPECT_TRUE( results.popError(error) );
|
EXPECT_TRUE( results.popError(error) );
|
||||||
EXPECT_EQ( "", error.context );
|
EXPECT_EQ( 1, error.context.size() );
|
||||||
|
EXPECT_EQ( "<root>", error.context[0] );
|
||||||
EXPECT_EQ( "Failed to validate item #2 in array.", error.description );
|
EXPECT_EQ( "Failed to validate item #2 in array.", error.description );
|
||||||
|
|
||||||
EXPECT_TRUE( results.popError(error) );
|
EXPECT_TRUE( results.popError(error) );
|
||||||
EXPECT_EQ( "", error.context );
|
EXPECT_EQ( 1, error.context.size() );
|
||||||
EXPECT_EQ( "Failed to validate against child schema at index #0 of allOf constraint.", error.description );
|
EXPECT_EQ( "<root>", error.context[0] );
|
||||||
|
EXPECT_EQ( "Failed to validate against child schema #0 of allOf constraint.", error.description );
|
||||||
|
|
||||||
EXPECT_FALSE( results.popError(error) );
|
EXPECT_FALSE( results.popError(error) );
|
||||||
|
|
||||||
while (results.popError(error)) {
|
while (results.popError(error)) {
|
||||||
std::cerr << error.context << std::endl;
|
//std::cerr << error.context << std::endl;
|
||||||
std::cerr << error.description << std::endl;
|
std::cerr << error.description << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
6A725F4917F6404100D6B2FF /* test_rapidjson_adapter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6AC18D3917CC874100FE0EC9 /* test_rapidjson_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 */; };
|
6A725F4A17F6404100D6B2FF /* test_validator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6AC18D3517CC86E000FE0EC9 /* test_validator.cpp */; };
|
||||||
6A725F4D17F8964B00D6B2FF /* test_uri_resolution.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6A725F4B17F8956A00D6B2FF /* test_uri_resolution.cpp */; };
|
6A725F4D17F8964B00D6B2FF /* test_uri_resolution.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6A725F4B17F8956A00D6B2FF /* test_uri_resolution.cpp */; };
|
||||||
6AA8A5DB17F8BDCA002728A0 /* test_dereference_callback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6AA8A5DA17F8BDCA002728A0 /* test_dereference_callback.cpp */; };
|
6A9E1856194DC44B003F1C4C /* test_dereference_callback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6AA8A5DA17F8BDCA002728A0 /* test_dereference_callback.cpp */; };
|
||||||
6AB8FE8717E6A56F0028E147 /* external_schema.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6AB8FE8617E6A56F0028E147 /* external_schema.cpp */; };
|
6AB8FE8717E6A56F0028E147 /* external_schema.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6AB8FE8617E6A56F0028E147 /* external_schema.cpp */; };
|
||||||
6AB8FE8D17E6A57E0028E147 /* libboost_regex-mt.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 6A477F8417D6BCBB0013571C /* libboost_regex-mt.dylib */; };
|
6AB8FE8D17E6A57E0028E147 /* libboost_regex-mt.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 6A477F8417D6BCBB0013571C /* libboost_regex-mt.dylib */; };
|
||||||
6AB8FEAD17E6C0D70028E147 /* json_reader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6AB8FEA717E6C08D0028E147 /* json_reader.cpp */; };
|
6AB8FEAD17E6C0D70028E147 /* json_reader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6AB8FEA717E6C08D0028E147 /* json_reader.cpp */; };
|
||||||
@ -845,7 +845,6 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
6AA8A5DB17F8BDCA002728A0 /* test_dereference_callback.cpp in Sources */,
|
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@ -855,6 +854,7 @@
|
|||||||
files = (
|
files = (
|
||||||
6AB8FEAD17E6C0D70028E147 /* json_reader.cpp in Sources */,
|
6AB8FEAD17E6C0D70028E147 /* json_reader.cpp in Sources */,
|
||||||
6AB8FEAE17E6C0D70028E147 /* json_value.cpp in Sources */,
|
6AB8FEAE17E6C0D70028E147 /* json_value.cpp in Sources */,
|
||||||
|
6A9E1856194DC44B003F1C4C /* test_dereference_callback.cpp in Sources */,
|
||||||
6AB8FEAF17E6C0D70028E147 /* json_writer.cpp in Sources */,
|
6AB8FEAF17E6C0D70028E147 /* json_writer.cpp in Sources */,
|
||||||
6A725F4517F61D7000D6B2FF /* test_validation_errors.cpp in Sources */,
|
6A725F4517F61D7000D6B2FF /* test_validation_errors.cpp in Sources */,
|
||||||
6AF70BB018FE728800342325 /* gtest-all.cc in Sources */,
|
6AF70BB018FE728800342325 /* gtest-all.cc in Sources */,
|
||||||
|
Loading…
Reference in New Issue
Block a user