Single-commit clean baseline after security scrub of niche-tells, project codenames, internal jargon, and contributor-email leaks. Contents: - 100 Rust crates (_primitives/_rust/) - 37 agent manifests (_manifests/) + generated specs (_generated/) - 67 user-invocable skills (skills/) - 33 hooks (hooks/) - Composition blocks (_blocks/) - Documentation (docs/, README.md) - TS adapter packages (_ts_packages/) - Assembler (_assembler/) - Roles (_roles/) - Templates (_templates/) - Forgejo CI (.forgejo/) Author: Denis Parfionovich <info@greendragon.info> License: see LICENSE.
88 lines
2.9 KiB
Rust
88 lines
2.9 KiB
Rust
//! Integration tests for kei-conflict-scan.
|
|
|
|
use std::fs;
|
|
use std::path::{Path, PathBuf};
|
|
use tempfile::TempDir;
|
|
|
|
fn bin() -> PathBuf {
|
|
PathBuf::from(env!("CARGO_BIN_EXE_kei-conflict-scan"))
|
|
}
|
|
|
|
fn write(root: &Path, rel: &str, body: &str) {
|
|
let full = root.join(rel);
|
|
if let Some(parent) = full.parent() {
|
|
fs::create_dir_all(parent).unwrap();
|
|
}
|
|
fs::write(&full, body).unwrap();
|
|
}
|
|
|
|
fn run(root: &Path, extra: &[&str]) -> serde_json::Value {
|
|
let mut args = vec!["--path".to_string(), root.to_string_lossy().into_owned()];
|
|
args.extend(extra.iter().map(|s| s.to_string()));
|
|
let out = std::process::Command::new(bin()).args(&args).output().unwrap();
|
|
assert!(out.status.success(), "stderr: {}", String::from_utf8_lossy(&out.stderr));
|
|
serde_json::from_slice(&out.stdout).unwrap()
|
|
}
|
|
|
|
#[test]
|
|
fn empty_tree_is_clean() {
|
|
let tmp = TempDir::new().unwrap();
|
|
let v = run(tmp.path(), &[]);
|
|
assert_eq!(v["hit_count"], 0);
|
|
}
|
|
|
|
#[test]
|
|
fn contradictory_rules_flagged() {
|
|
let tmp = TempDir::new().unwrap();
|
|
write(tmp.path(), "rules/a.md", "Never: push to github\n");
|
|
write(tmp.path(), "rules/b.md", "Always: push to github\n");
|
|
let v = run(tmp.path(), &["--only", "rules"]);
|
|
assert!(v["hit_count"].as_u64().unwrap() >= 1, "{}", v);
|
|
assert_eq!(v["conflicts"][0]["category"], "rules");
|
|
}
|
|
|
|
#[test]
|
|
fn duplicate_blocks_flagged() {
|
|
let tmp = TempDir::new().unwrap();
|
|
let body =
|
|
"this is a long shared paragraph with many identical words over and over again repeated";
|
|
write(tmp.path(), "_blocks/a.md", body);
|
|
write(tmp.path(), "_blocks/b.md", body);
|
|
let v = run(tmp.path(), &["--only", "blocks"]);
|
|
assert!(v["hit_count"].as_u64().unwrap() >= 1, "{}", v);
|
|
assert_eq!(v["conflicts"][0]["category"], "blocks");
|
|
}
|
|
|
|
#[test]
|
|
fn orphan_wikilinks_flagged() {
|
|
let tmp = TempDir::new().unwrap();
|
|
write(tmp.path(), "docs/a.md", "see [[nonexistent-target]] for details");
|
|
let v = run(tmp.path(), &["--only", "orphans"]);
|
|
assert!(v["hit_count"].as_u64().unwrap() >= 1, "{}", v);
|
|
assert_eq!(v["conflicts"][0]["category"], "orphans");
|
|
}
|
|
|
|
#[test]
|
|
fn oversize_file_flagged() {
|
|
let tmp = TempDir::new().unwrap();
|
|
let mut body = String::new();
|
|
for _ in 0..250 {
|
|
body.push_str("line\n");
|
|
}
|
|
write(tmp.path(), "src/big.rs", &body);
|
|
let v = run(tmp.path(), &["--only", "cp"]);
|
|
assert!(v["hit_count"].as_u64().unwrap() >= 1, "{}", v);
|
|
assert_eq!(v["conflicts"][0]["category"], "cp");
|
|
}
|
|
|
|
#[test]
|
|
fn json_schema_has_required_fields() {
|
|
let tmp = TempDir::new().unwrap();
|
|
write(tmp.path(), "rules/a.md", "Never: do X\n");
|
|
write(tmp.path(), "rules/b.md", "Always: do X\n");
|
|
let v = run(tmp.path(), &["--only", "rules"]);
|
|
let c = &v["conflicts"][0];
|
|
for k in ["category", "severity", "files", "evidence", "suggested_fix", "auto_resolvable"] {
|
|
assert!(c.get(k).is_some(), "missing field {}: {}", k, c);
|
|
}
|
|
}
|