Skip to content

Commit

Permalink
feature(Result): add Bind method
Browse files Browse the repository at this point in the history
  • Loading branch information
daht-x authored Jan 5, 2024
1 parent 4f016c2 commit fcb44b3
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 19 deletions.
17 changes: 13 additions & 4 deletions source/Monads/Result.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,22 +111,31 @@ public Result<TSuccess, TFailure> Ensure<TAuxiliary>(Func<TAuxiliary> createAuxi
: this;
}

/// <summary>Creates a new result with a different expected success.</summary>
/// <summary>Creates a new result with the same or different type of expected success.</summary>
/// <param name="successToMap">The expected success to map.</param>
/// <typeparam name="TSuccessToMap">Type of expected success to map.</typeparam>
/// <returns>A new result with a different expected success.</returns>
/// <returns>A new result with the same or different type of expected success.</returns>
public Result<TSuccessToMap, TFailure> Map<TSuccessToMap>(TSuccessToMap successToMap)
=> IsFailed
? new(Failure)
: new(successToMap);

/// <summary>Creates a new result with a different expected success.</summary>
/// <summary>Creates a new result with the same or different type of expected success.</summary>
/// <param name="createSuccessToMap">Creates the expected success to map.</param>
/// <typeparam name="TSuccessToMap">Type of expected success to map.</typeparam>
/// <returns>A new result with a different expected success.</returns>
/// <returns>A new result with the same or different type of expected success.</returns>
public Result<TSuccessToMap, TFailure> Map<TSuccessToMap>(Func<TSuccess, TSuccessToMap> createSuccessToMap)
=> IsFailed
? new(Failure)
: new(createSuccessToMap(Success));

/// <summary>Creates a new result in combination with another result with the same or different type of expected success.</summary>
/// <param name="createResultToBind">Creates a new result to bind.</param>
/// <typeparam name="TSuccessToBind">Type of expected success to bind.</typeparam>
/// <returns>A new result in combination with another result with the same or different type of expected success.</returns>
public Result<TSuccessToBind, TFailure> Bind<TSuccessToBind>(Func<TSuccess, Result<TSuccessToBind, TFailure>> createResultToBind)
=> IsFailed
? new(Failure)
: createResultToBind(Success);
}
#pragma warning restore CA1062
6 changes: 6 additions & 0 deletions test/unit/Monads/Fixtures/ResultFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
{
Expand Down
9 changes: 6 additions & 3 deletions test/unit/Monads/Mothers/ResultMother.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ namespace Daht.Sagitta.Core.UnitTest.Monads.Mothers;
internal static class ResultMother
{
internal static Result<Constellation, string> Succeed()
=> ResultFactory.Succeed<Constellation, string>(ResultFixture.Success);
=> new(ResultFixture.Success);

internal static Result<Constellation, string> Succeed(Constellation success)
=> ResultFactory.Succeed<Constellation, string>(success);
=> new(success);

internal static Result<Constellation, string> SucceedRandomly()
=> new(ResultFixture.RandomSuccess);

internal static Result<Constellation, string> Fail(string failure)
=> ResultFactory.Fail<Constellation, string>(failure);
=> new(failure);
}
78 changes: 66 additions & 12 deletions test/unit/Monads/ResultTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ public sealed class ResultTest

private const string map = nameof(Result<object, object>.Map);

private const string bind = nameof(Result<object, object>.Bind);

#region Constructor

#region Overload
Expand Down Expand Up @@ -329,30 +331,30 @@ 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<Start, string> actualResult = ResultMother.Fail(expectedFailure)
.Map(successToMap);

//Assert
// Assert
ResultAsserter.AreFailed(expectedFailure, actualResult);
}

[Fact]
[Trait(root, map)]
public void Map_SuccessfulResultPlusSuccessToMap_SuccessfulResult()
{
//Arrange
// Arrange
Start expectedSuccess = ResultFixture.SuccessToMap;

//Act
// Act
Result<Start, string> actualResult = ResultMother.Succeed()
.Map(expectedSuccess);

//Assert
// Assert
ResultAsserter.AreSuccessful(expectedSuccess, actualResult);
}

Expand All @@ -364,35 +366,87 @@ public void Map_SuccessfulResultPlusSuccessToMap_SuccessfulResult()
[Trait(root, map)]
public void Map_FailedResultPlusCreateSuccessToMap_FailedResult()
{
//Arrange
// Arrange
const string expectedFailure = ResultFixture.Failure;
Func<Constellation, Start> createSuccessToMap = static _ => ResultFixture.SuccessToMap;

//Act
// Act
Result<Start, string> actualResult = ResultMother.Fail(expectedFailure)
.Map(createSuccessToMap);

//Assert
// Assert
ResultAsserter.AreFailed(expectedFailure, actualResult);
}

[Fact]
[Trait(root, map)]
public void Map_SuccessfulResultPlusCreateSuccessToMap_SuccessfulResult()
{
//Arrange
// Arrange
Start expectedSuccess = ResultFixture.SuccessToMap;
Func<Constellation, Start> createSuccessToMap = _ => expectedSuccess;

//Act
// Act
Result<Start, string> 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<Constellation, Result<Constellation, string>> createResultToBind = static _ => ResultMother.Succeed();

// Act
Result<Constellation, string> 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<Constellation, Result<Constellation, string>> createResultToBind = static _ => ResultMother.Fail(expectedFailure);

// Act
Result<Constellation, string> 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<Constellation, Result<Constellation, string>> createResultToBind = _ => ResultMother.Succeed(expectedSuccess);

// Act
Result<Constellation, string> actualResult = ResultMother.SucceedRandomly()
.Bind(createResultToBind);

// Assert
ResultAsserter.AreSuccessful(expectedSuccess, actualResult);
}

#endregion
}

0 comments on commit fcb44b3

Please sign in to comment.