Description: - Differentiate integer and floating point validation - Correct exclusive minimum/maximum comparison operators
This commit is contained in:
parent
c552c7c02a
commit
bffa46cb20
@ -34,6 +34,12 @@ lives in his namespace.
|
|||||||
Schema-reference resolution is not recursivity-proven: If there is a nested
|
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)
|
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
|
# How to use
|
||||||
|
|
||||||
The current state of the build-system needs at least version **3.1.1** of NLohmann's
|
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);
|
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
|
// multipleOf - if the rest of the division is 0 -> OK
|
||||||
const auto &multipleOf = schema.find("multipleOf");
|
const auto &multipleOf = schema.find("multipleOf");
|
||||||
if (multipleOf != schema.end()) {
|
if (multipleOf != schema.end()) {
|
||||||
if (multipleOf.value().get<double>() != 0.0) {
|
T multiple = multipleOf.value();
|
||||||
|
if (multiple != 0.0) {
|
||||||
|
|
||||||
double v = value;
|
T v = value / multiple;
|
||||||
v /= multipleOf.value().get<double>();
|
if (v != (T) (long) v)
|
||||||
|
throw std::out_of_range(name + " is not a multiple of " + std::to_string(multiple));
|
||||||
if (v != (double) (long) v)
|
|
||||||
throw std::out_of_range(name + " is not a multiple ...");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto &maximum = schema.find("maximum");
|
const auto &maximum = schema.find("maximum");
|
||||||
if (maximum != schema.end()) {
|
if (maximum != schema.end()) {
|
||||||
double maxi = maximum.value();
|
T maxi = maximum.value();
|
||||||
auto ex = std::out_of_range(name + " exceeds maximum of " + std::to_string(maxi));
|
|
||||||
if (schema.find("exclusiveMaximum") != schema.end()) {
|
const auto &excl = schema.find("exclusiveMaximum");
|
||||||
if (value >= maxi)
|
bool exclusive = (excl != schema.end()) ? excl.value().get<bool>() : false;
|
||||||
throw ex;
|
|
||||||
} else {
|
if (violates_numeric_maximum<T>(maxi, value, exclusive))
|
||||||
if (value > maxi)
|
throw std::out_of_range(name + " exceeds maximum of " + std::to_string(maxi));
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto &minimum = schema.find("minimum");
|
const auto &minimum = schema.find("minimum");
|
||||||
if (minimum != schema.end()) {
|
if (minimum != schema.end()) {
|
||||||
double mini = minimum.value();
|
T 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()) {
|
const auto &excl = schema.find("exclusiveMinimum");
|
||||||
if (value <= mini)
|
bool exclusive = (excl != schema.end()) ? excl.value().get<bool>() : false;
|
||||||
throw ex;
|
|
||||||
} else {
|
if (violates_numeric_minimum<T>(mini, value, exclusive))
|
||||||
if (value < mini)
|
throw std::out_of_range(name + " is below minimum of " + std::to_string(mini));
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void validate_integer(const json &instance, const json &schema, const std::string &name)
|
void validate_integer(const json &instance, const json &schema, const std::string &name)
|
||||||
{
|
{
|
||||||
validate_type(schema, "integer", 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)
|
void validate_unsigned(const json &instance, const json &schema, const std::string &name)
|
||||||
{
|
{
|
||||||
validate_type(schema, "integer", 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)
|
void validate_float(const json &instance, const json &schema, const std::string &name)
|
||||||
{
|
{
|
||||||
validate_type(schema, "number", 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)
|
void validate_null(const json & /*instance*/, const json &schema, const std::string &name)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user