use serde_json::json;
use std::sync::Arc;
use zen_engine::policy::{PolicyWorkspace, ReferenceKind, RenameTarget, ScopeRequest};
fn workspace_with(doc: serde_json::Value) -> PolicyWorkspace {
let mut ws = PolicyWorkspace::new();
ws.set_policy("p", serde_json::from_value(doc).unwrap());
ws
}
fn customer_company_dm() -> Vec<serde_json::Value> {
vec![
json!({ "id": "dm-customer", "type": "dataModel", "props": { "data": {
"name": "customer",
"properties": [
{ "id": "p1", "name": "name", "type": "string", "array": false, "optional": false },
{ "id": "p2", "name": "companies", "type": "relationship", "target": "company", "array": true, "optional": false }
]
} } }),
json!({ "id": "dm-company", "type": "dataModel", "props": { "data": {
"name": "company",
"properties": [
{ "id": "p1", "name": "name", "type": "string", "array": false, "optional": false },
{ "id": "p2", "name": "revenue", "type": "number", "array": false, "optional": false }
]
} } }),
]
}
fn instance_of(ws: &PolicyWorkspace, entity: &str, field: &str) -> Option<serde_json::Value> {
let entities = ws.entities(&ScopeRequest::for_policy("p"));
let entity_obj = entities.iter().find(|e| e.name.as_ref() == entity)?;
let field_obj = entity_obj
.fields
.iter()
.find(|f| f.name.as_ref() == field)?;
let origin = serde_json::to_value(&field_obj.origin).unwrap();
origin.get("instanceOf").cloned()
}
#[test]
fn chained_computed_identity_resolves_transitively() {
let mut blocks = customer_company_dm();
blocks.push(
json!({ "id": "e1", "type": "expression", "props": { "data": {
"key": "customer.profitable",
"value": "filter(customer.companies, $.revenue > 0)"
} } }),
);
blocks.push(
json!({ "id": "e2", "type": "expression", "props": { "data": {
"key": "customer.topThree",
"value": "customer.profitable[0:3]"
} } }),
);
blocks.push(
json!({ "id": "e3", "type": "expression", "props": { "data": {
"key": "customer.best",
"value": "customer.topThree[0]"
} } }),
);
let ws = workspace_with(json!({ "blocks": blocks }));
assert_eq!(
instance_of(&ws, "customer", "profitable"),
Some(json!({ "target": "company", "array": true }))
);
assert_eq!(
instance_of(&ws, "customer", "topThree"),
Some(json!({ "target": "company", "array": true }))
);
assert_eq!(
instance_of(&ws, "customer", "best"),
Some(json!({ "target": "company", "array": false }))
);
}
#[test]
fn match_arms_with_agreeing_identity() {
let mut blocks = customer_company_dm();
blocks.push(json!({ "id": "m1", "type": "match", "props": { "data": {
"key": "customer.picked",
"arms": [
{ "id": "a1", "condition": "customer.name == \"vip\"", "value": "customer.companies[0]" },
{ "id": "a2", "condition": "", "value": "customer.companies[1]" }
]
} } }));
let ws = workspace_with(json!({ "blocks": blocks }));
assert_eq!(
instance_of(&ws, "customer", "picked"),
Some(json!({ "target": "company", "array": false }))
);
}
#[test]
fn match_arms_with_disagreeing_identity_erase() {
let mut blocks = customer_company_dm();
blocks.push(json!({ "id": "m1", "type": "match", "props": { "data": {
"key": "customer.picked",
"arms": [
{ "id": "a1", "condition": "customer.name == \"vip\"", "value": "customer.companies[0]" },
{ "id": "a2", "condition": "", "value": "customer.name" }
]
} } }));
let ws = workspace_with(json!({ "blocks": blocks }));
assert_eq!(instance_of(&ws, "customer", "picked"), None);
}
#[test]
fn pool_root_filter_keeps_array() {
let doc = json!({ "blocks": [
{ "id": "dm-customer", "type": "dataModel", "props": { "data": {
"name": "customer",
"properties": [
{ "id": "p1", "name": "favorite", "type": "reference", "target": "company", "array": false, "optional": false }
]
} } },
{ "id": "dm-company", "type": "dataModel", "props": { "data": {
"name": "company",
"properties": [
{ "id": "p1", "name": "revenue", "type": "number", "array": false, "optional": false }
]
} } },
{ "id": "e1", "type": "expression", "props": { "data": {
"key": "customer.richPool",
"value": "filter(company, $.revenue > 100)"
} } }
] });
let ws = workspace_with(doc);
assert_eq!(
instance_of(&ws, "customer", "richPool"),
Some(json!({ "target": "company", "array": true }))
);
}
#[test]
fn outputs_carry_instance_of() {
let mut blocks = customer_company_dm();
blocks.push(
json!({ "id": "e1", "type": "expression", "props": { "data": {
"key": "customer.profitable",
"value": "filter(customer.companies, $.revenue > 0)"
} } }),
);
let ws = workspace_with(json!({ "blocks": blocks }));
let outputs = ws.outputs(&ScopeRequest::for_policy("p"));
let profitable = outputs
.iter()
.find(|o| o.path.as_ref() == "customer.profitable")
.expect("output registered");
let serialized = serde_json::to_value(profitable).unwrap();
assert_eq!(
serialized["instanceOf"],
json!({ "target": "company", "array": true })
);
}
#[test]
fn rename_finds_reads_through_computed_collection_and_pointer() {
let mut blocks = customer_company_dm();
blocks.push(
json!({ "id": "e1", "type": "expression", "props": { "data": {
"key": "customer.profitable",
"value": "filter(customer.companies, $.revenue > 0)"
} } }),
);
blocks.push(
json!({ "id": "e2", "type": "expression", "props": { "data": {
"key": "customer.total",
"value": "sum(map(customer.profitable as c, c.revenue))"
} } }),
);
let ws = workspace_with(json!({ "blocks": blocks }));
let sites = ws.references(&RenameTarget::Field {
entity: Arc::from("company"),
field: Arc::from("revenue"),
});
let expression_sites: Vec<&str> = sites
.iter()
.filter(|s| s.kind == ReferenceKind::ExpressionRead)
.map(|s| s.block_id.as_ref())
.collect();
assert!(
expression_sites.contains(&"e1"),
"$ read over declared relationship must be found: {sites:#?}"
);
assert!(
expression_sites.contains(&"e2"),
"alias read over computed collection must be found: {sites:#?}"
);
let edits = ws.rename(
&RenameTarget::Field {
entity: Arc::from("company"),
field: Arc::from("revenue"),
},
"income",
);
let serialized = serde_json::to_string(&edits).unwrap();
assert!(
serialized.contains("$.income > 0"),
"pointer read must be rewritten: {serialized}"
);
assert!(
serialized.contains("c.income"),
"alias read must be rewritten: {serialized}"
);
}
#[test]
fn map_and_arithmetic_erase_identity() {
let mut blocks = customer_company_dm();
blocks.push(
json!({ "id": "e1", "type": "expression", "props": { "data": {
"key": "customer.summaries",
"value": "map(customer.companies as c, { label: c.name })"
} } }),
);
blocks.push(
json!({ "id": "e2", "type": "expression", "props": { "data": {
"key": "customer.count",
"value": "len(customer.companies)"
} } }),
);
let ws = workspace_with(json!({ "blocks": blocks }));
assert_eq!(instance_of(&ws, "customer", "summaries"), None);
assert_eq!(instance_of(&ws, "customer", "count"), None);
}