Merge bffa46cb20 into 7ee17659fe
This commit is contained in:
commit
a2e615f8e3
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user