use anyhow::{Result, ensure};
use serde_yaml::Value;
#[path = "coverage_workflows/closure_properties.rs"]
mod closure_properties;
#[path = "coverage_workflows/placement.rs"]
mod placement;
#[path = "coverage_workflows/placement_cases.rs"]
mod placement_cases;
#[path = "coverage_workflows/publisher_cases.rs"]
mod publisher_cases;
#[path = "coverage_workflows/pull_request_cases.rs"]
mod pull_request_cases;
#[path = "coverage_workflows/reader.rs"]
mod reader;
#[path = "coverage_workflows/rules.rs"]
mod rules;
#[path = "coverage_workflows/text.rs"]
mod text;
const KNOWN_PULL_REQUEST_WORKFLOWS: [&str; 2] = ["ci.yml", "verus.yml"];
#[test]
fn no_workflow_a_pull_request_reaches_touches_codescene() -> Result<()> {
let all = reader::workflows()?;
let closure = reader::pull_request_closure(&all);
for known in KNOWN_PULL_REQUEST_WORKFLOWS {
ensure!(
closure.contains(known),
"{known} is no longer read as a pull-request workflow; the closure is {closure:?}"
);
}
let breaches: Vec<String> = closure
.iter()
.filter_map(|name| Some((name, all.get(name)?)))
.flat_map(|(name, workflow)| {
rules::pull_request_findings(workflow)
.into_iter()
.map(move |finding| format!("{name}: {finding}"))
})
.chain(reader::missing_callees(&all, &closure))
.collect();
ensure!(breaches.is_empty(), "CV-005 breaches: {breaches:?}");
Ok(())
}
#[test]
fn exactly_one_main_publisher_uploads_ratcheted_coverage() -> Result<()> {
let all = reader::workflows()?;
let publishers: Vec<(&String, &Value)> = all
.iter()
.filter(|(_, workflow)| rules::publishes_from_main(workflow))
.collect();
let [(name, workflow)] = publishers.as_slice() else {
let names: Vec<_> = publishers.iter().map(|(name, _)| name).collect();
anyhow::bail!("expected one push-to-main publisher, found {names:?}");
};
ensure!(
!reader::pull_request_closure(&all).contains(*name),
"{name} publishes from main but a pull request can reach it"
);
let mut findings = rules::publisher_findings(workflow);
findings.extend(rules::wiring_findings(workflow));
ensure!(findings.is_empty(), "{name}: {findings:?}");
Ok(())
}
fn baselines(name: &str, workflow: &Value) -> Vec<(String, String, String)> {
reader::steps(workflow)
.into_iter()
.filter(|step| reader::uses(step).is_some_and(|r| r.starts_with(rules::COVERAGE_ACTION)))
.map(|step| {
let with = reader::get(step, "with").and_then(Value::as_mapping);
let path = |key: &str| {
with.and_then(|with| reader::get(with, key))
.and_then(Value::as_str)
.unwrap_or("<default>")
.to_owned()
};
(
name.to_owned(),
path("baseline-rust-file"),
path("baseline-python-file"),
)
})
.collect()
}
#[test]
fn every_pull_request_lane_reads_the_publisher_baseline() -> Result<()> {
let all = reader::workflows()?;
let written: Vec<_> = all
.iter()
.filter(|(_, workflow)| rules::publishes_from_main(workflow))
.flat_map(|(name, workflow)| baselines(name, workflow))
.collect();
let [(_, rust, python)] = written.as_slice() else {
anyhow::bail!("expected one publisher coverage step, saw {written:?}");
};
let read: Vec<_> = reader::pull_request_closure(&all)
.iter()
.filter_map(|name| Some(baselines(name, all.get(name)?)))
.flatten()
.collect();
ensure!(!read.is_empty(), "no pull-request lane measures coverage");
for (name, lane_rust, lane_python) in &read {
ensure!(
(lane_rust, lane_python) == (rust, python),
"{name} reads {lane_rust} / {lane_python}, the publisher writes {rust} / {python}"
);
}
Ok(())
}