#[test]
fn the_npm_manifest_carries_the_version_cargo_declares() {
let root = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
let toml = std::fs::read_to_string(root.join("Cargo.toml")).unwrap();
let cargo = toml
.lines()
.find_map(|l| l.strip_prefix("version = \""))
.and_then(|l| l.split('"').next())
.expect("Cargo.toml declares a version");
let pkg = std::fs::read_to_string(root.join("npm/package.json")).unwrap();
let npm = pkg
.lines()
.find_map(|l| l.trim().strip_prefix("\"version\": \""))
.and_then(|l| l.split('"').next())
.expect("npm/package.json declares a version");
assert_eq!(
cargo, npm,
"npm/package.json says {npm} while Cargo.toml says {cargo} - this tag \
does not reproduce the release it names"
);
}
#[test]
fn the_pinned_platform_packages_carry_that_version_too() {
let root = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
let toml = std::fs::read_to_string(root.join("Cargo.toml")).unwrap();
let cargo = toml
.lines()
.find_map(|l| l.strip_prefix("version = \""))
.and_then(|l| l.split('"').next())
.expect("Cargo.toml declares a version");
let pkg = std::fs::read_to_string(root.join("npm/package.json")).unwrap();
let pinned: Vec<(&str, &str)> = pkg
.lines()
.filter(|l| l.contains("@youdie006/swapdex-"))
.filter_map(|l| {
let mut q = l.split('"').filter(|p| !p.trim().is_empty() && *p != ": ");
let name = q.next()?;
let ver = l.rsplit('"').nth(1)?;
Some((name, ver))
})
.collect();
assert!(!pinned.is_empty(), "no platform packages found to check");
for (name, ver) in pinned {
assert_eq!(
ver, cargo,
"{name} is pinned at {ver} while this release is {cargo} - an npm \
install from this tag fetches the wrong binary"
);
}
}
#[test]
fn the_changelog_has_notes_for_the_version_cargo_declares() {
let root = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
let toml = std::fs::read_to_string(root.join("Cargo.toml")).unwrap();
let version = toml
.lines()
.find_map(|l| l.strip_prefix("version = \""))
.and_then(|l| l.split('"').next())
.expect("Cargo.toml declares a version");
let out = std::process::Command::new("sh")
.arg(root.join("scripts/release-notes.sh"))
.arg(version)
.arg(root.join("CHANGELOG.md"))
.output()
.expect("run scripts/release-notes.sh");
assert!(
out.status.success(),
"release-notes.sh failed: {}",
String::from_utf8_lossy(&out.stderr)
);
let notes = String::from_utf8_lossy(&out.stdout);
assert!(
!notes.trim().is_empty(),
"CHANGELOG.md has no section for {version}, so the release would be a blank page"
);
assert!(
notes.lines().filter(|l| !l.trim().is_empty()).count() >= 2,
"the section for {version} has no content: {notes:?}"
);
}
#[test]
fn release_notes_match_one_version_exactly() {
let root = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
let run = |v: &str| {
let out = std::process::Command::new("sh")
.arg(root.join("scripts/release-notes.sh"))
.arg(v)
.arg(root.join("CHANGELOG.md"))
.output()
.expect("run scripts/release-notes.sh");
String::from_utf8_lossy(&out.stdout).into_owned()
};
assert!(
run("0.15").trim().is_empty(),
"a prefix of a real version must match nothing"
);
assert!(
run("9.999.0").trim().is_empty(),
"a version with no section must match nothing"
);
let toml = std::fs::read_to_string(root.join("Cargo.toml")).unwrap();
let version = toml
.lines()
.find_map(|l| l.strip_prefix("version = \""))
.and_then(|l| l.split('"').next())
.unwrap();
assert_eq!(
run(version),
run(&format!("v{version}")),
"the tag name and the bare version name the same section"
);
}
const PLACEHOLDER_DOMAINS: &[&str] = &[
"example.com",
"x.com",
"x.co",
"y.com",
"b.com",
"g.com",
"company.com",
"work.com",
"personal.com",
"personal.dev",
];
#[test]
fn no_tracked_file_names_a_real_mailbox() {
let root = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
let out = std::process::Command::new("git")
.args(["ls-files", "-z"])
.current_dir(root)
.output()
.expect("run git ls-files");
assert!(out.status.success(), "git ls-files failed");
let listing = String::from_utf8(out.stdout).expect("git ls-files prints utf-8 paths");
let files: Vec<&str> = listing.split('\0').filter(|p| !p.is_empty()).collect();
assert!(!files.is_empty(), "no tracked files found to check");
let mut found: Vec<String> = Vec::new();
for rel in files {
let Ok(bytes) = std::fs::read(root.join(rel)) else {
continue;
};
let Ok(text) = String::from_utf8(bytes) else {
continue;
};
for (n, line) in text.lines().enumerate() {
for domain in addresses(line) {
if !PLACEHOLDER_DOMAINS.contains(&domain.as_str()) {
found.push(format!("{rel}:{} (on {domain})", n + 1));
}
}
}
}
assert!(
found.is_empty(),
"these lines name a mailbox outside the placeholder domains:\n{}",
found.join("\n")
);
}
fn addresses(line: &str) -> Vec<String> {
let b: Vec<char> = line.chars().collect();
let local = |c: char| c.is_ascii_alphanumeric() || "._%+-".contains(c);
let host = |c: char| c.is_ascii_alphanumeric() || c == '.' || c == '-';
let mut out = Vec::new();
for (i, c) in b.iter().enumerate() {
if *c != '@' || i == 0 || !local(b[i - 1]) {
continue;
}
let mut j = i + 1;
while j < b.len() && host(b[j]) {
j += 1;
}
let domain: String = b[i + 1..j].iter().collect();
let domain = domain.trim_end_matches('.').to_string();
match domain.rsplit_once('.') {
Some((_, tld)) if tld.len() >= 2 && tld.chars().all(|c| c.is_ascii_alphabetic()) => {
out.push(domain)
}
_ => {}
}
}
out
}
#[test]
fn version_pins_and_scoped_packages_are_not_addresses() {
assert_eq!(addresses("kong (a@example.com) - 5h"), vec!["example.com"]);
for line in [
"swapdex@0.155.0",
"pkg@1.2.10",
"uses: actions/checkout@v4",
"npm i @youdie006/swapdex-linux-x64",
"a @ b",
] {
assert!(
addresses(line).is_empty(),
"not a mailbox: {line:?} read as {:?}",
addresses(line)
);
}
}