From 1b138e8544d87f8bc4b35214be9f2bdcf78d1f36 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Wed, 25 May 2011 04:19:17 +0000 Subject: [PATCH] Gave a more consistent behavior to the Value::isFoo methods. See NEWS.txt for more details. --- NEWS.txt | 20 +++ include/json/value.h | 2 + src/lib_json/json_value.cpp | 200 +++++++++++++++----------- src/test_lib_json/main.cpp | 275 +++++++++++++++++++++++++++++------- 4 files changed, 364 insertions(+), 133 deletions(-) diff --git a/NEWS.txt b/NEWS.txt index e53b880..ac7c856 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -1,3 +1,23 @@ + New in SVN: + ----------- + +* Value + + - Updated the Value::isFoo methods to work as follows: + + * isInt, isInt64, isUInt, and isUInt64 return true if and only if the + value can be exactly representable as that type. In particular, a value + constructed with a double like 17.0 will now return true for all of + these methods. + + * isDouble and isFloat now return true for all numeric values, since all + numeric values can be converted to a double or float without + truncation. Note that the conversion may not be exact -- for example, + doubles cannot exactly represent integers above 2^53. + + * isBool, isNull, isString, isArray, and isObject now return true if and + only if the value is of that type. + New in JsonCpp 0.6.0: --------------------- diff --git a/include/json/value.h b/include/json/value.h index e3869e5..b013c9b 100644 --- a/include/json/value.h +++ b/include/json/value.h @@ -280,7 +280,9 @@ namespace Json { bool isNull() const; bool isBool() const; bool isInt() const; + bool isInt64() const; bool isUInt() const; + bool isUInt64() const; bool isIntegral() const; bool isDouble() const; bool isNumeric() const; diff --git a/src/lib_json/json_value.cpp b/src/lib_json/json_value.cpp index 0819f3e..35ec41d 100644 --- a/src/lib_json/json_value.cpp +++ b/src/lib_json/json_value.cpp @@ -11,6 +11,7 @@ # include "json_batchallocator.h" # endif // #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR #endif // if !defined(JSON_IS_AMALGAMATION) +#include #include #include #include @@ -539,6 +540,7 @@ Value::compare( const Value &other ) const } +// TODO(jacobsa): Check this for correctness given the new type-coallescing API. bool Value::operator <( const Value &other ) const { @@ -601,6 +603,7 @@ Value::operator >( const Value &other ) const return other < *this; } +// TODO(jacobsa): Check this for correctness given the new type-coallescing API. bool Value::operator ==( const Value &other ) const { @@ -694,59 +697,38 @@ Value::asConstString() const Value::Int Value::asInt() const { + JSON_ASSERT_MESSAGE(isInt(), "Value is not convertible to Int"); switch ( type_ ) { - case nullValue: - return 0; case intValue: - JSON_ASSERT_MESSAGE( value_.int_ >= minInt && value_.int_ <= maxInt, "unsigned integer out of signed int range" ); return Int(value_.int_); case uintValue: - JSON_ASSERT_MESSAGE( value_.uint_ <= UInt(maxInt), "unsigned integer out of signed int range" ); return Int(value_.uint_); case realValue: - JSON_ASSERT_MESSAGE( value_.real_ >= minInt && value_.real_ <= maxInt, "Real out of signed integer range" ); return Int( value_.real_ ); - case booleanValue: - return value_.bool_ ? 1 : 0; - case stringValue: - case arrayValue: - case objectValue: - JSON_FAIL_MESSAGE( "Type is not convertible to int" ); default: - JSON_ASSERT_UNREACHABLE; + break; } - return 0; // unreachable; + JSON_ASSERT_UNREACHABLE; + return 0; } Value::UInt Value::asUInt() const { + JSON_ASSERT_MESSAGE(isUInt(), "Value is not convertible to UInt"); switch ( type_ ) { - case nullValue: - return 0; case intValue: - JSON_ASSERT_MESSAGE( value_.int_ >= 0, "Negative integer can not be converted to unsigned integer" ); - JSON_ASSERT_MESSAGE( UInt(value_.int_) <= maxUInt, "signed integer out of UInt range" ); return UInt(value_.int_); case uintValue: - JSON_ASSERT_MESSAGE( value_.uint_ <= maxUInt, "unsigned integer out of UInt range" ); return UInt(value_.uint_); case realValue: - JSON_ASSERT_MESSAGE( value_.real_ >= 0 && value_.real_ <= maxUInt, "Real out of unsigned integer range" ); return UInt( value_.real_ ); - case booleanValue: - return value_.bool_ ? 1 : 0; - case stringValue: - case arrayValue: - case objectValue: - JSON_FAIL_MESSAGE( "Type is not convertible to uint" ); - default: - JSON_ASSERT_UNREACHABLE; } - return 0; // unreachable; + JSON_ASSERT_UNREACHABLE; + return 0; } @@ -755,55 +737,40 @@ Value::asUInt() const Value::Int64 Value::asInt64() const { + JSON_ASSERT_MESSAGE(isInt64(), "Value is not convertible to Int64"); switch ( type_ ) { - case nullValue: - return 0; case intValue: - return value_.int_; + return Int64(value_.int_); case uintValue: - JSON_ASSERT_MESSAGE( value_.uint_ <= UInt64(maxInt64), "unsigned integer out of Int64 range" ); - return value_.uint_; + return Int64(value_.uint_); case realValue: - JSON_ASSERT_MESSAGE( value_.real_ >= minInt64 && value_.real_ <= maxInt64, "Real out of Int64 range" ); return Int64( value_.real_ ); - case booleanValue: - return value_.bool_ ? 1 : 0; - case stringValue: - case arrayValue: - case objectValue: - JSON_FAIL_MESSAGE( "Type is not convertible to Int64" ); default: - JSON_ASSERT_UNREACHABLE; + break; } - return 0; // unreachable; + JSON_ASSERT_UNREACHABLE; + return 0; } Value::UInt64 Value::asUInt64() const { + JSON_ASSERT_MESSAGE(isUInt64(), "Value is not convertible to UInt64"); switch ( type_ ) { - case nullValue: - return 0; case intValue: - JSON_ASSERT_MESSAGE( value_.int_ >= 0, "Negative integer can not be converted to UInt64" ); - return value_.int_; + return UInt64(value_.int_); case uintValue: - return value_.uint_; + return UInt64(value_.uint_); case realValue: - JSON_ASSERT_MESSAGE( value_.real_ >= 0 && value_.real_ <= maxUInt64, "Real out of UInt64 range" ); return UInt64( value_.real_ ); - case booleanValue: - return value_.bool_ ? 1 : 0; - case stringValue: - case arrayValue: - case objectValue: - JSON_FAIL_MESSAGE( "Type is not convertible to UInt64" ); default: - JSON_ASSERT_UNREACHABLE; + break; } + JSON_ASSERT_UNREACHABLE; + return 0; return 0; // unreachable; } # endif // if defined(JSON_HAS_INT64) @@ -836,8 +803,6 @@ Value::asDouble() const { switch ( type_ ) { - case nullValue: - return 0.0; case intValue: return static_cast( value_.int_ ); case uintValue: @@ -848,12 +813,12 @@ Value::asDouble() const #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) case realValue: return value_.real_; + case nullValue: case booleanValue: - return value_.bool_ ? 1.0 : 0.0; case stringValue: case arrayValue: case objectValue: - JSON_FAIL_MESSAGE( "Type is not convertible to double" ); + JSON_FAIL_MESSAGE( "Value is not a double" ); default: JSON_ASSERT_UNREACHABLE; } @@ -865,8 +830,6 @@ Value::asFloat() const { switch ( type_ ) { - case nullValue: - return 0.0f; case intValue: return static_cast( value_.int_ ); case uintValue: @@ -877,12 +840,12 @@ Value::asFloat() const #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) case realValue: return static_cast( value_.real_ ); + case nullValue: case booleanValue: - return value_.bool_ ? 1.0f : 0.0f; case stringValue: case arrayValue: case objectValue: - JSON_FAIL_MESSAGE( "Type is not convertible to float" ); + JSON_FAIL_MESSAGE( "Value is not a float" ); default: JSON_ASSERT_UNREACHABLE; } @@ -894,20 +857,16 @@ Value::asBool() const { switch ( type_ ) { - case nullValue: - return false; - case intValue: - case uintValue: - return value_.int_ != 0; - case realValue: - return value_.real_ != 0.0; case booleanValue: return value_.bool_; + case nullValue: + case intValue: + case uintValue: + case realValue: case stringValue: - return value_.string_ && value_.string_[0] != 0; case arrayValue: case objectValue: - return value_.map_->size() != 0; + JSON_FAIL_MESSAGE( "Value is not a bool" ); default: JSON_ASSERT_UNREACHABLE; } @@ -1366,6 +1325,11 @@ Value::getMemberNames() const // //# endif +static bool IsIntegral(double d) { + double integral_part; + return modf(d, &integral_part) == 0.0; +} + bool Value::isNull() const @@ -1384,30 +1348,106 @@ Value::isBool() const bool Value::isInt() const { - return type_ == intValue; + switch ( type_ ) + { + case intValue: + return value_.int_ >= minInt && value_.int_ <= maxInt; + case uintValue: + return value_.uint_ <= UInt(maxInt); + case realValue: + return value_.real_ >= minInt && + value_.real_ <= maxInt && + IsIntegral(value_.real_); + default: + break; + } + return false; } bool Value::isUInt() const { - return type_ == uintValue; + switch ( type_ ) + { + case intValue: + return value_.int_ >= 0 && value_.int_ <= maxUInt; + case uintValue: + return value_.uint_ <= maxUInt; + case realValue: + return value_.real_ >= 0 && + value_.real_ <= maxUInt && + IsIntegral(value_.real_); + default: + break; + } + return false; +} + +bool +Value::isInt64() const +{ +# if defined(JSON_HAS_INT64) + switch ( type_ ) + { + case intValue: + return true; + case uintValue: + return value_.uint_ <= UInt64(maxInt64); + case realValue: + // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a + // double, so double(maxInt64) will be rounded up to 2^63. Therefore we + // require the value to be strictly less than the limit. + return value_.real_ >= double(minInt64) && + value_.real_ < double(maxInt64) && + IsIntegral(value_.real_); + default: + break; + } +# endif // JSON_HAS_INT64 + return false; +} + +bool +Value::isUInt64() const +{ +# if defined(JSON_HAS_INT64) + switch ( type_ ) + { + case intValue: + return value_.int_ >= 0; + case uintValue: + return true; + case realValue: + // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a + // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we + // require the value to be strictly less than the limit. + return value_.real_ >= 0 && + value_.real_ < double(maxUInt64) && + IsIntegral(value_.real_); + default: + break; + } +# endif // JSON_HAS_INT64 + return false; } bool Value::isIntegral() const { - return type_ == intValue - || type_ == uintValue - || type_ == booleanValue; +#if defined(JSON_HAS_INT64) + return isInt64() || isUInt64(); +#else + return isInt() || isUInt(); +#endif } bool Value::isDouble() const { - return type_ == realValue; + return type_ == realValue || isIntegral(); } @@ -1428,14 +1468,14 @@ Value::isString() const bool Value::isArray() const { - return type_ == nullValue || type_ == arrayValue; + return type_ == arrayValue; } bool Value::isObject() const { - return type_ == nullValue || type_ == objectValue; + return type_ == objectValue; } diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index 07b1495..0684c90 100644 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -74,13 +74,16 @@ struct ValueTest : JsonTest::TestCase bool isObject_; bool isArray_; bool isBool_; - bool isDouble_; - bool isInt_; - bool isUInt_; - bool isIntegral_; - bool isNumeric_; bool isString_; bool isNull_; + + bool isInt_; + bool isInt64_; + bool isUInt_; + bool isUInt64_; + bool isIntegral_; + bool isDouble_; + bool isNumeric_; }; void checkConstMemberCount( const Json::Value &value, unsigned int expectedCount ); @@ -120,6 +123,8 @@ JSONTEST_FIXTURE( ValueTest, objects ) JSONTEST_ASSERT_PRED( checkIs( emptyObject_, checks ) ); JSONTEST_ASSERT_PRED( checkIs( object1_, checks ) ); + JSONTEST_ASSERT_EQUAL( Json::objectValue, emptyObject_.type()); + // Access through const reference const Json::Value &constObject = object1_; @@ -145,6 +150,8 @@ JSONTEST_FIXTURE( ValueTest, arrays ) JSONTEST_ASSERT_PRED( checkIs( emptyArray_, checks ) ); JSONTEST_ASSERT_PRED( checkIs( array1_, checks ) ); + JSONTEST_ASSERT_EQUAL( Json::arrayValue, array1_.type()); + // Access through const reference const Json::Value &constArray = array1_; JSONTEST_ASSERT( Json::Value(1234) == constArray[index0] ); @@ -162,16 +169,18 @@ JSONTEST_FIXTURE( ValueTest, arrays ) JSONTEST_FIXTURE( ValueTest, null ) { + JSONTEST_ASSERT_EQUAL( Json::nullValue, null_.type()); + IsCheck checks; checks.isNull_ = true; - checks.isObject_ = true; - checks.isArray_ = true; JSONTEST_ASSERT_PRED( checkIs( null_, checks ) ); } JSONTEST_FIXTURE( ValueTest, strings ) { + JSONTEST_ASSERT_EQUAL( Json::stringValue, string1_.type()); + IsCheck checks; checks.isString_ = true; JSONTEST_ASSERT_PRED( checkIs( emptyString_, checks ) ); @@ -185,10 +194,10 @@ JSONTEST_FIXTURE( ValueTest, strings ) JSONTEST_FIXTURE( ValueTest, bools ) { + JSONTEST_ASSERT_EQUAL( Json::booleanValue, false_.type()); + IsCheck checks; checks.isBool_ = true; - checks.isIntegral_ = true; - checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( false_, checks ) ); JSONTEST_ASSERT_PRED( checkIs( true_, checks ) ); @@ -209,8 +218,12 @@ JSONTEST_FIXTURE( ValueTest, integers ) checks = IsCheck(); checks.isInt_ = true; - checks.isNumeric_ = true; + checks.isInt64_ = true; + checks.isUInt_ = true; + checks.isUInt64_ = true; checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); JSONTEST_ASSERT( 0 == val.asInt()); @@ -226,9 +239,35 @@ JSONTEST_FIXTURE( ValueTest, integers ) JSONTEST_ASSERT_EQUAL(Json::uintValue, val.type()); checks = IsCheck(); + checks.isInt_ = true; + checks.isInt64_ = true; checks.isUInt_ = true; - checks.isNumeric_ = true; + checks.isUInt64_ = true; checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); + + JSONTEST_ASSERT( 0 == val.asInt()); + JSONTEST_ASSERT( 0 == val.asLargestInt()); + JSONTEST_ASSERT( 0 == val.asUInt()); + JSONTEST_ASSERT( 0 == val.asLargestUInt()); + JSONTEST_ASSERT( 0.0 == val.asDouble()); + JSONTEST_ASSERT( 0.0 == val.asFloat()); + + // Default real + val = Json::Value(Json::realValue); + + JSONTEST_ASSERT_EQUAL(Json::realValue, val.type()); + + checks = IsCheck(); + checks.isInt_ = true; + checks.isInt64_ = true; + checks.isUInt_ = true; + checks.isUInt64_ = true; + checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); JSONTEST_ASSERT( 0 == val.asInt()); @@ -241,10 +280,16 @@ JSONTEST_FIXTURE( ValueTest, integers ) // Zero (signed constructor arg) val = Json::Value(0); + JSONTEST_ASSERT_EQUAL( Json::intValue, val.type()); + checks = IsCheck(); checks.isInt_ = true; - checks.isNumeric_ = true; + checks.isInt64_ = true; + checks.isUInt_ = true; + checks.isUInt64_ = true; checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); JSONTEST_ASSERT( 0 == val.asInt()); @@ -257,10 +302,16 @@ JSONTEST_FIXTURE( ValueTest, integers ) // Zero (unsigned constructor arg) val = Json::Value(0u); + JSONTEST_ASSERT_EQUAL( Json::uintValue, val.type()); + checks = IsCheck(); + checks.isInt_ = true; + checks.isInt64_ = true; checks.isUInt_ = true; - checks.isNumeric_ = true; + checks.isUInt64_ = true; checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); JSONTEST_ASSERT( 0 == val.asInt()); @@ -273,7 +324,14 @@ JSONTEST_FIXTURE( ValueTest, integers ) // Zero (floating-point constructor arg) val = Json::Value(0.0); + JSONTEST_ASSERT_EQUAL( Json::realValue, val.type()); + checks = IsCheck(); + checks.isInt_ = true; + checks.isInt64_ = true; + checks.isUInt_ = true; + checks.isUInt64_ = true; + checks.isIntegral_ = true; checks.isDouble_ = true; checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); @@ -288,10 +346,16 @@ JSONTEST_FIXTURE( ValueTest, integers ) // 2^20 (signed constructor arg) val = Json::Value(1 << 20); + JSONTEST_ASSERT_EQUAL( Json::intValue, val.type()); + checks = IsCheck(); checks.isInt_ = true; - checks.isNumeric_ = true; + checks.isInt64_ = true; + checks.isUInt_ = true; + checks.isUInt64_ = true; checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); JSONTEST_ASSERT( (1 << 20) == val.asInt()); @@ -304,10 +368,16 @@ JSONTEST_FIXTURE( ValueTest, integers ) // 2^20 (unsigned constructor arg) val = Json::Value(1u << 20); + JSONTEST_ASSERT_EQUAL( Json::uintValue, val.type()); + checks = IsCheck(); + checks.isInt_ = true; + checks.isInt64_ = true; checks.isUInt_ = true; - checks.isNumeric_ = true; + checks.isUInt64_ = true; checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); JSONTEST_ASSERT( (1 << 20) == val.asInt()); @@ -320,7 +390,14 @@ JSONTEST_FIXTURE( ValueTest, integers ) // 2^20 (floating-point constructor arg) val = Json::Value((1 << 20) / 1.0); + JSONTEST_ASSERT_EQUAL( Json::realValue, val.type()); + checks = IsCheck(); + checks.isInt_ = true; + checks.isInt64_ = true; + checks.isUInt_ = true; + checks.isUInt64_ = true; + checks.isIntegral_ = true; checks.isDouble_ = true; checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); @@ -335,10 +412,14 @@ JSONTEST_FIXTURE( ValueTest, integers ) // -2^20 val = Json::Value(-(1 << 20)); + JSONTEST_ASSERT_EQUAL( Json::intValue, val.type()); + checks = IsCheck(); checks.isInt_ = true; - checks.isNumeric_ = true; + checks.isInt64_ = true; checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); JSONTEST_ASSERT( -(1 << 20) == val.asInt()); @@ -349,10 +430,16 @@ JSONTEST_FIXTURE( ValueTest, integers ) // int32 max val = Json::Value(kint32max); + JSONTEST_ASSERT_EQUAL( Json::intValue, val.type()); + checks = IsCheck(); checks.isInt_ = true; - checks.isNumeric_ = true; + checks.isInt64_ = true; + checks.isUInt_ = true; + checks.isUInt64_ = true; checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); JSONTEST_ASSERT( kint32max == val.asInt()); @@ -365,10 +452,14 @@ JSONTEST_FIXTURE( ValueTest, integers ) // int32 min val = Json::Value(kint32min); + JSONTEST_ASSERT_EQUAL( Json::intValue, val.type()); + checks = IsCheck(); checks.isInt_ = true; - checks.isNumeric_ = true; + checks.isInt64_ = true; checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); JSONTEST_ASSERT( kint32min == val.asInt()); @@ -379,10 +470,15 @@ JSONTEST_FIXTURE( ValueTest, integers ) // uint32 max val = Json::Value(kuint32max); + JSONTEST_ASSERT_EQUAL( Json::uintValue, val.type()); + checks = IsCheck(); + checks.isInt64_ = true; checks.isUInt_ = true; - checks.isNumeric_ = true; + checks.isUInt64_ = true; checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); #ifndef JSON_NO_INT64 @@ -397,6 +493,8 @@ JSONTEST_FIXTURE( ValueTest, integers ) // int64 max val = Json::Value(double(kint64max)); + JSONTEST_ASSERT_EQUAL( Json::realValue, val.type()); + checks = IsCheck(); checks.isDouble_ = true; checks.isNumeric_ = true; @@ -408,6 +506,8 @@ JSONTEST_FIXTURE( ValueTest, integers ) // int64 min val = Json::Value(double(kint64min)); + JSONTEST_ASSERT_EQUAL( Json::realValue, val.type()); + checks = IsCheck(); checks.isDouble_ = true; checks.isNumeric_ = true; @@ -419,6 +519,8 @@ JSONTEST_FIXTURE( ValueTest, integers ) // uint64 max val = Json::Value(double(kuint64max)); + JSONTEST_ASSERT_EQUAL( Json::realValue, val.type()); + checks = IsCheck(); checks.isDouble_ = true; checks.isNumeric_ = true; @@ -430,10 +532,14 @@ JSONTEST_FIXTURE( ValueTest, integers ) // 2^40 (signed constructor arg) val = Json::Value(1LL << 40); + JSONTEST_ASSERT_EQUAL( Json::intValue, val.type()); + checks = IsCheck(); - checks.isInt_ = true; - checks.isNumeric_ = true; + checks.isInt64_ = true; + checks.isUInt64_ = true; checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); JSONTEST_ASSERT( (1LL << 40) == val.asInt64()); @@ -446,10 +552,14 @@ JSONTEST_FIXTURE( ValueTest, integers ) // 2^40 (unsigned constructor arg) val = Json::Value(1ULL << 40); + JSONTEST_ASSERT_EQUAL( Json::uintValue, val.type()); + checks = IsCheck(); - checks.isUInt_ = true; - checks.isNumeric_ = true; + checks.isInt64_ = true; + checks.isUInt64_ = true; checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); JSONTEST_ASSERT( (1LL << 40) == val.asInt64()); @@ -462,7 +572,12 @@ JSONTEST_FIXTURE( ValueTest, integers ) // 2^40 (floating-point constructor arg) val = Json::Value((1LL << 40) / 1.0); + JSONTEST_ASSERT_EQUAL( Json::realValue, val.type()); + checks = IsCheck(); + checks.isInt64_ = true; + checks.isUInt64_ = true; + checks.isIntegral_ = true; checks.isDouble_ = true; checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); @@ -477,10 +592,13 @@ JSONTEST_FIXTURE( ValueTest, integers ) // -2^40 val = Json::Value(-(1LL << 40)); + JSONTEST_ASSERT_EQUAL( Json::intValue, val.type()); + checks = IsCheck(); - checks.isInt_ = true; - checks.isNumeric_ = true; + checks.isInt64_ = true; checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); JSONTEST_ASSERT( -(1LL << 40) == val.asInt64()); @@ -491,10 +609,14 @@ JSONTEST_FIXTURE( ValueTest, integers ) // int64 max val = Json::Value(Json::Int64(kint64max)); + JSONTEST_ASSERT_EQUAL( Json::intValue, val.type()); + checks = IsCheck(); - checks.isInt_ = true; - checks.isNumeric_ = true; + checks.isInt64_ = true; + checks.isUInt64_ = true; checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); JSONTEST_ASSERT( kint64max == val.asInt64()); @@ -504,13 +626,34 @@ JSONTEST_FIXTURE( ValueTest, integers ) JSONTEST_ASSERT( double(kint64max) == val.asDouble()); JSONTEST_ASSERT( float(kint64max) == val.asFloat()); + // int64 max (floating point constructor). Note that kint64max is not exactly + // representable as a double, and will be rounded up to be higher. + val = Json::Value(double(kint64max)); + + JSONTEST_ASSERT_EQUAL( Json::realValue, val.type()); + + checks = IsCheck(); + checks.isUInt64_ = true; + checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); + + JSONTEST_ASSERT( 9223372036854775808ULL == val.asUInt64()); + JSONTEST_ASSERT( 9223372036854775808ULL == val.asLargestUInt()); + JSONTEST_ASSERT( 9223372036854775808ULL == val.asDouble()); + JSONTEST_ASSERT( 9223372036854775808ULL == val.asFloat()); + // int64 min val = Json::Value(Json::Int64(kint64min)); + JSONTEST_ASSERT_EQUAL( Json::intValue, val.type()); + checks = IsCheck(); - checks.isInt_ = true; - checks.isNumeric_ = true; + checks.isInt64_ = true; checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); JSONTEST_ASSERT( kint64min == val.asInt64()); @@ -518,19 +661,54 @@ JSONTEST_FIXTURE( ValueTest, integers ) JSONTEST_ASSERT( double(kint64min) == val.asDouble()); JSONTEST_ASSERT( float(kint64min) == val.asFloat()); + // int64 min (floating point constructor). Note that kint64min *is* exactly + // representable as a double. + val = Json::Value(double(kint64min)); + + JSONTEST_ASSERT_EQUAL( Json::realValue, val.type()); + + checks = IsCheck(); + checks.isInt64_ = true; + checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); + + JSONTEST_ASSERT( -9223372036854775808LL == val.asInt64()); + JSONTEST_ASSERT( -9223372036854775808LL == val.asLargestInt()); + JSONTEST_ASSERT( -9223372036854775808.0 == val.asDouble()); + JSONTEST_ASSERT( -9223372036854775808.0 == val.asFloat()); + // uint64 max val = Json::Value(Json::UInt64(kuint64max)); + JSONTEST_ASSERT_EQUAL( Json::uintValue, val.type()); + checks = IsCheck(); - checks.isUInt_ = true; - checks.isNumeric_ = true; + checks.isUInt64_ = true; checks.isIntegral_ = true; + checks.isDouble_ = true; + checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); JSONTEST_ASSERT( kuint64max == val.asUInt64()); JSONTEST_ASSERT( kuint64max == val.asLargestUInt()); JSONTEST_ASSERT( double(kuint64max) == val.asDouble()); JSONTEST_ASSERT( float(kuint64max) == val.asFloat()); + + // uint64 max (floating point constructor). Note that kuint64max is not + // exactly representable as a double, and will be rounded up to be higher. + val = Json::Value(double(kuint64max)); + + JSONTEST_ASSERT_EQUAL( Json::realValue, val.type()); + + checks = IsCheck(); + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); + + JSONTEST_ASSERT( 18446744073709551616.0 == val.asDouble()); + JSONTEST_ASSERT( 18446744073709551616.0 == val.asFloat()); #endif } @@ -540,26 +718,11 @@ JSONTEST_FIXTURE( ValueTest, nonIntegers ) IsCheck checks; Json::Value val; - // Default real - val = Json::Value(Json::realValue); - - JSONTEST_ASSERT_EQUAL(Json::realValue, val.type()); - - checks = IsCheck(); - checks.isDouble_ = true; - checks.isNumeric_ = true; - JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); - - JSONTEST_ASSERT( 0 == val.asInt()); - JSONTEST_ASSERT( 0 == val.asLargestInt()); - JSONTEST_ASSERT( 0 == val.asUInt()); - JSONTEST_ASSERT( 0 == val.asLargestUInt()); - JSONTEST_ASSERT( 0.0 == val.asDouble()); - JSONTEST_ASSERT( 0.0 == val.asFloat()); - // Positive number val = Json::Value(0.25); + JSONTEST_ASSERT_EQUAL( Json::realValue, val.type()); + checks = IsCheck(); checks.isDouble_ = true; checks.isNumeric_ = true; @@ -571,6 +734,8 @@ JSONTEST_FIXTURE( ValueTest, nonIntegers ) // Negative number val = Json::Value(-0.25); + JSONTEST_ASSERT_EQUAL( Json::realValue, val.type()); + checks = IsCheck(); checks.isDouble_ = true; checks.isNumeric_ = true; @@ -614,13 +779,15 @@ ValueTest::IsCheck::IsCheck() : isObject_( false ) , isArray_( false ) , isBool_( false ) - , isDouble_( false ) - , isInt_( false ) - , isUInt_( false ) - , isIntegral_( false ) - , isNumeric_( false ) , isString_( false ) , isNull_( false ) + , isInt_( false ) + , isInt64_( false ) + , isUInt_( false ) + , isUInt64_( false ) + , isIntegral_( false ) + , isDouble_( false ) + , isNumeric_( false ) { } @@ -633,7 +800,9 @@ ValueTest::checkIs( const Json::Value &value, const IsCheck &check ) JSONTEST_ASSERT_EQUAL( check.isBool_, value.isBool() ); JSONTEST_ASSERT_EQUAL( check.isDouble_, value.isDouble() ); JSONTEST_ASSERT_EQUAL( check.isInt_, value.isInt() ); + JSONTEST_ASSERT_EQUAL( check.isInt64_, value.isInt64() ); JSONTEST_ASSERT_EQUAL( check.isUInt_, value.isUInt() ); + JSONTEST_ASSERT_EQUAL( check.isUInt64_, value.isUInt64() ); JSONTEST_ASSERT_EQUAL( check.isIntegral_, value.isIntegral() ); JSONTEST_ASSERT_EQUAL( check.isNumeric_, value.isNumeric() ); JSONTEST_ASSERT_EQUAL( check.isString_, value.isString() );