alma 0.1.1

A Bevy-native modal text editor with Vim-style navigation.
Documentation
//! Regression tests for typed error-surface policy.

use std::{
    fs,
    path::{Path, PathBuf},
};

#[test]
fn source_tree_does_not_introduce_erased_error_surfaces() {
    let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
    let source_dir = manifest_dir.join("src");
    let mut violations = Vec::new();

    visit_rust_files(&source_dir, &mut |path| {
        let contents = fs::read_to_string(path).expect("source file should be readable");
        for (line_index, line) in contents.lines().enumerate() {
            let line_number = line_index + 1;

            if line.contains("Box<dyn Error")
                || line.contains("Box<dyn std::error::Error")
                || line.contains("anyhow::Error")
                || line.contains("eyre::")
            {
                violations.push(format!(
                    "{}:{line_number}: erased error surface: {line}",
                    path.display()
                ));
            }

            if line.contains("impl Error for") || line.contains("impl std::error::Error for") {
                violations.push(format!(
                    "{}:{line_number}: handwritten Error impl: {line}",
                    path.display()
                ));
            }

            if (line.contains("dyn Error") || line.contains("dyn std::error::Error"))
                && !is_standard_source_signature(line)
            {
                violations.push(format!(
                    "{}:{line_number}: dyn Error outside Error::source: {line}",
                    path.display()
                ));
            }
        }
    });

    assert!(
        violations.is_empty(),
        "typed error policy violations:\n{}",
        violations.join("\n")
    );
}

fn visit_rust_files(path: &Path, visit: &mut impl FnMut(&Path)) {
    if path.is_dir() {
        for entry in fs::read_dir(path).expect("source directory should be readable") {
            let entry = entry.expect("source directory entry should be readable");
            visit_rust_files(&entry.path(), visit);
        }
    } else if path.extension().is_some_and(|extension| extension == "rs") {
        visit(path);
    }
}

fn is_standard_source_signature(line: &str) -> bool {
    line.trim() == "fn source(&self) -> Option<&(dyn Error + 'static)> {"
        || line.trim() == "fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {"
}