mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-22 10:34:30 +08:00
fix(coroutine): 修复 WaitForMultipleEvents 的事件处理逻辑
- 添加了完成状态检查,避免在已完成或释放后继续处理事件 - 立即注销事件监听器以防止内存泄漏 - 在事件触发后清理注册器引用 - 添加了完整的单元测试覆盖各种事件场景
This commit is contained in:
parent
4748198696
commit
42a1ab0f29
148
GFramework.Core.Tests/coroutine/WaitForMultipleEventsTests.cs
Normal file
148
GFramework.Core.Tests/coroutine/WaitForMultipleEventsTests.cs
Normal file
@ -0,0 +1,148 @@
|
||||
using GFramework.Core.Abstractions.events;
|
||||
using GFramework.Core.coroutine.instructions;
|
||||
using GFramework.Core.events;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GFramework.Core.Tests.coroutine
|
||||
{
|
||||
[TestFixture]
|
||||
public class WaitForMultipleEventsTests
|
||||
{
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
eventBus = new EventBus();
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
(eventBus as IDisposable)?.Dispose();
|
||||
}
|
||||
|
||||
private IEventBus eventBus;
|
||||
|
||||
[Test]
|
||||
public void Constructor_RegistersBothEventTypes()
|
||||
{
|
||||
// Arrange & Act
|
||||
var waitForMultipleEvents = new WaitForMultipleEvents<TestEvent1, TestEvent2>(eventBus);
|
||||
|
||||
// Assert
|
||||
Assert.That(waitForMultipleEvents.IsDone, Is.False);
|
||||
Assert.That(waitForMultipleEvents.TriggeredBy, Is.EqualTo(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public Task FirstEventWins_WhenBothEventsFired()
|
||||
{
|
||||
// Arrange
|
||||
var waitForMultipleEvents = new WaitForMultipleEvents<TestEvent1, TestEvent2>(eventBus);
|
||||
|
||||
// Act
|
||||
eventBus.Send(new TestEvent1 { Data = "first_event" });
|
||||
eventBus.Send(new TestEvent2 { Data = "second_event" });
|
||||
|
||||
// Assert
|
||||
Assert.That(waitForMultipleEvents.IsDone, Is.True);
|
||||
Assert.That(waitForMultipleEvents.TriggeredBy, Is.EqualTo(1)); // First event should win
|
||||
Assert.That(waitForMultipleEvents.FirstEventData?.Data, Is.EqualTo("first_event"));
|
||||
Assert.That(waitForMultipleEvents.SecondEventData, Is.Null);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public Task SecondEventWins_WhenOnlySecondEventFired()
|
||||
{
|
||||
// Arrange
|
||||
var waitForMultipleEvents = new WaitForMultipleEvents<TestEvent1, TestEvent2>(eventBus);
|
||||
|
||||
// Act
|
||||
eventBus.Send(new TestEvent2 { Data = "second_event" });
|
||||
|
||||
// Assert
|
||||
Assert.That(waitForMultipleEvents.IsDone, Is.True);
|
||||
Assert.That(waitForMultipleEvents.TriggeredBy, Is.EqualTo(2)); // Second event should win
|
||||
Assert.That(waitForMultipleEvents.SecondEventData?.Data, Is.EqualTo("second_event"));
|
||||
Assert.That(waitForMultipleEvents.FirstEventData, Is.Null);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public Task FirstEventWins_WhenBothEventsFiredInReverseOrder()
|
||||
{
|
||||
// Arrange
|
||||
var waitForMultipleEvents = new WaitForMultipleEvents<TestEvent1, TestEvent2>(eventBus);
|
||||
|
||||
// Act
|
||||
eventBus.Send(new TestEvent2 { Data = "second_event" });
|
||||
eventBus.Send(new TestEvent1 { Data = "first_event" });
|
||||
|
||||
// Assert
|
||||
Assert.That(waitForMultipleEvents.IsDone, Is.True);
|
||||
// Second event should win because it fired first and set _done = true
|
||||
Assert.That(waitForMultipleEvents.TriggeredBy,
|
||||
Is.EqualTo(2)); // Second event actually won since it fired first
|
||||
Assert.That(waitForMultipleEvents.SecondEventData?.Data, Is.EqualTo("second_event"));
|
||||
Assert.That(waitForMultipleEvents.FirstEventData, Is.Null);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public Task MultipleEvents_AfterCompletion_DoNotOverrideState()
|
||||
{
|
||||
// Arrange
|
||||
var waitForMultipleEvents = new WaitForMultipleEvents<TestEvent1, TestEvent2>(eventBus);
|
||||
|
||||
// Act - Fire first event
|
||||
eventBus.Send(new TestEvent1 { Data = "first_event" });
|
||||
|
||||
// Verify first event was processed
|
||||
Assert.That(waitForMultipleEvents.IsDone, Is.True);
|
||||
Assert.That(waitForMultipleEvents.TriggeredBy, Is.EqualTo(1));
|
||||
Assert.That(waitForMultipleEvents.FirstEventData?.Data, Is.EqualTo("first_event"));
|
||||
|
||||
// Fire second event after completion
|
||||
eventBus.Send(new TestEvent2 { Data = "second_event" });
|
||||
|
||||
// Assert - The state should not change
|
||||
Assert.That(waitForMultipleEvents.IsDone, Is.True);
|
||||
Assert.That(waitForMultipleEvents.TriggeredBy, Is.EqualTo(1)); // Should remain as 1, not change to 2
|
||||
Assert.That(waitForMultipleEvents.FirstEventData?.Data,
|
||||
Is.EqualTo("first_event")); // Should remain unchanged
|
||||
Assert.That(waitForMultipleEvents.SecondEventData, Is.Null); // Should remain null
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public Task Disposal_PreventsFurtherEventHandling()
|
||||
{
|
||||
// Arrange
|
||||
var waitForMultipleEvents = new WaitForMultipleEvents<TestEvent1, TestEvent2>(eventBus);
|
||||
|
||||
// Act - Dispose the instance
|
||||
waitForMultipleEvents.Dispose();
|
||||
|
||||
// Fire an event after disposal
|
||||
eventBus.Send(new TestEvent1 { Data = "after_disposal" });
|
||||
|
||||
// Assert - Event should not be processed due to disposal
|
||||
// Since we disposed, no event data should be captured
|
||||
Assert.That(waitForMultipleEvents.FirstEventData, Is.Null);
|
||||
Assert.That(waitForMultipleEvents.IsDone, Is.False); // Should remain false after disposal
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
// Test event classes
|
||||
private class TestEvent1
|
||||
{
|
||||
public string Data { get; init; } = string.Empty;
|
||||
}
|
||||
|
||||
private class TestEvent2
|
||||
{
|
||||
public string Data { get; init; } = string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -82,9 +82,18 @@ public sealed class WaitForMultipleEvents<TEvent1, TEvent2> : IYieldInstruction,
|
||||
/// </summary>
|
||||
private void OnFirstEvent(TEvent1 eventData)
|
||||
{
|
||||
// 如果已经完成或者被释放,则直接返回
|
||||
if (_done || _disposed) return;
|
||||
|
||||
FirstEventData = eventData;
|
||||
TriggeredBy = 1;
|
||||
_done = true;
|
||||
|
||||
// 立即注销事件监听器
|
||||
_unRegister1?.UnRegister();
|
||||
_unRegister2?.UnRegister();
|
||||
_unRegister1 = null;
|
||||
_unRegister2 = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -92,8 +101,17 @@ public sealed class WaitForMultipleEvents<TEvent1, TEvent2> : IYieldInstruction,
|
||||
/// </summary>
|
||||
private void OnSecondEvent(TEvent2 eventData)
|
||||
{
|
||||
// 如果已经完成或者被释放,则直接返回
|
||||
if (_done || _disposed) return;
|
||||
|
||||
SecondEventData = eventData;
|
||||
TriggeredBy = 2;
|
||||
_done = true;
|
||||
|
||||
// 立即注销事件监听器
|
||||
_unRegister1?.UnRegister();
|
||||
_unRegister2?.UnRegister();
|
||||
_unRegister1 = null;
|
||||
_unRegister2 = null;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user