using System.Text.RegularExpressions; namespace SQLInsight.Community.Tests; /// /// A table cell must stay a table cell. A class that sets display: flex or grid turns a <td>/<th> into a flex box, /// so it gets its own height and border and the row's divider jumps (the severity badges on the overviews did that). /// Such classes belong on an element inside the cell. Checked for every site's stylesheet against its own pages. /// public sealed partial class TableMarkupTests { [Theory] [InlineData("SQLInsight.Web")] [InlineData("SQLInsight.Hub")] [InlineData("SQLInsight.Community")] public void No_table_cell_has_a_flex_or_grid_class(string project) { var folder = Path.Combine(RepositoryRoot(), "src", project); var layoutClasses = Directory.EnumerateFiles(Path.Combine(folder, "wwwroot"), "*.css", SearchOption.AllDirectories) .SelectMany(css => FlexOrGridRule().Matches(File.ReadAllText(css))) .SelectMany(rule => ClassName().Matches(rule.Groups["selectors"].Value).Select(c => c.Groups[1].Value)) .ToHashSet(StringComparer.Ordinal); var offenders = Directory.EnumerateFiles(folder, "*.razor", SearchOption.AllDirectories) .Where(file => !file.Contains($"{Path.DirectorySeparatorChar}bin{Path.DirectorySeparatorChar}", StringComparison.Ordinal) && !file.Contains($"{Path.DirectorySeparatorChar}obj{Path.DirectorySeparatorChar}", StringComparison.Ordinal)) .SelectMany(file => CellClass().Matches(File.ReadAllText(file)) .SelectMany(cell => cell.Groups["classes"].Value.Split(' ', StringSplitOptions.RemoveEmptyEntries)) .Where(layoutClasses.Contains) .Select(c => $"{Path.GetFileName(file)}: ")) .ToList(); Assert.True(offenders.Count == 0, "Flyt klassen ind på et element i cellen: " + string.Join(", ", offenders)); } private static string RepositoryRoot() { var root = AppContext.BaseDirectory; while (!File.Exists(Path.Combine(root, "SQLInsight.slnx"))) { root = Path.GetDirectoryName(root) ?? throw new InvalidOperationException("SQLInsight.slnx ikke fundet."); } return root; } // A rule whose declarations set display to (inline-)flex or (inline-)grid; media queries are fine, their inner rules match. [GeneratedRegex(@"(?[^{}]+)\{[^{}]*\bdisplay\s*:\s*(inline-)?(flex|grid)\b")] private static partial Regex FlexOrGridRule(); [GeneratedRegex(@"\.([A-Za-z][\w-]*)")] private static partial Regex ClassName(); // Literal class names only; Razor expressions (@…) in the attribute are skipped by splitting on spaces. [GeneratedRegex(@"]*\bclass=""(?[^""]*)""")] private static partial Regex CellClass(); }