97001e1544
Move all 29 workspace members from packages/<name>/ to crates/<name>/. Updates: workspace Cargo.toml (members + path deps), justfile, root CLAUDE.md, scripts/build/CARGO_INSTALL.md, docs/architecture/crates.md (renamed from packages.md), structural references in docs/architecture and docs/configuration, per-crate CLAUDE.md self-references. Historical plans, reports, and building/ docs are left untouched. No behavior change; just check-all stays green and fermata tests pass.
136 lines
4.2 KiB
Rust
136 lines
4.2 KiB
Rust
use dirigent_fermata::core::botignore::BotignoreSet;
|
|
use std::fs;
|
|
use tempfile::TempDir;
|
|
|
|
#[test]
|
|
fn matches_simple_pattern() {
|
|
let tmp = TempDir::new().unwrap();
|
|
let root = tmp.path();
|
|
fs::write(root.join(".botignore"), ".env\nsecrets/\n").unwrap();
|
|
|
|
let set = BotignoreSet::load(root).unwrap();
|
|
|
|
let env = root.join(".env");
|
|
fs::write(&env, "").unwrap();
|
|
let m = set.matched(&env).unwrap();
|
|
assert!(m.is_some(), ".env should be matched");
|
|
assert_eq!(m.unwrap().pattern, ".env");
|
|
}
|
|
|
|
#[test]
|
|
fn does_not_match_unrelated_files() {
|
|
let tmp = TempDir::new().unwrap();
|
|
let root = tmp.path();
|
|
fs::write(root.join(".botignore"), ".env\n").unwrap();
|
|
|
|
let set = BotignoreSet::load(root).unwrap();
|
|
|
|
let other = root.join("README.md");
|
|
fs::write(&other, "").unwrap();
|
|
assert!(set.matched(&other).unwrap().is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn negation_pattern_excludes() {
|
|
let tmp = TempDir::new().unwrap();
|
|
let root = tmp.path();
|
|
fs::write(root.join(".botignore"), "*.log\n!keep.log\n").unwrap();
|
|
|
|
let set = BotignoreSet::load(root).unwrap();
|
|
|
|
let blocked = root.join("foo.log");
|
|
fs::write(&blocked, "").unwrap();
|
|
assert!(set.matched(&blocked).unwrap().is_some());
|
|
|
|
let allowed = root.join("keep.log");
|
|
fs::write(&allowed, "").unwrap();
|
|
assert!(set.matched(&allowed).unwrap().is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn empty_or_missing_botignore_is_ok() {
|
|
let tmp = TempDir::new().unwrap();
|
|
let set = BotignoreSet::load(tmp.path()).unwrap();
|
|
let any = tmp.path().join("anything.txt");
|
|
std::fs::write(&any, "").unwrap();
|
|
assert!(set.matched(&any).unwrap().is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn nested_botignore_is_scoped_to_its_directory() {
|
|
// A `.botignore` in a subdirectory only applies under that subdirectory,
|
|
// matching gitignore semantics: a sibling file with the same name at the
|
|
// root is NOT affected.
|
|
let tmp = TempDir::new().unwrap();
|
|
let root = tmp.path();
|
|
fs::create_dir_all(root.join("frontend")).unwrap();
|
|
fs::write(root.join("frontend/.botignore"), "secret.key\n").unwrap();
|
|
|
|
let set = BotignoreSet::load(root).unwrap();
|
|
|
|
let blocked = root.join("frontend/secret.key");
|
|
fs::write(&blocked, "").unwrap();
|
|
let m = set
|
|
.matched(&blocked)
|
|
.unwrap()
|
|
.expect("frontend/secret.key should match");
|
|
let src = m.source.to_string_lossy().replace('\\', "/");
|
|
assert!(
|
|
src.ends_with("frontend/.botignore"),
|
|
"Rule.source should point at the nested file; was {}",
|
|
src,
|
|
);
|
|
|
|
let unblocked = root.join("secret.key");
|
|
fs::write(&unblocked, "").unwrap();
|
|
assert!(
|
|
set.matched(&unblocked).unwrap().is_none(),
|
|
"top-level secret.key should NOT be matched (rule scoped to frontend/)",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn nested_botignore_anchored_pattern_is_local() {
|
|
// A leading `/` anchors the pattern to the directory of the .botignore
|
|
// file it's declared in.
|
|
let tmp = TempDir::new().unwrap();
|
|
let root = tmp.path();
|
|
fs::create_dir_all(root.join("frontend")).unwrap();
|
|
fs::write(root.join("frontend/.botignore"), "/secret.key\n").unwrap();
|
|
|
|
let set = BotignoreSet::load(root).unwrap();
|
|
|
|
let blocked = root.join("frontend/secret.key");
|
|
fs::write(&blocked, "").unwrap();
|
|
assert!(set.matched(&blocked).unwrap().is_some());
|
|
|
|
let unblocked = root.join("secret.key");
|
|
fs::write(&unblocked, "").unwrap();
|
|
assert!(
|
|
set.matched(&unblocked).unwrap().is_none(),
|
|
"anchored /secret.key should NOT match outside frontend/",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn nested_botignore_overrides_root() {
|
|
let tmp = TempDir::new().unwrap();
|
|
let root = tmp.path();
|
|
fs::write(root.join(".botignore"), "*.log\n").unwrap();
|
|
fs::create_dir_all(root.join("logs")).unwrap();
|
|
fs::write(root.join("logs/.botignore"), "!keep.log\n").unwrap();
|
|
|
|
let set = BotignoreSet::load(root).unwrap();
|
|
|
|
let blocked = root.join("logs/foo.log");
|
|
fs::write(&blocked, "").unwrap();
|
|
assert!(set.matched(&blocked).unwrap().is_some());
|
|
|
|
let kept = root.join("logs/keep.log");
|
|
fs::write(&kept, "").unwrap();
|
|
assert!(
|
|
set.matched(&kept).unwrap().is_none(),
|
|
"logs/.botignore should un-ignore keep.log",
|
|
);
|
|
}
|