diff --git a/src/Examples/Example.Random/AsyncSpecificationsValueTask.cs b/src/Examples/Example.Random/AsyncSpecificationsValueTask.cs new file mode 100644 index 00000000..7eae7c6b --- /dev/null +++ b/src/Examples/Example.Random/AsyncSpecificationsValueTask.cs @@ -0,0 +1,40 @@ +using System.Threading.Tasks; +using Machine.Specifications; + +#if !NET45 +namespace Example.Random +{ + public class AsyncSpecificationsValueTask + { + public static int establish_value; + + public static int because_value; + + public static int async_it_value; + + public static int sync_it_value; + + public static int cleanup_value; + + public static ValueTask Test() + { + return new ValueTask(10); + } + + Establish context = async () => + establish_value = await Test(); + + Because of = async () => + because_value = await Test(); + + It should_invoke_sync = () => + sync_it_value = Test().Result; + + It should_invoke_async = async () => + async_it_value = await Test(); + + Cleanup after = async () => + cleanup_value = await Test(); + } +} +#endif diff --git a/src/Machine.Specifications.Specs/CatchSpecs.cs b/src/Machine.Specifications.Specs/CatchSpecs.cs index fa633f7a..f7436716 100644 --- a/src/Machine.Specifications.Specs/CatchSpecs.cs +++ b/src/Machine.Specifications.Specs/CatchSpecs.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using FluentAssertions; @@ -125,7 +126,52 @@ public class with_a_non_throwing_Action () => ActionSideEffect.Should().Be("hi"); It should_return_null = - () => Result.Should().BeNull(); + () => Result.Should().BeNull(); + } } - } -} \ No newline at end of file + + [Subject(typeof(Catch))] + public class when_calling_catch_with_async_methods + { + static Exception exception; + + [Subject(typeof(Catch))] + public class with_a_non_throwing_action + { + static Task Test() => Task.Run(() => { }); + + Because of = async () => + exception = await Catch.ExceptionAsync(Test); + + It should_return_null = () => + exception.Should().BeNull(); + } + + [Subject(typeof(Catch))] + public class with_a_throwing_action + { + static Task Test() => Task.Run(() => throw new ArgumentNullException()); + + Because of = async () => + exception = await Catch.ExceptionAsync(Test); + + It should_return_exception = () => + exception.Should().BeOfType(); + } + + [Subject(typeof(Catch))] + public class calling_wrong_catch_method + { + static Task Test() => Task.Run(() => throw new ArgumentNullException()); + + Because of = () => + exception = Catch.Exception(() => Catch.Exception(Test)); + + It should_return_exception = () => + exception.Should().BeOfType(); + + It should_contain_message = () => + exception.Message.Should().Be("You must use Catch.ExceptionAsync for async methods"); + } + } +} diff --git a/src/Machine.Specifications.Specs/Runner/AsyncDelegateRunnerSpecs.cs b/src/Machine.Specifications.Specs/Runner/AsyncDelegateRunnerSpecs.cs index be3abfe8..51744149 100644 --- a/src/Machine.Specifications.Specs/Runner/AsyncDelegateRunnerSpecs.cs +++ b/src/Machine.Specifications.Specs/Runner/AsyncDelegateRunnerSpecs.cs @@ -69,4 +69,37 @@ public class when_running_async_specifications_with_exceptions : RunnerSpecs It should_have_failures = () => results.Should().Match(x => x.All(y => !y.Passed)); } + +#if NETCOREAPP + [Subject("Async Delegate Runner")] + public class when_running_async_value_task_specifications : RunnerSpecs + { + Establish context = () => + { + AsyncSpecificationsValueTask.establish_value = 0; + AsyncSpecificationsValueTask.because_value = 0; + AsyncSpecificationsValueTask.async_it_value = 0; + AsyncSpecificationsValueTask.sync_it_value = 0; + AsyncSpecificationsValueTask.cleanup_value = 0; + }; + + Because of = () => + Run(); + + It should_call_establish = () => + AsyncSpecificationsValueTask.establish_value.Should().Be(10); + + It should_call_because = () => + AsyncSpecificationsValueTask.because_value.Should().Be(10); + + It should_call_async_spec = () => + AsyncSpecificationsValueTask.async_it_value.Should().Be(10); + + It should_call_sync_spec = () => + AsyncSpecificationsValueTask.sync_it_value.Should().Be(10); + + It should_call_cleanup = () => + AsyncSpecificationsValueTask.cleanup_value.Should().Be(10); + } +#endif } diff --git a/src/Machine.Specifications.Specs/TaskSpecificationExtensionsSpecs.cs b/src/Machine.Specifications.Specs/TaskSpecificationExtensionsSpecs.cs index 49ba9882..9ba63ef0 100644 --- a/src/Machine.Specifications.Specs/TaskSpecificationExtensionsSpecs.cs +++ b/src/Machine.Specifications.Specs/TaskSpecificationExtensionsSpecs.cs @@ -50,17 +50,6 @@ public class when_an_async_operation_runs_with_await : AsyncSpecs () => Result.Should().Be("result"); } - [Subject(typeof(TaskSpecificationExtensions), "exception")] - public class when_an_async_operation_fails_without_await : AsyncSpecs - { - static Exception exception; - - Because of = () => exception = Catch.Exception(() => Delayed.Fail()); - - It should_not_capture_the_exception = - () => exception.Should().BeNull(); - } - [Subject(typeof(TaskSpecificationExtensions), "exception")] public class when_a_single_async_operation_fails_with_await : AsyncSpecs { @@ -90,4 +79,4 @@ public class AsyncSpecs { } } -#endif \ No newline at end of file +#endif diff --git a/src/Machine.Specifications/Catch.cs b/src/Machine.Specifications/Catch.cs index db7f913b..3c00153b 100644 --- a/src/Machine.Specifications/Catch.cs +++ b/src/Machine.Specifications/Catch.cs @@ -1,4 +1,7 @@ using System; +#if !NET35 && !NET40 +using System.Threading.Tasks; +#endif namespace Machine.Specifications { @@ -6,25 +9,63 @@ public static class Catch { public static Exception Exception(Action throwingAction) { - return Only(throwingAction); + try + { + throwingAction(); + } + catch (Exception ex) + { + return ex; + } + + return null; } public static Exception Exception(Func throwingFunc) { +#if !NET35 && !NET40 + Task task; +#endif try { - throwingFunc(); + var result = throwingFunc(); +#if !NET35 && !NET40 + task = result as Task; +#endif } catch (Exception exception) { return exception; } - +#if !NET35 && !NET40 + if (task != null) + { + throw new InvalidOperationException("You must use Catch.ExceptionAsync for async methods"); + } +#endif return null; } +#if !NET35 && !NET40 + public static async Task ExceptionAsync(Func throwingAction) + { + Exception exception = null; + + try + { + await throwingAction(); + } + catch (Exception ex) + { + exception = ex; + } + + return exception; + } +#endif + public static TException Only(Action throwingAction) - where TException : Exception + where TException : Exception { try {