summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/rapidjson/test/unittest/schematest.cpp
diff options
context:
space:
mode:
author Miodrag Milanović <mmicko@gmail.com>2023-01-20 21:44:28 +0100
committer GitHub <noreply@github.com>2023-01-20 15:44:28 -0500
commitf6630310ebd116a9230976d4a47b894946f5aa6f (patch)
treebb1363ada5f0515564552c4dc3f6219c40108f01 /3rdparty/rapidjson/test/unittest/schematest.cpp
parent898b04e457cdcb44a0798afd90d25bd36c748f44 (diff)
Update rapidjson to 012be8528783cdbf4b7a9e64f78bd8f056b97e24 (#10842)
Co-authored-by: Milo Yip <miloyip@gmail.com>
Diffstat (limited to '3rdparty/rapidjson/test/unittest/schematest.cpp')
-rw-r--r--3rdparty/rapidjson/test/unittest/schematest.cpp2582
1 files changed, 2422 insertions, 160 deletions
diff --git a/3rdparty/rapidjson/test/unittest/schematest.cpp b/3rdparty/rapidjson/test/unittest/schematest.cpp
index 6a8b685f454..7387c08961e 100644
--- a/3rdparty/rapidjson/test/unittest/schematest.cpp
+++ b/3rdparty/rapidjson/test/unittest/schematest.cpp
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -12,14 +12,22 @@
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
+#define RAPIDJSON_SCHEMA_VERBOSE 0
+#define RAPIDJSON_HAS_STDSTRING 1
+
#include "unittest.h"
#include "rapidjson/schema.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/writer.h"
+#include "rapidjson/error/error.h"
+#include "rapidjson/error/en.h"
#ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(variadic-macros)
+#elif defined(_MSC_VER)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4822) // local class member function does not have a body
#endif
using namespace rapidjson;
@@ -104,6 +112,13 @@ TEST(SchemaValidator, Hasher) {
#define VALIDATE(schema, json, expected) \
{\
+ VALIDATE_(schema, json, expected, true) \
+}
+
+#define VALIDATE_(schema, json, expected, expected2) \
+{\
+ EXPECT_TRUE(expected2 == schema.GetError().ObjectEmpty());\
+ EXPECT_TRUE(schema.IsSupportedSpecification());\
SchemaValidator validator(schema);\
Document d;\
/*printf("\n%s\n", json);*/\
@@ -111,27 +126,50 @@ TEST(SchemaValidator, Hasher) {
EXPECT_FALSE(d.HasParseError());\
EXPECT_TRUE(expected == d.Accept(validator));\
EXPECT_TRUE(expected == validator.IsValid());\
+ ValidateErrorCode code = validator.GetInvalidSchemaCode();\
+ if (expected) {\
+ EXPECT_TRUE(code == kValidateErrorNone);\
+ EXPECT_TRUE(validator.GetInvalidSchemaKeyword() == 0);\
+ }\
if ((expected) && !validator.IsValid()) {\
StringBuffer sb;\
validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);\
printf("Invalid schema: %s\n", sb.GetString());\
printf("Invalid keyword: %s\n", validator.GetInvalidSchemaKeyword());\
+ printf("Invalid code: %d\n", code);\
+ printf("Invalid message: %s\n", GetValidateError_En(code));\
sb.Clear();\
validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);\
printf("Invalid document: %s\n", sb.GetString());\
+ sb.Clear();\
+ Writer<StringBuffer> w(sb);\
+ validator.GetError().Accept(w);\
+ printf("Validation error: %s\n", sb.GetString());\
}\
}
-#define INVALIDATE(schema, json, invalidSchemaPointer, invalidSchemaKeyword, invalidDocumentPointer) \
+#define INVALIDATE(schema, json, invalidSchemaPointer, invalidSchemaKeyword, invalidDocumentPointer, error) \
{\
- SchemaValidator validator(schema);\
+ INVALIDATE_(schema, json, invalidSchemaPointer, invalidSchemaKeyword, invalidDocumentPointer, error, kValidateDefaultFlags, SchemaValidator, Pointer) \
+}
+
+#define INVALIDATE_(schema, json, invalidSchemaPointer, invalidSchemaKeyword, invalidDocumentPointer, error, \
+ flags, SchemaValidatorType, PointerType) \
+{\
+ EXPECT_TRUE(schema.GetError().ObjectEmpty());\
+ EXPECT_TRUE(schema.IsSupportedSpecification());\
+ SchemaValidatorType validator(schema);\
+ validator.SetValidateFlags(flags);\
Document d;\
/*printf("\n%s\n", json);*/\
d.Parse(json);\
EXPECT_FALSE(d.HasParseError());\
- EXPECT_FALSE(d.Accept(validator));\
+ d.Accept(validator);\
EXPECT_FALSE(validator.IsValid());\
- if (validator.GetInvalidSchemaPointer() != Pointer(invalidSchemaPointer)) {\
+ ValidateErrorCode code = validator.GetInvalidSchemaCode();\
+ ASSERT_TRUE(code != kValidateErrorNone);\
+ ASSERT_TRUE(strcmp(GetValidateError_En(code), "Unknown error.") != 0);\
+ if (validator.GetInvalidSchemaPointer() != PointerType(invalidSchemaPointer)) {\
StringBuffer sb;\
validator.GetInvalidSchemaPointer().Stringify(sb);\
printf("GetInvalidSchemaPointer() Expected: %s Actual: %s\n", invalidSchemaPointer, sb.GetString());\
@@ -142,12 +180,35 @@ TEST(SchemaValidator, Hasher) {
printf("GetInvalidSchemaKeyword() Expected: %s Actual %s\n", invalidSchemaKeyword, validator.GetInvalidSchemaKeyword());\
ADD_FAILURE();\
}\
- if (validator.GetInvalidDocumentPointer() != Pointer(invalidDocumentPointer)) {\
+ if (validator.GetInvalidDocumentPointer() != PointerType(invalidDocumentPointer)) {\
StringBuffer sb;\
validator.GetInvalidDocumentPointer().Stringify(sb);\
printf("GetInvalidDocumentPointer() Expected: %s Actual: %s\n", invalidDocumentPointer, sb.GetString());\
ADD_FAILURE();\
}\
+ Document e;\
+ e.Parse(error);\
+ if (validator.GetError() != e) {\
+ StringBuffer sb;\
+ Writer<StringBuffer> w(sb);\
+ validator.GetError().Accept(w);\
+ printf("GetError() Expected: %s Actual: %s\n", error, sb.GetString());\
+ ADD_FAILURE();\
+ }\
+}
+
+// Use for checking whether a compiled schema document contains errors
+#define SCHEMAERROR(schema, error) \
+{\
+ Document e;\
+ e.Parse(error);\
+ if (schema.GetError() != e) {\
+ StringBuffer sb;\
+ Writer<StringBuffer> w(sb);\
+ schema.GetError().Accept(w);\
+ printf("GetError() Expected: %s Actual: %s\n", error, sb.GetString());\
+ ADD_FAILURE();\
+ }\
}
TEST(SchemaValidator, Typeless) {
@@ -167,7 +228,12 @@ TEST(SchemaValidator, MultiType) {
VALIDATE(s, "42", true);
VALIDATE(s, "\"Life, the universe, and everything\"", true);
- INVALIDATE(s, "[\"Life\", \"the universe\", \"and everything\"]", "", "type", "");
+ INVALIDATE(s, "[\"Life\", \"the universe\", \"and everything\"]", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"string\", \"number\"], \"actual\": \"array\""
+ "}}");
}
TEST(SchemaValidator, Enum_Typed) {
@@ -176,10 +242,11 @@ TEST(SchemaValidator, Enum_Typed) {
SchemaDocument s(sd);
VALIDATE(s, "\"red\"", true);
- INVALIDATE(s, "\"blue\"", "", "enum", "");
+ INVALIDATE(s, "\"blue\"", "", "enum", "",
+ "{ \"enum\": { \"errorCode\": 19, \"instanceRef\": \"#\", \"schemaRef\": \"#\" }}");
}
-TEST(SchemaValidator, Enum_Typless) {
+TEST(SchemaValidator, Enum_Typeless) {
Document sd;
sd.Parse("{ \"enum\": [\"red\", \"amber\", \"green\", null, 42] }");
SchemaDocument s(sd);
@@ -187,7 +254,8 @@ TEST(SchemaValidator, Enum_Typless) {
VALIDATE(s, "\"red\"", true);
VALIDATE(s, "null", true);
VALIDATE(s, "42", true);
- INVALIDATE(s, "0", "", "enum", "");
+ INVALIDATE(s, "0", "", "enum", "",
+ "{ \"enum\": { \"errorCode\": 19, \"instanceRef\": \"#\", \"schemaRef\": \"#\" }}");
}
TEST(SchemaValidator, Enum_InvalidType) {
@@ -196,7 +264,12 @@ TEST(SchemaValidator, Enum_InvalidType) {
SchemaDocument s(sd);
VALIDATE(s, "\"red\"", true);
- INVALIDATE(s, "null", "", "type", "");
+ INVALIDATE(s, "null", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"string\"], \"actual\": \"null\""
+ "}}");
}
TEST(SchemaValidator, AllOf) {
@@ -206,7 +279,14 @@ TEST(SchemaValidator, AllOf) {
SchemaDocument s(sd);
VALIDATE(s, "\"ok\"", true);
- INVALIDATE(s, "\"too long\"", "", "allOf", "");
+ INVALIDATE(s, "\"too long\"", "", "allOf", "",
+ "{ \"allOf\": {"
+ " \"errors\": ["
+ " {},"
+ " {\"maxLength\": {\"errorCode\": 6, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/1\", \"expected\": 5, \"actual\": \"too long\"}}"
+ " ],"
+ " \"errorCode\": 23, \"instanceRef\": \"#\", \"schemaRef\": \"#\""
+ "}}");
}
{
Document sd;
@@ -214,7 +294,14 @@ TEST(SchemaValidator, AllOf) {
SchemaDocument s(sd);
VALIDATE(s, "\"No way\"", false);
- INVALIDATE(s, "-1", "", "allOf", "");
+ INVALIDATE(s, "-1", "", "allOf", "",
+ "{ \"allOf\": {"
+ " \"errors\": ["
+ " {\"type\": { \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/0\", \"errorCode\": 20, \"expected\": [\"string\"], \"actual\": \"integer\"}},"
+ " {}"
+ " ],"
+ " \"errorCode\": 23, \"instanceRef\": \"#\", \"schemaRef\": \"#\""
+ "}}");
}
}
@@ -225,7 +312,23 @@ TEST(SchemaValidator, AnyOf) {
VALIDATE(s, "\"Yes\"", true);
VALIDATE(s, "42", true);
- INVALIDATE(s, "{ \"Not a\": \"string or number\" }", "", "anyOf", "");
+ INVALIDATE(s, "{ \"Not a\": \"string or number\" }", "", "anyOf", "",
+ "{ \"anyOf\": {"
+ " \"errorCode\": 24,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\", "
+ " \"errors\": ["
+ " { \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#/anyOf/0\","
+ " \"expected\": [\"string\"], \"actual\": \"object\""
+ " }},"
+ " { \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#/anyOf/1\","
+ " \"expected\": [\"number\"], \"actual\": \"object\""
+ " }}"
+ " ]"
+ "}}");
}
TEST(SchemaValidator, OneOf) {
@@ -235,8 +338,25 @@ TEST(SchemaValidator, OneOf) {
VALIDATE(s, "10", true);
VALIDATE(s, "9", true);
- INVALIDATE(s, "2", "", "oneOf", "");
- INVALIDATE(s, "15", "", "oneOf", "");
+ INVALIDATE(s, "2", "", "oneOf", "",
+ "{ \"oneOf\": {"
+ " \"errorCode\": 21,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"errors\": ["
+ " { \"multipleOf\": {"
+ " \"errorCode\": 1,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#/oneOf/0\","
+ " \"expected\": 5, \"actual\": 2"
+ " }},"
+ " { \"multipleOf\": {"
+ " \"errorCode\": 1,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#/oneOf/1\","
+ " \"expected\": 3, \"actual\": 2"
+ " }}"
+ " ]"
+ "}}");
+ INVALIDATE(s, "15", "", "oneOf", "",
+ "{ \"oneOf\": { \"errorCode\": 22, \"instanceRef\": \"#\", \"schemaRef\": \"#\", \"matches\": [0,1]}}");
}
TEST(SchemaValidator, Not) {
@@ -246,7 +366,8 @@ TEST(SchemaValidator, Not) {
VALIDATE(s, "42", true);
VALIDATE(s, "{ \"key\": \"value\" }", true);
- INVALIDATE(s, "\"I am a string\"", "", "not", "");
+ INVALIDATE(s, "\"I am a string\"", "", "not", "",
+ "{ \"not\": { \"errorCode\": 25, \"instanceRef\": \"#\", \"schemaRef\": \"#\" }}");
}
TEST(SchemaValidator, Ref) {
@@ -310,7 +431,14 @@ TEST(SchemaValidator, Ref_AllOf) {
"}");
SchemaDocument s(sd);
- INVALIDATE(s, "{\"shipping_address\": {\"street_address\": \"1600 Pennsylvania Avenue NW\", \"city\": \"Washington\", \"state\": \"DC\"} }", "/properties/shipping_address", "allOf", "/shipping_address");
+ INVALIDATE(s, "{\"shipping_address\": {\"street_address\": \"1600 Pennsylvania Avenue NW\", \"city\": \"Washington\", \"state\": \"DC\"} }", "/properties/shipping_address", "allOf", "/shipping_address",
+ "{ \"allOf\": {"
+ " \"errors\": ["
+ " {},"
+ " {\"required\": {\"errorCode\": 15, \"instanceRef\": \"#/shipping_address\", \"schemaRef\": \"#/properties/shipping_address/allOf/1\", \"missing\": [\"type\"]}}"
+ " ],"
+ " \"errorCode\":23,\"instanceRef\":\"#/shipping_address\",\"schemaRef\":\"#/properties/shipping_address\""
+ "}}");
VALIDATE(s, "{\"shipping_address\": {\"street_address\": \"1600 Pennsylvania Avenue NW\", \"city\": \"Washington\", \"state\": \"DC\", \"type\": \"business\"} }", true);
}
@@ -320,11 +448,36 @@ TEST(SchemaValidator, String) {
SchemaDocument s(sd);
VALIDATE(s, "\"I'm a string\"", true);
- INVALIDATE(s, "42", "", "type", "");
- INVALIDATE(s, "2147483648", "", "type", ""); // 2^31 can only be fit in unsigned
- INVALIDATE(s, "-2147483649", "", "type", ""); // -2^31 - 1 can only be fit in int64_t
- INVALIDATE(s, "4294967296", "", "type", ""); // 2^32 can only be fit in int64_t
- INVALIDATE(s, "3.1415926", "", "type", "");
+ INVALIDATE(s, "42", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"string\"], \"actual\": \"integer\""
+ "}}");
+ INVALIDATE(s, "2147483648", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"string\"], \"actual\": \"integer\""
+ "}}"); // 2^31 can only be fit in unsigned
+ INVALIDATE(s, "-2147483649", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"string\"], \"actual\": \"integer\""
+ "}}"); // -2^31 - 1 can only be fit in int64_t
+ INVALIDATE(s, "4294967296", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"string\"], \"actual\": \"integer\""
+ "}}"); // 2^32 can only be fit in int64_t
+ INVALIDATE(s, "3.1415926", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"string\"], \"actual\": \"number\""
+ "}}");
}
TEST(SchemaValidator, String_LengthRange) {
@@ -332,10 +485,20 @@ TEST(SchemaValidator, String_LengthRange) {
sd.Parse("{\"type\":\"string\",\"minLength\":2,\"maxLength\":3}");
SchemaDocument s(sd);
- INVALIDATE(s, "\"A\"", "", "minLength", "");
+ INVALIDATE(s, "\"A\"", "", "minLength", "",
+ "{ \"minLength\": {"
+ " \"errorCode\": 7,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 2, \"actual\": \"A\""
+ "}}");
VALIDATE(s, "\"AB\"", true);
VALIDATE(s, "\"ABC\"", true);
- INVALIDATE(s, "\"ABCD\"", "", "maxLength", "");
+ INVALIDATE(s, "\"ABCD\"", "", "maxLength", "",
+ "{ \"maxLength\": {"
+ " \"errorCode\": 6,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 3, \"actual\": \"ABCD\""
+ "}}");
}
#if RAPIDJSON_SCHEMA_HAS_REGEX
@@ -346,18 +509,29 @@ TEST(SchemaValidator, String_Pattern) {
VALIDATE(s, "\"555-1212\"", true);
VALIDATE(s, "\"(888)555-1212\"", true);
- INVALIDATE(s, "\"(888)555-1212 ext. 532\"", "", "pattern", "");
- INVALIDATE(s, "\"(800)FLOWERS\"", "", "pattern", "");
+ INVALIDATE(s, "\"(888)555-1212 ext. 532\"", "", "pattern", "",
+ "{ \"pattern\": {"
+ " \"errorCode\": 8,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"actual\": \"(888)555-1212 ext. 532\""
+ "}}");
+ INVALIDATE(s, "\"(800)FLOWERS\"", "", "pattern", "",
+ "{ \"pattern\": {"
+ " \"errorCode\": 8,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"actual\": \"(800)FLOWERS\""
+ "}}");
}
TEST(SchemaValidator, String_Pattern_Invalid) {
Document sd;
- sd.Parse("{\"type\":\"string\",\"pattern\":\"a{0}\"}"); // TODO: report regex is invalid somehow
+ sd.Parse("{\"type\":\"string\",\"pattern\":\"a{0}\"}");
SchemaDocument s(sd);
+ SCHEMAERROR(s, "{\"RegexInvalid\":{\"errorCode\":9,\"instanceRef\":\"#/pattern\",\"value\":\"a{0}\"}}");
- VALIDATE(s, "\"\"", true);
- VALIDATE(s, "\"a\"", true);
- VALIDATE(s, "\"aa\"", true);
+ VALIDATE_(s, "\"\"", true, false);
+ VALIDATE_(s, "\"a\"", true, false);
+ VALIDATE_(s, "\"aa\"", true, false);
}
#endif
@@ -372,8 +546,18 @@ TEST(SchemaValidator, Integer) {
VALIDATE(s, "-2147483649", true); // -2^31 - 1 can only be fit in int64_t
VALIDATE(s, "2147483648", true); // 2^31 can only be fit in unsigned
VALIDATE(s, "4294967296", true); // 2^32 can only be fit in int64_t
- INVALIDATE(s, "3.1415926", "", "type", "");
- INVALIDATE(s, "\"42\"", "", "type", "");
+ INVALIDATE(s, "3.1415926", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"integer\"], \"actual\": \"number\""
+ "}}");
+ INVALIDATE(s, "\"42\"", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"integer\"], \"actual\": \"string\""
+ "}}");
}
TEST(SchemaValidator, Integer_Range) {
@@ -381,12 +565,27 @@ TEST(SchemaValidator, Integer_Range) {
sd.Parse("{\"type\":\"integer\",\"minimum\":0,\"maximum\":100,\"exclusiveMaximum\":true}");
SchemaDocument s(sd);
- INVALIDATE(s, "-1", "", "minimum", "");
+ INVALIDATE(s, "-1", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 0, \"actual\": -1"
+ "}}");
VALIDATE(s, "0", true);
VALIDATE(s, "10", true);
VALIDATE(s, "99", true);
- INVALIDATE(s, "100", "", "maximum", "");
- INVALIDATE(s, "101", "", "maximum", "");
+ INVALIDATE(s, "100", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 100, \"exclusiveMaximum\": true, \"actual\": 100"
+ "}}");
+ INVALIDATE(s, "101", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 100, \"exclusiveMaximum\": true, \"actual\": 101"
+ "}}");
}
TEST(SchemaValidator, Integer_Range64Boundary) {
@@ -394,7 +593,12 @@ TEST(SchemaValidator, Integer_Range64Boundary) {
sd.Parse("{\"type\":\"integer\",\"minimum\":-9223372036854775807,\"maximum\":9223372036854775806}");
SchemaDocument s(sd);
- INVALIDATE(s, "-9223372036854775808", "", "minimum", "");
+ INVALIDATE(s, "-9223372036854775808", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": -9223372036854775807, \"actual\": -9223372036854775808"
+ "}}");
VALIDATE(s, "-9223372036854775807", true);
VALIDATE(s, "-2147483648", true); // int min
VALIDATE(s, "0", true);
@@ -402,8 +606,18 @@ TEST(SchemaValidator, Integer_Range64Boundary) {
VALIDATE(s, "2147483648", true); // unsigned first
VALIDATE(s, "4294967295", true); // unsigned max
VALIDATE(s, "9223372036854775806", true);
- INVALIDATE(s, "9223372036854775807", "", "maximum", "");
- INVALIDATE(s, "18446744073709551615", "", "maximum", ""); // uint64_t max
+ INVALIDATE(s, "9223372036854775807", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 2,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 9223372036854775806, \"actual\": 9223372036854775807"
+ "}}");
+ INVALIDATE(s, "18446744073709551615", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 2,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 9223372036854775806, \"actual\": 18446744073709551615"
+ "}}"); // uint64_t max
}
TEST(SchemaValidator, Integer_RangeU64Boundary) {
@@ -411,16 +625,56 @@ TEST(SchemaValidator, Integer_RangeU64Boundary) {
sd.Parse("{\"type\":\"integer\",\"minimum\":9223372036854775808,\"maximum\":18446744073709551614}");
SchemaDocument s(sd);
- INVALIDATE(s, "-9223372036854775808", "", "minimum", "");
- INVALIDATE(s, "9223372036854775807", "", "minimum", "");
- INVALIDATE(s, "-2147483648", "", "minimum", ""); // int min
- INVALIDATE(s, "0", "", "minimum", "");
- INVALIDATE(s, "2147483647", "", "minimum", ""); // int max
- INVALIDATE(s, "2147483648", "", "minimum", ""); // unsigned first
- INVALIDATE(s, "4294967295", "", "minimum", ""); // unsigned max
+ INVALIDATE(s, "-9223372036854775808", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 9223372036854775808, \"actual\": -9223372036854775808"
+ "}}");
+ INVALIDATE(s, "9223372036854775807", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 9223372036854775808, \"actual\": 9223372036854775807"
+ "}}");
+ INVALIDATE(s, "-2147483648", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 9223372036854775808, \"actual\": -2147483648"
+ "}}"); // int min
+ INVALIDATE(s, "0", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 9223372036854775808, \"actual\": 0"
+ "}}");
+ INVALIDATE(s, "2147483647", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 9223372036854775808, \"actual\": 2147483647"
+ "}}"); // int max
+ INVALIDATE(s, "2147483648", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 9223372036854775808, \"actual\": 2147483648"
+ "}}"); // unsigned first
+ INVALIDATE(s, "4294967295", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 9223372036854775808, \"actual\": 4294967295"
+ "}}"); // unsigned max
VALIDATE(s, "9223372036854775808", true);
VALIDATE(s, "18446744073709551614", true);
- INVALIDATE(s, "18446744073709551615", "", "maximum", "");
+ INVALIDATE(s, "18446744073709551615", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 2,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 18446744073709551614, \"actual\": 18446744073709551615"
+ "}}");
}
TEST(SchemaValidator, Integer_Range64BoundaryExclusive) {
@@ -428,10 +682,22 @@ TEST(SchemaValidator, Integer_Range64BoundaryExclusive) {
sd.Parse("{\"type\":\"integer\",\"minimum\":-9223372036854775808,\"maximum\":18446744073709551615,\"exclusiveMinimum\":true,\"exclusiveMaximum\":true}");
SchemaDocument s(sd);
- INVALIDATE(s, "-9223372036854775808", "", "minimum", "");
+ INVALIDATE(s, "-9223372036854775808", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 5,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": -9223372036854775808, \"exclusiveMinimum\": true, "
+ " \"actual\": -9223372036854775808"
+ "}}");
VALIDATE(s, "-9223372036854775807", true);
VALIDATE(s, "18446744073709551614", true);
- INVALIDATE(s, "18446744073709551615", "", "maximum", "");
+ INVALIDATE(s, "18446744073709551615", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 18446744073709551615, \"exclusiveMaximum\": true, "
+ " \"actual\": 18446744073709551615"
+ "}}");
}
TEST(SchemaValidator, Integer_MultipleOf) {
@@ -443,8 +709,18 @@ TEST(SchemaValidator, Integer_MultipleOf) {
VALIDATE(s, "10", true);
VALIDATE(s, "-10", true);
VALIDATE(s, "20", true);
- INVALIDATE(s, "23", "", "multipleOf", "");
- INVALIDATE(s, "-23", "", "multipleOf", "");
+ INVALIDATE(s, "23", "", "multipleOf", "",
+ "{ \"multipleOf\": {"
+ " \"errorCode\": 1,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 10, \"actual\": 23"
+ "}}");
+ INVALIDATE(s, "-23", "", "multipleOf", "",
+ "{ \"multipleOf\": {"
+ " \"errorCode\": 1,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 10, \"actual\": -23"
+ "}}");
}
TEST(SchemaValidator, Integer_MultipleOf64Boundary) {
@@ -454,7 +730,12 @@ TEST(SchemaValidator, Integer_MultipleOf64Boundary) {
VALIDATE(s, "0", true);
VALIDATE(s, "18446744073709551615", true);
- INVALIDATE(s, "18446744073709551614", "", "multipleOf", "");
+ INVALIDATE(s, "18446744073709551614", "", "multipleOf", "",
+ "{ \"multipleOf\": {"
+ " \"errorCode\": 1,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 18446744073709551615, \"actual\": 18446744073709551614"
+ "}}");
}
TEST(SchemaValidator, Number_Range) {
@@ -462,15 +743,35 @@ TEST(SchemaValidator, Number_Range) {
sd.Parse("{\"type\":\"number\",\"minimum\":0,\"maximum\":100,\"exclusiveMaximum\":true}");
SchemaDocument s(sd);
- INVALIDATE(s, "-1", "", "minimum", "");
+ INVALIDATE(s, "-1", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 0, \"actual\": -1"
+ "}}");
VALIDATE(s, "0", true);
VALIDATE(s, "0.1", true);
VALIDATE(s, "10", true);
VALIDATE(s, "99", true);
VALIDATE(s, "99.9", true);
- INVALIDATE(s, "100", "", "maximum", "");
- INVALIDATE(s, "100.0", "", "maximum", "");
- INVALIDATE(s, "101.5", "", "maximum", "");
+ INVALIDATE(s, "100", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 100, \"exclusiveMaximum\": true, \"actual\": 100"
+ "}}");
+ INVALIDATE(s, "100.0", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 100, \"exclusiveMaximum\": true, \"actual\": 100.0"
+ "}}");
+ INVALIDATE(s, "101.5", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 100, \"exclusiveMaximum\": true, \"actual\": 101.5"
+ "}}");
}
TEST(SchemaValidator, Number_RangeInt) {
@@ -478,19 +779,74 @@ TEST(SchemaValidator, Number_RangeInt) {
sd.Parse("{\"type\":\"number\",\"minimum\":-100,\"maximum\":-1,\"exclusiveMaximum\":true}");
SchemaDocument s(sd);
- INVALIDATE(s, "-101", "", "minimum", "");
- INVALIDATE(s, "-100.1", "", "minimum", "");
+ INVALIDATE(s, "-101", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": -100, \"actual\": -101"
+ "}}");
+ INVALIDATE(s, "-100.1", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": -100, \"actual\": -100.1"
+ "}}");
VALIDATE(s, "-100", true);
VALIDATE(s, "-2", true);
- INVALIDATE(s, "-1", "", "maximum", "");
- INVALIDATE(s, "-0.9", "", "maximum", "");
- INVALIDATE(s, "0", "", "maximum", "");
- INVALIDATE(s, "2147483647", "", "maximum", ""); // int max
- INVALIDATE(s, "2147483648", "", "maximum", ""); // unsigned first
- INVALIDATE(s, "4294967295", "", "maximum", ""); // unsigned max
- INVALIDATE(s, "9223372036854775808", "", "maximum", "");
- INVALIDATE(s, "18446744073709551614", "", "maximum", "");
- INVALIDATE(s, "18446744073709551615", "", "maximum", "");
+ INVALIDATE(s, "-1", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": -1"
+ "}}");
+ INVALIDATE(s, "-0.9", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": -0.9"
+ "}}");
+ INVALIDATE(s, "0", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 0"
+ "}}");
+ INVALIDATE(s, "2147483647", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 2147483647"
+ "}}"); // int max
+ INVALIDATE(s, "2147483648", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 2147483648"
+ "}}"); // unsigned first
+ INVALIDATE(s, "4294967295", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 4294967295"
+ "}}"); // unsigned max
+ INVALIDATE(s, "9223372036854775808", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 9223372036854775808"
+ "}}");
+ INVALIDATE(s, "18446744073709551614", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 18446744073709551614"
+ "}}");
+ INVALIDATE(s, "18446744073709551615", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 18446744073709551615"
+ "}}");
}
TEST(SchemaValidator, Number_RangeDouble) {
@@ -498,23 +854,88 @@ TEST(SchemaValidator, Number_RangeDouble) {
sd.Parse("{\"type\":\"number\",\"minimum\":0.1,\"maximum\":100.1,\"exclusiveMaximum\":true}");
SchemaDocument s(sd);
- INVALIDATE(s, "-9223372036854775808", "", "minimum", "");
- INVALIDATE(s, "-2147483648", "", "minimum", ""); // int min
- INVALIDATE(s, "-1", "", "minimum", "");
+ INVALIDATE(s, "-9223372036854775808", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 0.1, \"actual\": -9223372036854775808"
+ "}}");
+ INVALIDATE(s, "-2147483648", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 0.1, \"actual\": -2147483648"
+ "}}"); // int min
+ INVALIDATE(s, "-1", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 0.1, \"actual\": -1"
+ "}}");
VALIDATE(s, "0.1", true);
VALIDATE(s, "10", true);
VALIDATE(s, "99", true);
VALIDATE(s, "100", true);
- INVALIDATE(s, "101", "", "maximum", "");
- INVALIDATE(s, "101.5", "", "maximum", "");
- INVALIDATE(s, "18446744073709551614", "", "maximum", "");
- INVALIDATE(s, "18446744073709551615", "", "maximum", "");
- INVALIDATE(s, "2147483647", "", "maximum", ""); // int max
- INVALIDATE(s, "2147483648", "", "maximum", ""); // unsigned first
- INVALIDATE(s, "4294967295", "", "maximum", ""); // unsigned max
- INVALIDATE(s, "9223372036854775808", "", "maximum", "");
- INVALIDATE(s, "18446744073709551614", "", "maximum", "");
- INVALIDATE(s, "18446744073709551615", "", "maximum", "");
+ INVALIDATE(s, "101", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 101"
+ "}}");
+ INVALIDATE(s, "101.5", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 101.5"
+ "}}");
+ INVALIDATE(s, "18446744073709551614", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 18446744073709551614"
+ "}}");
+ INVALIDATE(s, "18446744073709551615", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 18446744073709551615"
+ "}}");
+ INVALIDATE(s, "2147483647", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 2147483647"
+ "}}"); // int max
+ INVALIDATE(s, "2147483648", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 2147483648"
+ "}}"); // unsigned first
+ INVALIDATE(s, "4294967295", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 4294967295"
+ "}}"); // unsigned max
+ INVALIDATE(s, "9223372036854775808", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 9223372036854775808"
+ "}}");
+ INVALIDATE(s, "18446744073709551614", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 18446744073709551614"
+ "}}");
+ INVALIDATE(s, "18446744073709551615", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 18446744073709551615"
+ "}}");
}
TEST(SchemaValidator, Number_RangeDoubleU64Boundary) {
@@ -522,15 +943,50 @@ TEST(SchemaValidator, Number_RangeDoubleU64Boundary) {
sd.Parse("{\"type\":\"number\",\"minimum\":9223372036854775808.0,\"maximum\":18446744073709550000.0}");
SchemaDocument s(sd);
- INVALIDATE(s, "-9223372036854775808", "", "minimum", "");
- INVALIDATE(s, "-2147483648", "", "minimum", ""); // int min
- INVALIDATE(s, "0", "", "minimum", "");
- INVALIDATE(s, "2147483647", "", "minimum", ""); // int max
- INVALIDATE(s, "2147483648", "", "minimum", ""); // unsigned first
- INVALIDATE(s, "4294967295", "", "minimum", ""); // unsigned max
+ INVALIDATE(s, "-9223372036854775808", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 9223372036854775808.0, \"actual\": -9223372036854775808"
+ "}}");
+ INVALIDATE(s, "-2147483648", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 9223372036854775808.0, \"actual\": -2147483648"
+ "}}"); // int min
+ INVALIDATE(s, "0", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 9223372036854775808.0, \"actual\": 0"
+ "}}");
+ INVALIDATE(s, "2147483647", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 9223372036854775808.0, \"actual\": 2147483647"
+ "}}"); // int max
+ INVALIDATE(s, "2147483648", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 9223372036854775808.0, \"actual\": 2147483648"
+ "}}"); // unsigned first
+ INVALIDATE(s, "4294967295", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 9223372036854775808.0, \"actual\": 4294967295"
+ "}}"); // unsigned max
VALIDATE(s, "9223372036854775808", true);
VALIDATE(s, "18446744073709540000", true);
- INVALIDATE(s, "18446744073709551615", "", "maximum", "");
+ INVALIDATE(s, "18446744073709551615", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 2,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 18446744073709550000.0, \"actual\": 18446744073709551615"
+ "}}");
}
TEST(SchemaValidator, Number_MultipleOf) {
@@ -542,13 +998,38 @@ TEST(SchemaValidator, Number_MultipleOf) {
VALIDATE(s, "10", true);
VALIDATE(s, "-10", true);
VALIDATE(s, "20", true);
- INVALIDATE(s, "23", "", "multipleOf", "");
- INVALIDATE(s, "-2147483648", "", "multipleOf", ""); // int min
+ INVALIDATE(s, "23", "", "multipleOf", "",
+ "{ \"multipleOf\": {"
+ " \"errorCode\": 1,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 10.0, \"actual\": 23"
+ "}}");
+ INVALIDATE(s, "-2147483648", "", "multipleOf", "",
+ "{ \"multipleOf\": {"
+ " \"errorCode\": 1,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 10.0, \"actual\": -2147483648"
+ "}}"); // int min
VALIDATE(s, "-2147483640", true);
- INVALIDATE(s, "2147483647", "", "multipleOf", ""); // int max
- INVALIDATE(s, "2147483648", "", "multipleOf", ""); // unsigned first
+ INVALIDATE(s, "2147483647", "", "multipleOf", "",
+ "{ \"multipleOf\": {"
+ " \"errorCode\": 1,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 10.0, \"actual\": 2147483647"
+ "}}"); // int max
+ INVALIDATE(s, "2147483648", "", "multipleOf", "",
+ "{ \"multipleOf\": {"
+ " \"errorCode\": 1,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 10.0, \"actual\": 2147483648"
+ "}}"); // unsigned first
VALIDATE(s, "2147483650", true);
- INVALIDATE(s, "4294967295", "", "multipleOf", ""); // unsigned max
+ INVALIDATE(s, "4294967295", "", "multipleOf", "",
+ "{ \"multipleOf\": {"
+ " \"errorCode\": 1,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 10.0, \"actual\": 4294967295"
+ "}}"); // unsigned max
VALIDATE(s, "4294967300", true);
}
@@ -559,7 +1040,12 @@ TEST(SchemaValidator, Number_MultipleOfOne) {
VALIDATE(s, "42", true);
VALIDATE(s, "42.0", true);
- INVALIDATE(s, "3.1415926", "", "multipleOf", "");
+ INVALIDATE(s, "3.1415926", "", "multipleOf", "",
+ "{ \"multipleOf\": {"
+ " \"errorCode\": 1,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 1, \"actual\": 3.1415926"
+ "}}");
}
TEST(SchemaValidator, Object) {
@@ -569,8 +1055,18 @@ TEST(SchemaValidator, Object) {
VALIDATE(s, "{\"key\":\"value\",\"another_key\":\"another_value\"}", true);
VALIDATE(s, "{\"Sun\":1.9891e30,\"Jupiter\":1.8986e27,\"Saturn\":5.6846e26,\"Neptune\":10.243e25,\"Uranus\":8.6810e25,\"Earth\":5.9736e24,\"Venus\":4.8685e24,\"Mars\":6.4185e23,\"Mercury\":3.3022e23,\"Moon\":7.349e22,\"Pluto\":1.25e22}", true);
- INVALIDATE(s, "[\"An\", \"array\", \"not\", \"an\", \"object\"]", "", "type", "");
- INVALIDATE(s, "\"Not an object\"", "", "type", "");
+ INVALIDATE(s, "[\"An\", \"array\", \"not\", \"an\", \"object\"]", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"object\"], \"actual\": \"array\""
+ "}}");
+ INVALIDATE(s, "\"Not an object\"", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"object\"], \"actual\": \"string\""
+ "}}");
}
TEST(SchemaValidator, Object_Properties) {
@@ -588,7 +1084,19 @@ TEST(SchemaValidator, Object_Properties) {
SchemaDocument s(sd);
VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", true);
- INVALIDATE(s, "{ \"number\": \"1600\", \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", "/properties/number", "type", "/number");
+ INVALIDATE(s, "{ \"number\": \"1600\", \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", "/properties/number", "type", "/number",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/number\", \"schemaRef\": \"#/properties/number\","
+ " \"expected\": [\"number\"], \"actual\": \"string\""
+ "}}");
+ INVALIDATE(s, "{ \"number\": \"One\", \"street_name\": \"Microsoft\", \"street_type\": \"Way\" }",
+ "/properties/number", "type", "/number",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/number\", \"schemaRef\": \"#/properties/number\","
+ " \"expected\": [\"number\"], \"actual\": \"string\""
+ "}}"); // fail fast
VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\" }", true);
VALIDATE(s, "{}", true);
VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"direction\": \"NW\" }", true);
@@ -612,7 +1120,12 @@ TEST(SchemaValidator, Object_AdditionalPropertiesBoolean) {
SchemaDocument s(sd);
VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", true);
- INVALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"direction\": \"NW\" }", "", "additionalProperties", "/direction");
+ INVALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"direction\": \"NW\" }", "", "additionalProperties", "/direction",
+ "{ \"additionalProperties\": {"
+ " \"errorCode\": 16,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"disallowed\": \"direction\""
+ "}}");
}
TEST(SchemaValidator, Object_AdditionalPropertiesObject) {
@@ -633,7 +1146,12 @@ TEST(SchemaValidator, Object_AdditionalPropertiesObject) {
VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", true);
VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"direction\": \"NW\" }", true);
- INVALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"office_number\": 201 }", "/additionalProperties", "type", "/office_number");
+ INVALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"office_number\": 201 }", "/additionalProperties", "type", "/office_number",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/office_number\", \"schemaRef\": \"#/additionalProperties\","
+ " \"expected\": [\"string\"], \"actual\": \"integer\""
+ "}}");
}
TEST(SchemaValidator, Object_Required) {
@@ -653,20 +1171,75 @@ TEST(SchemaValidator, Object_Required) {
VALIDATE(s, "{ \"name\": \"William Shakespeare\", \"email\" : \"bill@stratford-upon-avon.co.uk\" }", true);
VALIDATE(s, "{ \"name\": \"William Shakespeare\", \"email\" : \"bill@stratford-upon-avon.co.uk\", \"address\" : \"Henley Street, Stratford-upon-Avon, Warwickshire, England\", \"authorship\" : \"in question\"}", true);
- INVALIDATE(s, "{ \"name\": \"William Shakespeare\", \"address\" : \"Henley Street, Stratford-upon-Avon, Warwickshire, England\" }", "", "required", "");
-}
+ INVALIDATE(s, "{ \"name\": \"William Shakespeare\", \"address\" : \"Henley Street, Stratford-upon-Avon, Warwickshire, England\" }", "", "required", "",
+ "{ \"required\": {"
+ " \"errorCode\": 15,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"missing\": [\"email\"]"
+ "}}");
+ INVALIDATE(s, "{}", "", "required", "",
+ "{ \"required\": {"
+ " \"errorCode\": 15,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"missing\": [\"name\", \"email\"]"
+ "}}");
+}
+
+TEST(SchemaValidator, Object_Required_PassWithDefault) {
+ Document sd;
+ sd.Parse(
+ "{"
+ " \"type\": \"object\","
+ " \"properties\" : {"
+ " \"name\": { \"type\": \"string\", \"default\": \"William Shakespeare\" },"
+ " \"email\" : { \"type\": \"string\", \"default\": \"\" },"
+ " \"address\" : { \"type\": \"string\" },"
+ " \"telephone\" : { \"type\": \"string\" }"
+ " },"
+ " \"required\":[\"name\", \"email\"]"
+ "}");
+ SchemaDocument s(sd);
+ VALIDATE(s, "{ \"email\" : \"bill@stratford-upon-avon.co.uk\", \"address\" : \"Henley Street, Stratford-upon-Avon, Warwickshire, England\", \"authorship\" : \"in question\"}", true);
+ INVALIDATE(s, "{ \"name\": \"William Shakespeare\", \"address\" : \"Henley Street, Stratford-upon-Avon, Warwickshire, England\" }", "", "required", "",
+ "{ \"required\": {"
+ " \"errorCode\": 15,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"missing\": [\"email\"]"
+ "}}");
+ INVALIDATE(s, "{}", "", "required", "",
+ "{ \"required\": {"
+ " \"errorCode\": 15,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"missing\": [\"email\"]"
+ "}}");
+}
TEST(SchemaValidator, Object_PropertiesRange) {
Document sd;
sd.Parse("{\"type\":\"object\", \"minProperties\":2, \"maxProperties\":3}");
SchemaDocument s(sd);
- INVALIDATE(s, "{}", "", "minProperties", "");
- INVALIDATE(s, "{\"a\":0}", "", "minProperties", "");
+ INVALIDATE(s, "{}", "", "minProperties", "",
+ "{ \"minProperties\": {"
+ " \"errorCode\": 14,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 2, \"actual\": 0"
+ "}}");
+ INVALIDATE(s, "{\"a\":0}", "", "minProperties", "",
+ "{ \"minProperties\": {"
+ " \"errorCode\": 14,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 2, \"actual\": 1"
+ "}}");
VALIDATE(s, "{\"a\":0,\"b\":1}", true);
VALIDATE(s, "{\"a\":0,\"b\":1,\"c\":2}", true);
- INVALIDATE(s, "{\"a\":0,\"b\":1,\"c\":2,\"d\":3}", "", "maxProperties", "");
+ INVALIDATE(s, "{\"a\":0,\"b\":1,\"c\":2,\"d\":3}", "", "maxProperties", "",
+ "{ \"maxProperties\": {"
+ " \"errorCode\": 13,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\", "
+ " \"expected\": 3, \"actual\": 4"
+ "}}");
}
TEST(SchemaValidator, Object_PropertyDependencies) {
@@ -677,19 +1250,32 @@ TEST(SchemaValidator, Object_PropertyDependencies) {
" \"properties\": {"
" \"name\": { \"type\": \"string\" },"
" \"credit_card\": { \"type\": \"number\" },"
+ " \"cvv_code\": { \"type\": \"number\" },"
" \"billing_address\": { \"type\": \"string\" }"
" },"
" \"required\": [\"name\"],"
" \"dependencies\": {"
- " \"credit_card\": [\"billing_address\"]"
+ " \"credit_card\": [\"cvv_code\", \"billing_address\"]"
" }"
"}");
SchemaDocument s(sd);
- VALIDATE(s, "{ \"name\": \"John Doe\", \"credit_card\": 5555555555555555, \"billing_address\": \"555 Debtor's Lane\" }", true);
- INVALIDATE(s, "{ \"name\": \"John Doe\", \"credit_card\": 5555555555555555 }", "", "dependencies", "");
+ VALIDATE(s, "{ \"name\": \"John Doe\", \"credit_card\": 5555555555555555, \"cvv_code\": 777, "
+ "\"billing_address\": \"555 Debtor's Lane\" }", true);
+ INVALIDATE(s, "{ \"name\": \"John Doe\", \"credit_card\": 5555555555555555 }", "", "dependencies", "",
+ "{ \"dependencies\": {"
+ " \"errorCode\": 18,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"errors\": {"
+ " \"credit_card\": {"
+ " \"required\": {"
+ " \"errorCode\": 15,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#/dependencies/credit_card\","
+ " \"missing\": [\"cvv_code\", \"billing_address\"]"
+ " } } }"
+ "}}");
VALIDATE(s, "{ \"name\": \"John Doe\"}", true);
- VALIDATE(s, "{ \"name\": \"John Doe\", \"billing_address\": \"555 Debtor's Lane\" }", true);
+ VALIDATE(s, "{ \"name\": \"John Doe\", \"cvv_code\": 777, \"billing_address\": \"555 Debtor's Lane\" }", true);
}
TEST(SchemaValidator, Object_SchemaDependencies) {
@@ -714,7 +1300,18 @@ TEST(SchemaValidator, Object_SchemaDependencies) {
SchemaDocument s(sd);
VALIDATE(s, "{\"name\": \"John Doe\", \"credit_card\" : 5555555555555555,\"billing_address\" : \"555 Debtor's Lane\"}", true);
- INVALIDATE(s, "{\"name\": \"John Doe\", \"credit_card\" : 5555555555555555 }", "", "dependencies", "");
+ INVALIDATE(s, "{\"name\": \"John Doe\", \"credit_card\" : 5555555555555555 }", "", "dependencies", "",
+ "{ \"dependencies\": {"
+ " \"errorCode\": 18,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"errors\": {"
+ " \"credit_card\": {"
+ " \"required\": {"
+ " \"errorCode\": 15,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#/dependencies/credit_card\","
+ " \"missing\": [\"billing_address\"]"
+ " } } }"
+ "}}");
VALIDATE(s, "{\"name\": \"John Doe\", \"billing_address\" : \"555 Debtor's Lane\"}", true);
}
@@ -733,12 +1330,85 @@ TEST(SchemaValidator, Object_PatternProperties) {
VALIDATE(s, "{ \"S_25\": \"This is a string\" }", true);
VALIDATE(s, "{ \"I_0\": 42 }", true);
- INVALIDATE(s, "{ \"S_0\": 42 }", "", "patternProperties", "/S_0");
- INVALIDATE(s, "{ \"I_42\": \"This is a string\" }", "", "patternProperties", "/I_42");
+ INVALIDATE(s, "{ \"S_0\": 42 }", "", "patternProperties", "/S_0",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/S_0\", \"schemaRef\": \"#/patternProperties/%5ES_\","
+ " \"expected\": [\"string\"], \"actual\": \"integer\""
+ "}}");
+ INVALIDATE(s, "{ \"I_42\": \"This is a string\" }", "", "patternProperties", "/I_42",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/I_42\", \"schemaRef\": \"#/patternProperties/%5EI_\","
+ " \"expected\": [\"integer\"], \"actual\": \"string\""
+ "}}");
VALIDATE(s, "{ \"keyword\": \"value\" }", true);
}
-TEST(SchemaValidator, Object_PatternProperties_AdditionalProperties) {
+TEST(SchemaValidator, Object_PatternProperties_ErrorConflict) {
+ Document sd;
+ sd.Parse(
+ "{"
+ " \"type\": \"object\","
+ " \"patternProperties\": {"
+ " \"^I_\": { \"multipleOf\": 5 },"
+ " \"30$\": { \"multipleOf\": 6 }"
+ " }"
+ "}");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "{ \"I_30\": 30 }", true);
+ INVALIDATE(s, "{ \"I_30\": 7 }", "", "patternProperties", "/I_30",
+ "{ \"multipleOf\": ["
+ " {"
+ " \"errorCode\": 1,"
+ " \"instanceRef\": \"#/I_30\", \"schemaRef\": \"#/patternProperties/%5EI_\","
+ " \"expected\": 5, \"actual\": 7"
+ " }, {"
+ " \"errorCode\": 1,"
+ " \"instanceRef\": \"#/I_30\", \"schemaRef\": \"#/patternProperties/30%24\","
+ " \"expected\": 6, \"actual\": 7"
+ " }"
+ "]}");
+}
+
+TEST(SchemaValidator, Object_Properties_PatternProperties) {
+ Document sd;
+ sd.Parse(
+ "{"
+ " \"type\": \"object\","
+ " \"properties\": {"
+ " \"I_42\": { \"type\": \"integer\", \"minimum\": 73 }"
+ " },"
+ " \"patternProperties\": {"
+ " \"^I_\": { \"type\": \"integer\", \"multipleOf\": 6 }"
+ " }"
+ "}");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "{ \"I_6\": 6 }", true);
+ VALIDATE(s, "{ \"I_42\": 78 }", true);
+ INVALIDATE(s, "{ \"I_42\": 42 }", "", "patternProperties", "/I_42",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#/I_42\", \"schemaRef\": \"#/properties/I_42\","
+ " \"expected\": 73, \"actual\": 42"
+ "}}");
+ INVALIDATE(s, "{ \"I_42\": 7 }", "", "patternProperties", "/I_42",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#/I_42\", \"schemaRef\": \"#/properties/I_42\","
+ " \"expected\": 73, \"actual\": 7"
+ " },"
+ " \"multipleOf\": {"
+ " \"errorCode\": 1,"
+ " \"instanceRef\": \"#/I_42\", \"schemaRef\": \"#/patternProperties/%5EI_\","
+ " \"expected\": 6, \"actual\": 7"
+ " }"
+ "}");
+}
+
+TEST(SchemaValidator, Object_PatternProperties_AdditionalPropertiesObject) {
Document sd;
sd.Parse(
"{"
@@ -756,7 +1426,36 @@ TEST(SchemaValidator, Object_PatternProperties_AdditionalProperties) {
VALIDATE(s, "{ \"builtin\": 42 }", true);
VALIDATE(s, "{ \"keyword\": \"value\" }", true);
- INVALIDATE(s, "{ \"keyword\": 42 }", "/additionalProperties", "type", "/keyword");
+ INVALIDATE(s, "{ \"keyword\": 42 }", "/additionalProperties", "type", "/keyword",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/keyword\", \"schemaRef\": \"#/additionalProperties\","
+ " \"expected\": [\"string\"], \"actual\": \"integer\""
+ "}}");
+}
+
+// Replaces test Issue285 and tests failure as well as success
+TEST(SchemaValidator, Object_PatternProperties_AdditionalPropertiesBoolean) {
+ Document sd;
+ sd.Parse(
+ "{"
+ " \"type\": \"object\","
+ " \"patternProperties\": {"
+ " \"^S_\": { \"type\": \"string\" },"
+ " \"^I_\": { \"type\": \"integer\" }"
+ " },"
+ " \"additionalProperties\": false"
+ "}");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "{ \"S_25\": \"This is a string\" }", true);
+ VALIDATE(s, "{ \"I_0\": 42 }", true);
+ INVALIDATE(s, "{ \"keyword\": \"value\" }", "", "additionalProperties", "/keyword",
+ "{ \"additionalProperties\": {"
+ " \"errorCode\": 16,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"disallowed\": \"keyword\""
+ "}}");
}
#endif
@@ -767,7 +1466,12 @@ TEST(SchemaValidator, Array) {
VALIDATE(s, "[1, 2, 3, 4, 5]", true);
VALIDATE(s, "[3, \"different\", { \"types\" : \"of values\" }]", true);
- INVALIDATE(s, "{\"Not\": \"an array\"}", "", "type", "");
+ INVALIDATE(s, "{\"Not\": \"an array\"}", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"array\"], \"actual\": \"object\""
+ "}}");
}
TEST(SchemaValidator, Array_ItemsList) {
@@ -782,7 +1486,12 @@ TEST(SchemaValidator, Array_ItemsList) {
SchemaDocument s(sd);
VALIDATE(s, "[1, 2, 3, 4, 5]", true);
- INVALIDATE(s, "[1, 2, \"3\", 4, 5]", "/items", "type", "/2");
+ INVALIDATE(s, "[1, 2, \"3\", 4, 5]", "/items", "type", "/2",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/2\", \"schemaRef\": \"#/items\","
+ " \"expected\": [\"number\"], \"actual\": \"string\""
+ "}}");
VALIDATE(s, "[]", true);
}
@@ -811,13 +1520,25 @@ TEST(SchemaValidator, Array_ItemsTuple) {
SchemaDocument s(sd);
VALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\"]", true);
- INVALIDATE(s, "[24, \"Sussex\", \"Drive\"]", "/items/2", "enum", "/2");
- INVALIDATE(s, "[\"Palais de l'Elysee\"]", "/items/0", "type", "/0");
+ INVALIDATE(s, "[24, \"Sussex\", \"Drive\"]", "/items/2", "enum", "/2",
+ "{ \"enum\": { \"errorCode\": 19, \"instanceRef\": \"#/2\", \"schemaRef\": \"#/items/2\" }}");
+ INVALIDATE(s, "[\"Palais de l'Elysee\"]", "/items/0", "type", "/0",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/0\", \"schemaRef\": \"#/items/0\","
+ " \"expected\": [\"number\"], \"actual\": \"string\""
+ "}}");
+ INVALIDATE(s, "[\"Twenty-four\", \"Sussex\", \"Drive\"]", "/items/0", "type", "/0",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/0\", \"schemaRef\": \"#/items/0\","
+ " \"expected\": [\"number\"], \"actual\": \"string\""
+ "}}"); // fail fast
VALIDATE(s, "[10, \"Downing\", \"Street\"]", true);
VALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\", \"Washington\"]", true);
}
-TEST(SchemaValidator, Array_AdditionalItmes) {
+TEST(SchemaValidator, Array_AdditionalItems) {
Document sd;
sd.Parse(
"{"
@@ -844,7 +1565,12 @@ TEST(SchemaValidator, Array_AdditionalItmes) {
VALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\"]", true);
VALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\"]", true);
- INVALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\", \"Washington\"]", "", "items", "/4");
+ INVALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\", \"Washington\"]", "", "additionalItems", "/4",
+ "{ \"additionalItems\": {"
+ " \"errorCode\": 12,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"disallowed\": 4"
+ "}}");
}
TEST(SchemaValidator, Array_ItemsRange) {
@@ -852,11 +1578,26 @@ TEST(SchemaValidator, Array_ItemsRange) {
sd.Parse("{\"type\": \"array\",\"minItems\": 2,\"maxItems\" : 3}");
SchemaDocument s(sd);
- INVALIDATE(s, "[]", "", "minItems", "");
- INVALIDATE(s, "[1]", "", "minItems", "");
+ INVALIDATE(s, "[]", "", "minItems", "",
+ "{ \"minItems\": {"
+ " \"errorCode\": 10,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 2, \"actual\": 0"
+ "}}");
+ INVALIDATE(s, "[1]", "", "minItems", "",
+ "{ \"minItems\": {"
+ " \"errorCode\": 10,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 2, \"actual\": 1"
+ "}}");
VALIDATE(s, "[1, 2]", true);
VALIDATE(s, "[1, 2, 3]", true);
- INVALIDATE(s, "[1, 2, 3, 4]", "", "maxItems", "");
+ INVALIDATE(s, "[1, 2, 3, 4]", "", "maxItems", "",
+ "{ \"maxItems\": {"
+ " \"errorCode\": 9,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 3, \"actual\": 4"
+ "}}");
}
TEST(SchemaValidator, Array_UniqueItems) {
@@ -865,7 +1606,18 @@ TEST(SchemaValidator, Array_UniqueItems) {
SchemaDocument s(sd);
VALIDATE(s, "[1, 2, 3, 4, 5]", true);
- INVALIDATE(s, "[1, 2, 3, 3, 4]", "", "uniqueItems", "/3");
+ INVALIDATE(s, "[1, 2, 3, 3, 4]", "", "uniqueItems", "/3",
+ "{ \"uniqueItems\": {"
+ " \"errorCode\": 11,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"duplicates\": [2, 3]"
+ "}}");
+ INVALIDATE(s, "[1, 2, 3, 3, 3]", "", "uniqueItems", "/3",
+ "{ \"uniqueItems\": {"
+ " \"errorCode\": 11,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"duplicates\": [2, 3]"
+ "}}"); // fail fast
VALIDATE(s, "[]", true);
}
@@ -876,8 +1628,18 @@ TEST(SchemaValidator, Boolean) {
VALIDATE(s, "true", true);
VALIDATE(s, "false", true);
- INVALIDATE(s, "\"true\"", "", "type", "");
- INVALIDATE(s, "0", "", "type", "");
+ INVALIDATE(s, "\"true\"", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"boolean\"], \"actual\": \"string\""
+ "}}");
+ INVALIDATE(s, "0", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"boolean\"], \"actual\": \"integer\""
+ "}}");
}
TEST(SchemaValidator, Null) {
@@ -886,9 +1648,24 @@ TEST(SchemaValidator, Null) {
SchemaDocument s(sd);
VALIDATE(s, "null", true);
- INVALIDATE(s, "false", "", "type", "");
- INVALIDATE(s, "0", "", "type", "");
- INVALIDATE(s, "\"\"", "", "type", "");
+ INVALIDATE(s, "false", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"null\"], \"actual\": \"boolean\""
+ "}}");
+ INVALIDATE(s, "0", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"null\"], \"actual\": \"integer\""
+ "}}");
+ INVALIDATE(s, "\"\"", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"null\"], \"actual\": \"string\""
+ "}}");
}
// Additional tests
@@ -899,8 +1676,18 @@ TEST(SchemaValidator, ObjectInArray) {
SchemaDocument s(sd);
VALIDATE(s, "[\"a\"]", true);
- INVALIDATE(s, "[1]", "/items", "type", "/0");
- INVALIDATE(s, "[{}]", "/items", "type", "/0");
+ INVALIDATE(s, "[1]", "/items", "type", "/0",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/0\", \"schemaRef\": \"#/items\","
+ " \"expected\": [\"string\"], \"actual\": \"integer\""
+ "}}");
+ INVALIDATE(s, "[{}]", "/items", "type", "/0",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/0\", \"schemaRef\": \"#/items\","
+ " \"expected\": [\"string\"], \"actual\": \"object\""
+ "}}");
}
TEST(SchemaValidator, MultiTypeInObject) {
@@ -918,7 +1705,12 @@ TEST(SchemaValidator, MultiTypeInObject) {
VALIDATE(s, "{ \"tel\": 999 }", true);
VALIDATE(s, "{ \"tel\": \"123-456\" }", true);
- INVALIDATE(s, "{ \"tel\": true }", "/properties/tel", "type", "/tel");
+ INVALIDATE(s, "{ \"tel\": true }", "/properties/tel", "type", "/tel",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/tel\", \"schemaRef\": \"#/properties/tel\","
+ " \"expected\": [\"string\", \"integer\"], \"actual\": \"boolean\""
+ "}}");
}
TEST(SchemaValidator, MultiTypeWithObject) {
@@ -936,7 +1728,12 @@ TEST(SchemaValidator, MultiTypeWithObject) {
VALIDATE(s, "\"Hello\"", true);
VALIDATE(s, "{ \"tel\": 999 }", true);
- INVALIDATE(s, "{ \"tel\": \"fail\" }", "/properties/tel", "type", "/tel");
+ INVALIDATE(s, "{ \"tel\": \"fail\" }", "/properties/tel", "type", "/tel",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/tel\", \"schemaRef\": \"#/properties/tel\","
+ " \"expected\": [\"integer\"], \"actual\": \"string\""
+ "}}");
}
TEST(SchemaValidator, AllOf_Nested) {
@@ -953,11 +1750,72 @@ TEST(SchemaValidator, AllOf_Nested) {
VALIDATE(s, "\"ok\"", true);
VALIDATE(s, "\"OK\"", true);
- INVALIDATE(s, "\"okay\"", "", "allOf", "");
- INVALIDATE(s, "\"o\"", "", "allOf", "");
- INVALIDATE(s, "\"n\"", "", "allOf", "");
- INVALIDATE(s, "\"too long\"", "", "allOf", "");
- INVALIDATE(s, "123", "", "allOf", "");
+ INVALIDATE(s, "\"okay\"", "", "allOf", "",
+ "{ \"allOf\": {"
+ " \"errors\": ["
+ " {},{},"
+ " { \"allOf\": {"
+ " \"errors\": ["
+ " {},"
+ " { \"enum\": {\"errorCode\": 19, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/1\" }}"
+ " ],"
+ " \"errorCode\": 23, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2\""
+ " }}],"
+ " \"errorCode\": 23, \"instanceRef\": \"#\", \"schemaRef\": \"#\""
+ "}}");
+ INVALIDATE(s, "\"o\"", "", "allOf", "",
+ "{ \"allOf\": {"
+ " \"errors\": ["
+ " { \"minLength\": {\"actual\": \"o\", \"expected\": 2, \"errorCode\": 7, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/0\" }},"
+ " {},{}"
+ " ],"
+ " \"errorCode\": 23, \"instanceRef\": \"#\", \"schemaRef\": \"#\""
+ "}}");
+ INVALIDATE(s, "\"n\"", "", "allOf", "",
+ "{ \"allOf\": {"
+ " \"errors\": ["
+ " { \"minLength\": {\"actual\": \"n\", \"expected\": 2, \"errorCode\": 7, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/0\" }},"
+ " {},"
+ " { \"allOf\": {"
+ " \"errors\": ["
+ " { \"enum\": {\"errorCode\": 19 ,\"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/0\"}},"
+ " { \"enum\": {\"errorCode\": 19, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/1\"}}"
+ " ],"
+ " \"errorCode\": 23, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2\""
+ " }}"
+ " ],"
+ " \"errorCode\":23,\"instanceRef\":\"#\",\"schemaRef\":\"#\""
+ "}}");
+ INVALIDATE(s, "\"too long\"", "", "allOf", "",
+ "{ \"allOf\": {"
+ " \"errors\": ["
+ " {},"
+ " { \"maxLength\": {\"actual\": \"too long\", \"expected\": 5, \"errorCode\": 6, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/1\" }},"
+ " { \"allOf\": {"
+ " \"errors\": ["
+ " { \"enum\": {\"errorCode\": 19 ,\"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/0\"}},"
+ " { \"enum\": {\"errorCode\": 19, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/1\"}}"
+ " ],"
+ " \"errorCode\": 23, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2\""
+ " }}"
+ " ],"
+ " \"errorCode\":23,\"instanceRef\":\"#\",\"schemaRef\":\"#\""
+ "}}");
+ INVALIDATE(s, "123", "", "allOf", "",
+ "{ \"allOf\": {"
+ " \"errors\": ["
+ " {\"type\": {\"expected\": [\"string\"], \"actual\": \"integer\", \"errorCode\": 20, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/0\"}},"
+ " {\"type\": {\"expected\": [\"string\"], \"actual\": \"integer\", \"errorCode\": 20, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/1\"}},"
+ " { \"allOf\": {"
+ " \"errors\": ["
+ " { \"enum\": {\"errorCode\": 19 ,\"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/0\"}},"
+ " { \"enum\": {\"errorCode\": 19, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/1\"}}"
+ " ],"
+ " \"errorCode\": 23, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2\""
+ " }}"
+ " ],"
+ " \"errorCode\":23,\"instanceRef\":\"#\",\"schemaRef\":\"#\""
+ "}}");
}
TEST(SchemaValidator, EscapedPointer) {
@@ -970,7 +1828,189 @@ TEST(SchemaValidator, EscapedPointer) {
" }"
"}");
SchemaDocument s(sd);
- INVALIDATE(s, "{\"~/\":true}", "/properties/~0~1", "type", "/~0~1");
+ INVALIDATE(s, "{\"~/\":true}", "/properties/~0~1", "type", "/~0~1",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/~0~1\", \"schemaRef\": \"#/properties/~0~1\","
+ " \"expected\": [\"number\"], \"actual\": \"boolean\""
+ "}}");
+}
+
+TEST(SchemaValidator, SchemaPointer) {
+ Document sd;
+ sd.Parse(
+ "{"
+ " \"swagger\": \"2.0\","
+ " \"paths\": {"
+ " \"/some/path\": {"
+ " \"post\": {"
+ " \"parameters\": ["
+ " {"
+ " \"in\": \"body\","
+ " \"name\": \"body\","
+ " \"schema\": {"
+ " \"properties\": {"
+ " \"a\": {"
+ " \"$ref\": \"#/definitions/Prop_a\""
+ " },"
+ " \"b\": {"
+ " \"type\": \"integer\""
+ " }"
+ " },"
+ " \"type\": \"object\""
+ " }"
+ " }"
+ " ],"
+ " \"responses\": {"
+ " \"200\": {"
+ " \"schema\": {"
+ " \"$ref\": \"#/definitions/Resp_200\""
+ " }"
+ " }"
+ " }"
+ " }"
+ " }"
+ " },"
+ " \"definitions\": {"
+ " \"Prop_a\": {"
+ " \"properties\": {"
+ " \"c\": {"
+ " \"enum\": ["
+ " \"C1\","
+ " \"C2\","
+ " \"C3\""
+ " ],"
+ " \"type\": \"string\""
+ " },"
+ " \"d\": {"
+ " \"$ref\": \"#/definitions/Prop_d\""
+ " },"
+ " \"s\": {"
+ " \"type\": \"string\""
+ " }"
+ " },"
+ " \"required\": [\"c\"],"
+ " \"type\": \"object\""
+ " },"
+ " \"Prop_d\": {"
+ " \"properties\": {"
+ " \"a\": {"
+ " \"$ref\": \"#/definitions/Prop_a\""
+ " },"
+ " \"c\": {"
+ " \"$ref\": \"#/definitions/Prop_a/properties/c\""
+ " }"
+ " },"
+ " \"type\": \"object\""
+ " },"
+ " \"Resp_200\": {"
+ " \"properties\": {"
+ " \"e\": {"
+ " \"type\": \"string\""
+ " },"
+ " \"f\": {"
+ " \"type\": \"boolean\""
+ " }"
+ " },"
+ " \"type\": \"object\""
+ " }"
+ " }"
+ "}");
+ SchemaDocument s1(sd, NULL, 0, NULL, NULL, Pointer("#/paths/~1some~1path/post/parameters/0/schema"));
+ VALIDATE(s1,
+ "{"
+ " \"a\": {"
+ " \"c\": \"C1\","
+ " \"d\": {"
+ " \"a\": {"
+ " \"c\": \"C2\""
+ " },"
+ " \"c\": \"C3\""
+ " }"
+ " },"
+ " \"b\": 123"
+ "}",
+ true);
+ INVALIDATE(s1,
+ "{"
+ " \"a\": {"
+ " \"c\": \"C1\","
+ " \"d\": {"
+ " \"a\": {"
+ " \"c\": \"C2\""
+ " },"
+ " \"c\": \"C3\""
+ " }"
+ " },"
+ " \"b\": \"should be an int\""
+ "}",
+ "#/paths/~1some~1path/post/parameters/0/schema/properties/b", "type", "#/b",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\":\"#/b\","
+ " \"schemaRef\":\"#/paths/~1some~1path/post/parameters/0/schema/properties/b\","
+ " \"expected\": [\"integer\"], \"actual\":\"string\""
+ "}}");
+ INVALIDATE(s1,
+ "{"
+ " \"a\": {"
+ " \"c\": \"C1\","
+ " \"d\": {"
+ " \"a\": {"
+ " \"c\": \"should be within enum\""
+ " },"
+ " \"c\": \"C3\""
+ " }"
+ " },"
+ " \"b\": 123"
+ "}",
+ "#/definitions/Prop_a/properties/c", "enum", "#/a/d/a/c",
+ "{ \"enum\": {"
+ " \"errorCode\": 19,"
+ " \"instanceRef\":\"#/a/d/a/c\","
+ " \"schemaRef\":\"#/definitions/Prop_a/properties/c\""
+ "}}");
+ INVALIDATE(s1,
+ "{"
+ " \"a\": {"
+ " \"c\": \"C1\","
+ " \"d\": {"
+ " \"a\": {"
+ " \"s\": \"required 'c' is missing\""
+ " }"
+ " }"
+ " },"
+ " \"b\": 123"
+ "}",
+ "#/definitions/Prop_a", "required", "#/a/d/a",
+ "{ \"required\": {"
+ " \"errorCode\": 15,"
+ " \"missing\":[\"c\"],"
+ " \"instanceRef\":\"#/a/d/a\","
+ " \"schemaRef\":\"#/definitions/Prop_a\""
+ "}}");
+ SchemaDocument s2(sd, NULL, 0, NULL, NULL, Pointer("#/paths/~1some~1path/post/responses/200/schema"));
+ VALIDATE(s2,
+ "{ \"e\": \"some string\", \"f\": false }",
+ true);
+ INVALIDATE(s2,
+ "{ \"e\": true, \"f\": false }",
+ "#/definitions/Resp_200/properties/e", "type", "#/e",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\":\"#/e\","
+ " \"schemaRef\":\"#/definitions/Resp_200/properties/e\","
+ " \"expected\": [\"string\"], \"actual\":\"boolean\""
+ "}}");
+ INVALIDATE(s2,
+ "{ \"e\": \"some string\", \"f\": 123 }",
+ "#/definitions/Resp_200/properties/f", "type", "#/f",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\":\"#/f\","
+ " \"schemaRef\":\"#/definitions/Resp_200/properties/f\","
+ " \"expected\": [\"boolean\"], \"actual\":\"integer\""
+ "}}");
}
template <typename Allocator>
@@ -1012,14 +2052,21 @@ TEST(SchemaValidator, ValidateMetaSchema) {
ASSERT_FALSE(d.HasParseError());
SchemaDocument sd(d);
SchemaValidator validator(sd);
- if (!d.Accept(validator)) {
+ d.Accept(validator);
+ if (!validator.IsValid()) {
StringBuffer sb;
validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);
printf("Invalid schema: %s\n", sb.GetString());
printf("Invalid keyword: %s\n", validator.GetInvalidSchemaKeyword());
+ printf("Invalid code: %d\n", validator.GetInvalidSchemaCode());
+ printf("Invalid message: %s\n", GetValidateError_En(validator.GetInvalidSchemaCode()));
sb.Clear();
validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);
printf("Invalid document: %s\n", sb.GetString());
+ sb.Clear();
+ Writer<StringBuffer> w(sb);
+ validator.GetError().Accept(w);
+ printf("Validation error: %s\n", sb.GetString());
ADD_FAILURE();
}
CrtAllocator::Free(json);
@@ -1039,7 +2086,8 @@ TEST(SchemaValidator, ValidateMetaSchema_UTF16) {
ASSERT_FALSE(d.HasParseError());
SD sd(d);
SV validator(sd);
- if (!d.Accept(validator)) {
+ d.Accept(validator);
+ if (!validator.IsValid()) {
GenericStringBuffer<UTF16<> > sb;
validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);
wprintf(L"Invalid schema: %ls\n", sb.GetString());
@@ -1047,6 +2095,10 @@ TEST(SchemaValidator, ValidateMetaSchema_UTF16) {
sb.Clear();
validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);
wprintf(L"Invalid document: %ls\n", sb.GetString());
+ sb.Clear();
+ Writer<GenericStringBuffer<UTF16<> >, UTF16<> > w(sb);
+ validator.GetError().Accept(w);
+ printf("Validation error: %ls\n", sb.GetString());
ADD_FAILURE();
}
CrtAllocator::Free(json);
@@ -1063,7 +2115,15 @@ public:
"jsonschema/remotes/integer.json",
"jsonschema/remotes/subSchemas.json",
"jsonschema/remotes/folder/folderInteger.json",
- "draft-04/schema"
+ "draft-04/schema",
+ "unittestschema/address.json"
+ };
+ const char* uris[kCount] = {
+ "http://localhost:1234/integer.json",
+ "http://localhost:1234/subSchemas.json",
+ "http://localhost:1234/folder/folderInteger.json",
+ "http://json-schema.org/draft-04/schema",
+ "http://localhost:1234/address.json"
};
for (size_t i = 0; i < kCount; i++) {
@@ -1081,7 +2141,7 @@ public:
MemoryPoolAllocator<> stackAllocator(stackBuffer, sizeof(stackBuffer));
DocumentType d(&documentAllocator_, 1024, &stackAllocator);
d.Parse(json);
- sd_[i] = new SchemaDocumentType(d, 0, &schemaAllocator_);
+ sd_[i] = new SchemaDocumentType(d, uris[i], static_cast<SizeType>(strlen(uris[i])), 0, &schemaAllocator_);
MemoryPoolAllocator<>::Free(json);
}
};
@@ -1093,16 +2153,13 @@ public:
}
virtual const SchemaDocumentType* GetRemoteDocument(const char* uri, SizeType length) {
- const char* uris[kCount] = {
- "http://localhost:1234/integer.json",
- "http://localhost:1234/subSchemas.json",
- "http://localhost:1234/folder/folderInteger.json",
- "http://json-schema.org/draft-04/schema"
- };
-
+ //printf("GetRemoteDocument : %s\n", uri);
for (size_t i = 0; i < kCount; i++)
- if (strncmp(uri, uris[i], length) == 0 && strlen(uris[i]) == length)
+ if (typename SchemaDocumentType::GValue(uri, length) == sd_[i]->GetURI()) {
+ //printf("Matched document");
return sd_[i];
+ }
+ //printf("No matched document");
return 0;
}
@@ -1112,12 +2169,12 @@ private:
RemoteSchemaDocumentProvider(const RemoteSchemaDocumentProvider&);
RemoteSchemaDocumentProvider& operator=(const RemoteSchemaDocumentProvider&);
- static const size_t kCount = 4;
+ static const size_t kCount = 5;
SchemaDocumentType* sd_[kCount];
typename DocumentType::AllocatorType documentAllocator_;
typename SchemaDocumentType::AllocatorType schemaAllocator_;
char documentBuffer_[16384];
- char schemaBuffer_[128 * 1024];
+ char schemaBuffer_[128u * 1024];
};
TEST(SchemaValidator, TestSuite) {
@@ -1181,6 +2238,7 @@ TEST(SchemaValidator, TestSuite) {
ADD_FAILURE();
}
else {
+ //printf("\njson test suite file %s parsed ok\n", filename);
GenericDocument<UTF8<>, MemoryPoolAllocator<>, MemoryPoolAllocator<> > d(&documentAllocator, 1024, &documentStackAllocator);
d.Parse(json);
if (d.HasParseError()) {
@@ -1190,22 +2248,27 @@ TEST(SchemaValidator, TestSuite) {
else {
for (Value::ConstValueIterator schemaItr = d.Begin(); schemaItr != d.End(); ++schemaItr) {
{
- SchemaDocumentType schema((*schemaItr)["schema"], &provider, &schemaAllocator);
- GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > validator(schema, &validatorAllocator);
const char* description1 = (*schemaItr)["description"].GetString();
+ //printf("\ncompiling schema for json test %s \n", description1);
+ SchemaDocumentType schema((*schemaItr)["schema"], filenames[i], static_cast<SizeType>(strlen(filenames[i])), &provider, &schemaAllocator);
+ GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > validator(schema, &validatorAllocator);
const Value& tests = (*schemaItr)["tests"];
for (Value::ConstValueIterator testItr = tests.Begin(); testItr != tests.End(); ++testItr) {
const char* description2 = (*testItr)["description"].GetString();
+ //printf("running json test %s \n", description2);
if (!onlyRunDescription || strcmp(description2, onlyRunDescription) == 0) {
const Value& data = (*testItr)["data"];
bool expected = (*testItr)["valid"].GetBool();
testCount++;
validator.Reset();
- bool actual = data.Accept(validator);
+ data.Accept(validator);
+ bool actual = validator.IsValid();
if (expected != actual)
printf("Fail: %30s \"%s\" \"%s\"\n", filename, description1, description2);
- else
+ else {
+ //printf("Passed: %30s \"%s\" \"%s\"\n", filename, description1, description2);
passCount++;
+ }
}
}
//printf("%zu %zu %zu\n", documentAllocator.Size(), schemaAllocator.Size(), validatorAllocator.Size());
@@ -1220,8 +2283,8 @@ TEST(SchemaValidator, TestSuite) {
jsonAllocator.Clear();
}
printf("%d / %d passed (%2d%%)\n", passCount, testCount, passCount * 100 / testCount);
- // if (passCount != testCount)
- // ADD_FAILURE();
+ if (passCount != testCount)
+ ADD_FAILURE();
}
TEST(SchemaValidatingReader, Simple) {
@@ -1252,9 +2315,20 @@ TEST(SchemaValidatingReader, Invalid) {
EXPECT_FALSE(reader.IsValid());
EXPECT_EQ(kParseErrorTermination, reader.GetParseResult().Code());
EXPECT_STREQ("maxLength", reader.GetInvalidSchemaKeyword());
+ EXPECT_TRUE(reader.GetInvalidSchemaCode() == kValidateErrorMaxLength);
EXPECT_TRUE(reader.GetInvalidSchemaPointer() == SchemaDocument::PointerType(""));
EXPECT_TRUE(reader.GetInvalidDocumentPointer() == SchemaDocument::PointerType(""));
EXPECT_TRUE(d.IsNull());
+ Document e;
+ e.Parse(
+ "{ \"maxLength\": {"
+ " \"errorCode\": 6,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 3, \"actual\": \"ABCD\""
+ "}}");
+ if (e != reader.GetError()) {
+ ADD_FAILURE();
+ }
}
TEST(SchemaValidatingWriter, Simple) {
@@ -1279,6 +2353,21 @@ TEST(SchemaValidatingWriter, Simple) {
EXPECT_FALSE(validator.IsValid());
EXPECT_TRUE(validator.GetInvalidSchemaPointer() == SchemaDocument::PointerType(""));
EXPECT_TRUE(validator.GetInvalidDocumentPointer() == SchemaDocument::PointerType(""));
+ EXPECT_TRUE(validator.GetInvalidSchemaCode() == kValidateErrorMaxLength);
+ Document e;
+ e.Parse(
+ "{ \"maxLength\": {"
+" \"errorCode\": 6,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 3, \"actual\": \"ABCD\""
+ "}}");
+ EXPECT_EQ(e, validator.GetError());
+}
+
+TEST(Schema, Issue848) {
+ rapidjson::Document d;
+ rapidjson::SchemaDocument s(d);
+ rapidjson::GenericSchemaValidator<rapidjson::SchemaDocument, rapidjson::Document> v(s);
}
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
@@ -1294,7 +2383,12 @@ TEST(Schema, Issue552) {
SchemaDocument s = ReturnSchemaDocument();
VALIDATE(s, "42", true);
VALIDATE(s, "\"Life, the universe, and everything\"", true);
- INVALIDATE(s, "[\"Life\", \"the universe\", \"and everything\"]", "", "type", "");
+ INVALIDATE(s, "[\"Life\", \"the universe\", \"and everything\"]", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"string\", \"number\"], \"actual\": \"array\""
+ "}}");
}
#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
@@ -1305,9 +2399,1177 @@ TEST(SchemaValidator, Issue608) {
SchemaDocument s(sd);
VALIDATE(s, "{\"a\" : null, \"b\": null}", true);
- INVALIDATE(s, "{\"a\" : null, \"a\" : null}", "", "required", "");
+ INVALIDATE(s, "{\"a\" : null, \"a\" : null}", "", "required", "",
+ "{ \"required\": {"
+ " \"errorCode\": 15,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"missing\": [\"b\"]"
+ "}}");
}
-#ifdef __clang__
+// Fail to resolve $ref in allOf causes crash in SchemaValidator::StartObject()
+TEST(SchemaValidator, Issue728_AllOfRef) {
+ Document sd;
+ sd.Parse("{\"allOf\": [{\"$ref\": \"#/abc\"}]}");
+ SchemaDocument s(sd);
+ SCHEMAERROR(s, "{\"RefUnknown\":{\"errorCode\":5,\"instanceRef\":\"#/allOf/0\",\"value\":\"#/abc\"}}");
+
+ VALIDATE_(s, "{\"key1\": \"abc\", \"key2\": \"def\"}", true, false);
+}
+
+TEST(SchemaValidator, Issue1017_allOfHandler) {
+ Document sd;
+ sd.Parse("{\"allOf\": [{\"type\": \"object\",\"properties\": {\"cyanArray2\": {\"type\": \"array\",\"items\": { \"type\": \"string\" }}}},{\"type\": \"object\",\"properties\": {\"blackArray\": {\"type\": \"array\",\"items\": { \"type\": \"string\" }}},\"required\": [ \"blackArray\" ]}]}");
+ SchemaDocument s(sd);
+ StringBuffer sb;
+ Writer<StringBuffer> writer(sb);
+ GenericSchemaValidator<SchemaDocument, Writer<StringBuffer> > validator(s, writer);
+ EXPECT_TRUE(validator.StartObject());
+ EXPECT_TRUE(validator.Key("cyanArray2", 10, false));
+ EXPECT_TRUE(validator.StartArray());
+ EXPECT_TRUE(validator.EndArray(0));
+ EXPECT_TRUE(validator.Key("blackArray", 10, false));
+ EXPECT_TRUE(validator.StartArray());
+ EXPECT_TRUE(validator.EndArray(0));
+ EXPECT_TRUE(validator.EndObject(0));
+ EXPECT_TRUE(validator.IsValid());
+ EXPECT_STREQ("{\"cyanArray2\":[],\"blackArray\":[]}", sb.GetString());
+}
+
+TEST(SchemaValidator, Ref_remote) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
+ Document sd;
+ sd.Parse("{\"$ref\": \"http://localhost:1234/subSchemas.json#/integer\"}");
+ SchemaDocumentType s(sd, 0, 0, &provider);
+ typedef GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > SchemaValidatorType;
+ typedef GenericPointer<Value, MemoryPoolAllocator<> > PointerType;
+ INVALIDATE_(s, "null", "/integer", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\","
+ " \"schemaRef\": \"http://localhost:1234/subSchemas.json#/integer\","
+ " \"expected\": [\"integer\"], \"actual\": \"null\""
+ "}}",
+ kValidateDefaultFlags, SchemaValidatorType, PointerType);
+}
+
+// Merge with id where $ref is full URI
+TEST(SchemaValidator, Ref_remote_change_resolution_scope_uri) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
+ Document sd;
+ sd.Parse("{\"id\": \"http://ignore/blah#/ref\", \"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"http://localhost:1234/subSchemas.json#/integer\"}}}");
+ SchemaDocumentType s(sd, 0, 0, &provider);
+ typedef GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > SchemaValidatorType;
+ typedef GenericPointer<Value, MemoryPoolAllocator<> > PointerType;
+ INVALIDATE_(s, "{\"myInt\": null}", "/integer", "type", "/myInt",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/myInt\","
+ " \"schemaRef\": \"http://localhost:1234/subSchemas.json#/integer\","
+ " \"expected\": [\"integer\"], \"actual\": \"null\""
+ "}}",
+ kValidateDefaultFlags, SchemaValidatorType, PointerType);
+}
+
+// Merge with id where $ref is a relative path
+TEST(SchemaValidator, Ref_remote_change_resolution_scope_relative_path) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
+ Document sd;
+ sd.Parse("{\"id\": \"http://localhost:1234/\", \"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"subSchemas.json#/integer\"}}}");
+ SchemaDocumentType s(sd, 0, 0, &provider);
+ typedef GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > SchemaValidatorType;
+ typedef GenericPointer<Value, MemoryPoolAllocator<> > PointerType;
+ INVALIDATE_(s, "{\"myInt\": null}", "/integer", "type", "/myInt",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/myInt\","
+ " \"schemaRef\": \"http://localhost:1234/subSchemas.json#/integer\","
+ " \"expected\": [\"integer\"], \"actual\": \"null\""
+ "}}",
+ kValidateDefaultFlags, SchemaValidatorType, PointerType);
+}
+
+// Merge with id where $ref is an absolute path
+TEST(SchemaValidator, Ref_remote_change_resolution_scope_absolute_path) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
+ Document sd;
+ sd.Parse("{\"id\": \"http://localhost:1234/xxxx\", \"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"/subSchemas.json#/integer\"}}}");
+ SchemaDocumentType s(sd, 0, 0, &provider);
+ typedef GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > SchemaValidatorType;
+ typedef GenericPointer<Value, MemoryPoolAllocator<> > PointerType;
+ INVALIDATE_(s, "{\"myInt\": null}", "/integer", "type", "/myInt",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/myInt\","
+ " \"schemaRef\": \"http://localhost:1234/subSchemas.json#/integer\","
+ " \"expected\": [\"integer\"], \"actual\": \"null\""
+ "}}",
+ kValidateDefaultFlags, SchemaValidatorType, PointerType);
+}
+
+// Merge with id where $ref is an absolute path, and the document has a base URI
+TEST(SchemaValidator, Ref_remote_change_resolution_scope_absolute_path_document) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
+ Document sd;
+ sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"/subSchemas.json#/integer\"}}}");
+ SchemaDocumentType s(sd, "http://localhost:1234/xxxx", 26, &provider);
+ typedef GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > SchemaValidatorType;
+ typedef GenericPointer<Value, MemoryPoolAllocator<> > PointerType;
+ INVALIDATE_(s, "{\"myInt\": null}", "/integer", "type", "/myInt",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/myInt\","
+ " \"schemaRef\": \"http://localhost:1234/subSchemas.json#/integer\","
+ " \"expected\": [\"integer\"], \"actual\": \"null\""
+ "}}",
+ kValidateDefaultFlags, SchemaValidatorType, PointerType);
+}
+
+// $ref is a non-JSON pointer fragment and there a matching id
+TEST(SchemaValidator, Ref_internal_id_1) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ Document sd;
+ sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt1\": {\"$ref\": \"#myId\"}, \"myStr\": {\"type\": \"string\", \"id\": \"#myStrId\"}, \"myInt2\": {\"type\": \"integer\", \"id\": \"#myId\"}}}");
+ SchemaDocumentType s(sd);
+ typedef GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > SchemaValidatorType;
+ typedef GenericPointer<Value, MemoryPoolAllocator<> > PointerType;
+ INVALIDATE_(s, "{\"myInt1\": null}", "/properties/myInt2", "type", "/myInt1",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/myInt1\","
+ " \"schemaRef\": \"#/properties/myInt2\","
+ " \"expected\": [\"integer\"], \"actual\": \"null\""
+ "}}",
+ kValidateDefaultFlags, SchemaValidatorType, PointerType);
+}
+
+// $ref is a non-JSON pointer fragment and there are two matching ids so we take the first
+TEST(SchemaValidator, Ref_internal_id_2) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ Document sd;
+ sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt1\": {\"$ref\": \"#myId\"}, \"myInt2\": {\"type\": \"integer\", \"id\": \"#myId\"}, \"myStr\": {\"type\": \"string\", \"id\": \"#myId\"}}}");
+ SchemaDocumentType s(sd);
+ typedef GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > SchemaValidatorType;
+ typedef GenericPointer<Value, MemoryPoolAllocator<> > PointerType;
+ INVALIDATE_(s, "{\"myInt1\": null}", "/properties/myInt2", "type", "/myInt1",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/myInt1\","
+ " \"schemaRef\": \"#/properties/myInt2\","
+ " \"expected\": [\"integer\"], \"actual\": \"null\""
+ "}}",
+ kValidateDefaultFlags, SchemaValidatorType, PointerType);
+}
+
+// $ref is a non-JSON pointer fragment and there is a matching id within array
+TEST(SchemaValidator, Ref_internal_id_in_array) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ Document sd;
+ sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt1\": {\"$ref\": \"#myId\"}, \"myInt2\": {\"anyOf\": [{\"type\": \"string\", \"id\": \"#myStrId\"}, {\"type\": \"integer\", \"id\": \"#myId\"}]}}}");
+ SchemaDocumentType s(sd);
+ typedef GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > SchemaValidatorType;
+ typedef GenericPointer<Value, MemoryPoolAllocator<> > PointerType;
+ INVALIDATE_(s, "{\"myInt1\": null}", "/properties/myInt2/anyOf/1", "type", "/myInt1",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/myInt1\","
+ " \"schemaRef\": \"#/properties/myInt2/anyOf/1\","
+ " \"expected\": [\"integer\"], \"actual\": \"null\""
+ "}}",
+ kValidateDefaultFlags, SchemaValidatorType, PointerType);
+}
+
+// $ref is a non-JSON pointer fragment and there is a matching id, and the schema is embedded in the document
+TEST(SchemaValidator, Ref_internal_id_and_schema_pointer) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ Document sd;
+ sd.Parse("{ \"schema\": {\"type\": \"object\", \"properties\": {\"myInt1\": {\"$ref\": \"#myId\"}, \"myInt2\": {\"anyOf\": [{\"type\": \"integer\", \"id\": \"#myId\"}]}}}}");
+ typedef GenericPointer<Value, MemoryPoolAllocator<> > PointerType;
+ SchemaDocumentType s(sd, 0, 0, 0, 0, PointerType("/schema"));
+ typedef GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > SchemaValidatorType;
+ INVALIDATE_(s, "{\"myInt1\": null}", "/schema/properties/myInt2/anyOf/0", "type", "/myInt1",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/myInt1\","
+ " \"schemaRef\": \"#/schema/properties/myInt2/anyOf/0\","
+ " \"expected\": [\"integer\"], \"actual\": \"null\""
+ "}}",
+ kValidateDefaultFlags, SchemaValidatorType, PointerType);
+}
+
+// Test that $refs are correctly resolved when intermediate multiple ids are present
+// Includes $ref to a part of the document with a different in-scope id, which also contains $ref..
+TEST(SchemaValidator, Ref_internal_multiple_ids) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ //RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
+ CrtAllocator allocator;
+ char* schema = ReadFile("unittestschema/idandref.json", allocator);
+ Document sd;
+ sd.Parse(schema);
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocumentType s(sd, "http://xyz", 10/*, &provider*/);
+ typedef GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > SchemaValidatorType;
+ typedef GenericPointer<Value, MemoryPoolAllocator<> > PointerType;
+ INVALIDATE_(s, "{\"PA1\": \"s\", \"PA2\": \"t\", \"PA3\": \"r\", \"PX1\": 1, \"PX2Y\": 2, \"PX3Z\": 3, \"PX4\": 4, \"PX5\": 5, \"PX6\": 6, \"PX7W\": 7, \"PX8N\": { \"NX\": 8}}", "#", "errors", "#",
+ "{ \"type\": ["
+ " {\"errorCode\": 20, \"instanceRef\": \"#/PA1\", \"schemaRef\": \"http://xyz#/definitions/A\", \"expected\": [\"integer\"], \"actual\": \"string\"},"
+ " {\"errorCode\": 20, \"instanceRef\": \"#/PA2\", \"schemaRef\": \"http://xyz#/definitions/A\", \"expected\": [\"integer\"], \"actual\": \"string\"},"
+ " {\"errorCode\": 20, \"instanceRef\": \"#/PA3\", \"schemaRef\": \"http://xyz#/definitions/A\", \"expected\": [\"integer\"], \"actual\": \"string\"},"
+ " {\"errorCode\": 20, \"instanceRef\": \"#/PX1\", \"schemaRef\": \"http://xyz#/definitions/B/definitions/X\", \"expected\": [\"boolean\"], \"actual\": \"integer\"},"
+ " {\"errorCode\": 20, \"instanceRef\": \"#/PX2Y\", \"schemaRef\": \"http://xyz#/definitions/B/definitions/X\", \"expected\": [\"boolean\"], \"actual\": \"integer\"},"
+ " {\"errorCode\": 20, \"instanceRef\": \"#/PX3Z\", \"schemaRef\": \"http://xyz#/definitions/B/definitions/X\", \"expected\": [\"boolean\"], \"actual\": \"integer\"},"
+ " {\"errorCode\": 20, \"instanceRef\": \"#/PX4\", \"schemaRef\": \"http://xyz#/definitions/B/definitions/X\", \"expected\": [\"boolean\"], \"actual\": \"integer\"},"
+ " {\"errorCode\": 20, \"instanceRef\": \"#/PX5\", \"schemaRef\": \"http://xyz#/definitions/B/definitions/X\", \"expected\": [\"boolean\"], \"actual\": \"integer\"},"
+ " {\"errorCode\": 20, \"instanceRef\": \"#/PX6\", \"schemaRef\": \"http://xyz#/definitions/B/definitions/X\", \"expected\": [\"boolean\"], \"actual\": \"integer\"},"
+ " {\"errorCode\": 20, \"instanceRef\": \"#/PX7W\", \"schemaRef\": \"http://xyz#/definitions/B/definitions/X\", \"expected\": [\"boolean\"], \"actual\": \"integer\"},"
+ " {\"errorCode\": 20, \"instanceRef\": \"#/PX8N/NX\", \"schemaRef\": \"http://xyz#/definitions/B/definitions/X\", \"expected\": [\"boolean\"], \"actual\": \"integer\"}"
+ "]}",
+ kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidatorType, PointerType);
+ CrtAllocator::Free(schema);
+}
+
+TEST(SchemaValidator, Ref_remote_issue1210) {
+ class SchemaDocumentProvider : public IRemoteSchemaDocumentProvider {
+ SchemaDocument** collection;
+
+ // Dummy private copy constructor & assignment operator.
+ // Function bodies added so that they compile in MSVC 2019.
+ SchemaDocumentProvider(const SchemaDocumentProvider&) : collection(NULL) {
+ }
+ SchemaDocumentProvider& operator=(const SchemaDocumentProvider&) {
+ return *this;
+ }
+
+ public:
+ SchemaDocumentProvider(SchemaDocument** collection) : collection(collection) { }
+ virtual const SchemaDocument* GetRemoteDocument(const char* uri, SizeType length) {
+ int i = 0;
+ while (collection[i] && SchemaDocument::GValue(uri, length) != collection[i]->GetURI()) ++i;
+ return collection[i];
+ }
+ };
+ SchemaDocument* collection[] = { 0, 0, 0 };
+ SchemaDocumentProvider provider(collection);
+
+ Document x, y, z;
+ x.Parse("{\"properties\":{\"country\":{\"$ref\":\"y.json#/definitions/country_remote\"}},\"type\":\"object\"}");
+ y.Parse("{\"definitions\":{\"country_remote\":{\"$ref\":\"z.json#/definitions/country_list\"}}}");
+ z.Parse("{\"definitions\":{\"country_list\":{\"enum\":[\"US\"]}}}");
+
+ SchemaDocument sz(z, "z.json", 6, &provider);
+ collection[0] = &sz;
+ SchemaDocument sy(y, "y.json", 6, &provider);
+ collection[1] = &sy;
+ SchemaDocument sx(x, "x.json", 6, &provider);
+
+ VALIDATE(sx, "{\"country\":\"UK\"}", false);
+ VALIDATE(sx, "{\"country\":\"US\"}", true);
+}
+
+// Test that when kValidateContinueOnErrorFlag is set, all errors are reported.
+TEST(SchemaValidator, ContinueOnErrors) {
+ CrtAllocator allocator;
+ char* schema = ReadFile("unittestschema/address.json", allocator);
+ Document sd;
+ sd.Parse(schema);
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ VALIDATE(s, "{\"version\": 1.0, \"address\": {\"number\": 24, \"street1\": \"The Woodlands\", \"street3\": \"Ham\", \"city\": \"Romsey\", \"area\": \"Kent\", \"country\": \"UK\", \"postcode\": \"SO51 0GP\"}, \"phones\": [\"0111-222333\", \"0777-666888\"], \"names\": [\"Fred\", \"Bloggs\"]}", true);
+ INVALIDATE_(s, "{\"version\": 1.01, \"address\": {\"number\": 0, \"street2\": false, \"street3\": \"Ham\", \"city\": \"RomseyTownFC\", \"area\": \"Narnia\", \"country\": \"USA\", \"postcode\": \"999ABC\"}, \"phones\": [], \"planet\": \"Earth\", \"extra\": {\"S_xxx\": 123}}", "#", "errors", "#",
+ "{ \"multipleOf\": {"
+ " \"errorCode\": 1, \"instanceRef\": \"#/version\", \"schemaRef\": \"#/definitions/decimal_type\", \"expected\": 1.0, \"actual\": 1.01"
+ " },"
+ " \"minimum\": {"
+ " \"errorCode\": 5, \"instanceRef\": \"#/address/number\", \"schemaRef\": \"#/definitions/positiveInt_type\", \"expected\": 0, \"actual\": 0, \"exclusiveMinimum\": true"
+ " },"
+ " \"type\": ["
+ " {\"expected\": [\"null\", \"string\"], \"actual\": \"boolean\", \"errorCode\": 20, \"instanceRef\": \"#/address/street2\", \"schemaRef\": \"#/definitions/address_type/properties/street2\"},"
+ " {\"expected\": [\"string\"], \"actual\": \"integer\", \"errorCode\": 20, \"instanceRef\": \"#/extra/S_xxx\", \"schemaRef\": \"#/properties/extra/patternProperties/%5ES_\"}"
+ " ],"
+ " \"maxLength\": {"
+ " \"actual\": \"RomseyTownFC\", \"expected\": 10, \"errorCode\": 6, \"instanceRef\": \"#/address/city\", \"schemaRef\": \"#/definitions/address_type/properties/city\""
+ " },"
+ " \"anyOf\": {"
+ " \"errors\":["
+ " {\"pattern\": {\"actual\": \"999ABC\", \"errorCode\": 8, \"instanceRef\": \"#/address/postcode\", \"schemaRef\": \"#/definitions/address_type/properties/postcode/anyOf/0\"}},"
+ " {\"pattern\": {\"actual\": \"999ABC\", \"errorCode\": 8, \"instanceRef\": \"#/address/postcode\", \"schemaRef\": \"#/definitions/address_type/properties/postcode/anyOf/1\"}}"
+ " ],"
+ " \"errorCode\": 24, \"instanceRef\": \"#/address/postcode\", \"schemaRef\": \"#/definitions/address_type/properties/postcode\""
+ " },"
+ " \"allOf\": {"
+ " \"errors\":["
+ " {\"enum\":{\"errorCode\":19,\"instanceRef\":\"#/address/country\",\"schemaRef\":\"#/definitions/country_type\"}}"
+ " ],"
+ " \"errorCode\":23,\"instanceRef\":\"#/address/country\",\"schemaRef\":\"#/definitions/address_type/properties/country\""
+ " },"
+ " \"minItems\": {"
+ " \"actual\": 0, \"expected\": 1, \"errorCode\": 10, \"instanceRef\": \"#/phones\", \"schemaRef\": \"#/properties/phones\""
+ " },"
+ " \"additionalProperties\": {"
+ " \"disallowed\": \"planet\", \"errorCode\": 16, \"instanceRef\": \"#\", \"schemaRef\": \"#\""
+ " },"
+ " \"required\": {"
+ " \"missing\": [\"street1\"], \"errorCode\": 15, \"instanceRef\": \"#/address\", \"schemaRef\": \"#/definitions/address_type\""
+ " },"
+ " \"oneOf\": {"
+ " \"matches\": [0, 1], \"errorCode\": 22, \"instanceRef\": \"#/address/area\", \"schemaRef\": \"#/definitions/address_type/properties/area\""
+ " }"
+ "}",
+ kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
+ INVALIDATE_(s, "{\"address\": {\"number\": 200, \"street1\": {}, \"street3\": null, \"city\": \"Rom\", \"area\": \"Dorset\", \"postcode\": \"SO51 0GP\"}, \"phones\": [\"0111-222333\", \"0777-666888\", \"0777-666888\"], \"names\": [\"Fred\", \"S\", \"M\", \"Bloggs\"]}", "#", "errors", "#",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3, \"instanceRef\": \"#/address/number\", \"schemaRef\": \"#/definitions/positiveInt_type\", \"expected\": 100, \"actual\": 200, \"exclusiveMaximum\": true"
+ " },"
+ " \"type\": {"
+ " \"expected\": [\"string\"], \"actual\": \"object\", \"errorCode\": 20, \"instanceRef\": \"#/address/street1\", \"schemaRef\": \"#/definitions/address_type/properties/street1\""
+ " },"
+ " \"not\": {"
+ " \"errorCode\": 25, \"instanceRef\": \"#/address/street3\", \"schemaRef\": \"#/definitions/address_type/properties/street3\""
+ " },"
+ " \"minLength\": {"
+ " \"actual\": \"Rom\", \"expected\": 4, \"errorCode\": 7, \"instanceRef\": \"#/address/city\", \"schemaRef\": \"#/definitions/address_type/properties/city\""
+ " },"
+ " \"maxItems\": {"
+ " \"actual\": 3, \"expected\": 2, \"errorCode\": 9, \"instanceRef\": \"#/phones\", \"schemaRef\": \"#/properties/phones\""
+ " },"
+ " \"uniqueItems\": {"
+ " \"duplicates\": [1, 2], \"errorCode\": 11, \"instanceRef\": \"#/phones\", \"schemaRef\": \"#/properties/phones\""
+ " },"
+ " \"minProperties\": {\"actual\": 6, \"expected\": 7, \"errorCode\": 14, \"instanceRef\": \"#/address\", \"schemaRef\": \"#/definitions/address_type\""
+ " },"
+ " \"additionalItems\": ["
+ " {\"disallowed\": 2, \"errorCode\": 12, \"instanceRef\": \"#/names\", \"schemaRef\": \"#/properties/names\"},"
+ " {\"disallowed\": 3, \"errorCode\": 12, \"instanceRef\": \"#/names\", \"schemaRef\": \"#/properties/names\"}"
+ " ],"
+ " \"dependencies\": {"
+ " \"errors\": {"
+ " \"address\": {\"required\": {\"missing\": [\"version\"], \"errorCode\": 15, \"instanceRef\": \"#\", \"schemaRef\": \"#/dependencies/address\"}},"
+ " \"names\": {\"required\": {\"missing\": [\"version\"], \"errorCode\": 15, \"instanceRef\": \"#\", \"schemaRef\": \"#/dependencies/names\"}}"
+ " },"
+ " \"errorCode\": 18, \"instanceRef\": \"#\", \"schemaRef\": \"#\""
+ " },"
+ " \"oneOf\": {"
+ " \"errors\": ["
+ " {\"enum\": {\"errorCode\": 19, \"instanceRef\": \"#/address/area\", \"schemaRef\": \"#/definitions/county_type\"}},"
+ " {\"enum\": {\"errorCode\": 19, \"instanceRef\": \"#/address/area\", \"schemaRef\": \"#/definitions/province_type\"}}"
+ " ],"
+ " \"errorCode\": 21, \"instanceRef\": \"#/address/area\", \"schemaRef\": \"#/definitions/address_type/properties/area\""
+ " }"
+ "}",
+ kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
+
+ CrtAllocator::Free(schema);
+}
+
+// Test that when kValidateContinueOnErrorFlag is set, it is not propagated to oneOf sub-validator so we only get the first error.
+TEST(SchemaValidator, ContinueOnErrors_OneOf) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
+ CrtAllocator allocator;
+ char* schema = ReadFile("unittestschema/oneOf_address.json", allocator);
+ Document sd;
+ sd.Parse(schema);
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocumentType s(sd, 0, 0, &provider);
+ typedef GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > SchemaValidatorType;
+ typedef GenericPointer<Value, MemoryPoolAllocator<> > PointerType;
+ INVALIDATE_(s, "{\"version\": 1.01, \"address\": {\"number\": 0, \"street2\": false, \"street3\": \"Ham\", \"city\": \"RomseyTownFC\", \"area\": \"BC\", \"country\": \"USA\", \"postcode\": \"999ABC\"}, \"phones\": [], \"planet\": \"Earth\", \"extra\": {\"S_xxx\": 123}}", "#", "errors", "#",
+ "{ \"oneOf\": {"
+ " \"errors\": [{"
+ " \"multipleOf\": {"
+ " \"errorCode\": 1, \"instanceRef\": \"#/version\", \"schemaRef\": \"http://localhost:1234/address.json#/definitions/decimal_type\", \"expected\": 1.0, \"actual\": 1.01"
+ " }"
+ " }],"
+ " \"errorCode\": 21, \"instanceRef\": \"#\", \"schemaRef\": \"#\""
+ " }"
+ "}",
+ kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidatorType, PointerType);
+ CrtAllocator::Free(schema);
+}
+
+// Test that when kValidateContinueOnErrorFlag is set, it is not propagated to allOf sub-validator so we only get the first error.
+TEST(SchemaValidator, ContinueOnErrors_AllOf) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
+ CrtAllocator allocator;
+ char* schema = ReadFile("unittestschema/allOf_address.json", allocator);
+ Document sd;
+ sd.Parse(schema);
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocumentType s(sd, 0, 0, &provider);
+ typedef GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > SchemaValidatorType;
+ typedef GenericPointer<Value, MemoryPoolAllocator<> > PointerType;
+ INVALIDATE_(s, "{\"version\": 1.01, \"address\": {\"number\": 0, \"street2\": false, \"street3\": \"Ham\", \"city\": \"RomseyTownFC\", \"area\": \"BC\", \"country\": \"USA\", \"postcode\": \"999ABC\"}, \"phones\": [], \"planet\": \"Earth\", \"extra\": {\"S_xxx\": 123}}", "#", "errors", "#",
+ "{ \"allOf\": {"
+ " \"errors\": [{"
+ " \"multipleOf\": {"
+ " \"errorCode\": 1, \"instanceRef\": \"#/version\", \"schemaRef\": \"http://localhost:1234/address.json#/definitions/decimal_type\", \"expected\": 1.0, \"actual\": 1.01"
+ " }"
+ " }],"
+ " \"errorCode\": 23, \"instanceRef\": \"#\", \"schemaRef\": \"#\""
+ " }"
+ "}",
+ kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidatorType, PointerType);
+ CrtAllocator::Free(schema);
+}
+
+// Test that when kValidateContinueOnErrorFlag is set, it is not propagated to anyOf sub-validator so we only get the first error.
+TEST(SchemaValidator, ContinueOnErrors_AnyOf) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
+ CrtAllocator allocator;
+ char* schema = ReadFile("unittestschema/anyOf_address.json", allocator);
+ Document sd;
+ sd.Parse(schema);
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocumentType s(sd, 0, 0, &provider);
+ typedef GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > SchemaValidatorType;
+ typedef GenericPointer<Value, MemoryPoolAllocator<> > PointerType;
+ INVALIDATE_(s, "{\"version\": 1.01, \"address\": {\"number\": 0, \"street2\": false, \"street3\": \"Ham\", \"city\": \"RomseyTownFC\", \"area\": \"BC\", \"country\": \"USA\", \"postcode\": \"999ABC\"}, \"phones\": [], \"planet\": \"Earth\", \"extra\": {\"S_xxx\": 123}}", "#", "errors", "#",
+ "{ \"anyOf\": {"
+ " \"errors\": [{"
+ " \"multipleOf\": {"
+ " \"errorCode\": 1, \"instanceRef\": \"#/version\", \"schemaRef\": \"http://localhost:1234/address.json#/definitions/decimal_type\", \"expected\": 1.0, \"actual\": 1.01"
+ " }"
+ " }],"
+ " \"errorCode\": 24, \"instanceRef\": \"#\", \"schemaRef\": \"#\""
+ " }"
+ "}",
+ kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidatorType, PointerType);
+
+ CrtAllocator::Free(schema);
+}
+
+// Test that when kValidateContinueOnErrorFlag is set, arrays with uniqueItems:true are correctly processed when an item is invalid.
+// This tests that we don't blow up if a hasher does not get created.
+TEST(SchemaValidator, ContinueOnErrors_UniqueItems) {
+ CrtAllocator allocator;
+ char* schema = ReadFile("unittestschema/address.json", allocator);
+ Document sd;
+ sd.Parse(schema);
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ VALIDATE(s, "{\"phones\":[\"12-34\",\"56-78\"]}", true);
+ INVALIDATE_(s, "{\"phones\":[\"12-34\",\"12-34\"]}", "#", "errors", "#",
+ "{\"uniqueItems\": {\"duplicates\": [0,1], \"errorCode\": 11, \"instanceRef\": \"#/phones\", \"schemaRef\": \"#/properties/phones\"}}",
+ kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
+ INVALIDATE_(s, "{\"phones\":[\"ab-34\",\"cd-78\"]}", "#", "errors", "#",
+ "{\"pattern\": ["
+ " {\"actual\": \"ab-34\", \"errorCode\": 8, \"instanceRef\": \"#/phones/0\", \"schemaRef\": \"#/definitions/phone_type\"},"
+ " {\"actual\": \"cd-78\", \"errorCode\": 8, \"instanceRef\": \"#/phones/1\", \"schemaRef\": \"#/definitions/phone_type\"}"
+ "]}",
+ kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
+ CrtAllocator::Free(schema);
+}
+
+// Test that when kValidateContinueOnErrorFlag is set, an enum field is correctly processed when it has an invalid value.
+// This tests that we don't blow up if a hasher does not get created.
+TEST(SchemaValidator, ContinueOnErrors_Enum) {
+ CrtAllocator allocator;
+ char* schema = ReadFile("unittestschema/address.json", allocator);
+ Document sd;
+ sd.Parse(schema);
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ VALIDATE(s, "{\"gender\":\"M\"}", true);
+ INVALIDATE_(s, "{\"gender\":\"X\"}", "#", "errors", "#",
+ "{\"enum\": {\"errorCode\": 19, \"instanceRef\": \"#/gender\", \"schemaRef\": \"#/properties/gender\"}}",
+ kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
+ INVALIDATE_(s, "{\"gender\":1}", "#", "errors", "#",
+ "{\"type\": {\"expected\":[\"string\"], \"actual\": \"integer\", \"errorCode\": 20, \"instanceRef\": \"#/gender\", \"schemaRef\": \"#/properties/gender\"}}",
+ kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
+ CrtAllocator::Free(schema);
+}
+
+// Test that when kValidateContinueOnErrorFlag is set, an array appearing for an object property is handled
+// This tests that we don't blow up when there is a type mismatch.
+TEST(SchemaValidator, ContinueOnErrors_RogueArray) {
+ CrtAllocator allocator;
+ char* schema = ReadFile("unittestschema/address.json", allocator);
+ Document sd;
+ sd.Parse(schema);
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ INVALIDATE_(s, "{\"address\":[{\"number\": 0}]}", "#", "errors", "#",
+ "{\"type\": {\"expected\":[\"object\"], \"actual\": \"array\", \"errorCode\": 20, \"instanceRef\": \"#/address\", \"schemaRef\": \"#/definitions/address_type\"},"
+ " \"dependencies\": {"
+ " \"errors\": {"
+ " \"address\": {\"required\": {\"missing\": [\"version\"], \"errorCode\": 15, \"instanceRef\": \"#\", \"schemaRef\": \"#/dependencies/address\"}}"
+ " },\"errorCode\": 18, \"instanceRef\": \"#\", \"schemaRef\": \"#\"}}",
+ kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
+ CrtAllocator::Free(schema);
+}
+
+// Test that when kValidateContinueOnErrorFlag is set, an object appearing for an array property is handled
+// This tests that we don't blow up when there is a type mismatch.
+TEST(SchemaValidator, ContinueOnErrors_RogueObject) {
+ CrtAllocator allocator;
+ char* schema = ReadFile("unittestschema/address.json", allocator);
+ Document sd;
+ sd.Parse(schema);
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ INVALIDATE_(s, "{\"phones\":{\"number\": 0}}", "#", "errors", "#",
+ "{\"type\": {\"expected\":[\"array\"], \"actual\": \"object\", \"errorCode\": 20, \"instanceRef\": \"#/phones\", \"schemaRef\": \"#/properties/phones\"}}",
+ kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
+ CrtAllocator::Free(schema);
+}
+
+// Test that when kValidateContinueOnErrorFlag is set, a string appearing for an array or object property is handled
+// This tests that we don't blow up when there is a type mismatch.
+TEST(SchemaValidator, ContinueOnErrors_RogueString) {
+ CrtAllocator allocator;
+ char* schema = ReadFile("unittestschema/address.json", allocator);
+ Document sd;
+ sd.Parse(schema);
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ INVALIDATE_(s, "{\"address\":\"number\"}", "#", "errors", "#",
+ "{\"type\": {\"expected\":[\"object\"], \"actual\": \"string\", \"errorCode\": 20, \"instanceRef\": \"#/address\", \"schemaRef\": \"#/definitions/address_type\"},"
+ " \"dependencies\": {"
+ " \"errors\": {"
+ " \"address\": {\"required\": {\"missing\": [\"version\"], \"errorCode\": 15, \"instanceRef\": \"#\", \"schemaRef\": \"#/dependencies/address\"}}"
+ " },\"errorCode\": 18, \"instanceRef\": \"#\", \"schemaRef\": \"#\"}}",
+ kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
+ INVALIDATE_(s, "{\"phones\":\"number\"}", "#", "errors", "#",
+ "{\"type\": {\"expected\":[\"array\"], \"actual\": \"string\", \"errorCode\": 20, \"instanceRef\": \"#/phones\", \"schemaRef\": \"#/properties/phones\"}}",
+ kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
+ CrtAllocator::Free(schema);
+}
+
+// Test that when kValidateContinueOnErrorFlag is set, an incorrect simple type with a sub-schema is handled correctly.
+// This tests that we don't blow up when there is a type mismatch but there is a sub-schema present
+TEST(SchemaValidator, ContinueOnErrors_BadSimpleType) {
+ Document sd;
+ sd.Parse("{\"type\":\"string\", \"anyOf\":[{\"maxLength\":2}]}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ VALIDATE(s, "\"AB\"", true);
+ INVALIDATE_(s, "\"ABC\"", "#", "errors", "#",
+ "{ \"anyOf\": {"
+ " \"errors\": [{"
+ " \"maxLength\": {"
+ " \"errorCode\": 6, \"instanceRef\": \"#\", \"schemaRef\": \"#/anyOf/0\", \"expected\": 2, \"actual\": \"ABC\""
+ " }"
+ " }],"
+ " \"errorCode\": 24, \"instanceRef\": \"#\", \"schemaRef\": \"#\""
+ " }"
+ "}",
+ kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
+ // Invalid type
+ INVALIDATE_(s, "333", "#", "errors", "#",
+ "{ \"type\": {"
+ " \"errorCode\": 20, \"instanceRef\": \"#\", \"schemaRef\": \"#\", \"expected\": [\"string\"], \"actual\": \"integer\""
+ " }"
+ "}",
+ kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
+}
+
+
+TEST(SchemaValidator, UnknownValidationError) {
+ ASSERT_TRUE(SchemaValidator::SchemaType::GetValidateErrorKeyword(kValidateErrors).GetString() == std::string("null"));
+}
+
+// The first occurrence of a duplicate keyword is taken
+TEST(SchemaValidator, DuplicateKeyword) {
+ Document sd;
+ sd.Parse("{ \"title\": \"test\",\"type\": \"number\", \"type\": \"string\" }");
+ EXPECT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ VALIDATE(s, "42", true);
+ INVALIDATE(s, "\"Life, the universe, and everything\"", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"number\"], \"actual\": \"string\""
+ "}}");
+}
+
+
+// SchemaDocument tests
+
+// Specification (schema draft, open api version)
+TEST(SchemaValidator, Schema_SupportedNotObject) {
+ Document sd;
+ sd.Parse("true");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_TRUE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft04);
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
+ EXPECT_TRUE(s.GetError().ObjectEmpty());
+}
+
+TEST(SchemaValidator, Schema_SupportedNoSpec) {
+ Document sd;
+ sd.Parse("{\"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_TRUE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft04);
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
+ EXPECT_TRUE(s.GetError().ObjectEmpty());
+}
+
+TEST(SchemaValidator, Schema_SupportedNoSpecStatic) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ Document sd;
+ sd.Parse("{\"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ Specification spec = SchemaDocumentType::GetSpecification(sd);
+ ASSERT_FALSE(spec.IsSupported());
+ ASSERT_TRUE(spec.draft == kDraftNone);
+ ASSERT_TRUE(spec.oapi == kVersionNone);
+}
+
+TEST(SchemaValidator, Schema_SupportedDraft5Static) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ Document sd;
+ sd.Parse("{\"$schema\":\"http://json-schema.org/draft-05/schema#\", \"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ Specification spec = SchemaDocumentType::GetSpecification(sd);
+ ASSERT_TRUE(spec.IsSupported());
+ ASSERT_TRUE(spec.draft == kDraft05);
+ ASSERT_TRUE(spec.oapi == kVersionNone);
+}
+
+TEST(SchemaValidator, Schema_SupportedDraft4) {
+ Document sd;
+ sd.Parse("{\"$schema\":\"http://json-schema.org/draft-04/schema#\", \"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_TRUE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft04);
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
+ EXPECT_TRUE(s.GetError().ObjectEmpty());
+}
+
+TEST(SchemaValidator, Schema_SupportedDraft4NoFrag) {
+ Document sd;
+ sd.Parse("{\"$schema\":\"http://json-schema.org/draft-04/schema\", \"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_TRUE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft04);
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
+ EXPECT_TRUE(s.GetError().ObjectEmpty());
+}
+
+TEST(SchemaValidator, Schema_SupportedDraft5) {
+ Document sd;
+ sd.Parse("{\"$schema\":\"http://json-schema.org/draft-05/schema#\", \"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_TRUE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft05);
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
+ EXPECT_TRUE(s.GetError().ObjectEmpty());
+}
+
+TEST(SchemaValidator, Schema_SupportedDraft5NoFrag) {
+ Document sd;
+ sd.Parse("{\"$schema\":\"http://json-schema.org/draft-05/schema\", \"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_TRUE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft05);
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
+ EXPECT_TRUE(s.GetError().ObjectEmpty());
+}
+
+TEST(SchemaValidator, Schema_IgnoreDraftEmbedded) {
+ Document sd;
+ sd.Parse("{\"root\": {\"$schema\":\"http://json-schema.org/draft-05/schema#\", \"type\": \"integer\"}}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd, 0, 0, 0, 0, SchemaDocument::PointerType("/root"));
+ ASSERT_TRUE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft04);
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
+ EXPECT_TRUE(s.GetError().ObjectEmpty());
+}
+
+TEST(SchemaValidator, Schema_SupportedDraftOverride) {
+ Document sd;
+ sd.Parse("{\"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd, 0, 0, 0, 0, 0, Specification(kDraft04));
+ ASSERT_TRUE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft04);
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
+ EXPECT_TRUE(s.GetError().ObjectEmpty());
+}
+
+TEST(SchemaValidator, Schema_UnknownDraftOverride) {
+ Document sd;
+ sd.Parse("{\"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd, 0, 0, 0, 0, 0, Specification(kDraftUnknown));
+ ASSERT_FALSE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().draft == kDraftUnknown);
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
+ SCHEMAERROR(s, "{\"SpecUnknown\":{\"errorCode\":10,\"instanceRef\":\"#\"}}");
+}
+
+TEST(SchemaValidator, Schema_UnsupportedDraftOverride) {
+ Document sd;
+ sd.Parse("{\"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd, 0, 0, 0, 0, 0, Specification(kDraft03));
+ ASSERT_FALSE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft03);
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
+ SCHEMAERROR(s, "{\"SpecUnsupported\":{\"errorCode\":11,\"instanceRef\":\"#\"}}");
+}
+
+TEST(SchemaValidator, Schema_UnknownDraft) {
+ Document sd;
+ sd.Parse("{\"$schema\":\"http://json-schema.org/draft-xxx/schema#\", \"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_FALSE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().draft == kDraftUnknown);
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
+ SCHEMAERROR(s, "{\"SpecUnknown\":{\"errorCode\":10,\"instanceRef\":\"#\"}}");
+}
+
+TEST(SchemaValidator, Schema_UnknownDraftNotString) {
+ Document sd;
+ sd.Parse("{\"$schema\": 4, \"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_FALSE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().draft == kDraftUnknown);
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
+ SCHEMAERROR(s, "{\"SpecUnknown\":{\"errorCode\":10,\"instanceRef\":\"#\"}}");
+}
+
+TEST(SchemaValidator, Schema_UnsupportedDraft3) {
+ Document sd;
+ sd.Parse("{\"$schema\":\"http://json-schema.org/draft-03/schema#\", \"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_FALSE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft03);
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
+ SCHEMAERROR(s, "{\"SpecUnsupported\":{\"errorCode\":11,\"instanceRef\":\"#\"}}");
+}
+
+TEST(SchemaValidator, Schema_UnsupportedDraft6) {
+ Document sd;
+ sd.Parse("{\"$schema\":\"http://json-schema.org/draft-06/schema#\", \"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_FALSE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft06);
+ SCHEMAERROR(s, "{\"SpecUnsupported\":{\"errorCode\":11,\"instanceRef\":\"#\"}}");
+}
+
+TEST(SchemaValidator, Schema_UnsupportedDraft7) {
+ Document sd;
+ sd.Parse("{\"$schema\":\"http://json-schema.org/draft-07/schema#\", \"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_FALSE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft07);
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
+ SCHEMAERROR(s, "{\"SpecUnsupported\":{\"errorCode\":11,\"instanceRef\":\"#\"}}");
+}
+
+TEST(SchemaValidator, Schema_UnsupportedDraft2019_09) {
+ Document sd;
+ sd.Parse("{\"$schema\":\"https://json-schema.org/draft/2019-09/schema\", \"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_FALSE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft2019_09);
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
+ SCHEMAERROR(s, "{\"SpecUnsupported\":{\"errorCode\":11,\"instanceRef\":\"#\"}}");
+}
+
+TEST(SchemaValidator, Schema_UnsupportedDraft2020_12) {
+ Document sd;
+ sd.Parse("{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\", \"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_FALSE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft2020_12);
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
+ SCHEMAERROR(s, "{\"SpecUnsupported\":{\"errorCode\":11,\"instanceRef\":\"#\"}}");
+}
+
+TEST(SchemaValidator, Schema_SupportedVersion20Static) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ Document sd;
+ sd.Parse("{\"swagger\":\"2.0\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ Specification spec = SchemaDocumentType::GetSpecification(sd);
+ ASSERT_TRUE(spec.IsSupported());
+ ASSERT_TRUE(spec.draft == kDraft04);
+ ASSERT_TRUE(spec.oapi == kVersion20);
+}
+
+TEST(SchemaValidator, Schema_SupportedVersion20) {
+ Document sd;
+ sd.Parse("{\"swagger\":\"2.0\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_TRUE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersion20);
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft04);
+ EXPECT_TRUE(s.GetError().ObjectEmpty());
+}
+
+TEST(SchemaValidator, Schema_SupportedVersion30x) {
+ Document sd;
+ sd.Parse("{\"openapi\":\"3.0.0\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_TRUE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersion30);
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft05);
+ EXPECT_TRUE(s.GetError().ObjectEmpty());
+}
+
+TEST(SchemaValidator, Schema_SupportedVersionOverride) {
+ Document sd;
+ sd.Parse("{\"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd, 0, 0, 0, 0, 0, Specification(kVersion20));
+ ASSERT_TRUE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersion20);
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft04);
+ EXPECT_TRUE(s.GetError().ObjectEmpty());
+}
+
+TEST(SchemaValidator, Schema_UnknownVersionOverride) {
+ Document sd;
+ sd.Parse("{\"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd, 0, 0, 0, 0, 0, Specification(kVersionUnknown));
+ ASSERT_FALSE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionUnknown);
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft04);
+ SCHEMAERROR(s, "{\"SpecUnknown\":{\"errorCode\":10,\"instanceRef\":\"#\"}}");
+}
+
+TEST(SchemaValidator, Schema_UnsupportedVersionOverride) {
+ Document sd;
+ sd.Parse("{\"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd, 0, 0, 0, 0, 0, Specification(kVersion31));
+ ASSERT_FALSE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersion31);
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft2020_12);
+ SCHEMAERROR(s, "{\"SpecUnsupported\":{\"errorCode\":11,\"instanceRef\":\"#\"}}");
+}
+
+TEST(SchemaValidator, Schema_UnknownVersion) {
+ Document sd;
+ sd.Parse("{\"openapi\":\"1.0\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_FALSE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionUnknown);
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft04);
+ SCHEMAERROR(s, "{\"SpecUnknown\":{\"errorCode\":10,\"instanceRef\":\"#\"}}");
+}
+
+TEST(SchemaValidator, Schema_UnknownVersionShort) {
+ Document sd;
+ sd.Parse("{\"openapi\":\"3.0.\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_FALSE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionUnknown);
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft04);
+ SCHEMAERROR(s, "{\"SpecUnknown\":{\"errorCode\":10,\"instanceRef\":\"#\"}}");
+}
+
+TEST(SchemaValidator, Schema_UnknownVersionNotString) {
+ Document sd;
+ sd.Parse("{\"swagger\": 2}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_FALSE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionUnknown);
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft04);
+ SCHEMAERROR(s, "{\"SpecUnknown\":{\"errorCode\":10,\"instanceRef\":\"#\"}}");
+}
+
+TEST(SchemaValidator, Schema_UnsupportedVersion31) {
+ Document sd;
+ sd.Parse("{\"openapi\":\"3.1.0\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_FALSE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersion31);
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft2020_12);
+ SCHEMAERROR(s, "{\"SpecUnsupported\":{\"errorCode\":11,\"instanceRef\":\"#\"}}");
+}
+
+TEST(SchemaValidator, Schema_DraftAndVersion) {
+ Document sd;
+ sd.Parse("{\"swagger\": \"2.0\", \"$schema\": \"http://json-schema.org/draft-04/schema#\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_TRUE(s.IsSupportedSpecification());
+ SCHEMAERROR(s, "{\"SpecIllegal\":{\"errorCode\":12,\"instanceRef\":\"#\"}}");
+}
+
+TEST(SchemaValidator, Schema_StartUnknown) {
+ Document sd;
+ sd.Parse("{\"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd, 0, 0, 0, 0, SchemaDocument::PointerType("/nowhere"));
+ SCHEMAERROR(s, "{\"StartUnknown\":{\"errorCode\":1,\"instanceRef\":\"#\", \"value\":\"#/nowhere\"}}");
+}
+
+TEST(SchemaValidator, Schema_MultipleErrors) {
+ Document sd;
+ sd.Parse("{\"swagger\": \"foo\", \"$schema\": \"bar\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ SCHEMAERROR(s, "{ \"SpecUnknown\": {\"errorCode\":10,\"instanceRef\":\"#\"},"
+ " \"SpecIllegal\": {\"errorCode\":12,\"instanceRef\":\"#\"}"
+ "}");
+}
+
+// $ref is a non-JSON pointer fragment - not allowed when OpenAPI
+TEST(SchemaValidator, Schema_RefPlainNameOpenApi) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ Document sd;
+ sd.Parse("{\"swagger\": \"2.0\", \"type\": \"object\", \"properties\": {\"myInt1\": {\"$ref\": \"#myId\"}, \"myStr\": {\"type\": \"string\", \"id\": \"#myStrId\"}, \"myInt2\": {\"type\": \"integer\", \"id\": \"#myId\"}}}");
+ SchemaDocumentType s(sd);
+ SCHEMAERROR(s, "{\"RefPlainName\":{\"errorCode\":2,\"instanceRef\":\"#/properties/myInt1\",\"value\":\"#myId\"}}");
+}
+
+// $ref is a non-JSON pointer fragment - not allowed when remote document
+TEST(SchemaValidator, Schema_RefPlainNameRemote) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
+ Document sd;
+ sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"/subSchemas.json#plainname\"}}}");
+ SchemaDocumentType s(sd, "http://localhost:1234/xxxx", 26, &provider);
+ SCHEMAERROR(s, "{\"RefPlainName\":{\"errorCode\":2,\"instanceRef\":\"#/properties/myInt\",\"value\":\"#plainname\"}}");
+}
+
+// $ref is an empty string
+TEST(SchemaValidator, Schema_RefEmptyString) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ Document sd;
+ sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt1\": {\"$ref\": \"\"}}}");
+ SchemaDocumentType s(sd);
+ SCHEMAERROR(s, "{\"RefInvalid\":{\"errorCode\":3,\"instanceRef\":\"#/properties/myInt1\"}}");
+}
+
+// $ref is remote but no provider
+TEST(SchemaValidator, Schema_RefNoRemoteProvider) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ Document sd;
+ sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"/subSchemas.json#plainname\"}}}");
+ SchemaDocumentType s(sd, "http://localhost:1234/xxxx", 26, 0);
+ SCHEMAERROR(s, "{\"RefNoRemoteProvider\":{\"errorCode\":7,\"instanceRef\":\"#/properties/myInt\"}}");
+}
+
+// $ref is remote but no schema returned
+TEST(SchemaValidator, Schema_RefNoRemoteSchema) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
+ Document sd;
+ sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"/will-not-resolve.json\"}}}");
+ SchemaDocumentType s(sd, "http://localhost:1234/xxxx", 26, &provider);
+ SCHEMAERROR(s, "{\"RefNoRemoteSchema\":{\"errorCode\":8,\"instanceRef\":\"#/properties/myInt\",\"value\":\"http://localhost:1234/will-not-resolve.json\"}}");
+}
+
+// $ref pointer is invalid
+TEST(SchemaValidator, Schema_RefPointerInvalid) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ Document sd;
+ sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"#/&&&&&\"}}}");
+ SchemaDocumentType s(sd);
+ SCHEMAERROR(s, "{\"RefPointerInvalid\":{\"errorCode\":4,\"instanceRef\":\"#/properties/myInt\",\"value\":\"#/&&&&&\",\"offset\":2}}");
+}
+
+// $ref is remote and pointer is invalid
+TEST(SchemaValidator, Schema_RefPointerInvalidRemote) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
+ Document sd;
+ sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"/subSchemas.json#/abc&&&&&\"}}}");
+ SchemaDocumentType s(sd, "http://localhost:1234/xxxx", 26, &provider);
+ SCHEMAERROR(s, "{\"RefPointerInvalid\":{\"errorCode\":4,\"instanceRef\":\"#/properties/myInt\",\"value\":\"#/abc&&&&&\",\"offset\":5}}");
+}
+
+// $ref is unknown non-pointer
+TEST(SchemaValidator, Schema_RefUnknownPlainName) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ Document sd;
+ sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"#plainname\"}}}");
+ SchemaDocumentType s(sd);
+ SCHEMAERROR(s, "{\"RefUnknown\":{\"errorCode\":5,\"instanceRef\":\"#/properties/myInt\",\"value\":\"#plainname\"}}");
+}
+
+/// $ref is unknown pointer
+TEST(SchemaValidator, Schema_RefUnknownPointer) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ Document sd;
+ sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"#/a/b\"}}}");
+ SchemaDocumentType s(sd);
+ SCHEMAERROR(s, "{\"RefUnknown\":{\"errorCode\":5,\"instanceRef\":\"#/properties/myInt\",\"value\":\"#/a/b\"}}");
+}
+
+// $ref is remote and unknown pointer
+TEST(SchemaValidator, Schema_RefUnknownPointerRemote) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
+ Document sd;
+ sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"/subSchemas.json#/a/b\"}}}");
+ SchemaDocumentType s(sd, "http://localhost:1234/xxxx", 26, &provider);
+ SCHEMAERROR(s, "{\"RefUnknown\":{\"errorCode\":5,\"instanceRef\":\"#/properties/myInt\",\"value\":\"http://localhost:1234/subSchemas.json#/a/b\"}}");
+}
+
+// $ref is cyclical
+TEST(SchemaValidator, Schema_RefCyclical) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ Document sd;
+ sd.Parse("{\"type\": \"object\", \"properties\": {"
+ " \"cyclic_source\": {"
+ " \"$ref\": \"#/properties/cyclic_target\""
+ " },"
+ " \"cyclic_target\": {"
+ " \"$ref\": \"#/properties/cyclic_source\""
+ " }"
+ "}}");
+ SchemaDocumentType s(sd);
+ SCHEMAERROR(s, "{\"RefCyclical\":{\"errorCode\":6,\"instanceRef\":\"#/properties/cyclic_target\",\"value\":\"#/properties/cyclic_source\"}}");
+}
+
+TEST(SchemaValidator, Schema_ReadOnlyAndWriteOnly) {
+ Document sd;
+ sd.Parse("{\"type\": \"integer\", \"readOnly\": true, \"writeOnly\": true}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s1(sd, 0, 0, 0, 0, 0, Specification(kDraft04));
+ EXPECT_TRUE(s1.GetError().ObjectEmpty());
+ SchemaDocument s2(sd, 0, 0, 0, 0, 0, Specification(kVersion30));
+ SCHEMAERROR(s2, "{\"ReadOnlyAndWriteOnly\":{\"errorCode\":13,\"instanceRef\":\"#\"}}");
+}
+
+TEST(SchemaValidator, ReadOnlyWhenWriting) {
+ Document sd;
+ sd.Parse(
+ "{"
+ " \"type\":\"object\","
+ " \"properties\": {"
+ " \"rprop\" : {"
+ " \"type\": \"string\","
+ " \"readOnly\": true"
+ " }"
+ " }"
+ "}");
+ SchemaDocument s(sd, 0, 0, 0, 0, 0, Specification(kVersion20));
+ VALIDATE(s, "{ \"rprop\": \"hello\" }", true);
+ INVALIDATE_(s, "{ \"rprop\": \"hello\" }", "/properties/rprop", "readOnly", "/rprop",
+ "{ \"readOnly\": {"
+ " \"errorCode\": 26, \"instanceRef\": \"#/rprop\", \"schemaRef\": \"#/properties/rprop\""
+ " }"
+ "}",
+ kValidateDefaultFlags | kValidateWriteFlag, SchemaValidator, Pointer);
+}
+
+TEST(SchemaValidator, WriteOnlyWhenReading) {
+ Document sd;
+ sd.Parse(
+ "{"
+ " \"type\":\"object\","
+ " \"properties\": {"
+ " \"wprop\" : {"
+ " \"type\": \"boolean\","
+ " \"writeOnly\": true"
+ " }"
+ " }"
+ "}");
+ SchemaDocument s(sd, 0, 0, 0, 0, 0, Specification(kVersion30));
+ VALIDATE(s, "{ \"wprop\": true }", true);
+ INVALIDATE_(s, "{ \"wprop\": true }", "/properties/wprop", "writeOnly", "/wprop",
+ "{ \"writeOnly\": {"
+ " \"errorCode\": 27, \"instanceRef\": \"#/wprop\", \"schemaRef\": \"#/properties/wprop\""
+ " }"
+ "}",
+ kValidateDefaultFlags | kValidateReadFlag, SchemaValidator, Pointer);
+}
+
+TEST(SchemaValidator, NullableTrue) {
+ Document sd;
+ sd.Parse("{\"type\": \"string\", \"nullable\": true}");
+ SchemaDocument s(sd, 0, 0, 0, 0, 0, kVersion20);
+
+ VALIDATE(s, "\"hello\"", true);
+ INVALIDATE(s, "null", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"string\"], \"actual\": \"null\""
+ "}}");
+ INVALIDATE(s, "false", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"string\"], \"actual\": \"boolean\""
+ "}}");
+
+ SchemaDocument s30(sd, 0, 0, 0, 0, 0, kVersion30);
+
+ VALIDATE(s30, "\"hello\"", true);
+ VALIDATE(s30, "null", true);
+ INVALIDATE(s30, "false", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"null\", \"string\"], \"actual\": \"boolean\""
+ "}}");
+}
+
+TEST(SchemaValidator, NullableFalse) {
+ Document sd;
+ sd.Parse("{\"type\": \"string\", \"nullable\": false}");
+ SchemaDocument s(sd, 0, 0, 0, 0, 0, kVersion20);
+
+ VALIDATE(s, "\"hello\"", true);
+ INVALIDATE(s, "null", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"string\"], \"actual\": \"null\""
+ "}}");
+ INVALIDATE(s, "false", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"string\"], \"actual\": \"boolean\""
+ "}}");
+
+ SchemaDocument s30(sd, 0, 0, 0, 0, 0, kVersion30);
+
+ VALIDATE(s30, "\"hello\"", true);
+ INVALIDATE(s, "null", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"string\"], \"actual\": \"null\""
+ "}}");
+ INVALIDATE(s30, "false", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"string\"], \"actual\": \"boolean\""
+ "}}");
+}
+
+#if defined(_MSC_VER) || defined(__clang__)
RAPIDJSON_DIAG_POP
#endif