test: scan source directories recursively

This commit is contained in:
aiongg
2026-10-26 20:54:01 +00:00
parent 02120c84f7
commit 33350b3833
5 changed files with 39 additions and 18 deletions
+5 -2
View File
@@ -499,8 +499,11 @@ mod tests {
let mut offenders = vec![];
for path in files {
let name = path.file_name().and_then(|n| n.to_str()).unwrap_or("");
// `io` and this module are the checked gateway; `tests*.rs` are test-only modules.
if path.parent() == Some(src.as_path()) && (name == "io.rs" || name == "file_access.rs" || name.starts_with("tests"))
// `io` and this module are the checked gateway; `tests*.rs` files and `tests/`
// directories are test-only modules.
if path.parent() == Some(src.as_path()) && (name == "io.rs" || name == "file_access.rs")
|| name.starts_with("tests")
|| path.strip_prefix(&src).is_ok_and(|rel| rel.components().any(|c| c.as_os_str() == "tests"))
|| path.starts_with(src.join("io"))
|| path == src.join("recovery/desktop.rs")
{
+1 -3
View File
@@ -523,9 +523,7 @@ fn literals(code: &str) -> Vec<String> {
/// reasons resolved.
fn disabled_reasons() -> std::collections::BTreeSet<String> {
let dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("../engine/src/cmd");
let mut files: Vec<_> =
std::fs::read_dir(&dir).unwrap().map(|e| e.unwrap().path()).filter(|p| p.extension().is_some_and(|e| e == "rs")).collect();
files.sort();
let files = crate::rust_sources(&dir);
let all: String = files.iter().map(|p| std::fs::read_to_string(p).unwrap()).collect::<Vec<_>>().join("\n");
// A named check's bodies (any file's `fn name(…) -> Option<&'static str>`).
let checks = |name: &str| -> Vec<&str> {
+20
View File
@@ -3412,6 +3412,26 @@ fn control_click_as_secondary(events: &mut [egui::Event], held: &mut bool) {
#[cfg(test)]
mod tests_perf;
/// Every `.rs` file under `dir`, subdirectories included, in a fixed order: tests that scan the
/// sources must keep seeing code that moves into a module directory.
#[cfg(test)]
pub(crate) fn rust_sources(dir: &std::path::Path) -> Vec<std::path::PathBuf> {
let mut files = vec![];
let mut dirs = vec![dir.to_path_buf()];
while let Some(dir) = dirs.pop() {
for entry in std::fs::read_dir(&dir).unwrap() {
let path = entry.unwrap().path();
if path.is_dir() {
dirs.push(path);
} else if path.extension().is_some_and(|e| e == "rs") {
files.push(path);
}
}
}
files.sort();
files
}
#[cfg(test)]
mod tests {
use super::*;
+7 -3
View File
@@ -3467,10 +3467,14 @@ mod tests {
app.run("layout.pageSetup", json!({})).unwrap();
assert!(matches!(app.dialog, Some(crate::dialogs::Dialog::PageSetup { .. })));
// `ui.dialog` needs a dialog name, so it can't be a launcher.
let launchers: Vec<&str> = include_str!("ribbon.rs")
.split("group(ui, \"")
.filter_map(|g| g.split_once('"')?.1.strip_prefix(", Some(\"")?.split('"').next())
let src = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("src");
let ribbon: String = crate::rust_sources(&src)
.iter()
.filter(|p| **p == src.join("ribbon.rs") || p.starts_with(src.join("ribbon")))
.map(|p| std::fs::read_to_string(p).unwrap())
.collect();
let launchers: Vec<&str> =
ribbon.split("group(ui, \"").filter_map(|g| g.split_once('"')?.1.strip_prefix(", Some(\"")?.split('"').next()).collect();
assert!(launchers.contains(&"layout.pageSetup"), "{launchers:?}");
assert!(!launchers.contains(&"ui.dialog"), "{launchers:?}");
}
+6 -10
View File
@@ -983,10 +983,9 @@ mod tests {
fn interface_colours_come_from_the_theme() {
let banned = ["fill(crate::theme::APP_COLOR)", "0x58, 0x65, 0xF2", "0x47, 0x52, 0xC4", "0xFF, 0xF1, 0x76", "0xD1, 0x3B, 0x3B"];
let dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("src");
for entry in std::fs::read_dir(&dir).unwrap() {
let path = entry.unwrap().path();
for path in crate::rust_sources(&dir) {
let name = path.file_name().unwrap().to_string_lossy().to_string();
if !name.ends_with(".rs") || name == "theme.rs" || name == "icons.rs" {
if path == dir.join("theme.rs") || path == dir.join("icons.rs") {
continue;
}
let src = std::fs::read_to_string(&path).unwrap();
@@ -1028,11 +1027,8 @@ mod tests {
ctx.run_ui(egui::RawInput::default(), |_| {}).drop_without_applying_deltas();
let dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("src");
let mut symbols = BTreeSet::new();
for entry in std::fs::read_dir(&dir).unwrap() {
let path = entry.unwrap().path();
if path.extension().is_none_or(|e| e != "rs") {
continue;
}
// The i18n module's literals are catalog and pseudo-locale test text, not interface text.
for path in crate::rust_sources(&dir).into_iter().filter(|p| !p.starts_with(dir.join("i18n"))) {
let code = std::fs::read_to_string(&path).unwrap();
// Characters inside string literals, line by line (good enough for this code base).
for line in code.lines().filter(|l| !l.trim_start().starts_with("//")) {
@@ -1041,7 +1037,7 @@ mod tests {
symbols.extend(
part.chars()
.filter(|c| !c.is_ascii() && !c.is_alphabetic() && !c.is_whitespace())
.map(|c| (c, path.file_name().unwrap().to_string_lossy().to_string())),
.map(|c| (c, path.strip_prefix(&dir).unwrap().to_string_lossy().replace('\\', "/"))),
);
}
}
@@ -1052,7 +1048,7 @@ mod tests {
// The ➢ bullet is a value for `para.bullets`; its menu tile draws the shape instead.
let exempt = |c: char, file: &str| match file {
"equation_tab.rs" => matches!(c, '≜' | '┬'),
"ribbon.rs" => c == '➢',
_ if file == "ribbon.rs" || file.starts_with("ribbon/") => c == '➢',
_ => false,
};
symbols.retain(|(c, file)| !exempt(*c, file));