alef 0.83.0

Opinionated polyglot binding generator for Rust libraries
Documentation
//! Coverage for [`cfg_default_and_forwarding_lines`].
//!
//! Split out of the parent test module so both files stay under the
//! `file-modularization` cap; the shared feature-forwarding formula is a self-contained
//! concern shared by every Rust-emitting binding scaffolder (ruby, elixir, node, php, python).

use crate::codegen::cfg::cfg_default_and_forwarding_lines;
use std::collections::{BTreeSet, HashSet};

fn set(names: &[&str]) -> BTreeSet<String> {
    names.iter().map(|n| (*n).to_string()).collect()
}

/// The formula every caller relies on: a `default = [...]` line naming every feature, then one
/// `<feature> = ["<core>/<feature>"]` forwarding row per feature, in the set's sorted order.
#[test]
fn builds_default_line_then_one_forwarding_row_per_feature() {
    let features = set(&["chunking-tokenizers", "ner"]);
    let excluded = HashSet::new();

    let lines = cfg_default_and_forwarding_lines(&features, "core-lib", &excluded);

    assert_eq!(
        lines,
        vec![
            r#"default = ["chunking-tokenizers", "ner"]"#.to_string(),
            r#"chunking-tokenizers = ["core-lib/chunking-tokenizers"]"#.to_string(),
            r#"ner = ["core-lib/ner"]"#.to_string(),
        ],
        "got: {lines:?}"
    );
}

/// A name in `excluded_default_features` still gets a forwarding row (so `cargo build
/// --features <name>` keeps working, matching `RubyConfig::excluded_default_features`'s
/// documented escape hatch) but is dropped from the `default = [...]` array.
#[test]
fn excluded_default_feature_is_forwarded_but_not_defaulted() {
    let features = set(&["chunking-tokenizers", "heic"]);
    let excluded: HashSet<&str> = ["heic"].into_iter().collect();

    let lines = cfg_default_and_forwarding_lines(&features, "core-lib", &excluded);

    assert_eq!(
        lines[0], r#"default = ["chunking-tokenizers"]"#,
        "excluded name must not appear in default: {lines:?}"
    );
    assert!(
        lines.contains(&r#"heic = ["core-lib/heic"]"#.to_string()),
        "excluded name must still get a forwarding row: {lines:?}"
    );
}

/// An empty feature set still produces a `default = []` line and no forwarding rows -- Elixir's
/// scaffold has always emitted its `[features]` table unconditionally, so this must not
/// special-case emptiness away; callers that want "no table at all" for an empty set (ruby,
/// node, python) check `features.is_empty()` themselves before calling.
#[test]
fn empty_feature_set_still_emits_a_default_line_with_no_forwarding_rows() {
    let features = BTreeSet::new();
    let excluded = HashSet::new();

    let lines = cfg_default_and_forwarding_lines(&features, "core-lib", &excluded);

    assert_eq!(lines, vec!["default = []".to_string()], "got: {lines:?}");
}