use anyhow::Result;
use std::fs::{self, File};
use std::io::Write;
use tempfile::TempDir;
use crate::CargoAutodd;
use crate::dependency_manager::DependencyAnalyzer;
fn create_monorepo_test_environment() -> Result<TempDir> {
let temp_dir = TempDir::new()?;
let root_path = temp_dir.path();
let root_cargo_toml = root_path.join("Cargo.toml");
let root_content = r#"
[workspace]
members = [
"public-crate",
"internal-crate"
]
[workspace.package]
version = "0.1.0"
edition = "2021"
"#;
let mut file = File::create(&root_cargo_toml)?;
writeln!(file, "{}", root_content)?;
let internal_crate_dir = root_path.join("internal-crate");
fs::create_dir(&internal_crate_dir)?;
let internal_cargo_toml = internal_crate_dir.join("Cargo.toml");
let internal_content = r#"
[package]
name = "internal-crate"
version = "0.1.0"
edition = "2021"
publish = false
[dependencies]
serde = "1.0"
"#;
let mut file = File::create(&internal_cargo_toml)?;
writeln!(file, "{}", internal_content)?;
fs::create_dir(internal_crate_dir.join("src"))?;
let internal_lib_rs = internal_crate_dir.join("src/lib.rs");
let internal_lib_content = r#"
use serde;
pub fn internal_function() -> &'static str {
"This is an internal function"
}
"#;
let mut file = File::create(internal_lib_rs)?;
writeln!(file, "{}", internal_lib_content)?;
let public_crate_dir = root_path.join("public-crate");
fs::create_dir(&public_crate_dir)?;
let public_cargo_toml = public_crate_dir.join("Cargo.toml");
let public_content = r#"
[package]
name = "public-crate"
version = "0.1.0"
edition = "2021"
[dependencies]
internal-crate = { path = "../internal-crate" }
tokio = "1.0"
"#;
let mut file = File::create(&public_cargo_toml)?;
writeln!(file, "{}", public_content)?;
fs::create_dir(public_crate_dir.join("src"))?;
let public_lib_rs = public_crate_dir.join("src/lib.rs");
let public_lib_content = r#"
use internal_crate;
use tokio;
pub fn public_function() -> &'static str {
let internal_result = internal_crate::internal_function();
"This is a public function using an internal crate"
}
"#;
let mut file = File::create(public_lib_rs)?;
writeln!(file, "{}", public_lib_content)?;
Ok(temp_dir)
}
#[test]
fn test_monorepo_dependency_analysis() -> Result<()> {
let temp_dir = create_monorepo_test_environment()?;
let root_path = temp_dir.path().to_path_buf();
let public_crate_path = root_path.join("public-crate");
let analyzer = DependencyAnalyzer::with_debug(public_crate_path.clone(), true);
let crate_refs = analyzer.analyze_dependencies()?;
assert!(
crate_refs.contains_key("tokio"),
"tokio dependency should be detected"
);
let has_internal_crate =
crate_refs.contains_key("internal-crate") || crate_refs.contains_key("internal_crate");
assert!(
has_internal_crate,
"internal crate dependency should be detected"
);
if let Some(internal_crate) = crate_refs.get("internal-crate") {
assert!(
internal_crate.is_path_dependency,
"internal-crate should be a path dependency"
);
} else if let Some(_internal_crate) = crate_refs.get("internal_crate") {
println!("internal_crate detected instead of internal-crate");
}
Ok(())
}
#[test]
#[ignore] fn test_monorepo_update_with_internal_crates() -> Result<()> {
let temp_dir = create_monorepo_test_environment()?;
let root_path = temp_dir.path().to_path_buf();
let public_crate_path = root_path.join("public-crate");
let autodd = CargoAutodd::with_debug(public_crate_path, true);
let result = autodd.analyze_and_update();
assert!(
result.is_ok(),
"analyze_and_update should succeed with internal crates"
);
let cargo_toml_content = fs::read_to_string(root_path.join("public-crate/Cargo.toml"))?;
assert!(
cargo_toml_content.contains("tokio"),
"tokio should be added to Cargo.toml"
);
assert!(
cargo_toml_content.contains("internal-crate = { path ="),
"internal-crate should be maintained as a path dependency"
);
Ok(())
}
#[test]
#[ignore] fn test_monorepo_with_publish_false_crates() -> Result<()> {
let temp_dir = create_monorepo_test_environment()?;
let root_path = temp_dir.path().to_path_buf();
let internal_crate_path = root_path.join("internal-crate");
let autodd = CargoAutodd::with_debug(internal_crate_path, true);
let result = autodd.analyze_and_update();
assert!(
result.is_ok(),
"analyze_and_update should succeed with publish=false crates"
);
let cargo_toml_content = fs::read_to_string(root_path.join("internal-crate/Cargo.toml"))?;
assert!(
cargo_toml_content.contains("publish = false"),
"publish = false should be maintained"
);
assert!(
cargo_toml_content.contains("serde"),
"serde should be in Cargo.toml"
);
Ok(())
}