feat: add inital in memory dispatcher
All checks were successful
default / dotnet-default-workflow (push) Successful in 1m27s

Add a simple in memory dispatcher for scalar requests and stream request.
This commit is contained in:
Louis Seubert 2026-05-08 20:26:26 +02:00
commit 28c07c5c3f
Signed by: louis9902
GPG key ID: 4B9DB28F826553BD
145 changed files with 6380 additions and 0 deletions

View file

@ -0,0 +1,9 @@
[*.{cs,vb}]
# disable CA1822: Mark members as static
# -> TUnit requiring instance methods for test cases
dotnet_diagnostic.CA1822.severity = none
# disable CA1707: Identifiers should not contain underscores
dotnet_diagnostic.CA1707.severity = none
# disable IDE0060: Remove unused parameter
dotnet_diagnostic.IDE0060.severity = none

View file

@ -0,0 +1,27 @@
// Copyright (c) The Geekeey Authors
// SPDX-License-Identifier: EUPL-1.2
namespace Geekeey.Request.Result.Tests;
internal sealed class ErrorTests
{
[Test]
public async Task I_can_implicitly_convert_from_string_and_get_string_error()
{
Error error = "error";
using var scope = Assert.Multiple();
await Assert.That(error).IsTypeOf<StringError>();
await Assert.That(error.Message).IsEqualTo("error");
}
[Test]
public async Task I_can_implicitly_convert_from_exception_and_get_exception_error()
{
Error error = new CustomTestException();
using var scope = Assert.Multiple();
var instance = await Assert.That(error).IsTypeOf<ExceptionError>();
await Assert.That(instance?.Exception).IsTypeOf<CustomTestException>();
}
}

View file

@ -0,0 +1,50 @@
// Copyright (c) The Geekeey Authors
// SPDX-License-Identifier: EUPL-1.2
namespace Geekeey.Request.Result.Tests;
internal sealed class ExtensionsEnumerableTests
{
[Test]
public async Task I_can_join_sequence_and_get_all_success_when_all_elements_are_success()
{
IEnumerable<Result<int>> xs = [1, 2, 3, 4, 5];
var result = xs.Join();
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsTrue();
await Assert.That(result.Value).IsEquivalentTo([1, 2, 3, 4, 5]);
}
[Test]
public async Task I_can_join_sequence_and_get_first_failure_when_sequence_contains_failure()
{
IEnumerable<Result<int>> xs =
[
Prelude.Success(1),
Prelude.Success(2),
Prelude.Failure<int>("error 1"),
Prelude.Success(4),
Prelude.Failure<int>("error 2")
];
var result = xs.Join();
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
await Assert.That(result.Error?.Message).IsEqualTo("error 1");
}
[Test]
public async Task I_can_join_empty_sequence_and_get_success()
{
IEnumerable<Result<int>> xs = [];
var result = xs.Join();
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsTrue();
await Assert.That(result.Value).IsEmpty();
}
}

View file

@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TUnit" />
</ItemGroup>
<ItemGroup>
<AssemblyAttribute Include="System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\request.result\Geekeey.Request.Result.csproj" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,100 @@
// Copyright (c) The Geekeey Authors
// SPDX-License-Identifier: EUPL-1.2
namespace Geekeey.Request.Result.Tests;
internal sealed class PreludeTests
{
[Test]
public async Task I_can_try_with_success_value_and_get_a_success_result()
{
var result = Prelude.Try(() => 2);
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsTrue();
await Assert.That(result.Value).IsEqualTo(2);
}
[Test]
public async Task I_can_try_with_throwing_exception_and_get_a_failure_result()
{
var result = Prelude.Try<int>(() => throw new CustomTestException());
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
var instance = await Assert.That(result.Error).IsTypeOf<ExceptionError>();
await Assert.That(instance?.Exception).IsTypeOf<CustomTestException>();
}
[Test]
public async Task I_can_try_with_async_success_value_and_get_a_success_result()
{
var result = await Prelude.TryAsync(() => Task.FromResult(2));
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsTrue();
await Assert.That(result.Value).IsEqualTo(2);
}
[Test]
public async Task I_can_try_with_async_throwing_exception_and_get_a_failure_result()
{
var result = await Prelude.TryAsync(Task<int> () => throw new CustomTestException());
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
var instance = await Assert.That(result.Error).IsTypeOf<ExceptionError>();
await Assert.That(instance?.Exception).IsTypeOf<CustomTestException>();
}
[Test]
public async Task I_can_try_with_async_await_throwing_exception_and_get_a_failure_result()
{
var result = await Prelude.TryAsync(async Task<int> () =>
{
await Task.CompletedTask;
throw new CustomTestException();
});
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
var instance = await Assert.That(result.Error).IsTypeOf<ExceptionError>();
await Assert.That(instance?.Exception).IsTypeOf<CustomTestException>();
}
[Test]
public async Task I_can_try_with_async_success_value_and_get_a_success_result_of_type_ValueTask()
{
var result = await Prelude.TryAsync(() => ValueTask.FromResult(2));
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsTrue();
await Assert.That(result.Value).IsEqualTo(2);
}
[Test]
public async Task I_can_try_with_async_throwing_exception_and_get_a_failure_result_of_type_ValueTask()
{
var result = await Prelude.TryAsync(ValueTask<int> () => throw new CustomTestException());
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
var instance = await Assert.That(result.Error).IsTypeOf<ExceptionError>();
await Assert.That(instance?.Exception).IsTypeOf<CustomTestException>();
}
[Test]
public async Task I_can_try_with_async_await_throwing_exception_and_get_a_failure_result_of_type_ValueTask()
{
var result = await Prelude.TryAsync(async ValueTask<int> () =>
{
await Task.CompletedTask;
throw new CustomTestException();
});
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
var instance = await Assert.That(result.Error).IsTypeOf<ExceptionError>();
await Assert.That(instance?.Exception).IsTypeOf<CustomTestException>();
}
}

View file

@ -0,0 +1,64 @@
// Copyright (c) The Geekeey Authors
// SPDX-License-Identifier: EUPL-1.2
namespace Geekeey.Request.Result.Tests;
internal sealed class ResultConversionTests
{
[Test]
public async Task I_can_implicitly_convert_from_value_and_get_success()
{
var result = Prelude.Success(2);
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsTrue();
await Assert.That(result.IsFailure).IsFalse();
await Assert.That(result.Value).IsEqualTo(2);
}
[Test]
public async Task I_can_implicitly_convert_from_error_and_get_failure()
{
var error = new CustomTestError();
var result = Prelude.Failure<int>(error);
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
await Assert.That(result.IsFailure).IsTrue();
await Assert.That(result.Error).IsTypeOf<CustomTestError>();
}
[Test]
public async Task I_can_unwrap_and_get_value_for_success()
{
var result = Prelude.Success(2);
var value = result.Unwrap();
await Assert.That(value).IsEqualTo(2);
}
[Test]
public async Task I_can_unwrap_and_get_exception_for_failure()
{
var result = Prelude.Failure<int>("error");
await Assert.That(result.Unwrap).Throws<UnwrapException>();
}
[Test]
public async Task I_can_explicitly_convert_and_get_value_for_success()
{
var result = Prelude.Success(2);
var value = (int)result;
await Assert.That(value).IsEqualTo(2);
}
[Test]
public async Task I_can_explicitly_convert_and_get_exception_for_failure()
{
var result = Prelude.Failure<int>("error");
await Assert.That(() => (int)result).Throws<UnwrapException>();
}
}

View file

@ -0,0 +1,175 @@
// Copyright (c) The Geekeey Authors
// SPDX-License-Identifier: EUPL-1.2
namespace Geekeey.Request.Result.Tests;
internal sealed class ResultEqualityTests
{
[Test]
public async Task I_can_equal_t_and_get_true_for_success_with_equal_value()
{
var a = Prelude.Success(2);
var b = 2;
await Assert.That(a.Equals(b)).IsTrue();
}
[Test]
public async Task I_can_equal_t_and_get_false_for_success_with_unequal_value()
{
var a = Prelude.Success(2);
var b = 3;
await Assert.That(a.Equals(b)).IsFalse();
}
[Test]
public async Task I_can_equal_t_and_get_false_for_failure()
{
var a = Prelude.Failure<int>("error");
var b = 2;
await Assert.That(a.Equals(b)).IsFalse();
}
[Test]
public async Task I_can_equal_result_and_get_true_for_success_and_success_with_equal_value()
{
var a = Prelude.Success(2);
var b = Prelude.Success(2);
await Assert.That(a.Equals(b)).IsTrue();
}
[Test]
public async Task I_can_equal_result_and_get_false_for_success_and_success_with_unequal_value()
{
var a = Prelude.Success(2);
var b = Prelude.Success(3);
await Assert.That(a.Equals(b)).IsFalse();
}
[Test]
public async Task I_can_equals_result_and_get_false_for_success_and_failure()
{
var a = Prelude.Success(2);
var b = Prelude.Failure<int>("error 1");
await Assert.That(a.Equals(b)).IsFalse();
}
[Test]
public async Task I_can_equals_result_and_get_false_for_failure_and_success()
{
var a = Prelude.Failure<int>("error");
var b = Prelude.Success(2);
await Assert.That(a.Equals(b)).IsFalse();
}
[Test]
public async Task I_can_equals_result_and_get_true_for_failure_and_failure()
{
var a = Prelude.Failure<int>("error 1");
var b = Prelude.Failure<int>("error 2");
await Assert.That(a.Equals(b)).IsTrue();
}
[Test]
public async Task I_can_equal_t_and_get_true_for_success_with_equal_value_using_comparer()
{
var a = Prelude.Success(2);
var b = 2;
await Assert.That(a.Equals(b, EqualityComparer<int>.Default)).IsTrue();
}
[Test]
public async Task I_can_equal_t_and_get_false_for_success_with_unequal_value_using_comparer()
{
var a = Prelude.Success(2);
var b = 3;
await Assert.That(a.Equals(b, EqualityComparer<int>.Default)).IsFalse();
}
[Test]
public async Task I_can_equal_t_and_get_false_for_failure_using_comparer()
{
var a = Prelude.Failure<int>("error");
var b = 2;
await Assert.That(a.Equals(b, EqualityComparer<int>.Default)).IsFalse();
}
[Test]
public async Task I_can_equal_result_and_get_true_for_success_and_success_with_equal_value_using_comparer()
{
var a = Prelude.Success(2);
var b = Prelude.Success(2);
await Assert.That(a.Equals(b, EqualityComparer<int>.Default)).IsTrue();
}
[Test]
public async Task I_can_equal_result_and_get_false_for_success_and_success_with_unequal_value_using_comparer()
{
var a = Prelude.Success(2);
var b = Prelude.Success(3);
await Assert.That(a.Equals(b, EqualityComparer<int>.Default)).IsFalse();
}
[Test]
public async Task I_can_equals_result_and_get_false_for_success_and_failure_using_comparer()
{
var a = Prelude.Success(2);
var b = Prelude.Failure<int>("error 1");
await Assert.That(a.Equals(b, EqualityComparer<int>.Default)).IsFalse();
}
[Test]
public async Task I_can_equals_result_and_get_false_for_failure_and_success_using_comparer()
{
var a = Prelude.Failure<int>("error");
var b = Prelude.Success(2);
await Assert.That(a.Equals(b, EqualityComparer<int>.Default)).IsFalse();
}
[Test]
public async Task I_can_equals_result_and_get_true_for_failure_and_failure_using_comparer()
{
var a = Prelude.Failure<int>("error 1");
var b = Prelude.Failure<int>("error 2");
await Assert.That(a.Equals(b, EqualityComparer<int>.Default)).IsTrue();
}
[Test]
public async Task I_can_get_hashcode_and_get_hashcode_for_success()
{
var result = Prelude.Success(2);
await Assert.That(result.GetHashCode()).IsEqualTo(2.GetHashCode());
}
[Test]
public async Task I_can_get_hashcode_and_get_zero_for_null()
{
var result = Prelude.Success<string?>(null);
await Assert.That(result.GetHashCode()).IsZero();
}
[Test]
public async Task I_can_get_hashcode_and_get_zero_for_failure()
{
var result = Prelude.Failure<int>("error");
await Assert.That(result.GetHashCode()).IsZero();
}
}

View file

@ -0,0 +1,232 @@
// Copyright (c) The Geekeey Authors
// SPDX-License-Identifier: EUPL-1.2
namespace Geekeey.Request.Result.Tests;
internal sealed class ResultMatchingTests
{
[Test]
public async Task I_can_match_and_it_calls_success_func_for_success()
{
var result = Prelude.Success(2);
var match = result.Match(
v => v,
_ => throw new InvalidOperationException());
await Assert.That(match).IsEqualTo(2);
}
[Test]
public async Task I_can_match_and_it_calls_failure_func_for_failure()
{
var result = Prelude.Failure<int>("error");
var match = result.Match(
_ => throw new InvalidOperationException(),
e => e);
await Assert.That(match.Message).IsEqualTo("error");
}
[Test]
public async Task I_can_switch_and_it_calls_success_action_for_success()
{
var called = false;
var value = default(int);
var result = Prelude.Success(2);
result.Switch(OnSuccess, OnFailure);
await Assert.That(called).IsTrue();
await Assert.That(value).IsEqualTo(2);
return;
void OnSuccess(int i)
{
value = i;
called = true;
}
void OnFailure(Error e)
{
throw new InvalidOperationException();
}
}
[Test]
public async Task I_can_switch_and_it_calls_failure_action_for_failure()
{
var called = false;
var value = default(Error);
var result = Prelude.Failure<int>("error");
result.Switch(OnSuccess, OnFailure);
await Assert.That(called).IsTrue();
await Assert.That(value?.Message).IsEqualTo("error");
return;
void OnSuccess(int i)
{
throw new InvalidOperationException();
}
void OnFailure(Error e)
{
value = e;
called = true;
}
}
[Test]
public async Task I_can_match_async_and_it_calls_success_func_for_success()
{
var result = Prelude.Success(2);
var match = await result.MatchAsync(
Task.FromResult,
_ => throw new InvalidOperationException());
await Assert.That(match).IsEqualTo(2);
}
[Test]
public async Task I_can_match_async_and_it_calls_failure_func_for_failure()
{
var result = Prelude.Failure<int>("error");
var match = await result.MatchAsync(
_ => throw new InvalidOperationException(),
Task.FromResult);
await Assert.That(match.Message).IsEqualTo("error");
}
[Test]
public async Task I_can_switch_async_and_it_calls_success_action_for_success()
{
var called = false;
var value = default(int);
var result = Prelude.Success(2);
await result.SwitchAsync(OnSuccess, OnFailure);
await Assert.That(called).IsTrue();
await Assert.That(value).IsEqualTo(2);
return;
Task OnSuccess(int i)
{
value = i;
called = true;
return Task.CompletedTask;
}
Task OnFailure(Error e)
{
throw new InvalidOperationException();
}
}
[Test]
public async Task I_can_switch_async_and_it_calls_failure_action_for_failure()
{
var called = false;
var value = default(Error);
var result = Prelude.Failure<int>("error");
await result.SwitchAsync(OnSuccess, OnFailure);
await Assert.That(called).IsTrue();
await Assert.That(value?.Message).IsEqualTo("error");
return;
Task OnSuccess(int i)
{
throw new InvalidOperationException();
}
Task OnFailure(Error e)
{
value = e;
called = true;
return Task.CompletedTask;
}
}
[Test]
public async Task I_can_match_and_it_calls_success_func_for_success_ValueTask()
{
var result = Prelude.Success(2);
var match = await result.MatchAsync(
ValueTask.FromResult,
_ => throw new InvalidOperationException());
await Assert.That(match).IsEqualTo(2);
}
[Test]
public async Task I_can_match_async_and_it_calls_failure_func_for_failure_ValueTask()
{
var result = Prelude.Failure<int>("error");
var match = await result.MatchAsync(
_ => throw new InvalidOperationException(),
ValueTask.FromResult);
await Assert.That(match.Message).IsEqualTo("error");
}
[Test]
public async Task I_can_switch_async_and_it_calls_success_action_for_success_ValueTask()
{
var called = false;
var value = default(int);
var result = Prelude.Success(2);
await result.SwitchAsync(OnSuccess, OnFailure);
await Assert.That(called).IsTrue();
await Assert.That(value).IsEqualTo(2);
return;
ValueTask OnSuccess(int i)
{
value = i;
called = true;
return ValueTask.CompletedTask;
}
ValueTask OnFailure(Error e)
{
throw new InvalidOperationException();
}
}
[Test]
public async Task I_can_switch_async_and_it_calls_failure_action_for_failure_ValueTask()
{
var called = false;
var value = default(Error);
var result = Prelude.Failure<int>("error");
await result.SwitchAsync(OnSuccess, OnFailure);
await Assert.That(called).IsTrue();
await Assert.That(value?.Message).IsEqualTo("error");
return;
ValueTask OnSuccess(int i)
{
throw new InvalidOperationException();
}
ValueTask OnFailure(Error e)
{
value = e;
called = true;
return ValueTask.CompletedTask;
}
}
}

View file

@ -0,0 +1,59 @@
// Copyright (c) The Geekeey Authors
// SPDX-License-Identifier: EUPL-1.2
namespace Geekeey.Request.Result.Tests;
internal sealed class ResultTests
{
[Test]
public async Task I_can_create_new_success_result_from_t()
{
var result = new Result<int>(1);
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsTrue();
await Assert.That(result.IsFailure).IsFalse();
await Assert.That(result.Value).IsNotEqualTo(default);
await Assert.That(result.Error).IsNull();
}
[Test]
public async Task I_can_create_new_failure_result_from_error()
{
var result = new Result<int>(new CustomTestError());
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
await Assert.That(result.IsFailure).IsTrue();
await Assert.That(result.Value).IsEqualTo(default(int));
await Assert.That(result.Error).IsTypeOf<CustomTestError>();
}
[Test]
public async Task I_can_distinguish_default_result_from_created()
{
var result = default(Result<int>);
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
await Assert.That(result.IsFailure).IsTrue();
await Assert.That(result.Value).IsEqualTo(default(int));
await Assert.That(result.Error).IsEqualTo(Error.DefaultValueError);
}
[Test]
public async Task I_can_to_string_success_result_value()
{
Result<int> result = 2;
await Assert.That(result.ToString()).IsEqualTo("Success { 2 }");
}
[Test]
public async Task I_can_to_string_failure_result_value()
{
Result<int> result = new StringError("error");
await Assert.That(result.ToString()).IsEqualTo("Failure { error }");
}
}

View file

@ -0,0 +1,644 @@
// Copyright (c) The Geekeey Authors
// SPDX-License-Identifier: EUPL-1.2
using System.Globalization;
namespace Geekeey.Request.Result.Tests;
internal sealed class ResultTransformTests
{
[Test]
public async Task I_can_map_and_it_returns_success_for_success()
{
var start = Prelude.Success(2);
var result = start.Map(value => value.ToString(CultureInfo.InvariantCulture));
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsTrue();
await Assert.That(result.Value).IsEqualTo("2");
}
[Test]
public async Task I_can_map_and_it_returns_failure_for_failure()
{
var start = Prelude.Failure<int>("error");
var result = start.Map(value => value.ToString(CultureInfo.InvariantCulture));
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
await Assert.That(result.Error?.Message).IsEqualTo("error");
}
[Test]
public async Task I_can_transform_result_with_then_and_it_returns_success_for_success_and_mapping_returning_success()
{
var start = Prelude.Success(2);
var result = start.Then(value => Prelude.Success(value.ToString(CultureInfo.InvariantCulture)));
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsTrue();
await Assert.That(result.Value).IsEqualTo("2");
}
[Test]
public async Task I_can_transform_result_with_then_and_it_returns_failure_for_success_and_mapping_returning_failure()
{
var start = Prelude.Success(2);
var result = start.Then(_ => Prelude.Failure<string>("error"));
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
await Assert.That(result.Error?.Message).IsEqualTo("error");
}
[Test]
public async Task I_can_transform_result_with_then_and_it_returns_failure_for_failure_and_mapping_returning_success()
{
var start = Prelude.Failure<int>("error");
var result = start.Then(value => Prelude.Success(value.ToString(CultureInfo.InvariantCulture)));
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
await Assert.That(result.Error?.Message).IsEqualTo("error");
}
[Test]
public async Task I_can_transform_result_with_then_and_it_returns_failure_for_failure_and_mapping_returning_failure()
{
var start = Prelude.Failure<int>("error");
var result = start.Then(_ => Prelude.Failure<int>("error 2"));
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
await Assert.That(result.Error?.Message).IsEqualTo("error");
}
[Test]
public async Task I_can_try_map_and_it_returns_success_for_success_without_throwing()
{
var start = Prelude.Success(2);
var result = start.TryMap(value => value.ToString(CultureInfo.InvariantCulture));
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsTrue();
await Assert.That(result.Value).IsEqualTo("2");
}
[Test]
public async Task I_can_try_map_and_it_returns_failure_for_failure_without_throwing()
{
var start = Prelude.Failure<int>("error");
var result = start.TryMap(value => value.ToString(CultureInfo.InvariantCulture));
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
await Assert.That(result.Error?.Message).IsEqualTo("error");
}
[Test]
public async Task I_can_try_map_and_it_returns_failure_for_success_with_throwing()
{
var start = Prelude.Success(2);
var result = start.TryMap<string>(_ => throw new CustomTestException());
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
var instance = await Assert.That(result.Error).IsTypeOf<ExceptionError>();
await Assert.That(instance?.Exception).IsTypeOf<CustomTestException>();
}
[Test]
public async Task I_can_try_map_and_it_returns_failure_for_failure_with_throwing()
{
var start = Prelude.Failure<int>("error");
var result = start.TryMap<string>(_ => throw new CustomTestException());
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
await Assert.That(result.Error).IsTypeOf<StringError>();
await Assert.That(result.Error?.Message).IsEqualTo("error");
}
[Test]
public async Task I_can_try_transform_result_with_then_and_it_returns_success_for_success_and_mapping_returning_success()
{
var start = Prelude.Success(2);
var result = start.ThenTry(value => Prelude.Success(value.ToString(CultureInfo.InvariantCulture)));
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsTrue();
await Assert.That(result.Value).IsEqualTo("2");
}
[Test]
public async Task I_can_try_transform_result_with_then_and_it_returns_failure_for_success_and_mapping_returning_failure()
{
var start = Prelude.Success(2);
var result = start.ThenTry(_ => Prelude.Failure<string>("error"));
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
await Assert.That(result.Error?.Message).IsEqualTo("error");
}
[Test]
public async Task I_can_try_transform_result_with_then_and_it_returns_failure_for_failure_and_mapping_returning_failure()
{
var start = Prelude.Failure<int>("error");
var result = start.ThenTry(x => Prelude.Success(x.ToString(CultureInfo.InvariantCulture)));
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
await Assert.That(result.Error?.Message).IsEqualTo("error");
}
[Test]
public async Task I_can_try_transform_result_with_then_and_it_returns_failure_for_success_and_mapping_throwing()
{
var start = Prelude.Success(2);
var result = start.ThenTry<string>(_ => throw new CustomTestException());
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
var instance = await Assert.That(result.Error).IsTypeOf<ExceptionError>();
await Assert.That(instance?.Exception).IsTypeOf<CustomTestException>();
}
[Test]
public async Task I_can_try_transform_result_with_then_and_it_returns_failure_for_failure_and_mapping_throwing()
{
var start = Prelude.Failure<int>("error");
var result = start.ThenTry<string>(_ => throw new CustomTestException());
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
await Assert.That(result.Error).IsTypeOf<StringError>();
await Assert.That(result.Error?.Message).IsEqualTo("error");
}
[Test]
public async Task I_can_map_async_and_it_returns_success_for_success()
{
var start = Prelude.Success(2);
var result = await start.MapAsync(value => Task.FromResult(value.ToString(CultureInfo.InvariantCulture)));
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsTrue();
await Assert.That(result.Value).IsEqualTo("2");
}
[Test]
public async Task I_can_map_async_and_it_returns_failure_for_failure()
{
var start = Prelude.Failure<int>("error");
var result = await start.MapAsync(value => Task.FromResult(value.ToString(CultureInfo.InvariantCulture)));
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
await Assert.That(result.Error?.Message).IsEqualTo("error");
}
[Test]
public async Task I_can_transform_result_async_with_then_and_it_returns_success_for_success_and_mapping_returning_success()
{
var start = Prelude.Success(2);
var result = await start.ThenAsync(value => Task.FromResult(Prelude.Success(value.ToString(CultureInfo.InvariantCulture))));
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsTrue();
await Assert.That(result.Value).IsEqualTo("2");
}
[Test]
public async Task I_can_transform_result_async_with_then_and_it_returns_failure_for_success_and_mapping_returning_failure()
{
var start = Prelude.Success(2);
var result = await start.ThenAsync(_ => Task.FromResult(Prelude.Failure<string>("error")));
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
await Assert.That(result.Error?.Message).IsEqualTo("error");
}
[Test]
public async Task I_can_transform_result_async_with_then_and_it_returns_failure_for_failure_and_mapping_returning_success()
{
var start = Prelude.Failure<int>("error");
var result = await start.ThenAsync(value => Task.FromResult(Prelude.Success(value.ToString(CultureInfo.InvariantCulture))));
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
await Assert.That(result.Error?.Message).IsEqualTo("error");
}
[Test]
public async Task I_can_transform_result_async_with_then_and_it_returns_failure_for_failure_and_mapping_returning_failure()
{
var start = Prelude.Failure<int>("error");
var result = await start.ThenAsync(_ => Task.FromResult(Prelude.Failure<int>("error 2")));
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
await Assert.That(result.Error?.Message).IsEqualTo("error");
}
[Test]
public async Task I_can_try_map_async_and_it_returns_success_for_success_without_throwing()
{
var start = Prelude.Success(2);
var result = await start.TryMapAsync(value => Task.FromResult(value.ToString(CultureInfo.InvariantCulture)));
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsTrue();
await Assert.That(result.Value).IsEqualTo("2");
}
[Test]
public async Task I_can_try_map_async_and_it_returns_failure_for_failure_without_throwing()
{
var start = Prelude.Failure<int>("error");
var result = await start.TryMapAsync(value => Task.FromResult(value.ToString(CultureInfo.InvariantCulture)));
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
await Assert.That(result.Error?.Message).IsEqualTo("error");
}
[Test]
public async Task I_can_try_map_async_and_it_returns_failure_for_success_with_throwing()
{
var start = Prelude.Success(2);
var result = await start.TryMapAsync(Task<string> (_) => throw new CustomTestException());
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
var instance = await Assert.That(result.Error).IsTypeOf<ExceptionError>();
await Assert.That(instance?.Exception).IsTypeOf<CustomTestException>();
}
[Test]
public async Task I_can_try_map_async_and_it_returns_failure_for_success_with_await_throwing()
{
var start = Prelude.Success(2);
var result = await start.TryMapAsync(async Task<string> (_) =>
{
await Task.CompletedTask;
throw new CustomTestException();
});
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
var instance = await Assert.That(result.Error).IsTypeOf<ExceptionError>();
await Assert.That(instance?.Exception).IsTypeOf<CustomTestException>();
}
[Test]
public async Task I_can_try_map_async_and_it_returns_failure_for_failure_with_throwing()
{
var start = Prelude.Failure<int>("error");
var result = await start.TryMapAsync(Task<string> (_) => throw new CustomTestException());
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
await Assert.That(result.Error).IsTypeOf<StringError>();
await Assert.That(result.Error?.Message).IsEqualTo("error");
}
[Test]
public async Task I_can_try_map_async_and_it_returns_failure_for_failure_with_await_throwing()
{
var start = Prelude.Failure<int>("error");
var result = await start.TryMapAsync(async Task<string> (_) =>
{
await Task.CompletedTask;
throw new CustomTestException();
});
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
await Assert.That(result.Error).IsTypeOf<StringError>();
await Assert.That(result.Error?.Message).IsEqualTo("error");
}
[Test]
public async Task I_can_try_transform_result_async_with_then_and_it_returns_success_for_success_and_mapping_returning_success()
{
var start = Prelude.Success(2);
var result = await start.ThenTryAsync(value => Task.FromResult(Prelude.Success(value.ToString(CultureInfo.InvariantCulture))));
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsTrue();
await Assert.That(result.Value).IsEqualTo("2");
}
[Test]
public async Task I_can_try_transform_result_async_with_then_and_it_returns_failure_for_success_and_mapping_returning_failure()
{
var start = Prelude.Success(2);
var result = await start.ThenTryAsync(_ => Task.FromResult(Prelude.Failure<string>("error")));
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
await Assert.That(result.Error?.Message).IsEqualTo("error");
}
[Test]
public async Task I_can_try_transform_result_async_with_then_and_it_returns_failure_for_failure_and_mapping_returning_failure()
{
var start = Prelude.Failure<int>("error");
var result = await start.ThenTryAsync(x => Task.FromResult(Prelude.Success(x.ToString(CultureInfo.InvariantCulture))));
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
await Assert.That(result.Error?.Message).IsEqualTo("error");
}
[Test]
public async Task I_can_try_transform_result_async_with_then_and_it_returns_failure_for_success_and_mapping_throwing()
{
var start = Prelude.Success(2);
var result = await start.ThenTryAsync(Task<Result<string>> (_) => throw new CustomTestException());
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
var instance = await Assert.That(result.Error).IsTypeOf<ExceptionError>();
await Assert.That(instance?.Exception).IsTypeOf<CustomTestException>();
}
[Test]
public async Task I_can_try_transform_result_async_with_then_and_it_returns_failure_for_success_and_mapping_await_throwing()
{
var start = Prelude.Success(2);
var result = await start.ThenTryAsync(async Task<Result<string>> (_) =>
{
await Task.CompletedTask;
throw new CustomTestException();
});
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
var instance = await Assert.That(result.Error).IsTypeOf<ExceptionError>();
await Assert.That(instance?.Exception).IsTypeOf<CustomTestException>();
}
[Test]
public async Task I_can_try_transform_result_async_with_then_and_it_returns_failure_for_failure_and_mapping_throwing()
{
var start = Prelude.Failure<int>("error");
var result = await start.ThenTryAsync(Task<Result<string>> (_) => throw new CustomTestException());
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
await Assert.That(result.Error).IsTypeOf<StringError>();
await Assert.That(result.Error?.Message).IsEqualTo("error");
}
[Test]
public async Task I_can_try_transform_result_async_with_then_and_it_returns_failure_for_failure_and_mapping_await_throwing()
{
var start = Prelude.Failure<int>("error");
var result = await start.ThenTryAsync(async Task<Result<string>> (_) =>
{
await Task.CompletedTask;
throw new CustomTestException();
});
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
await Assert.That(result.Error).IsTypeOf<StringError>();
await Assert.That(result.Error?.Message).IsEqualTo("error");
}
[Test]
public async Task I_can_map_async_and_it_returns_success_for_success_ValueTask()
{
var start = Prelude.Success(2);
var result = await start.MapAsync(value => ValueTask.FromResult(value.ToString(CultureInfo.InvariantCulture)));
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsTrue();
await Assert.That(result.Value).IsEqualTo("2");
}
[Test]
public async Task I_can_map_async_and_it_returns_failure_for_failure_ValueTask()
{
var start = Prelude.Failure<int>("error");
var result = await start.MapAsync(value => ValueTask.FromResult(value.ToString(CultureInfo.InvariantCulture)));
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
await Assert.That(result.Error?.Message).IsEqualTo("error");
}
[Test]
public async Task I_can_transform_result_async_with_then_and_it_returns_success_for_success_and_mapping_returning_success_ValueTask()
{
var start = Prelude.Success(2);
var result = await start.ThenAsync(value => ValueTask.FromResult(Prelude.Success(value.ToString(CultureInfo.InvariantCulture))));
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsTrue();
await Assert.That(result.Value).IsEqualTo("2");
}
[Test]
public async Task I_can_transform_result_async_with_then_and_it_returns_failure_for_success_and_mapping_returning_failure_ValueTask()
{
var start = Prelude.Success(2);
var result = await start.ThenAsync(_ => ValueTask.FromResult(Prelude.Failure<string>("error")));
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
await Assert.That(result.Error?.Message).IsEqualTo("error");
}
[Test]
public async Task I_can_transform_result_async_with_then_and_it_returns_failure_for_failure_and_mapping_returning_success_ValueTask()
{
var start = Prelude.Failure<int>("error");
var result = await start.ThenAsync(value => ValueTask.FromResult(Prelude.Success(value.ToString(CultureInfo.InvariantCulture))));
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
await Assert.That(result.Error?.Message).IsEqualTo("error");
}
[Test]
public async Task I_can_transform_result_async_with_then_and_it_returns_failure_for_failure_and_mapping_returning_failure_ValueTask()
{
var start = Prelude.Failure<int>("error");
var result = await start.ThenAsync(_ => ValueTask.FromResult(Prelude.Failure<int>("error 2")));
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
await Assert.That(result.Error?.Message).IsEqualTo("error");
}
[Test]
public async Task I_can_try_map_async_and_it_returns_success_for_success_without_throwing_ValueTask()
{
var start = Prelude.Success(2);
var result = await start.TryMapAsync(value => ValueTask.FromResult(value.ToString(CultureInfo.InvariantCulture)));
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsTrue();
await Assert.That(result.Value).IsEqualTo("2");
}
[Test]
public async Task I_can_try_map_async_and_it_returns_failure_for_failure_without_throwing_ValueTask()
{
var start = Prelude.Failure<int>("error");
var result = await start.TryMapAsync(value => ValueTask.FromResult(value.ToString(CultureInfo.InvariantCulture)));
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
await Assert.That(result.Error?.Message).IsEqualTo("error");
}
[Test]
public async Task I_can_try_map_async_and_it_returns_failure_for_success_with_throwing_ValueTask()
{
var start = Prelude.Success(2);
var result = await start.TryMapAsync(ValueTask<string> (_) => throw new CustomTestException());
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
var instance = await Assert.That(result.Error).IsTypeOf<ExceptionError>();
await Assert.That(instance?.Exception).IsTypeOf<CustomTestException>();
}
[Test]
public async Task I_can_try_map_async_and_it_returns_failure_for_success_with_await_throwing_ValueTask()
{
var start = Prelude.Success(2);
var result = await start.TryMapAsync(async ValueTask<string> (_) =>
{
await ValueTask.CompletedTask;
throw new CustomTestException();
});
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
var instance = await Assert.That(result.Error).IsTypeOf<ExceptionError>();
await Assert.That(instance?.Exception).IsTypeOf<CustomTestException>();
}
[Test]
public async Task I_can_try_map_async_and_it_returns_failure_for_failure_with_throwing_ValueTask()
{
var start = Prelude.Failure<int>("error");
var result = await start.TryMapAsync(ValueTask<string> (_) => throw new CustomTestException());
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
await Assert.That(result.Error).IsTypeOf<StringError>();
await Assert.That(result.Error?.Message).IsEqualTo("error");
}
[Test]
public async Task I_can_try_map_async_and_it_returns_failure_for_failure_with_await_throwing_ValueTask()
{
var start = Prelude.Failure<int>("error");
var result = await start.TryMapAsync(async ValueTask<string> (_) =>
{
await ValueTask.CompletedTask;
throw new CustomTestException();
});
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
await Assert.That(result.Error).IsTypeOf<StringError>();
await Assert.That(result.Error?.Message).IsEqualTo("error");
}
[Test]
public async Task I_can_try_transform_result_async_with_then_and_it_returns_success_for_success_and_mapping_returning_success_ValueTask()
{
var start = Prelude.Success(2);
var result = await start.ThenTryAsync(value => ValueTask.FromResult(Prelude.Success(value.ToString(CultureInfo.InvariantCulture))));
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsTrue();
await Assert.That(result.Value).IsEqualTo("2");
}
[Test]
public async Task I_can_try_transform_result_async_with_then_and_it_returns_failure_for_success_and_mapping_returning_failure_ValueTask()
{
var start = Prelude.Success(2);
var result = await start.ThenTryAsync(_ => ValueTask.FromResult(Prelude.Failure<string>("error")));
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
await Assert.That(result.Error?.Message).IsEqualTo("error");
}
[Test]
public async Task I_can_try_transform_result_async_with_then_and_it_returns_failure_for_failure_and_mapping_returning_failure_ValueTask()
{
var start = Prelude.Failure<int>("error");
var result = await start.ThenTryAsync(x => ValueTask.FromResult(Prelude.Success(x.ToString(CultureInfo.InvariantCulture))));
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
await Assert.That(result.Error?.Message).IsEqualTo("error");
}
[Test]
public async Task I_can_try_transform_result_async_with_then_and_it_returns_failure_for_success_and_mapping_throwing_ValueTask()
{
var start = Prelude.Success(2);
var result = await start.ThenTryAsync(ValueTask<Result<string>> (_) => throw new CustomTestException());
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
var instance = await Assert.That(result.Error).IsTypeOf<ExceptionError>();
await Assert.That(instance?.Exception).IsTypeOf<CustomTestException>();
}
[Test]
public async Task I_can_try_transform_result_async_with_then_and_it_returns_failure_for_success_and_mapping_await_throwing_ValueTask()
{
var start = Prelude.Success(2);
var result = await start.ThenTryAsync(async ValueTask<Result<string>> (_) =>
{
await ValueTask.CompletedTask;
throw new CustomTestException();
});
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
var instance = await Assert.That(result.Error).IsTypeOf<ExceptionError>();
await Assert.That(instance?.Exception).IsTypeOf<CustomTestException>();
}
[Test]
public async Task I_can_try_transform_result_async_with_then_and_it_returns_failure_for_failure_and_mapping_throwing_ValueTask()
{
var start = Prelude.Failure<int>("error");
var result = await start.ThenTryAsync(ValueTask<Result<string>> (_) => throw new CustomTestException());
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
await Assert.That(result.Error).IsTypeOf<StringError>();
await Assert.That(result.Error?.Message).IsEqualTo("error");
}
[Test]
public async Task I_can_try_transform_result_async_with_then_and_it_returns_failure_for_failure_and_mapping_await_throwing_ValueTask()
{
var start = Prelude.Failure<int>("error");
var result = await start.ThenTryAsync(async ValueTask<Result<string>> (_) =>
{
await ValueTask.CompletedTask;
throw new CustomTestException();
});
using var scope = Assert.Multiple();
await Assert.That(result.IsSuccess).IsFalse();
await Assert.That(result.Error).IsTypeOf<StringError>();
await Assert.That(result.Error?.Message).IsEqualTo("error");
}
}

View file

@ -0,0 +1,99 @@
// Copyright (c) The Geekeey Authors
// SPDX-License-Identifier: EUPL-1.2
namespace Geekeey.Request.Result.Tests;
internal sealed class ResultUnboxTests
{
[Test]
public async Task I_can_try_get_value_and_it_returns_true_and_sets_value_for_success_with_1_param()
{
var result = Prelude.Success(2);
var ok = result.TryGetValue(out int value);
using var scope = Assert.Multiple();
await Assert.That(ok).IsTrue();
await Assert.That(value).IsEqualTo(2);
}
[Test]
public async Task I_can_try_get_value_and_it_returns_false_for_failure_with_1_param()
{
var result = Prelude.Failure<int>("error");
var ok = result.TryGetValue(out int value);
using var scope = Assert.Multiple();
await Assert.That(ok).IsFalse();
await Assert.That(value).IsEqualTo(default(int));
}
[Test]
public async Task I_can_try_get_value_and_it_returns_true_and_sets_value_for_success_with_2_param()
{
var result = Prelude.Success(2);
var ok = result.TryGetValue(out int value, out var error);
using var scope = Assert.Multiple();
await Assert.That(ok).IsTrue();
await Assert.That(value).IsEqualTo(2);
await Assert.That(error).IsEqualTo(default(Error));
}
[Test]
public async Task I_can_try_get_value_and_it_returns_false_and_sets_error_for_failure_with_2_param()
{
var result = Prelude.Failure<int>("error");
var ok = result.TryGetValue(out int value, out var error);
using var scope = Assert.Multiple();
await Assert.That(ok).IsFalse();
await Assert.That(value).IsEqualTo(default(int));
await Assert.That(error?.Message).IsEqualTo("error");
}
[Test]
public async Task I_can_try_get_error_and_it_returns_true_and_sets_error_for_failure_with_1_param()
{
var result = Prelude.Failure<int>("error");
var ok = result.TryGetValue(out Error? error);
using var scope = Assert.Multiple();
await Assert.That(ok).IsTrue();
await Assert.That(error?.Message).IsEqualTo("error");
}
[Test]
public async Task I_can_try_get_error_and_it_returns_false_for_success_with_1_param()
{
var result = Prelude.Success(2);
var ok = result.TryGetValue(out Error? error);
using var scope = Assert.Multiple();
await Assert.That(ok).IsFalse();
await Assert.That(error).IsEqualTo(default(Error));
}
[Test]
public async Task I_can_try_get_error_and_it_returns_true_and_sets_error_for_failure_with_2_param()
{
var result = Prelude.Failure<int>("error");
var ok = result.TryGetValue(out Error? error, out var value);
using var scope = Assert.Multiple();
await Assert.That(ok).IsTrue();
await Assert.That(error?.Message).IsEqualTo("error");
await Assert.That(value).IsEqualTo(default(int));
}
[Test]
public async Task I_can_try_get_error_and_it_returns_false_and_sets_value_for_success_with_2_param()
{
var result = Prelude.Success(2);
var ok = result.TryGetValue(out Error? error, out var value);
using var scope = Assert.Multiple();
await Assert.That(ok).IsFalse();
await Assert.That(error).IsEqualTo(default(Error));
await Assert.That(value).IsEqualTo(2);
}
}

View file

@ -0,0 +1,11 @@
// Copyright (c) The Geekeey Authors
// SPDX-License-Identifier: EUPL-1.2
namespace Geekeey.Request.Result.Tests;
internal sealed class CustomTestError : Error
{
internal const string DefaultMessage = "This is a custom error for test";
public override string Message => DefaultMessage;
}

View file

@ -0,0 +1,8 @@
// Copyright (c) The Geekeey Authors
// SPDX-License-Identifier: EUPL-1.2
namespace Geekeey.Request.Result.Tests;
internal sealed class CustomTestException : Exception
{
}