Skip to content

Commit 6d400ab

Browse files
authored
Terminal logger fixes (#4834)
* Terminal logger fixes * Fix test
1 parent 58a1f6b commit 6d400ab

File tree

3 files changed

+92
-55
lines changed

3 files changed

+92
-55
lines changed

src/Microsoft.TestPlatform.Build/Tasks/VSTestTask2.cs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ public class VSTestTask2 : ToolTask, ITestTask
4040
public string? VSTestArtifactsProcessingMode { get; set; }
4141
public string? VSTestSessionCorrelationId { get; set; }
4242

43+
private readonly string _testResultSplitter = "++++";
44+
private readonly string[] _testResultSplitterArray = new[] { "++++" };
4345

4446
private readonly string _errorSplitter = "||||";
4547
private readonly string[] _errorSplitterArray = new[] { "||||" };
@@ -91,8 +93,7 @@ protected override void LogEventsFromTextOutput(string singleLine, MessageImport
9193
return;
9294
}
9395
}
94-
95-
if (singleLine.StartsWith(_fullErrorSplitter))
96+
else if (singleLine.StartsWith(_fullErrorSplitter))
9697
{
9798
var parts = singleLine.Split(_fullErrorSplitterArray, StringSplitOptions.None);
9899
if (parts.Length > 1)
@@ -119,6 +120,18 @@ protected override void LogEventsFromTextOutput(string singleLine, MessageImport
119120
return;
120121
}
121122
}
123+
else if (singleLine.StartsWith(_testResultSplitter))
124+
{
125+
var parts = singleLine.Split(_testResultSplitterArray, StringSplitOptions.None);
126+
if (parts.Length == 3)
127+
{
128+
var outcome = parts[1];
129+
var testName = parts[2];
130+
131+
Log.LogMessage(MessageImportance.Low, $"{outcome} {testName}");
132+
return;
133+
}
134+
}
122135

123136
base.LogEventsFromTextOutput(singleLine, messageImportance);
124137
}

src/vstest.console/Internal/MSBuildLogger.cs

Lines changed: 74 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
namespace Microsoft.VisualStudio.TestPlatform.CommandLine.Internal;
2020

21-
// Not using FriendlyName because it
2221
[ExtensionUri(ExtensionUri)]
2322
[FriendlyName(FriendlyName)]
2423
internal class MSBuildLogger : ITestLoggerWithParameters
@@ -100,72 +99,83 @@ private void TestResultHandler(object? sender, TestResultEventArgs e)
10099
TPDebug.Assert(Output != null, "Initialize should have been called.");
101100
switch (e.Result.Outcome)
102101
{
102+
case TestOutcome.Passed:
103+
case TestOutcome.Skipped:
104+
105+
var test = e.Result.TestCase.DisplayName;
106+
var outcome = e.Result.Outcome == TestOutcome.Passed
107+
? CommandLineResources.PassedTestIndicator
108+
: CommandLineResources.SkippedTestIndicator;
109+
var info = $"++++{outcome}++++{ReplacePlusSeparator(test)}";
110+
111+
Debug.WriteLine(">>>>MESSAGE:" + info);
112+
Output.Information(false, info);
113+
break;
103114
case TestOutcome.Failed:
115+
116+
var result = e.Result;
117+
if (!StringUtils.IsNullOrWhiteSpace(result.ErrorStackTrace))
104118
{
105-
var result = e.Result;
106-
if (!StringUtils.IsNullOrWhiteSpace(result.ErrorStackTrace))
119+
var maxLength = 1000;
120+
string? error = null;
121+
if (result.ErrorMessage != null)
107122
{
108-
var maxLength = 1000;
109-
string? error = null;
110-
if (result.ErrorMessage != null)
111-
{
112-
var oneLineMessage = result.ErrorMessage.Replace(Environment.NewLine, " ");
113-
error = oneLineMessage.Length > maxLength ? oneLineMessage.Substring(0, maxLength) : oneLineMessage;
114-
}
123+
// Do not use environment.newline here, we want to replace also \n on Windows.
124+
var oneLineMessage = result.ErrorMessage.Replace("\n", " ").Replace("\r", " ");
125+
error = oneLineMessage.Length > maxLength ? oneLineMessage.Substring(0, maxLength) : oneLineMessage;
126+
}
115127

116-
string? stackFrame = null;
117-
var stackFrames = Regex.Split(result.ErrorStackTrace, Environment.NewLine);
118-
string? line = null;
119-
string? file = null;
120-
string? place = null;
121-
if (stackFrames.Length > 0)
128+
string? stackFrame = null;
129+
var stackFrames = Regex.Split(result.ErrorStackTrace, Environment.NewLine);
130+
string? line = null;
131+
string? file = null;
132+
string? place = null;
133+
if (stackFrames.Length > 0)
134+
{
135+
foreach (var frame in stackFrames.Take(20))
122136
{
123-
foreach (var frame in stackFrames.Take(20))
137+
if (TryGetStackFrameLocation(frame, out line, out file, out place))
124138
{
125-
if (TryGetStackFrameLocation(frame, out line, out file, out place))
126-
{
127-
break;
128-
}
139+
break;
129140
}
130141
}
142+
}
131143

132-
// We did not find any stack frame with location in the first 20 frames.
133-
// Try getting location of the test.
134-
if (file == null)
144+
// We did not find any stack frame with location in the first 20 frames.
145+
// Try getting location of the test.
146+
if (file == null)
147+
{
148+
if (!StringUtils.IsNullOrEmpty(result.TestCase.CodeFilePath))
135149
{
136-
if (!StringUtils.IsNullOrEmpty(result.TestCase.CodeFilePath))
137-
{
138-
// if there are no symbols but we collect source info, us the source info.
139-
file = result.TestCase.CodeFilePath;
140-
line = result.TestCase.LineNumber > 0 ? result.TestCase.LineNumber.ToString(CultureInfo.InvariantCulture) : null;
141-
place = stackFrame;
142-
}
143-
else
144-
{
145-
// if there are no symbols and no source info use the dll
146-
place = result.TestCase.DisplayName;
147-
file = result.TestCase.Source;
148-
}
150+
// if there are no symbols but we collect source info, us the source info.
151+
file = result.TestCase.CodeFilePath;
152+
line = result.TestCase.LineNumber > 0 ? result.TestCase.LineNumber.ToString(CultureInfo.InvariantCulture) : null;
153+
place = stackFrame;
154+
}
155+
else
156+
{
157+
// if there are no symbols and no source info use the dll
158+
place = result.TestCase.DisplayName;
159+
file = result.TestCase.Source;
149160
}
150-
151-
place = $"({result.TestCase.DisplayName}) {place}";
152-
var message = $"||||{ReplacePipeSeparator(file)}||||{line}||||{ReplacePipeSeparator(place)}||||{ReplacePipeSeparator(error)}";
153-
154-
Trace.WriteLine(">>>>MESSAGE:" + message);
155-
Output.Error(false, message);
156-
157-
var fullError = $"~~~~{ReplaceTildaSeparator(result.ErrorMessage)}~~~~{ReplaceTildaSeparator(result.ErrorStackTrace)}";
158-
Output.Information(false, fullError);
159-
return;
160-
}
161-
else
162-
{
163-
Output.Error(false, result.DisplayName?.Replace(Environment.NewLine, " ") ?? string.Empty);
164161
}
165162

163+
place = $"({result.TestCase.DisplayName}) {place}";
164+
var message = $"||||{ReplacePipeSeparator(file)}||||{line}||||{ReplacePipeSeparator(place)}||||{ReplacePipeSeparator(error)}";
166165

167-
break;
166+
Debug.WriteLine(">>>>MESSAGE:" + message);
167+
Output.Error(false, message);
168+
169+
var fullError = $"~~~~{ReplaceTildaSeparator(result.ErrorMessage)}~~~~{ReplaceTildaSeparator(result.ErrorStackTrace)}";
170+
Output.Information(false, fullError);
171+
return;
172+
}
173+
else
174+
{
175+
Output.Error(false, result.DisplayName?.Replace(Environment.NewLine, " ") ?? string.Empty);
168176
}
177+
178+
break;
169179
}
170180
}
171181

@@ -186,7 +196,7 @@ private static bool TryGetStackFrameLocation(string stackFrame, out string? line
186196
line = match.Groups["line"].Value;
187197
}
188198

189-
Trace.WriteLine($">>>> {(match.Success ? "MATCH" : "NOMATCH")} {stackFrame}");
199+
Debug.WriteLine($">>>> {(match.Success ? "MATCH" : "NOMATCH")} {stackFrame}");
190200

191201
return match.Success;
192202
}
@@ -203,6 +213,17 @@ private static bool TryGetStackFrameLocation(string stackFrame, out string? line
203213
return text.Replace("||||", "____");
204214
}
205215

216+
private static string? ReplacePlusSeparator(string? text)
217+
{
218+
if (text == null)
219+
{
220+
return null;
221+
}
222+
223+
// Remove any occurrence of message splitter.
224+
return text.Replace("++++", "____");
225+
}
226+
206227
private static string? ReplaceTildaSeparator(string? text)
207228
{
208229
if (text == null)

test/Microsoft.TestPlatform.Acceptance.IntegrationTests/DotnetTestMSBuildOutputTests.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ public void RunDotnetTestWithCsproj(RunnerInfo runnerInfo)
3232
// C:\Users\nohwnd\AppData\Local\Temp\vstest\xvoVt\UnitTest1.cs(41): error VSTEST1: (FailingTest) SampleUnitTestProject.UnitTest1.FailingTest() Assert.AreEqual failed. Expected:<2>. Actual:<3>. [C:\Users\nohwnd\AppData\Local\Temp\vstest\xvoVt\SimpleTestProject.csproj::TargetFramework=netcoreapp3.1]
3333

3434
StdOutputContains("error VSTEST1: (FailingTest) SampleUnitTestProject.UnitTest1.FailingTest() Assert.AreEqual failed. Expected:<2>. Actual:<3>.");
35+
// We are sending those as low prio messages, they won't show up on screen but will be in binlog.
36+
//StdOutputContains("passed PassingTest");
37+
//StdOutputContains("skipped SkippingTest");
3538
ExitCodeEquals(1);
3639
}
3740
}

0 commit comments

Comments
 (0)