Commit 15c712dc authored by miloyip's avatar miloyip

Attempt to make correct implementation of logic combiners

parent d6871c3f
...@@ -68,6 +68,7 @@ public: ...@@ -68,6 +68,7 @@ public:
typedef typename Encoding::Ch Ch; typedef typename Encoding::Ch Ch;
virtual ~ISchemaValidator() {}; virtual ~ISchemaValidator() {};
virtual bool IsValid() = 0;
virtual bool Null() = 0; virtual bool Null() = 0;
virtual bool Bool(bool) = 0; virtual bool Bool(bool) = 0;
virtual bool Int(int) = 0; virtual bool Int(int) = 0;
...@@ -190,49 +191,47 @@ public: ...@@ -190,49 +191,47 @@ public:
virtual SchemaType GetSchemaType() const = 0; virtual SchemaType GetSchemaType() const = 0;
virtual bool HandleMultiType(Context&, SchemaType) const { return true; } virtual bool HandleMultiType(Context&, SchemaType) const { return true; }
virtual bool BeginValue(Context&) const { return true; }
virtual bool BeginValue(Context& context) const { return true; }
#define RAPIDJSON_BASESCHEMA_HANDLER_LGOICAL_(context, method_call)\
if (allOf_.schemas) {\ virtual bool EndValue(Context& context) const {
CreateSchemaValidators(context, context.allOfValidators, allOf_);\ if (allOf_.schemas) {
for (SizeType i_ = 0; i_ < allOf_.count; i_++)\ for (SizeType i_ = 0; i_ < allOf_.count; i_++)
if (!context.allOfValidators.validators[i_]->method_call)\ if (!context.allOfValidators.validators[i_]->IsValid())
return false;\ return false;
}\ }
if (anyOf_.schemas) {\ if (anyOf_.schemas) {
CreateSchemaValidators(context, context.anyOfValidators, anyOf_);\ bool anyValid = false;
bool anyValid = false;\ for (SizeType i_ = 0; i_ < anyOf_.count; i_++)
for (SizeType i_ = 0; i_ < anyOf_.count; i_++)\ if (context.anyOfValidators.validators[i_]->IsValid()) {
if (context.anyOfValidators.validators[i_]->method_call)\ anyValid = true;
anyValid = true;\ break;
if (!anyValid)\ }
return false;\ if (!anyValid)
}\ return false;
if (oneOf_.schemas) {\ }
CreateSchemaValidators(context, context.oneOfValidators, oneOf_);\ if (oneOf_.schemas) {
bool oneValid = false;\ CreateSchemaValidators(context, context.oneOfValidators, oneOf_);
for (SizeType i_ = 0; i_ < oneOf_.count; i_++)\ bool oneValid = false;
if (context.oneOfValidators.validators[i_]->method_call) {\ for (SizeType i_ = 0; i_ < oneOf_.count; i_++)
if (oneValid)\ if (context.oneOfValidators.validators[i_]->IsValid()) {
return false;\ if (oneValid)
else\ return false;
oneValid = true;\ else
}\ oneValid = true;
if (!oneValid)\ }
return false;\ if (!oneValid)
}\ return false;
if (not_) {\ }
if (!context.notValidator)\ if (not_) {
context.notValidator = context.schemaValidatorFactory->CreateSchemaValidator(*not_);\ if (context.notValidator->IsValid())
if (context.notValidator->method_call)\ return false;
return false;\ }
}\ return true;
return true }
#define RAPIDJSON_BASESCHEMA_HANDLER_(context, arg, method_call)\ #define RAPIDJSON_BASESCHEMA_HANDLER_(context, arg, method_call)\
if (enum_.IsArray() && !CheckEnum(GenericValue<Encoding> arg .Move()))\ CreateLogicValidators(context); return !enum_.IsArray() || CheckEnum(GenericValue<Encoding> arg .Move())
return false;\
RAPIDJSON_BASESCHEMA_HANDLER_LGOICAL_(context, method_call);
virtual bool Null(Context& context) const { RAPIDJSON_BASESCHEMA_HANDLER_(context, (), Null()); } virtual bool Null(Context& context) const { RAPIDJSON_BASESCHEMA_HANDLER_(context, (), Null()); }
virtual bool Bool(Context& context, bool b) const { RAPIDJSON_BASESCHEMA_HANDLER_(context, (b), Bool(b)); } virtual bool Bool(Context& context, bool b) const { RAPIDJSON_BASESCHEMA_HANDLER_(context, (b), Bool(b)); }
...@@ -242,11 +241,11 @@ public: ...@@ -242,11 +241,11 @@ public:
virtual bool Uint64(Context& context, uint64_t u) const { RAPIDJSON_BASESCHEMA_HANDLER_(context, (u), Int(u)); } virtual bool Uint64(Context& context, uint64_t u) const { RAPIDJSON_BASESCHEMA_HANDLER_(context, (u), Int(u)); }
virtual bool Double(Context& context, double d) const { RAPIDJSON_BASESCHEMA_HANDLER_(context, (d), Double(d)); } virtual bool Double(Context& context, double d) const { RAPIDJSON_BASESCHEMA_HANDLER_(context, (d), Double(d)); }
virtual bool String(Context& context, const Ch* s, SizeType length, bool copy) const { RAPIDJSON_BASESCHEMA_HANDLER_(context, (s, length), String(s, length, copy)); } virtual bool String(Context& context, const Ch* s, SizeType length, bool copy) const { RAPIDJSON_BASESCHEMA_HANDLER_(context, (s, length), String(s, length, copy)); }
virtual bool StartObject(Context& context) const { RAPIDJSON_BASESCHEMA_HANDLER_LGOICAL_(context, StartObject()); } virtual bool StartObject(Context& context) const { CreateLogicValidators(context); return true; }
virtual bool Key(Context& context, const Ch* s, SizeType length, bool copy) const { RAPIDJSON_BASESCHEMA_HANDLER_LGOICAL_(context, Key(s, length, copy)); } virtual bool Key(Context& context, const Ch* s, SizeType length, bool copy) const { return true; }
virtual bool EndObject(Context& context, SizeType memberCount) const { RAPIDJSON_BASESCHEMA_HANDLER_LGOICAL_(context, EndObject(memberCount)); } virtual bool EndObject(Context& context, SizeType memberCount) const { return true; }
virtual bool StartArray(Context& context) const { RAPIDJSON_BASESCHEMA_HANDLER_LGOICAL_(context, StartArray()); } virtual bool StartArray(Context& context) const { CreateLogicValidators(context); return true; }
virtual bool EndArray(Context& context, SizeType elementCount) const { RAPIDJSON_BASESCHEMA_HANDLER_LGOICAL_(context, EndArray(elementCount)); } virtual bool EndArray(Context& context, SizeType elementCount) const { return true; }
#undef RAPIDJSON_BASESCHEMA_HANDLER_LGOICAL_ #undef RAPIDJSON_BASESCHEMA_HANDLER_LGOICAL_
#undef RAPIDJSON_BASESCHEMA_HANDLER_ #undef RAPIDJSON_BASESCHEMA_HANDLER_
...@@ -272,6 +271,14 @@ protected: ...@@ -272,6 +271,14 @@ protected:
return false; return false;
} }
void CreateLogicValidators(Context& context) const {
if (allOf_.schemas) CreateSchemaValidators(context, context.allOfValidators, allOf_);
if (anyOf_.schemas) CreateSchemaValidators(context, context.anyOfValidators, anyOf_);
if (oneOf_.schemas) CreateSchemaValidators(context, context.oneOfValidators, oneOf_);
if (not_ && !context.notValidator)
context.notValidator = context.schemaValidatorFactory->CreateSchemaValidator(*not_);
}
void CreateSchemaValidators(Context& context, SchemaValidatorArray<Encoding>& validators, const BaseSchemaArray<Encoding>& schemas) const { void CreateSchemaValidators(Context& context, SchemaValidatorArray<Encoding>& validators, const BaseSchemaArray<Encoding>& schemas) const {
if (!validators.validators) { if (!validators.validators) {
validators.validators = new ISchemaValidator<Encoding>*[schemas.count]; validators.validators = new ISchemaValidator<Encoding>*[schemas.count];
...@@ -289,6 +296,14 @@ protected: ...@@ -289,6 +296,14 @@ protected:
BaseSchema<Encoding>* not_; BaseSchema<Encoding>* not_;
}; };
template <typename Encoding>
class EmptySchema : public BaseSchema<Encoding> {
public:
virtual ~EmptySchema() {}
virtual SchemaType GetSchemaType() const { return kTypelessSchemaType; }
virtual bool BeginValue(Context& context) const { context.valueSchema = this; return BaseSchema::BeginValue(context); }
};
template <typename Encoding> template <typename Encoding>
class TypelessSchema : public BaseSchema<Encoding> { class TypelessSchema : public BaseSchema<Encoding> {
public: public:
...@@ -300,8 +315,10 @@ public: ...@@ -300,8 +315,10 @@ public:
TypelessSchema(const ValueType& value) : BaseSchema<Encoding>(value) {} TypelessSchema(const ValueType& value) : BaseSchema<Encoding>(value) {}
virtual SchemaType GetSchemaType() const { return kTypelessSchemaType; } virtual SchemaType GetSchemaType() const { return kTypelessSchemaType; }
virtual bool BeginValue(Context& context) const { context.valueSchema = &empty_; return BaseSchema::BeginValue(context); }
virtual bool BeginValue(Context& context) const { context.valueSchema = this; return true; } private:
EmptySchema<Encoding> empty_;
}; };
template <typename Encoding> template <typename Encoding>
...@@ -1257,8 +1274,9 @@ public: ...@@ -1257,8 +1274,9 @@ public:
: :
root_(*schema.root_), root_(*schema.root_),
outputHandler_(nullOutputHandler_), outputHandler_(nullOutputHandler_),
schemaStack_(allocator, schemaStackCapacity) schemaStack_(allocator, schemaStackCapacity),
// ,documentStack_(allocator, documentStackCapacity) // documentStack_(allocator, documentStackCapacity),
valid_(true)
{ {
} }
...@@ -1271,8 +1289,9 @@ public: ...@@ -1271,8 +1289,9 @@ public:
: :
root_(*schema.root_), root_(*schema.root_),
outputHandler_(outputHandler), outputHandler_(outputHandler),
schemaStack_(allocator, schemaStackCapacity) schemaStack_(allocator, schemaStackCapacity),
// , documentStack_(allocator, documentStackCapacity) // documentStack_(allocator, documentStackCapacity),
valid_(true)
{ {
} }
...@@ -1287,19 +1306,81 @@ public: ...@@ -1287,19 +1306,81 @@ public:
}; };
// Implementation of ISchemaValidator<Encoding> // Implementation of ISchemaValidator<Encoding>
virtual bool Null() { return BeginValue(kNullSchemaType) && CurrentSchema().Null (CurrentContext() ) && EndValue() && outputHandler_.Null ( ); } virtual bool IsValid() { return valid_; }
virtual bool Bool(bool b) { return BeginValue(kBooleanSchemaType) && CurrentSchema().Bool (CurrentContext(), b ) && EndValue() && outputHandler_.Bool (b ); }
virtual bool Int(int i) { return BeginValue(kIntegerSchemaType) && CurrentSchema().Int (CurrentContext(), i ) && EndValue() && outputHandler_.Int (i ); } #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(schemaType, method, arg1)\
virtual bool Uint(unsigned u) { return BeginValue(kIntegerSchemaType) && CurrentSchema().Uint (CurrentContext(), u ) && EndValue() && outputHandler_.Uint (u ); } if (!valid_) return false; \
virtual bool Int64(int64_t i64) { return BeginValue(kIntegerSchemaType) && CurrentSchema().Int64 (CurrentContext(), i64) && EndValue() && outputHandler_.Int64 (i64); } if (!BeginValue(schemaType) || !CurrentSchema().method arg1) return valid_ = false;
virtual bool Uint64(uint64_t u64) { return BeginValue(kIntegerSchemaType) && CurrentSchema().Uint64(CurrentContext(), u64) && EndValue() && outputHandler_.Uint64(u64); }
virtual bool Double(double d) { return BeginValue(kNumberSchemaType) && CurrentSchema().Double(CurrentContext(), d ) && EndValue() && outputHandler_.Double( d); } #define RAPIDJSON_SCHEMA_HANDLE_LOGIC_(method, arg2)\
virtual bool String(const Ch* str, SizeType length, bool copy) { return BeginValue(kStringSchemaType) && CurrentSchema().String(CurrentContext(), str, length, copy) && EndValue() && outputHandler_.String(str, length, copy); } for (Context* context = schemaStack_.template Bottom<Context>(); context <= schemaStack_.template Top<Context>(); context++) {\
virtual bool StartObject() { return BeginValue(kObjectSchemaType) && CurrentSchema().StartObject(CurrentContext()) && outputHandler_.StartObject(); } if (context->allOfValidators.validators)\
virtual bool Key(const Ch* str, SizeType len, bool copy) { return CurrentSchema().Key(CurrentContext(), str, len, copy) && outputHandler_.Key(str, len, copy); } for (SizeType i_ = 0; i_ < context->allOfValidators.count; i_++)\
virtual bool EndObject(SizeType memberCount) { return CurrentSchema().EndObject(CurrentContext(), memberCount) && EndValue() && outputHandler_.EndObject(memberCount); } context->allOfValidators.validators[i_]->method arg2;\
virtual bool StartArray() { return BeginValue(kArraySchemaType) && CurrentSchema().StartArray(CurrentContext()) ? outputHandler_.StartArray() : false; } if (context->anyOfValidators.validators)\
virtual bool EndArray(SizeType elementCount) { return CurrentSchema().EndArray(CurrentContext(), elementCount) && EndValue() && outputHandler_.EndArray(elementCount); } for (SizeType i_ = 0; i_ < context->anyOfValidators.count; i_++)\
context->anyOfValidators.validators[i_]->method arg2;\
if (context->oneOfValidators.validators)\
for (SizeType i_ = 0; i_ < context->oneOfValidators.count; i_++)\
context->oneOfValidators.validators[i_]->method arg2;\
if (context->notValidator)\
context->notValidator->method arg2;\
}
#define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\
return valid_ = EndValue() && outputHandler_.method arg2
#define RAPIDJSON_SCHEMA_HANDLE_VALUE_(schemaType, method, arg1, arg2) \
RAPIDJSON_SCHEMA_HANDLE_BEGIN_(schemaType, method, arg1);\
RAPIDJSON_SCHEMA_HANDLE_LOGIC_(method, arg2);\
RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2)
virtual bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(kNullSchemaType, Null, (CurrentContext() ), ( )); }
virtual bool Bool(bool b) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(kBooleanSchemaType, Bool, (CurrentContext(), b), (b)); }
virtual bool Int(int i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(kIntegerSchemaType, Int, (CurrentContext(), i), (i)); }
virtual bool Uint(unsigned u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(kIntegerSchemaType, Uint, (CurrentContext(), u), (u)); }
virtual bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(kIntegerSchemaType, Int64, (CurrentContext(), i), (i)); }
virtual bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(kIntegerSchemaType, Uint64, (CurrentContext(), u), (u)); }
virtual bool Double(double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(kNumberSchemaType, Double, (CurrentContext(), d), (d)); }
virtual bool String(const Ch* str, SizeType length, bool copy)
{ RAPIDJSON_SCHEMA_HANDLE_VALUE_(kStringSchemaType, String, (CurrentContext(), str, length, copy), (str, length, copy)); }
virtual bool StartObject() {
RAPIDJSON_SCHEMA_HANDLE_BEGIN_(kObjectSchemaType, StartObject, (CurrentContext()));
RAPIDJSON_SCHEMA_HANDLE_LOGIC_(StartObject, ());
return valid_ = outputHandler_.StartObject();
}
virtual bool Key(const Ch* str, SizeType len, bool copy) {
if (!valid_) return false;
if (!CurrentSchema().Key(CurrentContext(), str, len, copy)) return valid_ = false;
RAPIDJSON_SCHEMA_HANDLE_LOGIC_(Key, (str, len, copy));
return valid_ = outputHandler_.Key(str, len, copy);
}
virtual bool EndObject(SizeType memberCount) {
if (!valid_) return false;
if (!CurrentSchema().EndObject(CurrentContext(), memberCount)) return valid_ = false;
RAPIDJSON_SCHEMA_HANDLE_LOGIC_(EndObject, (memberCount));
RAPIDJSON_SCHEMA_HANDLE_END_ (EndObject, (memberCount));
}
virtual bool StartArray() {
RAPIDJSON_SCHEMA_HANDLE_BEGIN_(kArraySchemaType, StartArray, (CurrentContext()));
RAPIDJSON_SCHEMA_HANDLE_LOGIC_(StartArray, ());
return valid_ = outputHandler_.StartArray();
}
virtual bool EndArray(SizeType elementCount) {
if (!valid_) return false;
if (!CurrentSchema().EndArray(CurrentContext(), elementCount)) return valid_ = false;
RAPIDJSON_SCHEMA_HANDLE_LOGIC_(EndArray, (elementCount));
RAPIDJSON_SCHEMA_HANDLE_END_ (EndArray, (elementCount));
}
#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_
#undef RAPIDJSON_SCHEMA_HANDLE_LOGIC_
#undef RAPIDJSON_SCHEMA_HANDLE_VALUE_
// Implementation of ISchemaValidatorFactory<Encoding> // Implementation of ISchemaValidatorFactory<Encoding>
virtual ISchemaValidator<Encoding>* CreateSchemaValidator(const BaseSchema<Encoding>& root) { virtual ISchemaValidator<Encoding>* CreateSchemaValidator(const BaseSchema<Encoding>& root) {
...@@ -1318,8 +1399,9 @@ private: ...@@ -1318,8 +1399,9 @@ private:
: :
root_(root), root_(root),
outputHandler_(nullOutputHandler_), outputHandler_(nullOutputHandler_),
schemaStack_(allocator, schemaStackCapacity) schemaStack_(allocator, schemaStackCapacity),
// , documentStack_(allocator, documentStackCapacity) // documentStack_(allocator, documentStackCapacity),
valid_(true)
{ {
} }
...@@ -1344,9 +1426,13 @@ private: ...@@ -1344,9 +1426,13 @@ private:
} }
bool EndValue() { bool EndValue() {
if (!CurrentSchema().EndValue(CurrentContext()))
return false;
PopSchema(); PopSchema();
if (!schemaStack_.Empty() && CurrentContext().multiTypeSchema) if (!schemaStack_.Empty() && CurrentContext().multiTypeSchema)
PopSchema(); PopSchema();
return true; return true;
} }
...@@ -1362,6 +1448,7 @@ private: ...@@ -1362,6 +1448,7 @@ private:
OutputHandler& outputHandler_; OutputHandler& outputHandler_;
internal::Stack<Allocator> schemaStack_; //!< stack to store the current path of schema (BaseSchemaType *) internal::Stack<Allocator> schemaStack_; //!< stack to store the current path of schema (BaseSchemaType *)
//internal::Stack<Allocator> documentStack_; //!< stack to store the current path of validating document (Value *) //internal::Stack<Allocator> documentStack_; //!< stack to store the current path of validating document (Value *)
bool valid_;
}; };
typedef GenericSchemaValidator<UTF8<> > SchemaValidator; typedef GenericSchemaValidator<UTF8<> > SchemaValidator;
......
...@@ -27,10 +27,14 @@ using namespace rapidjson; ...@@ -27,10 +27,14 @@ using namespace rapidjson;
/*printf("\n%s\n", json);*/\ /*printf("\n%s\n", json);*/\
d.Parse(json);\ d.Parse(json);\
EXPECT_FALSE(d.HasParseError());\ EXPECT_FALSE(d.HasParseError());\
if (expected)\ if (expected) {\
EXPECT_TRUE(d.Accept(validator));\ EXPECT_TRUE(d.Accept(validator));\
else\ EXPECT_TRUE(validator.IsValid());\
}\
else {\
EXPECT_FALSE(d.Accept(validator));\ EXPECT_FALSE(d.Accept(validator));\
EXPECT_FALSE(validator.IsValid()); \
}\
} }
TEST(SchemaValidator, Typeless) { TEST(SchemaValidator, Typeless) {
...@@ -88,7 +92,7 @@ TEST(SchemaValidator, AllOf) { ...@@ -88,7 +92,7 @@ TEST(SchemaValidator, AllOf) {
sd.Parse("{\"allOf\": [{ \"type\": \"string\" }, { \"type\": \"string\", \"maxLength\": 5 }]}"); // need "type": "string" now sd.Parse("{\"allOf\": [{ \"type\": \"string\" }, { \"type\": \"string\", \"maxLength\": 5 }]}"); // need "type": "string" now
Schema s(sd); Schema s(sd);
VALIDATE(s, "\"ok\"", true); //VALIDATE(s, "\"ok\"", true);
VALIDATE(s, "\"too long\"", false); VALIDATE(s, "\"too long\"", false);
} }
{ {
...@@ -106,8 +110,8 @@ TEST(SchemaValidator, AnyOf) { ...@@ -106,8 +110,8 @@ TEST(SchemaValidator, AnyOf) {
sd.Parse("{\"anyOf\": [{ \"type\": \"string\" }, { \"type\": \"number\" } ] }"); sd.Parse("{\"anyOf\": [{ \"type\": \"string\" }, { \"type\": \"number\" } ] }");
Schema s(sd); Schema s(sd);
VALIDATE(s, "\"Yes\"", true); //VALIDATE(s, "\"Yes\"", true);
VALIDATE(s, "42", true); //VALIDATE(s, "42", true);
VALIDATE(s, "{ \"Not a\": \"string or number\" }", false); VALIDATE(s, "{ \"Not a\": \"string or number\" }", false);
} }
...@@ -128,7 +132,7 @@ TEST(SchemaValidator, Not) { ...@@ -128,7 +132,7 @@ TEST(SchemaValidator, Not) {
Schema s(sd); Schema s(sd);
VALIDATE(s, "42", true); VALIDATE(s, "42", true);
// VALIDATE(s, "{ \"key\": \"value\" }", true); // TO FIX VALIDATE(s, "{ \"key\": \"value\" }", true); // TO FIX
VALIDATE(s, "\"I am a string\"", false); VALIDATE(s, "\"I am a string\"", false);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment