|
| 1 | +import Foundation |
| 2 | +import Testing |
| 3 | + |
| 4 | +/// Guards the customer-probe corpus's queryable index (`corpus.jsonl`) so the |
| 5 | +/// audit fixtures cannot silently vanish. The post-redesign diagnostic audit |
| 6 | +/// (and the work it spawned: TRM/DAR-134, advanced-PD/DAR-136, cable-trust/ |
| 7 | +/// DAR-137) leans on these signals being present in the corpus. A bad |
| 8 | +/// regeneration or an accidental edit that drops records or strips a signal |
| 9 | +/// would quietly remove the fixtures those tasks and their regression tests |
| 10 | +/// depend on. This catches that. |
| 11 | +/// |
| 12 | +/// Reads the git-tracked `corpus.jsonl` (not the gitignored raw probes), so it |
| 13 | +/// runs identically on a fresh clone. Thresholds sit comfortably below the |
| 14 | +/// current counts: they flag a collapse, not normal growth. |
| 15 | +@Suite("Customer-probe corpus coverage") |
| 16 | +struct CorpusCoverageTests { |
| 17 | + private static let corpusURL: URL = { |
| 18 | + URL(fileURLWithPath: #filePath) |
| 19 | + .deletingLastPathComponent() // WhatCableCoreTests |
| 20 | + .deletingLastPathComponent() // Tests |
| 21 | + .deletingLastPathComponent() // repo root |
| 22 | + .appendingPathComponent("research/customer-probes/corpus.jsonl") |
| 23 | + }() |
| 24 | + |
| 25 | + struct MalformedCorpusLine: Error { let line: Int } |
| 26 | + |
| 27 | + private static func records() throws -> [[String: Any]] { |
| 28 | + let text = try String(contentsOf: corpusURL, encoding: .utf8) |
| 29 | + // Fail fast on a malformed line rather than silently dropping it: a |
| 30 | + // corrupt regeneration must surface as a test failure, not a quietly |
| 31 | + // lower record count that still clears the thresholds. |
| 32 | + return try text |
| 33 | + .split(separator: "\n") |
| 34 | + .enumerated() |
| 35 | + .map { index, line in |
| 36 | + guard let obj = try JSONSerialization.jsonObject(with: Data(line.utf8)) as? [String: Any] else { |
| 37 | + throw MalformedCorpusLine(line: index + 1) |
| 38 | + } |
| 39 | + return obj |
| 40 | + } |
| 41 | + } |
| 42 | + |
| 43 | + private static func signals(_ r: [String: Any]) -> [String: Any] { |
| 44 | + (r["signals"] as? [String: Any]) ?? [:] |
| 45 | + } |
| 46 | + |
| 47 | + @Test("corpus has the expected total record count") |
| 48 | + func totalRecords() throws { |
| 49 | + let recs = try Self.records() |
| 50 | + #expect(recs.count >= 200, |
| 51 | + "corpus.jsonl should hold the full corpus (200+ folders); found \(recs.count). A drop means records were lost in regeneration.") |
| 52 | + } |
| 53 | + |
| 54 | + @Test("TRM-restriction fixtures present (DAR-134)") |
| 55 | + func trmFixtures() throws { |
| 56 | + let n = try Self.records().filter { ((Self.signals($0)["trm_restricted"] as? Int) ?? 0) > 0 }.count |
| 57 | + #expect(n >= 30, "expected 30+ TRM-restricted folders as fixtures for DAR-134; found \(n)") |
| 58 | + } |
| 59 | + |
| 60 | + @Test("CIO / connected-Thunderbolt fixtures present") |
| 61 | + func cioFixtures() throws { |
| 62 | + let n = try Self.records().filter { ((($0["cio_blocks"] as? Int)) ?? 0) > 0 }.count |
| 63 | + #expect(n >= 25, "expected 25+ CIO folders (mine-cio + port-key fixtures); found \(n)") |
| 64 | + } |
| 65 | + |
| 66 | + @Test("advanced-PD fixtures present (DAR-136)") |
| 67 | + func advancedPDFixtures() throws { |
| 68 | + let n = try Self.records().filter { ((Self.signals($0)["advanced_pd"] as? [Any]) ?? []).isEmpty == false }.count |
| 69 | + #expect(n >= 80, "expected 80+ advanced-PD folders as fixtures for DAR-136; found \(n)") |
| 70 | + } |
| 71 | + |
| 72 | + @Test("zeroed-VID cable-trust fixtures present (DAR-137)") |
| 73 | + func zeroedVIDFixtures() throws { |
| 74 | + let n = try Self.records().filter { |
| 75 | + (($0["trust"] as? [String: Any])?["zeroed_vid_cables"] as? [Any] ?? []).isEmpty == false |
| 76 | + }.count |
| 77 | + #expect(n >= 20, "expected 20+ zeroed-VID cable folders as fixtures for DAR-137; found \(n)") |
| 78 | + } |
| 79 | + |
| 80 | + @Test("Billboard fixtures present") |
| 81 | + func billboardFixtures() throws { |
| 82 | + let n = try Self.records().filter { ((Self.signals($0)["billboard"] as? Int) ?? 0) > 0 }.count |
| 83 | + #expect(n >= 30, "expected 30+ Billboard (bDeviceClass 0x11) folders; found \(n)") |
| 84 | + } |
| 85 | +} |
0 commit comments