Selaa lähdekoodia

Add comprehensive documentation for FakeDriver testing infrastructure

Co-authored-by: tig <[email protected]>
copilot-swe-agent[bot] 1 kuukausi sitten
vanhempi
sitoutus
0132aebd77

+ 42 - 1
Terminal.Gui/Drivers/FakeDriver/FakeConsole.cs

@@ -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.

+ 35 - 1
Terminal.Gui/Drivers/FakeDriver/FakeDriver.cs

@@ -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 - 0
Terminal.Gui/Drivers/FakeDriver/README.md

@@ -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