use splitrs::file_analyzer::FileAnalyzer;
use splitrs::module_generator::{generate_mod_rs, Module};
fn parse(code: &str) -> syn::File {
syn::parse_file(code).expect("test fixture must parse as Rust")
}
fn analyze(code: &str) -> (syn::File, FileAnalyzer) {
let file = parse(code);
let mut analyzer = FileAnalyzer::new(false, 500);
analyzer.analyze(&file);
(file, analyzer)
}
#[test]
fn test_file_inner_doc_preserved_in_mod_rs() {
let code = r#"
//! This is crate documentation.
//! It spans multiple lines.
pub struct Foo {
value: i32,
}
"#;
let (_, analyzer) = analyze(code);
assert!(
!analyzer.file_inner_docs.is_empty(),
"expected file_inner_docs to be populated from //! attrs"
);
let modules: Vec<Module> = analyzer.group_by_module(500);
let mod_rs = generate_mod_rs(
&modules,
&std::env::temp_dir().join("splitrs-doc-test"),
None,
false,
&analyzer.file_inner_docs,
)
.expect("generate_mod_rs must succeed");
assert!(
mod_rs.contains("This is crate documentation"),
"expected doc text in mod.rs output; got:\n{}",
mod_rs
);
assert!(
mod_rs.contains("//!"),
"expected //! style doc comment in mod.rs; got:\n{}",
mod_rs
);
}
#[test]
fn test_type_doc_comment_preserved() {
let code = r#"
/// A documented struct.
/// Has multiple doc lines.
pub struct Documented {
value: i32,
}
impl Documented {
pub fn new(value: i32) -> Self { Self { value } }
}
"#;
let (file, analyzer) = analyze(code);
let modules = analyzer.group_by_module(500);
let dummy_needs_pub: std::collections::HashSet<String> = std::collections::HashSet::new();
let dummy_fields: std::collections::HashMap<String, std::collections::HashSet<String>> =
std::collections::HashMap::new();
let empty_uses: Vec<syn::Item> = Vec::new();
let type_to_module: std::collections::HashMap<String, String> = modules
.iter()
.flat_map(|m| m.types.iter().map(|t| (t.name.clone(), m.name.clone())))
.collect();
let doc_module = modules
.iter()
.find(|m| m.types.iter().any(|t| t.name == "Documented"))
.expect("expected a module containing 'Documented'");
let content = doc_module.generate_content(
&file,
&empty_uses,
&type_to_module,
&dummy_needs_pub,
None,
&dummy_fields,
None,
&dummy_needs_pub,
);
assert!(
content.contains("A documented struct"),
"expected struct doc comment in module content; got:\n{}",
content
);
}
#[test]
fn test_regular_item_doc_unchanged() {
let code = r#"
/// A very helpful utility function.
/// Returns x plus one.
pub fn increment(x: i32) -> i32 {
x + 1
}
"#;
let (file, analyzer) = analyze(code);
let modules = analyzer.group_by_module(500);
let dummy_needs_pub: std::collections::HashSet<String> = std::collections::HashSet::new();
let dummy_fields: std::collections::HashMap<String, std::collections::HashSet<String>> =
std::collections::HashMap::new();
let empty_uses: Vec<syn::Item> = Vec::new();
let type_to_module: std::collections::HashMap<String, String> =
std::collections::HashMap::new();
let fn_module = modules
.iter()
.find(|m| m.name == "functions")
.expect("expected 'functions' module");
let content = fn_module.generate_content(
&file,
&empty_uses,
&type_to_module,
&dummy_needs_pub,
None,
&dummy_fields,
None,
&dummy_needs_pub,
);
assert!(
content.contains("A very helpful utility function"),
"expected function doc comment in functions module; got:\n{}",
content
);
assert!(
content.contains("Returns x plus one"),
"expected second doc line in functions module; got:\n{}",
content
);
}