diff --git a/CultLib.sln b/CultLib.sln index c56c38e8..e4cf225d 100644 --- a/CultLib.sln +++ b/CultLib.sln @@ -11,8 +11,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCult.Caching", "src\Gam EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCult.Caching.MessagePack", "src\GameCult.Caching.MessagePack\GameCult.Caching.MessagePack.csproj", "{26EE4C38-F06E-4E7A-A89C-908318BCB0DB}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCult.Caching.NewtonsoftJson", "src\GameCult.Caching.NewtonsoftJson\GameCult.Caching.NewtonsoftJson.csproj", "{6C749A7B-A037-4AD4-A210-A411E7105D31}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCult.Caching.MessagePack.Generator", "src\GameCult.Caching.MessagePack.Generator\GameCult.Caching.MessagePack.Generator.csproj", "{0E990C96-3808-450E-9349-A0C3262195ED}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameCult.Caching.MessagePack.Analyzers", "src\GameCult.Caching.MessagePack.Analyzers\GameCult.Caching.MessagePack.Analyzers.csproj", "{DBE06954-EC85-4034-9049-72C7D27556DF}" @@ -46,10 +44,6 @@ Global {26EE4C38-F06E-4E7A-A89C-908318BCB0DB}.Debug|Any CPU.Build.0 = Debug|Any CPU {26EE4C38-F06E-4E7A-A89C-908318BCB0DB}.Release|Any CPU.ActiveCfg = Release|Any CPU {26EE4C38-F06E-4E7A-A89C-908318BCB0DB}.Release|Any CPU.Build.0 = Release|Any CPU - {6C749A7B-A037-4AD4-A210-A411E7105D31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6C749A7B-A037-4AD4-A210-A411E7105D31}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6C749A7B-A037-4AD4-A210-A411E7105D31}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6C749A7B-A037-4AD4-A210-A411E7105D31}.Release|Any CPU.Build.0 = Release|Any CPU {67383F6C-C9C3-4C5B-95D4-5C50C20EDD4F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {67383F6C-C9C3-4C5B-95D4-5C50C20EDD4F}.Debug|Any CPU.Build.0 = Debug|Any CPU {67383F6C-C9C3-4C5B-95D4-5C50C20EDD4F}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -75,7 +69,6 @@ Global {72AEDD42-E881-4EB7-99A8-FD3B9667189C} = {E733CBFF-42AE-4B6A-B5B9-0071ECFB45F1} {9DDA917D-B4DB-4AC1-9B9A-4ECF06A5ABA1} = {E733CBFF-42AE-4B6A-B5B9-0071ECFB45F1} {26EE4C38-F06E-4E7A-A89C-908318BCB0DB} = {E733CBFF-42AE-4B6A-B5B9-0071ECFB45F1} - {6C749A7B-A037-4AD4-A210-A411E7105D31} = {E733CBFF-42AE-4B6A-B5B9-0071ECFB45F1} {67383F6C-C9C3-4C5B-95D4-5C50C20EDD4F} = {E733CBFF-42AE-4B6A-B5B9-0071ECFB45F1} {E2DC8FF6-D39E-4FCA-9549-1F7681F0AA81} = {39D316AB-ABB5-49A2-8E83-CAF4C75B48F4} {EB15435B-7147-4BD9-BB9C-B0A14318D3D5} = {39D316AB-ABB5-49A2-8E83-CAF4C75B48F4} diff --git a/src/GameCult.Caching.MessagePack/CultDocumentMessagePackSerialization.cs b/src/GameCult.Caching.MessagePack/CultDocumentMessagePackSerialization.cs index 57c5ec0f..b4651c95 100644 --- a/src/GameCult.Caching.MessagePack/CultDocumentMessagePackSerialization.cs +++ b/src/GameCult.Caching.MessagePack/CultDocumentMessagePackSerialization.cs @@ -308,42 +308,3 @@ public class SingleFileMessagePackBackingStore : SingleFileBackingStore return CultDocumentMessagePackSerialization.DeserializeUntyped(documentType, payload); } } - -public class MultiFileMessagePackBackingStore : MultiFileBackingStore -{ - public MultiFileMessagePackBackingStore(string path) : base(path) - { - } - - protected override byte[] SerializeRecord(CultPersistedRecord record) - { - return CultDocumentMessagePackSerialization.SerializePersistedRecord(record); - } - - protected override CultPersistedRecord DeserializeRecord(byte[] data) - { - return CultDocumentMessagePackSerialization.DeserializePersistedRecord(data); - } - - protected override byte[] SerializeCatalog(CultSchemaCatalogEntry[] catalog) - { - return CultDocumentMessagePackSerialization.SerializeSchemaCatalog(catalog); - } - - protected override CultSchemaCatalogEntry[] DeserializeCatalog(byte[] data) - { - return CultDocumentMessagePackSerialization.DeserializeSchemaCatalog(data); - } - - protected override byte[] SerializePayload(object document) - { - return CultDocumentMessagePackSerialization.SerializeUntyped(document, document.GetType()); - } - - protected override object DeserializePayload(Type documentType, byte[] payload) - { - return CultDocumentMessagePackSerialization.DeserializeUntyped(documentType, payload); - } - - public override string Extension => "msgpack"; -} diff --git a/src/GameCult.Caching.MessagePack/README.md b/src/GameCult.Caching.MessagePack/README.md index a5cef489..660da700 100644 --- a/src/GameCult.Caching.MessagePack/README.md +++ b/src/GameCult.Caching.MessagePack/README.md @@ -1,25 +1,25 @@ # GameCult.Caching.MessagePack -`GameCult.Caching.MessagePack` provides MessagePack persistence for the -attribute-first `GameCult.Caching` stack. +`GameCult.Caching.MessagePack` provides the canonical CultCache persistence +format for the attribute-first `GameCult.Caching` stack. ## Included Types - `SingleFileMessagePackBackingStore` -- `MultiFileMessagePackBackingStore` - `CultDocumentMessagePackSerialization` - `CultDocumentResolver` - `CultRecordRefFormatter` When a project declares `[CultDocument]` models, wire in the `GameCult.Caching.MessagePack.Generator` analyzer there as well. It emits -assembly-local metadata providers for the cache registry; MessagePack itself -still handles payload serialization through the normal resolver path. +assembly-local metadata providers for the cache registry. Cult documents then +serialize through explicit generated slot codecs, while the store snapshot +format is written by hand against `MessagePackWriter`/`MessagePackReader`. ## What It Does -- stores CultCache snapshots and records in MessagePack -- serializes plain attributed document payloads +- stores whole CultCache snapshots in MessagePack +- serializes plain attributed document payloads through explicit generated slot codecs - keeps explicit `CultRecordRef` values compact on disk/wire - preserves the cache/store split where metadata lives outside the domain model @@ -30,7 +30,6 @@ using GameCult.Caching; using MessagePack; [CultDocument("gamecult.item_data", "gamecult.item_data.v1")] -[MessagePackObject] public sealed class ItemData { [Key(0)] [CultName] public string Name = string.Empty; @@ -45,7 +44,7 @@ using GameCult.Caching; using GameCult.Caching.MessagePack; var cache = new CultCache(); -var store = new MultiFileMessagePackBackingStore("Data"); +var store = new SingleFileMessagePackBackingStore("Data.msgpack"); cache.AddBackingStore(store); await cache.PullAllBackingStoresAsync(); @@ -54,7 +53,7 @@ await cache.PullAllBackingStoresAsync(); ## Notes - Payload bytes are MessagePack. Store metadata and schema catalogs are also - persisted through MessagePack in this package. + persisted through hand-written MessagePack array layouts in this package. - The generator package now targets attributed document types instead of `DatabaseEntry` subclasses. - The raw CultNet document lane should treat these payload bytes as already diff --git a/src/GameCult.Caching.NewtonsoftJson/GameCult.Caching.NewtonsoftJson.csproj b/src/GameCult.Caching.NewtonsoftJson/GameCult.Caching.NewtonsoftJson.csproj deleted file mode 100644 index 72760e16..00000000 --- a/src/GameCult.Caching.NewtonsoftJson/GameCult.Caching.NewtonsoftJson.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - Newtonsoft.Json backing stores for CultCache - - - - - - - - diff --git a/src/GameCult.Caching.NewtonsoftJson/NewtonsoftJsonBackingStore.cs b/src/GameCult.Caching.NewtonsoftJson/NewtonsoftJsonBackingStore.cs deleted file mode 100644 index 84dff1b1..00000000 --- a/src/GameCult.Caching.NewtonsoftJson/NewtonsoftJsonBackingStore.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using GameCult.Caching.MessagePack; -using Newtonsoft.Json; - -namespace GameCult.Caching.NewtonsoftJson; - -public class SingleFileNewtonsoftJsonBackingStore : SingleFileBackingStore -{ - public SingleFileNewtonsoftJsonBackingStore(string filePath) : base(filePath) - { - } - - protected override byte[] SerializeSnapshot(CultPersistedStoreSnapshot snapshot) - { - return System.Text.Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(snapshot, Formatting.Indented)); - } - - protected override CultPersistedStoreSnapshot DeserializeSnapshot(byte[] data) - { - var json = System.Text.Encoding.UTF8.GetString(data); - return JsonConvert.DeserializeObject(json) - ?? new CultPersistedStoreSnapshot(); - } - - protected override byte[] SerializePayload(object document) - { - return CultDocumentMessagePackSerialization.SerializeUntyped(document, document.GetType()); - } - - protected override object DeserializePayload(Type documentType, byte[] payload) - { - return CultDocumentMessagePackSerialization.DeserializeUntyped(documentType, payload); - } -} - -public class MultiFileNewtonsoftJsonBackingStore : MultiFileBackingStore -{ - public MultiFileNewtonsoftJsonBackingStore(string path) : base(path) - { - } - - protected override byte[] SerializeRecord(CultPersistedRecord record) - { - return System.Text.Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(record, Formatting.Indented)); - } - - protected override CultPersistedRecord DeserializeRecord(byte[] data) - { - var json = System.Text.Encoding.UTF8.GetString(data); - return JsonConvert.DeserializeObject(json) - ?? new CultPersistedRecord(); - } - - protected override byte[] SerializeCatalog(CultSchemaCatalogEntry[] catalog) - { - return System.Text.Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(catalog, Formatting.Indented)); - } - - protected override CultSchemaCatalogEntry[] DeserializeCatalog(byte[] data) - { - var json = System.Text.Encoding.UTF8.GetString(data); - return JsonConvert.DeserializeObject(json) - ?? Array.Empty(); - } - - protected override byte[] SerializePayload(object document) - { - return CultDocumentMessagePackSerialization.SerializeUntyped(document, document.GetType()); - } - - protected override object DeserializePayload(Type documentType, byte[] payload) - { - return CultDocumentMessagePackSerialization.DeserializeUntyped(documentType, payload); - } - - public override string Extension => "json"; -} diff --git a/src/GameCult.Caching.NewtonsoftJson/README.md b/src/GameCult.Caching.NewtonsoftJson/README.md deleted file mode 100644 index f3ddf4ce..00000000 --- a/src/GameCult.Caching.NewtonsoftJson/README.md +++ /dev/null @@ -1,49 +0,0 @@ -# GameCult.Caching.NewtonsoftJson - -`GameCult.Caching.NewtonsoftJson` provides human-readable JSON backing stores for `GameCult.Caching` using Newtonsoft.Json. - -## Scope - -The package provides: - -- `SingleFileNewtonsoftJsonBackingStore` -- `MultiFileNewtonsoftJsonBackingStore` -- known-type polymorphic `DatabaseEntry` serialization through closed discriminators - -## Usage - -```csharp -using GameCult.Caching; -using GameCult.Caching.NewtonsoftJson; - -var cache = new CultCache(); -var store = new MultiFileNewtonsoftJsonBackingStore("Data"); - -cache.AddBackingStore(store); -await cache.PullAllBackingStoresAsync(); -``` - -## Type Discovery - -The JSON backing stores build a known-type map from the assemblies already loaded in the current `AppDomain`. In the common case, this means entry types defined in the consumer's application assembly work without extra configuration once that assembly is loaded. - -The stores do not deserialize arbitrary CLR type names from JSON. Each file contains a closed discriminator plus the entry payload, and deserialization succeeds only when the discriminator matches a registered concrete `DatabaseEntry` subtype. - -For less typical setups, the stores also expose: - -- `RegisterType()` -- `RegisterAssembly(Assembly assembly)` -- `RefreshKnownTypes()` - -Example: - -```csharp -var store = new MultiFileNewtonsoftJsonBackingStore("Data"); -store.RegisterAssembly(typeof(MyCustomEntry).Assembly); -``` - -## Notes - -- Files are indented JSON for inspection and editing. -- Polymorphic entry types are serialized with a closed discriminator map rather than open-ended type-name handling. -- `MultiFileNewtonsoftJsonBackingStore` builds on the base multi-file store behavior in `GameCult.Caching`, including rename-safe writes. diff --git a/src/GameCult.Caching/CultCache.cs b/src/GameCult.Caching/CultCache.cs index d107d682..09ec4e81 100644 --- a/src/GameCult.Caching/CultCache.cs +++ b/src/GameCult.Caching/CultCache.cs @@ -904,11 +904,6 @@ namespace GameCult.Caching } } - public interface IRealtimeBackingStore - { - void ObserveChanges(); - } - public abstract class CacheBackingStore : IDisposable { private CultDocumentRegistry? _registry; @@ -972,135 +967,6 @@ namespace GameCult.Caching } } - public abstract class MultiFileBackingStore : CacheBackingStore, IRealtimeBackingStore - { - private readonly ConcurrentDictionary _pathsByKey = new(StringComparer.Ordinal); - - protected MultiFileBackingStore(string rootPath) - { - RootDirectory = new DirectoryInfo(rootPath); - } - - protected DirectoryInfo RootDirectory { get; } - protected abstract byte[] SerializeRecord(CultPersistedRecord record); - protected abstract CultPersistedRecord DeserializeRecord(byte[] data); - protected abstract byte[] SerializeCatalog(CultSchemaCatalogEntry[] catalog); - protected abstract CultSchemaCatalogEntry[] DeserializeCatalog(byte[] data); - protected abstract byte[] SerializePayload(object document); - protected abstract object DeserializePayload(Type documentType, byte[] payload); - public abstract string Extension { get; } - protected virtual string CatalogFileName => $"__cultcache.catalog.{Extension}"; - - public override void PullAll() - { - if (!RootDirectory.Exists) - { - return; - } - - var catalog = LoadCatalog(); - foreach (var file in RootDirectory.EnumerateFiles($"*.{Extension}", SearchOption.AllDirectories) - .Where(file => !string.Equals(file.Name, CatalogFileName, StringComparison.OrdinalIgnoreCase))) - { - var stored = ToStoredDocument( - DeserializeRecord(File.ReadAllBytes(file.FullName)), - catalog, - DeserializePayload); - Entries[stored.Key.Value] = stored; - _pathsByKey[stored.Key.Value] = file.FullName; - EntryAdded.OnNext(stored); - } - } - - public override void Push(CultStoredDocument entry) - { - Entries[entry.Key.Value] = entry; - var filePath = GetFilePath(entry); - if (_pathsByKey.TryGetValue(entry.Key.Value, out var existingPath) && - !string.Equals(existingPath, filePath, StringComparison.OrdinalIgnoreCase)) - { - TryDeleteFile(existingPath); - } - - Directory.CreateDirectory(Path.GetDirectoryName(filePath)!); - File.WriteAllBytes(filePath, SerializeRecord(ToPersistedRecord(entry, SerializePayload))); - _pathsByKey[entry.Key.Value] = filePath; - PersistCatalog(); - } - - public override void Delete(CultStoredDocument entry) - { - Entries.TryRemove(entry.Key.Value, out _); - if (_pathsByKey.TryRemove(entry.Key.Value, out var existingPath)) - { - TryDeleteFile(existingPath); - } - - PersistCatalog(); - } - - public override void PushAll(bool soft = false) - { - foreach (var entry in Entries.Values.ToArray()) - { - Push(entry); - } - } - - public virtual void ObserveChanges() - { - } - - private CultSchemaCatalogEntry[] LoadCatalog() - { - var catalogFile = Path.Combine(RootDirectory.FullName, CatalogFileName); - if (!File.Exists(catalogFile)) - { - return Array.Empty(); - } - - return DeserializeCatalog(File.ReadAllBytes(catalogFile)); - } - - private void PersistCatalog() - { - Directory.CreateDirectory(RootDirectory.FullName); - var catalogFile = Path.Combine(RootDirectory.FullName, CatalogFileName); - var catalog = Entries.Values - .Select(entry => entry.Descriptor.ToCatalogEntry()) - .GroupBy(entry => entry.SchemaId, StringComparer.Ordinal) - .Select(group => group.First()) - .OrderBy(entry => entry.SchemaName, StringComparer.Ordinal) - .ToArray(); - File.WriteAllBytes(catalogFile, SerializeCatalog(catalog)); - } - - private string GetFilePath(CultStoredDocument entry) - { - var directory = Path.Combine(RootDirectory.FullName, entry.Descriptor.SchemaName); - var fileName = SanitizeFileName(entry.Descriptor.GetPreferredFileStem(entry.Document)); - return Path.Combine(directory, $"{fileName}.{Extension}"); - } - - private static string SanitizeFileName(string value) - { - foreach (var invalid in Path.GetInvalidFileNameChars()) - { - value = value.Replace(invalid, '_'); - } - - return value; - } - - private static void TryDeleteFile(string path) - { - if (File.Exists(path)) - { - File.Delete(path); - } - } - } - public abstract class SingleFileBackingStore : CacheBackingStore { protected SingleFileBackingStore(string filePath) diff --git a/src/GameCult.Caching/README.md b/src/GameCult.Caching/README.md index 278db401..42dcbd1c 100644 --- a/src/GameCult.Caching/README.md +++ b/src/GameCult.Caching/README.md @@ -1,8 +1,9 @@ # GameCult.Caching -`GameCult.Caching` is an attribute-driven typed cache with pluggable stores. -Domain models stay clean. The cache owns record keys, schema ids, timestamps, -and persistence metadata instead of smearing that sludge across every class. +`GameCult.Caching` is an attribute-driven typed cache with a canonical +single-file MessagePack store. Domain models stay clean. The cache owns record +keys, schema ids, timestamps, and persistence metadata instead of smearing +that sludge across every class. ## Authoring Model @@ -13,7 +14,6 @@ using GameCult.Caching; using MessagePack; [CultDocument("gamecult.item_data", "gamecult.item_data.v1")] -[MessagePackObject] public sealed class ItemData { [Key(0)] @@ -78,7 +78,6 @@ but it will not quietly build an entire haunted object graph behind your back. ```csharp [CultDocument("gamecult.quest_data", "gamecult.quest_data.v1")] -[MessagePackObject] public sealed class QuestData { [Key(0)] public string Title = string.Empty; @@ -103,24 +102,24 @@ Each persisted record carries: The domain payload stays free of storage metadata. -## Backing Stores +## Backing Store -Base abstractions: - -- `CacheBackingStore` -- `SingleFileBackingStore` -- `MultiFileBackingStore` - -Included implementations in sibling packages: +CultCache now has one sanctioned persistence format: - `SingleFileMessagePackBackingStore` -- `MultiFileMessagePackBackingStore` -- `SingleFileNewtonsoftJsonBackingStore` -- `MultiFileNewtonsoftJsonBackingStore` -`MultiFileBackingStore` derives filenames from the `CultName` member when one -exists, so renames replace stale files instead of leaving little corpses -behind. +It persists the whole store as: + +1. store format version +2. embedded schema catalog +3. persisted records + +Each persisted record carries: + +- `key` +- `schemaId` +- `storedAt` +- `payload` ## Typical Startup @@ -129,7 +128,7 @@ using GameCult.Caching; using GameCult.Caching.MessagePack; var cache = new CultCache(); -var store = new MultiFileMessagePackBackingStore("Data"); +var store = new SingleFileMessagePackBackingStore("Data.msgpack"); cache.AddBackingStore(store); await cache.PullAllBackingStoresAsync(); diff --git a/tests/GameCult.Caching.Tests/BackingStoreTests.cs b/tests/GameCult.Caching.Tests/BackingStoreTests.cs index 7b3ad6fc..1bddfc20 100644 --- a/tests/GameCult.Caching.Tests/BackingStoreTests.cs +++ b/tests/GameCult.Caching.Tests/BackingStoreTests.cs @@ -4,7 +4,6 @@ using System.Linq; using System.Threading.Tasks; using GameCult.Caching; using GameCult.Caching.MessagePack; -using GameCult.Caching.NewtonsoftJson; using MessagePack; using NUnit.Framework; @@ -12,123 +11,6 @@ namespace GameCult.Caching.Tests { public class BackingStoreTests { - [Test] - public async Task MultiFileBackingStore_Rename_RemovesStaleFile() - { - var rootPath = Path.Combine(Path.GetTempPath(), $"cultlib-tests-{Guid.NewGuid():N}"); - Directory.CreateDirectory(rootPath); - - try - { - var store = new MultiFileNewtonsoftJsonBackingStore(rootPath); - var cache = new CultCache(); - cache.AddBackingStore(store); - - var entry = new NamedTestEntry - { - Name = "OriginalName", - Value = "value" - }; - - await cache.AddAsync(entry); - - entry.Name = "RenamedUser"; - await cache.AddAsync(entry); - - var files = Directory.GetFiles(rootPath, "*.json", SearchOption.AllDirectories) - .Select(Path.GetFileName) - .ToArray(); - - Assert.That(files, Does.Contain("RenamedUser.json")); - Assert.That(files, Does.Not.Contain("OriginalName.json")); - } - finally - { - if (Directory.Exists(rootPath)) - { - Directory.Delete(rootPath, true); - } - } - } - - [Test] - public async Task MultiFileNewtonsoftJsonBackingStore_RoundTrips_DiscoveredEntryType() - { - var rootPath = Path.Combine(Path.GetTempPath(), $"cultlib-tests-{Guid.NewGuid():N}"); - Directory.CreateDirectory(rootPath); - - try - { - var writeStore = new MultiFileNewtonsoftJsonBackingStore(rootPath); - var writeCache = new CultCache(); - writeCache.AddBackingStore(writeStore); - - var entry = new NamedTestEntry - { - Name = "RoundTrip", - Value = "payload" - }; - - var handle = await writeCache.AddAsync(entry); - - var readStore = new MultiFileNewtonsoftJsonBackingStore(rootPath); - var readCache = new CultCache(); - readCache.AddBackingStore(readStore); - await readCache.PullAllBackingStoresAsync(); - - var loaded = readCache.Get(handle.Key); - - Assert.That(loaded, Is.Not.Null); - Assert.That(loaded!.Value, Is.EqualTo("payload")); - } - finally - { - if (Directory.Exists(rootPath)) - { - Directory.Delete(rootPath, true); - } - } - } - - [Test] - public async Task SingleFileNewtonsoftJsonBackingStore_RoundTrips_DiscoveredEntryType() - { - var filePath = Path.Combine(Path.GetTempPath(), $"cultlib-tests-{Guid.NewGuid():N}.json"); - - try - { - var writeStore = new SingleFileNewtonsoftJsonBackingStore(filePath); - var writeCache = new CultCache(); - writeCache.AddBackingStore(writeStore); - - var entry = new NamedTestEntry - { - Name = "SingleFile", - Value = "payload" - }; - - var handle = await writeCache.AddAsync(entry); - writeStore.PushAll(); - - var readStore = new SingleFileNewtonsoftJsonBackingStore(filePath); - var readCache = new CultCache(); - readCache.AddBackingStore(readStore); - await readCache.PullAllBackingStoresAsync(); - - var loaded = readCache.Get(handle.Key); - - Assert.That(loaded, Is.Not.Null); - Assert.That(loaded!.Value, Is.EqualTo("payload")); - } - finally - { - if (File.Exists(filePath)) - { - File.Delete(filePath); - } - } - } - [Test] public async Task SingleFileMessagePackBackingStore_RoundTrips_DiscoveredEntryType() { diff --git a/tests/GameCult.Caching.Tests/GameCult.Caching.Tests.csproj b/tests/GameCult.Caching.Tests/GameCult.Caching.Tests.csproj index 3c563a73..6e8ec411 100644 --- a/tests/GameCult.Caching.Tests/GameCult.Caching.Tests.csproj +++ b/tests/GameCult.Caching.Tests/GameCult.Caching.Tests.csproj @@ -12,7 +12,6 @@ - diff --git a/tests/GameCult.Caching.Tests/README.md b/tests/GameCult.Caching.Tests/README.md index 8dc3cae0..1b1c49a3 100644 --- a/tests/GameCult.Caching.Tests/README.md +++ b/tests/GameCult.Caching.Tests/README.md @@ -1,12 +1,15 @@ # GameCult.Caching.Tests -`GameCult.Caching.Tests` contains NUnit tests for the caching library and its persistence abstractions. +`GameCult.Caching.Tests` contains NUnit tests for the caching library and its +single-file MessagePack persistence path. ## Scope The tests currently cover: -- rename behavior in `MultiFileNewtonsoftJsonBackingStore` +- `SingleFileMessagePackBackingStore` round-trips +- explicit Cult document payload codecs +- hand-written MessagePack store snapshot/record/catalog serialization ## Run