From 7086ffaa1b0da7f500c7666f466ab4e7a57e8486 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Sat, 21 Oct 2023 09:12:59 +0200 Subject: [PATCH] fixed #12045 - print error when using an option which has not been compiled in instead of treating it as non-existent or a no-op (#5508) Also disabled more internal code around those options and did some cleanups. --- cli/cmdlineparser.cpp | 371 +++++++++++++++++++------------------ cli/cmdlineparser.h | 2 +- cli/cppcheckexecutor.cpp | 19 +- cli/cppcheckexecutor.h | 2 + lib/settings.h | 4 +- test/testcmdlineparser.cpp | 109 +++++++++++ 6 files changed, 320 insertions(+), 187 deletions(-) diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index 70da8b86a..b4a092799 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -356,11 +356,17 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[]) // Exception handling inside cppcheck client else if (std::strcmp(argv[i], "--exception-handling") == 0) { +#if defined(USE_WINDOWS_SEH) || defined(USE_UNIX_SIGNAL_HANDLING) mSettings.exceptionHandling = true; +#else + mLogger.printError("Option --exception-handling is not supported since Cppcheck has not been built with any exception handling enabled."); + return false; +#endif } // Exception handling inside cppcheck client else if (std::strncmp(argv[i], "--exception-handling=", 21) == 0) { +#if defined(USE_WINDOWS_SEH) || defined(USE_UNIX_SIGNAL_HANDLING) const std::string exceptionOutfilename = argv[i] + 21; if (exceptionOutfilename != "stderr" && exceptionOutfilename != "stdout") { mLogger.printError("invalid '--exception-handling' argument"); @@ -368,6 +374,10 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[]) } mSettings.exceptionHandling = true; CppCheckExecutor::setExceptionOutput((exceptionOutfilename == "stderr") ? stderr : stdout); +#else + mLogger.printError("Option --exception-handling is not supported since Cppcheck has not been built with any exception handling enabled."); + return false; +#endif } // Filter errors @@ -508,8 +518,8 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[]) mSettings.jobs = tmp; } -#ifdef THREADING_MODEL_FORK else if (std::strncmp(argv[i], "-l", 2) == 0) { +#ifdef THREADING_MODEL_FORK std::string numberString; // "-l 3" @@ -534,8 +544,11 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[]) return false; } mSettings.loadAverage = tmp; - } +#else + mLogger.printError("Option -l cannot be used as Cppcheck has not been built with fork threading model."); + return false; #endif + } // Enforce language (--language=, -x) else if (std::strncmp(argv[i], "--language=", 11) == 0 || std::strcmp(argv[i], "-x") == 0) { @@ -760,18 +773,25 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[]) mSettings.reportProgress = tmp; } -#ifdef HAVE_RULES // Rule given at command line else if (std::strncmp(argv[i], "--rule=", 7) == 0) { +#ifdef HAVE_RULES Settings::Rule rule; rule.pattern = 7 + argv[i]; mSettings.rules.emplace_back(std::move(rule)); +#else + mLogger.printError("Option --rule cannot be used as Cppcheck has not been built with rules support."); + return false; +#endif } // Rule file else if (std::strncmp(argv[i], "--rule-file=", 12) == 0) { +#ifdef HAVE_RULES + const std::string ruleFile = argv[i] + 12; tinyxml2::XMLDocument doc; - if (doc.LoadFile(12+argv[i]) == tinyxml2::XML_SUCCESS) { + const tinyxml2::XMLError err = doc.LoadFile(ruleFile.c_str()); + if (err == tinyxml2::XML_SUCCESS) { tinyxml2::XMLElement *node = doc.FirstChildElement(); if (node && strcmp(node->Value(), "rules") == 0) node = node->FirstChildElement("rule"); @@ -806,11 +826,14 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[]) mSettings.rules.emplace_back(std::move(rule)); } } else { - mLogger.printError("unable to load rule-file: " + std::string(12+argv[i])); + mLogger.printError("unable to load rule-file '" + ruleFile + "' (" + tinyxml2::XMLDocument::ErrorIDToName(err) + ")."); return false; } - } +#else + mLogger.printError("Option --rule-file cannot be used as Cppcheck has not been built with rules support."); + return false; #endif + } // show timing information.. else if (std::strncmp(argv[i], "--showtime=", 11) == 0) { @@ -1051,7 +1074,7 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[]) return true; } -void CmdLineParser::printHelp() +void CmdLineParser::printHelp() const { const std::string manualUrl(isCppcheckPremium() ? "https://cppcheck.sourceforge.io/manual.pdf" : @@ -1190,64 +1213,62 @@ void CmdLineParser::printHelp() " more comments, like: '// cppcheck-suppress warningId'\n" " on the lines before the warning to suppress.\n" " -j Start threads to do the checking simultaneously.\n" -#ifdef THREADING_MODEL_FORK - " -l Specifies that no new threads should be started if\n" - " there are other threads running and the load average is\n" - " at least .\n" -#endif - " --language=, -x \n" - " Forces cppcheck to check all files as the given\n" - " language. Valid values are: c, c++\n" - " --library= Load file that contains information about types\n" - " and functions. With such information Cppcheck\n" - " understands your code better and therefore you\n" - " get better results. The std.cfg file that is\n" - " distributed with Cppcheck is loaded automatically.\n" - " For more information about library files, read the\n" - " manual.\n" - " --max-configs=\n" - " Maximum number of configurations to check in a file\n" - " before skipping it. Default is '12'. If used together\n" - " with '--force', the last option is the one that is\n" - " effective.\n" - " --max-ctu-depth=N Max depth in whole program analysis. The default value\n" - " is 2. A larger value will mean more errors can be found\n" - " but also means the analysis will be slower.\n" - " --output-file= Write results to file, rather than standard error.\n" - " --platform=, --platform=\n" - " Specifies platform specific types and sizes. The\n" - " available builtin platforms are:\n" - " * unix32\n" - " 32 bit unix variant\n" - " * unix64\n" - " 64 bit unix variant\n" - " * win32A\n" - " 32 bit Windows ASCII character encoding\n" - " * win32W\n" - " 32 bit Windows UNICODE character encoding\n" - " * win64\n" - " 64 bit Windows\n" - " * avr8\n" - " 8 bit AVR microcontrollers\n" - " * elbrus-e1cp\n" - " Elbrus e1c+ architecture\n" - " * pic8\n" - " 8 bit PIC microcontrollers\n" - " Baseline and mid-range architectures\n" - " * pic8-enhanced\n" - " 8 bit PIC microcontrollers\n" - " Enhanced mid-range and high end (PIC18) architectures\n" - " * pic16\n" - " 16 bit PIC microcontrollers\n" - " * mips32\n" - " 32 bit MIPS microcontrollers\n" - " * native\n" - " Type sizes of host system are assumed, but no\n" - " further assumptions.\n" - " * unspecified\n" - " Unknown type sizes\n" - " --plist-output=\n" - " Generate Clang-plist output files in folder.\n"; + " -l Specifies that no new threads should be started if\n" + " there are other threads running and the load average is\n" + " at least .\n" + " --language=, -x \n" + " Forces cppcheck to check all files as the given\n" + " language. Valid values are: c, c++\n" + " --library= Load file that contains information about types\n" + " and functions. With such information Cppcheck\n" + " understands your code better and therefore you\n" + " get better results. The std.cfg file that is\n" + " distributed with Cppcheck is loaded automatically.\n" + " For more information about library files, read the\n" + " manual.\n" + " --max-configs=\n" + " Maximum number of configurations to check in a file\n" + " before skipping it. Default is '12'. If used together\n" + " with '--force', the last option is the one that is\n" + " effective.\n" + " --max-ctu-depth=N Max depth in whole program analysis. The default value\n" + " is 2. A larger value will mean more errors can be found\n" + " but also means the analysis will be slower.\n" + " --output-file= Write results to file, rather than standard error.\n" + " --platform=, --platform=\n" + " Specifies platform specific types and sizes. The\n" + " available builtin platforms are:\n" + " * unix32\n" + " 32 bit unix variant\n" + " * unix64\n" + " 64 bit unix variant\n" + " * win32A\n" + " 32 bit Windows ASCII character encoding\n" + " * win32W\n" + " 32 bit Windows UNICODE character encoding\n" + " * win64\n" + " 64 bit Windows\n" + " * avr8\n" + " 8 bit AVR microcontrollers\n" + " * elbrus-e1cp\n" + " Elbrus e1c+ architecture\n" + " * pic8\n" + " 8 bit PIC microcontrollers\n" + " Baseline and mid-range architectures\n" + " * pic8-enhanced\n" + " 8 bit PIC microcontrollers\n" + " Enhanced mid-range and high end (PIC18) architectures\n" + " * pic16\n" + " 16 bit PIC microcontrollers\n" + " * mips32\n" + " 32 bit MIPS microcontrollers\n" + " * native\n" + " Type sizes of host system are assumed, but no\n" + " further assumptions.\n" + " * unspecified\n" + " Unknown type sizes\n" + " --plist-output=\n" + " Generate Clang-plist output files in folder.\n"; if (isCppcheckPremium()) { oss << @@ -1287,117 +1308,115 @@ void CmdLineParser::printHelp() " currently only possible to apply the base paths to\n" " files that are on a lower level in the directory tree.\n" " --report-progress Report progress messages while checking a file (single job only).\n" -#ifdef HAVE_RULES - " --rule= Match regular expression.\n" - " --rule-file= Use given rule file. For more information, see:\n" - " http://sourceforge.net/projects/cppcheck/files/Articles/\n" -#endif - " --showtime= Show timing information.\n" - " The available modes are:\n" - " * none\n" - " Show nothing (default)\n" - " * file\n" - " Show for each processed file\n" - " * file-total\n" - " Show total time only for each processed file\n" - " * summary\n" - " Show a summary at the end\n" - " * top5_file\n" - " Show the top 5 for each processed file\n" - " * top5_summary\n" - " Show the top 5 summary at the end\n" - " * top5\n" - " Alias for top5_file (deprecated)\n" - " --std= Set standard.\n" - " The available options are:\n" - " * c89\n" - " C code is C89 compatible\n" - " * c99\n" - " C code is C99 compatible\n" - " * c11\n" - " C code is C11 compatible (default)\n" - " * c++03\n" - " C++ code is C++03 compatible\n" - " * c++11\n" - " C++ code is C++11 compatible\n" - " * c++14\n" - " C++ code is C++14 compatible\n" - " * c++17\n" - " C++ code is C++17 compatible\n" - " * c++20\n" - " C++ code is C++20 compatible (default)\n" - " --suppress= Suppress warnings that match . The format of\n" - " is:\n" - " [error id]:[filename]:[line]\n" - " The [filename] and [line] are optional. If [error id]\n" - " is a wildcard '*', all error ids match.\n" - " --suppressions-list=\n" - " Suppress warnings listed in the file. Each suppression\n" - " is in the same format as above.\n" - " --suppress-xml=\n" - " Suppress warnings listed in a xml file. XML file should\n" - " follow the manual.pdf format specified in section.\n" - " `6.4 XML suppressions` .\n" - " --template='' Format the error messages. Available fields:\n" - " {file} file name\n" - " {line} line number\n" - " {column} column number\n" - " {callstack} show a callstack. Example:\n" - " [file.c:1] -> [file.c:100]\n" - " {inconclusive:text} if warning is inconclusive, text\n" - " is written\n" - " {severity} severity\n" - " {message} warning message\n" - " {id} warning id\n" - " {cwe} CWE id (Common Weakness Enumeration)\n" - " {code} show the real code\n" - " \\t insert tab\n" - " \\n insert newline\n" - " \\r insert carriage return\n" - " Example formats:\n" - " '{file}:{line},{severity},{id},{message}' or\n" - " '{file}({line}):({severity}) {message}' or\n" - " '{callstack} {message}'\n" - " Pre-defined templates: gcc (default), cppcheck1 (old default), vs, edit.\n" - // Note: template daca2 also exists, but is for internal use (cppcheck scripts). - " --template-location=''\n" - " Format error message location. If this is not provided\n" - " then no extra location info is shown.\n" - " Available fields:\n" - " {file} file name\n" - " {line} line number\n" - " {column} column number\n" - " {info} location info\n" - " {code} show the real code\n" - " \\t insert tab\n" - " \\n insert newline\n" - " \\r insert carriage return\n" - " Example format (gcc-like):\n" - " '{file}:{line}:{column}: note: {info}\\n{code}'\n" - " -U Undefine preprocessor symbol. Use -U to explicitly\n" - " hide certain #ifdef code paths from checking.\n" - " Example: '-UDEBUG'\n" - " -v, --verbose Output more detailed error information.\n" - " Note that this option is not mutually exclusive with --quiet.\n" - " --version Print out version number.\n" - " --xml Write results in xml format to error stream (stderr).\n" - "\n" - "Example usage:\n" - " # Recursively check the current folder. Print the progress on the screen and\n" - " # write errors to a file:\n" - " cppcheck . 2> err.txt\n" - "\n" - " # Recursively check ../myproject/ and don't print progress:\n" - " cppcheck --quiet ../myproject/\n" - "\n" - " # Check test.cpp, enable all checks:\n" - " cppcheck --enable=all --inconclusive --library=posix test.cpp\n" - "\n" - " # Check f.cpp and search include files from inc1/ and inc2/:\n" - " cppcheck -I inc1/ -I inc2/ f.cpp\n" - "\n" - "For more information:\n" - " " << manualUrl << "\n" + " --rule= Match regular expression.\n" + " --rule-file= Use given rule file. For more information, see:\n" + " http://sourceforge.net/projects/cppcheck/files/Articles/\n" + " --showtime= Show timing information.\n" + " The available modes are:\n" + " * none\n" + " Show nothing (default)\n" + " * file\n" + " Show for each processed file\n" + " * file-total\n" + " Show total time only for each processed file\n" + " * summary\n" + " Show a summary at the end\n" + " * top5_file\n" + " Show the top 5 for each processed file\n" + " * top5_summary\n" + " Show the top 5 summary at the end\n" + " * top5\n" + " Alias for top5_file (deprecated)\n" + " --std= Set standard.\n" + " The available options are:\n" + " * c89\n" + " C code is C89 compatible\n" + " * c99\n" + " C code is C99 compatible\n" + " * c11\n" + " C code is C11 compatible (default)\n" + " * c++03\n" + " C++ code is C++03 compatible\n" + " * c++11\n" + " C++ code is C++11 compatible\n" + " * c++14\n" + " C++ code is C++14 compatible\n" + " * c++17\n" + " C++ code is C++17 compatible\n" + " * c++20\n" + " C++ code is C++20 compatible (default)\n" + " --suppress= Suppress warnings that match . The format of\n" + " is:\n" + " [error id]:[filename]:[line]\n" + " The [filename] and [line] are optional. If [error id]\n" + " is a wildcard '*', all error ids match.\n" + " --suppressions-list=\n" + " Suppress warnings listed in the file. Each suppression\n" + " is in the same format as above.\n" + " --suppress-xml=\n" + " Suppress warnings listed in a xml file. XML file should\n" + " follow the manual.pdf format specified in section.\n" + " `6.4 XML suppressions` .\n" + " --template='' Format the error messages. Available fields:\n" + " {file} file name\n" + " {line} line number\n" + " {column} column number\n" + " {callstack} show a callstack. Example:\n" + " [file.c:1] -> [file.c:100]\n" + " {inconclusive:text} if warning is inconclusive, text\n" + " is written\n" + " {severity} severity\n" + " {message} warning message\n" + " {id} warning id\n" + " {cwe} CWE id (Common Weakness Enumeration)\n" + " {code} show the real code\n" + " \\t insert tab\n" + " \\n insert newline\n" + " \\r insert carriage return\n" + " Example formats:\n" + " '{file}:{line},{severity},{id},{message}' or\n" + " '{file}({line}):({severity}) {message}' or\n" + " '{callstack} {message}'\n" + " Pre-defined templates: gcc (default), cppcheck1 (old default), vs, edit.\n" + // Note: template daca2 also exists, but is for internal use (cppcheck scripts). + " --template-location=''\n" + " Format error message location. If this is not provided\n" + " then no extra location info is shown.\n" + " Available fields:\n" + " {file} file name\n" + " {line} line number\n" + " {column} column number\n" + " {info} location info\n" + " {code} show the real code\n" + " \\t insert tab\n" + " \\n insert newline\n" + " \\r insert carriage return\n" + " Example format (gcc-like):\n" + " '{file}:{line}:{column}: note: {info}\\n{code}'\n" + " -U Undefine preprocessor symbol. Use -U to explicitly\n" + " hide certain #ifdef code paths from checking.\n" + " Example: '-UDEBUG'\n" + " -v, --verbose Output more detailed error information.\n" + " Note that this option is not mutually exclusive with --quiet.\n" + " --version Print out version number.\n" + " --xml Write results in xml format to error stream (stderr).\n" + "\n" + "Example usage:\n" + " # Recursively check the current folder. Print the progress on the screen and\n" + " # write errors to a file:\n" + " cppcheck . 2> err.txt\n" + "\n" + " # Recursively check ../myproject/ and don't print progress:\n" + " cppcheck --quiet ../myproject/\n" + "\n" + " # Check test.cpp, enable all checks:\n" + " cppcheck --enable=all --inconclusive --library=posix test.cpp\n" + "\n" + " # Check f.cpp and search include files from inc1/ and inc2/:\n" + " cppcheck -I inc1/ -I inc2/ f.cpp\n" + "\n" + "For more information:\n" + " " << manualUrl << "\n" "\n" "Many thanks to the 3rd party libraries we use:\n" " * tinyxml2 -- loading project/library/ctu files.\n" diff --git a/cli/cmdlineparser.h b/cli/cmdlineparser.h index 51770969f..d032a00eb 100644 --- a/cli/cmdlineparser.h +++ b/cli/cmdlineparser.h @@ -99,7 +99,7 @@ protected: /** * Print help text to the console. */ - void printHelp(); + void printHelp() const; private: bool isCppcheckPremium() const; diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp index 10e6c7424..d218543af 100644 --- a/cli/cppcheckexecutor.cpp +++ b/cli/cppcheckexecutor.cpp @@ -108,7 +108,9 @@ public: // TODO: do not directly write to stdout +#if defined(USE_WINDOWS_SEH) || defined(USE_UNIX_SIGNAL_HANDLING) /*static*/ FILE* CppCheckExecutor::mExceptionOutput = stdout; +#endif CppCheckExecutor::~CppCheckExecutor() { @@ -257,11 +259,7 @@ int CppCheckExecutor::check(int argc, const char* const argv[]) cppCheck.settings() = settings; mSettings = &settings; - int ret; - if (settings.exceptionHandling) - ret = check_wrapper(cppCheck); - else - ret = check_internal(cppCheck); + const int ret = check_wrapper(cppCheck); mSettings = nullptr; return ret; @@ -270,12 +268,13 @@ int CppCheckExecutor::check(int argc, const char* const argv[]) int CppCheckExecutor::check_wrapper(CppCheck& cppcheck) { #ifdef USE_WINDOWS_SEH - return check_wrapper_seh(*this, &CppCheckExecutor::check_internal, cppcheck); + if (cppcheck.settings().exceptionHandling) + return check_wrapper_seh(*this, &CppCheckExecutor::check_internal, cppcheck); #elif defined(USE_UNIX_SIGNAL_HANDLING) - return check_wrapper_sig(*this, &CppCheckExecutor::check_internal, cppcheck); -#else - return check_internal(cppcheck); + if (cppcheck.settings().exceptionHandling) + return check_wrapper_sig(*this, &CppCheckExecutor::check_internal, cppcheck); #endif + return check_internal(cppcheck); } bool CppCheckExecutor::reportSuppressions(const Settings &settings, bool unusedFunctionCheckEnabled, const std::map &files, ErrorLogger& errorLogger) { @@ -522,6 +521,7 @@ void CppCheckExecutor::reportErr(const ErrorMessage &msg) reportErr(msg.toString(mSettings->verbose, mSettings->templateFormat, mSettings->templateLocation)); } +#if defined(USE_WINDOWS_SEH) || defined(USE_UNIX_SIGNAL_HANDLING) void CppCheckExecutor::setExceptionOutput(FILE* exceptionOutput) { mExceptionOutput = exceptionOutput; @@ -531,6 +531,7 @@ FILE* CppCheckExecutor::getExceptionOutput() { return mExceptionOutput; } +#endif bool CppCheckExecutor::tryLoadLibrary(Library& destination, const std::string& basepath, const char* filename) { diff --git a/cli/cppcheckexecutor.h b/cli/cppcheckexecutor.h index a1b7cf1d8..1b4865501 100644 --- a/cli/cppcheckexecutor.h +++ b/cli/cppcheckexecutor.h @@ -185,10 +185,12 @@ private: */ std::time_t mLatestProgressOutputTime{}; +#if defined(USE_WINDOWS_SEH) || defined(USE_UNIX_SIGNAL_HANDLING) /** * Output file name for exception handler */ static FILE* mExceptionOutput; +#endif /** * Error output diff --git a/lib/settings.h b/lib/settings.h index bac343347..fa9289db2 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -190,8 +190,10 @@ public: /** @brief Name of the language that is enforced. Empty per default. */ Language enforcedLang{}; +#if defined(USE_WINDOWS_SEH) || defined(USE_UNIX_SIGNAL_HANDLING) /** @brief Is --exception-handling given */ bool exceptionHandling{}; +#endif // argv[0] std::string exename; @@ -276,6 +278,7 @@ public: /** @brief --report-progress */ int reportProgress{-1}; +#ifdef HAVE_RULES /** Rule */ struct CPPCHECKLIB Rule { std::string tokenlist = "normal"; // use normal tokenlist @@ -285,7 +288,6 @@ public: Severity severity = Severity::style; // default severity }; -#ifdef HAVE_RULES /** * @brief Extra rules */ diff --git a/test/testcmdlineparser.cpp b/test/testcmdlineparser.cpp index c541db7fc..8162b8f37 100644 --- a/test/testcmdlineparser.cpp +++ b/test/testcmdlineparser.cpp @@ -255,11 +255,16 @@ private: TEST_CASE(errorlistverbose1); TEST_CASE(errorlistverbose2); TEST_CASE(ignorepathsnopath); +#if defined(USE_WINDOWS_SEH) || defined(USE_UNIX_SIGNAL_HANDLING) TEST_CASE(exceptionhandling); TEST_CASE(exceptionhandling2); TEST_CASE(exceptionhandling3); TEST_CASE(exceptionhandlingInvalid); TEST_CASE(exceptionhandlingInvalid2); +#else + TEST_CASE(exceptionhandlingNotSupported); + TEST_CASE(exceptionhandlingNotSupported2); +#endif TEST_CASE(clang); TEST_CASE(clang2); TEST_CASE(clangInvalid); @@ -275,6 +280,8 @@ private: TEST_CASE(loadAverage); TEST_CASE(loadAverage2); TEST_CASE(loadAverageInvalid); +#else + TEST_CASE(loadAverageNotSupported); #endif TEST_CASE(maxCtuDepth); TEST_CASE(maxCtuDepthInvalid); @@ -297,6 +304,19 @@ private: TEST_CASE(projectMissing); TEST_CASE(projectNoPaths); TEST_CASE(addon); +#ifdef HAVE_RULES + TEST_CASE(rule); +#else + TEST_CASE(ruleNotSupported); +#endif +#ifdef HAVE_RULES + TEST_CASE(ruleFile); + TEST_CASE(ruleFileEmpty); + TEST_CASE(ruleFileMissing); + TEST_CASE(ruleFileInvalid); +#else + TEST_CASE(ruleFileNotSupported); +#endif TEST_CASE(ignorepaths1); TEST_CASE(ignorepaths2); @@ -1703,6 +1723,7 @@ private: ASSERT_EQUALS("cppcheck: error: argument to '-i' is missing.\n", logger->str()); } +#if defined(USE_WINDOWS_SEH) || defined(USE_UNIX_SIGNAL_HANDLING) void exceptionhandling() { REDIRECT; const char * const argv[] = {"cppcheck", "--exception-handling", "file.cpp"}; @@ -1749,6 +1770,21 @@ private: ASSERT_EQUALS(false, parser->parseFromArgs(2, argv)); ASSERT_EQUALS("cppcheck: error: unrecognized command line option: \"--exception-handling-foo\".\n", logger->str()); } +#else + void exceptionhandlingNotSupported() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--exception-handling", "file.cpp"}; + ASSERT(!parser->parseFromArgs(3, argv)); + ASSERT_EQUALS("cppcheck: error: Option --exception-handling is not supported since Cppcheck has not been built with any exception handling enabled.\n", logger->str()); + } + + void exceptionhandlingNotSupported2() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--exception-handling=stderr", "file.cpp"}; + ASSERT(!parser->parseFromArgs(3, argv)); + ASSERT_EQUALS("cppcheck: error: Option --exception-handling is not supported since Cppcheck has not been built with any exception handling enabled.\n", logger->str()); + } +#endif void clang() { REDIRECT; @@ -1866,6 +1902,13 @@ private: ASSERT(!parser->parseFromArgs(4, argv)); ASSERT_EQUALS("cppcheck: error: argument to '-l' is not valid - not an integer.\n", logger->str()); } +#else + void loadAverageNotSupported() { + REDIRECT; + const char * const argv[] = {"cppcheck", "-l", "12", "file.cpp"}; + ASSERT(!parser->parseFromArgs(4, argv)); + ASSERT_EQUALS("cppcheck: error: Option -l cannot be used as Cppcheck has not been built with fork threading model.\n", logger->str()); + } #endif void maxCtuDepth() { @@ -2026,6 +2069,72 @@ private: ASSERT_EQUALS("", GET_REDIRECT_OUTPUT); } +#ifdef HAVE_RULES + void rule() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--rule=.+", "file.cpp"}; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(1, settings->rules.size()); + auto it = settings->rules.cbegin(); + ASSERT_EQUALS(".+", it->pattern); + ASSERT_EQUALS("", logger->str()); + } +#else + void ruleNotSupported() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--rule=.+", "file.cpp"}; + ASSERT(!parser->parseFromArgs(3, argv)); + ASSERT_EQUALS("cppcheck: error: Option --rule cannot be used as Cppcheck has not been built with rules support.\n", logger->str()); + } +#endif + +#ifdef HAVE_RULES + void ruleFile() { + REDIRECT; + ScopedFile file("rule.xml", + "\n" + "\n" + ".+\n" + "\n" + ""); + const char * const argv[] = {"cppcheck", "--rule-file=rule.xml", "file.cpp"}; + ASSERT(parser->parseFromArgs(3, argv)); + ASSERT_EQUALS(1, settings->rules.size()); + auto it = settings->rules.cbegin(); + ASSERT_EQUALS(".+", it->pattern); + ASSERT_EQUALS("", logger->str()); + } + + void ruleFileEmpty() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--rule-file=", "file.cpp"}; + ASSERT(!parser->parseFromArgs(3, argv)); + ASSERT_EQUALS("cppcheck: error: unable to load rule-file '' (XML_ERROR_FILE_NOT_FOUND).\n", logger->str()); + } + + void ruleFileMissing() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--rule-file=rule.xml", "file.cpp"}; + ASSERT(!parser->parseFromArgs(3, argv)); + ASSERT_EQUALS("cppcheck: error: unable to load rule-file 'rule.xml' (XML_ERROR_FILE_NOT_FOUND).\n", logger->str()); + } + + void ruleFileInvalid() { + REDIRECT; + ScopedFile file("rule.xml", ""); + const char * const argv[] = {"cppcheck", "--rule-file=rule.xml", "file.cpp"}; + ASSERT(!parser->parseFromArgs(3, argv)); + ASSERT_EQUALS("cppcheck: error: unable to load rule-file 'rule.xml' (XML_ERROR_EMPTY_DOCUMENT).\n", logger->str()); + } +#else + void ruleFileNotSupported() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--rule-file=rule.xml", "file.cpp"}; + ASSERT(!parser->parseFromArgs(3, argv)); + ASSERT_EQUALS("cppcheck: error: Option --rule-file cannot be used as Cppcheck has not been built with rules support.\n", logger->str()); + } +#endif + void ignorepaths1() { REDIRECT; const char * const argv[] = {"cppcheck", "-isrc", "file.cpp"};