using GFramework.Core.Functional.Control; using NUnit.Framework; namespace GFramework.Core.Tests.Functional.Control; /// /// ControlExtensions扩展方法测试类,用于验证控制流函数式编程扩展方法的正确性 /// [TestFixture] public class ControlExtensionsTests { /// /// 测试TakeIf方法 - 验证条件为真时返回原值 /// [Test] public void TakeIf_Should_Return_Value_When_Condition_Is_True() { // Arrange var str = "Hello"; // Act var result = str.TakeIf(s => s.Length > 3); // Assert Assert.That(result, Is.EqualTo("Hello")); } /// /// 测试TakeIf方法 - 验证条件为假时返回null /// [Test] public void TakeIf_Should_Return_Null_When_Condition_Is_False() { // Arrange var str = "Hi"; // Act var result = str.TakeIf(s => s.Length > 3); // Assert Assert.That(result, Is.Null); } /// /// 测试TakeUnless方法 - 验证条件为假时返回原值 /// [Test] public void TakeUnless_Should_Return_Value_When_Condition_Is_False() { // Arrange var str = "Hi"; // Act var result = str.TakeUnless(s => s.Length > 3); // Assert Assert.That(result, Is.EqualTo("Hi")); } /// /// 测试TakeUnless方法 - 验证条件为真时返回null /// [Test] public void TakeUnless_Should_Return_Null_When_Condition_Is_True() { // Arrange var str = "Hello"; // Act var result = str.TakeUnless(s => s.Length > 3); // Assert Assert.That(result, Is.Null); } [Test] public void TakeIfValue_Should_Return_Value_When_Condition_Is_True() { // Arrange var value = 42; // Act var result = value.TakeIfValue(x => x > 0); // Assert Assert.That(result, Is.EqualTo(42)); } [Test] public void TakeIfValue_Should_Return_Null_When_Condition_Is_False() { // Arrange var value = -5; // Act var result = value.TakeIfValue(x => x > 0); // Assert Assert.That(result, Is.Null); } [Test] public void TakeIfValue_WithNullPredicate_Should_Throw_ArgumentNullException() { // Arrange var value = 42; // Act & Assert Assert.Throws(() => value.TakeIfValue(null!)); } [Test] public void TakeUnlessValue_Should_Return_Value_When_Condition_Is_False() { // Arrange var value = 42; // Act var result = value.TakeUnlessValue(x => x < 0); // Assert Assert.That(result, Is.EqualTo(42)); } [Test] public void TakeUnlessValue_Should_Return_Null_When_Condition_Is_True() { // Arrange var value = -5; // Act var result = value.TakeUnlessValue(x => x < 0); // Assert Assert.That(result, Is.Null); } [Test] public void TakeUnlessValue_WithNullPredicate_Should_Throw_ArgumentNullE() { // Arrange var value = 42; // Act & Assert Assert.Throws(() => value.TakeUnlessValue(null!)); } [Test] public void When_Should_Execute_Action_When_Condition_Is_True() { // Arrange var value = 42; var executed = false; // Act var result = value.When(x => x > 0, x => executed = true); // Assert Assert.That(result, Is.EqualTo(42)); Assert.That(executed, Is.True); } [Test] public void When_Should_Not_Executehen_Condition_Is_False() { // Arrange var value = -5; var executed = false; // Act var result = value.When(x => x > 0, x => executed = true); // Assert Assert.That(result, Is.EqualTo(-5)); Assert.That(executed, Is.False); } [Test] public void When_WithNullPredicate_Should_Throw_ArgumentNullException() { // Arrange var value = 42; // Act & Assert Assert.Throws(() => value.When(null!, x => { })); } [Test] public void When_WithNullAction_Should_Throw_ArgumentNullException() { // Arrange var value = 42; // Act & Assert Assert.Throws(() => value.When(x => true, null!)); } [Test] public void When_Should_Allow_Chaining() { // Arrange var value = 10; var log = new List(); // Act var result = value .When(x => x > 5, x => log.Add("Greater than 5")) .When(x => x % 2 == 0, x => log.Add("Even number")); // Assert Assert.That(result, Is.EqualTo(10)); Assert.That(log, Has.Count.EqualTo(2)); } [Test] public void RepeatUntil_Should_Repeat_Until_Condition_Is_Met() { // Arrange var value = 1; // Act var result = value.RepeatUntil( x => x * 2, x => x >= 100, maxIterations: 10 ); // Assert Assert.That(result, Is.EqualTo(128)); } [Test] public void RepeatUntil_Should_Return_Initial_Value_If_Condition_Already_Met() { // Arrange var value = 100; // Act var result = value.RepeatUntil( x => x * 2, x => x >= 100, maxIterations: 10 ); // Assert Assert.That(result, Is.EqualTo(100)); } [Test] public void RepeatUntil_Should_Throw_When_Max_Iterations_Reached() { // Arrange var value = 1; // Act & Assert Assert.Throws(() => value.RepeatUntil( x => x + 1, x => x > 1000, maxIterations: 10 )); } [Test] public void RepeatUntil_WithNullFunc_Should_Throw_ArgumentNullException() { // Arrange var value = 1; // Act & Assert Assert.Throws(() => value.RepeatUntil(null!, x => true)); } [Test] public void RepeatUntil_WithNullPredicate_Should_Throw_ArgumentNullException() { // Arrange var value = 1; // Act & Assert Assert.Throws(() => value.RepeatUntil(x => x, null!)); } [Test] public void RepeatUntil_WithInvalidMaxIterations_Should_Throw_ArgumentOutOfRangeException() { // Arrange var value = 1; // Act & Assert Assert.Throws(() => value.RepeatUntil(x => x, x => true, maxIterations: 0)); } [Test] public void Retry_Should_Return_Result_On_First_Success() { // Arrange var counter = 0; Func func = () => ++counter; // Act var result = ControlExtensions.Retry(func, maxRetries: 3); // Assert Assert.That(result, Is.EqualTo(1)); Assert.That(counter, Is.EqualTo(1)); } [Test] public void Retry_Should_Retry_On_Failure() { // Arrange var counter = 0; Func func = () => { counter++; if (counter < 3) throw new InvalidOperationException("Not ready"); return counter; }; // Act var result = ControlExtensions.Retry(func, maxRetries: 3); // Assert Assert.That(result, Is.EqualTo(3)); Assert.That(counter, Is.EqualTo(3)); } [Test] public void Retry_Should_Throw_AggregateException_When_All_Retries_Fail() { // Arrange var counter = 0; Func func = () => { counter++; throw new InvalidOperationException($"Attempt {counter}"); }; // Act & Assert var ex = Assert.Throws(() => ControlExtensions.Retry(func, maxRetries: 2)); Assert.That(counter, Is.EqualTo(3)); // 1 initial + 2 retries Assert.That(ex!.InnerExceptions, Has.Count.EqualTo(3)); } [Test] public void Retry_WithNullFunc_Should_Throw_ArgumentNullException() { // Act & Assert Assert.Throws(() => ControlExtensions.Retry(null!, maxRetries: 3)); } [Test] public void Retry_WithNegativeMaxRetries_Should_Throw_ArgumentOutOfRangeException() { // Arrange Func func = () => 42; // Act & Assert Assert.Throws(() => ControlExtensions.Retry(func, maxRetries: -1)); } [Test] public void Retry_WithNegativeDelay_Should_Throw_ArgumentOutOfRangeException() { // Arrange Func func = () => 42; // Act & Assert Assert.Throws(() => ControlExtensions.Retry(func, maxRetries: 3, delayMilliseconds: -1)); } [Test] public void Retry_Should_Delay_Between_Retries() { // Arrange var counter = 0; var startTime = DateTime.UtcNow; Func func = () => { counter++; if (counter < 3) throw new InvalidOperationException("Not ready"); return counter; }; // Act var result = ControlExtensions.Retry(func, maxRetries: 3, delayMilliseconds: 50); var elapsed = DateTime.UtcNow - startTime; // Assert Assert.That(result, Is.EqualTo(3)); Assert.That(elapsed.TotalMilliseconds, Is.GreaterThanOrEqualTo(100)); // 2 delays of 50ms } }