alef 0.84.1

Opinionated polyglot binding generator for Rust libraries
Documentation
//! Stamp-line syntax and round-tripping, split out of [`super::tests`] (`tests.rs`), which is
//! over the 1,000-line cap and may not grow.
//!
//! The concern these share is the `alef:hash:` line's own shape: which comment delimiters it is
//! written with, that emission and read-back agree on them, and that neither one touches body
//! text that merely resembles a stamp.

use super::*;

#[test]
fn generated_hash_stamp_shapes_round_trip() {
    let fixtures = [
        (
            "double slash",
            "// auto-generated by alef\n// alef:hash:abc123\nvalue\n",
        ),
        ("hash", "# auto-generated by alef\n# alef:hash:abc123\nvalue\n"),
        ("semicolon", "; auto-generated by alef\n; alef:hash:abc123\nvalue=1\n"),
        ("block", "/* auto-generated by alef\n * alef:hash:abc123\n */\nvalue\n"),
        (
            "html",
            "<!-- auto-generated by alef -->\n<!-- alef:hash:abc123 -->\nvalue\n",
        ),
    ];

    for (name, content) in fixtures {
        assert_eq!(extract_hash(content).as_deref(), Some("abc123"), "{name}");
        assert!(!strip_hash_line(content).contains(HASH_PREFIX), "{name}");
    }
}

/// The stamp line must be a comment in the same syntax as the marker line it sits under.
/// A `//` stamp beneath a `;` marker is not merely inconsistent: `//` opens no comment in INI,
/// where it is the prefix of a registry-scoped auth key, so the line parses as configuration.
#[test]
fn stamp_line_uses_the_comment_syntax_of_its_own_marker_line() {
    let fixtures = [
        ("double slash", "// auto-generated by alef", "// alef:hash:abc123"),
        ("hash", "# auto-generated by alef", "# alef:hash:abc123"),
        ("semicolon", "; auto-generated by alef", "; alef:hash:abc123"),
        ("block", " * auto-generated by alef", " * alef:hash:abc123"),
        ("html", "<!-- auto-generated by alef -->", "<!-- alef:hash:abc123 -->"),
    ];

    for (name, marker, expected_stamp) in fixtures {
        let injected = inject_hash_line(&format!("{marker}\nbody\n"), "abc123");
        assert_eq!(injected.lines().nth(1), Some(expected_stamp), "{name}");
        assert_eq!(extract_hash(&injected).as_deref(), Some("abc123"), "{name}");
    }
}

/// Transition guard for the INI stamp-syntax fix: files already on disk in every consumer tree
/// carry a `// alef:hash:` line under a `;` marker, because that is what alef emitted before the
/// emit and read-back sides were unified. Read-back must keep accepting it. If it did not, every
/// such file would extract no hash, keep an unstrippable line in its hashed body, and look to
/// `alef verify` like a file whose provenance alef cannot account for. ~keep
#[test]
fn legacy_double_slash_stamp_under_a_semicolon_marker_is_still_recognised() {
    let legacy = "; auto-generated by alef\n// alef:hash:abc123\nvalue=1\n";

    assert!(content_has_alef_marker(legacy));
    assert_eq!(extract_hash(legacy).as_deref(), Some("abc123"));
    assert_eq!(strip_hash_line(legacy), "; auto-generated by alef\nvalue=1\n");
    assert_eq!(
        inject_hash_line(&strip_hash_line(legacy), "abc123"),
        "; auto-generated by alef\n; alef:hash:abc123\nvalue=1\n",
        "re-stamping a legacy file must migrate the prefix to the marker's own syntax"
    );
}

#[test]
fn markdown_frontmatter_stamp_at_raw_line_ten_round_trips() {
    let content =
        "---\ntitle: Fixture\nlayout: reference\n---\n\nintro\n\nmetadata\n\n<!-- auto-generated by alef -->\nbody\n";
    let injected = inject_hash_line(content, "abc123");

    assert_eq!(injected.lines().nth(10), Some("<!-- alef:hash:abc123 -->"));
    assert_eq!(extract_hash(&injected).as_deref(), Some("abc123"));
    assert_eq!(strip_hash_line(&injected), content);
}

#[test]
fn hash_like_body_content_is_never_extracted_or_stripped() {
    let fixtures = [
        (
            "prose",
            "// auto-generated by alef\nbody mentions alef:hash:abc123 in prose\n",
        ),
        (
            "wrong shape",
            "// auto-generated by alef\n// alef:hash:abc123 trailing text\n",
        ),
        (
            "stamp after marker at raw line ten",
            "prefix\nprefix\nprefix\nprefix\nprefix\nprefix\nprefix\nprefix\nprefix\nprefix\n// auto-generated by alef\n// alef:hash:abc123\n",
        ),
        (
            "structured body stamp",
            "// auto-generated by alef\nbody\n// alef:hash:abc123\n",
        ),
    ];

    for (name, content) in fixtures {
        assert_eq!(extract_hash(content), None, "{name}");
        assert_eq!(strip_hash_line(content), content, "{name}");
    }
}