use super::{count_files_by_extension, detect_primary_language_with_confidence};
use proptest::prelude::*;
use std::fs;
use std::path::{Path, PathBuf};
use tempfile::TempDir;
struct ProjectFixture {
#[allow(dead_code)]
temp_dir: TempDir,
path: PathBuf,
}
impl ProjectFixture {
fn new() -> Self {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let path = temp_dir.path().to_path_buf();
Self { temp_dir, path }
}
fn create_file(&self, relative_path: &str, content: &str) {
let file_path = self.path.join(relative_path);
if let Some(parent) = file_path.parent() {
fs::create_dir_all(parent).expect("Failed to create parent dir");
}
fs::write(&file_path, content).expect("Failed to write file");
}
fn path(&self) -> &Path {
&self.path
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod property_tests {
use super::*;
#[test]
fn test_typescript_detection_consistency() {
let fixture = ProjectFixture::new();
fixture.create_file("src/main.ts", "console.log('Hello, TypeScript!');");
fixture.create_file(
"src/component.tsx",
"export const Component = () => <div>Hello</div>;",
);
fixture.create_file("package.json", r#"{"name": "test", "type": "module"}"#);
let result = detect_primary_language_with_confidence(fixture.path());
assert!(result.is_some(), "TypeScript project must be detected");
let (lang, confidence) = result.unwrap();
assert_eq!(
lang, "typescript",
"TypeScript files must be detected as 'typescript', got '{}'",
lang
);
assert!(confidence > 0.0, "Confidence must be positive");
}
#[test]
fn test_javascript_detection_consistency() {
let fixture = ProjectFixture::new();
fixture.create_file("src/main.js", "console.log('Hello, JavaScript!');");
fixture.create_file(
"src/component.jsx",
"export const Component = () => <div>Hello</div>;",
);
fixture.create_file("package.json", r#"{"name": "test", "type": "module"}"#);
let result = detect_primary_language_with_confidence(fixture.path());
assert!(result.is_some(), "JavaScript project must be detected");
let (lang, confidence) = result.unwrap();
assert_eq!(
lang, "javascript",
"JavaScript files must be detected as 'javascript', got '{}'",
lang
);
assert!(confidence > 0.0, "Confidence must be positive");
}
#[test]
fn test_rust_detection_consistency() {
let fixture = ProjectFixture::new();
fixture.create_file("src/main.rs", "fn main() { println!(\"Hello, Rust!\"); }");
fixture.create_file(
"Cargo.toml",
r#"[package]
name = "test"
version = "0.1.0""#,
);
let result = detect_primary_language_with_confidence(fixture.path());
assert!(result.is_some(), "Rust project must be detected");
let (lang, confidence) = result.unwrap();
assert_eq!(
lang, "rust",
"Rust files must be detected as 'rust', got '{}'",
lang
);
assert!(confidence > 0.0, "Confidence must be positive");
}
#[test]
fn test_deno_detection_with_deno_config() {
let fixture = ProjectFixture::new();
fixture.create_file("src/main.ts", "console.log('Hello, Deno!');");
fixture.create_file("package.json", r#"{"name": "test", "type": "module"}"#);
fixture.create_file(
"deno.json",
r#"{"imports": {"std/": "https://deno.land/std/"}}"#,
);
let result = detect_primary_language_with_confidence(fixture.path());
assert!(result.is_some(), "Deno project must be detected");
let (lang, confidence) = result.unwrap();
assert_eq!(
lang, "deno",
"Deno projects with deno.json must be detected as 'deno', got '{}'",
lang
);
assert_eq!(
confidence, 100.0,
"Deno with deno.json should have 100% confidence"
);
}
#[test]
fn test_detection_determinism() {
let fixture1 = ProjectFixture::new();
let fixture2 = ProjectFixture::new();
let files = vec![
("src/main.ts", "console.log('test');"),
("src/utils.ts", "export const helper = () => {};"),
("package.json", r#"{"name": "test"}"#),
];
for (path, content) in &files {
fixture1.create_file(path, content);
fixture2.create_file(path, content);
}
let result1 = detect_primary_language_with_confidence(fixture1.path());
let result2 = detect_primary_language_with_confidence(fixture2.path());
assert_eq!(
result1, result2,
"Language detection must be deterministic for identical projects"
);
}
#[test]
fn test_file_extension_counting_accuracy() {
let fixture = ProjectFixture::new();
fixture.create_file("file1.ts", "// TypeScript 1");
fixture.create_file("file2.ts", "// TypeScript 2");
fixture.create_file("file3.tsx", "// TypeScript JSX");
fixture.create_file("file1.js", "// JavaScript 1");
fixture.create_file("ignored.txt", "// Should be ignored");
let result = count_files_by_extension(fixture.path());
assert!(result.is_some(), "Should detect files");
let (detected_lang, confidence) = result.unwrap();
assert_eq!(
detected_lang, "typescript",
"Should detect typescript as dominant language"
);
assert!(confidence > 0.0, "Confidence should be positive");
}
#[test]
fn test_empty_project_handling() {
let fixture = ProjectFixture::new();
let result = detect_primary_language_with_confidence(fixture.path());
assert!(result.is_none(), "Empty projects should return None");
}
#[test]
fn test_config_only_project_handling() {
let fixture = ProjectFixture::new();
fixture.create_file("package.json", r#"{"name": "test"}"#);
fixture.create_file("README.md", "# Test Project");
let result = detect_primary_language_with_confidence(fixture.path());
if let Some((lang, confidence)) = result {
assert!(
confidence > 0.0,
"If detected, confidence should be positive"
);
assert!(
!lang.is_empty(),
"If detected, language should not be empty"
);
}
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod integration_tests {
#[test]
fn test_cross_command_language_consistency() {
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod regression_tests {
use super::*;
#[test]
fn test_typescript_not_detected_as_deno_regression() {
let fixture = ProjectFixture::new();
fixture.create_file(
"src/main.ts",
"const greeting: string = 'Hello, TypeScript!';",
);
fixture.create_file(
"src/types.ts",
"export interface User { id: number; name: string; }",
);
fixture.create_file(
"package.json",
r#"{"name": "typescript-project", "dependencies": {"typescript": "^5.0.0"}}"#,
);
let result = detect_primary_language_with_confidence(fixture.path());
assert!(result.is_some(), "TypeScript project must be detected");
let (lang, _) = result.unwrap();
assert_ne!(
lang, "deno",
"REGRESSION: TypeScript project must not be detected as 'deno'"
);
assert_ne!(
lang, "rust",
"REGRESSION: TypeScript project must not be detected as 'rust'"
);
assert_eq!(
lang, "typescript",
"TypeScript project must be detected as 'typescript'"
);
}
#[test]
fn test_function_count_consistency_regression() {
}
}
mod proptest_generators {
use super::*;
fn file_extension_strategy() -> impl Strategy<Value = (&'static str, &'static str)> {
prop_oneof![
Just(("ts", "typescript")),
Just(("tsx", "typescript")),
Just(("js", "javascript")),
Just(("jsx", "javascript")),
Just(("rs", "rust")),
Just(("py", "python-uv")),
Just(("kt", "kotlin")),
Just(("kts", "kotlin")),
]
}
proptest! {
#[test]
fn test_extension_mapping_correctness((ext, expected_lang) in file_extension_strategy()) {
let fixture = ProjectFixture::new();
let filename = format!("test.{}", ext);
fixture.create_file(&filename, "// Test content");
let result = count_files_by_extension(fixture.path());
if let Some((detected_lang, _)) = result {
prop_assert_eq!(detected_lang.clone(), expected_lang,
"Extension '{}' must map to '{}', got '{}'", ext, expected_lang, detected_lang);
} else {
prop_assert!(false, "Must detect language for extension '{}'", ext);
}
}
}
}