dotnet-installer/test/dotnet.Tests/PrintableTableTests.cs
Peter Huene 9ef495327a
Implement a printable table.
This commit implements a simple printable table that can be used to display
tabular data.

The columns of the table can specify a maximum width which will cause the
column text to wrap around to the next line.
2018-02-27 15:57:53 -08:00

420 lines
14 KiB
C#

// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using FluentAssertions;
using Microsoft.DotNet.Cli;
using Microsoft.DotNet.Tools.Test.Utilities;
using Xunit;
namespace Microsoft.DotNet.Tests
{
public class PrintableTableTests : TestBase
{
[Fact]
public void GivenNoColumnsItPrintsNoLines()
{
var table = new PrintableTable<string[]>();
var lines = new List<string>();
table.PrintRows(new string[][] {}, l => lines.Add(l));
lines.Should().BeEmpty();
}
[Fact]
public void GivenAnEmptyRowsCollectionItPrintsColumnHeaders()
{
RunTest(new TestData() {
Columns = new[] {
"First Column",
"2nd Column",
"Another Column"
},
Rows = new string[][] {
},
ExpectedLines = new[] {
"First Column 2nd Column Another Column",
"------------------------------------------------"
},
ExpectedTableWidth = 48
});
}
[Fact]
public void GivenASingleRowItPrintsCorrectly()
{
RunTest(new TestData() {
Columns = new[] {
"1st",
"2nd",
"3rd"
},
Rows = new string[][] {
new[] {
"first",
"second",
"third"
}
},
ExpectedLines = new[] {
"1st 2nd 3rd ",
"----------------------------",
"first second third"
},
ExpectedTableWidth = 28
});
}
[Fact]
public void GivenMultipleRowsItPrintsCorrectly()
{
RunTest(new TestData() {
Columns = new[] {
"First",
"Second",
"Third",
"Fourth",
"Fifth"
},
Rows = new string[][] {
new[] {
"1st",
"2nd",
"3rd",
"4th",
"5th"
},
new [] {
"a",
"b",
"c",
"d",
"e"
},
new [] {
"much longer string 1",
"much longer string 2",
"much longer string 3",
"much longer string 4",
"much longer string 5",
}
},
ExpectedLines = new[] {
"First Second Third Fourth Fifth ",
"----------------------------------------------------------------------------------------------------------------------------",
"1st 2nd 3rd 4th 5th ",
"a b c d e ",
"much longer string 1 much longer string 2 much longer string 3 much longer string 4 much longer string 5"
},
ExpectedTableWidth = 124
});
}
[Fact]
public void GivenARowWithEmptyStringsItPrintsCorrectly()
{
RunTest(new TestData() {
Columns = new[] {
"First",
"Second",
"Third",
"Fourth",
"Fifth"
},
Rows = new string[][] {
new[] {
"1st",
"2nd",
"3rd",
"4th",
"5th"
},
new [] {
"",
"",
"",
"",
""
},
new [] {
"much longer string 1",
"much longer string 2",
"much longer string 3",
"much longer string 4",
"much longer string 5",
}
},
ExpectedLines = new[] {
"First Second Third Fourth Fifth ",
"----------------------------------------------------------------------------------------------------------------------------",
"1st 2nd 3rd 4th 5th ",
" ",
"much longer string 1 much longer string 2 much longer string 3 much longer string 4 much longer string 5"
},
ExpectedTableWidth = 124
});
}
[Fact]
public void GivenColumnsWithMaximumWidthsItPrintsCorrectly()
{
RunTest(new TestData() {
Columns = new[] {
"First",
"Second",
"Third",
},
ColumnWidths = new[] {
3,
int.MaxValue,
4
},
Rows = new string[][] {
new[] {
"123",
"1234567890",
"1234"
},
new [] {
"1",
"1",
"1",
},
new [] {
"12345",
"a much longer string",
"1234567890"
},
new [] {
"123456",
"hello world",
"12345678"
}
},
ExpectedLines = new[] {
"Fir Second Thir",
"st d ",
"---------------------------------------",
"123 1234567890 1234",
"1 1 1 ",
"123 a much longer string 1234",
"45 5678",
" 90 ",
"123 hello world 1234",
"456 5678"
},
ExpectedTableWidth = 39
});
}
[Fact]
public void GivenARowContainingUnicodeCharactersItPrintsCorrectly()
{
RunTest(new TestData() {
Columns = new[] {
"Poem"
},
Rows = new string[][] {
new [] {
"\u3044\u308D\u306F\u306B\u307B\u3078\u3068\u3061\u308A\u306C\u308B\u3092"
}
},
ExpectedLines = new[] {
"Poem ",
"------------",
"\u3044\u308D\u306F\u306B\u307B\u3078\u3068\u3061\u308A\u306C\u308B\u3092"
},
ExpectedTableWidth = 12
});
}
[Fact]
public void GivenARowContainingUnicodeCharactersItWrapsCorrectly()
{
RunTest(new TestData() {
Columns = new[] {
"Poem"
},
ColumnWidths = new [] {
5
},
Rows = new string[][] {
new [] {
"\u3044\u308D\u306F\u306B\u307B\u3078\u3068\u3061\u308A\u306C\u308B\u3092"
}
},
ExpectedLines = new[] {
"Poem ",
"-----",
"\u3044\u308D\u306F\u306B\u307B",
"\u3078\u3068\u3061\u308A\u306C",
"\u308B\u3092 "
},
ExpectedTableWidth = 5
});
}
[Fact]
public void GivenARowContainingUnicodeCombiningCharactersItPrintsCorrectly()
{
// The unicode string is "test" with "enclosing circle backslash" around each character
// Given 0x20E0 is a combining character, the string should be four graphemes in length,
// despite having eight codepoints. Thus there should be 10 spaces following the characters.
RunTest(new TestData() {
Columns = new[] {
"Unicode String"
},
Rows = new string[][] {
new [] {
"\u0074\u20E0\u0065\u20E0\u0073\u20E0\u0074\u20E0"
}
},
ExpectedLines = new[] {
"Unicode String",
"--------------",
"\u0074\u20E0\u0065\u20E0\u0073\u20E0\u0074\u20E0 "
},
ExpectedTableWidth = 14
});
}
[Fact]
public void GivenARowContainingUnicodeCombiningCharactersItWrapsCorrectly()
{
// See comment for GivenARowContainingUnicodeCombiningCharactersItPrintsCorrectly regarding string content
// This should wrap after the second grapheme rather than the second code point (constituting the first grapheme)
RunTest(new TestData() {
Columns = new[] {
"01"
},
ColumnWidths = new[] {
2
},
Rows = new string[][] {
new [] {
"\u0074\u20E0\u0065\u20E0\u0073\u20E0\u0074\u20E0"
}
},
ExpectedLines = new[] {
"01",
"--",
"\u0074\u20E0\u0065\u20E0",
"\u0073\u20E0\u0074\u20E0"
},
ExpectedTableWidth = 2
});
}
[Fact]
public void GivenAnEmptyColumnHeaderItPrintsTheColumnHeaderAsEmpty()
{
RunTest(new TestData() {
Columns = new[] {
"First",
"",
"Third",
},
Rows = new string[][] {
new[] {
"1st",
"2nd",
"3rd"
}
},
ExpectedLines = new[] {
"First Third",
"-------------------------",
"1st 2nd 3rd "
},
ExpectedTableWidth = 25
});
}
[Fact]
public void GivenAllEmptyColumnHeadersItPrintsTheEntireHeaderAsEmpty()
{
RunTest(new TestData() {
Columns = new[] {
null,
"",
null,
},
Rows = new string[][] {
new[] {
"1st",
"2nd",
"3rd"
}
},
ExpectedLines = new[] {
" ",
"---------------------",
"1st 2nd 3rd"
},
ExpectedTableWidth = 21
});
}
[Fact]
public void GivenZeroWidthColumnsItSkipsTheColumns()
{
RunTest(new TestData() {
Columns = new[] {
"",
"First",
null,
"Second",
""
},
Rows = new string[][] {
new[] {
"",
"1st",
null,
"2nd",
""
}
},
ExpectedLines = new[] {
"First Second",
"-----------------",
"1st 2nd "
},
ExpectedTableWidth = 17
});
}
public class TestData
{
public IEnumerable<string> Columns { get; set; }
public int[] ColumnWidths { get; set; }
public IEnumerable<string[]> Rows { get; set; }
public IEnumerable<string> ExpectedLines { get; set; }
public int ExpectedTableWidth { get; set; }
}
private void RunTest(TestData data)
{
var table = new PrintableTable<string[]>();
int index = 0;
foreach (var column in data.Columns)
{
var i = index;
table.AddColumn(
column,
r => r[i],
data.ColumnWidths?[i] ?? int.MaxValue);
++index;
}
var lines = new List<string>();
table.PrintRows(data.Rows, l => lines.Add(l));
lines.Should().Equal(data.ExpectedLines);
table.CalculateWidth(data.Rows).Should().Be(data.ExpectedTableWidth);
}
}
}