use assert_cmd::Command;
use std::fs;
use tempfile::TempDir;
#[test]
fn test_trace_imports_includes_imported_files() {
let temp_dir = TempDir::new().unwrap();
let root = temp_dir.path();
fs::create_dir_all(root.join(".git")).unwrap();
fs::write(
root.join("main.rs"),
r#"
mod utils;
use utils::helper;
fn main() {
helper();
}
"#,
)
.unwrap();
fs::write(
root.join("utils.rs"),
r#"
pub fn helper() {
println!("Helper function");
}
"#,
)
.unwrap();
let mut cmd = Command::cargo_bin("context-creator").unwrap();
cmd.current_dir(root)
.arg("--trace-imports")
.arg("--include")
.arg("main.rs")
.arg("--output-file")
.arg("output.md");
cmd.assert().success();
let output_content = fs::read_to_string(root.join("output.md")).unwrap();
assert!(
output_content.contains("## main.rs"),
"Output should contain main.rs"
);
assert!(
output_content.contains("## utils.rs"),
"Output should contain utils.rs"
);
assert!(
output_content.contains("mod utils;"),
"Output should contain the import statement"
);
assert!(
output_content.contains("pub fn helper()"),
"Output should contain the helper function"
);
}
#[test]
fn test_trace_imports_respects_depth() {
let temp_dir = TempDir::new().unwrap();
let root = temp_dir.path();
fs::create_dir_all(root.join(".git")).unwrap();
fs::write(
root.join("a.rs"),
r#"
mod b;
use b::func_b;
pub fn func_a() {
func_b();
}
"#,
)
.unwrap();
fs::write(
root.join("b.rs"),
r#"
mod c;
use c::func_c;
pub fn func_b() {
func_c();
}
"#,
)
.unwrap();
fs::write(
root.join("c.rs"),
r#"
mod d;
use d::func_d;
pub fn func_c() {
func_d();
}
"#,
)
.unwrap();
fs::write(
root.join("d.rs"),
r#"
pub fn func_d() {
println!("Deep function");
}
"#,
)
.unwrap();
let mut cmd = Command::cargo_bin("context-creator").unwrap();
cmd.current_dir(root)
.arg("--trace-imports")
.arg("--semantic-depth")
.arg("2")
.arg("--include")
.arg("a.rs")
.arg("--output-file")
.arg("output.md");
cmd.assert().success();
let output_content = fs::read_to_string(root.join("output.md")).unwrap();
assert!(
output_content.contains("## a.rs"),
"Output should contain a.rs"
);
assert!(
output_content.contains("## b.rs"),
"Output should contain b.rs"
);
assert!(
output_content.contains("## c.rs"),
"Output should contain c.rs"
);
assert!(
!output_content.contains("## d.rs"),
"Output should NOT contain d.rs (beyond depth limit)"
);
}
#[test]
fn test_trace_imports_with_multiple_languages() {
let temp_dir = TempDir::new().unwrap();
let root = temp_dir.path();
fs::create_dir_all(root.join(".git")).unwrap();
fs::write(
root.join("main.py"),
r#"
import utils
from helpers import process_data
def main():
utils.setup()
process_data()
"#,
)
.unwrap();
fs::write(
root.join("utils.py"),
r#"
def setup():
print("Setting up")
"#,
)
.unwrap();
fs::write(
root.join("helpers.py"),
r#"
def process_data():
print("Processing data")
"#,
)
.unwrap();
let mut cmd = Command::cargo_bin("context-creator").unwrap();
cmd.current_dir(root)
.arg("--trace-imports")
.arg("--include")
.arg("main.py")
.arg("--output-file")
.arg("output.md");
cmd.assert().success();
let output_content = fs::read_to_string(root.join("output.md")).unwrap();
assert!(
output_content.contains("## main.py"),
"Output should contain main.py"
);
assert!(
output_content.contains("## utils.py"),
"Output should contain utils.py"
);
assert!(
output_content.contains("## helpers.py"),
"Output should contain helpers.py"
);
}
#[test]
fn test_trace_imports_excludes_external_dependencies() {
let temp_dir = TempDir::new().unwrap();
let root = temp_dir.path();
fs::create_dir_all(root.join(".git")).unwrap();
fs::write(
root.join("app.rs"),
r#"
use std::collections::HashMap;
use serde::{Serialize, Deserialize};
mod config;
use config::AppConfig;
fn main() {
let _map = HashMap::new();
let _config = AppConfig::default();
}
"#,
)
.unwrap();
fs::write(
root.join("config.rs"),
r#"
#[derive(Default)]
pub struct AppConfig {
pub port: u16,
}
"#,
)
.unwrap();
let mut cmd = Command::cargo_bin("context-creator").unwrap();
cmd.current_dir(root)
.arg("--trace-imports")
.arg("--include")
.arg("app.rs")
.arg("--output-file")
.arg("output.md");
cmd.assert().success();
let output_content = fs::read_to_string(root.join("output.md")).unwrap();
assert!(
output_content.contains("## app.rs"),
"Output should contain app.rs"
);
assert!(
output_content.contains("## config.rs"),
"Output should contain config.rs"
);
assert!(
!output_content.contains("## serde"),
"Output should NOT contain external crate serde"
);
assert!(
!output_content.contains("## std"),
"Output should NOT contain external crate std"
);
}
#[test]
fn test_trace_imports_combined_with_include_types() {
let temp_dir = TempDir::new().unwrap();
let root = temp_dir.path();
fs::create_dir_all(root.join(".git")).unwrap();
fs::write(
root.join("main.rs"),
r#"
mod data;
use data::User;
fn main() {
let user: User = User::new("Alice");
}
"#,
)
.unwrap();
fs::write(
root.join("data.rs"),
r#"
mod types;
use types::UserId;
pub struct User {
id: UserId,
name: String,
}
impl User {
pub fn new(name: &str) -> Self {
Self {
id: UserId::generate(),
name: name.to_string(),
}
}
}
"#,
)
.unwrap();
fs::write(
root.join("types.rs"),
r#"
pub struct UserId(u64);
impl UserId {
pub fn generate() -> Self {
UserId(42)
}
}
"#,
)
.unwrap();
let mut cmd = Command::cargo_bin("context-creator").unwrap();
cmd.current_dir(root)
.arg("--trace-imports")
.arg("--include-types")
.arg("--include")
.arg("main.rs")
.arg("--semantic-depth")
.arg("3") .arg("--output-file")
.arg("output.md");
cmd.assert().success();
let output_content = fs::read_to_string(root.join("output.md")).unwrap();
println!("Output content:\n{output_content}");
assert!(
output_content.contains("## main.rs"),
"Output should contain main.rs"
);
assert!(
output_content.contains("## data.rs"),
"Output should contain data.rs"
);
}