use std::fs;
use std::path::{Path, PathBuf};
const MEMBERS: [&str; 3] = ["libredwg-sys", "uncad", "uncad-cli"];
fn repo_root() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR"))
.join("../..")
.canonicalize()
.expect("the workspace root is two levels above this crate")
}
fn read(path: impl AsRef<Path>) -> String {
let path = path.as_ref();
fs::read_to_string(path).unwrap_or_else(|e| panic!("{}: {e}", path.display()))
}
#[test]
fn every_published_crate_ships_the_gpl_text() {
let root = repo_root();
let canonical = read(root.join("LICENSE"));
assert!(
canonical.contains("GNU GENERAL PUBLIC LICENSE")
&& canonical.contains("Version 3, 29 June 2007"),
"the repository's LICENSE should be the GPLv3 text"
);
for member in MEMBERS {
let path = root.join("crates").join(member).join("LICENSE");
assert!(
path.exists(),
"crates/{member}/LICENSE is missing: `cargo package` only includes files under \
the crate directory, so this crate would be published with no licence text"
);
assert_eq!(
read(&path),
canonical,
"crates/{member}/LICENSE has drifted from the repository's LICENSE"
);
}
}
#[test]
fn the_vendored_libredwg_ships_its_own_licence() {
let copying = read(repo_root().join("crates/libredwg-sys/vendor/libredwg/COPYING"));
assert!(
copying.contains("GNU GENERAL PUBLIC LICENSE"),
"LibreDWG's own COPYING should stay beside the vendored sources"
);
}
fn patched_vendor_files(root: &Path) -> Vec<String> {
fn walk(dir: &Path, vendor: &Path, out: &mut Vec<String>) {
for entry in fs::read_dir(dir).expect("the vendored tree is readable") {
let path = entry.expect("a readable directory entry").path();
if path.is_dir() {
walk(&path, vendor, out);
} else if fs::read(&path)
.expect("a readable vendored file")
.windows(b"uncad local patch".len())
.any(|w| w == b"uncad local patch")
{
out.push(
path.strip_prefix(vendor)
.expect("inside the vendored tree")
.to_string_lossy()
.replace('\\', "/"),
);
}
}
}
let vendor = root.join("crates/libredwg-sys/vendor/libredwg");
let mut out = Vec::new();
walk(&vendor, &vendor, &mut out);
out.sort();
out
}
fn leading_comment(text: &str) -> String {
if text.starts_with("//!") {
return text
.lines()
.take_while(|line| line.starts_with("//!"))
.collect::<Vec<_>>()
.join("\n");
}
assert!(
text.starts_with("/*"),
"the file should open with a comment"
);
let end = text.find("*/").expect("the opening comment is closed");
text[..end].to_string()
}
#[test]
fn nothing_describes_the_patched_libredwg_as_unmodified() {
let root = repo_root();
let patched = patched_vendor_files(&root);
assert!(
!patched.is_empty(),
"expected the vendored LibreDWG to carry `uncad local patch` markers; if the \
patches were dropped, the claims this test guards have to be revisited too"
);
let manifest = read(root.join("crates/libredwg-sys/Cargo.toml"));
let description = manifest
.lines()
.find(|line| line.starts_with("description ="))
.expect("libredwg-sys declares a description");
let rustdoc = leading_comment(&read(root.join("crates/libredwg-sys/src/lib.rs")));
let config_h = leading_comment(&read(
root.join("crates/libredwg-sys/vendor-config/config.h"),
));
for (what, text) in [
("the crates.io description", description.to_string()),
("src/lib.rs's crate documentation", rustdoc),
("vendor-config/config.h's header", config_h),
] {
assert!(
!text.contains("unmodified"),
"{what} calls the vendored LibreDWG unmodified, but {patched:?} carry local \
patches:\n{text}"
);
assert!(
text.contains("patch"),
"{what} should say the vendored LibreDWG carries local patches:\n{text}"
);
}
for (doc, wrong) in [
("README.md", "holds the unmodified"),
("docs/ARCHITECTURE.md", "unmodified (see"),
("docs/THIRD_PARTY_NOTICES.md", "unmodified subset"),
(
"docs/THIRD_PARTY_NOTICES.md",
"an unmodified, byte-for-byte copy",
),
(
"docs/THIRD_PARTY_NOTICES.md",
"**Modified**: no — built directly",
),
] {
let text = read(root.join(doc));
assert!(
!text.contains(wrong),
"{doc} says \"{wrong}\" of the vendored LibreDWG while {patched:?} carry local \
patches"
);
assert!(
text.contains("local patch"),
"{doc} should say the vendored LibreDWG carries local patches"
);
}
let notice = read(root.join("crates/libredwg-sys/NOTICE.md"));
let caveats = read(root.join("docs/CAVEATS.md"));
for file in &patched {
assert!(
notice.contains(&format!("vendor/libredwg/{file}")),
"crates/libredwg-sys/NOTICE.md should name the patched vendor/libredwg/{file}"
);
assert!(
caveats.contains(&format!("`{file}`")),
"docs/CAVEATS.md's \"Local patches to the vendored LibreDWG\" should name the \
patched {file}"
);
}
}