using System.Diagnostics; using GFramework.Core.extensions; using GFramework.Core.Functional.Async; using NUnit.Framework; namespace GFramework.Core.Tests.extensions; /// /// 测试 AsyncExtensions 扩展方法的功能 /// [TestFixture] public class AsyncExtensionsTests { /// /// 测试WithTimeout方法在任务超时前完成时返回结果 /// [Test] public async Task WithTimeout_Should_Return_Result_When_Task_Completes_Before_Timeout() { // Act var result = await AsyncExtensions.WithTimeout( _ => Task.FromResult(42), TimeSpan.FromSeconds(1)); // Assert Assert.That(result, Is.EqualTo(42)); } /// /// 测试WithTimeout方法在任务超过超时时抛出TimeoutException /// [Test] public void WithTimeout_Should_Throw_TimeoutException_When_Task_Exceeds_Timeout() { // Act & Assert Assert.ThrowsAsync(async () => await AsyncExtensions.WithTimeout( async ct => { await Task.Delay(TimeSpan.FromSeconds(2), ct); return 42; }, TimeSpan.FromMilliseconds(100))); } /// /// 测试WithTimeout方法在取消请求时抛出OperationCanceledException /// [Test] public void WithTimeout_Should_Throw_OperationCanceledException_When_Cancellation_Requested() { // Arrange using var cts = new CancellationTokenSource(); cts.Cancel(); // Act & Assert Assert.ThrowsAsync(async () => await AsyncExtensions.WithTimeout( async ct => { await Task.Delay(TimeSpan.FromSeconds(2), ct); return 42; }, TimeSpan.FromSeconds(1), cts.Token)); } /// /// 测试WithTimeout方法在超时时取消内部任务 /// [Test] public void WithTimeout_Should_Cancel_Inner_Task_When_Timeout_Elapses() { // Arrange var innerTaskCanceled = false; // Act & Assert Assert.ThrowsAsync(async () => await AsyncExtensions.WithTimeout( async ct => { try { await Task.Delay(TimeSpan.FromSeconds(5), ct); return 0; } catch (OperationCanceledException) { innerTaskCanceled = true; throw; } }, TimeSpan.FromMilliseconds(100))); Assert.That(innerTaskCanceled, Is.True, "内部任务应在超时时收到取消信号"); } /// /// 测试无返回值的WithTimeout在任务超时前完成 /// [Test] public async Task WithTimeout_NoResult_Should_Complete_When_Task_Completes_Before_Timeout() { // Arrange var stopwatch = Stopwatch.StartNew(); // Act await AsyncExtensions.WithTimeout( _ => Task.CompletedTask, TimeSpan.FromSeconds(1)); stopwatch.Stop(); // Assert Assert.That(stopwatch.ElapsedMilliseconds, Is.LessThan(1000), "Task should complete before timeout"); Assert.Pass("Task completed successfully within timeout period"); } /// /// 测试无返回值的WithTimeout在任务超时时抛出TimeoutException /// [Test] public void WithTimeout_NoResult_Should_Throw_TimeoutException_When_Task_Exceeds_Timeout() { // Act & Assert Assert.ThrowsAsync(async () => await AsyncExtensions.WithTimeout( ct => Task.Delay(TimeSpan.FromSeconds(2), ct), TimeSpan.FromMilliseconds(100))); } /// /// 测试无返回值的WithTimeout在超时时取消内部任务 /// [Test] public void WithTimeout_NoResult_Should_Cancel_Inner_Task_When_Timeout_Elapses() { // Arrange var innerTaskCanceled = false; // Act & Assert Assert.ThrowsAsync(async () => await AsyncExtensions.WithTimeout( async ct => { try { await Task.Delay(TimeSpan.FromSeconds(5), ct); } catch (OperationCanceledException) { innerTaskCanceled = true; throw; } }, TimeSpan.FromMilliseconds(100))); Assert.That(innerTaskCanceled, Is.True, "内部任务应在超时时收到取消信号"); } /// /// 测试WithRetry方法在任务成功时返回结果 /// [Test] public async Task WithRetry_Should_Return_Result_When_Task_Succeeds() { // Arrange var attemptCount = 0; Func> taskFactory = () => { attemptCount++; return Task.FromResult(42); }; // Act var result = await taskFactory.WithRetry(3, TimeSpan.FromMilliseconds(10)); // Assert Assert.That(result, Is.EqualTo(42)); Assert.That(attemptCount, Is.EqualTo(1)); } /// /// 测试WithRetry方法在失败时重试 /// [Test] public async Task WithRetry_Should_Retry_On_Failure() { // Arrange var attemptCount = 0; Func> taskFactory = () => { attemptCount++; if (attemptCount < 3) throw new InvalidOperationException("Temporary failure"); return Task.FromResult(42); }; // Act var result = await taskFactory.WithRetry(3, TimeSpan.FromMilliseconds(10)); // Assert Assert.That(result, Is.EqualTo(42)); Assert.That(attemptCount, Is.EqualTo(3)); } /// /// 测试WithRetry方法在所有重试都失败时抛出AggregateException /// [Test] public void WithRetry_Should_Throw_AggregateException_When_All_Retries_Fail() { // Arrange var attemptCount = 0; Func> taskFactory = () => { attemptCount++; throw new InvalidOperationException("Permanent failure"); }; // Act & Assert Assert.ThrowsAsync(async () => await taskFactory.WithRetry(2, TimeSpan.FromMilliseconds(10))); } /// /// 测试WithRetry方法遵守ShouldRetry谓词 /// [Test] public async Task WithRetry_Should_Respect_ShouldRetry_Predicate() { // Arrange var attemptCount = 0; Func> taskFactory = () => { attemptCount++; throw new ArgumentException("Should not retry"); }; // Act & Assert Assert.ThrowsAsync(async () => await taskFactory.WithRetry(3, TimeSpan.FromMilliseconds(10), ex => ex is not ArgumentException)); await Task.Delay(50); // 等待任务完成 Assert.That(attemptCount, Is.EqualTo(1)); // 不应该重试 } /// /// 测试TryAsync方法在任务成功时返回成功结果 /// [Test] public async Task TryAsync_Should_Return_Success_When_Task_Succeeds() { // Arrange Func> func = () => Task.FromResult(42); // Act var result = await func.TryAsync(); // Assert Assert.That(result.IsSuccess, Is.True); Assert.That(result.IfFail(0), Is.EqualTo(42)); } /// /// 测试TryAsync方法在任务抛出异常时返回失败结果 /// [Test] public async Task TryAsync_Should_Return_Failure_When_Task_Throws() { // Arrange Func> func = () => throw new InvalidOperationException("Test error"); // Act var result = await func.TryAsync(); // Assert Assert.That(result.IsFaulted, Is.True); } /// /// 测试WithFallback方法在任务成功时返回结果 /// [Test] public async Task WithFallback_Should_Return_Result_When_Task_Succeeds() { // Arrange var task = Task.FromResult(42); // Act var result = await task.WithFallback(_ => -1); // Assert Assert.That(result, Is.EqualTo(42)); } /// /// 测试WithFallback方法在任务失败时返回备用值 /// [Test] public async Task WithFallback_Should_Return_Fallback_Value_When_Task_Fails() { // Arrange var task = Task.FromException(new InvalidOperationException("Test error")); // Act var result = await task.WithFallback(_ => -1); // Assert Assert.That(result, Is.EqualTo(-1)); } /// /// 测试WithFallback方法将异常传递给备用函数 /// [Test] public async Task WithFallback_Should_Pass_Exception_To_Fallback() { // Arrange var expectedException = new InvalidOperationException("Test error"); var task = Task.FromException(expectedException); Exception? capturedEx = null; // Act await task.WithFallback(ex => { capturedEx = ex; return -1; }); // Assert Assert.That(capturedEx, Is.SameAs(expectedException)); } }