From b7560fcc08ff61d1bd55121568a1fd37e3526211 Mon Sep 17 00:00:00 2001 From: gewuyou <95328647+GeWuYou@users.noreply.github.com> Date: Sat, 25 Apr 2026 10:08:59 +0800 Subject: [PATCH] =?UTF-8?q?test(core-tests):=20=E6=94=B6=E6=95=9B=E5=87=BD?= =?UTF-8?q?=E6=95=B0=E5=BC=8F=E4=B8=8E=E7=8A=B6=E6=80=81=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E7=9A=84=E4=BD=8E=E9=A3=8E=E9=99=A9=20warning?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 补齐 WaitForTask、ResourceManager、State 与 StateMachine 测试中的低风险 ConfigureAwait(false) - 更新 AsyncKeyLock、ResultExtensions、ResultT 与 Pipe 测试中的 culture 和异步等待写法 --- .../Concurrency/AsyncKeyLockManagerTests.cs | 62 +++++++++---------- .../Coroutine/WaitForTaskTests.cs | 6 +- .../Extensions/ResultExtensionsTests.cs | 20 +++--- .../Functional/Pipe/PipeExtensionsTests.cs | 9 +-- .../Functional/ResultTTests.cs | 15 ++--- .../Resource/ResourceManagerTests.cs | 6 +- .../State/StateMachineTests.cs | 6 +- GFramework.Core.Tests/State/StateTests.cs | 8 +-- 8 files changed, 68 insertions(+), 64 deletions(-) diff --git a/GFramework.Core.Tests/Concurrency/AsyncKeyLockManagerTests.cs b/GFramework.Core.Tests/Concurrency/AsyncKeyLockManagerTests.cs index 1fe7cf3b..9e43e880 100644 --- a/GFramework.Core.Tests/Concurrency/AsyncKeyLockManagerTests.cs +++ b/GFramework.Core.Tests/Concurrency/AsyncKeyLockManagerTests.cs @@ -25,7 +25,7 @@ public sealed class AsyncKeyLockManagerTests using var manager = new AsyncKeyLockManager(); // Act - await using var handle = await manager.AcquireLockAsync("test-key"); + await using var handle = await manager.AcquireLockAsync("test-key").ConfigureAwait(false); // Assert Assert.That(handle, Is.Not.Null); @@ -47,13 +47,13 @@ public sealed class AsyncKeyLockManagerTests var index = i; tasks.Add(Task.Run(async () => { - await using var handle = await manager.AcquireLockAsync("same-key"); + await using var handle = await manager.AcquireLockAsync("same-key").ConfigureAwait(false); executionOrder.Add(index); - await Task.Delay(10); + await Task.Delay(10).ConfigureAwait(false); })); } - await Task.WhenAll(tasks); + await Task.WhenAll(tasks).ConfigureAwait(false); // Assert Assert.That(executionOrder.Count, Is.EqualTo(5)); @@ -75,15 +75,15 @@ public sealed class AsyncKeyLockManagerTests var key = $"key-{i}"; tasks.Add(Task.Run(async () => { - await using var handle = await manager.AcquireLockAsync(key); + await using var handle = await manager.AcquireLockAsync(key).ConfigureAwait(false); var current = Interlocked.Increment(ref concurrentCount); maxConcurrent = Math.Max(maxConcurrent, current); - await Task.Delay(50); + await Task.Delay(50).ConfigureAwait(false); Interlocked.Decrement(ref concurrentCount); })); } - await Task.WhenAll(tasks); + await Task.WhenAll(tasks).ConfigureAwait(false); // Assert Assert.That(maxConcurrent, Is.GreaterThan(1)); @@ -94,13 +94,13 @@ public sealed class AsyncKeyLockManagerTests { // Arrange using var manager = new AsyncKeyLockManager(); - var handle = await manager.AcquireLockAsync("test-key"); + var handle = await manager.AcquireLockAsync("test-key").ConfigureAwait(false); // Act - await handle.DisposeAsync(); + await handle.DisposeAsync().ConfigureAwait(false); // Assert - 应该能再次获取锁 - await using var handle2 = await manager.AcquireLockAsync("test-key"); + await using var handle2 = await manager.AcquireLockAsync("test-key").ConfigureAwait(false); Assert.That(handle2, Is.Not.Null); } @@ -117,8 +117,8 @@ public sealed class AsyncKeyLockManagerTests var key = $"key-{i % 10}"; tasks.Add(Task.Run(async () => { - await using var handle = await manager.AcquireLockAsync(key); - await Task.Delay(1); + await using var handle = await manager.AcquireLockAsync(key).ConfigureAwait(false); + await Task.Delay(1).ConfigureAwait(false); })); } @@ -139,14 +139,14 @@ public sealed class AsyncKeyLockManagerTests { tasks.Add(Task.Run(async () => { - await using var handle = await manager.AcquireLockAsync("same-key"); + await using var handle = await manager.AcquireLockAsync("same-key").ConfigureAwait(false); var temp = counter; - await Task.Delay(1); + await Task.Delay(1).ConfigureAwait(false); counter = temp + 1; })); } - await Task.WhenAll(tasks); + await Task.WhenAll(tasks).ConfigureAwait(false); // Assert Assert.That(counter, Is.EqualTo(100)); @@ -161,13 +161,13 @@ public sealed class AsyncKeyLockManagerTests lockTimeout: TimeSpan.FromMilliseconds(200)); // Act - await using (var handle = await manager.AcquireLockAsync("temp-key")) + await using (var handle = await manager.AcquireLockAsync("temp-key").ConfigureAwait(false)) { // 持有锁 } // 等待清理 - await Task.Delay(400); + await Task.Delay(400).ConfigureAwait(false); var stats = manager.GetStatistics(); @@ -184,10 +184,10 @@ public sealed class AsyncKeyLockManagerTests lockTimeout: TimeSpan.FromMilliseconds(200)); // Act - await using var handle = await manager.AcquireLockAsync("active-key"); + await using var handle = await manager.AcquireLockAsync("active-key").ConfigureAwait(false); // 等待清理尝试 - await Task.Delay(400); + await Task.Delay(400).ConfigureAwait(false); var activeLocks = manager.GetActiveLocks(); @@ -202,9 +202,9 @@ public sealed class AsyncKeyLockManagerTests using var manager = new AsyncKeyLockManager(); // Act - await using (await manager.AcquireLockAsync("key1")) + await using (await manager.AcquireLockAsync("key1").ConfigureAwait(false)) { - await using var handle2 = await manager.AcquireLockAsync("key2"); + await using var handle2 = await manager.AcquireLockAsync("key2").ConfigureAwait(false); var stats = manager.GetStatistics(); // Assert @@ -223,8 +223,8 @@ public sealed class AsyncKeyLockManagerTests using var manager = new AsyncKeyLockManager(); // Act - await using var handle1 = await manager.AcquireLockAsync("key1"); - await using var handle2 = await manager.AcquireLockAsync("key2"); + await using var handle1 = await manager.AcquireLockAsync("key1").ConfigureAwait(false); + await using var handle2 = await manager.AcquireLockAsync("key2").ConfigureAwait(false); var activeLocks = manager.GetActiveLocks(); @@ -254,14 +254,14 @@ public sealed class AsyncKeyLockManagerTests using var cts = new CancellationTokenSource(); // 先获取锁 - await using var handle = await manager.AcquireLockAsync("test-key", cts.Token); + await using var handle = await manager.AcquireLockAsync("test-key", cts.Token).ConfigureAwait(false); // Act - await cts.CancelAsync(); + await cts.CancelAsync().ConfigureAwait(false); // Assert Assert.CatchAsync(async () => - await manager.AcquireLockAsync("test-key", cts.Token)); + await manager.AcquireLockAsync("test-key", cts.Token).ConfigureAwait(false)); } [Test] @@ -295,8 +295,8 @@ public sealed class AsyncKeyLockManagerTests { for (var j = 0; j < 10; j++) { - await using var handle = await manager.AcquireLockAsync($"key-{j % 5}"); - await Task.Delay(10); + await using var handle = await manager.AcquireLockAsync($"key-{j % 5}").ConfigureAwait(false); + await Task.Delay(10).ConfigureAwait(false); } })); } @@ -324,11 +324,11 @@ public sealed class AsyncKeyLockManagerTests { // Arrange using var manager = new AsyncKeyLockManager(); - var handle = await manager.AcquireLockAsync("test-key"); + var handle = await manager.AcquireLockAsync("test-key").ConfigureAwait(false); // Act - await handle.DisposeAsync(); - await handle.DisposeAsync(); + await handle.DisposeAsync().ConfigureAwait(false); + await handle.DisposeAsync().ConfigureAwait(false); handle.Dispose(); // Assert - 不应该抛出异常 diff --git a/GFramework.Core.Tests/Coroutine/WaitForTaskTests.cs b/GFramework.Core.Tests/Coroutine/WaitForTaskTests.cs index c6565bbf..73789a5d 100644 --- a/GFramework.Core.Tests/Coroutine/WaitForTaskTests.cs +++ b/GFramework.Core.Tests/Coroutine/WaitForTaskTests.cs @@ -284,13 +284,13 @@ public class WaitForTaskTests var expectedValue = 123; var task = Task.Run(async () => { - await Task.Delay(50); + await Task.Delay(50).ConfigureAwait(false); return expectedValue; }); var wait = new WaitForTask(task); - await task; + await task.ConfigureAwait(false); Task.Delay(100).Wait(); @@ -313,4 +313,4 @@ public class WaitForTaskTests Assert.That(wait.IsDone, Is.True); } -} \ No newline at end of file +} diff --git a/GFramework.Core.Tests/Extensions/ResultExtensionsTests.cs b/GFramework.Core.Tests/Extensions/ResultExtensionsTests.cs index aaa78210..6de644d3 100644 --- a/GFramework.Core.Tests/Extensions/ResultExtensionsTests.cs +++ b/GFramework.Core.Tests/Extensions/ResultExtensionsTests.cs @@ -11,6 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +using System.Globalization; using GFramework.Core.Functional; namespace GFramework.Core.Tests.Extensions; @@ -122,7 +123,7 @@ public class ResultExtensionsTests public void Map_Should_Transform_Success_Value() { var result = Result.Succeed(42); - var mapped = result.Map(x => x.ToString()); + var mapped = result.Map(x => x.ToString(CultureInfo.InvariantCulture)); Assert.That(mapped.IsSuccess, Is.True); Assert.That(mapped.Match(succ: v => v, fail: _ => ""), Is.EqualTo("42")); } @@ -135,7 +136,7 @@ public class ResultExtensionsTests { var exception = new Exception("Error"); var result = Result.Fail(exception); - var mapped = result.Map(x => x.ToString()); + var mapped = result.Map(x => x.ToString(CultureInfo.InvariantCulture)); Assert.That(mapped.IsFaulted, Is.True); Assert.That(mapped.Exception, Is.SameAs(exception)); } @@ -157,7 +158,7 @@ public class ResultExtensionsTests public void Bind_Should_Chain_Success_Results() { var result = Result.Succeed(42); - var bound = result.Bind(x => Result.Succeed(x.ToString())); + var bound = result.Bind(x => Result.Succeed(x.ToString(CultureInfo.InvariantCulture))); Assert.That(bound.IsSuccess, Is.True); Assert.That(bound.Match(succ: v => v, fail: _ => ""), Is.EqualTo("42")); } @@ -170,7 +171,7 @@ public class ResultExtensionsTests { var exception = new Exception("Error"); var result = Result.Fail(exception); - var bound = result.Bind(x => Result.Succeed(x.ToString())); + var bound = result.Bind(x => Result.Succeed(x.ToString(CultureInfo.InvariantCulture))); Assert.That(bound.IsFaulted, Is.True); Assert.That(bound.Exception, Is.SameAs(exception)); } @@ -449,9 +450,9 @@ public class ResultExtensionsTests { var result = await ResultExtensions.TryAsync(async () => { - await Task.Delay(1); + await Task.Delay(1).ConfigureAwait(false); return 42; - }); + }).ConfigureAwait(false); Assert.That(result.IsSuccess, Is.True); Assert.That(result.Match(succ: v => v, fail: _ => 0), Is.EqualTo(42)); } @@ -464,9 +465,9 @@ public class ResultExtensionsTests { var result = await ResultExtensions.TryAsync(async () => { - await Task.Delay(1); + await Task.Delay(1).ConfigureAwait(false); throw new InvalidOperationException("Error"); - }); + }).ConfigureAwait(false); Assert.That(result.IsFaulted, Is.True); Assert.That(result.Exception, Is.TypeOf()); } @@ -477,7 +478,8 @@ public class ResultExtensionsTests [Test] public async Task TryAsync_Should_Handle_Synchronous_Exceptions() { - var result = await ResultExtensions.TryAsync(() => throw new InvalidOperationException("Sync error")); + var result = await ResultExtensions.TryAsync(() => throw new InvalidOperationException("Sync error")) + .ConfigureAwait(false); Assert.That(result.IsFaulted, Is.True); } diff --git a/GFramework.Core.Tests/Functional/Pipe/PipeExtensionsTests.cs b/GFramework.Core.Tests/Functional/Pipe/PipeExtensionsTests.cs index 780356cb..1d79749e 100644 --- a/GFramework.Core.Tests/Functional/Pipe/PipeExtensionsTests.cs +++ b/GFramework.Core.Tests/Functional/Pipe/PipeExtensionsTests.cs @@ -1,3 +1,4 @@ +using System.Globalization; using GFramework.Core.Functional.Pipe; using NUnit.Framework; @@ -123,7 +124,7 @@ public class PipeExtensionsTests var result = value .Pipe(x => x * 2) .Pipe(x => x + 10) - .Pipe(x => x.ToString()); + .Pipe(x => x.ToString(CultureInfo.InvariantCulture)); // Assert Assert.That(result, Is.EqualTo("20")); @@ -139,7 +140,7 @@ public class PipeExtensionsTests var value = 42; // Act - var result = value.Let(x => x.ToString()); + var result = value.Let(x => x.ToString(CultureInfo.InvariantCulture)); // Assert Assert.That(result, Is.EqualTo("42")); @@ -171,7 +172,7 @@ public class PipeExtensionsTests var result = value.Let(s => new { Original = s, - Upper = s.ToUpper(), + Upper = s.ToUpperInvariant(), Length = s.Length }); @@ -280,4 +281,4 @@ public class PipeExtensionsTests // Assert Assert.That(result, Is.EqualTo("Large: 20")); } -} \ No newline at end of file +} diff --git a/GFramework.Core.Tests/Functional/ResultTTests.cs b/GFramework.Core.Tests/Functional/ResultTTests.cs index ec2d86c6..93dacc5e 100644 --- a/GFramework.Core.Tests/Functional/ResultTTests.cs +++ b/GFramework.Core.Tests/Functional/ResultTTests.cs @@ -11,6 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +using System.Globalization; using GFramework.Core.Functional; using NUnit.Framework; @@ -314,7 +315,7 @@ public class ResultTTests public void Map_Should_Transform_Value_When_Success() { var result = Result.Succeed(42); - var mapped = result.Map(x => x.ToString()); + var mapped = result.Map(x => x.ToString(CultureInfo.InvariantCulture)); Assert.That(mapped.IsSuccess, Is.True); Assert.That(mapped.Match(succ: v => v, fail: _ => ""), Is.EqualTo("42")); } @@ -327,7 +328,7 @@ public class ResultTTests { var exception = new Exception("Error"); var result = Result.Fail(exception); - var mapped = result.Map(x => x.ToString()); + var mapped = result.Map(x => x.ToString(CultureInfo.InvariantCulture)); Assert.That(mapped.IsFaulted, Is.True); Assert.That(mapped.Exception, Is.SameAs(exception)); } @@ -360,7 +361,7 @@ public class ResultTTests public void Bind_Should_Chain_Success_Results() { var result = Result.Succeed(42); - var bound = result.Bind(x => Result.Succeed(x.ToString())); + var bound = result.Bind(x => Result.Succeed(x.ToString(CultureInfo.InvariantCulture))); Assert.That(bound.IsSuccess, Is.True); Assert.That(bound.Match(succ: v => v, fail: _ => ""), Is.EqualTo("42")); } @@ -373,7 +374,7 @@ public class ResultTTests { var exception = new Exception("Error"); var result = Result.Fail(exception); - var bound = result.Bind(x => Result.Succeed(x.ToString())); + var bound = result.Bind(x => Result.Succeed(x.ToString(CultureInfo.InvariantCulture))); Assert.That(bound.IsFaulted, Is.True); Assert.That(bound.Exception, Is.SameAs(exception)); } @@ -414,7 +415,7 @@ public class ResultTTests var mapped = await result.MapAsync(async x => { await Task.Delay(1); - return x.ToString(); + return x.ToString(CultureInfo.InvariantCulture); }); Assert.That(mapped.IsSuccess, Is.True); Assert.That(mapped.Match(succ: v => v, fail: _ => ""), Is.EqualTo("42")); @@ -431,7 +432,7 @@ public class ResultTTests var mapped = await result.MapAsync(async x => { await Task.Delay(1); - return x.ToString(); + return x.ToString(CultureInfo.InvariantCulture); }); Assert.That(mapped.IsFaulted, Is.True); Assert.That(mapped.Exception, Is.SameAs(exception)); @@ -804,4 +805,4 @@ public class ResultTTests var bottom2 = Result.Bottom; Assert.That(bottom1.Equals(bottom2), Is.True); } -} \ No newline at end of file +} diff --git a/GFramework.Core.Tests/Resource/ResourceManagerTests.cs b/GFramework.Core.Tests/Resource/ResourceManagerTests.cs index 7e2e788c..dba15f62 100644 --- a/GFramework.Core.Tests/Resource/ResourceManagerTests.cs +++ b/GFramework.Core.Tests/Resource/ResourceManagerTests.cs @@ -33,7 +33,7 @@ public class TestResourceLoader : IResourceLoader public async Task LoadAsync(string path) { - await Task.Delay(10); // 模拟异步加载 + await Task.Delay(10).ConfigureAwait(false); // 模拟异步加载 return Load(path); } @@ -99,7 +99,7 @@ public class ResourceManagerTests [Test] public async Task LoadAsync_Should_Load_Resource() { - var resource = await _resourceManager.LoadAsync("test/resource1.txt"); + var resource = await _resourceManager.LoadAsync("test/resource1.txt").ConfigureAwait(false); Assert.That(resource, Is.Not.Null); Assert.That(resource!.Content, Is.EqualTo("Content 1")); @@ -404,4 +404,4 @@ public class ResourceManagerTests handle2!.Dispose(); Assert.That(_resourceManager.IsLoaded("test/resource2.txt"), Is.False); } -} \ No newline at end of file +} diff --git a/GFramework.Core.Tests/State/StateMachineTests.cs b/GFramework.Core.Tests/State/StateMachineTests.cs index a9f17a50..9edfb036 100644 --- a/GFramework.Core.Tests/State/StateMachineTests.cs +++ b/GFramework.Core.Tests/State/StateMachineTests.cs @@ -525,7 +525,7 @@ public sealed class TestAsyncState : IState, IAsyncState /// 从哪个状态进入 public async Task OnEnterAsync(IState? from) { - await Task.Delay(1); + await Task.Delay(1).ConfigureAwait(false); EnterCalled = true; EnterCallCount++; EnterFrom = from; @@ -537,7 +537,7 @@ public sealed class TestAsyncState : IState, IAsyncState /// 离开到哪个状态 public async Task OnExitAsync(IState? to) { - await Task.Delay(1); + await Task.Delay(1).ConfigureAwait(false); ExitCalled = true; ExitCallCount++; ExitTo = to; @@ -550,7 +550,7 @@ public sealed class TestAsyncState : IState, IAsyncState /// 是否允许转换 public async Task CanTransitionToAsync(IState target) { - await Task.Delay(1); + await Task.Delay(1).ConfigureAwait(false); CanTransitionToCallCount++; return AllowTransition; } diff --git a/GFramework.Core.Tests/State/StateTests.cs b/GFramework.Core.Tests/State/StateTests.cs index 6e2d25f8..d8ac2044 100644 --- a/GFramework.Core.Tests/State/StateTests.cs +++ b/GFramework.Core.Tests/State/StateTests.cs @@ -674,7 +674,7 @@ public sealed class ConcreteAsyncStateV2 : IState, IAsyncState /// 从哪个状态进入 public async Task OnEnterAsync(IState? from) { - await Task.Delay(1); + await Task.Delay(1).ConfigureAwait(false); EnterCalled = true; EnterCallCount++; EnterFrom = from; @@ -686,7 +686,7 @@ public sealed class ConcreteAsyncStateV2 : IState, IAsyncState /// 退出到哪个状态 public async Task OnExitAsync(IState? to) { - await Task.Delay(1); + await Task.Delay(1).ConfigureAwait(false); ExitCalled = true; ExitCallCount++; ExitTo = to; @@ -699,7 +699,7 @@ public sealed class ConcreteAsyncStateV2 : IState, IAsyncState /// 如果可以转换则返回true,否则返回false public async Task CanTransitionToAsync(IState target) { - await Task.Delay(1); + await Task.Delay(1).ConfigureAwait(false); CanTransitionToAsyncAction?.Invoke(target); return AllowTransitions; } @@ -731,4 +731,4 @@ public sealed class ConcreteAsyncStateV2 : IState, IAsyncState { throw new InvalidOperationException("Sync CanTransitionTo should not be called for async state"); } -} \ No newline at end of file +}