use std::path::{Path, PathBuf};
fn root() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR"))
.parent()
.and_then(Path::parent)
.expect("repo root")
.to_path_buf()
}
fn read(rel: &str) -> String {
let p = root().join(rel);
std::fs::read_to_string(&p).unwrap_or_else(|e| panic!("read {}: {e}", p.display()))
}
fn release_targets() -> Vec<String> {
read(".github/workflows/release.yaml")
.lines()
.filter_map(|l| l.trim().strip_prefix("- target: ").map(str::to_string))
.collect()
}
fn packed_pairs() -> Vec<(String, String)> {
read("scripts/npm-pack.sh")
.lines()
.map(str::trim)
.filter(|l| l.starts_with('"') && l.contains("|amont-"))
.filter_map(|l| {
let row = l.trim_start_matches('"').trim_end_matches('"');
let mut it = row.split('|');
Some((it.next()?.to_string(), it.next()?.to_string()))
})
.collect()
}
fn declared_packages() -> Vec<String> {
let text = read("npm/amont/package.json.in");
let (_, after) = text
.split_once("\"optionalDependencies\"")
.expect("optionalDependencies block");
after
.lines()
.take_while(|l| !l.contains('}'))
.filter_map(|l| {
let l = l.trim();
l.strip_prefix('"')?
.split_once('"')
.map(|(name, _)| name.to_string())
})
.collect()
}
fn wrapper_packages() -> Vec<String> {
let text = read("npm/amont/bin/amont.js");
let (_, after) = text.split_once("const PACKAGES").expect("PACKAGES map");
after
.lines()
.take_while(|l| !l.starts_with("};"))
.flat_map(|l| {
l.match_indices("\"amont-")
.filter_map(|(i, _)| {
let rest = &l[i + 1..];
rest.split_once('"').map(|(name, _)| name.to_string())
})
.collect::<Vec<_>>()
})
.collect()
}
fn sorted(mut v: Vec<String>) -> Vec<String> {
v.sort();
v.dedup();
v
}
#[test]
fn every_released_target_is_packed_for_npm() {
let built = sorted(release_targets());
let packed = sorted(packed_pairs().into_iter().map(|(t, _)| t).collect());
assert_eq!(
built, packed,
"release.yaml builds one set of targets and npm-pack.sh packs another"
);
}
#[test]
fn the_packed_packages_are_exactly_the_declared_ones() {
let packed = sorted(packed_pairs().into_iter().map(|(_, p)| p).collect());
let declared = sorted(declared_packages());
assert_eq!(
packed, declared,
"npm-pack.sh lays out one set of packages and amont declares another \
as optionalDependencies — npm rejects a version that does not exist"
);
}
#[test]
fn the_wrapper_can_resolve_every_package_that_is_published() {
let declared = sorted(declared_packages());
let known = sorted(wrapper_packages());
assert_eq!(
declared, known,
"bin/amont.js resolves a different set than npm installs — a platform \
with a binary would be told it has none"
);
}
#[test]
fn init_bakes_the_native_binary_not_the_node_wrapper() {
let src = read("crates/amont-runtime/src/install.rs");
let init_body: Vec<&str> = src
.lines()
.skip_while(|l| !l.starts_with("pub fn init()"))
.take_while(|l| !l.starts_with('}') || l.starts_with("pub fn init()"))
.collect();
assert!(
init_body.len() > 1,
"could not find the body of pub fn init()"
);
let init_body = init_body.join("\n");
assert!(
init_body.contains("current_exe()"),
"init no longer bakes current_exe()"
);
assert!(
!init_body.contains("on_path_already"),
"init consults PATH — under npm that resolves to the JS wrapper, and \
every commit would spawn node"
);
}