From 4aaf312f936ea72db9b0fea63cf403e6c9f0a9af Mon Sep 17 00:00:00 2001 From: Your Date: Thu, 30 Jul 2026 01:48:09 +0200 Subject: [PATCH] test(visual): fail loud on cold-start across Pdf*Tests (#957 residu ii) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #963 (f7875f68) closed the cold-start faux-vert for VisualQaHarness. The same EnsureTarget() pattern carried across ~20 tests in PdfDimensionTests, PdfSnapshotTests, and PdfContentTests — each one a pass-on-nothing: a missing Target/ made the test green without asserting anything. Same correctif as #963: the silent `return;` removed, replaced by an explicit Assert.Fail("..."). A subtraction, not a counterweight — no [Fact(Skip)] (static in xUnit, would kill the tests where they work), no continue-on-error, no fabricated coverage. Secondary guards that verified nothing (missing lang dir, 0 PDFs, pdf==null, sizes.Count<2, missing expected file) get the same treatment, so a *partial* Target/ (some languages missing, a CardSet absent) can't pass silently either — those were the subtler faux-verts. CI scope verified: VisualTests.csproj is in the .sln (compiled by `dotnet build`), but build.yml's Test step targets ONLY Argumentum.AssetConverter.Tests .csproj, so these tests do NOT run in CI. Assert.Fail therefore fails locally (run the pipeline first), not in the release gate. Scope: test code only (~+30/-10 across 3 files). 0 prod write, 0 CSV, 0 OWL. Build: 0 Avertissement(s) 0 Erreur(s) on VisualTests.csproj. Co-Authored-By: Claude-Code --- .../PdfContentTests.cs | 47 ++++++++--------- .../PdfDimensionTests.cs | 51 ++++++++++--------- .../PdfSnapshotTests.cs | 27 +++++----- 3 files changed, 64 insertions(+), 61 deletions(-) diff --git a/Generation/Converters/Argumentum.AssetConverter.VisualTests/PdfContentTests.cs b/Generation/Converters/Argumentum.AssetConverter.VisualTests/PdfContentTests.cs index 66c2317d9..d209737ce 100644 --- a/Generation/Converters/Argumentum.AssetConverter.VisualTests/PdfContentTests.cs +++ b/Generation/Converters/Argumentum.AssetConverter.VisualTests/PdfContentTests.cs @@ -15,7 +15,7 @@ namespace Argumentum.AssetConverter.VisualTests /// (TarotCards/PokerCards) or uses font encodings without ToUnicode mappings /// (FallaciesWeb). Structural checks catch the same regressions (empty cards, /// broken generation) more reliably. - /// Tests pass silently if Target/ doesn't exist (CI cold-start). + /// Fails LOUD if Target/ doesn't exist (#957 residu ii) — was a silent faux-vert (pass-on-nothing). /// public class PdfContentTests : IDisposable { @@ -38,14 +38,15 @@ public void Dispose() { } private static string GetPdfDir(string lang) => Path.Combine(TargetRoot, lang, "Documents", "density-0"); - private bool EnsureTarget() + private void EnsureTarget() { + // #957 residu ii: cold-start faux-vert. A missing Target/ must FAIL LOUD, not pass silently — + // these tests verify generated PDFs and assert nothing without them. Assert.Fail is a subtraction + // (removes the silent `return;`), not a counterweight: no [Fact(Skip)] (static, would kill the + // tests where they work), no continue-on-error. VisualTests is NOT run by CI (build.yml targets + // only Argumentum.AssetConverter.Tests.csproj), so this fails locally, not in the release gate. if (!Directory.Exists(TargetRoot)) - { - _output.WriteLine("Skipped: Target/ not found — run pipeline first"); - return false; - } - return true; + Assert.Fail("PdfContentTests require a generated Target/ — run the pipeline first (bin/Debug/net9.0-windows/Target not found). This test verified nothing."); } // --- File size sanity checks --- @@ -57,11 +58,11 @@ private bool EnsureTarget() [InlineData("pt")] public void All_Pdfs_Have_Minimum_Size(string lang) { - if (!EnsureTarget()) return; + EnsureTarget(); var dir = GetPdfDir(lang); - if (!Directory.Exists(dir)) return; + if (!Directory.Exists(dir)) Assert.Fail($"Language directory not found: {dir} — test verified nothing (Target/ exists but this language produced no Documents/density-0/; check pipeline output)."); var pdfs = Directory.GetFiles(dir, "*.pdf"); - if (pdfs.Length == 0) return; + if (pdfs.Length == 0) Assert.Fail($"No PDFs found for {lang} in Target/ — test verified nothing (check pipeline output)."); var failures = new List(); foreach (var pdf in pdfs) @@ -80,7 +81,7 @@ public void All_Pdfs_Have_Minimum_Size(string lang) [Fact] public void A0_Pdf_Sizes_Are_Consistent_Across_Languages() { - if (!EnsureTarget()) return; + EnsureTarget(); var sizes = new Dictionary(); foreach (var lang in Languages) @@ -90,7 +91,7 @@ public void A0_Pdf_Sizes_Are_Consistent_Across_Languages() sizes[lang] = new FileInfo(pdfs[0]).Length; } - if (sizes.Count < 2) return; + if (sizes.Count < 2) Assert.Fail($"Only {sizes.Count} language(s) with A0 PDFs found in Target/ — test verified nothing (expected >= 2 languages to compare; check pipeline output for missing languages)."); var avgSize = sizes.Values.Average(); var minSize = sizes.Values.Min(); @@ -117,13 +118,13 @@ public void A0_Pdf_Sizes_Are_Consistent_Across_Languages() [InlineData("pt")] public void FallaciesWeb_A4_Has_Reasonable_Page_Count(string lang) { - if (!EnsureTarget()) return; + EnsureTarget(); var dir = GetPdfDir(lang); - if (!Directory.Exists(dir)) return; + if (!Directory.Exists(dir)) Assert.Fail($"Language directory not found: {dir} — test verified nothing (Target/ exists but this language produced no Documents/density-0/; check pipeline output)."); var pdfs = Directory.GetFiles(dir, "*_Fallacies_Web_A4_*.pdf") .Where(p => !Path.GetFileName(p).Contains("Thumbnails")) .ToArray(); - if (pdfs.Length == 0) return; + if (pdfs.Length == 0) Assert.Fail($"No PDFs found for {lang} in Target/ — test verified nothing (check pipeline output)."); foreach (var pdf in pdfs) { @@ -145,16 +146,16 @@ public void FallaciesWeb_A4_Has_Reasonable_Page_Count(string lang) [InlineData("pt")] public void TarotCards_Has_Multiple_Pages(string lang) { - if (!EnsureTarget()) return; + EnsureTarget(); var dir = GetPdfDir(lang); - if (!Directory.Exists(dir)) return; + if (!Directory.Exists(dir)) Assert.Fail($"Language directory not found: {dir} — test verified nothing (Target/ exists but this language produced no Documents/density-0/; check pipeline output)."); // Main TarotCards PDF (not split, not FacesOnly, not Virtues) var pdf = Directory.GetFiles(dir, "Argumentum_TarotCards_*.pdf") .FirstOrDefault(p => !Path.GetFileName(p).Contains("-") && !Path.GetFileName(p).Contains("Virtues") && !Path.GetFileName(p).Contains("FacesOnly") && !Path.GetFileName(p).Contains("Print")); - if (pdf == null) return; + if (pdf == null) Assert.Fail($"No matching PDF found for {lang} in Target/ — test verified nothing (Target/ exists but the expected CardSet PDF is missing; check pipeline output)."); using var doc = PdfDocument.Open(pdf); var pages = doc.NumberOfPages; @@ -172,14 +173,14 @@ public void TarotCards_Has_Multiple_Pages(string lang) [InlineData("pt")] public void PokerCards_Has_Multiple_Pages(string lang) { - if (!EnsureTarget()) return; + EnsureTarget(); var dir = GetPdfDir(lang); - if (!Directory.Exists(dir)) return; + if (!Directory.Exists(dir)) Assert.Fail($"Language directory not found: {dir} — test verified nothing (Target/ exists but this language produced no Documents/density-0/; check pipeline output)."); // Main PokerCards PDF (not split, not Print&Play) var pdf = Directory.GetFiles(dir, "Argumentum_PokerCards_*.pdf") .FirstOrDefault(p => !Path.GetFileName(p).Contains("-") && !Path.GetFileName(p).Contains("Print")); - if (pdf == null) return; + if (pdf == null) Assert.Fail($"No matching PDF found for {lang} in Target/ — test verified nothing (Target/ exists but the expected CardSet PDF is missing; check pipeline output)."); using var doc = PdfDocument.Open(pdf); var pages = doc.NumberOfPages; @@ -197,9 +198,9 @@ public void PokerCards_Has_Multiple_Pages(string lang) [InlineData("pt")] public void Each_Language_Has_Multiple_Pdf_Types(string lang) { - if (!EnsureTarget()) return; + EnsureTarget(); var dir = GetPdfDir(lang); - if (!Directory.Exists(dir)) return; + if (!Directory.Exists(dir)) Assert.Fail($"Language directory not found: {dir} — test verified nothing (Target/ exists but this language produced no Documents/density-0/; check pipeline output)."); var pdfs = Directory.GetFiles(dir, "*.pdf"); // Each language should have at least: A0, A4, Thumbnails, Print&Play, diff --git a/Generation/Converters/Argumentum.AssetConverter.VisualTests/PdfDimensionTests.cs b/Generation/Converters/Argumentum.AssetConverter.VisualTests/PdfDimensionTests.cs index 8886365f6..bca2c5c66 100644 --- a/Generation/Converters/Argumentum.AssetConverter.VisualTests/PdfDimensionTests.cs +++ b/Generation/Converters/Argumentum.AssetConverter.VisualTests/PdfDimensionTests.cs @@ -11,7 +11,7 @@ namespace Argumentum.AssetConverter.VisualTests /// /// Stage 1 of #212: PDF dimension and page count regression tests. /// Validates that generated PDFs have correct page sizes and reasonable page counts. - /// Tests pass silently if Target/ doesn't exist (CI cold-start). + /// Fails LOUD if Target/ doesn't exist (#957 residu ii) — was a silent faux-vert (pass-on-nothing). /// public class PdfDimensionTests : IDisposable { @@ -52,14 +52,15 @@ private static int GetPageCount(string pdfPath) return doc.NumberOfPages; } - private bool EnsureTarget() + private void EnsureTarget() { + // #957 residu ii: cold-start faux-vert. A missing Target/ must FAIL LOUD, not pass silently — + // these tests verify generated PDFs and assert nothing without them. Assert.Fail is a subtraction + // (removes the silent `return;`), not a counterweight: no [Fact(Skip)] (static, would kill the + // tests where they work), no continue-on-error. VisualTests is NOT run by CI (build.yml targets + // only Argumentum.AssetConverter.Tests.csproj), so this fails locally, not in the release gate. if (!Directory.Exists(TargetRoot)) - { - _output.WriteLine("Skipped: Target/ not found — run pipeline first"); - return false; - } - return true; + Assert.Fail("PdfDimensionTests require a generated Target/ — run the pipeline first (bin/Debug/net9.0-windows/Target not found). This test verified nothing."); } // --- A0 Format Tests --- @@ -71,9 +72,9 @@ private bool EnsureTarget() [InlineData("pt")] public void A0_Pdf_Has_Correct_Dimensions(string lang) { - if (!EnsureTarget()) return; + EnsureTarget(); var pdfs = GetPdfs(lang, "*_A0_*.pdf").ToList(); - if (pdfs.Count == 0) { _output.WriteLine($"No A0 PDFs for {lang}"); return; } + if (pdfs.Count == 0) Assert.Fail($"No A0 PDFs for {lang} in Target/ — test verified nothing (check pipeline output)."); foreach (var pdf in pdfs) { @@ -91,9 +92,9 @@ public void A0_Pdf_Has_Correct_Dimensions(string lang) [InlineData("pt")] public void A0_Pdf_Has_Exactly_One_Page(string lang) { - if (!EnsureTarget()) return; + EnsureTarget(); var pdfs = GetPdfs(lang, "*_A0_*.pdf").ToList(); - if (pdfs.Count == 0) return; + if (pdfs.Count == 0) Assert.Fail($"No matching PDFs found for {lang} in Target/ — test verified nothing (Target/ exists but this CardSet pattern produced no files; check pipeline output)."); foreach (var pdf in pdfs) Assert.Equal(1, GetPageCount(pdf)); @@ -108,9 +109,9 @@ public void A0_Pdf_Has_Exactly_One_Page(string lang) [InlineData("pt")] public void A4_Pdf_Has_Correct_Dimensions(string lang) { - if (!EnsureTarget()) return; + EnsureTarget(); var pdfs = GetPdfs(lang, "*_A4_*.pdf").ToList(); - if (pdfs.Count == 0) { _output.WriteLine($"No A4 PDFs for {lang}"); return; } + if (pdfs.Count == 0) Assert.Fail($"No A4 PDFs for {lang} in Target/ — test verified nothing (check pipeline output)."); foreach (var pdf in pdfs) { @@ -128,9 +129,9 @@ public void A4_Pdf_Has_Correct_Dimensions(string lang) [InlineData("pt")] public void A4_Pdf_Has_At_Least_One_Page(string lang) { - if (!EnsureTarget()) return; + EnsureTarget(); var pdfs = GetPdfs(lang, "*_A4_*.pdf").ToList(); - if (pdfs.Count == 0) return; + if (pdfs.Count == 0) Assert.Fail($"No matching PDFs found for {lang} in Target/ — test verified nothing (Target/ exists but this CardSet pattern produced no files; check pipeline output)."); foreach (var pdf in pdfs) Assert.True(GetPageCount(pdf) >= 1, $"{Path.GetFileName(pdf)} has 0 pages"); @@ -145,9 +146,9 @@ public void A4_Pdf_Has_At_Least_One_Page(string lang) [InlineData("pt")] public void PrintAndPlay_Pdf_Is_A4_Format(string lang) { - if (!EnsureTarget()) return; + EnsureTarget(); var pdfs = GetPdfs(lang, "*_Print&Play_*.pdf").ToList(); - if (pdfs.Count == 0) return; + if (pdfs.Count == 0) Assert.Fail($"No matching PDFs found for {lang} in Target/ — test verified nothing (Target/ exists but this CardSet pattern produced no files; check pipeline output)."); foreach (var pdf in pdfs) { @@ -167,11 +168,11 @@ public void PrintAndPlay_Pdf_Is_A4_Format(string lang) [InlineData("pt")] public void All_Pdfs_Have_NonZero_Pages(string lang) { - if (!EnsureTarget()) return; + EnsureTarget(); var dir = GetPdfDir(lang); - if (!Directory.Exists(dir)) return; + if (!Directory.Exists(dir)) Assert.Fail($"Language directory not found: {dir} — test verified nothing (Target/ exists but this language produced no Documents/density-0/; check pipeline output)."); var pdfs = Directory.GetFiles(dir, "*.pdf"); - if (pdfs.Length == 0) return; + if (pdfs.Length == 0) Assert.Fail($"No PDFs at all for {lang} in {dir} — test verified nothing."); foreach (var pdf in pdfs) Assert.True(GetPageCount(pdf) > 0, $"{Path.GetFileName(pdf)} has 0 pages"); @@ -182,7 +183,7 @@ public void All_Pdfs_Have_NonZero_Pages(string lang) [Fact] public void All_Languages_Have_FallaciesWeb_A0() { - if (!EnsureTarget()) return; + EnsureTarget(); foreach (var lang in Languages) { var pdfs = GetPdfs(lang, "*_Fallacies_Web_A0_*.pdf").ToList(); @@ -194,7 +195,7 @@ public void All_Languages_Have_FallaciesWeb_A0() [Fact] public void All_Languages_Have_FallaciesWeb_A4() { - if (!EnsureTarget()) return; + EnsureTarget(); foreach (var lang in Languages) { var pdfs = GetPdfs(lang, "*_Fallacies_Web_A4_*.pdf").ToList(); @@ -205,7 +206,7 @@ public void All_Languages_Have_FallaciesWeb_A4() [Fact] public void All_Languages_Have_TarotCards() { - if (!EnsureTarget()) return; + EnsureTarget(); foreach (var lang in Languages) { var pdfs = GetPdfs(lang, "*_TarotCards_*.pdf") @@ -219,7 +220,7 @@ public void All_Languages_Have_TarotCards() [Fact] public void All_Languages_Have_PokerCards() { - if (!EnsureTarget()) return; + EnsureTarget(); foreach (var lang in Languages) { var pdfs = GetPdfs(lang, "*_PokerCards_*.pdf").ToList(); @@ -231,7 +232,7 @@ public void All_Languages_Have_PokerCards() [Fact] public void All_Languages_Have_PrintAndPlay() { - if (!EnsureTarget()) return; + EnsureTarget(); foreach (var lang in Languages) { var pdfs = GetPdfs(lang, "*_Print&Play_*.pdf").ToList(); diff --git a/Generation/Converters/Argumentum.AssetConverter.VisualTests/PdfSnapshotTests.cs b/Generation/Converters/Argumentum.AssetConverter.VisualTests/PdfSnapshotTests.cs index 469eda57a..9a34f50b1 100644 --- a/Generation/Converters/Argumentum.AssetConverter.VisualTests/PdfSnapshotTests.cs +++ b/Generation/Converters/Argumentum.AssetConverter.VisualTests/PdfSnapshotTests.cs @@ -11,7 +11,7 @@ namespace Argumentum.AssetConverter.VisualTests /// /// Stage 2 of #212: PDF structural regression via Verify snapshot comparison. /// Captures page dimensions, page count, text length, and letter count. - /// Tests pass silently if Target/ doesn't exist (CI cold-start). + /// Fails LOUD if Target/ doesn't exist (#957 residu ii) — was a silent faux-vert (pass-on-nothing). /// public class PdfSnapshotTests : IDisposable { @@ -30,14 +30,15 @@ public void Dispose() { } private static string GetPdfPath(string lang, string filename) => Path.Combine(TargetRoot, lang, "Documents", "density-0", filename); - private bool EnsureTarget() + private void EnsureTarget() { + // #957 residu ii: cold-start faux-vert. A missing Target/ must FAIL LOUD, not pass silently — + // these tests verify generated PDFs and assert nothing without them. Assert.Fail is a subtraction + // (removes the silent `return;`), not a counterweight: no [Fact(Skip)] (static, would kill the + // tests where they work), no continue-on-error. VisualTests is NOT run by CI (build.yml targets + // only Argumentum.AssetConverter.Tests.csproj), so this fails locally, not in the release gate. if (!Directory.Exists(TargetRoot)) - { - _output.WriteLine("Skipped: Target/ not found — run pipeline first"); - return false; - } - return true; + Assert.Fail("PdfSnapshotTests require a generated Target/ — run the pipeline first (bin/Debug/net9.0-windows/Target not found). This test verified nothing."); } // --- FallaciesWeb A4 (all languages) --- @@ -49,10 +50,10 @@ private bool EnsureTarget() [InlineData("pt")] public async Task FallaciesWeb_A4_FirstPage_Structure(string lang) { - if (!EnsureTarget()) return; + EnsureTarget(); var pdfPath = GetPdfPath(lang, $"Argumentum_Fallacies_Web_A4_{lang}.pdf"); - if (!File.Exists(pdfPath)) { _output.WriteLine($"PDF not found: {pdfPath}"); return; } + if (!File.Exists(pdfPath)) Assert.Fail($"Expected PDF not found: {pdfPath} — Target/ exists but this file is missing (test verified nothing; check harvest/pipeline output)."); using var doc = PdfDocument.Open(pdfPath); var page = doc.GetPage(1); @@ -82,10 +83,10 @@ public async Task FallaciesWeb_A4_FirstPage_Structure(string lang) [InlineData("pt")] public async Task TarotCards_FirstPage_Structure(string lang) { - if (!EnsureTarget()) return; + EnsureTarget(); var pdfPath = GetPdfPath(lang, $"Argumentum_TarotCards_{lang}.pdf"); - if (!File.Exists(pdfPath)) { _output.WriteLine($"PDF not found: {pdfPath}"); return; } + if (!File.Exists(pdfPath)) Assert.Fail($"Expected PDF not found: {pdfPath} — Target/ exists but this file is missing (test verified nothing; check harvest/pipeline output)."); using var doc = PdfDocument.Open(pdfPath); var page = doc.GetPage(1); @@ -113,10 +114,10 @@ public async Task TarotCards_FirstPage_Structure(string lang) [InlineData("pt")] public async Task PokerCards_FirstPage_Structure(string lang) { - if (!EnsureTarget()) return; + EnsureTarget(); var pdfPath = GetPdfPath(lang, $"Argumentum_PokerCards_{lang}.pdf"); - if (!File.Exists(pdfPath)) { _output.WriteLine($"PDF not found: {pdfPath}"); return; } + if (!File.Exists(pdfPath)) Assert.Fail($"Expected PDF not found: {pdfPath} — Target/ exists but this file is missing (test verified nothing; check harvest/pipeline output)."); using var doc = PdfDocument.Open(pdfPath); var page = doc.GetPage(1);