use super::*;
fn cargo_only_config(cargo: ScaffoldCargo) -> ResolvedCrateConfig {
let mut cfg = test_config();
cfg.scaffold = Some(ScaffoldConfig {
description: Some("Test library".to_string()),
license: Some("MIT".to_string()),
repository: Some("https://github.com/test/my-lib".to_string()),
homepage: None,
authors: vec!["Alice".to_string()],
keywords: vec!["test".to_string()],
generated_header: None,
precommit: None,
cargo: Some(cargo),
});
cfg
}
#[test]
fn cargo_config_default_renders_canonical_six_target_template() {
let rendered = render_cargo_config(&ScaffoldCargo::default());
assert!(rendered.starts_with("# This file is auto-generated by alef. DO NOT EDIT.\n"));
assert!(rendered.contains("# Re-generate with: alef scaffold\n"));
assert!(rendered.contains("[build]\nincremental = true"));
assert!(rendered.contains("[net]\ngit-fetch-with-cli = true"));
assert!(rendered.contains("[registries.crates-io]\nprotocol = \"sparse\""));
assert!(rendered.contains("[target.'cfg(target_os = \"macos\")']"));
assert!(rendered.contains("link-arg=-Wl,-undefined,dynamic_lookup"));
assert!(rendered.contains("[target.x86_64-pc-windows-msvc]"));
assert!(rendered.contains("[target.i686-pc-windows-msvc]"));
assert!(rendered.contains("[target.aarch64-unknown-linux-gnu]"));
assert!(rendered.contains("[target.x86_64-unknown-linux-musl]"));
assert!(rendered.contains("[target.wasm32-unknown-unknown]"));
assert!(rendered.contains("getrandom_backend=\\\"wasm_js\\\""));
assert!(!rendered.contains("\n[env]\n"));
}
#[test]
fn cargo_config_re_render_is_byte_identical() {
let cargo = ScaffoldCargo::default();
let first = render_cargo_config(&cargo);
let second = render_cargo_config(&cargo);
assert_eq!(first, second);
}
#[test]
fn cargo_config_disabling_individual_targets_omits_their_blocks() {
let cargo = ScaffoldCargo {
targets: ScaffoldCargoTargets {
i686_pc_windows_msvc: false,
x86_64_unknown_linux_musl: false,
..ScaffoldCargoTargets::default()
},
build_jobs: 4,
env: Default::default(),
};
let rendered = render_cargo_config(&cargo);
assert!(!rendered.contains("[target.i686-pc-windows-msvc]"));
assert!(!rendered.contains("[target.x86_64-unknown-linux-musl]"));
assert!(rendered.contains("[target.x86_64-pc-windows-msvc]"));
assert!(rendered.contains("[target.aarch64-unknown-linux-gnu]"));
assert!(rendered.contains("[target.'cfg(target_os = \"macos\")']"));
}
#[test]
fn cargo_config_disabling_macos_omits_dynamic_lookup() {
let cargo = ScaffoldCargo {
targets: ScaffoldCargoTargets {
macos_dynamic_lookup: false,
..ScaffoldCargoTargets::default()
},
build_jobs: 4,
env: Default::default(),
};
let rendered = render_cargo_config(&cargo);
assert!(!rendered.contains("dynamic_lookup"));
assert!(!rendered.contains("cfg(target_os = \"macos\")"));
}
#[test]
fn cargo_config_env_plain_string_renders_into_env_block() {
let mut env = std::collections::HashMap::new();
env.insert("MY_VAR".to_string(), ScaffoldCargoEnvValue::Plain("hello".to_string()));
let cargo = ScaffoldCargo {
targets: ScaffoldCargoTargets::default(),
build_jobs: 4,
env,
};
let rendered = render_cargo_config(&cargo);
assert!(rendered.contains("\n[env]\n"));
assert!(rendered.contains("MY_VAR = \"hello\"\n"));
}
#[test]
fn cargo_config_env_structured_value_renders_with_relative() {
let mut env = std::collections::HashMap::new();
env.insert(
"RUBY".to_string(),
ScaffoldCargoEnvValue::Structured {
value: "scripts/preferred-ruby.sh".to_string(),
relative: true,
},
);
let cargo = ScaffoldCargo {
targets: ScaffoldCargoTargets::default(),
build_jobs: 4,
env,
};
let rendered = render_cargo_config(&cargo);
assert!(rendered.contains("[env]\n"));
assert!(rendered.contains("RUBY = { value = \"scripts/preferred-ruby.sh\", relative = true }\n"));
}
#[test]
fn cargo_config_env_keys_are_sorted_for_determinism() {
let mut env = std::collections::HashMap::new();
env.insert("ZED".to_string(), ScaffoldCargoEnvValue::Plain("z".to_string()));
env.insert("ALPHA".to_string(), ScaffoldCargoEnvValue::Plain("a".to_string()));
env.insert("MID".to_string(), ScaffoldCargoEnvValue::Plain("m".to_string()));
let cargo = ScaffoldCargo {
targets: ScaffoldCargoTargets::default(),
build_jobs: 4,
env,
};
let rendered = render_cargo_config(&cargo);
let env_section = rendered.split("[env]\n").nth(1).expect("env section present");
let alpha_pos = env_section.find("ALPHA").expect("ALPHA present");
let mid_pos = env_section.find("MID").expect("MID present");
let zed_pos = env_section.find("ZED").expect("ZED present");
assert!(alpha_pos < mid_pos);
assert!(mid_pos < zed_pos);
}
#[test]
fn cargo_config_env_string_with_quotes_is_escaped() {
let mut env = std::collections::HashMap::new();
env.insert(
"QUOTED".to_string(),
ScaffoldCargoEnvValue::Plain(r#"a"b\c"#.to_string()),
);
let cargo = ScaffoldCargo {
targets: ScaffoldCargoTargets::default(),
build_jobs: 4,
env,
};
let rendered = render_cargo_config(&cargo);
assert!(rendered.contains("QUOTED = \"a\\\"b\\\\c\"\n"));
}
#[test]
fn cargo_config_default_includes_build_jobs_limit() {
let rendered = render_cargo_config(&ScaffoldCargo::default());
assert!(
rendered.contains("[build]\nincremental = true\njobs = 4\n"),
"build_jobs default (4) must be in [build] section; got:\n{rendered}"
);
}
#[test]
fn cargo_config_build_jobs_zero_disables_limit() {
let cargo = ScaffoldCargo {
targets: ScaffoldCargoTargets::default(),
build_jobs: 0,
env: Default::default(),
};
let rendered = render_cargo_config(&cargo);
assert!(
!rendered.contains("jobs = "),
"build_jobs = 0 must not emit jobs limit; got:\n{rendered}"
);
}
#[test]
fn cargo_config_build_jobs_custom_value_renders() {
let cargo = ScaffoldCargo {
targets: ScaffoldCargoTargets::default(),
build_jobs: 2,
env: Default::default(),
};
let rendered = render_cargo_config(&cargo);
assert!(
rendered.contains("jobs = 2\n"),
"custom build_jobs value must render; got:\n{rendered}"
);
}
#[test]
fn scaffold_emits_cargo_config_when_scaffold_cargo_is_set() {
let config = cargo_only_config(ScaffoldCargo::default());
let api = test_api();
let all_files = scaffold(&api, &config, &[Language::Wasm]).unwrap();
let cargo_file = all_files
.iter()
.find(|f| f.path == std::path::Path::new(".cargo/config.toml"))
.expect(".cargo/config.toml should be emitted when [scaffold.cargo] is set");
assert!(
cargo_file.generated_header,
"generated_header must be true so verify walks it"
);
assert!(cargo_file.content.contains("auto-generated by alef"));
assert!(cargo_file.content.contains("dynamic_lookup"));
assert!(cargo_file.content.contains("[target.x86_64-pc-windows-msvc]"));
}
#[test]
fn scaffold_skips_cargo_config_in_legacy_mode_when_file_exists() {
let config = test_config(); let api = test_api();
let all_files = scaffold(&api, &config, &[Language::Python]).unwrap();
let cargo_files: Vec<_> = all_files
.iter()
.filter(|f| f.path == std::path::Path::new(".cargo/config.toml"))
.collect();
assert!(
cargo_files.is_empty(),
"legacy branch should not emit .cargo/config.toml without Wasm",
);
}
#[test]
fn scaffold_emits_cargo_config_with_env_block_for_sample_markup_style_ruby_path() {
let mut env = std::collections::HashMap::new();
env.insert(
"RUBY".to_string(),
ScaffoldCargoEnvValue::Structured {
value: "scripts/preferred-ruby.sh".to_string(),
relative: true,
},
);
let config = cargo_only_config(ScaffoldCargo {
targets: ScaffoldCargoTargets::default(),
build_jobs: 4,
env,
});
let api = test_api();
let all_files = scaffold(&api, &config, &[Language::Ruby]).unwrap();
let cargo_file = all_files
.iter()
.find(|f| f.path == std::path::Path::new(".cargo/config.toml"))
.expect(".cargo/config.toml should be emitted");
assert!(cargo_file.content.contains("[env]\n"));
assert!(
cargo_file
.content
.contains("RUBY = { value = \"scripts/preferred-ruby.sh\", relative = true }")
);
}