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