mirror of
https://github.com/tristanpenman/valijson.git
synced 2024-12-12 10:13:51 +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;
|
||||
unsigned int errorNum = 1;
|
||||
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
|
||||
<< " context: " << error.context << endl
|
||||
<< " context: " << context << endl
|
||||
<< " desc: " << error.description << endl;
|
||||
++errorNum;
|
||||
}
|
||||
|
@ -41,8 +41,9 @@ inline int u8_strlen(const char *s)
|
||||
int count = 0;
|
||||
int i = 0;
|
||||
|
||||
while (u8_nextchar(s, &i) != 0)
|
||||
while (s[i] != 0 && u8_nextchar(s, &i) != 0) {
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include <deque>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace valijson {
|
||||
|
||||
@ -36,12 +37,12 @@ public:
|
||||
* @param context Context 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),
|
||||
description(description) { }
|
||||
|
||||
/// Path to the node that failed validation.
|
||||
std::string context;
|
||||
std::vector<std::string> context;
|
||||
|
||||
/// A detailed description of the validation error.
|
||||
std::string description;
|
||||
@ -72,7 +73,7 @@ public:
|
||||
* @param description Description of the validation error.
|
||||
*/
|
||||
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));
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ public:
|
||||
* stop immediately.
|
||||
*/
|
||||
ValidationVisitor(const AdapterType &target,
|
||||
const std::string &context,
|
||||
const std::vector<std::string> &context,
|
||||
const bool strictTypes,
|
||||
ValidationResults *results)
|
||||
: target(target),
|
||||
@ -120,7 +120,7 @@ public:
|
||||
if (results) {
|
||||
validated = false;
|
||||
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.");
|
||||
} else {
|
||||
return false;
|
||||
@ -165,7 +165,7 @@ public:
|
||||
}
|
||||
|
||||
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;
|
||||
@ -305,10 +305,10 @@ public:
|
||||
// Validate all items against single schema
|
||||
unsigned int index = 0;
|
||||
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,
|
||||
context + "[" + boost::lexical_cast<std::string>(index) + "]",
|
||||
strictTypes,
|
||||
results);
|
||||
newContext, strictTypes, results);
|
||||
if (!v.validateSchema(*constraint.itemSchema)) {
|
||||
if (results) {
|
||||
results->pushError(context, "Failed to validate item #" + boost::lexical_cast<std::string>(index) + " in array.");
|
||||
@ -338,10 +338,10 @@ public:
|
||||
// additionalItems schema
|
||||
unsigned int index = 0;
|
||||
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,
|
||||
context + "[" + boost::lexical_cast<std::string>(index) + "]",
|
||||
strictTypes,
|
||||
results);
|
||||
newContext, strictTypes, results);
|
||||
if (index >= constraint.itemSchemas->size()) {
|
||||
if (constraint.additionalItemsSchema) {
|
||||
if (!v.validateSchema(*constraint.additionalItemsSchema)) {
|
||||
@ -376,10 +376,10 @@ public:
|
||||
// Validate each item against additional items schema
|
||||
unsigned int index = 0;
|
||||
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,
|
||||
context + "[" + boost::lexical_cast<std::string>(index) + "]",
|
||||
strictTypes,
|
||||
results);
|
||||
newContext, strictTypes, results);
|
||||
if (!v.validateSchema(*constraint.additionalItemsSchema)) {
|
||||
if (results) {
|
||||
results->pushError(context, "Failed to validate item #" +
|
||||
@ -729,7 +729,11 @@ public:
|
||||
const std::string propertyName = m.first;
|
||||
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
|
||||
PropertiesConstraint::PropertySchemaMap::const_iterator itr =
|
||||
@ -739,8 +743,8 @@ public:
|
||||
if (!v.validateSchema(*itr->second)) {
|
||||
if (results) {
|
||||
results->pushError(context,
|
||||
"Failed to validate against 'properties' schema associated with property name '" +
|
||||
propertyName + "'.");
|
||||
"Failed to validate against schema associated with property name '" +
|
||||
propertyName + "' in properties constraint.");
|
||||
validated = false;
|
||||
} else {
|
||||
return false;
|
||||
@ -757,8 +761,8 @@ public:
|
||||
if (!v.validateSchema(*itr->second)) {
|
||||
if (results) {
|
||||
results->pushError(context,
|
||||
"Failed to validate against 'patternProperties' schema associated with regex '" +
|
||||
itr->first + "'.");
|
||||
"Failed to validate against schema associated with regex '" +
|
||||
itr->first + "' in patternProperties constraint.");
|
||||
validated = false;
|
||||
} else {
|
||||
return false;
|
||||
@ -782,7 +786,7 @@ public:
|
||||
continue;
|
||||
} else if (results) {
|
||||
results->pushError(context, "Failed to validate property '" +
|
||||
propertyName + "' against additionalProperties schema.");
|
||||
propertyName + "' against schema in additionalProperties constraint.");
|
||||
validated = false;
|
||||
} else {
|
||||
return false;
|
||||
@ -965,8 +969,8 @@ private:
|
||||
/// Reference to the JSON value being validated
|
||||
const AdapterType ⌖
|
||||
|
||||
/// String describing the current object context
|
||||
const std::string context;
|
||||
/// Vector of strings describing the current object context
|
||||
const std::vector<std::string> context;
|
||||
|
||||
/// Optional pointer to a ValidationResults object to be populated
|
||||
ValidationResults *results;
|
||||
|
@ -18,8 +18,8 @@ class ValidationResults;
|
||||
* This class wraps a Schema object, and encapsulates the logic required to
|
||||
* validate rapidjson values aginst the schema.
|
||||
*/
|
||||
class Validator {
|
||||
|
||||
class Validator
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
@ -68,7 +68,7 @@ public:
|
||||
bool validate(const AdapterType &target, ValidationResults *results)
|
||||
{
|
||||
// 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);
|
||||
|
||||
return v.validateSchema(*schema);
|
||||
|
@ -53,37 +53,47 @@ TEST_F(TestValidationErrors, AllOfConstraintFailure)
|
||||
ValidationResults::Error 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_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_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_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_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_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_TRUE( results.popError(error) );
|
||||
EXPECT_EQ( "", error.context );
|
||||
EXPECT_EQ( "Failed to validate against child schema at index #0 of allOf constraint.", error.description );
|
||||
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_FALSE( 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;
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
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 */; };
|
||||
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 */; };
|
||||
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 */; };
|
||||
@ -845,7 +845,6 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
6AA8A5DB17F8BDCA002728A0 /* test_dereference_callback.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -855,6 +854,7 @@
|
||||
files = (
|
||||
6AB8FEAD17E6C0D70028E147 /* json_reader.cpp in Sources */,
|
||||
6AB8FEAE17E6C0D70028E147 /* json_value.cpp in Sources */,
|
||||
6A9E1856194DC44B003F1C4C /* test_dereference_callback.cpp in Sources */,
|
||||
6AB8FEAF17E6C0D70028E147 /* json_writer.cpp in Sources */,
|
||||
6A725F4517F61D7000D6B2FF /* test_validation_errors.cpp in Sources */,
|
||||
6AF70BB018FE728800342325 /* gtest-all.cc in Sources */,
|
||||
|
Loading…
Reference in New Issue
Block a user