amberjs 1.17.0

JavaScript/TypeScript runtime built with Rust and V8
Documentation
// Test Discoverer - Fixed version
// Finds and loads test files

use crate::testing::test_context::TestSuite;
use std::fs;
use std::path::{Path, PathBuf};

/// Test file patterns
const TEST_FILE_PATTERNS: &[&str] = &[
    "*.test.js",
    "*.test.ts",
    "*.test.mjs",
    "*.spec.js",
    "*.spec.ts",
    "*.spec.mjs",
];
/// Test discoverer configuration
#[derive(Debug, Clone)]
pub struct TestDiscovererConfig {
    pub root_path: PathBuf,
    pub test_patterns: Vec<String>,
    pub exclude_patterns: Vec<String>,
}
impl Default for TestDiscovererConfig {
    fn default() -> Self {
        TestDiscovererConfig {
            root_path: PathBuf::from("."),
            test_patterns: TEST_FILE_PATTERNS.iter().map(|s| s.to_string()).collect(),
            exclude_patterns: vec!["node_modules".to_string()],
        }
    }
}
/// Test discovery result
#[derive(Debug, Clone)]
pub struct DiscoveryResult {
    pub test_files: Vec<PathBuf>,
    pub total_files: usize,
}
impl DiscoveryResult {
    pub fn new() -> Self {
        DiscoveryResult {
            test_files: Vec::new(),
            total_files: 0,
        }
    }
    pub fn add_file(&mut self, path: PathBuf) {
        self.test_files.push(path);
    }
}
/// Test discoverer
pub struct TestDiscoverer {
    pub config: TestDiscovererConfig,
}
impl TestDiscoverer {
    pub fn new(config: TestDiscovererConfig) -> Self {
        TestDiscoverer { config }
    }
    /// Discover test files in the configured root path
    pub fn discover(&self) -> std::io::Result<DiscoveryResult> {
        self.discover_with_read_permission(|_| Ok(()))
    }

    /// Discover test files while checking read access before each directory scan.
    pub fn discover_with_read_permission<F>(
        &self,
        mut check_read: F,
    ) -> std::io::Result<DiscoveryResult>
    where
        F: FnMut(&Path) -> std::io::Result<()>,
    {
        let mut result = DiscoveryResult::new();
        self.discover_recursive(&self.config.root_path, &mut result, &mut check_read)?;
        Ok(result)
    }

    /// Recursively discover test files
    fn discover_recursive<F>(
        &self,
        path: &Path,
        result: &mut DiscoveryResult,
        check_read: &mut F,
    ) -> std::io::Result<()>
    where
        F: FnMut(&Path) -> std::io::Result<()>,
    {
        check_read(path)?;
        let entries: _ = fs::read_dir(path)?;
        for entry in entries {
            let entry: _ = entry?;
            let path: _ = entry.path();
            // Check if path should be excluded
            if self.should_exclude(&path) {
                continue;
            }
            if path.is_dir() {
                // Recursively search directories (except excluded ones)
                self.discover_recursive(&path, result, check_read)?;
            } else if path.is_file() {
                // Check if file matches test patterns
                if self.is_test_file(&path) {
                    result.add_file(path);
                }
            }
        }
        Ok(())
    }
    /// Check if a path should be excluded
    fn should_exclude(&self, path: &Path) -> bool {
        let path_str: _ = path.to_string_lossy();
        for pattern in &self.config.exclude_patterns {
            if path_str.contains(pattern) {
                return true;
            }
        }
        false
    }
    /// Check if a file is a test file
    fn is_test_file(&self, path: &Path) -> bool {
        let file_name: _ = path.file_name().and_then(|s| s.to_str()).unwrap_or("");
        for pattern in &self.config.test_patterns {
            // Simple pattern matching - could be enhanced with glob patterns
            let pattern_str = pattern.trim_start_matches('*').to_string();
            if file_name.ends_with(&pattern_str) {
                return true;
            }
        }
        false
    }
    /// Load a test file and extract test suites
    pub fn load_test_file(&self, path: &Path) -> std::io::Result<Vec<TestSuite>> {
        let result = std::fs::read_to_string(path);
        let _code = result.map_err(|e| {
            std::io::Error::new(e.kind(), format!("Failed to read test file: {}", e))
        })?;
        let file_name = path
            .file_name()
            .and_then(|s| s.to_str())
            .unwrap_or("unknown");
        let suite = TestSuite {
            name: format!("Test Suite - {}", file_name),
            parent: None,
            child_suites: Vec::new(),
            tests: Vec::new(),
            before_each: Vec::new(),
            after_each: Vec::new(),
            before_all: None,
            after_all: None,
        };
        Ok(vec![suite])
    }
    /// Load all discovered test files
    pub fn load_all_tests(&self, discovery: &DiscoveryResult) -> std::io::Result<Vec<TestSuite>> {
        let mut all_suites = Vec::new();
        for test_file in &discovery.test_files {
            match self.load_test_file(test_file) {
                Ok(suites) => all_suites.extend(suites),
                Err(e) => eprintln!("Warning: Failed to load test file {:?}: {}", test_file, e),
            }
        }
        Ok(all_suites)
    }
}