use crate::backends::swift::SwiftBackend;
use crate::core::backend::{Backend, GeneratedFile};
use crate::core::config::{NewAlefConfig, ResolvedCrateConfig};
use crate::core::ir::{ApiSurface, EnumDef, EnumVariant};
const ENUM_NAME: &str = "RoutingStrategy";
const GATING_FEATURE: &str = "extra-tier";
fn swift_config_with_feature(configured_feature: Option<&str>) -> ResolvedCrateConfig {
let features_line = configured_feature
.map(|f| format!("features = [\"{f}\"]\n"))
.unwrap_or_default();
let toml_src = format!(
"[workspace]\nlanguages = [\"swift\"]\n[[crates]]\nname = \"test-lib\"\nsources = [\"src/lib.rs\"]\n\
[crates.swift]\n{features_line}"
);
let cfg: NewAlefConfig = toml::from_str(&toml_src).unwrap();
cfg.resolve().unwrap().remove(0)
}
fn foreign_cfg_enum_api(rust_path: &str) -> ApiSurface {
ApiSurface {
crate_name: "test-lib".to_string(),
version: "0.1.0".to_string(),
enums: vec![EnumDef {
name: ENUM_NAME.to_string(),
rust_path: rust_path.to_string(),
has_serde: true,
variants: vec![
EnumVariant {
name: "Primary".to_string(),
..Default::default()
},
EnumVariant {
name: "Extra".to_string(),
cfg: Some(format!(r#"feature = "{GATING_FEATURE}""#)),
..Default::default()
},
],
..Default::default()
}],
..Default::default()
}
}
fn file_declaring<'a>(files: &'a [GeneratedFile], suffix: &str, marker: &str) -> &'a str {
let matches: Vec<&GeneratedFile> = files
.iter()
.filter(|f| f.path.to_string_lossy().ends_with(suffix) && f.content.contains(marker))
.collect();
assert_eq!(
matches.len(),
1,
"expected exactly one generated {suffix} file containing {marker:?}, found {} ({:?})",
matches.len(),
files.iter().map(|f| f.path.display().to_string()).collect::<Vec<_>>()
);
&matches[0].content
}
fn mirror_variants(lib_rs: &str) -> Vec<String> {
let header = format!("pub enum {ENUM_NAME} {{\n");
let start = lib_rs
.find(&header)
.map(|i| i + header.len())
.unwrap_or_else(|| panic!("bridge lib.rs must declare the mirror enum, got:\n{lib_rs}"));
let body = &lib_rs[start..];
let end = body
.find("\n}")
.unwrap_or_else(|| panic!("mirror enum declaration must close, got:\n{body}"));
body[..end]
.lines()
.map(|line| line.trim().trim_end_matches(',').to_string())
.filter(|line| !line.is_empty())
.collect()
}
fn swift_cases(swift_src: &str) -> Vec<String> {
let header = format!("public enum {ENUM_NAME}: String");
let start = swift_src
.find(&header)
.unwrap_or_else(|| panic!("Swift source must declare the public enum, got:\n{swift_src}"));
let body = &swift_src[start..];
let end = body
.find("\n}")
.unwrap_or_else(|| panic!("Swift enum declaration must close, got:\n{body}"));
body[..end]
.lines()
.filter_map(|line| line.trim().strip_prefix("case "))
.map(|rest| {
rest.split('=')
.next()
.unwrap_or_default()
.trim()
.trim_matches('`')
.to_string()
})
.collect()
}
fn as_swift_case(variant_name: &str) -> String {
use heck::ToLowerCamelCase;
crate::backends::swift::naming::swift_source_ident(&variant_name.to_lower_camel_case())
.trim_matches('`')
.to_string()
}
fn emitted_surfaces(configured_feature: Option<&str>, rust_path: &str) -> (Vec<String>, Vec<String>) {
let api = foreign_cfg_enum_api(rust_path);
let config = swift_config_with_feature(configured_feature);
let files = SwiftBackend.generate_bindings(&api, &config).unwrap();
let mirror_header = format!("pub enum {ENUM_NAME} {{\n");
let swift_header = format!("public enum {ENUM_NAME}: String");
let mirror = mirror_variants(file_declaring(&files, ".rs", &mirror_header));
let cases = swift_cases(file_declaring(&files, ".swift", &swift_header));
(mirror, cases)
}
fn assert_surfaces_agree(configured_feature: Option<&str>, rust_path: &str) -> Vec<String> {
let (mirror, cases) = emitted_surfaces(configured_feature, rust_path);
let expected: Vec<String> = mirror.iter().map(|v| as_swift_case(v)).collect();
assert_eq!(
cases, expected,
"the public Swift enum's `case` list and the swift-bridge mirror enum's variant list must \
name the same variants; mirror declared {mirror:?}, Swift declared {cases:?}"
);
mirror
}
#[test]
fn swift_case_list_matches_mirror_when_foreign_variant_is_proven_unreachable() {
let mirror = assert_surfaces_agree(None, "dep_crate::RoutingStrategy");
assert_eq!(
mirror,
vec!["Primary".to_string()],
"sanity check on the fixture itself: with the gating feature off the mirror must have \
dropped the foreign variant, otherwise this test proves nothing"
);
}
#[test]
fn swift_case_list_matches_mirror_when_foreign_variant_is_reachable() {
let mirror = assert_surfaces_agree(Some(GATING_FEATURE), "dep_crate::RoutingStrategy");
assert_eq!(
mirror,
vec!["Primary".to_string(), "Extra".to_string()],
"with the gating feature configured the foreign variant is not proven unreachable, so the \
mirror must still declare it"
);
}
#[test]
fn swift_case_list_matches_mirror_for_a_host_owned_cfg_gated_variant() {
let mirror = assert_surfaces_agree(None, "test_lib::RoutingStrategy");
assert_eq!(
mirror,
vec!["Primary".to_string(), "Extra".to_string()],
"a host-owned cfg-gated variant must stay on the mirror declaration regardless of the \
configured feature set"
);
}