Files
Just.Railway/Raliway.Tests/TryExtensions/Run.cs
T
just 0e7986996f
.NET Test / .NET tests (push) Successful in 2m0s
extensions rework pt1
2026-07-13 22:20:47 +04:00

559 lines
21 KiB
C#

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");
}
}
}