alef 0.84.2

Opinionated polyglot binding generator for Rust libraries
Documentation
use super::*;

/// `sync_versions` must bump the `[package] version` field itself in the Ruby
/// native (Magnus) crate manifest at `packages/ruby/ext/<gem>_rb/native/Cargo.toml`,
/// not just the core-crate dependency pin inside it (covered separately by
/// `sync_versions_bumps_ruby_native_core_dep_pin`).
///
/// Regression test: the only rewrite ever applied to this file was
/// `patch_workspace_dep_versions`, which walks `[dependencies]` /
/// `[dev-dependencies]` / `[build-dependencies]` tables and only touches entries
/// whose key names a workspace member — it never looks at the file's own
/// `[package].version` field. `write_version_to_cargo_toml` (which does update
/// `[package].version`) was never called for this path, so the crate's own
/// declared version silently drifted from the workspace version on every bump.
#[test]
fn sync_versions_bumps_ruby_native_package_version_field() {
    use crate::core::config::NewAlefConfig;
    let _guard = CWD_LOCK.lock().unwrap_or_else(|e| e.into_inner());
    let original_cwd = std::env::current_dir().expect("cwd");

    let tmp = tempfile::tempdir().expect("tempdir");
    let root = tmp.path();

    std::fs::write(
        root.join("Cargo.toml"),
        "[workspace.package]\nversion = \"1.3.1\"\n\n[workspace]\nresolver = \"2\"\nmembers = []\n",
    )
    .expect("write Cargo.toml");

    let native_dir = root.join("packages/ruby/ext/demolib_rb/native");
    std::fs::create_dir_all(&native_dir).expect("mkdir ruby native");
    std::fs::write(
        native_dir.join("Cargo.toml"),
        concat!(
            "# Code generated by alef — DO NOT EDIT.\n",
            "# alef:hash:deadbeef\n",
            "[package]\n",
            "name = \"demolib-rb\"\n",
            "version = \"1.3.0\"\n",
            "edition = \"2024\"\n",
            "\n",
            "[dependencies]\n",
            "magnus = \"0.7\"\n",
            // Coincidentally carries the same digits as the pre-bump project version.
            // A naive string replace across the file would corrupt this; the fix must
            // only ever touch the `[package].version` key and named workspace-member
            // dependency pins.
            "serde = \"1.3.0\"\n",
            "demolib = { version = \"1.3.0\", path = \"../../../../../crates/demolib\", features = [\"full\"] }\n",
        ),
    )
    .expect("write ruby native Cargo.toml");

    let alef_toml = format!(
        "[workspace]\nlanguages = [\"ruby\"]\n[[crates]]\nname = \"demolib\"\nsources = []\nversion_from = \"{}\"\n",
        root.join("Cargo.toml").display().to_string().replace('\\', "/")
    );
    let alef_toml_path = root.join("alef.toml");
    std::fs::write(&alef_toml_path, &alef_toml).expect("write alef.toml");

    let cfg: NewAlefConfig = toml::from_str(&alef_toml).expect("parse alef.toml");
    let mut resolved = cfg.resolve().expect("resolve config");
    let resolved_cfg = resolved.remove(0);

    std::env::set_current_dir(root).expect("set_current_dir");
    let sync_result = sync_versions(&resolved_cfg, &alef_toml_path, None, true, true, None);
    let _ = std::env::set_current_dir(&original_cwd);
    sync_result.expect("sync_versions ok");

    let out = std::fs::read_to_string(native_dir.join("Cargo.toml")).expect("read ruby native Cargo.toml");
    assert!(
        out.contains("name = \"demolib-rb\"\nversion = \"1.3.1\""),
        "ruby native crate's own [package] version must be bumped to 1.3.1, got:\n{out}"
    );
    assert!(
        !out.contains("name = \"demolib-rb\"\nversion = \"1.3.0\""),
        "stale [package] version 1.3.0 must be gone, got:\n{out}"
    );
    assert!(
        out.contains(r#"demolib = { version = "1.3.1""#),
        "core dep pin must still be bumped to 1.3.1, got:\n{out}"
    );
    assert!(
        out.contains(r#"magnus = "0.7""#),
        "external magnus dep must not be touched, got:\n{out}"
    );
    assert!(
        out.contains("serde = \"1.3.0\""),
        "external serde dep pin coincidentally matching the old project version must be left \
         byte-identical, got:\n{out}"
    );
}