use std::sync::Arc;
use crate::command::CommandRunner;
use crate::command::test_support::RecordingCommandRunner;
use crate::filesystem::LocalFilesystem;
use crate::model::config::NpmConfig;
use crate::package_manager::{
NpmAdapter, PackageManagerAdapter, build_dependency_graph, enumerate_projects,
};
use crate::path::AbsolutePath;
#[tokio::test]
async fn build_dependency_graph_empty_for_single_package() {
let dir = tempfile::tempdir().unwrap();
std::fs::write(
dir.path().join("package.json"),
r#"{"name": "test-package", "version": "0.1.0"}"#,
)
.unwrap();
let adapter: Arc<dyn PackageManagerAdapter> = Arc::new(NpmAdapter::new(
NpmConfig::default(),
AbsolutePath::new(dir.path()).unwrap(),
{
let r = Arc::new(RecordingCommandRunner::new(0)) as Arc<dyn CommandRunner>;
crate::Env::new(
Arc::clone(&r),
Arc::new(LocalFilesystem),
Arc::new(crate::git::GitWorkdir::new(
r,
crate::path::AbsolutePath::new("/tmp").unwrap(),
)),
)
},
));
let projects = enumerate_projects([adapter]).await.unwrap();
let graph = build_dependency_graph(&projects).unwrap();
let sorted = graph.sort_leaves_first();
assert_eq!(sorted, vec!["test-package"]);
}
#[tokio::test]
async fn build_dependency_graph_with_workspace_dependencies() {
let dir = tempfile::tempdir().unwrap();
std::fs::write(
dir.path().join("package.json"),
r#"{"name": "root", "version": "0.1.0", "workspaces": ["packages/*"]}"#,
)
.unwrap();
std::fs::create_dir_all(dir.path().join("packages/lib")).unwrap();
std::fs::write(
dir.path().join("packages/lib/package.json"),
r#"{"name": "lib", "version": "0.1.0"}"#,
)
.unwrap();
std::fs::create_dir_all(dir.path().join("packages/app")).unwrap();
std::fs::write(
dir.path().join("packages/app/package.json"),
r#"{"name": "app", "version": "0.1.0", "dependencies": {"lib": "0.1.0"}}"#,
)
.unwrap();
let adapter: Arc<dyn PackageManagerAdapter> = Arc::new(NpmAdapter::new(
NpmConfig::default(),
AbsolutePath::new(dir.path()).unwrap(),
{
let r = Arc::new(RecordingCommandRunner::new(0)) as Arc<dyn CommandRunner>;
crate::Env::new(
Arc::clone(&r),
Arc::new(LocalFilesystem),
Arc::new(crate::git::GitWorkdir::new(
r,
crate::path::AbsolutePath::new("/tmp").unwrap(),
)),
)
},
));
let projects = enumerate_projects([adapter]).await.unwrap();
let graph = build_dependency_graph(&projects).unwrap();
let sorted = graph.sort_leaves_first();
let lib_index = sorted.iter().position(|n| n == "lib").unwrap();
let app_index = sorted.iter().position(|n| n == "app").unwrap();
assert!(lib_index < app_index, "lib should come before app");
}
#[tokio::test]
async fn build_dependency_graph_excludes_external_dependencies() {
let dir = tempfile::tempdir().unwrap();
std::fs::write(
dir.path().join("package.json"),
r#"{"name": "root", "version": "0.1.0", "workspaces": ["packages/*"]}"#,
)
.unwrap();
std::fs::create_dir_all(dir.path().join("packages/lib")).unwrap();
std::fs::write(
dir.path().join("packages/lib/package.json"),
r#"{"name": "lib", "version": "0.1.0"}"#,
)
.unwrap();
std::fs::create_dir_all(dir.path().join("packages/app")).unwrap();
std::fs::write(
dir.path().join("packages/app/package.json"),
r#"{"name": "app", "version": "0.1.0", "dependencies": {"lib": "0.1.0", "react": "^18.0.0"}}"#,
)
.unwrap();
let adapter: Arc<dyn PackageManagerAdapter> = Arc::new(NpmAdapter::new(
NpmConfig::default(),
AbsolutePath::new(dir.path()).unwrap(),
{
let r = Arc::new(RecordingCommandRunner::new(0)) as Arc<dyn CommandRunner>;
crate::Env::new(
Arc::clone(&r),
Arc::new(LocalFilesystem),
Arc::new(crate::git::GitWorkdir::new(
r,
crate::path::AbsolutePath::new("/tmp").unwrap(),
)),
)
},
));
let projects = enumerate_projects([adapter]).await.unwrap();
let graph = build_dependency_graph(&projects).unwrap();
assert_eq!(
graph.adjacency.get("app").unwrap(),
&vec!["lib".to_string()]
);
assert!(!graph.adjacency.contains_key("react"));
let sorted = graph.sort_leaves_first();
assert!(!sorted.contains(&"react".to_string()));
let lib_index = sorted.iter().position(|n| n == "lib").unwrap();
let app_index = sorted.iter().position(|n| n == "app").unwrap();
assert!(lib_index < app_index, "lib should come before app");
}