// // VMime library (http://www.vmime.org) // Copyright (C) 2002 Vincent Richard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 3 of // the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // General Public License for more details. // // You should have received a copy of the GNU General Public License along // with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // // Linking this library statically or dynamically with other modules is making // a combined work based on this library. Thus, the terms and conditions of // the GNU General Public License cover the whole combination. // #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "vmime/vmime.hpp" #include "vmime/platforms/posix/posixHandler.hpp" class Clock { public: void reset() { struct timezone tz; gettimeofday(&m_start, &tz); } double getDuration() const { struct timeval tv; struct timezone tz; gettimeofday(&tv, &tz); return static_cast (tv.tv_sec - m_start.tv_sec) + static_cast (tv.tv_usec - m_start.tv_usec) / 1000000.0; } private: struct timeval m_start; }; class XmlTestListener : public CppUnit::TestListener { public: XmlTestListener() : m_doc("utf-8"), m_testElt(NULL) { m_doc.setRootElement(new CppUnit::XmlElement("TestRun")); } void startTest(CppUnit::Test* test) { m_testElt = new CppUnit::XmlElement("Test"); m_suiteElt.back()->addElement(m_testElt); m_testElt->addElement(new CppUnit::XmlElement("Name", test->getName())); m_chrono.reset(); } void addFailure(const CppUnit::TestFailure& failure) { CppUnit::XmlElement* failElt = new CppUnit::XmlElement("Failure"); m_testElt->addElement(failElt); failElt->addElement( new CppUnit::XmlElement("FailureType", failure.isError() ? "Error" : "Assertion") ); if (failure.sourceLine().isValid()) { CppUnit::XmlElement* locElt = new CppUnit::XmlElement("Location"); failElt->addElement(locElt); locElt->addElement(new CppUnit::XmlElement("File", failure.sourceLine().fileName())); locElt->addElement(new CppUnit::XmlElement("Line", failure.sourceLine().lineNumber())); } CppUnit::XmlElement* exElt = new CppUnit::XmlElement("Exception"); failElt->addElement(exElt); exElt->addElement(new CppUnit::XmlElement("Message", failure.thrownException()->what())); } void endTest(CppUnit::Test* /* test */) { std::ostringstream ossTime; ossTime << (m_chrono.getDuration() * 1000.0); m_testElt->addElement(new CppUnit::XmlElement("Time", ossTime.str())); m_testElt = NULL; } void startSuite(CppUnit::Test* suite) { if (suite->getName() == "All Tests") { return; } CppUnit::XmlElement* suiteElt = new CppUnit::XmlElement("Suite"); if (m_suiteElt.size() == 0) { m_doc.rootElement().addElement(suiteElt); } else { m_suiteElt.back()->addElement(suiteElt); } m_suiteElt.push_back(suiteElt); suiteElt->addElement(new CppUnit::XmlElement("Name", suite->getName())); } void endSuite(CppUnit::Test* /* suite */) { if (m_suiteElt.size()) { m_suiteElt.pop_back(); } } void startTestRun(CppUnit::Test* /* test */, CppUnit::TestResult* /* eventManager */) { } void endTestRun(CppUnit::Test* /* test */, CppUnit::TestResult* /* eventManager */) { } void output(std::ostream& os) { os << m_doc.toString(); } private: Clock m_chrono; CppUnit::XmlDocument m_doc; std::vector m_suiteElt; CppUnit::XmlElement* m_testElt; }; // see testUtils.hpp std::vector & getTestModules() { static std::vector allModules; return allModules; } void registerTestModule(const char* name_) { std::vector & testModules = getTestModules(); std::string name(name_); if (std::find(testModules.begin(), testModules.end(), name) == testModules.end()) { testModules.push_back(name); } } const std::string getNormalizedPath(const std::string& path) { std::string res = path; for (std::size_t i = 0, n = res.length() ; i < n ; ++i) { if (res[i] == '\\') { res[i] = '/'; } } return res; } const std::string getFileNameFromPath(const std::string& path) { const std::size_t pos = path.find_last_of('/'); if (pos == std::string::npos) { return ""; } return path.substr(pos + 1); } static char g_moduleNameBuffer[2048]; const char* getTestModuleNameFromSourceFile(const char *path_) { static const std::string testRunnerPath(getNormalizedPath(__FILE__)); static const std::string testRunnerFileName(getFileNameFromPath(testRunnerPath)); const std::string path = getNormalizedPath(path_); // "/path/to/testRunner.cpp" --> "/path/to/" const std::string basePath (testRunnerPath.begin(), testRunnerPath.end() - testRunnerFileName.length()); // "/path/to/module/testFile.cpp" --> "module/testFile.cpp" const std::string testFileName(getFileNameFromPath(path)); const std::string testPath(path.begin() + basePath.length(), path.end()); // "module/testFile.cpp" --> "module" const std::string moduleName(testPath.substr(0, testPath.length() - testFileName.length() - 1)); std::copy(moduleName.begin(), moduleName.end(), g_moduleNameBuffer); g_moduleNameBuffer[moduleName.length()] = 0; return g_moduleNameBuffer; } int main(int argc, char* argv[]) { // Parse arguments bool xmlOutput = false; for (int c = 1 ; c < argc ; ++c) { const std::string arg = argv[c]; if (arg == "--xml") { xmlOutput = true; } } // Run the tests if (xmlOutput) { // Get the test suites from the registry and add them to the list of tests to run CppUnit::TestRunner runner; for (unsigned int i = 0 ; i < getTestModules().size() ; ++i) { runner.addTest( CppUnit::TestFactoryRegistry::getRegistry(getTestModules()[i]).makeTest() ); } XmlTestListener xmlListener; CppUnit::TestResult controller; controller.addListener(&xmlListener); CppUnit::TestResultCollector result; controller.addListener(&result); runner.run(controller); xmlListener.output(std::cout); // Return error code 1 if a test failed return result.wasSuccessful() ? 0 : 1; } else { // Get the top level suite from the registry CppUnit::TextUi::TestRunner runner; runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest()); return runner.run() ? 0 : 1; } }