mirror of
https://github.com/Tencent/rapidjson.git
synced 2025-11-10 16:37:46 +01:00
code and tests
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,6 +3,7 @@
|
|||||||
!/bin/encodings
|
!/bin/encodings
|
||||||
!/bin/jsonchecker
|
!/bin/jsonchecker
|
||||||
!/bin/types
|
!/bin/types
|
||||||
|
!/bin/unittestschema
|
||||||
/build
|
/build
|
||||||
/doc/html
|
/doc/html
|
||||||
/doc/doxygen_*.db
|
/doc/doxygen_*.db
|
||||||
|
|||||||
139
bin/unittestschema/address.json
Normal file
139
bin/unittestschema/address.json
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"version": {
|
||||||
|
"$ref": "#/definitions/decimal_type"
|
||||||
|
},
|
||||||
|
"address": {
|
||||||
|
"$ref": "#/definitions/address_type"
|
||||||
|
},
|
||||||
|
"phones": {
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
|
"maxItems": 2,
|
||||||
|
"uniqueItems": true,
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/phone_type"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"names": {
|
||||||
|
"type": "array",
|
||||||
|
"items": [
|
||||||
|
{ "type": "string" },
|
||||||
|
{ "type": "string" }
|
||||||
|
],
|
||||||
|
"additionalItems": false
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
|
"type": "object",
|
||||||
|
"patternProperties": {
|
||||||
|
"^S_": { "type": "string" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"gender": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["M", "F"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"dependencies": {
|
||||||
|
"address": [ "version" ],
|
||||||
|
"names": {
|
||||||
|
"properties": {
|
||||||
|
"version": { "$ref": "#/definitions/decimal_type" }
|
||||||
|
},
|
||||||
|
"required": ["version"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"address_type": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"number": {
|
||||||
|
"$ref": "#/definitions/positiveInt_type"
|
||||||
|
},
|
||||||
|
"street1": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"street2": {
|
||||||
|
"type": ["string", "null"]
|
||||||
|
},
|
||||||
|
"street3": {
|
||||||
|
"not": { "type": ["boolean", "number", ",integer", "object", "null"] }
|
||||||
|
},
|
||||||
|
"city": {
|
||||||
|
"type": "string",
|
||||||
|
"maxLength": 10,
|
||||||
|
"minLength": 4
|
||||||
|
},
|
||||||
|
"area": {
|
||||||
|
"oneOf": [
|
||||||
|
{ "$ref": "#/definitions/county_type" },
|
||||||
|
{ "$ref": "#/definitions/province_type" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"country": {
|
||||||
|
"allOf": [
|
||||||
|
{ "$ref": "#/definitions/country_type" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"postcode": {
|
||||||
|
"anyOf": [
|
||||||
|
{ "type": "string", "pattern": "^[A-Z]{2}[0-9]{1,2} [0-9][A-Z]{2}$" },
|
||||||
|
{ "type": "string", "pattern": "^[0-9]{5}$" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"minProperties": 7,
|
||||||
|
"required": [
|
||||||
|
"number",
|
||||||
|
"street1",
|
||||||
|
"city"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"country_type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["UK", "Canada"]
|
||||||
|
},
|
||||||
|
"county_type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["Sussex", "Surrey", "Kent"]
|
||||||
|
},
|
||||||
|
"province_type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["Quebec", "BC", "Alberta"]
|
||||||
|
},
|
||||||
|
"date_type": {
|
||||||
|
"pattern": "^([0-9]([0-9]([0-9][1-9]|[1-9]0)|[1-9]00)|[1-9]000)(-(0[1-9]|1[0-2])(-(0[1-9]|[1-2][0-9]|3[0-1]))?)?$",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"positiveInt_type": {
|
||||||
|
"minimum": 0,
|
||||||
|
"exclusiveMinimum": true,
|
||||||
|
"maximum": 100,
|
||||||
|
"exclusiveMaximum": true,
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"decimal_type": {
|
||||||
|
"multipleOf": 0.1,
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"time_type": {
|
||||||
|
"pattern": "^([01][0-9]|2[0-3]):[0-5][0-9]:([0-5][0-9]|60)(\\.[0-9]+)?$",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"unsignedInt_type": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 99999
|
||||||
|
},
|
||||||
|
"phone_type": {
|
||||||
|
"pattern": "^[0-9]*-[0-9]*",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"url_type": {
|
||||||
|
"pattern": "^\\S*$",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
7
bin/unittestschema/allOf_address.json
Normal file
7
bin/unittestschema/allOf_address.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "http://localhost:1234/address.json#"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
7
bin/unittestschema/anyOf_address.json
Normal file
7
bin/unittestschema/anyOf_address.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "http://localhost:1234/address.json#"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
7
bin/unittestschema/oneOf_address.json
Normal file
7
bin/unittestschema/oneOf_address.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"$ref": "http://localhost:1234/address.json#"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -7,9 +7,122 @@
|
|||||||
#include "rapidjson/schema.h"
|
#include "rapidjson/schema.h"
|
||||||
#include "rapidjson/stringbuffer.h"
|
#include "rapidjson/stringbuffer.h"
|
||||||
#include "rapidjson/prettywriter.h"
|
#include "rapidjson/prettywriter.h"
|
||||||
|
#include <string>
|
||||||
|
#include <regex>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
using namespace rapidjson;
|
using namespace rapidjson;
|
||||||
|
|
||||||
|
typedef GenericValue<UTF8<>, CrtAllocator > ValueType;
|
||||||
|
|
||||||
|
// Forward ref
|
||||||
|
static void CreateErrorMessages(const ValueType& errors, size_t depth, const char* context);
|
||||||
|
|
||||||
|
// Convert GenericValue to std::string
|
||||||
|
static std::string GetString(const ValueType& val) {
|
||||||
|
std::string str("");
|
||||||
|
if (val.IsString()) {
|
||||||
|
str = val.GetString();
|
||||||
|
} else if (val.IsDouble()) {
|
||||||
|
str = std::to_string(val.GetDouble());
|
||||||
|
} else if (val.IsUint()) {
|
||||||
|
str = std::to_string(val.GetUint());
|
||||||
|
} else if (val.IsInt()) {
|
||||||
|
str = std::to_string(val.GetInt());
|
||||||
|
} else if (val.IsUint64()) {
|
||||||
|
str = std::to_string(val.GetUint64());
|
||||||
|
} else if (val.IsInt64()) {
|
||||||
|
str = std::to_string(val.GetInt64());
|
||||||
|
} else if (val.IsBool()) {
|
||||||
|
str = std::to_string(val.GetBool());
|
||||||
|
} else if (val.IsFloat()) {
|
||||||
|
str = std::to_string(val.GetFloat());
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the error message for a named error
|
||||||
|
// Expects the error object to contain at least member properties:
|
||||||
|
// {
|
||||||
|
// "errorCode": <code>,
|
||||||
|
// "instanceRef": "<pointer>",
|
||||||
|
// "schemaRef": "<pointer>"
|
||||||
|
// }
|
||||||
|
// Additional properties may be present for use as inserts.
|
||||||
|
// An "errors" property may be present if there are child errors.
|
||||||
|
static void HandleError(const char* errorName, const ValueType& error, size_t depth, const char* context) {
|
||||||
|
// Get error code and look up error message text (English)
|
||||||
|
int code = error["errorCode"].GetInt();
|
||||||
|
std::string message(GetValidateError_En(static_cast<ValidateErrorCode>(code)));
|
||||||
|
// For each member property in the error, see if its name exists as an insert in the error message and if so replace with the stringified property value
|
||||||
|
// So for example - "Number '%actual' is not a multiple of the 'multipleOf' value '%expected'." - we would expect "actual" and "expected" members.
|
||||||
|
for (ValueType::ConstMemberIterator insertsItr = error.MemberBegin(); insertsItr != error.MemberEnd(); ++insertsItr) {
|
||||||
|
std::string insertRegex("\\%");
|
||||||
|
insertRegex += insertsItr->name.GetString(); // eg "\%actual"
|
||||||
|
if (std::regex_search(message, std::regex(insertRegex))) {
|
||||||
|
std::string insertString("");
|
||||||
|
const ValueType &insert = insertsItr->value;
|
||||||
|
if (insert.IsArray()) {
|
||||||
|
// Member is an array so create comma-separated list of items for the insert string
|
||||||
|
for (ValueType::ConstValueIterator itemsItr = insert.Begin(); itemsItr != insert.End(); ++itemsItr) {
|
||||||
|
if (itemsItr != insert.Begin()) insertString += ",";
|
||||||
|
insertString += GetString(*itemsItr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
insertString += GetString(insert);
|
||||||
|
}
|
||||||
|
message = std::regex_replace(message, std::regex(insertRegex), insertString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Output error message, references, context
|
||||||
|
std::string indent(depth*2, ' ');
|
||||||
|
std::cout << indent << "Error Name: " << errorName << std::endl;
|
||||||
|
std::cout << indent << "Message: " << message.c_str() << std::endl;
|
||||||
|
std::cout << indent << "Instance: " << error["instanceRef"].GetString() << std::endl;
|
||||||
|
std::cout << indent << "Schema: " << error["schemaRef"].GetString() << std::endl;
|
||||||
|
if (depth > 0 ) std::cout << indent << "Context: " << context << std::endl;
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
// If child errors exist, apply the process recursively to each error structure.
|
||||||
|
// This occurs for "oneOf", "allOf", "anyOf" and "dependencies" errors, so pass the error name as context.
|
||||||
|
if (error.HasMember("errors")) {
|
||||||
|
depth++;
|
||||||
|
const ValueType& childErrors = error["errors"];
|
||||||
|
if (childErrors.IsArray()) {
|
||||||
|
// Array - each item is an error structure - example
|
||||||
|
// "anyOf": {"errorCode": ..., "errors":[{"pattern": {"errorCode\": ...\"}}, {"pattern": {"errorCode\": ...}}]
|
||||||
|
for (ValueType::ConstValueIterator errorsItr = childErrors.Begin(); errorsItr != childErrors.End(); ++errorsItr) {
|
||||||
|
CreateErrorMessages(*errorsItr, depth, errorName);
|
||||||
|
}
|
||||||
|
} else if (childErrors.IsObject()) {
|
||||||
|
// Object - each member is an error structure - example
|
||||||
|
// "dependencies": {"errorCode": ..., "errors": {"address": {"required": {"errorCode": ...}}, "name": {"required": {"errorCode": ...}}}
|
||||||
|
for (ValueType::ConstMemberIterator propsItr = childErrors.MemberBegin(); propsItr != childErrors.MemberEnd(); ++propsItr) {
|
||||||
|
CreateErrorMessages(propsItr->value, depth, errorName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create error message for all errors in an error structure
|
||||||
|
// Context is used to indicate whether the error structure has a parent 'dependencies', 'allOf', 'anyOf' or 'oneOf' error
|
||||||
|
static void CreateErrorMessages(const ValueType& errors, size_t depth = 0, const char* context = 0) {
|
||||||
|
// Each member property contains one or more errors of a given type
|
||||||
|
for (ValueType::ConstMemberIterator errorTypeItr = errors.MemberBegin(); errorTypeItr != errors.MemberEnd(); ++errorTypeItr) {
|
||||||
|
const char* errorName = errorTypeItr->name.GetString();
|
||||||
|
const ValueType& errorContent = errorTypeItr->value;
|
||||||
|
if (errorContent.IsArray()) {
|
||||||
|
// Member is an array where each item is an error - eg "type": [{"errorCode": ...}, {"errorCode": ...}]
|
||||||
|
for (ValueType::ConstValueIterator contentItr = errorContent.Begin(); contentItr != errorContent.End(); ++contentItr) {
|
||||||
|
HandleError(errorName, *contentItr, depth, context);
|
||||||
|
}
|
||||||
|
} else if (errorContent.IsObject()) {
|
||||||
|
// Member is an object which is a single error - eg "type": {"errorCode": ... }
|
||||||
|
HandleError(errorName, errorContent, depth, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
if (argc != 2) {
|
if (argc != 2) {
|
||||||
fprintf(stderr, "Usage: schemavalidator schema.json < input.json\n");
|
fprintf(stderr, "Usage: schemavalidator schema.json < input.json\n");
|
||||||
@@ -65,6 +178,8 @@ int main(int argc, char *argv[]) {
|
|||||||
validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);
|
validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);
|
||||||
fprintf(stderr, "Invalid schema: %s\n", sb.GetString());
|
fprintf(stderr, "Invalid schema: %s\n", sb.GetString());
|
||||||
fprintf(stderr, "Invalid keyword: %s\n", validator.GetInvalidSchemaKeyword());
|
fprintf(stderr, "Invalid keyword: %s\n", validator.GetInvalidSchemaKeyword());
|
||||||
|
fprintf(stderr, "Invalid code: %d\n", validator.GetInvalidSchemaCode());
|
||||||
|
fprintf(stderr, "Invalid message: %s\n", GetValidateError_En(validator.GetInvalidSchemaCode()));
|
||||||
sb.Clear();
|
sb.Clear();
|
||||||
validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);
|
validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);
|
||||||
fprintf(stderr, "Invalid document: %s\n", sb.GetString());
|
fprintf(stderr, "Invalid document: %s\n", sb.GetString());
|
||||||
@@ -73,6 +188,7 @@ int main(int argc, char *argv[]) {
|
|||||||
PrettyWriter<StringBuffer> w(sb);
|
PrettyWriter<StringBuffer> w(sb);
|
||||||
validator.GetError().Accept(w);
|
validator.GetError().Accept(w);
|
||||||
fprintf(stderr, "Error report:\n%s\n", sb.GetString());
|
fprintf(stderr, "Error report:\n%s\n", sb.GetString());
|
||||||
|
CreateErrorMessages(validator.GetError());
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,6 +65,54 @@ inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Maps error code of validation into error message.
|
||||||
|
/*!
|
||||||
|
\ingroup RAPIDJSON_ERRORS
|
||||||
|
\param validateErrorCode Error code obtained from validator.
|
||||||
|
\return the error message.
|
||||||
|
\note User can make a copy of this function for localization.
|
||||||
|
Using switch-case is safer for future modification of error codes.
|
||||||
|
*/
|
||||||
|
inline const RAPIDJSON_ERROR_CHARTYPE* GetValidateError_En(ValidateErrorCode validateErrorCode) {
|
||||||
|
switch (validateErrorCode) {
|
||||||
|
case kValidateErrors: return RAPIDJSON_ERROR_STRING("One or more validation errors have occurred");
|
||||||
|
case kValidateErrorNone: return RAPIDJSON_ERROR_STRING("No error.");
|
||||||
|
|
||||||
|
case kValidateErrorMultipleOf: return RAPIDJSON_ERROR_STRING("Number '%actual' is not a multiple of the 'multipleOf' value '%expected'.");
|
||||||
|
case kValidateErrorMaximum: return RAPIDJSON_ERROR_STRING("Number '%actual' is greater than the 'maximum' value '%expected'.");
|
||||||
|
case kValidateErrorExclusiveMaximum: return RAPIDJSON_ERROR_STRING("Number '%actual' is greater than or equal to the 'exclusiveMaximum' value '%expected'.");
|
||||||
|
case kValidateErrorMinimum: return RAPIDJSON_ERROR_STRING("Number '%actual' is less than the 'minimum' value '%expected'.");
|
||||||
|
case kValidateErrorExclusiveMinimum: return RAPIDJSON_ERROR_STRING("Number '%actual' is less than or equal to the 'exclusiveMinimum' value '%expected'.");
|
||||||
|
|
||||||
|
case kValidateErrorMaxLength: return RAPIDJSON_ERROR_STRING("String '%actual' is longer than the 'maxLength' value '%expected'.");
|
||||||
|
case kValidateErrorMinLength: return RAPIDJSON_ERROR_STRING("String '%actual' is shorter than the 'minLength' value '%expected'.");
|
||||||
|
case kValidateErrorPattern: return RAPIDJSON_ERROR_STRING("String '%actual' does not match the 'pattern' regular expression.");
|
||||||
|
|
||||||
|
case kValidateErrorMaxItems: return RAPIDJSON_ERROR_STRING("Array of length '%actual' is longer than the 'maxItems' value '%expected'.");
|
||||||
|
case kValidateErrorMinItems: return RAPIDJSON_ERROR_STRING("Array of length '%actual' is shorter than the 'minItems' value '%expected'.");
|
||||||
|
case kValidateErrorUniqueItems: return RAPIDJSON_ERROR_STRING("Array has duplicate items at indices '%duplicates' but 'uniqueItems' is true.");
|
||||||
|
case kValidateErrorAdditionalItems: return RAPIDJSON_ERROR_STRING("Array has an additional item at index '%disallowed' that is not allowed by the schema.");
|
||||||
|
|
||||||
|
case kValidateErrorMaxProperties: return RAPIDJSON_ERROR_STRING("Object has '%actual' members which is more than 'maxProperties' value '%expected'.");
|
||||||
|
case kValidateErrorMinProperties: return RAPIDJSON_ERROR_STRING("Object has '%actual' members which is less than 'minProperties' value '%expected'.");
|
||||||
|
case kValidateErrorRequired: return RAPIDJSON_ERROR_STRING("Object is missing the following members required by the schema: '%missing'.");
|
||||||
|
case kValidateErrorAdditionalProperties: return RAPIDJSON_ERROR_STRING("Object has an additional member '%disallowed' that is not allowed by the schema.");
|
||||||
|
case kValidateErrorPatternProperties: return RAPIDJSON_ERROR_STRING("Object has 'patternProperties' that are not allowed by the schema.");
|
||||||
|
case kValidateErrorDependencies: return RAPIDJSON_ERROR_STRING("Object has missing property or schema dependencies, refer to following errors.");
|
||||||
|
|
||||||
|
case kValidateErrorEnum: return RAPIDJSON_ERROR_STRING("Property has a value that is not one of its allowed enumerated values.");
|
||||||
|
case kValidateErrorType: return RAPIDJSON_ERROR_STRING("Property has a type '%actual' that is not in the following list: '%expected'.");
|
||||||
|
|
||||||
|
case kValidateErrorOneOf: return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'oneOf', refer to following errors.");
|
||||||
|
case kValidateErrorOneOfMatch: return RAPIDJSON_ERROR_STRING("Property matched more than one of the sub-schemas specified by 'oneOf'.");
|
||||||
|
case kValidateErrorAllOf: return RAPIDJSON_ERROR_STRING("Property did not match all of the sub-schemas specified by 'allOf', refer to following errors.");
|
||||||
|
case kValidateErrorAnyOf: return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'anyOf', refer to following errors.");
|
||||||
|
case kValidateErrorNot: return RAPIDJSON_ERROR_STRING("Property matched the sub-schema specified by 'not'.");
|
||||||
|
|
||||||
|
default: return RAPIDJSON_ERROR_STRING("Unknown error.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RAPIDJSON_NAMESPACE_END
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
|
|||||||
@@ -152,6 +152,61 @@ private:
|
|||||||
*/
|
*/
|
||||||
typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);
|
typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// ValidateErrorCode
|
||||||
|
|
||||||
|
//! Error codes when validating.
|
||||||
|
/*! \ingroup RAPIDJSON_ERRORS
|
||||||
|
\see GenericSchemaValidator
|
||||||
|
*/
|
||||||
|
enum ValidateErrorCode {
|
||||||
|
kValidateErrors = -1, //!< Top level error code when kValidateContinueOnErrorsFlag set.
|
||||||
|
kValidateErrorNone = 0, //!< No error.
|
||||||
|
|
||||||
|
kValidateErrorMultipleOf, //!< Number is not a multiple of the 'multipleOf' value.
|
||||||
|
kValidateErrorMaximum, //!< Number is greater than the 'maximum' value.
|
||||||
|
kValidateErrorExclusiveMaximum, //!< Number is greater than or equal to the 'maximum' value.
|
||||||
|
kValidateErrorMinimum, //!< Number is less than the 'minimum' value.
|
||||||
|
kValidateErrorExclusiveMinimum, //!< Number is less than or equal to the 'minimum' value.
|
||||||
|
|
||||||
|
kValidateErrorMaxLength, //!< String is longer than the 'maxLength' value.
|
||||||
|
kValidateErrorMinLength, //!< String is longer than the 'maxLength' value.
|
||||||
|
kValidateErrorPattern, //!< String does not match the 'pattern' regular expression.
|
||||||
|
|
||||||
|
kValidateErrorMaxItems, //!< Array is longer than the 'maxItems' value.
|
||||||
|
kValidateErrorMinItems, //!< Array is shorter than the 'minItems' value.
|
||||||
|
kValidateErrorUniqueItems, //!< Array has duplicate items but 'uniqueItems' is true.
|
||||||
|
kValidateErrorAdditionalItems, //!< Array has additional items that are not allowed by the schema.
|
||||||
|
|
||||||
|
kValidateErrorMaxProperties, //!< Object has more members than 'maxProperties' value.
|
||||||
|
kValidateErrorMinProperties, //!< Object has less members than 'minProperties' value.
|
||||||
|
kValidateErrorRequired, //!< Object is missing one or more members required by the schema.
|
||||||
|
kValidateErrorAdditionalProperties, //!< Object has additional members that are not allowed by the schema.
|
||||||
|
kValidateErrorPatternProperties, //!< See other errors.
|
||||||
|
kValidateErrorDependencies, //!< Object has missing property or schema dependencies.
|
||||||
|
|
||||||
|
kValidateErrorEnum, //!< Property has a value that is not one of its allowed enumerated values
|
||||||
|
kValidateErrorType, //!< Property has a type that is not allowed by the schema..
|
||||||
|
|
||||||
|
kValidateErrorOneOf, //!< Property did not match any of the sub-schemas specified by 'oneOf'.
|
||||||
|
kValidateErrorOneOfMatch, //!< Property matched more than one of the sub-schemas specified by 'oneOf'.
|
||||||
|
kValidateErrorAllOf, //!< Property did not match all of the sub-schemas specified by 'allOf'.
|
||||||
|
kValidateErrorAnyOf, //!< Property did not match any of the sub-schemas specified by 'anyOf'.
|
||||||
|
kValidateErrorNot //!< Property matched the sub-schema specified by 'not'.
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Function pointer type of GetValidateError().
|
||||||
|
/*! \ingroup RAPIDJSON_ERRORS
|
||||||
|
|
||||||
|
This is the prototype for \c GetValidateError_X(), where \c X is a locale.
|
||||||
|
User can dynamically change locale in runtime, e.g.:
|
||||||
|
\code
|
||||||
|
GetValidateErrorFunc GetValidateError = GetValidateError_En; // or whatever
|
||||||
|
const RAPIDJSON_ERROR_CHARTYPE* s = GetValidateError(validator.GetInvalidSchemaCode());
|
||||||
|
\endcode
|
||||||
|
*/
|
||||||
|
typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetValidateErrorFunc)(ValidateErrorCode);
|
||||||
|
|
||||||
RAPIDJSON_NAMESPACE_END
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -51,6 +51,8 @@ RAPIDJSON_DIAG_POP
|
|||||||
|
|
||||||
class Schema : public PerfTest {
|
class Schema : public PerfTest {
|
||||||
public:
|
public:
|
||||||
|
typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
|
||||||
|
|
||||||
Schema() {}
|
Schema() {}
|
||||||
|
|
||||||
virtual void SetUp() {
|
virtual void SetUp() {
|
||||||
@@ -89,6 +91,8 @@ public:
|
|||||||
|
|
||||||
char jsonBuffer[65536];
|
char jsonBuffer[65536];
|
||||||
MemoryPoolAllocator<> jsonAllocator(jsonBuffer, sizeof(jsonBuffer));
|
MemoryPoolAllocator<> jsonAllocator(jsonBuffer, sizeof(jsonBuffer));
|
||||||
|
char schemaBuffer[65536];
|
||||||
|
MemoryPoolAllocator<> schemaAllocator(schemaBuffer, sizeof(schemaBuffer));
|
||||||
|
|
||||||
for (size_t i = 0; i < ARRAY_SIZE(filenames); i++) {
|
for (size_t i = 0; i < ARRAY_SIZE(filenames); i++) {
|
||||||
char filename[FILENAME_MAX];
|
char filename[FILENAME_MAX];
|
||||||
@@ -112,7 +116,7 @@ public:
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
TestSuite* ts = new TestSuite;
|
TestSuite* ts = new TestSuite;
|
||||||
ts->schema = new SchemaDocument((*schemaItr)["schema"]);
|
ts->schema = new SchemaDocumentType((*schemaItr)["schema"], 0, 0, 0, &schemaAllocator);
|
||||||
|
|
||||||
const Value& tests = (*schemaItr)["tests"];
|
const Value& tests = (*schemaItr)["tests"];
|
||||||
for (Value::ConstValueIterator testItr = tests.Begin(); testItr != tests.End(); ++testItr) {
|
for (Value::ConstValueIterator testItr = tests.Begin(); testItr != tests.End(); ++testItr) {
|
||||||
@@ -187,7 +191,7 @@ protected:
|
|||||||
for (DocumentList::iterator itr = tests.begin(); itr != tests.end(); ++itr)
|
for (DocumentList::iterator itr = tests.begin(); itr != tests.end(); ++itr)
|
||||||
delete *itr;
|
delete *itr;
|
||||||
}
|
}
|
||||||
SchemaDocument* schema;
|
SchemaDocumentType* schema;
|
||||||
DocumentList tests;
|
DocumentList tests;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -199,13 +203,14 @@ TEST_F(Schema, TestSuite) {
|
|||||||
char validatorBuffer[65536];
|
char validatorBuffer[65536];
|
||||||
MemoryPoolAllocator<> validatorAllocator(validatorBuffer, sizeof(validatorBuffer));
|
MemoryPoolAllocator<> validatorAllocator(validatorBuffer, sizeof(validatorBuffer));
|
||||||
|
|
||||||
const int trialCount = 100000;
|
// DCOLES - Reduce number by a factor of 100 to make it more reasonable and inline with other test counts
|
||||||
|
const int trialCount = 1000;
|
||||||
int testCount = 0;
|
int testCount = 0;
|
||||||
clock_t start = clock();
|
clock_t start = clock();
|
||||||
for (int i = 0; i < trialCount; i++) {
|
for (int i = 0; i < trialCount; i++) {
|
||||||
for (TestSuiteList::const_iterator itr = testSuites.begin(); itr != testSuites.end(); ++itr) {
|
for (TestSuiteList::const_iterator itr = testSuites.begin(); itr != testSuites.end(); ++itr) {
|
||||||
const TestSuite& ts = **itr;
|
const TestSuite& ts = **itr;
|
||||||
GenericSchemaValidator<SchemaDocument, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > validator(*ts.schema, &validatorAllocator);
|
GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > validator(*ts.schema, &validatorAllocator);
|
||||||
for (DocumentList::const_iterator testItr = ts.tests.begin(); testItr != ts.tests.end(); ++testItr) {
|
for (DocumentList::const_iterator testItr = ts.tests.begin(); testItr != ts.tests.end(); ++testItr) {
|
||||||
validator.Reset();
|
validator.Reset();
|
||||||
(*testItr)->Accept(validator);
|
(*testItr)->Accept(validator);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user