alef 0.68.0

Opinionated polyglot binding generator for Rust libraries
Documentation
//! Unit coverage for the stamp/format seam. The pipeline-level proof that `alef all` actually
//! ships canonical scaffold output lives in
//! `bin_cli::core_commands::post_build_format_order_tests`; this module pins the narrower
//! invariants those tests depend on.

use super::*;

const MARKED_AND_STAMPED: &str = "# This file is auto-generated by alef — DO NOT EDIT.\n\
                                  # alef:hash:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n\
                                  body = 1\n";
const MARKED_ONLY: &str = "# This file is auto-generated by alef — DO NOT EDIT.\nbody = 1\n";
const UNMARKED: &str = "# alef:hash:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\nbody = 1\n";

fn write(dir: &Path, name: &str, content: &str) -> PathBuf {
    let path = dir.join(name);
    std::fs::write(&path, content).expect("write fixture file");
    path
}

#[test]
fn unstamping_removes_the_hash_line_and_leaves_the_body_untouched() {
    let dir = tempfile::tempdir().expect("tempdir");
    let path = write(dir.path(), "stamped.toml", MARKED_AND_STAMPED);

    let count = unstamp_before_formatting(&HashSet::from([path.clone()]));

    assert_eq!(count, 1, "the one stamped file must be reported as rewritten");
    assert_eq!(
        std::fs::read_to_string(&path).expect("read back"),
        MARKED_ONLY,
        "unstamping must remove exactly the hash line, leaving header and body byte-identical"
    );
}

/// The predicate has to be the marker, not the hash line: a file that carries a `<tool>:hash:`
/// line without ever declaring itself alef-generated is not alef's to rewrite, and stripping its
/// hash line would be a silent edit to someone else's generated file. ~keep
#[test]
fn unstamping_leaves_a_file_that_carries_no_alef_marker_alone() {
    let dir = tempfile::tempdir().expect("tempdir");
    let path = write(dir.path(), "foreign.toml", UNMARKED);

    let count = unstamp_before_formatting(&HashSet::from([path.clone()]));

    assert_eq!(count, 0, "an unmarked file must not be counted as rewritten");
    assert_eq!(
        std::fs::read_to_string(&path).expect("read back"),
        UNMARKED,
        "an unmarked file must keep every byte, including its own hash-shaped line"
    );
}

#[test]
fn unstamping_an_already_unstamped_file_writes_nothing() {
    let dir = tempfile::tempdir().expect("tempdir");
    let path = write(dir.path(), "fresh.toml", MARKED_ONLY);

    assert_eq!(
        unstamp_before_formatting(&HashSet::from([path.clone()])),
        0,
        "a marked file with no hash line has nothing to strip"
    );
    assert_eq!(std::fs::read_to_string(&path).expect("read back"), MARKED_ONLY);
}

#[test]
fn unstamping_a_missing_path_is_survived_rather_than_panicking() {
    let dir = tempfile::tempdir().expect("tempdir");
    let missing = dir.path().join("never-written.toml");

    assert_eq!(unstamp_before_formatting(&HashSet::from([missing])), 0);
}

/// The gate must answer "yes" for a tree whose only non-canonical file is stamped -- the exact
/// state a pre-fix run leaves behind, and the state a `--check` without `--fix-generated` reports
/// as clean. Without this the whole heal path is unreachable on a run whose writers changed
/// nothing. ~keep
#[test]
fn the_gate_sees_a_stamped_non_canonical_file() {
    if !super::super::is_tool_available("poly") {
        return;
    }
    let dir = tempfile::tempdir().expect("tempdir");
    let root = dir.path().canonicalize().unwrap_or_else(|_| dir.path().to_path_buf());
    write(
        &root,
        "pyproject.toml",
        "# This file is auto-generated by alef — DO NOT EDIT.\n\
         # alef:hash:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n\
         [project]\nname = \"x\"\nclassifiers = [ \"one\", \"two\" ]\n",
    );

    assert!(
        generated_tree_needs_formatting(&root),
        "a stamped, non-canonical file must still trigger the gate -- poly's own default skip \
         hides exactly this case"
    );
}

/// The negative control the test above needs: the gate must NOT fire on a settled tree, or it is
/// a constant `true` and every run pays for a full formatting pass. ~keep
#[test]
fn the_gate_stays_quiet_on_a_canonical_tree() {
    if !super::super::is_tool_available("poly") {
        return;
    }
    let dir = tempfile::tempdir().expect("tempdir");
    let root = dir.path().canonicalize().unwrap_or_else(|_| dir.path().to_path_buf());
    write(
        &root,
        "pyproject.toml",
        "# This file is auto-generated by alef — DO NOT EDIT.\n\
         # alef:hash:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n\
         [project]\nname = \"x\"\nclassifiers = [\"one\", \"two\"]\n",
    );

    assert!(
        !generated_tree_needs_formatting(&root),
        "a canonical tree must not trigger the gate"
    );
}