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 {
|
struct format_error : public json::schema_error {
|
||||||
using schema_error::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 ()) {
|
if (exclusiveMax != schema.end () && exclusiveMax->second->as_boolean ()) {
|
||||||
switch (cmp.repr ()) {
|
switch (cmp.repr ()) {
|
||||||
case R::REAL: if (val >= T(cmp.real ())) throw json::schema_error ("exclusiveMax"); break;
|
case R::REAL:
|
||||||
case R::SINT: if (val >= T(cmp.uint ())) throw json::schema_error ("exclusiveMax"); break;
|
if (T(val) >= cmp.real ())
|
||||||
case R::UINT: if (val >= T(cmp.sint ())) throw json::schema_error ("exclusiveMax"); break;
|
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 {
|
} else {
|
||||||
switch (cmp.repr ()) {
|
switch (cmp.repr ()) {
|
||||||
case R::REAL: if (val > T(cmp.real ())) throw json::schema_error ("maximum"); break;
|
case R::REAL:
|
||||||
case R::SINT: if (val > T(cmp.sint ())) throw json::schema_error ("maximum"); break;
|
if (T(val) > cmp.real ())
|
||||||
case R::UINT: if (val > T(cmp.uint ())) throw json::schema_error ("maximum"); break;
|
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 {
|
} else {
|
||||||
@ -257,15 +290,47 @@ validate_number (T val, const json::tree::object &schema) {
|
|||||||
|
|
||||||
if (exclusiveMin != schema.end () && exclusiveMin->second->as_boolean ()) {
|
if (exclusiveMin != schema.end () && exclusiveMin->second->as_boolean ()) {
|
||||||
switch (cmp.repr ()) {
|
switch (cmp.repr ()) {
|
||||||
case R::REAL: if (val <= T(cmp.real ())) throw json::schema_error ("exclusiveMin"); break;
|
case R::REAL:
|
||||||
case R::SINT: if (val <= T(cmp.sint ())) throw json::schema_error ("exclusiveMin"); break;
|
if (T(val) < cmp.real ())
|
||||||
case R::UINT: if (val <= T(cmp.uint ())) throw json::schema_error ("exclusiveMin"); break;
|
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 {
|
} else {
|
||||||
switch (cmp.repr ()) {
|
switch (cmp.repr ()) {
|
||||||
case R::REAL: if (val < T(cmp.real ())) throw json::schema_error ("minimum"); break;
|
case R::REAL:
|
||||||
case R::SINT: if (val < T(cmp.sint ())) throw json::schema_error ("minimum"); break;
|
if (T(val) <= cmp.real ())
|
||||||
case R::UINT: if (val < T(cmp.uint ())) throw json::schema_error ("minimum"); break;
|
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 {
|
} else {
|
||||||
|
@ -869,14 +869,26 @@ json::tree::number::operator ==(const json::tree::number &rhs) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
json::tree::number::real_t
|
json::tree::number::real_t
|
||||||
json::tree::number::real (void) const
|
json::tree::number::real (void) const
|
||||||
{
|
{
|
||||||
if (m_repr != REAL)
|
switch (repr ()) {
|
||||||
throw json::type_error ("number is not a real");
|
case REAL:
|
||||||
|
return m_value.r;
|
||||||
|
|
||||||
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_t
|
||||||
json::tree::number::sint (void) const
|
json::tree::number::sint (void) const
|
||||||
{
|
{
|
||||||
if (m_repr != SINT)
|
switch (repr ()) {
|
||||||
throw json::type_error ("number is not a sint");
|
case SINT:
|
||||||
|
return m_value.s;
|
||||||
|
|
||||||
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_t
|
||||||
json::tree::number::uint (void) const
|
json::tree::number::uint (void) const
|
||||||
{
|
{
|
||||||
if (m_repr != UINT)
|
switch (repr ()) {
|
||||||
throw json::type_error ("number is not a uint");
|
case UINT:
|
||||||
|
return m_value.u;
|
||||||
|
|
||||||
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
|
json::tree::number::operator json::tree::number::real_t (void) const
|
||||||
{
|
{
|
||||||
return real ();
|
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