Finishes #16 in the three places its earlier remedies missed. `tests/`: the last four local `disc_root()` copies now use `tests/common`, and with them goes the one real hardcoded fallback — `ui_keyframe_record_disc.rs` fell back to an absolute path on one machine, which made `unset SYLPHEED_DISC` a no-op there. Control: with the corpus absent that suite now finishes in 0.00s instead of 57.55s, so it skips rather than finding a disc of its own. `examples/`: seventeen examples defaulted to `/disc`, the mount point inside the CI container. Redundant there — `docker/ci/run` sets `SYLPHEED_DISC=/disc` — and wrong everywhere else, where a missing corpus turned into a file-not-found against a path that has never existed on the host. They now name the variable to set, like the other hundred examples already did. `docker/ci/run`: mount `$SYLPHEED_RES3D` and `$SYLPHEED_ISO` alongside the disc. Only the disc was mounted, so an in-container run sat out the res3d and iso suites while looking like a full one — the defect this issue is about, in the runner itself. Measured in the container on this desktop with all three corpora present: 45 suites / 377 passed / 0 failed / 14 ignored, and `sylpheed-corpus-report.txt` now reports PRESENT for all three rather than for the disc alone. Refs #16. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
99 lines
3.9 KiB
Rust
99 lines
3.9 KiB
Rust
//! Which focus records have a VARYING alpha — disc-wide, not export-wide?
|
|
//!
|
|
//! `rest()` returns an element's last hold keyframe. For a constant-alpha
|
|
//! element that is harmless. For one that pulses it returns the PEAK, which is
|
|
//! the `ui-settle-time.md` pathology: the plate's `ptbtn00f` ramps 0→80→0 and
|
|
//! `rest()` reports 80, its maximum.
|
|
//!
|
|
//! The port censused this over its own export (34 records, 2 varying) and
|
|
//! concluded there is nothing to fix. That conclusion is only as wide as the
|
|
//! export. This asks the same question of the whole disc.
|
|
use sylpheed_formats::{pak, ratc, ui_layout};
|
|
|
|
fn main() {
|
|
let root =
|
|
std::env::var("SYLPHEED_DISC").expect("set SYLPHEED_DISC to the extracted disc root");
|
|
let mut paks: Vec<_> = std::fs::read_dir(format!("{root}/dat"))
|
|
.expect("dat/")
|
|
.flatten()
|
|
.map(|e| e.path())
|
|
.filter(|p| p.extension().and_then(|s| s.to_str()) == Some("pak"))
|
|
.collect();
|
|
paks.sort();
|
|
let (mut n_rec, mut n_elem, mut varying) = (0usize, 0usize, 0usize);
|
|
let (mut at_peak, mut mid_ramp) = (0usize, 0usize);
|
|
let mut by_pak: std::collections::BTreeMap<String, usize> = Default::default();
|
|
let mut hits: Vec<String> = Vec::new();
|
|
for p in &paks {
|
|
let pn = p.file_name().unwrap().to_string_lossy().to_string();
|
|
let Ok(ar) = pak::PakArchive::open(p) else {
|
|
continue;
|
|
};
|
|
for (ei, e) in ar.entries().iter().enumerate() {
|
|
let Ok(by) = ar.read(e) else { continue };
|
|
if !ratc::is_ratc(&by) {
|
|
continue;
|
|
}
|
|
let Some(b) = ui_layout::parse_build(&by) else {
|
|
continue;
|
|
};
|
|
for (rn, &(o, s)) in &b.records {
|
|
// A focus record is one whose name is another record's plus `f`.
|
|
let Some(stem) = rn.strip_suffix("f.rat") else {
|
|
continue;
|
|
};
|
|
if !b.records.contains_key(&format!("{stem}.rat")) {
|
|
continue;
|
|
}
|
|
if o + s > by.len() {
|
|
continue;
|
|
}
|
|
let Some(lb) = ui_layout::parse_build(&by[o..o + s]) else {
|
|
continue;
|
|
};
|
|
n_rec += 1;
|
|
for el in &lb.elements {
|
|
if el.keyframes.is_empty() {
|
|
continue;
|
|
}
|
|
n_elem += 1;
|
|
let a: Vec<u32> = el.keyframes.iter().map(|k| k.fade >> 24).collect();
|
|
let (lo, hi) = (*a.iter().min().unwrap(), *a.iter().max().unwrap());
|
|
if lo == hi {
|
|
continue;
|
|
}
|
|
varying += 1;
|
|
let rest = el.rest().map(|k| k.fade >> 24).unwrap_or(0);
|
|
if rest == hi {
|
|
at_peak += 1
|
|
} else {
|
|
mid_ramp += 1
|
|
}
|
|
*by_pak.entry(pn.clone()).or_default() += 1;
|
|
hits.push(format!(
|
|
"{pn} [{ei}] {rn}::{} alpha {lo}..{hi} rest()={rest}{}",
|
|
el.name,
|
|
if rest == hi { " 🔴 == PEAK" } else { "" }
|
|
));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
println!("focus records disc-wide : {n_rec}");
|
|
println!(" their timed elements : {n_elem}");
|
|
println!(" with a VARYING alpha : {varying}");
|
|
println!(" of which rest() == the PEAK : {at_peak} <- burns bright forever");
|
|
println!(" of which rest() is MID-RAMP : {mid_ramp} <- neither extreme; looks plausible");
|
|
println!("\nby pak:");
|
|
for (k, v) in &by_pak {
|
|
println!(" {k:<34} {v}")
|
|
}
|
|
println!("\nevery varying one:");
|
|
hits.sort();
|
|
hits.dedup();
|
|
for h in &hits {
|
|
println!(" {h}")
|
|
}
|
|
println!("\n({} distinct)", hits.len());
|
|
}
|