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:
Danny Robson 2016-09-20 16:02:08 +10:00
parent 94e60d8cd2
commit d9713fe8b7
8 changed files with 130 additions and 23 deletions

View File

@ -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 {

View File

@ -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 ();

View File

@ -0,0 +1 @@
{ "type": "number", "minimum": -1 }

View File

@ -0,0 +1 @@
0

View File

@ -0,0 +1 @@
-1

View File

@ -0,0 +1 @@
{ "type": "number", "maximum": 1 }

View File

@ -0,0 +1 @@
-1

View File

@ -0,0 +1 @@
1