From 08715ac55c783d02b1c7706ccb1ba22285ee1068 Mon Sep 17 00:00:00 2001 From: Libby Date: Sat, 7 Nov 2026 16:17:05 +0000 Subject: [PATCH] cultcache-rs: pin the one-global rule on load_soa load_soa installs a whole table and checks it with refuse_second_globals, but no test reached that call (PR #15 covered put paths and pull_all). A table holding two records of a global type is refused with CultCacheSecondGlobal and the prior view survives; a table with one global loads and replaces the view. Co-Authored-By: Claude Sonnet 5.5 --- packages/cultcache-rs/tests/lookups.rs | 31 +++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/packages/cultcache-rs/tests/lookups.rs b/packages/cultcache-rs/tests/lookups.rs index 2467fbc6..ca5b459d 100644 --- a/packages/cultcache-rs/tests/lookups.rs +++ b/packages/cultcache-rs/tests/lookups.rs @@ -2,7 +2,8 @@ //! (`src/GameCult.Caching/CultCache.cs`) and the one-global rule its commit enforces. use cultcache_rs::{ - CacheBackingStore, CultCache, CultCacheSecondGlobal, DatabaseEntry, SingleFileMessagePackBackingStore, + CacheBackingStore, CultCache, CultCacheSecondGlobal, CultCacheSoaTable, DatabaseEntry, + SingleFileMessagePackBackingStore, }; #[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] @@ -321,3 +322,31 @@ fn loading_a_store_that_holds_two_globals_is_refused() { assert!(loading.pull_all_backing_stores().unwrap_err().is::()); assert_eq!(loading.get_global::().unwrap(), None, "a refused load installs nothing"); } + +// load_soa installs a whole table at once, so the one-global rule has to hold there too: a table holding two +// records of a global type is refused whole and the prior view survives. +#[test] +fn loading_an_soa_table_that_holds_two_globals_is_refused() { + let source = cache(); + let (first, _) = source.prepare_entry("g1", &settings("one")).unwrap(); + let (second, _) = source.prepare_entry("g2", &settings("two")).unwrap(); + + let mut loading = cache(); + loading.put("g0", &settings("prior")).unwrap(); + loading.put("plain:1", &Plain { value: "prior".into() }).unwrap(); + + let refusal = loading + .load_soa(CultCacheSoaTable::from_envelopes(vec![first.clone(), second])) + .unwrap_err(); + let second_global = refusal.downcast_ref::().expect("a typed refusal"); + let mut named = [second_global.existing_key.as_str(), second_global.key.as_str()]; + named.sort(); + assert_eq!(named, ["g1", "g2"], "the refusal names both records"); + assert_eq!(loading.get_global::().unwrap(), Some(settings("prior")), "a refused load keeps the prior view"); + assert_eq!(loading.get::("plain:1").unwrap(), Some(Plain { value: "prior".into() })); + + // One global in the table is the rule's own case, not a second. + loading.load_soa(CultCacheSoaTable::from_envelopes(vec![first])).unwrap(); + assert_eq!(loading.get_global::().unwrap(), Some(settings("one"))); + assert_eq!(loading.get::("plain:1").unwrap(), None, "a load replaces the view"); +} -- 2.47.3