diff --git a/src/Spectre.Console/Color.cs b/src/Spectre.Console/Color.cs index 38825a991..d3fc25396 100644 --- a/src/Spectre.Console/Color.cs +++ b/src/Spectre.Console/Color.cs @@ -213,6 +213,50 @@ public static Color FromInt32(int number) return ColorTable.GetColor(number); } + /// + /// Creates a color from a hexadecimal string representation. + /// + /// The hexadecimal string representation of the color. + /// The color created from the hexadecimal string. + public static Color FromHex(string hex) + { + if (hex is null) + { + throw new ArgumentNullException(nameof(hex)); + } + + if (hex.StartsWith("#")) + { + hex = hex.Substring(1); + } + + var r = byte.Parse(hex.Substring(0, 2), NumberStyles.HexNumber); + var g = byte.Parse(hex.Substring(2, 2), NumberStyles.HexNumber); + var b = byte.Parse(hex.Substring(4, 2), NumberStyles.HexNumber); + + return new Color(r, g, b); + } + + /// + /// Tries to convert a hexadecimal color code to a object. + /// + /// The hexadecimal color code. + /// When this method returns, contains the equivalent of the hexadecimal color code, if the conversion succeeded, or if the conversion failed. + /// true if the conversion succeeded; otherwise, false. + public static bool TryFromHex(string hex, out Color color) + { + try + { + color = FromHex(hex); + return true; + } + catch + { + color = Color.Default; + return false; + } + } + /// /// Converts a to a . /// diff --git a/test/Spectre.Console.Tests/Unit/ColorTests.cs b/test/Spectre.Console.Tests/Unit/ColorTests.cs index 5c07195be..e2ea9dde1 100644 --- a/test/Spectre.Console.Tests/Unit/ColorTests.cs +++ b/test/Spectre.Console.Tests/Unit/ColorTests.cs @@ -1,9 +1,73 @@ +using System.Drawing; + namespace Spectre.Console.Tests.Unit; public sealed class ColorTests { public sealed class TheEqualsMethod { + [Theory] + [InlineData("800080")] + [InlineData("#800080")] + public void Should_Consider_Color_And_Color_From_Hex_Equal(string color) + { + // Given + var color1 = new Color(128, 0, 128); + + // When + var color2 = Color.FromHex(color); + + // Then + color2.ShouldBe(color1); + } + + [Theory] + [InlineData("800080")] + [InlineData("#800080")] + public void Should_Consider_Color_And_Color_Try_From_Hex_Equal(string color) + { + // Given + var color1 = new Color(128, 0, 128); + + // When + var result = Color.TryFromHex(color, out var color2); + + // Then + result.ShouldBeTrue(); + color2.ShouldBe(color1); + } + + [Theory] + [InlineData(null)] + [InlineData("")] + [InlineData("#")] + [InlineData("#80")] + [InlineData("FOO")] + public void Should_Not_Parse_Non_Color_From_Hex(string noncolor) + { + // Given, When + var result = Record.Exception(() => Color.FromHex(noncolor)); + + // Then + result.ShouldBeAssignableTo(); + } + + [Theory] + [InlineData(null)] + [InlineData("")] + [InlineData("#")] + [InlineData("#80")] + [InlineData("FOO")] + public void Should_Not_Parse_Non_Color_Try_From_Hex(string noncolor) + { + // Given, When + var result = Color.TryFromHex(noncolor, out var color); + + // Then + result.ShouldBeFalse(); + color.ShouldBe(Color.Default); + } + [Fact] public void Should_Consider_Color_And_Non_Color_Equal() {