improved `MathLib::to{ULong|Long|Double}Number()` and increased test coverage / added CMake option `USE_LIBCXX` / fixed #10695 (#4611)

This commit is contained in:
Oliver Stöneberg 2022-12-07 09:20:09 +01:00 committed by GitHub
parent 89dba226dd
commit 8bb5ac0efd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 341 additions and 105 deletions

View File

@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
env: env:
UBSAN_OPTIONS: print_stacktrace=1:halt_on_error=1 UBSAN_OPTIONS: print_stacktrace=1:halt_on_error=1:report_error_type=1
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3

View File

@ -13,11 +13,15 @@ if (MSVC)
endif() endif()
# TODO: this should probably apply to the compiler and not the platform # TODO: this should probably apply to the compiler and not the platform
if (CPPCHK_GLIBCXX_DEBUG AND UNIX) if (CPPCHK_GLIBCXX_DEBUG AND UNIX AND CMAKE_BUILD_TYPE STREQUAL "Debug")
# TODO: check if this can be enabled again for Clang - also done in Makefile if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
if (CMAKE_BUILD_TYPE STREQUAL "Debug" AND NOT (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) if (USE_LIBCXX)
add_definitions(-DLIBCXX_ENABLE_DEBUG_MODE)
endif()
else()
# TODO: check if this can be enabled again for Clang - also done in Makefile
add_definitions(-D_GLIBCXX_DEBUG) add_definitions(-D_GLIBCXX_DEBUG)
endif() endif()
endif() endif()
if (HAVE_RULES) if (HAVE_RULES)

View File

@ -65,6 +65,11 @@ elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-gdwarf-4) add_compile_options(-gdwarf-4)
endif() endif()
if (USE_LIBCXX)
add_compile_options(-stdlib=libc++)
add_link_options(-lc++)
endif()
add_compile_options_safe(-Wno-documentation-unknown-command) add_compile_options_safe(-Wno-documentation-unknown-command)
# TODO: fix and enable these warnings - or move to suppression list below # TODO: fix and enable these warnings - or move to suppression list below

View File

@ -42,9 +42,10 @@ option(USE_QT6 "Prefer Qt6 when available"
option(HAVE_RULES "Usage of rules (needs PCRE library and headers)" OFF) option(HAVE_RULES "Usage of rules (needs PCRE library and headers)" OFF)
option(USE_BUNDLED_TINYXML2 "Usage of bundled tinyxml2 library" ON) option(USE_BUNDLED_TINYXML2 "Usage of bundled tinyxml2 library" ON)
option(CPPCHK_GLIBCXX_DEBUG "Usage of _GLIBCXX_DEBUG in Debug build" ON) option(CPPCHK_GLIBCXX_DEBUG "Usage of STL debug checks in Debug build" ON)
option(USE_THREADS "Usage of threads instead of fork() for -j" OFF) option(USE_THREADS "Usage of threads instead of fork() for -j" OFF)
option(USE_BOOST "Usage of Boost" OFF) option(USE_BOOST "Usage of Boost" OFF)
option(USE_LIBCXX "Use libc++ instead of libstdc++" OFF)
option(DISABLE_CRTDBG_MAP_ALLOC "Disable usage of Visual Studio C++ memory leak detection in Debug build" OFF) option(DISABLE_CRTDBG_MAP_ALLOC "Disable usage of Visual Studio C++ memory leak detection in Debug build" OFF)
option(NO_UNIX_SIGNAL_HANDLING "Disable usage of Unix Signal Handling" OFF) option(NO_UNIX_SIGNAL_HANDLING "Disable usage of Unix Signal Handling" OFF)

View File

@ -76,6 +76,7 @@ if (USE_BOOST)
message( STATUS "Boost_VERSION_STRING = ${Boost_VERSION_STRING}") message( STATUS "Boost_VERSION_STRING = ${Boost_VERSION_STRING}")
message( STATUS "Boost_INCLUDE_DIRS = ${Boost_INCLUDE_DIRS}") message( STATUS "Boost_INCLUDE_DIRS = ${Boost_INCLUDE_DIRS}")
endif() endif()
message( STATUS "USE_LIBCXX = ${USE_LIBCXX}" )
message( STATUS ) message( STATUS )
if(${ANALYZE_ADDRESS}) if(${ANALYZE_ADDRESS})

View File

@ -293,8 +293,10 @@ MathLib::biguint MathLib::toULongNumber(const std::string & str)
try { try {
const biguint ret = std::stoull(str, nullptr, 16); const biguint ret = std::stoull(str, nullptr, 16);
return ret; return ret;
} catch (const std::out_of_range& e) { } catch (const std::out_of_range& /*e*/) {
throw InternalError(nullptr, "Internal Error. MathLib::toULongNumber: out_of_range: " + str + " (" + e.what() +")"); throw InternalError(nullptr, "Internal Error. MathLib::toULongNumber: out_of_range: " + str);
} catch (const std::invalid_argument& /*e*/) {
throw InternalError(nullptr, "Internal Error. MathLib::toULongNumber: invalid_argument: " + str);
} }
} }
@ -303,8 +305,10 @@ MathLib::biguint MathLib::toULongNumber(const std::string & str)
try { try {
const biguint ret = std::stoull(str, nullptr, 8); const biguint ret = std::stoull(str, nullptr, 8);
return ret; return ret;
} catch (const std::out_of_range& e) { } catch (const std::out_of_range& /*e*/) {
throw InternalError(nullptr, "Internal Error. MathLib::toULongNumber: out_of_range: " + str + " (" + e.what() +")"); throw InternalError(nullptr, "Internal Error. MathLib::toULongNumber: out_of_range: " + str);
} catch (const std::invalid_argument& /*e*/) {
throw InternalError(nullptr, "Internal Error. MathLib::toULongNumber: invalid_argument: " + str);
} }
} }
@ -318,26 +322,38 @@ MathLib::biguint MathLib::toULongNumber(const std::string & str)
if (str[i] == '1') if (str[i] == '1')
ret |= 1; ret |= 1;
} }
/* if (str[0] == '-') if (str[0] == '-')
ret = -ret; */ ret = -ret;
return ret; return ret;
} }
if (isFloat(str)) { if (isFloat(str)) {
// Things are going to be less precise now: the value can't b represented in the biguint type. // Things are going to be less precise now: the value can't be represented in the biguint type.
// Use min/max values as an approximation. See #5843 // Use min/max values as an approximation. See #5843
const double doubleval = std::atof(str.c_str()); // TODO: bail out when we are out of range?
const double doubleval = toDoubleNumber(str);
if (doubleval > (double)std::numeric_limits<biguint>::max()) if (doubleval > (double)std::numeric_limits<biguint>::max())
return std::numeric_limits<biguint>::max(); return std::numeric_limits<biguint>::max();
else else // cast to bigint to avoid UBSAN warning about negative double being out-of-range
return static_cast<biguint>(doubleval); return static_cast<biguint>(static_cast<bigint>(doubleval));
} }
if (isCharLiteral(str))
return simplecpp::characterLiteralToLL(str);
try { try {
const biguint ret = std::stoull(str, nullptr, 10); std::size_t idx = 0;
const biguint ret = std::stoull(str, &idx, 10);
if (idx != str.size()) {
const std::string s = str.substr(idx);
if (s.find_first_not_of("LlUu") != std::string::npos && s != "i64" && s != "ui64")
throw InternalError(nullptr, "Internal Error. MathLib::toULongNumber: input was not completely consumed: " + str);
}
return ret; return ret;
} catch (const std::out_of_range& e) { } catch (const std::out_of_range& /*e*/) {
throw InternalError(nullptr, "Internal Error. MathLib::toULongNumber: out_of_range: " + str + " (" + e.what() +")"); throw InternalError(nullptr, "Internal Error. MathLib::toULongNumber: out_of_range: " + str);
} catch (const std::invalid_argument& /*e*/) {
throw InternalError(nullptr, "Internal Error. MathLib::toULongNumber: invalid_argument: " + str);
} }
} }
@ -355,8 +371,10 @@ MathLib::bigint MathLib::toLongNumber(const std::string & str)
try { try {
const biguint ret = std::stoull(str, nullptr, 16); const biguint ret = std::stoull(str, nullptr, 16);
return (bigint)ret; return (bigint)ret;
} catch (const std::out_of_range& e) { } catch (const std::out_of_range& /*e*/) {
throw InternalError(nullptr, "Internal Error. MathLib::toLongNumber: out_of_range: " + str + " (" + e.what() +")"); throw InternalError(nullptr, "Internal Error. MathLib::toLongNumber: out_of_range: " + str);
} catch (const std::invalid_argument& /*e*/) {
throw InternalError(nullptr, "Internal Error. MathLib::toLongNumber: invalid_argument: " + str);
} }
} }
@ -365,8 +383,10 @@ MathLib::bigint MathLib::toLongNumber(const std::string & str)
try { try {
const biguint ret = std::stoull(str, nullptr, 8); const biguint ret = std::stoull(str, nullptr, 8);
return ret; return ret;
} catch (const std::out_of_range& e) { } catch (const std::out_of_range& /*e*/) {
throw InternalError(nullptr, "Internal Error. MathLib::toLongNumber: out_of_range: " + str + " (" + e.what() +")"); throw InternalError(nullptr, "Internal Error. MathLib::toLongNumber: out_of_range: " + str);
} catch (const std::invalid_argument& /*e*/) {
throw InternalError(nullptr, "Internal Error. MathLib::toLongNumber: invalid_argument: " + str);
} }
} }
@ -388,6 +408,7 @@ MathLib::bigint MathLib::toLongNumber(const std::string & str)
if (isFloat(str)) { if (isFloat(str)) {
// Things are going to be less precise now: the value can't be represented in the bigint type. // Things are going to be less precise now: the value can't be represented in the bigint type.
// Use min/max values as an approximation. See #5843 // Use min/max values as an approximation. See #5843
// TODO: bail out when we are out of range?
const double doubleval = toDoubleNumber(str); const double doubleval = toDoubleNumber(str);
if (doubleval > (double)std::numeric_limits<bigint>::max()) if (doubleval > (double)std::numeric_limits<bigint>::max())
return std::numeric_limits<bigint>::max(); return std::numeric_limits<bigint>::max();
@ -401,10 +422,18 @@ MathLib::bigint MathLib::toLongNumber(const std::string & str)
return simplecpp::characterLiteralToLL(str); return simplecpp::characterLiteralToLL(str);
try { try {
const biguint ret = std::stoull(str, nullptr, 10); std::size_t idx = 0;
const biguint ret = std::stoull(str, &idx, 10);
if (idx != str.size()) {
const std::string s = str.substr(idx);
if (s.find_first_not_of("LlUu") != std::string::npos && s != "i64" && s != "ui64")
throw InternalError(nullptr, "Internal Error. MathLib::toLongNumber: input was not completely consumed: " + str);
}
return ret; return ret;
} catch (const std::out_of_range& e) { } catch (const std::out_of_range& /*e*/) {
throw InternalError(nullptr, "Internal Error. MathLib::toLongNumber: out_of_range: " + str + " (" + e.what() +")"); throw InternalError(nullptr, "Internal Error. MathLib::toLongNumber: out_of_range: " + str);
} catch (const std::invalid_argument& /*e*/) {
throw InternalError(nullptr, "Internal Error. MathLib::toLongNumber: invalid_argument: " + str);
} }
} }
@ -463,7 +492,7 @@ double MathLib::toDoubleNumber(const std::string &str)
try { try {
return simplecpp::characterLiteralToLL(str); return simplecpp::characterLiteralToLL(str);
} catch (const std::exception& e) { } catch (const std::exception& e) {
throw InternalError(nullptr, "Internal Error. MathLib::toLongNumber: characterLiteralToLL(" + str + ") => " + e.what()); throw InternalError(nullptr, "Internal Error. MathLib::toDoubleNumber: characterLiteralToLL(" + str + ") => " + e.what());
} }
} }
if (isIntHex(str)) if (isIntHex(str))
@ -479,7 +508,13 @@ double MathLib::toDoubleNumber(const std::string &str)
std::istringstream istr(str); std::istringstream istr(str);
istr.imbue(std::locale::classic()); istr.imbue(std::locale::classic());
double ret; double ret;
istr >> ret; if (!(istr >> ret))
throw InternalError(nullptr, "Internal Error. MathLib::toDoubleNumber: conversion failed: " + str);
std::string s;
if (istr >> s) {
if (s.find_first_not_of("FfLl") != std::string::npos)
throw InternalError(nullptr, "Internal Error. MathLib::toDoubleNumber: input was not completely consumed: " + str);
}
return ret; return ret;
} }
@ -488,11 +523,12 @@ template<> std::string MathLib::toString<double>(double value)
std::ostringstream result; std::ostringstream result;
result.precision(12); result.precision(12);
result << value; result << value;
if (result.str() == "-0") std::string s = result.str();
if (s == "-0")
return "0.0"; return "0.0";
if (result.str().find('.') == std::string::npos) if (s.find_first_of(".e") == std::string::npos)
return result.str() + ".0"; return s + ".0";
return result.str(); return s;
} }
bool MathLib::isFloat(const std::string &str) bool MathLib::isFloat(const std::string &str)

View File

@ -54,6 +54,7 @@ private:
TEST_CASE(calculate1); TEST_CASE(calculate1);
TEST_CASE(typesuffix); TEST_CASE(typesuffix);
TEST_CASE(toLongNumber); TEST_CASE(toLongNumber);
TEST_CASE(toULongNumber);
TEST_CASE(toDoubleNumber); TEST_CASE(toDoubleNumber);
TEST_CASE(naninf); TEST_CASE(naninf);
TEST_CASE(isNullValue); TEST_CASE(isNullValue);
@ -145,13 +146,13 @@ private:
ASSERT_EQUALS("5.0", MathLib::divide("25.5", "5.1")); ASSERT_EQUALS("5.0", MathLib::divide("25.5", "5.1"));
ASSERT_EQUALS("7.0", MathLib::divide("21.", "3")); ASSERT_EQUALS("7.0", MathLib::divide("21.", "3"));
ASSERT_EQUALS("1", MathLib::divide("3", "2")); ASSERT_EQUALS("1", MathLib::divide("3", "2"));
ASSERT_THROW(MathLib::divide("123", "0"), InternalError); // decimal zero: throw ASSERT_THROW_EQUALS(MathLib::divide("123", "0"), InternalError, "Internal Error: Division by zero"); // decimal zero: throw
ASSERT_THROW(MathLib::divide("123", "00"), InternalError); // octal zero: throw ASSERT_THROW_EQUALS(MathLib::divide("123", "00"), InternalError, "Internal Error: Division by zero"); // octal zero: throw
ASSERT_THROW(MathLib::divide("123", "0x0"), InternalError); // hex zero: throw ASSERT_THROW_EQUALS(MathLib::divide("123", "0x0"), InternalError, "Internal Error: Division by zero"); // hex zero: throw
MathLib::divide("123", "0.0f"); // float zero: don't throw MathLib::divide("123", "0.0f"); // float zero: don't throw
MathLib::divide("123", "0.0"); // double zero: don't throw MathLib::divide("123", "0.0"); // double zero: don't throw
MathLib::divide("123", "0.0L"); // long double zero: don't throw MathLib::divide("123", "0.0L"); // long double zero: don't throw
ASSERT_THROW(MathLib::divide("-9223372036854775808", "-1"), InternalError); // #4520 - out of range => throw ASSERT_THROW_EQUALS(MathLib::divide("-9223372036854775808", "-1"), InternalError, "Internal Error: Division overflow"); // #4520 - out of range => throw
ASSERT_EQUALS("4611686018427387904", MathLib::divide("-9223372036854775808", "-2")); // #6679 ASSERT_EQUALS("4611686018427387904", MathLib::divide("-9223372036854775808", "-2")); // #6679
@ -166,7 +167,7 @@ private:
ASSERT_EQUALS("1", MathLib::calculate("0", "1", '^')); ASSERT_EQUALS("1", MathLib::calculate("0", "1", '^'));
// Unknown action should throw exception // Unknown action should throw exception
ASSERT_THROW(MathLib::calculate("1","2",'j'),InternalError); ASSERT_THROW_EQUALS(MathLib::calculate("1","2",'j'),InternalError, "Unexpected action 'j' in MathLib::calculate(). Please report this to Cppcheck developers.");
} }
void calculate1() const { void calculate1() const {
@ -183,7 +184,7 @@ private:
MathLib::calculate("123", "0.0", '%'); // don't throw MathLib::calculate("123", "0.0", '%'); // don't throw
#endif #endif
ASSERT_THROW(MathLib::calculate("123", "0", '%'), InternalError); // throw ASSERT_THROW_EQUALS(MathLib::calculate("123", "0", '%'), InternalError, "Internal Error: Division by zero"); // throw
ASSERT_EQUALS("0", MathLib::calculate("1", "1", '^')); ASSERT_EQUALS("0", MathLib::calculate("1", "1", '^'));
ASSERT_EQUALS("3", MathLib::calculate("2", "1", '^')); ASSERT_EQUALS("3", MathLib::calculate("2", "1", '^'));
@ -250,6 +251,33 @@ private:
} }
void toLongNumber() const { void toLongNumber() const {
// zero input
ASSERT_EQUALS(0, MathLib::toLongNumber("0"));
ASSERT_EQUALS(0, MathLib::toLongNumber("-0"));
ASSERT_EQUALS(0, MathLib::toLongNumber("+0"));
ASSERT_EQUALS(0, MathLib::toLongNumber("0L"));
ASSERT_EQUALS(0, MathLib::toLongNumber("0l"));
ASSERT_EQUALS(0, MathLib::toLongNumber("0LL"));
ASSERT_EQUALS(0, MathLib::toLongNumber("0ll"));
ASSERT_EQUALS(0, MathLib::toLongNumber("0U"));
ASSERT_EQUALS(0, MathLib::toLongNumber("0u"));
ASSERT_EQUALS(0, MathLib::toLongNumber("0UL"));
ASSERT_EQUALS(0, MathLib::toLongNumber("0ul"));
ASSERT_EQUALS(0, MathLib::toLongNumber("0ULL"));
ASSERT_EQUALS(0, MathLib::toLongNumber("0ull"));
ASSERT_EQUALS(0, MathLib::toLongNumber("0i64")); // Visual Studio-specific
ASSERT_EQUALS(0, MathLib::toLongNumber("0ui64")); // Visual Studio-specific
// TODO: needs to fail
//ASSERT_EQUALS(0, MathLib::toLongNumber("0lll"));
//ASSERT_EQUALS(0, MathLib::toLongNumber("0uu"));
ASSERT_EQUALS(1U, MathLib::toLongNumber("1U"));
ASSERT_EQUALS(10000U, MathLib::toLongNumber("1e4"));
ASSERT_EQUALS(10000U, MathLib::toLongNumber("1e4"));
ASSERT_EQUALS(0xFF00000000000000UL, MathLib::toLongNumber("0xFF00000000000000UL"));
ASSERT_EQUALS(0x0A00000000000000UL, MathLib::toLongNumber("0x0A00000000000000UL"));
// from hex // from hex
ASSERT_EQUALS(0, MathLib::toLongNumber("0x0")); ASSERT_EQUALS(0, MathLib::toLongNumber("0x0"));
ASSERT_EQUALS(0, MathLib::toLongNumber("-0x0")); ASSERT_EQUALS(0, MathLib::toLongNumber("-0x0"));
@ -279,6 +307,8 @@ private:
ASSERT_EQUALS(1, MathLib::toLongNumber("0b1LLU")); ASSERT_EQUALS(1, MathLib::toLongNumber("0b1LLU"));
ASSERT_EQUALS(1, MathLib::toLongNumber("+0b1")); ASSERT_EQUALS(1, MathLib::toLongNumber("+0b1"));
ASSERT_EQUALS(-1, MathLib::toLongNumber("-0b1")); ASSERT_EQUALS(-1, MathLib::toLongNumber("-0b1"));
ASSERT_EQUALS(9U, MathLib::toLongNumber("011"));
ASSERT_EQUALS(5U, MathLib::toLongNumber("0b101"));
ASSERT_EQUALS(215, MathLib::toLongNumber("0b11010111")); ASSERT_EQUALS(215, MathLib::toLongNumber("0b11010111"));
ASSERT_EQUALS(-215, MathLib::toLongNumber("-0b11010111")); ASSERT_EQUALS(-215, MathLib::toLongNumber("-0b11010111"));
ASSERT_EQUALS(215, MathLib::toLongNumber("0B11010111")); ASSERT_EQUALS(215, MathLib::toLongNumber("0B11010111"));
@ -305,30 +335,6 @@ private:
ASSERT_EQUALS(-8552249625308161526, MathLib::toLongNumber("0x89504e470d0a1a0a")); ASSERT_EQUALS(-8552249625308161526, MathLib::toLongNumber("0x89504e470d0a1a0a"));
ASSERT_EQUALS(-8481036456200365558, MathLib::toLongNumber("0x8a4d4e470d0a1a0a")); ASSERT_EQUALS(-8481036456200365558, MathLib::toLongNumber("0x8a4d4e470d0a1a0a"));
ASSERT_EQUALS(9894494448401390090ULL, MathLib::toULongNumber("0x89504e470d0a1a0a"));
ASSERT_EQUALS(9965707617509186058ULL, MathLib::toULongNumber("0x8a4d4e470d0a1a0a"));
// zero input
ASSERT_EQUALS(0, MathLib::toULongNumber("0"));
ASSERT_EQUALS(0, MathLib::toULongNumber("-0"));
ASSERT_EQUALS(0, MathLib::toULongNumber("+0"));
ASSERT_EQUALS(0U, MathLib::toULongNumber("0U"));
ASSERT_EQUALS(0, MathLib::toULongNumber("-0x0"));
ASSERT_EQUALS(1U, MathLib::toULongNumber("1U"));
ASSERT_EQUALS(10000U, MathLib::toULongNumber("1e4"));
ASSERT_EQUALS(10000U, MathLib::toULongNumber("1e4"));
ASSERT_EQUALS(0xFF00000000000000UL, MathLib::toULongNumber("0xFF00000000000000UL"));
ASSERT_EQUALS(0x0A00000000000000UL, MathLib::toULongNumber("0x0A00000000000000UL"));
ASSERT_EQUALS(0, MathLib::toULongNumber("0b0"));
ASSERT_EQUALS(1, MathLib::toULongNumber("0b1"));
ASSERT_EQUALS(1, MathLib::toULongNumber("0b1U"));
ASSERT_EQUALS(1, MathLib::toULongNumber("0b1L"));
ASSERT_EQUALS(1, MathLib::toULongNumber("0b1LU"));
ASSERT_EQUALS(1, MathLib::toULongNumber("0b1LL"));
ASSERT_EQUALS(1, MathLib::toULongNumber("0b1LLU"));
ASSERT_EQUALS(9U, MathLib::toULongNumber("011"));
ASSERT_EQUALS(5U, MathLib::toULongNumber("0b101"));
// from long long // from long long
/* /*
@ -345,37 +351,20 @@ private:
ASSERT_EQUALS(std::numeric_limits<unsigned long long>::min(), MathLib::toLongNumber(std::to_string(std::numeric_limits<unsigned long long>::min()))); ASSERT_EQUALS(std::numeric_limits<unsigned long long>::min(), MathLib::toLongNumber(std::to_string(std::numeric_limits<unsigned long long>::min())));
ASSERT_EQUALS(std::numeric_limits<unsigned long long>::max(), MathLib::toLongNumber(std::to_string(std::numeric_limits<unsigned long long>::max()))); ASSERT_EQUALS(std::numeric_limits<unsigned long long>::max(), MathLib::toLongNumber(std::to_string(std::numeric_limits<unsigned long long>::max())));
ASSERT_EQUALS(std::numeric_limits<long long>::min(), MathLib::toULongNumber(std::to_string(std::numeric_limits<long long>::min())));
ASSERT_EQUALS(std::numeric_limits<long long>::max(), MathLib::toULongNumber(std::to_string(std::numeric_limits<long long>::max())));
ASSERT_EQUALS(std::numeric_limits<unsigned long long>::min(), MathLib::toULongNumber(std::to_string(std::numeric_limits<unsigned long long>::min())));
ASSERT_EQUALS(std::numeric_limits<unsigned long long>::max(), MathLib::toULongNumber(std::to_string(std::numeric_limits<unsigned long long>::max())));
// min/max and out-of-bounds - hex // min/max and out-of-bounds - hex
{ {
const MathLib::bigint i = 0xFFFFFFFFFFFFFFFF; const MathLib::bigint i = 0xFFFFFFFFFFFFFFFF;
ASSERT_EQUALS(i, MathLib::toLongNumber(std::to_string(i))); ASSERT_EQUALS(i, MathLib::toLongNumber(std::to_string(i)));
ASSERT_EQUALS(i, MathLib::toLongNumber("0xFFFFFFFFFFFFFFFF")); ASSERT_EQUALS(i, MathLib::toLongNumber("0xFFFFFFFFFFFFFFFF"));
} }
{
const MathLib::biguint u = 0xFFFFFFFFFFFFFFFF;
ASSERT_EQUALS(u, MathLib::toULongNumber(std::to_string(u)));
ASSERT_EQUALS(u, MathLib::toULongNumber("0xFFFFFFFFFFFFFFFF"));
}
{ {
const MathLib::bigint i = -0xFFFFFFFFFFFFFFFF; const MathLib::bigint i = -0xFFFFFFFFFFFFFFFF;
ASSERT_EQUALS(i, MathLib::toLongNumber(std::to_string(i))); ASSERT_EQUALS(i, MathLib::toLongNumber(std::to_string(i)));
ASSERT_EQUALS(i, MathLib::toLongNumber("-0xFFFFFFFFFFFFFFFF")); ASSERT_EQUALS(i, MathLib::toLongNumber("-0xFFFFFFFFFFFFFFFF"));
} }
{
const MathLib::biguint u = -0xFFFFFFFFFFFFFFFF;
ASSERT_EQUALS(u, MathLib::toULongNumber(std::to_string(u)));
ASSERT_EQUALS(u, MathLib::toULongNumber("-0xFFFFFFFFFFFFFFFF"));
}
ASSERT_THROW(MathLib::toLongNumber("0x10000000000000000"), InternalError); ASSERT_THROW_EQUALS(MathLib::toLongNumber("0x10000000000000000"), InternalError, "Internal Error. MathLib::toLongNumber: out_of_range: 0x10000000000000000");
ASSERT_THROW(MathLib::toULongNumber("0x10000000000000000"), InternalError); ASSERT_THROW_EQUALS(MathLib::toLongNumber("-0x10000000000000000"), InternalError, "Internal Error. MathLib::toLongNumber: out_of_range: -0x10000000000000000");
ASSERT_THROW(MathLib::toLongNumber("-0x10000000000000000"), InternalError);
ASSERT_THROW(MathLib::toULongNumber("-0x10000000000000000"), InternalError);
// min/max and out-of-bounds - octal // min/max and out-of-bounds - octal
{ {
@ -383,26 +372,14 @@ private:
ASSERT_EQUALS(i, MathLib::toLongNumber(std::to_string(i))); ASSERT_EQUALS(i, MathLib::toLongNumber(std::to_string(i)));
ASSERT_EQUALS(i, MathLib::toLongNumber("01777777777777777777777")); ASSERT_EQUALS(i, MathLib::toLongNumber("01777777777777777777777"));
} }
{
const MathLib::biguint u = 01777777777777777777777;
ASSERT_EQUALS(u, MathLib::toULongNumber(std::to_string(u)));
ASSERT_EQUALS(u, MathLib::toULongNumber("01777777777777777777777"));
}
{ {
const MathLib::bigint i = -01777777777777777777777; const MathLib::bigint i = -01777777777777777777777;
ASSERT_EQUALS(i, MathLib::toLongNumber(std::to_string(i))); ASSERT_EQUALS(i, MathLib::toLongNumber(std::to_string(i)));
ASSERT_EQUALS(i, MathLib::toLongNumber("-01777777777777777777777")); ASSERT_EQUALS(i, MathLib::toLongNumber("-01777777777777777777777"));
} }
{
const MathLib::biguint u = -01777777777777777777777;
ASSERT_EQUALS(u, MathLib::toULongNumber(std::to_string(u)));
ASSERT_EQUALS(u, MathLib::toULongNumber("-01777777777777777777777"));
}
ASSERT_THROW(MathLib::toLongNumber("02000000000000000000000"), InternalError); ASSERT_THROW_EQUALS(MathLib::toLongNumber("02000000000000000000000"), InternalError, "Internal Error. MathLib::toLongNumber: out_of_range: 02000000000000000000000");
ASSERT_THROW(MathLib::toULongNumber("02000000000000000000000"), InternalError); ASSERT_THROW_EQUALS(MathLib::toLongNumber("-02000000000000000000000"), InternalError, "Internal Error. MathLib::toLongNumber: out_of_range: -02000000000000000000000");
ASSERT_THROW(MathLib::toLongNumber("-02000000000000000000000"), InternalError);
ASSERT_THROW(MathLib::toULongNumber("-02000000000000000000000"), InternalError);
// min/max and out-of-bounds - decimal // min/max and out-of-bounds - decimal
{ {
@ -410,26 +387,176 @@ private:
ASSERT_EQUALS(i, MathLib::toLongNumber(std::to_string(i))); ASSERT_EQUALS(i, MathLib::toLongNumber(std::to_string(i)));
ASSERT_EQUALS(i, MathLib::toLongNumber("18446744073709551615")); ASSERT_EQUALS(i, MathLib::toLongNumber("18446744073709551615"));
} }
{
const MathLib::biguint u = 18446744073709551615;
ASSERT_EQUALS(u, MathLib::toULongNumber(std::to_string(u)));
ASSERT_EQUALS(u, MathLib::toULongNumber("18446744073709551615"));
}
{ {
const MathLib::bigint i = -18446744073709551615; const MathLib::bigint i = -18446744073709551615;
ASSERT_EQUALS(i, MathLib::toLongNumber(std::to_string(i))); ASSERT_EQUALS(i, MathLib::toLongNumber(std::to_string(i)));
ASSERT_EQUALS(i, MathLib::toLongNumber("-18446744073709551615")); ASSERT_EQUALS(i, MathLib::toLongNumber("-18446744073709551615"));
} }
ASSERT_THROW_EQUALS(MathLib::toLongNumber("18446744073709551616"), InternalError, "Internal Error. MathLib::toLongNumber: out_of_range: 18446744073709551616");
ASSERT_THROW_EQUALS(MathLib::toLongNumber("-18446744073709551616"), InternalError, "Internal Error. MathLib::toLongNumber: out_of_range: -18446744073709551616");
ASSERT_THROW_EQUALS(MathLib::toLongNumber("invalid"), InternalError, "Internal Error. MathLib::toLongNumber: invalid_argument: invalid");
ASSERT_THROW_EQUALS(MathLib::toLongNumber("1invalid"), InternalError, "Internal Error. MathLib::toLongNumber: input was not completely consumed: 1invalid");
ASSERT_THROW_EQUALS(MathLib::toLongNumber("1 invalid"), InternalError, "Internal Error. MathLib::toLongNumber: input was not completely consumed: 1 invalid");
// TODO: test binary
// TODO: test floating point
// TODO: test with 128-bit values
}
void toULongNumber() const {
// zero input
ASSERT_EQUALS(0, MathLib::toULongNumber("0"));
ASSERT_EQUALS(0, MathLib::toULongNumber("-0"));
ASSERT_EQUALS(0, MathLib::toULongNumber("+0"));
ASSERT_EQUALS(0, MathLib::toULongNumber("0L"));
ASSERT_EQUALS(0, MathLib::toULongNumber("0l"));
ASSERT_EQUALS(0, MathLib::toULongNumber("0LL"));
ASSERT_EQUALS(0, MathLib::toULongNumber("0ll"));
ASSERT_EQUALS(0, MathLib::toULongNumber("0U"));
ASSERT_EQUALS(0, MathLib::toULongNumber("0u"));
ASSERT_EQUALS(0, MathLib::toULongNumber("0UL"));
ASSERT_EQUALS(0, MathLib::toULongNumber("0ul"));
ASSERT_EQUALS(0, MathLib::toULongNumber("0ULL"));
ASSERT_EQUALS(0, MathLib::toULongNumber("0ull"));
ASSERT_EQUALS(0, MathLib::toULongNumber("0i64")); // Visual Studio-specific
ASSERT_EQUALS(0, MathLib::toULongNumber("0ui64")); // Visual Studio-specific
// TODO: needs to fail
//ASSERT_EQUALS(0, MathLib::toULongNumber("0lll"));
//ASSERT_EQUALS(0, MathLib::toULongNumber("0uu"));
ASSERT_EQUALS(1U, MathLib::toULongNumber("1U"));
ASSERT_EQUALS(10000U, MathLib::toULongNumber("1e4"));
ASSERT_EQUALS(10000U, MathLib::toULongNumber("1e4"));
ASSERT_EQUALS(0xFF00000000000000UL, MathLib::toULongNumber("0xFF00000000000000UL"));
ASSERT_EQUALS(0x0A00000000000000UL, MathLib::toULongNumber("0x0A00000000000000UL"));
// from hex
ASSERT_EQUALS(0, MathLib::toULongNumber("0x0"));
ASSERT_EQUALS(0, MathLib::toULongNumber("-0x0"));
ASSERT_EQUALS(0, MathLib::toULongNumber("+0x0"));
ASSERT_EQUALS(10, MathLib::toULongNumber("0xa"));
ASSERT_EQUALS(10995, MathLib::toULongNumber("0x2AF3"));
ASSERT_EQUALS(-10, MathLib::toULongNumber("-0xa"));
ASSERT_EQUALS(-10995, MathLib::toULongNumber("-0x2AF3"));
ASSERT_EQUALS(10, MathLib::toULongNumber("+0xa"));
ASSERT_EQUALS(10995, MathLib::toULongNumber("+0x2AF3"));
// from octal
ASSERT_EQUALS(8, MathLib::toULongNumber("010"));
ASSERT_EQUALS(8, MathLib::toULongNumber("+010"));
ASSERT_EQUALS(-8, MathLib::toULongNumber("-010"));
ASSERT_EQUALS(125, MathLib::toULongNumber("0175"));
ASSERT_EQUALS(125, MathLib::toULongNumber("+0175"));
ASSERT_EQUALS(-125, MathLib::toULongNumber("-0175"));
// from binary
ASSERT_EQUALS(0, MathLib::toULongNumber("0b0"));
ASSERT_EQUALS(1, MathLib::toULongNumber("0b1"));
ASSERT_EQUALS(1, MathLib::toULongNumber("0b1U"));
ASSERT_EQUALS(1, MathLib::toULongNumber("0b1L"));
ASSERT_EQUALS(1, MathLib::toULongNumber("0b1LU"));
ASSERT_EQUALS(1, MathLib::toULongNumber("0b1LL"));
ASSERT_EQUALS(1, MathLib::toULongNumber("0b1LLU"));
ASSERT_EQUALS(1, MathLib::toULongNumber("+0b1"));
ASSERT_EQUALS(-1, MathLib::toULongNumber("-0b1"));
ASSERT_EQUALS(9U, MathLib::toULongNumber("011"));
ASSERT_EQUALS(5U, MathLib::toULongNumber("0b101"));
ASSERT_EQUALS(215, MathLib::toULongNumber("0b11010111"));
ASSERT_EQUALS(-215, MathLib::toULongNumber("-0b11010111"));
ASSERT_EQUALS(215, MathLib::toULongNumber("0B11010111"));
// from base 10
ASSERT_EQUALS(10, MathLib::toULongNumber("10"));
ASSERT_EQUALS(10, MathLib::toULongNumber("10."));
ASSERT_EQUALS(10, MathLib::toULongNumber("10.0"));
ASSERT_EQUALS(100, MathLib::toULongNumber("10E+1"));
ASSERT_EQUALS(1, MathLib::toULongNumber("10E-1"));
ASSERT_EQUALS(100, MathLib::toULongNumber("+10E+1"));
ASSERT_EQUALS(-1, MathLib::toULongNumber("-10E-1"));
ASSERT_EQUALS(100, MathLib::toULongNumber("+10.E+1"));
ASSERT_EQUALS(-1, MathLib::toULongNumber("-10.E-1"));
ASSERT_EQUALS(100, MathLib::toULongNumber("+10.0E+1"));
ASSERT_EQUALS(-1, MathLib::toULongNumber("-10.0E-1"));
// from char
ASSERT_EQUALS((int)('A'), MathLib::toULongNumber("'A'"));
ASSERT_EQUALS((int)('\x10'), MathLib::toULongNumber("'\\x10'"));
ASSERT_EQUALS((int)('\100'), MathLib::toULongNumber("'\\100'"));
ASSERT_EQUALS((int)('\200'), MathLib::toULongNumber("'\\200'"));
ASSERT_EQUALS((int)(L'A'), MathLib::toULongNumber("L'A'"));
ASSERT_EQUALS(9894494448401390090ULL, MathLib::toULongNumber("0x89504e470d0a1a0a"));
ASSERT_EQUALS(9965707617509186058ULL, MathLib::toULongNumber("0x8a4d4e470d0a1a0a"));
// from long long
/*
* ASSERT_EQUALS(0xFF00000000000000LL, MathLib::toULongNumber("0xFF00000000000000LL"));
* This does not work in a portable way!
* While it succeeds on 32bit Visual Studio it fails on Linux 64bit because it is greater than 0x7FFFFFFFFFFFFFFF (=LLONG_MAX)
*/
ASSERT_EQUALS(0x0A00000000000000LL, MathLib::toULongNumber("0x0A00000000000000LL"));
// min/max numeric limits
ASSERT_EQUALS(std::numeric_limits<long long>::min(), MathLib::toULongNumber(std::to_string(std::numeric_limits<long long>::min())));
ASSERT_EQUALS(std::numeric_limits<long long>::max(), MathLib::toULongNumber(std::to_string(std::numeric_limits<long long>::max())));
ASSERT_EQUALS(std::numeric_limits<unsigned long long>::min(), MathLib::toULongNumber(std::to_string(std::numeric_limits<unsigned long long>::min())));
ASSERT_EQUALS(std::numeric_limits<unsigned long long>::max(), MathLib::toULongNumber(std::to_string(std::numeric_limits<unsigned long long>::max())));
// min/max and out-of-bounds - hex
{
const MathLib::biguint u = 0xFFFFFFFFFFFFFFFF;
ASSERT_EQUALS(u, MathLib::toULongNumber(std::to_string(u)));
ASSERT_EQUALS(u, MathLib::toULongNumber("0xFFFFFFFFFFFFFFFF"));
}
{
const MathLib::biguint u = -0xFFFFFFFFFFFFFFFF;
ASSERT_EQUALS(u, MathLib::toULongNumber(std::to_string(u)));
ASSERT_EQUALS(u, MathLib::toULongNumber("-0xFFFFFFFFFFFFFFFF"));
}
ASSERT_THROW_EQUALS(MathLib::toULongNumber("0x10000000000000000"), InternalError, "Internal Error. MathLib::toULongNumber: out_of_range: 0x10000000000000000");
ASSERT_THROW_EQUALS(MathLib::toULongNumber("-0x10000000000000000"), InternalError, "Internal Error. MathLib::toULongNumber: out_of_range: -0x10000000000000000");
// min/max and out-of-bounds - octal
{
const MathLib::biguint u = 01777777777777777777777;
ASSERT_EQUALS(u, MathLib::toULongNumber(std::to_string(u)));
ASSERT_EQUALS(u, MathLib::toULongNumber("01777777777777777777777"));
}
{
const MathLib::biguint u = -01777777777777777777777;
ASSERT_EQUALS(u, MathLib::toULongNumber(std::to_string(u)));
ASSERT_EQUALS(u, MathLib::toULongNumber("-01777777777777777777777"));
}
ASSERT_THROW_EQUALS(MathLib::toULongNumber("02000000000000000000000"), InternalError, "Internal Error. MathLib::toULongNumber: out_of_range: 02000000000000000000000");
ASSERT_THROW_EQUALS(MathLib::toULongNumber("-02000000000000000000000"), InternalError, "Internal Error. MathLib::toULongNumber: out_of_range: -02000000000000000000000");
// min/max and out-of-bounds - decimal
{
const MathLib::biguint u = 18446744073709551615;
ASSERT_EQUALS(u, MathLib::toULongNumber(std::to_string(u)));
ASSERT_EQUALS(u, MathLib::toULongNumber("18446744073709551615"));
}
{ {
const MathLib::biguint u = -18446744073709551615; const MathLib::biguint u = -18446744073709551615;
ASSERT_EQUALS(u, MathLib::toULongNumber(std::to_string(u))); ASSERT_EQUALS(u, MathLib::toULongNumber(std::to_string(u)));
ASSERT_EQUALS(u, MathLib::toULongNumber("-18446744073709551615")); ASSERT_EQUALS(u, MathLib::toULongNumber("-18446744073709551615"));
} }
ASSERT_THROW(MathLib::toLongNumber("18446744073709551616"), InternalError); ASSERT_THROW_EQUALS(MathLib::toULongNumber("18446744073709551616"), InternalError, "Internal Error. MathLib::toULongNumber: out_of_range: 18446744073709551616");
ASSERT_THROW(MathLib::toULongNumber("18446744073709551616"), InternalError); ASSERT_THROW_EQUALS(MathLib::toULongNumber("-18446744073709551616"), InternalError, "Internal Error. MathLib::toULongNumber: out_of_range: -18446744073709551616");
ASSERT_THROW(MathLib::toLongNumber("-18446744073709551616"), InternalError);
ASSERT_THROW(MathLib::toULongNumber("-18446744073709551616"), InternalError); ASSERT_THROW_EQUALS(MathLib::toULongNumber("invalid"), InternalError, "Internal Error. MathLib::toULongNumber: invalid_argument: invalid");
ASSERT_THROW_EQUALS(MathLib::toULongNumber("1invalid"), InternalError, "Internal Error. MathLib::toULongNumber: input was not completely consumed: 1invalid");
ASSERT_THROW_EQUALS(MathLib::toULongNumber("1 invalid"), InternalError, "Internal Error. MathLib::toULongNumber: input was not completely consumed: 1 invalid");
// TODO: test binary // TODO: test binary
// TODO: test floating point // TODO: test floating point
@ -438,10 +565,22 @@ private:
} }
void toDoubleNumber() const { void toDoubleNumber() const {
ASSERT_EQUALS_DOUBLE(1.0, MathLib::toDoubleNumber("1"), 0.001); // float values
ASSERT_EQUALS_DOUBLE(1.0, MathLib::toDoubleNumber("1."), 0.001);
ASSERT_EQUALS_DOUBLE(1.0, MathLib::toDoubleNumber("1.f"), 0.001);
ASSERT_EQUALS_DOUBLE(1.0, MathLib::toDoubleNumber("1.F"), 0.001);
ASSERT_EQUALS_DOUBLE(1.0, MathLib::toDoubleNumber("1.l"), 0.001);
ASSERT_EQUALS_DOUBLE(1.0, MathLib::toDoubleNumber("1.L"), 0.001);
ASSERT_EQUALS_DOUBLE(1.0, MathLib::toDoubleNumber("1.0"), 0.001);
ASSERT_EQUALS_DOUBLE(1.0, MathLib::toDoubleNumber("1.0f"), 0.001);
ASSERT_EQUALS_DOUBLE(1.0, MathLib::toDoubleNumber("1.0F"), 0.001);
ASSERT_EQUALS_DOUBLE(1.0, MathLib::toDoubleNumber("1.0l"), 0.001);
ASSERT_EQUALS_DOUBLE(1.0, MathLib::toDoubleNumber("1.0L"), 0.001);
ASSERT_EQUALS_DOUBLE(1.0, MathLib::toDoubleNumber("0x1"), 0.001); ASSERT_EQUALS_DOUBLE(1.0, MathLib::toDoubleNumber("0x1"), 0.001);
ASSERT_EQUALS_DOUBLE(10.0, MathLib::toDoubleNumber("10"), 0.001); ASSERT_EQUALS_DOUBLE(10.0, MathLib::toDoubleNumber("10"), 0.001);
ASSERT_EQUALS_DOUBLE(1000.0, MathLib::toDoubleNumber("10E+2"), 0.001); ASSERT_EQUALS_DOUBLE(1000.0, MathLib::toDoubleNumber("10E+2"), 0.001);
ASSERT_EQUALS_DOUBLE(1000.0, MathLib::toDoubleNumber("10E+2l"), 0.001);
ASSERT_EQUALS_DOUBLE(1000.0, MathLib::toDoubleNumber("10E+2L"), 0.001);
ASSERT_EQUALS_DOUBLE(100.0, MathLib::toDoubleNumber("1.0E+2"), 0.001); ASSERT_EQUALS_DOUBLE(100.0, MathLib::toDoubleNumber("1.0E+2"), 0.001);
ASSERT_EQUALS_DOUBLE(-100.0, MathLib::toDoubleNumber("-1.0E+2"), 0.001); ASSERT_EQUALS_DOUBLE(-100.0, MathLib::toDoubleNumber("-1.0E+2"), 0.001);
ASSERT_EQUALS_DOUBLE(-1e+10, MathLib::toDoubleNumber("-1.0E+10"), 1); ASSERT_EQUALS_DOUBLE(-1e+10, MathLib::toDoubleNumber("-1.0E+10"), 1);
@ -449,6 +588,34 @@ private:
ASSERT_EQUALS_DOUBLE(1e+10, MathLib::toDoubleNumber("+1.0E+10"), 1); ASSERT_EQUALS_DOUBLE(1e+10, MathLib::toDoubleNumber("+1.0E+10"), 1);
ASSERT_EQUALS_DOUBLE(100.0, MathLib::toDoubleNumber("1.0E+2"), 0.001); ASSERT_EQUALS_DOUBLE(100.0, MathLib::toDoubleNumber("1.0E+2"), 0.001);
ASSERT_EQUALS_DOUBLE(1e+10, MathLib::toDoubleNumber("1.0E+10"), 1); ASSERT_EQUALS_DOUBLE(1e+10, MathLib::toDoubleNumber("1.0E+10"), 1);
// valid non-float values
ASSERT_EQUALS_DOUBLE(1.0, MathLib::toDoubleNumber("1"), 0.001);
ASSERT_EQUALS_DOUBLE(1.0, MathLib::toDoubleNumber("1l"), 0.001);
ASSERT_EQUALS_DOUBLE(1.0, MathLib::toDoubleNumber("1L"), 0.001);
ASSERT_EQUALS_DOUBLE(1.0, MathLib::toDoubleNumber("1ll"), 0.001);
ASSERT_EQUALS_DOUBLE(1.0, MathLib::toDoubleNumber("1LL"), 0.001);
// TODO: need to succeed
//ASSERT_EQUALS_DOUBLE(1.0, MathLib::toDoubleNumber("1u"), 0.001);
//ASSERT_EQUALS_DOUBLE(1.0, MathLib::toDoubleNumber("1U"), 0.001);
//ASSERT_EQUALS_DOUBLE(1.0, MathLib::toDoubleNumber("1ul"), 0.001);
//ASSERT_EQUALS_DOUBLE(1.0, MathLib::toDoubleNumber("1UL"), 0.001);
//ASSERT_EQUALS_DOUBLE(1.0, MathLib::toDoubleNumber("1ULL"), 0.001);
//ASSERT_EQUALS_DOUBLE(1.0, MathLib::toDoubleNumber("1ULL"), 0.001);
// TODO: need to fail
// invalid values
//ASSERT_EQUALS_DOUBLE(1.0, MathLib::toDoubleNumber("1f"), 0.001);
//ASSERT_EQUALS_DOUBLE(1.0, MathLib::toDoubleNumber("1F"), 0.001);
//ASSERT_EQUALS_DOUBLE(1.0, MathLib::toDoubleNumber("1.ff"), 0.001);
//ASSERT_EQUALS_DOUBLE(1.0, MathLib::toDoubleNumber("1.FF"), 0.001);
//ASSERT_EQUALS_DOUBLE(1.0, MathLib::toDoubleNumber("1.ll"), 0.001);
//ASSERT_EQUALS_DOUBLE(1.0, MathLib::toDoubleNumber("1.0LL"), 0.001);
//ASSERT_EQUALS_DOUBLE(1.0, MathLib::toDoubleNumber("1.0ff"), 0.001);
//ASSERT_EQUALS_DOUBLE(1.0, MathLib::toDoubleNumber("1.0FF"), 0.001);
//ASSERT_EQUALS_DOUBLE(1.0, MathLib::toDoubleNumber("1.0ll"), 0.001);
//ASSERT_EQUALS_DOUBLE(1.0, MathLib::toDoubleNumber("1.0LL"), 0.001);
ASSERT_EQUALS_DOUBLE(0.0, MathLib::toDoubleNumber("0E+0"), 0.000001); ASSERT_EQUALS_DOUBLE(0.0, MathLib::toDoubleNumber("0E+0"), 0.000001);
ASSERT_EQUALS_DOUBLE(0.0, MathLib::toDoubleNumber("0E-0"), 0.000001); ASSERT_EQUALS_DOUBLE(0.0, MathLib::toDoubleNumber("0E-0"), 0.000001);
ASSERT_EQUALS_DOUBLE(0.0, MathLib::toDoubleNumber("0E+00"), 0.000001); ASSERT_EQUALS_DOUBLE(0.0, MathLib::toDoubleNumber("0E+00"), 0.000001);
@ -476,6 +643,25 @@ private:
ASSERT_EQUALS_DOUBLE(9.0, MathLib::toDoubleNumber("0x1.2P3"), 0.000001); ASSERT_EQUALS_DOUBLE(9.0, MathLib::toDoubleNumber("0x1.2P3"), 0.000001);
ASSERT_EQUALS_DOUBLE(0.0625, MathLib::toDoubleNumber("0x.1P0"), 0.000001); ASSERT_EQUALS_DOUBLE(0.0625, MathLib::toDoubleNumber("0x.1P0"), 0.000001);
// from char
ASSERT_EQUALS_DOUBLE((double)('A'), MathLib::toDoubleNumber("'A'"), 0.000001);
ASSERT_EQUALS_DOUBLE((double)('\x10'), MathLib::toDoubleNumber("'\\x10'"), 0.000001);
ASSERT_EQUALS_DOUBLE((double)('\100'), MathLib::toDoubleNumber("'\\100'"), 0.000001);
ASSERT_EQUALS_DOUBLE((double)('\200'), MathLib::toDoubleNumber("'\\200'"), 0.000001);
ASSERT_EQUALS_DOUBLE((double)(L'A'), MathLib::toDoubleNumber("L'A'"), 0.000001);
ASSERT_THROW_EQUALS(MathLib::toDoubleNumber("invalid"), InternalError, "Internal Error. MathLib::toDoubleNumber: conversion failed: invalid");
#ifdef _LIBCPP_VERSION
ASSERT_THROW_EQUALS(MathLib::toDoubleNumber("1invalid"), InternalError, "Internal Error. MathLib::toDoubleNumber: conversion failed: 1invalid");
ASSERT_THROW_EQUALS(MathLib::toDoubleNumber("1.1invalid"), InternalError, "Internal Error. MathLib::toDoubleNumber: conversion failed: 1.1invalid");
#else
ASSERT_THROW_EQUALS(MathLib::toDoubleNumber("1invalid"), InternalError, "Internal Error. MathLib::toDoubleNumber: input was not completely consumed: 1invalid");
ASSERT_THROW_EQUALS(MathLib::toDoubleNumber("1.1invalid"), InternalError, "Internal Error. MathLib::toDoubleNumber: input was not completely consumed: 1.1invalid");
#endif
ASSERT_THROW_EQUALS(MathLib::toDoubleNumber("1 invalid"), InternalError, "Internal Error. MathLib::toDoubleNumber: input was not completely consumed: 1 invalid");
ASSERT_THROW_EQUALS(MathLib::toDoubleNumber("-1e-08.0"), InternalError, "Internal Error. MathLib::toDoubleNumber: input was not completely consumed: -1e-08.0");
// verify: string --> double --> string conversion // verify: string --> double --> string conversion
ASSERT_EQUALS("1.0", MathLib::toString(MathLib::toDoubleNumber("1.0f"))); ASSERT_EQUALS("1.0", MathLib::toString(MathLib::toDoubleNumber("1.0f")));
ASSERT_EQUALS("1.0", MathLib::toString(MathLib::toDoubleNumber("1.0"))); ASSERT_EQUALS("1.0", MathLib::toString(MathLib::toDoubleNumber("1.0")));
@ -1230,6 +1416,9 @@ private:
ASSERT_EQUALS("0.000000", MathLib::toString(0.0L)); ASSERT_EQUALS("0.000000", MathLib::toString(0.0L));
ASSERT_EQUALS("0.000000", MathLib::toString(+0.0L)); ASSERT_EQUALS("0.000000", MathLib::toString(+0.0L));
ASSERT_EQUALS("-0.000000", MathLib::toString(-0.0L)); ASSERT_EQUALS("-0.000000", MathLib::toString(-0.0L));
ASSERT_EQUALS("1e-08", MathLib::toString(0.00000001));
ASSERT_EQUALS("-1e-08", MathLib::toString(-0.00000001));
} }
void CPP14DigitSeparators() const { // Ticket #7137, #7565 void CPP14DigitSeparators() const { // Ticket #7137, #7565