Phil Scott 1d8154f9b0
Introduce MarkupInterpolated and MarkupLineInterpolated extensions (#761)
* Introduce MarkupInterpolated and MarkupLineInterpolated extensions

These new methods enable easily writing markup with a nice and intuitive syntax without having to worry about escaping the markup.

```csharp
string input = args[0];
string output = Process(input);
AnsiConsole.MarkupLineInterpolated($"[blue]{input}[/] -> [green]{output}[/]");

```

The `Interpolated` suffix was inspired by the Entity Framework Core [FromSqlInterpolated][1] method.

[1]: https://docs.microsoft.com/en-us/ef/core/querying/raw-sql#passing-parameters

* Fixing whitespace to match file scoped namespaces

* Adding FromInterpolated helper to Markup widget

Allows automatic handling of interpolated strings to be used on the Markup widget. This would be helpful for people working with Tables and the Tree control who would not be using the MarkupInterpolated methods.

* Documentation for markup interpolated methods.

Co-authored-by: Cédric Luthi <cedric.luthi@gmail.com>
2022-03-22 22:34:25 +01:00

178 lines
5.3 KiB
C#

namespace Spectre.Console.Tests.Unit;
public sealed class MarkupTests
{
public sealed class TheLengthProperty
{
[Theory]
[InlineData("Hello", 5)]
[InlineData("Hello\nWorld", 11)]
[InlineData("[yellow]Hello[/]", 5)]
public void Should_Return_The_Number_Of_Characters(string input, int expected)
{
// Given
var markup = new Markup(input);
// When
var result = markup.Length;
// Then
result.ShouldBe(expected);
}
}
public sealed class TheLinesProperty
{
[Theory]
[InlineData("Hello", 1)]
[InlineData("Hello\nWorld", 2)]
[InlineData("[yellow]Hello[/]\nWorld", 2)]
public void Should_Return_The_Number_Of_Lines(string input, int expected)
{
// Given
var markup = new Markup(input);
// When
var result = markup.Lines;
// Then
result.ShouldBe(expected);
}
}
public sealed class TheEscapeMethod
{
[Theory]
[InlineData("Hello World", "Hello World")]
[InlineData("Hello World [", "Hello World [[")]
[InlineData("Hello World ]", "Hello World ]]")]
[InlineData("Hello [World]", "Hello [[World]]")]
[InlineData("Hello [[World]]", "Hello [[[[World]]]]")]
public void Should_Escape_Markup_As_Expected(string input, string expected)
{
// Given, When
var result = Markup.Escape(input);
// Then
result.ShouldBe(expected);
}
}
public sealed class TheRemoveMethod
{
[Theory]
[InlineData("Hello World", "Hello World")]
[InlineData("Hello [blue]World", "Hello World")]
[InlineData("Hello [blue]World[/]", "Hello World")]
public void Should_Remove_Markup_From_Text(string input, string expected)
{
// Given, When
var result = Markup.Remove(input);
// Then
result.ShouldBe(expected);
}
[Theory]
[InlineData("Hello", "World", "\x1B[38;5;11mHello\x1B[0m \x1B[38;5;9mWorld\x1B[0m 2021-02-03")]
[InlineData("Hello", "World [", "\x1B[38;5;11mHello\x1B[0m \x1B[38;5;9mWorld [\x1B[0m 2021-02-03")]
[InlineData("Hello", "World ]", "\x1B[38;5;11mHello\x1B[0m \x1B[38;5;9mWorld ]\x1B[0m 2021-02-03")]
[InlineData("[Hello]", "World", "\x1B[38;5;11m[Hello]\x1B[0m \x1B[38;5;9mWorld\x1B[0m 2021-02-03")]
[InlineData("[[Hello]]", "[World]", "\x1B[38;5;11m[[Hello]]\x1B[0m \x1B[38;5;9m[World]\x1B[0m 2021-02-03")]
public void Should_Escape_Markup_When_Using_MarkupInterpolated(string input1, string input2, string expected)
{
// Given
var console = new TestConsole().EmitAnsiSequences();
var date = new DateTime(2021, 2, 3);
// When
console.MarkupInterpolated($"[yellow]{input1}[/] [red]{input2}[/] {date:yyyy-MM-dd}");
// Then
console.Output.ShouldBe(expected);
}
}
[Theory]
[InlineData("Hello [[ World ]")]
[InlineData("Hello [[ World ] !")]
public void Should_Throw_If_Closing_Tag_Is_Not_Properly_Escaped(string input)
{
// Given
var console = new TestConsole();
// When
var result = Record.Exception(() => new Markup(input));
// Then
result.ShouldNotBeNull();
result.ShouldBeOfType<InvalidOperationException>();
result.Message.ShouldBe("Encountered unescaped ']' token at position 16");
}
[Fact]
public void Should_Escape_Markup_Blocks_As_Expected()
{
// Given
var console = new TestConsole();
var markup = new Markup("Hello [[ World ]] !");
// When
console.Write(markup);
// Then
console.Output.ShouldBe("Hello [ World ] !");
}
[Theory]
[InlineData("Hello [link=http://example.com]example.com[/]", "Hello example.com")]
[InlineData("Hello [link=http://example.com]http://example.com[/]", "Hello http://example.com")]
public void Should_Render_Links_As_Expected(string input, string output)
{
// Given
var console = new TestConsole();
var markup = new Markup(input);
// When
console.Write(markup);
// Then
console.Output.ShouldBe(output);
}
[Fact]
public void Should_Not_Fail_With_Brackets_On_Calls_Without_Args()
{
// Given
var console = new TestConsole();
// When
console.MarkupLine("{");
// Then
console.Output.NormalizeLineEndings()
.ShouldBe("{\n");
}
[Fact]
public void Can_Use_Interpolated_Markup_As_IRenderable()
{
// Given
var console = new TestConsole();
const string Num = "[value[";
var table = new Table().AddColumns("First Column");
table.AddRow(Markup.FromInterpolated($"Result: {Num}"));
// When
console.Write(table);
// Then
console.Output.NormalizeLineEndings().ShouldBe(@"┌─────────────────┐
│ First Column │
├─────────────────┤
│ Result: [value[ │
└─────────────────┘
".NormalizeLineEndings());
}
}