KeiSeiKit-1.0/_primitives/_rust/kei-conflict-scan/tests/integration.rs
Parfii-bot a4e667de10 KeiSeiKit-public — clean state
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.
2026-05-01 12:09:03 +08:00

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);
}
}