use std::path::Path;
enum Expect {
StoreSymlink(&'static str),
PlugNPlay,
Flat,
}
struct Case {
name: &'static str,
expect: Expect,
}
const CASES: &[Case] = &[
Case {
name: "pnpm-isolated",
expect: Expect::StoreSymlink("node_modules/.pnpm/"),
},
Case {
name: "bun",
expect: Expect::StoreSymlink("node_modules/.bun/"),
},
Case {
name: "yarn-pnpm",
expect: Expect::StoreSymlink("node_modules/.store/"),
},
Case {
name: "yarn-pnp",
expect: Expect::PlugNPlay,
},
Case {
name: "npm",
expect: Expect::Flat,
},
Case {
name: "yarn-nm",
expect: Expect::Flat,
},
];
#[test]
fn package_manager_layouts_carry_expected_store_signatures() {
let Ok(base) = std::env::var("PM_LAYOUTS_DIR") else {
eprintln!("skipping module_layout_e2e: set PM_LAYOUTS_DIR (run crates/sidecar/tests/fixtures/gen-pm-layouts.sh)");
return;
};
let base = Path::new(&base);
let mut checked = 0;
for case in CASES {
let layout = base.join(case.name);
if !layout.exists() {
eprintln!("[{}] layout missing — skipping", case.name);
continue;
}
checked += 1;
let app_nm = layout.join("app/node_modules");
let is_odd = app_nm.join("is-odd");
match case.expect {
Expect::StoreSymlink(marker) => {
let target = std::fs::read_link(&is_odd).unwrap_or_else(|e| {
panic!(
"[{}] app/node_modules/is-odd should be a symlink: {e}",
case.name
)
});
let target = target.to_string_lossy();
eprintln!(
"[{}] is-odd -> {target} (expect store marker {marker:?})",
case.name
);
assert!(
target.contains(marker),
"[{}] symlink target {target:?} should contain store marker {marker:?}",
case.name
);
}
Expect::PlugNPlay => {
eprintln!("[{}] expect .pnp.cjs + no node_modules", case.name);
assert!(
layout.join(".pnp.cjs").exists(),
"[{}] expected .pnp.cjs",
case.name
);
assert!(
!app_nm.exists(),
"[{}] PnP should have no app/node_modules",
case.name
);
}
Expect::Flat => {
eprintln!("[{}] expect flat (hoisted to root, no store)", case.name);
let root_isodd = layout.join("node_modules/is-odd");
assert!(
root_isodd.exists(),
"[{}] expected hoisted node_modules/is-odd",
case.name
);
assert!(
!root_isodd
.symlink_metadata()
.unwrap()
.file_type()
.is_symlink(),
"[{}] flat layout's is-odd should be a real dir, not a symlink",
case.name
);
for store in [
"node_modules/.pnpm",
"node_modules/.bun",
"node_modules/.store",
] {
assert!(
!layout.join(store).exists(),
"[{}] flat layout must not have {store}",
case.name
);
}
}
}
}
assert!(
checked > 0,
"no layouts found under PM_LAYOUTS_DIR — generate them first"
);
eprintln!("\nvalidated {checked} package-manager layouts");
}