using GFramework.Core.Functional.Functions; using NUnit.Framework; namespace GFramework.Core.Tests.Functional.Functions; /// /// FunctionExtensions扩展方法测试类,用于验证高级函数式编程扩展方法的正确性 /// 包括柯里化、偏函数应用、重复执行、安全执行和缓存等功能的测试 /// [TestFixture] public class FunctionExtensionsTests { /// /// 测试Partial方法 - 验证部分应用函数功能 /// [Test] public void Partial_Should_Fix_First_Argument_Of_Binary_Function() { // Arrange Func multiply = (x, y) => x * y; // Act var doubleFunction = multiply.Partial(2); var result = doubleFunction(5); // Assert Assert.That(result, Is.EqualTo(10)); } /// /// 测试Repeat方法 - 验证重复执行函数功能 /// [Test] public void Repeat_Should_Execute_Function_N_Times() { // Arrange var initialValue = 2; // Act var result = initialValue.Repeat(3, x => x * 2); // Assert // 2 -> 4 -> 8 -> 16 (3次重复) Assert.That(result, Is.EqualTo(16)); } [Test] public void Compose_Should_Apply_Functions_In_Reverse_Order() { // Arrange int AddOne(int x) => x + 1; Func multiplyTwo = x => x * 2; // Act var composed = multiplyTwo.Compose((Func)AddOne); // (x + 1) * 2 // Assert Assert.That(composed(5), Is.EqualTo(12)); // (5 + 1) * 2 = 12 } [Test] public void Compose_WithNullOuterFunction_Should_Throw_ArgumentNullException() { // Arrange Func addOne = x => x + 1; // Act & Assert Assert.Throws(() => ((Func)null!).Compose(addOne)); } [Test] public void Compose_WithNullInnerFunction_Should_Throw_ArgumentNullException() { // Arrange Func multiplyTwo = x => x * 2; // Act & Assert Assert.Throws(() => multiplyTwo.Compose(null!)); } [Test] public void AndThen_Should_Apply_Functions_In_Order() { // Arrange Func addOne = x => x + 1; int MultiplyTwo(int x) => x * 2; // Act var chained = addOne.AndThen((Func)MultiplyTwo); // (x + 1) * 2 // Assert Assert.That(chained(5), Is.EqualTo(12)); // (5 + 1) * 2 = 12 } [Test] public void AndThen_WithNullFirstFunction_Should_Throw_ArgumentNullException() { // Arrange Func multiplyTwo = x => x * 2; // Act & Assert Assert.Throws(() => ((Func)null!).AndThen(multiplyTwo)); } [Test] public void AndThen_WithNullSecondFunction_Should_Throw_ArgumentNullException() { // Arrange Func addOne = x => x + 1; // Act & Assert Assert.Throws(() => addOne.AndThen(null!)); } [Test] public void Curry_TwoParameters_Should_Return_Nested_Functions() { // Arrange Func add = (x, y) => x + y; // Act var curriedAdd = add.Curry(); var add5 = curriedAdd(5); var result = add5(3); // Assert Assert.That(result, Is.EqualTo(8)); } [Test] public void Curry_ThreeParameters_Should_Return_Nested_Functions() { // Arrange Func add3 = (x, y, z) => x + y + z; // Act var curriedAdd = add3.Curry(); var result = curriedAdd(1)(2)(3); // Assert Assert.That(result, Is.EqualTo(6)); } [Test] public void Curry_WithNullFunction_Should_Throw_ArgumentNullException() { // Arrange Func func = null!; // Act & Assert Assert.Throws(() => func.Curry()); } [Test] public void Uncurry_Should_Restore_Multi_Parameter_Function() { // Arrange Func> curriedAdd = x => y => x + y; // Act var add = curriedAdd.Uncurry(); var result = add(5, 3); // Assert Assert.That(result, Is.EqualTo(8)); } [Test] public void Uncurry_WithNullFunction_Should_Throw_ArgumentNullException() { // Arrange Func> func = null!; // Act & Assert Assert.Throws(() => func.Uncurry()); } [Test] public void Curry_Then_Uncurry_Should_Be_Identity() { // Arrange Func original = (x, y) => x * y; // Act var restored = original.Curry().Uncurry(); var result = restored(6, 7); // Assert Assert.That(result, Is.EqualTo(42)); } [Test] public void Defer_Should_Not_Execute_Immediately() { // Arrange var executed = false; Func func = () => { executed = true; return 42; }; // Act var lazy = func.Defer(); // Assert Assert.That(executed, Is.False); Assert.That(lazy.Value, Is.EqualTo(42)); Assert.That(executed, Is.True); } [Test] public void Defer_WithNullFunction_Should_Throw_ArgumentNullException() { // Arrange Func func = null!; // Act & Assert Assert.Throws(() => func.Defer()); } [Test] public void Once_Should_Execute_Function_Only_Once() { // Arrange var counter = 0; Func func = () => ++counter; // Act var once = func.Once(); var result1 = once(); var result2 = once(); var result3 = once(); // Assert Assert.That(result1, Is.EqualTo(1)); Assert.That(result2, Is.EqualTo(1)); Assert.That(result3, Is.EqualTo(1)); Assert.That(counter, Is.EqualTo(1)); } [Test] public void Once_WithNullFunction_Should_Throw_ArgumentNullException() { // Arrange Func func = null!; // Act & Assert Assert.Throws(() => func.Once()); } [Test] public void Once_Should_Be_Thread_Safe() { // Arrange var counter = 0; Func func = () => Interlocked.Increment(ref counter); var once = func.Once(); // Act var tasks = Enumerable.Range(0, 10) .Select(_ => Task.Run(() => once())) .ToArray(); Task.WaitAll(tasks.Cast().ToArray()); // Assert Assert.That(counter, Is.EqualTo(1)); Assert.That(tasks.Select(t => t.Result).Distinct().Count(), Is.EqualTo(1)); } }