use assay_core::policy_engine::{evaluate_tool_args, PolicyState, VerdictStatus};
use serde_json::json;
fn policy() -> serde_json::Value {
json!({
"send_money": {
"type": "object",
"properties": {
"recipient": { "type": "string", "enum": ["acc_alice"] },
"amount": { "type": "number", "maximum": 1000 }
},
"required": ["recipient", "amount"]
},
"broken": { "type": "not-a-real-type" }
})
}
fn assert_parity(tool: &str, args: &serde_json::Value) {
let p = policy();
let state = PolicyState::compile(&p);
let cached = state.evaluate(tool, args);
let one_shot = evaluate_tool_args(&p, tool, args);
assert_eq!(cached.status, one_shot.status, "status differs for {tool}");
assert_eq!(
cached.reason_code, one_shot.reason_code,
"reason_code differs for {tool}"
);
}
#[test]
fn allowed_call_parity() {
assert_parity(
"send_money",
&json!({ "recipient": "acc_alice", "amount": 100 }),
);
}
#[test]
fn blocked_over_ceiling_parity() {
let p = policy();
let v = PolicyState::compile(&p).evaluate(
"send_money",
&json!({ "recipient": "acc_alice", "amount": 9999 }),
);
assert_eq!(v.status, VerdictStatus::Blocked);
assert_eq!(v.reason_code, "E_ARG_SCHEMA");
assert_parity(
"send_money",
&json!({ "recipient": "acc_alice", "amount": 9999 }),
);
}
#[test]
fn off_allowlist_recipient_parity() {
assert_parity(
"send_money",
&json!({ "recipient": "acc_attacker", "amount": 10 }),
);
}
#[test]
fn missing_tool_parity() {
let p = policy();
let v = PolicyState::compile(&p).evaluate("send_monye", &json!({}));
assert_eq!(v.status, VerdictStatus::Blocked);
assert_eq!(v.reason_code, "E_POLICY_MISSING_TOOL");
assert_parity("send_monye", &json!({}));
}
#[test]
fn broken_schema_only_surfaces_when_that_tool_is_evaluated() {
let p = policy();
let state = PolicyState::compile(&p);
let ok = state.evaluate(
"send_money",
&json!({ "recipient": "acc_alice", "amount": 1 }),
);
assert_eq!(ok.status, VerdictStatus::Allowed);
let broken = state.evaluate("broken", &json!({}));
assert_eq!(broken.status, VerdictStatus::Blocked);
assert_eq!(broken.reason_code, "E_SCHEMA_COMPILE");
assert_parity("broken", &json!({}));
}
#[test]
fn compile_once_reused_across_many_calls() {
let p = policy();
let state = PolicyState::compile(&p);
for _ in 0..50 {
assert_eq!(
state
.evaluate(
"send_money",
&json!({ "recipient": "acc_alice", "amount": 100 })
)
.status,
VerdictStatus::Allowed
);
assert_eq!(
state
.evaluate(
"send_money",
&json!({ "recipient": "acc_alice", "amount": 5000 })
)
.status,
VerdictStatus::Blocked
);
}
}