Skip to content

Commit 8d930f8

Browse files
Feature/async catch backport (#431)
* Add async catch method (#430) * Only 4.5 and netstandard supported
1 parent 745ff75 commit 8d930f8

File tree

5 files changed

+168
-19
lines changed

5 files changed

+168
-19
lines changed
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using System.Threading.Tasks;
2+
using Machine.Specifications;
3+
4+
#if !NET45
5+
namespace Example.Random
6+
{
7+
public class AsyncSpecificationsValueTask
8+
{
9+
public static int establish_value;
10+
11+
public static int because_value;
12+
13+
public static int async_it_value;
14+
15+
public static int sync_it_value;
16+
17+
public static int cleanup_value;
18+
19+
public static ValueTask<int> Test()
20+
{
21+
return new ValueTask<int>(10);
22+
}
23+
24+
Establish context = async () =>
25+
establish_value = await Test();
26+
27+
Because of = async () =>
28+
because_value = await Test();
29+
30+
It should_invoke_sync = () =>
31+
sync_it_value = Test().Result;
32+
33+
It should_invoke_async = async () =>
34+
async_it_value = await Test();
35+
36+
Cleanup after = async () =>
37+
cleanup_value = await Test();
38+
}
39+
}
40+
#endif

src/Machine.Specifications.Specs/CatchSpecs.cs

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Threading.Tasks;
23

34
using FluentAssertions;
45

@@ -125,7 +126,52 @@ public class with_a_non_throwing_Action
125126
() => ActionSideEffect.Should().Be("hi");
126127

127128
It should_return_null =
128-
() => Result.Should().BeNull();
129+
() => Result.Should().BeNull();
130+
}
129131
}
130-
}
131-
}
132+
133+
[Subject(typeof(Catch))]
134+
public class when_calling_catch_with_async_methods
135+
{
136+
static Exception exception;
137+
138+
[Subject(typeof(Catch))]
139+
public class with_a_non_throwing_action
140+
{
141+
static Task Test() => Task.Run(() => { });
142+
143+
Because of = async () =>
144+
exception = await Catch.ExceptionAsync(Test);
145+
146+
It should_return_null = () =>
147+
exception.Should().BeNull();
148+
}
149+
150+
[Subject(typeof(Catch))]
151+
public class with_a_throwing_action
152+
{
153+
static Task Test() => Task.Run(() => throw new ArgumentNullException());
154+
155+
Because of = async () =>
156+
exception = await Catch.ExceptionAsync(Test);
157+
158+
It should_return_exception = () =>
159+
exception.Should().BeOfType<ArgumentNullException>();
160+
}
161+
162+
[Subject(typeof(Catch))]
163+
public class calling_wrong_catch_method
164+
{
165+
static Task Test() => Task.Run(() => throw new ArgumentNullException());
166+
167+
Because of = () =>
168+
exception = Catch.Exception(() => Catch.Exception(Test));
169+
170+
It should_return_exception = () =>
171+
exception.Should().BeOfType<InvalidOperationException>();
172+
173+
It should_contain_message = () =>
174+
exception.Message.Should().Be("You must use Catch.ExceptionAsync for async methods");
175+
}
176+
}
177+
}

src/Machine.Specifications.Specs/Runner/AsyncDelegateRunnerSpecs.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,37 @@ public class when_running_async_specifications_with_exceptions : RunnerSpecs
6969
It should_have_failures = () =>
7070
results.Should().Match(x => x.All(y => !y.Passed));
7171
}
72+
73+
#if NETCOREAPP
74+
[Subject("Async Delegate Runner")]
75+
public class when_running_async_value_task_specifications : RunnerSpecs
76+
{
77+
Establish context = () =>
78+
{
79+
AsyncSpecificationsValueTask.establish_value = 0;
80+
AsyncSpecificationsValueTask.because_value = 0;
81+
AsyncSpecificationsValueTask.async_it_value = 0;
82+
AsyncSpecificationsValueTask.sync_it_value = 0;
83+
AsyncSpecificationsValueTask.cleanup_value = 0;
84+
};
85+
86+
Because of = () =>
87+
Run<AsyncSpecificationsValueTask>();
88+
89+
It should_call_establish = () =>
90+
AsyncSpecificationsValueTask.establish_value.Should().Be(10);
91+
92+
It should_call_because = () =>
93+
AsyncSpecificationsValueTask.because_value.Should().Be(10);
94+
95+
It should_call_async_spec = () =>
96+
AsyncSpecificationsValueTask.async_it_value.Should().Be(10);
97+
98+
It should_call_sync_spec = () =>
99+
AsyncSpecificationsValueTask.sync_it_value.Should().Be(10);
100+
101+
It should_call_cleanup = () =>
102+
AsyncSpecificationsValueTask.cleanup_value.Should().Be(10);
103+
}
104+
#endif
72105
}

src/Machine.Specifications.Specs/TaskSpecificationExtensionsSpecs.cs

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -50,17 +50,6 @@ public class when_an_async_operation_runs_with_await : AsyncSpecs
5050
() => Result.Should().Be("result");
5151
}
5252

53-
[Subject(typeof(TaskSpecificationExtensions), "exception")]
54-
public class when_an_async_operation_fails_without_await : AsyncSpecs
55-
{
56-
static Exception exception;
57-
58-
Because of = () => exception = Catch.Exception(() => Delayed.Fail());
59-
60-
It should_not_capture_the_exception =
61-
() => exception.Should().BeNull();
62-
}
63-
6453
[Subject(typeof(TaskSpecificationExtensions), "exception")]
6554
public class when_a_single_async_operation_fails_with_await : AsyncSpecs
6655
{
@@ -90,4 +79,4 @@ public class AsyncSpecs
9079
{
9180
}
9281
}
93-
#endif
82+
#endif

src/Machine.Specifications/Catch.cs

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,71 @@
11
using System;
2+
#if !NET35 && !NET40
3+
using System.Threading.Tasks;
4+
#endif
25

36
namespace Machine.Specifications
47
{
58
public static class Catch
69
{
710
public static Exception Exception(Action throwingAction)
811
{
9-
return Only<Exception>(throwingAction);
12+
try
13+
{
14+
throwingAction();
15+
}
16+
catch (Exception ex)
17+
{
18+
return ex;
19+
}
20+
21+
return null;
1022
}
1123

1224
public static Exception Exception<T>(Func<T> throwingFunc)
1325
{
26+
#if !NET35 && !NET40
27+
Task task;
28+
#endif
1429
try
1530
{
16-
throwingFunc();
31+
var result = throwingFunc();
32+
#if !NET35 && !NET40
33+
task = result as Task;
34+
#endif
1735
}
1836
catch (Exception exception)
1937
{
2038
return exception;
2139
}
22-
40+
#if !NET35 && !NET40
41+
if (task != null)
42+
{
43+
throw new InvalidOperationException("You must use Catch.ExceptionAsync for async methods");
44+
}
45+
#endif
2346
return null;
2447
}
2548

49+
#if !NET35 && !NET40
50+
public static async Task<Exception> ExceptionAsync(Func<Task> throwingAction)
51+
{
52+
Exception exception = null;
53+
54+
try
55+
{
56+
await throwingAction();
57+
}
58+
catch (Exception ex)
59+
{
60+
exception = ex;
61+
}
62+
63+
return exception;
64+
}
65+
#endif
66+
2667
public static TException Only<TException>(Action throwingAction)
27-
where TException : Exception
68+
where TException : Exception
2869
{
2970
try
3071
{

0 commit comments

Comments
 (0)