json/tree: fix signed min, unsigned max constraints
signed/unsigned casting issues prevented correct comparisons with the min/max constraints. account for the source type's range before doing the comparison.
This commit is contained in:
parent
94e60d8cd2
commit
d9713fe8b7
@ -32,6 +32,7 @@ struct length_error : public json::schema_error {
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
struct format_error : public json::schema_error {
|
||||
using schema_error::schema_error;
|
||||
};
|
||||
@ -233,15 +234,47 @@ validate_number (T val, const json::tree::object &schema) {
|
||||
|
||||
if (exclusiveMax != schema.end () && exclusiveMax->second->as_boolean ()) {
|
||||
switch (cmp.repr ()) {
|
||||
case R::REAL: if (val >= T(cmp.real ())) throw json::schema_error ("exclusiveMax"); break;
|
||||
case R::SINT: if (val >= T(cmp.uint ())) throw json::schema_error ("exclusiveMax"); break;
|
||||
case R::UINT: if (val >= T(cmp.sint ())) throw json::schema_error ("exclusiveMax"); break;
|
||||
case R::REAL:
|
||||
if (T(val) >= cmp.real ())
|
||||
throw json::schema_error ("exclusiveMax");
|
||||
break;
|
||||
|
||||
case R::SINT:
|
||||
if (json::tree::number::sint_t(std::numeric_limits<T>::max ()) >= cmp.sint () &&
|
||||
val >= T(cmp.sint ()))
|
||||
{
|
||||
throw json::schema_error ("exclusiveMax");
|
||||
}
|
||||
break;
|
||||
|
||||
case R::UINT:
|
||||
if (json::tree::number::uint_t(std::numeric_limits<T>::max ()) >= cmp.uint () &&
|
||||
val >= T(cmp.uint ()))
|
||||
{
|
||||
throw json::schema_error ("exclusiveMax");
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (cmp.repr ()) {
|
||||
case R::REAL: if (val > T(cmp.real ())) throw json::schema_error ("maximum"); break;
|
||||
case R::SINT: if (val > T(cmp.sint ())) throw json::schema_error ("maximum"); break;
|
||||
case R::UINT: if (val > T(cmp.uint ())) throw json::schema_error ("maximum"); break;
|
||||
case R::REAL:
|
||||
if (T(val) > cmp.real ())
|
||||
throw json::schema_error ("maximum");
|
||||
break;
|
||||
case R::SINT:
|
||||
if (json::tree::number::sint_t(std::numeric_limits<T>::max ()) >= cmp.sint () &&
|
||||
val >= T(cmp.sint ()))
|
||||
{
|
||||
throw json::schema_error ("maximum");
|
||||
}
|
||||
break;
|
||||
case R::UINT:
|
||||
if (json::tree::number::uint_t(std::numeric_limits<T>::max ()) >= cmp.uint () &&
|
||||
val >= T(cmp.uint ()))
|
||||
{
|
||||
throw json::schema_error ("maximum");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -257,15 +290,47 @@ validate_number (T val, const json::tree::object &schema) {
|
||||
|
||||
if (exclusiveMin != schema.end () && exclusiveMin->second->as_boolean ()) {
|
||||
switch (cmp.repr ()) {
|
||||
case R::REAL: if (val <= T(cmp.real ())) throw json::schema_error ("exclusiveMin"); break;
|
||||
case R::SINT: if (val <= T(cmp.sint ())) throw json::schema_error ("exclusiveMin"); break;
|
||||
case R::UINT: if (val <= T(cmp.uint ())) throw json::schema_error ("exclusiveMin"); break;
|
||||
case R::REAL:
|
||||
if (T(val) < cmp.real ())
|
||||
throw json::schema_error ("exclusiveMin");
|
||||
break;
|
||||
case R::SINT:
|
||||
if (cmp.sint () > json::tree::number::sint_t(std::numeric_limits<T>::min ()) &&
|
||||
val < T(cmp.sint ()))
|
||||
{
|
||||
throw json::schema_error ("exclusiveMin");
|
||||
}
|
||||
break;
|
||||
case R::UINT:
|
||||
if (cmp.uint () > json::tree::number::uint_t(std::numeric_limits<T>::min ()) &&
|
||||
val < T(cmp.uint ()))
|
||||
{
|
||||
throw json::schema_error ("exclusiveMin");
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (cmp.repr ()) {
|
||||
case R::REAL: if (val < T(cmp.real ())) throw json::schema_error ("minimum"); break;
|
||||
case R::SINT: if (val < T(cmp.sint ())) throw json::schema_error ("minimum"); break;
|
||||
case R::UINT: if (val < T(cmp.uint ())) throw json::schema_error ("minimum"); break;
|
||||
case R::REAL:
|
||||
if (T(val) <= cmp.real ())
|
||||
throw json::schema_error ("minimum");
|
||||
break;
|
||||
|
||||
case R::SINT:
|
||||
if (cmp.sint () >= json::tree::number::sint_t(std::numeric_limits<T>::min ()) &&
|
||||
val <= T(cmp.sint ()))
|
||||
{
|
||||
throw json::schema_error ("minimum");
|
||||
}
|
||||
break;
|
||||
|
||||
case R::UINT:
|
||||
if (cmp.uint () >= json::tree::number::uint_t(std::numeric_limits<T>::min ()) &&
|
||||
val <= T(cmp.uint ()))
|
||||
{
|
||||
throw json::schema_error ("minimum");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -869,14 +869,26 @@ json::tree::number::operator ==(const json::tree::number &rhs) const {
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
json::tree::number::real_t
|
||||
json::tree::number::real (void) const
|
||||
{
|
||||
if (m_repr != REAL)
|
||||
throw json::type_error ("number is not a real");
|
||||
|
||||
switch (repr ()) {
|
||||
case REAL:
|
||||
return m_value.r;
|
||||
|
||||
case UINT:
|
||||
if (uint_t (real_t (m_value.u)) != m_value.u)
|
||||
throw type_error ("number is not a real");
|
||||
return m_value.u;
|
||||
|
||||
case SINT:
|
||||
if (sint_t (real_t (m_value.s)) != m_value.s)
|
||||
throw type_error ("number is not a real");
|
||||
return m_value.s;
|
||||
}
|
||||
|
||||
unreachable ();
|
||||
}
|
||||
|
||||
|
||||
@ -884,10 +896,22 @@ json::tree::number::real (void) const
|
||||
json::tree::number::sint_t
|
||||
json::tree::number::sint (void) const
|
||||
{
|
||||
if (m_repr != SINT)
|
||||
throw json::type_error ("number is not a sint");
|
||||
|
||||
switch (repr ()) {
|
||||
case SINT:
|
||||
return m_value.s;
|
||||
|
||||
case REAL:
|
||||
if (!::util::exactly_equal (real_t (sint_t (m_value.r)), m_value.r))
|
||||
throw type_error ("number is not a sint");
|
||||
return sint_t (m_value.r);
|
||||
|
||||
case UINT:
|
||||
if (uint_t (sint_t (m_value.u)) != m_value.u)
|
||||
throw type_error ("number is not a sint");
|
||||
return m_value.s;
|
||||
}
|
||||
|
||||
unreachable ();
|
||||
}
|
||||
|
||||
|
||||
@ -895,14 +919,26 @@ json::tree::number::sint (void) const
|
||||
json::tree::number::uint_t
|
||||
json::tree::number::uint (void) const
|
||||
{
|
||||
if (m_repr != UINT)
|
||||
throw json::type_error ("number is not a uint");
|
||||
|
||||
switch (repr ()) {
|
||||
case UINT:
|
||||
return m_value.u;
|
||||
|
||||
case REAL:
|
||||
if (!::util::exactly_equal (real_t (uint_t (m_value.r)), m_value.r))
|
||||
throw type_error ("number is not a uint");
|
||||
return uint_t (m_value.r);
|
||||
|
||||
case SINT:
|
||||
if (sint_t (uint_t (m_value.s)) != m_value.s)
|
||||
throw type_error ("number is not a uint");
|
||||
return m_value.s;
|
||||
}
|
||||
|
||||
unreachable ();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
json::tree::number::operator json::tree::number::real_t (void) const
|
||||
{
|
||||
return real ();
|
||||
|
1
test/json/schema/signed_min.schema
Normal file
1
test/json/schema/signed_min.schema
Normal file
@ -0,0 +1 @@
|
||||
{ "type": "number", "minimum": -1 }
|
1
test/json/schema/signed_min_0001_pass.json
Normal file
1
test/json/schema/signed_min_0001_pass.json
Normal file
@ -0,0 +1 @@
|
||||
0
|
1
test/json/schema/signed_min_0002_fail.json
Normal file
1
test/json/schema/signed_min_0002_fail.json
Normal file
@ -0,0 +1 @@
|
||||
-1
|
1
test/json/schema/unsigned_max.schema
Normal file
1
test/json/schema/unsigned_max.schema
Normal file
@ -0,0 +1 @@
|
||||
{ "type": "number", "maximum": 1 }
|
1
test/json/schema/unsigned_max_0001_pass.json
Normal file
1
test/json/schema/unsigned_max_0001_pass.json
Normal file
@ -0,0 +1 @@
|
||||
-1
|
1
test/json/schema/unsigned_max_0002_fail.json
Normal file
1
test/json/schema/unsigned_max_0002_fail.json
Normal file
@ -0,0 +1 @@
|
||||
1
|
Loading…
Reference in New Issue
Block a user