use std::fs;
use std::path::{Path, PathBuf};
const EMBEDDED_FILES: &[(&str, &str)] = &[
(
"tools/database-url.mjs",
"crates/cli/embedded/tools/database-url.mjs",
),
(
"tools/farm-build.mjs",
"crates/cli/embedded/tools/farm-build.mjs",
),
(
"tools/farm-dev.mjs",
"crates/cli/embedded/tools/farm-dev.mjs",
),
(
"tools/native-esm.mjs",
"crates/cli/embedded/tools/native-esm.mjs",
),
(
"tools/node-sqlite.mjs",
"crates/cli/embedded/tools/node-sqlite.mjs",
),
(
"tools/noxid-action-dev.mjs",
"crates/cli/embedded/tools/noxid-action-dev.mjs",
),
(
"tools/noxid-db.mjs",
"crates/cli/embedded/tools/noxid-db.mjs",
),
(
"tools/noxid-prerender.mjs",
"crates/cli/embedded/tools/noxid-prerender.mjs",
),
(
"tools/server-lifecycle-exports.txt",
"crates/cli/embedded/tools/server-lifecycle-exports.txt",
),
(
"plugins/drizzle-orm/VETTING.md",
"crates/cli/embedded/plugins/drizzle-orm/VETTING.md",
),
(
"plugins/drizzle-orm/adapter.js",
"crates/cli/embedded/plugins/drizzle-orm/adapter.js",
),
(
"plugins/drizzle-orm/data-scopes.test.mjs",
"crates/cli/embedded/plugins/drizzle-orm/data-scopes.test.mjs",
),
(
"plugins/postgres/VETTING.md",
"crates/cli/embedded/plugins/postgres/VETTING.md",
),
(
"tools/server-lifecycle-exports.txt",
"crates/codegen-server-js/embedded/tools/server-lifecycle-exports.txt",
),
];
const EMBEDDED_TREES: &[(&str, &str)] = &[("examples/templates", "crates/cli/embedded/templates")];
const SKIPPED_DIRECTORIES: [&str; 4] = ["target", "dist", "node_modules", ".git"];
fn repository() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR"))
.join("../..")
.canonicalize()
.expect("repository root")
}
fn inside_checkout(repository: &Path) -> bool {
repository.join("tools/sync-embedded.sh").is_file()
}
#[test]
fn embedded_files_match_their_repository_originals() {
let repository = repository();
if !inside_checkout(&repository) {
return;
}
for (original, copy) in EMBEDDED_FILES {
let original_path = repository.join(original);
let copy_path = repository.join(copy);
let original_bytes = fs::read(&original_path)
.unwrap_or_else(|error| panic!("read {}: {error}", original_path.display()));
let copy_bytes = fs::read(©_path).unwrap_or_else(|error| {
panic!(
"read {}: {error}\nrun tools/sync-embedded.sh",
copy_path.display()
)
});
assert!(
original_bytes == copy_bytes,
"{copy} has drifted from {original}; run tools/sync-embedded.sh"
);
}
}
#[test]
fn embedded_trees_match_their_repository_originals() {
let repository = repository();
if !inside_checkout(&repository) {
return;
}
for (original, copy) in EMBEDDED_TREES {
let original_files = tree(&repository.join(original));
let copy_files = tree(&repository.join(copy));
assert!(
original_files
.iter()
.map(|(path, _)| path)
.eq(copy_files.iter().map(|(path, _)| path)),
"{copy} holds a different file set than {original}; run tools/sync-embedded.sh"
);
for ((path, original_bytes), (_, copy_bytes)) in original_files.iter().zip(©_files) {
assert!(
original_bytes == copy_bytes,
"{copy}/{path} has drifted from {original}/{path}; run tools/sync-embedded.sh"
);
}
}
}
fn tree(root: &Path) -> Vec<(String, Vec<u8>)> {
let mut files = Vec::new();
collect(root, root, &mut files);
files.sort_by(|(left, _), (right, _)| left.cmp(right));
assert!(!files.is_empty(), "{} holds no files", root.display());
files
}
fn collect(root: &Path, directory: &Path, files: &mut Vec<(String, Vec<u8>)>) {
let entries = fs::read_dir(directory).unwrap_or_else(|error| {
panic!(
"read {}: {error}\nrun tools/sync-embedded.sh",
directory.display()
)
});
for entry in entries {
let path = entry.expect("directory entry").path();
let name = path
.file_name()
.and_then(|name| name.to_str())
.expect("entry name")
.to_string();
if path.is_dir() {
if !SKIPPED_DIRECTORIES.contains(&name.as_str()) {
collect(root, &path, files);
}
continue;
}
if name == ".DS_Store" {
continue;
}
let relative = path
.strip_prefix(root)
.expect("entry inside its root")
.components()
.map(|component| component.as_os_str().to_string_lossy().into_owned())
.collect::<Vec<_>>()
.join("/");
files.push((relative, fs::read(&path).expect("read entry")));
}
}