From cd86b276547c0dfca676c86502ff349b524ed245 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amaury=20Lev=C3=A9?= Date: Tue, 19 May 2026 10:23:02 +0200 Subject: [PATCH 1/2] Enable anti-flicker progress version check in AnsiTerminalTestProgressFrame In `AnsiTerminalTestProgressFrame.Render` the `TestProgressState` branch had `&& false` hard-coded in the comparison against the previously rendered line, which made the optimization always fall through to the full re-render branch (`CSI K` erase + `AppendTestWorkerProgress`). The intent of the optimization is documented in the comment that follows the check ("only update the timestamp if possible to avoid flicker") and the parallel `TestDetailState` branch a few lines below already does the correct comparison: if (previouslyRenderedLine.ProgressId == detailItem.Id && previouslyRenderedLine.ProgressVersion == detailItem.Version) `TestProgressState.Version` is bumped in `TestProgressStateAwareTerminal.UpdateWorker` only when there is new data for that worker, so when no test result has come in between two 500 ms refresh ticks the Id+Version pair matches and we can rewrite just the duration cell at the right of the line instead of erasing and re-rendering the whole counters/assembly-name segment. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../OutputDevice/Terminal/AnsiTerminalTestProgressFrame.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/AnsiTerminalTestProgressFrame.cs b/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/AnsiTerminalTestProgressFrame.cs index 8261280b96..db1f3130a5 100644 --- a/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/AnsiTerminalTestProgressFrame.cs +++ b/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/AnsiTerminalTestProgressFrame.cs @@ -225,7 +225,7 @@ public void Render(AnsiTerminalTestProgressFrame previousFrame, TestProgressStat // We have a line that was rendered previously, compare it and decide how to render. RenderedProgressItem previouslyRenderedLine = previousFrame.RenderedLines[i]; - if (previouslyRenderedLine.ProgressId == progressItem.Id && false) + if (previouslyRenderedLine.ProgressId == progressItem.Id && previouslyRenderedLine.ProgressVersion == progressItem.Version) { // This is the same progress item and it was not updated since we rendered it, only update the timestamp if possible to avoid flicker. string durationString = HumanReadableDurationFormatter.Render(progressItem.Stopwatch.Elapsed); From a826ced937dd4566a17ba56e5412182c9ebcdf9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amaury=20Lev=C3=A9?= Date: Tue, 19 May 2026 11:15:11 +0200 Subject: [PATCH 2/2] Fix per-line indexing in progress frame Render loop The Render foreach loop never incremented `i`, so: - `previousFrame.RenderedLines[i]` (lines 229 and 264) always read slot 0, meaning every line in the new frame was being compared against the first previously-rendered line. With the version check now enabled, an iteration whose `ProgressId` happens to match slot 0's would incorrectly take the partial-update branch and write the `duration only` patch at the wrong screen position. - The post-loop `i < previousFrame.RenderedLines.Count` cleanup check (line 318) was essentially `0 < Count`, so the `EraseInDisplay` ANSI sequence was emitted unconditionally whenever the previous frame had any lines. Convert the `foreach` to a `for` loop so the index is properly tied to the iteration, and keep `i` in scope for the post-loop cleanup check. After the loop `i == progresses.Count`, which is the correct value to compare against `previousFrame.RenderedLines.Count`. This bug was latent because `&& false` previously made the partial-update branch unreachable for `TestProgressState` (the `TestDetailState` branch had the same misindexing but rarely hit the matching `Id`+`Version` combination). Surfaced by review feedback on this PR (Copilot reviewer). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../OutputDevice/Terminal/AnsiTerminalTestProgressFrame.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/AnsiTerminalTestProgressFrame.cs b/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/AnsiTerminalTestProgressFrame.cs index db1f3130a5..31e24f622b 100644 --- a/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/AnsiTerminalTestProgressFrame.cs +++ b/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/AnsiTerminalTestProgressFrame.cs @@ -210,12 +210,14 @@ public void Render(AnsiTerminalTestProgressFrame previousFrame, TestProgressStat terminal.AppendLine(); } - int i = 0; + int i; RenderedLines = [with(progress.Length * 2)]; List progresses = GenerateLinesToRender(progress); - foreach (object item in progresses) + for (i = 0; i < progresses.Count; i++) { + object item = progresses[i]; + if (previousFrame.RenderedLines != null && previousFrame.RenderedLines.Count > i) { if (item is TestProgressState progressItem)