#![cfg(feature = "std")]
use dejadoc::{Dejadoc, Report};
use std::path::Path;
#[cfg(feature = "cli")]
use std::process::Command;
const FIXTURE: &str = "tests/fixtures/dupws";
fn scan() -> Report {
dejadoc::Dejadoc::default().run(FIXTURE).unwrap()
}
const FN_FIXTURE: &str = "tests/fixtures/fnws";
type FnGroup<'a> = (Vec<&'a str>, Vec<Option<&'a str>>, bool);
#[test]
fn functions_group_per_module_across_targets_and_cfgs() {
let report = Dejadoc::default().run(FN_FIXTURE).unwrap();
assert_eq!(
(report.total, report.functions, report.unique_functions),
(0, 12, 6)
);
let mut groups: Vec<FnGroup<'_>> = report
.groups
.iter()
.map(|g| {
assert_eq!(g.kind, dejadoc::Kind::Function);
let items = g.sites.iter().map(|s| s.item.as_str()).collect();
let types = g.sites.iter().map(|s| s.self_type.as_deref()).collect();
(items, types, g.spans_types())
})
.collect();
groups.sort();
assert_eq!(
groups,
[
(
vec!["fnws::platform::width", "fnws::platform::height"],
vec![None, None],
false
),
(
vec!["fnws::render::Alpha::render", "fnws::render::Beta::render"],
vec![Some("Alpha"), Some("Beta")],
true
),
(
vec![
"fnws::tests::totals_small_values",
"fnws::tests::totals_large_values"
],
vec![None, None],
false
),
(
vec!["fnws::total_over", "fnws::sum_over"],
vec![None, None],
false
),
(
vec!["it::renders_values", "it::renders_values_again"],
vec![None, None],
false
),
]
);
for site in report.groups.iter().flat_map(|g| &g.sites) {
let text = std::fs::read_to_string(Path::new(FN_FIXTURE).join(&site.file)).unwrap();
let lines: Vec<&str> = text.lines().collect();
let first = lines[site.line as usize - 1].trim_start();
let last = lines[site.end.unwrap() as usize - 1].trim();
assert!(
first.starts_with("///") || first.starts_with("#[") || first.contains("fn "),
"{site:?}"
);
assert_eq!(last, "}", "{site:?}");
assert_eq!(
site.code.lines().count(),
(site.end.unwrap() - site.line + 1) as usize
);
}
let off = Dejadoc::default().no_functions().run(FN_FIXTURE).unwrap();
assert_eq!((off.functions, off.groups.len()), (0, 0));
}
#[test]
fn shared_group_spans_crates_and_variants() {
let report = scan();
assert_eq!(report.total, 9);
assert_eq!(report.unique, 4);
assert_eq!(report.groups.len(), 2);
let shared = report
.groups
.iter()
.find(|g| g.sites.iter().any(|s| s.item == "alpha::alpha_fn"))
.expect("shared group present");
assert_eq!(shared.sites.len(), 4);
let items: Vec<&str> = shared.sites.iter().map(|s| s.item.as_str()).collect();
assert_eq!(
items,
vec![
"alpha::util::helper",
"beta::util::helper",
"alpha::alpha_fn",
"alpha::alpha_variant"
]
);
let files: Vec<&str> = shared.sites.iter().map(|s| s.file.as_str()).collect();
assert_eq!(
files,
vec![
"alpha/src/util.rs",
"beta/src/util.rs",
"alpha/src/lib.rs",
"alpha/src/lib.rs"
]
);
}
#[test]
fn unparsed_pair_groups_with_flag() {
let report = scan();
let unparsed = report
.groups
.iter()
.find(|g| g.unparsed)
.expect("unparsed group present");
assert_eq!(unparsed.sites.len(), 2);
}
#[test]
fn allowed_sites_are_not_grouped() {
for group in scan().groups {
for site in group.sites {
assert!(!site.allow);
assert_ne!(site.item, "alpha::alpha_allowed");
}
}
}
#[test]
fn config_threshold_suppresses_groups() {
let strict = Path::new(FIXTURE).join(".dejadoc-strict.toml");
let report = Dejadoc::default()
.config(&strict)
.unwrap()
.run(FIXTURE)
.unwrap();
assert_eq!(report.groups, Vec::new());
let report = Dejadoc::default()
.threshold(2)
.config(&strict)
.unwrap()
.run(FIXTURE)
.unwrap();
assert_eq!(report.groups.len(), 2);
let report = Dejadoc::default()
.config(&strict)
.unwrap()
.threshold(2)
.run(FIXTURE)
.unwrap();
assert_eq!(report.groups.len(), 2);
}
#[test]
fn all_targets_builder_scans_bin_targets() {
let report = Dejadoc::default().all_targets().run(FIXTURE).unwrap();
assert_eq!(report.total, 10);
assert_eq!(report.unique, 4);
assert_eq!(report.groups.len(), 2);
}
#[test]
fn a_package_filter_keeps_the_package_bin_targets() {
let report = Dejadoc::default()
.package("alpha")
.all_targets()
.run(FIXTURE)
.unwrap();
assert!(
report
.groups
.iter()
.any(|g| g.sites.iter().any(|s| s.file.ends_with("dupbin.rs")))
);
}
#[test]
fn min_tokens_builder_filters_blocks() {
let report = Dejadoc::default().min_tokens(4).run(FIXTURE).unwrap();
assert_eq!(report.total, 9);
assert_eq!(report.groups.len(), 1);
}
#[test]
fn exit_code_reflects_duplicates() {
let report = scan();
assert_eq!(
dejadoc::exit_code(&report, false),
std::process::ExitCode::from(1)
);
assert_eq!(
dejadoc::exit_code(&report, true),
std::process::ExitCode::SUCCESS
);
}
#[test]
#[cfg(feature = "cli")]
fn binary_runs_end_to_end() {
let bin = env!("CARGO_BIN_EXE_cargo-dejadoc");
let out = Command::new(bin)
.current_dir(FIXTURE)
.arg("dejadoc")
.arg("--json")
.output()
.expect("run dejadoc binary");
assert_eq!(out.status.code(), Some(1));
let value: serde_json::Value = serde_json::from_slice(&out.stdout).expect("valid json output");
assert_eq!(value["total"], 9);
assert_eq!(value["groups"].as_array().unwrap().len(), 2);
}
#[test]
#[cfg(feature = "cli")]
fn binary_prints_annotations_beside_the_report() {
let bin = env!("CARGO_BIN_EXE_cargo-dejadoc");
let out = Command::new(bin)
.current_dir(FIXTURE)
.arg("dejadoc")
.arg("--github")
.output()
.expect("run dejadoc binary");
assert_eq!(out.status.code(), Some(1));
let text = String::from_utf8(out.stdout).expect("utf8 output");
assert!(text.contains("9 doctests (4 unique)"), "{text}");
let marks: Vec<&str> = text.lines().filter(|l| l.starts_with("::")).collect();
assert_eq!(marks.len(), 4, "{text}");
assert!(
marks
.iter()
.all(|l| l.starts_with("::error file=") && l.contains("title=dejadoc::")),
"{text}"
);
}
#[test]
#[cfg(feature = "cli")]
fn package_named_dejadoc_is_not_filtered() {
let bin = env!("CARGO_BIN_EXE_cargo-dejadoc");
let out = Command::new(bin)
.current_dir(FIXTURE)
.arg("dejadoc")
.arg("--json")
.arg("--package")
.arg("dejadoc")
.output()
.expect("run dejadoc binary");
assert_eq!(
out.status.code(),
Some(0),
"stderr: {:?}",
String::from_utf8_lossy(&out.stderr)
);
let value: serde_json::Value = serde_json::from_slice(&out.stdout).expect("valid json output");
assert_eq!(value["total"], 0);
}
#[test]
fn file_module_items_carry_module_prefix() {
let report = scan();
let helper = report
.groups
.iter()
.find(|g| g.sites.iter().any(|s| s.item.contains("helper")))
.expect("helper group present");
let items: Vec<&str> = helper
.sites
.iter()
.map(|s| s.item.as_str())
.filter(|item| item.contains("helper"))
.collect();
assert_eq!(items, vec!["alpha::util::helper", "beta::util::helper"]);
}
#[test]
fn threshold_builder_narrows_groups() {
let report = dejadoc::Dejadoc::default()
.threshold(3)
.run(FIXTURE)
.unwrap();
assert_eq!(report.total, 9);
assert_eq!(report.groups.len(), 1);
}