use super::support::test_symbol;
use super::*;
use std::fs;
use std::path::Path;
fn write_source(root: &Path, rel: &str, contents: &str) {
let path = root.join(rel);
if let Some(parent) = path.parent() {
fs::create_dir_all(parent).expect("create source dir");
}
fs::write(&path, contents).expect("write source file");
}
fn input(
symbols: Vec<Symbol>,
edges: Vec<CodewikiGraphEdge>,
availability: CodewikiGraphAvailability,
) -> CodewikiInput {
CodewikiInput {
files: symbols.iter().map(|s| s.file_path.clone()).collect(),
graph_edges: edges,
graph_availability: availability,
symbols,
leading_chunks: std::collections::BTreeMap::new(),
}
}
#[test]
fn deprecation_attribute_and_doc_comment_are_detected_badged_and_listed() {
let dir = tempfile::tempdir().expect("tempdir");
let root = dir.path();
let src = "\
/// A live helper.
pub fn keep() {}
#[deprecated(note = \"use keep instead\")]
pub fn attr_dep() {}
/// DEPRECATED: superseded by keep.
pub fn doc_dep() {}
";
let file = "src/lib.rs";
write_source(root, file, src);
let keep = test_symbol(file, "keep", "function", 2, "pub fn keep()");
let attr_dep = test_symbol(file, "attr_dep", "function", 5, "pub fn attr_dep()");
let doc_dep = test_symbol(file, "doc_dep", "function", 8, "pub fn doc_dep()");
let input = input(
vec![keep.clone(), attr_dep.clone(), doc_dep.clone()],
Vec::new(),
CodewikiGraphAvailability::Available,
);
let audit = build_audit_context(root, &input);
assert!(
audit.deprecations.contains_key(&attr_dep.id),
"attribute-deprecated symbol must be detected"
);
assert!(
audit.deprecations.contains_key(&doc_dep.id),
"doc-comment-deprecated symbol must be detected"
);
assert!(
!audit.deprecations.contains_key(&keep.id),
"a plain fn must not be flagged deprecated"
);
assert_eq!(
audit.deprecations.get(&attr_dep.id).map(String::as_str),
Some("use keep instead")
);
let file_doc = build_file_doc(
file,
"src".to_string(),
vec![keep.clone(), attr_dep.clone(), doc_dep.clone()],
None,
&RelationshipFacts::default(),
Some(&audit.deprecations),
Some(&audit.tests),
&mut None,
&mut None,
&mut None,
AiDepth::Sections,
&mut CodewikiProgress::silent(),
FileDocPosition { index: 1, total: 1 },
);
let attr_doc = file_doc
.symbols
.iter()
.find(|s| s.symbol.name == "attr_dep")
.expect("attr_dep symbol doc");
assert_eq!(
attr_doc.deprecation.as_deref(),
Some("use keep instead"),
"the file doc must stamp the deprecation reason"
);
let keep_doc = file_doc
.symbols
.iter()
.find(|s| s.symbol.name == "keep")
.expect("keep symbol doc");
assert!(
keep_doc.deprecation.is_none(),
"a non-deprecated symbol must not be stamped"
);
let rendered = render_file_doc(&file_doc);
assert!(
rendered.contains("⚠️ **deprecated**"),
"the rendered file page must show a deprecation badge; page:\n{rendered}"
);
let deprecations_doc = build_deprecations_doc(&input, &audit.deprecations);
assert_eq!(deprecations_doc.symbols.len(), 2);
let page = render_deprecations_doc(&deprecations_doc);
assert!(
page.contains("attr_dep"),
"page must list attr_dep:\n{page}"
);
assert!(page.contains("doc_dep"), "page must list doc_dep:\n{page}");
assert!(
page.contains("use keep instead"),
"page must show the recorded reason:\n{page}"
);
assert!(!page.contains("No deprecated symbols found."));
assert!(deprecations_doc.degraded_sources.is_empty());
}
#[test]
fn empty_deprecations_page_renders_cleanly_and_does_not_degrade() {
let input = input(Vec::new(), Vec::new(), CodewikiGraphAvailability::Available);
let deprecations = std::collections::BTreeMap::new();
let doc = build_deprecations_doc(&input, &deprecations);
assert!(doc.symbols.is_empty());
assert!(doc.degraded_sources.is_empty());
let page = render_deprecations_doc(&doc);
assert!(
page.contains("No deprecated symbols found."),
"empty deprecations page must render a clear line:\n{page}"
);
assert!(
!page.contains("degraded: true"),
"the deprecations page must never be degraded:\n{page}"
);
}