Skip to content

Commit 176d4bc

Browse files
committed
Phase 3: Add CharacterBufferTests (15/15 passing)
- Test cell operations (get/set) - Test string writing (clipped and unclipped) - Test fill operations (rect, clear) - Test line drawing (horizontal, vertical) - Test box drawing - Test dirty tracking (GetChanges, GetDirtyCells) - Test resize operations - Test ANSI generation (ToLines) Top Layer: 1/4 files complete
1 parent b6c5b3a commit 176d4bc

1 file changed

Lines changed: 289 additions & 0 deletions

File tree

Lines changed: 289 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,289 @@
1+
// -----------------------------------------------------------------------
2+
// ConsoleEx - A simple console window system for .NET Core
3+
//
4+
// Author: Nikolaos Protopapas
5+
// Email: nikolaos.protopapas@gmail.com
6+
// License: MIT
7+
// -----------------------------------------------------------------------
8+
9+
using SharpConsoleUI.Drawing;
10+
using SharpConsoleUI.Layout;
11+
using Spectre.Console;
12+
using Xunit;
13+
14+
namespace SharpConsoleUI.Tests.Rendering.Unit.TopLayer;
15+
16+
/// <summary>
17+
/// Tests for CharacterBuffer - the top layer of the rendering pipeline.
18+
/// Validates cell operations, dirty tracking, and buffer manipulation.
19+
/// </summary>
20+
public class CharacterBufferTests
21+
{
22+
[Fact]
23+
public void CharacterBuffer_Create_HasCorrectDimensions()
24+
{
25+
// Arrange & Act
26+
var buffer = new CharacterBuffer(80, 25);
27+
28+
// Assert
29+
Assert.Equal(80, buffer.Width);
30+
Assert.Equal(25, buffer.Height);
31+
}
32+
33+
[Fact]
34+
public void CharacterBuffer_SetCell_UpdatesCell()
35+
{
36+
// Arrange
37+
var buffer = new CharacterBuffer(10, 10);
38+
39+
// Act
40+
buffer.SetCell(5, 5, 'X', Color.Red, Color.Blue);
41+
42+
// Assert
43+
var cell = buffer.GetCell(5, 5);
44+
Assert.Equal('X', cell.Character);
45+
Assert.Equal(Color.Red, cell.Foreground);
46+
Assert.Equal(Color.Blue, cell.Background);
47+
}
48+
49+
[Fact]
50+
public void CharacterBuffer_WriteString_WritesAllCharacters()
51+
{
52+
// Arrange
53+
var buffer = new CharacterBuffer(20, 10);
54+
var text = "Hello";
55+
56+
// Act
57+
buffer.WriteString(5, 3, text, Color.White, Color.Black);
58+
59+
// Assert
60+
Assert.Equal('H', buffer.GetCell(5, 3).Character);
61+
Assert.Equal('e', buffer.GetCell(6, 3).Character);
62+
Assert.Equal('l', buffer.GetCell(7, 3).Character);
63+
Assert.Equal('l', buffer.GetCell(8, 3).Character);
64+
Assert.Equal('o', buffer.GetCell(9, 3).Character);
65+
}
66+
67+
[Fact]
68+
public void CharacterBuffer_WriteStringClipped_RespectsClipRect()
69+
{
70+
// Arrange
71+
var buffer = new CharacterBuffer(20, 10);
72+
var text = "Hello World";
73+
var clipRect = new LayoutRect(5, 3, 5, 1); // Only 5 chars wide
74+
75+
// Act
76+
buffer.WriteStringClipped(5, 3, text, Color.White, Color.Black, clipRect);
77+
78+
// Assert - Only "Hello" should be written (5 chars)
79+
Assert.Equal('H', buffer.GetCell(5, 3).Character);
80+
Assert.Equal('o', buffer.GetCell(9, 3).Character);
81+
// "World" should not be written
82+
Assert.NotEqual('W', buffer.GetCell(10, 3).Character);
83+
}
84+
85+
[Fact]
86+
public void CharacterBuffer_FillRect_FillsEntireRegion()
87+
{
88+
// Arrange
89+
var buffer = new CharacterBuffer(20, 10);
90+
var rect = new LayoutRect(5, 3, 10, 4);
91+
92+
// Act
93+
buffer.FillRect(rect, '#', Color.Yellow, Color.Green);
94+
95+
// Assert - Check corners and middle
96+
Assert.Equal('#', buffer.GetCell(5, 3).Character); // Top-left
97+
Assert.Equal('#', buffer.GetCell(14, 6).Character); // Bottom-right
98+
Assert.Equal('#', buffer.GetCell(10, 5).Character); // Middle
99+
Assert.Equal(Color.Yellow, buffer.GetCell(10, 5).Foreground);
100+
Assert.Equal(Color.Green, buffer.GetCell(10, 5).Background);
101+
}
102+
103+
[Fact]
104+
public void CharacterBuffer_Clear_ClearsAllCells()
105+
{
106+
// Arrange
107+
var buffer = new CharacterBuffer(10, 10);
108+
buffer.SetCell(5, 5, 'X', Color.Red, Color.Blue);
109+
110+
// Act
111+
buffer.Clear(Color.Black);
112+
113+
// Assert
114+
var cell = buffer.GetCell(5, 5);
115+
Assert.Equal(' ', cell.Character);
116+
Assert.Equal(Color.Black, cell.Background);
117+
}
118+
119+
[Fact]
120+
public void CharacterBuffer_DrawHorizontalLine_DrawsLine()
121+
{
122+
// Arrange
123+
var buffer = new CharacterBuffer(20, 10);
124+
125+
// Act
126+
buffer.DrawHorizontalLine(5, 5, 10, '─', Color.White, Color.Black);
127+
128+
// Assert
129+
for (int x = 5; x < 15; x++)
130+
{
131+
Assert.Equal('─', buffer.GetCell(x, 5).Character);
132+
}
133+
}
134+
135+
[Fact]
136+
public void CharacterBuffer_DrawVerticalLine_DrawsLine()
137+
{
138+
// Arrange
139+
var buffer = new CharacterBuffer(20, 10);
140+
141+
// Act
142+
buffer.DrawVerticalLine(5, 2, 6, '│', Color.White, Color.Black);
143+
144+
// Assert
145+
for (int y = 2; y < 8; y++)
146+
{
147+
Assert.Equal('│', buffer.GetCell(5, y).Character);
148+
}
149+
}
150+
151+
[Fact]
152+
public void CharacterBuffer_DrawBox_DrawsCompleteBox()
153+
{
154+
// Arrange
155+
var buffer = new CharacterBuffer(20, 10);
156+
var rect = new LayoutRect(5, 3, 10, 5);
157+
var boxChars = BoxChars.Single;
158+
159+
// Act
160+
buffer.DrawBox(rect, boxChars, Color.White, Color.Black);
161+
162+
// Assert - Check corners
163+
Assert.Equal(boxChars.TopLeft, buffer.GetCell(5, 3).Character);
164+
Assert.Equal(boxChars.TopRight, buffer.GetCell(14, 3).Character);
165+
Assert.Equal(boxChars.BottomLeft, buffer.GetCell(5, 7).Character);
166+
Assert.Equal(boxChars.BottomRight, buffer.GetCell(14, 7).Character);
167+
168+
// Check edges
169+
Assert.Equal(boxChars.Horizontal, buffer.GetCell(10, 3).Character); // Top
170+
Assert.Equal(boxChars.Horizontal, buffer.GetCell(10, 7).Character); // Bottom
171+
Assert.Equal(boxChars.Vertical, buffer.GetCell(5, 5).Character); // Left
172+
Assert.Equal(boxChars.Vertical, buffer.GetCell(14, 5).Character); // Right
173+
}
174+
175+
[Fact]
176+
public void CharacterBuffer_GetDirtyCells_ReturnsModifiedCells()
177+
{
178+
// Arrange
179+
var buffer = new CharacterBuffer(10, 10);
180+
// Clear initial dirty state by rendering once
181+
buffer.ToLines(Color.White, Color.Black);
182+
183+
// Act
184+
buffer.SetCell(3, 4, 'A', Color.Red, Color.Black);
185+
buffer.SetCell(7, 2, 'B', Color.Blue, Color.White);
186+
187+
var dirtyCells = buffer.GetDirtyCells().ToList();
188+
189+
// Assert - At minimum, the two cells we modified should be in the dirty list
190+
Assert.True(dirtyCells.Count >= 2);
191+
Assert.Contains(dirtyCells, c => c.X == 3 && c.Y == 4);
192+
Assert.Contains(dirtyCells, c => c.X == 7 && c.Y == 2);
193+
}
194+
195+
[Fact]
196+
public void CharacterBuffer_GetChanges_ReturnsAllChanges()
197+
{
198+
// Arrange
199+
var buffer = new CharacterBuffer(10, 10);
200+
// Clear initial dirty state by rendering once
201+
buffer.ToLines(Color.White, Color.Black);
202+
203+
// Act
204+
buffer.SetCell(3, 4, 'A', Color.Red, Color.Black);
205+
buffer.SetCell(7, 2, 'B', Color.Blue, Color.White);
206+
207+
var changes = buffer.GetChanges().ToList();
208+
209+
// Assert - Should include our modifications
210+
Assert.True(changes.Count >= 2);
211+
var change1 = changes.First(c => c.X == 3 && c.Y == 4);
212+
Assert.Equal('A', change1.Cell.Character);
213+
Assert.Equal(Color.Red, change1.Cell.Foreground);
214+
}
215+
216+
[Fact]
217+
public void CharacterBuffer_Resize_PreservesContent()
218+
{
219+
// Arrange
220+
var buffer = new CharacterBuffer(10, 10);
221+
buffer.SetCell(5, 5, 'X', Color.Red, Color.Blue);
222+
223+
// Act
224+
buffer.Resize(20, 20);
225+
226+
// Assert
227+
Assert.Equal(20, buffer.Width);
228+
Assert.Equal(20, buffer.Height);
229+
// Content should still be there
230+
var cell = buffer.GetCell(5, 5);
231+
Assert.Equal('X', cell.Character);
232+
Assert.Equal(Color.Red, cell.Foreground);
233+
}
234+
235+
[Fact]
236+
public void CharacterBuffer_Resize_TruncatesWhenShrinking()
237+
{
238+
// Arrange
239+
var buffer = new CharacterBuffer(20, 20);
240+
buffer.SetCell(15, 15, 'X', Color.Red, Color.Blue);
241+
242+
// Act - Shrink to 10x10
243+
buffer.Resize(10, 10);
244+
245+
// Assert
246+
Assert.Equal(10, buffer.Width);
247+
Assert.Equal(10, buffer.Height);
248+
// Cell at (15,15) should no longer be accessible
249+
}
250+
251+
[Fact]
252+
public void CharacterBuffer_ToLines_GeneratesAnsiOutput()
253+
{
254+
// Arrange
255+
var buffer = new CharacterBuffer(10, 3);
256+
buffer.WriteString(0, 0, "Red", Color.Red, Color.Black);
257+
buffer.WriteString(0, 1, "Blue", Color.Blue, Color.Black);
258+
259+
// Act
260+
var lines = buffer.ToLines(Color.White, Color.Black);
261+
262+
// Assert
263+
Assert.Equal(3, lines.Count);
264+
Assert.Contains("Red", lines[0]);
265+
Assert.Contains("Blue", lines[1]);
266+
// Lines should contain ANSI escape sequences
267+
Assert.Contains("\x1b[", lines[0]); // ANSI escape start
268+
}
269+
270+
[Fact]
271+
public void CharacterBuffer_ClearRect_ClearsOnlySpecifiedRegion()
272+
{
273+
// Arrange
274+
var buffer = new CharacterBuffer(20, 10);
275+
buffer.FillRect(new LayoutRect(0, 0, 20, 10), 'X', Color.White, Color.Black);
276+
277+
// Act - Clear only a small region
278+
buffer.ClearRect(new LayoutRect(5, 3, 5, 3), Color.Red);
279+
280+
// Assert
281+
// Inside cleared region
282+
Assert.Equal(' ', buffer.GetCell(7, 5).Character);
283+
Assert.Equal(Color.Red, buffer.GetCell(7, 5).Background);
284+
285+
// Outside cleared region (should still have X)
286+
Assert.Equal('X', buffer.GetCell(2, 2).Character);
287+
Assert.Equal('X', buffer.GetCell(15, 7).Character);
288+
}
289+
}

0 commit comments

Comments
 (0)