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.dependencies]
serde = "1.0"
"#;
let mut file = File::create(root_cargo_toml)?;
writeln!(file, "{}", root_content)?;
fs::create_dir_all(root_path.join("internal-crate/src"))?;
let internal_cargo_toml = root_path.join("internal-crate/Cargo.toml");
let internal_content = r#"
[package]
name = "internal-crate"
version = "0.1.0"
edition = "2021"
publish = false
[dependencies]
serde = { workspace = true }
"#;
let mut file = File::create(internal_cargo_toml)?;
writeln!(file, "{}", internal_content)?;
let internal_main_rs = root_path.join("internal-crate/src/lib.rs");
let internal_main_content = r#"
use serde;
pub fn hello() -> &'static str {
"Hello from internal crate"
}
"#;
let mut file = File::create(internal_main_rs)?;
writeln!(file, "{}", internal_main_content)?;
fs::create_dir_all(root_path.join("public-crate/src"))?;
let public_cargo_toml = root_path.join("public-crate/Cargo.toml");
let public_content = r#"
[package]
name = "public-crate"
version = "0.1.0"
edition = "2021"
[dependencies]
internal-crate = { path = "../internal-crate" }
"#;
let mut file = File::create(public_cargo_toml)?;
writeln!(file, "{}", public_content)?;
let public_main_rs = root_path.join("public-crate/src/main.rs");
let public_main_content = r#"
use internal_crate;
use tokio;
fn main() {
println!("{}", internal_crate::hello());
}
"#;
let mut file = File::create(public_main_rs)?;
writeln!(file, "{}", public_main_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, true);
let crate_refs = analyzer.analyze_dependencies()?;
assert!(
crate_refs.contains_key("tokio"),
"tokio dependency not found"
);
assert!(
crate_refs.contains_key("internal-crate") || crate_refs.contains_key("internal_crate"),
"internal-crate dependency not found"
);
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!("Note: 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(())
}