Added initial support for rendering composites

This is far from complete, but it's a start
and it will enable us to create things like tables
and other complex objects in the long run.
This commit is contained in:
Patrik Svensson
2020-07-29 17:34:54 +02:00
committed by Patrik Svensson
parent e596e6eb4f
commit 8e4f33bba4
41 changed files with 1164 additions and 24 deletions

View File

@ -0,0 +1,31 @@
using System;
using System.IO;
namespace Spectre.Console.Tests
{
public sealed class AnsiConsoleFixture : IDisposable
{
private readonly StringWriter _writer;
public IAnsiConsole Console { get; }
public string Output => _writer.ToString();
public AnsiConsoleFixture(ColorSystem system, AnsiSupport ansi = AnsiSupport.Yes)
{
_writer = new StringWriter();
Console = AnsiConsole.Create(new AnsiConsoleSettings
{
Ansi = ansi,
ColorSystem = (ColorSystemSupport)system,
Out = _writer,
});
}
public void Dispose()
{
_writer?.Dispose();
}
}
}

View File

@ -0,0 +1,216 @@
using Shouldly;
using Xunit;
namespace Spectre.Console.Tests
{
public partial class AnsiConsoleTests
{
public sealed class TrueColor
{
[Theory]
[InlineData(true, "\u001b[38;2;128;0;128mHello\u001b[0m")]
[InlineData(false, "\u001b[48;2;128;0;128mHello\u001b[0m")]
public void Should_Return_Correct_Code(bool foreground, string expected)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.TrueColor);
fixture.Console.SetColor(new Color(128, 0, 128), foreground);
// When
fixture.Console.Write("Hello");
// Then
fixture.Output.ShouldBe(expected);
}
[Theory]
[InlineData(true, "\u001b[38;5;5mHello\u001b[0m")]
[InlineData(false, "\u001b[48;5;5mHello\u001b[0m")]
public void Should_Return_Eight_Bit_Ansi_Code_For_Known_Colors(bool foreground, string expected)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.TrueColor);
fixture.Console.SetColor(Color.Purple, foreground);
// When
fixture.Console.Write("Hello");
// Then
fixture.Output.ShouldBe(expected);
}
}
public sealed class EightBit
{
[Theory]
[InlineData(true, "\u001b[38;5;3mHello\u001b[0m")]
[InlineData(false, "\u001b[48;5;3mHello\u001b[0m")]
public void Should_Return_Correct_Code_For_Known_Color(bool foreground, string expected)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.EightBit);
fixture.Console.SetColor(Color.Olive, foreground);
// When
fixture.Console.Write("Hello");
// Then
fixture.Output.ShouldBe(expected);
}
[Theory]
[InlineData(true, "\u001b[38;5;3mHello\u001b[0m")]
[InlineData(false, "\u001b[48;5;3mHello\u001b[0m")]
public void Should_Map_TrueColor_To_Nearest_Eight_Bit_Color_If_Possible(bool foreground, string expected)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.EightBit);
fixture.Console.SetColor(new Color(128, 128, 0), foreground);
// When
fixture.Console.Write("Hello");
// Then
fixture.Output.ShouldBe(expected);
}
[Theory]
[InlineData(true, "\u001b[38;5;3mHello\u001b[0m")]
[InlineData(false, "\u001b[48;5;3mHello\u001b[0m")]
public void Should_Estimate_TrueColor_To_Nearest_Eight_Bit_Color(bool foreground, string expected)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.EightBit);
fixture.Console.SetColor(new Color(126, 127, 0), foreground);
// When
fixture.Console.Write("Hello");
// Then
fixture.Output.ShouldBe(expected);
}
}
public sealed class Standard
{
[Theory]
[InlineData(true, "\u001b[33mHello\u001b[0m")]
[InlineData(false, "\u001b[43mHello\u001b[0m")]
public void Should_Return_Correct_Code_For_Known_Color(bool foreground, string expected)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard);
fixture.Console.SetColor(Color.Olive, foreground);
// When
fixture.Console.Write("Hello");
// Then
fixture.Output.ShouldBe(expected);
}
[Theory]
[InlineData(true, 128, 128, 128, "\u001b[90mHello\u001b[0m")]
[InlineData(false, 128, 128, 128, "\u001b[100mHello\u001b[0m")]
[InlineData(true, 0, 128, 0, "\u001b[32mHello\u001b[0m")]
[InlineData(false, 0, 128, 0, "\u001b[42mHello\u001b[0m")]
public void Should_Map_TrueColor_To_Nearest_Four_Bit_Color_If_Possible(
bool foreground,
byte r, byte g, byte b,
string expected)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard);
fixture.Console.SetColor(new Color(r, g, b), foreground);
// When
fixture.Console.Write("Hello");
// Then
fixture.Output.ShouldBe(expected);
}
[Theory]
[InlineData(true, 112, 120, 128, "\u001b[90mHello\u001b[0m")]
[InlineData(false, 112, 120, 128, "\u001b[100mHello\u001b[0m")]
[InlineData(true, 0, 120, 12, "\u001b[32mHello\u001b[0m")]
[InlineData(false, 0, 120, 12, "\u001b[42mHello\u001b[0m")]
public void Should_Estimate_TrueColor_To_Nearest_Four_Bit_Color(
bool foreground,
byte r, byte g, byte b,
string expected)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard);
fixture.Console.SetColor(new Color(r, g, b), foreground);
// When
fixture.Console.Write("Hello");
// Then
fixture.Output.ShouldBe(expected);
}
}
public sealed class Legacy
{
[Theory]
[InlineData(true, "\u001b[33mHello\u001b[0m")]
[InlineData(false, "\u001b[43mHello\u001b[0m")]
public void Should_Return_Correct_Code_For_Known_Color(bool foreground, string expected)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Legacy);
fixture.Console.SetColor(Color.Olive, foreground);
// When
fixture.Console.Write("Hello");
// Then
fixture.Output.ShouldBe(expected);
}
[Theory]
[InlineData(true, 128, 128, 128, "\u001b[37mHello\u001b[0m")]
[InlineData(false, 128, 128, 128, "\u001b[47mHello\u001b[0m")]
[InlineData(true, 0, 128, 0, "\u001b[32mHello\u001b[0m")]
[InlineData(false, 0, 128, 0, "\u001b[42mHello\u001b[0m")]
public void Should_Map_TrueColor_To_Nearest_Three_Bit_Color_If_Possible(
bool foreground,
byte r, byte g, byte b,
string expected)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Legacy);
fixture.Console.SetColor(new Color(r, g, b), foreground);
// When
fixture.Console.Write("Hello");
// Then
fixture.Output.ShouldBe(expected);
}
[Theory]
[InlineData(true, 112, 120, 128, "\u001b[36mHello\u001b[0m")]
[InlineData(false, 112, 120, 128, "\u001b[46mHello\u001b[0m")]
[InlineData(true, 0, 120, 12, "\u001b[32mHello\u001b[0m")]
[InlineData(false, 0, 120, 12, "\u001b[42mHello\u001b[0m")]
public void Should_Estimate_TrueColor_To_Nearest_Three_Bit_Color(
bool foreground,
byte r, byte g, byte b,
string expected)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Legacy);
fixture.Console.SetColor(new Color(r, g, b), foreground);
// When
fixture.Console.Write("Hello");
// Then
fixture.Output.ShouldBe(expected);
}
}
}
}

View File

@ -0,0 +1,89 @@
using System;
using System.Diagnostics.CodeAnalysis;
using Shouldly;
using Xunit;
namespace Spectre.Console.Tests
{
public partial class AnsiConsoleTests
{
[SuppressMessage("Naming", "CA1724:Type names should not match namespaces")]
public sealed class Markup
{
[Theory]
[InlineData("[yellow]Hello[/]", "Hello")]
[InlineData("[yellow]Hello [italic]World[/]![/]", "Hello World!")]
public void Should_Output_Expected_Ansi_For_Markup(string markup, string expected)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, AnsiSupport.Yes);
// When
fixture.Console.Markup(markup);
// Then
fixture.Output.ShouldBe(expected);
}
[Theory]
[InlineData("[yellow]Hello [[ World[/]", "Hello [ World")]
public void Should_Be_Able_To_Escape_Tags(string markup, string expected)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, AnsiSupport.Yes);
// When
fixture.Console.Markup(markup);
// Then
fixture.Output.ShouldBe(expected);
}
[Theory]
[InlineData("[yellow]Hello[", "Encountered malformed markup tag at position 14.")]
[InlineData("[yellow]Hello[/", "Encountered malformed markup tag at position 15.")]
[InlineData("[yellow]Hello[/foo", "Encountered malformed markup tag at position 15.")]
[InlineData("[yellow Hello", "Encountered malformed markup tag at position 13.")]
public void Should_Throw_If_Encounters_Malformed_Tag(string markup, string expected)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, AnsiSupport.Yes);
// When
var result = Record.Exception(() => fixture.Console.Markup(markup));
// Then
result.ShouldBeOfType<InvalidOperationException>()
.Message.ShouldBe(expected);
}
[Fact]
public void Should_Throw_If_Tags_Are_Unbalanced()
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, AnsiSupport.Yes);
// When
var result = Record.Exception(() => fixture.Console.Markup("[yellow][blue]Hello[/]"));
// Then
result.ShouldBeOfType<InvalidOperationException>()
.Message.ShouldBe("Unbalanced markup stack. Did you forget to close a tag?");
}
[Fact]
public void Should_Throw_If_Encounters_Closing_Tag()
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard, AnsiSupport.Yes);
// When
var result = Record.Exception(() => fixture.Console.Markup("Hello[/]World"));
// Then
result.ShouldBeOfType<InvalidOperationException>()
.Message.ShouldBe("Encountered closing tag when none was expected near position 5.");
}
}
}
}

View File

@ -0,0 +1,47 @@
using Shouldly;
using Xunit;
namespace Spectre.Console.Tests
{
public partial class AnsiConsoleTests
{
[Theory]
[InlineData(Styles.Bold, "\u001b[1mHello World")]
[InlineData(Styles.Dim, "\u001b[2mHello World")]
[InlineData(Styles.Italic, "\u001b[3mHello World")]
[InlineData(Styles.Underline, "\u001b[4mHello World")]
[InlineData(Styles.Invert, "\u001b[7mHello World")]
[InlineData(Styles.Conceal, "\u001b[8mHello World")]
[InlineData(Styles.SlowBlink, "\u001b[5mHello World")]
[InlineData(Styles.RapidBlink, "\u001b[6mHello World")]
[InlineData(Styles.Strikethrough, "\u001b[9mHello World")]
public void Should_Write_Style_Correctly(Styles style, string expected)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.TrueColor);
fixture.Console.Style = style;
// When
fixture.Console.Write("Hello World");
// Then
fixture.Output.ShouldBe(expected);
}
[Theory]
[InlineData(Styles.Bold | Styles.Underline, "\u001b[1;4mHello World")]
[InlineData(Styles.Bold | Styles.Underline | Styles.Conceal, "\u001b[1;4;8mHello World")]
public void Should_Write_Combined_Styles_Correctly(Styles style, string expected)
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.TrueColor);
fixture.Console.Style = style;
// When
fixture.Console.Write("Hello World");
// Then
fixture.Output.ShouldBe(expected);
}
}
}

View File

@ -0,0 +1,420 @@
using System;
using System.Globalization;
using Shouldly;
using Xunit;
namespace Spectre.Console.Tests
{
public partial class AnsiConsoleTests
{
[Fact]
public void Should_Combine_Style_And_Colors()
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard);
fixture.Console.Foreground = Color.RoyalBlue1;
fixture.Console.Background = Color.NavajoWhite1;
fixture.Console.Style = Styles.Italic;
// When
fixture.Console.Write("Hello");
// Then
fixture.Output.ShouldBe("\u001b[3;90;47mHello\u001b[0m");
}
[Fact]
public void Should_Not_Include_Foreground_If_Set_To_Default_Color()
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard);
fixture.Console.Foreground = Color.Default;
fixture.Console.Background = Color.NavajoWhite1;
fixture.Console.Style = Styles.Italic;
// When
fixture.Console.Write("Hello");
// Then
fixture.Output.ShouldBe("\u001b[3;47mHello\u001b[0m");
}
[Fact]
public void Should_Not_Include_Background_If_Set_To_Default_Color()
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard);
fixture.Console.Foreground = Color.RoyalBlue1;
fixture.Console.Background = Color.Default;
fixture.Console.Style = Styles.Italic;
// When
fixture.Console.Write("Hello");
// Then
fixture.Output.ShouldBe("\u001b[3;90mHello\u001b[0m");
}
[Fact]
public void Should_Not_Include_Style_If_Set_To_None()
{
// Given
var fixture = new AnsiConsoleFixture(ColorSystem.Standard);
fixture.Console.Foreground = Color.RoyalBlue1;
fixture.Console.Background = Color.NavajoWhite1;
fixture.Console.Style = Styles.None;
// When
fixture.Console.Write("Hello");
// 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
{
[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

@ -0,0 +1,126 @@
using Shouldly;
using Spectre.Console.Composition;
using Xunit;
namespace Spectre.Console.Tests.Unit.Composition
{
public sealed class PanelTests
{
[Fact]
public void Should_Render_Panel()
{
// Given
var console = new PlainConsole(width: 80);
// When
console.Render(new Panel(new Text("Hello World")));
// Then
console.Lines.Count.ShouldBe(3);
console.Lines[0].ShouldBe("┌─────────────┐");
console.Lines[1].ShouldBe("│ Hello World │");
console.Lines[2].ShouldBe("└─────────────┘");
}
[Fact]
public void Should_Render_Panel_With_Unicode_Correctly()
{
// Given
var console = new PlainConsole(width: 80);
// When
console.Render(new Panel(new Text(" \n💩\n ")));
// Then
console.Lines.Count.ShouldBe(5);
console.Lines[0].ShouldBe("┌────┐");
console.Lines[1].ShouldBe("│ │");
console.Lines[2].ShouldBe("│ 💩 │");
console.Lines[3].ShouldBe("│ │");
console.Lines[4].ShouldBe("└────┘");
}
[Fact]
public void Should_Render_Panel_With_Multiple_Lines()
{
// Given
var console = new PlainConsole(width: 80);
// When
console.Render(new Panel(new Text("Hello World\nFoo Bar")));
// Then
console.Lines.Count.ShouldBe(4);
console.Lines[0].ShouldBe("┌─────────────┐");
console.Lines[1].ShouldBe("│ Hello World │");
console.Lines[2].ShouldBe("│ Foo Bar │");
console.Lines[3].ShouldBe("└─────────────┘");
}
[Fact]
public void Should_Fit_Panel_To_Parent_If_Enabled()
{
// Given
var console = new PlainConsole(width: 25);
// When
console.Render(new Panel(new Text("Hello World"), fit: true));
// Then
console.Lines.Count.ShouldBe(3);
console.Lines[0].ShouldBe("┌───────────────────────┐");
console.Lines[1].ShouldBe("│ Hello World │");
console.Lines[2].ShouldBe("└───────────────────────┘");
}
[Fact]
public void Should_Justify_Child_To_Right()
{
// Given
var console = new PlainConsole(width: 25);
// When
console.Render(new Panel(new Text("Hello World", justify: Justify.Right), fit: true));
// Then
console.Lines.Count.ShouldBe(3);
console.Lines[0].ShouldBe("┌───────────────────────┐");
console.Lines[1].ShouldBe("│ Hello World │");
console.Lines[2].ShouldBe("└───────────────────────┘");
}
[Fact]
public void Should_Justify_Child_To_Center()
{
// Given
var console = new PlainConsole(width: 25);
// When
console.Render(new Panel(new Text("Hello World", justify: Justify.Center), fit: true));
// Then
console.Lines.Count.ShouldBe(3);
console.Lines[0].ShouldBe("┌───────────────────────┐");
console.Lines[1].ShouldBe("│ Hello World │");
console.Lines[2].ShouldBe("└───────────────────────┘");
}
[Fact]
public void Should_Render_Panel_Inside_Panel_Correctly()
{
// Given
var console = new PlainConsole(width: 80);
// When
console.Render(new Panel(new Panel(new Text("Hello World"))));
// Then
console.Lines.Count.ShouldBe(5);
console.Lines[0].ShouldBe("┌─────────────────┐");
console.Lines[1].ShouldBe("│ ┌─────────────┐ │");
console.Lines[2].ShouldBe("│ │ Hello World │ │");
console.Lines[3].ShouldBe("│ └─────────────┘ │");
console.Lines[4].ShouldBe("└─────────────────┘");
}
}
}

View File

@ -0,0 +1,67 @@
using Shouldly;
using Spectre.Console.Composition;
using Xunit;
namespace Spectre.Console.Tests.Unit.Composition
{
public sealed class SegmentTests
{
[Fact]
public void Should_Split_Segment()
{
var lines = Segment.Split(new[]
{
new Segment("Foo"),
new Segment("Bar"),
new Segment("\n"),
new Segment("Baz"),
new Segment("Qux"),
new Segment("\n"),
new Segment("Corgi"),
});
// Then
lines.Count.ShouldBe(3);
lines[0].Count.ShouldBe(2);
lines[0][0].Text.ShouldBe("Foo");
lines[0][1].Text.ShouldBe("Bar");
lines[1].Count.ShouldBe(2);
lines[1][0].Text.ShouldBe("Baz");
lines[1][1].Text.ShouldBe("Qux");
lines[2].Count.ShouldBe(1);
lines[2][0].Text.ShouldBe("Corgi");
}
[Fact]
public void Should_Split_Segments_With_Linebreak_In_Text()
{
var lines = Segment.Split(new[]
{
new Segment("Foo\n"),
new Segment("Bar\n"),
new Segment("Baz"),
new Segment("Qux\n"),
new Segment("Corgi"),
});
// Then
lines.Count.ShouldBe(4);
lines[0].Count.ShouldBe(1);
lines[0][0].Text.ShouldBe("Foo");
lines[1].Count.ShouldBe(1);
lines[1][0].Text.ShouldBe("Bar");
lines[2].Count.ShouldBe(2);
lines[2][0].Text.ShouldBe("Baz");
lines[2][1].Text.ShouldBe("Qux");
lines[3].Count.ShouldBe(1);
lines[3][0].Text.ShouldBe("Corgi");
}
}
}

View File

@ -0,0 +1,61 @@
using Shouldly;
using Spectre.Console.Composition;
using Xunit;
namespace Spectre.Console.Tests.Composition
{
public sealed class TextTests
{
[Fact]
public void Should_Render_Text_To_Console()
{
// Given
var console = new PlainConsole();
// When
console.Render(new Text("Hello World"));
// Then
console.Output.ShouldBe("Hello World");
}
[Fact]
public void Should_Right_Align_Text_To_Parent()
{
// Given
var console = new PlainConsole(width: 15);
// When
console.Render(new Text("Hello World", justify: Justify.Right));
// Then
console.Output.ShouldBe(" Hello World");
}
[Fact]
public void Should_Center_Text_To_Parent()
{
// Given
var console = new PlainConsole(width: 15);
// When
console.Render(new Text("Hello World", justify: Justify.Center));
// Then
console.Output.ShouldBe(" Hello World ");
}
[Fact]
public void Should_Split_Text_To_Multiple_Lines_If_It_Does_Not_Fit()
{
// Given
var console = new PlainConsole(width: 5);
// When
console.Render(new Text("Hello World"));
// Then
console.Output.ShouldBe("Hello\n Worl\nd");
}
}
}