diff --git a/cfg/cppcheck-cfg.rng b/cfg/cppcheck-cfg.rng index 0dafccad9..048f6b7d5 100644 --- a/cfg/cppcheck-cfg.rng +++ b/cfg/cppcheck-cfg.rng @@ -154,7 +154,7 @@ - (-?[0-9]*[,:])*([-]?[0-9]+)? + (-?[0-9]*(\.[0-9]+)?[,:])*([-]?[0-9]+(\.[0-9]+)?)? diff --git a/cfg/std.cfg b/cfg/std.cfg index 5a2456bc7..8db8eb5d9 100644 --- a/cfg/std.cfg +++ b/cfg/std.cfg @@ -108,6 +108,7 @@ + -1.0:1.0 @@ -119,6 +120,7 @@ + -1.0:1.0 @@ -130,6 +132,7 @@ + -1.0:1.0 @@ -348,6 +351,7 @@ false + -1.0:1.0 @@ -359,6 +363,7 @@ false + -1.0:1.0 @@ -370,6 +375,7 @@ false + -1.0:1.0 diff --git a/lib/checkfunctions.cpp b/lib/checkfunctions.cpp index b17541aa7..22f7570a2 100644 --- a/lib/checkfunctions.cpp +++ b/lib/checkfunctions.cpp @@ -32,6 +32,7 @@ #include #include +#include #include #include @@ -119,9 +120,9 @@ void CheckFunctions::invalidFunctionUsage() invalidFunctionArgBoolError(argtok, functionToken->str(), argnr); // Are the values 0 and 1 valid? - else if (!mSettings->library.isargvalid(functionToken, argnr, 0)) + else if (!mSettings->library.isargvalid(functionToken, argnr, static_cast(0))) invalidFunctionArgError(argtok, functionToken->str(), argnr, nullptr, mSettings->library.validarg(functionToken, argnr)); - else if (!mSettings->library.isargvalid(functionToken, argnr, 1)) + else if (!mSettings->library.isargvalid(functionToken, argnr, static_cast(1))) invalidFunctionArgError(argtok, functionToken->str(), argnr, nullptr, mSettings->library.validarg(functionToken, argnr)); } } @@ -139,7 +140,7 @@ void CheckFunctions::invalidFunctionArgError(const Token *tok, const std::string else errmsg << "Invalid $symbol() argument nr " << argnr << '.'; if (invalidValue) - errmsg << " The value is " << invalidValue->intvalue << " but the valid values are '" << validstr << "'."; + errmsg << " The value is " << std::setprecision(10) << (invalidValue->isIntValue() ? invalidValue->intvalue : invalidValue->floatValue) << " but the valid values are '" << validstr << "'."; else errmsg << " The value is 0 or 1 (boolean) but the valid values are '" << validstr << "'."; if (invalidValue) @@ -241,11 +242,6 @@ void CheckFunctions::checkMathFunctions() } } - // acos( x ), asin( x ) where x is defined for interval [-1,+1], but not beyond - else if (Token::Match(tok, "acos|acosl|acosf|asin|asinf|asinl ( %num% )")) { - if (std::fabs(MathLib::toDoubleNumber(tok->strAt(2))) > 1.0) - mathfunctionCallWarning(tok); - } // sqrt( x ): if x is negative the result is undefined else if (Token::Match(tok, "sqrt|sqrtf|sqrtl ( %num% )")) { if (MathLib::isNegative(tok->strAt(2))) diff --git a/lib/library.cpp b/lib/library.cpp index 22cd75f62..353f3e8e4 100644 --- a/lib/library.cpp +++ b/lib/library.cpp @@ -43,6 +43,18 @@ static std::vector getnames(const char *names) return ret; } +static void gettokenlistfromvalid(const std::string& valid, TokenList& tokenList) +{ + std::istringstream istr(valid + ','); + tokenList.createTokens(istr); + for (Token *tok = tokenList.front(); tok; tok = tok->next()) { + if (Token::Match(tok,"- %num%")) { + tok->str("-" + tok->strAt(1)); + tok->deleteNext(); + } + } +} + Library::Library() : mAllocId(0) { } @@ -578,19 +590,33 @@ Library::Error Library::loadFunction(const tinyxml2::XMLElement * const node, co const char *p = argnode->GetText(); bool error = false; bool range = false; + bool has_dot = false; + + if (!p) + return Error(BAD_ATTRIBUTE_VALUE, "\"\""); + + error = *p == '.'; for (; *p; p++) { if (std::isdigit(*p)) error |= (*(p+1) == '-'); - else if (*p == ':') - error |= range; + else if (*p == ':') { + error |= range | (*(p+1) == '.'); + range = true; + has_dot = false; + } else if (*p == '-') error |= (!std::isdigit(*(p+1))); - else if (*p == ',') + else if (*p == ',') { range = false; + error |= *(p+1) == '.'; + has_dot = false; + } + else if (*p == '.') { + error |= has_dot | (!std::isdigit(*(p+1))); + has_dot = true; + } else error = true; - - range |= (*p == ':'); } if (error) return Error(BAD_ATTRIBUTE_VALUE, argnode->GetText()); @@ -705,15 +731,10 @@ bool Library::isargvalid(const Token *ftok, int argnr, const MathLib::bigint arg const ArgumentChecks *ac = getarg(ftok, argnr); if (!ac || ac->valid.empty()) return true; + else if (ac->valid.find('.') != std::string::npos) + return isargvalid(ftok, argnr, static_cast(argvalue)); TokenList tokenList(nullptr); - std::istringstream istr(ac->valid + ','); - tokenList.createTokens(istr); - for (Token *tok = tokenList.front(); tok; tok = tok->next()) { - if (Token::Match(tok,"- %num%")) { - tok->str("-" + tok->strAt(1)); - tok->deleteNext(); - } - } + gettokenlistfromvalid(ac->valid, tokenList); for (const Token *tok = tokenList.front(); tok; tok = tok->next()) { if (tok->isNumber() && argvalue == MathLib::toLongNumber(tok->str())) return true; @@ -727,6 +748,24 @@ bool Library::isargvalid(const Token *ftok, int argnr, const MathLib::bigint arg return false; } +bool Library::isargvalid(const Token *ftok, int argnr, double argvalue) const +{ + const ArgumentChecks *ac = getarg(ftok, argnr); + if (!ac || ac->valid.empty()) + return true; + TokenList tokenList(nullptr); + gettokenlistfromvalid(ac->valid, tokenList); + for (const Token *tok = tokenList.front(); tok; tok = tok->next()) { + if (Token::Match(tok, "%num% : %num%") && argvalue >= MathLib::toDoubleNumber(tok->str()) && argvalue <= MathLib::toDoubleNumber(tok->strAt(2))) + return true; + if (Token::Match(tok, "%num% : ,") && argvalue >= MathLib::toDoubleNumber(tok->str())) + return true; + if ((!tok->previous() || tok->previous()->str() == ",") && Token::Match(tok,": %num%") && argvalue <= MathLib::toDoubleNumber(tok->strAt(1))) + return true; + } + return false; +} + std::string Library::getFunctionName(const Token *ftok, bool *error) const { if (!ftok) { diff --git a/lib/library.h b/lib/library.h index 378075bca..6546e0718 100644 --- a/lib/library.h +++ b/lib/library.h @@ -301,6 +301,7 @@ public: } bool isargvalid(const Token *ftok, int argnr, const MathLib::bigint argvalue) const; + bool isargvalid(const Token *ftok, int argnr, double argvalue) const; const std::string& validarg(const Token *ftok, int argnr) const { const ArgumentChecks *arg = getarg(ftok, argnr); diff --git a/lib/token.cpp b/lib/token.cpp index d6af64e74..c4632390f 100644 --- a/lib/token.cpp +++ b/lib/token.cpp @@ -1497,7 +1497,8 @@ const ValueFlow::Value * Token::getInvalidValue(const Token *ftok, unsigned int const ValueFlow::Value *ret = nullptr; std::list::const_iterator it; for (it = mValues->begin(); it != mValues->end(); ++it) { - if (it->isIntValue() && !settings->library.isargvalid(ftok, argnr, it->intvalue)) { + if ((it->isIntValue() && !settings->library.isargvalid(ftok, argnr, it->intvalue)) || + (it->isFloatValue() && !settings->library.isargvalid(ftok, argnr, it->floatValue))) { if (!ret || ret->isInconclusive() || (ret->condition && !it->isInconclusive())) ret = &(*it); if (!ret->isInconclusive() && !ret->condition) diff --git a/man/manual.docbook b/man/manual.docbook index 4fed1f6be..c4e14108a 100644 --- a/man/manual.docbook +++ b/man/manual.docbook @@ -1498,7 +1498,8 @@ Checking range.c... -10:20 => all values between -10 and 20 are valid :0 => all values that are less or equal to 0 are valid 0: => all values that are greater or equal to 0 are valid -0,2:32 => the value 0 and all values between 2 and 32 are valid +0,2:32 => the value 0 and all values between 2 and 32 are valid +-1.5:5.6 => all values between -1.5 and 5.6 are valid
diff --git a/test/testfunctions.cpp b/test/testfunctions.cpp index fb4936bec..cdc6cacb0 100644 --- a/test/testfunctions.cpp +++ b/test/testfunctions.cpp @@ -604,9 +604,9 @@ private: " std::cout << acosf(1.1) << std::endl;\n" " std::cout << acosl(1.1) << std::endl;\n" "}"); - ASSERT_EQUALS("[test.cpp:3]: (warning) Passing value 1.1 to acos() leads to implementation-defined result.\n" - "[test.cpp:4]: (warning) Passing value 1.1 to acosf() leads to implementation-defined result.\n" - "[test.cpp:5]: (warning) Passing value 1.1 to acosl() leads to implementation-defined result.\n", errout.str()); + ASSERT_EQUALS("[test.cpp:3]: (error) Invalid acos() argument nr 1. The value is 1.1 but the valid values are '-1.0:1.0'.\n" + "[test.cpp:4]: (error) Invalid acosf() argument nr 1. The value is 1.1 but the valid values are '-1.0:1.0'.\n" + "[test.cpp:5]: (error) Invalid acosl() argument nr 1. The value is 1.1 but the valid values are '-1.0:1.0'.\n", errout.str()); check("void foo()\n" "{\n" @@ -614,9 +614,9 @@ private: " std::cout << acosf(-1.1) << std::endl;\n" " std::cout << acosl(-1.1) << std::endl;\n" "}"); - ASSERT_EQUALS("[test.cpp:3]: (warning) Passing value -1.1 to acos() leads to implementation-defined result.\n" - "[test.cpp:4]: (warning) Passing value -1.1 to acosf() leads to implementation-defined result.\n" - "[test.cpp:5]: (warning) Passing value -1.1 to acosl() leads to implementation-defined result.\n", errout.str()); + ASSERT_EQUALS("[test.cpp:3]: (error) Invalid acos() argument nr 1. The value is -1.1 but the valid values are '-1.0:1.0'.\n" + "[test.cpp:4]: (error) Invalid acosf() argument nr 1. The value is -1.1 but the valid values are '-1.0:1.0'.\n" + "[test.cpp:5]: (error) Invalid acosl() argument nr 1. The value is -1.1 but the valid values are '-1.0:1.0'.\n", errout.str()); } void mathfunctionCall_asin() { @@ -665,9 +665,9 @@ private: " std::cout << asinf(1.1) << std::endl;\n" " std::cout << asinl(1.1) << std::endl;\n" "}"); - ASSERT_EQUALS("[test.cpp:3]: (warning) Passing value 1.1 to asin() leads to implementation-defined result.\n" - "[test.cpp:4]: (warning) Passing value 1.1 to asinf() leads to implementation-defined result.\n" - "[test.cpp:5]: (warning) Passing value 1.1 to asinl() leads to implementation-defined result.\n", errout.str()); + ASSERT_EQUALS("[test.cpp:3]: (error) Invalid asin() argument nr 1. The value is 1.1 but the valid values are '-1.0:1.0'.\n" + "[test.cpp:4]: (error) Invalid asinf() argument nr 1. The value is 1.1 but the valid values are '-1.0:1.0'.\n" + "[test.cpp:5]: (error) Invalid asinl() argument nr 1. The value is 1.1 but the valid values are '-1.0:1.0'.\n", errout.str()); check("void foo()\n" "{\n" @@ -675,9 +675,9 @@ private: " std::cout << asinf(-1.1) << std::endl;\n" " std::cout << asinl(-1.1) << std::endl;\n" "}"); - ASSERT_EQUALS("[test.cpp:3]: (warning) Passing value -1.1 to asin() leads to implementation-defined result.\n" - "[test.cpp:4]: (warning) Passing value -1.1 to asinf() leads to implementation-defined result.\n" - "[test.cpp:5]: (warning) Passing value -1.1 to asinl() leads to implementation-defined result.\n", errout.str()); + ASSERT_EQUALS("[test.cpp:3]: (error) Invalid asin() argument nr 1. The value is -1.1 but the valid values are '-1.0:1.0'.\n" + "[test.cpp:4]: (error) Invalid asinf() argument nr 1. The value is -1.1 but the valid values are '-1.0:1.0'.\n" + "[test.cpp:5]: (error) Invalid asinl() argument nr 1. The value is -1.1 but the valid values are '-1.0:1.0'.\n", errout.str()); } void mathfunctionCall_pow() { diff --git a/test/testlibrary.cpp b/test/testlibrary.cpp index 1fedf4393..590375bef 100644 --- a/test/testlibrary.cpp +++ b/test/testlibrary.cpp @@ -282,6 +282,11 @@ private: " 1:5,8\n" " -1,5\n" " :1,5\n" + " 1.5:\n" + " -6.7:-5.5,-3.3:-2.7\n" + " 0.0:\n" + " :2.0\n" + " 0.0\n" " \n" ""; @@ -289,41 +294,125 @@ private: ASSERT_EQUALS(true, Library::OK == (readLibrary(library, xmldata)).errorcode); TokenList tokenList(nullptr); - std::istringstream istr("foo(a,b,c,d,e);"); + std::istringstream istr("foo(a,b,c,d,e,f,g,h,i,j);"); tokenList.createTokens(istr); tokenList.front()->next()->astOperand1(tokenList.front()); // 1- - ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 1, -10)); - ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 1, 0)); - ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 1, 1)); - ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 1, 10)); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 1, static_cast(-10))); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 1, -10.0)); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 1, static_cast(0))); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 1, 0.0)); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 1, static_cast(1))); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 1, 1.0)); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 1, static_cast(10))); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 1, 10.0)); // -7-0 - ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 2, -10)); - ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 2, -7)); - ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 2, -3)); - ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 2, 0)); - ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 2, 1)); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 2, static_cast(-10))); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 2, -10.0)); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 2, -7.5)); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 2, -7.1)); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 2, static_cast(-7))); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 2, -7.0)); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 2, static_cast(-3))); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 2, -3.0)); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 2, -3.5)); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 2, static_cast(0))); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 2, 0.0)); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 2, 0.5)); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 2, static_cast(1))); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 2, 1.0)); // 1-5,8 - ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 3, 0)); - ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 3, 1)); - ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 3, 3)); - ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 3, 5)); - ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 3, 6)); - ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 3, 7)); - ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 3, 8)); - ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 3, 9)); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 3, static_cast(0))); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 3, 0.0)); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 3, static_cast(1))); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 3, 1.0)); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 3, static_cast(3))); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 3, 3.0)); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 3, static_cast(5))); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 3, 5.0)); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 3, static_cast(6))); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 3, 6.0)); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 3, static_cast(7))); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 3, 7.0)); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 3, static_cast(8))); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 3, 8.0)); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 3, static_cast(9))); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 3, 9.0)); // -1,5 - ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 4, -10)); - ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 4, -1)); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 4, static_cast(-10))); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 4, -10.0)); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 4, static_cast(-1))); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 4, -1.0)); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 4, 5.000001)); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 4, 5.5)); // :1,5 - ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 5, -10)); - ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 5, 1)); - ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 5, 2)); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 5, static_cast(-10))); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 5, -10.0)); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 5, static_cast(1))); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 5, 1.0)); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 5, static_cast(2))); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 5, 2.0)); + + // 1.5: + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 6, static_cast(0))); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 6, 0.0)); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 6, static_cast(1))); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 6, 1.499999)); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 6, 1.5)); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 6, static_cast(2))); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 6, static_cast(10))); + + // -6.7:-5.5,-3.3:-2.7 + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 7, static_cast(-7))); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 7, -7.0)); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 7, -6.7000001)); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 7, -6.7)); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 7, static_cast(-6))); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 7, -6.0)); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 7, -5.5)); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 7, -5.4999999)); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 7, -3.3000001)); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 7, -3.3)); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 7, static_cast(-3))); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 7, -3.0)); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 7, -2.7)); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 7, -2.6999999)); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 7, static_cast(-2))); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 7, -2.0)); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 7, static_cast(0))); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 7, 0.0)); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 7, static_cast(3))); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 7, 3.0)); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 7, static_cast(6))); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 7, 6.0)); + + // 0.0: + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 8, static_cast(-1))); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 8, -1.0)); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 8, -0.00000001)); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 8, static_cast(0))); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 8, 0.0)); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 8, 0.000000001)); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 8, static_cast(1))); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 8, 1.0)); + + // :2.0 + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 9, static_cast(-1))); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 9, -1.0)); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 9, static_cast(2))); + ASSERT_EQUALS(true, library.isargvalid(tokenList.front(), 9, 2.0)); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 9, 2.00000001)); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 9, static_cast(200))); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 9, 200.0)); + + // 0.0 + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 10, static_cast(0))); + ASSERT_EQUALS(false, library.isargvalid(tokenList.front(), 10, 0.0)); } void function_arg_minsize() const { @@ -724,54 +813,105 @@ private: } } + void loadLibError(const char xmldata [], Library::ErrorCode errorcode, const char* file, unsigned line) const { + Library library; + assertEquals(file, line, errorcode, readLibrary(library, xmldata).errorcode); + } + +#define LOADLIBERROR(xmldata, errorcode) loadLibError(xmldata, errorcode, __FILE__, __LINE__) +#define LOADLIB_ERROR_INVALID_RANGE(valid) LOADLIBERROR("\n" \ + "\n" \ + "\n" \ + "\n" \ + "" valid "\n" \ + "\n" \ + "\n" \ + "", \ + Library::BAD_ATTRIBUTE_VALUE) + void loadLibErrors() const { - // UNKNOWN_ELEMENT - { - const char xmldata [] = "\n" - "\n" - " \n" - ""; - Library library; - ASSERT_EQUALS(Library::UNKNOWN_ELEMENT, readLibrary(library, xmldata).errorcode); - } - // MISSING_ATTRIBUTE - { - // #define without attributes - { - const char xmldata [] = "\n" - "\n" - " \n" // no attributes provided at all - ""; - Library library; - ASSERT_EQUALS(Library::MISSING_ATTRIBUTE, readLibrary(library, xmldata).errorcode); - } - // #define with name but without value - { - const char xmldata [] = "\n" - "\n" - " \n" // no value provided - ""; - Library library; - ASSERT_EQUALS(Library::MISSING_ATTRIBUTE, readLibrary(library, xmldata).errorcode); - } - // #define with value but without a name - { - const char xmldata [] = "\n" - "\n" - " \n" // no name provided - ""; - Library library; - ASSERT_EQUALS(Library::MISSING_ATTRIBUTE, readLibrary(library, xmldata).errorcode); - } - } - // UNSUPPORTED_FORMAT - { - const char xmldata [] = "\n" - "\n" - ""; - Library library; - ASSERT_EQUALS(Library::UNSUPPORTED_FORMAT, readLibrary(library, xmldata).errorcode); - } + + LOADLIBERROR("\n" + "\n" + " \n" + "", + Library::UNKNOWN_ELEMENT); + + // #define without attributes + LOADLIBERROR("\n" + "\n" + " \n" // no attributes provided at all + "", + Library::MISSING_ATTRIBUTE); + + // #define with name but without value + LOADLIBERROR("\n" + "\n" + " \n" // no value provided + "", + Library::MISSING_ATTRIBUTE); + + LOADLIBERROR("\n" + "\n" + " \n" // no name provided + "", + Library::MISSING_ATTRIBUTE); + + LOADLIBERROR("\n" + "\n" + "", + Library::UNSUPPORTED_FORMAT); + + // empty range + LOADLIB_ERROR_INVALID_RANGE(""); + + // letter as range + LOADLIB_ERROR_INVALID_RANGE("a"); + + // letter and number as range + LOADLIB_ERROR_INVALID_RANGE("1a"); + + // digit followed by dash + LOADLIB_ERROR_INVALID_RANGE("0:2-1"); + + // single dash + LOADLIB_ERROR_INVALID_RANGE("-"); + + // range with multiple colons + LOADLIB_ERROR_INVALID_RANGE("1:2:3"); + + // extra dot + LOADLIB_ERROR_INVALID_RANGE("1.0.0:10"); + + // consecutive dots + LOADLIB_ERROR_INVALID_RANGE("1..0:10"); + + // dot followed by dash + LOADLIB_ERROR_INVALID_RANGE("1.-0:10"); + + // dot without preceding number + LOADLIB_ERROR_INVALID_RANGE(".5:10"); + + // dash followed by dot + LOADLIB_ERROR_INVALID_RANGE("-.5:10"); + + // colon followed by dot without preceding number + LOADLIB_ERROR_INVALID_RANGE("0:.5"); + + // colon followed by dash followed by dot + LOADLIB_ERROR_INVALID_RANGE("-10:-.5"); + + // dot not followed by number + LOADLIB_ERROR_INVALID_RANGE("1:5."); + + // dot not followed by number + LOADLIB_ERROR_INVALID_RANGE("1.:5"); + + // dot followed by comma + LOADLIB_ERROR_INVALID_RANGE("1:5.,6:10"); + + // comma followed by dot + LOADLIB_ERROR_INVALID_RANGE("-10:0,.5:"); } };