use core_policy::{ContextExpr, MAX_EXPR_DEPTH, MAX_EXPR_LENGTH};
use std::collections::BTreeMap;
#[test]
fn test_deep_nesting_no_crash() {
for depth in 1..=100 {
let open_parens = "(".repeat(depth);
let close_parens = ")".repeat(depth);
let expr = format!("{}TRUE{}", open_parens, close_parens);
let result = ContextExpr::parse(&expr);
if let Ok(parsed) = result {
let ctx = BTreeMap::new();
let eval_result = parsed.evaluate(&ctx, 0);
let _ = eval_result;
}
}
}
#[test]
fn test_extreme_nesting_handled() {
let depth = MAX_EXPR_DEPTH + 50;
let open_parens = "(".repeat(depth);
let close_parens = ")".repeat(depth);
let expr = format!("{}TRUE{}", open_parens, close_parens);
let result = ContextExpr::parse(&expr);
if let Ok(parsed) = result {
let ctx = BTreeMap::new();
let eval_result = parsed.evaluate(&ctx, 0);
assert!(
eval_result.is_err() || eval_result.is_ok(),
"Evaluation must return a proper Result, not panic"
);
}
}
#[test]
fn test_many_operators_no_crash() {
let base = "role == \"admin\"";
for count in 1..=50 {
let repeated = vec![base; count].join(" AND ");
let result = ContextExpr::parse(&repeated);
let _ = result;
}
for count in 1..=50 {
let repeated = vec![base; count].join(" OR ");
let result = ContextExpr::parse(&repeated);
let _ = result;
}
}
#[test]
fn test_unbalanced_parens_no_crash() {
let cases = [
"(((",
")))",
"(((TRUE))",
"((TRUE)))",
"(role == \"admin\"",
"role == \"admin\")",
"(((role == \"admin\"))(((",
")))role == \"admin\"(((",
"((((((((((",
"))))))))))",
"(TRUE AND (FALSE OR (TRUE AND (FALSE))))",
"((((((((((TRUE))))))))))",
];
for case in cases {
let result = ContextExpr::parse(case);
assert!(result.is_ok() || result.is_err(), "Must return Result");
}
}
#[test]
fn test_oversized_input_rejected() {
let huge = "a".repeat(MAX_EXPR_LENGTH + 100);
let result = ContextExpr::parse(&huge);
assert!(result.is_err(), "Oversized input should be rejected");
}
#[test]
fn test_boundary_size_input() {
let under = "a".repeat(MAX_EXPR_LENGTH - 10);
let result = ContextExpr::parse(&under);
let _ = result;
let exact = "a".repeat(MAX_EXPR_LENGTH);
let result = ContextExpr::parse(&exact);
let _ = result;
let over = "a".repeat(MAX_EXPR_LENGTH + 1);
let result = ContextExpr::parse(&over);
assert!(result.is_err(), "Over limit should be rejected");
}
#[test]
fn test_special_chars_no_crash() {
let cases = [
"\0",
"\x00\x01\x02",
"role\0== \"admin\"",
"role == \"admin\x00\"",
"\n\r\t",
" \t\t\t ",
"role\n==\r\"admin\"",
];
for case in cases {
let _ = ContextExpr::parse(case);
}
}
#[test]
fn test_unicode_no_crash() {
let cases = [
"роль == \"админ\"", "角色 == \"管理员\"", "🔒 == \"🔑\"", "rôle == \"àdmin\"", "役割 == \"管理者\"", "תפקיד == \"מנהל\"", "دور == \"مدير\"", ];
for case in cases {
let _ = ContextExpr::parse(case);
}
}
#[test]
fn test_empty_input_no_crash() {
let cases = ["", " ", " ", "\t", "\n", "\r\n", " \t \n "];
for case in cases {
let _ = ContextExpr::parse(case);
}
}
#[test]
fn test_malformed_operators_no_crash() {
let cases = [
"AND AND",
"OR OR OR",
"NOT NOT NOT",
"AND OR AND",
"== ==",
"!= !=",
"role == == \"admin\"",
"AND",
"OR",
"NOT",
"HAS",
"TRUE AND",
"AND TRUE",
"role ==",
"== \"admin\"",
];
for case in cases {
let _ = ContextExpr::parse(case);
}
}
#[test]
fn test_string_literal_edge_cases() {
let cases = [
"role == \"\"", "role == \"\\\"\"", "role == \"\\\\\"", "role == \"a\\\"b\"", "role == \"", "role == \"admin", "role == admin\"", ];
for case in cases {
let _ = ContextExpr::parse(case);
}
}
#[test]
fn test_stress_parse_evaluate() {
let expressions = [
"TRUE",
"FALSE",
"role == \"admin\"",
"role == \"admin\" AND dept == \"IT\"",
"(role == \"admin\" OR role == \"mod\") AND active == \"true\"",
"NOT (banned == \"true\")",
"HAS role",
"HAS role AND role == \"admin\"",
"a == \"1\" AND b == \"2\" AND c == \"3\" AND d == \"4\"",
"(((TRUE)))",
"NOT NOT NOT TRUE",
];
let mut ctx = BTreeMap::new();
ctx.insert("role".to_string(), "admin".to_string());
ctx.insert("dept".to_string(), "IT".to_string());
ctx.insert("active".to_string(), "true".to_string());
for expr_str in expressions {
if let Ok(expr) = ContextExpr::parse(expr_str) {
let _ = expr.evaluate(&ctx, 0);
}
}
}