Skip to content

Commit 1f17765

Browse files
committed
Add comprehensive rendering pipeline tests
Add test files for three-layer rendering pipeline: Bottom Layer (Double-buffering): - ConsoleBufferTests.cs - front/back buffer comparison - DoubleBufferingTests.cs - dirty cell detection - DirtyTrackingTests.cs - change detection accuracy - DirtyTrackingModeTests.cs - LINE vs CELL mode behavior - ForceRenderTests.cs - DesktopNeedsRender flag validation Middle Layer (ANSI generation): - AnsiGenerationTests.cs - ANSI escape sequence generation - AnsiOptimizationTests.cs - color reuse, redundancy detection - ColorSequenceTests.cs - RGB color encoding Top Layer (DOM rendering): - CellRenderingTests.cs - color, character validation - DOMLayoutTests.cs - layout calculations All tests passing, validates correct behavior across rendering pipeline
1 parent 8e43277 commit 1f17765

10 files changed

Lines changed: 4256 additions & 0 deletions

File tree

SharpConsoleUI.Tests/Rendering/Unit/BottomLayer/ConsoleBufferTests.cs

Lines changed: 506 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
using SharpConsoleUI;
2+
using SharpConsoleUI.Configuration;
3+
using SharpConsoleUI.Controls;
4+
using SharpConsoleUI.Tests.Infrastructure;
5+
using Xunit;
6+
using Xunit.Abstractions;
7+
8+
namespace SharpConsoleUI.Tests.Rendering.Unit.BottomLayer;
9+
10+
/// <summary>
11+
/// Tests for both Line-level and Cell-level dirty tracking modes.
12+
/// Validates that Cell mode produces minimal output for small changes.
13+
/// </summary>
14+
public class DirtyTrackingModeTests
15+
{
16+
private readonly ITestOutputHelper _output;
17+
18+
public DirtyTrackingModeTests(ITestOutputHelper output)
19+
{
20+
_output = output;
21+
}
22+
23+
[Fact]
24+
public void LineMode_SingleCharChange_RendersEntireLine()
25+
{
26+
// Arrange - LINE MODE
27+
var system = TestWindowSystemBuilder.CreateTestSystemWithLineMode();
28+
var control = new MarkupControl(new List<string> { "ABCDEF" });
29+
var window = new Window(system)
30+
{
31+
Left = 10,
32+
Top = 5,
33+
Width = 30,
34+
Height = 10,
35+
Title = "Line Mode"
36+
};
37+
38+
window.AddControl(control);
39+
system.WindowStateService.AddWindow(window);
40+
41+
system.Render.UpdateDisplay(); // Frame 1
42+
43+
// Act - change one character
44+
control.SetContent(new List<string> { "ABXDEF" }); // C → X
45+
window.Invalidate(true);
46+
system.Render.UpdateDisplay(); // Frame 2
47+
48+
// Assert - Line mode renders entire line (200 cells wide)
49+
var metrics = system.RenderingDiagnostics?.LastMetrics;
50+
Assert.NotNull(metrics);
51+
52+
_output.WriteLine($"Mode: Line");
53+
_output.WriteLine($"Dirty cells marked: {metrics.DirtyCellsMarked}");
54+
_output.WriteLine($"Cells actually rendered: {metrics.CellsActuallyRendered}");
55+
56+
// Line mode: even 1 char change renders entire line (200 cells)
57+
Assert.Equal(1, metrics.DirtyCellsMarked); // Only 1 cell differs
58+
Assert.Equal(200, metrics.CellsActuallyRendered); // But renders entire line
59+
}
60+
61+
[Fact]
62+
public void CellMode_SingleCharChange_RendersOnlyChangedRegion()
63+
{
64+
// Arrange - CELL MODE
65+
var system = TestWindowSystemBuilder.CreateTestSystemWithCellMode();
66+
var control = new MarkupControl(new List<string> { "ABCDEF" });
67+
var window = new Window(system)
68+
{
69+
Left = 10,
70+
Top = 5,
71+
Width = 30,
72+
Height = 10,
73+
Title = "Cell Mode"
74+
};
75+
76+
window.AddControl(control);
77+
system.WindowStateService.AddWindow(window);
78+
79+
system.Render.UpdateDisplay(); // Frame 1
80+
81+
// Act - change one character
82+
control.SetContent(new List<string> { "ABXDEF" }); // C → X
83+
window.Invalidate(true);
84+
system.Render.UpdateDisplay(); // Frame 2
85+
86+
// Assert - Cell mode renders only changed region (~1 cell)
87+
var metrics = system.RenderingDiagnostics?.LastMetrics;
88+
Assert.NotNull(metrics);
89+
90+
_output.WriteLine($"Mode: Cell");
91+
_output.WriteLine($"Dirty cells marked: {metrics.DirtyCellsMarked}");
92+
_output.WriteLine($"Cells actually rendered: {metrics.CellsActuallyRendered}");
93+
94+
// Cell mode: minimal output for minimal change
95+
Assert.Equal(1, metrics.DirtyCellsMarked); // Only 1 cell differs
96+
Assert.True(metrics.CellsActuallyRendered <= 10); // Renders only region (~1 cell + margin)
97+
}
98+
99+
[Fact]
100+
public void CellMode_NoChanges_ZeroOutput()
101+
{
102+
// Arrange
103+
var system = TestWindowSystemBuilder.CreateTestSystemWithCellMode();
104+
var window = new Window(system)
105+
{
106+
Left = 10,
107+
Top = 5,
108+
Width = 30,
109+
Height = 10,
110+
Title = "Static"
111+
};
112+
113+
window.AddControl(new MarkupControl(new List<string> { "Static content" }));
114+
system.WindowStateService.AddWindow(window);
115+
116+
// Act - Frame 1 then Frame 2 with no changes
117+
system.Render.UpdateDisplay(); // Frame 1
118+
system.Render.UpdateDisplay(); // Frame 2
119+
120+
// Assert - Zero output for no changes (works in both modes)
121+
var metrics = system.RenderingDiagnostics?.LastMetrics;
122+
Assert.NotNull(metrics);
123+
124+
_output.WriteLine($"Bytes written: {metrics.BytesWritten}");
125+
Assert.Equal(0, metrics.BytesWritten);
126+
Assert.Equal(0, metrics.CharactersChanged);
127+
}
128+
129+
[Fact]
130+
public void CellMode_MultipleRegions_RendersEachRegion()
131+
{
132+
// Arrange
133+
var system = TestWindowSystemBuilder.CreateTestSystemWithCellMode();
134+
var control = new MarkupControl(new List<string> { "AAAA____BBBB____CCCC" }); // 20 chars
135+
var window = new Window(system)
136+
{
137+
Left = 10,
138+
Top = 5,
139+
Width = 40,
140+
Height = 10,
141+
Title = "Multi-Region"
142+
};
143+
144+
window.AddControl(control);
145+
system.WindowStateService.AddWindow(window);
146+
147+
system.Render.UpdateDisplay(); // Frame 1
148+
149+
// Act - change 3 separate regions: AAAA, BBBB, CCCC → XXXX, YYYY, ZZZZ
150+
control.SetContent(new List<string> { "XXXX____YYYY____ZZZZ" });
151+
window.Invalidate(true);
152+
system.Render.UpdateDisplay(); // Frame 2
153+
154+
// Assert - Should render 3 regions (12 cells total)
155+
var metrics = system.RenderingDiagnostics?.LastMetrics;
156+
Assert.NotNull(metrics);
157+
158+
_output.WriteLine($"Dirty cells marked: {metrics.DirtyCellsMarked}");
159+
_output.WriteLine($"Cells actually rendered: {metrics.CellsActuallyRendered}");
160+
_output.WriteLine($"Bytes written: {metrics.BytesWritten}");
161+
162+
// 12 cells changed (3 regions * 4 chars each)
163+
Assert.Equal(12, metrics.DirtyCellsMarked);
164+
// Cell mode renders only those 12 cells (plus small overhead for cursor positioning)
165+
Assert.True(metrics.CellsActuallyRendered >= 12);
166+
Assert.True(metrics.CellsActuallyRendered <= 20); // Some overhead for positioning
167+
}
168+
169+
[Fact]
170+
public void BothModes_SameContentResult_DifferentPerformance()
171+
{
172+
// This test validates that both modes produce correct output
173+
// but Cell mode is more efficient for small changes
174+
175+
// Line Mode
176+
var lineSystem = TestWindowSystemBuilder.CreateTestSystemWithLineMode();
177+
var lineControl = new MarkupControl(new List<string> { "TEST" });
178+
var lineWindow = new Window(lineSystem) { Left = 10, Top = 5, Width = 30, Height = 10, Title = "Line" };
179+
lineWindow.AddControl(lineControl);
180+
lineSystem.WindowStateService.AddWindow(lineWindow);
181+
lineSystem.Render.UpdateDisplay();
182+
lineControl.SetContent(new List<string> { "BEST" });
183+
lineWindow.Invalidate(true);
184+
lineSystem.Render.UpdateDisplay();
185+
var lineMetrics = lineSystem.RenderingDiagnostics?.LastMetrics;
186+
187+
// Cell Mode
188+
var cellSystem = TestWindowSystemBuilder.CreateTestSystemWithCellMode();
189+
var cellControl = new MarkupControl(new List<string> { "TEST" });
190+
var cellWindow = new Window(cellSystem) { Left = 10, Top = 5, Width = 30, Height = 10, Title = "Cell" };
191+
cellWindow.AddControl(cellControl);
192+
cellSystem.WindowStateService.AddWindow(cellWindow);
193+
cellSystem.Render.UpdateDisplay();
194+
cellControl.SetContent(new List<string> { "BEST" });
195+
cellWindow.Invalidate(true);
196+
cellSystem.Render.UpdateDisplay();
197+
var cellMetrics = cellSystem.RenderingDiagnostics?.LastMetrics;
198+
199+
// Assert - Cell mode is more efficient
200+
_output.WriteLine($"Line Mode - Cells rendered: {lineMetrics?.CellsActuallyRendered}, Bytes: {lineMetrics?.BytesWritten}");
201+
_output.WriteLine($"Cell Mode - Cells rendered: {cellMetrics?.CellsActuallyRendered}, Bytes: {cellMetrics?.BytesWritten}");
202+
203+
Assert.NotNull(lineMetrics);
204+
Assert.NotNull(cellMetrics);
205+
206+
// Cell mode should render significantly fewer cells
207+
Assert.True(cellMetrics.CellsActuallyRendered < lineMetrics.CellsActuallyRendered);
208+
// Cell mode should output less data
209+
Assert.True(cellMetrics.BytesWritten < lineMetrics.BytesWritten);
210+
}
211+
}

0 commit comments

Comments
 (0)