Add 64-bit integer schema validations

This commit is contained in:
miloyip 2015-05-13 09:44:25 +08:00
parent 1a59ab50dc
commit 979088de60
2 changed files with 158 additions and 50 deletions

View File

@ -298,10 +298,6 @@ public:
pattern_(), pattern_(),
minLength_(0), minLength_(0),
maxLength_(~SizeType(0)), maxLength_(~SizeType(0)),
minimum_(-HUGE_VAL),
maximum_(HUGE_VAL),
multipleOf_(0),
hasMultipleOf_(false),
exclusiveMinimum_(false), exclusiveMinimum_(false),
exclusiveMaximum_(false) exclusiveMaximum_(false)
{ {
@ -478,26 +474,20 @@ public:
pattern_ = CreatePattern(*v); pattern_ = CreatePattern(*v);
// Number // Number
ConstMemberIterator minimumItr = value.FindMember("minimum"); if (const ValueType* v = GetMember(value, "minimum"))
if (minimumItr != value.MemberEnd()) if (v->IsNumber())
if (minimumItr->value.IsNumber()) minimum_.CopyFrom(*v, *allocator_);
minimum_ = minimumItr->value.GetDouble();
ConstMemberIterator maximumItr = value.FindMember("maximum"); if (const ValueType* v = GetMember(value, "maximum"))
if (maximumItr != value.MemberEnd()) if (v->IsNumber())
if (maximumItr->value.IsNumber()) maximum_.CopyFrom(*v, *allocator_);
maximum_ = maximumItr->value.GetDouble();
AssignIfExist(exclusiveMinimum_, value, "exclusiveMinimum"); AssignIfExist(exclusiveMinimum_, value, "exclusiveMinimum");
AssignIfExist(exclusiveMaximum_, value, "exclusiveMaximum"); AssignIfExist(exclusiveMaximum_, value, "exclusiveMaximum");
ConstMemberIterator multipleOfItr = value.FindMember("multipleOf"); if (const ValueType* v = GetMember(value, "multipleOf"))
if (multipleOfItr != value.MemberEnd()) { if (v->IsNumber() && v->GetDouble() > 0.0)
if (multipleOfItr->value.IsNumber()) { multipleOf_.CopyFrom(*v, *allocator_);
multipleOf_ = multipleOfItr->value.GetDouble();
hasMultipleOf_ = true;
}
}
} }
~Schema() { ~Schema() {
@ -629,33 +619,43 @@ public:
} }
bool Int(Context& context, int i) const { bool Int(Context& context, int i) const {
if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) if (!CheckInt(context, i))
RAPIDJSON_INVALID_KEYWORD_RETURN("type"); return false;
return CheckDouble(context, i) && CreateParallelValidator(context); return CreateParallelValidator(context);
} }
bool Uint(Context& context, unsigned u) const { bool Uint(Context& context, unsigned u) const {
if ((type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) if (!CheckUint(context, u))
RAPIDJSON_INVALID_KEYWORD_RETURN("type"); return false;
return CheckDouble(context, u) && CreateParallelValidator(context); return CreateParallelValidator(context);
} }
bool Int64(Context& context, int64_t i) const { bool Int64(Context& context, int64_t i) const {
if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) if (!CheckInt(context, i))
RAPIDJSON_INVALID_KEYWORD_RETURN("type"); return false;
return CheckDouble(context, i) && CreateParallelValidator(context); return CreateParallelValidator(context);
} }
bool Uint64(Context& context, uint64_t u) const { bool Uint64(Context& context, uint64_t u) const {
if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) if (!CheckUint(context, u))
RAPIDJSON_INVALID_KEYWORD_RETURN("type"); return false;
return CheckDouble(context, u) && CreateParallelValidator(context); return CreateParallelValidator(context);
} }
bool Double(Context& context, double d) const { bool Double(Context& context, double d) const {
if (!(type_ & (1 << kNumberSchemaType))) if (!(type_ & (1 << kNumberSchemaType)))
RAPIDJSON_INVALID_KEYWORD_RETURN("type"); RAPIDJSON_INVALID_KEYWORD_RETURN("type");
return CheckDouble(context, d) && CreateParallelValidator(context);
if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d))
return false;
if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d))
return false;
if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d))
return false;
return CreateParallelValidator(context);
} }
bool String(Context& context, const Ch* str, SizeType length, bool) const { bool String(Context& context, const Ch* str, SizeType length, bool) const {
@ -963,20 +963,92 @@ private:
return false; return false;
} }
bool CheckDouble(Context& context, double d) const { bool CheckInt(Context& context, int64_t i) const {
if (exclusiveMinimum_ ? d <= minimum_ : d < minimum_) if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))
RAPIDJSON_INVALID_KEYWORD_RETURN("minimum"); RAPIDJSON_INVALID_KEYWORD_RETURN("type");
if (exclusiveMaximum_ ? d >= maximum_ : d > maximum_)
RAPIDJSON_INVALID_KEYWORD_RETURN("maximum");
if (hasMultipleOf_) { if (!minimum_.IsNull()) {
double a = std::abs(d), b = std::abs(multipleOf_); if (minimum_.IsInt64()) {
double q = std::floor(a / b); if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64())
double r = a - q * b; RAPIDJSON_INVALID_KEYWORD_RETURN("minimum");
if (r > 0.0) }
RAPIDJSON_INVALID_KEYWORD_RETURN("multipleOf"); else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
return false;
} }
if (!maximum_.IsNull()) {
if (maximum_.IsInt64()) {
if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64())
RAPIDJSON_INVALID_KEYWORD_RETURN("maximum");
}
else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
return false;
}
if (!multipleOf_.IsNull()) {
if (multipleOf_.IsUint64()) {
if (static_cast<uint64_t>(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0)
RAPIDJSON_INVALID_KEYWORD_RETURN("multipleOf");
}
else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
return false;
}
return true;
}
bool CheckUint(Context& context, uint64_t i) const {
if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))
RAPIDJSON_INVALID_KEYWORD_RETURN("type");
if (!minimum_.IsNull()) {
if (minimum_.IsUint64()) {
if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64())
RAPIDJSON_INVALID_KEYWORD_RETURN("minimum");
}
else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
return false;
}
if (!maximum_.IsNull()) {
if (maximum_.IsUint64()) {
if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64())
RAPIDJSON_INVALID_KEYWORD_RETURN("maximum");
}
else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
return false;
}
if (!multipleOf_.IsNull()) {
if (multipleOf_.IsUint64()) {
if (i % multipleOf_.GetUint64() != 0)
RAPIDJSON_INVALID_KEYWORD_RETURN("multipleOf");
}
else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
return false;
}
return true;
}
bool CheckDoubleMinimum(Context& context, double d) const {
if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble())
RAPIDJSON_INVALID_KEYWORD_RETURN("minimum");
return true;
}
bool CheckDoubleMaximum(Context& context, double d) const {
if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble())
RAPIDJSON_INVALID_KEYWORD_RETURN("maximum");
return true;
}
bool CheckDoubleMultipleOf(Context& context, double d) const {
double a = std::abs(d), b = std::abs(multipleOf_.GetDouble());
double q = std::floor(a / b);
double r = a - q * b;
if (r > 0.0)
RAPIDJSON_INVALID_KEYWORD_RETURN("multipleOf");
return true; return true;
} }
@ -1038,9 +1110,9 @@ private:
SizeType minLength_; SizeType minLength_;
SizeType maxLength_; SizeType maxLength_;
double minimum_; SValue minimum_;
double maximum_; SValue maximum_;
double multipleOf_; SValue multipleOf_;
bool hasMultipleOf_; bool hasMultipleOf_;
bool exclusiveMinimum_; bool exclusiveMinimum_;
bool exclusiveMaximum_; bool exclusiveMaximum_;

View File

@ -125,6 +125,7 @@ TEST(SchemaValidator, Hasher) {
printf("GetInvalidSchemaPointer() Expected: %s Actual: %s\n", invalidSchemaPointer, sb.GetString());\ printf("GetInvalidSchemaPointer() Expected: %s Actual: %s\n", invalidSchemaPointer, sb.GetString());\
ADD_FAILURE();\ ADD_FAILURE();\
}\ }\
ASSERT_TRUE(validator.GetInvalidSchemaKeyword() != 0);\
if (strcmp(validator.GetInvalidSchemaKeyword(), invalidSchemaKeyword) != 0) {\ if (strcmp(validator.GetInvalidSchemaKeyword(), invalidSchemaKeyword) != 0) {\
printf("GetInvalidSchemaKeyword() Expected: %s Actual %s\n", invalidSchemaKeyword, validator.GetInvalidSchemaKeyword());\ printf("GetInvalidSchemaKeyword() Expected: %s Actual %s\n", invalidSchemaKeyword, validator.GetInvalidSchemaKeyword());\
ADD_FAILURE();\ ADD_FAILURE();\
@ -358,15 +359,49 @@ TEST(SchemaValidator, Integer_Range) {
INVALIDATE(s, "101", "", "maximum", ""); INVALIDATE(s, "101", "", "maximum", "");
} }
TEST(SchemaValidator, Integer_Range64Boundary) {
Document sd;
sd.Parse("{\"type\":\"integer\",\"minimum\":-9223372036854775807,\"maximum\":18446744073709551614}");
SchemaDocument s(sd);
INVALIDATE(s, "-9223372036854775808", "", "minimum", "");
VALIDATE(s, "-9223372036854775807", true);
VALIDATE(s, "18446744073709551614", true);
INVALIDATE(s, "18446744073709551615", "", "maximum", "");
}
TEST(SchemaValidator, Integer_Range64BoundaryExclusive) {
Document sd;
sd.Parse("{\"type\":\"integer\",\"minimum\":-9223372036854775808,\"maximum\":18446744073709551615,\"exclusiveMinimum\":true,\"exclusiveMaximum\":true}");
SchemaDocument s(sd);
INVALIDATE(s, "-9223372036854775808", "", "minimum", "");
VALIDATE(s, "-9223372036854775807", true);
VALIDATE(s, "18446744073709551614", true);
INVALIDATE(s, "18446744073709551615", "", "maximum", "");
}
TEST(SchemaValidator, Integer_MultipleOf) { TEST(SchemaValidator, Integer_MultipleOf) {
Document sd; Document sd;
sd.Parse("{\"type\":\"integer\",\"multipleOf\":10}"); sd.Parse("{\"type\":\"integer\",\"multipleOf\":10}");
SchemaDocument s(sd); SchemaDocument s(sd);
VALIDATE(s, "0", true); // VALIDATE(s, "0", true);
VALIDATE(s, "10", true); // VALIDATE(s, "10", true);
VALIDATE(s, "-10", true);
VALIDATE(s, "20", true); VALIDATE(s, "20", true);
INVALIDATE(s, "23", "", "multipleOf", ""); INVALIDATE(s, "23", "", "multipleOf", "");
INVALIDATE(s, "-23", "", "multipleOf", "");
}
TEST(SchemaValidator, Integer_MultipleOf64Boundary) {
Document sd;
sd.Parse("{\"type\":\"integer\",\"multipleOf\":18446744073709551615}");
SchemaDocument s(sd);
VALIDATE(s, "0", true);
VALIDATE(s, "18446744073709551615", true);
INVALIDATE(s, "18446744073709551614", "", "multipleOf", "");
} }
TEST(SchemaValidator, Number_Range) { TEST(SchemaValidator, Number_Range) {
@ -384,11 +419,12 @@ TEST(SchemaValidator, Number_Range) {
TEST(SchemaValidator, Number_MultipleOf) { TEST(SchemaValidator, Number_MultipleOf) {
Document sd; Document sd;
sd.Parse("{\"type\":\"number\",\"multipleOf\":10}"); sd.Parse("{\"type\":\"number\",\"multipleOf\":10.0}");
SchemaDocument s(sd); SchemaDocument s(sd);
VALIDATE(s, "0", true); VALIDATE(s, "0", true);
VALIDATE(s, "10", true); VALIDATE(s, "10", true);
VALIDATE(s, "-10", true);
VALIDATE(s, "20", true); VALIDATE(s, "20", true);
INVALIDATE(s, "23", "", "multipleOf", ""); INVALIDATE(s, "23", "", "multipleOf", "");
} }