use std::fs;
use std::path::{Path, PathBuf};
fn source_files() -> Vec<PathBuf> {
fn walk(dir: &Path, out: &mut Vec<PathBuf>) {
for entry in fs::read_dir(dir).expect("readable source dir") {
let path = entry.expect("readable dir entry").path();
if path.is_dir() {
walk(&path, out);
} else if path.extension().is_some_and(|e| e == "rs") {
out.push(path);
}
}
}
let mut out = Vec::new();
walk(Path::new("src"), &mut out);
out
}
#[test]
fn kurbo_and_peniko_are_reached_through_our_own_module_paths() {
const EXEMPT: &[&str] = &[
"src/geometry.rs",
"src/path.rs",
"src/brush.rs",
"src/color.rs",
"src/stroke.rs",
"src/mesh.rs",
"src/scene/mod.rs",
"src/backend/",
];
let mut offenders = Vec::new();
for file in source_files() {
let display = file.to_string_lossy().replace('\\', "/");
if EXEMPT.iter().any(|e| display.starts_with(e)) {
continue;
}
for (i, line) in fs::read_to_string(&file)
.expect("readable source file")
.lines()
.enumerate()
{
let code = line.trim_start();
if code.starts_with("//") {
continue;
}
if code.contains("kurbo::") || code.contains("peniko::") {
offenders.push(format!("{display}:{}: {}", i + 1, line.trim()));
}
}
}
assert!(
offenders.is_empty(),
"reach these through `crate::geometry` / `crate::path` / `crate::brush` \
instead:\n{}",
offenders.join("\n")
);
}
#[test]
fn the_scales_layer_stays_free_of_the_plot_layer() {
let mut offenders = Vec::new();
for file in source_files() {
let display = file.to_string_lossy().replace('\\', "/");
if !display.starts_with("src/scales/") {
continue;
}
for (i, line) in fs::read_to_string(&file)
.expect("readable source file")
.lines()
.enumerate()
{
let code = line.trim_start();
if code.starts_with("//") {
continue;
}
for forbidden in [
"crate::plot",
"crate::scene",
"crate::backend",
"crate::primitives",
"crate::text",
] {
if code.contains(forbidden) {
offenders.push(format!("{display}:{}: {}", i + 1, line.trim()));
}
}
}
}
assert!(
offenders.is_empty(),
"src/scales/ must not depend on the layers above it:\n{}",
offenders.join("\n")
);
}