using System.Runtime.CompilerServices; using System.Text.RegularExpressions; using Xunit; namespace Azaion.Missions.E2E.Tests; /// /// Enforces AC-7 of AZ-576 — every [Fact] / [Theory] method /// under tests/Azaion.Missions.E2E.Tests/Tests/ contains the literal /// AAA marker comments in order. /// /// /// The check uses regex over source files rather than Roslyn — it is meant /// to be a cheap sentinel test, not a full analyzer. Empty "Arrange" /// blocks may be omitted (the spec allows it); "Act" and "Assert" /// are mandatory and must appear in that order. /// public sealed partial class AaaPatternEnforcement { [Fact] [Trait("Category", "Blackbox")] [Trait("Traces", "AC-7")] public void Every_test_method_under_Tests_uses_AAA_markers() { // Arrange var testsDir = LocateTestsDir(); var sourceFiles = Directory.GetFiles(testsDir, "*.cs", SearchOption.AllDirectories); Assert.NotEmpty(sourceFiles); var failures = new List(); // Act foreach (var file in sourceFiles) { var src = File.ReadAllText(file); foreach (Match match in TestMethodRegex().Matches(src)) { var methodName = match.Groups["name"].Value; var body = match.Groups["body"].Value; var actIdx = body.IndexOf("// Act", StringComparison.Ordinal); var assertIdx = body.IndexOf("// Assert", StringComparison.Ordinal); var arrangeIdx = body.IndexOf("// Arrange", StringComparison.Ordinal); if (actIdx < 0 || assertIdx < 0) { failures.Add($"{Path.GetFileName(file)}::{methodName} missing // Act and/or // Assert"); continue; } if (assertIdx < actIdx) { failures.Add($"{Path.GetFileName(file)}::{methodName} // Assert appears before // Act"); continue; } if (arrangeIdx >= 0 && arrangeIdx > actIdx) { failures.Add($"{Path.GetFileName(file)}::{methodName} // Arrange appears after // Act"); } } } // Assert Assert.True(failures.Count == 0, "AAA markers missing or out-of-order:\n " + string.Join("\n ", failures)); } [GeneratedRegex( @"\[(?:Fact|Theory)(?:\s*,\s*\w+(?:\([^)]*\))?)*\][^{}]*?(?:\[[^\]]*\][^{}]*?)*public\s+(?:async\s+)?(?:void|Task)\s+(?\w+)\s*\([^)]*\)\s*(?\{(?:[^{}]|(?\{)|(?<-o>\}))*(?(o)(?!))\})", RegexOptions.Singleline | RegexOptions.CultureInvariant)] private static partial Regex TestMethodRegex(); private static string LocateTestsDir([CallerFilePath] string thisFile = "") { // thisFile is .../tests/Azaion.Missions.E2E.Tests/Tests/AaaPatternEnforcement.cs var dir = Path.GetDirectoryName(thisFile); if (dir is null || !Directory.Exists(dir)) throw new DirectoryNotFoundException( $"Could not locate Tests/ directory from CallerFilePath '{thisFile}'"); return dir; } }