306 lines
7.0 KiB
C++
306 lines
7.0 KiB
C++
//
|
|
// VMime library (http://www.vmime.org)
|
|
// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
|
|
//
|
|
// 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 <sys/time.h>
|
|
#include <time.h>
|
|
|
|
#include <iostream>
|
|
#include <vector>
|
|
#include <algorithm>
|
|
#include <memory>
|
|
|
|
#include <cppunit/XmlOutputter.h>
|
|
#include <cppunit/extensions/TestFactoryRegistry.h>
|
|
#include <cppunit/ui/text/TestRunner.h>
|
|
#include <cppunit/TestListener.h>
|
|
#include <cppunit/TestResult.h>
|
|
#include <cppunit/TestResultCollector.h>
|
|
#include <cppunit/TestFailure.h>
|
|
#include <cppunit/SourceLine.h>
|
|
#include <cppunit/Exception.h>
|
|
#include <cppunit/tools/XmlDocument.h>
|
|
#include <cppunit/tools/XmlElement.h>
|
|
|
|
#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 <double>(tv.tv_sec - m_start.tv_sec)
|
|
+ static_cast <double>(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 <CppUnit::XmlElement*> m_suiteElt;
|
|
CppUnit::XmlElement* m_testElt;
|
|
};
|
|
|
|
|
|
|
|
// see testUtils.hpp
|
|
|
|
std::vector <std::string>& getTestModules() {
|
|
|
|
static std::vector <std::string> allModules;
|
|
return allModules;
|
|
}
|
|
|
|
|
|
void registerTestModule(const char* name_) {
|
|
|
|
std::vector <std::string>& 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;
|
|
}
|
|
}
|