PageRenderTime 33ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/mordor/test/antxmllistener.cpp

http://github.com/mozy/mordor
C++ | 216 lines | 194 code | 21 blank | 1 comment | 24 complexity | 11091ad23a6031143119f4b173c7d6e4 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. // Copyright (c) 2010 - Mozy, Inc.
  2. #include "mordor/predef.h"
  3. #include "antxmllistener.h"
  4. #include <iostream>
  5. #include <boost/date_time/posix_time/posix_time_io.hpp>
  6. #include "mordor/config.h"
  7. #include "mordor/log.h"
  8. #include "mordor/streams/file.h"
  9. #include "mordor/string.h"
  10. #include "mordor/timer.h"
  11. namespace Mordor {
  12. namespace Test {
  13. class AntXMLLogSink : public LogSink
  14. {
  15. public:
  16. typedef boost::shared_ptr<AntXMLLogSink> ptr;
  17. AntXMLLogSink() : m_out(NULL), m_err(NULL)
  18. {}
  19. void log(const std::string &logger,
  20. boost::posix_time::ptime now, unsigned long long elapsed,
  21. tid_t thread, void *fiber,
  22. Log::Level level, const std::string &str,
  23. const char* file, int line)
  24. {
  25. std::ostringstream *os = NULL;
  26. std::ostringstream localOS;
  27. switch (level) {
  28. case Log::FATAL:
  29. case Log::ERROR:
  30. os = m_err;
  31. break;
  32. default:
  33. os = m_out;
  34. }
  35. if (os) {
  36. localOS << now << " " << elapsed << " " << level << " " << thread
  37. << " " << fiber << " " << logger << " " << file << ":"
  38. << line << " " << str << std::endl;
  39. boost::mutex::scoped_lock lock(m_mutex);
  40. *os << localOS.str();
  41. }
  42. }
  43. boost::mutex m_mutex;
  44. std::ostringstream *m_out, *m_err;
  45. };
  46. AntXMLListener::AntXMLListener(const std::string &directory)
  47. : m_directory(directory)
  48. {
  49. m_logSink.reset(new AntXMLLogSink());
  50. Log::root()->addSink(m_logSink);
  51. }
  52. AntXMLListener::~AntXMLListener()
  53. {
  54. if (m_logSink)
  55. Log::root()->removeSink(m_logSink);
  56. }
  57. void
  58. AntXMLListener::testStarted(const std::string &suite, const std::string &test)
  59. {
  60. TestSuiteInfo &suiteInfo = m_testSuites[suite];
  61. if (!suiteInfo.out) {
  62. suiteInfo.out.reset(new std::ostringstream());
  63. suiteInfo.err.reset(new std::ostringstream());
  64. }
  65. m_logSink->m_out = suiteInfo.out.get();
  66. m_logSink->m_err = suiteInfo.err.get();
  67. if (test != "<invariant>") {
  68. TestInfo &testInfo = suiteInfo.tests[test];
  69. testInfo.start = TimerManager::now();
  70. if (suiteInfo.start == ~0ull)
  71. suiteInfo.start = testInfo.start;
  72. }
  73. }
  74. void
  75. AntXMLListener::testComplete(const std::string &suite, const std::string &test)
  76. {
  77. if (test != "<invariant>") {
  78. TestSuiteInfo &suiteInfo = m_testSuites[suite];
  79. TestInfo &testInfo = suiteInfo.tests[test];
  80. suiteInfo.end = testInfo.end = TimerManager::now();
  81. }
  82. }
  83. void
  84. AntXMLListener::testSkipped(const std::string &suite, const std::string &test)
  85. {
  86. if (test != "<invariant>") {
  87. TestSuiteInfo &suiteInfo = m_testSuites[suite];
  88. suiteInfo.tests.erase(test);
  89. suiteInfo.end = TimerManager::now();
  90. }
  91. }
  92. void
  93. AntXMLListener::testAsserted(const std::string &suite, const std::string &test,
  94. const Assertion &assertion)
  95. {
  96. if (test != "<invariant>") {
  97. TestSuiteInfo &suiteInfo = m_testSuites[suite];
  98. TestInfo &testInfo = suiteInfo.tests[test];
  99. ++suiteInfo.failures;
  100. suiteInfo.end = testInfo.end = TimerManager::now();
  101. testInfo.exceptionType = "Assertion";
  102. testInfo.exceptionMessage = assertion.what();
  103. replace(testInfo.exceptionMessage, "&", "&amp;");
  104. replace(testInfo.exceptionMessage, "\"", "&quot;");
  105. replace(testInfo.exceptionMessage, '\0', "&#00;");
  106. testInfo.exceptionDetails = boost::current_exception_diagnostic_information();
  107. }
  108. }
  109. void
  110. AntXMLListener::testException(const std::string &suite, const std::string &test)
  111. {
  112. if (test != "<invariant>") {
  113. TestSuiteInfo &suiteInfo = m_testSuites[suite];
  114. TestInfo &testInfo = suiteInfo.tests[test];
  115. ++suiteInfo.errors;
  116. suiteInfo.end = testInfo.end = TimerManager::now();
  117. try {
  118. throw;
  119. } catch (std::exception &ex) {
  120. testInfo.exceptionMessage = ex.what();
  121. testInfo.exceptionType = typeid(ex).name();
  122. } catch (boost::exception &ex) {
  123. testInfo.exceptionType = typeid(ex).name();
  124. } catch (...) {
  125. }
  126. testInfo.exceptionMessage = boost::current_exception_diagnostic_information();
  127. }
  128. }
  129. static void listProperties(std::ostringstream *os, ConfigVarBase::ptr var)
  130. {
  131. *os << " <property name=\"" << var->name() << "\" value=\""
  132. << var->toString() << "\" />" << std::endl;
  133. }
  134. static std::string sanitize(std::string string, bool cdata = true)
  135. {
  136. replace(string, '&', "&amp;");
  137. replace(string, '<', "&lt;");
  138. replace(string, '\0', "&#00;");
  139. if (!cdata)
  140. replace(string, '\"', "&quot;");
  141. return string;
  142. }
  143. void
  144. AntXMLListener::testsComplete()
  145. {
  146. for (std::map<std::string, TestSuiteInfo>::const_iterator it = m_testSuites.begin();
  147. it != m_testSuites.end();
  148. ++it) {
  149. try {
  150. FileStream file(m_directory + "TEST-" + it->first + ".xml",
  151. FileStream::WRITE, FileStream::OVERWRITE_OR_CREATE);
  152. std::ostringstream os;
  153. os << "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" << std::endl
  154. << "<testsuite errors=\"" << it->second.errors
  155. << "\" failures=\"" << it->second.failures << "\" name=\""
  156. << it->first << "\" tests=\"" << it->second.tests.size()
  157. << "\" time=\""
  158. << (double)(it->second.end - it->second.start) / 1000000ull
  159. << "\">" << std::endl
  160. << " <properties>" << std::endl;
  161. Config::visit(boost::bind(&listProperties, &os, _1));
  162. os << " </properties>" << std::endl;
  163. for (std::map<std::string, TestInfo>::const_iterator it2 = it->second.tests.begin();
  164. it2 != it->second.tests.end();
  165. ++it2) {
  166. os << " <testcase name=\"" << it2->first << "\" time=\""
  167. << (double)(it2->second.end - it2->second.start) / 1000000ull
  168. << "\"";
  169. if (!it2->second.exceptionMessage.empty()) {
  170. os << ">" << std::endl
  171. << " <failure message=\""
  172. << sanitize(it2->second.exceptionMessage, false) << "\" type=\""
  173. << sanitize(it2->second.exceptionType, false) << "\"><![CDATA["
  174. << sanitize(it2->second.exceptionDetails) << "]]></failure>"
  175. << std::endl << " </testcase>" << std::endl;
  176. } else {
  177. os << " />" << std::endl;
  178. }
  179. }
  180. os << " <system-out><![CDATA[" << sanitize(it->second.out->str())
  181. << "]]></system-out>" << std::endl
  182. << " <system-err><![CDATA[" << sanitize(it->second.err->str())
  183. << "]]></system-err>" << std::endl
  184. << "</testsuite>" << std::endl;
  185. std::string xml = os.str();
  186. size_t written = 0;
  187. while (written < xml.size())
  188. written += file.write(xml.c_str() + written,
  189. xml.size() - written);
  190. } catch (...) {
  191. std::cerr << boost::current_exception_diagnostic_information();
  192. }
  193. }
  194. }
  195. }}