use core_policy::builder::PolicyRuleBuilder;
use core_policy::context_expr::{CompareOp, ContextExpr};
use core_policy::{Action, PolicyRule, Resource};
use std::collections::BTreeMap;
#[test]
fn test_context_expr_integration_simple() {
let rule = PolicyRuleBuilder::new()
.for_peer("alice")
.allow(Action::Read)
.on(Resource::File("/secure/*".into()))
.with_context_expr("role == \"admin\"")
.unwrap()
.build()
.unwrap();
let mut context = BTreeMap::new();
context.insert("role".to_string(), "admin".to_string());
assert!(rule.matches_context(&context));
let mut context = BTreeMap::new();
context.insert("role".to_string(), "user".to_string());
assert!(!rule.matches_context(&context));
}
#[test]
fn test_context_expr_integration_and() {
let rule = PolicyRuleBuilder::new()
.for_peer("alice")
.allow(Action::Write)
.on(Resource::File("/data/*".into()))
.with_context_expr("role == \"admin\" AND department == \"IT\"")
.unwrap()
.build()
.unwrap();
let mut context = BTreeMap::new();
context.insert("role".to_string(), "admin".to_string());
context.insert("department".to_string(), "IT".to_string());
assert!(rule.matches_context(&context));
let mut context = BTreeMap::new();
context.insert("role".to_string(), "admin".to_string());
context.insert("department".to_string(), "HR".to_string());
assert!(!rule.matches_context(&context));
let mut context = BTreeMap::new();
context.insert("role".to_string(), "user".to_string());
context.insert("department".to_string(), "IT".to_string());
assert!(!rule.matches_context(&context));
}
#[test]
fn test_context_expr_integration_or() {
let rule = PolicyRuleBuilder::new()
.for_peer("bob")
.allow(Action::Read)
.on(Resource::All)
.with_context_expr("role == \"admin\" OR role == \"moderator\"")
.unwrap()
.build()
.unwrap();
let mut context = BTreeMap::new();
context.insert("role".to_string(), "admin".to_string());
assert!(rule.matches_context(&context));
let mut context = BTreeMap::new();
context.insert("role".to_string(), "moderator".to_string());
assert!(rule.matches_context(&context));
let mut context = BTreeMap::new();
context.insert("role".to_string(), "user".to_string());
assert!(!rule.matches_context(&context));
}
#[test]
fn test_context_expr_integration_not() {
let rule = PolicyRuleBuilder::new()
.for_peer("eve")
.allow(Action::Execute)
.on(Resource::File("/scripts/*".into()))
.with_context_expr("NOT (status == \"banned\")")
.unwrap()
.build()
.unwrap();
let mut context = BTreeMap::new();
context.insert("status".to_string(), "active".to_string());
assert!(rule.matches_context(&context));
let mut context = BTreeMap::new();
context.insert("status".to_string(), "banned".to_string());
assert!(!rule.matches_context(&context));
let context = BTreeMap::new();
assert!(rule.matches_context(&context));
}
#[test]
fn test_context_expr_integration_complex() {
let rule = PolicyRuleBuilder::new()
.for_peer("charlie")
.allow(Action::Write)
.on(Resource::File("/sensitive/*".into()))
.with_context_expr("(role == \"admin\" OR role == \"moderator\") AND active == \"true\"")
.unwrap()
.build()
.unwrap();
let mut context = BTreeMap::new();
context.insert("role".to_string(), "admin".to_string());
context.insert("active".to_string(), "true".to_string());
assert!(rule.matches_context(&context));
let mut context = BTreeMap::new();
context.insert("role".to_string(), "moderator".to_string());
context.insert("active".to_string(), "true".to_string());
assert!(rule.matches_context(&context));
let mut context = BTreeMap::new();
context.insert("role".to_string(), "admin".to_string());
context.insert("active".to_string(), "false".to_string());
assert!(!rule.matches_context(&context));
let mut context = BTreeMap::new();
context.insert("role".to_string(), "user".to_string());
context.insert("active".to_string(), "true".to_string());
assert!(!rule.matches_context(&context));
}
#[test]
fn test_context_expr_integration_has_attribute() {
let rule = PolicyRuleBuilder::new()
.for_peer("dave")
.allow(Action::Read)
.on(Resource::File("/logs/*".into()))
.with_context_expr("HAS security_clearance")
.unwrap()
.build()
.unwrap();
let mut context = BTreeMap::new();
context.insert("security_clearance".to_string(), "top_secret".to_string());
assert!(rule.matches_context(&context));
let context = BTreeMap::new();
assert!(!rule.matches_context(&context));
}
#[test]
fn test_context_expr_integration_comparison_operators() {
let rule = PolicyRuleBuilder::new()
.for_peer("frank")
.allow(Action::Read)
.on(Resource::File("/age-restricted/*".into()))
.with_context_expr("age >= \"18\"")
.unwrap()
.build()
.unwrap();
let mut context = BTreeMap::new();
context.insert("age".to_string(), "20".to_string());
assert!(rule.matches_context(&context));
let mut context = BTreeMap::new();
context.insert("age".to_string(), "18".to_string());
assert!(rule.matches_context(&context));
let mut context = BTreeMap::new();
context.insert("age".to_string(), "15".to_string());
assert!(!rule.matches_context(&context));
}
#[test]
fn test_context_expr_integration_combined_with_legacy_attributes() {
let rule = PolicyRuleBuilder::new()
.for_peer("grace")
.allow(Action::Write)
.on(Resource::File("/shared/*".into()))
.with_attribute("location", "office")
.with_context_expr("role == \"admin\"")
.unwrap()
.build()
.unwrap();
let mut context = BTreeMap::new();
context.insert("location".to_string(), "office".to_string());
context.insert("role".to_string(), "admin".to_string());
assert!(rule.matches_context(&context));
let mut context = BTreeMap::new();
context.insert("location".to_string(), "remote".to_string());
context.insert("role".to_string(), "admin".to_string());
assert!(!rule.matches_context(&context));
let mut context = BTreeMap::new();
context.insert("location".to_string(), "office".to_string());
context.insert("role".to_string(), "user".to_string());
assert!(!rule.matches_context(&context));
}
#[test]
fn test_context_expr_programmatic_construction() {
let expr = ContextExpr::And(
Box::new(ContextExpr::Compare {
key: "role".into(),
op: CompareOp::Equal,
value: "admin".into(),
}),
Box::new(ContextExpr::Not(Box::new(ContextExpr::Compare {
key: "status".into(),
op: CompareOp::Equal,
value: "suspended".into(),
}))),
);
let rule =
PolicyRule::new("heidi".into(), Action::Delete, Resource::All).with_context_expr(expr);
let mut context = BTreeMap::new();
context.insert("role".to_string(), "admin".to_string());
context.insert("status".to_string(), "active".to_string());
assert!(rule.matches_context(&context));
let mut context = BTreeMap::new();
context.insert("role".to_string(), "admin".to_string());
context.insert("status".to_string(), "suspended".to_string());
assert!(!rule.matches_context(&context));
}
#[test]
fn test_context_expr_invalid_expression() {
let result = PolicyRuleBuilder::new()
.for_peer("mallory")
.allow(Action::Read)
.on(Resource::All)
.with_context_expr("role = \"admin\"");
assert!(result.is_err());
}
#[test]
fn test_context_expr_expression_too_long() {
let long_expr = "role == \"admin\"".repeat(100);
let result = PolicyRuleBuilder::new()
.for_peer("nancy")
.allow(Action::Read)
.on(Resource::All)
.with_context_expr(&long_expr);
assert!(result.is_err());
}