mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-04-14 16:02:50 +08:00
parent
57731c0d55
commit
e169df6303
2
.github/workflows/ci.yaml
vendored
2
.github/workflows/ci.yaml
vendored
@ -89,7 +89,7 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
dotnet tool restore
|
||||
dotnet example --all
|
||||
dotnet example --all --skip live --skip livetable --skip prompt
|
||||
|
||||
- name: Build
|
||||
shell: bash
|
||||
|
@ -15,7 +15,7 @@
|
||||
]
|
||||
},
|
||||
"dotnet-example": {
|
||||
"version": "1.3.1",
|
||||
"version": "1.5.0",
|
||||
"commands": [
|
||||
"dotnet-example"
|
||||
]
|
||||
|
@ -5,7 +5,7 @@
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<ExampleTitle>Live</ExampleTitle>
|
||||
<ExampleDescription>Demonstrates how to do live updates.</ExampleDescription>
|
||||
<ExampleGroup>Misc</ExampleGroup>
|
||||
<ExampleGroup>Live</ExampleGroup>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
15
examples/Console/LiveTable/LiveTable.csproj
Normal file
15
examples/Console/LiveTable/LiveTable.csproj
Normal file
@ -0,0 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<ExampleTitle>LiveTable</ExampleTitle>
|
||||
<ExampleDescription>Demonstrates how to do live updates in a table.</ExampleDescription>
|
||||
<ExampleGroup>Live</ExampleGroup>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Shared\Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
86
examples/Console/LiveTable/Program.cs
Normal file
86
examples/Console/LiveTable/Program.cs
Normal file
@ -0,0 +1,86 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Spectre.Console.Examples
|
||||
{
|
||||
public static class Program
|
||||
{
|
||||
private const int NumberOfRows = 10;
|
||||
|
||||
private static readonly Random _random = new();
|
||||
private static readonly string[] _exchanges = new string[]
|
||||
{
|
||||
"SGD", "SEK", "PLN",
|
||||
"MYR", "EUR", "USD",
|
||||
"AUD", "JPY", "CNH",
|
||||
"HKD", "CAD", "INR",
|
||||
"DKK", "GBP", "RUB",
|
||||
"NZD", "MXN", "IDR",
|
||||
"TWD", "THB", "VND",
|
||||
};
|
||||
|
||||
public static async Task Main(string[] args)
|
||||
{
|
||||
var table = new Table().Expand().BorderColor(Color.Grey);
|
||||
table.AddColumn("[yellow]Source currency[/]");
|
||||
table.AddColumn("[yellow]Destination currency[/]");
|
||||
table.AddColumn("[yellow]Exchange rate[/]");
|
||||
|
||||
AnsiConsole.MarkupLine("Press [yellow]CTRL+C[/] to exit");
|
||||
|
||||
await AnsiConsole.Live(table)
|
||||
.AutoClear(false)
|
||||
.Overflow(VerticalOverflow.Ellipsis)
|
||||
.Cropping(VerticalOverflowCropping.Bottom)
|
||||
.StartAsync(async ctx =>
|
||||
{
|
||||
// Add some initial rows
|
||||
foreach (var _ in Enumerable.Range(0, NumberOfRows))
|
||||
{
|
||||
AddExchangeRateRow(table);
|
||||
}
|
||||
|
||||
// Continously update the table
|
||||
while (true)
|
||||
{
|
||||
// More rows than we want?
|
||||
if (table.Rows.Count > NumberOfRows)
|
||||
{
|
||||
// Remove the first one
|
||||
table.Rows.RemoveAt(0);
|
||||
}
|
||||
|
||||
// Add a new row
|
||||
AddExchangeRateRow(table);
|
||||
|
||||
// Refresh and wait for a while
|
||||
ctx.Refresh();
|
||||
await Task.Delay(400);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void AddExchangeRateRow(Table table)
|
||||
{
|
||||
var (source, destination, rate) = GetExchangeRate();
|
||||
table.AddRow(
|
||||
source, destination,
|
||||
_random.NextDouble() > 0.35D ? $"[green]{rate}[/]" : $"[red]{rate}[/]");
|
||||
}
|
||||
|
||||
private static (string Source, string Destination, double Rate) GetExchangeRate()
|
||||
{
|
||||
var source = _exchanges[_random.Next(0, _exchanges.Length)];
|
||||
var dest = _exchanges[_random.Next(0, _exchanges.Length)];
|
||||
var rate = 200 / ((_random.NextDouble() * 320) + 1);
|
||||
|
||||
while (source == dest)
|
||||
{
|
||||
dest = _exchanges[_random.Next(0, _exchanges.Length)];
|
||||
}
|
||||
|
||||
return (source, dest, rate);
|
||||
}
|
||||
}
|
||||
}
|
@ -63,6 +63,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tables", "Console\Tables\Ta
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Trees", "Console\Trees\Trees.csproj", "{2BD88288-E05D-4978-B045-17937078E63C}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LiveTable", "Console\LiveTable\LiveTable.csproj", "{E5FAAFB4-1D0F-4E29-A94F-A647D64AE64E}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -409,6 +411,18 @@ Global
|
||||
{2BD88288-E05D-4978-B045-17937078E63C}.Release|x64.Build.0 = Release|Any CPU
|
||||
{2BD88288-E05D-4978-B045-17937078E63C}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{2BD88288-E05D-4978-B045-17937078E63C}.Release|x86.Build.0 = Release|Any CPU
|
||||
{E5FAAFB4-1D0F-4E29-A94F-A647D64AE64E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E5FAAFB4-1D0F-4E29-A94F-A647D64AE64E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E5FAAFB4-1D0F-4E29-A94F-A647D64AE64E}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{E5FAAFB4-1D0F-4E29-A94F-A647D64AE64E}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{E5FAAFB4-1D0F-4E29-A94F-A647D64AE64E}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{E5FAAFB4-1D0F-4E29-A94F-A647D64AE64E}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{E5FAAFB4-1D0F-4E29-A94F-A647D64AE64E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E5FAAFB4-1D0F-4E29-A94F-A647D64AE64E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E5FAAFB4-1D0F-4E29-A94F-A647D64AE64E}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{E5FAAFB4-1D0F-4E29-A94F-A647D64AE64E}.Release|x64.Build.0 = Release|Any CPU
|
||||
{E5FAAFB4-1D0F-4E29-A94F-A647D64AE64E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{E5FAAFB4-1D0F-4E29-A94F-A647D64AE64E}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
@ -35,6 +36,28 @@ namespace Spectre.Console
|
||||
return table;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a row to the table.
|
||||
/// </summary>
|
||||
/// <param name="table">The table to add the row to.</param>
|
||||
/// <param name="columns">The row columns to add.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static Table AddRow(this Table table, IEnumerable<IRenderable> columns)
|
||||
{
|
||||
if (table is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(table));
|
||||
}
|
||||
|
||||
if (columns is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(columns));
|
||||
}
|
||||
|
||||
table.Rows.Add(new TableRow(columns));
|
||||
return table;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a row to the table.
|
||||
/// </summary>
|
||||
@ -48,7 +71,7 @@ namespace Spectre.Console
|
||||
throw new ArgumentNullException(nameof(table));
|
||||
}
|
||||
|
||||
return table.AddRow(columns);
|
||||
return table.AddRow((IEnumerable<IRenderable>)columns);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -143,6 +166,80 @@ namespace Spectre.Console
|
||||
return table;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts a row in the table at the specified index.
|
||||
/// </summary>
|
||||
/// <param name="table">The table to add the row to.</param>
|
||||
/// <param name="index">The index to insert the row at.</param>
|
||||
/// <param name="columns">The row columns to add.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static Table InsertRow(this Table table, int index, IEnumerable<IRenderable> columns)
|
||||
{
|
||||
if (table is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(table));
|
||||
}
|
||||
|
||||
if (columns is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(columns));
|
||||
}
|
||||
|
||||
table.Rows.Insert(index, new TableRow(columns));
|
||||
return table;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts a row in the table at the specified index.
|
||||
/// </summary>
|
||||
/// <param name="table">The table to add the row to.</param>
|
||||
/// <param name="index">The index to insert the row at.</param>
|
||||
/// <param name="columns">The row columns to add.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static Table InsertRow(this Table table, int index, params IRenderable[] columns)
|
||||
{
|
||||
if (table is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(table));
|
||||
}
|
||||
|
||||
return InsertRow(table, index, (IEnumerable<IRenderable>)columns);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts a row in the table at the specified index.
|
||||
/// </summary>
|
||||
/// <param name="table">The table to add the row to.</param>
|
||||
/// <param name="index">The index to insert the row at.</param>
|
||||
/// <param name="columns">The row columns to add.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static Table InsertRow(this Table table, int index, params string[] columns)
|
||||
{
|
||||
if (table is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(table));
|
||||
}
|
||||
|
||||
return InsertRow(table, index, columns.Select(column => new Markup(column)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a row from the table with the specified index.
|
||||
/// </summary>
|
||||
/// <param name="table">The table to add the row to.</param>
|
||||
/// <param name="index">The index to remove the row at.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public static Table RemoveRow(this Table table, int index)
|
||||
{
|
||||
if (table is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(table));
|
||||
}
|
||||
|
||||
table.Rows.RemoveAt(index);
|
||||
return table;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the table width.
|
||||
/// </summary>
|
||||
|
@ -11,7 +11,6 @@ namespace Spectre.Console
|
||||
public sealed class Table : Renderable, IHasTableBorder, IExpandable, IAlignable
|
||||
{
|
||||
private readonly List<TableColumn> _columns;
|
||||
private readonly List<TableRow> _rows;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the table columns.
|
||||
@ -21,7 +20,7 @@ namespace Spectre.Console
|
||||
/// <summary>
|
||||
/// Gets the table rows.
|
||||
/// </summary>
|
||||
public IReadOnlyList<TableRow> Rows => _rows;
|
||||
public TableRowCollection Rows { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public TableBorder Border { get; set; } = TableBorder.Square;
|
||||
@ -81,7 +80,7 @@ namespace Spectre.Console
|
||||
public Table()
|
||||
{
|
||||
_columns = new List<TableColumn>();
|
||||
_rows = new List<TableRow>();
|
||||
Rows = new TableRowCollection(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -96,7 +95,7 @@ namespace Spectre.Console
|
||||
throw new ArgumentNullException(nameof(column));
|
||||
}
|
||||
|
||||
if (_rows.Count > 0)
|
||||
if (Rows.Count > 0)
|
||||
{
|
||||
throw new InvalidOperationException("Cannot add new columns to table with existing rows.");
|
||||
}
|
||||
@ -105,36 +104,6 @@ namespace Spectre.Console
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a row to the table.
|
||||
/// </summary>
|
||||
/// <param name="columns">The row columns to add.</param>
|
||||
/// <returns>The same instance so that multiple calls can be chained.</returns>
|
||||
public Table AddRow(IEnumerable<IRenderable> columns)
|
||||
{
|
||||
if (columns is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(columns));
|
||||
}
|
||||
|
||||
var rowColumnCount = columns.GetCount();
|
||||
if (rowColumnCount > _columns.Count)
|
||||
{
|
||||
throw new InvalidOperationException("The number of row columns are greater than the number of table columns.");
|
||||
}
|
||||
|
||||
_rows.Add(new TableRow(columns));
|
||||
|
||||
// Need to add missing columns?
|
||||
if (rowColumnCount < _columns.Count)
|
||||
{
|
||||
var diff = _columns.Count - rowColumnCount;
|
||||
Enumerable.Range(0, diff).ForEach(_ => _rows.Last().Add(Text.Empty));
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override Measurement Measure(RenderContext context, int maxWidth)
|
||||
{
|
||||
@ -190,7 +159,7 @@ namespace Spectre.Console
|
||||
}
|
||||
|
||||
// Add rows
|
||||
rows.AddRange(_rows);
|
||||
rows.AddRange(Rows);
|
||||
|
||||
// Show footers?
|
||||
if (ShowFooters && _columns.Any(c => c.Footer != null))
|
||||
|
@ -12,6 +12,11 @@ namespace Spectre.Console
|
||||
{
|
||||
private readonly List<IRenderable> _items;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of columns in the row.
|
||||
/// </summary>
|
||||
public int Count => _items.Count;
|
||||
|
||||
internal bool IsHeader { get; }
|
||||
internal bool IsFooter { get; }
|
||||
|
||||
|
160
src/Spectre.Console/Widgets/Table/TableRowCollection.cs
Normal file
160
src/Spectre.Console/Widgets/Table/TableRowCollection.cs
Normal file
@ -0,0 +1,160 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Spectre.Console.Rendering;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a collection holding table rows.
|
||||
/// </summary>
|
||||
public sealed class TableRowCollection : IReadOnlyList<TableRow>
|
||||
{
|
||||
private readonly Table _table;
|
||||
private readonly IList<TableRow> _list;
|
||||
private readonly object _lock;
|
||||
|
||||
/// <inheritdoc/>
|
||||
TableRow IReadOnlyList<TableRow>.this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
return _list[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of rows in the collection.
|
||||
/// </summary>
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
return _list.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal TableRowCollection(Table table)
|
||||
{
|
||||
_table = table ?? throw new ArgumentNullException(nameof(table));
|
||||
_list = new List<TableRow>();
|
||||
_lock = new object();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new row.
|
||||
/// </summary>
|
||||
/// <param name="columns">The columns that are part of the row to add.</param>
|
||||
/// <returns>The index of the added item.</returns>
|
||||
public int Add(IEnumerable<IRenderable> columns)
|
||||
{
|
||||
if (columns is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(columns));
|
||||
}
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
var row = CreateRow(columns);
|
||||
_list.Add(row);
|
||||
return _list.IndexOf(row);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts a new row at the specified index.
|
||||
/// </summary>
|
||||
/// <param name="index">The index to insert the row at.</param>
|
||||
/// <param name="columns">The columns that are part of the row to insert.</param>
|
||||
/// <returns>The index of the inserted item.</returns>
|
||||
public int Insert(int index, IEnumerable<IRenderable> columns)
|
||||
{
|
||||
if (columns is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(columns));
|
||||
}
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
var row = CreateRow(columns);
|
||||
_list.Insert(index, row);
|
||||
return _list.IndexOf(row);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a row at the specified index.
|
||||
/// </summary>
|
||||
/// <param name="index">The index to remove a row at.</param>
|
||||
public void RemoveAt(int index)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (index < 0)
|
||||
{
|
||||
throw new IndexOutOfRangeException("Table row index cannot be negative.");
|
||||
}
|
||||
else if (index >= _list.Count)
|
||||
{
|
||||
throw new IndexOutOfRangeException("Table row index cannot exceed the number of rows in the table.");
|
||||
}
|
||||
|
||||
_list.RemoveAt(index);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all rows.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_list.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerator<TableRow> GetEnumerator()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
var items = new TableRow[_list.Count];
|
||||
_list.CopyTo(items, 0);
|
||||
return new TableRowEnumerator(items);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
private TableRow CreateRow(IEnumerable<IRenderable> columns)
|
||||
{
|
||||
var row = new TableRow(columns);
|
||||
|
||||
if (row.Count > _table.Columns.Count)
|
||||
{
|
||||
throw new InvalidOperationException("The number of row columns are greater than the number of table columns.");
|
||||
}
|
||||
|
||||
// Need to add missing columns
|
||||
if (row.Count < _table.Columns.Count)
|
||||
{
|
||||
var diff = _table.Columns.Count - row.Count;
|
||||
Enumerable.Range(0, diff).ForEach(_ => row.Add(Text.Empty));
|
||||
}
|
||||
|
||||
return row;
|
||||
}
|
||||
}
|
||||
}
|
36
src/Spectre.Console/Widgets/Table/TableRowEnumerator.cs
Normal file
36
src/Spectre.Console/Widgets/Table/TableRowEnumerator.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Spectre.Console
|
||||
{
|
||||
internal sealed class TableRowEnumerator : IEnumerator<TableRow>
|
||||
{
|
||||
private readonly TableRow[] _items;
|
||||
private int _index;
|
||||
|
||||
public TableRow Current => _items[_index];
|
||||
object? IEnumerator.Current => _items[_index];
|
||||
|
||||
public TableRowEnumerator(TableRow[] items)
|
||||
{
|
||||
_items = items ?? throw new ArgumentNullException(nameof(items));
|
||||
_index = -1;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
_index++;
|
||||
return _index < _items.Length;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_index = -1;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
┌───────────┐
|
||||
│ Column #1 │
|
||||
├───────────┤
|
||||
│ 1 │
|
||||
│ 2 │
|
||||
│ 3 │
|
||||
└───────────┘
|
@ -0,0 +1,7 @@
|
||||
┌───────────┬───────────┐
|
||||
│ Column #1 │ Column #2 │
|
||||
├───────────┼───────────┤
|
||||
│ 1 │ 1-2 │
|
||||
│ 2 │ 2-2 │
|
||||
│ 3 │ 3-2 │
|
||||
└───────────┴───────────┘
|
@ -0,0 +1,7 @@
|
||||
┌───────────┬───────────┐
|
||||
│ Column #1 │ Column #2 │
|
||||
├───────────┼───────────┤
|
||||
│ 1 │ 1-2 │
|
||||
│ 2 │ 2-2 │
|
||||
│ 3 │ 3-2 │
|
||||
└───────────┴───────────┘
|
@ -0,0 +1,7 @@
|
||||
┌───────────┬───────────┐
|
||||
│ Column #1 │ Column #2 │
|
||||
├───────────┼───────────┤
|
||||
│ 1 │ 1-2 │
|
||||
│ 3 │ 3-2 │
|
||||
│ 2 │ 2-2 │
|
||||
└───────────┴───────────┘
|
@ -0,0 +1,7 @@
|
||||
┌───────────┬───────────┐
|
||||
│ Column #1 │ Column #2 │
|
||||
├───────────┼───────────┤
|
||||
│ 1 │ 1-2 │
|
||||
│ 3 │ 3-2 │
|
||||
│ 2 │ 2-2 │
|
||||
└───────────┴───────────┘
|
@ -0,0 +1,6 @@
|
||||
┌───────────┬───────────┐
|
||||
│ Column #1 │ Column #2 │
|
||||
├───────────┼───────────┤
|
||||
│ 1 │ 1-2 │
|
||||
│ 3 │ 3-2 │
|
||||
└───────────┴───────────┘
|
@ -0,0 +1,7 @@
|
||||
┌───────────┐
|
||||
│ Column #1 │
|
||||
├───────────┤
|
||||
│ 1 │
|
||||
│ 3 │
|
||||
│ 2 │
|
||||
└───────────┘
|
@ -0,0 +1,6 @@
|
||||
┌───────────┐
|
||||
│ Column #1 │
|
||||
├───────────┤
|
||||
│ 1 │
|
||||
│ 3 │
|
||||
└───────────┘
|
@ -37,6 +37,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Expectations\Widgets\Table\Rows\Extensions\" />
|
||||
<Folder Include="Expectations\Widgets\Tree\" />
|
||||
</ItemGroup>
|
||||
|
||||
|
@ -1,5 +1,3 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Shouldly;
|
||||
using Spectre.Console.Testing;
|
||||
using Spectre.Console.Tests.Data;
|
||||
|
@ -0,0 +1,131 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Spectre.Console.Testing;
|
||||
using Spectre.Verify.Extensions;
|
||||
using VerifyXunit;
|
||||
using Xunit;
|
||||
|
||||
namespace Spectre.Console.Tests.Unit
|
||||
{
|
||||
[UsesVerify]
|
||||
[ExpectationPath("Widgets/Table/Rows/Extensions")]
|
||||
public sealed class TableRowCollectionExtensionsTests
|
||||
{
|
||||
[UsesVerify]
|
||||
public sealed class TheAddRowMethod
|
||||
{
|
||||
[Fact]
|
||||
[Expectation("Add", "Renderables")]
|
||||
public Task Should_Add_Renderables()
|
||||
{
|
||||
// Given
|
||||
var console = new TestConsole();
|
||||
var table = new Table();
|
||||
table.AddColumn("Column #1");
|
||||
table.AddColumn("Column #2");
|
||||
table.AddRow(new[] { new Text("1"), new Text("1-2") });
|
||||
table.AddRow(new[] { new Text("2"), new Text("2-2") });
|
||||
table.AddRow(new[] { new Text("3"), new Text("3-2") });
|
||||
|
||||
// When
|
||||
console.Write(table);
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(console.Output);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Expectation("Add", "Strings")]
|
||||
public Task Should_Add_Strings()
|
||||
{
|
||||
// Given
|
||||
var console = new TestConsole();
|
||||
var table = new Table();
|
||||
table.AddColumn("Column #1");
|
||||
table.AddColumn("Column #2");
|
||||
table.AddRow("1", "1-2");
|
||||
table.AddRow("2", "2-2");
|
||||
table.AddRow("3", "3-2");
|
||||
|
||||
// When
|
||||
console.Write(table);
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(console.Output);
|
||||
}
|
||||
}
|
||||
|
||||
[UsesVerify]
|
||||
public sealed class TheInsertRowMethod
|
||||
{
|
||||
[Fact]
|
||||
[Expectation("Insert", "Renderables")]
|
||||
public Task Should_Insert_Renderables()
|
||||
{
|
||||
// Given
|
||||
var console = new TestConsole();
|
||||
var table = new Table();
|
||||
table.AddColumn("Column #1");
|
||||
table.AddColumn("Column #2");
|
||||
table.AddRow(new[] { new Text("1"), new Text("1-2") });
|
||||
table.AddRow(new[] { new Text("2"), new Text("2-2") });
|
||||
|
||||
// When
|
||||
table.InsertRow(1, new[] { new Text("3"), new Text("3-2") });
|
||||
|
||||
// Then
|
||||
console.Write(table);
|
||||
return Verifier.Verify(console.Output);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Expectation("Insert", "Strings")]
|
||||
public Task Should_Insert_Strings()
|
||||
{
|
||||
// Given
|
||||
var console = new TestConsole();
|
||||
var table = new Table();
|
||||
table.AddColumn("Column #1");
|
||||
table.AddColumn("Column #2");
|
||||
table.AddRow("1", "1-2");
|
||||
table.AddRow("2", "2-2");
|
||||
|
||||
// When
|
||||
table.InsertRow(1, "3", "3-2");
|
||||
|
||||
|
||||
// Then
|
||||
console.Write(table);
|
||||
return Verifier.Verify(console.Output);
|
||||
}
|
||||
}
|
||||
|
||||
[UsesVerify]
|
||||
public sealed class TheRemoveRowMethod
|
||||
{
|
||||
[Fact]
|
||||
[Expectation("Remove")]
|
||||
public Task Should_Remove_Row()
|
||||
{
|
||||
// Given
|
||||
var console = new TestConsole();
|
||||
var table = new Table();
|
||||
table.AddColumn("Column #1");
|
||||
table.AddColumn("Column #2");
|
||||
table.AddRow(new[] { new Text("1"), new Text("1-2") });
|
||||
table.AddRow(new[] { new Text("2"), new Text("2-2") });
|
||||
table.AddRow(new[] { new Text("3"), new Text("3-2") });
|
||||
|
||||
// When
|
||||
table.RemoveRow(1);
|
||||
|
||||
// Then
|
||||
console.Write(table);
|
||||
return Verifier.Verify(console.Output);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,226 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Shouldly;
|
||||
using Spectre.Console.Testing;
|
||||
using Spectre.Verify.Extensions;
|
||||
using VerifyXunit;
|
||||
using Xunit;
|
||||
|
||||
namespace Spectre.Console.Tests.Unit
|
||||
{
|
||||
[ExpectationPath("Widgets/Table/Rows")]
|
||||
public sealed class TableRowCollectionTests
|
||||
{
|
||||
[UsesVerify]
|
||||
public sealed class TheAddMethod
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Throw_If_Columns_Are_Null()
|
||||
{
|
||||
// Given
|
||||
var table = new Table();
|
||||
|
||||
// When
|
||||
var result = Record.Exception(() => table.Rows.Add(null));
|
||||
|
||||
// Then
|
||||
result.ShouldBeOfType<ArgumentNullException>()
|
||||
.ParamName.ShouldBe("columns");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Add_Row_To_Collection()
|
||||
{
|
||||
// Given
|
||||
var table = new Table();
|
||||
table.AddColumn("Column #1");
|
||||
|
||||
// When
|
||||
table.Rows.Add(new[] { Text.Empty });
|
||||
|
||||
// Then
|
||||
table.Rows.Count.ShouldBe(1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Return_Index_Of_Added_Row()
|
||||
{
|
||||
// Given
|
||||
var table = new Table();
|
||||
table.AddColumn("Column #1");
|
||||
table.Rows.Add(new[] { Text.Empty });
|
||||
|
||||
// When
|
||||
var result = table.Rows.Add(new[] { Text.Empty });
|
||||
|
||||
// Then
|
||||
result.ShouldBe(1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Expectation("Add")]
|
||||
public Task Should_Add_Item_At_Correct_Place()
|
||||
{
|
||||
// Given
|
||||
var console = new TestConsole();
|
||||
var table = new Table();
|
||||
table.AddColumn("Column #1");
|
||||
table.Rows.Add(new[] { new Text("1") });
|
||||
table.Rows.Add(new[] { new Text("2") });
|
||||
table.Rows.Add(new[] { new Text("3") });
|
||||
|
||||
// When
|
||||
console.Write(table);
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(console.Output);
|
||||
}
|
||||
}
|
||||
|
||||
[UsesVerify]
|
||||
public sealed class TheInsertMethod
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Throw_If_Columns_Are_Null()
|
||||
{
|
||||
// Given
|
||||
var table = new Table();
|
||||
|
||||
// When
|
||||
var result = Record.Exception(() => table.Rows.Insert(0, null));
|
||||
|
||||
// Then
|
||||
result.ShouldBeOfType<ArgumentNullException>()
|
||||
.ParamName.ShouldBe("columns");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Insert_Row()
|
||||
{
|
||||
// Given
|
||||
var table = new Table();
|
||||
table.AddColumn("Column #1");
|
||||
table.Rows.Add(new[] { Text.Empty });
|
||||
|
||||
// When
|
||||
table.Rows.Insert(0, new[] { Text.Empty });
|
||||
|
||||
// Then
|
||||
table.Rows.Count.ShouldBe(2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Return_Index_Of_Inserted_Row()
|
||||
{
|
||||
// Given
|
||||
var table = new Table();
|
||||
table.AddColumn("Column #1");
|
||||
table.Rows.Add(new[] { new Text("1") });
|
||||
table.Rows.Add(new[] { new Text("2") });
|
||||
|
||||
// When
|
||||
var result = table.Rows.Insert(1, new[] { new Text("3") });
|
||||
|
||||
// Then
|
||||
result.ShouldBe(1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Expectation("Insert")]
|
||||
public Task Should_Insert_Item_At_Correct_Place()
|
||||
{
|
||||
// Given
|
||||
var console = new TestConsole();
|
||||
var table = new Table();
|
||||
table.AddColumn("Column #1");
|
||||
table.Rows.Add(new[] { new Text("1") });
|
||||
table.Rows.Add(new[] { new Text("2") });
|
||||
table.Rows.Insert(1, new[] { new Text("3") });
|
||||
|
||||
// When
|
||||
console.Write(table);
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(console.Output);
|
||||
}
|
||||
}
|
||||
|
||||
[UsesVerify]
|
||||
public sealed class TheRemoveMethod
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Throw_If_Index_Is_Negative()
|
||||
{
|
||||
// Given
|
||||
var table = new Table();
|
||||
table.AddColumn("Column #1");
|
||||
|
||||
// When
|
||||
var result = Record.Exception(() => table.Rows.RemoveAt(-1));
|
||||
|
||||
// Then
|
||||
result.ShouldBeOfType<IndexOutOfRangeException>()
|
||||
.Message.ShouldBe("Table row index cannot be negative.");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Throw_If_Index_Is_Larger_Than_Number_Of_Rows()
|
||||
{
|
||||
// Given
|
||||
var table = new Table();
|
||||
table.AddColumn("Column #1");
|
||||
table.Rows.Add(new[] { new Text("1") });
|
||||
table.Rows.Add(new[] { new Text("2") });
|
||||
table.Rows.Add(new[] { new Text("3") });
|
||||
|
||||
// When
|
||||
var result = Record.Exception(() => table.Rows.RemoveAt(3));
|
||||
|
||||
// Then
|
||||
result.ShouldBeOfType<IndexOutOfRangeException>()
|
||||
.Message.ShouldBe("Table row index cannot exceed the number of rows in the table.");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Expectation("Remove")]
|
||||
public Task Should_Remove_Row()
|
||||
{
|
||||
// Given
|
||||
var console = new TestConsole();
|
||||
var table = new Table();
|
||||
table.AddColumn("Column #1");
|
||||
table.Rows.Add(new[] { new Text("1") });
|
||||
table.Rows.Add(new[] { new Text("2") });
|
||||
table.Rows.Add(new[] { new Text("3") });
|
||||
table.Rows.RemoveAt(1);
|
||||
|
||||
// When
|
||||
console.Write(table);
|
||||
|
||||
// Then
|
||||
return Verifier.Verify(console.Output);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class TheClearMethod
|
||||
{
|
||||
[Fact]
|
||||
public void Should_Remove_All_Rows()
|
||||
{
|
||||
// Given
|
||||
var table = new Table();
|
||||
table.AddColumn("Column #1");
|
||||
table.Rows.Add(new[] { new Text("1") });
|
||||
table.Rows.Add(new[] { new Text("2") });
|
||||
table.Rows.Add(new[] { new Text("3") });
|
||||
table.Rows.Clear();
|
||||
|
||||
// When
|
||||
var result = table.Rows.Count;
|
||||
|
||||
// Then
|
||||
result.ShouldBe(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -78,20 +78,6 @@ namespace Spectre.Console.Tests.Unit
|
||||
.ParamName.ShouldBe("columns");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Throw_If_Renderable_Rows_Are_Null()
|
||||
{
|
||||
// Given
|
||||
var table = new Table();
|
||||
|
||||
// When
|
||||
var result = Record.Exception(() => table.AddRow(null));
|
||||
|
||||
// Then
|
||||
result.ShouldBeOfType<ArgumentNullException>()
|
||||
.ParamName.ShouldBe("columns");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Add_Empty_Items_If_User_Provides_Less_Row_Items_Than_Columns()
|
||||
{
|
@ -1,8 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Spectre.Console.Tests
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user