diff --git a/Makefile b/Makefile index 36567d263..d6aa7e937 100644 --- a/Makefile +++ b/Makefile @@ -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 $(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 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 $(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 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 diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp index 162bbb453..3b0418a7f 100644 --- a/cli/cppcheckexecutor.cpp +++ b/cli/cppcheckexecutor.cpp @@ -325,9 +325,9 @@ int CppCheckExecutor::check_internal(CppCheck& cppcheck) returnValue = executor.check(); } else { #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) - ProcessExecutor executor(mFiles, settings, settings.nomsg, *this); + ProcessExecutor executor(mFiles, settings, settings.nomsg, *this, CppCheckExecutor::executeCommand); #endif returnValue = executor.check(); } diff --git a/cli/processexecutor.cpp b/cli/processexecutor.cpp index 0e1c7b041..29affc2ab 100644 --- a/cli/processexecutor.cpp +++ b/cli/processexecutor.cpp @@ -62,8 +62,9 @@ enum class Color; using std::memset; -ProcessExecutor::ProcessExecutor(const std::map &files, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger) +ProcessExecutor::ProcessExecutor(const std::map &files, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger, CppCheck::ExecuteCmdFn executeCommand) : Executor(files, settings, suppressions, errorLogger) + , mExecuteCommand(std::move(executeCommand)) { assert(mSettings.jobs > 1); } @@ -272,7 +273,7 @@ unsigned int ProcessExecutor::check() close(pipes[0]); PipeWriter pipewriter(pipes[1]); - CppCheck fileChecker(pipewriter, false, CppCheckExecutor::executeCommand); + CppCheck fileChecker(pipewriter, false, mExecuteCommand); fileChecker.settings() = mSettings; unsigned int resultOfCheck = 0; diff --git a/cli/processexecutor.h b/cli/processexecutor.h index 580c344cf..b7ee94dbe 100644 --- a/cli/processexecutor.h +++ b/cli/processexecutor.h @@ -19,6 +19,7 @@ #ifndef PROCESSEXECUTOR_H #define PROCESSEXECUTOR_H +#include "cppcheck.h" #include "executor.h" #include @@ -38,7 +39,7 @@ class Suppressions; */ class ProcessExecutor : public Executor { public: - ProcessExecutor(const std::map &files, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger); + ProcessExecutor(const std::map &files, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger, CppCheck::ExecuteCmdFn executeCommand); ProcessExecutor(const ProcessExecutor &) = delete; void operator=(const ProcessExecutor &) = delete; @@ -63,6 +64,8 @@ private: * @param msg The error message */ void reportInternalChildErr(const std::string &childname, const std::string &msg); + + CppCheck::ExecuteCmdFn mExecuteCommand; }; /// @} diff --git a/cli/threadexecutor.cpp b/cli/threadexecutor.cpp index aeffe9362..a52b535c7 100644 --- a/cli/threadexecutor.cpp +++ b/cli/threadexecutor.cpp @@ -41,8 +41,9 @@ enum class Color; -ThreadExecutor::ThreadExecutor(const std::map &files, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger) +ThreadExecutor::ThreadExecutor(const std::map &files, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger, CppCheck::ExecuteCmdFn executeCommand) : Executor(files, settings, suppressions, errorLogger) + , mExecuteCommand(std::move(executeCommand)) { assert(mSettings.jobs > 1); } @@ -82,8 +83,8 @@ private: class ThreadData { public: - ThreadData(ThreadExecutor &threadExecutor, ErrorLogger &errorLogger, const Settings &settings, const std::map &files, const std::list &fileSettings) - : mFiles(files), mFileSettings(fileSettings), mSettings(settings), logForwarder(threadExecutor, errorLogger) + ThreadData(ThreadExecutor &threadExecutor, ErrorLogger &errorLogger, const Settings &settings, const std::map &files, const std::list &fileSettings, CppCheck::ExecuteCmdFn executeCommand) + : mFiles(files), mFileSettings(fileSettings), mSettings(settings), mExecuteCommand(std::move(executeCommand)), logForwarder(threadExecutor, errorLogger) { mItNextFile = mFiles.begin(); mItNextFileSettings = mFileSettings.begin(); @@ -115,7 +116,7 @@ public: } 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 unsigned int result; @@ -153,6 +154,7 @@ private: std::mutex mFileSync; const Settings &mSettings; + CppCheck::ExecuteCmdFn mExecuteCommand; public: SyncLogForwarder logForwarder; @@ -180,7 +182,7 @@ unsigned int ThreadExecutor::check() std::vector> threadFutures; 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) { try { diff --git a/cli/threadexecutor.h b/cli/threadexecutor.h index 8ebae323b..52de732d9 100644 --- a/cli/threadexecutor.h +++ b/cli/threadexecutor.h @@ -19,6 +19,7 @@ #ifndef THREADEXECUTOR_H #define THREADEXECUTOR_H +#include "cppcheck.h" #include "executor.h" #include @@ -37,14 +38,16 @@ class Suppressions; * all files using threads. */ class ThreadExecutor : public Executor { + friend class SyncLogForwarder; + public: - ThreadExecutor(const std::map &files, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger); + ThreadExecutor(const std::map &files, const Settings &settings, Suppressions &suppressions, ErrorLogger &errorLogger, CppCheck::ExecuteCmdFn executeCommand); ThreadExecutor(const ThreadExecutor &) = delete; void operator=(const ThreadExecutor &) = delete; unsigned int check() override; - friend class SyncLogForwarder; + CppCheck::ExecuteCmdFn mExecuteCommand; }; /// @} diff --git a/lib/library.h b/lib/library.h index c91079939..6474699ea 100644 --- a/lib/library.h +++ b/lib/library.h @@ -54,8 +54,8 @@ class CPPCHECKLIB Library { // TODO: get rid of this friend class TestSymbolDatabase; // For testing only friend class TestSingleExecutorBase; // For testing only - friend class TestThreadExecutor; // For testing only - friend class TestProcessExecutor; // For testing only + friend class TestThreadExecutorBase; // For testing only + friend class TestProcessExecutorBase; // For testing only public: Library() = default; diff --git a/test/testprocessexecutor.cpp b/test/testprocessexecutor.cpp index 69757bf42..e47938cab 100644 --- a/test/testprocessexecutor.cpp +++ b/test/testprocessexecutor.cpp @@ -34,15 +34,18 @@ #include #include -class TestProcessExecutor : public TestFixture { +class TestProcessExecutorBase : public TestFixture { public: - TestProcessExecutor() : TestFixture("TestProcessExecutor") {} + TestProcessExecutorBase(const char * const name, bool useFS) : TestFixture(name), useFS(useFS) {} private: Settings settings = settingsBuilder().library("std.cfg").build(); + bool useFS; - static std::string fprefix() + std::string fprefix() const { + if (useFS) + return "processfs"; return "process"; } @@ -53,6 +56,10 @@ private: SHOWTIME_MODES showtime = SHOWTIME_MODES::SHOWTIME_NONE; const char* plistOutput = nullptr; std::vector filesList; + bool clangTidy = false; + bool executeCommandCalled = false; + std::string exe; + std::vector args; }; /** @@ -63,35 +70,67 @@ private: errout.str(""); output.str(""); + Settings s = settings; + std::map filemap; if (opt.filesList.empty()) { for (int i = 1; i <= files; ++i) { - std::ostringstream oss; - oss << fprefix() << "_" << i << ".cpp"; - filemap[oss.str()] = data.size(); + std::string f_s = fprefix() + "_" + std::to_string(i) + ".cpp"; + filemap[f_s] = data.size(); + if (useFS) { + ImportProject::FileSettings fs; + fs.filename = std::move(f_s); + s.project.fileSettings.emplace_back(std::move(fs)); + } } } else { for (const auto& f : opt.filesList) { 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.showtime = opt.showtime; - settings.quiet = opt.quiet; + s.quiet = opt.quiet; if (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 args; + // NOLINTNEXTLINE(performance-unnecessary-value-param) + auto executeFn = [&executeCommandCalled, &exe, &args](std::string e,std::vector a,std::string,std::string&){ + executeCommandCalled = true; + exe = std::move(e); + args = std::move(a); + return EXIT_SUCCESS; + }; + std::vector> scopedfiles; scopedfiles.reserve(filemap.size()); for (std::map::const_iterator i = filemap.cbegin(); i != filemap.cend(); ++i) 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(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 { @@ -106,6 +145,7 @@ private: TEST_CASE(one_error_less_files); TEST_CASE(one_error_several_files); TEST_CASE(markup); + TEST_CASE(clangTidy); TEST_CASE(showtime_top5_file); TEST_CASE(showtime_top5_summary); TEST_CASE(showtime_file); @@ -148,7 +188,7 @@ private: } void many_threads_plist() { - const char plistOutput[] = "plist_process/"; + const std::string plistOutput = "plist_" + fprefix() + "/"; ScopedFile plistFile("dummy", "", plistOutput); check(16, 100, 100, @@ -156,7 +196,7 @@ private: "{\n" " char *a = malloc(10);\n" " return 0;\n" - "}", dinit(CheckOptions, $.plistOutput = plistOutput)); + "}", dinit(CheckOptions, $.plistOutput = plistOutput.c_str())); } void no_errors_more_files() { @@ -241,6 +281,34 @@ private: 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: 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: test clang-tidy // 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) diff --git a/test/testsingleexecutor.cpp b/test/testsingleexecutor.cpp index 593ca2b67..01adac877 100644 --- a/test/testsingleexecutor.cpp +++ b/test/testsingleexecutor.cpp @@ -68,6 +68,7 @@ private: SHOWTIME_MODES showtime = SHOWTIME_MODES::SHOWTIME_NONE; const char* plistOutput = nullptr; std::vector filesList; + bool clangTidy = false; bool executeCommandCalled = false; std::string exe; std::vector args; @@ -76,17 +77,18 @@ private: void check(int files, int result, const std::string &data, const CheckOptions& opt = make_default_obj{}) { errout.str(""); output.str(""); - settings.project.fileSettings.clear(); + + Settings s = settings; std::map filemap; if (opt.filesList.empty()) { for (int i = 1; i <= files; ++i) { - const std::string s = fprefix() + "_" + zpad3(i) + ".cpp"; - filemap[s] = data.size(); + std::string f_s = fprefix() + "_" + zpad3(i) + ".cpp"; + filemap[f_s] = data.size(); if (useFS) { ImportProject::FileSettings fs; - fs.filename = s; - settings.project.fileSettings.emplace_back(std::move(fs)); + fs.filename = std::move(f_s); + s.project.fileSettings.emplace_back(std::move(fs)); } } } @@ -97,15 +99,16 @@ private: if (useFS) { ImportProject::FileSettings fs; fs.filename = f; - settings.project.fileSettings.emplace_back(std::move(fs)); + s.project.fileSettings.emplace_back(std::move(fs)); } } } - settings.showtime = opt.showtime; - settings.quiet = opt.quiet; + s.showtime = opt.showtime; + s.quiet = opt.quiet; if (opt.plistOutput) - settings.plistOutput = opt.plistOutput; + s.plistOutput = opt.plistOutput; + s.clangTidy = opt.clangTidy; bool executeCommandCalled = false; std::string exe; @@ -117,7 +120,7 @@ private: args = std::move(a); return EXIT_SUCCESS; }); - cppcheck.settings() = settings; + cppcheck.settings() = s; std::vector> scopedfiles; scopedfiles.reserve(filemap.size()); @@ -128,8 +131,7 @@ private: if (useFS) filemap.clear(); - // TODO: test with settings.project.fileSettings; - SingleExecutor executor(cppcheck, filemap, settings, settings.nomsg, *this); + SingleExecutor executor(cppcheck, filemap, s, s.nomsg, *this); ASSERT_EQUALS(result, executor.check()); ASSERT_EQUALS(opt.executeCommandCalled, executeCommandCalled); ASSERT_EQUALS(opt.exe, exe); @@ -274,9 +276,6 @@ private: if (!useFS) return; - const Settings settingsOld = settings; - settings.clangTidy = true; - #ifdef _WIN32 const char exe[] = "clang-tidy.exe"; #else @@ -291,11 +290,11 @@ private: "}", dinit(CheckOptions, $.quiet = false, + $.clangTidy = true, $.executeCommandCalled = true, $.exe = exe, $.args = {"-quiet", "-checks=*,-clang-analyzer-*,-llvm*", file, "--"})); ASSERT_EQUALS("Checking " + file + " ...\n", output.str()); - settings = settingsOld; } // TODO: provide data which actually shows values above 0 diff --git a/test/testsuppressions.cpp b/test/testsuppressions.cpp index 19fdf307c..bfcc121d7 100644 --- a/test/testsuppressions.cpp +++ b/test/testsuppressions.cpp @@ -235,7 +235,7 @@ private: if (!suppression.empty()) { EXPECT_EQ("", settings.nomsg.addSuppressionLine(suppression)); } - ThreadExecutor executor(files, settings, settings.nomsg, *this); + ThreadExecutor executor(files, settings, settings.nomsg, *this, CppCheckExecutor::executeCommand); std::vector> scopedfiles; scopedfiles.reserve(files.size()); for (std::map::const_iterator i = files.cbegin(); i != files.cend(); ++i) @@ -263,7 +263,7 @@ private: if (!suppression.empty()) { EXPECT_EQ("", settings.nomsg.addSuppressionLine(suppression)); } - ProcessExecutor executor(files, settings, settings.nomsg, *this); + ProcessExecutor executor(files, settings, settings.nomsg, *this, CppCheckExecutor::executeCommand); std::vector> scopedfiles; scopedfiles.reserve(files.size()); for (std::map::const_iterator i = files.cbegin(); i != files.cend(); ++i) diff --git a/test/testthreadexecutor.cpp b/test/testthreadexecutor.cpp index d12bf289a..2c36f274b 100644 --- a/test/testthreadexecutor.cpp +++ b/test/testthreadexecutor.cpp @@ -34,15 +34,18 @@ #include #include -class TestThreadExecutor : public TestFixture { +class TestThreadExecutorBase : public TestFixture { public: - TestThreadExecutor() : TestFixture("TestThreadExecutor") {} + TestThreadExecutorBase(const char * const name, bool useFS) : TestFixture(name), useFS(useFS) {} private: Settings settings = settingsBuilder().library("std.cfg").build(); + bool useFS; - static std::string fprefix() + std::string fprefix() const { + if (useFS) + return "threadfs"; return "thread"; } @@ -53,6 +56,10 @@ private: SHOWTIME_MODES showtime = SHOWTIME_MODES::SHOWTIME_NONE; const char* plistOutput = nullptr; std::vector filesList; + bool clangTidy = false; + bool executeCommandCalled = false; + std::string exe; + std::vector args; }; /** @@ -63,35 +70,68 @@ private: errout.str(""); output.str(""); + Settings s = settings; + std::map filemap; if (opt.filesList.empty()) { for (int i = 1; i <= files; ++i) { - std::ostringstream oss; - oss << fprefix() << "_" << i << ".cpp"; - filemap[oss.str()] = data.size(); + std::string f_s = fprefix() + "_" + std::to_string(i) + ".cpp"; + filemap[f_s] = data.size(); + if (useFS) { + ImportProject::FileSettings fs; + fs.filename = std::move(f_s); + s.project.fileSettings.emplace_back(std::move(fs)); + } } } else { for (const auto& f : opt.filesList) { filemap[f] = data.size(); + if (useFS) { + ImportProject::FileSettings fs; + fs.filename = f; + s.project.fileSettings.emplace_back(std::move(fs)); + } } } - Settings settings1 = settings; - settings1.jobs = jobs; - settings1.showtime = opt.showtime; - settings1.quiet = opt.quiet; + s.jobs = jobs; + s.showtime = opt.showtime; + s.quiet = opt.quiet; if (opt.plistOutput) - settings1.plistOutput = opt.plistOutput; - // TODO: test with settings.project.fileSettings; - ThreadExecutor executor(filemap, settings1, settings1.nomsg, *this); + s.plistOutput = opt.plistOutput; + s.clangTidy = opt.clangTidy; + + bool executeCommandCalled = false; + std::string exe; + std::vector args; + // NOLINTNEXTLINE(performance-unnecessary-value-param) + auto executeFn = [&executeCommandCalled, &exe, &args](std::string e,std::vector a,std::string,std::string&){ + executeCommandCalled = true; + exe = std::move(e); + args = std::move(a); + return EXIT_SUCCESS; + }; + std::vector> scopedfiles; scopedfiles.reserve(filemap.size()); for (std::map::const_iterator i = filemap.cbegin(); i != filemap.cend(); ++i) 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(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 { @@ -105,6 +145,7 @@ private: TEST_CASE(one_error_less_files); TEST_CASE(one_error_several_files); TEST_CASE(markup); + TEST_CASE(clangTidy); TEST_CASE(showtime_top5_file); TEST_CASE(showtime_top5_summary); TEST_CASE(showtime_file); @@ -142,12 +183,11 @@ private: "{\n" " char *a = malloc(10);\n" " return 0;\n" - "}", dinit(CheckOptions, - $.showtime = SHOWTIME_MODES::SHOWTIME_SUMMARY)); + "}", dinit(CheckOptions, $.showtime = SHOWTIME_MODES::SHOWTIME_SUMMARY)); } void many_threads_plist() { - const char plistOutput[] = "plist_thread/"; + const std::string plistOutput = "plist_" + fprefix() + "/"; ScopedFile plistFile("dummy", "", plistOutput); check(16, 100, 100, @@ -155,8 +195,7 @@ private: "{\n" " char *a = malloc(10);\n" " return 0;\n" - "}", dinit(CheckOptions, - $.plistOutput = plistOutput)); + "}", dinit(CheckOptions, $.plistOutput = plistOutput.c_str())); } void no_errors_more_files() { @@ -217,7 +256,9 @@ private: " char *a = malloc(10);\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_ASSERT_EQUALS("Checking " + fprefix() + "_2.cpp ...\n" "1/4 files checked 25% done\n" @@ -239,6 +280,31 @@ private: 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 @@ -302,8 +368,18 @@ private: ASSERT(output_s.find("Check time: " + fprefix() + "_2.cpp: ") != std::string::npos); } - // TODO: test clang-tidy // 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)