Add link support for supported terminals

Also refactors the code quite a bit, to make it a bit more
easier to add features like this in the future.

Closes #75
This commit is contained in:
Patrik Svensson
2020-09-11 00:34:45 +02:00
committed by Patrik Svensson
parent 1601ef24b3
commit 504746c5dc
33 changed files with 574 additions and 1539 deletions

View File

@@ -14,10 +14,9 @@ namespace Spectre.Console.Tests.Unit
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.TrueColor);
fixture.Console.SetColor(new Color(128, 0, 128), foreground);
// When
fixture.Console.Write("Hello");
fixture.Console.Write("Hello", new Style().SetColor(new Color(128, 0, 128), foreground));
// Then
fixture.Output.ShouldBe(expected);
@@ -30,10 +29,9 @@ namespace Spectre.Console.Tests.Unit
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.TrueColor);
fixture.Console.SetColor(Color.Purple, foreground);
// When
fixture.Console.Write("Hello");
fixture.Console.Write("Hello", new Style().SetColor(Color.Purple, foreground));
// Then
fixture.Output.ShouldBe(expected);
@@ -49,10 +47,9 @@ namespace Spectre.Console.Tests.Unit
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.EightBit);
fixture.Console.SetColor(Color.Olive, foreground);
// When
fixture.Console.Write("Hello");
fixture.Console.Write("Hello", new Style().SetColor(Color.Olive, foreground));
// Then
fixture.Output.ShouldBe(expected);
@@ -65,10 +62,9 @@ namespace Spectre.Console.Tests.Unit
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.EightBit);
fixture.Console.SetColor(new Color(128, 128, 0), foreground);
// When
fixture.Console.Write("Hello");
fixture.Console.Write("Hello", new Style().SetColor(new Color(128, 128, 0), foreground));
// Then
fixture.Output.ShouldBe(expected);
@@ -81,10 +77,9 @@ namespace Spectre.Console.Tests.Unit
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.EightBit);
fixture.Console.SetColor(new Color(126, 127, 0), foreground);
// When
fixture.Console.Write("Hello");
fixture.Console.Write("Hello", new Style().SetColor(new Color(126, 127, 0), foreground));
// Then
fixture.Output.ShouldBe(expected);
@@ -100,10 +95,9 @@ namespace Spectre.Console.Tests.Unit
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard);
fixture.Console.SetColor(Color.Olive, foreground);
// When
fixture.Console.Write("Hello");
fixture.Console.Write("Hello", new Style().SetColor(Color.Olive, foreground));
// Then
fixture.Output.ShouldBe(expected);
@@ -121,10 +115,9 @@ namespace Spectre.Console.Tests.Unit
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard);
fixture.Console.SetColor(new Color(r, g, b), foreground);
// When
fixture.Console.Write("Hello");
fixture.Console.Write("Hello", new Style().SetColor(new Color(r, g, b), foreground));
// Then
fixture.Output.ShouldBe(expected);
@@ -142,10 +135,9 @@ namespace Spectre.Console.Tests.Unit
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard);
fixture.Console.SetColor(new Color(r, g, b), foreground);
// When
fixture.Console.Write("Hello");
fixture.Console.Write("Hello", new Style().SetColor(new Color(r, g, b), foreground));
// Then
fixture.Output.ShouldBe(expected);
@@ -161,10 +153,9 @@ namespace Spectre.Console.Tests.Unit
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Legacy);
fixture.Console.SetColor(Color.Olive, foreground);
// When
fixture.Console.Write("Hello");
fixture.Console.Write("Hello", new Style().SetColor(Color.Olive, foreground));
// Then
fixture.Output.ShouldBe(expected);
@@ -182,10 +173,9 @@ namespace Spectre.Console.Tests.Unit
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Legacy);
fixture.Console.SetColor(new Color(r, g, b), foreground);
// When
fixture.Console.Write("Hello");
fixture.Console.Write("Hello", new Style().SetColor(new Color(r, g, b), foreground));
// Then
fixture.Output.ShouldBe(expected);
@@ -203,10 +193,9 @@ namespace Spectre.Console.Tests.Unit
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Legacy);
fixture.Console.SetColor(new Color(r, g, b), foreground);
// When
fixture.Console.Write("Hello");
fixture.Console.Write("Hello", new Style().SetColor(new Color(r, g, b), foreground));
// Then
fixture.Output.ShouldBe(expected);

View File

@@ -13,6 +13,8 @@ namespace Spectre.Console.Tests.Unit
[Theory]
[InlineData("[yellow]Hello[/]", "Hello")]
[InlineData("[yellow]Hello [italic]World[/]![/]", "Hello World!")]
[InlineData("[link=https://patriksvensson.se]Click to visit my blog[/]", "]8;id=2026695893;https://patriksvensson.se\\Click to visit my blog]8;;\\")]
[InlineData("[link]https://patriksvensson.se[/]", "]8;id=2026695893;https://patriksvensson.se\\https://patriksvensson.se]8;;\\")]
public void Should_Output_Expected_Ansi_For_Markup(string markup, string expected)
{
// Given

View File

@@ -19,10 +19,9 @@ namespace Spectre.Console.Tests.Unit
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.TrueColor);
fixture.Console.Decoration = decoration;
// When
fixture.Console.Write("Hello World");
fixture.Console.Write("Hello World", Style.WithDecoration(decoration));
// Then
fixture.Output.ShouldBe(expected);
@@ -35,10 +34,9 @@ namespace Spectre.Console.Tests.Unit
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.TrueColor);
fixture.Console.Decoration = decoration;
// When
fixture.Console.Write("Hello World");
fixture.Console.Write("Hello World", Style.WithDecoration(decoration));
// Then
fixture.Output.ShouldBe(expected);

View File

@@ -1,5 +1,4 @@
using System;
using System.Globalization;
using Shouldly;
using Xunit;
@@ -12,12 +11,13 @@ namespace Spectre.Console.Tests.Unit
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard);
fixture.Console.Foreground = Color.RoyalBlue1;
fixture.Console.Background = Color.NavajoWhite1;
fixture.Console.Decoration = Decoration.Italic;
// When
fixture.Console.Write("Hello");
fixture.Console.Write(
"Hello",
Style.WithForeground(Color.RoyalBlue1)
.WithBackground(Color.NavajoWhite1)
.WithDecoration(Decoration.Italic));
// Then
fixture.Output.ShouldBe("\u001b[3;90;47mHello\u001b[0m");
@@ -28,12 +28,13 @@ namespace Spectre.Console.Tests.Unit
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard);
fixture.Console.Foreground = Color.Default;
fixture.Console.Background = Color.NavajoWhite1;
fixture.Console.Decoration = Decoration.Italic;
// When
fixture.Console.Write("Hello");
fixture.Console.Write(
"Hello",
Style.WithForeground(Color.Default)
.WithBackground(Color.NavajoWhite1)
.WithDecoration(Decoration.Italic));
// Then
fixture.Output.ShouldBe("\u001b[3;47mHello\u001b[0m");
@@ -44,12 +45,13 @@ namespace Spectre.Console.Tests.Unit
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard);
fixture.Console.Foreground = Color.RoyalBlue1;
fixture.Console.Background = Color.Default;
fixture.Console.Decoration = Decoration.Italic;
// When
fixture.Console.Write("Hello");
fixture.Console.Write(
"Hello",
Style.WithForeground(Color.RoyalBlue1)
.WithBackground(Color.Default)
.WithDecoration(Decoration.Italic));
// Then
fixture.Output.ShouldBe("\u001b[3;90mHello\u001b[0m");
@@ -60,190 +62,18 @@ namespace Spectre.Console.Tests.Unit
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard);
fixture.Console.Foreground = Color.RoyalBlue1;
fixture.Console.Background = Color.NavajoWhite1;
fixture.Console.Decoration = Decoration.None;
// When
fixture.Console.Write("Hello");
fixture.Console.Write(
"Hello",
Style.WithForeground(Color.RoyalBlue1)
.WithBackground(Color.NavajoWhite1)
.WithDecoration(Decoration.None));
// Then
fixture.Output.ShouldBe("\u001b[90;47mHello\u001b[0m");
}
public sealed class Write
{
[Theory]
[InlineData(AnsiSupport.Yes)]
[InlineData(AnsiSupport.No)]
public void Should_Write_Int32_With_Format_Provider(AnsiSupport ansi)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
// When
fixture.Console.Write(CultureInfo.InvariantCulture, 32);
// Then
fixture.Output.ShouldBe("32");
}
[Theory]
[InlineData(AnsiSupport.Yes)]
[InlineData(AnsiSupport.No)]
public void Should_Write_UInt32_With_Format_Provider(AnsiSupport ansi)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
// When
fixture.Console.Write(CultureInfo.InvariantCulture, 32U);
// Then
fixture.Output.ShouldBe("32");
}
[Theory]
[InlineData(AnsiSupport.Yes)]
[InlineData(AnsiSupport.No)]
public void Should_Write_Int64_With_Format_Provider(AnsiSupport ansi)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
// When
fixture.Console.Write(CultureInfo.InvariantCulture, 32L);
// Then
fixture.Output.ShouldBe("32");
}
[Theory]
[InlineData(AnsiSupport.Yes)]
[InlineData(AnsiSupport.No)]
public void Should_Write_UInt64_With_Format_Provider(AnsiSupport ansi)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
// When
fixture.Console.Write(CultureInfo.InvariantCulture, 32UL);
// Then
fixture.Output.ShouldBe("32");
}
[Theory]
[InlineData(AnsiSupport.Yes)]
[InlineData(AnsiSupport.No)]
public void Should_Write_Single_With_Format_Provider(AnsiSupport ansi)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
// When
fixture.Console.Write(CultureInfo.InvariantCulture, 32.432F);
// Then
fixture.Output.ShouldBe("32.432");
}
[Theory]
[InlineData(AnsiSupport.Yes)]
[InlineData(AnsiSupport.No)]
public void Should_Write_Double_With_Format_Provider(AnsiSupport ansi)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
// When
fixture.Console.Write(CultureInfo.InvariantCulture, (double)32.432);
// Then
fixture.Output.ShouldBe("32.432");
}
[Theory]
[InlineData(AnsiSupport.Yes)]
[InlineData(AnsiSupport.No)]
public void Should_Write_Decimal_With_Format_Provider(AnsiSupport ansi)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
// When
fixture.Console.Write(CultureInfo.InvariantCulture, 32.432M);
// Then
fixture.Output.ShouldBe("32.432");
}
[Theory]
[InlineData(AnsiSupport.Yes)]
[InlineData(AnsiSupport.No)]
public void Should_Write_Boolean_With_Format_Provider(AnsiSupport ansi)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
// When
fixture.Console.Write(CultureInfo.InvariantCulture, true);
// Then
fixture.Output.ShouldBe("True");
}
[Theory]
[InlineData(AnsiSupport.Yes)]
[InlineData(AnsiSupport.No)]
public void Should_Write_Char_With_Format_Provider(AnsiSupport ansi)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
// When
fixture.Console.Write(CultureInfo.InvariantCulture, 'P');
// Then
fixture.Output.ShouldBe("P");
}
[Theory]
[InlineData(AnsiSupport.Yes)]
[InlineData(AnsiSupport.No)]
public void Should_Write_Char_Array_With_Format_Provider(AnsiSupport ansi)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
// When
fixture.Console.Write(
CultureInfo.InvariantCulture,
new[] { 'P', 'a', 't', 'r', 'i', 'k' });
// Then
fixture.Output.ShouldBe("Patrik");
}
[Theory]
[InlineData(AnsiSupport.Yes)]
[InlineData(AnsiSupport.No)]
public void Should_Write_Formatted_String_With_Format_Provider(AnsiSupport ansi)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
// When
fixture.Console.Write(
CultureInfo.InvariantCulture,
"Hello {0}! {1}",
"World", 32);
// Then
fixture.Output.ShouldBe("Hello World! 32");
}
}
public sealed class WriteLine
{
[Fact]
@@ -253,10 +83,8 @@ namespace Spectre.Console.Tests.Unit
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, AnsiSupport.Yes);
// When
fixture.Console.Background = ConsoleColor.Red;
fixture.Console.WriteLine("Hello");
fixture.Console.Background = ConsoleColor.Green;
fixture.Console.WriteLine("World");
fixture.Console.WriteLine("Hello", Style.WithBackground(ConsoleColor.Red));
fixture.Console.WriteLine("World", Style.WithBackground(ConsoleColor.Green));
// Then
fixture.Output.NormalizeLineEndings()
@@ -270,183 +98,12 @@ namespace Spectre.Console.Tests.Unit
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, AnsiSupport.Yes);
// When
fixture.Console.Background = ConsoleColor.Red;
fixture.Console.WriteLine("Hello\nWorld");
fixture.Console.WriteLine("Hello\nWorld", Style.WithBackground(ConsoleColor.Red));
// Then
fixture.Output.NormalizeLineEndings()
.ShouldBe("Hello\nWorld\n");
}
[Theory]
[InlineData(AnsiSupport.Yes)]
[InlineData(AnsiSupport.No)]
public void Should_Write_Int32_With_Format_Provider(AnsiSupport ansi)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
// When
fixture.Console.WriteLine(CultureInfo.InvariantCulture, 32);
// Then
fixture.Output.ShouldBe("32" + Environment.NewLine);
}
[Theory]
[InlineData(AnsiSupport.Yes)]
[InlineData(AnsiSupport.No)]
public void Should_Write_UInt32_With_Format_Provider(AnsiSupport ansi)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
// When
fixture.Console.WriteLine(CultureInfo.InvariantCulture, 32U);
// Then
fixture.Output.ShouldBe("32" + Environment.NewLine);
}
[Theory]
[InlineData(AnsiSupport.Yes)]
[InlineData(AnsiSupport.No)]
public void Should_Write_Int64_With_Format_Provider(AnsiSupport ansi)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
// When
fixture.Console.WriteLine(CultureInfo.InvariantCulture, 32L);
// Then
fixture.Output.ShouldBe("32" + Environment.NewLine);
}
[Theory]
[InlineData(AnsiSupport.Yes)]
[InlineData(AnsiSupport.No)]
public void Should_Write_UInt64_With_Format_Provider(AnsiSupport ansi)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
// When
fixture.Console.WriteLine(CultureInfo.InvariantCulture, 32UL);
// Then
fixture.Output.ShouldBe("32" + Environment.NewLine);
}
[Theory]
[InlineData(AnsiSupport.Yes)]
[InlineData(AnsiSupport.No)]
public void Should_Write_Single_With_Format_Provider(AnsiSupport ansi)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
// When
fixture.Console.WriteLine(CultureInfo.InvariantCulture, 32.432F);
// Then
fixture.Output.ShouldBe("32.432" + Environment.NewLine);
}
[Theory]
[InlineData(AnsiSupport.Yes)]
[InlineData(AnsiSupport.No)]
public void Should_Write_Double_With_Format_Provider(AnsiSupport ansi)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
// When
fixture.Console.WriteLine(CultureInfo.InvariantCulture, (double)32.432);
// Then
fixture.Output.ShouldBe("32.432" + Environment.NewLine);
}
[Theory]
[InlineData(AnsiSupport.Yes)]
[InlineData(AnsiSupport.No)]
public void Should_Write_Decimal_With_Format_Provider(AnsiSupport ansi)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
// When
fixture.Console.WriteLine(CultureInfo.InvariantCulture, 32.432M);
// Then
fixture.Output.ShouldBe("32.432" + Environment.NewLine);
}
[Theory]
[InlineData(AnsiSupport.Yes)]
[InlineData(AnsiSupport.No)]
public void Should_Write_Boolean_With_Format_Provider(AnsiSupport ansi)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
// When
fixture.Console.WriteLine(CultureInfo.InvariantCulture, true);
// Then
fixture.Output.ShouldBe("True" + Environment.NewLine);
}
[Theory]
[InlineData(AnsiSupport.Yes)]
[InlineData(AnsiSupport.No)]
public void Should_Write_Char_With_Format_Provider(AnsiSupport ansi)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
// When
fixture.Console.WriteLine(CultureInfo.InvariantCulture, 'P');
// Then
fixture.Output.ShouldBe("P" + Environment.NewLine);
}
[Theory]
[InlineData(AnsiSupport.Yes)]
[InlineData(AnsiSupport.No)]
public void Should_Write_Char_Array_With_Format_Provider(AnsiSupport ansi)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
// When
fixture.Console.WriteLine(
CultureInfo.InvariantCulture,
new[] { 'P', 'a', 't', 'r', 'i', 'k' });
// Then
fixture.Output.ShouldBe("Patrik" + Environment.NewLine);
}
[Theory]
[InlineData(AnsiSupport.Yes)]
[InlineData(AnsiSupport.No)]
public void Should_Write_Formatted_String_With_Format_Provider(AnsiSupport ansi)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, ansi);
// When
fixture.Console.WriteLine(
CultureInfo.InvariantCulture,
"Hello {0}! {1}",
"World", 32);
// Then
fixture.Output.ShouldBe("Hello World! 32" + Environment.NewLine);
}
}
}
}

View File

@@ -11,7 +11,7 @@ namespace Spectre.Console.Tests.Unit
{
// Given
var first = new Style(Color.White, Color.Yellow, Decoration.Bold | Decoration.Italic);
var other = new Style(Color.Green, Color.Silver, Decoration.Underline);
var other = new Style(Color.Green, Color.Silver, Decoration.Underline, "https://example.com");
// When
var result = first.Combine(other);
@@ -20,6 +20,77 @@ namespace Spectre.Console.Tests.Unit
result.Foreground.ShouldBe(Color.Green);
result.Background.ShouldBe(Color.Silver);
result.Decoration.ShouldBe(Decoration.Bold | Decoration.Italic | Decoration.Underline);
result.Link.ShouldBe("https://example.com");
}
[Fact]
public void Should_Consider_Two_Identical_Styles_Equal()
{
// Given
var first = new Style(Color.White, Color.Yellow, Decoration.Bold | Decoration.Italic, "http://example.com");
var second = new Style(Color.White, Color.Yellow, Decoration.Bold | Decoration.Italic, "http://example.com");
// When
var result = first.Equals(second);
// Then
result.ShouldBeTrue();
}
[Fact]
public void Should_Not_Consider_Two_Styles_With_Different_Foreground_Colors_Equal()
{
// Given
var first = new Style(Color.White, Color.Yellow, Decoration.Bold | Decoration.Italic, "http://example.com");
var second = new Style(Color.Blue, Color.Yellow, Decoration.Bold | Decoration.Italic, "http://example.com");
// When
var result = first.Equals(second);
// Then
result.ShouldBeFalse();
}
[Fact]
public void Should_Not_Consider_Two_Styles_With_Different_Background_Colors_Equal()
{
// Given
var first = new Style(Color.White, Color.Yellow, Decoration.Bold | Decoration.Italic, "http://example.com");
var second = new Style(Color.White, Color.Blue, Decoration.Bold | Decoration.Italic, "http://example.com");
// When
var result = first.Equals(second);
// Then
result.ShouldBeFalse();
}
[Fact]
public void Should_Not_Consider_Two_Styles_With_Different_Decorations_Equal()
{
// Given
var first = new Style(Color.White, Color.Yellow, Decoration.Bold | Decoration.Italic, "http://example.com");
var second = new Style(Color.White, Color.Yellow, Decoration.Bold, "http://example.com");
// When
var result = first.Equals(second);
// Then
result.ShouldBeFalse();
}
[Fact]
public void Should_Not_Consider_Two_Styles_With_Different_Links_Equal()
{
// Given
var first = new Style(Color.White, Color.Yellow, Decoration.Bold | Decoration.Italic, "http://example.com");
var second = new Style(Color.White, Color.Yellow, Decoration.Bold | Decoration.Italic, "http://foo.com");
// When
var result = first.Equals(second);
// Then
result.ShouldBeFalse();
}
public sealed class TheParseMethod
@@ -62,16 +133,36 @@ namespace Spectre.Console.Tests.Unit
}
[Fact]
public void Should_Parse_Text_And_Decoration()
public void Should_Parse_Link_Without_Address()
{
// Given, When
var result = Style.Parse("bold underline blue on green");
var result = Style.Parse("link");
// Then
result.ShouldNotBeNull();
result.Decoration.ShouldBe(Decoration.Bold | Decoration.Underline);
result.Foreground.ShouldBe(Color.Blue);
result.Background.ShouldBe(Color.Green);
result.Link.ShouldBe("https://emptylink");
}
[Fact]
public void Should_Parse_Link()
{
// Given, When
var result = Style.Parse("link=https://example.com");
// Then
result.ShouldNotBeNull();
result.Link.ShouldBe("https://example.com");
}
[Fact]
public void Should_Throw_If_Link_Is_Set_Twice()
{
// Given, When
var result = Record.Exception(() => Style.Parse("link=https://example.com link=https://example.com"));
// Then
result.ShouldBeOfType<InvalidOperationException>();
result.Message.ShouldBe("A link has already been set.");
}
[Fact]
@@ -131,6 +222,20 @@ namespace Spectre.Console.Tests.Unit
result.Message.ShouldBe("Could not find color 'lol'.");
}
[Fact]
public void Should_Parse_Colors_And_Decoration_And_Link()
{
// Given, When
var result = Style.Parse("link=https://example.com bold underline blue on green");
// Then
result.ShouldNotBeNull();
result.Decoration.ShouldBe(Decoration.Bold | Decoration.Underline);
result.Foreground.ShouldBe(Color.Blue);
result.Background.ShouldBe(Color.Green);
result.Link.ShouldBe("https://example.com");
}
[Theory]
[InlineData("#FF0000 on #0000FF")]
[InlineData("#F00 on #00F")]