use std::path::{Path, PathBuf};
fn manifest() -> toml::Value {
let path: PathBuf = Path::new(env!("CARGO_MANIFEST_DIR")).join("Cargo.toml");
let raw = std::fs::read_to_string(&path).unwrap_or_else(|e| panic!("read {}: {e}", path.display()));
toml::from_str(&raw).expect("Cargo.toml is valid TOML")
}
fn metadata(key: &str) -> toml::Value {
manifest()
.get("package")
.and_then(|p| p.get("metadata"))
.and_then(|m| m.get(key))
.cloned()
.unwrap_or_else(|| panic!("[package.metadata.{key}] block is present"))
}
fn asset_sources(block: &toml::Value) -> Vec<String> {
let assets = block
.get("assets")
.and_then(|a| a.as_array())
.expect("assets is an array");
assets
.iter()
.map(|row| {
if let Some(arr) = row.as_array() {
arr[0].as_str().expect("deb asset source is a string").to_string()
} else {
row
.get("source")
.and_then(|s| s.as_str())
.expect("rpm asset source is a string")
.to_string()
}
})
.collect()
}
fn release_yml() -> String {
let path = Path::new(env!("CARGO_MANIFEST_DIR")).join(".github/workflows/release.yml");
std::fs::read_to_string(&path).unwrap_or_else(|e| panic!("read {}: {e}", path.display()))
}
#[test]
fn release_workflow_builds_both_linux_packages() {
let yml = release_yml();
assert!(
yml.contains("cargo deb --no-build --no-strip --target"),
"release.yml must build the .deb with --no-build --no-strip --target"
);
assert!(
yml.contains("cargo generate-rpm --target"),
"release.yml must build the .rpm per target"
);
}
#[test]
fn release_workflow_publishes_both_linux_packages() {
let yml = release_yml();
for glob in ["dist/*.deb", "dist/*.deb.sha256", "dist/*.rpm", "dist/*.rpm.sha256"] {
assert!(yml.contains(glob), "the release upload step must publish {glob}");
}
}
#[test]
fn deb_ships_the_binary_under_usr_bin() {
let deb = metadata("deb");
let assets = deb
.get("assets")
.and_then(|a| a.as_array())
.expect("deb assets is an array");
let bin_row = assets
.iter()
.find(|r| {
r.as_array()
.is_some_and(|a| a[0].as_str() == Some("target/release/gwm"))
})
.expect("deb must ship target/release/gwm");
let row = bin_row.as_array().unwrap();
assert_eq!(row[1].as_str(), Some("usr/bin/"), "gwm must land in usr/bin/");
assert_eq!(row[2].as_str(), Some("755"), "the binary must be executable");
}
#[test]
fn deb_declares_glibc_with_a_version_floor() {
let deb = metadata("deb");
let depends = deb
.get("depends")
.and_then(|v| v.as_str())
.expect("depends is a string");
assert!(depends.starts_with("libc6"), "libc6 leads the depends list: {depends}");
assert!(depends.contains(">= 2.34"), "depends must pin a glibc floor: {depends}");
}
#[test]
fn deb_and_rpm_declare_git_as_a_runtime_dep() {
let deb = metadata("deb");
let depends = deb
.get("depends")
.and_then(|v| v.as_str())
.expect("depends is a string");
assert!(
depends.split(',').any(|d| d.trim() == "git"),
"deb depends must include git: {depends}"
);
let rpm = metadata("generate-rpm");
let requires = rpm.get("requires").expect("rpm requires table is present");
assert!(
requires.get("git").is_some(),
"rpm requires must include git: {requires:?}"
);
}
#[test]
fn rpm_ships_the_binary_under_usr_bin() {
let rpm = metadata("generate-rpm");
let sources = asset_sources(&rpm);
assert!(
sources.iter().any(|s| s == "target/release/gwm"),
"rpm must ship target/release/gwm, got: {sources:?}"
);
let bin = rpm
.get("assets")
.and_then(|a| a.as_array())
.unwrap()
.iter()
.find(|r| r.get("source").and_then(|s| s.as_str()) == Some("target/release/gwm"))
.expect("rpm binary asset present");
assert_eq!(bin.get("dest").and_then(|d| d.as_str()), Some("/usr/bin/gwm"));
assert_eq!(bin.get("mode").and_then(|m| m.as_str()), Some("755"));
}
#[test]
fn deb_conflicts_with_debian_gwm_window_manager() {
let deb = metadata("deb");
assert_eq!(
deb.get("conflicts").and_then(|v| v.as_str()),
Some("gwm"),
"deb must declare Conflicts: gwm"
);
}
#[test]
fn rpm_declares_glibc_requirement() {
let rpm = metadata("generate-rpm");
let requires = rpm.get("requires").expect("rpm requires table is present");
let glibc = requires
.get("glibc")
.and_then(|v| v.as_str())
.expect("glibc requirement present");
assert!(
glibc.contains(">= 2.34"),
"rpm glibc requirement must pin a floor, got: {glibc}"
);
}
#[test]
fn rpm_disables_auto_req() {
let rpm = metadata("generate-rpm");
assert_eq!(
rpm.get("auto-req").and_then(|v| v.as_str()),
Some("no"),
"auto-req must be disabled for cross-packaging"
);
}
#[test]
fn both_packages_agree_on_the_doc_dir() {
for key in ["deb", "generate-rpm"] {
let sources = asset_sources(&metadata(key));
assert!(
sources.iter().any(|s| s.contains("README")),
"{key} should ship the README"
);
}
let deb = metadata("deb");
let deb_readme = deb
.get("assets")
.and_then(|a| a.as_array())
.unwrap()
.iter()
.find_map(|r| {
r.as_array()
.and_then(|a| a[1].as_str())
.filter(|d| d.contains("README"))
})
.expect("deb README dest");
assert_eq!(deb_readme, "usr/share/doc/gwm-cli/README.md");
}