use code_digest::core::cache::FileCache;
use code_digest::core::digest::{generate_markdown, DigestOptions};
use code_digest::core::prioritizer::prioritize_files;
use code_digest::core::walker::{walk_directory, WalkOptions};
use std::fs;
use std::path::Path;
use std::sync::Arc;
use std::time::Instant;
use tempfile::TempDir;
fn create_large_test_project(base_dir: &Path, file_count: usize) -> Vec<std::path::PathBuf> {
let mut files = Vec::new();
fs::create_dir_all(base_dir.join("src/core")).unwrap();
fs::create_dir_all(base_dir.join("src/utils")).unwrap();
fs::create_dir_all(base_dir.join("tests")).unwrap();
fs::create_dir_all(base_dir.join("docs")).unwrap();
for i in 0..file_count {
let (path, content) = match i % 10 {
0 => (
format!("src/core/module_{i}.rs"),
format!("//! Module {i}\n\nuse std::collections::HashMap;\n\npub struct Module{i} {{\n data: HashMap<String, String>,\n}}\n\nimpl Module{i} {{\n pub fn new() -> Self {{\n Self {{ data: HashMap::new() }}\n }}\n}}\n"),
),
1 => (
format!("src/utils/helper_{i}.rs"),
format!("//! Helper {i}\n\npub fn process_data(input: &str) -> String {{\n input.trim().to_uppercase()\n}}\n\n#[cfg(test)]\nmod tests {{\n use super::*;\n \n #[test]\n fn test_process() {{\n assert_eq!(process_data(\"hello\"), \"HELLO\");\n }}\n}}\n"),
),
2 => (
format!("tests/test_{i}.rs"),
format!("#[test]\nfn test_module_{i}() {{\n let result = 2 + 2;\n assert_eq!(result, 4);\n}}\n"),
),
3 => (
format!("docs/doc_{i}.md"),
format!("# Documentation {i}\n\nThis is documentation for module {i}.\n\n## Usage\n\n```rust\nlet module = Module::new();\n```\n"),
),
_ => (
format!("src/file_{i}.rs"),
format!("//! File {i}\n\nconst DATA: &str = \"{}\";\n\npub fn get_data() -> &'static str {{\n DATA\n}}\n", "x".repeat(100)),
),
};
let file_path = base_dir.join(&path);
if let Some(parent) = file_path.parent() {
fs::create_dir_all(parent).unwrap();
}
fs::write(&file_path, content).unwrap();
files.push(file_path);
}
files
}
#[test]
fn test_performance_1000_files_under_1_second() {
let temp_dir = TempDir::new().unwrap();
let _files = create_large_test_project(temp_dir.path(), 1000);
let start = Instant::now();
let walk_options = WalkOptions::default();
let files = walk_directory(temp_dir.path(), walk_options).unwrap();
assert_eq!(files.len(), 1000, "Should find all 1000 files");
let cache = Arc::new(FileCache::new());
let digest_options = DigestOptions {
max_tokens: Some(100_000),
include_tree: true,
include_stats: true,
group_by_type: false,
sort_by_priority: true,
file_header_template: "## {path}".to_string(),
doc_header_template: "# Code Digest".to_string(),
include_toc: true,
enhanced_context: false,
};
let prioritized_files = prioritize_files(files, &digest_options, cache.clone()).unwrap();
let _markdown = generate_markdown(prioritized_files, digest_options, cache).unwrap();
let elapsed = start.elapsed();
let time_limit = if std::env::var("CI").is_ok() { 3.0 } else { 1.0 };
assert!(
elapsed.as_secs_f64() < time_limit,
"Processing 1000 files took {:.3}s, which exceeds the {} second requirement",
elapsed.as_secs_f64(),
time_limit
);
println!("✅ Performance test passed: 1000 files processed in {:.3}s", elapsed.as_secs_f64());
}
#[test]
fn test_cache_eliminates_redundant_io() {
let temp_dir = TempDir::new().unwrap();
let test_file = temp_dir.path().join("test.txt");
fs::write(&test_file, "test content").unwrap();
let cache = Arc::new(FileCache::new());
let content1 = cache.get_or_load(&test_file).unwrap();
let stats1 = cache.stats();
assert_eq!(stats1.entries, 1);
for _ in 0..10 {
let content = cache.get_or_load(&test_file).unwrap();
assert!(Arc::ptr_eq(&content1, &content), "Should return same Arc");
}
let stats2 = cache.stats();
assert_eq!(stats2.entries, 1, "Cache should still have only 1 entry");
println!("✅ Cache test passed: 10 reads returned the same Arc reference");
}