Files
Sylpheed/crates/sylpheed-formats/tests/ui_opt_link_disc.rs
Fabian Hamm 15d51b30ac test(formats): make $SYLPHEED_DISC an actual control (#16 remedy 3)
Before this commit, `unset SYLPHEED_DISC` did not disable the disc-backed
suites on the machine that has the disc: every `disc_root()` fell back to a
hardcoded absolute path that exists on this box. The env var looked like a
control and was not one. Same for $SYLPHEED_RES3D and $SYLPHEED_ISO.

Replace the duplicated resolvers with one `tests/common/mod.rs`:

  - 17 local `disc_root()` definitions -> 1
  - 7 copies of the skip macro -> 1 (`skip_without_disc!` and siblings)
  - 16 hardcoded absolute paths -> 0 executable ones
    (3 of those were inline in `mesh_disc.rs`, in no resolver at all,
     and 2 were in `examples/`)
  - `corpus_report.rs` now reports on the SAME resolver the suites use,
    instead of a second copy of the logic its own comments flagged as a
    drift risk.

The 17 copies had already drifted into FIVE variants, and they were not all
the same function. `movie_manifest_disc`, `movie_subtitle_disc` and `slb_disc`
honoured $SYLPHEED_DISC and nothing else, while the other 14 fell back. So one
name already meant two things -- a third instance of the shape #16 is about.
The shared helper adopts the env-only behaviour those three already had, rather
than inventing a sixth variant.

Two module docs still described the fallback after it was deleted, which is the
same defect in prose: `texture_disc` claimed "or the default dev path exists"
and `pak_idxd_disc` said "or drop it at the default dev path below". Both now
say what the code does.

Verified both ways on the machine that HAS the corpus, which is the only place
this refactor can be falsified:

  A  env unset  -> "ABSENT -- $SYLPHEED_DISC unset; its suites self-skip"
                   suites=31 passed=209 failed=0 ignored=14, slowest 0.12s
  B  env set    -> "PRESENT via $SYLPHEED_DISC" (all three corpora)
                   suites=31 passed=209 failed=0 ignored=14,
                   slowest 1235.53s (mesh_consistency_disc)

Identical tallies, opposite corpus states, ~10000x apart in wall clock. (A) is
new behaviour -- it was previously unreachable here. (B) proves nothing broke.

`just test-disc` sources `.env` (already gitignored) for the set case. Note the
quoting trap documented there: the corpus paths contain spaces, and an unquoted
`VAR=a b c` parses as "run command `b`", failing silently into ABSENT -- which
looks exactly like a working skip.

Remedy (1) (`#[ignore]` + `--ignored`) is deliberately NOT done here: (3) already
moves the mode from the filesystem into the environment, and `#[ignore]` already
carries three meanings in this directory (corpus-absent, known-failing, bare).
Overloading it a fourth time would re-create the defect.

`cargo fmt --all --check` clean; no new compiler warnings.

Refs #16

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-10 20:47:23 +02:00

160 lines
5.9 KiB
Rust

//! What does the `.rat` record's `opt ` link actually point at?
//!
//! `ui-rat-layout.md` reads it as *normal state → focused state*, from one
//! example: `pgpbtn00.rat` links to `pgpbtn00f.rat`. The backlog carries the
//! opposite verdict — "refuted as focus; unexplained otherwise" — with no number
//! behind either. This settles it by classifying **every** `opt ` link on the
//! disc, so the answer is a distribution rather than an anecdote.
//!
//! Four questions per link, in order of how much they would explain:
//! 1. is the target `<source stem>f.<ext>` — the focus pattern?
//! 2. is the target another element of the SAME build?
//! 3. is it a RATC child of the bundle (a resource rather than an element)?
//! 4. otherwise: what do the leftovers look like?
use std::collections::{HashMap, HashSet};
use std::path::{Path, PathBuf};
use sylpheed_formats::{pak::PakArchive, ratc, ui_layout};
mod common;
use common::disc_root;
fn for_each_build(root: &Path, mut f: impl FnMut(&str, &[u8])) {
let mut paks: Vec<PathBuf> = std::fs::read_dir(root.join("dat"))
.expect("dat/")
.flatten()
.map(|e| e.path())
.filter(|p| p.extension().and_then(|s| s.to_str()) == Some("pak"))
.collect();
paks.sort();
for p in &paks {
let name = p.file_name().unwrap().to_string_lossy().to_string();
let Ok(arc) = PakArchive::open(p) else {
continue;
};
for e in arc.entries() {
let Ok(bytes) = arc.read(e) else { continue };
if ratc::is_ratc(&bytes) {
f(&name, &bytes);
}
}
}
}
#[test]
fn every_opt_link_on_the_disc_is_classified() {
let Some(root) = disc_root() else {
eprintln!("SKIP: extracted disc not found (set SYLPHEED_DISC to enable)");
return;
};
let (mut links, mut focus_pattern, mut same_build, mut ratc_child) = (0usize, 0, 0, 0);
// `opt_link` returns the FIRST `opt ` tag in a record. If records can carry
// several, every count here understates - so count the tags themselves in
// the raw bundle rather than trusting the parser's one-per-record view.
let mut opt_tags = 0usize;
let mut self_link = 0usize;
let mut ext_pairs: HashMap<(String, String), usize> = HashMap::new();
let mut leftovers: Vec<String> = Vec::new();
for_each_build(&root, |pak, bytes| {
let Some(build) = ui_layout::parse_build(bytes) else {
return;
};
if build.from_fallback {
return;
}
let names: HashSet<String> = build
.elements
.iter()
.map(|e| e.name.to_ascii_lowercase())
.collect();
let kids: HashSet<String> = ratc::parse(bytes)
.unwrap_or_default()
.into_iter()
.map(|c| c.name.to_ascii_lowercase())
.collect();
opt_tags += bytes.windows(4).filter(|w| *w == b"opt ").count();
for el in &build.elements {
let Some(target) = el.focus_link.as_ref() else {
continue;
};
links += 1;
let src = el.name.to_ascii_lowercase();
let tgt = target.to_ascii_lowercase();
let se = src
.rsplit_once('.')
.map(|(_, e)| e.to_string())
.unwrap_or_default();
let te = tgt
.rsplit_once('.')
.map(|(_, e)| e.to_string())
.unwrap_or_default();
*ext_pairs.entry((se, te)).or_default() += 1;
if tgt == src {
self_link += 1;
}
let is_focus = src
.rsplit_once('.')
.map(|(stem, ext)| format!("{stem}f.{ext}") == tgt)
.unwrap_or(false);
if is_focus {
focus_pattern += 1;
}
if names.contains(&tgt) {
same_build += 1;
}
if kids.contains(&tgt) {
ratc_child += 1;
}
if !is_focus && leftovers.len() < 14 {
leftovers.push(format!(
"{pak}: {} -> {}{}",
el.name,
target,
if names.contains(&tgt) {
" [declared element]"
} else {
""
}
));
}
}
});
eprintln!("opt links on the disc: {links} raw `opt ` tags in the bundles: {opt_tags}");
eprintln!(" target is <stem>f.<ext> (the focus pattern): {focus_pattern}");
eprintln!(" target is another element of the same build: {same_build}");
eprintln!(" target is a RATC child of the bundle: {ratc_child}");
eprintln!(" target is the element ITSELF: {self_link}");
let mut ep: Vec<_> = ext_pairs.iter().collect();
ep.sort_by_key(|(_, n)| std::cmp::Reverse(**n));
eprintln!(" source-ext -> target-ext: {:?}", &ep[..ep.len().min(8)]);
for l in &leftovers {
eprintln!(" NOT the f-pattern: {l}");
}
assert!(links > 0, "no opt links found — the sweep is broken");
// MEASURED 2026-08-24 and asserted, because both prior readings were wrong
// in different directions: `opt ` is not "the focused state" (that fits 73 %
// of links, not all of them) and it is not "unexplained" either — EVERY
// link resolves to a RATC child of its own bundle, and every one is
// .rat -> .rat.
assert_eq!(links, 1467, "the disc has 1467 opt links");
assert_eq!(
ratc_child, links,
"an opt link does not resolve to a RATC child"
);
assert_eq!(
ext_pairs
.get(&("rat".to_string(), "rat".to_string()))
.copied(),
Some(links),
"an opt link points at something other than a .rat record"
);
assert_eq!(self_link, 0, "a record links to itself");
assert_eq!(focus_pattern, 1076, "the f-pattern share moved");
}