diff --git a/source/TestAdapter/Executor.cs b/source/TestAdapter/Executor.cs index 2f3a92e..6e20b3e 100644 --- a/source/TestAdapter/Executor.cs +++ b/source/TestAdapter/Executor.cs @@ -794,11 +794,34 @@ private void ParseTestResults(string rawOutput, List results) TestResult testResult = new TestResult(new TestCase()); string[] resultDataSet = default; - foreach (var line in outputStrings) + foreach (var rawLine in outputStrings) { - if ((line.Contains(TestPassed) - || (line.Contains(TestFailed)) - || (line.Contains(TestSkipped)))) + string line = rawLine; + + // Some tests write output without ending in a newline, so test result markers can be + // concatenated at the end of the same output line. + int markerIndex = GetResultMarkerIndex(line); + + if (markerIndex > 0) + { + if (readyFound) + { + string outputPrefix = line.Substring(0, markerIndex); + + if (!string.IsNullOrWhiteSpace(outputPrefix)) + { + testOutput.AppendLine(outputPrefix); + } + } + + line = line.Substring(markerIndex); + } + + bool isResultLine = line.StartsWith($"{TestPassed},") + || line.StartsWith($"{TestFailed},") + || line.StartsWith($"{TestSkipped},"); + + if (isResultLine) { resultDataSet = line.Split(new char[] { ',' }, 3); @@ -825,7 +848,7 @@ private void ParseTestResults(string rawOutput, List results) } } - if (line.Contains(TestPassed)) + if (line.StartsWith($"{TestPassed},")) { // Format is "Test passed,MethodName,ticks"; @@ -841,7 +864,7 @@ private void ParseTestResults(string rawOutput, List results) // reset test output testOutput = new StringBuilder(); } - else if (line.Contains(TestFailed)) + else if (line.StartsWith($"{TestFailed},")) { // Format is "Test failed,MethodName,Exception message"; @@ -854,7 +877,7 @@ private void ParseTestResults(string rawOutput, List results) // reset test output testOutput = new StringBuilder(); } - else if (line.Contains(TestSkipped)) + else if (line.StartsWith($"{TestSkipped},")) { // Format is "Test failed,MethodName,Exception message"; @@ -907,6 +930,32 @@ private void ParseTestResults(string rawOutput, List results) } } } + + int GetResultMarkerIndex(string content) + { + int passedIndex = content.IndexOf($"{TestPassed},", StringComparison.Ordinal); + int failedIndex = content.IndexOf($"{TestFailed},", StringComparison.Ordinal); + int skippedIndex = content.IndexOf($"{TestSkipped},", StringComparison.Ordinal); + + int markerIndex = -1; + + if (passedIndex >= 0) + { + markerIndex = passedIndex; + } + + if (failedIndex >= 0 && (markerIndex < 0 || failedIndex < markerIndex)) + { + markerIndex = failedIndex; + } + + if (skippedIndex >= 0 && (markerIndex < 0 || skippedIndex < markerIndex)) + { + markerIndex = skippedIndex; + } + + return markerIndex; + } } } } diff --git a/source/UnitTestLauncher/Program.cs b/source/UnitTestLauncher/Program.cs index cb53327..b88fc50 100644 --- a/source/UnitTestLauncher/Program.cs +++ b/source/UnitTestLauncher/Program.cs @@ -84,15 +84,17 @@ private static bool RunTest( method.Invoke(null, parameters); totalTicks = DateTime.UtcNow.Ticks - dt; - // on change this pattern it has to be updated at Executor.CheckAllTests - Console.WriteLine($"Test passed,{methodName},{totalTicks}"); + // Keep result markers at the beginning of a line even if a test used Write() without trailing newline. + // On change this pattern it has to be updated at Executor.CheckAllTests. + Console.WriteLine($"\r\nTest passed,{methodName},{totalTicks}"); } catch (Exception ex) { if (ex.GetType() == typeof(SkipTestException)) { - // on change this pattern it has to be updated at Executor.CheckAllTests - Console.WriteLine($"Test skipped,{methodName},{ex.Message}"); + // Keep result markers at the beginning of a line even if a test used Write() without trailing newline. + // On change this pattern it has to be updated at Executor.CheckAllTests. + Console.WriteLine($"\r\nTest skipped,{methodName},{ex.Message}"); if (isSetupMethod) { @@ -103,8 +105,9 @@ private static bool RunTest( } else { - // on change this pattern it has to be updated at Executor.CheckAllTests - Console.WriteLine($"Test failed,{methodName},{ex.Message}"); + // Keep result markers at the beginning of a line even if a test used Write() without trailing newline. + // On change this pattern it has to be updated at Executor.CheckAllTests. + Console.WriteLine($"\r\nTest failed,{methodName},{ex.Message}"); } } }