Add comprehensive documentation for FakeDriver testing infrastructure

Co-authored-by: tig <585482+tig@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2025-10-27 02:29:40 +00:00
parent 267b9fb4ad
commit 0132aebd77
3 changed files with 282 additions and 2 deletions

View File

@@ -5,7 +5,48 @@
namespace Terminal.Gui.Drivers;
#pragma warning disable RCS1138 // Add summary to documentation comment.
/// <summary></summary>
/// <summary>
/// Static mock console implementation that simulates the .NET Console API for testing purposes.
/// Used by <see cref="FakeDriver"/> to provide input/output simulation without requiring a real terminal.
/// </summary>
/// <remarks>
/// <para>
/// <see cref="FakeConsole"/> provides static properties and methods that mirror the standard
/// <see cref="System.Console"/> API. It maintains internal state for window size, cursor position,
/// colors, and buffered input/output.
/// </para>
/// <para>
/// <strong>Key Capabilities:</strong>
/// </para>
/// <list type="bullet">
/// <item>Simulating keyboard input via <see cref="PushMockKeyPress"/></item>
/// <item>Tracking cursor position and visibility</item>
/// <item>Managing console colors (foreground/background)</item>
/// <item>Simulating window and buffer size operations</item>
/// <item>Recording output for verification</item>
/// </list>
/// <para>
/// <strong>Thread Safety:</strong> This class maintains static state and is not thread-safe.
/// Tests should not run in parallel if they access FakeConsole.
/// </para>
/// <para>
/// <strong>Usage:</strong> Most tests don't need to interact with FakeConsole directly.
/// <see cref="FakeDriver"/> uses it internally, and <see cref="AutoInitShutdownAttribute"/>
/// handles setup/teardown. However, tests can use <see cref="PushMockKeyPress"/> to
/// simulate keyboard input.
/// </para>
/// </remarks>
/// <example>
/// <code>
/// // Simulate keyboard input
/// FakeConsole.PushMockKeyPress(new ConsoleKeyInfo('a', ConsoleKey.A, false, false, false));
/// FakeConsole.PushMockKeyPress(new ConsoleKeyInfo('\r', ConsoleKey.Enter, false, false, false));
///
/// // The input will be processed by FakeDriver when Application.Run or RunIteration is called
/// </code>
/// </example>
/// <seealso cref="FakeDriver"/>
/// <seealso cref="AutoInitShutdownAttribute"/>
public static class FakeConsole
{
#pragma warning restore RCS1138 // Add summary to documentation comment.

View File

@@ -10,7 +10,41 @@ using System.Runtime.InteropServices;
namespace Terminal.Gui.Drivers;
/// <summary>Implements a mock IConsoleDriver for unit testing</summary>
/// <summary>
/// Implements a mock <see cref="IConsoleDriver"/> for unit testing. This driver simulates console behavior
/// without requiring a real terminal, allowing for deterministic testing of Terminal.Gui applications.
/// </summary>
/// <remarks>
/// <para>
/// <see cref="FakeDriver"/> extends the legacy <see cref="ConsoleDriver"/> base class and is designed
/// for backward compatibility with existing tests. It provides programmatic control over console state,
/// including screen size, keyboard input, and output verification.
/// </para>
/// <para>
/// <strong>Key Features:</strong>
/// </para>
/// <list type="bullet">
/// <item>Programmatic screen resizing via <see cref="SetBufferSize"/> and <see cref="SetWindowSize"/></item>
/// <item>Keyboard input simulation via <see cref="FakeConsole.PushMockKeyPress"/></item>
/// <item>Mouse input simulation via <see cref="FakeConsole"/> methods</item>
/// <item>Output verification via <see cref="ConsoleDriver.Contents"/> buffer inspection</item>
/// <item>Event firing for resize, keyboard, and mouse events</item>
/// </list>
/// <para>
/// <strong>Usage:</strong> Most tests should use <see cref="AutoInitShutdownAttribute"/> which automatically
/// initializes Application with FakeDriver. For more control, create and configure FakeDriver instances directly.
/// </para>
/// <para>
/// <strong>Thread Safety:</strong> FakeDriver is not thread-safe. Tests using this driver should not run
/// in parallel with other tests that access driver state.
/// </para>
/// <para>
/// For detailed usage examples and patterns, see the README.md file in this directory.
/// </para>
/// </remarks>
/// <seealso cref="AutoInitShutdownAttribute"/>
/// <seealso cref="FakeConsole"/>
/// <seealso cref="FakeComponentFactory"/>
public class FakeDriver : ConsoleDriver
{
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member

View File

@@ -0,0 +1,205 @@
# FakeDriver Testing Guide
## Overview
Terminal.Gui provides testing infrastructure through two complementary driver implementations:
1. **FakeDriver** (this directory) - Legacy ConsoleDriver-based fake driver for backward compatibility
2. **FakeConsoleDriver** (in TerminalGuiFluentTesting) - Modern component-based fake driver for fluent testing
## FakeDriver Architecture
`FakeDriver` extends the abstract `ConsoleDriver` base class and is designed for:
- Backward compatibility with existing tests
- Use with `AutoInitShutdownAttribute` in traditional unit tests
- Direct driver manipulation and state inspection
### Key Components
- **FakeDriver.cs** - Main driver implementation
- **FakeConsole.cs** - Static mock console for input/output simulation
- **FakeComponentFactory.cs** - Component factory for modern initialization path
- **FakeConsoleInput.cs** - Input simulation
- **FakeConsoleOutput.cs** - Output capture and validation
- **FakeWindowSizeMonitor.cs** - Window resize simulation
## Usage Patterns
### Basic Test Setup
```csharp
[Fact]
[AutoInitShutdown] // Automatically initializes and shuts down Application
public void My_Test()
{
// Application is already initialized with FakeDriver
Assert.NotNull(Application.Driver);
Assert.True(Application.Initialized);
}
```
### Simulating Screen Resizes
```csharp
[Fact]
[AutoInitShutdown]
public void Test_Resize_Behavior()
{
// Start with default size (80x25)
Assert.Equal(80, Application.Driver.Cols);
Assert.Equal(25, Application.Driver.Rows);
// Simulate a terminal resize
AutoInitShutdownAttribute.FakeResize(new Size(120, 40));
// Verify the resize took effect
Assert.Equal(120, Application.Driver.Cols);
Assert.Equal(40, Application.Driver.Rows);
Assert.Equal(new Rectangle(0, 0, 120, 40), Application.Screen);
}
```
### Subscribing to Resize Events
```csharp
[Fact]
[AutoInitShutdown]
public void Test_Resize_Events()
{
bool eventFired = false;
Size? newSize = null;
Application.Driver.SizeChanged += (sender, args) =>
{
eventFired = true;
newSize = args.Size;
};
AutoInitShutdownAttribute.FakeResize(new Size(100, 30));
Assert.True(eventFired);
Assert.Equal(100, newSize.Value.Width);
Assert.Equal(30, newSize.Value.Height);
}
```
### Simulating Keyboard Input
```csharp
[Fact]
[AutoInitShutdown]
public void Test_Keyboard_Input()
{
// Queue keyboard input before it's processed
FakeConsole.PushMockKeyPress(new ConsoleKeyInfo('a', ConsoleKey.A, false, false, false));
FakeConsole.PushMockKeyPress(new ConsoleKeyInfo('\r', ConsoleKey.Enter, false, false, false));
// Your test logic that processes the input
// ...
}
```
### Verifying Screen Output
```csharp
[Fact]
[AutoInitShutdown]
public void Test_Screen_Output()
{
Application.Top = new Toplevel();
var label = new Label { Text = "Hello", X = 0, Y = 0 };
Application.Top.Add(label);
Application.Begin(Application.Top);
AutoInitShutdownAttribute.RunIteration();
// Access driver contents to verify output
var contents = Application.Driver.Contents;
Assert.NotNull(contents);
// Verify specific characters were drawn
// contents[row, col] gives you access to individual cells
}
```
## Relationship Between Driver Properties
Understanding the relationship between key driver properties:
- **Screen** - `Rectangle` representing the full console area. Always starts at (0,0) with size (Cols, Rows).
- **Cols** - Number of columns (width) in the console.
- **Rows** - Number of rows (height) in the console.
- **Contents** - 2D array `[rows, cols]` containing the actual screen buffer cells.
When you resize:
1. `SetBufferSize(width, height)` or `FakeResize(Size)` is called
2. `Cols` and `Rows` are updated
3. `Contents` buffer is reallocated to match new dimensions
4. `Screen` property returns updated rectangle
5. `SizeChanged` event fires with new size
6. Application propagates resize to top-level views
## Thread Safety
⚠️ **Important**: FakeDriver is **not thread-safe**. Tests that use FakeDriver should:
- Not run in parallel with other tests that access the driver
- Not share driver state between test methods
- Use `AutoInitShutdownAttribute` to ensure clean initialization/shutdown per test
For parallel-safe tests, use the UnitTestsParallelizable project with its own test infrastructure.
## Differences from Production Drivers
FakeDriver differs from production drivers (WindowsDriver, UnixDriver, DotNetDriver) in several ways:
| Aspect | FakeDriver | Production Drivers |
|--------|------------|-------------------|
| Screen Size | Programmatically set via `SetBufferSize` | Determined by actual terminal size |
| Input | Queued via `FakeConsole.PushMockKeyPress` | Reads from actual stdin |
| Output | Captured in memory buffer | Written to actual terminal |
| Resize | Triggered by test code | Triggered by OS (SIGWINCH, WINDOW_BUFFER_SIZE_EVENT) |
| Buffer vs Window | Always equal (no scrollback) | Can differ (scrollback support) |
## Advanced: Direct Driver Access
For tests that need more control, you can access the driver directly:
```csharp
[Fact]
public void Test_With_Direct_Driver_Access()
{
// Create and initialize driver manually
Application.ResetState(true);
var driver = new FakeDriver();
Application.Driver = driver;
Application.SubscribeDriverEvents();
// Use driver directly
driver.SetBufferSize(100, 50);
Assert.Equal(100, driver.Cols);
Assert.Equal(50, driver.Rows);
// Cleanup
Application.ResetState(true);
}
```
## Modern Component-Based Architecture
For new test infrastructure, consider using the modern component factory approach via `FakeComponentFactory`:
```csharp
var factory = new FakeComponentFactory();
// Modern driver initialization through component factory pattern
// This is used internally by the fluent testing infrastructure
```
The fluent testing project (`TerminalGuiFluentTesting`) provides a higher-level API built on this architecture.
## See Also
- **AutoInitShutdownAttribute** - Attribute for automatic test setup/teardown
- **TerminalGuiFluentTesting** - Modern fluent testing infrastructure
- **FakeConsole** - Static mock console used by FakeDriver
- **ConsoleDriver** - Base class documentation for all drivers