From 281e1b238c2383f85ece604e2581a65dc5b14c00 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 29 Sep 2026 20:03:08 +0200 Subject: [PATCH] Keep the test frame from holding the subscription it checks the cache released Co-Authored-By: Claude Opus 5.5 --- .../CultCacheObserverTests.cs | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/tests/GameCult.Caching.Tests/CultCacheObserverTests.cs b/tests/GameCult.Caching.Tests/CultCacheObserverTests.cs index b26d4ca4..b2c8e7f5 100644 --- a/tests/GameCult.Caching.Tests/CultCacheObserverTests.cs +++ b/tests/GameCult.Caching.Tests/CultCacheObserverTests.cs @@ -127,25 +127,32 @@ namespace GameCult.Caching.Tests public void AnUnsubscribedObserverIsReleasedByTheCache() { using var cache = new CultCache(Registry); - var target = Subscribe(cache, out var subscription); + var kept = new List(); + var live = Subscribe(cache, kept, dispose: false); + var gone = Subscribe(cache, kept, dispose: true); Send(cache, "one"); CollectGarbage(); - Assert.That(target.IsAlive, Is.True, "a live subscription is held by the cache"); - subscription.Dispose(); - CollectGarbage(); - - Assert.That(target.IsAlive, Is.False, "an unsubscribed observer is no longer held"); + Assert.Multiple(() => + { + Assert.That(live.IsAlive, Is.True, "a live subscription is held by the cache"); + Assert.That(gone.IsAlive, Is.False, "an unsubscribed observer is no longer held"); + }); + GC.KeepAlive(kept); GC.KeepAlive(cache); } // A disposed R3 subscription ignores OnNext, so a stale entry in the cache is invisible to a receiver; it shows as - // a leak: the cache keeps the subscriber alive. + // a leak: the cache keeps the subscriber alive. The test frame must not hold the subscription itself. [MethodImpl(MethodImplOptions.NoInlining)] - private static WeakReference Subscribe(CultCache cache, out IDisposable subscription) + private static WeakReference Subscribe(CultCache cache, List kept, bool dispose) { var target = new object(); - subscription = cache.Watch().Subscribe(_ => GC.KeepAlive(target)); + var subscription = cache.Watch().Subscribe(_ => GC.KeepAlive(target)); + if (dispose) + subscription.Dispose(); + else + kept.Add(subscription); return new WeakReference(target); }