// Copyright (c) 2025 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.Core.Functional;
namespace GFramework.Core.Tests.Extensions;
///
/// ResultExtensions 扩展方法测试类
///
[TestFixture]
public class ResultExtensionsTests
{
///
/// 测试Combine方法在所有结果成功时返回成功列表
///
[Test]
public void Combine_Should_Return_Success_List_When_All_Results_Succeed()
{
var results = new[]
{
Result.Succeed(1),
Result.Succeed(2),
Result.Succeed(3)
};
var combined = results.Combine();
Assert.That(combined.IsSuccess, Is.True);
var list = combined.Match(succ: v => v, fail: _ => new List());
Assert.That(list, Has.Count.EqualTo(3));
Assert.That(list, Is.EqualTo(new[] { 1, 2, 3 }));
}
[Test]
public void Combine_Should_Return_First_Failure_When_Any_Result_Fails()
{
var exception = new Exception("Error");
var results = new[]
{
Result.Succeed(1),
Result.Fail(exception),
Result.Succeed(3)
};
var combined = results.Combine();
Assert.That(combined.IsFaulted, Is.True);
Assert.That(combined.Exception, Is.SameAs(exception));
}
///
/// 测试Combine方法处理空集合
///
[Test]
public void Combine_Should_Handle_Empty_Collection()
{
var results = Array.Empty>();
var combined = results.Combine();
Assert.That(combined.IsSuccess, Is.True);
var list = combined.Match(succ: v => v, fail: _ => new List());
Assert.That(list, Is.Empty);
}
///
/// 测试Combine方法在集合为null时抛出ArgumentNullException
///
[Test]
public void Combine_Should_Throw_ArgumentNullException_When_Collection_Is_Null()
{
Assert.Throws(() => ((IEnumerable>)null!).Combine());
}
///
/// 测试Combine方法保留值的顺序
///
[Test]
public void Combine_Should_Preserve_Order_Of_Values()
{
var results = new[]
{
Result.Succeed(3),
Result.Succeed(1),
Result.Succeed(2)
};
var combined = results.Combine();
var list = combined.Match(succ: v => v, fail: _ => new List());
Assert.That(list, Is.EqualTo(new[] { 3, 1, 2 }));
}
///
/// 测试Combine方法在第一个失败时短路
///
[Test]
public void Combine_Should_Short_Circuit_On_First_Failure()
{
var callCount = 0;
var results = new[]
{
Result.Succeed(1),
Result.Fail(new Exception("Error")),
Result.Try(() =>
{
callCount++;
return 3;
})
};
var combined = results.Combine();
Assert.That(combined.IsFaulted, Is.True);
}
///
/// 测试Map方法转换成功值
///
[Test]
public void Map_Should_Transform_Success_Value()
{
var result = Result.Succeed(42);
var mapped = result.Map(x => x.ToString());
Assert.That(mapped.IsSuccess, Is.True);
Assert.That(mapped.Match(succ: v => v, fail: _ => ""), Is.EqualTo("42"));
}
///
/// 测试Map方法传播失败
///
[Test]
public void Map_Should_Propagate_Failure()
{
var exception = new Exception("Error");
var result = Result.Fail(exception);
var mapped = result.Map(x => x.ToString());
Assert.That(mapped.IsFaulted, Is.True);
Assert.That(mapped.Exception, Is.SameAs(exception));
}
///
/// 测试Map方法在映射器为null时抛出ArgumentNullException
///
[Test]
public void Map_Should_Throw_ArgumentNullException_When_Mapper_Is_Null()
{
var result = Result.Succeed(42);
Assert.Throws(() => result.Map(null!));
}
///
/// 测试Bind方法链接成功结果
///
[Test]
public void Bind_Should_Chain_Success_Results()
{
var result = Result.Succeed(42);
var bound = result.Bind(x => Result.Succeed(x.ToString()));
Assert.That(bound.IsSuccess, Is.True);
Assert.That(bound.Match(succ: v => v, fail: _ => ""), Is.EqualTo("42"));
}
///
/// 测试Bind方法传播失败
///
[Test]
public void Bind_Should_Propagate_Failure()
{
var exception = new Exception("Error");
var result = Result.Fail(exception);
var bound = result.Bind(x => Result.Succeed(x.ToString()));
Assert.That(bound.IsFaulted, Is.True);
Assert.That(bound.Exception, Is.SameAs(exception));
}
///
/// 测试Bind方法在绑定器为null时抛出ArgumentNullException
///
[Test]
public void Bind_Should_Throw_ArgumentNullException_When_Binder_Is_Null()
{
var result = Result.Succeed(42);
Assert.Throws(() => result.Bind(null!));
}
///
/// 测试OnSuccess方法在成功时执行操作
///
[Test]
public void OnSuccess_Should_Execute_Action_When_Success()
{
var result = Result.Succeed(42);
var executed = false;
result.OnSuccess(_ => executed = true);
Assert.That(executed, Is.True);
}
///
/// 测试OnSuccess方法在失败时不执行操作
///
[Test]
public void OnSuccess_Should_Not_Execute_Action_When_Faulted()
{
var result = Result.Fail(new Exception("Error"));
var executed = false;
result.OnSuccess(_ => executed = true);
Assert.That(executed, Is.False);
}
///
/// 测试OnSuccess方法返回原始结果用于链式调用
///
[Test]
public void OnSuccess_Should_Return_Original_Result_For_Chaining()
{
var result = Result.Succeed(42);
var returned = result.OnSuccess(_ => { });
Assert.That(returned, Is.EqualTo(result));
}
///
/// 测试OnSuccess方法在操作为null时抛出ArgumentNullException
///
[Test]
public void OnSuccess_Should_Throw_ArgumentNullException_When_Action_Is_Null()
{
var result = Result.Succeed(42);
Assert.Throws(() => result.OnSuccess(null!));
}
///
/// 测试OnFailure方法在失败时执行操作
///
[Test]
public void OnFailure_Should_Execute_Action_When_Faulted()
{
var result = Result.Fail(new Exception("Error"));
var executed = false;
result.OnFailure(_ => executed = true);
Assert.That(executed, Is.True);
}
///
/// 测试OnFailure方法在成功时不执行操作
///
[Test]
public void OnFailure_Should_Not_Execute_Action_When_Success()
{
var result = Result.Succeed(42);
var executed = false;
result.OnFailure(_ => executed = true);
Assert.That(executed, Is.False);
}
///
/// 测试OnFailure方法返回原始结果用于链式调用
///
[Test]
public void OnFailure_Should_Return_Original_Result_For_Chaining()
{
var result = Result.Fail(new Exception("Error"));
var returned = result.OnFailure(_ => { });
Assert.That(returned, Is.EqualTo(result));
}
///
/// 测试OnFailure方法在操作为null时抛出ArgumentNullException
///
[Test]
public void OnFailure_Should_Throw_ArgumentNullException_When_Action_Is_Null()
{
var result = Result.Fail(new Exception("Error"));
Assert.Throws(() => result.OnFailure(null!));
}
///
/// 测试Ensure方法在谓词为true时返回成功
///
[Test]
public void Ensure_Should_Return_Success_When_Predicate_Is_True()
{
var result = Result.Succeed(42);
var ensured = result.Ensure(x => x > 0, "Value must be positive");
Assert.That(ensured.IsSuccess, Is.True);
}
///
/// 测试Ensure方法在谓词为false时返回失败
///
[Test]
public void Ensure_Should_Return_Failure_When_Predicate_Is_False()
{
var result = Result.Succeed(-1);
var ensured = result.Ensure(x => x > 0, "Value must be positive");
Assert.That(ensured.IsFaulted, Is.True);
Assert.That(ensured.Exception, Is.TypeOf());
}
///
/// 测试Ensure方法传播现有失败
///
[Test]
public void Ensure_Should_Propagate_Existing_Failure()
{
var exception = new Exception("Original error");
var result = Result.Fail(exception);
var ensured = result.Ensure(x => x > 0, "Value must be positive");
Assert.That(ensured.IsFaulted, Is.True);
Assert.That(ensured.Exception, Is.SameAs(exception));
}
///
/// 测试Ensure方法创建带消息的ArgumentException
///
[Test]
public void Ensure_Should_Create_ArgumentException_With_Message()
{
var result = Result.Succeed(-1);
var ensured = result.Ensure(x => x > 0, "Value must be positive");
Assert.That(ensured.Exception.Message, Is.EqualTo("Value must be positive"));
}
///
/// 测试Ensure方法在谓词为null时抛出ArgumentNullException
///
[Test]
public void Ensure_Should_Throw_ArgumentNullException_When_Predicate_Is_Null()
{
var result = Result.Succeed(42);
Assert.Throws(() => result.Ensure(null!, "Error"));
}
///
/// 测试Ensure方法在消息为null或空白时抛出ArgumentException
///
[Test]
public void Ensure_Should_Throw_ArgumentException_When_Message_Is_NullOrWhiteSpace()
{
var result = Result.Succeed(42);
Assert.Throws(() => result.Ensure(x => true, ""));
Assert.Throws(() => result.Ensure(x => true, " "));
}
///
/// 测试带工厂的Ensure方法在谓词为true时返回成功
///
[Test]
public void Ensure_WithFactory_Should_Return_Success_When_Predicate_Is_True()
{
var result = Result.Succeed(42);
var ensured = result.Ensure(x => x > 0, _ => new InvalidOperationException("Error"));
Assert.That(ensured.IsSuccess, Is.True);
}
///
/// 测试带工厂的Ensure方法返回带自定义异常的成功
///
[Test]
public void Ensure_WithFactory_Should_Return_Failure_With_Custom_Exception()
{
var result = Result.Succeed(-1);
var ensured = result.Ensure(x => x > 0, _ => new InvalidOperationException("Custom error"));
Assert.That(ensured.IsFaulted, Is.True);
Assert.That(ensured.Exception, Is.TypeOf());
}
///
/// 测试带工厂的Ensure方法传递值给异常工厂
///
[Test]
public void Ensure_WithFactory_Should_Pass_Value_To_Exception_Factory()
{
var result = Result.Succeed(-1);
var capturedValue = 0;
result.Ensure(x => x > 0, v =>
{
capturedValue = v;
return new Exception("Error");
});
Assert.That(capturedValue, Is.EqualTo(-1));
}
///
/// 测试带工厂的Ensure方法传播现有失败
///
[Test]
public void Ensure_WithFactory_Should_Propagate_Existing_Failure()
{
var exception = new Exception("Original error");
var result = Result.Fail(exception);
var ensured = result.Ensure(x => x > 0, _ => new InvalidOperationException("Error"));
Assert.That(ensured.Exception, Is.SameAs(exception));
}
///
/// 测试带工厂的Ensure方法在参数为null时抛出ArgumentNullException
///
[Test]
public void Ensure_WithFactory_Should_Throw_ArgumentNullException_When_Parameters_Are_Null()
{
var result = Result.Succeed(42);
Assert.Throws(() => result.Ensure(null!, (Func)(_ => new Exception())));
Assert.Throws(() => result.Ensure(x => true, (Func)null!));
}
///
/// 测试Try方法在函数成功时返回成功
///
[Test]
public void Try_Should_Return_Success_When_Function_Succeeds()
{
var result = ResultExtensions.Try(() => 42);
Assert.That(result.IsSuccess, Is.True);
Assert.That(result.Match(succ: v => v, fail: _ => 0), Is.EqualTo(42));
}
///
/// 测试Try方法在函数抛出异常时返回失败
///
[Test]
public void Try_Should_Return_Failure_When_Function_Throws()
{
var result = ResultExtensions.Try(() => throw new InvalidOperationException("Error"));
Assert.That(result.IsFaulted, Is.True);
Assert.That(result.Exception, Is.TypeOf());
}
///
/// 测试Try方法在函数为null时抛出ArgumentNullException
///
[Test]
public void Try_Should_Throw_ArgumentNullException_When_Function_Is_Null()
{
Assert.Throws(() => ResultExtensions.Try(null!));
}
///
/// 测试TryAsync方法在异步函数成功时返回成功
///
[Test]
public async Task TryAsync_Should_Return_Success_When_Async_Function_Succeeds()
{
var result = await ResultExtensions.TryAsync(async () =>
{
await Task.Delay(1);
return 42;
});
Assert.That(result.IsSuccess, Is.True);
Assert.That(result.Match(succ: v => v, fail: _ => 0), Is.EqualTo(42));
}
///
/// 测试TryAsync方法在异步函数抛出异常时返回失败
///
[Test]
public async Task TryAsync_Should_Return_Failure_When_Async_Function_Throws()
{
var result = await ResultExtensions.TryAsync(async () =>
{
await Task.Delay(1);
throw new InvalidOperationException("Error");
});
Assert.That(result.IsFaulted, Is.True);
Assert.That(result.Exception, Is.TypeOf());
}
///
/// 测试TryAsync方法处理同步异常
///
[Test]
public async Task TryAsync_Should_Handle_Synchronous_Exceptions()
{
var result = await ResultExtensions.TryAsync(() => throw new InvalidOperationException("Sync error"));
Assert.That(result.IsFaulted, Is.True);
}
///
/// 测试TryAsync方法在函数为null时抛出ArgumentNullException
///
[Test]
public void TryAsync_Should_Throw_ArgumentNullException_When_Function_Is_Null()
{
Assert.ThrowsAsync(async () => await ResultExtensions.TryAsync(null!));
}
///
/// 测试ToNullable方法在成功时返回值
///
[Test]
public void ToNullable_Should_Return_Value_When_Success()
{
var result = Result.Succeed(42);
var nullable = result.ToNullable();
Assert.That(nullable, Is.EqualTo(42));
}
///
/// 测试ToNullable方法在失败时返回null
///
[Test]
public void ToNullable_Should_Return_Null_When_Faulted()
{
var result = Result.Fail(new Exception("Error"));
var nullable = result.ToNullable();
Assert.That(nullable, Is.Null);
}
///
/// 测试ToNullable方法与值类型一起工作
///
[Test]
public void ToNullable_Should_Work_With_Value_Types()
{
var result = Result.Succeed(new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc));
var nullable = result.ToNullable();
Assert.That(nullable, Is.Not.Null);
Assert.That(nullable!.Value.Year, Is.EqualTo(2025));
Assert.That(nullable!.Value.Kind, Is.EqualTo(DateTimeKind.Utc));
}
///
/// 测试ToResult方法在值不为null时返回成功
///
[Test]
public void ToResult_Should_Return_Success_When_Value_Is_Not_Null()
{
string value = "test";
var result = value.ToResult();
Assert.That(result.IsSuccess, Is.True);
Assert.That(result.Match(succ: v => v, fail: _ => ""), Is.EqualTo("test"));
}
///
/// 测试ToResult方法在值为null时返回失败
///
[Test]
public void ToResult_Should_Return_Failure_When_Value_Is_Null()
{
string? value = null;
var result = value.ToResult();
Assert.That(result.IsFaulted, Is.True);
Assert.That(result.Exception, Is.TypeOf());
}
///
/// 测试ToResult方法使用自定义错误消息
///
[Test]
public void ToResult_Should_Use_Custom_Error_Message()
{
string? value = null;
var result = value.ToResult("Custom error");
Assert.That(result.Exception.Message, Does.Contain("Custom error"));
}
///
/// 测试ToResult方法在可空类型有值时返回成功
///
[Test]
public void ToResult_Should_Return_Success_When_Nullable_Has_Value()
{
int? value = 42;
var result = value.ToResult();
Assert.That(result.IsSuccess, Is.True);
Assert.That(result.Match(succ: v => v, fail: _ => 0), Is.EqualTo(42));
}
///
/// 测试ToResult方法在可空类型为null时返回失败
///
[Test]
public void ToResult_Should_Return_Failure_When_Nullable_Is_Null()
{
int? value = null;
var result = value.ToResult();
Assert.That(result.IsFaulted, Is.True);
Assert.That(result.Exception, Is.TypeOf());
}
///
/// 测试ToResult方法对可空类型使用自定义错误消息
///
[Test]
public void ToResult_Should_Use_Custom_Error_Message_For_Nullable()
{
int? value = null;
var result = value.ToResult("Custom nullable error");
Assert.That(result.Exception.Message, Does.Contain("Custom nullable error"));
}
///
/// 测试支持多个操作的复杂链式调用
///
[Test]
public void Should_Support_Complex_Chaining_With_Multiple_Operations()
{
var result = Result.Succeed(10)
.Map(x => x * 2)
.Bind(x => Result.Succeed(x + 5))
.Ensure(x => x > 20, "Value must be greater than 20")
.OnSuccess(x => Console.WriteLine($"Success: {x}"))
.OnFailure(ex => Console.WriteLine($"Error: {ex.Message}"));
Assert.That(result.IsSuccess, Is.True);
Assert.That(result.Match(succ: v => v, fail: _ => 0), Is.EqualTo(25));
}
///
/// 测试支持OnSuccess和OnFailure链式调用
///
[Test]
public void Should_Support_OnSuccess_And_OnFailure_Chaining()
{
var successCount = 0;
var failureCount = 0;
Result.Succeed(42)
.OnSuccess(_ => successCount++)
.OnFailure(_ => failureCount++);
Assert.That(successCount, Is.EqualTo(1));
Assert.That(failureCount, Is.EqualTo(0));
}
[Test]
public void Should_Support_Ensure_Chaining_With_Multiple_Conditions()
{
var result = Result.Succeed(50)
.Ensure(x => x > 0, "Must be positive")
.Ensure(x => x < 100, "Must be less than 100")
.Ensure(x => x % 2 == 0, "Must be even");
Assert.That(result.IsSuccess, Is.True);
}
}