From fcb44b3a2a38367b0e495ba6b647f1f9023a2c24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hern=C3=A1ndez?= <140873695+daht-x@users.noreply.github.com> Date: Thu, 4 Jan 2024 23:03:46 -0500 Subject: [PATCH] feature(`Result`): add `Bind` method --- source/Monads/Result.cs | 17 +++-- test/unit/Monads/Fixtures/ResultFixture.cs | 6 ++ test/unit/Monads/Mothers/ResultMother.cs | 9 ++- test/unit/Monads/ResultTest.cs | 78 ++++++++++++++++++---- 4 files changed, 91 insertions(+), 19 deletions(-) diff --git a/source/Monads/Result.cs b/source/Monads/Result.cs index f7a414f..685fb6e 100644 --- a/source/Monads/Result.cs +++ b/source/Monads/Result.cs @@ -111,22 +111,31 @@ public Result Ensure(Func createAuxi : this; } - /// Creates a new result with a different expected success. + /// Creates a new result with the same or different type of expected success. /// The expected success to map. /// Type of expected success to map. - /// A new result with a different expected success. + /// A new result with the same or different type of expected success. public Result Map(TSuccessToMap successToMap) => IsFailed ? new(Failure) : new(successToMap); - /// Creates a new result with a different expected success. + /// Creates a new result with the same or different type of expected success. /// Creates the expected success to map. /// Type of expected success to map. - /// A new result with a different expected success. + /// A new result with the same or different type of expected success. public Result Map(Func createSuccessToMap) => IsFailed ? new(Failure) : new(createSuccessToMap(Success)); + + /// Creates a new result in combination with another result with the same or different type of expected success. + /// Creates a new result to bind. + /// Type of expected success to bind. + /// A new result in combination with another result with the same or different type of expected success. + public Result Bind(Func> createResultToBind) + => IsFailed + ? new(Failure) + : createResultToBind(Success); } #pragma warning restore CA1062 diff --git a/test/unit/Monads/Fixtures/ResultFixture.cs b/test/unit/Monads/Fixtures/ResultFixture.cs index 6afcff2..3a82c8e 100644 --- a/test/unit/Monads/Fixtures/ResultFixture.cs +++ b/test/unit/Monads/Fixtures/ResultFixture.cs @@ -15,6 +15,12 @@ internal static Constellation Success Symbolism = "The arrow" }; + internal static Constellation RandomSuccess + => Success with + { + Abbreviation = $"{Success.Name} | {Guid.NewGuid()}" + }; + internal static Start SuccessToMap => new() { diff --git a/test/unit/Monads/Mothers/ResultMother.cs b/test/unit/Monads/Mothers/ResultMother.cs index 7fc25d7..d7948dd 100644 --- a/test/unit/Monads/Mothers/ResultMother.cs +++ b/test/unit/Monads/Mothers/ResultMother.cs @@ -3,11 +3,14 @@ namespace Daht.Sagitta.Core.UnitTest.Monads.Mothers; internal static class ResultMother { internal static Result Succeed() - => ResultFactory.Succeed(ResultFixture.Success); + => new(ResultFixture.Success); internal static Result Succeed(Constellation success) - => ResultFactory.Succeed(success); + => new(success); + + internal static Result SucceedRandomly() + => new(ResultFixture.RandomSuccess); internal static Result Fail(string failure) - => ResultFactory.Fail(failure); + => new(failure); } diff --git a/test/unit/Monads/ResultTest.cs b/test/unit/Monads/ResultTest.cs index d327617..47723ca 100644 --- a/test/unit/Monads/ResultTest.cs +++ b/test/unit/Monads/ResultTest.cs @@ -12,6 +12,8 @@ public sealed class ResultTest private const string map = nameof(Result.Map); + private const string bind = nameof(Result.Bind); + #region Constructor #region Overload @@ -329,15 +331,15 @@ public void Ensure_SuccessfulResultPlusCreateAuxiliaryPlusFalsePredicatePlusCrea [Trait(root, map)] public void Map_FailedResultPlusSuccessToMap_FailedResult() { - //Arrange + // Arrange const string expectedFailure = ResultFixture.Failure; Start successToMap = ResultFixture.SuccessToMap; - //Act + // Act Result actualResult = ResultMother.Fail(expectedFailure) .Map(successToMap); - //Assert + // Assert ResultAsserter.AreFailed(expectedFailure, actualResult); } @@ -345,14 +347,14 @@ public void Map_FailedResultPlusSuccessToMap_FailedResult() [Trait(root, map)] public void Map_SuccessfulResultPlusSuccessToMap_SuccessfulResult() { - //Arrange + // Arrange Start expectedSuccess = ResultFixture.SuccessToMap; - //Act + // Act Result actualResult = ResultMother.Succeed() .Map(expectedSuccess); - //Assert + // Assert ResultAsserter.AreSuccessful(expectedSuccess, actualResult); } @@ -364,15 +366,15 @@ public void Map_SuccessfulResultPlusSuccessToMap_SuccessfulResult() [Trait(root, map)] public void Map_FailedResultPlusCreateSuccessToMap_FailedResult() { - //Arrange + // Arrange const string expectedFailure = ResultFixture.Failure; Func createSuccessToMap = static _ => ResultFixture.SuccessToMap; - //Act + // Act Result actualResult = ResultMother.Fail(expectedFailure) .Map(createSuccessToMap); - //Assert + // Assert ResultAsserter.AreFailed(expectedFailure, actualResult); } @@ -380,19 +382,71 @@ public void Map_FailedResultPlusCreateSuccessToMap_FailedResult() [Trait(root, map)] public void Map_SuccessfulResultPlusCreateSuccessToMap_SuccessfulResult() { - //Arrange + // Arrange Start expectedSuccess = ResultFixture.SuccessToMap; Func createSuccessToMap = _ => expectedSuccess; - //Act + // Act Result actualResult = ResultMother.Succeed() .Map(createSuccessToMap); - //Assert + // Assert ResultAsserter.AreSuccessful(expectedSuccess, actualResult); } #endregion #endregion + + #region Bind + + [Fact] + [Trait(root, bind)] + public void Bind_FailedResultPlusCreateResultToBindWithSuccessfulResult_FailedResult() + { + // Arrange + const string expectedFailure = ResultFixture.Failure; + Func> createResultToBind = static _ => ResultMother.Succeed(); + + // Act + Result actualResult = ResultMother.Fail(expectedFailure) + .Bind(createResultToBind); + + // Assert + ResultAsserter.AreFailed(expectedFailure, actualResult); + } + + [Fact] + [Trait(root, bind)] + public void Bind_SuccessfulResultPlusCreateResultToBindWithFailedResult_FailedResult() + { + // Arrange + const string expectedFailure = ResultFixture.Failure; + Func> createResultToBind = static _ => ResultMother.Fail(expectedFailure); + + // Act + Result actualResult = ResultMother.Succeed() + .Bind(createResultToBind); + + // Assert + ResultAsserter.AreFailed(expectedFailure, actualResult); + } + + [Fact] + [Trait(root, bind)] + public void Bind_SuccessfulResultPlusCreateResultToBindWithSuccessfulResult_SuccessfulResult() + { + // Arrange + Constellation expectedSuccess = ResultFixture.Success; + Func> createResultToBind = _ => ResultMother.Succeed(expectedSuccess); + + // Act + Result actualResult = ResultMother.SucceedRandomly() + .Bind(createResultToBind); + + // Assert + ResultAsserter.AreSuccessful(expectedSuccess, actualResult); + } + + #endregion }