This commit is contained in:
RPGillespie6 2018-04-18 09:51:04 +00:00 committed by GitHub
commit a2e615f8e3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 68 additions and 28 deletions

View File

@ -34,6 +34,12 @@ lives in his namespace.
Schema-reference resolution is not recursivity-proven: If there is a nested
cross-schema reference, it will not stop. (Though I haven't tested it)
Numerical validation uses `int64_t`, `uint64_t` or `double`, depending on if the schema type is "integer" or "number". Bignum (i.e. arbitrary precision and range) is not supported at this time.
Unsigned integer validation will only take place if the following two conditions are true:
- The nlohmann `type()` of the json object under validation is `nlohmann::json::value_t::number_unsigned`
- The schema specifies a numerical minimum greater than or equal to 0
# How to use
The current state of the build-system needs at least version **3.1.1** of NLohmann's

View File

@ -186,64 +186,98 @@ void validate_boolean(const json & /*instance*/, const json &schema, const std::
validate_type(schema, "boolean", name);
}
void validate_numeric(const json &schema, const std::string &name, double value)
template <class T>
bool violates_numeric_maximum(T max, T value, bool exclusive)
{
if (exclusive)
return value > max;
return value >= max;
}
template <class T>
bool violates_numeric_minimum(T min, T value, bool exclusive)
{
if (exclusive)
return value < min;
return value <= min;
}
template <class T>
void validate_numeric(const json &instance, const json &schema, const std::string &name)
{
T value = instance;
// multipleOf - if the rest of the division is 0 -> OK
const auto &multipleOf = schema.find("multipleOf");
if (multipleOf != schema.end()) {
if (multipleOf.value().get<double>() != 0.0) {
T multiple = multipleOf.value();
if (multiple != 0.0) {
double v = value;
v /= multipleOf.value().get<double>();
if (v != (double) (long) v)
throw std::out_of_range(name + " is not a multiple ...");
T v = value / multiple;
if (v != (T) (long) v)
throw std::out_of_range(name + " is not a multiple of " + std::to_string(multiple));
}
}
const auto &maximum = schema.find("maximum");
if (maximum != schema.end()) {
double maxi = maximum.value();
auto ex = std::out_of_range(name + " exceeds maximum of " + std::to_string(maxi));
if (schema.find("exclusiveMaximum") != schema.end()) {
if (value >= maxi)
throw ex;
} else {
if (value > maxi)
throw ex;
}
T maxi = maximum.value();
const auto &excl = schema.find("exclusiveMaximum");
bool exclusive = (excl != schema.end()) ? excl.value().get<bool>() : false;
if (violates_numeric_maximum<T>(maxi, value, exclusive))
throw std::out_of_range(name + " exceeds maximum of " + std::to_string(maxi));
}
const auto &minimum = schema.find("minimum");
if (minimum != schema.end()) {
double mini = minimum.value();
auto ex = std::out_of_range(name + " is below the minimum of " + std::to_string(mini));
if (schema.find("exclusiveMinimum") != schema.end()) {
if (value <= mini)
throw ex;
} else {
if (value < mini)
throw ex;
}
T mini = minimum.value();
const auto &excl = schema.find("exclusiveMinimum");
bool exclusive = (excl != schema.end()) ? excl.value().get<bool>() : false;
if (violates_numeric_minimum<T>(mini, value, exclusive))
throw std::out_of_range(name + " is below minimum of " + std::to_string(mini));
}
}
void validate_integer(const json &instance, const json &schema, const std::string &name)
{
validate_type(schema, "integer", name);
validate_numeric(schema, name, instance.get<double>());
//TODO: Validate schema values are json::value_t::number_integer/unsigned?
validate_numeric<int64_t>(instance, schema, name);
}
bool is_unsigned(const json &schema)
{
const auto &minimum = schema.find("minimum");
// Number is expected to be unsigned if a minimum >= 0 is set
return minimum != schema.end() && minimum.value() >= 0;
}
void validate_unsigned(const json &instance, const json &schema, const std::string &name)
{
validate_type(schema, "integer", name);
validate_numeric(schema, name, instance.get<double>());
//TODO: Validate schema values are json::value_t::unsigned?
//Is there a better way to determine whether an unsigned comparison should take place?
if (is_unsigned(schema))
validate_numeric<uint64_t>(instance, schema, name);
else
validate_numeric<int64_t>(instance, schema, name);
}
void validate_float(const json &instance, const json &schema, const std::string &name)
{
validate_type(schema, "number", name);
validate_numeric(schema, name, instance.get<double>());
//TODO: Validate schema values are json::value_t::number_float?
validate_numeric<double>(instance, schema, name);
}
void validate_null(const json & /*instance*/, const json &schema, const std::string &name)