Core.Attempt - backport and refactor Attempt.Outcome from v7
This commit is contained in:
@@ -52,5 +52,115 @@ namespace Umbraco.Core
|
||||
{
|
||||
return Attempt<T>.SucceedIf(success, result);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Executes an attempt function, with callbacks.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the attempted operation result.</typeparam>
|
||||
/// <param name="attempt">The attempt returned by the attempt function.</param>
|
||||
/// <param name="onSuccess">An action to execute in case the attempt succeeds.</param>
|
||||
/// <param name="onFail">An action to execute in case the attempt fails.</param>
|
||||
/// <returns>The outcome of the attempt.</returns>
|
||||
/// <remarks>Runs <paramref name="onSuccess"/> or <paramref name="onFail"/> depending on the
|
||||
/// whether the attempt function reports a success or a failure.</remarks>
|
||||
public static Outcome Try<T>(Attempt<T> attempt, Action<T> onSuccess, Action<Exception> onFail = null)
|
||||
{
|
||||
if (attempt.Success)
|
||||
{
|
||||
onSuccess(attempt.Result);
|
||||
return Outcome.Success;
|
||||
}
|
||||
|
||||
if (onFail != null)
|
||||
{
|
||||
onFail(attempt.Exception);
|
||||
}
|
||||
|
||||
return Outcome.Failure;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents the outcome of an attempt.
|
||||
/// </summary>
|
||||
/// <remarks>Can be a success or a failure, and allows for attempts chaining.</remarks>
|
||||
public struct Outcome
|
||||
{
|
||||
private readonly bool _success;
|
||||
|
||||
/// <summary>
|
||||
/// Gets an outcome representing a success.
|
||||
/// </summary>
|
||||
public static readonly Outcome Success = new Outcome(true);
|
||||
|
||||
/// <summary>
|
||||
/// Gets an outcome representing a failure.
|
||||
/// </summary>
|
||||
public static readonly Outcome Failure = new Outcome(false);
|
||||
|
||||
private Outcome(bool success)
|
||||
{
|
||||
_success = success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes another attempt function, if the previous one failed, with callbacks.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the attempted operation result.</typeparam>
|
||||
/// <param name="nextFunction">The attempt function to execute, returning an attempt.</param>
|
||||
/// <param name="onSuccess">An action to execute in case the attempt succeeds.</param>
|
||||
/// <param name="onFail">An action to execute in case the attempt fails.</param>
|
||||
/// <returns>If it executes, returns the outcome of the attempt, else returns a success outcome.</returns>
|
||||
/// <remarks>
|
||||
/// <para>Executes only if the previous attempt failed, else does not execute and return a success outcome.</para>
|
||||
/// <para>If it executes, then runs <paramref name="onSuccess"/> or <paramref name="onFail"/> depending on the
|
||||
/// whether the attempt function reports a success or a failure.</para>
|
||||
/// </remarks>
|
||||
public Outcome OnFailure<T>(Func<Attempt<T>> nextFunction, Action<T> onSuccess, Action<Exception> onFail = null)
|
||||
{
|
||||
return _success
|
||||
? Success
|
||||
: ExecuteNextFunction(nextFunction, onSuccess, onFail);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes another attempt function, if the previous one succeeded, with callbacks.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the attempted operation result.</typeparam>
|
||||
/// <param name="nextFunction">The attempt function to execute, returning an attempt.</param>
|
||||
/// <param name="onSuccess">An action to execute in case the attempt succeeds.</param>
|
||||
/// <param name="onFail">An action to execute in case the attempt fails.</param>
|
||||
/// <returns>If it executes, returns the outcome of the attempt, else returns a failed outcome.</returns>
|
||||
/// <remarks>
|
||||
/// <para>Executes only if the previous attempt succeeded, else does not execute and return a success outcome.</para>
|
||||
/// <para>If it executes, then runs <paramref name="onSuccess"/> or <paramref name="onFail"/> depending on the
|
||||
/// whether the attempt function reports a success or a failure.</para>
|
||||
/// </remarks>
|
||||
public Outcome OnSuccess<T>(Func<Attempt<T>> nextFunction, Action<T> onSuccess, Action<Exception> onFail = null)
|
||||
{
|
||||
return _success
|
||||
? ExecuteNextFunction(nextFunction, onSuccess, onFail)
|
||||
: Failure;
|
||||
}
|
||||
|
||||
private static Outcome ExecuteNextFunction<T>(Func<Attempt<T>> nextFunction, Action<T> onSuccess, Action<Exception> onFail = null)
|
||||
{
|
||||
var attempt = nextFunction();
|
||||
|
||||
if (attempt.Success)
|
||||
{
|
||||
onSuccess(attempt.Result);
|
||||
return Success;
|
||||
}
|
||||
|
||||
if (onFail != null)
|
||||
{
|
||||
onFail(attempt.Exception);
|
||||
}
|
||||
|
||||
return Failure;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
41
src/Umbraco.Tests/AttemptTests.cs
Normal file
41
src/Umbraco.Tests/AttemptTests.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
|
||||
namespace Umbraco.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class AttemptTests
|
||||
{
|
||||
[Test]
|
||||
public void Chained_Attempts()
|
||||
{
|
||||
Attempt.Try(Attempt.Succeed("success!"),
|
||||
s => Assert.AreEqual("success!", s),
|
||||
exception => Assert.Fail("Should have been successful."))
|
||||
|
||||
// previous one was a success so that one SHOULD NOT run
|
||||
// and report success
|
||||
.OnFailure(() => Attempt.Succeed(123),
|
||||
i => Assert.Fail("The previous attempt was successful!"),
|
||||
exception => Assert.Fail("The previous attempt was successful!"))
|
||||
|
||||
// previous one did not run, last run was a success so that one SHOULD run
|
||||
// and report failure
|
||||
.OnSuccess(() => Attempt<double>.Fail(new Exception("Failed!")),
|
||||
d => Assert.Fail("Should have failed."),
|
||||
exception => Assert.AreEqual("Failed!", exception.Message))
|
||||
|
||||
// previous one did run and was a failure so that one SHOULD NOT run
|
||||
.OnSuccess(() => Attempt.Succeed(987),
|
||||
i => Assert.Fail("The previous attempt failed!"),
|
||||
exception => Assert.Fail("The previous attempt failed!"))
|
||||
|
||||
// previous one did not run, last run was a failure so that one SHOULD run
|
||||
// then why does it run?
|
||||
.OnFailure(() => Attempt.Succeed("finished"),
|
||||
i => Assert.AreEqual("finished", i),
|
||||
exception => Assert.Fail("Should have been successful."));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -142,6 +142,7 @@
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AttemptTests.cs" />
|
||||
<Compile Include="Auditing\AuditTests.cs" />
|
||||
<Compile Include="BootManagers\CoreBootManagerTests.cs" />
|
||||
<Compile Include="BusinessLogic\DictionaryTest.cs" />
|
||||
|
||||
Reference in New Issue
Block a user