#ifndef TESTUTILS_H #define TESTUTILS_H #include "../application/argumentparser.h" #include "../misc/traits.h" #include #include namespace TestUtilities { /*! * \brief The WorkingCopyMode enum specifies additional options to influence behavior of TestApplication::workingCopyPathMode(). */ enum class WorkingCopyMode { 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 */ }; class CPP_UTILITIES_EXPORT TestApplication { public: TestApplication(int argc, char **argv); ~TestApplication(); operator bool() const; std::string testFilePath(const std::string &name) const; #ifdef PLATFORM_UNIX std::string workingCopyPathMode(const std::string &name, WorkingCopyMode mode) const; std::string workingCopyPath(const std::string &name) const; int execApp(const char *const *args, std::string &output, std::string &errors, bool suppressLogging = false, int timeout = -1) const; #endif bool unitsSpecified() const; const std::vector &units() const; static const TestApplication *instance(); private: ApplicationUtilities::ArgumentParser m_parser; ApplicationUtilities::HelpArgument m_helpArg; ApplicationUtilities::Argument m_testFilesPathArg; ApplicationUtilities::Argument m_applicationPathArg; ApplicationUtilities::Argument m_workingDirArg; ApplicationUtilities::Argument m_unitsArg; std::string m_testFilesPathArgValue; std::string m_testFilesPathEnvValue; std::string m_workingDir; bool m_valid; static TestApplication *m_instance; }; /*! * \brief Returns whether the TestApplication instance is valid. * * An instance is considered invalid if an error occured when * parsing the command line arguments. */ inline TestApplication::operator bool() const { return m_valid; } /*! * \brief Returns the current TestApplication instance. */ inline const TestApplication *TestApplication::instance() { return TestApplication::m_instance; } /*! * \brief Returns whether particular units have been specified. */ inline bool TestApplication::unitsSpecified() const { return m_unitsArg.isPresent(); } /*! * \brief Returns the specified test units. * \remarks The units argument must be present. */ inline const std::vector &TestApplication::units() const { return m_unitsArg.values(); } /*! * \brief Convenience function which returns the full path of the test file with the specified \a name. * \remarks A TestApplication must be present. * \sa TestApplication::testFilePath() */ inline CPP_UTILITIES_EXPORT std::string testFilePath(const std::string &name) { return TestApplication::instance()->testFilePath(name); } #ifdef PLATFORM_UNIX /*! * \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::workingCopyPath() */ inline CPP_UTILITIES_EXPORT std::string workingCopyPath(const std::string &name) { return TestApplication::instance()->workingCopyPath(name); } /*! * \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); } /*! * \brief Convenience function which executes the application to be tested with the specified \a args. * \remarks A TestApplication must be present. * \sa TestApplication::execApp() */ inline CPP_UTILITIES_EXPORT int execApp(const char *const *args, std::string &output, std::string &errors) { return TestApplication::instance()->execApp(args, output, errors); } CPP_UTILITIES_EXPORT int execHelperApp( const char *appPath, const char *const *args, std::string &output, std::string &errors, bool suppressLogging = false, int timeout = -1); #endif /*! * \brief The AsHexNumber class allows printing values asserted with cppunit (or similar test framework) using the * hex system in the error case. */ template class AsHexNumber { public: /// \brief Constructs a new instance; use asHexNumber() for convenience instead. AsHexNumber(const T &value) : value(value) { } const T &value; }; /*! * \brief Provides operator == required by CPPUNIT_ASSERT_EQUAL. */ template bool operator==(const AsHexNumber &lhs, const AsHexNumber &rhs) { return lhs.value == rhs.value; } /*! * \brief Provides the actual formatting of the output for AsHexNumber class. */ template std::ostream &operator<<(std::ostream &out, const AsHexNumber &value) { return out << std::hex << '0' << 'x' << unsigned(value.value) << std::dec; } /*! * \brief Wraps a value to be printed using the hex system in the error case when asserted * with cppunit (or similar test framework). */ template AsHexNumber asHexNumber(const T &value) { return AsHexNumber(value); } #ifndef TESTUTILS_ASSERT_EXEC /*! * \brief Asserts successful execution of application via TestApplication::execApp(). Output is stored in stdout and stderr. * \remarks Requires cppunit. */ #define TESTUTILS_ASSERT_EXEC(args) CPPUNIT_ASSERT_EQUAL(0, execApp(args, stdout, stderr)) #endif /*! * \brief Allows printing iteratable objects so those can be asserted using CPPUNIT_ASSERT_EQUAL. */ template , Traits::Not>>...> inline std::ostream &operator<<(std::ostream &out, const Iteratable &iteratable) { for (const auto &item : iteratable) out << item << '\n'; return out; } /*! * \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(size); } } } #endif // TESTUTILS_H