f77fd73966
- Walk-up: .botignore no longer stops the search but is remembered as a fallback when no strong marker (.git, botignore.toml, .botignore.toml) is found — prevents fail-open regression for projects without .git - Extract inline SVGs to policy-layers.svg and architecture.svg - READMEs reference SVGs via <img> tags Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
121 lines
3.6 KiB
Rust
121 lines
3.6 KiB
Rust
use dirigent_fermata::core::project::find_project_root;
|
|
use std::fs;
|
|
use tempfile::TempDir;
|
|
|
|
#[test]
|
|
fn finds_botignore_toml_first() {
|
|
let tmp = TempDir::new().unwrap();
|
|
let root = tmp.path();
|
|
fs::create_dir_all(root.join("sub/deep")).unwrap();
|
|
fs::write(root.join("botignore.toml"), "").unwrap();
|
|
fs::write(root.join(".botignore.toml"), "").unwrap();
|
|
fs::create_dir_all(root.join(".git")).unwrap();
|
|
|
|
let target = root.join("sub/deep/file.rs");
|
|
fs::write(&target, "").unwrap();
|
|
|
|
let found = find_project_root(&target).unwrap();
|
|
assert_eq!(found, root);
|
|
}
|
|
|
|
#[test]
|
|
fn finds_dot_botignore_toml() {
|
|
let tmp = TempDir::new().unwrap();
|
|
let root = tmp.path();
|
|
fs::create_dir_all(root.join("sub")).unwrap();
|
|
fs::write(root.join(".botignore.toml"), "").unwrap();
|
|
|
|
let target = root.join("sub/file.rs");
|
|
fs::write(&target, "").unwrap();
|
|
|
|
let found = find_project_root(&target).unwrap();
|
|
assert_eq!(found, root);
|
|
}
|
|
|
|
#[test]
|
|
fn botignore_alone_does_not_stop_walk() {
|
|
// A bare .botignore is a policy file, not a project boundary.
|
|
// The walk should continue past it to find a real root marker.
|
|
let tmp = TempDir::new().unwrap();
|
|
let root = tmp.path();
|
|
fs::create_dir_all(root.join("a/b")).unwrap();
|
|
fs::create_dir_all(root.join(".git")).unwrap();
|
|
fs::write(root.join("a/.botignore"), "*.secret").unwrap();
|
|
|
|
let target = root.join("a/b/file.rs");
|
|
fs::write(&target, "").unwrap();
|
|
|
|
// Should find root (with .git), NOT root/a (with .botignore)
|
|
let found = find_project_root(&target).unwrap();
|
|
assert_eq!(found, root);
|
|
}
|
|
|
|
#[test]
|
|
fn botignore_used_as_fallback() {
|
|
// If only .botignore exists (no strong marker), it serves as a fallback
|
|
// root so that policy is still enforced.
|
|
let tmp = TempDir::new().unwrap();
|
|
let root = tmp.path();
|
|
fs::create_dir_all(root.join("sub")).unwrap();
|
|
fs::write(root.join(".botignore"), "*.secret").unwrap();
|
|
|
|
let target = root.join("sub/file.rs");
|
|
fs::write(&target, "").unwrap();
|
|
|
|
let found = find_project_root(&target).unwrap();
|
|
assert_eq!(found, root);
|
|
}
|
|
|
|
#[test]
|
|
fn strong_marker_preferred_over_botignore_fallback() {
|
|
// .botignore at a/b/, .git at root — walk past .botignore, use root.
|
|
let tmp = TempDir::new().unwrap();
|
|
let root = tmp.path();
|
|
fs::create_dir_all(root.join("a/b/c")).unwrap();
|
|
fs::create_dir_all(root.join(".git")).unwrap();
|
|
fs::write(root.join("a/b/.botignore"), "*.key").unwrap();
|
|
|
|
let target = root.join("a/b/c/file.rs");
|
|
fs::write(&target, "").unwrap();
|
|
|
|
// Should find root (with .git), not a/b (with .botignore)
|
|
let found = find_project_root(&target).unwrap();
|
|
assert_eq!(found, root);
|
|
}
|
|
|
|
#[test]
|
|
fn falls_back_to_git() {
|
|
let tmp = TempDir::new().unwrap();
|
|
let root = tmp.path();
|
|
fs::create_dir_all(root.join("sub")).unwrap();
|
|
fs::create_dir_all(root.join(".git")).unwrap();
|
|
|
|
let target = root.join("sub/file.rs");
|
|
fs::write(&target, "").unwrap();
|
|
|
|
let found = find_project_root(&target).unwrap();
|
|
assert_eq!(found, root);
|
|
}
|
|
|
|
#[test]
|
|
fn returns_none_when_no_marker() {
|
|
let tmp = TempDir::new().unwrap();
|
|
let target = tmp.path().join("file.rs");
|
|
std::fs::write(&target, "").unwrap();
|
|
assert!(find_project_root(&target).is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn walks_up_from_file_path_not_cwd() {
|
|
let tmp = TempDir::new().unwrap();
|
|
let root = tmp.path();
|
|
fs::create_dir_all(root.join("a/b/c")).unwrap();
|
|
fs::write(root.join("a/botignore.toml"), "").unwrap();
|
|
|
|
let target = root.join("a/b/c/file.rs");
|
|
fs::write(&target, "").unwrap();
|
|
|
|
let found = find_project_root(&target).unwrap();
|
|
assert_eq!(found, root.join("a"));
|
|
}
|