Skip to content
This repository was archived by the owner on Oct 17, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 48 additions & 10 deletions TcUnit-Runner/TcUnitResultCollector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ class TcUnitResultCollector
private enum ErrorLogEntryType
{
TEST_SUITE_FINISHED_RUNNING = 0, // For example: | Test suite ID=1 'PRG_TEST.fbDiagnosticMessageFlagsParser_Test'
TEST_SUITE_STATISTICS, // For example: | ID=1 number of tests=4, number of failed tests=1
TEST_SUITE_STATISTICS, // For example: | ID=1 number of tests=4, number of failed tests=1, duration=0.1
TEST_NAME, // For example: | Test name=WhenWarningMessageExpectWarningMessageLocalTimestampAndTwoParameters
TEST_CLASS_NAME, // For example: | Test class name=PRG_TEST.fbDiagnosticMessageFlagsParser_Test
TEST_DURATION, // For example: | Test duration=0.010
TEST_STATUS_AND_NUMBER_OF_ASSERTS, // For example: | Test status=SUCCESS, number of asserts=3
TEST_ASSERT_MESSAGE, // For example: | Test assert message=Test 'Warning message' failed at 'diagnosis type'
TEST_ASSERT_TYPE, // For example: | Test assert type=ANY
Expand All @@ -27,11 +28,12 @@ private enum ErrorLogEntryType
private int numberOfTests = -1;
private int numberOfSuccessfulTests = -1;
private int numberOfFailedTests = -1;
private double duration = 0.0;
private const string tcUnitResult_TestSuites = "| Test suites:";
private const string tcUnitResult_Tests = "| Tests:";
private const string tcUnitResult_SuccessfulTests = "| Successful tests:";
private const string tcUnitResult_FailedTests = "| Failed tests:";

private const string tcUnitResult_Duration = "| Duration:";

public TcUnitResultCollector()
{ }
Expand Down Expand Up @@ -73,6 +75,11 @@ public bool AreResultsAvailable(ErrorItems errorItems)
string noFailedTests = line.Substring(line.LastIndexOf(tcUnitResult_FailedTests) + tcUnitResult_FailedTests.Length + 1);
Int32.TryParse(noFailedTests, out numberOfFailedTests);
}
if (line.Contains(tcUnitResult_Duration))
{
string durationString = line.Substring(line.LastIndexOf(tcUnitResult_Duration) + tcUnitResult_Duration.Length + 1);
double.TryParse(durationString, out duration);
}
}
return AreTestResultsAvailable();
}
Expand All @@ -97,7 +104,8 @@ public TcUnitTestResult ParseResults(IEnumerable<ErrorList.Error> errors, string
ErrorLogEntryType expectedErrorLogEntryType = ErrorLogEntryType.TEST_SUITE_FINISHED_RUNNING;

tcUnitTestResult.AddGeneralTestResults((uint)numberOfTestSuites, (uint)numberOfTests,
(uint)numberOfSuccessfulTests, (uint)numberOfFailedTests);
(uint)numberOfSuccessfulTests, (uint)numberOfFailedTests,
duration);

// Temporary variables
uint currentTestIdentity = 0;
Expand All @@ -109,10 +117,12 @@ public TcUnitTestResult ParseResults(IEnumerable<ErrorList.Error> errors, string
uint testSuiteIdentity = 0;
uint testSuiteNumberOfTests = 0;
uint testSuiteNumberOfFailedTests = 0;
double testSuiteDuration = 0.0;

// Test case
string testSuiteTestCaseName = "";
string testSuiteTestCaseClassName = "";
double testSuiteTestCaseDuration = 0.0;
string testSuiteTestCaseStatus = "";
string testSuiteTestCaseFailureMessage = "";
string testSuiteTestCaseAssertType = "";
Expand All @@ -139,9 +149,11 @@ public TcUnitTestResult ParseResults(IEnumerable<ErrorList.Error> errors, string
testSuiteIdentity = 0;
testSuiteNumberOfTests = 0;
testSuiteNumberOfFailedTests = 0;
testSuiteDuration = 0.0;

testSuiteTestCaseName = "";
testSuiteTestCaseClassName = "";
testSuiteTestCaseDuration = 0.0;
testSuiteTestCaseStatus = "";
testSuiteTestCaseFailureMessage = "";
testSuiteTestCaseAssertType = "";
Expand Down Expand Up @@ -178,11 +190,16 @@ public TcUnitTestResult ParseResults(IEnumerable<ErrorList.Error> errors, string
{
// Handle error
}
string numberOfFailedTestsString = tcUnitAdsMessage.Substring(tcUnitAdsMessage.LastIndexOf(", number of failed tests=") + 25);
string numberOfFailedTestsString = Utilities.GetStringBetween(tcUnitAdsMessage, ", number of failed tests=", ", duration=");
if (!uint.TryParse(numberOfFailedTestsString, out testSuiteNumberOfFailedTests))
{
// Handle error
}
string durationString = tcUnitAdsMessage.Substring(tcUnitAdsMessage.LastIndexOf(", duration=") + 11);
if (!double.TryParse(durationString, out testSuiteDuration))
{
// Handle error
}

/* Now two things can happen. Either the testsuite didn't have any tests (testSuiteNumberOfTests=0)
or it had tests. If it didn't have any tests, we store the testsuite result here and go to the
Expand All @@ -191,7 +208,7 @@ public TcUnitTestResult ParseResults(IEnumerable<ErrorList.Error> errors, string
if (testSuiteNumberOfTests.Equals(0))
{
// Store test suite & go to next test suite
TcUnitTestResult.TestSuiteResult tsResult = new TcUnitTestResult.TestSuiteResult(testSuiteName, testSuiteIdentity, testSuiteNumberOfTests, testSuiteNumberOfFailedTests);
TcUnitTestResult.TestSuiteResult tsResult = new TcUnitTestResult.TestSuiteResult(testSuiteName, testSuiteIdentity, testSuiteNumberOfTests, testSuiteNumberOfFailedTests, testSuiteDuration);
tcUnitTestResult.AddNewTestSuiteResult(tsResult);
expectedErrorLogEntryType = ErrorLogEntryType.TEST_SUITE_FINISHED_RUNNING;
}
Expand Down Expand Up @@ -243,6 +260,28 @@ public TcUnitTestResult ParseResults(IEnumerable<ErrorList.Error> errors, string
// Parse test class name
string testClassName = tcUnitAdsMessage.Substring(tcUnitAdsMessage.LastIndexOf("Test class name=") + 16);
testSuiteTestCaseClassName = testClassName;
expectedErrorLogEntryType = ErrorLogEntryType.TEST_DURATION;
}
else
{
log.Error("While parsing TcUnit results, expected " + expectedErrorLogEntryType.ToString() + " but got " + ErrorLogEntryType.TEST_CLASS_NAME.ToString());
return null;
}
}

/* -------------------------------------
Look for test duration
------------------------------------- */
else if (tcUnitAdsMessage.Contains("Test duration="))
{
if (expectedErrorLogEntryType == ErrorLogEntryType.TEST_DURATION)
{
// Parse test class name
string testDuration = tcUnitAdsMessage.Substring(tcUnitAdsMessage.LastIndexOf("Test duration=") + 14);
if (!double.TryParse(testDuration, out testSuiteTestCaseDuration))
{
// Handle error
}
expectedErrorLogEntryType = ErrorLogEntryType.TEST_STATUS_AND_NUMBER_OF_ASSERTS;
}
else
Expand Down Expand Up @@ -276,7 +315,7 @@ or the next test suite */
else
{
// Store test case
TcUnitTestResult.TestCaseResult tcResult = new TcUnitTestResult.TestCaseResult(testSuiteTestCaseName, testSuiteTestCaseClassName, testSuiteTestCaseStatus, "", "", testSuiteTestCaseNumberOfAsserts);
TcUnitTestResult.TestCaseResult tcResult = new TcUnitTestResult.TestCaseResult(testSuiteTestCaseName, testSuiteTestCaseClassName, testSuiteTestCaseStatus, "", "", testSuiteTestCaseNumberOfAsserts, testSuiteTestCaseDuration);

// Add test case result to test cases results
testSuiteTestCaseResults.Add(tcResult);
Expand All @@ -288,7 +327,7 @@ or the next test suite */
else
{ // Last test case in this test suite
// Create test suite result
TcUnitTestResult.TestSuiteResult tsResult = new TcUnitTestResult.TestSuiteResult(testSuiteName, testSuiteIdentity, testSuiteNumberOfTests, testSuiteNumberOfFailedTests);
TcUnitTestResult.TestSuiteResult tsResult = new TcUnitTestResult.TestSuiteResult(testSuiteName, testSuiteIdentity, testSuiteNumberOfTests, testSuiteNumberOfFailedTests, testSuiteDuration);

// Add test case results to test suite
foreach (TcUnitTestResult.TestCaseResult tcResultToBeStored in testSuiteTestCaseResults)
Expand All @@ -301,7 +340,6 @@ or the next test suite */
expectedErrorLogEntryType = ErrorLogEntryType.TEST_SUITE_FINISHED_RUNNING;
}
}

}
else
{
Expand Down Expand Up @@ -350,7 +388,7 @@ or the next test suite */
testSuiteTestCaseAssertType = testAssertType;

// Store test case
TcUnitTestResult.TestCaseResult tcResult = new TcUnitTestResult.TestCaseResult(testSuiteTestCaseName, testSuiteTestCaseClassName, testSuiteTestCaseStatus, testSuiteTestCaseFailureMessage, testSuiteTestCaseAssertType, testSuiteTestCaseNumberOfAsserts);
TcUnitTestResult.TestCaseResult tcResult = new TcUnitTestResult.TestCaseResult(testSuiteTestCaseName, testSuiteTestCaseClassName, testSuiteTestCaseStatus, testSuiteTestCaseFailureMessage, testSuiteTestCaseAssertType, testSuiteTestCaseNumberOfAsserts, testSuiteTestCaseDuration);

// Add test case result to test cases results
testSuiteTestCaseResults.Add(tcResult);
Expand All @@ -362,7 +400,7 @@ or the next test suite */
else
{ // Last test case in this test suite
// Create test suite result
TcUnitTestResult.TestSuiteResult tsResult = new TcUnitTestResult.TestSuiteResult(testSuiteName, testSuiteIdentity, testSuiteNumberOfTests, testSuiteNumberOfFailedTests);
TcUnitTestResult.TestSuiteResult tsResult = new TcUnitTestResult.TestSuiteResult(testSuiteName, testSuiteIdentity, testSuiteNumberOfTests, testSuiteNumberOfFailedTests, testSuiteTestCaseDuration);

// Add test case results to test suite
foreach (TcUnitTestResult.TestCaseResult tcResultToBeStored in testSuiteTestCaseResults)
Expand Down
16 changes: 13 additions & 3 deletions TcUnit-Runner/TcUnitTestResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class TcUnitTestResult : IEnumerable<TcUnitTestResult.TestSuiteResult>, IEnumera
protected uint _numberOfTestCases;
protected uint _numberOfSuccessfulTestCases;
protected uint _numberOfFailedTestCases;
protected double _duration;

/* Test results for each individiual test suite */
protected List<TestSuiteResult> _testSuiteResults = new List<TestSuiteResult>();
Expand Down Expand Up @@ -73,11 +74,13 @@ public struct TestCaseResult
public string FailureMessage;
public string AssertType;
public uint NumberOfAsserts;
public double TestDuration;
public bool WasSuccessful;
public TestCaseResult(string testName, string testClassName, string testStatus, string failureMessage, string assertType, uint numberOfAsserts)
public TestCaseResult(string testName, string testClassName, string testStatus, string failureMessage, string assertType, uint numberOfAsserts, double duration)
{
TestName = testName;
TestClassName = testClassName;
TestDuration = duration;
TestStatus = testStatus;
FailureMessage = failureMessage;
AssertType = assertType;
Expand All @@ -92,14 +95,16 @@ public struct TestSuiteResult
public uint Identity;
public uint NumberOfTests;
public uint NumberOfFailedTests;
public double Duration;
public List<TestCaseResult> TestCaseResults;

public TestSuiteResult(string name, uint identity, uint numberOfTests, uint numberOfFailedTests)
public TestSuiteResult(string name, uint identity, uint numberOfTests, uint numberOfFailedTests, double duration)
{
Name = name;
Identity = identity;
NumberOfTests = numberOfTests;
NumberOfFailedTests = numberOfFailedTests;
Duration = duration;
TestCaseResults = new List<TestCaseResult>();
}
}
Expand All @@ -109,12 +114,13 @@ public void AddNewTestSuiteResult(TestSuiteResult testsuiteResult)
_testSuiteResults.Add(testsuiteResult);
}

public void AddGeneralTestResults(uint numberOfTestSuites, uint numberOfTestCases, uint numberOfSuccessfulTestCases, uint numberOfFailedTestCases)
public void AddGeneralTestResults(uint numberOfTestSuites, uint numberOfTestCases, uint numberOfSuccessfulTestCases, uint numberOfFailedTestCases, double duration)
{
_numberOfTestSuites = numberOfTestSuites;
_numberOfTestCases = numberOfTestCases;
_numberOfSuccessfulTestCases = numberOfSuccessfulTestCases;
_numberOfFailedTestCases = numberOfFailedTestCases;
_duration = duration;
}

IEnumerator<TestSuiteResult> IEnumerable<TestSuiteResult>.GetEnumerator()
Expand Down Expand Up @@ -146,6 +152,10 @@ public uint GetNumberOfFailedTestCases()
{
return _numberOfFailedTestCases;
}
public double GetDuration()
{
return _duration;
}

public bool GetAllTestsPassed()
{
Expand Down
9 changes: 9 additions & 0 deletions TcUnit-Runner/XunitXmlCreator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ public static void WriteXml(TcUnitTestResult testResults, string filePath)
XmlAttribute testSuitesAttributeTests = xmlDoc.CreateAttribute("tests");
testSuitesAttributeTests.Value = testResults.GetNumberOfTestCases().ToString();
testSuitesNode.Attributes.Append(testSuitesAttributeTests);
XmlAttribute testSuitesAttributeTime = xmlDoc.CreateAttribute("time");
testSuitesAttributeTime.Value = testResults.GetDuration().ToString();
testSuitesNode.Attributes.Append(testSuitesAttributeTests);

foreach (TcUnitTestResult.TestSuiteResult tsResult in testResults)
{
Expand All @@ -52,6 +55,9 @@ public static void WriteXml(TcUnitTestResult testResults, string filePath)
XmlAttribute testSuiteAttributeFailures = xmlDoc.CreateAttribute("failures");
testSuiteAttributeFailures.Value = tsResult.NumberOfFailedTests.ToString();
testSuiteNode.Attributes.Append(testSuiteAttributeFailures);
XmlAttribute testSuiteAttributeTime = xmlDoc.CreateAttribute("time");
testSuiteAttributeTime.Value = tsResult.Duration.ToString();
testSuiteNode.Attributes.Append(testSuiteAttributeTime);

// <testcase>
foreach (TcUnitTestResult.TestCaseResult tcResult in tsResult.TestCaseResults)
Expand All @@ -68,6 +74,9 @@ public static void WriteXml(TcUnitTestResult testResults, string filePath)
XmlAttribute testCaseAttributeTestClassName = xmlDoc.CreateAttribute("classname");
testCaseAttributeTestClassName.Value = tcResult.TestClassName;
testCaseNode.Attributes.Append(testCaseAttributeTestClassName);
XmlAttribute testCaseAttributeTestTime = xmlDoc.CreateAttribute("time");
testCaseAttributeTestTime.Value = tcResult.TestDuration.ToString();
testCaseNode.Attributes.Append(testCaseAttributeTestTime);
XmlAttribute testCaseAttributeStatus = xmlDoc.CreateAttribute("status");
testCaseAttributeStatus.Value = tcResult.TestStatus;
testCaseNode.Attributes.Append(testCaseAttributeStatus);
Expand Down