Vault
4.1
|
00001 /* 00002 Copyright c1997-2014 Trygve Isaacson. All rights reserved. 00003 This file is part of the Code Vault version 4.1 00004 http://www.bombaydigital.com/ 00005 License: MIT. See LICENSE.md in the Vault top level directory. 00006 */ 00007 00010 #include "vunit.h" 00011 00012 #include "vlogger.h" 00013 #include "vexception.h" 00014 #include "vtextiostream.h" 00015 00016 // VUnit --------------------------------------------------------------------- 00017 00018 // static 00019 void VUnit::runUnit(VUnit& unit, VUnitOutputWriterList* writers) { 00020 unit.setWriters(writers); 00021 00022 unit.logStart(); 00023 00024 try { 00025 VAutoreleasePool pool; 00026 unit.run(); 00027 } catch (const std::exception& ex) { // will include VException 00028 unit.logExceptionalEnd(ex.what()); 00029 throw; 00030 } catch (...) { 00031 unit.logExceptionalEnd("(exception type unknown)"); 00032 throw; 00033 } 00034 00035 unit.logNormalEnd(); 00036 } 00037 00038 void VUnit::rerunUnit(VUnit& unit, VUnitOutputWriterList* writers) { 00039 unit.reset(); 00040 VUnit::runUnit(unit, writers); 00041 } 00042 00043 VUnit::VUnit(const VString& name, bool logOnSuccess, bool throwOnError) : 00044 mName(name), 00045 mLogOnSuccess(logOnSuccess), 00046 mThrowOnError(throwOnError), 00047 mWriters(NULL), 00048 mNumSuccessfulTests(0), 00049 mNumFailedTests(0), 00050 mResults(), 00051 mUnitStartTimeSnapshot(VInstant::snapshot()), 00052 mPreviousTestEndedSnapshot(VInstant::snapshot()), 00053 mLastTestDescription() { 00054 } 00055 00056 VUnit::~VUnit() { 00057 } 00058 00059 void VUnit::reset() { 00060 mNumSuccessfulTests = 0; 00061 mNumFailedTests = 0; 00062 mResults.clear(); 00063 mUnitStartTimeSnapshot = VInstant::snapshot(); 00064 mPreviousTestEndedSnapshot = VInstant::snapshot(); 00065 mLastTestDescription = VString::EMPTY(); 00066 } 00067 00068 void VUnit::logStart() { 00069 if (mWriters != NULL) 00070 for (VUnitOutputWriterList::iterator i = mWriters->begin(); i != mWriters->end(); ++i) 00071 (*i)->testSuiteBegin(mName); 00072 } 00073 00074 void VUnit::logNormalEnd() { 00075 if (mWriters != NULL) 00076 for (VUnitOutputWriterList::iterator i = mWriters->begin(); i != mWriters->end(); ++i) 00077 (*i)->testSuiteEnd(); 00078 } 00079 00080 void VUnit::logExceptionalEnd(const VString& exceptionMessage) { 00081 VTestInfo error(false, VSTRING_FORMAT("after %s, threw exception: %s", mLastTestDescription.chars(), exceptionMessage.chars()), VDuration::ZERO()); 00082 mResults.push_back(error); 00083 00084 ++mNumFailedTests; 00085 00086 if (mWriters != NULL) 00087 for (VUnitOutputWriterList::iterator i = mWriters->begin(); i != mWriters->end(); ++i) { 00088 (*i)->testCaseBegin("exception thrown"); 00089 (*i)->testCaseEnd(error); 00090 } 00091 } 00092 00093 void VUnit::assertSuccess(const VString& labelSuffix, const VString& filePath, int lineNumber) { 00094 VString fileName; 00095 filePath.getSubstring(fileName, filePath.lastIndexOf('/') + 1); 00096 VString testName(VSTRING_ARGS("%s:%d %s", fileName.chars(), lineNumber, labelSuffix.chars())); 00097 00098 mLastTestDescription = testName; 00099 00100 this->recordSuccess(testName); 00101 00102 mPreviousTestEndedSnapshot = VInstant::snapshot(); 00103 } 00104 00105 void VUnit::assertFailure(const VString& labelSuffix, const VString& filePath, int lineNumber) { 00106 VString fileName; 00107 filePath.getSubstring(fileName, filePath.lastIndexOf('/') + 1); 00108 VString testName(VSTRING_ARGS("%s:%d %s", fileName.chars(), lineNumber, labelSuffix.chars())); 00109 00110 mLastTestDescription = testName; 00111 00112 this->recordFailure(VSTRING_FORMAT("%s: %s", testName.chars())); 00113 00114 mPreviousTestEndedSnapshot = VInstant::snapshot(); 00115 } 00116 00117 void VUnit::testAssertion(bool successful, const VString& filePath, int lineNumber, const VString& labelSuffix, const VString& expectedDescription) { 00118 VString fileName; 00119 filePath.getSubstring(fileName, filePath.lastIndexOf('/') + 1); 00120 VString testName(VSTRING_ARGS("%s:%d %s", fileName.chars(), lineNumber, labelSuffix.chars())); 00121 00122 mLastTestDescription = testName; 00123 00124 if (successful) 00125 this->recordSuccess(testName); 00126 else 00127 this->recordFailure(VSTRING_FORMAT("%s: %s", testName.chars(), expectedDescription.chars())); 00128 00129 mPreviousTestEndedSnapshot = VInstant::snapshot(); 00130 } 00131 00132 void VUnit::test(bool successful, const VString& description) { 00133 mLastTestDescription = description; 00134 00135 if (successful) 00136 this->recordSuccess(description); 00137 else 00138 this->recordFailure(description); 00139 00140 mPreviousTestEndedSnapshot = VInstant::snapshot(); 00141 } 00142 00143 void VUnit::test(const VString& a, const VString& b, const VString& description) { 00144 this->test(a == b, description); 00145 } 00146 00147 void VUnit::logStatus(const VString& description) { 00148 if (mWriters != NULL) 00149 for (VUnitOutputWriterList::iterator i = mWriters->begin(); i != mWriters->end(); ++i) 00150 (*i)->testSuiteStatusMessage(description); 00151 } 00152 00153 void VUnit::recordSuccess(const VString& description) { 00154 if (mWriters != NULL) 00155 for (VUnitOutputWriterList::iterator i = mWriters->begin(); i != mWriters->end(); ++i) 00156 (*i)->testCaseBegin(description); 00157 00158 ++mNumSuccessfulTests; 00159 00160 VTestInfo info(true, description, VInstant::snapshotDelta(mPreviousTestEndedSnapshot)); 00161 mResults.push_back(info); 00162 00163 if (mWriters != NULL) 00164 for (VUnitOutputWriterList::iterator i = mWriters->begin(); i != mWriters->end(); ++i) 00165 (*i)->testCaseEnd(info); 00166 } 00167 00168 void VUnit::recordFailure(const VString& description) { 00169 if (mWriters != NULL) 00170 for (VUnitOutputWriterList::iterator i = mWriters->begin(); i != mWriters->end(); ++i) 00171 (*i)->testCaseBegin(description); 00172 00173 ++mNumFailedTests; 00174 00175 VTestInfo info(false, description, VInstant::snapshotDelta(mPreviousTestEndedSnapshot)); 00176 mResults.push_back(info); 00177 00178 if (mWriters != NULL) 00179 for (VUnitOutputWriterList::iterator i = mWriters->begin(); i != mWriters->end(); ++i) 00180 (*i)->testCaseEnd(info); 00181 } 00182 00183 // VTestInfo ----------------------------------------------------------------- 00184 00185 VTestInfo::VTestInfo(bool success, const VString& description, const VDuration& duration) : 00186 mSuccess(success), 00187 mDescription(description), 00188 mDuration(duration) { 00189 // Some tests that manipulate time simulation will yield bogus durations. 00190 if ((mDuration < VDuration::ZERO()) || (mDuration > VDuration::DAY())) 00191 mDuration = VDuration::ZERO(); 00192 } 00193 00194 // VFailureEmitter ----------------------------------------------------------- 00195 00196 VFailureEmitter::VFailureEmitter(const VString& testName, bool logOnSuccess, bool throwOnError, const VString& errorMessage) : 00197 VUnit(testName, logOnSuccess, throwOnError), fErrorMessage(errorMessage) { 00198 } 00199 00200 void VFailureEmitter::run() { 00201 this->logStatus(VSTRING_FORMAT("%s failed due to this error: %s", this->getName().chars(), fErrorMessage.chars())); 00202 this->test(false, fErrorMessage); 00203 } 00204 00205 // VUnitOutputWriter ------------------------------------------------------ 00206 00207 static const VString VUNIT_OUTPUT_DIRECTIVE("-vunit-out"); 00208 00209 static const VString OUTPUT_TYPE_SIMPLE("text"); 00210 static const VString OUTPUT_TYPE_JUNIT("junit"); 00211 static const VString OUTPUT_TYPE_TEAMCITY("tc"); 00212 static const VString OUTPUT_TYPE_TEAMCITY_STATUS("tcstatus"); 00213 00214 static const VString OUTPUT_FILEPATH_STDOUT("stdout"); 00215 00216 // static 00217 void VUnitOutputWriter::createOutputWriters(const VStringVector& args, VUnitOutputWriterList& writers, VUnitLogAppenderList& appenders) { 00218 for (VStringVector::const_iterator i = args.begin(); i != args.end(); ++i) { 00219 if ((*i) == VUNIT_OUTPUT_DIRECTIVE) { 00220 VString outputType = *(++i); 00221 VString filePath = *(++i); 00222 VUnitOutputWriter::_addNewOutputWriter(writers, appenders, outputType, filePath); 00223 } 00224 } 00225 00226 // If no specific output was specified, log simple output to stdout. 00227 if (writers.size() == 0) 00228 VUnitOutputWriter::_addNewOutputWriter(writers, appenders, OUTPUT_TYPE_SIMPLE, OUTPUT_FILEPATH_STDOUT); 00229 } 00230 00231 VUnitOutputWriter::VUnitOutputWriter(VLogAppender& outputAppender) : 00232 mLogAppender(outputAppender), 00233 mTestSuitesStartTime(VInstant::NEVER_OCCURRED()), 00234 mTotalNumSuccesses(0), 00235 mTotalNumErrors(0), 00236 mCurrentTestSuiteName(), 00237 mCurrentTestSuiteResults(), 00238 mCurrentTestSuiteNumSuccesses(0), 00239 mCurrentTestSuiteNumErrors(0), 00240 mCurrentTestSuiteStartTime(VInstant::NEVER_OCCURRED()), 00241 mCurrentTestSuiteEndTime(VInstant::NEVER_OCCURRED()), 00242 mCurrentTestCaseName(), 00243 mCurrentTestCaseStartTime(VInstant::NEVER_OCCURRED()), 00244 mCurrentTestCaseEndTime(VInstant::NEVER_OCCURRED()), 00245 mFailedTestSuiteNames() { 00246 } 00247 00248 void VUnitOutputWriter::_testSuitesBegin() { 00249 mTestSuitesStartTime.setNow(); 00250 } 00251 00252 void VUnitOutputWriter::_testSuiteBegin(const VString& testSuiteName) { 00253 mCurrentTestSuiteName = testSuiteName; 00254 mCurrentTestSuiteResults.clear(); 00255 mCurrentTestSuiteNumSuccesses = 0; 00256 mCurrentTestSuiteNumErrors = 0; 00257 mCurrentTestSuiteStartTime.setNow(); 00258 mCurrentTestSuiteEndTime = VInstant::NEVER_OCCURRED(); 00259 mCurrentTestCaseStartTime = VInstant::NEVER_OCCURRED(); 00260 mCurrentTestCaseEndTime = VInstant::NEVER_OCCURRED(); 00261 } 00262 00263 void VUnitOutputWriter::_testCaseBegin(const VString& testCaseName) { 00264 mCurrentTestCaseName = testCaseName; 00265 mCurrentTestCaseStartTime.setNow(); 00266 } 00267 00268 void VUnitOutputWriter::_testCaseEnd(const VTestInfo& testInfo) { 00269 mCurrentTestCaseEndTime.setNow(); 00270 mCurrentTestSuiteResults.push_back(testInfo); 00271 00272 if (testInfo.mSuccess) { 00273 ++mTotalNumSuccesses; 00274 ++mCurrentTestSuiteNumSuccesses; 00275 } else { 00276 ++mTotalNumErrors; 00277 ++mCurrentTestSuiteNumErrors; 00278 } 00279 } 00280 00281 void VUnitOutputWriter::_testSuiteEnd() { 00282 mCurrentTestSuiteEndTime.setNow(); 00283 00284 if (mCurrentTestSuiteNumErrors != 0) 00285 mFailedTestSuiteNames.push_back(mCurrentTestSuiteName); 00286 } 00287 00288 // static 00289 VLogAppender* VUnitOutputWriter::_newLogAppenderByType(const VString& outputType, const VString& filePath) { 00290 // We allow either cout logging, or file logging. 00291 VLogAppender* appender = NULL; 00292 if (filePath == OUTPUT_FILEPATH_STDOUT) { 00293 appender = new VCoutLogAppender(VSTRING_FORMAT("vunit-%s-cout", outputType.chars()), false, VString::EMPTY(), VString::EMPTY()); 00294 } else { 00295 VFSNode logFile(filePath); 00296 logFile.rm(); 00297 appender = new VFileLogAppender(VSTRING_FORMAT("vunit-%s-%s", outputType.chars(), filePath.chars()), false, VString::EMPTY(), VString::EMPTY(), filePath); 00298 } 00299 00300 return appender; 00301 } 00302 00303 // static 00304 VUnitOutputWriter* VUnitOutputWriter::_newOutputWriterByType(const VString& outputType, VLogAppender* appender) { 00305 VUnitOutputWriter* writer = NULL; 00306 00307 if (outputType == OUTPUT_TYPE_SIMPLE) { 00308 writer = new VUnitSimpleTextOutput(*appender); 00309 } else if (outputType == OUTPUT_TYPE_JUNIT) { 00310 writer = new VUnitJUnitXMLOutput(*appender); 00311 } else if (outputType == OUTPUT_TYPE_TEAMCITY) { 00312 writer = new VUnitTeamCityOutput(*appender); 00313 } else if (outputType == OUTPUT_TYPE_TEAMCITY_STATUS) { 00314 writer = new VUnitTeamCityBuildStatusOutput(*appender); 00315 } else { 00316 VLOGGER_ERROR(VSTRING_FORMAT("Invalid unit test output type '%s' will be ignored.", outputType.chars())); 00317 } 00318 00319 return writer; 00320 } 00321 00322 // static 00323 void VUnitOutputWriter::_addNewOutputWriter(VUnitOutputWriterList& outputters, VUnitLogAppenderList& outputAppenders, const VString& outputType, const VString& filePath) { 00324 VLogAppender* appender = VUnitOutputWriter::_newLogAppenderByType(outputType, filePath); 00325 VUnitOutputWriter* outputInterface = VUnitOutputWriter::_newOutputWriterByType(outputType, appender); 00326 00327 if (outputInterface == NULL) { 00328 delete appender; 00329 } else { 00330 outputAppenders.push_back(appender); 00331 outputters.push_back(outputInterface); 00332 } 00333 } 00334 00335 // VTestSuitesWrapper -------------------------------------------------------- 00336 00337 VTestSuitesWrapper::VTestSuitesWrapper(const VStringVector& args) : 00338 mWriters(), 00339 mAppenders() { 00340 VUnitOutputWriter::createOutputWriters(args, mWriters, mAppenders); 00341 00342 for (VUnitOutputWriterList::iterator i = mWriters.begin(); i != mWriters.end(); ++i) 00343 (*i)->testSuitesBegin(); 00344 } 00345 00346 VTestSuitesWrapper::~VTestSuitesWrapper() { 00347 for (VUnitOutputWriterList::iterator i = mWriters.begin(); i != mWriters.end(); ++i) 00348 (*i)->testSuitesEnd(); 00349 00350 vault::vectorDeleteAll(mWriters); 00351 vault::vectorDeleteAll(mAppenders); 00352 } 00353 00354 // VUnitJUnitXMLOutput ------------------------------------------------------- 00355 00356 static VString _escapeXMLString(const VString& original) { 00357 VString result(original); 00358 00359 result.replace("&", "&"); 00360 result.replace("\"", """); 00361 result.replace("<", "<"); 00362 result.replace(">", ">"); 00363 00364 return result; 00365 } 00366 00367 VUnitJUnitXMLOutput::VUnitJUnitXMLOutput(VLogAppender& outputAppender) : 00368 VUnitOutputWriter(outputAppender) { 00369 } 00370 00371 void VUnitJUnitXMLOutput::testSuitesBegin() { 00372 this->_testSuitesBegin(); 00373 00374 mLogAppender.emitRaw("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"); 00375 mLogAppender.emitRaw("<testsuites>"); 00376 } 00377 00378 void VUnitJUnitXMLOutput::testSuiteBegin(const VString& testSuiteName) { 00379 this->_testSuiteBegin(testSuiteName); 00380 } 00381 00382 void VUnitJUnitXMLOutput::testSuiteStatusMessage(const VString& /*message*/) { 00383 } 00384 00385 void VUnitJUnitXMLOutput::testCaseBegin(const VString& testCaseName) { 00386 this->_testCaseBegin(testCaseName); 00387 } 00388 00389 void VUnitJUnitXMLOutput::testCaseEnd(const VTestInfo& testInfo) { 00390 this->_testCaseEnd(testInfo); 00391 } 00392 00393 void VUnitJUnitXMLOutput::testSuiteEnd() { 00394 this->_testSuiteEnd(); 00395 00396 VDuration testSuiteDuration = mCurrentTestSuiteEndTime - mCurrentTestSuiteStartTime; 00397 00398 mLogAppender.emitRaw(VSTRING_FORMAT(" <testsuite errors=\"%d\" failures=\"0\" name=\"%s\" tests=\"%d\" time=\"%s\">", 00399 mCurrentTestSuiteNumErrors, mCurrentTestSuiteName.chars(), (int)mCurrentTestSuiteResults.size(), testSuiteDuration.getDurationString().chars())); 00400 00401 for (TestInfoVector::const_iterator i = mCurrentTestSuiteResults.begin(); i != mCurrentTestSuiteResults.end(); ++i) { 00402 mLogAppender.emitRaw(VSTRING_FORMAT(" <testcase class=\"%s\" name=\"%s\" time=\"%s\"></testcase>", 00403 mCurrentTestSuiteName.chars(), _escapeXMLString((*i).mDescription).chars(), (*i).mDuration.getDurationString().chars())); 00404 } 00405 00406 mLogAppender.emitRaw(" </testsuite>"); 00407 } 00408 00409 void VUnitJUnitXMLOutput::testSuitesEnd() { 00410 mLogAppender.emitRaw("</testsuites>"); 00411 } 00412 00413 // VUnitSimpleTextOutput ----------------------------------------------------- 00414 00415 VUnitSimpleTextOutput::VUnitSimpleTextOutput(VLogAppender& outputAppender) : 00416 VUnitOutputWriter(outputAppender) { 00417 } 00418 00419 void VUnitSimpleTextOutput::testSuitesBegin() { 00420 this->_testSuitesBegin(); 00421 00422 mLogAppender.emitRaw(VSTRING_FORMAT("[status ] Test run starting at %s.", mTestSuitesStartTime.getLocalString().chars())); 00423 mLogAppender.emitRaw(VString::EMPTY()); 00424 } 00425 00426 void VUnitSimpleTextOutput::testSuiteBegin(const VString& testSuiteName) { 00427 this->_testSuiteBegin(testSuiteName); 00428 00429 mLogAppender.emitRaw(VSTRING_FORMAT("[status ] %s : starting.", testSuiteName.chars())); 00430 } 00431 00432 void VUnitSimpleTextOutput::testSuiteStatusMessage(const VString& message) { 00433 mLogAppender.emitRaw(VSTRING_FORMAT("[status ] %s : %s", mCurrentTestSuiteName.chars(), message.chars())); 00434 } 00435 00436 void VUnitSimpleTextOutput::testCaseBegin(const VString& testCaseName) { 00437 this->_testCaseBegin(testCaseName); 00438 } 00439 00440 void VUnitSimpleTextOutput::testCaseEnd(const VTestInfo& testInfo) { 00441 this->_testCaseEnd(testInfo); 00442 00443 mLogAppender.emitRaw(VSTRING_FORMAT("[%s] %s : %s.", (testInfo.mSuccess ? "success" : "FAILURE"), mCurrentTestSuiteName.chars(), testInfo.mDescription.chars())); 00444 } 00445 00446 void VUnitSimpleTextOutput::testSuiteEnd() { 00447 this->_testSuiteEnd(); 00448 00449 mLogAppender.emitRaw(VSTRING_FORMAT("[status ] %s : ended.", mCurrentTestSuiteName.chars())); 00450 mLogAppender.emitRaw(VSTRING_FORMAT("[results] %s : tests passed: %d", mCurrentTestSuiteName.chars(), mCurrentTestSuiteNumSuccesses)); 00451 mLogAppender.emitRaw(VSTRING_FORMAT("[results] %s : tests failed: %d", mCurrentTestSuiteName.chars(), mCurrentTestSuiteNumErrors)); 00452 mLogAppender.emitRaw(VSTRING_FORMAT("[results] %s : summary: %s.", mCurrentTestSuiteName.chars(), ((mCurrentTestSuiteNumErrors == 0) ? "success" : "FAILURE"))); 00453 mLogAppender.emitRaw(VString::EMPTY()); 00454 } 00455 00456 void VUnitSimpleTextOutput::testSuitesEnd() { 00457 mLogAppender.emitRaw(VSTRING_FORMAT("[results] TOTAL tests passed: %d", mTotalNumSuccesses)); 00458 mLogAppender.emitRaw(VSTRING_FORMAT("[results] TOTAL tests failed: %d", mTotalNumErrors)); 00459 mLogAppender.emitRaw(VSTRING_FORMAT("[results] TOTAL summary: %s.", ((mTotalNumErrors == 0) ? "success" : "FAILURE"))); 00460 00461 if (mFailedTestSuiteNames.size() != 0) { 00462 VString names; 00463 for (VStringVector::const_iterator i = mFailedTestSuiteNames.begin(); i != mFailedTestSuiteNames.end(); ++i) { 00464 names += ' '; 00465 names += *i; 00466 } 00467 mLogAppender.emitRaw(VSTRING_FORMAT("[results] Names of suites with failures:%s", names.chars())); 00468 } 00469 00470 VInstant now; 00471 VDuration totalTestTime = now - mTestSuitesStartTime; 00472 mLogAppender.emitRaw(VString::EMPTY()); 00473 mLogAppender.emitRaw(VSTRING_FORMAT("[status ] Test run ending at %s. Total time %s.", now.getLocalString().chars(), totalTestTime.getDurationString().chars())); 00474 } 00475 00476 // VUnitTeamCityOutput ------------------------------------------------------- 00477 00478 static VString _escapeTeamCityString(const VString& original) { 00479 VString result = original; 00480 00481 result.replace("|", "||"); 00482 result.replace("'", "|'"); 00483 result.replace("\n", "|\n"); 00484 result.replace("\r", "|\r"); 00485 result.replace("]", "|]"); 00486 00487 return result; 00488 } 00489 00490 VUnitTeamCityOutput::VUnitTeamCityOutput(VLogAppender& outputAppender) : 00491 VUnitOutputWriter(outputAppender) { 00492 } 00493 00494 void VUnitTeamCityOutput::testSuitesBegin() { 00495 this->_testSuitesBegin(); 00496 } 00497 00498 void VUnitTeamCityOutput::testSuiteBegin(const VString& testSuiteName) { 00499 this->_testSuiteBegin(testSuiteName); 00500 00501 mLogAppender.emitRaw(VSTRING_FORMAT("##teamcity[testSuiteStarted name='%s']", _escapeTeamCityString(testSuiteName).chars())); 00502 } 00503 00504 void VUnitTeamCityOutput::testSuiteStatusMessage(const VString& /*message*/) { 00505 } 00506 00507 void VUnitTeamCityOutput::testCaseBegin(const VString& testCaseName) { 00508 this->_testCaseBegin(testCaseName); 00509 00510 mLogAppender.emitRaw(VSTRING_FORMAT("##teamcity[testStarted name='%s']", _escapeTeamCityString(testCaseName).chars())); 00511 } 00512 00513 void VUnitTeamCityOutput::testCaseEnd(const VTestInfo& testInfo) { 00514 this->_testCaseEnd(testInfo); 00515 00516 if (!testInfo.mSuccess) 00517 mLogAppender.emitRaw(VSTRING_FORMAT("##teamcity[testFailed name='%s' message='%s']", _escapeTeamCityString(mCurrentTestCaseName).chars(), _escapeTeamCityString(testInfo.mDescription).chars())); 00518 00519 mLogAppender.emitRaw(VSTRING_FORMAT("##teamcity[testFinished name='%s']", _escapeTeamCityString(mCurrentTestCaseName).chars())); 00520 } 00521 00522 void VUnitTeamCityOutput::testSuiteEnd() { 00523 this->_testSuiteEnd(); 00524 00525 mLogAppender.emitRaw(VSTRING_FORMAT("##teamcity[testSuiteFinished name='%s']", _escapeTeamCityString(mCurrentTestSuiteName).chars())); 00526 } 00527 00528 void VUnitTeamCityOutput::testSuitesEnd() { 00529 } 00530 00531 // VUnitTeamCityBuildStatusOutput -------------------------------------------- 00532 00533 VUnitTeamCityBuildStatusOutput::VUnitTeamCityBuildStatusOutput(VLogAppender& outputAppender) : 00534 VUnitOutputWriter(outputAppender) { 00535 } 00536 00537 void VUnitTeamCityBuildStatusOutput::testSuitesBegin() { 00538 this->_testSuitesBegin(); 00539 } 00540 00541 void VUnitTeamCityBuildStatusOutput::testSuiteBegin(const VString& testSuiteName) { 00542 this->_testSuiteBegin(testSuiteName); 00543 } 00544 00545 void VUnitTeamCityBuildStatusOutput::testSuiteStatusMessage(const VString& /*message*/) { 00546 } 00547 00548 void VUnitTeamCityBuildStatusOutput::testCaseBegin(const VString& testCaseName) { 00549 this->_testCaseBegin(testCaseName); 00550 } 00551 00552 void VUnitTeamCityBuildStatusOutput::testCaseEnd(const VTestInfo& testInfo) { 00553 this->_testCaseEnd(testInfo); 00554 } 00555 00556 void VUnitTeamCityBuildStatusOutput::testSuiteEnd() { 00557 this->_testSuiteEnd(); 00558 } 00559 00560 void VUnitTeamCityBuildStatusOutput::testSuitesEnd() { 00561 try { 00562 mLogAppender.emitRaw(VString("<build number=\"{build.number}\">")); 00563 mLogAppender.emitRaw(VSTRING_FORMAT(" <statusInfo status=\"%s\">", (mTotalNumErrors == 0 ? "SUCCESS" : "FAILURE"))); 00564 mLogAppender.emitRaw(VSTRING_FORMAT(" <text action=\"append\">Tests passed: %d</text>", mTotalNumSuccesses)); 00565 mLogAppender.emitRaw(VSTRING_FORMAT(" <text action=\"append\">Tests failed: %d</text>", mTotalNumErrors)); 00566 00567 if (mFailedTestSuiteNames.size() != 0) { 00568 VString names; 00569 for (VStringVector::const_iterator i = mFailedTestSuiteNames.begin(); i != mFailedTestSuiteNames.end(); ++i) { 00570 names += ' '; 00571 names += *i; 00572 } 00573 00574 mLogAppender.emitRaw(VSTRING_FORMAT(" <text action=\"append\">These are the names of the failed tests:%s</text>", names.chars())); 00575 } 00576 00577 mLogAppender.emitRaw(VString(" </statusInfo>")); 00578 00579 mLogAppender.emitRaw(VSTRING_FORMAT(" <statisticValue key=\"testCount\" value=\"%d\"/>", mTotalNumSuccesses + mTotalNumErrors)); 00580 mLogAppender.emitRaw(VSTRING_FORMAT(" <statisticValue key=\"testsPassed\" value=\"%d\"/>", mTotalNumSuccesses)); 00581 mLogAppender.emitRaw(VSTRING_FORMAT(" <statisticValue key=\"testsFailed\" value=\"%d\"/>", mTotalNumErrors)); 00582 00583 mLogAppender.emitRaw(VString("</build>")); 00584 } catch (...) {} // prevent exceptions from escaping destructor 00585 } 00586