use std::fs;
use std::path::Path;
use projd_core::{TestEcosystem, render_markdown, scan_path};
use tempfile::TempDir;
#[test]
fn detects_rust_test_files_and_command() {
let fixture = ProjectFixture::new();
fixture.write(
"Cargo.toml",
"[package]\nname = \"demo\"\nversion = \"0.1.0\"\n",
);
fixture.write("tests/integration.rs", "#[test]\nfn integration() {}\n");
fixture.write("src/lib_test.rs", "#[test]\nfn unit() {}\n");
let scan = scan_path(fixture.path()).expect("scan succeeds");
assert!(scan.tests.has_tests_dir);
assert_eq!(scan.tests.test_files, 2);
assert!(
scan.tests
.test_directories
.iter()
.any(|path| path.ends_with("tests"))
);
assert!(scan.tests.commands.iter().any(|command| {
command.ecosystem == TestEcosystem::Rust && command.command == "cargo test"
}));
}
#[test]
fn detects_node_test_scripts_and_files() {
let fixture = ProjectFixture::new();
fixture.write(
"package.json",
r#"{
"name": "demo",
"scripts": {
"test": "vitest run",
"test:e2e": "playwright test",
"build": "vite build"
}
}
"#,
);
fixture.write("src/app.test.ts", "it('works', () => {})\n");
fixture.write("__tests__/api.spec.ts", "it('works', () => {})\n");
let scan = scan_path(fixture.path()).expect("scan succeeds");
assert!(scan.tests.has_tests_dir);
assert_eq!(scan.tests.test_files, 2);
assert_eq!(
scan.tests
.commands
.iter()
.filter(|command| command.ecosystem == TestEcosystem::Node)
.count(),
2
);
}
#[test]
fn detects_python_pytest_signals() {
let fixture = ProjectFixture::new();
fixture.write(
"pyproject.toml",
"[project]\nname = \"demo\"\n[tool.pytest.ini_options]\naddopts = \"-q\"\n",
);
fixture.write("tests/test_api.py", "def test_api():\n assert True\n");
let scan = scan_path(fixture.path()).expect("scan succeeds");
assert!(scan.tests.has_tests_dir);
assert_eq!(scan.tests.test_files, 1);
assert!(scan.tests.commands.iter().any(|command| {
command.ecosystem == TestEcosystem::Python && command.command == "pytest"
}));
}
#[test]
fn detects_cmake_test_signals() {
let fixture = ProjectFixture::new();
fixture.write(
"CMakeLists.txt",
"cmake_minimum_required(VERSION 3.20)\nenable_testing()\nadd_test(NAME smoke COMMAND smoke)\n",
);
fixture.write("native/foo_test.cpp", "int main() { return 0; }\n");
let scan = scan_path(fixture.path()).expect("scan succeeds");
assert_eq!(scan.tests.test_files, 1);
assert!(scan.tests.commands.iter().any(|command| {
command.ecosystem == TestEcosystem::CMake && command.command == "ctest"
}));
}
#[test]
fn ignores_test_files_excluded_by_ignore_files() {
let fixture = ProjectFixture::new();
fixture.write(".gitignore", "generated-tests/\n");
fixture.write(
"Cargo.toml",
"[package]\nname = \"demo\"\nversion = \"0.1.0\"\n",
);
fixture.write("src/main.rs", "fn main() {}\n");
fixture.write("generated-tests/app.test.ts", "it('ignored', () => {})\n");
let scan = scan_path(fixture.path()).expect("scan succeeds");
assert_eq!(scan.tests.test_files, 0);
assert!(!scan.tests.has_tests_dir);
}
#[test]
fn renders_tests_in_markdown_report() {
let fixture = ProjectFixture::new();
fixture.write(
"Cargo.toml",
"[package]\nname = \"demo\"\nversion = \"0.1.0\"\n",
);
fixture.write("tests/integration.rs", "#[test]\nfn integration() {}\n");
let scan = scan_path(fixture.path()).expect("scan succeeds");
let report = render_markdown(&scan);
assert!(report.contains("## Tests"));
assert!(report.contains("- Test directories: 1"));
assert!(report.contains("- Test files: 1"));
assert!(report.contains("Rust: cargo test"));
}
struct ProjectFixture {
temp_dir: TempDir,
}
impl ProjectFixture {
fn new() -> Self {
Self {
temp_dir: tempfile::tempdir().expect("create temp dir"),
}
}
fn path(&self) -> &Path {
self.temp_dir.path()
}
fn write(&self, relative: &str, content: &str) {
let path = self.path().join(relative);
if let Some(parent) = path.parent() {
fs::create_dir_all(parent).expect("create fixture parent");
}
fs::write(path, content).expect("write fixture file");
}
}