Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ internal static bool IsWindows
}
}

// Copy of https://github.com/dotnet/msbuild/blob/4618ab514861c1aec4e9a5550ce685590de44bc7/src/Framework/NativeMethods.cs#L1613
internal static (bool AcceptAnsiColorCodes, bool OutputIsScreen, uint? OriginalConsoleMode) QueryIsScreenAndTryEnableAnsiColorCodes(StreamHandleType handleType = StreamHandleType.StdOut)
{
if (Console.IsOutputRedirected)
Expand All @@ -33,14 +34,24 @@ internal static (bool AcceptAnsiColorCodes, bool OutputIsScreen, uint? OriginalC
return (AcceptAnsiColorCodes: false, OutputIsScreen: false, OriginalConsoleMode: null);
}

if (!OperatingSystem.IsAndroid() && !OperatingSystem.IsBrowser() && !OperatingSystem.IsIOS() && !OperatingSystem.IsTvOS())
{
if (Console.BufferHeight == 0 || Console.BufferWidth == 0)
{
// The current console doesn't have a valid buffer size, which means it is not a real console. let's default to not using TL
// in those scenarios.
return (AcceptAnsiColorCodes: false, OutputIsScreen: false, OriginalConsoleMode: null);
}
}

bool acceptAnsiColorCodes = false;
bool outputIsScreen = false;
uint? originalConsoleMode = null;
if (IsWindows)
{
try
{
nint outputStream = GetStdHandle((int)handleType);
IntPtr outputStream = GetStdHandle((int)handleType);
if (GetConsoleMode(outputStream, out uint consoleMode))
{
if ((consoleMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) == ENABLE_VIRTUAL_TERMINAL_PROCESSING)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,17 +86,11 @@ public TerminalTestReporter(
_testApplicationCancellationTokenSource = testApplicationCancellationTokenSource;
_options = options;

Func<bool?> showProgress = _options.ShowProgress;
TestProgressStateAwareTerminal terminalWithProgress;

// When not writing to ANSI we write the progress to screen and leave it there so we don't want to write it more often than every few seconds.
int nonAnsiUpdateCadenceInMs = 3_000;
// When writing to ANSI we update the progress in place and it should look responsive so we update every half second, because we only show seconds on the screen, so it is good enough.
int ansiUpdateCadenceInMs = 500;
ITerminal terminal;
if (_options.AnsiMode == AnsiMode.SimpleAnsi)
{
// We are told externally that we are in CI, use simplified ANSI mode.
terminalWithProgress = new TestProgressStateAwareTerminal(new SimpleAnsiTerminal(console), showProgress, writeProgressImmediatelyAfterOutput: true, updateEvery: nonAnsiUpdateCadenceInMs);
terminal = new SimpleAnsiTerminal(console);
}
else
{
Expand All @@ -111,14 +105,10 @@ public TerminalTestReporter(
_ => throw ApplicationStateGuard.Unreachable(),
};

terminalWithProgress = new TestProgressStateAwareTerminal(
useAnsi ? new AnsiTerminal(console) : new NonAnsiTerminal(console),
showProgress,
writeProgressImmediatelyAfterOutput: useAnsi,
updateEvery: useAnsi ? ansiUpdateCadenceInMs : nonAnsiUpdateCadenceInMs);
terminal = useAnsi ? new AnsiTerminal(console) : new NonAnsiTerminal(console);
}

_terminalWithProgress = terminalWithProgress;
_terminalWithProgress = new TestProgressStateAwareTerminal(terminal, _options.ShowProgress);
}

public void TestExecutionStarted(DateTimeOffset testStartTime, int workerCount, bool isDiscovery)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ internal sealed class TerminalTestReporterOptions
public int MinimumExpectedTests { get; init; }

/// <summary>
/// Gets a value indicating whether we should write the progress periodically to screen. When ANSI is allowed we update the progress as often as we can. When ANSI is not allowed we update it every 3 seconds.
/// Gets a value indicating whether we should write the progress periodically to screen. When ANSI is allowed we update the progress as often as we can.
/// When ANSI is not allowed we never have progress.
/// This is a callback to nullable bool, because we don't know if we are running as test host controller until after we setup the console. So we should be polling for the value, until we get non-null boolean
/// and then cache that value.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ internal sealed partial class TestProgressStateAwareTerminal : IDisposable

private readonly ITerminal _terminal;
private readonly Func<bool?> _showProgress;
private readonly bool _writeProgressImmediatelyAfterOutput;
private readonly int _updateEvery;
private TestProgressState?[] _progressItems = [];
private bool? _showProgressCached;

Expand All @@ -43,7 +41,10 @@ private void ThreadProc()
{
try
{
while (!_cts.Token.WaitHandle.WaitOne(_updateEvery))
// When writing to ANSI, we update the progress in place and it should look responsive so we
// update every half second, because we only show seconds on the screen, so it is good enough.
// When writing to non-ANSI, we never show progress as the output can get long and messy.
while (!_cts.Token.WaitHandle.WaitOne(500))
{
lock (_lock)
{
Expand All @@ -69,12 +70,10 @@ private void ThreadProc()
_terminal.EraseProgress();
}

public TestProgressStateAwareTerminal(ITerminal terminal, Func<bool?> showProgress, bool writeProgressImmediatelyAfterOutput, int updateEvery)
public TestProgressStateAwareTerminal(ITerminal terminal, Func<bool?> showProgress)
{
_terminal = terminal;
_showProgress = showProgress;
_writeProgressImmediatelyAfterOutput = writeProgressImmediatelyAfterOutput;
_updateEvery = updateEvery;
}

public int AddWorker(TestProgressState testWorker)
Expand Down Expand Up @@ -134,10 +133,7 @@ internal void WriteToTerminal(Action<ITerminal> write)
_terminal.StartUpdate();
_terminal.EraseProgress();
write(_terminal);
if (_writeProgressImmediatelyAfterOutput)
{
_terminal.RenderProgress(_progressItems);
}
_terminal.RenderProgress(_progressItems);
}
finally
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,11 @@ await _policiesService.RegisterOnAbortCallbackAsync(
showPassed = () => true;
}

Func<bool?> shouldShowProgress = noProgress
Func<bool?> shouldShowProgress = noProgress || ansiMode is AnsiMode.NoAnsi or AnsiMode.SimpleAnsi
// User preference is to not show progress.
? () => false
// Or, we are in terminal that's not capable of changing cursor and we can't update progress in-place.
// In that case, we force disable progress as well.
? static () => false
// User preference is to allow showing progress, figure if we should actually show it based on whether or not we are a testhost controller.
//
// TestHost controller is not running any tests and it should not be writing progress.
Expand Down