diff --git a/.github/workflows/actions-audit.yaml b/.github/workflows/actions-audit.yaml
index 08f2bda1..085900ea 100644
--- a/.github/workflows/actions-audit.yaml
+++ b/.github/workflows/actions-audit.yaml
@@ -45,7 +45,7 @@ jobs:
go-version: 'stable'
- name: Install actionlint
- run: go install github.com/rhysd/actionlint/cmd/actionlint@v1.7.7
+ run: go install github.com/rhysd/actionlint/cmd/actionlint@v1.7.12
- name: Run actionlint
run: actionlint -color
diff --git a/tests/Wolfgang.TryPattern.Tests.Unit/CompileFailureMessage.cs b/tests/Wolfgang.TryPattern.Tests.Unit/CompileFailureMessage.cs
new file mode 100644
index 00000000..5dc47cdb
--- /dev/null
+++ b/tests/Wolfgang.TryPattern.Tests.Unit/CompileFailureMessage.cs
@@ -0,0 +1,34 @@
+#if NET8_0_OR_GREATER
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.CodeAnalysis;
+
+namespace Wolfgang.TryPattern.Tests.Unit;
+
+///
+/// Builds the assertion message the snippet-compilation tests
+/// (, )
+/// fail with: the compiler errors, the offending snippet indented for
+/// copy-paste reproduction, and a repo-specific hint on where to fix it.
+///
+internal static class CompileFailureMessage
+{
+ internal static string Format
+ (
+ string header,
+ IEnumerable errors,
+ string snippet,
+ string hint
+ )
+ {
+ string errorList = string.Join(Environment.NewLine, errors.Select(e => $" {e}"));
+ string reproHint = string.Join(Environment.NewLine, snippet.Split('\n').Select(l => $" {l.TrimEnd()}"));
+ return
+ $"{header}{Environment.NewLine}" +
+ $"Errors:{Environment.NewLine}{errorList}{Environment.NewLine}" +
+ $"Snippet:{Environment.NewLine}{reproHint}{Environment.NewLine}" +
+ hint;
+ }
+}
+#endif
diff --git a/tests/Wolfgang.TryPattern.Tests.Unit/CompileFailureMessageTests.cs b/tests/Wolfgang.TryPattern.Tests.Unit/CompileFailureMessageTests.cs
new file mode 100644
index 00000000..d9230b83
--- /dev/null
+++ b/tests/Wolfgang.TryPattern.Tests.Unit/CompileFailureMessageTests.cs
@@ -0,0 +1,33 @@
+#if NET8_0_OR_GREATER
+using System;
+using System.Linq;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Xunit;
+
+namespace Wolfgang.TryPattern.Tests.Unit;
+
+public class CompileFailureMessageTests
+{
+ [Fact]
+ public void Format_lists_every_error_then_the_indented_snippet_then_the_hint()
+ {
+ const string snippet = "class C\n{\n void M() { int x = ; } \n}";
+ var errors = CSharpSyntaxTree.ParseText(snippet)
+ .GetDiagnostics()
+ .Where(d => d.Severity == DiagnosticSeverity.Error)
+ .ToList();
+ Assert.NotEmpty(errors);
+
+ string message = CompileFailureMessage.Format("Fence #3 failed to compile.", errors, snippet, "Fix the fence.");
+
+ string[] lines = message.Split(Environment.NewLine);
+ Assert.Equal("Fence #3 failed to compile.", lines[0]);
+ Assert.Equal("Errors:", lines[1]);
+ Assert.All(errors, e => Assert.Contains($" {e}", lines));
+ Assert.Contains("Snippet:", lines);
+ Assert.Contains(" void M() { int x = ; }", lines); // 4-space indent added, trailing whitespace trimmed
+ Assert.Equal("Fix the fence.", lines[^1]);
+ }
+}
+#endif
diff --git a/tests/Wolfgang.TryPattern.Tests.Unit/DocExampleCompilationTests.cs b/tests/Wolfgang.TryPattern.Tests.Unit/DocExampleCompilationTests.cs
index 8be05a95..5e3529c6 100644
--- a/tests/Wolfgang.TryPattern.Tests.Unit/DocExampleCompilationTests.cs
+++ b/tests/Wolfgang.TryPattern.Tests.Unit/DocExampleCompilationTests.cs
@@ -150,13 +150,11 @@ private static void Process(int item) { }
if (errors.Count > 0)
{
- string errorList = string.Join(Environment.NewLine, errors.Select(e => $" {e}"));
- string reproHint = string.Join(Environment.NewLine, snippet.Split('\n').Select(l => $" {l.TrimEnd()}"));
- Assert.Fail(
- $"XML doc example on `{memberName}` (example index {index}) failed to compile.{Environment.NewLine}" +
- $"Errors:{Environment.NewLine}{errorList}{Environment.NewLine}" +
- $"Snippet:{Environment.NewLine}{reproHint}{Environment.NewLine}" +
- $"Fix the snippet in the source XML doc, or if it needs an additional using, add it inline in the `` block.");
+ Assert.Fail(CompileFailureMessage.Format(
+ $"XML doc example on `{memberName}` (example index {index}) failed to compile.",
+ errors,
+ snippet,
+ "Fix the snippet in the source XML doc, or if it needs an additional using, add it inline in the `` block."));
}
}
}
diff --git a/tests/Wolfgang.TryPattern.Tests.Unit/FuzzTests.cs b/tests/Wolfgang.TryPattern.Tests.Unit/FuzzTests.cs
index 18dc5d5d..4464ac2f 100644
--- a/tests/Wolfgang.TryPattern.Tests.Unit/FuzzTests.cs
+++ b/tests/Wolfgang.TryPattern.Tests.Unit/FuzzTests.cs
@@ -13,12 +13,17 @@
// pulled from the test output.
using System;
+using System.Diagnostics.CodeAnalysis;
using FsCheck;
using FsCheck.Xunit;
using Xunit;
namespace Wolfgang.TryPattern.Tests.Unit;
+// Never executed by the PR gate (`--filter "Category!=Fuzz"`), only by the
+// scheduled fuzz.yaml run, so the instrumented test assembly would score it
+// at 0% on every PR. The same properties ARE measured through PropertyTests.
+[ExcludeFromCodeCoverage]
[Trait("Category", "Fuzz")]
public class FuzzTests
{
diff --git a/tests/Wolfgang.TryPattern.Tests.Unit/ReadmeExampleCompilationTests.cs b/tests/Wolfgang.TryPattern.Tests.Unit/ReadmeExampleCompilationTests.cs
index f1a536b3..97cb2a80 100644
--- a/tests/Wolfgang.TryPattern.Tests.Unit/ReadmeExampleCompilationTests.cs
+++ b/tests/Wolfgang.TryPattern.Tests.Unit/ReadmeExampleCompilationTests.cs
@@ -111,10 +111,7 @@ public static IEnumerable