-
-
Notifications
You must be signed in to change notification settings - Fork 90
Expand file tree
/
Copy pathRecord.cs
More file actions
150 lines (134 loc) · 4.57 KB
/
Record.cs
File metadata and controls
150 lines (134 loc) · 4.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#pragma warning disable CA1031 // Do not catch general exception types
#pragma warning disable CA1052 // Static holder types should be static
#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task
#pragma warning disable IDE0059 // Unnecessary assignment of a value
#if XUNIT_NULLABLE
#nullable enable
#else
// In case this is source-imported with global nullable enabled but no XUNIT_NULLABLE
#pragma warning disable CS8603
#endif
using System;
using System.ComponentModel;
using System.Globalization;
using System.Threading.Tasks;
namespace Xunit
{
partial class Assert
{
/// <summary>
/// The contract for exceptions which indicate that something should be skipped rather than
/// failed is that exception message should start with this, and that any text following this
/// will be treated as the skip reason (for example, <c>"$XunitDynamicSkip$This code can only run
/// on Linux"</c>) will result in a skipped test with the reason of <c>"This code can only run
/// on Linux"</c>.
/// </summary>
const string DynamicSkipToken = "$XunitDynamicSkip$";
/// <summary>
/// Records any exception which is thrown by the given code.
/// </summary>
/// <param name="testCode">The code which may thrown an exception.</param>
/// <returns>Returns the exception that was thrown by the code; null, otherwise.</returns>
/// <remarks>
/// If the thrown exception is determined to be a "skip exception", it's not recorded, but
/// instead is allowed to escape this function uncaught.
/// </remarks>
#if XUNIT_NULLABLE
protected static Exception? RecordException(Action testCode)
#else
protected static Exception RecordException(Action testCode)
#endif
{
GuardArgumentNotNull(nameof(testCode), testCode);
try
{
testCode();
return null;
}
catch (Exception ex)
{
if (ex.Message?.StartsWith(DynamicSkipToken, StringComparison.Ordinal) == true)
throw;
return ex;
}
}
/// <summary>
/// Records any exception which is thrown by the given code that has
/// a return value. Generally used for testing property accessors.
/// </summary>
/// <param name="testCode">The code which may thrown an exception.</param>
/// <param name="asyncMethodName">The name of the async method the user should've called if they accidentally
/// passed in an async function</param>
/// <returns>Returns the exception that was thrown by the code; null, otherwise.</returns>
/// <remarks>
/// If the thrown exception is determined to be a "skip exception", it's not recorded, but
/// instead is allowed to escape this function uncaught.
/// </remarks>
#if XUNIT_NULLABLE
protected static Exception? RecordException(
Func<object?> testCode,
#else
protected static Exception RecordException(
Func<object> testCode,
#endif
string asyncMethodName)
{
GuardArgumentNotNull(nameof(testCode), testCode);
var result = default(object);
try
{
result = testCode();
}
catch (Exception ex)
{
if (ex.Message?.StartsWith(DynamicSkipToken, StringComparison.Ordinal) == true)
throw;
return ex;
}
if (result is Task)
throw new InvalidOperationException(
string.Format(
CultureInfo.CurrentCulture,
"You must call Assert.{0} when testing async code",
asyncMethodName
)
);
return null;
}
/// <summary/>
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("You must call Assert.RecordExceptionAsync (and await the result) when testing async code.", true)]
protected static Exception RecordException(Func<Task> testCode)
{
throw new NotSupportedException("You must call Assert.RecordExceptionAsync (and await the result) when testing async code.");
}
/// <summary>
/// Records any exception which is thrown by the given task.
/// </summary>
/// <param name="testCode">The task which may thrown an exception.</param>
/// <returns>Returns the exception that was thrown by the code; null, otherwise.</returns>
/// <remarks>
/// If the thrown exception is determined to be a "skip exception", it's not recorded, but
/// instead is allowed to escape this function uncaught.
/// </remarks>
#if XUNIT_NULLABLE
protected static async Task<Exception?> RecordExceptionAsync(Func<Task> testCode)
#else
protected static async Task<Exception> RecordExceptionAsync(Func<Task> testCode)
#endif
{
GuardArgumentNotNull(nameof(testCode), testCode);
try
{
await testCode();
return null;
}
catch (Exception ex)
{
if (ex.Message?.StartsWith(DynamicSkipToken, StringComparison.Ordinal) == true)
throw;
return ex;
}
}
}
}