2 * Copyright (C) 2008 Funambol, Inc.
3 * Copyright (C) 2008-2009 Patrick Ohly <patrick.ohly@gmx.de>
4 * Copyright (C) 2009 Intel Corporation
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) version 3.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 /** @addtogroup ClientTest */
32 #include <cppunit/CompilerOutputter.h>
33 #include <cppunit/ui/text/TestRunner.h>
34 #include <cppunit/TestListener.h>
35 #include <cppunit/TestResult.h>
36 #include <cppunit/TestFailure.h>
37 #include <cppunit/TestResultCollector.h>
38 #include <cppunit/extensions/TestFactoryRegistry.h>
39 #include <cppunit/extensions/HelperMacros.h>
42 #include <LogStdout.h>
55 void simplifyFilename(string &filename)
59 pos = filename.find(":", pos);
60 if (pos == filename.npos ) {
63 filename.replace(pos, 1, "_");
67 pos = filename.find("__", pos);
68 if (pos == filename.npos) {
71 filename.erase(pos, 1);
75 class ClientOutputter : public CppUnit::CompilerOutputter {
77 ClientOutputter(CppUnit::TestResultCollector *result, std::ostream &stream) :
78 CompilerOutputter(result, stream) {}
80 CompilerOutputter::write();
84 class ClientListener : public CppUnit::TestListener {
90 // install signal handler which turns an alarm signal into a runtime exception
91 // to abort tests which run too long
92 const char *alarm = getenv("CLIENT_TEST_ALARM");
93 m_alarmSeconds = alarm ? atoi(alarm) : -1;
95 struct sigaction action;
96 memset(&action, 0, sizeof(action));
97 action.sa_handler = alarmTriggered;
98 action.sa_flags = SA_NOMASK;
99 sigaction(SIGALRM, &action, NULL);
104 if (&SyncEvolution::LoggerBase::instance() == m_logger.get()) {
105 SyncEvolution::LoggerBase::popLogger();
109 void addAllowedFailures(string allowedFailures) {
110 size_t start = 0, end;
111 while ((end = allowedFailures.find(',', start)) != allowedFailures.npos) {
112 size_t len = end - start;
114 m_allowedFailures.insert(allowedFailures.substr(start, len));
118 if (allowedFailures.size() > start) {
119 m_allowedFailures.insert(allowedFailures.substr(start));
123 void startTest (CppUnit::Test *test) {
124 m_currentTest = test->getName();
125 cerr << m_currentTest;
126 string logfile = m_currentTest + ".log";
127 simplifyFilename(logfile);
128 m_logger.reset(new SyncEvolution::LoggerStdout(logfile));
129 m_logger->setLevel(SyncEvolution::Logger::DEBUG);
130 SyncEvolution::LoggerBase::pushLogger(m_logger.get());
131 SE_LOG_DEBUG(NULL, NULL, "*** starting %s ***", m_currentTest.c_str());
133 m_testFailed = false;
136 if (m_alarmSeconds > 0) {
137 alarm(m_alarmSeconds);
142 void addFailure(const CppUnit::TestFailure &failure) {
143 m_failures.addFailure(failure);
147 void endTest (CppUnit::Test *test) {
149 if (m_alarmSeconds > 0) {
158 CppUnit::CompilerOutputter formatter(&m_failures, output);
159 formatter.printFailureReport();
160 failure = output.str();
161 if (m_allowedFailures.find(m_currentTest) == m_allowedFailures.end()) {
162 result = "*** failed ***";
165 result = "*** failure ignored ***";
171 SE_LOG_DEBUG(NULL, NULL, "*** ending %s: %s ***", m_currentTest.c_str(), result.c_str());
172 if (!failure.empty()) {
173 SE_LOG_DEBUG(NULL, NULL, "%s", failure.c_str());
175 SyncEvolution::LoggerBase::popLogger();
178 string logfile = m_currentTest + ".log";
179 simplifyFilename(logfile);
181 const char* compareLog = getenv("CLIENT_TEST_COMPARE_LOG");
182 if(compareLog && strlen(compareLog)) {
183 FILE *fd = fopen ("____compare.log","r");
186 system ((string("cat ____compare.log >>")+logfile).c_str());
190 cerr << " " << result << "\n";
191 if (!failure.empty()) {
192 cerr << failure << "\n";
196 bool hasFailed() { return m_failed; }
197 const string &getCurrentTest() const { return m_currentTest; }
200 set<string> m_allowedFailures;
201 bool m_failed, m_testFailed;
202 string m_currentTest;
204 auto_ptr<SyncEvolution::LoggerStdout> m_logger;
205 CppUnit::TestResultCollector m_failures;
207 static void alarmTriggered(int signal) {
208 CPPUNIT_ASSERT_MESSAGE("test timed out", false);
212 const string &getCurrentTest() {
213 return syncListener.getCurrentTest();
216 static void printTests(CppUnit::Test *test, int indention)
222 std::string name = test->getName();
223 printf("%*s%s\n", indention * 3, "", name.c_str());
224 for (int i = 0; i < test->getChildTestCount(); i++) {
225 printTests(test->getChildTestAt(i), indention+1);
229 int main(int argc, char* argv[])
231 // Get the top level suite from the registry
232 CppUnit::Test *suite = CppUnit::TestFactoryRegistry::getRegistry().makeTest();
234 if (argc >= 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))) {
235 printf("usage: %s [test name]+\n\n"
236 "Without arguments all available tests are run.\n"
237 "Otherwise only the tests or group of tests listed are run.\n"
238 "Here is the test hierarchy of this test program:\n",
240 printTests(suite, 1);
244 // Adds the test to the list of test to run
245 CppUnit::TextUi::TestRunner runner;
246 runner.addTest( suite );
248 // Change the default outputter to a compiler error format outputter
249 runner.setOutputter( new ClientOutputter( &runner.result(),
252 // track current test and failure state
253 const char *allowedFailures = getenv("CLIENT_TEST_FAILURES");
254 if (allowedFailures) {
255 syncListener.addAllowedFailures(allowedFailures);
257 runner.eventManager().addListener(&syncListener);
263 runner.run("", false, true, false);
265 // run selected tests individually
266 for (int test = 1; test < argc; test++) {
267 runner.run(argv[test], false, true, false);
271 // Return error code 1 if the one of test failed.
272 return syncListener.hasFailed() ? 1 : 0;
273 } catch (invalid_argument e) {
274 // Test path not resolved
275 std::cerr << std::endl
276 << "ERROR: " << e.what()