зеркало из https://github.com/microsoft/testfx.git
Write standard output and error, and respect execution id (#3934)
This commit is contained in:
Родитель
cb555a15d2
Коммит
dec5768b8a
|
@ -48,6 +48,7 @@ This package provides the core platform and the .NET implementation of the proto
|
|||
<!-- end netstandard2.0 polyfill -->
|
||||
|
||||
<ItemGroup>
|
||||
<InternalsVisibleTo Include="dotnet" Key="$(MicrosoftAspNetCorePublicKey)" />
|
||||
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" Key="$(MoqPublicKey)" />
|
||||
<InternalsVisibleTo Include="Microsoft.Testing.Extensions.CrashDump" Key="$(VsPublicKey)" />
|
||||
<InternalsVisibleTo Include="Microsoft.Testing.Extensions.Experimental" Key="$(VsPublicKey)" />
|
||||
|
|
|
@ -177,7 +177,12 @@ internal sealed class AnsiTerminalTestProgressFrame
|
|||
terminal.MoveCursorUp(previousFrame.ProgressCount + 2);
|
||||
}
|
||||
|
||||
terminal.AppendLine();
|
||||
// When there is nothing to render, don't write empty lines, e.g. when we start the test run, and then we kick off build
|
||||
// in dotnet test, there is a long pause where we have no assemblies and no test results (yet).
|
||||
if (ProgressCount > 0)
|
||||
{
|
||||
terminal.AppendLine();
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
for (; i < ProgressCount; i++)
|
||||
|
|
|
@ -164,6 +164,7 @@ internal sealed class NonAnsiTerminal : ITerminal
|
|||
|
||||
public void RenderProgress(TestProgressState?[] progress)
|
||||
{
|
||||
int count = 0;
|
||||
foreach (TestProgressState? p in progress)
|
||||
{
|
||||
if (p == null)
|
||||
|
@ -171,6 +172,8 @@ internal sealed class NonAnsiTerminal : ITerminal
|
|||
continue;
|
||||
}
|
||||
|
||||
count++;
|
||||
|
||||
string durationString = HumanReadableDurationFormatter.Render(p.Stopwatch.Elapsed);
|
||||
|
||||
int passed = p.PassedTests;
|
||||
|
@ -232,7 +235,11 @@ internal sealed class NonAnsiTerminal : ITerminal
|
|||
AppendLine();
|
||||
}
|
||||
|
||||
AppendLine();
|
||||
// Do not render empty lines when there is nothing to show.
|
||||
if (count > 0)
|
||||
{
|
||||
AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
public void StartBusyIndicator()
|
||||
|
|
|
@ -138,7 +138,7 @@ internal sealed partial class TerminalTestReporter : IDisposable
|
|||
_terminalWithProgress.StartShowingProgress(workerCount);
|
||||
}
|
||||
|
||||
public void AssemblyRunStarted(string assembly, string? targetFramework, string? architecture)
|
||||
public void AssemblyRunStarted(string assembly, string? targetFramework, string? architecture, string? executionId)
|
||||
{
|
||||
if (_options.ShowAssembly && _options.ShowAssemblyStartAndComplete)
|
||||
{
|
||||
|
@ -151,12 +151,12 @@ internal sealed partial class TerminalTestReporter : IDisposable
|
|||
});
|
||||
}
|
||||
|
||||
GetOrAddAssemblyRun(assembly, targetFramework, architecture);
|
||||
GetOrAddAssemblyRun(assembly, targetFramework, architecture, executionId);
|
||||
}
|
||||
|
||||
private TestProgressState GetOrAddAssemblyRun(string assembly, string? targetFramework, string? architecture)
|
||||
private TestProgressState GetOrAddAssemblyRun(string assembly, string? targetFramework, string? architecture, string? executionId)
|
||||
{
|
||||
string key = $"{assembly}|{targetFramework}|{architecture}";
|
||||
string key = $"{assembly}|{targetFramework}|{architecture}|{executionId}";
|
||||
if (_assemblies.TryGetValue(key, out TestProgressState? asm))
|
||||
{
|
||||
return asm;
|
||||
|
@ -369,15 +369,18 @@ internal sealed partial class TerminalTestReporter : IDisposable
|
|||
string assembly,
|
||||
string? targetFramework,
|
||||
string? architecture,
|
||||
string? executionId,
|
||||
string displayName,
|
||||
TestOutcome outcome,
|
||||
TimeSpan duration,
|
||||
string? errorMessage,
|
||||
string? errorStackTrace,
|
||||
string? expected,
|
||||
string? actual)
|
||||
string? actual,
|
||||
string? standardOutput,
|
||||
string? errorOutput)
|
||||
{
|
||||
TestProgressState asm = _assemblies[$"{assembly}|{targetFramework}|{architecture}"];
|
||||
TestProgressState asm = _assemblies[$"{assembly}|{targetFramework}|{architecture}|{executionId}"];
|
||||
|
||||
switch (outcome)
|
||||
{
|
||||
|
@ -412,7 +415,9 @@ internal sealed partial class TerminalTestReporter : IDisposable
|
|||
errorMessage,
|
||||
errorStackTrace,
|
||||
expected,
|
||||
actual));
|
||||
actual,
|
||||
standardOutput,
|
||||
errorOutput));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -427,7 +432,9 @@ internal sealed partial class TerminalTestReporter : IDisposable
|
|||
string? errorMessage,
|
||||
string? errorStackTrace,
|
||||
string? expected,
|
||||
string? actual)
|
||||
string? actual,
|
||||
string? standardOutput,
|
||||
string? errorOutput)
|
||||
{
|
||||
if (outcome == TestOutcome.Passed && !_options.ShowPassedTests)
|
||||
{
|
||||
|
@ -472,6 +479,7 @@ internal sealed partial class TerminalTestReporter : IDisposable
|
|||
FormatErrorMessage(terminal, errorMessage);
|
||||
FormatExpectedAndActual(terminal, expected, actual);
|
||||
FormatStackTrace(terminal, errorStackTrace);
|
||||
FormatStandardAndErrorOutput(terminal, standardOutput, errorOutput);
|
||||
}
|
||||
|
||||
private static void AppendAssemblyLinkTargetFrameworkAndArchitecture(ITerminal terminal, string assembly, string? targetFramework, string? architecture)
|
||||
|
@ -621,9 +629,9 @@ internal sealed partial class TerminalTestReporter : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
internal void AssemblyRunCompleted(string assembly, string? targetFramework, string? architecture)
|
||||
internal void AssemblyRunCompleted(string assembly, string? targetFramework, string? architecture, string? executionId)
|
||||
{
|
||||
TestProgressState assemblyRun = GetOrAddAssemblyRun(assembly, targetFramework, architecture);
|
||||
TestProgressState assemblyRun = GetOrAddAssemblyRun(assembly, targetFramework, architecture, executionId);
|
||||
assemblyRun.Stopwatch.Stop();
|
||||
|
||||
_terminalWithProgress.RemoveWorker(assemblyRun.SlotIndex);
|
||||
|
@ -634,6 +642,30 @@ internal sealed partial class TerminalTestReporter : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
private static void FormatStandardAndErrorOutput(ITerminal terminal, string? standardOutput, string? standardError)
|
||||
{
|
||||
if (RoslynString.IsNullOrWhiteSpace(standardOutput) && RoslynString.IsNullOrWhiteSpace(standardError))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
terminal.SetColor(TerminalColor.DarkGray);
|
||||
terminal.Append(SingleIndentation);
|
||||
terminal.AppendLine(PlatformResources.StandardOutput);
|
||||
string? standardOutputWithoutSpecialChars = NormalizeSpecialCharacters(standardOutput);
|
||||
AppendIndentedLine(terminal, standardOutputWithoutSpecialChars, DoubleIndentation);
|
||||
terminal.Append(SingleIndentation);
|
||||
terminal.AppendLine(PlatformResources.StandardError);
|
||||
string? standardErrorWithoutSpecialChars = NormalizeSpecialCharacters(standardError);
|
||||
AppendIndentedLine(terminal, standardErrorWithoutSpecialChars, DoubleIndentation);
|
||||
terminal.ResetColor();
|
||||
}
|
||||
|
||||
private static string? NormalizeSpecialCharacters(string? text)
|
||||
=> text?.Replace('\0', '\x2400')
|
||||
// escape char
|
||||
.Replace('\x001b', '\x241b');
|
||||
|
||||
private static void AppendAssemblySummary(TestProgressState assemblyRun, ITerminal terminal)
|
||||
{
|
||||
int failedTests = assemblyRun.FailedTests;
|
||||
|
@ -644,6 +676,7 @@ internal sealed partial class TerminalTestReporter : IDisposable
|
|||
AppendAssemblyResult(terminal, assemblyRun.FailedTests == 0, failedTests, warnings);
|
||||
terminal.Append(' ');
|
||||
AppendLongDuration(terminal, assemblyRun.Stopwatch.Elapsed);
|
||||
terminal.AppendLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -666,8 +699,8 @@ internal sealed partial class TerminalTestReporter : IDisposable
|
|||
|
||||
public void Dispose() => _terminalWithProgress.Dispose();
|
||||
|
||||
public void ArtifactAdded(bool outOfProcess, string? assembly, string? targetFramework, string? architecture, string? testName, string path)
|
||||
=> _artifacts.Add(new TestRunArtifact(outOfProcess, assembly, targetFramework, architecture, testName, path));
|
||||
public void ArtifactAdded(bool outOfProcess, string? assembly, string? targetFramework, string? architecture, string? executionId, string? testName, string path)
|
||||
=> _artifacts.Add(new TestRunArtifact(outOfProcess, assembly, targetFramework, architecture, executionId, testName, path));
|
||||
|
||||
/// <summary>
|
||||
/// Let the user know that cancellation was triggered.
|
||||
|
@ -683,9 +716,9 @@ internal sealed partial class TerminalTestReporter : IDisposable
|
|||
});
|
||||
}
|
||||
|
||||
internal void WriteErrorMessage(string assembly, string? targetFramework, string? architecture, string text, int? padding)
|
||||
internal void WriteErrorMessage(string assembly, string? targetFramework, string? architecture, string? executionId, string text, int? padding)
|
||||
{
|
||||
TestProgressState asm = GetOrAddAssemblyRun(assembly, targetFramework, architecture);
|
||||
TestProgressState asm = GetOrAddAssemblyRun(assembly, targetFramework, architecture, executionId);
|
||||
asm.AddError(text);
|
||||
|
||||
_terminalWithProgress.WriteToTerminal(terminal =>
|
||||
|
@ -704,9 +737,9 @@ internal sealed partial class TerminalTestReporter : IDisposable
|
|||
});
|
||||
}
|
||||
|
||||
internal void WriteWarningMessage(string assembly, string? targetFramework, string? architecture, string text, int? padding)
|
||||
internal void WriteWarningMessage(string assembly, string? targetFramework, string? architecture, string? executionId, string text, int? padding)
|
||||
{
|
||||
TestProgressState asm = GetOrAddAssemblyRun(assembly, targetFramework, architecture);
|
||||
TestProgressState asm = GetOrAddAssemblyRun(assembly, targetFramework, architecture, executionId);
|
||||
asm.AddWarning(text);
|
||||
_terminalWithProgress.WriteToTerminal(terminal =>
|
||||
{
|
||||
|
@ -724,8 +757,8 @@ internal sealed partial class TerminalTestReporter : IDisposable
|
|||
});
|
||||
}
|
||||
|
||||
internal void WriteErrorMessage(string assembly, string? targetFramework, string? architecture, Exception exception)
|
||||
=> WriteErrorMessage(assembly, targetFramework, architecture, exception.ToString(), padding: null);
|
||||
internal void WriteErrorMessage(string assembly, string? targetFramework, string? architecture, string? executionId, Exception exception)
|
||||
=> WriteErrorMessage(assembly, targetFramework, architecture, executionId, exception.ToString(), padding: null);
|
||||
|
||||
internal void WriteMessage(string text, SystemConsoleColor? color = null, int? padding = null)
|
||||
{
|
||||
|
|
|
@ -6,4 +6,4 @@ namespace Microsoft.Testing.Platform.OutputDevice.Terminal;
|
|||
/// <summary>
|
||||
/// An artifact / attachment that was reported during run.
|
||||
/// </summary>
|
||||
internal record TestRunArtifact(bool OutOfProcess, string? Assembly, string? TargetFramework, string? Architecture, string? TestName, string Path);
|
||||
internal record TestRunArtifact(bool OutOfProcess, string? Assembly, string? TargetFramework, string? Architecture, string? ExecutionId, string? TestName, string Path);
|
||||
|
|
|
@ -140,13 +140,11 @@ internal partial class TerminalOutputDevice : IPlatformOutputDevice,
|
|||
// The test host controller info is not setup and populated until after this constructor, because it writes banner and then after it figures out if
|
||||
// the runner is a testHost controller, so we would always have it as null if we capture it directly. Instead we need to check it via
|
||||
// func.
|
||||
: () => _isVSTestMode
|
||||
: () => _isVSTestMode || _isListTests || _isServerMode
|
||||
? false
|
||||
: _isListTests
|
||||
? false
|
||||
: _testHostControllerInfo.IsCurrentProcessTestHostController == null
|
||||
? null
|
||||
: !_testHostControllerInfo.IsCurrentProcessTestHostController;
|
||||
: _testHostControllerInfo.IsCurrentProcessTestHostController == null
|
||||
? null
|
||||
: !_testHostControllerInfo.IsCurrentProcessTestHostController;
|
||||
|
||||
// This is single exe run, don't show all the details of assemblies and their summaries.
|
||||
_terminalTestReporter = new TerminalTestReporter(_console, new()
|
||||
|
@ -260,11 +258,11 @@ internal partial class TerminalOutputDevice : IPlatformOutputDevice,
|
|||
{
|
||||
if (_fileLoggerInformation.SyncronousWrite)
|
||||
{
|
||||
_terminalTestReporter.WriteWarningMessage(_assemblyName, _targetFramework, _shortArchitecture, string.Format(CultureInfo.CurrentCulture, PlatformResources.DiagnosticFileLevelWithFlush, _fileLoggerInformation.LogLevel, _fileLoggerInformation.LogFile.FullName), padding: null);
|
||||
_terminalTestReporter.WriteWarningMessage(_assemblyName, _targetFramework, _shortArchitecture, executionId: null, string.Format(CultureInfo.CurrentCulture, PlatformResources.DiagnosticFileLevelWithFlush, _fileLoggerInformation.LogLevel, _fileLoggerInformation.LogFile.FullName), padding: null);
|
||||
}
|
||||
else
|
||||
{
|
||||
_terminalTestReporter.WriteWarningMessage(_assemblyName, _targetFramework, _shortArchitecture, string.Format(CultureInfo.CurrentCulture, PlatformResources.DiagnosticFileLevelWithAsyncFlush, _fileLoggerInformation.LogLevel, _fileLoggerInformation.LogFile.FullName), padding: null);
|
||||
_terminalTestReporter.WriteWarningMessage(_assemblyName, _targetFramework, _shortArchitecture, executionId: null, string.Format(CultureInfo.CurrentCulture, PlatformResources.DiagnosticFileLevelWithAsyncFlush, _fileLoggerInformation.LogLevel, _fileLoggerInformation.LogFile.FullName), padding: null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -272,12 +270,17 @@ internal partial class TerminalOutputDevice : IPlatformOutputDevice,
|
|||
|
||||
public async Task DisplayBeforeSessionStartAsync()
|
||||
{
|
||||
if (_isServerMode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RoslynDebug.Assert(_terminalTestReporter is not null);
|
||||
|
||||
// Start test execution here, rather than in ShowBanner, because then we know
|
||||
// if we are a testHost controller or not, and if we should show progress bar.
|
||||
_terminalTestReporter.TestExecutionStarted(_clock.UtcNow, workerCount: 1);
|
||||
_terminalTestReporter.AssemblyRunStarted(_assemblyName, _targetFramework, _shortArchitecture);
|
||||
_terminalTestReporter.AssemblyRunStarted(_assemblyName, _targetFramework, _shortArchitecture, executionId: null);
|
||||
if (_logger is not null && _logger.IsEnabled(LogLevel.Trace))
|
||||
{
|
||||
await _logger.LogTraceAsync("DisplayBeforeSessionStartAsync");
|
||||
|
@ -297,7 +300,7 @@ internal partial class TerminalOutputDevice : IPlatformOutputDevice,
|
|||
{
|
||||
if (!_firstCallTo_OnSessionStartingAsync)
|
||||
{
|
||||
_terminalTestReporter.AssemblyRunCompleted(_assemblyName, _targetFramework, _shortArchitecture);
|
||||
_terminalTestReporter.AssemblyRunCompleted(_assemblyName, _targetFramework, _shortArchitecture, executionId: null);
|
||||
_terminalTestReporter.TestExecutionCompleted(_clock.UtcNow);
|
||||
}
|
||||
}
|
||||
|
@ -307,7 +310,7 @@ internal partial class TerminalOutputDevice : IPlatformOutputDevice,
|
|||
|
||||
public Task OnTestSessionStartingAsync(SessionUid sessionUid, CancellationToken cancellationToken)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
if (_isServerMode || cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
@ -347,10 +350,10 @@ internal partial class TerminalOutputDevice : IPlatformOutputDevice,
|
|||
switch (color.ConsoleColor)
|
||||
{
|
||||
case ConsoleColor.Red:
|
||||
_terminalTestReporter.WriteErrorMessage(_assemblyName, _targetFramework, _shortArchitecture, formattedTextOutputDeviceData.Text, formattedTextOutputDeviceData.Padding);
|
||||
_terminalTestReporter.WriteErrorMessage(_assemblyName, _targetFramework, _shortArchitecture, executionId: null, formattedTextOutputDeviceData.Text, formattedTextOutputDeviceData.Padding);
|
||||
break;
|
||||
case ConsoleColor.Yellow:
|
||||
_terminalTestReporter.WriteWarningMessage(_assemblyName, _targetFramework, _shortArchitecture, formattedTextOutputDeviceData.Text, formattedTextOutputDeviceData.Padding);
|
||||
_terminalTestReporter.WriteWarningMessage(_assemblyName, _targetFramework, _shortArchitecture, executionId: null, formattedTextOutputDeviceData.Text, formattedTextOutputDeviceData.Padding);
|
||||
break;
|
||||
default:
|
||||
_terminalTestReporter.WriteMessage(formattedTextOutputDeviceData.Text, color, formattedTextOutputDeviceData.Padding);
|
||||
|
@ -374,7 +377,7 @@ internal partial class TerminalOutputDevice : IPlatformOutputDevice,
|
|||
case ExceptionOutputDeviceData exceptionOutputDeviceData:
|
||||
{
|
||||
await LogDebugAsync(exceptionOutputDeviceData.Exception.ToString());
|
||||
_terminalTestReporter.WriteErrorMessage(_assemblyName, _targetFramework, _shortArchitecture, exceptionOutputDeviceData.Exception);
|
||||
_terminalTestReporter.WriteErrorMessage(_assemblyName, _targetFramework, _shortArchitecture, executionId: null, exceptionOutputDeviceData.Exception);
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -386,6 +389,11 @@ internal partial class TerminalOutputDevice : IPlatformOutputDevice,
|
|||
{
|
||||
RoslynDebug.Assert(_terminalTestReporter is not null);
|
||||
|
||||
if (_isServerMode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await Task.CompletedTask;
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
|
@ -397,6 +405,9 @@ internal partial class TerminalOutputDevice : IPlatformOutputDevice,
|
|||
case TestNodeUpdateMessage testNodeStateChanged:
|
||||
|
||||
TimeSpan duration = testNodeStateChanged.TestNode.Properties.SingleOrDefault<TimingProperty>()?.GlobalTiming.Duration ?? TimeSpan.Zero;
|
||||
string? standardOutput = testNodeStateChanged.TestNode.Properties.SingleOrDefault<StandardOutputProperty>()?.StandardOutput;
|
||||
string? standardError = testNodeStateChanged.TestNode.Properties.SingleOrDefault<StandardErrorProperty>()?.StandardError;
|
||||
|
||||
switch (testNodeStateChanged.TestNode.Properties.SingleOrDefault<TestNodeStateProperty>())
|
||||
{
|
||||
case InProgressTestNodeStateProperty:
|
||||
|
@ -408,13 +419,16 @@ internal partial class TerminalOutputDevice : IPlatformOutputDevice,
|
|||
_assemblyName,
|
||||
_targetFramework,
|
||||
_shortArchitecture,
|
||||
executionId: null,
|
||||
testNodeStateChanged.TestNode.DisplayName,
|
||||
TestOutcome.Error,
|
||||
duration,
|
||||
errorMessage: errorState.Exception?.Message ?? errorState.Explanation,
|
||||
errorState.Exception?.StackTrace,
|
||||
expected: null,
|
||||
actual: null);
|
||||
actual: null,
|
||||
standardOutput,
|
||||
standardError);
|
||||
break;
|
||||
|
||||
case FailedTestNodeStateProperty failedState:
|
||||
|
@ -422,13 +436,16 @@ internal partial class TerminalOutputDevice : IPlatformOutputDevice,
|
|||
_assemblyName,
|
||||
_targetFramework,
|
||||
_shortArchitecture,
|
||||
executionId: null,
|
||||
testNodeStateChanged.TestNode.DisplayName,
|
||||
TestOutcome.Fail,
|
||||
duration,
|
||||
errorMessage: failedState.Exception?.Message ?? failedState.Explanation,
|
||||
failedState.Exception?.StackTrace,
|
||||
expected: failedState.Exception?.Data["assert.expected"] as string,
|
||||
actual: failedState.Exception?.Data["assert.actual"] as string);
|
||||
actual: failedState.Exception?.Data["assert.actual"] as string,
|
||||
standardOutput,
|
||||
standardError);
|
||||
break;
|
||||
|
||||
case TimeoutTestNodeStateProperty timeoutState:
|
||||
|
@ -436,13 +453,16 @@ internal partial class TerminalOutputDevice : IPlatformOutputDevice,
|
|||
_assemblyName,
|
||||
_targetFramework,
|
||||
_shortArchitecture,
|
||||
executionId: null,
|
||||
testNodeStateChanged.TestNode.DisplayName,
|
||||
TestOutcome.Timeout,
|
||||
duration,
|
||||
errorMessage: timeoutState.Exception?.Message ?? timeoutState.Explanation,
|
||||
timeoutState.Exception?.StackTrace,
|
||||
expected: null,
|
||||
actual: null);
|
||||
actual: null,
|
||||
standardOutput,
|
||||
standardError);
|
||||
break;
|
||||
|
||||
case CancelledTestNodeStateProperty cancelledState:
|
||||
|
@ -450,13 +470,16 @@ internal partial class TerminalOutputDevice : IPlatformOutputDevice,
|
|||
_assemblyName,
|
||||
_targetFramework,
|
||||
_shortArchitecture,
|
||||
executionId: null,
|
||||
testNodeStateChanged.TestNode.DisplayName,
|
||||
TestOutcome.Canceled,
|
||||
duration,
|
||||
errorMessage: cancelledState.Exception?.Message ?? cancelledState.Explanation,
|
||||
cancelledState.Exception?.StackTrace,
|
||||
expected: null,
|
||||
actual: null);
|
||||
actual: null,
|
||||
standardOutput,
|
||||
standardError);
|
||||
break;
|
||||
|
||||
case PassedTestNodeStateProperty:
|
||||
|
@ -464,13 +487,16 @@ internal partial class TerminalOutputDevice : IPlatformOutputDevice,
|
|||
_assemblyName,
|
||||
_targetFramework,
|
||||
_shortArchitecture,
|
||||
executionId: null,
|
||||
testNodeStateChanged.TestNode.DisplayName,
|
||||
outcome: TestOutcome.Passed,
|
||||
duration: duration,
|
||||
errorMessage: null,
|
||||
errorStackTrace: null,
|
||||
expected: null,
|
||||
actual: null);
|
||||
actual: null,
|
||||
standardOutput,
|
||||
standardError);
|
||||
break;
|
||||
|
||||
case SkippedTestNodeStateProperty:
|
||||
|
@ -478,13 +504,16 @@ internal partial class TerminalOutputDevice : IPlatformOutputDevice,
|
|||
_assemblyName,
|
||||
_targetFramework,
|
||||
_shortArchitecture,
|
||||
executionId: null,
|
||||
testNodeStateChanged.TestNode.DisplayName,
|
||||
TestOutcome.Skipped,
|
||||
duration,
|
||||
errorMessage: null,
|
||||
errorStackTrace: null,
|
||||
expected: null,
|
||||
actual: null);
|
||||
actual: null,
|
||||
standardOutput,
|
||||
standardError);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -498,6 +527,7 @@ internal partial class TerminalOutputDevice : IPlatformOutputDevice,
|
|||
_assemblyName,
|
||||
_targetFramework,
|
||||
_shortArchitecture,
|
||||
executionId: null,
|
||||
artifact.TestNode.DisplayName,
|
||||
artifact.FileInfo.FullName);
|
||||
}
|
||||
|
@ -512,6 +542,7 @@ internal partial class TerminalOutputDevice : IPlatformOutputDevice,
|
|||
_assemblyName,
|
||||
_targetFramework,
|
||||
_shortArchitecture,
|
||||
executionId: null,
|
||||
testName: null,
|
||||
artifact.FileInfo.FullName);
|
||||
}
|
||||
|
@ -525,6 +556,7 @@ internal partial class TerminalOutputDevice : IPlatformOutputDevice,
|
|||
_assemblyName,
|
||||
_targetFramework,
|
||||
_shortArchitecture,
|
||||
executionId: null,
|
||||
testName: null,
|
||||
artifact.FileInfo.FullName);
|
||||
}
|
||||
|
|
|
@ -1161,6 +1161,24 @@ namespace Microsoft.Testing.Platform.Resources {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Error output.
|
||||
/// </summary>
|
||||
internal static string StandardError {
|
||||
get {
|
||||
return ResourceManager.GetString("StandardError", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Standard output.
|
||||
/// </summary>
|
||||
internal static string StandardOutput {
|
||||
get {
|
||||
return ResourceManager.GetString("StandardOutput", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Starting server. Listening on port '{0}'.
|
||||
/// </summary>
|
||||
|
|
|
@ -631,4 +631,10 @@ Takes one argument as string in the format <value>[h|m|s] where 'value' is
|
|||
<data name="MissingClientPortFoJsonRpc" xml:space="preserve">
|
||||
<value>Expected --client-port when jsonRpc protocol is used.</value>
|
||||
</data>
|
||||
<data name="StandardError" xml:space="preserve">
|
||||
<value>Error output</value>
|
||||
</data>
|
||||
<data name="StandardOutput" xml:space="preserve">
|
||||
<value>Standard output</value>
|
||||
</data>
|
||||
</root>
|
|
@ -633,6 +633,16 @@ Může mít jenom jeden argument jako řetězec ve formátu <value>[h|m|s]
|
|||
<target state="translated">Trasování zásobníku</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StandardError">
|
||||
<source>Error output</source>
|
||||
<target state="new">Error output</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StandardOutput">
|
||||
<source>Standard output</source>
|
||||
<target state="new">Standard output</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StartingServer">
|
||||
<source>Starting server. Listening on port '{0}'</source>
|
||||
<target state="translated">Spouští se server. Naslouchání na portu {0}</target>
|
||||
|
|
|
@ -633,6 +633,16 @@ Nimmt ein Argument als Zeichenfolge im Format <value>[h|m|s], wobei "value
|
|||
<target state="translated">Stapelüberwachung</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StandardError">
|
||||
<source>Error output</source>
|
||||
<target state="new">Error output</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StandardOutput">
|
||||
<source>Standard output</source>
|
||||
<target state="new">Standard output</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StartingServer">
|
||||
<source>Starting server. Listening on port '{0}'</source>
|
||||
<target state="translated">Server wird gestartet. An Port "{0}" lauschen</target>
|
||||
|
|
|
@ -633,6 +633,16 @@ Toma un argumento como cadena con el formato <value>[h|m|s] donde 'value'
|
|||
<target state="translated">Seguimiento de la pila</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StandardError">
|
||||
<source>Error output</source>
|
||||
<target state="new">Error output</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StandardOutput">
|
||||
<source>Standard output</source>
|
||||
<target state="new">Standard output</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StartingServer">
|
||||
<source>Starting server. Listening on port '{0}'</source>
|
||||
<target state="translated">Iniciando el servidor. Escuchando en el puerto '{0}'</target>
|
||||
|
|
|
@ -633,6 +633,16 @@ Prend un argument sous forme de chaîne au format <value>[h|m|s] où « v
|
|||
<target state="translated">Rapport des appels de procédure</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StandardError">
|
||||
<source>Error output</source>
|
||||
<target state="new">Error output</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StandardOutput">
|
||||
<source>Standard output</source>
|
||||
<target state="new">Standard output</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StartingServer">
|
||||
<source>Starting server. Listening on port '{0}'</source>
|
||||
<target state="translated">Démarrage du serveur. Écoute sur le port « {0} »</target>
|
||||
|
|
|
@ -633,6 +633,16 @@ Acquisisce un argomento come stringa nel formato <value>[h|m|s] dove 'valu
|
|||
<target state="translated">Analisi dello stack</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StandardError">
|
||||
<source>Error output</source>
|
||||
<target state="new">Error output</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StandardOutput">
|
||||
<source>Standard output</source>
|
||||
<target state="new">Standard output</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StartingServer">
|
||||
<source>Starting server. Listening on port '{0}'</source>
|
||||
<target state="translated">Avvio del server. In ascolto sulla porta '{0}'</target>
|
||||
|
|
|
@ -634,6 +634,16 @@ Takes one argument as string in the format <value>[h|m|s] where 'value' is
|
|||
<target state="translated">スタック トレース</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StandardError">
|
||||
<source>Error output</source>
|
||||
<target state="new">Error output</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StandardOutput">
|
||||
<source>Standard output</source>
|
||||
<target state="new">Standard output</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StartingServer">
|
||||
<source>Starting server. Listening on port '{0}'</source>
|
||||
<target state="translated">サーバーを起動しています。ポート '{0}' で聞いています</target>
|
||||
|
|
|
@ -633,6 +633,16 @@ Takes one argument as string in the format <value>[h|m|s] where 'value' is
|
|||
<target state="translated">스택 추적</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StandardError">
|
||||
<source>Error output</source>
|
||||
<target state="new">Error output</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StandardOutput">
|
||||
<source>Standard output</source>
|
||||
<target state="new">Standard output</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StartingServer">
|
||||
<source>Starting server. Listening on port '{0}'</source>
|
||||
<target state="translated">서버를 시작하는 중입니다. 포트 '{0}'에서 수신 대기 중</target>
|
||||
|
|
|
@ -633,6 +633,16 @@ Pobiera jeden argument jako ciąg w formacie <value>[h|m|s], gdzie element
|
|||
<target state="translated">Śledzenie stosu</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StandardError">
|
||||
<source>Error output</source>
|
||||
<target state="new">Error output</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StandardOutput">
|
||||
<source>Standard output</source>
|
||||
<target state="new">Standard output</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StartingServer">
|
||||
<source>Starting server. Listening on port '{0}'</source>
|
||||
<target state="translated">Uruchamianie serwera. Nasłuchiwanie na porcie „{0}”</target>
|
||||
|
|
|
@ -633,6 +633,16 @@ Recebe um argumento como cadeia de caracteres no formato <valor>[h|m|s] em
|
|||
<target state="translated">Rastreamento de Pilha</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StandardError">
|
||||
<source>Error output</source>
|
||||
<target state="new">Error output</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StandardOutput">
|
||||
<source>Standard output</source>
|
||||
<target state="new">Standard output</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StartingServer">
|
||||
<source>Starting server. Listening on port '{0}'</source>
|
||||
<target state="translated">Iniciando servidor. Escutando na porta “{0}”</target>
|
||||
|
|
|
@ -633,6 +633,16 @@ Takes one argument as string in the format <value>[h|m|s] where 'value' is
|
|||
<target state="translated">Трассировка стека</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StandardError">
|
||||
<source>Error output</source>
|
||||
<target state="new">Error output</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StandardOutput">
|
||||
<source>Standard output</source>
|
||||
<target state="new">Standard output</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StartingServer">
|
||||
<source>Starting server. Listening on port '{0}'</source>
|
||||
<target state="translated">Выполняется запуск сервера. Прослушивание порта "{0}"</target>
|
||||
|
|
|
@ -633,6 +633,16 @@ Bir bağımsız değişkeni, 'value' değerinin kayan olduğu <value>[h|m|
|
|||
<target state="translated">Yığın İzlemesi</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StandardError">
|
||||
<source>Error output</source>
|
||||
<target state="new">Error output</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StandardOutput">
|
||||
<source>Standard output</source>
|
||||
<target state="new">Standard output</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StartingServer">
|
||||
<source>Starting server. Listening on port '{0}'</source>
|
||||
<target state="translated">Sunucu başlatılıyor. '{0}' bağlantı noktasında dinleme işlemi yapılıyor</target>
|
||||
|
|
|
@ -633,6 +633,16 @@ Takes one argument as string in the format <value>[h|m|s] where 'value' is
|
|||
<target state="translated">堆栈跟踪</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StandardError">
|
||||
<source>Error output</source>
|
||||
<target state="new">Error output</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StandardOutput">
|
||||
<source>Standard output</source>
|
||||
<target state="new">Standard output</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StartingServer">
|
||||
<source>Starting server. Listening on port '{0}'</source>
|
||||
<target state="translated">正在启动服务器。正在侦听端口“{0}”</target>
|
||||
|
|
|
@ -633,6 +633,16 @@ Takes one argument as string in the format <value>[h|m|s] where 'value' is
|
|||
<target state="translated">堆疊追蹤</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StandardError">
|
||||
<source>Error output</source>
|
||||
<target state="new">Error output</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StandardOutput">
|
||||
<source>Standard output</source>
|
||||
<target state="new">Standard output</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="StartingServer">
|
||||
<source>Starting server. Listening on port '{0}'</source>
|
||||
<target state="translated">正在啟動伺服器。正在連接埠 '{0}' 上聆聽</target>
|
||||
|
|
|
@ -68,31 +68,50 @@ public sealed class TerminalTestReporterTests : TestBase
|
|||
string folderLink = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? @"C:/work/" : "mnt/work/";
|
||||
string folderLinkNoSlash = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? @"C:/work" : "mnt/work";
|
||||
|
||||
terminalReporter.AssemblyRunStarted(assembly, targetFramework, architecture);
|
||||
terminalReporter.TestCompleted(assembly, targetFramework, architecture, "PassedTest1", TestOutcome.Passed, TimeSpan.FromSeconds(10),
|
||||
errorMessage: null, errorStackTrace: null, expected: null, actual: null);
|
||||
terminalReporter.TestCompleted(assembly, targetFramework, architecture, "SkippedTest1", TestOutcome.Skipped, TimeSpan.FromSeconds(10),
|
||||
errorMessage: null, errorStackTrace: null, expected: null, actual: null);
|
||||
terminalReporter.AssemblyRunStarted(assembly, targetFramework, architecture, executionId: null);
|
||||
string standardOutput = "Hello!";
|
||||
string errorOutput = "Oh no!";
|
||||
|
||||
terminalReporter.TestCompleted(assembly, targetFramework, architecture, executionId: null, "PassedTest1", TestOutcome.Passed, TimeSpan.FromSeconds(10),
|
||||
errorMessage: null, errorStackTrace: null, expected: null, actual: null, standardOutput, errorOutput);
|
||||
terminalReporter.TestCompleted(assembly, targetFramework, architecture, executionId: null, "SkippedTest1", TestOutcome.Skipped, TimeSpan.FromSeconds(10),
|
||||
errorMessage: null, errorStackTrace: null, expected: null, actual: null, standardOutput, errorOutput);
|
||||
// timed out + cancelled + failed should all report as failed in summary
|
||||
terminalReporter.TestCompleted(assembly, targetFramework, architecture, "TimedoutTest1", TestOutcome.Timeout, TimeSpan.FromSeconds(10),
|
||||
errorMessage: null, errorStackTrace: null, expected: null, actual: null);
|
||||
terminalReporter.TestCompleted(assembly, targetFramework, architecture, "CanceledTest1", TestOutcome.Canceled, TimeSpan.FromSeconds(10),
|
||||
errorMessage: null, errorStackTrace: null, expected: null, actual: null);
|
||||
terminalReporter.TestCompleted(assembly, targetFramework, architecture, "FailedTest1", TestOutcome.Fail, TimeSpan.FromSeconds(10),
|
||||
errorMessage: "Tests failed", errorStackTrace: @$" at FailingTest() in {folder}codefile.cs:line 10", expected: "ABC", actual: "DEF");
|
||||
terminalReporter.ArtifactAdded(outOfProcess: true, assembly, targetFramework, architecture, testName: null, @$"{folder}artifact1.txt");
|
||||
terminalReporter.ArtifactAdded(outOfProcess: false, assembly, targetFramework, architecture, testName: null, @$"{folder}artifact2.txt");
|
||||
terminalReporter.AssemblyRunCompleted(assembly, targetFramework, architecture);
|
||||
terminalReporter.TestCompleted(assembly, targetFramework, architecture, executionId: null, "TimedoutTest1", TestOutcome.Timeout, TimeSpan.FromSeconds(10),
|
||||
errorMessage: null, errorStackTrace: null, expected: null, actual: null, standardOutput, errorOutput);
|
||||
terminalReporter.TestCompleted(assembly, targetFramework, architecture, executionId: null, "CanceledTest1", TestOutcome.Canceled, TimeSpan.FromSeconds(10),
|
||||
errorMessage: null, errorStackTrace: null, expected: null, actual: null, standardOutput, errorOutput);
|
||||
terminalReporter.TestCompleted(assembly, targetFramework, architecture, executionId: null, "FailedTest1", TestOutcome.Fail, TimeSpan.FromSeconds(10),
|
||||
errorMessage: "Tests failed", errorStackTrace: @$" at FailingTest() in {folder}codefile.cs:line 10", expected: "ABC", actual: "DEF", standardOutput, errorOutput);
|
||||
terminalReporter.ArtifactAdded(outOfProcess: true, assembly, targetFramework, architecture, executionId: null, testName: null, @$"{folder}artifact1.txt");
|
||||
terminalReporter.ArtifactAdded(outOfProcess: false, assembly, targetFramework, architecture, executionId: null, testName: null, @$"{folder}artifact2.txt");
|
||||
terminalReporter.AssemblyRunCompleted(assembly, targetFramework, architecture, executionId: null);
|
||||
terminalReporter.TestExecutionCompleted(endTime);
|
||||
|
||||
string output = stringBuilderConsole.Output;
|
||||
|
||||
string expected = $"""
|
||||
␛[92mpassed␛[m PassedTest1␛[90m ␛[90m(10s 000ms)␛[m
|
||||
␛[93mskipped␛[m SkippedTest1␛[90m ␛[90m(10s 000ms)␛[m
|
||||
␛[91mfailed (canceled)␛[m TimedoutTest1␛[90m ␛[90m(10s 000ms)␛[m
|
||||
␛[91mfailed (canceled)␛[m CanceledTest1␛[90m ␛[90m(10s 000ms)␛[m
|
||||
␛[91mfailed␛[m FailedTest1␛[90m ␛[90m(10s 000ms)␛[m
|
||||
␛[90m Standard output
|
||||
Hello!
|
||||
Error output
|
||||
Oh no!
|
||||
␛[m␛[93mskipped␛[m SkippedTest1␛[90m ␛[90m(10s 000ms)␛[m
|
||||
␛[90m Standard output
|
||||
Hello!
|
||||
Error output
|
||||
Oh no!
|
||||
␛[m␛[91mfailed (canceled)␛[m TimedoutTest1␛[90m ␛[90m(10s 000ms)␛[m
|
||||
␛[90m Standard output
|
||||
Hello!
|
||||
Error output
|
||||
Oh no!
|
||||
␛[m␛[91mfailed (canceled)␛[m CanceledTest1␛[90m ␛[90m(10s 000ms)␛[m
|
||||
␛[90m Standard output
|
||||
Hello!
|
||||
Error output
|
||||
Oh no!
|
||||
␛[m␛[91mfailed␛[m FailedTest1␛[90m ␛[90m(10s 000ms)␛[m
|
||||
␛[91m Tests failed
|
||||
␛[m␛[91m Expected
|
||||
ABC
|
||||
|
@ -100,7 +119,11 @@ public sealed class TerminalTestReporterTests : TestBase
|
|||
DEF
|
||||
␛[m␛[91m Stack Trace:
|
||||
␛[90mat ␛[m␛[91mFailingTest()␛[90m in ␛[90m␛]8;;file:///{folderLink}codefile.cs␛\{folder}codefile.cs:10␛]8;;␛\␛[m
|
||||
|
||||
␛[90m Standard output
|
||||
Hello!
|
||||
Error output
|
||||
Oh no!
|
||||
␛[m
|
||||
|
||||
Out of process file artifacts produced:
|
||||
- ␛[90m␛]8;;file:///{folderLink}artifact1.txt␛\{folder}artifact1.txt␛]8;;␛\␛[m
|
||||
|
|
Загрузка…
Ссылка в новой задаче