mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2026-01-01 00:46:39 +01:00
* Add comprehensive unit tests for WindowsKeyConverter - Implement 118 parallelizable unit tests for WindowsKeyConverter - Cover ToKey and ToKeyInfo methods with full bidirectional testing - Test basic characters, modifiers, special keys, function keys - Test VK_PACKET Unicode/IME input - Test OEM keys, NumPad keys, and lock states - Include round-trip conversion tests - All tests passing successfully Fixes #4389 * Add test documenting VK_PACKET surrogate pair limitation VK_PACKET sends surrogate pairs (e.g., emoji) as two separate events. Current WindowsKeyConverter processes each independently without combining. Test documents this limitation for future fix at InputProcessor level. * Mark WindowsKeyConverterTests as Windows-only Tests now skip on non-Windows platforms using SkipException in constructor. This prevents CI failures on macOS and Linux where Windows Console API is not available. * Properly mark WindowsKeyConverter tests as Windows-only Created custom xUnit attributes SkipOnNonWindowsFact and SkipOnNonWindowsTheory that automatically skip tests on non-Windows platforms. This prevents CI failures on macOS and Linux. * Refactor and enhance test coverage for input processors Refactored `ApplicationImpl.cs` to simplify its structure by removing the `_stopAfterFirstIteration` field. Reintroduced and modernized test files with improved structure and coverage: - `NetInputProcessorTests.cs`: Added tests for `ConsoleKeyInfo` to `Rune`/`Key` conversion and queue processing. - `WindowSizeMonitorTests.cs`: Added tests for size change event handling. - `WindowsInputProcessorTests.cs`: Added tests for keyboard and mouse input processing, including mouse flag mapping. - `WindowsKeyConverterTests.cs`: Added comprehensive tests for `InputRecord` to `Key` conversion, covering OEM keys, modifiers, Unicode, and round-trip integrity. Improved test coverage for edge cases, introduced parameterized tests, and documented known limitations for future improvements. * Use Trait-based platform filtering for WindowsKeyConverter tests Added [Trait('Platform', 'Windows')] and [Collection('Global Test Setup')] attributes. Tests will run on Windows but can be filtered in CI on other platforms using --filter 'Platform!=Windows' if needed. This approach doesn't interfere with GlobalTestSetup and works correctly with xUnit. * Filter Windows-specific tests on non-Windows CI platforms Added --filter 'Platform!=Windows' for Linux and macOS runners to exclude WindowsKeyConverterTests which require Windows Console APIs. Windows runner runs all tests normally. * Fix log path typo and remove Codecov upload step Corrected a typo in the log directory path from `logs/UnitTestsParallelable/` to `logs/UnitTestsParallelizable/`. Removed the "Upload Parallelizable UnitTests Coverage to Codecov" step, which was conditional on `matrix.os == 'ubuntu-latest'` and used the `codecov/codecov-action@v4` action. This change improves log handling and removes the Codecov integration. * Refactor application reset logic Replaced `Application.ResetState(true)` with a more explicit reset mechanism. Introduced `ApplicationImpl.SetInstance(null)` to clear the application instance and added `CM.Disable(true)` to disable specific components. This change improves control over the reset process and ensures a more granular approach to application state management. * Improve null safety with ?. and ! operators Enhanced null safety across the codebase by introducing the null-conditional operator (`?.`) and null-forgiving operator (`!`) where appropriate. - Updated `app` and `driver` method calls to use `?.` to prevent potential `NullReferenceException` errors. - Added `!` to assert non-nullability in cases like `e.Value!.ToString()` and `app.Driver?.Contents!`. - Modified `lv.SelectedItemChanged` event handler to ensure safe handling of nullable values. - Updated `app.Shutdown()`, `app.LayoutAndDraw()`, and mouse event handling to use `?.`. - Ensured `driver.SetScreenSize` is invoked only when `driver` is not null. - Improved string concatenation logic with null-forgiving operator for `Contents`. - General improvements to null safety to make the code more robust and resilient to null references. * Improve Unicode tests and clarify surrogate pair handling Updated `WindowsKeyConverterTests` to enhance readability, improve test data, and clarify comments. Key changes include: - Reformatted `[Collection]` and `[Trait]` attributes for consistency. - Replaced placeholder Unicode characters with meaningful examples: - Chinese: `中`, Japanese: `日`, Korean: `한`, Accented: `é`, Euro: `€`, Greek: `Ω`. - Updated comments to replace placeholder emojis (`??`) with `😀` (U+1F600) for clarity. - Adjusted surrogate pair test data to accurately reflect `😀`. - Improved documentation of current limitations and future fixes for surrogate pair handling. These changes ensure more accurate and meaningful test cases while improving code clarity. * Ensure platform-specific test execution on Windows Added `System.Runtime.InteropServices` and `Xunit.Sdk` namespaces to `WindowsKeyConverterTests.cs` to support platform checks and test setup. Marked the test class with `[Collection("Global Test Setup")]` to enable shared test setup. Updated the `ToKey_NumPadKeys_ReturnsExpectedKeyCode` method to include a platform check, ensuring the test only runs on Windows platforms. * Integrate TrueColor support into ColorPicker Merged TrueColors functionality into ColorPicker, enhancing the scenario with TrueColor demonstration and gradient features. Updated `ColorPicker.cs` to include driver information, TrueColor support indicators, and a toggle for `Force16Colors`. Removed `TrueColors.cs` as its functionality is now consolidated. Refined `ColorBar` to use dynamic height with `Dim.Auto` for better flexibility. Added documentation to `HueBar` to clarify its role in representing the Hue component in HSL color space. * Revert workflow change. * Reverted attribute that didn't actualy work.
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Text;
|
||||
|
||||
namespace UnitTests_Parallelizable.DriverTests;
|
||||
|
||||
public class NetInputProcessorTests
|
||||
{
|
||||
public static IEnumerable<object []> GetConsoleKeyInfoToKeyTestCases_Rune ()
|
||||
{
|
||||
yield return [new ConsoleKeyInfo ('C', ConsoleKey.None, false, false, false), new Rune ('C')];
|
||||
yield return [new ConsoleKeyInfo ('\\', ConsoleKey.Oem5, false, false, false), new Rune ('\\')];
|
||||
yield return [new ConsoleKeyInfo ('+', ConsoleKey.OemPlus, true, false, false), new Rune ('+')];
|
||||
yield return [new ConsoleKeyInfo ('=', ConsoleKey.OemPlus, false, false, false), new Rune ('=')];
|
||||
yield return new object [] { new ConsoleKeyInfo ('_', ConsoleKey.OemMinus, true, false, false), new Rune ('_') };
|
||||
yield return new object [] { new ConsoleKeyInfo ('-', ConsoleKey.OemMinus, false, false, false), new Rune ('-') };
|
||||
yield return new object [] { new ConsoleKeyInfo (')', ConsoleKey.None, false, false, false), new Rune (')') };
|
||||
yield return new object [] { new ConsoleKeyInfo ('0', ConsoleKey.None, false, false, false), new Rune ('0') };
|
||||
yield return new object [] { new ConsoleKeyInfo ('(', ConsoleKey.None, false, false, false), new Rune ('(') };
|
||||
yield return new object [] { new ConsoleKeyInfo ('9', ConsoleKey.None, false, false, false), new Rune ('9') };
|
||||
yield return new object [] { new ConsoleKeyInfo ('*', ConsoleKey.None, false, false, false), new Rune ('*') };
|
||||
yield return new object [] { new ConsoleKeyInfo ('8', ConsoleKey.None, false, false, false), new Rune ('8') };
|
||||
yield return new object [] { new ConsoleKeyInfo ('&', ConsoleKey.None, false, false, false), new Rune ('&') };
|
||||
yield return new object [] { new ConsoleKeyInfo ('7', ConsoleKey.None, false, false, false), new Rune ('7') };
|
||||
yield return new object [] { new ConsoleKeyInfo ('^', ConsoleKey.None, false, false, false), new Rune ('^') };
|
||||
yield return new object [] { new ConsoleKeyInfo ('6', ConsoleKey.None, false, false, false), new Rune ('6') };
|
||||
yield return new object [] { new ConsoleKeyInfo ('%', ConsoleKey.None, false, false, false), new Rune ('%') };
|
||||
yield return new object [] { new ConsoleKeyInfo ('5', ConsoleKey.None, false, false, false), new Rune ('5') };
|
||||
yield return new object [] { new ConsoleKeyInfo ('$', ConsoleKey.None, false, false, false), new Rune ('$') };
|
||||
yield return new object [] { new ConsoleKeyInfo ('4', ConsoleKey.None, false, false, false), new Rune ('4') };
|
||||
yield return new object [] { new ConsoleKeyInfo ('#', ConsoleKey.None, false, false, false), new Rune ('#') };
|
||||
yield return new object [] { new ConsoleKeyInfo ('@', ConsoleKey.None, false, false, false), new Rune ('@') };
|
||||
yield return new object [] { new ConsoleKeyInfo ('2', ConsoleKey.None, false, false, false), new Rune ('2') };
|
||||
yield return new object [] { new ConsoleKeyInfo ('!', ConsoleKey.None, false, false, false), new Rune ('!') };
|
||||
yield return new object [] { new ConsoleKeyInfo ('1', ConsoleKey.None, false, false, false), new Rune ('1') };
|
||||
yield return new object [] { new ConsoleKeyInfo ('\t', ConsoleKey.None, false, false, false), new Rune ('\t') };
|
||||
yield return new object [] { new ConsoleKeyInfo ('}', ConsoleKey.Oem6, true, false, false), new Rune ('}') };
|
||||
yield return new object [] { new ConsoleKeyInfo (']', ConsoleKey.Oem6, false, false, false), new Rune (']') };
|
||||
yield return new object [] { new ConsoleKeyInfo ('{', ConsoleKey.Oem4, true, false, false), new Rune ('{') };
|
||||
yield return new object [] { new ConsoleKeyInfo ('[', ConsoleKey.Oem4, false, false, false), new Rune ('[') };
|
||||
yield return new object [] { new ConsoleKeyInfo ('\"', ConsoleKey.Oem7, true, false, false), new Rune ('\"') };
|
||||
yield return new object [] { new ConsoleKeyInfo ('\'', ConsoleKey.Oem7, false, false, false), new Rune ('\'') };
|
||||
yield return new object [] { new ConsoleKeyInfo (':', ConsoleKey.Oem1, true, false, false), new Rune (':') };
|
||||
yield return new object [] { new ConsoleKeyInfo (';', ConsoleKey.Oem1, false, false, false), new Rune (';') };
|
||||
yield return new object [] { new ConsoleKeyInfo ('?', ConsoleKey.Oem2, true, false, false), new Rune ('?') };
|
||||
yield return new object [] { new ConsoleKeyInfo ('/', ConsoleKey.Oem2, false, false, false), new Rune ('/') };
|
||||
yield return new object [] { new ConsoleKeyInfo ('>', ConsoleKey.OemPeriod, true, false, false), new Rune ('>') };
|
||||
yield return new object [] { new ConsoleKeyInfo ('.', ConsoleKey.OemPeriod, false, false, false), new Rune ('.') };
|
||||
yield return new object [] { new ConsoleKeyInfo ('<', ConsoleKey.OemComma, true, false, false), new Rune ('<') };
|
||||
yield return new object [] { new ConsoleKeyInfo (',', ConsoleKey.OemComma, false, false, false), new Rune (',') };
|
||||
yield return new object [] { new ConsoleKeyInfo ('w', ConsoleKey.None, false, false, false), new Rune ('w') };
|
||||
yield return new object [] { new ConsoleKeyInfo ('e', ConsoleKey.None, false, false, false), new Rune ('e') };
|
||||
yield return new object [] { new ConsoleKeyInfo ('a', ConsoleKey.None, false, false, false), new Rune ('a') };
|
||||
yield return new object [] { new ConsoleKeyInfo ('s', ConsoleKey.None, false, false, false), new Rune ('s') };
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData (nameof (GetConsoleKeyInfoToKeyTestCases_Rune))]
|
||||
public void ConsoleKeyInfoToKey_ValidInput_AsRune (ConsoleKeyInfo input, Rune expected)
|
||||
{
|
||||
var converter = new NetKeyConverter ();
|
||||
|
||||
// Act
|
||||
var result = converter.ToKey (input);
|
||||
|
||||
// Assert
|
||||
Assert.Equal (expected, result.AsRune);
|
||||
}
|
||||
|
||||
public static IEnumerable<object []> GetConsoleKeyInfoToKeyTestCases_Key ()
|
||||
{
|
||||
yield return new object [] { new ConsoleKeyInfo ('\t', ConsoleKey.None, false, false, false), Key.Tab };
|
||||
yield return new object [] { new ConsoleKeyInfo ('\u001B', ConsoleKey.None, false, false, false), Key.Esc };
|
||||
yield return new object [] { new ConsoleKeyInfo ('\u007f', ConsoleKey.None, false, false, false), Key.Backspace };
|
||||
|
||||
// TODO: Terminal.Gui does not have a Key for this mapped
|
||||
// TODO: null and default(Key) are both not same as Null. Why user has to do (Key)0 to get a null key?!
|
||||
yield return new object [] { new ConsoleKeyInfo ('\0', ConsoleKey.LeftWindows, false, false, false), (Key)0 };
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData (nameof (GetConsoleKeyInfoToKeyTestCases_Key))]
|
||||
public void ConsoleKeyInfoToKey_ValidInput_AsKey (ConsoleKeyInfo input, Key expected)
|
||||
{
|
||||
var converter = new NetKeyConverter ();
|
||||
|
||||
// Act
|
||||
var result = converter.ToKey (input);
|
||||
|
||||
// Assert
|
||||
Assert.Equal (expected, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Test_ProcessQueue_CapitalHLowerE ()
|
||||
{
|
||||
ConcurrentQueue<ConsoleKeyInfo> queue = new ();
|
||||
|
||||
queue.Enqueue (new ('H', ConsoleKey.None, true, false, false));
|
||||
queue.Enqueue (new ('e', ConsoleKey.None, false, false, false));
|
||||
|
||||
var processor = new NetInputProcessor (queue);
|
||||
|
||||
List<Key> ups = new ();
|
||||
List<Key> downs = new ();
|
||||
|
||||
processor.KeyUp += (s, e) => { ups.Add (e); };
|
||||
processor.KeyDown += (s, e) => { downs.Add (e); };
|
||||
|
||||
Assert.Empty (ups);
|
||||
Assert.Empty (downs);
|
||||
|
||||
processor.ProcessQueue ();
|
||||
|
||||
Assert.Equal (Key.H.WithShift, ups [0]);
|
||||
Assert.Equal (Key.H.WithShift, downs [0]);
|
||||
Assert.Equal (Key.E, ups [1]);
|
||||
Assert.Equal (Key.E, downs [1]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user