Files
ShrinkEventBus/Tests/ShrinkEventBusDeferredDiagnosticsTests.cs
T
cneicy 901ad18453
Publish UPM package / publish (push) Successful in 3s
Publish NuGet packages / publish (push) Successful in 3m43s
feat: update Godot integration and coordinated package dependencies
2026-11-06 19:13:18 +08:00

252 lines
9.5 KiB
C#

using System;
using System.Collections.Generic;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
namespace ShrinkEventBus.Tests
{
[TestFixture]
public class ShrinkEventBusDeferredDiagnosticsTests
{
private IShrinkEventBusMainThreadDispatcher _originalDispatcher;
[SetUp]
public void SetUp()
{
_originalDispatcher = ShrinkEventBusRuntime.MainThreadDispatcher;
}
[TearDown]
public void TearDown()
{
ShrinkEventBusRuntime.ConfigureMainThreadDispatcher(_originalDispatcher);
}
[Test]
public void ObserveDiagnostics_ReportsMetadataAndUnsubscribes()
{
var diagnostics = new List<ShrinkEventDiagnostic>();
using var host = new ShrinkEventBusHost();
var key = new ShrinkBusKey("diagnostics", Guid.NewGuid().ToString("N"));
var bus = host.CreateBus(key, ShrinkBusOptions.Inline());
var subscription = EventBus.ObserveDiagnostics(diagnostics.Add);
bus.Post(new DeferredEvent(1));
subscription.Dispose();
bus.Post(new DeferredEvent(2));
Assert.AreEqual(1, diagnostics.Count);
Assert.AreEqual(typeof(DeferredEvent), diagnostics[0].EventType);
Assert.AreEqual(key, diagnostics[0].BusKey);
Assert.IsTrue(diagnostics[0].Result.Accepted);
Assert.IsFalse(diagnostics[0].IsAsync);
Assert.GreaterOrEqual(diagnostics[0].ElapsedTimestampTicks, 0L);
}
[Test]
public void ObserveDiagnostics_ThrowingObserverDoesNotBlockBusinessOrOtherObservers()
{
var calls = 0;
var secondObserverCalls = 0;
using var host = new ShrinkEventBusHost();
var key = new ShrinkBusKey("diagnostics", Guid.NewGuid().ToString("N"));
var bus = host.CreateBus(key, ShrinkBusOptions.Inline());
using var binding = ShrinkGeneratedBinding.Subscribe<DeferredEvent>(host, key, string.Empty,
this, _ => calls++, ShrinkEventPriority.Normal, 0, false);
using var first = EventBus.ObserveDiagnostics(_ =>
throw new InvalidOperationException("observer failure"));
using var second = EventBus.ObserveDiagnostics(_ => secondObserverCalls++);
var previous = LogAssert.ignoreFailingMessages;
LogAssert.ignoreFailingMessages = true;
try
{
Assert.DoesNotThrow(() => bus.Post(new DeferredEvent(3)));
}
finally
{
LogAssert.ignoreFailingMessages = previous;
}
Assert.AreEqual(1, calls);
Assert.AreEqual(1, secondObserverCalls);
}
[Test]
public void PostDeferred_DoesNotDispatchBeforePump()
{
var dispatcher = new ManualDispatcher();
ShrinkEventBusRuntime.ConfigureMainThreadDispatcher(dispatcher);
using var host = new ShrinkEventBusHost();
var key = new ShrinkBusKey("deferred", Guid.NewGuid().ToString("N"));
var bus = host.CreateBus(key, new ShrinkBusOptions
{
Scheduler = ShrinkBusSchedulerKind.MainThread,
QueueCapacity = 8
});
var calls = 0;
using var binding = ShrinkGeneratedBinding.Subscribe<DeferredEvent>(host, key, string.Empty,
this, _ => calls++, ShrinkEventPriority.Normal, 0, false);
var result = EventBus.PostDeferred(bus, new DeferredEvent(4));
Assert.IsTrue(result.Accepted);
Assert.IsFalse(result.Handled);
Assert.AreEqual(0, calls);
Assert.AreEqual(1, dispatcher.Count);
dispatcher.PumpAll();
Assert.AreEqual(1, calls);
}
[Test]
public void PostDeferred_ReentrantPostWaitsForNextPump()
{
var dispatcher = new ManualDispatcher();
ShrinkEventBusRuntime.ConfigureMainThreadDispatcher(dispatcher);
using var host = new ShrinkEventBusHost();
var key = new ShrinkBusKey("deferred", Guid.NewGuid().ToString("N"));
var bus = host.CreateBus(key, new ShrinkBusOptions
{
Scheduler = ShrinkBusSchedulerKind.MainThread,
QueueCapacity = 8
});
var calls = 0;
using var binding = ShrinkGeneratedBinding.Subscribe<DeferredEvent>(host, key, string.Empty,
this, _ =>
{
calls++;
if (calls == 1)
EventBus.PostDeferred(bus, new DeferredEvent(5));
}, ShrinkEventPriority.Normal, 0, false);
EventBus.PostDeferred(bus, new DeferredEvent(4));
dispatcher.PumpAll();
Assert.AreEqual(1, calls);
Assert.AreEqual(1, dispatcher.Count);
dispatcher.PumpAll();
Assert.AreEqual(2, calls);
}
[Test]
public void PostDeferred_DropOldestKeepsNewest()
{
var dispatcher = new ManualDispatcher();
ShrinkEventBusRuntime.ConfigureMainThreadDispatcher(dispatcher);
using var host = new ShrinkEventBusHost();
var key = new ShrinkBusKey("deferred", Guid.NewGuid().ToString("N"));
var bus = host.CreateBus(key, new ShrinkBusOptions
{
Scheduler = ShrinkBusSchedulerKind.MainThread,
QueueCapacity = 1,
OverflowPolicy = ShrinkQueueOverflowPolicy.DropOldest
});
var values = new List<int>();
using var binding = ShrinkGeneratedBinding.Subscribe<DeferredEvent>(host, key, string.Empty,
this, evt => values.Add(evt.Value), ShrinkEventPriority.Normal, 0, false);
EventBus.PostDeferred(bus, new DeferredEvent(1));
EventBus.PostDeferred(bus, new DeferredEvent(2));
dispatcher.PumpAll();
CollectionAssert.AreEqual(new[] { 2 }, values);
}
[Test]
public void PostDeferred_InlineBusFailsWithoutDispatch()
{
using var host = new ShrinkEventBusHost();
var key = new ShrinkBusKey("deferred", Guid.NewGuid().ToString("N"));
var bus = host.CreateBus(key, ShrinkBusOptions.Inline());
var calls = 0;
using var binding = ShrinkGeneratedBinding.Subscribe<DeferredEvent>(host, key, string.Empty,
this, _ => calls++, ShrinkEventPriority.Normal, 0, false);
var result = EventBus.PostDeferred(bus, new DeferredEvent(6));
Assert.AreEqual(ShrinkPostFailure.DeferredUnsupported, result.Failure);
Assert.AreEqual(0, calls);
}
[Test]
public void PostDeferred_WithoutDeferredDispatcherFailsWithoutDispatch()
{
ShrinkEventBusRuntime.ConfigureMainThreadDispatcher(new NonDeferredDispatcher());
using var host = new ShrinkEventBusHost();
var key = new ShrinkBusKey("deferred", Guid.NewGuid().ToString("N"));
var bus = host.CreateBus(key, new ShrinkBusOptions
{
Scheduler = ShrinkBusSchedulerKind.MainThread
});
var calls = 0;
using var binding = ShrinkGeneratedBinding.Subscribe<DeferredEvent>(host, key, string.Empty,
this, _ => calls++, ShrinkEventPriority.Normal, 0, false);
var result = EventBus.PostDeferred(bus, new DeferredEvent(7));
Assert.AreEqual(ShrinkPostFailure.DeferredUnsupported, result.Failure);
Assert.AreEqual(0, calls);
}
[Test]
public void PostDeferred_DisposedBusRejects()
{
var dispatcher = new ManualDispatcher();
ShrinkEventBusRuntime.ConfigureMainThreadDispatcher(dispatcher);
using var host = new ShrinkEventBusHost();
var key = new ShrinkBusKey("deferred", Guid.NewGuid().ToString("N"));
var bus = host.CreateBus(key, new ShrinkBusOptions
{
Scheduler = ShrinkBusSchedulerKind.MainThread
});
bus.Dispose();
var result = EventBus.PostDeferred(bus, new DeferredEvent(8));
Assert.AreEqual(ShrinkPostFailure.BusStopped, result.Failure);
}
private readonly struct DeferredEvent : IShrinkEvent
{
public DeferredEvent(int value) => Value = value;
public int Value { get; }
}
private sealed class ManualDispatcher : IShrinkEventBusMainThreadDispatcher,
ShrinkSDK.Runtime.IShrinkDeferredMainThreadDispatcher
{
private readonly Queue<Action> _queue = new();
public bool IsMainThread => true;
public int Count => _queue.Count;
public bool TryPost(Action action)
{
_queue.Enqueue(action);
return true;
}
public bool TryPostDeferred(Action action)
{
_queue.Enqueue(action);
return true;
}
public void PumpAll()
{
var count = _queue.Count;
for (var i = 0; i < count; i++)
_queue.Dequeue()();
}
}
private sealed class NonDeferredDispatcher : IShrinkEventBusMainThreadDispatcher
{
public bool IsMainThread => true;
public bool TryPost(Action action) => true;
}
}
}