Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/async catch backport #431

Merged
merged 2 commits into from
Feb 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions src/Examples/Example.Random/AsyncSpecificationsValueTask.cs
Original file line number Diff line number Diff line change
@@ -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<int> Test()
{
return new ValueTask<int>(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
52 changes: 49 additions & 3 deletions src/Machine.Specifications.Specs/CatchSpecs.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Threading.Tasks;

using FluentAssertions;

Expand Down Expand Up @@ -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();
}
}
}
}

[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<ArgumentNullException>();
}

[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<InvalidOperationException>();

It should_contain_message = () =>
exception.Message.Should().Be("You must use Catch.ExceptionAsync for async methods");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<AsyncSpecificationsValueTask>();

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
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -90,4 +79,4 @@ public class AsyncSpecs
{
}
}
#endif
#endif
49 changes: 45 additions & 4 deletions src/Machine.Specifications/Catch.cs
Original file line number Diff line number Diff line change
@@ -1,30 +1,71 @@
using System;
#if !NET35 && !NET40
using System.Threading.Tasks;
#endif

namespace Machine.Specifications
{
public static class Catch
{
public static Exception Exception(Action throwingAction)
{
return Only<Exception>(throwingAction);
try
{
throwingAction();
}
catch (Exception ex)
{
return ex;
}

return null;
}

public static Exception Exception<T>(Func<T> 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<Exception> ExceptionAsync(Func<Task> throwingAction)
{
Exception exception = null;

try
{
await throwingAction();
}
catch (Exception ex)
{
exception = ex;
}

return exception;
}
#endif

public static TException Only<TException>(Action throwingAction)
where TException : Exception
where TException : Exception
{
try
{
Expand Down