Skip to content

Commit 0f76658

Browse files
fix: invalid operation exception
1 parent 9e5c5ad commit 0f76658

2 files changed

Lines changed: 97 additions & 13 deletions

File tree

Runtime/InputsAndSnapshots/Snapshots/ElympicsSnapshot.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ internal void MergeWithSnapshot(ElympicsSnapshot? receivedSnapshot)
6666
if (receivedSnapshot == null)
6767
return;
6868

69+
if (Tick >= receivedSnapshot.Tick)
70+
return;
71+
6972
Tick = receivedSnapshot.Tick;
7073
TickStartUtc = receivedSnapshot.TickStartUtc;
7174

Tests/Runtime/SnapshotTests.cs

Lines changed: 94 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -179,10 +179,10 @@ public void MergeWithSnapshot_CoreFunctionality_InsertsNewReplacesExistingKeepsU
179179
new FactoryState(new Dictionary<int, FactoryPartState>()),
180180
new Dictionary<int, byte[]>
181181
{
182-
{ 1, new byte[] { 1, 1, 1 } }, // Will stay UNTOUCHED
183-
{ 2, new byte[] { 2, 2, 2 } }, // Will be REPLACED
184-
{ 3, new byte[] { 3, 3, 3 } }, // Will stay UNTOUCHED
185-
{ 4, new byte[] { 4, 4, 4 } }, // Will be REPLACED
182+
{ 1, new byte[] { 1, 1, 1 } }, // Will stay UNTOUCHED
183+
{ 2, new byte[] { 2, 2, 2 } }, // Will be REPLACED
184+
{ 3, new byte[] { 3, 3, 3 } }, // Will stay UNTOUCHED
185+
{ 4, new byte[] { 4, 4, 4 } }, // Will be REPLACED
186186
},
187187
null);
188188

@@ -374,13 +374,20 @@ public void MergeWithSnapshot_WithNullReceivedData_DoesNotModifyCurrentData()
374374
public void MergeWithSnapshot_RemovesDataOfDestroyedObjects()
375375
{
376376
var currentSnapshot = new ElympicsSnapshot(
377-
-1,
377+
1,
378378
default,
379-
new(new() { { 0, new(32, new(2, new()
379+
new(new()
380380
{
381-
{ 30, new(30, 29, "path1") },
382-
{ 31, new(31, 30, "path2") }
383-
})) } }),
381+
{
382+
0, new(32,
383+
new(2,
384+
new()
385+
{
386+
{ 30, new(30, 29, "path1") },
387+
{ 31, new(31, 30, "path2") }
388+
}))
389+
}
390+
}),
384391
new Dictionary<int, byte[]>
385392
{
386393
{ 30, new byte[0] },
@@ -389,12 +396,19 @@ public void MergeWithSnapshot_RemovesDataOfDestroyedObjects()
389396
null);
390397

391398
var receivedSnapshot = new ElympicsSnapshot(
392-
-1,
399+
2,
393400
default,
394-
new(new() { { 0, new(32, new(2, new()
401+
new(new()
395402
{
396-
{ 31, new(31, 30, "path2") }
397-
})) } }),
403+
{
404+
0, new(32,
405+
new(2,
406+
new()
407+
{
408+
{ 31, new(31, 30, "path2") }
409+
}))
410+
}
411+
}),
398412
new Dictionary<int, byte[]>(),
399413
null);
400414

@@ -404,5 +418,72 @@ public void MergeWithSnapshot_RemovesDataOfDestroyedObjects()
404418
Assert.AreEqual(1, currentSnapshot.Data!.Count);
405419
Assert.AreEqual(31, currentSnapshot.Data.First().Key);
406420
}
421+
422+
[Test]
423+
public void MergeWithSnapshot_CalledTwiceWithSameSnapshot_ShouldNotThrow()
424+
{
425+
var currentSnapshot = new ElympicsSnapshot(
426+
10,
427+
default,
428+
new FactoryState(new Dictionary<int, FactoryPartState>()),
429+
null, // Data is null - this triggers aliasing on first merge
430+
null);
431+
432+
var receivedSnapshot = new ElympicsSnapshot(
433+
20,
434+
DateTime.UtcNow,
435+
new FactoryState(new Dictionary<int, FactoryPartState>()),
436+
new Dictionary<int, byte[]>
437+
{
438+
{ 1, new byte[] { 1, 2, 3 } },
439+
{ 2, new byte[] { 4, 5, 6 } },
440+
{ 3, new byte[] { 7, 8, 9 } },
441+
},
442+
null);
443+
444+
currentSnapshot.MergeWithSnapshot(receivedSnapshot);
445+
446+
Assert.That(currentSnapshot.Data,
447+
Is.SameAs(receivedSnapshot.Data),
448+
"After first merge with null Data, currentSnapshot.Data should be aliased to receivedSnapshot.Data");
449+
450+
Assert.DoesNotThrow(() => currentSnapshot.MergeWithSnapshot(receivedSnapshot),
451+
"MergeWithSnapshot should not throw when called twice with the same snapshot");
452+
453+
// Verify data integrity after both merges
454+
Assert.That(currentSnapshot.Data!.Count, Is.EqualTo(3));
455+
Assert.That(currentSnapshot.Tick, Is.EqualTo(20));
456+
}
457+
458+
[Test]
459+
public void MergeWithSnapshot_CalledTwiceWithSameSnapshot_DataIntegrity()
460+
{
461+
var currentSnapshot = new ElympicsSnapshot(
462+
10,
463+
default,
464+
new FactoryState(new Dictionary<int, FactoryPartState>()),
465+
null,
466+
null);
467+
468+
var receivedSnapshot = new ElympicsSnapshot(
469+
20,
470+
DateTime.UtcNow,
471+
new FactoryState(new Dictionary<int, FactoryPartState>()),
472+
new Dictionary<int, byte[]>
473+
{
474+
{ 1, new byte[] { 10 } },
475+
{ 2, new byte[] { 20 } },
476+
},
477+
null);
478+
479+
currentSnapshot.MergeWithSnapshot(receivedSnapshot);
480+
currentSnapshot.MergeWithSnapshot(receivedSnapshot);
481+
currentSnapshot.MergeWithSnapshot(receivedSnapshot);
482+
483+
Assert.That(currentSnapshot.Data!.Count, Is.EqualTo(2));
484+
var dataDict = currentSnapshot.Data.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
485+
Assert.That(dataDict[1], Is.EqualTo(new byte[] { 10 }));
486+
Assert.That(dataDict[2], Is.EqualTo(new byte[] { 20 }));
487+
}
407488
}
408489
}

0 commit comments

Comments
 (0)