From 82f81d1f4f470198d2fa0159bb18657355c71959 Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 11 Sep 2013 09:28:01 +0200 Subject: [PATCH] Core.Attempt - backport and refactor Attempt.Outcome from v7 --- src/Umbraco.Core/Attempt.cs | 110 +++++++++++++++++++++++++ src/Umbraco.Tests/AttemptTests.cs | 41 +++++++++ src/Umbraco.Tests/Umbraco.Tests.csproj | 1 + 3 files changed, 152 insertions(+) create mode 100644 src/Umbraco.Tests/AttemptTests.cs diff --git a/src/Umbraco.Core/Attempt.cs b/src/Umbraco.Core/Attempt.cs index f87c46c6a3..ca2bbe35fe 100644 --- a/src/Umbraco.Core/Attempt.cs +++ b/src/Umbraco.Core/Attempt.cs @@ -52,5 +52,115 @@ namespace Umbraco.Core { return Attempt.SucceedIf(success, result); } + + + /// + /// Executes an attempt function, with callbacks. + /// + /// The type of the attempted operation result. + /// The attempt returned by the attempt function. + /// An action to execute in case the attempt succeeds. + /// An action to execute in case the attempt fails. + /// The outcome of the attempt. + /// Runs or depending on the + /// whether the attempt function reports a success or a failure. + public static Outcome Try(Attempt attempt, Action onSuccess, Action onFail = null) + { + if (attempt.Success) + { + onSuccess(attempt.Result); + return Outcome.Success; + } + + if (onFail != null) + { + onFail(attempt.Exception); + } + + return Outcome.Failure; + } + + /// + /// Represents the outcome of an attempt. + /// + /// Can be a success or a failure, and allows for attempts chaining. + public struct Outcome + { + private readonly bool _success; + + /// + /// Gets an outcome representing a success. + /// + public static readonly Outcome Success = new Outcome(true); + + /// + /// Gets an outcome representing a failure. + /// + public static readonly Outcome Failure = new Outcome(false); + + private Outcome(bool success) + { + _success = success; + } + + /// + /// Executes another attempt function, if the previous one failed, with callbacks. + /// + /// The type of the attempted operation result. + /// The attempt function to execute, returning an attempt. + /// An action to execute in case the attempt succeeds. + /// An action to execute in case the attempt fails. + /// If it executes, returns the outcome of the attempt, else returns a success outcome. + /// + /// Executes only if the previous attempt failed, else does not execute and return a success outcome. + /// If it executes, then runs or depending on the + /// whether the attempt function reports a success or a failure. + /// + public Outcome OnFailure(Func> nextFunction, Action onSuccess, Action onFail = null) + { + return _success + ? Success + : ExecuteNextFunction(nextFunction, onSuccess, onFail); + } + + /// + /// Executes another attempt function, if the previous one succeeded, with callbacks. + /// + /// The type of the attempted operation result. + /// The attempt function to execute, returning an attempt. + /// An action to execute in case the attempt succeeds. + /// An action to execute in case the attempt fails. + /// If it executes, returns the outcome of the attempt, else returns a failed outcome. + /// + /// Executes only if the previous attempt succeeded, else does not execute and return a success outcome. + /// If it executes, then runs or depending on the + /// whether the attempt function reports a success or a failure. + /// + public Outcome OnSuccess(Func> nextFunction, Action onSuccess, Action onFail = null) + { + return _success + ? ExecuteNextFunction(nextFunction, onSuccess, onFail) + : Failure; + } + + private static Outcome ExecuteNextFunction(Func> nextFunction, Action onSuccess, Action onFail = null) + { + var attempt = nextFunction(); + + if (attempt.Success) + { + onSuccess(attempt.Result); + return Success; + } + + if (onFail != null) + { + onFail(attempt.Exception); + } + + return Failure; + } + } + } } \ No newline at end of file diff --git a/src/Umbraco.Tests/AttemptTests.cs b/src/Umbraco.Tests/AttemptTests.cs new file mode 100644 index 0000000000..04da490664 --- /dev/null +++ b/src/Umbraco.Tests/AttemptTests.cs @@ -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.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.")); + } + } +} diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index e9ac0dbc8f..bca5360d84 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -142,6 +142,7 @@ +