C++ Utilities 5.26.1
Useful C++ classes and routines such as argument parser, IO and conversion utilities
Loading...
Searching...
No Matches
testutils.h
Go to the documentation of this file.
1#ifndef TESTUTILS_H
2#define TESTUTILS_H
3
5#include "../chrono/format.h"
6#include "../misc/traits.h"
7
8#include <iomanip>
9#include <optional>
10#include <ostream>
11#include <string>
12
13#if defined(PLATFORM_UNIX) || defined(CPP_UTILITIES_BOOST_PROCESS)
14#define CPP_UTILITIES_HAS_EXEC_APP
15#endif
16
17// ensure CppUnit's macros produce unique variable names when doing unity builds
18#if defined(__COUNTER__)
19#undef CPPUNIT_UNIQUE_COUNTER
20#define CPPUNIT_UNIQUE_COUNTER __COUNTER__
21#endif
22
23namespace CppUtilities {
24
28enum class WorkingCopyMode {
30 NoCopy,
31 Cleanup,
32};
33
35public:
36 // construction/destruction
37 explicit TestApplication();
38 explicit TestApplication(int argc, const char *const *argv);
40 operator bool() const;
41
42 // helper for tests
43 std::string testFilePath(const std::string &relativeTestFilePath) const;
44 std::string testDirPath(const std::string &relativeTestDirPath) const;
45 std::string workingCopyPath(const std::string &relativeTestFilePath, WorkingCopyMode mode = WorkingCopyMode::CreateCopy) const;
46 std::string workingCopyPathAs(const std::string &relativeTestFilePath, const std::string &relativeWorkingCopyPath,
47 WorkingCopyMode mode = WorkingCopyMode::CreateCopy) const;
48#ifdef CPP_UTILITIES_HAS_EXEC_APP
49 int execApp(const char *const *args, std::string &output, std::string &errors, bool suppressLogging = false, int timeout = -1) const;
50#endif
51
52 // read-only accessors
53 const std::vector<std::string> &testFilePaths() const;
54 const std::string &workingDirectory() const;
55 const char *applicationPath();
56 bool unitsSpecified() const;
57 const std::vector<const char *> &units() const;
58 bool onlyListUnits() const;
59
60 // static read-only accessors
61 static const TestApplication *instance();
62 static const char *appPath();
63
64private:
65 static std::string readTestfilePathFromEnv();
66 static std::vector<std::string> readTestfilePathFromSrcRef();
67
68 ArgumentParser m_parser;
69 OperationArgument m_listArg;
70 OperationArgument m_runArg;
71 ConfigValueArgument m_testFilesPathArg;
72 ConfigValueArgument m_applicationPathArg;
73 ConfigValueArgument m_workingDirArg;
74 ConfigValueArgument m_unitsArg;
75 std::vector<std::string> m_testFilesPaths;
76 std::string m_workingDir;
77 bool m_valid;
78 static TestApplication *s_instance;
79};
80
87inline TestApplication::operator bool() const
88{
89 return m_valid;
90}
91
96{
97 return TestApplication::s_instance;
98}
99
103inline const char *TestApplication::appPath()
104{
105 return s_instance ? s_instance->applicationPath() : "";
106}
107
111inline const std::vector<std::string> &TestApplication::testFilePaths() const
112{
113 return m_testFilesPaths;
114}
115
119inline const std::string &TestApplication::workingDirectory() const
120{
121 return m_workingDir;
122}
123
128{
129 return m_applicationPathArg.firstValue() ? m_applicationPathArg.firstValue() : "";
130}
131
136{
137 return m_unitsArg.isPresent();
138}
139
144inline const std::vector<const char *> &TestApplication::units() const
145{
146 return m_unitsArg.values();
147}
148
153{
154 return m_listArg.isPresent();
155}
156
161inline CPP_UTILITIES_EXPORT std::string testFilePath(const std::string &relativeTestFilePath)
162{
163 return TestApplication::instance()->testFilePath(relativeTestFilePath);
164}
165
170inline CPP_UTILITIES_EXPORT std::string testDirPath(const std::string &relativeTestDirPath)
171{
172 return TestApplication::instance()->testDirPath(relativeTestDirPath);
173}
174
179inline CPP_UTILITIES_EXPORT std::string workingCopyPath(const std::string &relativeTestFilePath, WorkingCopyMode mode = WorkingCopyMode::CreateCopy)
180{
181 return TestApplication::instance()->workingCopyPathAs(relativeTestFilePath, relativeTestFilePath, mode);
182}
183
189 const std::string &relativeTestFilePath, const std::string &relativeWorkingCopyPath, WorkingCopyMode mode = WorkingCopyMode::CreateCopy)
190{
191 return TestApplication::instance()->workingCopyPathAs(relativeTestFilePath, relativeWorkingCopyPath, mode);
192}
193
194#ifdef CPP_UTILITIES_HAS_EXEC_APP
200inline CPP_UTILITIES_EXPORT int execApp(const char *const *args, std::string &output, std::string &errors)
201{
202 return TestApplication::instance()->execApp(args, output, errors);
203}
204
205CPP_UTILITIES_EXPORT int execHelperApp(
206 const char *appPath, const char *const *args, std::string &output, std::string &errors, bool suppressLogging = false, int timeout = -1);
207CPP_UTILITIES_EXPORT int execHelperAppInSearchPath(
208 const char *appName, const char *const *args, std::string &output, std::string &errors, bool suppressLogging = false, int timeout = -1);
209#endif
210
214template <typename Optional, Traits::EnableIf<Traits::IsSpecializationOf<Optional, std::optional>> * = nullptr>
215inline std::ostream &operator<<(std::ostream &out, const Optional &optional)
216{
217 if (optional.has_value()) {
218 return out << *optional;
219 } else {
220 return out << "[no value]";
221 }
222}
223
228template <typename T> class AsHexNumber {
229public:
232 : value(value)
233 {
234 }
235 const T &value;
236};
237
241template <typename T> bool operator==(const AsHexNumber<T> &lhs, const AsHexNumber<T> &rhs)
242{
243 return lhs.value == rhs.value;
244}
245
249template <typename T> std::ostream &operator<<(std::ostream &out, const AsHexNumber<T> &value)
250{
251 return out << '0' << 'x' << std::hex << std::setfill('0') << std::setw(2) << unsigned(value.value) << std::dec;
252}
253
258template <typename T> AsHexNumber<T> asHexNumber(const T &value)
259{
260 return AsHexNumber<T>(value);
261}
262
268template <typename T, Traits::EnableIf<std::is_integral<T>> * = nullptr> AsHexNumber<T> integralsAsHexNumber(const T &value)
269{
270 return AsHexNumber<T>(value);
271}
272
278template <typename T, Traits::DisableIf<std::is_integral<T>> * = nullptr> const T &integralsAsHexNumber(const T &value)
279{
280 return value;
281}
282
291#define TESTUTILS_ASSERT_EXEC(args) TESTUTILS_ASSERT_EXEC_EXIT_STATUS(args, 0)
292
301#ifdef CPP_UTILITIES_BOOST_PROCESS
302#define TESTUTILS_ASSERT_EXEC_EXIT_STATUS(args, expectedExitStatus) \
303 { \
304 const auto status = execApp(args, stdout, stderr); \
305 if (status != expectedExitStatus) { \
306 CPPUNIT_FAIL(::CppUtilities::argsToString( \
307 "app exited with status ", status, " (expected ", expectedExitStatus, ")\nstdout: ", stdout, "\nstderr: ", stderr)); \
308 } \
309 }
310#else
311#define TESTUTILS_ASSERT_EXEC_EXIT_STATUS(args, expectedExitStatus) \
312 { \
313 const auto status = execApp(args, stdout, stderr); \
314 if (!WIFEXITED(status)) { \
315 CPPUNIT_FAIL(::CppUtilities::argsToString("app did not terminate normally\nstdout: ", stdout, "\nstderr: ", stderr)); \
316 } \
317 if (const auto exitStatus = WEXITSTATUS(status); exitStatus != expectedExitStatus) { \
318 CPPUNIT_FAIL(::CppUtilities::argsToString( \
319 "app exited with status ", exitStatus, " (expected ", expectedExitStatus, ")\nstdout: ", stdout, "\nstderr: ", stderr)); \
320 } \
321 }
322#endif
323
328#define TESTUTILS_ASSERT_LIKE_FLAGS(message, expectedRegex, regexFlags, actualString) \
329 (CPPUNIT_NS::Asserter::failIf(!(std::regex_match(actualString, std::regex(expectedRegex, regexFlags))), \
330 CPPUNIT_NS::Message( \
331 CppUtilities::argsToString('\"', actualString, "\"\n not like\n\"", expectedRegex, '\"'), "Expression: " #actualString, message), \
332 CPPUNIT_SOURCELINE()))
333
338#define TESTUTILS_ASSERT_LIKE(message, expectedRegex, actualString) \
339 TESTUTILS_ASSERT_LIKE_FLAGS(message, expectedRegex, std::regex::ECMAScript, actualString)
340
344template <typename Pair, CppUtilities::Traits::EnableIf<CppUtilities::Traits::IsSpecializationOf<Pair, std::pair>> * = nullptr>
345inline std::ostream &operator<<(std::ostream &out, const Pair &pair)
346{
347 return out << "key: " << pair.first << "; value: " << pair.second << '\n';
348}
349
353template <typename Iteratable, Traits::EnableIf<Traits::IsIteratable<Iteratable>, Traits::Not<Traits::IsString<Iteratable>>> * = nullptr>
354inline std::ostream &operator<<(std::ostream &out, const Iteratable &iteratable)
355{
356 out << '\n';
357 std::size_t index = 0;
358 for (const auto &item : iteratable) {
359 out << std::setw(2) << index << ':' << ' ' << integralsAsHexNumber(item) << '\n';
360 ++index;
361 }
362 return out;
363}
364
368namespace Literals {
373constexpr std::size_t operator"" _st(unsigned long long size)
374{
375 return static_cast<std::size_t>(size);
376}
377
382constexpr std::uint64_t operator"" _uint64(unsigned long long size)
383{
384 return static_cast<std::uint64_t>(size);
385}
386
391constexpr std::int64_t operator"" _int64(unsigned long long size)
392{
393 return static_cast<std::int64_t>(size);
394}
395} // namespace Literals
396} // namespace CppUtilities
397
398#endif // TESTUTILS_H
The ArgumentParser class provides a means for handling command line arguments.
const char * firstValue() const
Returns the first parameter value of the first occurrence of the argument.
const std::vector< const char * > & values(std::size_t occurrence=0) const
Returns the parameter values for the specified occurrence of argument.
bool isPresent() const
Returns an indication whether the argument could be detected when parsing.
The AsHexNumber class allows printing values asserted with cppunit (or similar test framework) using ...
Definition testutils.h:228
AsHexNumber(const T &value)
Constructs a new instance; use asHexNumber() for convenience instead.
Definition testutils.h:231
The ConfigValueArgument class is an Argument where setCombinable() is true by default.
The OperationArgument class is an Argument where denotesOperation() is true by default.
The TestApplication class simplifies writing test applications that require opening test files.
Definition testutils.h:34
bool onlyListUnits() const
Returns whether the test application should only list available units and not actually run any tests.
Definition testutils.h:152
const std::vector< const char * > & units() const
Returns the specified test units.
Definition testutils.h:144
std::string testFilePath(const std::string &relativeTestFilePath) const
Returns the full path of the test file with the specified relativeTestFilePath.
static const char * appPath()
Returns the application path or an empty string if no application path has been set.
Definition testutils.h:103
const std::vector< std::string > & testFilePaths() const
Returns the list of directories to look for test files.
Definition testutils.h:111
bool unitsSpecified() const
Returns whether particular units have been specified.
Definition testutils.h:135
const char * applicationPath()
Returns the application path or an empty string if no application path has been set.
Definition testutils.h:127
const std::string & workingDirectory() const
Returns the directory which is supposed to used for storing files created by tests.
Definition testutils.h:119
static const TestApplication * instance()
Returns the current TestApplication instance.
Definition testutils.h:95
std::string workingCopyPathAs(const std::string &relativeTestFilePath, const std::string &relativeWorkingCopyPath, WorkingCopyMode mode=WorkingCopyMode::CreateCopy) const
Returns the full path to a working copy of the test file with the specified relativeTestFilePath.
std::string testDirPath(const std::string &relativeTestDirPath) const
Returns the full path of the test directory with the specified relativeTestDirPath.
#define CPP_UTILITIES_EXPORT
Marks the symbol to be exported by the c++utilities library.
Definition global.h:14
Contains all utilities provides by the c++utilities library.
CPP_UTILITIES_EXPORT std::string testFilePath(const std::string &relativeTestFilePath)
Convenience function to invoke TestApplication::testFilePath().
Definition testutils.h:161
CPP_UTILITIES_EXPORT std::string workingCopyPath(const std::string &relativeTestFilePath, WorkingCopyMode mode=WorkingCopyMode::CreateCopy)
Convenience function to invoke TestApplication::workingCopyPath().
Definition testutils.h:179
WorkingCopyMode
The WorkingCopyMode enum specifies additional options to influence behavior of TestApplication::worki...
Definition testutils.h:28
CPP_UTILITIES_EXPORT std::string testDirPath(const std::string &relativeTestDirPath)
Convenience function to invoke TestApplication::testDirPath().
Definition testutils.h:170
CPP_UTILITIES_EXPORT std::ostream & operator<<(std::ostream &out, Indentation indentation)
bool operator==(const AsHexNumber< T > &lhs, const AsHexNumber< T > &rhs)
Provides operator == required by CPPUNIT_ASSERT_EQUAL.
Definition testutils.h:241
AsHexNumber< T > asHexNumber(const T &value)
Wraps a value to be printed using the hex system in the error case when asserted with cppunit (or sim...
Definition testutils.h:258
CPP_UTILITIES_EXPORT std::string workingCopyPathAs(const std::string &relativeTestFilePath, const std::string &relativeWorkingCopyPath, WorkingCopyMode mode=WorkingCopyMode::CreateCopy)
Convenience function to invoke TestApplication::workingCopyPathAs().
Definition testutils.h:188
AsHexNumber< T > integralsAsHexNumber(const T &value)
Wraps a value to be printed using the hex system in the error case when asserted with cppunit (or sim...
Definition testutils.h:268