added testing of clang-tidy invocation to executor tests / also some cleanups (#5514)

This commit is contained in:
Oliver Stöneberg 2023-10-08 09:06:02 +02:00 committed by GitHub
parent eb076d877b
commit 8dee551cad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 231 additions and 69 deletions

View File

@ -802,7 +802,7 @@ test/testpostfixoperator.o: test/testpostfixoperator.cpp lib/check.h lib/checkpo
test/testpreprocessor.o: test/testpreprocessor.cpp externals/simplecpp/simplecpp.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.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 test/helpers.h test/testpreprocessor.o: test/testpreprocessor.cpp externals/simplecpp/simplecpp.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.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 test/helpers.h
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testpreprocessor.cpp $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testpreprocessor.cpp
test/testprocessexecutor.o: test/testprocessexecutor.cpp cli/executor.h cli/processexecutor.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h test/redirect.h test/testprocessexecutor.o: test/testprocessexecutor.cpp cli/executor.h cli/processexecutor.h lib/analyzerinfo.h lib/check.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h test/redirect.h
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testprocessexecutor.cpp $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testprocessexecutor.cpp
test/testsettings.o: test/testsettings.cpp lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.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/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.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
@ -841,7 +841,7 @@ test/testsuppressions.o: test/testsuppressions.cpp cli/cppcheckexecutor.h cli/ex
test/testsymboldatabase.o: test/testsymboldatabase.cpp lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.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 test/testsymboldatabase.o: test/testsymboldatabase.cpp lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.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/testsymboldatabase.cpp $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsymboldatabase.cpp
test/testthreadexecutor.o: test/testthreadexecutor.cpp cli/executor.h cli/threadexecutor.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h test/redirect.h test/testthreadexecutor.o: test/testthreadexecutor.cpp cli/executor.h cli/threadexecutor.h lib/analyzerinfo.h lib/check.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h test/redirect.h
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testthreadexecutor.cpp $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testthreadexecutor.cpp
test/testtimer.o: test/testtimer.cpp lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h test/fixture.h test/testtimer.o: test/testtimer.cpp lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h test/fixture.h

View File

@ -325,9 +325,9 @@ int CppCheckExecutor::check_internal(CppCheck& cppcheck)
returnValue = executor.check(); returnValue = executor.check();
} else { } else {
#if defined(THREADING_MODEL_THREAD) #if defined(THREADING_MODEL_THREAD)
ThreadExecutor executor(mFiles, settings, settings.nomsg, *this); ThreadExecutor executor(mFiles, settings, settings.nomsg, *this, CppCheckExecutor::executeCommand);
#elif defined(THREADING_MODEL_FORK) #elif defined(THREADING_MODEL_FORK)
ProcessExecutor executor(mFiles, settings, settings.nomsg, *this); ProcessExecutor executor(mFiles, settings, settings.nomsg, *this, CppCheckExecutor::executeCommand);
#endif #endif
returnValue = executor.check(); returnValue = executor.check();
} }

View File

@ -62,8 +62,9 @@ enum class Color;
using std::memset; using std::memset;
ProcessExecutor::ProcessExecutor(const std::map<std::string, std::size_t> &files, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger) ProcessExecutor::ProcessExecutor(const std::map<std::string, std::size_t> &files, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger, CppCheck::ExecuteCmdFn executeCommand)
: Executor(files, settings, suppressions, errorLogger) : Executor(files, settings, suppressions, errorLogger)
, mExecuteCommand(std::move(executeCommand))
{ {
assert(mSettings.jobs > 1); assert(mSettings.jobs > 1);
} }
@ -272,7 +273,7 @@ unsigned int ProcessExecutor::check()
close(pipes[0]); close(pipes[0]);
PipeWriter pipewriter(pipes[1]); PipeWriter pipewriter(pipes[1]);
CppCheck fileChecker(pipewriter, false, CppCheckExecutor::executeCommand); CppCheck fileChecker(pipewriter, false, mExecuteCommand);
fileChecker.settings() = mSettings; fileChecker.settings() = mSettings;
unsigned int resultOfCheck = 0; unsigned int resultOfCheck = 0;

View File

@ -19,6 +19,7 @@
#ifndef PROCESSEXECUTOR_H #ifndef PROCESSEXECUTOR_H
#define PROCESSEXECUTOR_H #define PROCESSEXECUTOR_H
#include "cppcheck.h"
#include "executor.h" #include "executor.h"
#include <cstddef> #include <cstddef>
@ -38,7 +39,7 @@ class Suppressions;
*/ */
class ProcessExecutor : public Executor { class ProcessExecutor : public Executor {
public: public:
ProcessExecutor(const std::map<std::string, std::size_t> &files, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger); ProcessExecutor(const std::map<std::string, std::size_t> &files, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger, CppCheck::ExecuteCmdFn executeCommand);
ProcessExecutor(const ProcessExecutor &) = delete; ProcessExecutor(const ProcessExecutor &) = delete;
void operator=(const ProcessExecutor &) = delete; void operator=(const ProcessExecutor &) = delete;
@ -63,6 +64,8 @@ private:
* @param msg The error message * @param msg The error message
*/ */
void reportInternalChildErr(const std::string &childname, const std::string &msg); void reportInternalChildErr(const std::string &childname, const std::string &msg);
CppCheck::ExecuteCmdFn mExecuteCommand;
}; };
/// @} /// @}

View File

@ -41,8 +41,9 @@
enum class Color; enum class Color;
ThreadExecutor::ThreadExecutor(const std::map<std::string, std::size_t> &files, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger) ThreadExecutor::ThreadExecutor(const std::map<std::string, std::size_t> &files, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger, CppCheck::ExecuteCmdFn executeCommand)
: Executor(files, settings, suppressions, errorLogger) : Executor(files, settings, suppressions, errorLogger)
, mExecuteCommand(std::move(executeCommand))
{ {
assert(mSettings.jobs > 1); assert(mSettings.jobs > 1);
} }
@ -82,8 +83,8 @@ private:
class ThreadData class ThreadData
{ {
public: public:
ThreadData(ThreadExecutor &threadExecutor, ErrorLogger &errorLogger, const Settings &settings, const std::map<std::string, std::size_t> &files, const std::list<ImportProject::FileSettings> &fileSettings) ThreadData(ThreadExecutor &threadExecutor, ErrorLogger &errorLogger, const Settings &settings, const std::map<std::string, std::size_t> &files, const std::list<ImportProject::FileSettings> &fileSettings, CppCheck::ExecuteCmdFn executeCommand)
: mFiles(files), mFileSettings(fileSettings), mSettings(settings), logForwarder(threadExecutor, errorLogger) : mFiles(files), mFileSettings(fileSettings), mSettings(settings), mExecuteCommand(std::move(executeCommand)), logForwarder(threadExecutor, errorLogger)
{ {
mItNextFile = mFiles.begin(); mItNextFile = mFiles.begin();
mItNextFileSettings = mFileSettings.begin(); mItNextFileSettings = mFileSettings.begin();
@ -115,7 +116,7 @@ public:
} }
unsigned int check(ErrorLogger &errorLogger, const std::string *file, const ImportProject::FileSettings *fs) const { unsigned int check(ErrorLogger &errorLogger, const std::string *file, const ImportProject::FileSettings *fs) const {
CppCheck fileChecker(errorLogger, false, CppCheckExecutor::executeCommand); CppCheck fileChecker(errorLogger, false, mExecuteCommand);
fileChecker.settings() = mSettings; // this is a copy fileChecker.settings() = mSettings; // this is a copy
unsigned int result; unsigned int result;
@ -153,6 +154,7 @@ private:
std::mutex mFileSync; std::mutex mFileSync;
const Settings &mSettings; const Settings &mSettings;
CppCheck::ExecuteCmdFn mExecuteCommand;
public: public:
SyncLogForwarder logForwarder; SyncLogForwarder logForwarder;
@ -180,7 +182,7 @@ unsigned int ThreadExecutor::check()
std::vector<std::future<unsigned int>> threadFutures; std::vector<std::future<unsigned int>> threadFutures;
threadFutures.reserve(mSettings.jobs); threadFutures.reserve(mSettings.jobs);
ThreadData data(*this, mErrorLogger, mSettings, mFiles, mSettings.project.fileSettings); ThreadData data(*this, mErrorLogger, mSettings, mFiles, mSettings.project.fileSettings, mExecuteCommand);
for (unsigned int i = 0; i < mSettings.jobs; ++i) { for (unsigned int i = 0; i < mSettings.jobs; ++i) {
try { try {

View File

@ -19,6 +19,7 @@
#ifndef THREADEXECUTOR_H #ifndef THREADEXECUTOR_H
#define THREADEXECUTOR_H #define THREADEXECUTOR_H
#include "cppcheck.h"
#include "executor.h" #include "executor.h"
#include <cstddef> #include <cstddef>
@ -37,14 +38,16 @@ class Suppressions;
* all files using threads. * all files using threads.
*/ */
class ThreadExecutor : public Executor { class ThreadExecutor : public Executor {
friend class SyncLogForwarder;
public: public:
ThreadExecutor(const std::map<std::string, std::size_t> &files, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger); ThreadExecutor(const std::map<std::string, std::size_t> &files, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger, CppCheck::ExecuteCmdFn executeCommand);
ThreadExecutor(const ThreadExecutor &) = delete; ThreadExecutor(const ThreadExecutor &) = delete;
void operator=(const ThreadExecutor &) = delete; void operator=(const ThreadExecutor &) = delete;
unsigned int check() override; unsigned int check() override;
friend class SyncLogForwarder; CppCheck::ExecuteCmdFn mExecuteCommand;
}; };
/// @} /// @}

View File

@ -54,8 +54,8 @@ class CPPCHECKLIB Library {
// TODO: get rid of this // TODO: get rid of this
friend class TestSymbolDatabase; // For testing only friend class TestSymbolDatabase; // For testing only
friend class TestSingleExecutorBase; // For testing only friend class TestSingleExecutorBase; // For testing only
friend class TestThreadExecutor; // For testing only friend class TestThreadExecutorBase; // For testing only
friend class TestProcessExecutor; // For testing only friend class TestProcessExecutorBase; // For testing only
public: public:
Library() = default; Library() = default;

View File

@ -34,15 +34,18 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
class TestProcessExecutor : public TestFixture { class TestProcessExecutorBase : public TestFixture {
public: public:
TestProcessExecutor() : TestFixture("TestProcessExecutor") {} TestProcessExecutorBase(const char * const name, bool useFS) : TestFixture(name), useFS(useFS) {}
private: private:
Settings settings = settingsBuilder().library("std.cfg").build(); Settings settings = settingsBuilder().library("std.cfg").build();
bool useFS;
static std::string fprefix() std::string fprefix() const
{ {
if (useFS)
return "processfs";
return "process"; return "process";
} }
@ -53,6 +56,10 @@ private:
SHOWTIME_MODES showtime = SHOWTIME_MODES::SHOWTIME_NONE; SHOWTIME_MODES showtime = SHOWTIME_MODES::SHOWTIME_NONE;
const char* plistOutput = nullptr; const char* plistOutput = nullptr;
std::vector<std::string> filesList; std::vector<std::string> filesList;
bool clangTidy = false;
bool executeCommandCalled = false;
std::string exe;
std::vector<std::string> args;
}; };
/** /**
@ -63,35 +70,67 @@ private:
errout.str(""); errout.str("");
output.str(""); output.str("");
Settings s = settings;
std::map<std::string, std::size_t> filemap; std::map<std::string, std::size_t> filemap;
if (opt.filesList.empty()) { if (opt.filesList.empty()) {
for (int i = 1; i <= files; ++i) { for (int i = 1; i <= files; ++i) {
std::ostringstream oss; std::string f_s = fprefix() + "_" + std::to_string(i) + ".cpp";
oss << fprefix() << "_" << i << ".cpp"; filemap[f_s] = data.size();
filemap[oss.str()] = data.size(); if (useFS) {
ImportProject::FileSettings fs;
fs.filename = std::move(f_s);
s.project.fileSettings.emplace_back(std::move(fs));
}
} }
} }
else { else {
for (const auto& f : opt.filesList) for (const auto& f : opt.filesList)
{ {
filemap[f] = data.size(); filemap[f] = data.size();
if (useFS) {
ImportProject::FileSettings fs;
fs.filename = f;
s.project.fileSettings.emplace_back(std::move(fs));
}
} }
} }
Settings s = settings;
s.jobs = jobs; s.jobs = jobs;
s.showtime = opt.showtime; s.showtime = opt.showtime;
settings.quiet = opt.quiet; s.quiet = opt.quiet;
if (opt.plistOutput) if (opt.plistOutput)
s.plistOutput = opt.plistOutput; s.plistOutput = opt.plistOutput;
// TODO: test with settings.project.fileSettings;
ProcessExecutor executor(filemap, s, s.nomsg, *this); bool executeCommandCalled = false;
std::string exe;
std::vector<std::string> args;
// NOLINTNEXTLINE(performance-unnecessary-value-param)
auto executeFn = [&executeCommandCalled, &exe, &args](std::string e,std::vector<std::string> a,std::string,std::string&){
executeCommandCalled = true;
exe = std::move(e);
args = std::move(a);
return EXIT_SUCCESS;
};
std::vector<std::unique_ptr<ScopedFile>> scopedfiles; std::vector<std::unique_ptr<ScopedFile>> scopedfiles;
scopedfiles.reserve(filemap.size()); scopedfiles.reserve(filemap.size());
for (std::map<std::string, std::size_t>::const_iterator i = filemap.cbegin(); i != filemap.cend(); ++i) for (std::map<std::string, std::size_t>::const_iterator i = filemap.cbegin(); i != filemap.cend(); ++i)
scopedfiles.emplace_back(new ScopedFile(i->first, data)); scopedfiles.emplace_back(new ScopedFile(i->first, data));
// clear files list so only fileSettings are used
if (useFS)
filemap.clear();
ProcessExecutor executor(filemap, s, s.nomsg, *this, executeFn);
ASSERT_EQUALS(result, executor.check()); ASSERT_EQUALS(result, executor.check());
ASSERT_EQUALS(opt.executeCommandCalled, executeCommandCalled);
ASSERT_EQUALS(opt.exe, exe);
ASSERT_EQUALS(opt.args.size(), args.size());
for (int i = 0; i < args.size(); ++i)
{
ASSERT_EQUALS(opt.args[i], args[i]);
}
} }
void run() override { void run() override {
@ -106,6 +145,7 @@ private:
TEST_CASE(one_error_less_files); TEST_CASE(one_error_less_files);
TEST_CASE(one_error_several_files); TEST_CASE(one_error_several_files);
TEST_CASE(markup); TEST_CASE(markup);
TEST_CASE(clangTidy);
TEST_CASE(showtime_top5_file); TEST_CASE(showtime_top5_file);
TEST_CASE(showtime_top5_summary); TEST_CASE(showtime_top5_summary);
TEST_CASE(showtime_file); TEST_CASE(showtime_file);
@ -148,7 +188,7 @@ private:
} }
void many_threads_plist() { void many_threads_plist() {
const char plistOutput[] = "plist_process/"; const std::string plistOutput = "plist_" + fprefix() + "/";
ScopedFile plistFile("dummy", "", plistOutput); ScopedFile plistFile("dummy", "", plistOutput);
check(16, 100, 100, check(16, 100, 100,
@ -156,7 +196,7 @@ private:
"{\n" "{\n"
" char *a = malloc(10);\n" " char *a = malloc(10);\n"
" return 0;\n" " return 0;\n"
"}", dinit(CheckOptions, $.plistOutput = plistOutput)); "}", dinit(CheckOptions, $.plistOutput = plistOutput.c_str()));
} }
void no_errors_more_files() { void no_errors_more_files() {
@ -241,6 +281,34 @@ private:
settings = settingsOld; settings = settingsOld;
} }
void clangTidy() {
// TODO: we currently only invoke it with ImportProject::FileSettings
if (!useFS)
return;
#ifdef _WIN32
const char exe[] = "clang-tidy.exe";
#else
const char exe[] = "clang-tidy";
#endif
(void)exe;
const std::string file = fprefix() + "_1.cpp";
// TODO: the invocation cannot be checked as the code is called in the forked process
check(2, 1, 0,
"int main()\n"
"{\n"
" return 0;\n"
"}",
dinit(CheckOptions,
$.quiet = false,
$.clangTidy = true /*,
$.executeCommandCalled = true,
$.exe = exe,
$.args = {"-quiet", "-checks=*,-clang-analyzer-*,-llvm*", file, "--"}*/));
ASSERT_EQUALS("Checking " + file + " ...\n", output.str());
}
// TODO: provide data which actually shows values above 0 // TODO: provide data which actually shows values above 0
// TODO: should this be logged only once like summary? // TODO: should this be logged only once like summary?
@ -303,8 +371,18 @@ private:
TODO_ASSERT(output_s.find("Check time: " + fprefix() + "_2.cpp: ") != std::string::npos); TODO_ASSERT(output_s.find("Check time: " + fprefix() + "_2.cpp: ") != std::string::npos);
} }
// TODO: test clang-tidy
// TODO: test whole program analysis // TODO: test whole program analysis
}; };
REGISTER_TEST(TestProcessExecutor) class TestProcessExecutorFiles : public TestProcessExecutorBase {
public:
TestProcessExecutorFiles() : TestProcessExecutorBase("TestProcessExecutorFiles", false) {}
};
class TestProcessExecutorFS : public TestProcessExecutorBase {
public:
TestProcessExecutorFS() : TestProcessExecutorBase("TestProcessExecutorFS", true) {}
};
REGISTER_TEST(TestProcessExecutorFiles)
REGISTER_TEST(TestProcessExecutorFS)

View File

@ -68,6 +68,7 @@ private:
SHOWTIME_MODES showtime = SHOWTIME_MODES::SHOWTIME_NONE; SHOWTIME_MODES showtime = SHOWTIME_MODES::SHOWTIME_NONE;
const char* plistOutput = nullptr; const char* plistOutput = nullptr;
std::vector<std::string> filesList; std::vector<std::string> filesList;
bool clangTidy = false;
bool executeCommandCalled = false; bool executeCommandCalled = false;
std::string exe; std::string exe;
std::vector<std::string> args; std::vector<std::string> args;
@ -76,17 +77,18 @@ private:
void check(int files, int result, const std::string &data, const CheckOptions& opt = make_default_obj{}) { void check(int files, int result, const std::string &data, const CheckOptions& opt = make_default_obj{}) {
errout.str(""); errout.str("");
output.str(""); output.str("");
settings.project.fileSettings.clear();
Settings s = settings;
std::map<std::string, std::size_t> filemap; std::map<std::string, std::size_t> filemap;
if (opt.filesList.empty()) { if (opt.filesList.empty()) {
for (int i = 1; i <= files; ++i) { for (int i = 1; i <= files; ++i) {
const std::string s = fprefix() + "_" + zpad3(i) + ".cpp"; std::string f_s = fprefix() + "_" + zpad3(i) + ".cpp";
filemap[s] = data.size(); filemap[f_s] = data.size();
if (useFS) { if (useFS) {
ImportProject::FileSettings fs; ImportProject::FileSettings fs;
fs.filename = s; fs.filename = std::move(f_s);
settings.project.fileSettings.emplace_back(std::move(fs)); s.project.fileSettings.emplace_back(std::move(fs));
} }
} }
} }
@ -97,15 +99,16 @@ private:
if (useFS) { if (useFS) {
ImportProject::FileSettings fs; ImportProject::FileSettings fs;
fs.filename = f; fs.filename = f;
settings.project.fileSettings.emplace_back(std::move(fs)); s.project.fileSettings.emplace_back(std::move(fs));
} }
} }
} }
settings.showtime = opt.showtime; s.showtime = opt.showtime;
settings.quiet = opt.quiet; s.quiet = opt.quiet;
if (opt.plistOutput) if (opt.plistOutput)
settings.plistOutput = opt.plistOutput; s.plistOutput = opt.plistOutput;
s.clangTidy = opt.clangTidy;
bool executeCommandCalled = false; bool executeCommandCalled = false;
std::string exe; std::string exe;
@ -117,7 +120,7 @@ private:
args = std::move(a); args = std::move(a);
return EXIT_SUCCESS; return EXIT_SUCCESS;
}); });
cppcheck.settings() = settings; cppcheck.settings() = s;
std::vector<std::unique_ptr<ScopedFile>> scopedfiles; std::vector<std::unique_ptr<ScopedFile>> scopedfiles;
scopedfiles.reserve(filemap.size()); scopedfiles.reserve(filemap.size());
@ -128,8 +131,7 @@ private:
if (useFS) if (useFS)
filemap.clear(); filemap.clear();
// TODO: test with settings.project.fileSettings; SingleExecutor executor(cppcheck, filemap, s, s.nomsg, *this);
SingleExecutor executor(cppcheck, filemap, settings, settings.nomsg, *this);
ASSERT_EQUALS(result, executor.check()); ASSERT_EQUALS(result, executor.check());
ASSERT_EQUALS(opt.executeCommandCalled, executeCommandCalled); ASSERT_EQUALS(opt.executeCommandCalled, executeCommandCalled);
ASSERT_EQUALS(opt.exe, exe); ASSERT_EQUALS(opt.exe, exe);
@ -274,9 +276,6 @@ private:
if (!useFS) if (!useFS)
return; return;
const Settings settingsOld = settings;
settings.clangTidy = true;
#ifdef _WIN32 #ifdef _WIN32
const char exe[] = "clang-tidy.exe"; const char exe[] = "clang-tidy.exe";
#else #else
@ -291,11 +290,11 @@ private:
"}", "}",
dinit(CheckOptions, dinit(CheckOptions,
$.quiet = false, $.quiet = false,
$.clangTidy = true,
$.executeCommandCalled = true, $.executeCommandCalled = true,
$.exe = exe, $.exe = exe,
$.args = {"-quiet", "-checks=*,-clang-analyzer-*,-llvm*", file, "--"})); $.args = {"-quiet", "-checks=*,-clang-analyzer-*,-llvm*", file, "--"}));
ASSERT_EQUALS("Checking " + file + " ...\n", output.str()); ASSERT_EQUALS("Checking " + file + " ...\n", output.str());
settings = settingsOld;
} }
// TODO: provide data which actually shows values above 0 // TODO: provide data which actually shows values above 0

View File

@ -235,7 +235,7 @@ private:
if (!suppression.empty()) { if (!suppression.empty()) {
EXPECT_EQ("", settings.nomsg.addSuppressionLine(suppression)); EXPECT_EQ("", settings.nomsg.addSuppressionLine(suppression));
} }
ThreadExecutor executor(files, settings, settings.nomsg, *this); ThreadExecutor executor(files, settings, settings.nomsg, *this, CppCheckExecutor::executeCommand);
std::vector<std::unique_ptr<ScopedFile>> scopedfiles; std::vector<std::unique_ptr<ScopedFile>> scopedfiles;
scopedfiles.reserve(files.size()); scopedfiles.reserve(files.size());
for (std::map<std::string, std::size_t>::const_iterator i = files.cbegin(); i != files.cend(); ++i) for (std::map<std::string, std::size_t>::const_iterator i = files.cbegin(); i != files.cend(); ++i)
@ -263,7 +263,7 @@ private:
if (!suppression.empty()) { if (!suppression.empty()) {
EXPECT_EQ("", settings.nomsg.addSuppressionLine(suppression)); EXPECT_EQ("", settings.nomsg.addSuppressionLine(suppression));
} }
ProcessExecutor executor(files, settings, settings.nomsg, *this); ProcessExecutor executor(files, settings, settings.nomsg, *this, CppCheckExecutor::executeCommand);
std::vector<std::unique_ptr<ScopedFile>> scopedfiles; std::vector<std::unique_ptr<ScopedFile>> scopedfiles;
scopedfiles.reserve(files.size()); scopedfiles.reserve(files.size());
for (std::map<std::string, std::size_t>::const_iterator i = files.cbegin(); i != files.cend(); ++i) for (std::map<std::string, std::size_t>::const_iterator i = files.cbegin(); i != files.cend(); ++i)

View File

@ -34,15 +34,18 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
class TestThreadExecutor : public TestFixture { class TestThreadExecutorBase : public TestFixture {
public: public:
TestThreadExecutor() : TestFixture("TestThreadExecutor") {} TestThreadExecutorBase(const char * const name, bool useFS) : TestFixture(name), useFS(useFS) {}
private: private:
Settings settings = settingsBuilder().library("std.cfg").build(); Settings settings = settingsBuilder().library("std.cfg").build();
bool useFS;
static std::string fprefix() std::string fprefix() const
{ {
if (useFS)
return "threadfs";
return "thread"; return "thread";
} }
@ -53,6 +56,10 @@ private:
SHOWTIME_MODES showtime = SHOWTIME_MODES::SHOWTIME_NONE; SHOWTIME_MODES showtime = SHOWTIME_MODES::SHOWTIME_NONE;
const char* plistOutput = nullptr; const char* plistOutput = nullptr;
std::vector<std::string> filesList; std::vector<std::string> filesList;
bool clangTidy = false;
bool executeCommandCalled = false;
std::string exe;
std::vector<std::string> args;
}; };
/** /**
@ -63,35 +70,68 @@ private:
errout.str(""); errout.str("");
output.str(""); output.str("");
Settings s = settings;
std::map<std::string, std::size_t> filemap; std::map<std::string, std::size_t> filemap;
if (opt.filesList.empty()) { if (opt.filesList.empty()) {
for (int i = 1; i <= files; ++i) { for (int i = 1; i <= files; ++i) {
std::ostringstream oss; std::string f_s = fprefix() + "_" + std::to_string(i) + ".cpp";
oss << fprefix() << "_" << i << ".cpp"; filemap[f_s] = data.size();
filemap[oss.str()] = data.size(); if (useFS) {
ImportProject::FileSettings fs;
fs.filename = std::move(f_s);
s.project.fileSettings.emplace_back(std::move(fs));
}
} }
} }
else { else {
for (const auto& f : opt.filesList) for (const auto& f : opt.filesList)
{ {
filemap[f] = data.size(); filemap[f] = data.size();
if (useFS) {
ImportProject::FileSettings fs;
fs.filename = f;
s.project.fileSettings.emplace_back(std::move(fs));
}
} }
} }
Settings settings1 = settings; s.jobs = jobs;
settings1.jobs = jobs; s.showtime = opt.showtime;
settings1.showtime = opt.showtime; s.quiet = opt.quiet;
settings1.quiet = opt.quiet;
if (opt.plistOutput) if (opt.plistOutput)
settings1.plistOutput = opt.plistOutput; s.plistOutput = opt.plistOutput;
// TODO: test with settings.project.fileSettings; s.clangTidy = opt.clangTidy;
ThreadExecutor executor(filemap, settings1, settings1.nomsg, *this);
bool executeCommandCalled = false;
std::string exe;
std::vector<std::string> args;
// NOLINTNEXTLINE(performance-unnecessary-value-param)
auto executeFn = [&executeCommandCalled, &exe, &args](std::string e,std::vector<std::string> a,std::string,std::string&){
executeCommandCalled = true;
exe = std::move(e);
args = std::move(a);
return EXIT_SUCCESS;
};
std::vector<std::unique_ptr<ScopedFile>> scopedfiles; std::vector<std::unique_ptr<ScopedFile>> scopedfiles;
scopedfiles.reserve(filemap.size()); scopedfiles.reserve(filemap.size());
for (std::map<std::string, std::size_t>::const_iterator i = filemap.cbegin(); i != filemap.cend(); ++i) for (std::map<std::string, std::size_t>::const_iterator i = filemap.cbegin(); i != filemap.cend(); ++i)
scopedfiles.emplace_back(new ScopedFile(i->first, data)); scopedfiles.emplace_back(new ScopedFile(i->first, data));
// clear files list so only fileSettings are used
if (useFS)
filemap.clear();
ThreadExecutor executor(filemap, s, s.nomsg, *this, executeFn);
ASSERT_EQUALS(result, executor.check()); ASSERT_EQUALS(result, executor.check());
ASSERT_EQUALS(opt.executeCommandCalled, executeCommandCalled);
ASSERT_EQUALS(opt.exe, exe);
ASSERT_EQUALS(opt.args.size(), args.size());
for (int i = 0; i < args.size(); ++i)
{
ASSERT_EQUALS(opt.args[i], args[i]);
}
} }
void run() override { void run() override {
@ -105,6 +145,7 @@ private:
TEST_CASE(one_error_less_files); TEST_CASE(one_error_less_files);
TEST_CASE(one_error_several_files); TEST_CASE(one_error_several_files);
TEST_CASE(markup); TEST_CASE(markup);
TEST_CASE(clangTidy);
TEST_CASE(showtime_top5_file); TEST_CASE(showtime_top5_file);
TEST_CASE(showtime_top5_summary); TEST_CASE(showtime_top5_summary);
TEST_CASE(showtime_file); TEST_CASE(showtime_file);
@ -142,12 +183,11 @@ private:
"{\n" "{\n"
" char *a = malloc(10);\n" " char *a = malloc(10);\n"
" return 0;\n" " return 0;\n"
"}", dinit(CheckOptions, "}", dinit(CheckOptions, $.showtime = SHOWTIME_MODES::SHOWTIME_SUMMARY));
$.showtime = SHOWTIME_MODES::SHOWTIME_SUMMARY));
} }
void many_threads_plist() { void many_threads_plist() {
const char plistOutput[] = "plist_thread/"; const std::string plistOutput = "plist_" + fprefix() + "/";
ScopedFile plistFile("dummy", "", plistOutput); ScopedFile plistFile("dummy", "", plistOutput);
check(16, 100, 100, check(16, 100, 100,
@ -155,8 +195,7 @@ private:
"{\n" "{\n"
" char *a = malloc(10);\n" " char *a = malloc(10);\n"
" return 0;\n" " return 0;\n"
"}", dinit(CheckOptions, "}", dinit(CheckOptions, $.plistOutput = plistOutput.c_str()));
$.plistOutput = plistOutput));
} }
void no_errors_more_files() { void no_errors_more_files() {
@ -217,7 +256,9 @@ private:
" char *a = malloc(10);\n" " char *a = malloc(10);\n"
" return 0;\n" " return 0;\n"
"}", "}",
dinit(CheckOptions, $.filesList = files)); dinit(CheckOptions,
$.quiet = false,
$.filesList = files));
// TODO: order of "Checking" and "checked" is affected by thread // TODO: order of "Checking" and "checked" is affected by thread
/*TODO_ASSERT_EQUALS("Checking " + fprefix() + "_2.cpp ...\n" /*TODO_ASSERT_EQUALS("Checking " + fprefix() + "_2.cpp ...\n"
"1/4 files checked 25% done\n" "1/4 files checked 25% done\n"
@ -239,6 +280,31 @@ private:
settings = settingsOld; settings = settingsOld;
} }
void clangTidy() {
// TODO: we currently only invoke it with ImportProject::FileSettings
if (!useFS)
return;
#ifdef _WIN32
const char exe[] = "clang-tidy.exe";
#else
const char exe[] = "clang-tidy";
#endif
const std::string file = fprefix() + "_1.cpp";
check(2, 1, 0,
"int main()\n"
"{\n"
" return 0;\n"
"}",
dinit(CheckOptions,
$.quiet = false,
$.clangTidy = true,
$.executeCommandCalled = true,
$.exe = exe,
$.args = {"-quiet", "-checks=*,-clang-analyzer-*,-llvm*", file, "--"}));
ASSERT_EQUALS("Checking " + file + " ...\n", output.str());
}
// TODO: provide data which actually shows values above 0 // TODO: provide data which actually shows values above 0
@ -302,8 +368,18 @@ private:
ASSERT(output_s.find("Check time: " + fprefix() + "_2.cpp: ") != std::string::npos); ASSERT(output_s.find("Check time: " + fprefix() + "_2.cpp: ") != std::string::npos);
} }
// TODO: test clang-tidy
// TODO: test whole program analysis // TODO: test whole program analysis
}; };
REGISTER_TEST(TestThreadExecutor) class TestThreadExecutorFiles : public TestThreadExecutorBase {
public:
TestThreadExecutorFiles() : TestThreadExecutorBase("TestThreadExecutorFiles", false) {}
};
class TestThreadExecutorFS : public TestThreadExecutorBase {
public:
TestThreadExecutorFS() : TestThreadExecutorBase("TestThreadExecutorFS", true) {}
};
REGISTER_TEST(TestThreadExecutorFiles)
REGISTER_TEST(TestThreadExecutorFS)