@@ -0,0 +1,558 @@
|
||||
namespace Raliway.Tests.TryExtensions;
|
||||
|
||||
public class RunTests
|
||||
{
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// Action (void) — sync
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
public class Action_Void
|
||||
{
|
||||
[Fact]
|
||||
public void No_args_success()
|
||||
{
|
||||
var result = Try.Run(() => { });
|
||||
result.IsSuccess.ShouldBeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void No_args_exception()
|
||||
{
|
||||
var result = Try.Run(new Action(() => throw new InvalidOperationException("boom")));
|
||||
result.IsFailure.ShouldBeTrue();
|
||||
result.Error!.Message.ShouldBe("boom");
|
||||
result.Error!.Type.ShouldBe("System.InvalidOperationException");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void One_arg_success()
|
||||
{
|
||||
var captured = 0;
|
||||
var result = Try.Run<int>(x => captured = x, 42);
|
||||
result.IsSuccess.ShouldBeTrue();
|
||||
captured.ShouldBe(42);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void One_arg_exception()
|
||||
{
|
||||
var result = Try.Run(new Action<int>(_ => throw new InvalidOperationException("boom")), 42);
|
||||
result.IsFailure.ShouldBeTrue();
|
||||
result.Error!.Message.ShouldBe("boom");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Five_args_success()
|
||||
{
|
||||
var captured = "";
|
||||
var result = Try.Run<int, string, bool, double, char>(
|
||||
(a, b, c, d, e) => captured = $"{a}{b}{c}{d}{e}",
|
||||
1, "x", true, 3.14, 'z');
|
||||
result.IsSuccess.ShouldBeTrue();
|
||||
captured.ShouldBe("1xTrue3.14z");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Five_args_exception()
|
||||
{
|
||||
var result = Try.Run(
|
||||
new Action<int, string, bool, double, char>((_, _, _, _, _) => throw new InvalidOperationException("boom")),
|
||||
1, "x", true, 3.14, 'z');
|
||||
result.IsFailure.ShouldBeTrue();
|
||||
result.Error!.Message.ShouldBe("boom");
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// Func<Result> — sync
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
public class Func_Result
|
||||
{
|
||||
[Fact]
|
||||
public void No_args_returns_success()
|
||||
{
|
||||
var result = Try.Run(() => Result.Success());
|
||||
result.IsSuccess.ShouldBeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void No_args_returns_failure()
|
||||
{
|
||||
var error = Error.New("nope");
|
||||
var result = Try.Run(() => Result.Failure(error));
|
||||
result.IsFailure.ShouldBeTrue();
|
||||
result.Error.ShouldBe(error);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void No_args_exception_caught()
|
||||
{
|
||||
var result = Try.Run(new Func<Result>(() => throw new InvalidOperationException("boom")));
|
||||
result.IsFailure.ShouldBeTrue();
|
||||
result.Error!.Message.ShouldBe("boom");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void One_arg_passes_through()
|
||||
{
|
||||
var result = Try.Run<int>(x => Result.Success(x), 42);
|
||||
result.IsSuccess.ShouldBeTrue();
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// Func<T> — sync
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
public class Func_T
|
||||
{
|
||||
[Fact]
|
||||
public void No_args_success()
|
||||
{
|
||||
var result = Try.Run(() => 42);
|
||||
result.IsSuccess.ShouldBeTrue();
|
||||
result.Value.ShouldBe(42);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void No_args_exception()
|
||||
{
|
||||
var result = Try.Run(new Func<int>(() => throw new InvalidOperationException("boom")));
|
||||
result.IsFailure.ShouldBeTrue();
|
||||
result.Error!.Message.ShouldBe("boom");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void One_arg_success()
|
||||
{
|
||||
var result = Try.Run(x => $"val:{x}", 42);
|
||||
result.IsSuccess.ShouldBeTrue();
|
||||
result.Value.ShouldBe("val:42");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void One_arg_exception()
|
||||
{
|
||||
var result = Try.Run(new Func<int, string>(_ => throw new InvalidOperationException("boom")), 42);
|
||||
result.IsFailure.ShouldBeTrue();
|
||||
result.Error!.Message.ShouldBe("boom");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Null_value_is_preserved()
|
||||
{
|
||||
var result = Try.Run(() => (string?)null);
|
||||
result.IsSuccess.ShouldBeTrue();
|
||||
result.Value.ShouldBeNull();
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// Func<Result<T>> — sync
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
public class Func_ResultT
|
||||
{
|
||||
[Fact]
|
||||
public void No_args_returns_success()
|
||||
{
|
||||
var result = Try.Run(() => Result.Success(42));
|
||||
result.IsSuccess.ShouldBeTrue();
|
||||
result.Value.ShouldBe(42);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void No_args_returns_failure()
|
||||
{
|
||||
var error = Error.New("nope");
|
||||
var result = Try.Run(() => Result.Failure<int>(error));
|
||||
result.IsFailure.ShouldBeTrue();
|
||||
result.Error.ShouldBe(error);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void No_args_exception_caught()
|
||||
{
|
||||
var result = Try.Run(new Func<Result<int>>(() => throw new InvalidOperationException("boom")));
|
||||
result.IsFailure.ShouldBeTrue();
|
||||
result.Error!.Message.ShouldBe("boom");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void One_arg_passes_through()
|
||||
{
|
||||
var result = Try.Run(x => Result.Success($"val:{x}"), 42);
|
||||
result.IsSuccess.ShouldBeTrue();
|
||||
result.Value.ShouldBe("val:42");
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// Task async — Action (void)
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
public class Task_Action
|
||||
{
|
||||
[Fact]
|
||||
public async Task No_args_success()
|
||||
{
|
||||
var result = await Try.Run(() => Task.CompletedTask);
|
||||
result.IsSuccess.ShouldBeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task No_args_exception()
|
||||
{
|
||||
var result = await Try.Run(() => Task.FromException(new InvalidOperationException("boom")));
|
||||
result.IsFailure.ShouldBeTrue();
|
||||
result.Error!.Message.ShouldBe("boom");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task One_arg_success()
|
||||
{
|
||||
var captured = 0;
|
||||
var result = await Try.Run(x => { captured = x; return Task.CompletedTask; }, 42);
|
||||
result.IsSuccess.ShouldBeTrue();
|
||||
captured.ShouldBe(42);
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// Task async — Func<Task<Result>>
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
public class Task_Func_Result
|
||||
{
|
||||
[Fact]
|
||||
public async Task No_args_returns_success()
|
||||
{
|
||||
var result = await Try.Run(() => Task.FromResult(Result.Success()));
|
||||
result.IsSuccess.ShouldBeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task No_args_returns_failure()
|
||||
{
|
||||
var error = Error.New("nope");
|
||||
var result = await Try.Run(() => Task.FromResult(Result.Failure(error)));
|
||||
result.IsFailure.ShouldBeTrue();
|
||||
result.Error.ShouldBe(error);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task No_args_exception_caught()
|
||||
{
|
||||
var result = await Try.Run(new Func<Task<Result>>(() => throw new InvalidOperationException("boom")));
|
||||
result.IsFailure.ShouldBeTrue();
|
||||
result.Error!.Message.ShouldBe("boom");
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// Task async — Func<Task<T>>
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
public class Task_Func_T
|
||||
{
|
||||
[Fact]
|
||||
public async Task No_args_success()
|
||||
{
|
||||
var result = await Try.Run(() => Task.FromResult(42));
|
||||
result.IsSuccess.ShouldBeTrue();
|
||||
result.Value.ShouldBe(42);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task No_args_exception()
|
||||
{
|
||||
var result = await Try.Run(new Func<Task<int>>(() => throw new InvalidOperationException("boom")));
|
||||
result.IsFailure.ShouldBeTrue();
|
||||
result.Error!.Message.ShouldBe("boom");
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// Task async — Func<Task<Result<T>>>
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
public class Task_Func_ResultT
|
||||
{
|
||||
[Fact]
|
||||
public async Task No_args_returns_success()
|
||||
{
|
||||
var result = await Try.Run(() => Task.FromResult(Result.Success(42)));
|
||||
result.IsSuccess.ShouldBeTrue();
|
||||
result.Value.ShouldBe(42);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task No_args_returns_failure()
|
||||
{
|
||||
var error = Error.New("nope");
|
||||
var result = await Try.Run(() => Task.FromResult(Result.Failure<int>(error)));
|
||||
result.IsFailure.ShouldBeTrue();
|
||||
result.Error.ShouldBe(error);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task No_args_exception_caught()
|
||||
{
|
||||
var result = await Try.Run(new Func<Task<Result<int>>>(() => throw new InvalidOperationException("boom")));
|
||||
result.IsFailure.ShouldBeTrue();
|
||||
result.Error!.Message.ShouldBe("boom");
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// ValueTask async — Action (void)
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
public class ValueTask_Action
|
||||
{
|
||||
[Fact]
|
||||
public async Task No_args_success()
|
||||
{
|
||||
var result = await Try.RunValueTask(() => ValueTask.CompletedTask);
|
||||
result.IsSuccess.ShouldBeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task No_args_exception()
|
||||
{
|
||||
var result = await Try.RunValueTask(() => ValueTask.FromException(new InvalidOperationException("boom")));
|
||||
result.IsFailure.ShouldBeTrue();
|
||||
result.Error!.Message.ShouldBe("boom");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task One_arg_success()
|
||||
{
|
||||
var captured = 0;
|
||||
var result = await Try.RunValueTask(x => { captured = x; return ValueTask.CompletedTask; }, 42);
|
||||
result.IsSuccess.ShouldBeTrue();
|
||||
captured.ShouldBe(42);
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// ValueTask async — Func<ValueTask<Result>>
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
public class ValueTask_Func_Result
|
||||
{
|
||||
[Fact]
|
||||
public async Task No_args_returns_success()
|
||||
{
|
||||
var result = await Try.RunValueTask(() => ValueTask.FromResult(Result.Success()));
|
||||
result.IsSuccess.ShouldBeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task No_args_returns_failure()
|
||||
{
|
||||
var error = Error.New("nope");
|
||||
var result = await Try.RunValueTask(() => ValueTask.FromResult(Result.Failure(error)));
|
||||
result.IsFailure.ShouldBeTrue();
|
||||
result.Error.ShouldBe(error);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task No_args_exception_caught()
|
||||
{
|
||||
var result = await Try.RunValueTask(new Func<ValueTask<Result>>(() => throw new InvalidOperationException("boom")));
|
||||
result.IsFailure.ShouldBeTrue();
|
||||
result.Error!.Message.ShouldBe("boom");
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// ValueTask async — Func<ValueTask<T>>
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
public class ValueTask_Func_T
|
||||
{
|
||||
[Fact]
|
||||
public async Task No_args_success()
|
||||
{
|
||||
var result = await Try.RunValueTask(() => ValueTask.FromResult(42));
|
||||
result.IsSuccess.ShouldBeTrue();
|
||||
result.Value.ShouldBe(42);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task No_args_exception()
|
||||
{
|
||||
var result = await Try.RunValueTask<int>(() => throw new InvalidOperationException("boom"));
|
||||
result.IsFailure.ShouldBeTrue();
|
||||
result.Error!.Message.ShouldBe("boom");
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// ValueTask async — Func<ValueTask<Result<T>>>
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
public class ValueTask_Func_ResultT
|
||||
{
|
||||
[Fact]
|
||||
public async Task No_args_returns_success()
|
||||
{
|
||||
var result = await Try.RunValueTask(() => ValueTask.FromResult(Result.Success(42)));
|
||||
result.IsSuccess.ShouldBeTrue();
|
||||
result.Value.ShouldBe(42);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task No_args_returns_failure()
|
||||
{
|
||||
var error = Error.New("nope");
|
||||
var result = await Try.RunValueTask(() => ValueTask.FromResult(Result.Failure<int>(error)));
|
||||
result.IsFailure.ShouldBeTrue();
|
||||
result.Error.ShouldBe(error);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task No_args_exception_caught()
|
||||
{
|
||||
var result = await Try.RunValueTask(new Func<ValueTask<Result<int>>>(() => throw new InvalidOperationException("boom")));
|
||||
result.IsFailure.ShouldBeTrue();
|
||||
result.Error!.Message.ShouldBe("boom");
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// AggregateException unwrapping
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
public class AggregateException_Unwrapping
|
||||
{
|
||||
[Fact]
|
||||
public void Single_inner_exception_is_unwrapped()
|
||||
{
|
||||
var result = Try.Run(new Func<int>(() => throw new AggregateException(new InvalidOperationException("inner"))));
|
||||
result.IsFailure.ShouldBeTrue();
|
||||
result.Error!.Type.ShouldBe("System.InvalidOperationException");
|
||||
result.Error!.Message.ShouldBe("inner");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Multiple_inner_exceptions_become_ManyErrors()
|
||||
{
|
||||
var result = Try.Run(new Func<int>(() => throw new AggregateException(
|
||||
new InvalidOperationException("first"),
|
||||
new ArgumentException("second"))));
|
||||
result.IsFailure.ShouldBeTrue();
|
||||
result.Error!.Type.ShouldBe("many_errors");
|
||||
var many = (ManyErrors)result.Error!;
|
||||
many.Count.ShouldBe(2);
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// Async exception in task body (not Task.FromException)
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
public class Async_Exception_In_Body
|
||||
{
|
||||
[Fact]
|
||||
public async Task Task_throws_in_async_body()
|
||||
{
|
||||
var result = await Try.Run(async () =>
|
||||
{
|
||||
await Task.Yield();
|
||||
throw new InvalidOperationException("async boom");
|
||||
});
|
||||
result.IsFailure.ShouldBeTrue();
|
||||
result.Error!.Message.ShouldBe("async boom");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ValueTask_throws_in_async_body()
|
||||
{
|
||||
var result = await Try.RunValueTask(async () =>
|
||||
{
|
||||
await Task.Yield();
|
||||
throw new InvalidOperationException("async boom vt");
|
||||
});
|
||||
result.IsFailure.ShouldBeTrue();
|
||||
result.Error!.Message.ShouldBe("async boom vt");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Task_FuncT_throws_in_async_body()
|
||||
{
|
||||
var result = await Try.Run<int>(async () =>
|
||||
{
|
||||
await Task.Yield();
|
||||
throw new InvalidOperationException("async boom");
|
||||
});
|
||||
result.IsFailure.ShouldBeTrue();
|
||||
result.Error!.Message.ShouldBe("async boom");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ValueTask_ResultT_throws_in_async_body()
|
||||
{
|
||||
var result = await Try.RunValueTask<int>(async () =>
|
||||
{
|
||||
await Task.Yield();
|
||||
throw new InvalidOperationException("async boom vt");
|
||||
});
|
||||
result.IsFailure.ShouldBeTrue();
|
||||
result.Error!.Message.ShouldBe("async boom vt");
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// Edge cases
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
|
||||
public class Edge_Cases
|
||||
{
|
||||
[Fact]
|
||||
public void Reference_type_null_success_value_is_preserved()
|
||||
{
|
||||
var result = Try.Run(() => Result.Success<string?>(null));
|
||||
result.IsSuccess.ShouldBeTrue();
|
||||
result.Value.ShouldBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Large_ValueTuple_is_preserved()
|
||||
{
|
||||
var result = Try.Run(() => (1, 2, 3, 4, 5));
|
||||
result.IsSuccess.ShouldBeTrue();
|
||||
result.Value.ShouldBe((1, 2, 3, 4, 5));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Async_large_ValueTuple_is_preserved()
|
||||
{
|
||||
var result = await Try.Run(() => Task.FromResult((1, 2, 3, 4, 5)));
|
||||
result.IsSuccess.ShouldBeTrue();
|
||||
result.Value.ShouldBe((1, 2, 3, 4, 5));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Three_args_all_passed_correctly()
|
||||
{
|
||||
var result = Try.Run(
|
||||
(a, b, c) => $"{a}-{b}-{c}",
|
||||
1, "two", true);
|
||||
result.IsSuccess.ShouldBeTrue();
|
||||
result.Value.ShouldBe("1-two-True");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Task_with_three_args()
|
||||
{
|
||||
var result = await Try.Run(
|
||||
(a, b, c) => Task.FromResult($"{a}-{b}-{c}"),
|
||||
1, "two", true);
|
||||
result.IsSuccess.ShouldBeTrue();
|
||||
result.Value.ShouldBe("1-two-True");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user