diff --git a/lib/mathlib.cpp b/lib/mathlib.cpp index bb0fb1147..3fd336702 100644 --- a/lib/mathlib.cpp +++ b/lib/mathlib.cpp @@ -598,13 +598,107 @@ bool MathLib::isLessEqual(const std::string &first, const std::string &second) return toDoubleNumber(first) <= toDoubleNumber(second); } -bool MathLib::isNullValue(const std::string &str) +bool MathLib::isNullValue(const std::string &s) { - for (size_t i = 0; i < str.size(); i++) { - if (std::isdigit(static_cast(str[i])) && str[i] != '0') // May not contain digits other than 0 + enum {START, PLUSMINUS, LEADING_ZERO, BIN_OR_HEX_PREFIX, DOT, TRAILING_ZERO, TRAILING_F, ZERO, E, E_PLUSMINUS, E_DIGIT} state = START; + for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) { + switch (state) { + case START: + if (*it == '+' || *it == '-') + state = PLUSMINUS; + else if (*it == '0') + state = LEADING_ZERO; + else if (*it == '.') + state = DOT; + else + return isValidSuffix(it, s.end()); + break; + case PLUSMINUS: + if (*it == '0') + state = LEADING_ZERO; + else + return false; + break; + case LEADING_ZERO: + if (*it == '0') + state = LEADING_ZERO; + else if (*it == 'b' || *it == 'B') + state = BIN_OR_HEX_PREFIX; + else if (*it == 'x' || *it == 'X') + state = BIN_OR_HEX_PREFIX; + else if (*it == '.') + state = DOT; + else if (*it == 'e' || *it == 'E') + state = E; + else + return isValidSuffix(it, s.end()); + break; + case BIN_OR_HEX_PREFIX: + if (*it == '0') + state = ZERO; + else + return false; + break; + case ZERO: + if (*it == '0') + state = ZERO; + else + return isValidSuffix(it, s.end()); + break; + case DOT: + if (*it == '0') + state = TRAILING_ZERO; + else if (*it == 'f' || *it == 'F') + state = TRAILING_F; + else if (*it == 'e' || *it == 'E') + state = E; + else + return false; + break; + case E: + if (*it == '+' || *it == '-') + state = E_PLUSMINUS; + else if (isdigit(*it)) + state = E_DIGIT; + else + return false; + break; + case E_PLUSMINUS: + if (isdigit(*it)) + state = E_DIGIT; + else + return false; + break; + case E_DIGIT: + if (isdigit(*it)) + state = E_DIGIT; + else if (*it == 'f' || *it == 'F') + state = TRAILING_F; + else + return false; + break; + case TRAILING_ZERO: + if (*it == '0') + state = TRAILING_ZERO; + else if (*it == 'f' || *it == 'F') + state = TRAILING_F; + else if (*it == 'e' || *it == 'E') + state = E; + else + return false; + break; + default: return false; + } } - return !str.empty() && (std::isdigit(static_cast(str[0])) || str[0] == '-' || str[0] == '+'); // Has to be a number + return state == LEADING_ZERO || state == ZERO || state == DOT || state == E_DIGIT || state == TRAILING_ZERO || state == TRAILING_F; + /* + for (size_t i = 0; i < str.size(); i++) { + if (std::isdigit(static_cast(str[i])) && str[i] != '0') // May not contain digits other than 0 + return false; + } + return !str.empty() && (std::isdigit(static_cast(str[0])) || str[0] == '-' || str[0] == '+'); // Has to be a number + */ } bool MathLib::isOctalDigit(char c) diff --git a/test/testmathlib.cpp b/test/testmathlib.cpp index 60175cc04..0bb102895 100644 --- a/test/testmathlib.cpp +++ b/test/testmathlib.cpp @@ -45,7 +45,8 @@ private: TEST_CASE(calculate); TEST_CASE(calculate1); TEST_CASE(convert); - TEST_CASE(naninf) + TEST_CASE(naninf); + TEST_CASE(isNullValue); } void isGreater() const { @@ -601,6 +602,169 @@ private: ASSERT_EQUALS("inf.0", MathLib::divide("3.0", "0.0")); // inf ASSERT_EQUALS("-inf.0", MathLib::divide("-3.0", "0.0")); // -inf (#5142) } + + void isNullValue() const { + // inter zero value + ASSERT_EQUALS(true, MathLib::isNullValue("0")); + ASSERT_EQUALS(true, MathLib::isNullValue("+0")); + ASSERT_EQUALS(true, MathLib::isNullValue("-0")); + // inter zero value (octal) + ASSERT_EQUALS(true, MathLib::isNullValue("00")); + ASSERT_EQUALS(true, MathLib::isNullValue("+00")); + ASSERT_EQUALS(true, MathLib::isNullValue("-00")); + // inter zero value (hex) + ASSERT_EQUALS(true, MathLib::isNullValue("0x0")); + ASSERT_EQUALS(true, MathLib::isNullValue("+0x0")); + ASSERT_EQUALS(true, MathLib::isNullValue("-0x0")); + // unsigned integer zero value + ASSERT_EQUALS(true, MathLib::isNullValue("0U")); + ASSERT_EQUALS(true, MathLib::isNullValue("+0U")); + ASSERT_EQUALS(true, MathLib::isNullValue("-0U")); + // long integer zero value + ASSERT_EQUALS(true, MathLib::isNullValue("0L")); + ASSERT_EQUALS(true, MathLib::isNullValue("+0L")); + ASSERT_EQUALS(true, MathLib::isNullValue("-0L")); + // unsigned long integer zero value + ASSERT_EQUALS(true, MathLib::isNullValue("0UL")); + ASSERT_EQUALS(true, MathLib::isNullValue("+0UL")); + ASSERT_EQUALS(true, MathLib::isNullValue("-0UL")); + // unsigned long integer zero value + ASSERT_EQUALS(true, MathLib::isNullValue("0LU")); + ASSERT_EQUALS(true, MathLib::isNullValue("+0LU")); + ASSERT_EQUALS(true, MathLib::isNullValue("-0LU")); + // long long integer zero value + ASSERT_EQUALS(true, MathLib::isNullValue("0LL")); + ASSERT_EQUALS(true, MathLib::isNullValue("+0LL")); + ASSERT_EQUALS(true, MathLib::isNullValue("-0LL")); + // long long unsigend zero value + ASSERT_EQUALS(true, MathLib::isNullValue("0LLU")); + ASSERT_EQUALS(true, MathLib::isNullValue("+0LLU")); + ASSERT_EQUALS(true, MathLib::isNullValue("-0LLU")); + // unsigned long long zero value + ASSERT_EQUALS(true, MathLib::isNullValue("0ULL")); + ASSERT_EQUALS(true, MathLib::isNullValue("+0ULL")); + ASSERT_EQUALS(true, MathLib::isNullValue("-0ULL")); + // floating pointer zero value (no trailing zero after dot) + ASSERT_EQUALS(true, MathLib::isNullValue("0.")); + ASSERT_EQUALS(true, MathLib::isNullValue("+0.")); + ASSERT_EQUALS(true, MathLib::isNullValue("-0.")); + // floating pointer zero value (1 trailing zero after dot) + ASSERT_EQUALS(true, MathLib::isNullValue("0.0")); + ASSERT_EQUALS(true, MathLib::isNullValue("+0.0")); + ASSERT_EQUALS(true, MathLib::isNullValue("-0.0")); + // floating pointer zero value (3 trailing zeros after dot) + ASSERT_EQUALS(true, MathLib::isNullValue("0.000")); + ASSERT_EQUALS(true, MathLib::isNullValue("+0.000")); + ASSERT_EQUALS(true, MathLib::isNullValue("-0.000")); + // floating pointer zero value (no trailing zero after dot) + ASSERT_EQUALS(true, MathLib::isNullValue("00.")); + ASSERT_EQUALS(true, MathLib::isNullValue("+00.")); + ASSERT_EQUALS(true, MathLib::isNullValue("-00.")); + // floating pointer zero value (1 trailing zero after dot) + ASSERT_EQUALS(true, MathLib::isNullValue("00.0")); + ASSERT_EQUALS(true, MathLib::isNullValue("+00.0")); + ASSERT_EQUALS(true, MathLib::isNullValue("-00.0")); + // floating pointer zero value (3 trailing zero after dot) + ASSERT_EQUALS(true, MathLib::isNullValue("00.000")); + ASSERT_EQUALS(true, MathLib::isNullValue("+00.000")); + ASSERT_EQUALS(true, MathLib::isNullValue("-00.000")); + // floating pointer zero value (3 trailing zero after dot) + ASSERT_EQUALS(true, MathLib::isNullValue(".000")); + // integer scientific notation + ASSERT_EQUALS(true, MathLib::isNullValue("0E0")); + ASSERT_EQUALS(true, MathLib::isNullValue("+0E0")); + ASSERT_EQUALS(true, MathLib::isNullValue("-0E0")); + // integer scientific notation + ASSERT_EQUALS(true, MathLib::isNullValue("0E1")); + ASSERT_EQUALS(true, MathLib::isNullValue("+0E1")); + ASSERT_EQUALS(true, MathLib::isNullValue("-0E1")); + // integer scientific notation + ASSERT_EQUALS(true, MathLib::isNullValue("0E42")); + ASSERT_EQUALS(true, MathLib::isNullValue("+0E42")); + ASSERT_EQUALS(true, MathLib::isNullValue("-0E42")); + // integer scientific notation + ASSERT_EQUALS(true, MathLib::isNullValue("0E429999")); + ASSERT_EQUALS(true, MathLib::isNullValue("+0E429999")); + ASSERT_EQUALS(true, MathLib::isNullValue("-0E429999")); + // integer scientific notation + ASSERT_EQUALS(true, MathLib::isNullValue("0E+1")); + ASSERT_EQUALS(true, MathLib::isNullValue("+0E+1")); + ASSERT_EQUALS(true, MathLib::isNullValue("-0E+1")); + // integer scientific notation + ASSERT_EQUALS(true, MathLib::isNullValue("0E+42")); + ASSERT_EQUALS(true, MathLib::isNullValue("+0E+42")); + ASSERT_EQUALS(true, MathLib::isNullValue("-0E+42")); + // integer scientific notation + ASSERT_EQUALS(true, MathLib::isNullValue("0E+429999")); + ASSERT_EQUALS(true, MathLib::isNullValue("+0E+429999")); + ASSERT_EQUALS(true, MathLib::isNullValue("-0E+429999")); + // integer scientific notation + ASSERT_EQUALS(true, MathLib::isNullValue("0E-1")); + ASSERT_EQUALS(true, MathLib::isNullValue("+0E-1")); + ASSERT_EQUALS(true, MathLib::isNullValue("-0E-1")); + // integer scientific notation + ASSERT_EQUALS(true, MathLib::isNullValue("0E-42")); + ASSERT_EQUALS(true, MathLib::isNullValue("+0E-42")); + ASSERT_EQUALS(true, MathLib::isNullValue("-0E-42")); + // integer scientific notation + ASSERT_EQUALS(true, MathLib::isNullValue("0E-429999")); + ASSERT_EQUALS(true, MathLib::isNullValue("+0E-429999")); + ASSERT_EQUALS(true, MathLib::isNullValue("-0E-429999")); + // floating point scientific notation + ASSERT_EQUALS(true, MathLib::isNullValue("0.E0")); + ASSERT_EQUALS(true, MathLib::isNullValue("+0.E0")); + ASSERT_EQUALS(true, MathLib::isNullValue("-0.E0")); + // floating point scientific notation + ASSERT_EQUALS(true, MathLib::isNullValue("0.E-0")); + ASSERT_EQUALS(true, MathLib::isNullValue("+0.E-0")); + ASSERT_EQUALS(true, MathLib::isNullValue("-0.E+0")); + // floating point scientific notation + ASSERT_EQUALS(true, MathLib::isNullValue("0.E+0")); + ASSERT_EQUALS(true, MathLib::isNullValue("+0.E+0")); + ASSERT_EQUALS(true, MathLib::isNullValue("-0.E+0")); + // floating point scientific notation + ASSERT_EQUALS(true, MathLib::isNullValue("0.00E-0")); + ASSERT_EQUALS(true, MathLib::isNullValue("+0.00E-0")); + ASSERT_EQUALS(true, MathLib::isNullValue("-0.00E-0")); + // floating point scientific notation + ASSERT_EQUALS(true, MathLib::isNullValue("00000.00E-000000000")); + ASSERT_EQUALS(true, MathLib::isNullValue("+00000.00E-000000000")); + ASSERT_EQUALS(true, MathLib::isNullValue("-00000.00E-000000000")); + // floating point scientific notation (suffix f) + ASSERT_EQUALS(true, MathLib::isNullValue("0.f")); + ASSERT_EQUALS(true, MathLib::isNullValue("+0.f")); + ASSERT_EQUALS(true, MathLib::isNullValue("-0.f")); + // floating point scientific notation (suffix f) + ASSERT_EQUALS(true, MathLib::isNullValue("0.0f")); + ASSERT_EQUALS(true, MathLib::isNullValue("+0.0f")); + ASSERT_EQUALS(true, MathLib::isNullValue("-0.0f")); + // floating point scientific notation (suffix f) + ASSERT_EQUALS(true, MathLib::isNullValue("00.0f")); + ASSERT_EQUALS(true, MathLib::isNullValue("+00.0f")); + ASSERT_EQUALS(true, MathLib::isNullValue("-00.0f")); + // floating point scientific notation (suffix f) + ASSERT_EQUALS(true, MathLib::isNullValue("00.00f")); + ASSERT_EQUALS(true, MathLib::isNullValue("+00.00f")); + ASSERT_EQUALS(true, MathLib::isNullValue("-00.00f")); + // floating point scientific notation (suffix f) + ASSERT_EQUALS(true, MathLib::isNullValue("00.00E+1f")); + ASSERT_EQUALS(true, MathLib::isNullValue("+00.00E+1f")); + ASSERT_EQUALS(true, MathLib::isNullValue("-00.00E+1f")); + + // negative testing + ASSERT_EQUALS(false, MathLib::isNullValue("0.1")); + ASSERT_EQUALS(false, MathLib::isNullValue("1.0")); + ASSERT_EQUALS(false, MathLib::isNullValue("0.01")); + ASSERT_EQUALS(false, MathLib::isNullValue("-00.01e-12")); + ASSERT_EQUALS(false, MathLib::isNullValue("-00.01e+12")); + ASSERT_EQUALS(false, MathLib::isNullValue("")); + ASSERT_EQUALS(false, MathLib::isNullValue("x")); + ASSERT_EQUALS(false, MathLib::isNullValue("garbage")); + // suffix LUL is not allowed + ASSERT_EQUALS(false, MathLib::isNullValue("0LUL")); + ASSERT_EQUALS(false, MathLib::isNullValue("+0LUL")); + ASSERT_EQUALS(false, MathLib::isNullValue("-0LUL")); + } }; REGISTER_TEST(TestMathLib)