/*
* Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2023 Cppcheck team.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "color.h"
#include "cppcheck.h"
#include "errorlogger.h"
#include "filesettings.h"
#include "fixture.h"
#include "helpers.h"
#include
#include
#include
class TestCppcheck : public TestFixture {
public:
TestCppcheck() : TestFixture("TestCppcheck") {}
private:
class ErrorLogger2 : public ErrorLogger {
public:
std::list ids;
std::list errmsgs;
private:
void reportOut(const std::string & /*outmsg*/, Color /*c*/ = Color::Reset) override {}
void reportErr(const ErrorMessage &msg) override {
ids.push_back(msg.id);
errmsgs.push_back(msg);
}
};
void run() override {
TEST_CASE(getErrorMessages);
TEST_CASE(checkWithFile);
TEST_CASE(checkWithFS);
TEST_CASE(suppress_error_library);
TEST_CASE(unique_errors);
}
void getErrorMessages() const {
ErrorLogger2 errorLogger;
CppCheck::getErrorMessages(errorLogger);
ASSERT(!errorLogger.ids.empty());
// Check if there are duplicate error ids in errorLogger.id
std::string duplicate;
for (std::list::const_iterator it = errorLogger.ids.cbegin();
it != errorLogger.ids.cend();
++it) {
if (std::find(errorLogger.ids.cbegin(), it, *it) != it) {
duplicate = "Duplicate ID: " + *it;
break;
}
}
ASSERT_EQUALS("", duplicate);
// Check for error ids from this class.
bool foundPurgedConfiguration = false;
bool foundTooManyConfigs = false;
for (const std::string & it : errorLogger.ids) {
if (it == "purgedConfiguration")
foundPurgedConfiguration = true;
else if (it == "toomanyconfigs")
foundTooManyConfigs = true;
}
ASSERT(foundPurgedConfiguration);
ASSERT(foundTooManyConfigs);
}
void checkWithFile() const
{
ScopedFile file("test.cpp",
"int main()\n"
"{\n"
" int i = *((int*)0);\n"
" return 0;\n"
"}");
ErrorLogger2 errorLogger;
CppCheck cppcheck(errorLogger, false, {});
ASSERT_EQUALS(1, cppcheck.check(file.path()));
// TODO: how to properly disable these warnings?
errorLogger.ids.erase(std::remove_if(errorLogger.ids.begin(), errorLogger.ids.end(), [](const std::string& id) {
return id == "logChecker";
}), errorLogger.ids.end());
ASSERT_EQUALS(1, errorLogger.ids.size());
ASSERT_EQUALS("nullPointer", *errorLogger.ids.cbegin());
}
void checkWithFS() const
{
ScopedFile file("test.cpp",
"int main()\n"
"{\n"
" int i = *((int*)0);\n"
" return 0;\n"
"}");
ErrorLogger2 errorLogger;
CppCheck cppcheck(errorLogger, false, {});
FileSettings fs;
fs.filename = file.path();
ASSERT_EQUALS(1, cppcheck.check(fs));
// TODO: how to properly disable these warnings?
errorLogger.ids.erase(std::remove_if(errorLogger.ids.begin(), errorLogger.ids.end(), [](const std::string& id) {
return id == "logChecker";
}), errorLogger.ids.end());
ASSERT_EQUALS(1, errorLogger.ids.size());
ASSERT_EQUALS("nullPointer", *errorLogger.ids.cbegin());
}
void suppress_error_library() const
{
ScopedFile file("test.cpp",
"int main()\n"
"{\n"
" int i = *((int*)0);\n"
" return 0;\n"
"}");
ErrorLogger2 errorLogger;
CppCheck cppcheck(errorLogger, false, {});
const char xmldata[] = R"()";
const Settings s = settingsBuilder().libraryxml(xmldata, sizeof(xmldata)).build();
cppcheck.settings() = s;
ASSERT_EQUALS(0, cppcheck.check(file.path()));
// TODO: how to properly disable these warnings?
errorLogger.ids.erase(std::remove_if(errorLogger.ids.begin(), errorLogger.ids.end(), [](const std::string& id) {
return id == "logChecker";
}), errorLogger.ids.end());
ASSERT_EQUALS(0, errorLogger.ids.size());
}
// TODO: hwo to actually get duplicated findings
void unique_errors() const
{
ScopedFile file("inc.h",
"inline void f()\n"
"{\n"
" (void)*((int*)0);\n"
"}");
ScopedFile test_file_a("a.cpp",
"#include \"inc.h\"");
ScopedFile test_file_b("b.cpp",
"#include \"inc.h\"");
ErrorLogger2 errorLogger;
CppCheck cppcheck(errorLogger, false, {});
ASSERT_EQUALS(1, cppcheck.check(test_file_a.path()));
ASSERT_EQUALS(1, cppcheck.check(test_file_b.path()));
// TODO: how to properly disable these warnings?
errorLogger.errmsgs.erase(std::remove_if(errorLogger.errmsgs.begin(), errorLogger.errmsgs.end(), [](const ErrorMessage& errmsg) {
return errmsg.id == "logChecker";
}), errorLogger.errmsgs.end());
// the internal errorlist is cleared after each check() call
ASSERT_EQUALS(2, errorLogger.errmsgs.size());
auto it = errorLogger.errmsgs.cbegin();
ASSERT_EQUALS("nullPointer", it->id);
++it;
ASSERT_EQUALS("nullPointer", it->id);
}
// TODO: test suppressions
// TODO: test all with FS
};
REGISTER_TEST(TestCppcheck)