diff --git a/src/Cli/dotnet/Commands/CliCommandStrings.resx b/src/Cli/dotnet/Commands/CliCommandStrings.resx
index 4086103e08f5..300daaa0169d 100644
--- a/src/Cli/dotnet/Commands/CliCommandStrings.resx
+++ b/src/Cli/dotnet/Commands/CliCommandStrings.resx
@@ -1962,6 +1962,10 @@ Your project targets multiple frameworks. Specify which framework to run using '
Standard output
+
+ ... output truncated, {0} lines omitted ...
+ {0} is the number of output lines that were omitted from the summary.
+
Status
diff --git a/src/Cli/dotnet/Commands/Test/MTP/Terminal/TerminalTestReporter.cs b/src/Cli/dotnet/Commands/Test/MTP/Terminal/TerminalTestReporter.cs
index 15cc7ac3c3d6..d0a3cc319e64 100644
--- a/src/Cli/dotnet/Commands/Test/MTP/Terminal/TerminalTestReporter.cs
+++ b/src/Cli/dotnet/Commands/Test/MTP/Terminal/TerminalTestReporter.cs
@@ -4,6 +4,7 @@
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Globalization;
+using System.Text;
using System.Text.RegularExpressions;
using Microsoft.CodeAnalysis;
using Microsoft.DotNet.Cli.Commands.Test.IPC.Models;
@@ -866,7 +867,7 @@ private static void AppendExecutableSummary(ITerminal terminal, int? exitCode, s
terminal.Append(CliCommandStrings.ExitCode);
terminal.Append(": ");
terminal.AppendLine(exitCode?.ToString(CultureInfo.CurrentCulture) ?? "");
- AppendOutputWhenPresent(CliCommandStrings.StandardOutput, outputData);
+ AppendOutputWhenPresent(CliCommandStrings.StandardOutput, TruncateOutputForSummary(outputData));
AppendOutputWhenPresent(CliCommandStrings.StandardError, errorData);
void AppendOutputWhenPresent(string description, string? output)
@@ -878,6 +879,48 @@ void AppendOutputWhenPresent(string description, string? output)
}
}
+ // A test host that exits with a failure often prints its entire command-line help — hundreds of
+ // lines — to standard output. The classic case is an invalid argument (e.g. an unexpected value
+ // for a known option): the platform reports the error on the first few lines and then dumps the
+ // full usage, which buries the actual error in noise. Keep the beginning (where the real error
+ // is) and the end (where trailing diagnostics tend to be) and collapse the middle so the error
+ // stays easy to find. See https://github.com/dotnet/sdk/issues/52297.
+ private const int StandardOutputSummaryHeadLines = 30;
+ private const int StandardOutputSummaryTailLines = 10;
+ private const int StandardOutputSummaryMaxLines = StandardOutputSummaryHeadLines + StandardOutputSummaryTailLines;
+
+ internal static string? TruncateOutputForSummary(string? output)
+ {
+ if (string.IsNullOrWhiteSpace(output))
+ {
+ return output;
+ }
+
+ string[] lines = output.Split(NewLineStrings, StringSplitOptions.None);
+ if (lines.Length <= StandardOutputSummaryMaxLines)
+ {
+ return output;
+ }
+
+ int omitted = lines.Length - StandardOutputSummaryMaxLines;
+ var builder = new StringBuilder();
+ for (int i = 0; i < StandardOutputSummaryHeadLines; i++)
+ {
+ builder.AppendLine(lines[i]);
+ }
+
+ builder.AppendLine(string.Format(CultureInfo.CurrentCulture, CliCommandStrings.TestApplicationOutputTruncated, omitted));
+
+ for (int i = lines.Length - StandardOutputSummaryTailLines; i < lines.Length; i++)
+ {
+ builder.AppendLine(lines[i]);
+ }
+
+ // Drop the trailing newline so the value flows through AppendIndentedLine the same way an
+ // untruncated payload would.
+ return builder.ToString().TrimEnd('\r', '\n');
+ }
+
private static string? NormalizeSpecialCharacters(string? text)
=> text?.Replace('\0', '\x2400')
// escape char
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf
index 52cf349d9359..b1e58cab23ce 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf
@@ -3157,6 +3157,11 @@ Cílem projektu je více architektur. Pomocí parametru {0} určete, která arch
Zadejte dočasný adresář pro tento příkaz, který se má stáhnout a extrahujte balíčky NuGet (musí být zabezpečené).
+
+ ... output truncated, {0} lines omitted ...
+ ... output truncated, {0} lines omitted ...
+ {0} is the number of output lines that were omitted from the summary.
+ Run test(s), without displaying Microsoft Testplatform bannerSpustit testy bez zobrazení nápisu Microsoft Testplatform
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf
index 5da9cfd3e38c..7957c660dd14 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf
@@ -3157,6 +3157,11 @@ Ihr Projekt verwendet mehrere Zielframeworks. Geben Sie über "{0}" an, welches
Geben Sie ein temporäres Verzeichnis für diesen Befehl zum Herunterladen und Extrahieren von NuGet-Paketen an (muss sicher sein).
+
+ ... output truncated, {0} lines omitted ...
+ ... output truncated, {0} lines omitted ...
+ {0} is the number of output lines that were omitted from the summary.
+ Run test(s), without displaying Microsoft Testplatform bannerTest(s) ohne Anzeige des Microsoft-Testplattformbanners ausführen
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf
index 026a7a617b87..380aaa3a0754 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf
@@ -3157,6 +3157,11 @@ Su proyecto tiene como destino varias plataformas. Especifique la que quiere usa
Especifique un directorio temporal para que este comando descargue y extraiga paquetes NuGet (debe ser seguro).
+
+ ... output truncated, {0} lines omitted ...
+ ... output truncated, {0} lines omitted ...
+ {0} is the number of output lines that were omitted from the summary.
+ Run test(s), without displaying Microsoft Testplatform bannerEjecutar pruebas, sin mostrar la pancarta de Microsoft Testplatform
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf
index 1ed0ebedd929..682ef17c0211 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf
@@ -3157,6 +3157,11 @@ Votre projet cible plusieurs frameworks. Spécifiez le framework à exécuter à
Spécifiez un répertoire temporaire pour que cette commande télécharge et extrait les packages NuGet (doit être sécurisé).
+
+ ... output truncated, {0} lines omitted ...
+ ... output truncated, {0} lines omitted ...
+ {0} is the number of output lines that were omitted from the summary.
+ Run test(s), without displaying Microsoft Testplatform bannerExécute le ou les tests, sans afficher la bannière Microsoft Testplatform
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf
index dcee075434a1..5fe2071c60c5 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf
@@ -3157,6 +3157,11 @@ Il progetto è destinato a più framework. Specificare il framework da eseguire
Specificare una directory temporanea per questo comando per scaricare ed estrarre i pacchetti NuGet (deve essere protetta).
+
+ ... output truncated, {0} lines omitted ...
+ ... output truncated, {0} lines omitted ...
+ {0} is the number of output lines that were omitted from the summary.
+ Run test(s), without displaying Microsoft Testplatform bannerEsegui test senza visualizzare il banner di Microsoft Testplatform
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf
index d1174976d661..c13e31663d28 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf
@@ -3157,6 +3157,11 @@ Your project targets multiple frameworks. Specify which framework to run using '
このコマンドに NuGet パッケージをダウンロードして抽出するための一時ディレクトリを指定します (セキュリティで保護する必要があります)。
+
+ ... output truncated, {0} lines omitted ...
+ ... output truncated, {0} lines omitted ...
+ {0} is the number of output lines that were omitted from the summary.
+ Run test(s), without displaying Microsoft Testplatform bannerMicrosoft Testplatform バナーを表示せずにテストを実行する
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf
index 0d28c4d6356c..4cb39d88ed6e 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf
@@ -3157,6 +3157,11 @@ Your project targets multiple frameworks. Specify which framework to run using '
NuGet 패키지를 다운로드하고 추출하려면 이 명령의 임시 디렉터리를 지정합니다(보안이 있어야 합니다).
+
+ ... output truncated, {0} lines omitted ...
+ ... output truncated, {0} lines omitted ...
+ {0} is the number of output lines that were omitted from the summary.
+ Run test(s), without displaying Microsoft Testplatform bannerMicrosoft Testplatform 배너를 표시하지 않고 테스트 실행
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf
index 16ca245f7dc6..8815b7f2bce4 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf
@@ -3157,6 +3157,11 @@ Projekt ma wiele platform docelowych. Określ platformę do uruchomienia przy u
Określ katalog tymczasowy dla tego polecenia, aby pobrać i wyodrębnić pakiety NuGet (musi być bezpieczny).
+
+ ... output truncated, {0} lines omitted ...
+ ... output truncated, {0} lines omitted ...
+ {0} is the number of output lines that were omitted from the summary.
+ Run test(s), without displaying Microsoft Testplatform bannerUruchom testy bez wyświetlania baneru platformy testowej firmy Microsoft
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf
index 0c37f17485ed..f7b819fdc97e 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf
@@ -3157,6 +3157,11 @@ Ele tem diversas estruturas como destino. Especifique que estrutura executar usa
Especifique um diretório temporário para este comando baixar e extrair pacotes NuGet (deve ser seguro).
+
+ ... output truncated, {0} lines omitted ...
+ ... output truncated, {0} lines omitted ...
+ {0} is the number of output lines that were omitted from the summary.
+ Run test(s), without displaying Microsoft Testplatform bannerExecutar testes, sem exibir a faixa do Microsoft Testplatform
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf
index a6d938bc9aaa..3deeb5bc49fc 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf
@@ -3157,6 +3157,11 @@ Your project targets multiple frameworks. Specify which framework to run using '
Укажите временный каталог для этой команды, чтобы скачать и извлечь пакеты NuGet (должны быть защищены).
+
+ ... output truncated, {0} lines omitted ...
+ ... output truncated, {0} lines omitted ...
+ {0} is the number of output lines that were omitted from the summary.
+ Run test(s), without displaying Microsoft Testplatform bannerЗапуск тестов без отображения баннера Testplatform Майкрософт
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf
index d322bf11ab8c..05effa1a2e5d 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf
@@ -3157,6 +3157,11 @@ Projeniz birden fazla Framework'ü hedefliyor. '{0}' kullanarak hangi Framework'
Bu komut için NuGet paketlerini indirmek ve ayıklamak üzere geçici bir dizin belirtin (güvenli olmalıdır).
+
+ ... output truncated, {0} lines omitted ...
+ ... output truncated, {0} lines omitted ...
+ {0} is the number of output lines that were omitted from the summary.
+ Run test(s), without displaying Microsoft Testplatform bannerTestleri Microsoft Testplatform bandını görüntülemeden çalıştır
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf
index b5126ddcc08f..187c0fd21578 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf
@@ -3157,6 +3157,11 @@ Your project targets multiple frameworks. Specify which framework to run using '
为此命令指定一个临时目录,以下载并提取(必须安全)的 NuGet 包。
+
+ ... output truncated, {0} lines omitted ...
+ ... output truncated, {0} lines omitted ...
+ {0} is the number of output lines that were omitted from the summary.
+ Run test(s), without displaying Microsoft Testplatform banner运行测试,而不显示 Microsoft Testplatform 版权标志
diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf
index 542649b0629f..939e7e12d702 100644
--- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf
+++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf
@@ -3157,6 +3157,11 @@ Your project targets multiple frameworks. Specify which framework to run using '
指定此命令的暫存目錄,以下載並解壓縮 NuGet 套件 (必須為安全)。
+
+ ... output truncated, {0} lines omitted ...
+ ... output truncated, {0} lines omitted ...
+ {0} is the number of output lines that were omitted from the summary.
+ Run test(s), without displaying Microsoft Testplatform banner執行測試,但不顯示 Microsoft Testplatform 橫幅
diff --git a/test/dotnet.Tests/CommandTests/Test/TerminalTestReporterTests.cs b/test/dotnet.Tests/CommandTests/Test/TerminalTestReporterTests.cs
index 9a6dbdb8dd05..28892d77c028 100644
--- a/test/dotnet.Tests/CommandTests/Test/TerminalTestReporterTests.cs
+++ b/test/dotnet.Tests/CommandTests/Test/TerminalTestReporterTests.cs
@@ -185,6 +185,85 @@ public void AssemblyRunCompleted_WhenTestsWereRetried_ShowsRetriedCount()
assemblyLine.Should().Contain("[+1/x0/?0/r1]");
}
+ ///
+ /// Output that fits within the summary budget must be echoed verbatim (no truncation marker).
+ ///
+ [TestMethod]
+ public void TruncateOutputForSummary_WhenOutputIsSmall_ReturnsOutputUnchanged()
+ {
+ string output = string.Join(Environment.NewLine, Enumerable.Range(1, 10).Select(i => $"line {i}"));
+
+ string? result = TerminalTestReporter.TruncateOutputForSummary(output);
+
+ result.Should().Be(output);
+ }
+
+ ///
+ /// Regression test for https://github.com/dotnet/sdk/issues/52297: when a failing test host dumps
+ /// hundreds of lines (typically its full command-line help after an invalid argument), the summary
+ /// must keep the head (where the actual error is) and the tail, collapse the middle, and note how
+ /// many lines were omitted — instead of burying the error under a wall of noise.
+ ///
+ [TestMethod]
+ public void TruncateOutputForSummary_WhenOutputIsLarge_KeepsHeadAndTailAndNotesOmittedCount()
+ {
+ // The error the user cares about is on the first line; the rest is help noise.
+ var lines = new List { "Option '--show-live-output' has invalid arguments: Invalid value 'true' (must be one of: 'on', 'off')" };
+ lines.AddRange(Enumerable.Range(1, 699).Select(i => $"help line {i}"));
+ string output = string.Join(Environment.NewLine, lines);
+
+ string result = TerminalTestReporter.TruncateOutputForSummary(output)!;
+ string[] resultLines = result.Split(Environment.NewLine);
+
+ // Head is preserved so the invalid-argument error stays visible.
+ result.Should().Contain("Option '--show-live-output' has invalid arguments");
+ // Tail is preserved.
+ result.Should().Contain("help line 699");
+ // The bulk of the help noise in the middle is dropped.
+ result.Should().NotContain("help line 350");
+ // The omission is reported (700 total lines, 40 kept -> 660 omitted).
+ result.Should().Contain("660 lines omitted");
+ // Head + marker + tail only.
+ resultLines.Length.Should().Be(30 + 1 + 10);
+ }
+
+ ///
+ /// End-to-end through : a non-zero exit whose
+ /// captured standard output is a large help dump must be truncated in the emitted summary so the
+ /// error is not buried (https://github.com/dotnet/sdk/issues/52297).
+ ///
+ [TestMethod]
+ public void AssemblyRunCompleted_WithLargeStandardOutput_TruncatesInSummary()
+ {
+ var capturingConsole = new CapturingConsole();
+
+ var options = new TerminalTestReporterOptions
+ {
+ AnsiMode = AnsiMode.SimpleAnsi,
+ ShowProgress = false,
+ };
+
+ using var reporter = new TerminalTestReporter(capturingConsole, options);
+
+ reporter.TestExecutionStarted(DateTimeOffset.UtcNow, workerCount: 1, isDiscovery: false, isHelp: false, isRetry: false);
+
+ const string assembly = "/repo/bin/Debug/net9.0/MyTests.dll";
+ const string executionId = "exec-1";
+ reporter.AssemblyRunStarted(assembly, targetFramework: "net9.0", architecture: "x64", executionId, instanceId: "inst-1");
+
+ var lines = new List { "Option '--show-live-output' has invalid arguments: Invalid value 'true' (must be one of: 'on', 'off')" };
+ lines.AddRange(Enumerable.Range(1, 699).Select(i => $"help line {i}"));
+ string largeOutput = string.Join(Environment.NewLine, lines);
+
+ reporter.AssemblyRunCompleted(executionId, exitCode: 5, outputData: largeOutput, errorData: null);
+
+ string output = StripAnsi(capturingConsole.GetOutput());
+
+ output.Should().Contain("Option '--show-live-output' has invalid arguments");
+ output.Should().Contain("lines omitted");
+ output.Should().NotContain("help line 350");
+ }
+
private static void ReportTest(TerminalTestReporter reporter, string assembly, string executionId, string instanceId, string testUid, TestOutcome outcome)
{
reporter.TestCompleted(