Caching: a single-file refusal echoes a header only in its known shape
RequireSingleFileFormat echoed any header string. It now names one only in the shape cultcache.store.v<digits> and otherwise gives its byte length. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
853e8db5e5
commit
c996ae7892
2 changed files with 32 additions and 1 deletions
|
|
@ -224,7 +224,7 @@ public static class CultDocumentMessagePackSerialization
|
|||
!string.Equals(version, CultPersistedStoreSnapshot.FormatV2, StringComparison.Ordinal))
|
||||
{
|
||||
throw new NotSupportedException(
|
||||
$"Store format {version} is not readable; this runtime reads {CultPersistedStoreSnapshot.FormatV1} and {CultPersistedStoreSnapshot.FormatV2}.");
|
||||
$"Store format {DescribeHeader(version)} is not readable; this runtime reads {CultPersistedStoreSnapshot.FormatV1} and {CultPersistedStoreSnapshot.FormatV2}.");
|
||||
}
|
||||
|
||||
// Only a v2 store may hold a variant: a v1 header over a variant record is a store no reader could trust.
|
||||
|
|
@ -239,6 +239,17 @@ public static class CultDocumentMessagePackSerialization
|
|||
}
|
||||
}
|
||||
|
||||
// A store header as a refusal may show it: echoed in the shape cultcache.store.v<digits>, and otherwise described
|
||||
// only by its length, since the bytes are the store's.
|
||||
private static string DescribeHeader(string header)
|
||||
{
|
||||
const string prefix = "cultcache.store.v";
|
||||
var version = header.StartsWith(prefix, StringComparison.Ordinal) ? header.Substring(prefix.Length) : "";
|
||||
return version.Length > 0 && version.All(character => character >= '0' && character <= '9')
|
||||
? header
|
||||
: $"an unrecognised cultcache.store.* header of {System.Text.Encoding.UTF8.GetByteCount(header)} bytes";
|
||||
}
|
||||
|
||||
private static void WritePersistedRecord(ref MessagePackWriter writer, CultPersistedRecord record)
|
||||
{
|
||||
writer.WriteArrayHeader(record.Variant == null ? PersistedRecordFieldCount : VariantRecordFieldCount);
|
||||
|
|
|
|||
|
|
@ -202,6 +202,26 @@ namespace GameCult.Caching.Tests
|
|||
}
|
||||
}
|
||||
|
||||
// A refusal echoes a header only in the shape cultcache.store.v<digits>; any other is described by its length.
|
||||
[TestCase("cultcache.store.v12", true)]
|
||||
[TestCase("cultcache.store.SECRET-HEADER", false)]
|
||||
[TestCase("cultcache.store.v12SECRET", false)]
|
||||
[TestCase("cultcache.store.v", false)]
|
||||
public void SingleFileRefusalEchoesAHeaderOnlyInTheKnownShape(string header, bool echoed)
|
||||
{
|
||||
var snapshot = new CultPersistedStoreSnapshot { FormatVersion = header };
|
||||
var error = Assert.Throws<NotSupportedException>(() => CultDocumentMessagePackSerialization.RequireSingleFileFormat(snapshot))!;
|
||||
if (echoed)
|
||||
{
|
||||
Assert.That(error.Message, Does.Contain("format " + header + " is not"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.That(error.Message, Does.Not.Contain("SECRET").And.Not.Contain("format " + header + " is not"));
|
||||
Assert.That(error.Message, Does.Contain($"of {header.Length} bytes"));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void V1StoreWrittenAtTheBaseCommitStillDecodesByteForByte()
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue