Skip to content

Commit

Permalink
Added more integration for untyped Result.
Browse files Browse the repository at this point in the history
  • Loading branch information
KFAFSP committed Aug 3, 2018
1 parent 397ba0c commit 17b01f2
Show file tree
Hide file tree
Showing 3 changed files with 161 additions and 5 deletions.
56 changes: 56 additions & 0 deletions Whetstone.Contracts/Result.cs
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,25 @@ public Result<TOut> AndThen<TOut>([NotNull] [InstantHandle] Func<T, TOut> AFunc)
: new Result<TOut>(UnboxError);
}
/// <summary>
/// Execute an <see cref="Action{T}"/> on the successful value (if any) or propagate the
/// <see cref="Error"/> of this result.
/// </summary>
/// <param name="AAction">The <see cref="Action{T}"/>.</param>
/// <returns>A <see cref="Result"/> that propagates <see cref="Error"/>.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="AAction"/> is <see langword="null"/>.
/// </exception>
[ContractAnnotation("AAction: null => halt;")]
public Result AndThen([NotNull] [InstantHandle] Action<T> AAction)
{
if (AAction == null) throw new ArgumentNullException(nameof(AAction));

if (!IsSuccess) return new Result(UnboxError);

AAction(UnboxValue);
return new Result(true);
}
/// <summary>
/// Compute a <see cref="Func{T, TResult}"/> on the successful value (if any) and propagate
/// the results, or catch and propagate the error thrown from it.
/// </summary>
Expand Down Expand Up @@ -583,6 +602,35 @@ public Result<TOut> AndThenTry<TOut>([NotNull] [InstantHandle] Func<T, TOut> AFu
return new Result<TOut>(error);
}
}
/// <summary>
/// Execute an <see cref="Action{T}"/> on the successful value (if any) and propagate the
/// <see cref="Error"/> of this result, or catch and propagate the error thrown from it.
/// </summary>
/// <param name="AAction">The <see cref="Action{T}"/>.</param>
/// <returns>
/// A <see cref="Result"/> propagating the <see cref="Error"/> or propagating the error
/// during <paramref name="AAction"/>.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="AAction"/> is <see langword="null"/>.
/// </exception>
[ContractAnnotation("AAction: null => halt;")]
public Result AndThenTry([NotNull] [InstantHandle] Action<T> AAction)
{
if (AAction == null) throw new ArgumentNullException(nameof(AAction));

if (!IsSuccess) return new Result(UnboxError);

try
{
AAction(UnboxValue);
return new Result(true);
}
catch (Exception error)
{
return new Result(error);
}
}

/// <summary>
/// Ignore the contained error (if any).
Expand Down Expand Up @@ -757,6 +805,14 @@ public void ThrowIfError()
public static implicit operator Result<T>([NotNull] Exception AError)
=> new Result<T>(AError);

/// <summary>
/// Implicitly convert a <see cref="Result{T}"/> to an untyped <see cref="Result"/>.
/// </summary>
/// <param name="AResult">The <see cref="Result{T}"/>.</param>
[Pure]
public static implicit operator Result(Result<T> AResult)
=> AResult.IsSuccess ? new Result(true) : new Result(AResult.UnboxError);

/// <summary>
/// Shorthand for calling <see cref="Result{T}.Equals(Result{T})"/>.
/// </summary>
Expand Down
4 changes: 2 additions & 2 deletions Whetstone.Contracts/Whetstone.Contracts.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<package>
<metadata>
<id>Whetstone.Contracts</id>
<version>1.0.0.1</version>
<version>1.0.0.2</version>
<title>Whetstone.Contracts</title>
<authors>Karl F. A. Friebel</authors>
<owners>KFAFSP</owners>
Expand All @@ -13,7 +13,7 @@
Types and extensions for method contract validation.
</description>
<releaseNotes>
Minor project structure changes.
Added more integration for untyped Result.
</releaseNotes>
<copyright>Copyright (c) Karl F. A. Friebel 2018</copyright>
<tags></tags>
Expand Down
106 changes: 103 additions & 3 deletions Whetstone.Tests/Contracts/Result.cs
Original file line number Diff line number Diff line change
Expand Up @@ -721,7 +721,7 @@ public void AndThen_Successful_WrapsResult()
}

[Test]
[Description("AndThen on erroneous propagates the error..")]
[Description("AndThen on erroneous propagates the error.")]
public void AndThen_Erroneous_PropagatesError()
{
Assert.That(
Expand All @@ -741,6 +741,47 @@ public void AndThen_Successful_PropagatesFunctionException()
);
}

[Test]
[Description("AndThen on null action throws ArgumentNullException.")]
public void AndThen2_ActionIsNull_ThrowsArgumentNullException()
{
Assert.That(() => Result.Ok(0).AndThen(null), Throws.ArgumentNullException);
}

[Test]
[Description("AndThen on successful runs action and propagates IsSuccess.")]
public void AndThen2_Successful_PropagatesIsSuccess()
{
var executed = false;

Assert.That(Result.Ok(2).AndThen(X => { executed = true; }).IsSuccess, Is.True);
Assert.That(executed, Is.True);
}

[Test]
[Description("AndThen on erroneous does not run action and propagates the error.")]
public void AndThen2_Erroneous_PropagatesError()
{
var executed = false;

Assert.That(
Result.Fail<int>(_FCommonError).AndThen(X => { executed = true; }).Error,
Is.SameAs(_FCommonError)
);
Assert.That(executed, Is.False);
}

[Test]
[Description("AndThen on successful up-propagates an exception thrown in the action.")]
public void AndThen2_Successful_PropagatesFunctionException()
{
var error = new Exception();
Assert.That(
() => Result.Ok(1).AndThen(X => throw error),
Throws.Exception.SameAs(error)
);
}

[Test]
[Description("AndThenTry on null function throws ArgumentNullException.")]
public void AndThenTry_FunctionIsNull_ThrowsArgumentNullException()
Expand All @@ -756,7 +797,7 @@ public void AndThenTry_Successful_WrapsResult()
}

[Test]
[Description("AndThenTry on erroneous propagates the error..")]
[Description("AndThenTry on erroneous propagates the error.")]
public void AndThenTry_Erroneous_PropagatesError()
{
Assert.That(
Expand All @@ -766,7 +807,7 @@ public void AndThenTry_Erroneous_PropagatesError()
}

[Test]
[Description("AndThenTry on successfulwraps an exception thrown in the function.")]
[Description("AndThenTry on successful wraps an exception thrown in the function.")]
public void AndThenTry_Successful_WrapsFunctionException()
{
var error = new Exception();
Expand All @@ -776,6 +817,47 @@ public void AndThenTry_Successful_WrapsFunctionException()
);
}

[Test]
[Description("AndThenTry on null action throws ArgumentNullException.")]
public void AndThenTry2_ActionIsNull_ThrowsArgumentNullException()
{
Assert.That(() => Result.Ok(0).AndThenTry(null), Throws.ArgumentNullException);
}

[Test]
[Description("AndThenTry on successful runs action and propagates IsSuccess.")]
public void AndThenTry2_Successful_WrapsResult()
{
var executed = false;

Assert.That(Result.Ok(2).AndThenTry(X => { executed = true; }).IsSuccess, Is.True);
Assert.That(executed, Is.True);
}

[Test]
[Description("AndThenTry on erroneous does not run action and propagates the error.")]
public void AndThenTry2_Erroneous_PropagatesError()
{
var executed = false;

Assert.That(
Result.Fail<int>(_FCommonError).AndThenTry(X => { executed = true; }).Error,
Is.SameAs(_FCommonError)
);
Assert.That(executed, Is.False);
}

[Test]
[Description("AndThenTry on successful wraps an exception thrown in the action.")]
public void AndThenTry2_Successful_WrapsFunctionException()
{
var error = new Exception();
Assert.That(
Result.Ok(1).AndThenTry(X => throw error).Error,
Is.SameAs(error)
);
}

[Test]
[Description("IgnoreError on successful returns present Optional.")]
public void IgnoreError_Successful_WrapsValue()
Expand Down Expand Up @@ -942,6 +1024,24 @@ public void ImplicitCast_ToExceptionSuccessful_IsNull()
Assert.That(error, Is.Null);
}

[Test]
[Description("Implicit cast to untyped Result of erroneous propagates the Error.")]
public void ImplicitCast_ToResultErroneous_PropagatesError()
{
Result result = Result.Fail<int>(_FCommonError);

Assert.That(result.Error, Is.SameAs(_FCommonError));
}

[Test]
[Description("Implicit cast to untyped Result of successful propagates IsSuccess.")]
public void ImplicitCast_ToResultSuccessful_PropagatesIsSuccess()
{
Result result = Result.Ok(1);

Assert.That(result.IsSuccess, Is.True);
}

[TestCaseSource(nameof(ResResAlikeTestCases))]
[Description("Binary equals operator on Results is correct.")]
public bool EqOp_ResRes_Correct(Result<int> ALeft, Result<int> ARight)
Expand Down

0 comments on commit 17b01f2

Please sign in to comment.