Pin Holds on every list shape, and drop C#'s redundant first-slot check
CultElementIds.Holds is the one fact a store marks its header by; a test now drives it directly over a dictionary value, a list of lists, a list under an unset element and an element, and over unset ids that hold nothing, so a mutant that skips any of those branches fails. C# ReadStoreHeader refused a first-slot string without the cultcache.store. prefix and then ran RequireSingleFileFormat, which refuses every string that is not v1, v2 or v3 anyway. The prefix check is gone; a non-header string is refused as a format this runtime does not read. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
0be33c1198
commit
fd1cf22ffe
2 changed files with 19 additions and 2 deletions
|
|
@ -270,9 +270,8 @@ public static class CultDocumentMessagePackSerialization
|
|||
var reader = new MessagePackReader(bytes);
|
||||
if (reader.ReadArrayHeader() == 0 || reader.NextMessagePackType != MessagePackType.String)
|
||||
return null;
|
||||
// A first slot that is a string is a header, and one this runtime does not read is refused, whatever the string says.
|
||||
var header = reader.ReadString() ?? string.Empty;
|
||||
if (!header.StartsWith("cultcache.store.", StringComparison.Ordinal))
|
||||
throw new NotSupportedException($"The store's first slot is the string '{header}', not a store header; it is not rewritten.");
|
||||
RequireSingleFileFormat(new CultPersistedStoreSnapshot { FormatVersion = header });
|
||||
return header;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,6 +67,24 @@ namespace GameCult.Caching.Tests
|
|||
Assert.That(Assign(root, "r", deterministic: false), Is.EqualTo(0), "a second pass finds nothing unset");
|
||||
}
|
||||
|
||||
// Holds is what a store marks its header by: an id anywhere a list can sit counts, and an unset one does not.
|
||||
[Test]
|
||||
public void HoldsFindsASetIdWhereverAListCanSitAndNothingElse()
|
||||
{
|
||||
const string id = "0123456789ab";
|
||||
Assert.That(CultElementIds.Holds(null), Is.False);
|
||||
Assert.That(CultElementIds.Holds(new HAll
|
||||
{
|
||||
Dict = { ["k"] = new HHasIds { Items = { new EIded() } } },
|
||||
Grid = { new List<EIded> { new EIded() } },
|
||||
Nest = { new ENest { Sub = { new EIded() } } },
|
||||
}), Is.False, "unset ids hold nothing");
|
||||
Assert.That(CultElementIds.Holds(new HAll { Dict = { ["k"] = new HHasIds { Items = { new EIded { Id = id } } } } }), Is.True, "a dictionary value");
|
||||
Assert.That(CultElementIds.Holds(new HAll { Grid = { new List<EIded> { new EIded { Id = id } } } }), Is.True, "a list of lists");
|
||||
Assert.That(CultElementIds.Holds(new HAll { Nest = { new ENest { Sub = { new EIded { Id = id } } } } }), Is.True, "a list under an unset element");
|
||||
Assert.That(CultElementIds.Holds(new HAll { Nest = { new ENest { Id = id } } }), Is.True, "an element");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void APlanCountsAndChangesNothingUntilApplied()
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue