Skip to content

Commit 5d201c4

Browse files
authored
testrunner: use structs with designated initialization to pass options (#4975)
I need to add parameters to some `check()` functions in the tests and things are already pretty messy with having to specify all the default values - readability aside. I found this on https://stackoverflow.com/a/49572324/532627 - apparently the CC BY-SA license by StackOverflow allows the usage within GPL.
1 parent 4aae670 commit 5d201c4

File tree

5 files changed

+82
-28
lines changed

5 files changed

+82
-28
lines changed

test/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ if (BUILD_TESTS)
3535
target_compile_definitions(testrunner PRIVATE CPPCHECKLIB_IMPORT SIMPLECPP_IMPORT)
3636
target_link_libraries(testrunner cppcheck-core)
3737
endif()
38+
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
39+
# $ is used in dinit() dessignated initialization helper
40+
target_compile_options_safe(testrunner -Wno-dollar-in-identifier-extension)
41+
endif()
3842

3943
if (NOT CMAKE_DISABLE_PRECOMPILE_HEADERS)
4044
target_precompile_headers(testrunner PRIVATE precompiled.h)

test/helpers.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,4 +92,31 @@ class PreprocessorHelper
9292
static std::string getcode(Preprocessor &preprocessor, const std::string &filedata, const std::string &cfg, const std::string &filename, Suppressions *inlineSuppression = nullptr);
9393
};
9494

95+
/* designated initialization helper
96+
Usage:
97+
struct S
98+
{
99+
int i;
100+
};
101+
102+
const auto s = dinit(S,
103+
$.i = 1
104+
);
105+
*/
106+
#define dinit(T, ...) \
107+
([&] { T ${}; __VA_ARGS__; return $; }())
108+
109+
#if (defined(__GNUC__) && (__GNUC__ >= 5)) || defined(__clang__)
110+
// work around Clang compilation error
111+
// error: default member initializer for 'y' needed within definition of enclosing class 'X' outside of member functions
112+
// work around GCC compilation error
113+
// error: default member initializer for ‘x::y::z’ required before the end of its enclosing class
114+
// see https://stackoverflow.com/questions/53408962
115+
#define DINIT_NOEXCEPT noexcept
116+
#else
117+
// work around GCC 4.8 compilation error
118+
// error: function 'x()' defaulted on its first declaration with an exception-specification that differs from the implicit declaration 'x()'
119+
#define DINIT_NOEXCEPT
120+
#endif
121+
95122
#endif // helpersH

test/testprocessexecutor.cpp

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -46,33 +46,41 @@ class TestProcessExecutor : public TestFixture {
4646
return "process";
4747
}
4848

49+
struct CheckOptions
50+
{
51+
CheckOptions() DINIT_NOEXCEPT = default;
52+
SHOWTIME_MODES showtime = SHOWTIME_MODES::SHOWTIME_NONE;
53+
const char* plistOutput = nullptr;
54+
std::vector<std::string> filesList;
55+
};
56+
4957
/**
5058
* Execute check using n jobs for y files which are have
5159
* identical data, given within data.
5260
*/
53-
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<std::string>& filesList = {}) {
61+
void check(unsigned int jobs, int files, int result, const std::string &data, const CheckOptions &opt = {}) {
5462
errout.str("");
5563
output.str("");
5664

5765
std::map<std::string, std::size_t> filemap;
58-
if (filesList.empty()) {
66+
if (opt.filesList.empty()) {
5967
for (int i = 1; i <= files; ++i) {
6068
std::ostringstream oss;
6169
oss << fprefix() << "_" << i << ".cpp";
6270
filemap[oss.str()] = data.size();
6371
}
6472
}
6573
else {
66-
for (const auto& f : filesList)
74+
for (const auto& f : opt.filesList)
6775
{
6876
filemap[f] = data.size();
6977
}
7078
}
7179

7280
settings.jobs = jobs;
73-
settings.showtime = showtime;
74-
if (plistOutput)
75-
settings.plistOutput = plistOutput;
81+
settings.showtime = opt.showtime;
82+
if (opt.plistOutput)
83+
settings.plistOutput = opt.plistOutput;
7684
// TODO: test with settings.project.fileSettings;
7785
ProcessExecutor executor(filemap, settings, *this);
7886
std::vector<std::unique_ptr<ScopedFile>> scopedfiles;
@@ -127,7 +135,7 @@ class TestProcessExecutor : public TestFixture {
127135
"{\n"
128136
" char *a = malloc(10);\n"
129137
" return 0;\n"
130-
"}", SHOWTIME_MODES::SHOWTIME_SUMMARY);
138+
"}", dinit(CheckOptions, $.showtime = SHOWTIME_MODES::SHOWTIME_SUMMARY));
131139
}
132140

133141
void many_threads_plist() {
@@ -139,7 +147,7 @@ class TestProcessExecutor : public TestFixture {
139147
"{\n"
140148
" char *a = malloc(10);\n"
141149
" return 0;\n"
142-
"}", SHOWTIME_MODES::SHOWTIME_NONE, plistOutput);
150+
"}", dinit(CheckOptions, $.plistOutput = plistOutput));
143151
}
144152

145153
void no_errors_more_files() {
@@ -184,7 +192,6 @@ class TestProcessExecutor : public TestFixture {
184192
"}");
185193
}
186194

187-
188195
void markup() {
189196
const Settings settingsOld = settings;
190197
settings.library.mMarkupExtensions.emplace(".cp1");
@@ -201,7 +208,7 @@ class TestProcessExecutor : public TestFixture {
201208
" char *a = malloc(10);\n"
202209
" return 0;\n"
203210
"}",
204-
SHOWTIME_MODES::SHOWTIME_NONE, nullptr, files);
211+
dinit(CheckOptions, $.filesList = files));
205212
// TODO: order of "Checking" and "checked" is affected by thread
206213
/*TODO_ASSERT_EQUALS("Checking " + fprefix() + "_2.cpp ...\n"
207214
"1/4 files checked 25% done\n"

test/testsingleexecutor.cpp

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,21 @@ class TestSingleExecutorBase : public TestFixture {
6161
return std::to_string(i);
6262
}
6363

64-
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<std::string>& filesList = {}) {
64+
struct CheckOptions
65+
{
66+
CheckOptions() DINIT_NOEXCEPT = default;
67+
SHOWTIME_MODES showtime = SHOWTIME_MODES::SHOWTIME_NONE;
68+
const char* plistOutput = nullptr;
69+
std::vector<std::string> filesList;
70+
};
71+
72+
void check(int files, int result, const std::string &data, const CheckOptions &opt = {}) {
6573
errout.str("");
6674
output.str("");
6775
settings.project.fileSettings.clear();
6876

6977
std::map<std::string, std::size_t> filemap;
70-
if (filesList.empty()) {
78+
if (opt.filesList.empty()) {
7179
for (int i = 1; i <= files; ++i) {
7280
const std::string s = fprefix() + "_" + zpad3(i) + ".cpp";
7381
filemap[s] = data.size();
@@ -79,7 +87,7 @@ class TestSingleExecutorBase : public TestFixture {
7987
}
8088
}
8189
else {
82-
for (const auto& f : filesList)
90+
for (const auto& f : opt.filesList)
8391
{
8492
filemap[f] = data.size();
8593
if (useFS) {
@@ -90,9 +98,9 @@ class TestSingleExecutorBase : public TestFixture {
9098
}
9199
}
92100

93-
settings.showtime = showtime;
94-
if (plistOutput)
95-
settings.plistOutput = plistOutput;
101+
settings.showtime = opt.showtime;
102+
if (opt.plistOutput)
103+
settings.plistOutput = opt.plistOutput;
96104
// NOLINTNEXTLINE(performance-unnecessary-value-param)
97105
CppCheck cppcheck(*this, true, [](std::string,std::vector<std::string>,std::string,std::string&){
98106
return false;
@@ -152,7 +160,7 @@ class TestSingleExecutorBase : public TestFixture {
152160
"{\n"
153161
" char *a = malloc(10);\n"
154162
" return 0;\n"
155-
"}", SHOWTIME_MODES::SHOWTIME_SUMMARY);
163+
"}", dinit(CheckOptions, $.showtime = SHOWTIME_MODES::SHOWTIME_SUMMARY));
156164
}
157165

158166
void many_files_plist() {
@@ -164,7 +172,7 @@ class TestSingleExecutorBase : public TestFixture {
164172
"{\n"
165173
" char *a = malloc(10);\n"
166174
" return 0;\n"
167-
"}", SHOWTIME_MODES::SHOWTIME_NONE, plistOutput);
175+
"}", dinit(CheckOptions, $.plistOutput = plistOutput));
168176
}
169177

170178
void no_errors_more_files() {
@@ -225,7 +233,7 @@ class TestSingleExecutorBase : public TestFixture {
225233
" char *a = malloc(10);\n"
226234
" return 0;\n"
227235
"}",
228-
SHOWTIME_MODES::SHOWTIME_NONE, nullptr, files);
236+
dinit(CheckOptions, $.filesList = files));
229237
// TODO: filter out the "files checked" messages
230238
ASSERT_EQUALS("Checking " + fprefix() + "_2.cpp ...\n"
231239
"1/4 files checked 25% done\n"

test/testthreadexecutor.cpp

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,34 +46,42 @@ class TestThreadExecutor : public TestFixture {
4646
return "thread";
4747
}
4848

49+
struct CheckOptions
50+
{
51+
CheckOptions() DINIT_NOEXCEPT = default;
52+
SHOWTIME_MODES showtime = SHOWTIME_MODES::SHOWTIME_NONE;
53+
const char* plistOutput = nullptr;
54+
std::vector<std::string> filesList;
55+
};
56+
4957
/**
5058
* Execute check using n jobs for y files which are have
5159
* identical data, given within data.
5260
*/
53-
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<std::string>& filesList = {}) {
61+
void check(unsigned int jobs, int files, int result, const std::string &data, const CheckOptions &opt = {}) {
5462
errout.str("");
5563
output.str("");
5664

5765
std::map<std::string, std::size_t> filemap;
58-
if (filesList.empty()) {
66+
if (opt.filesList.empty()) {
5967
for (int i = 1; i <= files; ++i) {
6068
std::ostringstream oss;
6169
oss << fprefix() << "_" << i << ".cpp";
6270
filemap[oss.str()] = data.size();
6371
}
6472
}
6573
else {
66-
for (const auto& f : filesList)
74+
for (const auto& f : opt.filesList)
6775
{
6876
filemap[f] = data.size();
6977
}
7078
}
7179

7280
Settings settings1 = settings;
7381
settings1.jobs = jobs;
74-
settings1.showtime = showtime;
75-
if (plistOutput)
76-
settings1.plistOutput = plistOutput;
82+
settings1.showtime = opt.showtime;
83+
if (opt.plistOutput)
84+
settings1.plistOutput = opt.plistOutput;
7785
// TODO: test with settings.project.fileSettings;
7886
ThreadExecutor executor(filemap, settings1, *this);
7987
std::vector<std::unique_ptr<ScopedFile>> scopedfiles;
@@ -126,7 +134,7 @@ class TestThreadExecutor : public TestFixture {
126134
"{\n"
127135
" char *a = malloc(10);\n"
128136
" return 0;\n"
129-
"}", SHOWTIME_MODES::SHOWTIME_SUMMARY);
137+
"}", dinit(CheckOptions, $.showtime = SHOWTIME_MODES::SHOWTIME_SUMMARY));
130138
}
131139

132140
void many_threads_plist() {
@@ -138,7 +146,7 @@ class TestThreadExecutor : public TestFixture {
138146
"{\n"
139147
" char *a = malloc(10);\n"
140148
" return 0;\n"
141-
"}", SHOWTIME_MODES::SHOWTIME_NONE, plistOutput);
149+
"}", dinit(CheckOptions, $.plistOutput = plistOutput));
142150
}
143151

144152
void no_errors_more_files() {
@@ -199,7 +207,7 @@ class TestThreadExecutor : public TestFixture {
199207
" char *a = malloc(10);\n"
200208
" return 0;\n"
201209
"}",
202-
SHOWTIME_MODES::SHOWTIME_NONE, nullptr, files);
210+
dinit(CheckOptions, $.filesList = files));
203211
// TODO: order of "Checking" and "checked" is affected by thread
204212
/*TODO_ASSERT_EQUALS("Checking " + fprefix() + "_2.cpp ...\n"
205213
"1/4 files checked 25% done\n"

0 commit comments

Comments
 (0)