mirror of
https://github.com/radzenhq/radzen-blazor.git
synced 2026-07-08 18:16:08 +00:00
Three coupled refactors that share callers and tests: 1. Anchored drawing commands: IAnchoredDrawing interface; replace four near-identical Move/Resize Chart/Image commands with generic MoveAnchoredCommand<T> and ResizeAnchoredCommand<T>. Fixes dead-code null check in Unexecute and adds the missing null guard in the TwoCellAnchor Resize ctor. 2. Drawing overlay base: extract DrawingOverlayBase<T> covering ~95% duplication between ChartOverlay and ImageOverlay. Fix four buggy resize-handle predicates while consolidating (e gated on bottom, w gated on bottom, etc). 3. Insert/Delete row/column commands: collapse 4 nearly-identical InsertRow*/InsertColumn* commands to InsertRowCommand and InsertColumnCommand (caller adds +1 for 'after' semantics). Replace whole-sheet snapshot inverse (SheetSnapshotCommandBase) with a surgical inverse via new DeleteRangeCommandBase. Delete the dead SheetSnapshotCommandBase. The shared RadzenSpreadsheet.razor.cs callers and the test files touch both #1 and #3, hence the combined commit.
313 lines
11 KiB
C#
313 lines
11 KiB
C#
using Xunit;
|
|
|
|
using Radzen.Documents.Spreadsheet;
|
|
namespace Radzen.Blazor.Spreadsheet.Tests;
|
|
|
|
public class RowColumnCommandTests
|
|
{
|
|
[Fact]
|
|
public void DeleteRowsCommand_SingleRow_ExecuteAndUndo_RestoresState()
|
|
{
|
|
var sheet = new Worksheet(4, 3);
|
|
var view = new SheetView(sheet);
|
|
sheet.Cells[0, 0].Value = "R1";
|
|
sheet.Cells[1, 0].Value = "R2";
|
|
sheet.Cells[2, 0].Value = "R3";
|
|
sheet.Cells[3, 0].Value = "R4";
|
|
|
|
var cmd = new DeleteRowsCommand(sheet, 1, 1);
|
|
Assert.True(view.Commands.Execute(cmd));
|
|
|
|
Assert.Equal(3, sheet.RowCount);
|
|
Assert.Equal("R1", sheet.Cells[0, 0].Value);
|
|
Assert.Equal("R3", sheet.Cells[1, 0].Value);
|
|
Assert.Equal("R4", sheet.Cells[2, 0].Value);
|
|
|
|
view.Commands.Undo();
|
|
|
|
Assert.Equal(4, sheet.RowCount);
|
|
Assert.Equal("R1", sheet.Cells[0, 0].Value);
|
|
Assert.Equal("R2", sheet.Cells[1, 0].Value);
|
|
Assert.Equal("R3", sheet.Cells[2, 0].Value);
|
|
Assert.Equal("R4", sheet.Cells[3, 0].Value);
|
|
}
|
|
|
|
[Fact]
|
|
public void DeleteRowsCommand_ExecuteAndUndo_RestoresState()
|
|
{
|
|
var sheet = new Worksheet(6, 3);
|
|
var view = new SheetView(sheet);
|
|
sheet.Cells[0, 0].Value = "R1";
|
|
sheet.Cells[1, 0].Value = "R2";
|
|
sheet.Cells[2, 0].Value = "R3";
|
|
sheet.Cells[3, 0].Value = "R4";
|
|
sheet.Cells[4, 0].Value = "R5";
|
|
sheet.Cells[5, 0].Value = "R6";
|
|
|
|
var cmd = new DeleteRowsCommand(sheet, 1, 3); // delete rows 2..4
|
|
Assert.True(view.Commands.Execute(cmd));
|
|
|
|
Assert.Equal(3, sheet.RowCount);
|
|
Assert.Equal("R1", sheet.Cells[0, 0].Value);
|
|
Assert.Equal("R5", sheet.Cells[1, 0].Value);
|
|
Assert.Equal("R6", sheet.Cells[2, 0].Value);
|
|
|
|
view.Commands.Undo();
|
|
Assert.Equal(6, sheet.RowCount);
|
|
Assert.Equal("R1", sheet.Cells[0, 0].Value);
|
|
Assert.Equal("R2", sheet.Cells[1, 0].Value);
|
|
Assert.Equal("R3", sheet.Cells[2, 0].Value);
|
|
Assert.Equal("R4", sheet.Cells[3, 0].Value);
|
|
Assert.Equal("R5", sheet.Cells[4, 0].Value);
|
|
Assert.Equal("R6", sheet.Cells[5, 0].Value);
|
|
}
|
|
|
|
[Fact]
|
|
public void InsertRowAfterCommand_ExecuteAndUndo_RestoresState()
|
|
{
|
|
var sheet = new Worksheet(4, 3);
|
|
var view = new SheetView(sheet);
|
|
sheet.Cells[1, 0].Value = 1d; // A2
|
|
sheet.Cells[1, 1].Formula = "=A2+10"; // B2
|
|
|
|
var cmd = new InsertRowCommand(sheet, 2); // after row 1 -> insert at index 2
|
|
Assert.True(view.Commands.Execute(cmd));
|
|
|
|
Assert.Equal(5, sheet.RowCount);
|
|
// Inserting after row 1 does not move row 1; A2 and B2 stay
|
|
Assert.Equal(1d, sheet.Cells[1, 0].Value);
|
|
Assert.Equal("=A2+10", sheet.Cells[1, 1].Formula);
|
|
Assert.Equal(11d, sheet.Cells[1, 1].Value);
|
|
|
|
view.Commands.Undo();
|
|
|
|
Assert.Equal(4, sheet.RowCount);
|
|
Assert.Equal(1d, sheet.Cells[1, 0].Value);
|
|
Assert.Equal("=A2+10", sheet.Cells[1, 1].Formula);
|
|
}
|
|
|
|
[Fact]
|
|
public void InsertRowBeforeCommand_ExecuteAndUndo_RestoresState()
|
|
{
|
|
var sheet = new Worksheet(4, 3);
|
|
var view = new SheetView(sheet);
|
|
sheet.Cells[1, 0].Value = 1d; // A2
|
|
sheet.Cells[1, 1].Formula = "=A2+10"; // B2
|
|
|
|
var cmd = new InsertRowCommand(sheet, 1); // before row 1 -> insert at index 1
|
|
Assert.True(view.Commands.Execute(cmd));
|
|
|
|
Assert.Equal(5, sheet.RowCount);
|
|
// value shifted down (A2 becomes A3)
|
|
Assert.Equal(1d, sheet.Cells[2, 0].Value);
|
|
// formula shifted down and reference updated A2->A3
|
|
Assert.Equal("=A3+10", sheet.Cells[2, 1].Formula);
|
|
Assert.Equal(11d, sheet.Cells[2, 1].Value);
|
|
|
|
view.Commands.Undo();
|
|
|
|
Assert.Equal(4, sheet.RowCount);
|
|
Assert.Equal(1d, sheet.Cells[1, 0].Value);
|
|
Assert.Equal("=A2+10", sheet.Cells[1, 1].Formula);
|
|
}
|
|
|
|
[Fact]
|
|
public void InsertRowAfterCommand_WithMultiSelection_InsertsAfterLastRow()
|
|
{
|
|
var sheet = new Worksheet(6, 2);
|
|
var view = new SheetView(sheet);
|
|
// Mark rows with their index in A
|
|
for (int r = 0; r < 6; r++) sheet.Cells[r, 0].Value = r + 1;
|
|
|
|
// Simulate selection rows 1..3 (0-based), last is 3 -> insert after 3 at index 4
|
|
var cmd = new InsertRowCommand(sheet, 4);
|
|
Assert.True(view.Commands.Execute(cmd));
|
|
|
|
Assert.Equal(7, sheet.RowCount);
|
|
// Inserted row at index 4 is empty
|
|
Assert.Null(sheet.Cells[4, 0].Value);
|
|
// Row 5 takes previous row 4 value (5)
|
|
Assert.Equal(5d, sheet.Cells[5, 0].Value);
|
|
// Row 6 takes previous row 5 value (6)
|
|
Assert.Equal(6d, sheet.Cells[6, 0].Value);
|
|
|
|
view.Commands.Undo();
|
|
Assert.Equal(6, sheet.RowCount);
|
|
Assert.Equal(5d, sheet.Cells[4, 0].Value);
|
|
}
|
|
|
|
[Fact]
|
|
public void InsertRowBeforeCommand_WithMultiSelection_InsertsBeforeFirstRow()
|
|
{
|
|
var sheet = new Worksheet(6, 2);
|
|
var view = new SheetView(sheet);
|
|
for (int r = 0; r < 6; r++) sheet.Cells[r, 0].Value = r + 1;
|
|
|
|
// Simulate selection rows 2..4 (first is 2) -> insert at index 2
|
|
var cmd = new InsertRowCommand(sheet, 2);
|
|
Assert.True(view.Commands.Execute(cmd));
|
|
|
|
Assert.Equal(7, sheet.RowCount);
|
|
// Inserted row at index 2 is empty
|
|
Assert.Null(sheet.Cells[2, 0].Value);
|
|
// Row 3 takes previous row 2 value (3)
|
|
Assert.Equal(3d, sheet.Cells[3, 0].Value);
|
|
|
|
view.Commands.Undo();
|
|
Assert.Equal(6, sheet.RowCount);
|
|
Assert.Equal(3d, sheet.Cells[2, 0].Value);
|
|
}
|
|
|
|
[Fact]
|
|
public void InsertColumnAfterCommand_WithMultiSelection_InsertsAfterLastColumn()
|
|
{
|
|
var sheet = new Worksheet(2, 6);
|
|
var view = new SheetView(sheet);
|
|
// Mark columns with their index in row 1
|
|
for (int c = 0; c < 6; c++) sheet.Cells[0, c].Value = c + 1;
|
|
|
|
// Simulate selection columns 1..3 (last is 3) -> insert after col 3 at index 4
|
|
var cmd = new InsertColumnCommand(sheet, 4);
|
|
Assert.True(view.Commands.Execute(cmd));
|
|
|
|
Assert.Equal(7, sheet.ColumnCount);
|
|
// Inserted column at index 4 is empty
|
|
Assert.Null(sheet.Cells[0, 4].Value);
|
|
// Column 5 takes previous column 4 value (5)
|
|
Assert.Equal(5d, sheet.Cells[0, 5].Value);
|
|
|
|
view.Commands.Undo();
|
|
Assert.Equal(6, sheet.ColumnCount);
|
|
Assert.Equal(5d, sheet.Cells[0, 4].Value);
|
|
}
|
|
|
|
[Fact]
|
|
public void InsertColumnBeforeCommand_WithMultiSelection_InsertsBeforeFirstColumn()
|
|
{
|
|
var sheet = new Worksheet(2, 6);
|
|
var view = new SheetView(sheet);
|
|
for (int c = 0; c < 6; c++) sheet.Cells[0, c].Value = c + 1;
|
|
|
|
// Simulate selection columns 2..4 (first is 2) -> insert at index 2
|
|
var cmd = new InsertColumnCommand(sheet, 2);
|
|
Assert.True(view.Commands.Execute(cmd));
|
|
|
|
Assert.Equal(7, sheet.ColumnCount);
|
|
// Inserted column at index 2 is empty
|
|
Assert.Null(sheet.Cells[0, 2].Value);
|
|
// Column 3 takes previous column 2 value (3)
|
|
Assert.Equal(3d, sheet.Cells[0, 3].Value);
|
|
|
|
view.Commands.Undo();
|
|
Assert.Equal(6, sheet.ColumnCount);
|
|
Assert.Equal(3d, sheet.Cells[0, 2].Value);
|
|
}
|
|
|
|
[Fact]
|
|
public void DeleteColumnsCommand_SingleColumn_ExecuteAndUndo_RestoresState()
|
|
{
|
|
var sheet = new Worksheet(3, 4);
|
|
var view = new SheetView(sheet);
|
|
sheet.Cells[0, 0].Value = "A";
|
|
sheet.Cells[0, 1].Value = "B";
|
|
sheet.Cells[0, 2].Value = "C";
|
|
sheet.Cells[0, 3].Value = "D";
|
|
|
|
var cmd = new DeleteColumnsCommand(sheet, 1, 1);
|
|
Assert.True(view.Commands.Execute(cmd));
|
|
|
|
Assert.Equal(3, sheet.ColumnCount);
|
|
Assert.Equal("A", sheet.Cells[0, 0].Value);
|
|
Assert.Equal("C", sheet.Cells[0, 1].Value);
|
|
Assert.Equal("D", sheet.Cells[0, 2].Value);
|
|
|
|
view.Commands.Undo();
|
|
|
|
Assert.Equal(4, sheet.ColumnCount);
|
|
Assert.Equal("A", sheet.Cells[0, 0].Value);
|
|
Assert.Equal("B", sheet.Cells[0, 1].Value);
|
|
Assert.Equal("C", sheet.Cells[0, 2].Value);
|
|
Assert.Equal("D", sheet.Cells[0, 3].Value);
|
|
}
|
|
|
|
[Fact]
|
|
public void DeleteColumnsCommand_ExecuteAndUndo_RestoresState()
|
|
{
|
|
var sheet = new Worksheet(3, 6);
|
|
var view = new SheetView(sheet);
|
|
sheet.Cells[0, 0].Value = "A";
|
|
sheet.Cells[0, 1].Value = "B";
|
|
sheet.Cells[0, 2].Value = "C";
|
|
sheet.Cells[0, 3].Value = "D";
|
|
sheet.Cells[0, 4].Value = "E";
|
|
sheet.Cells[0, 5].Value = "F";
|
|
|
|
var cmd = new DeleteColumnsCommand(sheet, 1, 3); // delete B..D
|
|
Assert.True(view.Commands.Execute(cmd));
|
|
|
|
Assert.Equal(3, sheet.ColumnCount);
|
|
Assert.Equal("A", sheet.Cells[0, 0].Value);
|
|
Assert.Equal("E", sheet.Cells[0, 1].Value);
|
|
Assert.Equal("F", sheet.Cells[0, 2].Value);
|
|
|
|
view.Commands.Undo();
|
|
|
|
Assert.Equal(6, sheet.ColumnCount);
|
|
Assert.Equal("A", sheet.Cells[0, 0].Value);
|
|
Assert.Equal("B", sheet.Cells[0, 1].Value);
|
|
Assert.Equal("C", sheet.Cells[0, 2].Value);
|
|
Assert.Equal("D", sheet.Cells[0, 3].Value);
|
|
Assert.Equal("E", sheet.Cells[0, 4].Value);
|
|
Assert.Equal("F", sheet.Cells[0, 5].Value);
|
|
}
|
|
|
|
[Fact]
|
|
public void InsertColumnBeforeCommand_ExecuteAndUndo_RestoresState()
|
|
{
|
|
var sheet = new Worksheet(5, 5);
|
|
var view = new SheetView(sheet);
|
|
sheet.Cells[1, 0].Value = 1d; // A2
|
|
sheet.Cells[1, 1].Formula = "=A2+10"; // B2
|
|
|
|
var cmd = new InsertColumnCommand(sheet, 0); // before A
|
|
Assert.True(view.Commands.Execute(cmd));
|
|
|
|
Assert.Equal(6, sheet.ColumnCount);
|
|
// value shifted right (A2 becomes B2)
|
|
Assert.Equal(1d, sheet.Cells[1, 1].Value);
|
|
// formula shifted right and reference updated A2->B2
|
|
Assert.Equal("=B2+10", sheet.Cells[1, 2].Formula); // original B2 moved to C2
|
|
Assert.Equal(11d, sheet.Cells[1, 2].Value);
|
|
|
|
view.Commands.Undo();
|
|
|
|
Assert.Equal(5, sheet.ColumnCount);
|
|
Assert.Equal(1d, sheet.Cells[1, 0].Value);
|
|
Assert.Equal("=A2+10", sheet.Cells[1, 1].Formula);
|
|
}
|
|
|
|
[Fact]
|
|
public void InsertColumnAfterCommand_ExecuteAndUndo_RestoresState()
|
|
{
|
|
var sheet = new Worksheet(5, 5);
|
|
var view = new SheetView(sheet);
|
|
sheet.Cells[1, 0].Value = 1d; // A2
|
|
sheet.Cells[1, 1].Formula = "=A2+10"; // B2
|
|
|
|
var cmd = new InsertColumnCommand(sheet, 1); // after A
|
|
Assert.True(view.Commands.Execute(cmd));
|
|
|
|
Assert.Equal(6, sheet.ColumnCount);
|
|
// value at A2 stays, but B2 moves to C2; formula references should update if referencing >= inserted column
|
|
Assert.Equal(1d, sheet.Cells[1, 0].Value);
|
|
Assert.Equal("=A2+10", sheet.Cells[1, 2].Formula); // original B2 moved to C2
|
|
Assert.Equal(11d, sheet.Cells[1, 2].Value);
|
|
|
|
view.Commands.Undo();
|
|
|
|
Assert.Equal(5, sheet.ColumnCount);
|
|
Assert.Equal(1d, sheet.Cells[1, 0].Value);
|
|
Assert.Equal("=A2+10", sheet.Cells[1, 1].Formula);
|
|
}
|
|
}
|