Write standard output and error, and respect execution id (#3934)

This commit is contained in:
Jakub Jareš 2024-10-14 10:14:29 +02:00 коммит произвёл GitHub
Родитель cb555a15d2
Коммит dec5768b8a
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
22 изменённых файлов: 315 добавлений и 60 удалений

Просмотреть файл

@ -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 &apos;{0}&apos;.
/// </summary>

Просмотреть файл

@ -631,4 +631,10 @@ Takes one argument as string in the format &lt;value&gt;[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 &lt;value&gt;[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 &lt;value&gt;[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 &lt;value&gt;[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 &lt;value&gt;[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 &lt;value&gt;[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 &lt;value&gt;[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 &lt;value&gt;[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 &lt;value&gt;[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 &lt;valor&gt;[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 &lt;value&gt;[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 &lt;value&gt;[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 &lt;value&gt;[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 &lt;value&gt;[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