-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
ArgumentOutOfRangeException
when entity doesn't match pat…
…ches (#87)
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
using System.Text.Json.Serialization; | ||
using ChronoJsonDiffPatch; | ||
using FluentAssertions; | ||
|
||
namespace ChronoJsonDiffPatchTests; | ||
|
||
public class ListPatchingTests | ||
{ | ||
internal record ListItem | ||
{ | ||
[JsonPropertyName("value")] public string Value { get; set; } | ||
Check warning on line 11 in ChronoJsonDiffPatch/ChronoJsonDiffPatchTests/ListPatchingTests.cs GitHub Actions / unittest (7.0.100)
Check warning on line 11 in ChronoJsonDiffPatch/ChronoJsonDiffPatchTests/ListPatchingTests.cs GitHub Actions / unittest (8.0.100)
Check warning on line 11 in ChronoJsonDiffPatch/ChronoJsonDiffPatchTests/ListPatchingTests.cs GitHub Actions / unittest (6.0.201)
Check warning on line 11 in ChronoJsonDiffPatch/ChronoJsonDiffPatchTests/ListPatchingTests.cs GitHub Actions / coverage
Check warning on line 11 in ChronoJsonDiffPatch/ChronoJsonDiffPatchTests/ListPatchingTests.cs GitHub Actions / unittest (7.0.100)
Check warning on line 11 in ChronoJsonDiffPatch/ChronoJsonDiffPatchTests/ListPatchingTests.cs GitHub Actions / unittest (6.0.201)
Check warning on line 11 in ChronoJsonDiffPatch/ChronoJsonDiffPatchTests/ListPatchingTests.cs GitHub Actions / unittest (8.0.100)
Check warning on line 11 in ChronoJsonDiffPatch/ChronoJsonDiffPatchTests/ListPatchingTests.cs GitHub Actions / coverage
Check warning on line 11 in ChronoJsonDiffPatch/ChronoJsonDiffPatchTests/ListPatchingTests.cs GitHub Actions / pushrelease
Check warning on line 11 in ChronoJsonDiffPatch/ChronoJsonDiffPatchTests/ListPatchingTests.cs GitHub Actions / pushrelease
Check warning on line 11 in ChronoJsonDiffPatch/ChronoJsonDiffPatchTests/ListPatchingTests.cs GitHub Actions / unittest (7.0.100)
Check warning on line 11 in ChronoJsonDiffPatch/ChronoJsonDiffPatchTests/ListPatchingTests.cs GitHub Actions / unittest (6.0.201)
Check warning on line 11 in ChronoJsonDiffPatch/ChronoJsonDiffPatchTests/ListPatchingTests.cs GitHub Actions / unittest (8.0.100)
Check warning on line 11 in ChronoJsonDiffPatch/ChronoJsonDiffPatchTests/ListPatchingTests.cs GitHub Actions / coverage
|
||
} | ||
|
||
internal record EntityWithList | ||
{ | ||
[JsonPropertyName("myList")] public List<ListItem> MyList { get; set; } | ||
Check warning on line 16 in ChronoJsonDiffPatch/ChronoJsonDiffPatchTests/ListPatchingTests.cs GitHub Actions / unittest (7.0.100)
Check warning on line 16 in ChronoJsonDiffPatch/ChronoJsonDiffPatchTests/ListPatchingTests.cs GitHub Actions / unittest (8.0.100)
Check warning on line 16 in ChronoJsonDiffPatch/ChronoJsonDiffPatchTests/ListPatchingTests.cs GitHub Actions / unittest (6.0.201)
Check warning on line 16 in ChronoJsonDiffPatch/ChronoJsonDiffPatchTests/ListPatchingTests.cs GitHub Actions / coverage
Check warning on line 16 in ChronoJsonDiffPatch/ChronoJsonDiffPatchTests/ListPatchingTests.cs GitHub Actions / unittest (7.0.100)
Check warning on line 16 in ChronoJsonDiffPatch/ChronoJsonDiffPatchTests/ListPatchingTests.cs GitHub Actions / unittest (6.0.201)
Check warning on line 16 in ChronoJsonDiffPatch/ChronoJsonDiffPatchTests/ListPatchingTests.cs GitHub Actions / unittest (8.0.100)
Check warning on line 16 in ChronoJsonDiffPatch/ChronoJsonDiffPatchTests/ListPatchingTests.cs GitHub Actions / coverage
Check warning on line 16 in ChronoJsonDiffPatch/ChronoJsonDiffPatchTests/ListPatchingTests.cs GitHub Actions / pushrelease
Check warning on line 16 in ChronoJsonDiffPatch/ChronoJsonDiffPatchTests/ListPatchingTests.cs GitHub Actions / pushrelease
Check warning on line 16 in ChronoJsonDiffPatch/ChronoJsonDiffPatchTests/ListPatchingTests.cs GitHub Actions / unittest (7.0.100)
Check warning on line 16 in ChronoJsonDiffPatch/ChronoJsonDiffPatchTests/ListPatchingTests.cs GitHub Actions / unittest (6.0.201)
Check warning on line 16 in ChronoJsonDiffPatch/ChronoJsonDiffPatchTests/ListPatchingTests.cs GitHub Actions / unittest (8.0.100)
Check warning on line 16 in ChronoJsonDiffPatch/ChronoJsonDiffPatchTests/ListPatchingTests.cs GitHub Actions / coverage
|
||
} | ||
|
||
|
||
[Fact] | ||
public void Test_List_Patching_Generally_Works_With_Add_And_Reverse() | ||
{ | ||
var chain = new TimeRangePatchChain<EntityWithList>(); | ||
var initialEntity = new EntityWithList | ||
{ | ||
MyList = new List<ListItem> | ||
{ | ||
new() { Value = "Foo" }, | ||
new() { Value = "Bar" } | ||
} | ||
}; | ||
{ | ||
var updatedEntity1 = new EntityWithList | ||
{ | ||
MyList = new List<ListItem> | ||
{ | ||
new() { Value = "fOO" }, | ||
new() { Value = "bAR" } | ||
} | ||
}; | ||
var keyDate1 = new DateTimeOffset(2024, 1, 1, 0, 0, 0, TimeSpan.Zero); | ||
chain.Add(initialEntity, updatedEntity1, keyDate1); | ||
|
||
chain.Count.Should().Be(2); // [-infinity, keyDate1); [keyDate1, +infinity) | ||
ReverseAndRevert(chain, initialEntity); | ||
} | ||
|
||
{ | ||
var updatedEntity2 = new EntityWithList | ||
{ | ||
MyList = new List<ListItem> | ||
{ | ||
new() { Value = "fOO" }, | ||
new() { Value = "bAR" }, | ||
new() { Value = "bAZ" } | ||
} | ||
}; | ||
var keyDate2 = new DateTimeOffset(2025, 1, 1, 0, 0, 0, TimeSpan.Zero); | ||
chain.Add(initialEntity, updatedEntity2, keyDate2); | ||
|
||
chain.Count.Should().Be(3); // [-infinity, keyDate1); [keyDate1, keyDate2); [keyDate2, +infinity) | ||
ReverseAndRevert(chain, initialEntity); | ||
} | ||
|
||
{ | ||
var updatedEntity3 = new EntityWithList | ||
{ | ||
MyList = new List<ListItem> | ||
{ | ||
new() { Value = "Not so foo anymore" }, | ||
new() { Value = "bAR" }, | ||
new() { Value = "bAZ" } | ||
} | ||
}; | ||
var keyDate3 = new DateTimeOffset(2025, 1, 1, 0, 0, 0, TimeSpan.Zero); | ||
chain.Add(initialEntity, updatedEntity3, keyDate3); | ||
|
||
ReverseAndRevert(chain, initialEntity); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// In <see cref="Test_List_Patching_Generally_Works_With_Add_And_Reverse"/> we showed that adding and removing list entries is generally well-supported by this library. | ||
/// In this test, we show, than when users run into an <see cref="ArgumentOutOfRangeException"/>, this is probably due to initial entities not matching the expected state (corrupted). | ||
/// </summary> | ||
[Fact] | ||
public void Reproduce_ArgumentOutOfRangeException() | ||
{ | ||
var chain = new TimeRangePatchChain<EntityWithList>(); | ||
var initialEntity = new EntityWithList | ||
{ | ||
MyList = new List<ListItem> | ||
{ | ||
new() { Value = "My First Value" }, | ||
} | ||
}; | ||
var keyDate1 = new DateTimeOffset(2024, 1, 1, 0, 0, 0, TimeSpan.Zero); | ||
{ | ||
var updatedEntity1 = new EntityWithList | ||
{ | ||
MyList = new List<ListItem> | ||
{ | ||
new() { Value = "My First Value" }, | ||
new() { Value = "My Second Value" } | ||
} | ||
}; | ||
|
||
chain.Add(initialEntity, updatedEntity1, keyDate1); | ||
chain.Count.Should().Be(2); // [-infinity, keyDate1); [keyDate1, +infinity) | ||
ReverseAndRevert(chain, initialEntity); | ||
} | ||
(var antiparallelInitialEntity, var antiparallelChain) = chain.Reverse(initialEntity); | ||
antiparallelInitialEntity.Should().Match<EntityWithList>(x => x.MyList.Count == 2, because: "Initially the list had 2 items"); | ||
var patchingACorrectInitialEntity = () => antiparallelChain.PatchToDate(antiparallelInitialEntity, keyDate1 - TimeSpan.FromDays(10)); | ||
patchingACorrectInitialEntity.Should().NotThrow(); | ||
|
||
var corruptedInitialEntity = antiparallelInitialEntity; // we modify the reference here, but that's fine. We improve the readability but don't re-use the antiparallelInitialEntity anywhere downstream. | ||
corruptedInitialEntity.MyList.RemoveAt(1); | ||
var applyingPatchesToACorruptedInitialEntity = () => antiparallelChain.PatchToDate(corruptedInitialEntity, keyDate1 - TimeSpan.FromDays(10)); | ||
applyingPatchesToACorruptedInitialEntity.Should().ThrowExactly<ArgumentOutOfRangeException>(); | ||
} | ||
|
||
private static void ReverseAndRevert(TimeRangePatchChain<EntityWithList> chain, EntityWithList initialEntity) | ||
{ | ||
var (reverseEntity, reverseChain) = chain.Reverse(initialEntity); | ||
var (rereverseEntity, rereverseChain) = reverseChain.Reverse(reverseEntity); | ||
rereverseChain.Should().BeEquivalentTo(chain); | ||
initialEntity.Should().BeEquivalentTo(rereverseEntity); | ||
} | ||
} |