Skip to content

Commit a0a946b

Browse files
authored
Allow an example to specify that it is expected to throw an exception (#648)
Only the name (without the namespace) is specified; the FQN could be quite long-winded in the metadata. Towards #646.
1 parent d24bf4a commit a0a946b

File tree

3 files changed

+36
-2
lines changed

3 files changed

+36
-2
lines changed

standard/arrays.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ Because of array covariance, assignments to elements of reference type arrays in
129129
130130
> *Example*:
131131
>
132+
> <!-- Example: {template:"standalone-console", name:"CovarianceException", expectedException:"ArrayTypeMismatchException"} -->
132133
> ```csharp
133134
> class Test
134135
> {

tools/ExampleExtractor/ExampleMetadata.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public class ExampleMetadata
2323
public List<string> ExpectedErrors { get; set; }
2424
public List<string> ExpectedWarnings { get; set; }
2525
public List<string> ExpectedOutput { get; set; }
26+
public string ExpectedException { get; set; }
2627

2728
// Information provided by the example extractor
2829
public string MarkdownFile { get; set; }

tools/ExampleTester/GeneratedExample.cs

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,19 @@ bool ValidateOutput()
9595

9696
var oldOut = Console.Out;
9797
List<string> actualLines;
98+
Exception? actualException = null;
9899
try
99100
{
100101
var builder = new StringBuilder();
101102
Console.SetOut(new StringWriter(builder));
102-
method.Invoke(null, arguments);
103+
try
104+
{
105+
method.Invoke(null, arguments);
106+
}
107+
catch (TargetInvocationException outer)
108+
{
109+
actualException = outer.InnerException ?? throw new InvalidOperationException("TargetInvocationException had no nested exception");
110+
}
103111
// Skip blank lines, to avoid unnecessary trailing empties.
104112
actualLines = builder.ToString().Replace("\r\n", "\n").Split('\n').Where(line => line != "").ToList();
105113
}
@@ -108,7 +116,31 @@ bool ValidateOutput()
108116
Console.SetOut(oldOut);
109117
}
110118
var expectedLines = Metadata.ExpectedOutput ?? new List<string>();
111-
return ValidateExpectedAgainstActual("output", expectedLines, actualLines);
119+
return ValidateException(actualException, Metadata.ExpectedException) &&
120+
ValidateExpectedAgainstActual("output", expectedLines, actualLines);
121+
}
122+
123+
bool ValidateException(Exception? actualException, string? expectedExceptionName)
124+
{
125+
return (actualException, expectedExceptionName) switch
126+
{
127+
(null, null) => true,
128+
(Exception ex, string name) =>
129+
MaybeReportError(ex.GetType().Name == name, $" Mismatched exception type: Expected {name}; Was {ex.GetType().Name}"),
130+
(null, string name) =>
131+
MaybeReportError(false, $" Expected exception type {name}; no exception was thrown"),
132+
(Exception ex, null) =>
133+
MaybeReportError(false, $" Exception type {ex.GetType().Name} was thrown unexpectedly; Message: {ex.Message}")
134+
};
135+
136+
bool MaybeReportError(bool result, string message)
137+
{
138+
if (!result)
139+
{
140+
Console.WriteLine(message);
141+
}
142+
return result;
143+
}
112144
}
113145

114146
bool ValidateExpectedAgainstActual(string type, List<string> expected, List<string> actual)

0 commit comments

Comments
 (0)