diff --git a/.idea/.idea.Futurum.Core/.idea/indexLayout.xml b/.idea/.idea.Futurum.Core/.idea/indexLayout.xml index 7b08163..86d5170 100644 --- a/.idea/.idea.Futurum.Core/.idea/indexLayout.xml +++ b/.idea/.idea.Futurum.Core/.idea/indexLayout.xml @@ -1,7 +1,9 @@ - + + StrykerOutput + diff --git a/README.md b/README.md index 734bb52..9a3282b 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,9 @@ A dotnet library providing Option and Result data types, based on the concepts b - [x] Option data type that represents a value that is either present or not present - [x] Based on the concepts behind [Railway Oriented Programming](https://fsharpforfunandprofit.com/rop/) - [x] Extension methods that allows interacting with and going into and out of the Result and Option data types -- [x] [Tested solution](https://coveralls.io/github/futurum-dev/dotnet.futurum.core?branch=main) > 99% test coverage - [x] Fluent discoverable and commented API +- [x] [Tested solution](https://coveralls.io/github/futurum-dev/dotnet.futurum.core?branch=main) > 99% test coverage +- [x] [Tested](#stryker-mutation-testing) with [Stryker](https://stryker-mutator.io/docs/stryker-net/introduction/) mutation testing > 95% - [x] Integration with [Polly](https://github.com/App-vNext/Polly) via [Futurum.Core.Polly](https://github.com/futurum-dev/dotnet.futurum.core.polly) [Result](#result) @@ -213,8 +214,6 @@ Creates a *success* Result<T> with the payload provided var result = 2.ToResultOk(); ``` -#### FlatMap - #### IgnoreFailure Ignores the failure on Result and always returns Result.Ok(). @@ -356,6 +355,8 @@ var result = await Result.TryAsync(func, () => ERROR_MESSAGE); ``` A nice pattern to follow using local functions is as follows: + +##### With a return value ```csharp public Task> ExecuteAsync() { @@ -367,6 +368,8 @@ public Task> ExecuteAsync() } } ``` + +##### With a Result<T> return value ```csharp public Task> ExecuteAsync() { @@ -378,6 +381,8 @@ public Task> ExecuteAsync() } } ``` + +##### With no return value ```csharp public Task ExecuteAsync() { @@ -389,6 +394,8 @@ public Task ExecuteAsync() } } ``` + +##### With a Result return value ```csharp public Task ExecuteAsync() { @@ -424,18 +431,22 @@ Comes out of the *Result* monad. - If the *Result* is *Ok*, then return the value if there is one - If the *Result* is *Fail*, then throw an exception, passing through the ResultError data +##### Success - With no return value ```csharp Result.Ok().Unwrap(); ``` +##### Success - With a return value ```csharp -Result.Fail(ErrorMessage).Unwrap(); +var value = Result.Ok(1).Unwrap(); ``` +##### Failure - With no return value (Exception will be thrown) ```csharp -var value = Result.Ok(1).Unwrap(); +Result.Fail(ErrorMessage).Unwrap(); ``` +##### Failure - With a return value (Exception will be thrown) ```csharp var value = Result.Fail(ErrorMessage).Unwrap(); ``` @@ -447,9 +458,9 @@ Return only those elements of a sequence of Result<T> that are *success*. If none of the elements in the sequence are *success*, then a Result<T> *failure* is returned. ```csharp -var result1 = Result.Ok(value1); -var result2 = Result.Ok(value2); -var result3 = Result.Ok(value3); +var result1 = Result.Ok(1); +var result2 = Result.Ok(2); +var result3 = Result.Ok(3); IEnumerable values = new[] {result1, result2, result3}.Choose() ``` @@ -465,11 +476,130 @@ var resultInput = Result.Ok(values); Result> resultOutput = resultInput.Filter(x => x % 2 == 0); ``` +#### FlatMap +Transforms each element of a sequence to an IEnumerable<T> and flattens the resulting sequences into one sequence. + +```csharp +(IEnumerable, Func) -> Result +``` + +```csharp +var input = new[] {1, 2}; + +Result outputResult = input.FlatMap(x => Result.Ok()); +``` + +```csharp +(IEnumerable, Func>) -> Result> +``` + +```csharp +var input = new[] {1, 2}; + +Result outputResult = input.FlatMap(x => Result.Ok()); +``` + +```csharp +(IEnumerable, Func>) -> Result> +``` + +```csharp +var input = new[] {1, 2}; + +Result> outputResult = input.FlatMap(x => +{ + if (x == 1) return Result.Fail>(ErrorMessage1); + + return Result.Fail>(ErrorMessage2); +}); +``` + +```csharp +(Result>, Func>>) -> Result> +``` + +```csharp +var input = new[] {1, 2}.AsEnumerable().ToResultOk(); + +Result> outputResult = input.FlatMap(x => +{ + if (x == 1) return Result.Fail>(ErrorMessage1); + + return Result.Fail>(ErrorMessage2); +}); +``` + +```csharp +(Result>, Func>) -> Result> +``` + +```csharp +var input = new[] {1, 2}.AsEnumerable().ToResultOk(); + +Result> outputResult = input.FlatMap(x => +{ + if (x == 1) return Result.Fail(ErrorMessage1); + + return Result.Fail(ErrorMessage2); +}); +``` + +```csharp +Result>> -> Result> +``` + +```csharp +var input = new[] {1, 2}; + +Result> outputResult = input.FlatMap(x => new[] { x * 2 }.AsEnumerable().ToResultOk()); +``` + +**NOTE** +- If *ParallelOptions* is not specified, then it will use default *ParallelOptions*. +- There are overloads that take a *ParallelOptions*, so you can control the level of concurrency. + ##### FlatMapAs -Transforms an Result<IEnumerable>T>> to a IEnumerable>Result<T>> +Transforms an Result<IEnumerable<T>> to a Result<IEnumerable>TR>> + +```csharp +public record Container(IEnumerable Values); +``` + +```csharp +var values = Enumerable.Range(0, 1) + .Select(x => new Container(new []{x})); + +Result> resultInput = Result.Ok(values); + +Result> resultOutput = resultInput.FlatMapAs(x => x.Values, x -> x * 2); +``` + +#### FlatMapSequential +Transforms each element of a sequence to an IEnumerable<T> and flattens the resulting sequences into one sequence. + +**NOTE** This runs sequentially, i.e. runs with a ParallelOptions MaxDegreeOfParallelism = 1 + +```csharp +var input = new[] { 1, 2 }; + +Result outputResult = await input.FlatMapSequentialAsync(x => +{ + if (x == 1) return Result.FailAsync(ErrorMessage1); + + return Result.FailAsync(ErrorMessage2); +}); +``` +#### FlatMapSequentialUntilFailure +Transforms each element of a sequence to an IEnumerable<T>, returning the first error it finds. + +```csharp +var input = new [] {1,2, 3}; + +Result outputResult = input.FlatMapSequentialUntilFailure(x => x == 2 ? Result.Fail(ErrorMessage1) : Result.Ok()); +``` ##### MapAs -Transforms an Result<IEnumerable>T>> to a Result<IEnumerable>TR>> +Transforms an Result<IEnumerable<T>> to a Result<IEnumerable>TR>> ```csharp var values = Enumerable.Range(0, 1); @@ -506,7 +636,7 @@ Result result = new[] {result1, result2, result3}.PickFailureOrSuccess(); ``` ##### ThenAs -Transforms an Result<IEnumerable>T>> to a Result<IEnumerable>TR>> +Transforms an Result<IEnumerable<T>> to a Result<IEnumerable>TR>> ```csharp var values = Enumerable.Range(0, 1); @@ -534,7 +664,7 @@ Result result = input.TryFirst(x => ``` ##### TryToDictionary -Try to create a Dictionary<TKey, TElement;> from an IEnumerable>T> according to specified key selector and element selector functions. +Try to create a Dictionary<TKey, TElement;> from an IEnumerable<T> according to specified key selector and element selector functions. **NOTE:** This will explicitly checks for duplicate keys and return a Result<Dictionary<TKey, TElement>> *failure* if there are any. @@ -552,12 +682,10 @@ Return only those elements of a sequence of Result<T> that are *success*. If none of the elements in the sequence are *success*, then a Result<T> *failure* is returned. ```csharp -var result1 = Result.Ok(1); -var result2 = Result.Ok(2); -var result3 = Result.Ok(3); +IAsyncEnumerable> inputResults = AsyncEnumerable.Range(1, 3) + .Select(x => Core.Result.Result.Ok(x)); -List values = await ToAsyncEnumerable(new[] {result1, result2, result3}).Choose() - .ToListAsync(); +List values = await inputResults.Choose().ToListAsync(); ``` ##### Filter @@ -572,7 +700,7 @@ Result> returnedResult = resultInput.Filter(x => x % 2 == ``` ##### MapAs -Transforms an Result<IEnumerable>T>> to a Result<IEnumerable>TR>> +Transforms an Result<IEnumerable<T>> to a Result<IEnumerable>TR>> ```csharp var values = AsyncEnumerable.Range(0, 1); @@ -991,4 +1119,20 @@ var result = option.ToResult(ErrorMessage); ``` ##### Result -> Option -This is **not supported** as it would result in the loss of the error context. \ No newline at end of file +This is **not supported** as it would result in the loss of the error context. + +## Stryker mutation testing +### Make sure you have Stryker installed +```bash +dotnet tool install -g dotnet-stryker +``` + +### Make sure the Test project is built +```bash +dotnet build ./test/Futurum.Core.Tests +``` + +### Run Stryker +```bash +dotnet stryker +``` \ No newline at end of file diff --git a/src/Futurum.Core/Result/Result.FlatMap.ParallelOptions.cs b/src/Futurum.Core/Result/Result.Enumerable.FlatMap.ParallelOptions.cs similarity index 98% rename from src/Futurum.Core/Result/Result.FlatMap.ParallelOptions.cs rename to src/Futurum.Core/Result/Result.Enumerable.FlatMap.ParallelOptions.cs index ebdd346..731ed55 100644 --- a/src/Futurum.Core/Result/Result.FlatMap.ParallelOptions.cs +++ b/src/Futurum.Core/Result/Result.Enumerable.FlatMap.ParallelOptions.cs @@ -2,7 +2,7 @@ namespace Futurum.Core.Result; -public static partial class ResultExtensions +public static partial class ResultEnumerableExtensions { /// /// Transforms each element of a sequence to an and flattens the resulting sequences into one sequence. @@ -151,7 +151,7 @@ await Parallel.ForEachAsync(source, parallelOptions, /// public static Task>> FlatMapAsync(this Task>> resultTaskSource, ParallelOptions parallelOptions, Func>>> func) => - resultTaskSource.FlatMapAsync(parallelOptions, func, Combine); + resultTaskSource.FlatMapAsync(parallelOptions, func, ResultExtensions.Combine); /// /// Transforms each element of a sequence to an and flattens the resulting sequences into one sequence. @@ -171,7 +171,7 @@ public static Task>> FlatMapAsync(this TaskControl the parallelism with parameter /// public static Task FlatMapAsync(this Task>> resultTaskSource, ParallelOptions parallelOptions, Func> func) => - resultTaskSource.FlatMapAsync(parallelOptions, func, Combine); + resultTaskSource.FlatMapAsync(parallelOptions, func, ResultExtensions.Combine); public static Task> FlatMapAsync(this Task>> resultTaskSource, ParallelOptions parallelOptions, Func>> func, diff --git a/src/Futurum.Core/Result/Result.FlatMap.Sequential.cs b/src/Futurum.Core/Result/Result.Enumerable.FlatMap.Sequential.cs similarity index 99% rename from src/Futurum.Core/Result/Result.FlatMap.Sequential.cs rename to src/Futurum.Core/Result/Result.Enumerable.FlatMap.Sequential.cs index 355d54b..f67cdac 100644 --- a/src/Futurum.Core/Result/Result.FlatMap.Sequential.cs +++ b/src/Futurum.Core/Result/Result.Enumerable.FlatMap.Sequential.cs @@ -1,6 +1,6 @@ namespace Futurum.Core.Result; -public static partial class ResultExtensions +public static partial class ResultEnumerableExtensions { /// /// Transforms each element of a sequence to an and flattens the resulting sequences into one sequence. diff --git a/src/Futurum.Core/Result/Result.FlatMap.SequentialUntilFailure.cs b/src/Futurum.Core/Result/Result.Enumerable.FlatMap.SequentialUntilFailure.cs similarity index 97% rename from src/Futurum.Core/Result/Result.FlatMap.SequentialUntilFailure.cs rename to src/Futurum.Core/Result/Result.Enumerable.FlatMap.SequentialUntilFailure.cs index 9ba7c41..86710f0 100644 --- a/src/Futurum.Core/Result/Result.FlatMap.SequentialUntilFailure.cs +++ b/src/Futurum.Core/Result/Result.Enumerable.FlatMap.SequentialUntilFailure.cs @@ -1,6 +1,6 @@ namespace Futurum.Core.Result; -public static partial class ResultExtensions +public static partial class ResultEnumerableExtensions { /// /// Transforms each element of a sequence to an , returning the first error it finds. diff --git a/src/Futurum.Core/Result/Result.FlatMap.cs b/src/Futurum.Core/Result/Result.Enumerable.FlatMap.cs similarity index 99% rename from src/Futurum.Core/Result/Result.FlatMap.cs rename to src/Futurum.Core/Result/Result.Enumerable.FlatMap.cs index a723016..c4dbb25 100644 --- a/src/Futurum.Core/Result/Result.FlatMap.cs +++ b/src/Futurum.Core/Result/Result.Enumerable.FlatMap.cs @@ -2,7 +2,7 @@ namespace Futurum.Core.Result; -public static partial class ResultExtensions +public static partial class ResultEnumerableExtensions { /// /// Transforms each element of a sequence to an and flattens the resulting sequences into one sequence. @@ -120,7 +120,7 @@ public static Result> FlatMap(this IEnumerable source, /// /// public static Result> FlatMap(this Result> resultSource, Func>> func) => - resultSource.FlatMap(func, Combine); + resultSource.FlatMap(func, ResultExtensions.Combine); /// /// Transforms each element of a sequence to an and flattens the resulting sequences into one sequence. diff --git a/src/Futurum.Core/Result/Result.Enumerable.TryFirst.cs b/src/Futurum.Core/Result/Result.Enumerable.TryFirst.cs index e39f4e4..6f13f3c 100644 --- a/src/Futurum.Core/Result/Result.Enumerable.TryFirst.cs +++ b/src/Futurum.Core/Result/Result.Enumerable.TryFirst.cs @@ -1,5 +1,3 @@ -using Futurum.Core.Option; - namespace Futurum.Core.Result; public static partial class ResultEnumerableExtensions @@ -25,36 +23,14 @@ public static partial class ResultEnumerableExtensions /// public static Result TryFirst(this IEnumerable source, Func> func, string errorMessage) { - return Run(Option>.None, source.ToArray()); - - Result Run(Option> previous, TSource[] items) => - items.Length switch - { - 0 => Result.Fail(errorMessage), - _ => previous.HasNoValue - ? NoPrevious(items[0], items[1..]) - : WithPrevious(previous.Value, items[0], items[1..]) - }; - - Result NoPrevious(TSource item, TSource[] items) + foreach (var x in source) { - var current = func(item); + var result = func(x); - return current.IsSuccess - ? Result.Ok(current.Value.Value) - : Run(current, items); + if (result.IsSuccess) return result; } - Result WithPrevious(Result previous, TSource item, TSource[] items) - { - var current = previous.IsSuccess - ? Result.Ok(previous.Value.Value) - : func(item); - - return current.IsSuccess - ? Result.Ok(current.Value.Value) - : Run(current, items); - } + return Result.Fail(errorMessage); } /// @@ -78,36 +54,14 @@ Result WithPrevious(Result previous, TSource item, TSource[] items) /// public static Result TryFirst(this IEnumerable source, Func> func, IResultError errorMessage) { - return Run(Option>.None, source.ToArray()); - - Result Run(Option> previous, TSource[] items) => - items.Length switch - { - 0 => Result.Fail(errorMessage), - _ => previous.HasNoValue - ? NoPrevious(items[0], items[1..]) - : WithPrevious(previous.Value, items[0], items[1..]) - }; - - Result NoPrevious(TSource item, TSource[] items) + foreach (var x in source) { - var current = func(item); + var result = func(x); - return current.IsSuccess - ? Result.Ok(current.Value.Value) - : Run(current, items); + if (result.IsSuccess) return result; } - Result WithPrevious(Result previous, TSource item, TSource[] items) - { - var current = previous.IsSuccess - ? Result.Ok(previous.Value.Value) - : func(item); - - return current.IsSuccess - ? Result.Ok(current.Value.Value) - : Run(current, items); - } + return Result.Fail(errorMessage); } /// @@ -129,38 +83,16 @@ Result WithPrevious(Result previous, TSource item, TSource[] items) /// If none of the elements in the sequence when passed to returns with true, /// then with true and as the error is returned. /// - public static Task> TryFirstAsync(this IEnumerable source, Func>> func, string errorMessage) + public static async Task> TryFirstAsync(this IEnumerable source, Func>> func, string errorMessage) { - return RunAsync(Option>.None, source.ToArray()); - - async Task> RunAsync(Option> previous, TSource[] items) => - items.Length switch - { - 0 => Result.Fail(errorMessage), - _ => previous.HasNoValue - ? await NoPrevious(items[0], items[1..]) - : await WithPrevious(previous.Value, items[0], items[1..]) - }; - - async Task> NoPrevious(TSource item, TSource[] items) + foreach (var x in source) { - var current = await func(item); + var result = await func(x); - return await (current.IsSuccess - ? Result.OkAsync(current.Value.Value) - : RunAsync(current, items)); + if (result.IsSuccess) return result; } - async Task> WithPrevious(Result previous, TSource item, TSource[] items) - { - var current = await (previous.IsSuccess - ? Result.OkAsync(previous.Value.Value) - : func(item)); - - return await (current.IsSuccess - ? Result.OkAsync(current.Value.Value) - : RunAsync(current, items)); - } + return Result.Fail(errorMessage); } /// @@ -182,37 +114,15 @@ async Task> WithPrevious(Result previous, TSource item, TSource[] /// If none of the elements in the sequence when passed to returns with true, /// then with true and as the error is returned. /// - public static Task> TryFirstAsync(this IEnumerable source, Func>> func, IResultError errorMessage) + public static async Task> TryFirstAsync(this IEnumerable source, Func>> func, IResultError errorMessage) { - return RunAsync(Option>.None, source.ToArray()); - - async Task> RunAsync(Option> previous, TSource[] items) => - items.Length switch - { - 0 => Result.Fail(errorMessage), - _ => previous.HasNoValue - ? await NoPrevious(items[0], items[1..]) - : await WithPrevious(previous.Value, items[0], items[1..]) - }; - - async Task> NoPrevious(TSource item, TSource[] items) + foreach (var x in source) { - var current = await func(item); + var result = await func(x); - return await (current.IsSuccess - ? Result.OkAsync(current.Value.Value) - : RunAsync(current, items)); + if (result.IsSuccess) return result; } - async Task> WithPrevious(Result previous, TSource item, TSource[] items) - { - var current = await (previous.IsSuccess - ? Result.OkAsync(previous.Value.Value) - : func(item)); - - return await (current.IsSuccess - ? Result.OkAsync(current.Value.Value) - : RunAsync(current, items)); - } + return Result.Fail(errorMessage); } } \ No newline at end of file diff --git a/src/Futurum.Core/Result/Result.Factory.cs b/src/Futurum.Core/Result/Result.Factory.cs index c663b8b..7385926 100644 --- a/src/Futurum.Core/Result/Result.Factory.cs +++ b/src/Futurum.Core/Result/Result.Factory.cs @@ -4,7 +4,8 @@ namespace Futurum.Core.Result; public readonly partial struct Result { - private static readonly Result ResultOk = new(true); + private const bool OkIsSuccess = true; + private static readonly Result ResultOk = new(OkIsSuccess); private static readonly Task ResultOkAsync = Task.FromResult(ResultOk); /// diff --git a/src/Futurum.Core/Result/Result.IgnoreFailure.cs b/src/Futurum.Core/Result/Result.IgnoreFailure.cs index ce1a0f2..67ec194 100644 --- a/src/Futurum.Core/Result/Result.IgnoreFailure.cs +++ b/src/Futurum.Core/Result/Result.IgnoreFailure.cs @@ -15,7 +15,13 @@ public static Result IgnoreFailure(this Result result) /// public static async Task IgnoreFailureAsync(this Task result) { - await result; + try + { + await result; + } + catch (Exception) + { + } return Result.Ok(); } diff --git a/src/Futurum.Core/Result/Result.Unwrap.cs b/src/Futurum.Core/Result/Result.Unwrap.cs index 682d06d..fbee14d 100644 --- a/src/Futurum.Core/Result/Result.Unwrap.cs +++ b/src/Futurum.Core/Result/Result.Unwrap.cs @@ -21,7 +21,7 @@ public static void Unwrap(this Result result) { if (result.IsFailure) { - throw new Exception(result.Error.Value.ToErrorString(",")); + throw new Exception(result.Error.Value.ToErrorString()); } } @@ -44,7 +44,7 @@ public static T Unwrap(this Result result) { if (result.IsFailure) { - throw new Exception(result.Error.Value.ToErrorString(",")); + throw new Exception(result.Error.Value.ToErrorString()); } return result.Value.Value; @@ -71,7 +71,7 @@ public static async Task UnwrapAsync(this Task resultTask) if (result.IsFailure) { - throw new Exception(result.Error.Value.ToErrorString(",")); + throw new Exception(result.Error.Value.ToErrorString()); } } @@ -96,7 +96,7 @@ public static async Task UnwrapAsync(this Task> resultTask) if (result.IsFailure) { - throw new Exception(result.Error.Value.ToErrorString(",")); + throw new Exception(result.Error.Value.ToErrorString()); } return result.Value.Value; diff --git a/src/Futurum.Core/Result/ResultErrorExceptionExtensions.cs b/src/Futurum.Core/Result/ResultErrorExceptionExtensions.cs index e8e5912..980f8d5 100644 --- a/src/Futurum.Core/Result/ResultErrorExceptionExtensions.cs +++ b/src/Futurum.Core/Result/ResultErrorExceptionExtensions.cs @@ -17,7 +17,7 @@ public static IResultErrorNonComposite ToResultError(this Exception exception) = /// /// Transforms an and a into either a - /// or a with the and a + /// or a with the as the parent and a as the child /// public static IResultError ToResultError(this Exception exception, string errorMessage) => string.IsNullOrEmpty(errorMessage) diff --git a/test/Futurum.Core.Tests/Futurum.Core.Tests.csproj b/test/Futurum.Core.Tests/Futurum.Core.Tests.csproj index 3cfa150..fe32669 100644 --- a/test/Futurum.Core.Tests/Futurum.Core.Tests.csproj +++ b/test/Futurum.Core.Tests/Futurum.Core.Tests.csproj @@ -13,6 +13,7 @@ + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/test/Futurum.Core.Tests/Result/ResultErrorCompositeExtensionsTests.cs b/test/Futurum.Core.Tests/Result/ResultErrorCompositeExtensionsTests.cs index bc345dc..5289205 100644 --- a/test/Futurum.Core.Tests/Result/ResultErrorCompositeExtensionsTests.cs +++ b/test/Futurum.Core.Tests/Result/ResultErrorCompositeExtensionsTests.cs @@ -3,6 +3,7 @@ using FluentAssertions; using Futurum.Core.Result; +using Futurum.Core.Tests.Helper.Option; using Futurum.Core.Tests.Helper.Result; using Xunit; @@ -11,63 +12,67 @@ namespace Futurum.Core.Tests.Result; public class ResultErrorCompositeExtensionsTests { - public class ToResultError + public class with_Parent { + private const string ErrorMessage = "ERROR_MESSAGE"; + [Fact] - public void Array() + public void IEnumerable() { + var parentResultError = ErrorMessage.ToResultError(); + var resultErrors = Enumerable.Range(0, 10) .Select(x => x.ToString()) .Select(x => x.ToResultError()) - .ToArray(); + .ToList(); - var resultErrorComposite = resultErrors.ToResultError() as ResultErrorComposite; + var resultErrorComposite = ResultErrorCompositeExtensions.ToResultError(parentResultError, resultErrors) as ResultErrorComposite; + resultErrorComposite.Parent.ShouldBeHasValueWithValue(parentResultError); + resultErrorComposite.Children.Count().Should().Be(resultErrors.Count()); resultErrorComposite.Children.Should().BeEquivalentTo(resultErrors); } [Fact] - public void IEnumerble() + public void Array() { + var parentResultError = ErrorMessage.ToResultError(); + var resultErrors = Enumerable.Range(0, 10) .Select(x => x.ToString()) .Select(x => x.ToResultError()) - .ToList() - .AsEnumerable(); + .ToArray(); - var resultErrorComposite = resultErrors.ToResultError() as ResultErrorComposite; + var resultErrorComposite = ResultErrorCompositeExtensions.ToResultError(parentResultError, resultErrors) as ResultErrorComposite; + resultErrorComposite.Parent.ShouldBeHasValueWithValue(parentResultError); + resultErrorComposite.Children.Count().Should().Be(resultErrors.Count()); resultErrorComposite.Children.Should().BeEquivalentTo(resultErrors); } } - public class EnhanceWithError + public class without_Parent { - private const string ErrorMessage1 = "ERROR_MESSAGE_1"; - private const string ErrorMessage2 = "ERROR_MESSAGE_2"; - [Fact] - public void ErrorMessage() + public void IEnumerble() { - var error = ErrorMessage1.ToResultError(); - - var resultError = error.EnhanceWithError(ErrorMessage2); - - resultError.ShouldBeError(ErrorMessage2, ErrorMessage1); - } + var resultErrors = Enumerable.Range(0, 10) + .Select(x => x.ToString()) + .Select(x => x.ToResultError()) + .ToList() + .AsEnumerable(); - [Fact] - public void IResultError() - { - var error = ErrorMessage1.ToResultError(); + var resultErrorComposite = resultErrors.ToResultError() as ResultErrorComposite; - var resultError = error.EnhanceWithError(ErrorMessage2.ToResultError()); + resultErrorComposite.Parent.ShouldBeHasNoValue(); + + resultErrorComposite.Children.Count().Should().Be(resultErrors.Count()); - resultError.ShouldBeError(ErrorMessage2, ErrorMessage1); + resultErrorComposite.Children.Should().BeEquivalentTo(resultErrors); } } } \ No newline at end of file diff --git a/test/Futurum.Core.Tests/Result/ResultTests.CombineAll.WithSelector.cs b/test/Futurum.Core.Tests/Result/ResultTests.CombineAll.WithSelector.cs index dab5861..2fb3530 100644 --- a/test/Futurum.Core.Tests/Result/ResultTests.CombineAll.WithSelector.cs +++ b/test/Futurum.Core.Tests/Result/ResultTests.CombineAll.WithSelector.cs @@ -45,7 +45,7 @@ public void all_success() } [Fact] - public void mixed() + public void mixed_1() { var result1 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); var result2 = Core.Result.Result.Fail(ErrorMessage1); @@ -54,6 +54,17 @@ public void mixed() result.ShouldBeFailureWithError($"{ErrorMessage1}"); } + + [Fact] + public void mixed_2() + { + var result1 = Core.Result.Result.Fail(ErrorMessage1); + var result2 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + + var result = Core.Result.Result.CombineAll(result1, result2, (a, b) => (a, b)); + + result.ShouldBeFailureWithError($"{ErrorMessage1}"); + } } public class Three @@ -85,7 +96,7 @@ public void all_success() } [Fact] - public void mixed() + public void mixed_1() { var result1 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); var result2 = Core.Result.Result.Fail(ErrorMessage1); @@ -95,6 +106,42 @@ public void mixed() result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2}"); } + + [Fact] + public void mixed_2() + { + var result1 = Core.Result.Result.Fail(ErrorMessage1); + var result2 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + var result3 = Core.Result.Result.Fail(ErrorMessage2); + + var result = Core.Result.Result.CombineAll(result1, result2, result3, (a, b, c) => (a, b, c)); + + result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2}"); + } + + [Fact] + public void mixed_3() + { + var result1 = Core.Result.Result.Fail(ErrorMessage1); + var result2 = Core.Result.Result.Fail(ErrorMessage2); + var result3 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + + var result = Core.Result.Result.CombineAll(result1, result2, result3, (a, b, c) => (a, b, c)); + + result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2}"); + } + + [Fact] + public void mixed_4() + { + var result1 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + var result2 = Core.Result.Result.Fail(ErrorMessage1); + var result3 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + + var result = Core.Result.Result.CombineAll(result1, result2, result3, (a, b, c) => (a, b, c)); + + result.ShouldBeFailureWithError(ErrorMessage1); + } } public class Four @@ -130,7 +177,7 @@ public void all_success() } [Fact] - public void mixed() + public void mixed_1() { var result1 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); var result2 = Core.Result.Result.Fail(ErrorMessage1); @@ -141,6 +188,123 @@ public void mixed() result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2};{ErrorMessage3}"); } + + [Fact] + public void mixed_2() + { + var result1 = Core.Result.Result.Fail(ErrorMessage1); + var result2 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + var result3 = Core.Result.Result.Fail(ErrorMessage2); + var result4 = Core.Result.Result.Fail(ErrorMessage3); + + var result = Core.Result.Result.CombineAll(result1, result2, result3, result4, (a, b, c, d) => (a, b, c, d)); + + result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2};{ErrorMessage3}"); + } + + [Fact] + public void mixed_3() + { + var result1 = Core.Result.Result.Fail(ErrorMessage1); + var result2 = Core.Result.Result.Fail(ErrorMessage2); + var result3 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + var result4 = Core.Result.Result.Fail(ErrorMessage3); + + var result = Core.Result.Result.CombineAll(result1, result2, result3, result4, (a, b, c, d) => (a, b, c, d)); + + result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2};{ErrorMessage3}"); + } + + [Fact] + public void mixed_4() + { + var result1 = Core.Result.Result.Fail(ErrorMessage1); + var result2 = Core.Result.Result.Fail(ErrorMessage2); + var result3 = Core.Result.Result.Fail(ErrorMessage3); + var result4 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + + var result = Core.Result.Result.CombineAll(result1, result2, result3, result4, (a, b, c, d) => (a, b, c, d)); + + result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2};{ErrorMessage3}"); + } + + [Fact] + public void mixed_5() + { + var result1 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + var result2 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + var result3 = Core.Result.Result.Fail(ErrorMessage1); + var result4 = Core.Result.Result.Fail(ErrorMessage2); + + var result = Core.Result.Result.CombineAll(result1, result2, result3, result4, (a, b, c, d) => (a, b, c, d)); + + result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2}"); + } + + [Fact] + public void mixed_6() + { + var result1 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + var result2 = Core.Result.Result.Fail(ErrorMessage1); + var result3 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + var result4 = Core.Result.Result.Fail(ErrorMessage2); + + var result = Core.Result.Result.CombineAll(result1, result2, result3, result4, (a, b, c, d) => (a, b, c, d)); + + result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2}"); + } + + [Fact] + public void mixed_7() + { + var result1 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + var result2 = Core.Result.Result.Fail(ErrorMessage1); + var result3 = Core.Result.Result.Fail(ErrorMessage2); + var result4 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + + var result = Core.Result.Result.CombineAll(result1, result2, result3, result4, (a, b, c, d) => (a, b, c, d)); + + result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2}"); + } + + [Fact] + public void mixed_8() + { + var result1 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + var result2 = Core.Result.Result.Fail(ErrorMessage1); + var result3 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + var result4 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + + var result = Core.Result.Result.CombineAll(result1, result2, result3, result4, (a, b, c, d) => (a, b, c, d)); + + result.ShouldBeFailureWithError(ErrorMessage1); + } + + [Fact] + public void mixed_9() + { + var result1 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + var result2 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + var result3 = Core.Result.Result.Fail(ErrorMessage1); + var result4 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + + var result = Core.Result.Result.CombineAll(result1, result2, result3, result4, (a, b, c, d) => (a, b, c, d)); + + result.ShouldBeFailureWithError(ErrorMessage1); + } + + [Fact] + public void mixed_10() + { + var result1 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + var result2 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + var result3 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + var result4 = Core.Result.Result.Fail(ErrorMessage1); + + var result = Core.Result.Result.CombineAll(result1, result2, result3, result4, (a, b, c, d) => (a, b, c, d)); + + result.ShouldBeFailureWithError(ErrorMessage1); + } } } @@ -173,7 +337,7 @@ public async Task all_success() } [Fact] - public async Task mixed() + public async Task mixed_1() { var result1 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); var result2 = Core.Result.Result.FailAsync(ErrorMessage1); @@ -182,6 +346,17 @@ public async Task mixed() result.ShouldBeFailureWithError($"{ErrorMessage1}"); } + + [Fact] + public async Task mixed_2() + { + var result1 = Core.Result.Result.FailAsync(ErrorMessage1); + var result2 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + + var result = await Core.Result.Result.CombineAllAsync(result1, result2, (a, b) => (a, b)); + + result.ShouldBeFailureWithError($"{ErrorMessage1}"); + } } public class Three @@ -214,7 +389,7 @@ public async Task all_success() } [Fact] - public async Task mixed() + public async Task mixed_1() { var result1 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); var result2 = Core.Result.Result.FailAsync(ErrorMessage1); @@ -224,6 +399,42 @@ public async Task mixed() result.ShouldBeFailureWithError($"{ErrorMessage1}"); } + + [Fact] + public async Task mixed_2() + { + var result1 = Core.Result.Result.FailAsync(ErrorMessage1); + var result2 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + var result3 = Core.Result.Result.FailAsync(ErrorMessage2); + + var result = await Core.Result.Result.CombineAllAsync(result1, result2, result3, (a, b, c) => (a, b, c)); + + result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2}"); + } + + [Fact] + public async Task mixed_3() + { + var result1 = Core.Result.Result.FailAsync(ErrorMessage1); + var result2 = Core.Result.Result.FailAsync(ErrorMessage2); + var result3 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + + var result = await Core.Result.Result.CombineAllAsync(result1, result2, result3, (a, b, c) => (a, b, c)); + + result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2}"); + } + + [Fact] + public async Task mixed_4() + { + var result1 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + var result2 = Core.Result.Result.FailAsync(ErrorMessage1); + var result3 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + + var result = await Core.Result.Result.CombineAllAsync(result1, result2, result3, (a, b, c) => (a, b, c)); + + result.ShouldBeFailureWithError(ErrorMessage1); + } } public class Four @@ -259,16 +470,133 @@ public async Task all_success() } [Fact] - public async Task mixed() + public async Task mixed_1() { var result1 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); var result2 = Core.Result.Result.FailAsync(ErrorMessage1); + var result3 = Core.Result.Result.FailAsync(ErrorMessage2); + var result4 = Core.Result.Result.FailAsync(ErrorMessage3); + + var result = await Core.Result.Result.CombineAllAsync(result1, result2, result3, result4, (a, b, c, d) => (a, b, c, d)); + + result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2};{ErrorMessage3}"); + } + + [Fact] + public async Task mixed_2() + { + var result1 = Core.Result.Result.FailAsync(ErrorMessage1); + var result2 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + var result3 = Core.Result.Result.FailAsync(ErrorMessage2); + var result4 = Core.Result.Result.FailAsync(ErrorMessage3); + + var result = await Core.Result.Result.CombineAllAsync(result1, result2, result3, result4, (a, b, c, d) => (a, b, c, d)); + + result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2};{ErrorMessage3}"); + } + + [Fact] + public async Task mixed_3() + { + var result1 = Core.Result.Result.FailAsync(ErrorMessage1); + var result2 = Core.Result.Result.FailAsync(ErrorMessage2); var result3 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + var result4 = Core.Result.Result.FailAsync(ErrorMessage3); + + var result = await Core.Result.Result.CombineAllAsync(result1, result2, result3, result4, (a, b, c, d) => (a, b, c, d)); + + result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2};{ErrorMessage3}"); + } + + [Fact] + public async Task mixed_4() + { + var result1 = Core.Result.Result.FailAsync(ErrorMessage1); + var result2 = Core.Result.Result.FailAsync(ErrorMessage2); + var result3 = Core.Result.Result.FailAsync(ErrorMessage3); var result4 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); var result = await Core.Result.Result.CombineAllAsync(result1, result2, result3, result4, (a, b, c, d) => (a, b, c, d)); - result.ShouldBeFailureWithError($"{ErrorMessage1}"); + result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2};{ErrorMessage3}"); + } + + [Fact] + public async Task mixed_5() + { + var result1 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + var result2 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + var result3 = Core.Result.Result.FailAsync(ErrorMessage1); + var result4 = Core.Result.Result.FailAsync(ErrorMessage2); + + var result = await Core.Result.Result.CombineAllAsync(result1, result2, result3, result4, (a, b, c, d) => (a, b, c, d)); + + result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2}"); + } + + [Fact] + public async Task mixed_6() + { + var result1 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + var result2 = Core.Result.Result.FailAsync(ErrorMessage1); + var result3 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + var result4 = Core.Result.Result.FailAsync(ErrorMessage2); + + var result = await Core.Result.Result.CombineAllAsync(result1, result2, result3, result4, (a, b, c, d) => (a, b, c, d)); + + result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2}"); + } + + [Fact] + public async Task mixed_7() + { + var result1 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + var result2 = Core.Result.Result.FailAsync(ErrorMessage1); + var result3 = Core.Result.Result.FailAsync(ErrorMessage2); + var result4 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + + var result = await Core.Result.Result.CombineAllAsync(result1, result2, result3, result4, (a, b, c, d) => (a, b, c, d)); + + result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2}"); + } + + [Fact] + public async Task mixed_8() + { + var result1 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + var result2 = Core.Result.Result.FailAsync(ErrorMessage1); + var result3 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + var result4 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + + var result = await Core.Result.Result.CombineAllAsync(result1, result2, result3, result4, (a, b, c, d) => (a, b, c, d)); + + result.ShouldBeFailureWithError(ErrorMessage1); + } + + [Fact] + public async Task mixed_9() + { + var result1 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + var result2 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + var result3 = Core.Result.Result.FailAsync(ErrorMessage1); + var result4 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + + var result = await Core.Result.Result.CombineAllAsync(result1, result2, result3, result4, (a, b, c, d) => (a, b, c, d)); + + result.ShouldBeFailureWithError(ErrorMessage1); + } + + [Fact] + public async Task mixed_10() + { + var result1 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + var result2 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + var result3 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + var result4 = Core.Result.Result.FailAsync(ErrorMessage1); + + var result = await Core.Result.Result.CombineAllAsync(result1, result2, result3, result4, (a, b, c, d) => (a, b, c, d)); + + result.ShouldBeFailureWithError(ErrorMessage1); } } } diff --git a/test/Futurum.Core.Tests/Result/ResultTests.CombineAll.cs b/test/Futurum.Core.Tests/Result/ResultTests.CombineAll.cs index 6be0322..cf50bd4 100644 --- a/test/Futurum.Core.Tests/Result/ResultTests.CombineAll.cs +++ b/test/Futurum.Core.Tests/Result/ResultTests.CombineAll.cs @@ -45,7 +45,7 @@ public void all_success() } [Fact] - public void mixed() + public void mixed_1() { var result1 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); var result2 = Core.Result.Result.Fail(ErrorMessage1); @@ -54,8 +54,19 @@ public void mixed() result.ShouldBeFailureWithError($"{ErrorMessage1}"); } + + [Fact] + public void mixed_2() + { + var result1 = Core.Result.Result.Fail(ErrorMessage1); + var result2 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + + var result = Core.Result.Result.CombineAll(result1, result2); + + result.ShouldBeFailureWithError($"{ErrorMessage1}"); + } } - + public class Three { [Fact] @@ -86,7 +97,7 @@ public void all_success() } [Fact] - public void mixed() + public void mixed_1() { var result1 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); var result2 = Core.Result.Result.Fail(ErrorMessage1); @@ -96,8 +107,44 @@ public void mixed() result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2}"); } + + [Fact] + public void mixed_2() + { + var result1 = Core.Result.Result.Fail(ErrorMessage1); + var result2 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + var result3 = Core.Result.Result.Fail(ErrorMessage2); + + var result = Core.Result.Result.CombineAll(result1, result2, result3); + + result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2}"); + } + + [Fact] + public void mixed_3() + { + var result1 = Core.Result.Result.Fail(ErrorMessage1); + var result2 = Core.Result.Result.Fail(ErrorMessage2); + var result3 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + + var result = Core.Result.Result.CombineAll(result1, result2, result3); + + result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2}"); + } + + [Fact] + public void mixed_4() + { + var result1 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + var result2 = Core.Result.Result.Fail(ErrorMessage1); + var result3 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + + var result = Core.Result.Result.CombineAll(result1, result2, result3); + + result.ShouldBeFailureWithError(ErrorMessage1); + } } - + public class Four { [Fact] @@ -131,7 +178,7 @@ public void all_success() } [Fact] - public void mixed() + public void mixed_1() { var result1 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); var result2 = Core.Result.Result.Fail(ErrorMessage1); @@ -142,9 +189,126 @@ public void mixed() result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2};{ErrorMessage3}"); } + + [Fact] + public void mixed_2() + { + var result1 = Core.Result.Result.Fail(ErrorMessage1); + var result2 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + var result3 = Core.Result.Result.Fail(ErrorMessage2); + var result4 = Core.Result.Result.Fail(ErrorMessage3); + + var result = Core.Result.Result.CombineAll(result1, result2, result3, result4); + + result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2};{ErrorMessage3}"); + } + + [Fact] + public void mixed_3() + { + var result1 = Core.Result.Result.Fail(ErrorMessage1); + var result2 = Core.Result.Result.Fail(ErrorMessage2); + var result3 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + var result4 = Core.Result.Result.Fail(ErrorMessage3); + + var result = Core.Result.Result.CombineAll(result1, result2, result3, result4); + + result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2};{ErrorMessage3}"); + } + + [Fact] + public void mixed_4() + { + var result1 = Core.Result.Result.Fail(ErrorMessage1); + var result2 = Core.Result.Result.Fail(ErrorMessage2); + var result3 = Core.Result.Result.Fail(ErrorMessage3); + var result4 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + + var result = Core.Result.Result.CombineAll(result1, result2, result3, result4); + + result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2};{ErrorMessage3}"); + } + + [Fact] + public void mixed_5() + { + var result1 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + var result2 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + var result3 = Core.Result.Result.Fail(ErrorMessage1); + var result4 = Core.Result.Result.Fail(ErrorMessage2); + + var result = Core.Result.Result.CombineAll(result1, result2, result3, result4); + + result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2}"); + } + + [Fact] + public void mixed_6() + { + var result1 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + var result2 = Core.Result.Result.Fail(ErrorMessage1); + var result3 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + var result4 = Core.Result.Result.Fail(ErrorMessage2); + + var result = Core.Result.Result.CombineAll(result1, result2, result3, result4); + + result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2}"); + } + + [Fact] + public void mixed_7() + { + var result1 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + var result2 = Core.Result.Result.Fail(ErrorMessage1); + var result3 = Core.Result.Result.Fail(ErrorMessage2); + var result4 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + + var result = Core.Result.Result.CombineAll(result1, result2, result3, result4); + + result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2}"); + } + + [Fact] + public void mixed_8() + { + var result1 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + var result2 = Core.Result.Result.Fail(ErrorMessage1); + var result3 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + var result4 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + + var result = Core.Result.Result.CombineAll(result1, result2, result3, result4); + + result.ShouldBeFailureWithError(ErrorMessage1); + } + + [Fact] + public void mixed_9() + { + var result1 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + var result2 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + var result3 = Core.Result.Result.Fail(ErrorMessage1); + var result4 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + + var result = Core.Result.Result.CombineAll(result1, result2, result3, result4); + + result.ShouldBeFailureWithError(ErrorMessage1); + } + + [Fact] + public void mixed_10() + { + var result1 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + var result2 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + var result3 = Core.Result.Result.Ok(Guid.NewGuid().ToString()); + var result4 = Core.Result.Result.Fail(ErrorMessage1); + + var result = Core.Result.Result.CombineAll(result1, result2, result3, result4); + + result.ShouldBeFailureWithError(ErrorMessage1); + } } } - + public class Async { public class Two @@ -174,7 +338,7 @@ public async Task all_success() } [Fact] - public async Task mixed() + public async Task mixed_1() { var result1 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); var result2 = Core.Result.Result.FailAsync(ErrorMessage1); @@ -183,8 +347,19 @@ public async Task mixed() result.ShouldBeFailureWithError($"{ErrorMessage1}"); } + + [Fact] + public async Task mixed_2() + { + var result1 = Core.Result.Result.FailAsync(ErrorMessage1); + var result2 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + + var result = await Core.Result.Result.CombineAllAsync(result1, result2); + + result.ShouldBeFailureWithError($"{ErrorMessage1}"); + } } - + public class Three { [Fact] @@ -215,7 +390,7 @@ public async Task all_success() } [Fact] - public async Task mixed() + public async Task mixed_1() { var result1 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); var result2 = Core.Result.Result.FailAsync(ErrorMessage1); @@ -225,8 +400,44 @@ public async Task mixed() result.ShouldBeFailureWithError($"{ErrorMessage1}"); } + + [Fact] + public async Task mixed_2() + { + var result1 = Core.Result.Result.FailAsync(ErrorMessage1); + var result2 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + var result3 = Core.Result.Result.FailAsync(ErrorMessage2); + + var result = await Core.Result.Result.CombineAllAsync(result1, result2, result3); + + result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2}"); + } + + [Fact] + public async Task mixed_3() + { + var result1 = Core.Result.Result.FailAsync(ErrorMessage1); + var result2 = Core.Result.Result.FailAsync(ErrorMessage2); + var result3 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + + var result = await Core.Result.Result.CombineAllAsync(result1, result2, result3); + + result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2}"); + } + + [Fact] + public async Task mixed_4() + { + var result1 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + var result2 = Core.Result.Result.FailAsync(ErrorMessage1); + var result3 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + + var result = await Core.Result.Result.CombineAllAsync(result1, result2, result3); + + result.ShouldBeFailureWithError(ErrorMessage1); + } } - + public class Four { [Fact] @@ -260,7 +471,98 @@ public async Task all_success() } [Fact] - public async Task mixed() + public async Task mixed_1() + { + var result1 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + var result2 = Core.Result.Result.FailAsync(ErrorMessage1); + var result3 = Core.Result.Result.FailAsync(ErrorMessage2); + var result4 = Core.Result.Result.FailAsync(ErrorMessage3); + + var result = await Core.Result.Result.CombineAllAsync(result1, result2, result3, result4); + + result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2};{ErrorMessage3}"); + } + + [Fact] + public async Task mixed_2() + { + var result1 = Core.Result.Result.FailAsync(ErrorMessage1); + var result2 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + var result3 = Core.Result.Result.FailAsync(ErrorMessage2); + var result4 = Core.Result.Result.FailAsync(ErrorMessage3); + + var result = await Core.Result.Result.CombineAllAsync(result1, result2, result3, result4); + + result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2};{ErrorMessage3}"); + } + + [Fact] + public async Task mixed_3() + { + var result1 = Core.Result.Result.FailAsync(ErrorMessage1); + var result2 = Core.Result.Result.FailAsync(ErrorMessage2); + var result3 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + var result4 = Core.Result.Result.FailAsync(ErrorMessage3); + + var result = await Core.Result.Result.CombineAllAsync(result1, result2, result3, result4); + + result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2};{ErrorMessage3}"); + } + + [Fact] + public async Task mixed_4() + { + var result1 = Core.Result.Result.FailAsync(ErrorMessage1); + var result2 = Core.Result.Result.FailAsync(ErrorMessage2); + var result3 = Core.Result.Result.FailAsync(ErrorMessage3); + var result4 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + + var result = await Core.Result.Result.CombineAllAsync(result1, result2, result3, result4); + + result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2};{ErrorMessage3}"); + } + + [Fact] + public async Task mixed_5() + { + var result1 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + var result2 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + var result3 = Core.Result.Result.FailAsync(ErrorMessage1); + var result4 = Core.Result.Result.FailAsync(ErrorMessage2); + + var result = await Core.Result.Result.CombineAllAsync(result1, result2, result3, result4); + + result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2}"); + } + + [Fact] + public async Task mixed_6() + { + var result1 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + var result2 = Core.Result.Result.FailAsync(ErrorMessage1); + var result3 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + var result4 = Core.Result.Result.FailAsync(ErrorMessage2); + + var result = await Core.Result.Result.CombineAllAsync(result1, result2, result3, result4); + + result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2}"); + } + + [Fact] + public async Task mixed_7() + { + var result1 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + var result2 = Core.Result.Result.FailAsync(ErrorMessage1); + var result3 = Core.Result.Result.FailAsync(ErrorMessage2); + var result4 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + + var result = await Core.Result.Result.CombineAllAsync(result1, result2, result3, result4); + + result.ShouldBeFailureWithError($"{ErrorMessage1};{ErrorMessage2}"); + } + + [Fact] + public async Task mixed_8() { var result1 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); var result2 = Core.Result.Result.FailAsync(ErrorMessage1); @@ -269,7 +571,33 @@ public async Task mixed() var result = await Core.Result.Result.CombineAllAsync(result1, result2, result3, result4); - result.ShouldBeFailureWithError($"{ErrorMessage1}"); + result.ShouldBeFailureWithError(ErrorMessage1); + } + + [Fact] + public async Task mixed_9() + { + var result1 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + var result2 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + var result3 = Core.Result.Result.FailAsync(ErrorMessage1); + var result4 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + + var result = await Core.Result.Result.CombineAllAsync(result1, result2, result3, result4); + + result.ShouldBeFailureWithError(ErrorMessage1); + } + + [Fact] + public async Task mixed_10() + { + var result1 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + var result2 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + var result3 = Core.Result.Result.OkAsync(Guid.NewGuid().ToString()); + var result4 = Core.Result.Result.FailAsync(ErrorMessage1); + + var result = await Core.Result.Result.CombineAllAsync(result1, result2, result3, result4); + + result.ShouldBeFailureWithError(ErrorMessage1); } } } diff --git a/test/Futurum.Core.Tests/Result/ResultTests.EnhanceWithError.cs b/test/Futurum.Core.Tests/Result/ResultTests.EnhanceWithError.cs index 27e3116..a7e67b2 100644 --- a/test/Futurum.Core.Tests/Result/ResultTests.EnhanceWithError.cs +++ b/test/Futurum.Core.Tests/Result/ResultTests.EnhanceWithError.cs @@ -413,4 +413,27 @@ public async Task Success() } } } + + public class with_IResultError + { + [Fact] + public void ErrorMessage() + { + var error = ErrorMessage1.ToResultError(); + + var resultError = error.EnhanceWithError(ErrorMessage2); + + resultError.ShouldBeError(ErrorMessage2, ErrorMessage1); + } + + [Fact] + public void IResultError() + { + var error = ErrorMessage1.ToResultError(); + + var resultError = error.EnhanceWithError(ErrorMessage2.ToResultError()); + + resultError.ShouldBeError(ErrorMessage2, ErrorMessage1); + } + } } \ No newline at end of file diff --git a/test/Futurum.Core.Tests/Result/ResultTests.FlatMap.ParallelOptions.cs b/test/Futurum.Core.Tests/Result/ResultTests.Enumerable.FlatMap.ParallelOptions.cs similarity index 99% rename from test/Futurum.Core.Tests/Result/ResultTests.FlatMap.ParallelOptions.cs rename to test/Futurum.Core.Tests/Result/ResultTests.Enumerable.FlatMap.ParallelOptions.cs index 6b2adf2..d17616b 100644 --- a/test/Futurum.Core.Tests/Result/ResultTests.FlatMap.ParallelOptions.cs +++ b/test/Futurum.Core.Tests/Result/ResultTests.Enumerable.FlatMap.ParallelOptions.cs @@ -11,7 +11,7 @@ namespace Futurum.Core.Tests.Result; -public class ResultFlatMapParallelOptionsTests +public class ResultEnumerableFlatMapParallelOptionsTests { private const string ErrorMessage1 = "ERROR_MESSAGE_1"; private const string ErrorMessage2 = "ERROR_MESSAGE_2"; diff --git a/test/Futurum.Core.Tests/Result/ResultTests.FlatMap.Sequential.cs b/test/Futurum.Core.Tests/Result/ResultTests.Enumerable.FlatMap.Sequential.cs similarity index 99% rename from test/Futurum.Core.Tests/Result/ResultTests.FlatMap.Sequential.cs rename to test/Futurum.Core.Tests/Result/ResultTests.Enumerable.FlatMap.Sequential.cs index 6502a55..9821d37 100644 --- a/test/Futurum.Core.Tests/Result/ResultTests.FlatMap.Sequential.cs +++ b/test/Futurum.Core.Tests/Result/ResultTests.Enumerable.FlatMap.Sequential.cs @@ -11,7 +11,7 @@ namespace Futurum.Core.Tests.Result; -public class ResultFlatMapSequentialTests +public class ResultEnumerableFlatMapSequentialTests { private const string ErrorMessage1 = "ERROR_MESSAGE_1"; private const string ErrorMessage2 = "ERROR_MESSAGE_2"; diff --git a/test/Futurum.Core.Tests/Result/ResultTests.FlatMap.SequentialUntilFailure.cs b/test/Futurum.Core.Tests/Result/ResultTests.Enumerable.FlatMap.SequentialUntilFailure.cs similarity index 99% rename from test/Futurum.Core.Tests/Result/ResultTests.FlatMap.SequentialUntilFailure.cs rename to test/Futurum.Core.Tests/Result/ResultTests.Enumerable.FlatMap.SequentialUntilFailure.cs index 2c179f8..4d8b3f7 100644 --- a/test/Futurum.Core.Tests/Result/ResultTests.FlatMap.SequentialUntilFailure.cs +++ b/test/Futurum.Core.Tests/Result/ResultTests.Enumerable.FlatMap.SequentialUntilFailure.cs @@ -10,7 +10,7 @@ namespace Futurum.Core.Tests.Result; -public class ResultFlatMapSequentialUntilFailureTests +public class ResultEnumerableFlatMapSequentialUntilFailureTests { private const string ErrorMessage1 = "ERROR_MESSAGE_1"; diff --git a/test/Futurum.Core.Tests/Result/ResultTests.FlatMap.cs b/test/Futurum.Core.Tests/Result/ResultTests.Enumerable.FlatMap.cs similarity index 99% rename from test/Futurum.Core.Tests/Result/ResultTests.FlatMap.cs rename to test/Futurum.Core.Tests/Result/ResultTests.Enumerable.FlatMap.cs index f715e2f..8955a9b 100644 --- a/test/Futurum.Core.Tests/Result/ResultTests.FlatMap.cs +++ b/test/Futurum.Core.Tests/Result/ResultTests.Enumerable.FlatMap.cs @@ -11,7 +11,7 @@ namespace Futurum.Core.Tests.Result; -public class ResultFlatMapTests +public class ResultEnumerableFlatMapTests { private const string ErrorMessage1 = "ERROR_MESSAGE_1"; private const string ErrorMessage2 = "ERROR_MESSAGE_2"; diff --git a/test/Futurum.Core.Tests/Result/ResultTests.IgnoreFailure.cs b/test/Futurum.Core.Tests/Result/ResultTests.IgnoreFailure.cs index 5e62d94..4096d97 100644 --- a/test/Futurum.Core.Tests/Result/ResultTests.IgnoreFailure.cs +++ b/test/Futurum.Core.Tests/Result/ResultTests.IgnoreFailure.cs @@ -1,3 +1,4 @@ +using System; using System.Threading.Tasks; using Futurum.Core.Result; @@ -46,6 +47,21 @@ public async Task FailureInput() resultOutput.ShouldBeSuccess(); } + [Fact] + public async Task Exception() + { + var resultInput = ThrowException(); + + var resultOutput = await resultInput.IgnoreFailureAsync(); + + resultOutput.ShouldBeSuccess(); + + Task ThrowException() + { + return Task.FromException(new Exception(ErrorMessage)); + } + } + [Fact] public async Task SuccessInput() {