// Copyright (c) 2026 GeWuYou // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. using GFramework.Game.Abstractions.Routing; using GFramework.Game.Routing; namespace GFramework.Game.Tests.Routing; /// /// RouterBase 单元测试 /// [TestFixture] public class RouterBaseTests { /// /// 测试用路由项 /// private class TestRoute : IRoute { public string Key { get; set; } = string.Empty; } /// /// 测试用路由上下文 /// private class TestContext : IRouteContext { public string? Data { get; set; } } /// /// 测试用路由守卫 /// private class TestGuard : IRouteGuard { public Func>? EnterFunc { get; set; } public Func>? LeaveFunc { get; set; } public int Priority { get; set; } public bool CanInterrupt { get; set; } public ValueTask CanEnterAsync(string routeKey, IRouteContext? context) { return EnterFunc?.Invoke(routeKey, context) ?? ValueTask.FromResult(true); } public ValueTask CanLeaveAsync(string routeKey) { return LeaveFunc?.Invoke(routeKey) ?? ValueTask.FromResult(true); } } /// /// 测试用路由器实现 /// private class TestRouter : RouterBase { public bool HandlersRegistered { get; private set; } // 暴露 Stack 用于测试 public new Stack Stack => base.Stack; protected override void OnInit() { // 测试用路由器不需要初始化逻辑 } protected override void RegisterHandlers() { HandlersRegistered = true; } // 暴露 protected 方法用于测试 public new Task ExecuteEnterGuardsAsync(string routeKey, TestContext? context) { return base.ExecuteEnterGuardsAsync(routeKey, context); } public new Task ExecuteLeaveGuardsAsync(string routeKey) { return base.ExecuteLeaveGuardsAsync(routeKey); } } [Test] public void AddGuard_ShouldAddGuardToList() { // Arrange var router = new TestRouter(); var guard = new TestGuard { Priority = 10 }; // Act router.AddGuard(guard); // Assert - 通过尝试添加相同守卫来验证 Assert.DoesNotThrow(() => router.AddGuard(guard)); } [Test] public void AddGuard_ShouldSortByPriority() { // Arrange var router = new TestRouter(); var guard1 = new TestGuard { Priority = 20 }; var guard2 = new TestGuard { Priority = 10 }; var guard3 = new TestGuard { Priority = 30 }; // Act router.AddGuard(guard1); router.AddGuard(guard2); router.AddGuard(guard3); // Assert - 通过执行守卫来验证顺序 var executionOrder = new List(); guard1.EnterFunc = (_, _) => { executionOrder.Add(1); return ValueTask.FromResult(true); }; guard2.EnterFunc = (_, _) => { executionOrder.Add(2); return ValueTask.FromResult(true); }; guard3.EnterFunc = (_, _) => { executionOrder.Add(3); return ValueTask.FromResult(true); }; router.ExecuteEnterGuardsAsync("test", null).Wait(); Assert.That(executionOrder, Is.EqualTo(new[] { 2, 1, 3 })); } [Test] public void AddGuard_WithGeneric_ShouldCreateAndAddGuard() { // Arrange var router = new TestRouter(); // Act & Assert Assert.DoesNotThrow(() => router.AddGuard()); } [Test] public void AddGuard_WithNull_ShouldThrowArgumentNullException() { // Arrange var router = new TestRouter(); // Act & Assert Assert.Throws(() => router.AddGuard(null!)); } [Test] public void RemoveGuard_ShouldRemoveGuardFromList() { // Arrange var router = new TestRouter(); var guard = new TestGuard { Priority = 10 }; router.AddGuard(guard); // Act router.RemoveGuard(guard); // Assert - 守卫应该被移除,不会再执行 var executed = false; guard.EnterFunc = (_, _) => { executed = true; return ValueTask.FromResult(true); }; router.ExecuteEnterGuardsAsync("test", null).Wait(); Assert.That(executed, Is.False); } [Test] public void RemoveGuard_WithNull_ShouldThrowArgumentNullException() { // Arrange var router = new TestRouter(); // Act & Assert Assert.Throws(() => router.RemoveGuard(null!)); } [Test] public async Task ExecuteEnterGuardsAsync_WithNoGuards_ShouldReturnTrue() { // Arrange var router = new TestRouter(); // Act var result = await router.ExecuteEnterGuardsAsync("test", null); // Assert Assert.That(result, Is.True); } [Test] public async Task ExecuteEnterGuardsAsync_WithAllowingGuard_ShouldReturnTrue() { // Arrange var router = new TestRouter(); var guard = new TestGuard { Priority = 10, EnterFunc = (_, _) => ValueTask.FromResult(true) }; router.AddGuard(guard); // Act var result = await router.ExecuteEnterGuardsAsync("test", null); // Assert Assert.That(result, Is.True); } [Test] public async Task ExecuteEnterGuardsAsync_WithBlockingGuard_ShouldReturnFalse() { // Arrange var router = new TestRouter(); var guard = new TestGuard { Priority = 10, EnterFunc = (_, _) => ValueTask.FromResult(false) }; router.AddGuard(guard); // Act var result = await router.ExecuteEnterGuardsAsync("test", null); // Assert Assert.That(result, Is.False); } [Test] public async Task ExecuteEnterGuardsAsync_WithInterruptingGuard_ShouldStopExecution() { // Arrange var router = new TestRouter(); var guard1 = new TestGuard { Priority = 10, CanInterrupt = true, EnterFunc = (_, _) => ValueTask.FromResult(true) }; var guard2Executed = false; var guard2 = new TestGuard { Priority = 20, EnterFunc = (_, _) => { guard2Executed = true; return ValueTask.FromResult(true); } }; router.AddGuard(guard1); router.AddGuard(guard2); // Act var result = await router.ExecuteEnterGuardsAsync("test", null); // Assert Assert.That(result, Is.True); Assert.That(guard2Executed, Is.False); } [Test] public async Task ExecuteEnterGuardsAsync_WithThrowingGuard_ShouldContinueIfNotInterrupting() { // Arrange var router = new TestRouter(); var guard1 = new TestGuard { Priority = 10, CanInterrupt = false, EnterFunc = (_, _) => throw new InvalidOperationException("Test exception") }; var guard2Executed = false; var guard2 = new TestGuard { Priority = 20, EnterFunc = (_, _) => { guard2Executed = true; return ValueTask.FromResult(true); } }; router.AddGuard(guard1); router.AddGuard(guard2); // Act var result = await router.ExecuteEnterGuardsAsync("test", null); // Assert Assert.That(result, Is.True); Assert.That(guard2Executed, Is.True); } [Test] public async Task ExecuteEnterGuardsAsync_WithThrowingInterruptingGuard_ShouldReturnFalse() { // Arrange var router = new TestRouter(); var guard = new TestGuard { Priority = 10, CanInterrupt = true, EnterFunc = (_, _) => throw new InvalidOperationException("Test exception") }; router.AddGuard(guard); // Act var result = await router.ExecuteEnterGuardsAsync("test", null); // Assert Assert.That(result, Is.False); } [Test] public async Task ExecuteLeaveGuardsAsync_WithNoGuards_ShouldReturnTrue() { // Arrange var router = new TestRouter(); // Act var result = await router.ExecuteLeaveGuardsAsync("test"); // Assert Assert.That(result, Is.True); } [Test] public async Task ExecuteLeaveGuardsAsync_WithAllowingGuard_ShouldReturnTrue() { // Arrange var router = new TestRouter(); var guard = new TestGuard { Priority = 10, LeaveFunc = _ => ValueTask.FromResult(true) }; router.AddGuard(guard); // Act var result = await router.ExecuteLeaveGuardsAsync("test"); // Assert Assert.That(result, Is.True); } [Test] public async Task ExecuteLeaveGuardsAsync_WithBlockingGuard_ShouldReturnFalse() { // Arrange var router = new TestRouter(); var guard = new TestGuard { Priority = 10, LeaveFunc = _ => ValueTask.FromResult(false) }; router.AddGuard(guard); // Act var result = await router.ExecuteLeaveGuardsAsync("test"); // Assert Assert.That(result, Is.False); } [Test] public void Contains_WithEmptyStack_ShouldReturnFalse() { // Arrange var router = new TestRouter(); // Act var result = router.Contains("test"); // Assert Assert.That(result, Is.False); } [Test] public void Contains_WithMatchingRoute_ShouldReturnTrue() { // Arrange var router = new TestRouter(); var route = new TestRoute { Key = "test" }; router.Stack.Push(route); // Act var result = router.Contains("test"); // Assert Assert.That(result, Is.True); } [Test] public void Contains_WithNonMatchingRoute_ShouldReturnFalse() { // Arrange var router = new TestRouter(); var route = new TestRoute { Key = "test1" }; router.Stack.Push(route); // Act var result = router.Contains("test2"); // Assert Assert.That(result, Is.False); } [Test] public void PeekKey_WithEmptyStack_ShouldReturnEmptyString() { // Arrange var router = new TestRouter(); // Act var result = router.PeekKey(); // Assert Assert.That(result, Is.EqualTo(string.Empty)); } [Test] public void PeekKey_WithRoute_ShouldReturnRouteKey() { // Arrange var router = new TestRouter(); var route = new TestRoute { Key = "test" }; router.Stack.Push(route); // Act var result = router.PeekKey(); // Assert Assert.That(result, Is.EqualTo("test")); } [Test] public void IsTop_WithEmptyStack_ShouldReturnFalse() { // Arrange var router = new TestRouter(); // Act var result = router.IsTop("test"); // Assert Assert.That(result, Is.False); } [Test] public void IsTop_WithMatchingRoute_ShouldReturnTrue() { // Arrange var router = new TestRouter(); var route = new TestRoute { Key = "test" }; router.Stack.Push(route); // Act var result = router.IsTop("test"); // Assert Assert.That(result, Is.True); } [Test] public void IsTop_WithNonMatchingRoute_ShouldReturnFalse() { // Arrange var router = new TestRouter(); var route = new TestRoute { Key = "test1" }; router.Stack.Push(route); // Act var result = router.IsTop("test2"); // Assert Assert.That(result, Is.False); } [Test] public void Current_WithEmptyStack_ShouldReturnNull() { // Arrange var router = new TestRouter(); // Act var result = router.Current; // Assert Assert.That(result, Is.Null); } [Test] public void Current_WithRoute_ShouldReturnTopRoute() { // Arrange var router = new TestRouter(); var route = new TestRoute { Key = "test" }; router.Stack.Push(route); // Act var result = router.Current; // Assert Assert.That(result, Is.EqualTo(route)); } [Test] public void CurrentKey_WithEmptyStack_ShouldReturnNull() { // Arrange var router = new TestRouter(); // Act var result = router.CurrentKey; // Assert Assert.That(result, Is.Null); } [Test] public void CurrentKey_WithRoute_ShouldReturnRouteKey() { // Arrange var router = new TestRouter(); var route = new TestRoute { Key = "test" }; router.Stack.Push(route); // Act var result = router.CurrentKey; // Assert Assert.That(result, Is.EqualTo("test")); } [Test] public void Count_WithEmptyStack_ShouldReturnZero() { // Arrange var router = new TestRouter(); // Act var result = router.Count; // Assert Assert.That(result, Is.EqualTo(0)); } [Test] public void Count_WithRoutes_ShouldReturnCorrectCount() { // Arrange var router = new TestRouter(); router.Stack.Push(new TestRoute { Key = "test1" }); router.Stack.Push(new TestRoute { Key = "test2" }); // Act var result = router.Count; // Assert Assert.That(result, Is.EqualTo(2)); } }