From c025697ea540a76ed45eabea46b436ae931a223a Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Thu, 26 May 2011 02:46:28 +0000 Subject: [PATCH] Reworked the type conversion system again, so that:A * isFoo methods determine exact representability. * asFoo methods cause casting when safe. * isConvertibleTo indicates whether casting is safe. See NEWS.txt for details. --- NEWS.txt | 42 ++-- src/lib_json/json_value.cpp | 160 +++++++------ src/test_lib_json/jsontest.cpp | 3 +- src/test_lib_json/main.cpp | 404 ++++++++++++++++++++++++++++++++- 4 files changed, 518 insertions(+), 91 deletions(-) diff --git a/NEWS.txt b/NEWS.txt index ac7c856..86c28c0 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -1,22 +1,36 @@ - New in SVN: - ----------- +New in SVN +---------- -* Value + * Updated the type system's behavior, in order to better support backwards + compatibility with code that was written before 64-bit integer support was + introduced. Here's how it works now: - - 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 represented as that type. In particular, a value + constructed with a double like 17.0 will now return true for all of + these methods. - * 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 however that the conversion may not be exact -- for + example, doubles cannot exactly represent all integers above 2^53 + 1. - * 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. + + * isConvertibleTo(fooValue) indicates that it is safe to call asFoo. + (For each type foo, isFoo always implies isConvertibleTo(fooValue).) + asFoo returns an approximate or exact representation as appropriate. + For example, a double value may be truncated when asInt is called. + + * For backwards compatibility with old code, isConvertibleTo(intValue) + may return false even if type() == intValue. This is because the value + may have been constructed with a 64-bit integer larger than maxInt, + and calling asInt() would cause an exception. If you're writing new + code, use isInt64 to find out whether the value is exactly + representable using an Int64, or asDouble() combined with minInt64 and + maxInt64 to figure out whether it is approximately representable. - * 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/src/lib_json/json_value.cpp b/src/lib_json/json_value.cpp index aed7542..522817b 100644 --- a/src/lib_json/json_value.cpp +++ b/src/lib_json/json_value.cpp @@ -13,6 +13,7 @@ #endif // if !defined(JSON_IS_AMALGAMATION) #include #include +#include #include #include #include @@ -43,6 +44,11 @@ const LargestUInt Value::maxLargestUInt = LargestUInt(-1); /// Unknown size marker static const unsigned int unknown = (unsigned)-1; +template +static inline bool InRange(double d, T min, U max) { + return d >= min && d <= max; +} + /** Duplicates the specified string value. * @param value Pointer to the string to duplicate. Must be zero-terminated if @@ -663,6 +669,9 @@ Value::asCString() const std::string Value::asString() const { + // Let the STL sort it out for numeric types. + std::ostringstream oss; + switch ( type_ ) { case nullValue: @@ -672,15 +681,18 @@ Value::asString() const case booleanValue: return value_.bool_ ? "true" : "false"; case intValue: + oss << value_.int_; + break; case uintValue: + oss << value_.uint_; + break; case realValue: - case arrayValue: - case objectValue: - JSON_FAIL_MESSAGE( "Type is not convertible to string" ); + oss << value_.real_; + break; default: - JSON_ASSERT_UNREACHABLE; + JSON_FAIL_MESSAGE( "Type is not convertible to string" ); } - return ""; // unreachable + return oss.str(); } # ifdef JSON_USE_CPPTL @@ -695,17 +707,23 @@ Value::asConstString() const Value::Int Value::asInt() const { - JSON_ASSERT_MESSAGE(isInt(), "Value is not convertible to Int"); switch ( type_ ) { case intValue: + JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range"); return Int(value_.int_); case uintValue: + JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range"); return Int(value_.uint_); case realValue: - return Int( value_.real_ ); + JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt), "double out of Int range"); + return Int(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; default: - break; + JSON_FAIL_MESSAGE("Value is not convertible to Int."); } JSON_ASSERT_UNREACHABLE; return 0; @@ -715,17 +733,23 @@ Value::asInt() const Value::UInt Value::asUInt() const { - JSON_ASSERT_MESSAGE(isUInt(), "Value is not convertible to UInt"); switch ( type_ ) { case intValue: + JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range"); return UInt(value_.int_); case uintValue: + JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range"); return UInt(value_.uint_); case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt), "double out of UInt range"); return UInt( value_.real_ ); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; default: - break; + JSON_FAIL_MESSAGE("Value is not convertible to UInt."); } JSON_ASSERT_UNREACHABLE; return 0; @@ -737,17 +761,22 @@ Value::asUInt() const Value::Int64 Value::asInt64() const { - JSON_ASSERT_MESSAGE(isInt64(), "Value is not convertible to Int64"); switch ( type_ ) { case intValue: return Int64(value_.int_); case uintValue: + JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range"); return Int64(value_.uint_); case realValue: - return Int64( value_.real_ ); + JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64), "double out of Int64 range"); + return Int64(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; default: - break; + JSON_FAIL_MESSAGE("Value is not convertible to Int64."); } JSON_ASSERT_UNREACHABLE; return 0; @@ -757,15 +786,20 @@ Value::asInt64() const Value::UInt64 Value::asUInt64() const { - JSON_ASSERT_MESSAGE(isUInt64(), "Value is not convertible to UInt64"); switch ( type_ ) { case intValue: + JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range"); return UInt64(value_.int_); case uintValue: return UInt64(value_.uint_); case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64), "double out of UInt64 range"); return UInt64( value_.real_ ); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; default: break; } @@ -814,13 +848,11 @@ Value::asDouble() const case realValue: return value_.real_; case nullValue: + return 0.0; case booleanValue: - case stringValue: - case arrayValue: - case objectValue: - JSON_FAIL_MESSAGE( "Value is not a double" ); + return value_.bool_ ? 1.0 : 0.0; default: - JSON_ASSERT_UNREACHABLE; + JSON_FAIL_MESSAGE("Value is not convertible to double."); } return 0; // unreachable; } @@ -841,15 +873,14 @@ Value::asFloat() const case realValue: return static_cast( value_.real_ ); case nullValue: + return 0.0; case booleanValue: - case stringValue: - case arrayValue: - case objectValue: - JSON_FAIL_MESSAGE( "Value is not a float" ); + return value_.bool_ ? 1.0 : 0.0; default: - JSON_ASSERT_UNREACHABLE; + JSON_FAIL_MESSAGE("Value is not convertible to float."); } - return 0.0f; // unreachable; + JSON_ASSERT_UNREACHABLE; + return 0.0f; } bool @@ -860,68 +891,67 @@ Value::asBool() const case booleanValue: return value_.bool_; case nullValue: + return false; case intValue: + return value_.int_ ? true : false; case uintValue: + return value_.uint_ ? true : false; case realValue: - case stringValue: - case arrayValue: - case objectValue: - JSON_FAIL_MESSAGE( "Value is not a bool" ); + return value_.real_ ? true : false; default: - JSON_ASSERT_UNREACHABLE; + JSON_FAIL_MESSAGE("Value is not convertible to bool."); } - return false; // unreachable; + JSON_ASSERT_UNREACHABLE; + return false; } bool Value::isConvertibleTo( ValueType other ) const { - switch ( type_ ) + switch ( other ) { case nullValue: - return true; + return ( isNumeric() && asDouble() == 0.0 ) + || ( type_ == booleanValue && value_.bool_ == false ) + || ( type_ == stringValue && asString() == "" ) + || ( type_ == arrayValue && value_.map_->size() == 0 ) + || ( type_ == objectValue && value_.map_->size() == 0 ) + || type_ == nullValue; case intValue: - return ( other == nullValue && value_.int_ == 0 ) - || other == intValue - || ( other == uintValue && value_.int_ >= 0 ) - || other == realValue - || other == stringValue - || other == booleanValue; + return isInt() + || (type_ == realValue && InRange(value_.real_, minInt, maxInt)) + || type_ == booleanValue + || type_ == nullValue; case uintValue: - return ( other == nullValue && value_.uint_ == 0 ) - || ( other == intValue && value_.uint_ <= (LargestUInt)maxInt ) - || other == uintValue - || other == realValue - || other == stringValue - || other == booleanValue; + return isUInt() + || (type_ == realValue && InRange(value_.real_, 0, maxUInt)) + || type_ == booleanValue + || type_ == nullValue; case realValue: - return ( other == nullValue && value_.real_ == 0.0 ) - || ( other == intValue && value_.real_ >= minInt && value_.real_ <= maxInt ) - || ( other == uintValue && value_.real_ >= 0 && value_.real_ <= maxUInt ) - || other == realValue - || other == stringValue - || other == booleanValue; + return isNumeric() + || type_ == booleanValue + || type_ == nullValue; case booleanValue: - return ( other == nullValue && value_.bool_ == false ) - || other == intValue - || other == uintValue - || other == realValue - || other == stringValue - || other == booleanValue; + return isNumeric() + || type_ == booleanValue + || type_ == nullValue; case stringValue: - return other == stringValue - || ( other == nullValue && (!value_.string_ || value_.string_[0] == 0) ); + return isNumeric() + || type_ == booleanValue + || type_ == stringValue + || type_ == nullValue; case arrayValue: - return other == arrayValue - || ( other == nullValue && value_.map_->size() == 0 ); + return type_ == arrayValue + || type_ == nullValue; case objectValue: - return other == objectValue - || ( other == nullValue && value_.map_->size() == 0 ); + return type_ == objectValue + || type_ == nullValue; default: - JSON_ASSERT_UNREACHABLE; + break; } - return false; // unreachable; + JSON_ASSERT_UNREACHABLE; + return false; } diff --git a/src/test_lib_json/jsontest.cpp b/src/test_lib_json/jsontest.cpp index 3dda9f1..46f2eea 100644 --- a/src/test_lib_json/jsontest.cpp +++ b/src/test_lib_json/jsontest.cpp @@ -250,7 +250,6 @@ TestResult::addToLastFailure( const std::string &message ) } - // class TestCase // ////////////////////////////////////////////////////////////////// @@ -324,7 +323,7 @@ Runner::runTestAt( unsigned int index, TestResult &result ) const catch ( const std::exception &e ) { result.addFailure( __FILE__, __LINE__, - "Unexpected exception caugth:" ) << e.what(); + "Unexpected exception caught:" ) << e.what(); } #endif // if JSON_USE_EXCEPTION delete test; diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index 6dc4782..14f49c1 100644 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -121,6 +121,23 @@ JSONTEST_FIXTURE( ValueTest, objects ) JSONTEST_ASSERT_EQUAL(Json::objectValue, emptyObject_.type()); + // Empty object okay + JSONTEST_ASSERT(emptyObject_.isConvertibleTo(Json::nullValue)); + + // Non-empty object not okay + JSONTEST_ASSERT(!object1_.isConvertibleTo(Json::nullValue)); + + // Always okay + JSONTEST_ASSERT(emptyObject_.isConvertibleTo(Json::objectValue)); + + // Never okay + JSONTEST_ASSERT(!emptyObject_.isConvertibleTo(Json::arrayValue)); + JSONTEST_ASSERT(!emptyObject_.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!emptyObject_.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT(!emptyObject_.isConvertibleTo(Json::realValue)); + JSONTEST_ASSERT(!emptyObject_.isConvertibleTo(Json::booleanValue)); + JSONTEST_ASSERT(!emptyObject_.isConvertibleTo(Json::stringValue)); + // Access through const reference const Json::Value &constObject = object1_; @@ -148,6 +165,23 @@ JSONTEST_FIXTURE( ValueTest, arrays ) JSONTEST_ASSERT_EQUAL(Json::arrayValue, array1_.type()); + // Empty array okay + JSONTEST_ASSERT(emptyArray_.isConvertibleTo(Json::nullValue)); + + // Non-empty array not okay + JSONTEST_ASSERT(!array1_.isConvertibleTo(Json::nullValue)); + + // Always okay + JSONTEST_ASSERT(emptyArray_.isConvertibleTo(Json::arrayValue)); + + // Never okay + JSONTEST_ASSERT(!emptyArray_.isConvertibleTo(Json::objectValue)); + JSONTEST_ASSERT(!emptyArray_.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!emptyArray_.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT(!emptyArray_.isConvertibleTo(Json::realValue)); + JSONTEST_ASSERT(!emptyArray_.isConvertibleTo(Json::booleanValue)); + JSONTEST_ASSERT(!emptyArray_.isConvertibleTo(Json::stringValue)); + // Access through const reference const Json::Value &constArray = array1_; JSONTEST_ASSERT_EQUAL(Json::Value(1234), constArray[index0]); @@ -170,6 +204,23 @@ JSONTEST_FIXTURE( ValueTest, null ) IsCheck checks; checks.isNull_ = true; JSONTEST_ASSERT_PRED( checkIs( null_, checks ) ); + + JSONTEST_ASSERT(null_.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(null_.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(null_.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT(null_.isConvertibleTo(Json::realValue)); + JSONTEST_ASSERT(null_.isConvertibleTo(Json::booleanValue)); + JSONTEST_ASSERT(null_.isConvertibleTo(Json::stringValue)); + JSONTEST_ASSERT(null_.isConvertibleTo(Json::arrayValue)); + JSONTEST_ASSERT(null_.isConvertibleTo(Json::objectValue)); + + JSONTEST_ASSERT_EQUAL(Json::Int(0), null_.asInt()); + JSONTEST_ASSERT_EQUAL(Json::LargestInt(0), null_.asLargestInt()); + JSONTEST_ASSERT_EQUAL(Json::UInt(0), null_.asUInt()); + JSONTEST_ASSERT_EQUAL(Json::LargestUInt(0), null_.asLargestUInt()); + JSONTEST_ASSERT_EQUAL(0.0, null_.asDouble()); + JSONTEST_ASSERT_EQUAL(0.0, null_.asFloat()); + JSONTEST_ASSERT_STRING_EQUAL("", null_.asString()); } @@ -183,6 +234,22 @@ JSONTEST_FIXTURE( ValueTest, strings ) JSONTEST_ASSERT_PRED( checkIs( string_, checks ) ); JSONTEST_ASSERT_PRED( checkIs( string1_, checks ) ); + // Empty string okay + JSONTEST_ASSERT(emptyString_.isConvertibleTo(Json::nullValue)); + + // Non-empty string not okay + JSONTEST_ASSERT(!string1_.isConvertibleTo(Json::nullValue)); + + // Always okay + JSONTEST_ASSERT(string1_.isConvertibleTo(Json::stringValue)); + + // Never okay + JSONTEST_ASSERT(!string1_.isConvertibleTo(Json::objectValue)); + JSONTEST_ASSERT(!string1_.isConvertibleTo(Json::arrayValue)); + JSONTEST_ASSERT(!string1_.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!string1_.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT(!string1_.isConvertibleTo(Json::realValue)); + JSONTEST_ASSERT_STRING_EQUAL("a", string1_.asString()); JSONTEST_ASSERT_STRING_EQUAL("a", string1_.asCString()); } @@ -197,8 +264,38 @@ JSONTEST_FIXTURE( ValueTest, bools ) JSONTEST_ASSERT_PRED( checkIs( false_, checks ) ); JSONTEST_ASSERT_PRED( checkIs( true_, checks ) ); + // False okay + JSONTEST_ASSERT(false_.isConvertibleTo(Json::nullValue)); + + // True not okay + JSONTEST_ASSERT(!true_.isConvertibleTo(Json::nullValue)); + + // Always okay + JSONTEST_ASSERT(true_.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(true_.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT(true_.isConvertibleTo(Json::realValue)); + JSONTEST_ASSERT(true_.isConvertibleTo(Json::booleanValue)); + JSONTEST_ASSERT(true_.isConvertibleTo(Json::stringValue)); + + // Never okay + JSONTEST_ASSERT(!true_.isConvertibleTo(Json::arrayValue)); + JSONTEST_ASSERT(!true_.isConvertibleTo(Json::objectValue)); + JSONTEST_ASSERT_EQUAL(true, true_.asBool()); + JSONTEST_ASSERT_EQUAL(1, true_.asInt()); + JSONTEST_ASSERT_EQUAL(1, true_.asLargestInt()); + JSONTEST_ASSERT_EQUAL(1, true_.asUInt()); + JSONTEST_ASSERT_EQUAL(1, true_.asLargestUInt()); + JSONTEST_ASSERT_EQUAL(1.0, true_.asDouble()); + JSONTEST_ASSERT_EQUAL(1.0, true_.asFloat()); + JSONTEST_ASSERT_EQUAL(false, false_.asBool()); + JSONTEST_ASSERT_EQUAL(0, false_.asInt()); + JSONTEST_ASSERT_EQUAL(0, false_.asLargestInt()); + JSONTEST_ASSERT_EQUAL(0, false_.asUInt()); + JSONTEST_ASSERT_EQUAL(0, false_.asLargestUInt()); + JSONTEST_ASSERT_EQUAL(0.0, false_.asDouble()); + JSONTEST_ASSERT_EQUAL(0.0, false_.asFloat()); } @@ -207,6 +304,25 @@ JSONTEST_FIXTURE( ValueTest, integers ) IsCheck checks; Json::Value val; + // Conversions that don't depend on the value. + JSONTEST_ASSERT(Json::Value(17).isConvertibleTo(Json::realValue)); + JSONTEST_ASSERT(Json::Value(17).isConvertibleTo(Json::stringValue)); + JSONTEST_ASSERT(Json::Value(17).isConvertibleTo(Json::booleanValue)); + JSONTEST_ASSERT(!Json::Value(17).isConvertibleTo(Json::arrayValue)); + JSONTEST_ASSERT(!Json::Value(17).isConvertibleTo(Json::objectValue)); + + JSONTEST_ASSERT(Json::Value(17U).isConvertibleTo(Json::realValue)); + JSONTEST_ASSERT(Json::Value(17U).isConvertibleTo(Json::stringValue)); + JSONTEST_ASSERT(Json::Value(17U).isConvertibleTo(Json::booleanValue)); + JSONTEST_ASSERT(!Json::Value(17U).isConvertibleTo(Json::arrayValue)); + JSONTEST_ASSERT(!Json::Value(17U).isConvertibleTo(Json::objectValue)); + + JSONTEST_ASSERT(Json::Value(17.0).isConvertibleTo(Json::realValue)); + JSONTEST_ASSERT(Json::Value(17.0).isConvertibleTo(Json::stringValue)); + JSONTEST_ASSERT(Json::Value(17.0).isConvertibleTo(Json::booleanValue)); + JSONTEST_ASSERT(!Json::Value(17.0).isConvertibleTo(Json::arrayValue)); + JSONTEST_ASSERT(!Json::Value(17.0).isConvertibleTo(Json::objectValue)); + // Default int val = Json::Value(Json::intValue); @@ -222,12 +338,18 @@ JSONTEST_FIXTURE( ValueTest, integers ) checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); + JSONTEST_ASSERT(val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT_EQUAL(0, val.asInt()); JSONTEST_ASSERT_EQUAL(0, val.asLargestInt()); JSONTEST_ASSERT_EQUAL(0, val.asUInt()); JSONTEST_ASSERT_EQUAL(0, val.asLargestUInt()); JSONTEST_ASSERT_EQUAL(0.0, val.asDouble()); JSONTEST_ASSERT_EQUAL(0.0, val.asFloat()); + JSONTEST_ASSERT_EQUAL(false, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("0", val.asString()); // Default uint val = Json::Value(Json::uintValue); @@ -244,18 +366,28 @@ JSONTEST_FIXTURE( ValueTest, integers ) checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); + JSONTEST_ASSERT(val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT_EQUAL(0, val.asInt()); JSONTEST_ASSERT_EQUAL(0, val.asLargestInt()); JSONTEST_ASSERT_EQUAL(0, val.asUInt()); JSONTEST_ASSERT_EQUAL(0, val.asLargestUInt()); JSONTEST_ASSERT_EQUAL(0.0, val.asDouble()); JSONTEST_ASSERT_EQUAL(0.0, val.asFloat()); + JSONTEST_ASSERT_EQUAL(false, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("0", val.asString()); // Default real val = Json::Value(Json::realValue); JSONTEST_ASSERT_EQUAL(Json::realValue, val.type()); + JSONTEST_ASSERT(val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::uintValue)); + checks = IsCheck(); checks.isInt_ = true; checks.isInt64_ = true; @@ -272,6 +404,8 @@ JSONTEST_FIXTURE( ValueTest, integers ) JSONTEST_ASSERT_EQUAL(0, val.asLargestUInt()); JSONTEST_ASSERT_EQUAL(0.0, val.asDouble()); JSONTEST_ASSERT_EQUAL(0.0, val.asFloat()); + JSONTEST_ASSERT_EQUAL(false, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("0", val.asString()); // Zero (signed constructor arg) val = Json::Value(0); @@ -288,12 +422,18 @@ JSONTEST_FIXTURE( ValueTest, integers ) checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); + JSONTEST_ASSERT(val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT_EQUAL(0, val.asInt()); JSONTEST_ASSERT_EQUAL(0, val.asLargestInt()); JSONTEST_ASSERT_EQUAL(0, val.asUInt()); JSONTEST_ASSERT_EQUAL(0, val.asLargestUInt()); JSONTEST_ASSERT_EQUAL(0.0, val.asDouble()); JSONTEST_ASSERT_EQUAL(0.0, val.asFloat()); + JSONTEST_ASSERT_EQUAL(false, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("0", val.asString()); // Zero (unsigned constructor arg) val = Json::Value(0u); @@ -310,12 +450,18 @@ JSONTEST_FIXTURE( ValueTest, integers ) checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); + JSONTEST_ASSERT(val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT_EQUAL(0, val.asInt()); JSONTEST_ASSERT_EQUAL(0, val.asLargestInt()); JSONTEST_ASSERT_EQUAL(0, val.asUInt()); JSONTEST_ASSERT_EQUAL(0, val.asLargestUInt()); JSONTEST_ASSERT_EQUAL(0.0, val.asDouble()); JSONTEST_ASSERT_EQUAL(0.0, val.asFloat()); + JSONTEST_ASSERT_EQUAL(false, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("0", val.asString()); // Zero (floating-point constructor arg) val = Json::Value(0.0); @@ -332,12 +478,18 @@ JSONTEST_FIXTURE( ValueTest, integers ) checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); + JSONTEST_ASSERT(val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT_EQUAL(0, val.asInt()); JSONTEST_ASSERT_EQUAL(0, val.asLargestInt()); JSONTEST_ASSERT_EQUAL(0, val.asUInt()); JSONTEST_ASSERT_EQUAL(0, val.asLargestUInt()); JSONTEST_ASSERT_EQUAL(0.0, val.asDouble()); JSONTEST_ASSERT_EQUAL(0.0, val.asFloat()); + JSONTEST_ASSERT_EQUAL(false, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("0", val.asString()); // 2^20 (signed constructor arg) val = Json::Value(1 << 20); @@ -354,12 +506,18 @@ JSONTEST_FIXTURE( ValueTest, integers ) checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT_EQUAL((1 << 20), val.asInt()); JSONTEST_ASSERT_EQUAL((1 << 20), val.asLargestInt()); JSONTEST_ASSERT_EQUAL((1 << 20), val.asUInt()); JSONTEST_ASSERT_EQUAL((1 << 20), val.asLargestUInt()); JSONTEST_ASSERT_EQUAL((1 << 20), val.asDouble()); JSONTEST_ASSERT_EQUAL((1 << 20), val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("1048576", val.asString()); // 2^20 (unsigned constructor arg) val = Json::Value(1u << 20); @@ -376,12 +534,18 @@ JSONTEST_FIXTURE( ValueTest, integers ) checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT_EQUAL((1 << 20), val.asInt()); JSONTEST_ASSERT_EQUAL((1 << 20), val.asLargestInt()); JSONTEST_ASSERT_EQUAL((1 << 20), val.asUInt()); JSONTEST_ASSERT_EQUAL((1 << 20), val.asLargestUInt()); JSONTEST_ASSERT_EQUAL((1 << 20), val.asDouble()); JSONTEST_ASSERT_EQUAL((1 << 20), val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("1048576", val.asString()); // 2^20 (floating-point constructor arg) val = Json::Value((1 << 20) / 1.0); @@ -398,12 +562,18 @@ JSONTEST_FIXTURE( ValueTest, integers ) checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT_EQUAL((1 << 20), val.asInt()); JSONTEST_ASSERT_EQUAL((1 << 20), val.asLargestInt()); JSONTEST_ASSERT_EQUAL((1 << 20), val.asUInt()); JSONTEST_ASSERT_EQUAL((1 << 20), val.asLargestUInt()); JSONTEST_ASSERT_EQUAL((1 << 20), val.asDouble()); JSONTEST_ASSERT_EQUAL((1 << 20), val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("1.04858e+06", val.asString()); // -2^20 val = Json::Value(-(1 << 20)); @@ -418,10 +588,16 @@ JSONTEST_FIXTURE( ValueTest, integers ) checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT_EQUAL(-(1 << 20), val.asInt()); JSONTEST_ASSERT_EQUAL(-(1 << 20), val.asLargestInt()); JSONTEST_ASSERT_EQUAL(-(1 << 20), val.asDouble()); JSONTEST_ASSERT_EQUAL(-(1 << 20), val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("-1048576", val.asString()); // int32 max val = Json::Value(kint32max); @@ -438,12 +614,18 @@ JSONTEST_FIXTURE( ValueTest, integers ) checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT_EQUAL(kint32max, val.asInt()); JSONTEST_ASSERT_EQUAL(kint32max, val.asLargestInt()); JSONTEST_ASSERT_EQUAL(kint32max, val.asUInt()); JSONTEST_ASSERT_EQUAL(kint32max, val.asLargestUInt()); JSONTEST_ASSERT_EQUAL(kint32max, val.asDouble()); JSONTEST_ASSERT_EQUAL(kint32max, val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("2147483647", val.asString()); // int32 min val = Json::Value(kint32min); @@ -458,10 +640,16 @@ JSONTEST_FIXTURE( ValueTest, integers ) checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT_EQUAL(kint32min, val.asInt()); JSONTEST_ASSERT_EQUAL(kint32min, val.asLargestInt()); JSONTEST_ASSERT_EQUAL(kint32min, val.asDouble()); JSONTEST_ASSERT_EQUAL(kint32min, val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("-2147483648", val.asString()); // uint32 max val = Json::Value(kuint32max); @@ -477,6 +665,10 @@ JSONTEST_FIXTURE( ValueTest, integers ) checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::uintValue)); + #ifndef JSON_NO_INT64 JSONTEST_ASSERT_EQUAL(kuint32max, val.asLargestInt()); #endif @@ -484,6 +676,8 @@ JSONTEST_FIXTURE( ValueTest, integers ) JSONTEST_ASSERT_EQUAL(kuint32max, val.asLargestUInt()); JSONTEST_ASSERT_EQUAL(kuint32max, val.asDouble()); JSONTEST_ASSERT_EQUAL(kuint32max, val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("4294967295", val.asString()); #ifdef JSON_NO_INT64 // int64 max @@ -496,8 +690,14 @@ JSONTEST_FIXTURE( ValueTest, integers ) checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT_EQUAL(double(kint64max), val.asDouble()); JSONTEST_ASSERT_EQUAL(float(kint64max), val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("9.22337204e18", val.asString()); // int64 min val = Json::Value(double(kint64min)); @@ -509,8 +709,14 @@ JSONTEST_FIXTURE( ValueTest, integers ) checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT_EQUAL(double(kint64min), val.asDouble()); JSONTEST_ASSERT_EQUAL(float(kint64min), val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("-9.22337204e18", val.asString()); // uint64 max val = Json::Value(double(kuint64max)); @@ -522,8 +728,14 @@ JSONTEST_FIXTURE( ValueTest, integers ) checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT_EQUAL(double(kuint64max), val.asDouble()); JSONTEST_ASSERT_EQUAL(float(kuint64max), val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("1.84467441e19", val.asString()); #else // ifdef JSON_NO_INT64 // 2^40 (signed constructor arg) val = Json::Value(1LL << 40); @@ -538,12 +750,18 @@ JSONTEST_FIXTURE( ValueTest, integers ) checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT_EQUAL((1LL << 40), val.asInt64()); JSONTEST_ASSERT_EQUAL((1LL << 40), val.asLargestInt()); JSONTEST_ASSERT_EQUAL((1LL << 40), val.asUInt64()); JSONTEST_ASSERT_EQUAL((1LL << 40), val.asLargestUInt()); JSONTEST_ASSERT_EQUAL((1LL << 40), val.asDouble()); JSONTEST_ASSERT_EQUAL((1LL << 40), val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("1099511627776", val.asString()); // 2^40 (unsigned constructor arg) val = Json::Value(1ULL << 40); @@ -558,12 +776,18 @@ JSONTEST_FIXTURE( ValueTest, integers ) checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT_EQUAL((1LL << 40), val.asInt64()); JSONTEST_ASSERT_EQUAL((1LL << 40), val.asLargestInt()); JSONTEST_ASSERT_EQUAL((1LL << 40), val.asUInt64()); JSONTEST_ASSERT_EQUAL((1LL << 40), val.asLargestUInt()); JSONTEST_ASSERT_EQUAL((1LL << 40), val.asDouble()); JSONTEST_ASSERT_EQUAL((1LL << 40), val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("1099511627776", val.asString()); // 2^40 (floating-point constructor arg) val = Json::Value((1LL << 40) / 1.0); @@ -578,12 +802,18 @@ JSONTEST_FIXTURE( ValueTest, integers ) checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT_EQUAL((1LL << 40), val.asInt64()); JSONTEST_ASSERT_EQUAL((1LL << 40), val.asLargestInt()); JSONTEST_ASSERT_EQUAL((1LL << 40), val.asUInt64()); JSONTEST_ASSERT_EQUAL((1LL << 40), val.asLargestUInt()); JSONTEST_ASSERT_EQUAL((1LL << 40), val.asDouble()); JSONTEST_ASSERT_EQUAL((1LL << 40), val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("1.09951e+12", val.asString()); // -2^40 val = Json::Value(-(1LL << 40)); @@ -597,10 +827,16 @@ JSONTEST_FIXTURE( ValueTest, integers ) checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT_EQUAL(-(1LL << 40), val.asInt64()); JSONTEST_ASSERT_EQUAL(-(1LL << 40), val.asLargestInt()); JSONTEST_ASSERT_EQUAL(-(1LL << 40), val.asDouble()); JSONTEST_ASSERT_EQUAL(-(1LL << 40), val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("-1099511627776", val.asString()); // int64 max val = Json::Value(Json::Int64(kint64max)); @@ -615,12 +851,18 @@ JSONTEST_FIXTURE( ValueTest, integers ) checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT_EQUAL(kint64max, val.asInt64()); JSONTEST_ASSERT_EQUAL(kint64max, val.asLargestInt()); JSONTEST_ASSERT_EQUAL(kint64max, val.asUInt64()); JSONTEST_ASSERT_EQUAL(kint64max, val.asLargestUInt()); JSONTEST_ASSERT_EQUAL(double(kint64max), val.asDouble()); JSONTEST_ASSERT_EQUAL(float(kint64max), val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("9223372036854775807", val.asString()); // int64 max (floating point constructor). Note that kint64max is not exactly // representable as a double, and will be rounded up to be higher. @@ -635,10 +877,16 @@ JSONTEST_FIXTURE( ValueTest, integers ) checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT_EQUAL(9223372036854775808ULL, val.asUInt64()); JSONTEST_ASSERT_EQUAL(9223372036854775808ULL, val.asLargestUInt()); JSONTEST_ASSERT_EQUAL(9223372036854775808ULL, val.asDouble()); JSONTEST_ASSERT_EQUAL(9223372036854775808ULL, val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("9.22337e+18", val.asString()); // int64 min val = Json::Value(Json::Int64(kint64min)); @@ -652,10 +900,16 @@ JSONTEST_FIXTURE( ValueTest, integers ) checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT_EQUAL(kint64min, val.asInt64()); JSONTEST_ASSERT_EQUAL(kint64min, val.asLargestInt()); JSONTEST_ASSERT_EQUAL(double(kint64min), val.asDouble()); JSONTEST_ASSERT_EQUAL(float(kint64min), val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("-9223372036854775808", val.asString()); // int64 min (floating point constructor). Note that kint64min *is* exactly // representable as a double. @@ -670,10 +924,16 @@ JSONTEST_FIXTURE( ValueTest, integers ) checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); - JSONTEST_ASSERT_EQUAL(-9223372036854775808LL, val.asInt64()); - JSONTEST_ASSERT_EQUAL(-9223372036854775808LL, val.asLargestInt()); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + + JSONTEST_ASSERT_EQUAL(kint64min, val.asInt64()); + JSONTEST_ASSERT_EQUAL(kint64min, val.asLargestInt()); JSONTEST_ASSERT_EQUAL(-9223372036854775808.0, val.asDouble()); JSONTEST_ASSERT_EQUAL(-9223372036854775808.0, val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("-9.22337e+18", val.asString()); // uint64 max val = Json::Value(Json::UInt64(kuint64max)); @@ -687,10 +947,16 @@ JSONTEST_FIXTURE( ValueTest, integers ) checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT_EQUAL(kuint64max, val.asUInt64()); JSONTEST_ASSERT_EQUAL(kuint64max, val.asLargestUInt()); JSONTEST_ASSERT_EQUAL(double(kuint64max), val.asDouble()); JSONTEST_ASSERT_EQUAL(float(kuint64max), val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("18446744073709551615", val.asString()); // uint64 max (floating point constructor). Note that kuint64max is not // exactly representable as a double, and will be rounded up to be higher. @@ -703,8 +969,14 @@ JSONTEST_FIXTURE( ValueTest, integers ) checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT_EQUAL(18446744073709551616.0, val.asDouble()); JSONTEST_ASSERT_EQUAL(18446744073709551616.0, val.asFloat()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_STRING_EQUAL("1.84467e+19", val.asString()); #endif } @@ -714,8 +986,8 @@ JSONTEST_FIXTURE( ValueTest, nonIntegers ) IsCheck checks; Json::Value val; - // Positive number - val = Json::Value(0.25); + // Small positive number + val = Json::Value(1.5); JSONTEST_ASSERT_EQUAL(Json::realValue, val.type()); @@ -724,11 +996,26 @@ JSONTEST_FIXTURE( ValueTest, nonIntegers ) checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); - JSONTEST_ASSERT_EQUAL(0.25, val.asDouble()); - JSONTEST_ASSERT_EQUAL(0.25, val.asFloat()); + JSONTEST_ASSERT(val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::realValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::booleanValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::stringValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::arrayValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::objectValue)); - // Negative number - val = Json::Value(-0.25); + JSONTEST_ASSERT_EQUAL(1.5, val.asDouble()); + JSONTEST_ASSERT_EQUAL(1.5, val.asFloat()); + JSONTEST_ASSERT_EQUAL(1, val.asInt()); + JSONTEST_ASSERT_EQUAL(1, val.asLargestInt()); + JSONTEST_ASSERT_EQUAL(1, val.asUInt()); + JSONTEST_ASSERT_EQUAL(1, val.asLargestUInt()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_EQUAL("1.5", val.asString()); + + // Small negative number + val = Json::Value(-1.5); JSONTEST_ASSERT_EQUAL(Json::realValue, val.type()); @@ -737,8 +1024,105 @@ JSONTEST_FIXTURE( ValueTest, nonIntegers ) checks.isNumeric_ = true; JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); - JSONTEST_ASSERT_EQUAL(-0.25, val.asDouble()); - JSONTEST_ASSERT_EQUAL(-0.25, val.asFloat()); + JSONTEST_ASSERT(val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::realValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::booleanValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::stringValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::arrayValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::objectValue)); + + JSONTEST_ASSERT_EQUAL(-1.5, val.asDouble()); + JSONTEST_ASSERT_EQUAL(-1.5, val.asFloat()); + JSONTEST_ASSERT_EQUAL(-1, val.asInt()); + JSONTEST_ASSERT_EQUAL(-1, val.asLargestInt()); + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_EQUAL("-1.5", val.asString()); + + // A bit over int32 max + val = Json::Value(kint32max + 0.5); + + JSONTEST_ASSERT_EQUAL(Json::realValue, val.type()); + + checks = IsCheck(); + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); + + JSONTEST_ASSERT(val.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::realValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::booleanValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::stringValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::arrayValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::objectValue)); + + JSONTEST_ASSERT_EQUAL(2147483647.5, val.asDouble()); + JSONTEST_ASSERT_EQUAL(float(2147483647.5), val.asFloat()); + JSONTEST_ASSERT_EQUAL(2147483647U, val.asUInt()); +#ifdef JSON_HAS_INT64 + JSONTEST_ASSERT_EQUAL(2147483647L, val.asLargestInt()); + JSONTEST_ASSERT_EQUAL(2147483647U, val.asLargestUInt()); +#endif + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_EQUAL("2.14748e+09", val.asString()); + + // A bit under int32 min + val = Json::Value(kint32min - 0.5); + + JSONTEST_ASSERT_EQUAL(Json::realValue, val.type()); + + checks = IsCheck(); + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); + + JSONTEST_ASSERT(val.isConvertibleTo(Json::realValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::booleanValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::stringValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::arrayValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::objectValue)); + + JSONTEST_ASSERT_EQUAL(-2147483648.5, val.asDouble()); + JSONTEST_ASSERT_EQUAL(float(-2147483648.5), val.asFloat()); +#ifdef JSON_HAS_INT64 + JSONTEST_ASSERT_EQUAL(-2147483648LL, val.asLargestInt()); +#endif + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_EQUAL("-2.14748e+09", val.asString()); + + // A bit over uint32 max + val = Json::Value(kuint32max + 0.5); + + JSONTEST_ASSERT_EQUAL(Json::realValue, val.type()); + + checks = IsCheck(); + checks.isDouble_ = true; + checks.isNumeric_ = true; + JSONTEST_ASSERT_PRED( checkIs( val, checks ) ); + + JSONTEST_ASSERT(val.isConvertibleTo(Json::realValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::booleanValue)); + JSONTEST_ASSERT(val.isConvertibleTo(Json::stringValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::nullValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::arrayValue)); + JSONTEST_ASSERT(!val.isConvertibleTo(Json::objectValue)); + + JSONTEST_ASSERT_EQUAL(4294967295.5, val.asDouble()); + JSONTEST_ASSERT_EQUAL(float(4294967295.5), val.asFloat()); +#ifdef JSON_HAS_INT64 + JSONTEST_ASSERT_EQUAL(4294967295LL, val.asLargestInt()); + JSONTEST_ASSERT_EQUAL(4294967295ULL, val.asLargestUInt()); +#endif + JSONTEST_ASSERT_EQUAL(true, val.asBool()); + JSONTEST_ASSERT_EQUAL("4.29497e+09", val.asString()); }