diff --git a/src/Tranquire/ActionExtensions.cs b/src/Tranquire/ActionExtensions.cs index 5fea74fd..72de099b 100644 --- a/src/Tranquire/ActionExtensions.cs +++ b/src/Tranquire/ActionExtensions.cs @@ -1,6 +1,7 @@ using System; using System.Threading.Tasks; using Tranquire.Extensions; +using SM = Tranquire.Extensions.SelectMany; namespace Tranquire { @@ -111,12 +112,13 @@ public DiscardActionResult(IAction action) /// /// /// - /// The action which result is transformed + /// The action which result is transformed /// A transform function that returns a new action. /// - public static IAction SelectMany(this IAction action, Func> selector) + public static IAction SelectMany(this IAction source, Func> selector) { - return new SelectManyAction(action, selector); + var selectMany = SM.Create(source, SM.Execute(), selector, SM.Execute()); + return selectMany.ToAction(); } /// @@ -124,12 +126,13 @@ public static IAction SelectMany(this IAction /// /// - /// The action which result is transformed + /// The action which result is transformed /// A transform function that returns a new action. /// - public static IQuestion SelectMany(this IAction action, Func> selector) + public static IQuestion SelectMany(this IAction source, Func> selector) { - return new SelectManyActionToQuestion(action, selector); + var selectMany = SM.Create(source, SM.Execute(), selector, SM.AsksFor()); + return selectMany.ToQuestion(); } /// @@ -137,12 +140,13 @@ public static IQuestion SelectMany(this IAction /// /// - /// The action which result is transformed + /// The action which result is transformed /// A transform function that returns a new action. /// - public static IAction> SelectMany(this IAction> action, Func> selector) + public static IAction> SelectMany(this IAction> source, Func> selector) { - return new SelectManyActionAsync(action, selector); + var selectMany = SM.Create(source, SM.Execute>(), selector, SM.ExecuteAsync()); + return selectMany.ToAction(); } /// @@ -150,12 +154,26 @@ public static IAction> SelectMany(this IAction /// /// - /// The action which result is transformed + /// The action which result is transformed /// A transform function that returns a new action. /// - public static IAction> SelectMany(this IAction> action, Func>> selector) + public static IAction> SelectMany(this IAction> source, Func>> selector) { - return new SelectManyActionAsyncReturningAsync(action, selector); + var selectMany = SM.Create(source, SM.Execute>(), selector, SM.ExecuteAsync>()); + return selectMany.ToAction(); + } + + /// + /// Projects the result of an asynchronous action into a new action. + /// + /// + /// The action which result is transformed + /// A transform function that returns a new action. + /// + public static IAction SelectMany(this IAction> source, Func> selector) + { + var selectMany = SM.Create(source, SM.Execute>(), selector, SM.ExecuteAsync()); + return selectMany.ToAction(); } /// @@ -163,12 +181,13 @@ public static IAction> SelectMany(this IAction /// /// - /// The action which result is transformed + /// The action which result is transformed /// A transform function that returns a new action. /// - public static IQuestion> SelectMany(this IAction> action, Func> selector) + public static IQuestion> SelectMany(this IAction> source, Func> selector) { - return new SelectManyActionAsyncToQuestion(action, selector); + var selectMany = SM.Create(source, SM.Execute>(), selector, SM.AsksForAsync()); + return selectMany.ToQuestion(); } /// @@ -176,12 +195,77 @@ public static IQuestion> SelectMany(this IAction /// /// /// - /// The action which result is transformed + /// The action which result is transformed + /// A transform function that returns a new action. + /// + public static IQuestion> SelectMany(this IAction> source, Func>> selector) + { + var selectMany = SM.Create(source, SM.Execute>(), selector, SM.AsksForAsync>()); + return selectMany.ToQuestion(); + } + + /// + /// Projects the result of an asynchronous action into a new action. + /// + /// + /// The action which result is transformed + /// A transform function that returns a new action. + /// + public static IAction> SelectMany(this IAction source, Func> selector) + { + var selectMany = SM.Create(source, SM.Execute(), selector, SM.ExecuteAsync()); + return selectMany.ToAction(); + } + + /// + /// Projects the result of an asynchronous action into a new action. + /// + /// The action which result is transformed + /// A transform function that returns a new action. + /// + public static IAction SelectMany(this IAction source, Func> selector) + { + var selectMany = SM.Create(source, SM.Execute(), selector, SM.ExecuteAsync()); + return selectMany.ToAction(); + } + + /// + /// Projects the result of an asynchronous action into a new action. + /// + /// + /// The action which result is transformed + /// A transform function that returns a new action. + /// + public static IAction> SelectMany(this IAction source, Func>> selector) + { + var selectMany = SM.Create(source, SM.Execute(), selector, SM.ExecuteAsync>()); + return selectMany.ToAction(); + } + + /// + /// Projects the result of an asynchronous action into a new question. + /// + /// + /// The action which result is transformed + /// A transform function that returns a new action. + /// + public static IQuestion> SelectMany(this IAction source, Func> selector) + { + var selectMany = SM.Create(source, SM.Execute(), selector, SM.AsksForAsync()); + return selectMany.ToQuestion(); + } + + /// + /// Projects the result of an asynchronous action into a new question. + /// + /// + /// The action which result is transformed /// A transform function that returns a new action. /// - public static IQuestion> SelectMany(this IAction> action, Func>> selector) + public static IQuestion> SelectMany(this IAction source, Func>> selector) { - return new SelectManyActionAsyncToQuestionAsync(action, selector); + var selectMany = SM.Create(source, SM.Execute(), selector, SM.AsksForAsync>()); + return selectMany.ToQuestion(); } #endregion diff --git a/src/Tranquire/Extensions/SelectMany.cs b/src/Tranquire/Extensions/SelectMany.cs index ac83015c..9cf8c8e2 100644 --- a/src/Tranquire/Extensions/SelectMany.cs +++ b/src/Tranquire/Extensions/SelectMany.cs @@ -1,4 +1,5 @@ using System; +using System.Runtime.CompilerServices; using System.Threading.Tasks; namespace Tranquire.Extensions @@ -38,6 +39,7 @@ public TResult Apply(IActor actor) internal static class SelectMany { + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ISelectMany Create( TActionSource source, Func applySource, @@ -47,9 +49,19 @@ Func applyResult where TActionSource : class, INamed where TActionResult : class { + if (source is null) + { + throw new ArgumentNullException(nameof(source)); + } + if (selector is null) + { + throw new ArgumentNullException(nameof(selector)); + } + return new SelectMany(source, applySource, selector, applyResult); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ISelectMany> Create( TActionSource source, Func> applySource, @@ -59,6 +71,15 @@ Func, Task> applyResult where TActionSource : class, INamed where TActionResult : class { + if (source is null) + { + throw new ArgumentNullException(nameof(source)); + } + if (selector is null) + { + throw new ArgumentNullException(nameof(selector)); + } + Func, Task> selectorAsync = async sourceTask => { var s = await sourceTask; @@ -67,18 +88,101 @@ Func, Task> applyResult return Create(source, applySource, selectorAsync, applyResult); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ISelectMany> Create( + TActionSource source, + Func applySource, + Func selector, + Func, Task> applyResult + ) + where TActionSource : class, INamed + where TActionResult : class + { + if (source is null) + { + throw new ArgumentNullException(nameof(source)); + } + if (selector is null) + { + throw new ArgumentNullException(nameof(selector)); + } + + Func> selectorAsync = async sourceTask => + { + await sourceTask; + return selector(); + }; + return Create(source, applySource, selectorAsync, applyResult); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Func, T> AsksFor() => (actor, q) => actor.AsksFor(q); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Func>, Task> AsksForAsync() => async (actor, questionTask) => { var question = await questionTask; return actor.AsksFor(question); }; + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Func, T> Execute() => (actor, q) => actor.Execute(q); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Func>, Task> ExecuteAsync() => async (actor, actionTask) => { var action = await actionTask; return actor.Execute(action); }; } + + internal static class SelectManyExtensions + { + public static IAction ToAction(this ISelectMany selectMany) + { + return Actions.Create( + selectMany.Name, + actor => selectMany.Apply(actor)); + } + + public static IAction> ToAction(this ISelectMany>> selectMany) + { + return Actions.Create( + selectMany.Name, + async actor => + { + var task = await selectMany.Apply(actor); + return await task; + }); + } + + public static IAction ToAction(this ISelectMany> selectMany) + { + return Actions.Create( + selectMany.Name, + async actor => + { + var task = await selectMany.Apply(actor); + await task; + }); + } + + public static IQuestion ToQuestion(this ISelectMany selectMany) + { + return Questions.Create( + selectMany.Name, + actor => selectMany.Apply(actor)); + } + + public static IQuestion> ToQuestion(this ISelectMany>> selectMany) + { + return Questions.Create( + selectMany.Name, + async actor => + { + var task = await selectMany.Apply(actor); + return await task; + }); + } + } } diff --git a/src/Tranquire/Extensions/SelectManyAction.cs b/src/Tranquire/Extensions/SelectManyAction.cs deleted file mode 100644 index 54d512c5..00000000 --- a/src/Tranquire/Extensions/SelectManyAction.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; - -namespace Tranquire.Extensions -{ - /// - /// Represents an action which result is transform by the given selector function - /// - /// The result type of the source question - /// The result type of the selector function - internal sealed class SelectManyAction : ActionBase - { - private readonly ISelectMany _selectMany; - - /// Record Constructor - /// The question to get the result from - /// The function to apply of the question result. - public SelectManyAction(IAction action, Func> selector) - { - if (action == null) - { - throw new ArgumentNullException(nameof(action)); - } - - _selectMany = SelectMany.Create(action, SelectMany.Execute(), selector, SelectMany.Execute()); - } - - /// - public override string Name => _selectMany.Name; - - /// - protected override TResult ExecuteWhen(IActor actor) => _selectMany.Apply(actor); - } -} diff --git a/src/Tranquire/Extensions/SelectManyActionAsync.cs b/src/Tranquire/Extensions/SelectManyActionAsync.cs deleted file mode 100644 index c82bcedb..00000000 --- a/src/Tranquire/Extensions/SelectManyActionAsync.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.Threading.Tasks; - -namespace Tranquire.Extensions -{ - /// - /// Represents an asynchronous action which result is transform by the given selector function - /// - /// The result type of the source question - /// The result type of the selector function - internal sealed class SelectManyActionAsync : ActionBase> - { - private readonly ISelectMany> _selectMany; - - /// Record Constructor - /// The question to get the result from - /// The function to apply of the question result. - public SelectManyActionAsync(IAction> action, Func> selector) - { - if (action == null) - { - throw new ArgumentNullException(nameof(action)); - } - if (selector == null) - { - throw new ArgumentNullException(nameof(selector)); - } - - _selectMany = SelectMany.Create(action, SelectMany.Execute>(), selector, SelectMany.ExecuteAsync()); - } - - /// - public override string Name => _selectMany.Name; - - /// - protected override Task ExecuteWhen(IActor actor) => _selectMany.Apply(actor); - } -} diff --git a/src/Tranquire/Extensions/SelectManyActionAsyncReturningAsync.cs b/src/Tranquire/Extensions/SelectManyActionAsyncReturningAsync.cs deleted file mode 100644 index f50babcd..00000000 --- a/src/Tranquire/Extensions/SelectManyActionAsyncReturningAsync.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Threading.Tasks; - -namespace Tranquire.Extensions -{ - /// - /// Represents an asynchronous action which result is transform by the given selector function - /// - /// The result type of the source question - /// The result type of the selector function - internal sealed class SelectManyActionAsyncReturningAsync : ActionBase> - { - private readonly ISelectMany>> _selectMany; - - /// Record Constructor - /// The question to get the result from - /// The function to apply of the question result. - public SelectManyActionAsyncReturningAsync(IAction> action, Func>> selector) - { - if (action == null) - { - throw new ArgumentNullException(nameof(action)); - } - if (selector == null) - { - throw new ArgumentNullException(nameof(selector)); - } - - _selectMany = SelectMany.Create(action, SelectMany.Execute>(), selector, SelectMany.ExecuteAsync>()); - } - - /// - public override string Name => _selectMany.Name; - - /// - protected override async Task ExecuteWhen(IActor actor) - { - var resultTask = await _selectMany.Apply(actor); - return await resultTask; - } - } -} diff --git a/src/Tranquire/Extensions/SelectManyActionAsyncToQuestion.cs b/src/Tranquire/Extensions/SelectManyActionAsyncToQuestion.cs deleted file mode 100644 index cc49c41b..00000000 --- a/src/Tranquire/Extensions/SelectManyActionAsyncToQuestion.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.Threading.Tasks; - -namespace Tranquire.Extensions -{ - /// - /// Represents an action which result is transform by the given selector function - /// - /// The result type of the source action - /// The result type of the selector function - internal sealed class SelectManyActionAsyncToQuestion : QuestionBase> - { - private readonly ISelectMany> _selectMany; - - /// Creates a new instance of - /// The action to get the result from - /// The function to apply of the action result. - public SelectManyActionAsyncToQuestion(IAction> action, Func> selector) - { - if (action == null) - { - throw new ArgumentNullException(nameof(action)); - } - if (selector is null) - { - throw new ArgumentNullException(nameof(selector)); - } - - _selectMany = SelectMany.Create(action, SelectMany.Execute>(), selector, SelectMany.AsksForAsync()); - } - - /// - public override string Name => _selectMany.Name; - - /// - protected override Task Answer(IActor actor) => _selectMany.Apply(actor); - } -} diff --git a/src/Tranquire/Extensions/SelectManyActionAsyncToQuestionAsync.cs b/src/Tranquire/Extensions/SelectManyActionAsyncToQuestionAsync.cs deleted file mode 100644 index 2ffd2677..00000000 --- a/src/Tranquire/Extensions/SelectManyActionAsyncToQuestionAsync.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Threading.Tasks; - -namespace Tranquire.Extensions -{ - /// - /// Represents an action which result is transform by the given selector function - /// - /// The result type of the source action - /// The result type of the selector function - internal sealed class SelectManyActionAsyncToQuestionAsync : QuestionBase> - { - private readonly ISelectMany>> _selectMany; - - /// Creates a new instance of - /// The action to get the result from - /// The function to apply of the action result. - public SelectManyActionAsyncToQuestionAsync(IAction> action, Func>> selector) - { - if (action == null) - { - throw new ArgumentNullException(nameof(action)); - } - if (selector is null) - { - throw new ArgumentNullException(nameof(selector)); - } - - _selectMany = SelectMany.Create(action, SelectMany.Execute>(), selector, SelectMany.AsksForAsync>()); - } - - /// - public override string Name => _selectMany.Name; - - /// - protected override async Task Answer(IActor actor) - { - var questionTask = await _selectMany.Apply(actor); - return await questionTask; - } - } -} diff --git a/src/Tranquire/Extensions/SelectManyActionToQuestion.cs b/src/Tranquire/Extensions/SelectManyActionToQuestion.cs deleted file mode 100644 index 252f9acb..00000000 --- a/src/Tranquire/Extensions/SelectManyActionToQuestion.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; - -namespace Tranquire.Extensions -{ - /// - /// Represents an action which result is transform by the given selector function - /// - /// The result type of the source action - /// The result type of the selector function - internal sealed class SelectManyActionToQuestion : QuestionBase - { - private readonly ISelectMany _selectMany; - - /// Creates a new instance of - /// The action to get the result from - /// The function to apply of the action result. - public SelectManyActionToQuestion(IAction action, Func> selector) - { - if (action == null) - { - throw new ArgumentNullException(nameof(action)); - } - - _selectMany = SelectMany.Create(action, SelectMany.Execute(), selector, SelectMany.AsksFor()); - } - - /// - public override string Name => _selectMany.Name; - - /// - protected override TResult Answer(IActor actor) => _selectMany.Apply(actor); - } -} diff --git a/src/Tranquire/Extensions/SelectManyQuestion.cs b/src/Tranquire/Extensions/SelectManyQuestion.cs deleted file mode 100644 index d696a48d..00000000 --- a/src/Tranquire/Extensions/SelectManyQuestion.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; - -namespace Tranquire.Extensions -{ - /// - /// Represents a question which result is transform by the given selector function - /// - /// The result type of the source question - /// The result type of the selector function - internal sealed class SelectManyQuestion : QuestionBase - { - private readonly ISelectMany _selectMany; - - /// Record Constructor - /// The question to get the result from - /// The function to apply of the question result. - public SelectManyQuestion(IQuestion question, Func> selector) - { - if (question == null) - { - throw new ArgumentNullException(nameof(question)); - } - - _selectMany = SelectMany.Create(question, SelectMany.AsksFor(), selector, SelectMany.AsksFor()); - } - - /// - public override string Name => _selectMany.Name; - - /// - protected override TResult Answer(IActor actor) => _selectMany.Apply(actor); - } -} diff --git a/src/Tranquire/Extensions/SelectManyQuestionAsync.cs b/src/Tranquire/Extensions/SelectManyQuestionAsync.cs deleted file mode 100644 index 757491f6..00000000 --- a/src/Tranquire/Extensions/SelectManyQuestionAsync.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.Threading.Tasks; - -namespace Tranquire.Extensions -{ - /// - /// Represents a question which result is transform by the given selector function - /// - /// The result type of the source question - /// The result type of the selector function - internal sealed class SelectManyQuestionAsync : QuestionBase> - { - private readonly ISelectMany> _selectMany; - - /// Record Constructor - /// The question to get the result from - /// The function to apply of the question result. - public SelectManyQuestionAsync(IQuestion> question, Func> selector) - { - if (question == null) - { - throw new ArgumentNullException(nameof(question)); - } - if (selector is null) - { - throw new ArgumentNullException(nameof(selector)); - } - - _selectMany = SelectMany.Create(question, SelectMany.AsksFor>(), selector, SelectMany.AsksForAsync()); - } - - /// - public override string Name => _selectMany.Name; - - /// - protected override Task Answer(IActor actor) => _selectMany.Apply(actor); - } -} diff --git a/src/Tranquire/Extensions/SelectManyQuestionAsyncReturningAsync.cs b/src/Tranquire/Extensions/SelectManyQuestionAsyncReturningAsync.cs deleted file mode 100644 index aa54c3cf..00000000 --- a/src/Tranquire/Extensions/SelectManyQuestionAsyncReturningAsync.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Threading.Tasks; - -namespace Tranquire.Extensions -{ - /// - /// Represents a question which result is transform by the given selector function - /// - /// The result type of the source question - /// The result type of the selector function - internal sealed class SelectManyQuestionAsyncReturningAsync : QuestionBase> - { - private readonly ISelectMany>> _selectMany; - - /// Record Constructor - /// The question to get the result from - /// The function to apply of the question result. - public SelectManyQuestionAsyncReturningAsync(IQuestion> question, Func>> selector) - { - if (question == null) - { - throw new ArgumentNullException(nameof(question)); - } - if (selector is null) - { - throw new ArgumentNullException(nameof(selector)); - } - - _selectMany = SelectMany.Create(question, SelectMany.AsksFor>(), selector, SelectMany.AsksForAsync>()); - } - - /// - public override string Name => _selectMany.Name; - - /// - protected override async Task Answer(IActor actor) - { - var resultTask = await _selectMany.Apply(actor); - return await resultTask; - } - } -} diff --git a/src/Tranquire/Extensions/SelectManyQuestionAsyncToAction.cs b/src/Tranquire/Extensions/SelectManyQuestionAsyncToAction.cs deleted file mode 100644 index d051cff8..00000000 --- a/src/Tranquire/Extensions/SelectManyQuestionAsyncToAction.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.Threading.Tasks; - -namespace Tranquire.Extensions -{ - /// - /// Represents a question which result is transform by the given selector function - /// - /// The result type of the source question - /// The result type of the selector function - internal sealed class SelectManyQuestionAsyncToAction : Tranquire.ActionBase> - { - private readonly ISelectMany> _selectMany; - - /// Record Constructor - /// The question to get the result from - /// The function to apply of the question result. - public SelectManyQuestionAsyncToAction(IQuestion> question, Func> selector) - { - if (question == null) - { - throw new ArgumentNullException(nameof(question)); - } - if (selector is null) - { - throw new ArgumentNullException(nameof(selector)); - } - - _selectMany = SelectMany.Create(question, SelectMany.AsksFor>(), selector, SelectMany.ExecuteAsync()); - } - - /// - public override string Name => _selectMany.Name; - - /// - protected override TaskExecuteWhen(IActor actor) => _selectMany.Apply(actor); - } -} diff --git a/src/Tranquire/Extensions/SelectManyQuestionAsyncToActionAsync.cs b/src/Tranquire/Extensions/SelectManyQuestionAsyncToActionAsync.cs deleted file mode 100644 index 1eda315b..00000000 --- a/src/Tranquire/Extensions/SelectManyQuestionAsyncToActionAsync.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Threading.Tasks; - -namespace Tranquire.Extensions -{ - /// - /// Represents a question which result is transform by the given selector function - /// - /// The result type of the source question - /// The result type of the selector function - internal sealed class SelectManyQuestionAsyncToActionAsync : Tranquire.ActionBase> - { - private readonly ISelectMany>> _selectMany; - - /// Record Constructor - /// The question to get the result from - /// The function to apply of the question result. - public SelectManyQuestionAsyncToActionAsync(IQuestion> question, Func>> selector) - { - if (question == null) - { - throw new ArgumentNullException(nameof(question)); - } - if (selector is null) - { - throw new ArgumentNullException(nameof(selector)); - } - - _selectMany = SelectMany.Create(question, SelectMany.AsksFor>(), selector, SelectMany.ExecuteAsync>()); - } - - /// - public override string Name => _selectMany.Name; - - /// - protected override async Task ExecuteWhen(IActor actor) - { - var resultTask = await _selectMany.Apply(actor); - return await resultTask; - } - } -} diff --git a/src/Tranquire/Extensions/SelectManyQuestionToAction.cs b/src/Tranquire/Extensions/SelectManyQuestionToAction.cs deleted file mode 100644 index 6e491227..00000000 --- a/src/Tranquire/Extensions/SelectManyQuestionToAction.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; - -namespace Tranquire.Extensions -{ - /// - /// Represents a question which result is transform by the given selector function - /// - /// The result type of the source question - /// The result type of the selector function - internal sealed class SelectManyQuestionToAction : Tranquire.ActionBase - { - private readonly ISelectMany _selectMany; - - /// Record Constructor - /// The question to get the result from - /// The function to apply of the question result. - public SelectManyQuestionToAction(IQuestion question, Func> selector) - { - if (question == null) - { - throw new ArgumentNullException(nameof(question)); - } - - _selectMany = SelectMany.Create(question, SelectMany.AsksFor(), selector, SelectMany.Execute()); - } - - /// - public override string Name => _selectMany.Name; - - /// - protected override TResult ExecuteWhen(IActor actor) => _selectMany.Apply(actor); - } -} diff --git a/src/Tranquire/QuestionExtensions.cs b/src/Tranquire/QuestionExtensions.cs index 27a8f1dc..d14c19d6 100644 --- a/src/Tranquire/QuestionExtensions.cs +++ b/src/Tranquire/QuestionExtensions.cs @@ -1,6 +1,7 @@ using System; using System.Threading.Tasks; using Tranquire.Extensions; +using SM = Tranquire.Extensions.SelectMany; namespace Tranquire { @@ -61,12 +62,13 @@ public static IQuestion> Select(this IQuestion /// /// - /// The question which result is transformed + /// The question which result is transformed /// A transform function that returns a new question. /// - public static IQuestion SelectMany(this IQuestion question, Func> selector) + public static IQuestion SelectMany(this IQuestion source, Func> selector) { - return new SelectManyQuestion(question, selector); + var selectMany = SM.Create(source, SM.AsksFor(), selector, SM.AsksFor()); + return selectMany.ToQuestion(); } /// @@ -74,12 +76,13 @@ public static IQuestion SelectMany(this IQuestion /// /// - /// The question which result is transformed + /// The question which result is transformed /// A transform function that returns a new action. /// - public static IAction SelectMany(this IQuestion question, Func> selector) + public static IAction SelectMany(this IQuestion source, Func> selector) { - return new SelectManyQuestionToAction(question, selector); + var selectMany = SM.Create(source, SM.AsksFor(), selector, SM.Execute()); + return selectMany.ToAction(); } /// @@ -87,12 +90,13 @@ public static IAction SelectMany(this IQuestion /// /// - /// The question which result is transformed + /// The question which result is transformed /// A transform function that returns a new question. /// - public static IQuestion> SelectMany(this IQuestion> question, Func> selector) + public static IQuestion> SelectMany(this IQuestion> source, Func> selector) { - return new SelectManyQuestionAsync(question, selector); + var selectMany = SM.Create(source, SM.AsksFor>(), selector, SM.AsksForAsync()); + return selectMany.ToQuestion(); } /// @@ -100,12 +104,13 @@ public static IQuestion> SelectMany(this IQuesti /// /// /// - /// The question which result is transformed + /// The question which result is transformed /// A transform function that returns a new question. /// - public static IQuestion> SelectMany(this IQuestion> question, Func>> selector) + public static IQuestion> SelectMany(this IQuestion> source, Func>> selector) { - return new SelectManyQuestionAsyncReturningAsync(question, selector); + var selectMany = SM.Create(source, SM.AsksFor>(), selector, SM.AsksForAsync>()); + return selectMany.ToQuestion(); } /// @@ -113,12 +118,13 @@ public static IQuestion> SelectMany(this IQuesti /// /// /// - /// The question which result is transformed + /// The question which result is transformed /// A transform function that returns a new action. /// - public static IAction> SelectMany(this IQuestion> question, Func> selector) + public static IAction> SelectMany(this IQuestion> source, Func> selector) { - return new SelectManyQuestionAsyncToAction(question, selector); + var selectMany = SM.Create(source, SM.AsksFor>(), selector, SM.ExecuteAsync()); + return selectMany.ToAction(); } /// @@ -126,12 +132,26 @@ public static IAction> SelectMany(this IQuestion /// /// /// - /// The question which result is transformed + /// The question which result is transformed + /// A transform function that returns a new action. + /// + public static IAction> SelectMany(this IQuestion> source, Func>> selector) + { + var selectMany = SM.Create(source, SM.AsksFor>(), selector, SM.ExecuteAsync>()); + return selectMany.ToAction(); + } + + /// + /// Projects the result of an asynchronous question into a new asynchronous action. + /// + /// + /// The question which result is transformed /// A transform function that returns a new action. /// - public static IAction> SelectMany(this IQuestion> question, Func>> selector) + public static IAction SelectMany(this IQuestion> source, Func> selector) { - return new SelectManyQuestionAsyncToActionAsync(question, selector); + var selectMany = SM.Create(source, SM.AsksFor>(), selector, SM.ExecuteAsync()); + return selectMany.ToAction(); } #endregion diff --git a/tests/ToDoList.Specifications/Setup.cs b/tests/ToDoList.Specifications/Setup.cs index 3f584d35..aea26324 100644 --- a/tests/ToDoList.Specifications/Setup.cs +++ b/tests/ToDoList.Specifications/Setup.cs @@ -3,7 +3,6 @@ using Microsoft.AspNetCore.TestHost; using OpenQA.Selenium.Chrome; using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.IO; @@ -19,7 +18,6 @@ using Tranquire.Reporting; using Tranquire.Selenium; using Tranquire.Selenium.Extensions; -using static Microsoft.AspNetCore.Hosting.Internal.HostingApplication; namespace ToDoList.Specifications { diff --git a/tests/Tranquire.Tests/Extensions/ActionExtensionsTests.cs b/tests/Tranquire.Tests/Extensions/ActionExtensionsTests.cs index 501b8d2b..7457dc8a 100644 --- a/tests/Tranquire.Tests/Extensions/ActionExtensionsTests.cs +++ b/tests/Tranquire.Tests/Extensions/ActionExtensionsTests.cs @@ -1,11 +1,11 @@ -using FluentAssertions; -using Moq; -using AutoFixture; +using AutoFixture; using AutoFixture.Idioms; +using FluentAssertions; +using Moq; using System; +using System.Threading.Tasks; using Tranquire.Extensions; using Xunit; -using System.Threading.Tasks; namespace Tranquire.Tests.Extensions { @@ -86,7 +86,7 @@ public void Using_ShouldReturnCorrectValue(IAction disposableAction } #endregion - #region SelectMany - action + #region SelectMany: IAction -> IAction [Theory, DomainAutoData] public void SelectMany_ShouldReturnCorrectResult( int value1, @@ -136,7 +136,7 @@ public void SelectMany_Name_ShouldReturnCorrectResult( } #endregion - #region SelectMany - action to question + #region SelectMany: IAction -> IQuestion [Theory, DomainAutoData] public void SelectMany_ReturningQuestion_ShouldReturnCorrectResult( int value1, @@ -168,7 +168,7 @@ public void SelectMany_ReturningQuestion_Name_ShouldReturnCorrectResult( } #endregion - #region SelectMany - action async + #region SelectMany: IAction> -> IAction [Theory, DomainAutoData] public async Task SelectMany_Async_ShouldReturnCorrectResult( int value1, @@ -218,7 +218,7 @@ public void SelectMany_Async_Name_ShouldReturnCorrectResult( } #endregion - #region SelectMany - action async returning async action + #region SelectMany: IAction> -> IAction> [Theory, DomainAutoData] public async Task SelectMany_Async_ReturningAsyncAction_ShouldReturnCorrectResult( int value1, @@ -268,7 +268,41 @@ public void SelectMany_Async_Name_ReturningAsyncAction_ShouldReturnCorrectResult } #endregion - #region SelectMany - action to question async + #region SelectMany: IAction> -> IAction + [Theory, DomainAutoData] + public async Task SelectMany_Async_ReturningAsyncTaskAction_ShouldReturnCorrectResult( + int value1, + int value2) + { + // arrange + var actor = new Actor("John"); + var actual = 0; + var action = Actions.FromResult(Task.FromResult(value1)) + .SelectMany(v => Actions.Create("set result", _ => Delay(() => { actual = v + value2; }))); + // act + var task = actor.When(action); + await task; + // assert + var expected = value1 + value2; + Assert.Equal(expected, actual); + } + + [Theory, DomainAutoData] + public void SelectMany_Async_Name_ReturningAsyncTaskAction_ShouldReturnCorrectResult( + IAction> action1, + IAction action2) + { + // arrange + var action = action1.SelectMany(_ => action2); + // act + var actual = action.Name; + // assert + var expected = "[SelectMany] " + action1.Name; + Assert.Equal(expected, actual); + } + #endregion + + #region SelectMany: IAction> -> IQuestion [Theory, DomainAutoData] public async Task SelectMany_Async_ReturningQuestion_ShouldReturnCorrectResult( int value1, @@ -300,7 +334,7 @@ public void SelectMany_Async_Name_ReturningQuestion_ShouldReturnCorrectResult( } #endregion - #region SelectMany - action async returning async question + #region SelectMany: IAction> -> IQuestion> [Theory, DomainAutoData] public async Task SelectMany_Async_ReturningAsyncQuestion_ShouldReturnCorrectResult( int value1, @@ -332,6 +366,185 @@ public void SelectMany_Async_Name_ReturningAsyncQuestion_ShouldReturnCorrectResu } #endregion + #region SelectMany: IAction -> IAction + [Theory, DomainAutoData] + public async Task SelectMany_AsyncTask_ShouldReturnCorrectResult( + int value1, + int value2) + { + // arrange + var actor = new Actor("John"); + var currentValue = 0; + var action = Actions.Create("set value", _ => Delay(() => currentValue = value1)) + .SelectMany(() => Actions.FromResult(currentValue + value2)); + // act + var actual = await actor.When(action); + // assert + var expected = value1 + value2; + Assert.Equal(expected, actual); + } + + [Theory, DomainAutoData] + public void SelectMany_AsyncTask_Name_ShouldReturnCorrectResult( + IAction action1, + IAction action2) + { + // arrange + var action = action1.SelectMany(() => action2); + // act + var actual = action.Name; + // assert + var expected = "[SelectMany] " + action1.Name; + Assert.Equal(expected, actual); + } + #endregion + + #region SelectMany: IAction -> IAction> + [Theory, DomainAutoData] + public async Task SelectMany_Async_Task_ReturningAsyncAction_ShouldReturnCorrectResult( + int value1, + int value2) + { + // arrange + var actor = new Actor("John"); + var currentResult = 0; + var action = Actions.FromResult(Delay(() => { currentResult = value1; })) + .SelectMany(() => Actions.FromResult(Task.FromResult(currentResult + value2))); + // act + var actual = await actor.When(action); + // assert + var expected = value1 + value2; + Assert.Equal(expected, actual); + } + + [Theory, DomainAutoData] + public void SelectMany_Async_Task_Name_ReturningAsyncAction_ShouldReturnCorrectResult( + IAction action1, + IAction> action2) + { + // arrange + var action = action1.SelectMany(() => action2); + // act + var actual = action.Name; + // assert + var expected = "[SelectMany] " + action1.Name; + Assert.Equal(expected, actual); + } + #endregion + + #region SelectMany: IAction -> IAction + [Theory, DomainAutoData] + public async Task SelectMany_Async_Task_ReturningAsyncTaskAction_ShouldReturnCorrectResult( + int value1, + int value2) + { + // arrange + var actor = new Actor("John"); + var result = 0; + var action = Actions.FromResult(Delay(() => { result = value1; })) + .SelectMany(() => Actions.FromResult(Delay(() => { result += value2; }))); + // act + var task = actor.When(action); + await task; + var actual = result; + // assert + var expected = value1 + value2; + Assert.Equal(expected, actual); + } + + [Theory, DomainAutoData] + public void SelectMany_Async_Task_Name_ReturningAsyncTaskAction_ShouldReturnCorrectResult( + IAction action1, + IAction action2) + { + // arrange + var action = action1.SelectMany(() => action2); + // act + var actual = action.Name; + // assert + var expected = "[SelectMany] " + action1.Name; + Assert.Equal(expected, actual); + } + #endregion + + #region SelectMany: IAction -> IQuestion + [Theory, DomainAutoData] + public async Task SelectMany_Async_Task_ReturningQuestion_ShouldReturnCorrectResult( + int value1, + int value2) + { + // arrange + var actor = new Actor("John"); + var currentResult = 0; + var question = Actions.FromResult(Delay(() => { currentResult = value1; })) + .SelectMany(() => Questions.FromResult(currentResult + value2)); + // act + var actual = await actor.AsksFor(question); + // assert + var expected = value1 + value2; + Assert.Equal(expected, actual); + } + + [Theory, DomainAutoData] + public void SelectMany_Async_Task_Name_ReturningQuestion_ShouldReturnCorrectResult( + IAction action1, + IQuestion question2) + { + // arrange + var question = action1.SelectMany(() => question2); + // act + var actual = question.Name; + // assert + var expected = "[SelectMany] " + action1.Name; + Assert.Equal(expected, actual); + } + #endregion + + #region SelectMany: IAction -> IQuestion> + [Theory, DomainAutoData] + public async Task SelectMany_Async_Task_ReturningQuestionAsync_ShouldReturnCorrectResult( + int value1, + int value2) + { + // arrange + var actor = new Actor("John"); + var currentResult = 0; + var question = Actions.FromResult(Delay(() => { currentResult = value1; })) + .SelectMany(() => Questions.FromResult(Delay(() => currentResult + value2))); + // act + var actual = await actor.AsksFor(question); + // assert + var expected = value1 + value2; + Assert.Equal(expected, actual); + } + + [Theory, DomainAutoData] + public void SelectMany_Async_Task_Name_ReturningQuestionAsync_ShouldReturnCorrectResult( + IAction action1, + IQuestion> question2) + { + // arrange + var question = action1.SelectMany(() => question2); + // act + var actual = question.Name; + // assert + var expected = "[SelectMany] " + action1.Name; + Assert.Equal(expected, actual); + } + #endregion + + private static async Task Delay(Action action) + { + await Task.Delay(1); + action(); + } + + private static async Task Delay(Func action) + { + await Task.Delay(1); + return action(); + } + #region Select [Theory, DomainAutoData] public void Select_ShouldReturnCorrectResult(IAction action, Func selector) diff --git a/tests/Tranquire.Tests/QuestionExtensionsTests.cs b/tests/Tranquire.Tests/Extensions/QuestionExtensionsTests.cs similarity index 71% rename from tests/Tranquire.Tests/QuestionExtensionsTests.cs rename to tests/Tranquire.Tests/Extensions/QuestionExtensionsTests.cs index 14ff3168..59f26184 100644 --- a/tests/Tranquire.Tests/QuestionExtensionsTests.cs +++ b/tests/Tranquire.Tests/Extensions/QuestionExtensionsTests.cs @@ -1,12 +1,12 @@ -using FluentAssertions; -using AutoFixture.Idioms; +using AutoFixture.Idioms; +using FluentAssertions; +using Moq; using System; +using System.Threading.Tasks; using Tranquire.Extensions; using Xunit; -using Moq; -using System.Threading.Tasks; -namespace Tranquire.Tests +namespace Tranquire.Tests.Extensions { public class QuestionExtensionsTests { @@ -52,7 +52,7 @@ public void Select_Async_WithAsyncFunc_ShouldReturnCorrectResult(IQuestion -> IQuestion [Theory, DomainAutoData] public void SelectMany_ShouldReturnCorrectResult( int value1, @@ -101,8 +101,40 @@ public void SelectMany_Name_ShouldReturnCorrectResult( Assert.Equal(expected, actual); } #endregion + + #region SelectMany: IQuestion -> IQuestion> + [Theory, DomainAutoData] + public async Task SelectMany_ReturningAsyncQuestion_ShouldReturnCorrectResult( + int value1, + int value2) + { + // arrange + var question = Questions.FromResult(value1) + .SelectMany(v => Questions.FromResult(Delay(() => v + value2))); + var actor = new Actor("john"); + // act + var actual = await actor.AsksFor(question); + // assert + var expected = value1 + value2; + Assert.Equal(expected, actual); + } - #region SelectMany - question to action + [Theory, DomainAutoData] + public void SelectMany_Name_ReturningAsyncQuestion_ShouldReturnCorrectResult( + IQuestion question1, + IQuestion> question2) + { + // arrange + var question = question1.SelectMany(_ => question2); + // act + var actual = question.Name; + // assert + var expected = "[SelectMany] " + question1.Name; + Assert.Equal(expected, actual); + } + #endregion + + #region SelectMany: IQuestion -> IAction [Theory, DomainAutoData] public void SelectMany_ReturningAction_ShouldReturnCorrectResult( int value1, @@ -120,7 +152,7 @@ public void SelectMany_ReturningAction_ShouldReturnCorrectResult( } [Theory, DomainAutoData] - public void SelectMany_ReturningQuestion_Name_ShouldReturnCorrectResult( + public void SelectMany_ReturningAction_Name_ShouldReturnCorrectResult( IQuestion question1, IAction action2) { @@ -134,7 +166,42 @@ public void SelectMany_ReturningQuestion_Name_ShouldReturnCorrectResult( } #endregion - #region SelectMany - question async + #region SelectMany: IQuestion -> IAction + [Theory, DomainAutoData] + public async Task SelectMany_ReturningActionAsyncTask_ShouldReturnCorrectResult( + int value1, + int value2) + { + // arrange + var result = 0; + var action = Questions.FromResult(value1) + .SelectMany(v => Actions.FromResult(Delay(() => { result = v + value2; }))); + var actor = new Actor("john"); + // act + var task = actor.When(action); + await task; + var actual = result; + // assert + var expected = value1 + value2; + Assert.Equal(expected, actual); + } + + [Theory, DomainAutoData] + public void SelectMany_ReturningActionAsyncTask_Name_ShouldReturnCorrectResult( + IQuestion question1, + IAction action2) + { + // arrange + var action = question1.SelectMany(_ => action2); + // act + var actual = action.Name; + // assert + var expected = "[SelectMany] " + question1.Name; + Assert.Equal(expected, actual); + } + #endregion + + #region SelectMany: IQuestion> -> IQuestion [Theory, DomainAutoData] public async Task SelectMany_Async_ShouldReturnCorrectResult( int value1, @@ -184,7 +251,7 @@ public void SelectMany_Async_Name_ShouldReturnCorrectResult( } #endregion - #region SelectMany - question async returning async question + #region SelectMany: IQuestion> -> IQuestion> [Theory, DomainAutoData] public async Task SelectMany_Async_ReturningAsyncQuestion_ShouldReturnCorrectResult( int value1, @@ -234,7 +301,7 @@ public void SelectMany_Async_Name_ReturningAsyncQuestion_ShouldReturnCorrectResu } #endregion - #region SelectMany - question to action async + #region SelectMany: IQuestion> -> IAction [Theory, DomainAutoData] public async Task SelectMany_Async_ReturningAction_ShouldReturnCorrectResult( int value1, @@ -266,7 +333,7 @@ public void SelectMany_Async_Name_ReturningAction_ShouldReturnCorrectResult( } #endregion - #region SelectMany - question async returning async action + #region SelectMany: IQuestion> -> IAction> [Theory, DomainAutoData] public async Task SelectMany_Async_ReturningAsyncAction_ShouldReturnCorrectResult( int value1, @@ -298,6 +365,53 @@ public void SelectMany_Async_Name_ReturningAsyncAction_ShouldReturnCorrectResult } #endregion + #region SelectMany: IQuestion> -> IAction + [Theory, DomainAutoData] + public async Task SelectMany_Async_ReturningAsyncActionTask_ShouldReturnCorrectResult( + int value1, + int value2) + { + // arrange + var result = 0; + var action = Questions.FromResult(Task.FromResult(value1)) + .SelectMany(v => Actions.Create("set result", _ => Delay(() => { result = v + value2; }))); + var actor = new Actor("john"); + // act + var task = actor.When(action); + await task; + var actual = result; + // assert + var expected = value1 + value2; + Assert.Equal(expected, actual); + } + + [Theory, DomainAutoData] + public void SelectMany_Async_Name_ReturningAsyncActionTask_ShouldReturnCorrectResult( + IQuestion> question1, + IAction action2) + { + // arrange + var action = question1.SelectMany((int _) => action2); + // act + var actual = action.Name; + // assert + var expected = "[SelectMany] " + question1.Name; + Assert.Equal(expected, actual); + } + #endregion + + private static async Task Delay(Action action) + { + await Task.Delay(1); + action(); + } + + private static async Task Delay(Func action) + { + await Task.Delay(1); + return action(); + } + #region Tagged [Theory, DomainAutoData] public void Tagged_ShouldReturnCorrectValue(IQuestion question, string tag)