xtask/tests/container_robot_feature.rs
//! **L14: gunnar-server's container robot names edda's published `robot` feature itself.**
//!
//! `wg_appliance_core::robot` (the container-form ceremony robot's shared mechanics) is behind
//! wg-appliance-core's own `robot` feature (a test tool, A28 L14). Until wg-appliance-core 0.1.7
//! (R5D, 2026-10-27) the published crate had no such feature, so gunnar-server could not name it
//! and every run had to add `wg-appliance-core/robot` on the command line by hand. With the root
//! on crates.io (G-B7), the published feature is what a lone clone resolves, so the
//! `container-robot` feature turns it on and the command line names only `container-robot`.
//!
//! These read the tree only: no sibling, no network.
use std::path::{Path, PathBuf};
fn root() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR"))
.parent()
.expect("xtask has a parent")
.to_path_buf()
}
fn text(rel: &str) -> String {
std::fs::read_to_string(root().join(rel)).unwrap_or_else(|e| panic!("{rel}: {e}"))
}
/// The first non-comment line of `manifest` whose key is `key`.
fn line_of<'a>(manifest: &'a str, key: &str) -> &'a str {
manifest
.lines()
.find(|l| {
let l = l.trim_start();
!l.starts_with('#') && l.split_once('=').is_some_and(|(k, _)| k.trim() == key)
})
.unwrap_or_else(|| panic!("no `{key} = …` line"))
}
/// ★ L14: `container-robot` turns on `wg-appliance-core/robot`, and the dependency asks for the
/// first published line that has it (0.1.7).
#[test]
fn container_robot_turns_on_the_published_robot_feature() {
let manifest = text("crates/gunnar-server/Cargo.toml");
let feature = line_of(&manifest, "container-robot");
assert!(
feature.contains("\"wg-appliance-core/robot\""),
"gunnar-server's `container-robot` must name `wg-appliance-core/robot` itself (published in 0.1.7): {feature}"
);
let dep = line_of(&manifest, "wg-appliance-core");
assert!(
dep.contains("version = \"0.1.7\""),
"gunnar-server must ask for wg-appliance-core 0.1.7, the first published line with `robot`: {dep}"
);
}
/// ★ L14: no word tells a reader to add the feature by hand, or that the published crate lacks it.
#[test]
fn no_word_says_the_robot_feature_is_given_by_hand() {
for rel in [
"crates/gunnar-server/Cargo.toml",
"crates/gunnar-server/tests/appliance_container_robot.rs",
"crates/gunnar-recipe/src/recipe.rs",
".nornir/build-variants.toml",
] {
let t = text(rel);
for stale in [
"container-robot,wg-appliance-core/robot",
"has no `robot` feature yet",
"is not in the published wg-appliance-core",
] {
assert!(!t.contains(stale), "{rel} still says `{stale}`: the published wg-appliance-core 0.1.7 has `robot`, and `container-robot` names it");
}
}
}