Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

greatly improved Settings::loadCppcheckCfg() error handling #5712

Merged
merged 3 commits into from
Dec 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/cppcheck-premium.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@ jobs:
- name: Check
run: |
cppcheckpremium-${{ env.PREMIUM_VERSION }}/premiumaddon --check-loc-license cppcheck.lic > cppcheck-premium-loc
cppcheckpremium-${{ env.PREMIUM_VERSION }}/cppcheck -j$(nproc) -D__GNUC__ -D__CPPCHECK__ --suppressions-list=cppcheckpremium-suppressions --platform=unix64 --enable=style --premium=misra-c++-2008 --premium=cert-c++-2016 --error-exitcode=1 lib
cppcheckpremium-${{ env.PREMIUM_VERSION }}/cppcheck -j$(nproc) -D__GNUC__ -D__CPPCHECK__ --suppressions-list=cppcheckpremium-suppressions --platform=unix64 --enable=style --premium=misra-c++-2008 --premium=cert-c++-2016 --inline-suppr --error-exitcode=1 lib
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -728,7 +728,7 @@ test/testclangimport.o: test/testclangimport.cpp lib/addoninfo.h lib/check.h lib
test/testclass.o: test/testclass.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/checkclass.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/preprocessor.h lib/settings.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testclass.cpp

test/testcmdlineparser.o: test/testcmdlineparser.cpp cli/cmdlinelogger.h cli/cmdlineparser.h cli/cppcheckexecutor.h lib/addoninfo.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h test/redirect.h
test/testcmdlineparser.o: test/testcmdlineparser.cpp cli/cmdlinelogger.h cli/cmdlineparser.h cli/cppcheckexecutor.h lib/addoninfo.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h test/redirect.h
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testcmdlineparser.cpp

test/testcolor.o: test/testcolor.cpp lib/addoninfo.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h test/fixture.h
Expand Down Expand Up @@ -809,7 +809,7 @@ test/testpreprocessor.o: test/testpreprocessor.cpp externals/simplecpp/simplecpp
test/testprocessexecutor.o: test/testprocessexecutor.cpp cli/executor.h cli/processexecutor.h lib/addoninfo.h lib/analyzerinfo.h lib/check.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h test/redirect.h
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testprocessexecutor.cpp

test/testsettings.o: test/testsettings.cpp lib/addoninfo.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h test/fixture.h
test/testsettings.o: test/testsettings.cpp lib/addoninfo.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsettings.cpp

test/testsimplifytemplate.o: test/testsimplifytemplate.cpp lib/addoninfo.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h
Expand Down
32 changes: 23 additions & 9 deletions cli/cmdlineparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,8 @@ bool CmdLineParser::fillSettingsFromArgs(int argc, const char* const argv[])
// TODO: error out on all missing given files/paths
CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const argv[])
{
mSettings.exename = Path::getCurrentExecutablePath(argv[0]);

if (argc <= 1) {
printHelp();
return Result::Exit;
Expand All @@ -307,7 +309,8 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a

// print all possible error messages..
if (std::strcmp(argv[i], "--errorlist") == 0) {
mSettings.loadCppcheckCfg();
if (!loadCppcheckCfg())
return Result::Fail;
{
XMLErrorMessagesLogger xmlLogger;
std::cout << ErrorMessage::getXMLHeader(mSettings.cppcheckCfgProductName);
Expand All @@ -324,7 +327,8 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
}

if (std::strcmp(argv[i], "--version") == 0) {
mSettings.loadCppcheckCfg();
if (!loadCppcheckCfg())
return Result::Fail;
if (!mSettings.cppcheckCfgProductName.empty()) {
mLogger.printRaw(mSettings.cppcheckCfgProductName);
} else {
Expand All @@ -343,8 +347,6 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a

ImportProject project;

mSettings.exename = Path::getCurrentExecutablePath(argv[0]);

for (int i = 1; i < argc; i++) {
if (argv[i][0] == '-') {
// User define
Expand Down Expand Up @@ -1203,7 +1205,8 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
}
}

mSettings.loadCppcheckCfg();
if (!loadCppcheckCfg())
return Result::Fail;

// Default template format..
if (mSettings.templateFormat.empty()) {
Expand Down Expand Up @@ -1609,10 +1612,10 @@ void CmdLineParser::printHelp() const
mLogger.printRaw(oss.str());
}

bool CmdLineParser::isCppcheckPremium() const {
if (mSettings.cppcheckCfgProductName.empty())
mSettings.loadCppcheckCfg();
return startsWith(mSettings.cppcheckCfgProductName, "Cppcheck Premium");
bool CmdLineParser::isCppcheckPremium() {
Settings settings;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@firewave May I ask you why do we need to create the local settings here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we do not accidentally load the config multiple times times. That should be done in a deterministic way once.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay agree on that one. But you only creating local variable so it's not working.
adding static to it will help though.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But you only creating local variable so it's not working.

What is not working? We only need to compare s single string from the object. Also this is only done during the parsing of the command-line options.

adding static to it will help though.

What? The method or the object?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What? The method or the object?

Both but as you've already marked the method you need to add it only here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both but as you've already marked the method you need to add it only here.

On the object it would not help as it still requires the function call.

I think I did look at the method but I am not sure. It is also just a limited usage.

settings.loadCppcheckCfg(); // TODO: how to handle errors?
return startsWith(settings.cppcheckCfgProductName, "Cppcheck Premium");
}

bool CmdLineParser::tryLoadLibrary(Library& destination, const std::string& basepath, const char* filename)
Expand Down Expand Up @@ -1701,3 +1704,14 @@ bool CmdLineParser::loadAddons(Settings& settings)
}
return result;
}

bool CmdLineParser::loadCppcheckCfg()
{
const std::string cfgErr = mSettings.loadCppcheckCfg();
if (!cfgErr.empty()) {
mLogger.printError("could not load cppcheck.cfg - " + cfgErr);
return false;
}
return true;
}

4 changes: 3 additions & 1 deletion cli/cmdlineparser.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ class CmdLineParser {
void printHelp() const;

private:
bool isCppcheckPremium() const;
static bool isCppcheckPremium();

template<typename T>
bool parseNumberArg(const char* const arg, std::size_t offset, T& num, bool mustBePositive = false)
Expand Down Expand Up @@ -150,6 +150,8 @@ class CmdLineParser {
*/
bool loadAddons(Settings& settings);

bool loadCppcheckCfg();

CmdLineLogger &mLogger;

std::vector<std::string> mPathNames;
Expand Down
11 changes: 7 additions & 4 deletions gui/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ MainWindow::MainWindow(TranslationHandler* th, QSettings* settings) :
{
Settings tempSettings;
tempSettings.exename = QCoreApplication::applicationFilePath().toStdString();
tempSettings.loadCppcheckCfg();
tempSettings.loadCppcheckCfg(); // TODO: how to handle error?
mCppcheckCfgProductName = QString::fromStdString(tempSettings.cppcheckCfgProductName);
mCppcheckCfgAbout = QString::fromStdString(tempSettings.cppcheckCfgAbout);
}
Expand Down Expand Up @@ -903,8 +903,7 @@ bool MainWindow::tryLoadLibrary(Library *library, const QString& filename)
return true;
}

Settings MainWindow::getCppcheckSettings()
{
Settings MainWindow::getCppcheckSettings() {
saveSettings(); // Save settings

Settings result;
Expand All @@ -915,7 +914,11 @@ Settings MainWindow::getCppcheckSettings()
if (!std)
QMessageBox::critical(this, tr("Error"), tr("Failed to load %1. Your Cppcheck installation is broken. You can use --data-dir=<directory> at the command line to specify where this file is located. Please note that --data-dir is supposed to be used by installation scripts and therefore the GUI does not start when it is used, all that happens is that the setting is configured.").arg("std.cfg"));

result.loadCppcheckCfg();
{
const QString cfgErr = QString::fromStdString(result.loadCppcheckCfg());
if (!cfgErr.isEmpty())
QMessageBox::critical(this, tr("Error"), tr("Failed to load %1 - %2").arg("cppcheck.cfg").arg(cfgErr));
}

// If project file loaded, read settings from it
if (mProjectFile) {
Expand Down
93 changes: 70 additions & 23 deletions lib/settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,40 +40,87 @@ Settings::Settings()
setCheckLevelNormal();
}

// TODO: report error when the config is invalid
void Settings::loadCppcheckCfg()
std::string Settings::loadCppcheckCfg()
{
std::string fileName = Path::getPathFromFilename(exename) + "cppcheck.cfg";
static const std::string cfgFilename = "cppcheck.cfg";
std::string fileName;
#ifdef FILESDIR
if (Path::isFile(FILESDIR "/cppcheck.cfg"))
fileName = FILESDIR "/cppcheck.cfg";
if (Path::isFile(Path::join(FILESDIR, cfgFilename)))
fileName = Path::join(FILESDIR, cfgFilename);
#endif
// cppcheck-suppress knownConditionTrueFalse
if (fileName.empty()) {
fileName = Path::getPathFromFilename(exename) + cfgFilename;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is not working? We only need to compare s single string from the object. Also this is only done during the parsing of the command-line options.

loadCppcheckCfg() use member variable exename for storing relative path and it's empty if you create setting locally

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

loadCppcheckCfg() use member variable exename for storing relative path and it's empty if you create setting locally

Oh right. That again. I ran into his in another context as well. Will take a look later today.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I may. I'm already working on it in a separate ticket and was just asking you to help me clarify your thought process behind this particular change.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. I would have just hot fixed this this for now.

As it would have also tied into my upcoming changes to fix https://trac.cppcheck.net/ticket/12240 and #4424 I would have done any more refactoring within that.

Copy link
Collaborator

@olabetskyi olabetskyi Dec 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay hot fix it is

if (!Path::isFile(fileName))
return "";
}

std::ifstream fin(fileName);
if (!fin.is_open())
return;
return "could not open file";
picojson::value json;
fin >> json;
if (!picojson::get_last_error().empty())
return;
picojson::object obj = json.get<picojson::object>();
if (obj.count("productName") && obj["productName"].is<std::string>())
cppcheckCfgProductName = obj["productName"].get<std::string>();
if (obj.count("about") && obj["about"].is<std::string>())
cppcheckCfgAbout = obj["about"].get<std::string>();
if (obj.count("addons") && obj["addons"].is<picojson::array>()) {
for (const picojson::value &v : obj["addons"].get<picojson::array>()) {
const std::string &s = v.get<std::string>();
if (!Path::isAbsolute(s))
addons.emplace(Path::getPathFromFilename(fileName) + s);
else
addons.emplace(s);
{
const std::string& lastErr = picojson::get_last_error();
if (!lastErr.empty())
return "not a valid JSON - " + lastErr;
}
const picojson::object& obj = json.get<picojson::object>();
{
const picojson::object::const_iterator it = obj.find("productName");
if (it != obj.cend()) {
const auto& v = it->second;
if (!v.is<std::string>())
return "'productName' is not a string";
cppcheckCfgProductName = v.get<std::string>();
}
}
if (obj.count("suppressions") && obj["suppressions"].is<picojson::array>()) {
for (const picojson::value &v : obj["suppressions"].get<picojson::array>())
nomsg.addSuppressionLine(v.get<std::string>());
{
const picojson::object::const_iterator it = obj.find("about");
if (it != obj.cend()) {
const auto& v = it->second;
if (!v.is<std::string>())
return "'about' is not a string";
cppcheckCfgAbout = v.get<std::string>();
}
}
{
const picojson::object::const_iterator it = obj.find("addons");
if (it != obj.cend()) {
const auto& entry = it->second;
if (!entry.is<picojson::array>())
return "'addons' is not an array";
for (const picojson::value &v : entry.get<picojson::array>())
{
if (!v.is<std::string>())
return "'addons' array entry is not a string";
const std::string &s = v.get<std::string>();
if (!Path::isAbsolute(s))
addons.emplace(Path::join(Path::getPathFromFilename(fileName), s));
else
addons.emplace(s);
}
}
}
{
const picojson::object::const_iterator it = obj.find("suppressions");
if (it != obj.cend()) {
const auto& entry = it->second;
if (!entry.is<picojson::array>())
return "'suppressions' is not an array";
for (const picojson::value &v : entry.get<picojson::array>())
{
if (!v.is<std::string>())
return "'suppressions' array entry is not a string";
const std::string &s = v.get<std::string>();
const std::string err = nomsg.addSuppressionLine(s);
if (!err.empty())
return "could not parse suppression '" + s + "' - " + err;
}
}
}

return "";
}

std::string Settings::parseEnabled(const std::string &str, std::tuple<SimpleEnableGroup<Severity>, SimpleEnableGroup<Checks>> &groups)
Expand Down
2 changes: 1 addition & 1 deletion lib/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ class CPPCHECKLIB WARN_UNUSED Settings {
public:
Settings();

void loadCppcheckCfg();
std::string loadCppcheckCfg();

/** @brief addons, either filename of python/json file or json data */
std::unordered_set<std::string> addons;
Expand Down
1 change: 1 addition & 0 deletions releasenotes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ Other:
- You can suppress all warnings where macro is used using "-macro"
- fixed CMake build with UBSAN and GCC
- Added command-line options "--fsigned-char" and "--funsigned-char" to control the signess of the "char" type. This overrides previously specified "--platform" options and is overrides by following ones.
- An error is now reported when the "cppcheck.cfg" is invalid. The CLI version will also exit with a failure in that case.
49 changes: 46 additions & 3 deletions test/testcmdlineparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "cppcheckexecutor.h"
#include "errortypes.h"
#include "helpers.h"
#include "path.h"
#include "platform.h"
#include "redirect.h"
#include "settings.h"
Expand Down Expand Up @@ -125,6 +126,7 @@ class TestCmdlineParser : public TestFixture {
TEST_CASE(version);
TEST_CASE(versionWithCfg);
TEST_CASE(versionExclusive);
TEST_CASE(versionWithInvalidCfg);
TEST_CASE(onefile);
TEST_CASE(onepath);
TEST_CASE(optionwithoutfile);
Expand Down Expand Up @@ -268,7 +270,9 @@ class TestCmdlineParser : public TestFixture {
TEST_CASE(showtimeEmpty);
TEST_CASE(showtimeInvalid);
TEST_CASE(errorlist);
TEST_CASE(errorlistWithCfg);
TEST_CASE(errorlistExclusive);
TEST_CASE(errorlistWithInvalidCfg);
TEST_CASE(ignorepathsnopath);
#if defined(USE_WINDOWS_SEH) || defined(USE_UNIX_SIGNAL_HANDLING)
TEST_CASE(exceptionhandling);
Expand Down Expand Up @@ -360,6 +364,8 @@ class TestCmdlineParser : public TestFixture {
TEST_CASE(cppcheckBuildDirExistent);
TEST_CASE(cppcheckBuildDirNonExistent);
TEST_CASE(cppcheckBuildDirEmpty);

TEST_CASE(invalidCppcheckCfg);
}

void nooptions() {
Expand Down Expand Up @@ -412,7 +418,7 @@ class TestCmdlineParser : public TestFixture {

void versionWithCfg() {
REDIRECT;
ScopedFile file("cppcheck.cfg",
ScopedFile file(Path::join(Path::getPathFromFilename(Path::getCurrentExecutablePath("")), "cppcheck.cfg"),
"{\n"
"\"productName\": \"The Product\""
"}\n");
Expand All @@ -433,6 +439,16 @@ class TestCmdlineParser : public TestFixture {
ASSERT_EQUALS("", GET_REDIRECT_OUTPUT);
}

void versionWithInvalidCfg() {
REDIRECT;
ScopedFile file(Path::join(Path::getPathFromFilename(Path::getCurrentExecutablePath("")), "cppcheck.cfg"),
"{\n");
const char * const argv[] = {"cppcheck", "--version"};
ASSERT_EQUALS(CmdLineParser::Result::Fail, parser->parseFromArgs(2, argv));
ASSERT_EQUALS("cppcheck: error: could not load cppcheck.cfg - not a valid JSON - syntax error at line 1 near: \n", logger->str());
ASSERT_EQUALS("", GET_REDIRECT_OUTPUT);
}

void onefile() {
REDIRECT;
const char * const argv[] = {"cppcheck", "file.cpp"};
Expand Down Expand Up @@ -1690,11 +1706,19 @@ class TestCmdlineParser : public TestFixture {
const char * const argv[] = {"cppcheck", "--errorlist"};
ASSERT_EQUALS(CmdLineParser::Result::Exit, parser->parseFromArgs(2, argv));
ASSERT_EQUALS("", logger->str()); // empty since it is logged via ErrorLogger
ASSERT(startsWith(GET_REDIRECT_OUTPUT, "<?xml"));
ASSERT(startsWith(GET_REDIRECT_OUTPUT, ErrorMessage::getXMLHeader("")));
ASSERT(endsWith(GET_REDIRECT_OUTPUT, "</results>\n"));
}

// TODO: test --errorlist with product name
void errorlistWithCfg() {
REDIRECT;
ScopedFile file(Path::join(Path::getPathFromFilename(Path::getCurrentExecutablePath("")), "cppcheck.cfg"),
R"({"productName": "The Product"}\n)");
const char * const argv[] = {"cppcheck", "--errorlist"};
ASSERT_EQUALS(CmdLineParser::Result::Exit, parser->parseFromArgs(2, argv));
ASSERT_EQUALS("", logger->str()); // empty since it is logged via ErrorLogger
ASSERT(startsWith(GET_REDIRECT_OUTPUT, ErrorMessage::getXMLHeader("The Product")));
}

void errorlistExclusive() {
REDIRECT;
Expand All @@ -1705,6 +1729,16 @@ class TestCmdlineParser : public TestFixture {
ASSERT(endsWith(GET_REDIRECT_OUTPUT, "</results>\n"));
}

void errorlistWithInvalidCfg() {
REDIRECT;
ScopedFile file(Path::join(Path::getPathFromFilename(Path::getCurrentExecutablePath("")), "cppcheck.cfg"),
"{\n");
const char * const argv[] = {"cppcheck", "--errorlist"};
ASSERT_EQUALS(CmdLineParser::Result::Fail, parser->parseFromArgs(2, argv));
ASSERT_EQUALS("cppcheck: error: could not load cppcheck.cfg - not a valid JSON - syntax error at line 1 near: \n", logger->str());
ASSERT_EQUALS("", GET_REDIRECT_OUTPUT);
}

void ignorepathsnopath() {
REDIRECT;
const char * const argv[] = {"cppcheck", "-i"};
Expand Down Expand Up @@ -2309,6 +2343,15 @@ class TestCmdlineParser : public TestFixture {
ASSERT_EQUALS(CmdLineParser::Result::Fail, parser->parseFromArgs(2, argv));
ASSERT_EQUALS("cppcheck: error: Directory '' specified by --cppcheck-build-dir argument has to be existent.\n", logger->str());
}

void invalidCppcheckCfg() {
REDIRECT;
ScopedFile file(Path::join(Path::getPathFromFilename(Path::getCurrentExecutablePath("")), "cppcheck.cfg"),
"{\n");
const char * const argv[] = {"cppcheck", "test.cpp"};
ASSERT_EQUALS(CmdLineParser::Result::Fail, parser->parseFromArgs(2, argv));
ASSERT_EQUALS("cppcheck: error: could not load cppcheck.cfg - not a valid JSON - syntax error at line 1 near: \n", logger->str());
}
};

REGISTER_TEST(TestCmdlineParser)
Loading
Loading