From e3dfe23b5986fa1507198a41425dfc357ce3316f Mon Sep 17 00:00:00 2001 From: Christopher Rollings Date: Mon, 27 Sep 2021 12:03:45 +0100 Subject: [PATCH] Work done to allow user to update table cell. (#546) --- .../Extensions/TableExtensions.cs | 50 +++++++ .../Widgets/Table/TableRowCollection.cs | 49 ++++++ ...pdateMethod.Should_Update_Row.verified.txt | 7 + ...ld_Update_Row_With_Renderable.verified.txt | 7 + ...Should_Update_Row_With_String.verified.txt | 7 + .../Widgets/Table/TableRowCollectionTests.cs | 140 ++++++++++++++++++ 6 files changed, 260 insertions(+) create mode 100644 test/Spectre.Console.Tests/Expectations/TableRowCollectionTests.TheUpdateMethod.Should_Update_Row.verified.txt create mode 100644 test/Spectre.Console.Tests/Expectations/TableRowCollectionTests.TheUpdateMethod.Should_Update_Row_With_Renderable.verified.txt create mode 100644 test/Spectre.Console.Tests/Expectations/TableRowCollectionTests.TheUpdateMethod.Should_Update_Row_With_String.verified.txt diff --git a/src/Spectre.Console/Extensions/TableExtensions.cs b/src/Spectre.Console/Extensions/TableExtensions.cs index 8f0776d..eb96933 100644 --- a/src/Spectre.Console/Extensions/TableExtensions.cs +++ b/src/Spectre.Console/Extensions/TableExtensions.cs @@ -189,6 +189,56 @@ namespace Spectre.Console return table; } + /// + /// Updates a tables cell. + /// + /// The table to update. + /// The index of row to update. + /// The index of column to update. + /// New cell data. + /// The same instance so that multiple calls can be chained. + public static Table UpdateCell(this Table table, int rowIndex, int columnIndex, IRenderable cellData) + { + if (table is null) + { + throw new ArgumentNullException(nameof(table)); + } + + if (cellData is null) + { + throw new ArgumentNullException(nameof(cellData)); + } + + table.Rows.Update(rowIndex, columnIndex, cellData); + + return table; + } + + /// + /// Updates a tables cell. + /// + /// The table to update. + /// The index of row to update. + /// The index of column to update. + /// New cell data. + /// The same instance so that multiple calls can be chained. + public static Table UpdateCell(this Table table, int rowIndex, int columnIndex, string cellData) + { + if (table is null) + { + throw new ArgumentNullException(nameof(table)); + } + + if (cellData is null) + { + throw new ArgumentNullException(nameof(cellData)); + } + + table.Rows.Update(rowIndex, columnIndex, new Markup(cellData)); + + return table; + } + /// /// Inserts a row in the table at the specified index. /// diff --git a/src/Spectre.Console/Widgets/Table/TableRowCollection.cs b/src/Spectre.Console/Widgets/Table/TableRowCollection.cs index f189392..29f6128 100644 --- a/src/Spectre.Console/Widgets/Table/TableRowCollection.cs +++ b/src/Spectre.Console/Widgets/Table/TableRowCollection.cs @@ -89,6 +89,55 @@ namespace Spectre.Console } } + /// + /// Update a table cell at the specified index. + /// + /// Index of cell row. + /// index of cell column. + /// The new cells details. + public void Update(int row, int column, IRenderable cellData) + { + if (cellData is null) + { + throw new ArgumentNullException(nameof(cellData)); + } + + lock (_lock) + { + if (row < 0) + { + throw new IndexOutOfRangeException("Table row index cannot be negative."); + } + else if (row >= _list.Count) + { + throw new IndexOutOfRangeException("Table row index cannot exceed the number of rows in the table."); + } + + var tableRow = _list.ElementAtOrDefault(row); + + var currentRenderables = tableRow.ToList(); + + if (column < 0) + { + throw new IndexOutOfRangeException("Table column index cannot be negative."); + } + else if (column >= currentRenderables.Count) + { + throw new IndexOutOfRangeException("Table column index cannot exceed the number of rows in the table."); + } + + currentRenderables.RemoveAt(column); + + currentRenderables.Insert(column, cellData); + + var newTableRow = new TableRow(currentRenderables); + + _list.RemoveAt(row); + + _list.Insert(row, newTableRow); + } + } + /// /// Removes a row at the specified index. /// diff --git a/test/Spectre.Console.Tests/Expectations/TableRowCollectionTests.TheUpdateMethod.Should_Update_Row.verified.txt b/test/Spectre.Console.Tests/Expectations/TableRowCollectionTests.TheUpdateMethod.Should_Update_Row.verified.txt new file mode 100644 index 0000000..157cc59 --- /dev/null +++ b/test/Spectre.Console.Tests/Expectations/TableRowCollectionTests.TheUpdateMethod.Should_Update_Row.verified.txt @@ -0,0 +1,7 @@ +┌───────────┬───────────┬───────────┐ +│ Column #1 │ Column #2 │ Column #3 │ +├───────────┼───────────┼───────────┤ +│ 1 │ │ │ +│ 2 │ │ │ +│ 3 │ 4 │ 5 │ +└───────────┴───────────┴───────────┘ diff --git a/test/Spectre.Console.Tests/Expectations/TableRowCollectionTests.TheUpdateMethod.Should_Update_Row_With_Renderable.verified.txt b/test/Spectre.Console.Tests/Expectations/TableRowCollectionTests.TheUpdateMethod.Should_Update_Row_With_Renderable.verified.txt new file mode 100644 index 0000000..157cc59 --- /dev/null +++ b/test/Spectre.Console.Tests/Expectations/TableRowCollectionTests.TheUpdateMethod.Should_Update_Row_With_Renderable.verified.txt @@ -0,0 +1,7 @@ +┌───────────┬───────────┬───────────┐ +│ Column #1 │ Column #2 │ Column #3 │ +├───────────┼───────────┼───────────┤ +│ 1 │ │ │ +│ 2 │ │ │ +│ 3 │ 4 │ 5 │ +└───────────┴───────────┴───────────┘ diff --git a/test/Spectre.Console.Tests/Expectations/TableRowCollectionTests.TheUpdateMethod.Should_Update_Row_With_String.verified.txt b/test/Spectre.Console.Tests/Expectations/TableRowCollectionTests.TheUpdateMethod.Should_Update_Row_With_String.verified.txt new file mode 100644 index 0000000..157cc59 --- /dev/null +++ b/test/Spectre.Console.Tests/Expectations/TableRowCollectionTests.TheUpdateMethod.Should_Update_Row_With_String.verified.txt @@ -0,0 +1,7 @@ +┌───────────┬───────────┬───────────┐ +│ Column #1 │ Column #2 │ Column #3 │ +├───────────┼───────────┼───────────┤ +│ 1 │ │ │ +│ 2 │ │ │ +│ 3 │ 4 │ 5 │ +└───────────┴───────────┴───────────┘ diff --git a/test/Spectre.Console.Tests/Unit/Widgets/Table/TableRowCollectionTests.cs b/test/Spectre.Console.Tests/Unit/Widgets/Table/TableRowCollectionTests.cs index 15f931f..752baf1 100644 --- a/test/Spectre.Console.Tests/Unit/Widgets/Table/TableRowCollectionTests.cs +++ b/test/Spectre.Console.Tests/Unit/Widgets/Table/TableRowCollectionTests.cs @@ -222,5 +222,145 @@ namespace Spectre.Console.Tests.Unit result.ShouldBe(0); } } + + [UsesVerify] + public sealed class TheUpdateMethod + { + [Fact] + public Task Should_Update_Row_With_String() + { + // Given + var console = new TestConsole(); + var table = new Table(); + table.AddColumn("Column #1"); + table.AddColumn("Column #2"); + table.AddColumn("Column #3"); + table.Rows.Add(new[] { new Text("1") }); + table.Rows.Add(new[] { new Text("2") }); + table.Rows.Add(new[] { new Text("3"), new Text("4"), new Text("8") }); + + table.UpdateCell(2, 2, "5"); + + // When + console.Write(table); + + // Then + return Verifier.Verify(console.Output); + } + + [Fact] + public Task Should_Update_Row_With_Renderable() + { + // Given + var console = new TestConsole(); + var table = new Table(); + table.AddColumn("Column #1"); + table.AddColumn("Column #2"); + table.AddColumn("Column #3"); + table.Rows.Add(new[] { new Text("1") }); + table.Rows.Add(new[] { new Text("2") }); + table.Rows.Add(new[] { new Text("3"), new Text("4"), new Text("8") }); + + table.UpdateCell(2, 2, new Markup("5")); + + // When + console.Write(table); + + // Then + return Verifier.Verify(console.Output); + } + + [Fact] + public void Should_Throw_If_Index_Is_Larger_Than_Number_Of_Rows() + { + // Given + var console = new TestConsole(); + var table = new Table(); + table.AddColumn("Column #1"); + table.AddColumn("Column #2"); + table.AddColumn("Column #3"); + table.Rows.Add(new[] { new Text("1") }); + table.Rows.Add(new[] { new Text("2") }); + table.Rows.Add(new[] { new Text("3"), new Text("4"), new Text("8") }); + table.UpdateCell(2, 2, "5"); + + + // When + var result = Record.Exception(() => table.UpdateCell(5, 2, "5")); + + // Then + result.ShouldBeOfType() + .Message.ShouldBe("Table row index cannot exceed the number of rows in the table."); + } + + [Fact] + public void Should_Throw_If_Index_Is_Larger_Than_Number_Of_Columns() + { + // Given + var console = new TestConsole(); + var table = new Table(); + table.AddColumn("Column #1"); + table.AddColumn("Column #2"); + table.AddColumn("Column #3"); + table.Rows.Add(new[] { new Text("1") }); + table.Rows.Add(new[] { new Text("2") }); + table.Rows.Add(new[] { new Text("3"), new Text("4"), new Text("8") }); + table.UpdateCell(2, 2, "5"); + + + // When + var result = Record.Exception(() => table.UpdateCell(2, 5, "5")); + + // Then + result.ShouldBeOfType() + .Message.ShouldBe("Table column index cannot exceed the number of rows in the table."); + } + + [Fact] + public void Should_Throw_If_Index_Row_Is_Negative() + { + // Given + var console = new TestConsole(); + var table = new Table(); + table.AddColumn("Column #1"); + table.AddColumn("Column #2"); + table.AddColumn("Column #3"); + table.Rows.Add(new[] { new Text("1") }); + table.Rows.Add(new[] { new Text("2") }); + table.Rows.Add(new[] { new Text("3"), new Text("4"), new Text("8") }); + table.UpdateCell(2, 2, "5"); + + + // When + var result = Record.Exception(() => table.UpdateCell(-1, 2, "5")); + + // Then + result.ShouldBeOfType() + .Message.ShouldBe("Table row index cannot be negative."); + } + + [Fact] + public void Should_Throw_If_Index_Column_Is_Negative() + { + // Given + var console = new TestConsole(); + var table = new Table(); + table.AddColumn("Column #1"); + table.AddColumn("Column #2"); + table.AddColumn("Column #3"); + table.Rows.Add(new[] { new Text("1") }); + table.Rows.Add(new[] { new Text("2") }); + table.Rows.Add(new[] { new Text("3"), new Text("4"), new Text("8") }); + table.UpdateCell(2, 2, "5"); + + + // When + var result = Record.Exception(() => table.UpdateCell(2, -1, "5")); + + // Then + result.ShouldBeOfType() + .Message.ShouldBe("Table column index cannot be negative."); + } + } } }