2016-02-06 02:52:06 +01:00
|
|
|
#ifndef TESTUTILS_H
|
|
|
|
#define TESTUTILS_H
|
|
|
|
|
|
|
|
#include "../application/argumentparser.h"
|
2017-09-03 20:13:27 +02:00
|
|
|
#include "../conversion/types.h"
|
2017-05-10 23:32:48 +02:00
|
|
|
#include "../misc/traits.h"
|
2016-02-06 02:52:06 +01:00
|
|
|
|
2017-10-23 01:11:11 +02:00
|
|
|
#include <iomanip>
|
2016-07-27 18:24:37 +02:00
|
|
|
#include <ostream>
|
2017-05-01 03:13:11 +02:00
|
|
|
#include <string>
|
2016-02-06 02:52:06 +01:00
|
|
|
|
|
|
|
namespace TestUtilities {
|
|
|
|
|
2017-02-04 20:16:50 +01:00
|
|
|
/*!
|
|
|
|
* \brief The WorkingCopyMode enum specifies additional options to influence behavior of TestApplication::workingCopyPathMode().
|
|
|
|
*/
|
2017-05-01 03:13:11 +02:00
|
|
|
enum class WorkingCopyMode {
|
2017-02-04 20:16:50 +01:00
|
|
|
CreateCopy, /**< a working copy of the test file is created */
|
|
|
|
NoCopy /**< only the directory for the working copy is created but not the test file itself */
|
|
|
|
};
|
|
|
|
|
2017-05-01 03:13:11 +02:00
|
|
|
class CPP_UTILITIES_EXPORT TestApplication {
|
2016-02-06 02:52:06 +01:00
|
|
|
public:
|
|
|
|
TestApplication(int argc, char **argv);
|
|
|
|
~TestApplication();
|
|
|
|
|
|
|
|
operator bool() const;
|
|
|
|
std::string testFilePath(const std::string &name) const;
|
2016-02-27 01:18:54 +01:00
|
|
|
#ifdef PLATFORM_UNIX
|
2017-02-04 20:16:50 +01:00
|
|
|
std::string workingCopyPathMode(const std::string &name, WorkingCopyMode mode) const;
|
2016-02-09 02:21:42 +01:00
|
|
|
std::string workingCopyPath(const std::string &name) const;
|
2016-08-15 22:35:37 +02:00
|
|
|
int execApp(const char *const *args, std::string &output, std::string &errors, bool suppressLogging = false, int timeout = -1) const;
|
2016-02-27 01:18:54 +01:00
|
|
|
#endif
|
2016-06-12 01:56:57 +02:00
|
|
|
bool unitsSpecified() const;
|
|
|
|
const std::vector<const char *> &units() const;
|
2016-02-06 02:52:06 +01:00
|
|
|
static const TestApplication *instance();
|
2017-10-21 21:25:26 +02:00
|
|
|
static const char *appPath();
|
2016-02-06 02:52:06 +01:00
|
|
|
|
|
|
|
private:
|
2018-02-03 17:08:43 +01:00
|
|
|
static std::string readTestfilePathFromEnv();
|
|
|
|
static std::string readTestfilePathFromSrcRef();
|
2017-10-30 23:01:07 +01:00
|
|
|
|
2016-02-06 02:52:06 +01:00
|
|
|
ApplicationUtilities::ArgumentParser m_parser;
|
|
|
|
ApplicationUtilities::HelpArgument m_helpArg;
|
|
|
|
ApplicationUtilities::Argument m_testFilesPathArg;
|
2016-07-30 22:34:31 +02:00
|
|
|
ApplicationUtilities::Argument m_applicationPathArg;
|
2016-02-09 02:21:42 +01:00
|
|
|
ApplicationUtilities::Argument m_workingDirArg;
|
2016-05-01 20:09:20 +02:00
|
|
|
ApplicationUtilities::Argument m_unitsArg;
|
2017-10-30 23:01:07 +01:00
|
|
|
std::string m_testFilesPath;
|
|
|
|
std::string m_fallbackTestFilesPath;
|
2016-02-09 02:21:42 +01:00
|
|
|
std::string m_workingDir;
|
2016-02-06 02:52:06 +01:00
|
|
|
bool m_valid;
|
|
|
|
static TestApplication *m_instance;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns whether the TestApplication instance is valid.
|
2016-02-09 02:21:42 +01:00
|
|
|
*
|
|
|
|
* An instance is considered invalid if an error occured when
|
|
|
|
* parsing the command line arguments.
|
2016-02-06 02:52:06 +01:00
|
|
|
*/
|
|
|
|
inline TestApplication::operator bool() const
|
|
|
|
{
|
|
|
|
return m_valid;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the current TestApplication instance.
|
|
|
|
*/
|
|
|
|
inline const TestApplication *TestApplication::instance()
|
|
|
|
{
|
|
|
|
return TestApplication::m_instance;
|
|
|
|
}
|
|
|
|
|
2017-10-21 21:25:26 +02:00
|
|
|
/*!
|
|
|
|
* \brief Returns the application path or an empty string if no application path has been set.
|
|
|
|
*/
|
|
|
|
inline const char *TestApplication::appPath()
|
|
|
|
{
|
|
|
|
return m_instance && m_instance->m_applicationPathArg.firstValue() ? m_instance->m_applicationPathArg.firstValue() : "";
|
|
|
|
}
|
|
|
|
|
2016-06-12 01:56:57 +02:00
|
|
|
/*!
|
|
|
|
* \brief Returns whether particular units have been specified.
|
|
|
|
*/
|
|
|
|
inline bool TestApplication::unitsSpecified() const
|
|
|
|
{
|
|
|
|
return m_unitsArg.isPresent();
|
|
|
|
}
|
|
|
|
|
2016-05-01 20:09:20 +02:00
|
|
|
/*!
|
|
|
|
* \brief Returns the specified test units.
|
2016-06-12 01:56:57 +02:00
|
|
|
* \remarks The units argument must be present.
|
2016-05-01 20:09:20 +02:00
|
|
|
*/
|
2016-06-12 01:56:57 +02:00
|
|
|
inline const std::vector<const char *> &TestApplication::units() const
|
2016-05-01 20:09:20 +02:00
|
|
|
{
|
|
|
|
return m_unitsArg.values();
|
|
|
|
}
|
|
|
|
|
2016-02-06 02:52:06 +01:00
|
|
|
/*!
|
|
|
|
* \brief Convenience function which returns the full path of the test file with the specified \a name.
|
|
|
|
* \remarks A TestApplication must be present.
|
2016-07-30 22:34:31 +02:00
|
|
|
* \sa TestApplication::testFilePath()
|
2016-02-06 02:52:06 +01:00
|
|
|
*/
|
2016-08-29 15:35:48 +02:00
|
|
|
inline CPP_UTILITIES_EXPORT std::string testFilePath(const std::string &name)
|
2016-02-06 02:52:06 +01:00
|
|
|
{
|
|
|
|
return TestApplication::instance()->testFilePath(name);
|
|
|
|
}
|
|
|
|
|
2016-02-27 01:18:54 +01:00
|
|
|
#ifdef PLATFORM_UNIX
|
2016-02-09 02:21:42 +01:00
|
|
|
/*!
|
|
|
|
* \brief Convenience function which returns the full path to a working copy of the test file with the specified \a name.
|
|
|
|
* \remarks A TestApplication must be present.
|
2016-07-30 22:34:31 +02:00
|
|
|
* \sa TestApplication::workingCopyPath()
|
2016-02-09 02:21:42 +01:00
|
|
|
*/
|
2016-08-29 15:35:48 +02:00
|
|
|
inline CPP_UTILITIES_EXPORT std::string workingCopyPath(const std::string &name)
|
2016-02-09 02:21:42 +01:00
|
|
|
{
|
|
|
|
return TestApplication::instance()->workingCopyPath(name);
|
|
|
|
}
|
2016-07-30 22:34:31 +02:00
|
|
|
|
2017-02-04 20:16:50 +01:00
|
|
|
/*!
|
|
|
|
* \brief Convenience function which returns the full path to a working copy of the test file with the specified \a name.
|
|
|
|
* \remarks A TestApplication must be present.
|
|
|
|
* \sa TestApplication::workingCopyPathEx()
|
|
|
|
*/
|
|
|
|
inline CPP_UTILITIES_EXPORT std::string workingCopyPathMode(const std::string &name, WorkingCopyMode mode)
|
|
|
|
{
|
|
|
|
return TestApplication::instance()->workingCopyPathMode(name, mode);
|
|
|
|
}
|
|
|
|
|
2016-07-30 22:34:31 +02:00
|
|
|
/*!
|
|
|
|
* \brief Convenience function which executes the application to be tested with the specified \a args.
|
|
|
|
* \remarks A TestApplication must be present.
|
|
|
|
* \sa TestApplication::execApp()
|
|
|
|
*/
|
2016-08-29 15:35:48 +02:00
|
|
|
inline CPP_UTILITIES_EXPORT int execApp(const char *const *args, std::string &output, std::string &errors)
|
2016-07-30 22:34:31 +02:00
|
|
|
{
|
|
|
|
return TestApplication::instance()->execApp(args, output, errors);
|
|
|
|
}
|
2017-05-19 00:07:38 +02:00
|
|
|
|
|
|
|
CPP_UTILITIES_EXPORT int execHelperApp(
|
|
|
|
const char *appPath, const char *const *args, std::string &output, std::string &errors, bool suppressLogging = false, int timeout = -1);
|
2016-02-27 01:18:54 +01:00
|
|
|
#endif
|
2016-02-09 02:21:42 +01:00
|
|
|
|
2016-07-27 18:24:37 +02:00
|
|
|
/*!
|
|
|
|
* \brief The AsHexNumber class allows printing values asserted with cppunit (or similar test framework) using the
|
|
|
|
* hex system in the error case.
|
|
|
|
*/
|
2017-05-01 03:13:11 +02:00
|
|
|
template <typename T> class AsHexNumber {
|
2016-07-27 18:24:37 +02:00
|
|
|
public:
|
|
|
|
/// \brief Constructs a new instance; use asHexNumber() for convenience instead.
|
2017-05-01 03:13:11 +02:00
|
|
|
AsHexNumber(const T &value)
|
|
|
|
: value(value)
|
|
|
|
{
|
|
|
|
}
|
2016-07-27 18:24:37 +02:00
|
|
|
const T &value;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Provides operator == required by CPPUNIT_ASSERT_EQUAL.
|
|
|
|
*/
|
|
|
|
template <typename T> bool operator==(const AsHexNumber<T> &lhs, const AsHexNumber<T> &rhs)
|
|
|
|
{
|
|
|
|
return lhs.value == rhs.value;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Provides the actual formatting of the output for AsHexNumber class.
|
|
|
|
*/
|
2017-05-01 03:13:11 +02:00
|
|
|
template <typename T> std::ostream &operator<<(std::ostream &out, const AsHexNumber<T> &value)
|
2016-07-27 18:24:37 +02:00
|
|
|
{
|
2018-06-21 23:27:05 +02:00
|
|
|
return out << '0' << 'x' << std::hex << std::setfill('0') << std::setw(2) << unsigned(value.value) << std::dec;
|
2016-07-27 18:24:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2016-08-06 22:02:14 +02:00
|
|
|
* \brief Wraps a value to be printed using the hex system in the error case when asserted
|
|
|
|
* with cppunit (or similar test framework).
|
2016-07-27 18:24:37 +02:00
|
|
|
*/
|
|
|
|
template <typename T> AsHexNumber<T> asHexNumber(const T &value)
|
|
|
|
{
|
|
|
|
return AsHexNumber<T>(value);
|
|
|
|
}
|
|
|
|
|
2018-06-21 23:27:05 +02:00
|
|
|
/*!
|
|
|
|
* \brief Wraps a value to be printed using the hex system in the error case when asserted
|
|
|
|
* with cppunit (or similar test framework).
|
|
|
|
* \remarks Only affects integral types. Values of other types are printed as usual.
|
|
|
|
*/
|
|
|
|
template <typename T, Traits::EnableIf<std::is_integral<T>> * = nullptr> AsHexNumber<T> integralsAsHexNumber(const T &value)
|
|
|
|
{
|
|
|
|
return AsHexNumber<T>(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Wraps a value to be printed using the hex system in the error case when asserted
|
|
|
|
* with cppunit (or similar test framework).
|
|
|
|
* \remarks Only affects integral types. Values of other types are printed as usual.
|
|
|
|
*/
|
|
|
|
template <typename T, Traits::DisableIf<std::is_integral<T>> * = nullptr> const T &integralsAsHexNumber(const T &value)
|
|
|
|
{
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2016-08-06 22:02:14 +02:00
|
|
|
#ifndef TESTUTILS_ASSERT_EXEC
|
|
|
|
/*!
|
|
|
|
* \brief Asserts successful execution of application via TestApplication::execApp(). Output is stored in stdout and stderr.
|
|
|
|
* \remarks Requires cppunit.
|
|
|
|
*/
|
2017-05-01 03:13:11 +02:00
|
|
|
#define TESTUTILS_ASSERT_EXEC(args) CPPUNIT_ASSERT_EQUAL(0, execApp(args, stdout, stderr))
|
2016-08-06 22:02:14 +02:00
|
|
|
#endif
|
2017-05-10 23:32:48 +02:00
|
|
|
|
2017-11-13 20:06:09 +01:00
|
|
|
/*!
|
|
|
|
* \brief Allows printing pairs so key/values of maps/hashes can be asserted using CPPUNIT_ASSERT_EQUAL.
|
|
|
|
*/
|
2018-05-08 00:35:51 +02:00
|
|
|
template <typename Pair, Traits::EnableIf<Traits::IsSpecializationOf<Pair, std::pair>> * = nullptr>
|
2017-11-13 20:06:09 +01:00
|
|
|
inline std::ostream &operator<<(std::ostream &out, const Pair &pair)
|
|
|
|
{
|
|
|
|
return out << "key: " << pair.first << "; value: " << pair.second << '\n';
|
|
|
|
}
|
|
|
|
|
2017-05-10 23:32:48 +02:00
|
|
|
/*!
|
|
|
|
* \brief Allows printing iteratable objects so those can be asserted using CPPUNIT_ASSERT_EQUAL.
|
|
|
|
*/
|
2018-05-08 00:35:51 +02:00
|
|
|
template <typename Iteratable, Traits::EnableIf<Traits::IsIteratable<Iteratable>, Traits::Not<Traits::IsString<Iteratable>>> * = nullptr>
|
2017-05-10 23:32:48 +02:00
|
|
|
inline std::ostream &operator<<(std::ostream &out, const Iteratable &iteratable)
|
|
|
|
{
|
2017-10-23 01:11:11 +02:00
|
|
|
out << '\n';
|
|
|
|
std::size_t index = 0;
|
|
|
|
for (const auto &item : iteratable) {
|
2018-06-21 23:27:05 +02:00
|
|
|
out << std::setw(2) << index << ':' << ' ' << integralsAsHexNumber(item) << '\n';
|
2017-10-23 01:11:11 +02:00
|
|
|
++index;
|
|
|
|
}
|
2017-05-10 23:32:48 +02:00
|
|
|
return out;
|
|
|
|
}
|
2017-05-30 23:55:46 +02:00
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Contains literals to ease asserting with CPPUNIT_ASSERT_EQUAL.
|
|
|
|
*/
|
|
|
|
namespace Literals {
|
|
|
|
/*!
|
|
|
|
* \brief Literal for std::size_t to ease asserting std::size_t with CPPUNIT_ASSERT_EQUAL.
|
|
|
|
* \remarks Just using "ul"-suffix does not compile under 32-bit architecture!
|
|
|
|
*/
|
|
|
|
constexpr std::size_t operator"" _st(unsigned long long size)
|
|
|
|
{
|
|
|
|
return static_cast<std::size_t>(size);
|
|
|
|
}
|
2017-09-03 20:13:27 +02:00
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Literal for uint64 to ease asserting uint64 with CPPUNIT_ASSERT_EQUAL.
|
|
|
|
* \remarks Just using "ul"-suffix does not compile under 32-bit architecture!
|
|
|
|
*/
|
|
|
|
constexpr uint64 operator"" _uint64(unsigned long long size)
|
|
|
|
{
|
|
|
|
return static_cast<uint64>(size);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Literal for int64 to ease asserting int64 with CPPUNIT_ASSERT_EQUAL.
|
|
|
|
* \remarks Just using "l"-suffix does not compile under 32-bit architecture!
|
|
|
|
*/
|
|
|
|
constexpr int64 operator"" _int64(unsigned long long size)
|
|
|
|
{
|
|
|
|
return static_cast<int64>(size);
|
|
|
|
}
|
2017-09-17 21:45:23 +02:00
|
|
|
} // namespace Literals
|
|
|
|
} // namespace TestUtilities
|
2016-02-06 02:52:06 +01:00
|
|
|
|
|
|
|
#endif // TESTUTILS_H
|