summaryrefslogtreecommitdiffstats
path: root/tools/slang-test/test-context.cpp
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2018-11-09 10:23:37 -0500
committerGitHub <noreply@github.com>2018-11-09 10:23:37 -0500
commitd782a162a783eab3f4a57a22056c5eba04c2b4ae (patch)
tree36be12801f7e6833133f86eb7f6437c037038922 /tools/slang-test/test-context.cpp
parentde6ca4df6668aa4f3f5113410e2e898e37cd7bc4 (diff)
Feature/teamcity output (#715)
* First pass support for TeamCity compatible output. * Remove reset of counters on starting suite - so summary is over all suites.
Diffstat (limited to 'tools/slang-test/test-context.cpp')
-rw-r--r--tools/slang-test/test-context.cpp149
1 files changed, 149 insertions, 0 deletions
diff --git a/tools/slang-test/test-context.cpp b/tools/slang-test/test-context.cpp
index 822a5953c..158258873 100644
--- a/tools/slang-test/test-context.cpp
+++ b/tools/slang-test/test-context.cpp
@@ -99,7 +99,10 @@ bool TestContext::canWriteStdError() const
void TestContext::startTest(const String& testName)
{
+ // Must be in a suite
+ assert(m_suiteStack.Count());
assert(!m_inTest);
+
m_inTest = true;
m_numCurrentResults = 0;
@@ -112,6 +115,7 @@ void TestContext::startTest(const String& testName)
void TestContext::endTest()
{
+ assert(m_suiteStack.Count());
assert(m_inTest);
m_currentInfo.message = m_currentMessage;
@@ -196,6 +200,51 @@ void TestContext::dumpOutputDifference(const String& expectedOutput, const Strin
message(TestMessageType::TestFailure, builder);
}
+static char _getTeamCityEscapeChar(char c)
+{
+ switch (c)
+ {
+ case '|': return '|';
+ case '\'': return '\'';
+ case '\n': return 'n';
+ case '\r': return 'r';
+ case '[': return '[';
+ case ']': return ']';
+ default: return 0;
+ }
+}
+
+static void _appendEncodedTeamCityString(const UnownedStringSlice& in, StringBuilder& builder)
+{
+ const char* start = in.begin();
+ const char* cur = start;
+ const char* end = in.end();
+
+ for (const char* cur = start; cur < end; cur++)
+ {
+ const char c = *cur;
+ const char escapeChar = _getTeamCityEscapeChar(c);
+ if (escapeChar)
+ {
+ // Flush
+ if (cur > start)
+ {
+ builder.Append(start, UInt(cur - start));
+ }
+
+ builder.Append('|');
+ builder.Append(escapeChar);
+ start = cur + 1;
+ }
+ }
+
+ // Flush the end
+ if (end > start)
+ {
+ builder.Append(start, UInt(end - start));
+ }
+}
+
void TestContext::_addResult(const TestInfo& info)
{
m_totalTestCount++;
@@ -239,6 +288,63 @@ void TestContext::_addResult(const TestInfo& info)
printf("%s test: '%S'\n", resultString, info.name.ToWString().begin());
break;
}
+ case TestOutputMode::TeamCity:
+ {
+ StringBuilder escapedTestName;
+ _appendEncodedTeamCityString(info.name.getUnownedSlice(), escapedTestName);
+
+ printf("##teamcity[testStarted name='%s']\n", escapedTestName.begin());
+
+ switch (info.testResult)
+ {
+ case TestResult::Fail:
+ {
+ if (info.message.Length())
+ {
+ StringBuilder escapedMessage;
+ _appendEncodedTeamCityString(info.message.getUnownedSlice(), escapedMessage);
+ printf("##teamcity[testFailed name='%s' message='%s']\n", escapedTestName.begin(), escapedMessage.begin());
+ }
+ else
+ {
+ printf("##teamcity[testFailed name='%s']\n", escapedTestName.begin());
+ }
+ break;
+ }
+ case TestResult::Pass:
+ {
+ if (info.message.Length())
+ {
+ StringBuilder escapedMessage;
+ _appendEncodedTeamCityString(info.message.getUnownedSlice(), escapedMessage);
+ printf("##teamcity[testStdOut name='%s' out='%s']\n", escapedTestName.begin(), escapedMessage.begin());
+ }
+ break;
+ }
+ case TestResult::Ignored:
+ {
+ if (info.message.Length())
+ {
+ StringBuilder escapedMessage;
+ _appendEncodedTeamCityString(info.message.getUnownedSlice(), escapedMessage);
+
+ printf("##teamcity[testIgnored name='%s' message='%s']\n", escapedTestName.begin(), escapedMessage.begin());
+ }
+ else
+ {
+ printf("##teamcity[testIgnored name='%s']\n", escapedTestName.begin());
+ }
+ break;
+ }
+ default:
+ assert(!"unexpected");
+ break;
+ }
+
+ printf("##teamcity[testFinished name='%s']\n", escapedTestName.begin());
+ fflush(stdout);
+ break;
+ }
case TestOutputMode::XUnit2:
case TestOutputMode::XUnit:
{
@@ -397,6 +503,7 @@ void TestContext::outputSummary()
}
break;
}
+
case TestOutputMode::XUnit:
{
// xUnit 1.0 format
@@ -451,5 +558,47 @@ void TestContext::outputSummary()
assert("Not currently supported");
break;
}
+ case TestOutputMode::TeamCity:
+ {
+ // Don't output a summary
+ break;
+ }
+ }
+}
+
+void TestContext::startSuite(const String& name)
+{
+ m_suiteStack.Add(name);
+
+ switch (m_outputMode)
+ {
+ case TestOutputMode::TeamCity:
+ {
+ StringBuilder escapedSuiteName;
+ _appendEncodedTeamCityString(name.getUnownedSlice(), escapedSuiteName);
+ printf("##teamcity[testSuiteStarted name='%s']\n", escapedSuiteName.begin());
+ break;
+ }
+ default: break;
+ }
+}
+
+void TestContext::endSuite()
+{
+ assert(m_suiteStack.Count());
+
+ switch (m_outputMode)
+ {
+ case TestOutputMode::TeamCity:
+ {
+ const String& name = m_suiteStack.Last();
+ StringBuilder escapedSuiteName;
+ _appendEncodedTeamCityString(name.getUnownedSlice(), escapedSuiteName);
+ printf("##teamcity[testSuiteFinished name='%s']\n", escapedSuiteName.begin());
+ break;
+ }
+ default: break;
}
+
+ m_suiteStack.RemoveLast();
} \ No newline at end of file