#nullable enable using System.Collections.Generic; using Cysharp.Threading.Tasks; using NUnit.Framework; using ShrinkContext; using ShrinkEventBus; using UnityEngine; namespace ShrinkContext.EventBusAdapter.Tests { public sealed class PingEvent : IShrinkEvent { public int Value { get; set; } } /// /// EventBus 订阅/注册即效应:组件停用时自动退订,无需手写卸载路径。 /// public class EventBusEffectTests { private ShrinkContextRuntime _runtime = null!; private ShrinkCtx _ctx = null!; [SetUp] public void SetUp() { _runtime = new ShrinkContextRuntime(); _ctx = _runtime.RootContext; } [TearDown] public void TearDown() { _runtime.ShutdownAsync().GetAwaiter().GetResult(); } [Test] public void EffectAttach_ReceivesEvents_AndAutoUnsubscribesOnContextDispose() { var received = new List(); var subscriber = new InstanceSubscriber(received); _ctx.EffectAttach(subscriber); EventBus.Post(new PingEvent { Value = 1 }); EventBus.Post(new PingEvent { Value = 2 }); CollectionAssert.AreEqual(new[] { 1, 2 }, received); _ctx.DisposeAsync().GetAwaiter().GetResult(); EventBus.Post(new PingEvent { Value = 3 }); CollectionAssert.AreEqual(new[] { 1, 2 }, received, "上下文回滚后 EventBus binding 必须通过 IDisposable.Dispose 自动退订"); } [Test] public void EffectAttach_ManualDispose_OnlyUnsubscribesOwn() { var first = new List(); var second = new List(); _ctx.EffectAttach(new InstanceSubscriber(first)); var handle = _ctx.EffectAttach(new InstanceSubscriber(second)); handle.DisposeAsync().GetAwaiter().GetResult(); EventBus.Post(new PingEvent { Value = 7 }); CollectionAssert.AreEqual(new[] { 7 }, first, "手动退订只影响自己的订阅"); Assert.IsEmpty(second); } [Test] public void EffectAttach_ObjectSubscribers_AutoUnregisterOnContextDispose() { var values = new List(); var subscriber = new InstanceSubscriber(values); _ctx.EffectAttach(subscriber); EventBus.Post(new PingEvent { Value = 5 }); Assert.AreEqual(5, subscriber.LastValue); _ctx.DisposeAsync().GetAwaiter().GetResult(); EventBus.Post(new PingEvent { Value = 6 }); Assert.AreEqual(5, subscriber.LastValue, "实例注册随上下文回滚自动注销"); } [ShrinkEventSubscriber(DefaultBus = "game")] private sealed class InstanceSubscriber { private readonly List _values; public InstanceSubscriber(List values) { _values = values; } public int LastValue { get; private set; } [ShrinkSubscribe] public void OnPing(PingEvent e) { LastValue = e.Value; _values.Add(e.Value); } } } }