|
Packit |
6d2c1b |
/*
|
|
Packit |
6d2c1b |
* The MIT License
|
|
Packit |
6d2c1b |
*
|
|
Packit |
6d2c1b |
* Copyright (c) 2011 Bruno P. Kinoshita <http://www.kinoshita.eti.br>
|
|
Packit |
6d2c1b |
*
|
|
Packit |
6d2c1b |
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
Packit |
6d2c1b |
* of this software and associated documentation files (the "Software"), to deal
|
|
Packit |
6d2c1b |
* in the Software without restriction, including without limitation the rights
|
|
Packit |
6d2c1b |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
Packit |
6d2c1b |
* copies of the Software, and to permit persons to whom the Software is
|
|
Packit |
6d2c1b |
* furnished to do so, subject to the following conditions:
|
|
Packit |
6d2c1b |
*
|
|
Packit |
6d2c1b |
* The above copyright notice and this permission notice shall be included in
|
|
Packit |
6d2c1b |
* all copies or substantial portions of the Software.
|
|
Packit |
6d2c1b |
*
|
|
Packit |
6d2c1b |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
Packit |
6d2c1b |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
Packit |
6d2c1b |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
Packit |
6d2c1b |
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
Packit |
6d2c1b |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
Packit |
6d2c1b |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
Packit |
6d2c1b |
* THE SOFTWARE.
|
|
Packit |
6d2c1b |
*
|
|
Packit |
6d2c1b |
* @author Bruno P. Kinoshita <http://www.kinoshita.eti.br>
|
|
Packit |
6d2c1b |
* @since 0.1
|
|
Packit |
6d2c1b |
*/
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
#ifndef TAP_H_
|
|
Packit |
6d2c1b |
#define TAP_H_
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
#include <list>
|
|
Packit |
6d2c1b |
#include <iostream>
|
|
Packit |
6d2c1b |
#include <map>
|
|
Packit |
6d2c1b |
#include <fstream>
|
|
Packit |
6d2c1b |
#include <string>
|
|
Packit |
6d2c1b |
#include <algorithm>
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
namespace tap {
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
#ifdef GTEST_TAP_13_DIAGNOSTIC
|
|
Packit |
6d2c1b |
// based on http://stackoverflow.com/a/7724536/831180
|
|
Packit |
6d2c1b |
static std::string replace_all_copy(
|
|
Packit |
6d2c1b |
std::string const& original,
|
|
Packit |
6d2c1b |
std::string const& before,
|
|
Packit |
6d2c1b |
std::string const& after
|
|
Packit |
6d2c1b |
) {
|
|
Packit |
6d2c1b |
using namespace std;
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
if (before == after) return string(original);
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
string retval;
|
|
Packit |
6d2c1b |
if (before.length() == after.length()) retval.reserve(original.size());
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
basic_string <char>::const_iterator end = original.end();
|
|
Packit |
6d2c1b |
basic_string <char>::const_iterator current = original.begin();
|
|
Packit |
6d2c1b |
basic_string <char>::const_iterator next =
|
|
Packit |
6d2c1b |
search(current, end, before.begin(), before.end());
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
while ( next != end ) {
|
|
Packit |
6d2c1b |
retval.append( current, next );
|
|
Packit |
6d2c1b |
retval.append( after );
|
|
Packit |
6d2c1b |
current = next + before.size();
|
|
Packit |
6d2c1b |
next = search(current, end, before.begin(), before.end());
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
retval.append( current, next );
|
|
Packit |
6d2c1b |
return retval;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
#endif
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
class TestResult {
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
private:
|
|
Packit |
6d2c1b |
int number;
|
|
Packit |
6d2c1b |
std::string status;
|
|
Packit |
6d2c1b |
std::string name;
|
|
Packit |
6d2c1b |
std::string comment;
|
|
Packit |
6d2c1b |
bool skip;
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
public:
|
|
Packit |
6d2c1b |
std::string getComment() const {
|
|
Packit |
6d2c1b |
std::stringstream ss;
|
|
Packit |
6d2c1b |
if (this->skip) {
|
|
Packit |
6d2c1b |
ss << "# SKIP " << this->comment;
|
|
Packit |
6d2c1b |
} else if (!this->comment.empty()) {
|
|
Packit |
6d2c1b |
ss << "# " << this->comment;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
return ss.str();
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
const std::string& getName() const {
|
|
Packit |
6d2c1b |
return name;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
int getNumber() const {
|
|
Packit |
6d2c1b |
return number;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
const std::string& getStatus() const {
|
|
Packit |
6d2c1b |
return status;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
bool getSkip() const {
|
|
Packit |
6d2c1b |
return skip;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
void setComment(const std::string& value) {
|
|
Packit |
6d2c1b |
this->comment = value;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
void setName(const std::string& value) {
|
|
Packit |
6d2c1b |
this->name = value;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
void setNumber(int value) {
|
|
Packit |
6d2c1b |
this->number = value;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
void setStatus(const std::string& value) {
|
|
Packit |
6d2c1b |
this->status = value;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
void setSkip(bool value) {
|
|
Packit |
6d2c1b |
this->skip = value;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
std::string toString() const {
|
|
Packit |
6d2c1b |
std::stringstream ss;
|
|
Packit |
6d2c1b |
ss << this->status << " " << this->number << " " << this->name;
|
|
Packit |
6d2c1b |
#ifdef GTEST_TAP_13_DIAGNOSTIC
|
|
Packit |
6d2c1b |
std::string comment_text = this->getComment();
|
|
Packit |
6d2c1b |
if (!comment_text.empty()) {
|
|
Packit |
6d2c1b |
ss << std::endl
|
|
Packit |
6d2c1b |
<< "# Diagnostic" << std::endl
|
|
Packit |
6d2c1b |
<< " ---" << std::endl
|
|
Packit |
6d2c1b |
<< " " << replace_all_copy(this->getComment(), "\n", "\n ");
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
#endif
|
|
Packit |
6d2c1b |
return ss.str();
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
};
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
class TestSet {
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
private:
|
|
Packit |
6d2c1b |
std::list<TestResult> testResults;
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
public:
|
|
Packit |
6d2c1b |
const std::list<TestResult>& getTestResults() const {
|
|
Packit |
6d2c1b |
return testResults;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
void addTestResult(TestResult& testResult) {
|
|
Packit |
6d2c1b |
testResult.setNumber((this->getNumberOfTests() + 1));
|
|
Packit |
6d2c1b |
this->testResults.push_back(testResult);
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
int getNumberOfTests() const {
|
|
Packit |
6d2c1b |
return this->testResults.size();
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
std::string toString() const {
|
|
Packit |
6d2c1b |
std::stringstream ss;
|
|
Packit |
6d2c1b |
ss << "1.." << this->getNumberOfTests() << std::endl;
|
|
Packit |
6d2c1b |
for (std::list<TestResult>::const_iterator ci = this->testResults.begin();
|
|
Packit |
6d2c1b |
ci != this->testResults.end(); ++ci) {
|
|
Packit |
6d2c1b |
TestResult testResult = *ci;
|
|
Packit |
6d2c1b |
ss << testResult.toString() << std::endl;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
return ss.str();
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
};
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
class TapListener: public ::testing::EmptyTestEventListener {
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
private:
|
|
Packit |
6d2c1b |
std::map<std::string, tap::TestSet> testCaseTestResultMap;
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
void addTapTestResult(const testing::TestInfo& testInfo) {
|
|
Packit |
6d2c1b |
tap::TestResult tapResult;
|
|
Packit |
6d2c1b |
tapResult.setName(testInfo.name());
|
|
Packit |
6d2c1b |
tapResult.setSkip(!testInfo.should_run());
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
const testing::TestResult *testResult = testInfo.result();
|
|
Packit |
6d2c1b |
int number = testResult->total_part_count();
|
|
Packit |
6d2c1b |
tapResult.setNumber(number-1);
|
|
Packit |
6d2c1b |
if (testResult->HasFatalFailure()) {
|
|
Packit |
6d2c1b |
tapResult.setStatus("Bail out!");
|
|
Packit |
6d2c1b |
} else if (testResult->Failed()) {
|
|
Packit |
6d2c1b |
tapResult.setStatus("not ok");
|
|
Packit |
6d2c1b |
tapResult.setComment(testResult->GetTestPartResult(number-1).summary());
|
|
Packit |
6d2c1b |
} else {
|
|
Packit |
6d2c1b |
tapResult.setStatus("ok");
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
this->addNewOrUpdate(testInfo.test_case_name(), tapResult);
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
std::string getCommentOrDirective(const std::string& comment, bool skip) {
|
|
Packit |
6d2c1b |
std::stringstream commentText;
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
if (skip) {
|
|
Packit |
6d2c1b |
commentText << " # SKIP " << comment;
|
|
Packit |
6d2c1b |
} else if (!comment.empty()) {
|
|
Packit |
6d2c1b |
commentText << " # " << comment;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
return commentText.str();
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
void addNewOrUpdate(const std::string& testCaseName, tap::TestResult testResult) {
|
|
Packit |
6d2c1b |
std::map<std::string, tap::TestSet>::const_iterator ci =
|
|
Packit |
6d2c1b |
this->testCaseTestResultMap.find(testCaseName);
|
|
Packit |
6d2c1b |
if (ci != this->testCaseTestResultMap.end()) {
|
|
Packit |
6d2c1b |
tap::TestSet testSet = ci->second;
|
|
Packit |
6d2c1b |
testSet.addTestResult(testResult);
|
|
Packit |
6d2c1b |
this->testCaseTestResultMap[testCaseName] = testSet;
|
|
Packit |
6d2c1b |
} else {
|
|
Packit |
6d2c1b |
tap::TestSet testSet;
|
|
Packit |
6d2c1b |
testSet.addTestResult(testResult);
|
|
Packit |
6d2c1b |
this->testCaseTestResultMap[testCaseName] = testSet;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
public:
|
|
Packit |
6d2c1b |
virtual void OnTestEnd(const testing::TestInfo& testInfo) {
|
|
Packit |
6d2c1b |
//printf("%s %d - %s\n", testInfo.result()->Passed() ? "ok" : "not ok", this->testNumber, testInfo.name());
|
|
Packit |
6d2c1b |
this->addTapTestResult(testInfo);
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
virtual void OnTestProgramEnd(const testing::UnitTest& unit_test) {
|
|
Packit |
6d2c1b |
//--- Write the count and the word.
|
|
Packit |
6d2c1b |
(void)unit_test;
|
|
Packit |
6d2c1b |
std::map<std::string, tap::TestSet>::const_iterator ci;
|
|
Packit |
6d2c1b |
for (ci = this->testCaseTestResultMap.begin();
|
|
Packit |
6d2c1b |
ci != this->testCaseTestResultMap.end(); ++ci) {
|
|
Packit |
6d2c1b |
const tap::TestSet& testSet = ci->second;
|
|
Packit |
6d2c1b |
#ifdef GTEST_TAP_PRINT_TO_STDOUT
|
|
Packit |
6d2c1b |
std::cout << "TAP version 13" << std::endl;
|
|
Packit |
6d2c1b |
std::cout << testSet.toString();
|
|
Packit |
6d2c1b |
#else
|
|
Packit |
6d2c1b |
std::string ext = ".tap";
|
|
Packit |
6d2c1b |
std::ofstream tapFile;
|
|
Packit |
6d2c1b |
tapFile.open((ci->first + ext).c_str());
|
|
Packit |
6d2c1b |
tapFile << testSet.toString();
|
|
Packit |
6d2c1b |
tapFile.close();
|
|
Packit |
6d2c1b |
#endif
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
};
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
} // namespace tap
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
#endif // TAP_H_
|