use super::{sanitize_unknown_types, strip_binding_excluded};
#[test]
fn qualified_rust_only_enum_sample_from_extraction_typechecks_with_an_ambiguous_short_name() {
let dir = tempfile::tempdir().expect("tempdir");
let lib_rs = dir.path().join("lib.rs");
let source = r#"
pub mod one {
#[cfg_attr(alef, alef(skip))]
pub enum Policy { One }
}
pub mod two {
#[cfg_attr(alef, alef(skip))]
pub enum Policy { Two }
}
#[cfg_attr(alef, alef(skip))]
pub fn choose(policy: two::Policy) {
let _ = policy;
}
"#;
std::fs::write(&lib_rs, source).expect("write fixture");
let mut api =
crate::extract::extractor::extract(&[lib_rs.as_path()], "sample", "0.0.0", None).expect("extract fixture");
strip_binding_excluded(&mut api).expect("strip binding exclusions");
sanitize_unknown_types(&mut api);
let choose = api
.functions
.iter()
.find(|function| function.name == "choose")
.expect("choose function");
assert_eq!(choose.params[0].original_type.as_deref(), Some("two::Policy"));
let config: crate::core::config::NewAlefConfig = toml::from_str(
r#"
[workspace]
languages = ["rust"]
[[crates]]
name = "sample"
sources = ["src/lib.rs"]
"#,
)
.expect("valid config");
let config = config.resolve().expect("resolved config").remove(0);
let files = crate::docs::generate_docs(&api, &config, &[crate::core::config::Language::Rust], "out")
.expect("generate docs");
let rust = files
.iter()
.find(|file| file.path.ends_with("api-rust.md"))
.expect("Rust reference");
let snippet = rust
.content
.split("```rust")
.skip(1)
.find(|block| block.contains("choose(") && block.contains(';'))
.and_then(|block| block.split("```").next())
.expect("choose example");
assert!(
snippet.contains("choose(two::Policy::Two);") || snippet.contains("choose(sample::two::Policy::Two);"),
"qualified example must select the second enum: {snippet}"
);
let library = dir.path().join("libsample.rlib");
let library_output = std::process::Command::new("rustc")
.current_dir(dir.path())
.args(["--edition=2024", "--crate-name", "sample", "--crate-type=lib"])
.arg(&lib_rs)
.arg("-o")
.arg(&library)
.output()
.expect("run rustc for fixture library");
assert!(
library_output.status.success(),
"fixture library must compile: {}",
String::from_utf8_lossy(&library_output.stderr)
);
let main_rs = dir.path().join("main.rs");
std::fs::write(&main_rs, format!("use sample::*;\nfn main() {{\n{snippet}\n}}\n"))
.expect("write generated example");
let example_output = std::process::Command::new("rustc")
.current_dir(dir.path())
.args(["--edition=2024"])
.arg(&main_rs)
.arg("--extern")
.arg(format!("sample={}", library.display()))
.arg("-o")
.arg(dir.path().join("example"))
.output()
.expect("run rustc for generated example");
assert!(
example_output.status.success(),
"generated Rust example must typecheck: {}\n{snippet}",
String::from_utf8_lossy(&example_output.stderr)
);
}
#[test]
fn skipped_tuple_param_renders_as_rust_syntax_after_extraction() {
let dir = tempfile::tempdir().expect("tempdir");
let lib_rs = dir.path().join("lib.rs");
std::fs::write(
&lib_rs,
r#"
#[cfg_attr(alef, alef(skip))]
pub fn record(entry: (String, u32)) {
let _ = entry;
}
#[cfg_attr(alef, alef(skip))]
pub fn record_many(entries: &[(String, u32)]) {
let _ = entries;
}
#[cfg_attr(alef, alef(skip))]
pub fn record_optional(entries: Option<&[(String, u32)]>) {
let _ = entries;
}
"#,
)
.expect("write fixture");
let mut api =
crate::extract::extractor::extract(&[lib_rs.as_path()], "sample", "0.0.0", None).expect("extract fixture");
strip_binding_excluded(&mut api).expect("strip binding exclusions");
sanitize_unknown_types(&mut api);
let record = api
.functions
.iter()
.find(|function| function.name == "record")
.expect("record function");
assert!(record.binding_excluded);
assert_eq!(record.params[0].original_type.as_deref(), Some("(String,u32)"));
let config: crate::core::config::NewAlefConfig = toml::from_str(
r#"
[workspace]
languages = ["rust"]
[[crates]]
name = "sample"
sources = ["src/lib.rs"]
"#,
)
.expect("valid config");
let config = config.resolve().expect("resolved config").remove(0);
let files = crate::docs::generate_docs(&api, &config, &[crate::core::config::Language::Rust], "out")
.expect("generate docs");
let rust = files
.iter()
.find(|file| file.path.ends_with("api-rust.md"))
.expect("Rust reference");
assert!(
rust.content.contains("pub fn record(entry: (String,u32))"),
"Rust docs must render the tuple type as Rust syntax; got:\n{}",
rust.content
);
assert!(
rust.content.contains("pub fn record_many(entries: &[(String,u32)])"),
"Rust docs must preserve borrowed tuple slices; got:\n{}",
rust.content
);
assert!(
rust.content
.contains("pub fn record_optional(entries: Option<&[(String,u32)]>)"),
"Rust docs must preserve optional borrowed tuple slices; got:\n{}",
rust.content
);
}
#[test]
fn qualified_named_leaves_inside_containers_survive_extraction_into_rust_docs() {
let dir = tempfile::tempdir().expect("tempdir");
let lib_rs = dir.path().join("lib.rs");
std::fs::write(
&lib_rs,
r#"
pub mod one {
#[cfg_attr(alef, alef(skip))]
pub enum Policy { One }
}
pub mod two {
#[cfg_attr(alef, alef(skip))]
pub enum Policy { Two }
}
#[cfg_attr(alef, alef(skip))]
pub fn choose_many(policies: Vec<two::Policy>) {
let _ = policies;
}
#[cfg_attr(alef, alef(skip))]
pub fn choose_by_name(policies: std::collections::HashMap<String, two::Policy>) {
let _ = policies;
}
"#,
)
.expect("write fixture");
let mut api =
crate::extract::extractor::extract(&[lib_rs.as_path()], "sample", "0.0.0", None).expect("extract fixture");
strip_binding_excluded(&mut api).expect("strip binding exclusions");
sanitize_unknown_types(&mut api);
let config: crate::core::config::NewAlefConfig = toml::from_str(
r#"
[workspace]
languages = ["rust"]
[[crates]]
name = "sample"
sources = ["src/lib.rs"]
"#,
)
.expect("valid config");
let config = config.resolve().expect("resolved config").remove(0);
let files = crate::docs::generate_docs(&api, &config, &[crate::core::config::Language::Rust], "out")
.expect("generate docs");
let rust = files
.iter()
.find(|file| file.path.ends_with("api-rust.md"))
.expect("Rust reference");
assert!(
rust.content.contains("pub fn choose_many(policies: Vec<two::Policy>)"),
"Rust docs must preserve qualified vector leaves; got:\n{}",
rust.content
);
assert!(
rust.content
.contains("pub fn choose_by_name(policies: std::collections::HashMap<String,two::Policy>)"),
"Rust docs must preserve qualified map leaves; got:\n{}",
rust.content
);
}