Keep a missing catalog global loud for writable opens
Globals are owned by lifecycle, so the cache must never run without one, however the catalog is opened. Before this, opening the catalog writable skipped the check entirely. The editor now opens the catalog writable, so a missing global went silent in play mode. AetheriaStores.Open now skips the check only for a writable catalog that has no records: a seed store being authored from nothing, as the test fixtures do. A populated catalog is always checked, and so is a read-only empty one. Nothing else relied on the old skip: the game has no catalog globals, AetherDb opens the populated Aetheria.cc, and every writable test reopen already holds its fixture global. WritablePopulatedCatalogMissingGlobalIsLoud removes the global from a populated catalog and checks that a writable reopen throws. It fails when the old writable-skip condition is restored. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
0c44aacb5b
commit
ab4ced0f53
2 changed files with 20 additions and 3 deletions
|
|
@ -11,8 +11,8 @@ public static class AetheriaStores
|
|||
public static readonly Type[] PlayerTypes = { typeof(PlayerSettings) };
|
||||
|
||||
// Attaches (hydrates) the catalog read-only unless catalogWritable, then the run and player stores when given.
|
||||
// A read-only catalog throws when a [CultGlobal] type routed to it has no record. A writable catalog is being
|
||||
// authored (the importer starts from an empty file), so it is not held to that.
|
||||
// Throws when a [CultGlobal] type routed to the catalog has no record. The one exemption is a writable catalog with
|
||||
// no records at all, a seed store being authored from nothing; a populated catalog is held to it however it opens.
|
||||
public static CultCache Open(string catalogPath, string runPath = null, string playerPath = null, bool catalogWritable = false)
|
||||
{
|
||||
var cache = new CultCache();
|
||||
|
|
@ -21,7 +21,9 @@ public static class AetheriaStores
|
|||
cache.AddBackingStore(new SingleFileMessagePackBackingStore(catalogPath, !catalogWritable), CatalogTypes);
|
||||
if (runPath != null) cache.AddBackingStore(new SingleFileMessagePackBackingStore(runPath), RunTypes);
|
||||
if (playerPath != null) cache.AddBackingStore(new SingleFileMessagePackBackingStore(playerPath), PlayerTypes);
|
||||
var missing = catalogWritable ? null : cache.Registry.AllDescriptors.FirstOrDefault(descriptor =>
|
||||
var seeding = catalogWritable && !cache.AllStoredDocuments.Any(stored =>
|
||||
CatalogTypes.Any(home => home.IsAssignableFrom(stored.Descriptor.DocumentType)));
|
||||
var missing = seeding ? null : cache.Registry.AllDescriptors.FirstOrDefault(descriptor =>
|
||||
descriptor.IsGlobal &&
|
||||
CatalogTypes.Any(home => home.IsAssignableFrom(descriptor.DocumentType)) &&
|
||||
cache.AllStoredDocuments.All(stored => stored.Descriptor != descriptor));
|
||||
|
|
|
|||
|
|
@ -121,6 +121,21 @@ public sealed class AetheriaStoresTests : IDisposable
|
|||
using (AetheriaStores.Open(Catalog)) { }
|
||||
}
|
||||
|
||||
// Writability exempts only an empty seed catalog: a populated catalog missing a global is loud even when writable.
|
||||
[Fact]
|
||||
public void WritablePopulatedCatalogMissingGlobalIsLoud()
|
||||
{
|
||||
using (var cache = AetheriaStores.Open(Catalog, catalogWritable: true))
|
||||
{
|
||||
var global = cache.GetGlobal<TestCatalogGlobal>();
|
||||
var key = cache.RefOf(global).Key;
|
||||
Assert.True(cache.Commit(batch => batch.Remove(key)));
|
||||
}
|
||||
|
||||
var error = Assert.Throws<InvalidOperationException>(() => AetheriaStores.Open(Catalog, catalogWritable: true));
|
||||
Assert.Contains("aetheria.tests.catalogglobal", error.Message);
|
||||
}
|
||||
|
||||
private static string Hash(string path) => Convert.ToHexString(SHA256.HashData(File.ReadAllBytes(path)));
|
||||
|
||||
private static string[] SchemaNames(string path)
|
||||
|
|
|
|||
Loading…
Reference in a new issue