mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 15:57:56 +01:00
Fixes #4289 - Simplify Drawing/Color: unify named color handling under StandardColor and remove layered resolvers (#4432)
* Initial plan * Delete AnsiColorNameResolver and MultiStandardColorNameResolver, add legacy 16-color names to StandardColor Co-authored-by: tig <585482+tig@users.noreply.github.com> * Refactor and enhance tests for Color, Region, and Lines Refactored `Color` struct by removing unused methods and simplifying logic. Updated namespaces for better organization. Enhanced test coverage for `Color`, `Region`, and `LineCanvas` with new test cases, parameterized tests, and edge case handling. Added `StraightLineExtensionsTests`, `StraightLineTests`, and `RegionClassTests` to validate behavior under various scenarios. Improved `MergeRectangles` stability and addressed crash patterns. Removed legacy features and unused code. Enhanced documentation and optimized performance in key methods. * Improve Color struct and StandardColors functionality Enhanced the Color struct to fully support the alpha channel for rendering intent while maintaining semantic color identity. Updated TryNameColor to ignore alpha when matching colors, ensuring transparency does not affect color resolution. Expanded XML documentation to clarify alpha channel usage and future alpha blending support. Improved drawing documentation to explain the lifecycle, deferred rendering, and color support, including 24-bit true color and legacy 16-color compatibility. Added a new section on transparency and its role in rendering. Revised StandardColors implementation to use modern C# features and ensure consistent ARGB mapping. Added comprehensive tests for StandardColors and Color, covering alpha handling, color parsing, thread safety, and aliased color resolution. Removed outdated tests relying on legacy behavior. Enhanced code readability, maintainability, and test coverage to ensure correctness and backward compatibility. * Code cleanup * Code cleanup * Fix warnings. Code cleanup * Add comprehensive unit tests for ColorStrings class Introduced a new test class `ColorStringsTests` under the `DrawingTests.ColorTests` namespace to validate the functionality of the `ColorStrings` class. Key changes include: - Added tests for `GetColorName` to verify behavior for standard and non-standard colors, ignoring alpha channels, and handling known colors. - Added tests for `GetStandardColorNames` to ensure the method returns a non-empty, alphabetically sorted collection containing all `StandardColor` enum values. - Implemented tests for `TryParseStandardColorName` to validate case-insensitive parsing, hex color support, handling invalid input, and `ReadOnlySpan<char>` compatibility. - Added tests for `TryParseNamedColor` to verify parsing of named and hex colors, handling of aliases, and `ReadOnlySpan<char>` support. - Added round-trip tests to ensure consistency between `GetColorName`, `TryParseNamedColor`, `GetStandardColorNames`, and `TryParseStandardColorName`. These tests ensure robust validation of color parsing and naming functionality. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: tig <585482+tig@users.noreply.github.com> Co-authored-by: Tig <tig@users.noreply.github.com>
This commit is contained in:
@@ -9,7 +9,7 @@ namespace ApplicationTests.Timeout;
|
||||
/// These tests verify that timeouts fire correctly, can be added/removed,
|
||||
/// handle exceptions properly, and work with Application.Run() calls.
|
||||
/// </summary>
|
||||
public class TimeoutTests (ITestOutputHelper output)
|
||||
public class TimeoutTests
|
||||
{
|
||||
[Fact]
|
||||
public void AddTimeout_Callback_Can_Add_New_Timeout ()
|
||||
|
||||
@@ -52,7 +52,7 @@ public class ColorJsonConverterTests
|
||||
[InlineData (ColorName16.Red, "Red")]
|
||||
[InlineData (ColorName16.Magenta, "Fuchsia")] // W3C+ Standard overrides
|
||||
[InlineData (ColorName16.Yellow, "Yellow")]
|
||||
[InlineData (ColorName16.DarkGray, "DarkGray")]
|
||||
[InlineData (ColorName16.DarkGray, "BrightBlack")] // Legacy ColorName16.DarkGray now serializes as BrightBlack (first alphabetical match)
|
||||
[InlineData (ColorName16.BrightBlue, "BrightBlue")]
|
||||
[InlineData (ColorName16.BrightGreen, "BrightGreen")]
|
||||
[InlineData (ColorName16.BrightCyan, "BrightCyan")]
|
||||
@@ -98,7 +98,7 @@ public class ColorJsonConverterTests
|
||||
[InlineData ("BrightYellow", Color.BrightYellow)]
|
||||
[InlineData ("Yellow", Color.Yellow)]
|
||||
[InlineData ("Cyan", Color.Cyan)]
|
||||
[InlineData ("DarkGray", Color.DarkGray)]
|
||||
[InlineData ("BrightBlack", Color.DarkGray)] // Legacy ColorName16.DarkGray is now accessible as BrightBlack
|
||||
[InlineData ("Gray", Color.Gray)]
|
||||
[InlineData ("Green", Color.Green)]
|
||||
[InlineData ("Magenta", Color.Magenta)]
|
||||
@@ -113,7 +113,7 @@ public class ColorJsonConverterTests
|
||||
var actualColor = JsonSerializer.Deserialize<Color> (json, JsonOptions);
|
||||
|
||||
// Assert
|
||||
Assert.Equal (new Color (expectedColor), actualColor);
|
||||
Assert.Equal (new (expectedColor), actualColor);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -12,7 +12,7 @@ public class SourcesManagerTests
|
||||
// Arrange
|
||||
var sourcesManager = new SourcesManager ();
|
||||
var stream = new MemoryStream ();
|
||||
var source = "test.json";
|
||||
var source = "Load_WithNullSettingsScope_ReturnsFalse";
|
||||
var location = ConfigLocations.AppCurrent;
|
||||
|
||||
// Act
|
||||
@@ -37,7 +37,7 @@ public class SourcesManagerTests
|
||||
}
|
||||
""";
|
||||
var location = ConfigLocations.HardCoded;
|
||||
var source = "stream";
|
||||
var source = "Load_WithValidStream_UpdatesSettingsScope";
|
||||
|
||||
var stream = new MemoryStream ();
|
||||
var writer = new StreamWriter (stream);
|
||||
@@ -69,7 +69,7 @@ public class SourcesManagerTests
|
||||
writer.Flush ();
|
||||
stream.Position = 0;
|
||||
|
||||
var source = "test.json";
|
||||
var source = "Load_WithInvalidJson_AddsJsonError";
|
||||
var location = ConfigLocations.AppCurrent;
|
||||
|
||||
// Act
|
||||
@@ -180,7 +180,7 @@ public class SourcesManagerTests
|
||||
var sourcesManager = new SourcesManager ();
|
||||
|
||||
var settingsScope = new SettingsScope ();
|
||||
var source = "test.json";
|
||||
var source = "Load_WithNullOrEmptyJson_ReturnsFalse";
|
||||
var location = ConfigLocations.AppCurrent;
|
||||
|
||||
// Act
|
||||
@@ -206,7 +206,7 @@ public class SourcesManagerTests
|
||||
"Application.QuitKey": "Ctrl+Z"
|
||||
}
|
||||
""";
|
||||
var source = "test.json";
|
||||
var source = "Load_WithValidJson_UpdatesSettingsScope";
|
||||
var location = ConfigLocations.HardCoded;
|
||||
|
||||
// Act
|
||||
@@ -233,7 +233,7 @@ public class SourcesManagerTests
|
||||
// "Button.DefaultShadowStyle": "None"
|
||||
// }
|
||||
// """;
|
||||
// var source = "test.json";
|
||||
// var source = "Update_WithValidJson_UpdatesThemeScope";
|
||||
// var location = ConfigLocations.HardCoded;
|
||||
|
||||
// // Act
|
||||
|
||||
@@ -1,168 +0,0 @@
|
||||
#nullable enable
|
||||
|
||||
namespace DrawingTests;
|
||||
|
||||
public class AnsiColorNameResolverTests
|
||||
{
|
||||
private readonly AnsiColorNameResolver _candidate = new ();
|
||||
[Fact]
|
||||
public void TryNameColor_Resolves_All_ColorName16 ()
|
||||
{
|
||||
var resolver = new AnsiColorNameResolver ();
|
||||
|
||||
foreach (ColorName16 name in Enum.GetValues<ColorName16> ())
|
||||
{
|
||||
var color = new Color (name);
|
||||
bool success = resolver.TryNameColor (color, out string? resultName);
|
||||
|
||||
Assert.True (success, $"Expected TryNameColor to succeed for {name}");
|
||||
Assert.Equal (name.ToString (), resultName);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryParseColor_Resolves_All_ColorName16_Names ()
|
||||
{
|
||||
var resolver = new AnsiColorNameResolver ();
|
||||
|
||||
foreach (ColorName16 name in Enum.GetValues<ColorName16> ())
|
||||
{
|
||||
bool success = resolver.TryParseColor (name.ToString (), out Color parsed);
|
||||
|
||||
Assert.True (success, $"Expected TryParseColor to succeed for {name}");
|
||||
Assert.Equal (new Color (name), parsed);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<object []> AnsiColorName16NumericValues =>
|
||||
Enum.GetValues<ColorName16> ()
|
||||
.Select (e => new object [] { ((int)e).ToString () });
|
||||
[Theory]
|
||||
[MemberData (nameof (AnsiColorName16NumericValues))]
|
||||
public void TryParseColor_Accepts_Enum_UnderlyingNumbers (string numeric)
|
||||
{
|
||||
var resolver = new AnsiColorNameResolver ();
|
||||
|
||||
bool success = resolver.TryParseColor (numeric, out _);
|
||||
|
||||
Assert.True (success, $"Expected numeric enum value '{numeric}' to resolve successfully.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
[Fact]
|
||||
public void GetNames_Returns16ColorNames ()
|
||||
{
|
||||
string [] expected = Enum.GetNames<ColorName16> ();
|
||||
|
||||
string [] actual = _candidate.GetColorNames ().ToArray ();
|
||||
|
||||
Assert.Equal (expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData (0, 0, 0, nameof (ColorName16.Black))]
|
||||
[InlineData (0, 0, 255, nameof (ColorName16.Blue))]
|
||||
[InlineData (59, 120, 255, nameof (ColorName16.BrightBlue))]
|
||||
[InlineData (97, 214, 214, nameof (ColorName16.BrightCyan))]
|
||||
[InlineData (22, 198, 12, nameof (ColorName16.BrightGreen))]
|
||||
[InlineData (180, 0, 158, nameof (ColorName16.BrightMagenta))]
|
||||
[InlineData (231, 72, 86, nameof (ColorName16.BrightRed))]
|
||||
[InlineData (249, 241, 165, nameof (ColorName16.BrightYellow))]
|
||||
[InlineData (0, 255, 255, nameof (ColorName16.Cyan))]
|
||||
[InlineData (118, 118, 118, nameof (ColorName16.DarkGray))]
|
||||
[InlineData (128, 128, 128, nameof (ColorName16.Gray))]
|
||||
[InlineData (0, 128, 0, nameof (ColorName16.Green))]
|
||||
[InlineData (255, 0, 255, nameof (ColorName16.Magenta))]
|
||||
[InlineData (255, 0, 0, nameof (ColorName16.Red))]
|
||||
[InlineData (255, 255, 255, nameof (ColorName16.White))]
|
||||
[InlineData (255, 255, 0, nameof (ColorName16.Yellow))]
|
||||
public void TryNameColor_ReturnsExpectedColorName (byte r, byte g, byte b, string expectedName)
|
||||
{
|
||||
var expected = (true, expectedName);
|
||||
|
||||
bool actualSuccess = _candidate.TryNameColor (new Color (r, g, b), out string? actualName);
|
||||
var actual = (actualSuccess, actualName);
|
||||
|
||||
Assert.Equal (expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryNameColor_NoMatchFails ()
|
||||
{
|
||||
(bool, string?) expected = (false, null);
|
||||
|
||||
bool actualSuccess = _candidate.TryNameColor (new Color (1, 2, 3), out string? actualName);
|
||||
var actual = (actualSuccess, actualName);
|
||||
|
||||
Assert.Equal (expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData (nameof (ColorName16.Black), 0, 0, 0)]
|
||||
[InlineData (nameof (ColorName16.Blue), 0, 0, 255)]
|
||||
[InlineData (nameof (ColorName16.BrightBlue), 59, 120, 255)]
|
||||
[InlineData (nameof (ColorName16.BrightCyan), 97, 214, 214)]
|
||||
[InlineData (nameof (ColorName16.BrightGreen), 22, 198, 12)]
|
||||
[InlineData (nameof (ColorName16.BrightMagenta), 180, 0, 158)]
|
||||
[InlineData (nameof (ColorName16.BrightRed), 231, 72, 86)]
|
||||
[InlineData (nameof (ColorName16.BrightYellow), 249, 241, 165)]
|
||||
[InlineData (nameof (ColorName16.Cyan), 0, 255, 255)]
|
||||
[InlineData (nameof (ColorName16.DarkGray), 118, 118, 118)]
|
||||
[InlineData (nameof (ColorName16.Gray), 128, 128, 128)]
|
||||
[InlineData (nameof (ColorName16.Green), 0, 128, 0)]
|
||||
[InlineData (nameof (ColorName16.Magenta), 255, 0, 255)]
|
||||
[InlineData (nameof (ColorName16.Red), 255, 0, 0)]
|
||||
[InlineData (nameof (ColorName16.White), 255, 255, 255)]
|
||||
[InlineData (nameof (ColorName16.Yellow), 255, 255, 0)]
|
||||
// Case-insensitive
|
||||
[InlineData ("BRIGHTBLUE", 59, 120, 255)]
|
||||
[InlineData ("brightblue", 59, 120, 255)]
|
||||
public void TryParseColor_ReturnsExpectedColor (string inputName, byte r, byte g, byte b)
|
||||
{
|
||||
var expected = (true, new Color (r, g, b));
|
||||
|
||||
bool actualSuccess = _candidate.TryParseColor (inputName, out Color actualColor);
|
||||
var actual = (actualSuccess, actualColor);
|
||||
|
||||
Assert.Equal (expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData ("12", 231, 72, 86)] // ColorName16.BrightRed
|
||||
public void TryParseColor_ResolvesValidEnumNumber (string inputName, byte r, byte g, byte b)
|
||||
{
|
||||
var expected = (true, new Color (r, g, b));
|
||||
|
||||
bool actualSuccess = _candidate.TryParseColor (inputName, out Color actualColor);
|
||||
var actual = (actualSuccess, actualColor);
|
||||
|
||||
Assert.Equal (expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData (null)]
|
||||
[InlineData ("")]
|
||||
[InlineData ("brightlight")]
|
||||
public void TryParseColor_FailsOnInvalidColorName (string? invalidName)
|
||||
{
|
||||
var expected = (false, default (Color));
|
||||
|
||||
bool actualSuccess = _candidate.TryParseColor (invalidName, out Color actualColor);
|
||||
var actual = (actualSuccess, actualColor);
|
||||
|
||||
Assert.Equal (expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData ("-12")]
|
||||
public void TryParseColor_FailsOnInvalidEnumNumber (string invalidName)
|
||||
{
|
||||
var expected = (false, default (Color));
|
||||
|
||||
bool actualSuccess = _candidate.TryParseColor (invalidName, out Color actualColor);
|
||||
var actual = (actualSuccess, actualColor);
|
||||
|
||||
Assert.Equal (expected, actual);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace DrawingTests;
|
||||
namespace DrawingTests.ColorTests;
|
||||
|
||||
public partial class ColorTests
|
||||
public partial class ColorClassTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_Empty_ReturnsColorWithZeroValue ()
|
||||
@@ -1,9 +1,9 @@
|
||||
using System.Numerics;
|
||||
using System.Reflection;
|
||||
|
||||
namespace DrawingTests;
|
||||
namespace DrawingTests.ColorTests;
|
||||
|
||||
public partial class ColorTests
|
||||
public partial class ColorClassTests
|
||||
{
|
||||
[Theory]
|
||||
[Trait ("Category", "Operators")]
|
||||
@@ -2,9 +2,9 @@
|
||||
using System.Buffers.Binary;
|
||||
using System.Globalization;
|
||||
|
||||
namespace DrawingTests;
|
||||
namespace DrawingTests.ColorTests;
|
||||
|
||||
public partial class ColorTests
|
||||
public partial class ColorClassTests
|
||||
{
|
||||
[Fact]
|
||||
public void Color_ToString_WithNamedColor ()
|
||||
@@ -1,9 +1,9 @@
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace DrawingTests;
|
||||
namespace DrawingTests.ColorTests;
|
||||
|
||||
public partial class ColorTests
|
||||
public partial class ColorClassTests
|
||||
{
|
||||
[Fact]
|
||||
[Trait ("Category", "Type Checks")]
|
||||
@@ -1,8 +1,7 @@
|
||||
#nullable enable
|
||||
|
||||
namespace DrawingTests.ColorTests;
|
||||
|
||||
namespace DrawingTests;
|
||||
|
||||
public partial class ColorTests
|
||||
public partial class ColorClassTests
|
||||
{
|
||||
[Theory]
|
||||
[CombinatorialData]
|
||||
@@ -1,27 +0,0 @@
|
||||
using Xunit;
|
||||
|
||||
namespace DrawingTests;
|
||||
|
||||
public class ColorStandardColorTests
|
||||
{
|
||||
[Fact]
|
||||
public void ToString_Returns_Standard_Name_For_StandardColor_CadetBlue()
|
||||
{
|
||||
// Without the fix, this uses Color(in StandardColor) -> this((int)colorName),
|
||||
// which sets A=0x00 and prevents name resolution (expects A=0xFF).
|
||||
var c = new Terminal.Gui.Drawing.Color(Terminal.Gui.Drawing.StandardColor.CadetBlue);
|
||||
|
||||
// Expected: named color
|
||||
Assert.Equal("CadetBlue", c.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToString_G_Prints_Opaque_ARGB_For_StandardColor_CadetBlue()
|
||||
{
|
||||
// Without the fix, A=0x00, so "G" prints "#005F9EA0" instead of "#FF5F9EA0".
|
||||
var c = new Terminal.Gui.Drawing.Color(Terminal.Gui.Drawing.StandardColor.CadetBlue);
|
||||
|
||||
// Expected: #AARRGGBB with A=FF (opaque)
|
||||
Assert.Equal("#FF5F9EA0", c.ToString("G", null));
|
||||
}
|
||||
}
|
||||
326
Tests/UnitTestsParallelizable/Drawing/Color/ColorStringsTests.cs
Normal file
326
Tests/UnitTestsParallelizable/Drawing/Color/ColorStringsTests.cs
Normal file
@@ -0,0 +1,326 @@
|
||||
namespace DrawingTests.ColorTests;
|
||||
public class ColorStringsTests
|
||||
{
|
||||
[Fact]
|
||||
public void GetColorName_ReturnsNameForStandardColor ()
|
||||
{
|
||||
Color red = new (255, 0);
|
||||
string? name = ColorStrings.GetColorName (red);
|
||||
|
||||
Assert.Equal ("Red", name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetColorName_ReturnsNullForNonStandardColor ()
|
||||
{
|
||||
Color custom = new (1, 2, 3);
|
||||
string? name = ColorStrings.GetColorName (custom);
|
||||
|
||||
Assert.Null (name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetColorName_IgnoresAlphaChannel ()
|
||||
{
|
||||
Color opaqueRed = new (255, 0, 0, 255);
|
||||
Color transparentRed = new (255, 0, 0, 128);
|
||||
Color fullyTransparentRed = new (255, 0, 0, 0);
|
||||
|
||||
string? name1 = ColorStrings.GetColorName (opaqueRed);
|
||||
string? name2 = ColorStrings.GetColorName (transparentRed);
|
||||
string? name3 = ColorStrings.GetColorName (fullyTransparentRed);
|
||||
|
||||
Assert.Equal ("Red", name1);
|
||||
Assert.Equal ("Red", name2);
|
||||
Assert.Equal ("Red", name3);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData (240, 248, 255, "AliceBlue")]
|
||||
[InlineData (0, 255, 255, "Aqua")]
|
||||
[InlineData (0, 0, 0, "Black")]
|
||||
[InlineData (0, 0, 255, "Blue")]
|
||||
[InlineData (0, 128, 0, "Green")]
|
||||
[InlineData (255, 0, 0, "Red")]
|
||||
[InlineData (255, 255, 255, "White")]
|
||||
[InlineData (255, 255, 0, "Yellow")]
|
||||
public void GetColorName_ReturnsCorrectNameForKnownColors (int r, int g, int b, string expectedName)
|
||||
{
|
||||
Color color = new (r, g, b);
|
||||
string? name = ColorStrings.GetColorName (color);
|
||||
|
||||
Assert.Equal (expectedName, name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetStandardColorNames_ReturnsNonEmptyCollection ()
|
||||
{
|
||||
IEnumerable<string> names = ColorStrings.GetStandardColorNames ();
|
||||
|
||||
Assert.NotNull (names);
|
||||
Assert.NotEmpty (names);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetStandardColorNames_ReturnsAlphabeticallySortedNames ()
|
||||
{
|
||||
IEnumerable<string> names = ColorStrings.GetStandardColorNames ();
|
||||
string [] namesArray = names.ToArray ();
|
||||
string [] sortedNames = namesArray.OrderBy (n => n).ToArray ();
|
||||
|
||||
Assert.Equal (sortedNames, namesArray);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetStandardColorNames_ContainsKnownColors ()
|
||||
{
|
||||
IEnumerable<string> names = ColorStrings.GetStandardColorNames ();
|
||||
string [] namesArray = names.ToArray ();
|
||||
|
||||
Assert.Contains ("Red", namesArray);
|
||||
Assert.Contains ("Green", namesArray);
|
||||
Assert.Contains ("Blue", namesArray);
|
||||
Assert.Contains ("White", namesArray);
|
||||
Assert.Contains ("Black", namesArray);
|
||||
Assert.Contains ("AliceBlue", namesArray);
|
||||
Assert.Contains ("Tomato", namesArray);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetStandardColorNames_ContainsAllStandardColorEnumValues ()
|
||||
{
|
||||
IEnumerable<string> names = ColorStrings.GetStandardColorNames ();
|
||||
string [] namesArray = names.ToArray ();
|
||||
string [] enumNames = Enum.GetNames<StandardColor> ();
|
||||
|
||||
// All enum names should be in the returned collection
|
||||
foreach (string enumName in enumNames)
|
||||
{
|
||||
Assert.Contains (enumName, namesArray);
|
||||
}
|
||||
|
||||
// The counts should match
|
||||
Assert.Equal (enumNames.Length, namesArray.Length);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData ("Red")]
|
||||
[InlineData ("red")]
|
||||
[InlineData ("RED")]
|
||||
[InlineData ("Green")]
|
||||
[InlineData ("green")]
|
||||
[InlineData ("Blue")]
|
||||
[InlineData ("AliceBlue")]
|
||||
[InlineData ("aliceblue")]
|
||||
[InlineData ("ALICEBLUE")]
|
||||
public void TryParseStandardColorName_ParsesValidColorNamesCaseInsensitively (string colorName)
|
||||
{
|
||||
bool result = ColorStrings.TryParseStandardColorName (colorName, out Color color);
|
||||
|
||||
Assert.True (result);
|
||||
Assert.NotEqual (default (Color), color);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData ("Red", 255, 0, 0)]
|
||||
[InlineData ("Green", 0, 128, 0)]
|
||||
[InlineData ("Blue", 0, 0, 255)]
|
||||
[InlineData ("White", 255, 255, 255)]
|
||||
[InlineData ("Black", 0, 0, 0)]
|
||||
[InlineData ("AliceBlue", 240, 248, 255)]
|
||||
[InlineData ("Tomato", 255, 99, 71)]
|
||||
public void TryParseStandardColorName_ParsesCorrectRgbValues (string colorName, int expectedR, int expectedG, int expectedB)
|
||||
{
|
||||
bool result = ColorStrings.TryParseStandardColorName (colorName, out Color color);
|
||||
|
||||
Assert.True (result);
|
||||
Assert.Equal (expectedR, color.R);
|
||||
Assert.Equal (expectedG, color.G);
|
||||
Assert.Equal (expectedB, color.B);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData ("#FF0000", 255, 0, 0)]
|
||||
[InlineData ("#00FF00", 0, 255, 0)]
|
||||
[InlineData ("#0000FF", 0, 0, 255)]
|
||||
[InlineData ("#FFFFFF", 255, 255, 255)]
|
||||
[InlineData ("#000000", 0, 0, 0)]
|
||||
[InlineData ("#F0F8FF", 240, 248, 255)]
|
||||
public void TryParseStandardColorName_ParsesHexColorFormat (string hexColor, int expectedR, int expectedG, int expectedB)
|
||||
{
|
||||
bool result = ColorStrings.TryParseStandardColorName (hexColor, out Color color);
|
||||
|
||||
Assert.True (result);
|
||||
Assert.Equal (expectedR, color.R);
|
||||
Assert.Equal (expectedG, color.G);
|
||||
Assert.Equal (expectedB, color.B);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData ("#ff0000")]
|
||||
[InlineData ("#FF0000")]
|
||||
[InlineData ("#Ff0000")]
|
||||
public void TryParseStandardColorName_ParsesHexColorCaseInsensitively (string hexColor)
|
||||
{
|
||||
bool result = ColorStrings.TryParseStandardColorName (hexColor, out Color color);
|
||||
|
||||
Assert.True (result);
|
||||
Assert.Equal (255, color.R);
|
||||
Assert.Equal (0, color.G);
|
||||
Assert.Equal (0, color.B);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData ("")]
|
||||
[InlineData ("NotAColor")]
|
||||
[InlineData ("Invalid")]
|
||||
[InlineData ("123")]
|
||||
[InlineData ("#FF")]
|
||||
[InlineData ("#FFFF")]
|
||||
[InlineData ("#FFFFFFFF")]
|
||||
[InlineData ("FF0000")]
|
||||
public void TryParseStandardColorName_ReturnsFalseForInvalidInput (string invalidInput)
|
||||
{
|
||||
bool result = ColorStrings.TryParseStandardColorName (invalidInput, out Color color);
|
||||
|
||||
Assert.False (result);
|
||||
Assert.Equal (default (Color), color);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryParseStandardColorName_SetsAlphaToFullyOpaque ()
|
||||
{
|
||||
bool result = ColorStrings.TryParseStandardColorName ("Red", out Color color);
|
||||
|
||||
Assert.True (result);
|
||||
Assert.Equal (255, color.A);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryParseStandardColorName_WorksWithReadOnlySpan ()
|
||||
{
|
||||
ReadOnlySpan<char> span = "Red".AsSpan ();
|
||||
bool result = ColorStrings.TryParseStandardColorName (span, out Color color);
|
||||
|
||||
Assert.True (result);
|
||||
Assert.Equal (255, color.R);
|
||||
Assert.Equal (0, color.G);
|
||||
Assert.Equal (0, color.B);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData ("Red")]
|
||||
[InlineData ("Green")]
|
||||
[InlineData ("Blue")]
|
||||
[InlineData ("AliceBlue")]
|
||||
[InlineData ("#FF0000")]
|
||||
public void TryParseNamedColor_ParsesValidColorNames (string colorName)
|
||||
{
|
||||
bool result = ColorStrings.TryParseNamedColor (colorName, out Color color);
|
||||
|
||||
Assert.True (result);
|
||||
Assert.NotEqual (default (Color), color);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData ("Red", 255, 0, 0)]
|
||||
[InlineData ("Green", 0, 128, 0)]
|
||||
[InlineData ("Blue", 0, 0, 255)]
|
||||
[InlineData ("#FF0000", 255, 0, 0)]
|
||||
[InlineData ("#00FF00", 0, 255, 0)]
|
||||
public void TryParseNamedColor_ParsesCorrectRgbValues (string colorName, int expectedR, int expectedG, int expectedB)
|
||||
{
|
||||
bool result = ColorStrings.TryParseNamedColor (colorName, out Color color);
|
||||
|
||||
Assert.True (result);
|
||||
Assert.Equal (expectedR, color.R);
|
||||
Assert.Equal (expectedG, color.G);
|
||||
Assert.Equal (expectedB, color.B);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData ("")]
|
||||
[InlineData ("NotAColor")]
|
||||
[InlineData ("Invalid")]
|
||||
[InlineData ("#ZZ0000")]
|
||||
public void TryParseNamedColor_ReturnsFalseForInvalidInput (string invalidInput)
|
||||
{
|
||||
bool result = ColorStrings.TryParseNamedColor (invalidInput, out Color color);
|
||||
|
||||
Assert.False (result);
|
||||
Assert.Equal (default (Color), color);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryParseNamedColor_WorksWithReadOnlySpan ()
|
||||
{
|
||||
ReadOnlySpan<char> span = "Blue".AsSpan ();
|
||||
bool result = ColorStrings.TryParseNamedColor (span, out Color color);
|
||||
|
||||
Assert.True (result);
|
||||
Assert.Equal (0, color.R);
|
||||
Assert.Equal (0, color.G);
|
||||
Assert.Equal (255, color.B);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData (nameof (StandardColor.Aqua), nameof (StandardColor.Cyan))]
|
||||
[InlineData (nameof (StandardColor.Fuchsia), nameof (StandardColor.Magenta))]
|
||||
public void TryParseNamedColor_HandlesColorAliases (string name1, string name2)
|
||||
{
|
||||
bool result1 = ColorStrings.TryParseNamedColor (name1, out Color color1);
|
||||
bool result2 = ColorStrings.TryParseNamedColor (name2, out Color color2);
|
||||
|
||||
Assert.True (result1);
|
||||
Assert.True (result2);
|
||||
Assert.Equal (color1.R, color2.R);
|
||||
Assert.Equal (color1.G, color2.G);
|
||||
Assert.Equal (color1.B, color2.B);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetColorName_And_TryParseNamedColor_RoundTrip ()
|
||||
{
|
||||
// Get a standard color name
|
||||
Color originalColor = new (255, 0);
|
||||
string? colorName = ColorStrings.GetColorName (originalColor);
|
||||
|
||||
Assert.NotNull (colorName);
|
||||
|
||||
// Parse it back
|
||||
bool result = ColorStrings.TryParseNamedColor (colorName, out Color parsedColor);
|
||||
|
||||
Assert.True (result);
|
||||
Assert.Equal (originalColor.R, parsedColor.R);
|
||||
Assert.Equal (originalColor.G, parsedColor.G);
|
||||
Assert.Equal (originalColor.B, parsedColor.B);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetStandardColorNames_And_TryParseStandardColorName_RoundTrip ()
|
||||
{
|
||||
// Get all standard color names
|
||||
IEnumerable<string> names = ColorStrings.GetStandardColorNames ();
|
||||
|
||||
// Each name should parse successfully
|
||||
foreach (string name in names)
|
||||
{
|
||||
bool result = ColorStrings.TryParseStandardColorName (name, out Color color);
|
||||
Assert.True (result, $"Failed to parse standard color name: {name}");
|
||||
|
||||
// And should get the same name back (for non-aliases)
|
||||
string? retrievedName = ColorStrings.GetColorName (color);
|
||||
Assert.NotNull (retrievedName);
|
||||
|
||||
// The retrieved name should be one of the valid names for this color
|
||||
// (could be different if there are aliases)
|
||||
Assert.True (
|
||||
ColorStrings.TryParseStandardColorName (retrievedName, out Color retrievedColor),
|
||||
$"Retrieved name '{retrievedName}' should be parseable"
|
||||
);
|
||||
Assert.Equal (color.R, retrievedColor.R);
|
||||
Assert.Equal (color.G, retrievedColor.G);
|
||||
Assert.Equal (color.B, retrievedColor.B);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
#nullable enable
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Xunit.Abstractions;
|
||||
using Terminal.Gui;
|
||||
|
||||
namespace DrawingTests;
|
||||
|
||||
public class MultiStandardColorNameResolverTests (ITestOutputHelper output)
|
||||
{
|
||||
private readonly MultiStandardColorNameResolver _candidate = new ();
|
||||
|
||||
public static IEnumerable<object []> StandardColors =>
|
||||
Enum.GetValues<StandardColor> ().Select (sc => new object [] { sc });
|
||||
|
||||
[Theory]
|
||||
[MemberData (nameof (StandardColors))]
|
||||
public void TryParseColor_ResolvesAllStandardColorNames (StandardColor standardColor)
|
||||
{
|
||||
string name = standardColor.ToString ();
|
||||
bool parsed = _candidate.TryParseColor (name, out Color actualColor);
|
||||
|
||||
Assert.True (parsed, $"TryParseColor should succeed for {name}");
|
||||
|
||||
Color expectedColor = new (Terminal.Gui.Drawing.StandardColors.GetArgb (standardColor));
|
||||
|
||||
Assert.Equal (expectedColor.R, actualColor.R);
|
||||
Assert.Equal (expectedColor.G, actualColor.G);
|
||||
Assert.Equal (expectedColor.B, actualColor.B);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData (nameof (StandardColors))]
|
||||
public void TryNameColor_ResolvesAllStandardColors (StandardColor standardColor)
|
||||
{
|
||||
Color color = new (Terminal.Gui.Drawing.StandardColors.GetArgb (standardColor));
|
||||
|
||||
bool success = _candidate.TryNameColor (color, out string? resolvedName);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
output.WriteLine ($"Unmapped: {standardColor} → {color}");
|
||||
}
|
||||
|
||||
Assert.True (success, $"TryNameColor should succeed for {standardColor}");
|
||||
|
||||
List<string> expectedNames = Enum.GetNames<StandardColor> ()
|
||||
.Where (name => Terminal.Gui.Drawing.StandardColors.GetArgb (Enum.Parse<StandardColor> (name)) == color.Argb)
|
||||
.ToList ();
|
||||
|
||||
Assert.Contains (resolvedName, expectedNames);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryNameColor_Logs_Unmapped_StandardColors ()
|
||||
{
|
||||
List<StandardColor> unmapped = new ();
|
||||
|
||||
foreach (StandardColor sc in Enum.GetValues<StandardColor> ())
|
||||
{
|
||||
Color color = new (Terminal.Gui.Drawing.StandardColors.GetArgb (sc));
|
||||
if (!_candidate.TryNameColor (color, out _))
|
||||
{
|
||||
unmapped.Add (sc);
|
||||
}
|
||||
}
|
||||
|
||||
output.WriteLine ("Unmapped StandardColor entries:");
|
||||
foreach (StandardColor sc in unmapped.Distinct ())
|
||||
{
|
||||
output.WriteLine ($"- {sc}");
|
||||
}
|
||||
|
||||
Assert.True (unmapped.Count < 10, $"Too many StandardColor values are not name-resolvable. Got {unmapped.Count}.");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData (nameof (ColorName16.Black))]
|
||||
[InlineData (nameof (ColorName16.White))]
|
||||
[InlineData (nameof (ColorName16.Red))]
|
||||
[InlineData (nameof (ColorName16.Green))]
|
||||
[InlineData (nameof (ColorName16.Blue))]
|
||||
[InlineData (nameof (ColorName16.Cyan))]
|
||||
[InlineData (nameof (ColorName16.Magenta))]
|
||||
[InlineData (nameof (ColorName16.DarkGray))]
|
||||
[InlineData (nameof (ColorName16.BrightGreen))]
|
||||
[InlineData (nameof (ColorName16.BrightMagenta))]
|
||||
[InlineData (nameof (StandardColor.AliceBlue))]
|
||||
[InlineData (nameof (StandardColor.BlanchedAlmond))]
|
||||
public void GetNames_ContainsKnownNames (string name)
|
||||
{
|
||||
string [] names = _candidate.GetColorNames ().ToArray ();
|
||||
Assert.Contains (name, names);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData (0, 0, 0, nameof (ColorName16.Black))]
|
||||
[InlineData (0, 0, 255, nameof (ColorName16.Blue))]
|
||||
[InlineData (59, 120, 255, nameof (ColorName16.BrightBlue))]
|
||||
[InlineData (255, 0, 0, nameof (ColorName16.Red))]
|
||||
[InlineData (255, 255, 255, nameof (ColorName16.White))]
|
||||
[InlineData (240, 248, 255, nameof (StandardColor.AliceBlue))]
|
||||
[InlineData (178, 34, 34, nameof (StandardColor.FireBrick))]
|
||||
[InlineData (245, 245, 245, nameof (StandardColor.WhiteSmoke))]
|
||||
public void TryNameColor_ReturnsExpectedColorNames (byte r, byte g, byte b, string expectedName)
|
||||
{
|
||||
Color color = new (r, g, b);
|
||||
bool actualSuccess = _candidate.TryNameColor (color, out string? actualName);
|
||||
|
||||
Assert.True (actualSuccess);
|
||||
Assert.Equal (expectedName, actualName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryNameColor_NoMatchFails ()
|
||||
{
|
||||
Color input = new (1, 2, 3);
|
||||
bool success = _candidate.TryNameColor (input, out string? actualName);
|
||||
Assert.False (success);
|
||||
Assert.Null (actualName);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData ("12", 231, 72, 86)] // ColorName16.BrightRed
|
||||
[InlineData ("16737095", 255, 99, 71)] // StandardColor.Tomato
|
||||
[InlineData ("#FF0000", 255, 0, 0)] // Red
|
||||
public void TryParseColor_ResolvesValidEnumNumber (string inputName, byte r, byte g, byte b)
|
||||
{
|
||||
bool success = _candidate.TryParseColor (inputName, out Color actualColor);
|
||||
Assert.True (success);
|
||||
Assert.Equal (r, actualColor.R);
|
||||
Assert.Equal (g, actualColor.G);
|
||||
Assert.Equal (b, actualColor.B);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData (null)]
|
||||
[InlineData ("")]
|
||||
[InlineData ("brightlight")]
|
||||
public void TryParseColor_FailsOnInvalidColorName (string? input)
|
||||
{
|
||||
bool success = _candidate.TryParseColor (input, out Color actualColor);
|
||||
Assert.False (success);
|
||||
Assert.Equal (default, actualColor);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData ("-12")]
|
||||
[InlineData ("-16737095")]
|
||||
public void TryParseColor_FailsOnInvalidEnumNumber (string input)
|
||||
{
|
||||
bool success = _candidate.TryParseColor (input, out Color actualColor);
|
||||
Assert.False (success);
|
||||
Assert.Equal (default, actualColor);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
#nullable enable
|
||||
using Xunit.Abstractions;
|
||||
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace DrawingTests;
|
||||
namespace DrawingTests.ColorTests;
|
||||
|
||||
public class StandardColorNameResolverTests (ITestOutputHelper output)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,268 @@
|
||||
#pragma warning disable xUnit1031
|
||||
|
||||
namespace DrawingTests.ColorTests;
|
||||
|
||||
public class StandardColorsTests
|
||||
{
|
||||
[Fact]
|
||||
public void GetArgb_HandlesAllStandardColorValues ()
|
||||
{
|
||||
foreach (StandardColor sc in Enum.GetValues<StandardColor> ())
|
||||
{
|
||||
uint argb = StandardColors.GetArgb (sc);
|
||||
|
||||
// Verify alpha is always 0xFF (fully opaque)
|
||||
var alpha = (byte)((argb >> 24) & 0xFF);
|
||||
Assert.Equal (255, alpha);
|
||||
|
||||
// Verify the RGB components match the enum value
|
||||
var enumRgb = (int)sc;
|
||||
uint expectedArgb = (uint)enumRgb | 0xFF000000;
|
||||
Assert.Equal (expectedArgb, argb);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData (StandardColor.Red, 255, 0, 0)]
|
||||
[InlineData (StandardColor.Green, 0, 128, 0)]
|
||||
[InlineData (StandardColor.Blue, 0, 0, 255)]
|
||||
[InlineData (StandardColor.White, 255, 255, 255)]
|
||||
[InlineData (StandardColor.Black, 0, 0, 0)]
|
||||
[InlineData (StandardColor.AliceBlue, 240, 248, 255)]
|
||||
[InlineData (StandardColor.YellowGreen, 154, 205, 50)]
|
||||
public void GetArgb_ReturnsCorrectArgbWithFullAlpha (StandardColor standardColor, byte r, byte g, byte b)
|
||||
{
|
||||
uint argb = StandardColors.GetArgb (standardColor);
|
||||
|
||||
var actualA = (byte)((argb >> 24) & 0xFF);
|
||||
var actualR = (byte)((argb >> 16) & 0xFF);
|
||||
var actualG = (byte)((argb >> 8) & 0xFF);
|
||||
var actualB = (byte)(argb & 0xFF);
|
||||
|
||||
Assert.Equal (255, actualA);
|
||||
Assert.Equal (r, actualR);
|
||||
Assert.Equal (g, actualG);
|
||||
Assert.Equal (b, actualB);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetColorNames_ContainsAllStandardColorEnumValues ()
|
||||
{
|
||||
string [] enumNames = Enum.GetNames<StandardColor> ().Order ().ToArray ();
|
||||
IReadOnlyList<string> colorNames = StandardColors.GetColorNames ();
|
||||
|
||||
Assert.Equal (enumNames.Length, colorNames.Count);
|
||||
Assert.Equal (enumNames, colorNames);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetColorNames_IsAlphabeticallySorted ()
|
||||
{
|
||||
IReadOnlyList<string> colorNames = StandardColors.GetColorNames ();
|
||||
string [] sortedNames = colorNames.OrderBy (n => n).ToArray ();
|
||||
|
||||
Assert.Equal (sortedNames, colorNames);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LazyInitialization_IsThreadSafe ()
|
||||
{
|
||||
// Force initialization by calling GetColorNames multiple times in parallel
|
||||
Task [] tasks = new Task [10];
|
||||
|
||||
for (var i = 0; i < tasks.Length; i++)
|
||||
{
|
||||
tasks [i] = Task.Run (() =>
|
||||
{
|
||||
IReadOnlyList<string> names = StandardColors.GetColorNames ();
|
||||
Assert.NotNull (names);
|
||||
Assert.NotEmpty (names);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
Task.WaitAll (tasks);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MapValueFactory_CreatesConsistentMapping ()
|
||||
{
|
||||
// Call TryNameColor multiple times for the same color
|
||||
var testColor = new Color (255, 0);
|
||||
|
||||
bool result1 = StandardColors.TryNameColor (testColor, out string? name1);
|
||||
bool result2 = StandardColors.TryNameColor (testColor, out string? name2);
|
||||
|
||||
Assert.True (result1);
|
||||
Assert.True (result2);
|
||||
Assert.Equal (name1, name2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToString_G_Prints_Opaque_ARGB_For_StandardColor_CadetBlue ()
|
||||
{
|
||||
// Without the fix, A=0x00, so "G" prints "#005F9EA0" instead of "#FF5F9EA0".
|
||||
var c = new Color (StandardColor.CadetBlue);
|
||||
|
||||
// Expected: #AARRGGBB with A=FF (opaque)
|
||||
Assert.Equal ("#FF5F9EA0", c.ToString ("G"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToString_Returns_Standard_Name_For_StandardColor_CadetBlue ()
|
||||
{
|
||||
// Without the fix, this uses Color(in StandardColor) -> this((int)colorName),
|
||||
// which sets A=0x00 and prevents name resolution (expects A=0xFF).
|
||||
var c = new Color (StandardColor.CadetBlue);
|
||||
|
||||
// Expected: named color
|
||||
Assert.Equal ("CadetBlue", c.ToString ());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryNameColor_IgnoresAlphaChannel ()
|
||||
{
|
||||
var opaqueRed = new Color (255, 0, 0, 255);
|
||||
var transparentRed = new Color (255, 0, 0, 128);
|
||||
|
||||
Assert.True (StandardColors.TryNameColor (opaqueRed, out string? name1));
|
||||
Assert.True (StandardColors.TryNameColor (transparentRed, out string? name2));
|
||||
|
||||
Assert.Equal (name1, name2);
|
||||
Assert.Equal ("Red", name1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryNameColor_ReturnsConsistentResultsForSameArgb ()
|
||||
{
|
||||
List<Color> colors = new ();
|
||||
|
||||
// Create multiple Color instances with the same ARGB values
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
colors.Add (new (255, 0));
|
||||
}
|
||||
|
||||
HashSet<string?> names = new ();
|
||||
|
||||
foreach (Color color in colors)
|
||||
{
|
||||
StandardColors.TryNameColor (color, out string? name);
|
||||
names.Add (name);
|
||||
}
|
||||
|
||||
// All should resolve to the same name
|
||||
Assert.Single (names);
|
||||
Assert.Equal ("Red", names.First ());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryNameColor_ReturnsFalseForUnknownColor ()
|
||||
{
|
||||
var unknownColor = new Color (1, 2, 3);
|
||||
bool result = StandardColors.TryNameColor (unknownColor, out string? name);
|
||||
|
||||
Assert.False (result);
|
||||
Assert.Null (name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryNameColor_ReturnsFirstAlphabeticalNameForAliasedColors ()
|
||||
{
|
||||
// Aqua and Cyan have the same RGB values
|
||||
var aqua = new Color (0, 255, 255);
|
||||
Assert.True (StandardColors.TryNameColor (aqua, out string? name));
|
||||
|
||||
// Should return the alphabetically first name
|
||||
Assert.Equal ("Aqua", name);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData (nameof (StandardColor.Aqua), nameof (StandardColor.Cyan))]
|
||||
[InlineData (nameof (StandardColor.Fuchsia), nameof (StandardColor.Magenta))]
|
||||
[InlineData (nameof (StandardColor.DarkGray), nameof (StandardColor.DarkGrey))]
|
||||
[InlineData (nameof (StandardColor.DarkSlateGray), nameof (StandardColor.DarkSlateGrey))]
|
||||
[InlineData (nameof (StandardColor.DimGray), nameof (StandardColor.DimGrey))]
|
||||
[InlineData (nameof (StandardColor.Gray), nameof (StandardColor.Grey))]
|
||||
[InlineData (nameof (StandardColor.LightGray), nameof (StandardColor.LightGrey))]
|
||||
[InlineData (nameof (StandardColor.LightSlateGray), nameof (StandardColor.LightSlateGrey))]
|
||||
[InlineData (nameof (StandardColor.SlateGray), nameof (StandardColor.SlateGrey))]
|
||||
public void TryParseColor_HandlesColorAliases (string name1, string name2)
|
||||
{
|
||||
Assert.True (StandardColors.TryParseColor (name1, out Color color1));
|
||||
Assert.True (StandardColors.TryParseColor (name2, out Color color2));
|
||||
|
||||
Assert.Equal (color1, color2);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData (StandardColor.AmberPhosphor, 255, 191, 0)]
|
||||
[InlineData (StandardColor.GreenPhosphor, 0, 255, 102)]
|
||||
[InlineData (StandardColor.GuppieGreen, 173, 255, 47)]
|
||||
public void TryParseColor_HandlesNonW3CColors (StandardColor color, byte r, byte g, byte b)
|
||||
{
|
||||
bool result = StandardColors.TryParseColor (color.ToString (), out Color parsedColor);
|
||||
|
||||
Assert.True (result);
|
||||
Assert.Equal (r, parsedColor.R);
|
||||
Assert.Equal (g, parsedColor.G);
|
||||
Assert.Equal (b, parsedColor.B);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryParseColor_IsCaseInsensitive ()
|
||||
{
|
||||
Assert.True (StandardColors.TryParseColor ("RED", out Color upperColor));
|
||||
Assert.True (StandardColors.TryParseColor ("red", out Color lowerColor));
|
||||
Assert.True (StandardColors.TryParseColor ("Red", out Color mixedColor));
|
||||
|
||||
Assert.Equal (upperColor, lowerColor);
|
||||
Assert.Equal (upperColor, mixedColor);
|
||||
Assert.Equal (255, upperColor.R);
|
||||
Assert.Equal (0, upperColor.G);
|
||||
Assert.Equal (0, upperColor.B);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData ("")]
|
||||
[InlineData ("NotAColor")]
|
||||
[InlineData ("123456")]
|
||||
[InlineData ("-1")]
|
||||
public void TryParseColor_ReturnsFalseForInvalidInput (string invalidInput)
|
||||
{
|
||||
bool result = StandardColors.TryParseColor (invalidInput, out Color color);
|
||||
|
||||
Assert.False (result);
|
||||
Assert.Equal (default (Color), color);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryParseColor_SetsAlphaToFullyOpaque ()
|
||||
{
|
||||
Assert.True (StandardColors.TryParseColor ("Red", out Color color));
|
||||
|
||||
Assert.Equal (255, color.A);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryParseColor_WithEmptySpan_ReturnsFalse ()
|
||||
{
|
||||
ReadOnlySpan<char> emptySpan = ReadOnlySpan<char>.Empty;
|
||||
bool result = StandardColors.TryParseColor (emptySpan, out Color color);
|
||||
|
||||
Assert.False (result);
|
||||
Assert.Equal (default (Color), color);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryParseColor_WithReadOnlySpan_WorksCorrectly ()
|
||||
{
|
||||
ReadOnlySpan<char> span = "Red".AsSpan ();
|
||||
bool result = StandardColors.TryParseColor (span, out Color color);
|
||||
|
||||
Assert.True (result);
|
||||
Assert.Equal (255, color.R);
|
||||
Assert.Equal (0, color.G);
|
||||
Assert.Equal (0, color.B);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
using UnitTests;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace DrawingTests;
|
||||
namespace DrawingTests.Lines;
|
||||
|
||||
/// <summary>
|
||||
/// Pure unit tests for <see cref="LineCanvas"/> that don't require Application.Driver or View context.
|
||||
@@ -1,7 +1,7 @@
|
||||
using UnitTests;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace DrawingTests;
|
||||
namespace UnitTests.Parallelizable.Drawing.Lines;
|
||||
|
||||
public class StraightLineExtensionsTests (ITestOutputHelper output)
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace DrawingTests;
|
||||
namespace UnitTests.Parallelizable.Drawing.Lines;
|
||||
|
||||
public class StraightLineTests (ITestOutputHelper output)
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using Xunit.Sdk;
|
||||
|
||||
namespace DrawingTests;
|
||||
namespace DrawingTests.RegionTests;
|
||||
|
||||
public class DifferenceTests
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Collections.Concurrent;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace DrawingTests;
|
||||
namespace DrawingTests.RegionTests;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for <see cref="Region.DrawOuterBoundary"/>.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace DrawingTests;
|
||||
namespace DrawingTests.RegionTests;
|
||||
|
||||
|
||||
public class MergeRectanglesTests
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace DrawingTests;
|
||||
namespace DrawingTests.RegionTests;
|
||||
|
||||
public class RegionTests
|
||||
public class RegionClassTests
|
||||
{
|
||||
[Fact]
|
||||
public void Clone_CreatesExactCopy ()
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace DrawingTests;
|
||||
namespace DrawingTests.RegionTests;
|
||||
|
||||
using Xunit;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user