mir-analyzer 0.3.0

Analysis engine for the mir PHP static analyzer
Documentation
use std::fs;
use std::path::Path;

fn main() {
    let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
    let fixtures_dir = Path::new(&manifest_dir).join("tests").join("fixtures");

    let out_dir = std::env::var("OUT_DIR").unwrap();
    let out_path = Path::new(&out_dir).join("fixture_tests.rs");

    let mut code = String::from("// Auto-generated by build.rs — do not edit manually\n");

    if !fixtures_dir.exists() {
        fs::write(&out_path, &code).unwrap();
        return;
    }

    // Rerun when the top-level fixtures directory changes (category added/removed).
    println!("cargo:rerun-if-changed={}", fixtures_dir.display());

    let mut categories: Vec<_> = fs::read_dir(&fixtures_dir)
        .unwrap()
        .filter_map(|e| e.ok())
        .filter(|e| e.file_type().map(|t| t.is_dir()).unwrap_or(false))
        .collect();
    categories.sort_by_key(|e| e.file_name());

    for cat_entry in categories {
        let cat_dir_name = cat_entry.file_name().to_string_lossy().into_owned();
        let cat_mod_name = cat_dir_name.replace('-', "_");

        // Rerun when a fixture is added to or removed from this category.
        println!("cargo:rerun-if-changed={}", cat_entry.path().display());

        let mut fixtures: Vec<_> = fs::read_dir(cat_entry.path())
            .unwrap()
            .filter_map(|e| e.ok())
            .filter(|e| {
                e.path()
                    .extension()
                    .map(|ext| ext == "phpt")
                    .unwrap_or(false)
            })
            .collect();
        fixtures.sort_by_key(|e| e.file_name());

        if fixtures.is_empty() {
            continue;
        }

        code.push_str(&format!("\nmod {cat_mod_name} {{\n"));

        for fixture in fixtures {
            let path = fixture.path();
            let stem = path
                .file_stem()
                .unwrap()
                .to_string_lossy()
                .replace('-', "_");
            let file_name = path.file_name().unwrap().to_string_lossy().into_owned();
            let rel = format!("tests/fixtures/{cat_dir_name}/{file_name}");

            // Rerun when this specific fixture file changes.
            println!("cargo:rerun-if-changed={manifest_dir}/{rel}");

            code.push_str(&format!(
                "    #[test]\n    fn {stem}() {{\n        \
                 mir_analyzer::test_utils::run_fixture(concat!(env!(\"CARGO_MANIFEST_DIR\"), \"/{rel}\"));\n    \
                 }}\n"
            ));
        }

        code.push_str("}\n");
    }

    fs::write(&out_path, code).unwrap();
}