use crate::codegen::cfg::{core_default_features_active, enabled_features_for_language};
use crate::core::config::{Language, RConfig, ResolvedCrateConfig};
use std::collections::BTreeSet;
fn config_with_core_features(dir: &std::path::Path, features_body: &str, r: Option<RConfig>) -> ResolvedCrateConfig {
let core_dir = dir.join("crates").join("my-lib");
std::fs::create_dir_all(&core_dir).expect("create core crate dir");
std::fs::write(
core_dir.join("Cargo.toml"),
format!("[package]\nname = \"my-lib\"\n\n[features]\n{features_body}"),
)
.expect("write core Cargo.toml");
ResolvedCrateConfig {
workspace_root: Some(dir.to_path_buf()),
name: "my-lib".to_string(),
sources: vec![std::path::PathBuf::from("crates/my-lib/src/lib.rs")],
r,
..Default::default()
}
}
fn set(names: &[&str]) -> BTreeSet<String> {
names.iter().map(|n| (*n).to_string()).collect()
}
#[test]
fn core_default_features_active_is_unconditionally_true_outside_r() {
let config = ResolvedCrateConfig::default();
for lang in [
Language::Go,
Language::Java,
Language::Kotlin,
Language::KotlinAndroid,
Language::Csharp,
Language::Python,
Language::Ruby,
Language::Node,
Language::Php,
Language::Elixir,
Language::Wasm,
Language::Zig,
Language::Dart,
Language::Swift,
Language::Ffi,
] {
assert!(
core_default_features_active(&config, lang),
"{lang:?}'s base core dependency edge never emits `default-features = false`, so its \
defaults must always read as active"
);
}
}
#[test]
fn core_default_features_active_for_r_defaults_to_true_when_unset() {
let config = ResolvedCrateConfig {
r: Some(RConfig {
features: Some(vec!["curated".to_string()]),
default_features: None,
..r_config_defaults()
}),
..Default::default()
};
assert!(core_default_features_active(&config, Language::R));
}
#[test]
fn core_default_features_active_for_r_stays_true_with_no_replacement_features() {
let config = ResolvedCrateConfig {
r: Some(RConfig {
features: Some(vec![]),
default_features: Some(false),
..r_config_defaults()
}),
..Default::default()
};
assert!(core_default_features_active(&config, Language::R));
}
#[test]
fn core_default_features_active_for_r_is_false_with_default_features_disabled_and_a_replacement_list() {
let config = ResolvedCrateConfig {
r: Some(RConfig {
features: Some(vec!["curated".to_string()]),
default_features: Some(false),
..r_config_defaults()
}),
..Default::default()
};
assert!(!core_default_features_active(&config, Language::R));
}
fn r_config_defaults() -> RConfig {
RConfig {
package_name: None,
features: None,
default_features: None,
serde_rename_all: None,
exclude_functions: Vec::new(),
exclude_types: Vec::new(),
rename_fields: std::collections::HashMap::new(),
run_wrapper: None,
extra_lint_paths: Vec::new(),
extra_makevars_prelude: Vec::new(),
extra_pkg_libs: Vec::new(),
}
}
#[test]
fn enabled_features_for_language_includes_a_core_default_the_binding_never_configured() {
let dir = tempfile::tempdir().expect("tempdir");
let config = config_with_core_features(dir.path(), "default = [\"extended-mode\"]\nextended-mode = []\n", None);
let enabled: BTreeSet<String> = enabled_features_for_language(&config, Language::Go)
.into_iter()
.collect();
assert_eq!(
enabled,
set(&["extended-mode"]),
"a core-declared default feature must be counted as active even though this binding's own \
`alef.toml` never names it, got: {enabled:?}"
);
}
#[test]
fn enabled_features_for_language_expands_an_aggregate_reachable_only_through_core_defaults() {
let dir = tempfile::tempdir().expect("tempdir");
let config = config_with_core_features(
dir.path(),
"default = [\"mobile-target\"]\nmobile-target = [\"tokenizer\"]\ntokenizer = []\n",
None,
);
let enabled: BTreeSet<String> = enabled_features_for_language(&config, Language::Dart)
.into_iter()
.collect();
assert_eq!(
enabled,
set(&["mobile-target", "tokenizer"]),
"the aggregate named in core's own defaults, and its transitive member, must both count \
as enabled, got: {enabled:?}"
);
}
#[test]
fn enabled_features_for_language_does_not_resurrect_a_feature_r_genuinely_suppressed() {
let dir = tempfile::tempdir().expect("tempdir");
let config = config_with_core_features(
dir.path(),
"default = [\"extended-mode\"]\nextended-mode = []\ncurated = []\n",
Some(RConfig {
features: Some(vec!["curated".to_string()]),
default_features: Some(false),
..r_config_defaults()
}),
);
let enabled: BTreeSet<String> = enabled_features_for_language(&config, Language::R)
.into_iter()
.collect();
assert_eq!(
enabled,
set(&["curated"]),
"`extended-mode` is a core default this R binding's Cargo.toml explicitly suppresses -- it must \
stay absent, got: {enabled:?}"
);
}