Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions UndoRedo.Test/SerializationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,84 @@
Assert.HasCount(1, stack.SaveBoundaries, "A failed restore should keep the existing save boundaries");
}

[TestMethod]
[DataRow(-7, DisplayName = "boundary before the start")]
[DataRow(-2, DisplayName = "boundary one before the start")]
[DataRow(2, DisplayName = "boundary at the command count")]
[DataRow(42, DisplayName = "boundary far past the last command")]
public void UndoRedoService_RestoreFromStateInvalidBoundaryPosition_ReturnsFalseAndKeepsHistory(int boundaryPosition)
{
// Arrange
UndoRedoService stack = CreateService();
stack.Execute(new DelegateCommand("A", () => { }, () => { }));
stack.MarkAsSaved();

UndoRedoStackState state = new(
[new DelegateCommand("X", () => { }, () => { }), new DelegateCommand("Y", () => { }, () => { })],
1,
[new SaveBoundary(boundaryPosition)],
"1.0",
DateTime.UtcNow);

// Act
bool success = stack.RestoreFromState(state);

// Assert
Assert.IsFalse(success, "RestoreFromState should reject a save boundary outside the commands");
Assert.AreEqual(1, stack.CommandCount, "A failed restore should keep the existing commands");
Assert.AreEqual(0, stack.CurrentPosition, "A failed restore should keep the existing position");
Assert.HasCount(1, stack.SaveBoundaries, "A failed restore should keep the existing save boundaries");
Assert.AreEqual(0, stack.SaveBoundaries[0].Position, "A failed restore should keep the existing save boundary position");
}

[TestMethod]
[DataRow(-1, DisplayName = "boundary at the initial position")]
[DataRow(1, DisplayName = "boundary at the last command")]
public void UndoRedoService_RestoreFromStateBoundaryAtEdge_Restores(int boundaryPosition)
{
// Arrange
UndoRedoService stack = CreateService();
UndoRedoStackState state = new(
[new DelegateCommand("X", () => { }, () => { }), new DelegateCommand("Y", () => { }, () => { })],
1,
[new SaveBoundary(boundaryPosition)],
"1.0",
DateTime.UtcNow);

// Act
bool success = stack.RestoreFromState(state);

// Assert
Assert.IsTrue(success, "RestoreFromState should accept a save boundary at -1 or at the last command");
Assert.HasCount(1, stack.SaveBoundaries);
Assert.AreEqual(boundaryPosition, stack.SaveBoundaries[0].Position);
}

[TestMethod]
public async Task UndoRedoService_LoadStateAsyncInvalidBoundaryPosition_ReturnsFalseAndKeepsHistory()
{
// Arrange
JsonUndoRedoSerializer serializer = new();
byte[] data = await serializer.SerializeAsync(
[new TestSerializableCommand("X")],
0,
[new SaveBoundary(-7), new SaveBoundary(42)]).ConfigureAwait(false);

Check warning on line 531 in UndoRedo.Test/SerializationTests.cs

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Consider using the overload that accepts a CancellationToken and pass 'TestContext.CancellationToken'

See more on https://sonarcloud.io/project/issues?id=ktsu-dev_UndoRedo&issues=AaDfOmJLTFIbZ_TpYZoq&open=AaDfOmJLTFIbZ_TpYZoq&pullRequest=97

UndoRedoService stack = CreateService();
stack.SetSerializer(new JsonUndoRedoSerializer());
stack.Execute(new DelegateCommand("A", () => { }, () => { }));
stack.MarkAsSaved();

// Act
bool success = await stack.LoadStateAsync(data).ConfigureAwait(false);

Check warning on line 539 in UndoRedo.Test/SerializationTests.cs

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Consider using the overload that accepts a CancellationToken and pass 'TestContext.CancellationToken'

See more on https://sonarcloud.io/project/issues?id=ktsu-dev_UndoRedo&issues=AaDfOmJLTFIbZ_TpYZor&open=AaDfOmJLTFIbZ_TpYZor&pullRequest=97

// Assert
Assert.IsFalse(success, "LoadStateAsync should reject save boundaries outside the commands");
Assert.AreEqual(1, stack.CommandCount, "A failed load should keep the existing commands");
Assert.HasCount(1, stack.SaveBoundaries, "A failed load should keep the existing save boundaries");
Assert.AreEqual(0, stack.SaveBoundaries[0].Position, "A failed load should keep the existing save boundary position");
}

private sealed class ConstructorOnlySerializableCommand(string value)
: BaseCommand(ChangeType.Modify, ["test"]), ISerializableCommand
{
Expand Down
1 change: 1 addition & 0 deletions UndoRedo/Services/UndoRedoService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@

try
{
await _navigationProvider.NavigateToAsync(command.NavigationContext!, cts.Token).ConfigureAwait(false);

Check warning on line 175 in UndoRedo/Services/UndoRedoService.cs

View workflow job for this annotation

GitHub Actions / Analyze & Release

Remove this null-forgiving operator; the compiler already knows this expression is not null here.

Check warning on line 175 in UndoRedo/Services/UndoRedoService.cs

View workflow job for this annotation

GitHub Actions / Analyze & Release

Remove this null-forgiving operator; the compiler already knows this expression is not null here.

Check warning on line 175 in UndoRedo/Services/UndoRedoService.cs

View workflow job for this annotation

GitHub Actions / Analyze & Release

Remove this null-forgiving operator; the compiler already knows this expression is not null here.

Check warning on line 175 in UndoRedo/Services/UndoRedoService.cs

View workflow job for this annotation

GitHub Actions / Analyze & Release

Remove this null-forgiving operator; the compiler already knows this expression is not null here.
}
catch (OperationCanceledException)
{
Expand Down Expand Up @@ -208,7 +208,7 @@

try
{
await _navigationProvider.NavigateToAsync(command.NavigationContext!, cts.Token).ConfigureAwait(false);

Check warning on line 211 in UndoRedo/Services/UndoRedoService.cs

View workflow job for this annotation

GitHub Actions / Analyze & Release

Remove this null-forgiving operator; the compiler already knows this expression is not null here.

Check warning on line 211 in UndoRedo/Services/UndoRedoService.cs

View workflow job for this annotation

GitHub Actions / Analyze & Release

Remove this null-forgiving operator; the compiler already knows this expression is not null here.

Check warning on line 211 in UndoRedo/Services/UndoRedoService.cs

View workflow job for this annotation

GitHub Actions / Analyze & Release

Remove this null-forgiving operator; the compiler already knows this expression is not null here.

Check warning on line 211 in UndoRedo/Services/UndoRedoService.cs

View workflow job for this annotation

GitHub Actions / Analyze & Release

Remove this null-forgiving operator; the compiler already knows this expression is not null here.
}
catch (OperationCanceledException)
{
Expand Down Expand Up @@ -274,7 +274,7 @@

try
{
await _navigationProvider.NavigateToAsync(lastCommand.NavigationContext!, cts.Token).ConfigureAwait(false);

Check warning on line 277 in UndoRedo/Services/UndoRedoService.cs

View workflow job for this annotation

GitHub Actions / Analyze & Release

Remove this null-forgiving operator; the compiler already knows this expression is not null here.

Check warning on line 277 in UndoRedo/Services/UndoRedoService.cs

View workflow job for this annotation

GitHub Actions / Analyze & Release

Remove this null-forgiving operator; the compiler already knows this expression is not null here.
}
catch (OperationCanceledException)
{
Expand Down Expand Up @@ -396,6 +396,7 @@
state.SaveBoundaries is not null &&
!state.Commands.Any(command => command is null) &&
!state.SaveBoundaries.Any(boundary => boundary is null) &&
state.SaveBoundaries.All(boundary => boundary.Position >= -1 && boundary.Position < state.Commands.Count) &&
state.CurrentPosition >= -1 &&
state.CurrentPosition < state.Commands.Count;
}
Loading