use super::cargo::gen_cargo_toml;
use crate::core::config::{Language, NewAlefConfig, ResolvedCrateConfig};
use crate::core::ir::{ApiSurface, TypeDef};
const CORE_FEATURES_BODY: &str = r#"default = ["native-http"]
native-http = ["dep:tokio", "tokio/net"]
wasm-http = ["dep:gloo-timers"]
"#;
fn write_core_manifest(dir: &std::path::Path) {
let core_dir = dir.join("crates").join("test-lib");
std::fs::create_dir_all(&core_dir).expect("create core crate dir");
std::fs::write(
core_dir.join("Cargo.toml"),
format!("[package]\nname = \"test-lib\"\n\n[features]\n{CORE_FEATURES_BODY}"),
)
.expect("write core Cargo.toml");
}
fn config_with_core_manifest(dir: &std::path::Path, wasm_table: &str) -> ResolvedCrateConfig {
write_core_manifest(dir);
let toml_src = format!(
r#"
[workspace]
languages = ["wasm"]
[[crates]]
name = "test-lib"
sources = ["crates/test-lib/src/lib.rs"]
workspace_root = "{root}"
[crates.wasm]
{wasm_table}
"#,
root = dir.display().to_string().replace('\\', "/"),
);
let cfg: NewAlefConfig = toml::from_str(&toml_src).expect("valid alef config");
cfg.resolve().expect("resolve").remove(0)
}
fn api_gated_on_both_features() -> ApiSurface {
ApiSurface {
crate_name: "test-lib".to_string(),
version: "0.1.0".to_string(),
types: vec![TypeDef {
name: "Client".to_string(),
rust_path: "test_lib::Client".to_string(),
cfg: Some(r#"any(feature = "native-http", feature = "wasm-http")"#.to_string()),
..Default::default()
}],
..Default::default()
}
}
fn features_block(cargo_toml: &str) -> String {
let start = cargo_toml
.find("[features]\n")
.unwrap_or_else(|| panic!("no [features] table in:\n{cargo_toml}"));
let body = &cargo_toml[start..];
let end = body
.find("\n\n")
.unwrap_or_else(|| panic!("unterminated [features] table in:\n{cargo_toml}"));
body[..end].to_string()
}
fn dependency_line(cargo_toml: &str, name: &str) -> String {
let prefix = format!("{name} = ");
cargo_toml
.lines()
.find(|line| line.starts_with(&prefix))
.unwrap_or_else(|| panic!("no `{name}` dependency line in:\n{cargo_toml}"))
.to_string()
}
#[test]
fn wasm_features_default_excludes_a_core_default_the_dependency_line_disabled() {
let dir = tempfile::tempdir().expect("tempdir");
let config = config_with_core_manifest(dir.path(), r#"features = ["wasm-http"]"#);
let cargo_toml = gen_cargo_toml(&api_gated_on_both_features(), &config);
assert_eq!(
features_block(&cargo_toml),
"[features]\ndefault = [\"wasm-http\"]\n\
native-http = [\"test-lib/native-http\"]\n\
wasm-http = [\"test-lib/wasm-http\"]",
"`native-http` must stay declared-but-off: the core dep line already turned it off, and \
defaulting it back on re-enables the native tokio stack on wasm32:\n{cargo_toml}"
);
toml::from_str::<toml::Value>(&cargo_toml).expect("generated wasm Cargo.toml must be valid TOML");
}
#[test]
fn wasm_core_dependency_line_disables_default_features_and_names_only_the_wasm_set() {
let dir = tempfile::tempdir().expect("tempdir");
let config = config_with_core_manifest(dir.path(), r#"features = ["wasm-http"]"#);
let cargo_toml = gen_cargo_toml(&api_gated_on_both_features(), &config);
let core_path = config.core_crate_dep_path_for_language(&super::wasm_output_layout(&config).root, Language::Wasm);
assert_eq!(
dependency_line(&cargo_toml, "test-lib"),
format!(r#"test-lib = {{ path = "{core_path}", default-features = false, features = ["wasm-http"] }}"#),
"the core dep edge must suppress defaults and request exactly the configured wasm set:\n{cargo_toml}"
);
}
#[test]
fn wasm_features_default_keeps_core_defaults_when_no_wasm_feature_list_is_configured() {
let dir = tempfile::tempdir().expect("tempdir");
let config = config_with_core_manifest(dir.path(), "");
let cargo_toml = gen_cargo_toml(&api_gated_on_both_features(), &config);
let core_path = config.core_crate_dep_path_for_language(&super::wasm_output_layout(&config).root, Language::Wasm);
assert_eq!(
dependency_line(&cargo_toml, "test-lib"),
format!(r#"test-lib = {{ path = "{core_path}" }}"#),
"sanity: with nothing configured the dep line must leave the core defaults alone:\n{cargo_toml}"
);
assert_eq!(
features_block(&cargo_toml),
"[features]\ndefault = [\"native-http\"]\n\
native-http = [\"test-lib/native-http\"]\n\
wasm-http = [\"test-lib/wasm-http\"]",
"a core default that IS active on this dep edge must still be defaulted on:\n{cargo_toml}"
);
}