use std::collections::{BTreeMap, BTreeSet};
use toml::Value;
fn manifest() -> Value {
let path = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("Cargo.toml");
let text =
std::fs::read_to_string(&path).unwrap_or_else(|e| panic!("read {}: {e}", path.display()));
text.parse::<Value>()
.unwrap_or_else(|e| panic!("parse {}: {e}", path.display()))
}
fn feature_graph(manifest: &Value) -> BTreeMap<String, Vec<String>> {
let table = manifest
.get("features")
.and_then(Value::as_table)
.expect("[features] table");
table
.iter()
.map(|(name, enables)| {
let edges = enables
.as_array()
.unwrap_or_else(|| panic!("feature `{name}` must be an array"))
.iter()
.filter_map(Value::as_str)
.filter(|e| !e.starts_with("dep:") && !e.contains('/'))
.map(str::to_owned)
.collect();
(name.clone(), edges)
})
.collect()
}
fn closure(graph: &BTreeMap<String, Vec<String>>, seeds: &[String]) -> BTreeSet<String> {
let mut seen = BTreeSet::new();
let mut stack: Vec<String> = seeds.to_vec();
while let Some(feature) = stack.pop() {
if !seen.insert(feature.clone()) {
continue;
}
if let Some(edges) = graph.get(&feature) {
stack.extend(edges.iter().cloned());
}
}
seen
}
struct Coverage {
lanes: Vec<(String, Vec<String>)>,
exempt: Vec<(String, String)>,
}
fn coverage(manifest: &Value) -> Coverage {
let table = manifest
.get("package")
.and_then(|p| p.get("metadata"))
.and_then(|m| m.get("trusty-test-coverage"))
.and_then(Value::as_table)
.expect("[package.metadata.trusty-test-coverage] table — see #4474");
let lanes = table
.get("lanes")
.and_then(Value::as_array)
.expect("`lanes` array")
.iter()
.map(|lane| {
let name = lane
.get("name")
.and_then(Value::as_str)
.expect("every lane needs a `name`")
.to_owned();
let features = lane
.get("features")
.and_then(Value::as_array)
.unwrap_or_else(|| panic!("lane `{name}` needs a `features` array"))
.iter()
.filter_map(Value::as_str)
.map(str::to_owned)
.collect();
(name, features)
})
.collect();
let exempt = table
.get("exempt")
.and_then(Value::as_array)
.expect("`exempt` array")
.iter()
.map(|row| {
let feature = row
.get("feature")
.and_then(Value::as_str)
.expect("every exemption needs a `feature`")
.to_owned();
let reason = row
.get("reason")
.and_then(Value::as_str)
.unwrap_or_default()
.to_owned();
(feature, reason)
})
.collect();
Coverage { lanes, exempt }
}
#[test]
fn every_declared_feature_is_covered_by_a_lane_or_exempted() {
let manifest = manifest();
let graph = feature_graph(&manifest);
let coverage = coverage(&manifest);
let mut covered = BTreeSet::new();
for (_, features) in &coverage.lanes {
covered.extend(closure(&graph, features));
}
covered.extend(coverage.exempt.iter().map(|(f, _)| f.clone()));
let declared: BTreeSet<String> = graph.keys().cloned().collect();
let uncovered: Vec<&String> = declared.difference(&covered).collect();
assert!(
uncovered.is_empty(),
"these trusty-common features are in no coverage lane and carry no exemption: {uncovered:?}\n\
No `cargo test -p trusty-common` invocation runs their tests, so they can regress green.\n\
Add each to a lane in [package.metadata.trusty-test-coverage] in crates/trusty-common/Cargo.toml,\n\
or add an `exempt` row saying why no lane can run it. See #4474."
);
}
#[test]
fn lanes_and_exemptions_name_only_declared_features() {
let manifest = manifest();
let declared: BTreeSet<String> = feature_graph(&manifest).keys().cloned().collect();
let coverage = coverage(&manifest);
let named = coverage
.lanes
.iter()
.flat_map(|(lane, features)| features.iter().map(move |f| (lane.as_str(), f)))
.chain(coverage.exempt.iter().map(|(f, _)| ("exempt", f)));
let stale: Vec<String> = named
.filter(|(_, feature)| !declared.contains(*feature))
.map(|(owner, feature)| format!("{owner}: {feature}"))
.collect();
assert!(
stale.is_empty(),
"coverage rows name features this crate no longer declares: {stale:?}\n\
Fix the names in [package.metadata.trusty-test-coverage] in crates/trusty-common/Cargo.toml."
);
}
#[test]
fn every_exemption_states_a_reason() {
let manifest = manifest();
let coverage = coverage(&manifest);
let unreasoned: Vec<&String> = coverage
.exempt
.iter()
.filter(|(_, reason)| reason.trim().is_empty())
.map(|(feature, _)| feature)
.collect();
assert!(
unreasoned.is_empty(),
"these coverage exemptions state no reason: {unreasoned:?}\n\
Say why no lane can run the feature, so the exemption can be removed when that stops being true."
);
}
#[test]
fn default_feature_set_is_empty() {
let manifest = manifest();
let default = manifest
.get("features")
.and_then(|f| f.get("default"))
.and_then(Value::as_array)
.expect("[features] must declare `default`");
assert!(
default.is_empty(),
"trusty-common declares `default = {default:?}`, but the #4901 zero-feature guard \
in src/lib.rs assumes it is empty. A non-empty `default` sets CARGO_FEATURE_* on a \
bare `cargo test -p trusty-common`, which makes the guard stop firing and restores \
the vacuous green. Either keep `default` empty, or rewrite the guard in build.rs to \
compare the enabled feature set against the default set."
);
}