use std::path::Path;
use scryer_engine::dependency::{
CargoDependencyProvider, DependencyProvider, DependencySourceType,
};
#[tokio::test]
async fn test_discover_dependencies_scryer_workspace() -> anyhow::Result<()> {
let provider = CargoDependencyProvider::new();
let root = Path::new(env!("CARGO_MANIFEST_DIR"))
.parent()
.unwrap()
.parent()
.unwrap();
let deps = provider.discover_dependencies(root).await?;
assert!(!deps.is_empty(), "Should discover workspace dependencies");
let workspace_crates = ["scryer-engine", "scryer-db", "scryer-mcp", "scryer-cli"];
for ws_crate in workspace_crates {
assert!(
deps.iter().all(|d| d.name != ws_crate),
"Workspace member {ws_crate} should not be in external dependencies"
);
}
let direct_names = ["toasty", "tokio", "anyhow", "serde"];
for name in direct_names {
let found = deps.iter().find(|d| d.name == name);
assert!(
found.is_some(),
"Expected direct dependency '{name}' to be discovered"
);
let dep = found.unwrap();
assert!(
dep.is_direct,
"Dependency '{name}' should be classified as direct"
);
assert_eq!(
dep.source_type,
DependencySourceType::CratesIo,
"Dependency '{name}' should have CratesIo source type"
);
assert!(
dep.package_hash.is_some(),
"Dependency '{name}' should have package checksum resolved from Cargo.lock"
);
assert!(
dep.root_path.exists(),
"Dependency '{name}' root_path must exist on disk: {}",
dep.root_path.display()
);
let resolved_dir = provider.resolve_source_directory(dep)?;
assert!(resolved_dir.exists());
}
let transitive_names = ["libc", "bitflags", "proc-macro2"];
for name in transitive_names {
if let Some(dep) = deps.iter().find(|d| d.name == name) {
println!(
"Transitive dep check for {}: is_direct={}",
dep.name, dep.is_direct
);
}
}
Ok(())
}
#[tokio::test]
async fn test_discover_dependencies_non_existent_path_fails() {
let provider = CargoDependencyProvider::new();
let non_existent = Path::new("/path/that/does/not/exist/at/all");
let result = provider.discover_dependencies(non_existent).await;
assert!(result.is_err());
let err_msg = result.unwrap_err().to_string();
assert!(
err_msg.contains("Cargo manifest not found"),
"Expected error message indicating manifest not found, got: {err_msg}"
);
}
#[tokio::test]
async fn test_resolve_source_directory_error_for_invalid_path() {
let provider = CargoDependencyProvider::new();
let invalid_dep = scryer_engine::dependency::DiscoveredDependency {
name: "ghost-crate".to_string(),
version: "0.1.0".to_string(),
source_type: DependencySourceType::CratesIo,
manifest_path: std::path::PathBuf::from("/nonexistent/Cargo.toml"),
root_path: std::path::PathBuf::from("/nonexistent"),
package_hash: None,
is_direct: true,
features: vec![],
};
let result = provider.resolve_source_directory(&invalid_dep);
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("does not exist"));
}