KeiSeiKit-1.0/_primitives/_rust/kei-artifact/tests/integration.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

132 lines
4.1 KiB
Rust

//! Integration tests — core CRUD (register_schema / emit / get / list / chain).
//!
//! Constructor Pattern: each test = one scenario, one assertion focus.
//! Companion file `validation.rs` tests schema-validation edge cases.
use kei_artifact::artifact::{chain, emit, get, list, register_schema, ArtifactFilter};
use kei_artifact::hash::artifact_id;
use kei_artifact::schemas::{register_builtins, BUILTIN};
use kei_artifact::Store;
use serde_json::json;
fn seed() -> Store {
let s = Store::open_memory().unwrap();
register_builtins(&s).unwrap();
s
}
fn spec_bytes(goal: &str) -> Vec<u8> {
serde_json::to_vec(&json!({
"goal": goal, "constraints": [], "invariants": []
}))
.unwrap()
}
#[test]
fn register_builtin_schemas_and_list_them() {
let s = seed();
let names = kei_artifact::artifact::list_schemas(&s).unwrap();
for (n, _) in BUILTIN {
assert!(names.iter().any(|x| x == n), "missing {n}");
}
assert_eq!(names.len(), 5);
}
#[test]
fn register_schema_custom_and_query_back() {
let s = seed();
let custom = r#"{"type":"object","additionalProperties":false,"properties":{}}"#;
register_schema(&s, "custom", custom).unwrap();
let names = kei_artifact::artifact::list_schemas(&s).unwrap();
assert!(names.iter().any(|n| n == "custom"));
}
#[test]
fn emit_get_roundtrip_for_spec_schema() {
let s = seed();
let bytes = spec_bytes("ship v0.15");
let id = emit(&s, "spec", "kei-architect", &bytes, None, None).unwrap();
let got = get(&s, &id).unwrap().unwrap();
assert_eq!(got.schema_name, "spec");
assert_eq!(got.source_agent, "kei-architect");
assert_eq!(got.content, bytes);
assert_eq!(got.id, artifact_id("spec", &bytes));
}
#[test]
fn chain_walks_parent_handoff_up_the_graph() {
let s = seed();
let spec = spec_bytes("g");
let spec_id = emit(&s, "spec", "kei-architect", &spec, None, None).unwrap();
let plan = serde_json::to_vec(&json!({
"goal": "g",
"steps": [{"step": "s1", "verify": "v1"}]
}))
.unwrap();
let plan_id = emit(&s, "plan", "kei-architect", &plan, None, Some(&spec_id)).unwrap();
let patch = serde_json::to_vec(&json!({
"summary": "first cut",
"changes": [{"path": "a.rs", "op": "add", "summary": "new"}]
}))
.unwrap();
let patch_id = emit(&s, "patch", "kei-code-implementer", &patch, None, Some(&plan_id)).unwrap();
let walk = chain(&s, &patch_id).unwrap();
assert_eq!(walk.len(), 3);
assert_eq!(walk[0].id, spec_id);
assert_eq!(walk[1].id, plan_id);
assert_eq!(walk[2].id, patch_id);
}
#[test]
fn list_filters_by_schema_source_and_since() {
let s = seed();
let a = spec_bytes("a");
let b = spec_bytes("b");
emit(&s, "spec", "kei-architect", &a, None, None).unwrap();
emit(&s, "spec", "kei-researcher", &b, None, None).unwrap();
let by_source = list(&s, &ArtifactFilter {
source_agent: Some("kei-architect".into()),
..Default::default()
})
.unwrap();
assert_eq!(by_source.len(), 1);
assert_eq!(by_source[0].source_agent, "kei-architect");
let by_schema = list(&s, &ArtifactFilter {
schema_name: Some("spec".into()),
..Default::default()
})
.unwrap();
assert_eq!(by_schema.len(), 2);
let none = list(&s, &ArtifactFilter {
schema_name: Some("plan".into()),
..Default::default()
})
.unwrap();
assert!(none.is_empty());
}
#[test]
fn duplicate_emit_is_idempotent_same_id() {
let s = seed();
let content = spec_bytes("g");
let id1 = emit(&s, "spec", "kei-architect", &content, None, None).unwrap();
let id2 = emit(&s, "spec", "kei-architect", &content, None, None).unwrap();
assert_eq!(id1, id2);
let all = list(&s, &ArtifactFilter::default()).unwrap();
assert_eq!(all.len(), 1);
}
#[test]
fn missing_parent_rejected() {
let s = seed();
let content = spec_bytes("g");
let err = emit(&s, "spec", "kei-architect", &content, None, Some("deadbeef")).unwrap_err();
let msg = format!("{err:#}");
assert!(msg.contains("parent"), "unexpected: {msg}");
}