hblank-cli 0.4.0

Command-line harness for Hblank
Documentation
use std::fs;

use hblank_cli::{Config, discover_fixture_files, refresh_generated_fixtures};

fn write(path: &std::path::Path, contents: &str) {
    if let Some(parent) = path.parent() {
        fs::create_dir_all(parent).expect("parent directory should be created");
    }
    fs::write(path, contents).expect("fixture file should be written");
}

#[test]
fn discovers_direct_and_nested_fixture_files_in_stable_order() {
    let project = tempfile::tempdir().expect("temporary project should be created");
    write(&project.path().join("src/zeta.hblank.rs"), "// zeta\n");
    write(
        &project.path().join("src/components/alpha.hblank.rs"),
        "// alpha\n",
    );
    write(
        &project.path().join("src/component.rs"),
        "// not a fixture\n",
    );
    write(
        &project.path().join("target/generated.hblank.rs"),
        "// ignored\n",
    );

    let fixture_files = discover_fixture_files(project.path(), &Config::default())
        .expect("discovery should succeed");

    assert_eq!(fixture_files.len(), 2);
    assert_eq!(
        fixture_files[0].relative_path,
        std::path::Path::new("src/components/alpha.hblank.rs")
    );
    assert_eq!(
        fixture_files[1].relative_path,
        std::path::Path::new("src/zeta.hblank.rs")
    );
    assert_ne!(fixture_files[0].module_name, fixture_files[1].module_name);
}

#[test]
fn applies_custom_patterns_and_ignores() {
    let project = tempfile::tempdir().expect("temporary project should be created");
    write(
        &project.path().join("fixtures/a.fixture.rs"),
        "// include\n",
    );
    write(
        &project.path().join("fixtures/private/b.fixture.rs"),
        "// ignore\n",
    );
    let config = Config {
        fixtures: vec!["fixtures/**/*.fixture.rs".to_owned()],
        ignore: vec!["fixtures/private/**".to_owned()],
        ..Config::default()
    };

    let fixture_files =
        discover_fixture_files(project.path(), &config).expect("discovery should succeed");

    assert_eq!(fixture_files.len(), 1);
    assert_eq!(
        fixture_files[0].relative_path,
        std::path::Path::new("fixtures/a.fixture.rs")
    );
}

#[test]
fn refreshes_generated_imports_only_when_discovery_changes() {
    let project = tempfile::tempdir().expect("temporary project should be created");
    let first_path = project.path().join("src/first.hblank.rs");
    let second_path = project.path().join("src/nested/second.hblank.rs");
    write(&first_path, "// first\n");

    let first = refresh_generated_fixtures(project.path(), &Config::default())
        .expect("initial generation should succeed");
    let unchanged = refresh_generated_fixtures(project.path(), &Config::default())
        .expect("unchanged generation should succeed");
    write(&second_path, "// second\n");
    let added = refresh_generated_fixtures(project.path(), &Config::default())
        .expect("added fixture file should regenerate");
    fs::remove_file(&first_path).expect("first fixture file should be removed");
    let removed = refresh_generated_fixtures(project.path(), &Config::default())
        .expect("removed fixture file should regenerate");

    assert!(first.changed);
    assert!(!unchanged.changed);
    assert!(added.changed);
    assert_eq!(added.fixture_files.len(), 2);
    assert!(removed.changed);
    assert_eq!(removed.fixture_files.len(), 1);

    let generated = fs::read_to_string(project.path().join(".hblank/generated/fixtures.rs"))
        .expect("generated source should exist");
    assert!(generated.contains("second.hblank.rs"));
    assert!(!generated.contains("first.hblank.rs"));
    assert!(generated.contains("#[path = "));
}

#[test]
fn duplicate_file_stems_receive_distinct_module_names() {
    let project = tempfile::tempdir().expect("temporary project should be created");
    write(&project.path().join("src/a/card.hblank.rs"), "// a\n");
    write(&project.path().join("src/b/card.hblank.rs"), "// b\n");

    let fixture_files = discover_fixture_files(project.path(), &Config::default())
        .expect("discovery should succeed");

    assert_eq!(fixture_files.len(), 2);
    assert_ne!(fixture_files[0].module_name, fixture_files[1].module_name);
}