use super::*;
use crate::package_snapshot::probe_counter;
#[test]
fn package_export_map_resolves_declared_module() {
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let packages_root = package_fixture(root);
let packages = packages_root.join("acme/runtime");
fs::create_dir_all(&packages).unwrap();
fs::write(
packages_root.join("acme/harn.toml"),
"[exports]\ncapabilities = \"runtime/capabilities.harn\"\n",
)
.unwrap();
fs::write(
packages.join("capabilities.harn"),
"pub fn exported_capability() { 1 }\n",
)
.unwrap();
let entry = write_file(
root,
"entry.harn",
"import \"acme/capabilities\"\nexported_capability()\n",
);
let graph = build(std::slice::from_ref(&entry));
let imported = graph
.imported_names_for_file(&entry)
.expect("package export should resolve");
assert!(imported.contains("exported_capability"));
}
#[test]
fn many_files_under_one_root_acquire_a_single_snapshot() {
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
package_fixture(root);
let files: Vec<PathBuf> = (0..8)
.map(|i| write_file(root, &format!("entry{i}.harn"), ""))
.collect();
let (snapshots, walks, acquires) =
probe_counter::count_walks_and_acquires(|| acquire_package_snapshots(&files));
assert_eq!(snapshots.len(), 1, "one root must yield one snapshot");
assert_eq!(walks, 8, "each file still needs its own cheap root walk");
assert_eq!(
acquires, 1,
"the expensive acquire ran once per file instead of once per root"
);
}
#[test]
fn distinct_roots_each_acquire_their_own_snapshot() {
let tmp = tempfile::tempdir().unwrap();
let first = tmp.path().join("first");
let second = tmp.path().join("second");
for root in [&first, &second] {
fs::create_dir_all(root).unwrap();
fs::write(root.join(".git"), "").unwrap();
package_fixture(root);
}
let files = vec![
write_file(&first, "a.harn", ""),
write_file(&first, "b.harn", ""),
write_file(&second, "c.harn", ""),
];
let (snapshots, _, acquires) =
probe_counter::count_walks_and_acquires(|| acquire_package_snapshots(&files));
assert_eq!(
snapshots.len(),
2,
"each distinct root must yield a snapshot"
);
assert_eq!(
acquires, 2,
"one acquire per distinct root, no more, no fewer"
);
}
#[test]
fn stdlib_and_relative_imports_never_probe_for_a_package() {
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
package_fixture(root);
write_file(root, "sibling.harn", "pub fn helper() { 1 }\n");
let entry = write_file(root, "entry.harn", "");
let (resolved, probes) =
probe_counter::count_probes(|| resolve_import_path(&entry, "std/testing"));
assert!(resolved.is_some(), "std/testing must still resolve");
assert_eq!(
probes, 0,
"a std/ import probed the filesystem for a package"
);
let (resolved, probes) =
probe_counter::count_probes(|| resolve_import_path(&entry, "./sibling"));
assert!(resolved.is_some(), "a relative sibling must still resolve");
assert_eq!(
probes, 0,
"a relative import probed the filesystem for a package"
);
}
#[test]
fn a_package_import_still_acquires_a_snapshot() {
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let packages_root = package_fixture(root);
fs::create_dir_all(packages_root.join("acme")).unwrap();
fs::write(
packages_root.join("acme/capabilities.harn"),
"pub fn exported_capability() { 1 }\n",
)
.unwrap();
let entry = write_file(root, "entry.harn", "");
let (resolved, probes) =
probe_counter::count_probes(|| resolve_import_path(&entry, "acme/capabilities"));
assert!(resolved.is_some(), "a package import must still resolve");
assert_eq!(
probes, 1,
"a package import must acquire exactly one snapshot"
);
}
#[test]
fn an_unknown_stdlib_module_does_not_fall_through_to_packages() {
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let packages_root = package_fixture(root);
fs::create_dir_all(packages_root.join("std")).unwrap();
fs::write(
packages_root.join("std/not_a_real_module.harn"),
"pub fn impostor() { 1 }\n",
)
.unwrap();
let entry = write_file(root, "entry.harn", "");
let (resolved, probes) =
probe_counter::count_probes(|| resolve_import_path(&entry, "std/not_a_real_module"));
assert!(
resolved.is_none(),
"a package resolved a std/ import and shadowed the stdlib namespace"
);
assert_eq!(probes, 0, "an unknown std/ import probed for a package");
}
#[test]
fn package_direct_import_cannot_escape_packages_root() {
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
fs::create_dir_all(package_fixture(root).join("acme")).unwrap();
fs::write(root.join("secret.harn"), "pub fn leaked() { 1 }\n").unwrap();
let entry = write_file(root, "entry.harn", "");
let resolved = resolve_import_path(&entry, "acme/../../secret");
assert!(resolved.is_none(), "package import escaped package root");
}
#[test]
fn package_export_map_cannot_escape_package_root() {
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let packages_root = package_fixture(root);
fs::create_dir_all(packages_root.join("acme")).unwrap();
fs::write(root.join("secret.harn"), "pub fn leaked() { 1 }\n").unwrap();
fs::write(
packages_root.join("acme/harn.toml"),
"[exports]\nleak = \"../../secret.harn\"\n",
)
.unwrap();
let entry = write_file(root, "entry.harn", "");
let resolved = resolve_import_path(&entry, "acme/leak");
assert!(resolved.is_none(), "package export escaped package root");
}
#[test]
fn package_export_map_allows_symlinked_path_dependencies() {
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let source = root.join("source-package");
fs::create_dir_all(source.join("runtime")).unwrap();
fs::write(
source.join("harn.toml"),
"[exports]\ncapabilities = \"runtime/capabilities.harn\"\n",
)
.unwrap();
fs::write(
source.join("runtime/capabilities.harn"),
"pub fn exported_capability() { 1 }\n",
)
.unwrap();
let packages_root = package_fixture(root);
#[cfg(unix)]
std::os::unix::fs::symlink(&source, packages_root.join("acme")).unwrap();
#[cfg(windows)]
std::os::windows::fs::symlink_dir(&source, packages_root.join("acme")).unwrap();
let entry = write_file(root, "entry.harn", "");
let resolved = resolve_import_path(&entry, "acme/capabilities")
.expect("symlinked package export should resolve");
assert!(resolved.ends_with("runtime/capabilities.harn"));
}
#[test]
fn package_imports_resolve_from_nested_package_module() {
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
fs::create_dir_all(root.join(".git")).unwrap();
let packages_root = package_fixture(root);
fs::create_dir_all(packages_root.join("acme")).unwrap();
fs::create_dir_all(packages_root.join("shared")).unwrap();
fs::write(
packages_root.join("shared/lib.harn"),
"pub fn shared_helper() { 1 }\n",
)
.unwrap();
fs::write(
packages_root.join("acme/lib.harn"),
"import \"shared\"\npub fn use_shared() { shared_helper() }\n",
)
.unwrap();
let entry = write_file(root, "entry.harn", "import \"acme\"\nuse_shared()\n");
let graph = build(std::slice::from_ref(&entry));
let imported = graph
.imported_names_for_file(&entry)
.expect("nested package import should resolve");
assert!(imported.contains("use_shared"));
let acme_path = packages_root.join("acme/lib.harn");
let acme_imports = graph
.imported_names_for_file(&acme_path)
.expect("package module imports should resolve");
assert!(acme_imports.contains("shared_helper"));
}
#[test]
fn unknown_stdlib_import_is_unresolved() {
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
let entry = write_file(root, "entry.harn", "import \"std/does_not_exist\"\n");
let graph = build(std::slice::from_ref(&entry));
assert!(
graph.imported_names_for_file(&entry).is_none(),
"unknown std module should fail resolution and disable strict check"
);
}