use std::collections::BTreeMap;
use std::fmt::Write;
use crate::persist::local::models::catalogued_test::CataloguedTest;
use crate::persist::local::repos::catalogue_repo::CatalogueRepo;
use crate::catalogue::scan::display_repo;
pub struct Survey {
pub per_repo: Vec<(String, i64, i64)>,
pub duplicates: Vec<(String, i64, Vec<CataloguedTest>)>,
pub misnumbered: Vec<CataloguedTest>,
pub total: i64,
pub numbered: i64,
}
impl Survey {
pub fn read(repo: &CatalogueRepo) -> anyhow::Result<Self> {
let per_repo = repo.per_repo_counts()?;
let total = per_repo.iter().map(|(_, all, _)| all).sum();
let numbered = per_repo.iter().map(|(_, _, numbered)| numbered).sum();
Ok(Self {
per_repo,
duplicates: repo.duplicates_within_repos()?,
misnumbered: repo.misnumbered()?,
total,
numbered,
})
}
pub fn is_clean(&self) -> bool {
self.duplicates.is_empty() && self.misnumbered.is_empty()
}
pub fn render(&self) -> String {
let mut out = String::new();
let _ = writeln!(
out,
"{} tests, {} numbered, across {} repositories",
self.total,
self.numbered,
self.per_repo.len()
);
let width = self
.per_repo
.iter()
.map(|(repo, ..)| display_repo(repo).len())
.max()
.unwrap_or(0);
for (repo, all, numbered) in &self.per_repo {
let _ = writeln!(
out,
" {:width$} {:>5} tests {:>5} numbered",
display_repo(repo),
all,
numbered,
width = width
);
}
if self.duplicates.is_empty() {
let _ = writeln!(out, "\nNo number is used twice within a repository.");
} else {
let _ = writeln!(
out,
"\n{} number(s) used more than once within one repository:",
self.duplicates.len()
);
for (repo, number, members) in &self.duplicates {
let _ = writeln!(out, " {} TEST{number}", display_repo(repo));
for member in members {
let _ = writeln!(out, " {} — {}", member.location(), member.function_name);
}
}
}
if self.misnumbered.is_empty() {
let _ = writeln!(out, "\nEvery description agrees with the name above it.");
} else {
let _ = writeln!(
out,
"\n{} test(s) whose name and description claim different numbers:",
self.misnumbered.len()
);
for test in &self.misnumbered {
let _ = writeln!(
out,
" {} {} — named TEST{}, described as TEST{}",
display_repo(&test.repo),
test.location(),
test.number.unwrap_or_default(),
test.described_number().unwrap_or_default()
);
}
}
out
}
}
pub struct Parity {
pub members: Vec<String>,
pub rows: BTreeMap<i64, Vec<bool>>,
}
impl Parity {
pub fn read(repo: &CatalogueRepo, members: &[String]) -> anyhow::Result<Self> {
let coverage = repo.number_coverage()?;
let mut rows = BTreeMap::new();
for (number, repos) in coverage {
let present: Vec<bool> = members.iter().map(|m| repos.contains(m)).collect();
if present.iter().any(|p| *p) {
rows.insert(number, present);
}
}
Ok(Self {
members: members.to_vec(),
rows,
})
}
pub fn gaps(&self) -> Vec<(i64, Vec<String>)> {
self.rows
.iter()
.filter(|(_, present)| present.iter().any(|p| *p) && present.iter().any(|p| !*p))
.map(|(number, present)| {
let missing = self
.members
.iter()
.zip(present)
.filter(|(_, have)| !**have)
.map(|(member, _)| member.clone())
.collect();
(*number, missing)
})
.collect()
}
pub fn render(&self) -> String {
let mut out = String::new();
let gaps = self.gaps();
let _ = writeln!(
out,
"{} numbers across {} members; {} complete, {} with gaps",
self.rows.len(),
self.members.len(),
self.rows.len() - gaps.len(),
gaps.len()
);
if gaps.is_empty() {
return out;
}
let _ = writeln!(out);
for (number, missing) in gaps {
let _ = writeln!(out, " TEST{number} missing from {}", missing.join(", "));
}
out
}
}
pub fn parity_markdown(repo: &CatalogueRepo, members: &[String]) -> anyhow::Result<String> {
const SHARED_CEILING: i64 = 8000;
let parity = Parity::read(repo, members)?;
let all = repo.all()?;
let survey = Survey::read(repo)?;
let mut by_number: BTreeMap<i64, BTreeMap<String, Vec<&CataloguedTest>>> = BTreeMap::new();
for test in &all {
let (Some(number), true) = (test.number, members.contains(&test.repo)) else {
continue;
};
by_number
.entry(number)
.or_default()
.entry(test.repo.clone())
.or_default()
.push(test);
}
let label = |member: &str| -> String { member.rsplit('/').next().unwrap_or(member).to_string() };
let normalized = |text: &str| -> String {
text.split_whitespace().collect::<Vec<_>>().join(" ").to_lowercase()
};
let mut out = String::new();
let _ = writeln!(out, "# Cross-Mirror Test Parity\n");
let _ = writeln!(
out,
"> Generated from the test catalogue — do not hand-edit. Rescan and regenerate after \
changing any mirror's tests.\n"
);
let _ = writeln!(
out,
"Numbers **1–{}** are the SHARED range: the same number must test the same thing, with \
the same method, in every mirror that implements that feature. Numbers \
**{SHARED_CEILING}+** are implementation-specific.\n",
SHARED_CEILING - 1
);
let _ = writeln!(out, "## Mirrors scanned\n");
let _ = writeln!(out, "| Mirror | Numbered tests |");
let _ = writeln!(out, "|---|---|");
for member in members {
let count = all.iter().filter(|t| t.repo == *member && t.number.is_some()).count();
let _ = writeln!(out, "| `{}` | {count} |", display_repo(member));
}
let _ = writeln!(out);
let solo: Vec<i64> = by_number
.iter()
.filter(|(_, per_member)| per_member.len() == 1)
.map(|(number, _)| *number)
.collect();
let solo_shared: Vec<i64> = solo.iter().copied().filter(|n| *n < SHARED_CEILING).collect();
let gaps = parity.gaps();
let shared_gaps: Vec<&(i64, Vec<String>)> = gaps
.iter()
.filter(|(number, _)| *number < SHARED_CEILING)
.filter(|(number, _)| by_number.get(number).is_some_and(|m| m.len() > 1))
.collect();
let divergent: Vec<i64> = by_number
.iter()
.filter(|(_, per_member)| per_member.len() > 1)
.filter(|(_, per_member)| {
let mut seen: Vec<String> = per_member
.values()
.filter_map(|tests| tests.first())
.map(|t| normalized(&t.description))
.filter(|d| !d.is_empty())
.collect();
seen.sort();
seen.dedup();
seen.len() > 1
})
.map(|(number, _)| *number)
.collect();
let family_duplicates: Vec<&(String, i64, Vec<CataloguedTest>)> = survey
.duplicates
.iter()
.filter(|(member, ..)| members.contains(member))
.collect();
let _ = writeln!(out, "## Summary\n");
let _ = writeln!(out, "- Distinct numbered tests across all mirrors: **{}**", by_number.len());
let _ = writeln!(out, "- Shared (in \u{2265}2 mirrors): **{}**", by_number.len() - solo.len());
let _ = writeln!(out, "- Solo (in exactly 1 mirror): **{}**", solo.len());
let _ = writeln!(
out,
" - \u{2026}in the shared range 1\u{2013}{} \u{2014} **port targets**, unless the \
behaviour is genuinely implementation-specific, in which case the test moves to \
{SHARED_CEILING}+: **{}**",
SHARED_CEILING - 1,
solo_shared.len()
);
let _ = writeln!(
out,
" - \u{2026}already in the {SHARED_CEILING}+ implementation-specific range: **{}**",
solo.len() - solo_shared.len()
);
let _ = writeln!(
out,
"- Shared numbers with a parity gap (missing from \u{2265}1 mirror): **{}**",
shared_gaps.len()
);
let _ = writeln!(
out,
"- Shared numbers described differently by different mirrors: **{}**",
divergent.len()
);
let _ = writeln!(out, "- Within-mirror duplicate numbers: **{}**\n", family_duplicates.len());
let _ = writeln!(out, "---\n");
let _ = writeln!(out, "## Solo tests in the shared range \u{2192} port worklist\n");
let _ = writeln!(
out,
"These numbered tests exist in exactly ONE mirror but occupy the shared range. The \
default disposition is to port them to the others keeping the number.\n"
);
let _ = writeln!(out, "| Test # | Mirror | Function | Description | File |");
let _ = writeln!(out, "|---|---|---|---|---|");
for number in &solo_shared {
let Some(per_member) = by_number.get(number) else { continue };
for (member, tests) in per_member {
for test in tests {
let _ = writeln!(
out,
"| TEST{number} | `{}` | `{}` | {} | {} |",
label(member),
test.function_name,
cell(&test.description),
test.location()
);
}
}
}
let _ = writeln!(out);
let _ = writeln!(out, "## Parity gaps (shared number missing from a mirror)\n");
let _ = writeln!(
out,
"A shared-range number present in some mirrors and absent from others. A gap is \
legitimate only when the missing mirror does not implement the feature.\n"
);
let _ = writeln!(out, "| Test # | Present in | Missing from | Description (first present) |");
let _ = writeln!(out, "|---|---|---|---|");
for (number, missing) in &shared_gaps {
let Some(per_member) = by_number.get(number) else { continue };
let present: Vec<String> = per_member.keys().map(|m| label(m)).collect();
let description = per_member
.values()
.filter_map(|tests| tests.first())
.map(|t| t.description.clone())
.find(|d| !d.is_empty())
.unwrap_or_default();
let _ = writeln!(
out,
"| TEST{number} | {} | {} | {} |",
present.join(", "),
missing.iter().map(|m| label(m)).collect::<Vec<_>>().join(", "),
cell(&description)
);
}
let _ = writeln!(out);
let _ = writeln!(out, "## Divergent descriptions (same number, different wording)\n");
let _ = writeln!(
out,
"Same number, materially different descriptions. Read each: wording drift is fine, two \
different tests wearing one number is not.\n"
);
for number in &divergent {
let Some(per_member) = by_number.get(number) else { continue };
let _ = writeln!(out, "### TEST{number}\n");
for (member, tests) in per_member {
for test in tests {
let _ = writeln!(out, "- **{}**: {}", label(member), cell(&test.description));
}
}
let _ = writeln!(out);
}
let _ = writeln!(out, "## Within-mirror duplicate numbers\n");
if family_duplicates.is_empty() {
let _ = writeln!(out, "None.\n");
} else {
let _ = writeln!(
out,
"A number assigned to more than one function inside a single mirror. These must be \
fixed \u{2014} renumber all but the first \u{2014} whatever the cross-mirror picture \
says.\n"
);
for (member, number, tests) in &family_duplicates {
let _ = writeln!(
out,
"- `{}` TEST{number}: {}",
label(member),
tests
.iter()
.map(|t| format!("`{}` ({})", t.function_name, t.location()))
.collect::<Vec<_>>()
.join(", ")
);
}
let _ = writeln!(out);
}
let _ = writeln!(out, "## Full matrix\n");
let _ = writeln!(
out,
"\u{2713} = present, \u{b7} = absent. Range: `shared` below {SHARED_CEILING}, `impl` at \
or above it.\n"
);
let _ = writeln!(
out,
"| Test # | Range | {} | Kind |",
members.iter().map(|m| label(m)).collect::<Vec<_>>().join(" | ")
);
let _ = writeln!(
out,
"|---|---|{}---|",
members.iter().map(|_| "---|").collect::<String>()
);
for (number, present) in &parity.rows {
let range = if *number < SHARED_CEILING { "shared" } else { "impl" };
let kind = if present.iter().filter(|p| **p).count() > 1 { "shared" } else { "solo" };
let _ = writeln!(
out,
"| TEST{number} | {range} | {} | {kind} |",
present
.iter()
.map(|have| if *have { "\u{2713}" } else { "\u{b7}" })
.collect::<Vec<_>>()
.join(" | ")
);
}
Ok(out)
}
fn cell(description: &str) -> String {
let flattened = description
.split_whitespace()
.map(|word| word.trim_start_matches(['/', '#', '*']))
.filter(|word| !word.is_empty())
.collect::<Vec<_>>()
.join(" ");
if flattened.is_empty() {
"\u{2014}".to_string()
} else {
flattened.replace('|', "\\|")
}
}
pub fn markdown(repo: &CatalogueRepo, only_repo: Option<&str>) -> anyhow::Result<String> {
let tests: Vec<CataloguedTest> = repo
.all()?
.into_iter()
.filter(|test| only_repo.is_none_or(|wanted| test.repo == wanted))
.collect();
let mut out = String::new();
let scope = match only_repo {
Some(repo) => display_repo(repo).to_string(),
None => "the workspace".to_string(),
};
let _ = writeln!(out, "# Test catalogue — {scope}\n");
let _ = writeln!(
out,
"Generated from the test catalogue. Edit the tests, not this file.\n"
);
let numbered: Vec<&CataloguedTest> = tests.iter().filter(|t| t.number.is_some()).collect();
let unnumbered: Vec<&CataloguedTest> = tests.iter().filter(|t| t.number.is_none()).collect();
let _ = writeln!(
out,
"{} tests: {} numbered, {} unnumbered.\n",
tests.len(),
numbered.len(),
unnumbered.len()
);
if !numbered.is_empty() {
let _ = writeln!(out, "## Numbered\n");
let _ = writeln!(out, "| Number | Repository | Language | Test | Location | Description |");
let _ = writeln!(out, "|---|---|---|---|---|---|");
for test in numbered {
let _ = writeln!(
out,
"| TEST{} | {} | {} | `{}` | {} | {} |",
test.number.unwrap_or_default(),
display_repo(&test.repo),
test.language.as_str(),
test.function_name,
test.location(),
test.description.replace('|', "\\|")
);
}
let _ = writeln!(out);
}
if !unnumbered.is_empty() {
let _ = writeln!(out, "## Unnumbered\n");
let _ = writeln!(out, "| Repository | Language | Test | Location |");
let _ = writeln!(out, "|---|---|---|---|");
for test in unnumbered {
let _ = writeln!(
out,
"| {} | {} | `{}` | {} |",
display_repo(&test.repo),
test.language.as_str(),
test.function_name,
test.location()
);
}
}
Ok(out)
}
#[cfg(test)]
#[path = "report_tests.rs"]
mod tests;