From faaedbce53e6a7a1e05c451ba5ff788fd010611f Mon Sep 17 00:00:00 2001 From: firewave Date: Mon, 17 Apr 2023 18:27:36 +0200 Subject: [PATCH 1/3] testrunner: added designated initialization helper --- test/CMakeLists.txt | 4 ++++ test/helpers.h | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 371654bb579..93d8b513dcf 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -35,6 +35,10 @@ if (BUILD_TESTS) target_compile_definitions(testrunner PRIVATE CPPCHECKLIB_IMPORT SIMPLECPP_IMPORT) target_link_libraries(testrunner cppcheck-core) endif() + if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") + # $ is used in dinit() dessignated initialization helper + target_compile_options_safe(testrunner -Wno-dollar-in-identifier-extension) + endif() if (NOT CMAKE_DISABLE_PRECOMPILE_HEADERS) target_precompile_headers(testrunner PRIVATE precompiled.h) diff --git a/test/helpers.h b/test/helpers.h index 621544cf28e..54dd63cea89 100644 --- a/test/helpers.h +++ b/test/helpers.h @@ -92,4 +92,18 @@ class PreprocessorHelper static std::string getcode(Preprocessor &preprocessor, const std::string &filedata, const std::string &cfg, const std::string &filename, Suppressions *inlineSuppression = nullptr); }; +/* designated initialization helper + Usage: + struct S + { + int i; + }; + + const auto s = dinit(S, + $.i = 1 + ); + */ +#define dinit(T, ...) \ + ([&] { T ${}; __VA_ARGS__; return $; }()) + #endif // helpersH From baccbc6f3f91751cbe6208cee02b619b8e70f6fd Mon Sep 17 00:00:00 2001 From: firewave Date: Mon, 17 Apr 2023 18:35:09 +0200 Subject: [PATCH 2/3] testrunner: use structs with `dinit` to pass options --- test/testprocessexecutor.cpp | 27 +++++++++++++++++---------- test/testsingleexecutor.cpp | 26 +++++++++++++++++--------- test/testthreadexecutor.cpp | 26 +++++++++++++++++--------- 3 files changed, 51 insertions(+), 28 deletions(-) diff --git a/test/testprocessexecutor.cpp b/test/testprocessexecutor.cpp index cef576b5e66..3f7070f64f0 100644 --- a/test/testprocessexecutor.cpp +++ b/test/testprocessexecutor.cpp @@ -46,16 +46,24 @@ class TestProcessExecutor : public TestFixture { return "process"; } + struct CheckOptions + { + CheckOptions() noexcept = default; + SHOWTIME_MODES showtime = SHOWTIME_MODES::SHOWTIME_NONE; + const char* plistOutput = nullptr; + std::vector filesList; + }; + /** * Execute check using n jobs for y files which are have * identical data, given within data. */ - void check(unsigned int jobs, int files, int result, const std::string &data, SHOWTIME_MODES showtime = SHOWTIME_MODES::SHOWTIME_NONE, const char* const plistOutput = nullptr, const std::vector& filesList = {}) { + void check(unsigned int jobs, int files, int result, const std::string &data, const CheckOptions &opt = {}) { errout.str(""); output.str(""); std::map filemap; - if (filesList.empty()) { + if (opt.filesList.empty()) { for (int i = 1; i <= files; ++i) { std::ostringstream oss; oss << fprefix() << "_" << i << ".cpp"; @@ -63,16 +71,16 @@ class TestProcessExecutor : public TestFixture { } } else { - for (const auto& f : filesList) + for (const auto& f : opt.filesList) { filemap[f] = data.size(); } } settings.jobs = jobs; - settings.showtime = showtime; - if (plistOutput) - settings.plistOutput = plistOutput; + settings.showtime = opt.showtime; + if (opt.plistOutput) + settings.plistOutput = opt.plistOutput; // TODO: test with settings.project.fileSettings; ProcessExecutor executor(filemap, settings, *this); std::vector> scopedfiles; @@ -127,7 +135,7 @@ class TestProcessExecutor : public TestFixture { "{\n" " char *a = malloc(10);\n" " return 0;\n" - "}", SHOWTIME_MODES::SHOWTIME_SUMMARY); + "}", dinit(CheckOptions, $.showtime = SHOWTIME_MODES::SHOWTIME_SUMMARY)); } void many_threads_plist() { @@ -139,7 +147,7 @@ class TestProcessExecutor : public TestFixture { "{\n" " char *a = malloc(10);\n" " return 0;\n" - "}", SHOWTIME_MODES::SHOWTIME_NONE, plistOutput); + "}", dinit(CheckOptions, $.plistOutput = plistOutput)); } void no_errors_more_files() { @@ -184,7 +192,6 @@ class TestProcessExecutor : public TestFixture { "}"); } - void markup() { const Settings settingsOld = settings; settings.library.mMarkupExtensions.emplace(".cp1"); @@ -201,7 +208,7 @@ class TestProcessExecutor : public TestFixture { " char *a = malloc(10);\n" " return 0;\n" "}", - SHOWTIME_MODES::SHOWTIME_NONE, nullptr, files); + dinit(CheckOptions, $.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" diff --git a/test/testsingleexecutor.cpp b/test/testsingleexecutor.cpp index 2bdf94c8608..5999686799a 100644 --- a/test/testsingleexecutor.cpp +++ b/test/testsingleexecutor.cpp @@ -61,13 +61,21 @@ class TestSingleExecutorBase : public TestFixture { return std::to_string(i); } - void check(int files, int result, const std::string &data, SHOWTIME_MODES showtime = SHOWTIME_MODES::SHOWTIME_NONE, const char* const plistOutput = nullptr, const std::vector& filesList = {}) { + struct CheckOptions + { + CheckOptions() noexcept = default; + SHOWTIME_MODES showtime = SHOWTIME_MODES::SHOWTIME_NONE; + const char* plistOutput = nullptr; + std::vector filesList; + }; + + void check(int files, int result, const std::string &data, const CheckOptions &opt = {}) { errout.str(""); output.str(""); settings.project.fileSettings.clear(); std::map filemap; - if (filesList.empty()) { + if (opt.filesList.empty()) { for (int i = 1; i <= files; ++i) { const std::string s = fprefix() + "_" + zpad3(i) + ".cpp"; filemap[s] = data.size(); @@ -79,7 +87,7 @@ class TestSingleExecutorBase : public TestFixture { } } else { - for (const auto& f : filesList) + for (const auto& f : opt.filesList) { filemap[f] = data.size(); if (useFS) { @@ -90,9 +98,9 @@ class TestSingleExecutorBase : public TestFixture { } } - settings.showtime = showtime; - if (plistOutput) - settings.plistOutput = plistOutput; + settings.showtime = opt.showtime; + if (opt.plistOutput) + settings.plistOutput = opt.plistOutput; // NOLINTNEXTLINE(performance-unnecessary-value-param) CppCheck cppcheck(*this, true, [](std::string,std::vector,std::string,std::string&){ return false; @@ -152,7 +160,7 @@ class TestSingleExecutorBase : public TestFixture { "{\n" " char *a = malloc(10);\n" " return 0;\n" - "}", SHOWTIME_MODES::SHOWTIME_SUMMARY); + "}", dinit(CheckOptions, $.showtime = SHOWTIME_MODES::SHOWTIME_SUMMARY)); } void many_files_plist() { @@ -164,7 +172,7 @@ class TestSingleExecutorBase : public TestFixture { "{\n" " char *a = malloc(10);\n" " return 0;\n" - "}", SHOWTIME_MODES::SHOWTIME_NONE, plistOutput); + "}", dinit(CheckOptions, $.plistOutput = plistOutput)); } void no_errors_more_files() { @@ -225,7 +233,7 @@ class TestSingleExecutorBase : public TestFixture { " char *a = malloc(10);\n" " return 0;\n" "}", - SHOWTIME_MODES::SHOWTIME_NONE, nullptr, files); + dinit(CheckOptions, $.filesList = files)); // TODO: filter out the "files checked" messages ASSERT_EQUALS("Checking " + fprefix() + "_2.cpp ...\n" "1/4 files checked 25% done\n" diff --git a/test/testthreadexecutor.cpp b/test/testthreadexecutor.cpp index 69b529a26e6..2adadd62af4 100644 --- a/test/testthreadexecutor.cpp +++ b/test/testthreadexecutor.cpp @@ -46,16 +46,24 @@ class TestThreadExecutor : public TestFixture { return "thread"; } + struct CheckOptions + { + CheckOptions() noexcept = default; + SHOWTIME_MODES showtime = SHOWTIME_MODES::SHOWTIME_NONE; + const char* plistOutput = nullptr; + std::vector filesList; + }; + /** * Execute check using n jobs for y files which are have * identical data, given within data. */ - void check(unsigned int jobs, int files, int result, const std::string &data, SHOWTIME_MODES showtime = SHOWTIME_MODES::SHOWTIME_NONE, const char* const plistOutput = nullptr, const std::vector& filesList = {}) { + void check(unsigned int jobs, int files, int result, const std::string &data, const CheckOptions &opt = {}) { errout.str(""); output.str(""); std::map filemap; - if (filesList.empty()) { + if (opt.filesList.empty()) { for (int i = 1; i <= files; ++i) { std::ostringstream oss; oss << fprefix() << "_" << i << ".cpp"; @@ -63,7 +71,7 @@ class TestThreadExecutor : public TestFixture { } } else { - for (const auto& f : filesList) + for (const auto& f : opt.filesList) { filemap[f] = data.size(); } @@ -71,9 +79,9 @@ class TestThreadExecutor : public TestFixture { Settings settings1 = settings; settings1.jobs = jobs; - settings1.showtime = showtime; - if (plistOutput) - settings1.plistOutput = plistOutput; + settings1.showtime = opt.showtime; + if (opt.plistOutput) + settings1.plistOutput = opt.plistOutput; // TODO: test with settings.project.fileSettings; ThreadExecutor executor(filemap, settings1, *this); std::vector> scopedfiles; @@ -126,7 +134,7 @@ class TestThreadExecutor : public TestFixture { "{\n" " char *a = malloc(10);\n" " return 0;\n" - "}", SHOWTIME_MODES::SHOWTIME_SUMMARY); + "}", dinit(CheckOptions, $.showtime = SHOWTIME_MODES::SHOWTIME_SUMMARY)); } void many_threads_plist() { @@ -138,7 +146,7 @@ class TestThreadExecutor : public TestFixture { "{\n" " char *a = malloc(10);\n" " return 0;\n" - "}", SHOWTIME_MODES::SHOWTIME_NONE, plistOutput); + "}", dinit(CheckOptions, $.plistOutput = plistOutput)); } void no_errors_more_files() { @@ -199,7 +207,7 @@ class TestThreadExecutor : public TestFixture { " char *a = malloc(10);\n" " return 0;\n" "}", - SHOWTIME_MODES::SHOWTIME_NONE, nullptr, files); + dinit(CheckOptions, $.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" From ab88131b6934529030e7eb26056886485cdc82a3 Mon Sep 17 00:00:00 2001 From: firewave Date: Fri, 28 Jul 2023 18:39:55 +0200 Subject: [PATCH 3/3] work around GCC 4.8 compiler errors with objects used in `dinit()` --- test/helpers.h | 13 +++++++++++++ test/testprocessexecutor.cpp | 2 +- test/testsingleexecutor.cpp | 2 +- test/testthreadexecutor.cpp | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/test/helpers.h b/test/helpers.h index 54dd63cea89..9699d6b1f84 100644 --- a/test/helpers.h +++ b/test/helpers.h @@ -106,4 +106,17 @@ class PreprocessorHelper #define dinit(T, ...) \ ([&] { T ${}; __VA_ARGS__; return $; }()) +#if (defined(__GNUC__) && (__GNUC__ >= 5)) || defined(__clang__) +// work around Clang compilation error +// error: default member initializer for 'y' needed within definition of enclosing class 'X' outside of member functions +// work around GCC compilation error +// error: default member initializer for ‘x::y::z’ required before the end of its enclosing class +// see https://stackoverflow.com/questions/53408962 +#define DINIT_NOEXCEPT noexcept +#else +// work around GCC 4.8 compilation error +// error: function 'x()' defaulted on its first declaration with an exception-specification that differs from the implicit declaration 'x()' +#define DINIT_NOEXCEPT +#endif + #endif // helpersH diff --git a/test/testprocessexecutor.cpp b/test/testprocessexecutor.cpp index 3f7070f64f0..100aaa580d8 100644 --- a/test/testprocessexecutor.cpp +++ b/test/testprocessexecutor.cpp @@ -48,7 +48,7 @@ class TestProcessExecutor : public TestFixture { struct CheckOptions { - CheckOptions() noexcept = default; + CheckOptions() DINIT_NOEXCEPT = default; SHOWTIME_MODES showtime = SHOWTIME_MODES::SHOWTIME_NONE; const char* plistOutput = nullptr; std::vector filesList; diff --git a/test/testsingleexecutor.cpp b/test/testsingleexecutor.cpp index 5999686799a..beb1dd78f65 100644 --- a/test/testsingleexecutor.cpp +++ b/test/testsingleexecutor.cpp @@ -63,7 +63,7 @@ class TestSingleExecutorBase : public TestFixture { struct CheckOptions { - CheckOptions() noexcept = default; + CheckOptions() DINIT_NOEXCEPT = default; SHOWTIME_MODES showtime = SHOWTIME_MODES::SHOWTIME_NONE; const char* plistOutput = nullptr; std::vector filesList; diff --git a/test/testthreadexecutor.cpp b/test/testthreadexecutor.cpp index 2adadd62af4..d438dfa13a0 100644 --- a/test/testthreadexecutor.cpp +++ b/test/testthreadexecutor.cpp @@ -48,7 +48,7 @@ class TestThreadExecutor : public TestFixture { struct CheckOptions { - CheckOptions() noexcept = default; + CheckOptions() DINIT_NOEXCEPT = default; SHOWTIME_MODES showtime = SHOWTIME_MODES::SHOWTIME_NONE; const char* plistOutput = nullptr; std::vector filesList;