diff --git a/include/rapidjson/schema.h b/include/rapidjson/schema.h index 11f7160..6576c25 100644 --- a/include/rapidjson/schema.h +++ b/include/rapidjson/schema.h @@ -733,6 +733,7 @@ public: } RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const { + // Only check pattern properties if we have validators if (context.patternPropertiesValidatorCount > 0) { bool otherValid = false; SizeType count = context.patternPropertiesValidatorCount; @@ -775,41 +776,44 @@ public: foundEnum:; } - if (allOf_.schemas) - for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++) - if (!context.validators[i]->IsValid()) { - context.error_handler.NotAllOf(&context.validators[allOf_.begin], allOf_.count); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAllOf); - } - - if (anyOf_.schemas) { - for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++) - if (context.validators[i]->IsValid()) - goto foundAny; - context.error_handler.NoneOf(&context.validators[anyOf_.begin], anyOf_.count); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAnyOf); - foundAny:; - } + // Only check allOf etc if we have validators + if (context.validatorCount > 0) { + if (allOf_.schemas) + for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++) + if (!context.validators[i]->IsValid()) { + context.error_handler.NotAllOf(&context.validators[allOf_.begin], allOf_.count); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAllOf); + } - if (oneOf_.schemas) { - bool oneValid = false; - for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++) - if (context.validators[i]->IsValid()) { - if (oneValid) { - context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count, true); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorOneOfMatch); - } else - oneValid = true; - } - if (!oneValid) { - context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count, false); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorOneOf); + if (anyOf_.schemas) { + for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++) + if (context.validators[i]->IsValid()) + goto foundAny; + context.error_handler.NoneOf(&context.validators[anyOf_.begin], anyOf_.count); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAnyOf); + foundAny:; } - } - if (not_ && context.validators[notValidatorIndex_]->IsValid()) { - context.error_handler.Disallowed(); - RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorNot); + if (oneOf_.schemas) { + bool oneValid = false; + for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++) + if (context.validators[i]->IsValid()) { + if (oneValid) { + context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count, true); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorOneOfMatch); + } else + oneValid = true; + } + if (!oneValid) { + context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count, false); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorOneOf); + } + } + + if (not_ && context.validators[notValidatorIndex_]->IsValid()) { + context.error_handler.Disallowed(); + RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorNot); + } } return true; diff --git a/test/unittest/schematest.cpp b/test/unittest/schematest.cpp index ad19cd9..f381b4e 100644 --- a/test/unittest/schematest.cpp +++ b/test/unittest/schematest.cpp @@ -2550,6 +2550,34 @@ TEST(SchemaValidator, ContinueOnErrors_RogueString) { 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_Issue2) { + 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, Schema_UnknownError) { ASSERT_TRUE(SchemaValidator::SchemaType::GetValidateErrorKeyword(kValidateErrors).GetString() == std::string("null")); }