KeiSeiKit-1.0/_assembler/tests/rule_blocks_test.rs
Parfii-bot 0be354a920 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

151 lines
5.5 KiB
Rust

//! Integration tests for the v0.wave14 `rule_blocks` field.
//!
//! Strategy: invoke the `assemble` binary with `KEI_REGISTRY_DB` pointing at a
//! temp SQLite DB seeded with synthetic fragment rows. Helpers live in
//! `rule_blocks_helpers/mod.rs` (separate module to keep this file ≤200 LOC).
mod common;
mod rule_blocks_helpers;
use common::{assemble_bin, read_generated};
use rule_blocks_helpers::setup_kit;
use std::path::Path;
use std::process::Command;
fn run(root: &Path, db_path: &Path, extra_args: &[&str]) -> (bool, String, String) {
let mut cmd = Command::new(assemble_bin());
cmd.env("AGENT_ROOT", root)
.env("HOME", root)
.env("KEI_REGISTRY_DB", db_path);
for a in extra_args {
cmd.arg(a);
}
let out = cmd.output().expect("spawn assemble");
(
out.status.success(),
String::from_utf8_lossy(&out.stdout).to_string(),
String::from_utf8_lossy(&out.stderr).to_string(),
)
}
// ── tests ─────────────────────────────────────────────────────────────────
/// Fragment body appears after # ROLE and before first block.
#[test]
fn rule_blocks_injected_after_role_before_blocks() {
let (_tmp, root, db) = setup_kit(
&["foo::think"],
&[("foo::think", "## Think Before Coding\n\nProactive rule text.")],
);
let (ok, _out, stderr) = run(&root, &db, &[]);
assert!(ok, "assemble failed: {stderr}");
let md = read_generated(&root, "test-rule-blocks");
let role_pos = md.find("# ROLE").expect("# ROLE missing");
let frag_pos = md.find("Proactive rule text.").expect("fragment body missing");
let baseline_pos = md.find("# BASELINE").expect("# BASELINE missing");
assert!(role_pos < frag_pos, "rule fragment must come AFTER # ROLE");
assert!(frag_pos < baseline_pos, "rule fragment must come BEFORE first block (# BASELINE)");
}
/// `<!-- RULE: name -->` comment marker emitted for each fragment.
#[test]
fn rule_blocks_comment_marker_present() {
let (_tmp, root, db) = setup_kit(
&["karpathy::surgical"],
&[("karpathy::surgical", "## Surgical Changes\n\nTouch only what you must.")],
);
let (ok, _out, stderr) = run(&root, &db, &[]);
assert!(ok, "assemble failed: {stderr}");
let md = read_generated(&root, "test-rule-blocks");
assert!(
md.contains("<!-- RULE: karpathy::surgical -->"),
"missing comment marker in generated md"
);
}
/// Multiple fragments appear in the order declared in the manifest.
#[test]
fn rule_blocks_order_preserved() {
let (_tmp, root, db) = setup_kit(
&["alpha::one", "beta::two"],
&[
("alpha::one", "Alpha body text."),
("beta::two", "Beta body text."),
],
);
let (ok, _out, stderr) = run(&root, &db, &[]);
assert!(ok, "assemble failed: {stderr}");
let md = read_generated(&root, "test-rule-blocks");
let alpha_pos = md.find("Alpha body text.").expect("alpha missing");
let beta_pos = md.find("Beta body text.").expect("beta missing");
assert!(alpha_pos < beta_pos, "alpha must appear before beta in output");
}
/// Absent registry DB → warn on stderr but assemble succeeds (graceful skip).
#[test]
fn missing_registry_db_warn_and_skip() {
let (_tmp, root, _db) = setup_kit(&["foo::bar"], &[("foo::bar", "some text")]);
let absent_db = root.join("does-not-exist.sqlite");
let (ok, _out, stderr) = run(&root, &absent_db, &[]);
assert!(
ok,
"assemble should succeed (warn+skip) when registry DB absent; stderr: {stderr}"
);
assert!(
stderr.contains("not found") || stderr.contains("rule_blocks will be skipped"),
"expected warning about missing DB in stderr: {stderr}"
);
}
/// Fragment name present in manifest but missing from registry → hard fail with clear message.
#[test]
fn missing_fragment_in_db_fails_validation() {
let (_tmp, root, db) = setup_kit(&["ghost::missing"], &[]);
let (ok, _out, stderr) = run(&root, &db, &[]);
assert!(!ok, "assemble should FAIL when fragment not in registry; stderr: {stderr}");
assert!(
stderr.contains("ghost::missing"),
"error must name the missing fragment; stderr: {stderr}"
);
}
/// Manifests WITHOUT `rule_blocks` produce byte-identical output on re-run.
#[test]
fn no_rule_blocks_produces_identical_output() {
let (_tmp, root, db) = setup_kit(&[], &[]);
let (ok1, _, e1) = run(&root, &db, &[]);
assert!(ok1, "first run failed: {e1}");
let first = read_generated(&root, "test-rule-blocks");
let (ok2, _, e2) = run(&root, &db, &[]);
assert!(ok2, "second run failed: {e2}");
let second = read_generated(&root, "test-rule-blocks");
assert_eq!(first, second, "output must be byte-identical on re-run");
assert!(
!first.contains("<!-- RULE:"),
"no-rule-blocks manifest must not emit RULE comment markers"
);
}
/// Re-assembling a manifest WITH `rule_blocks` is byte-identical (determinism).
#[test]
fn idempotent_reassemble() {
let (_tmp, root, db) = setup_kit(
&["idem::check"],
&[("idem::check", "Idempotency rule body.")],
);
let (ok1, _, e1) = run(&root, &db, &[]);
assert!(ok1, "first run failed: {e1}");
let first = read_generated(&root, "test-rule-blocks");
let (ok2, _, e2) = run(&root, &db, &[]);
assert!(ok2, "second run failed: {e2}");
let second = read_generated(&root, "test-rule-blocks");
assert_eq!(first, second, "re-assemble must be byte-identical");
}