mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 07:47:54 +01:00
Add comprehensive documentation for FakeDriver testing infrastructure
Co-authored-by: tig <585482+tig@users.noreply.github.com>
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
205
Terminal.Gui/Drivers/FakeDriver/README.md
Normal file
205
Terminal.Gui/Drivers/FakeDriver/README.md
Normal 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
|
||||
Reference in New Issue
Block a user