use super::{AccessDecision, AccessScope, QueryAccessContext, QueryOperationKind};
use crate::velesql::{CompareOp, Comparison, Condition, Value};
fn classify(decision: &AccessDecision) -> &'static str {
match decision {
AccessDecision::Allow => "allow",
AccessDecision::Deny(_) => "deny",
AccessDecision::AllowWithScope(_) => "allow_with_scope",
}
}
#[test]
fn access_decision_allow_can_be_constructed_and_matched() {
let decision = AccessDecision::Allow;
assert_eq!(classify(&decision), "allow");
}
#[test]
fn access_decision_deny_carries_the_supplied_error() {
let decision = AccessDecision::Deny(crate::Error::Query("denied".to_string()));
assert_eq!(classify(&decision), "deny");
match decision {
AccessDecision::Deny(err) => {
assert!(err.to_string().contains("denied"));
}
other => panic!("expected Deny, got {other:?}"),
}
}
#[test]
fn access_decision_allow_with_scope_carries_the_scope() {
let scope = AccessScope {
tenant: Some("tenant-a".to_string()),
filter: Some(Condition::Comparison(Comparison {
column: "org".to_string(),
operator: CompareOp::Eq,
value: Value::String("acme".to_string()),
})),
};
let decision = AccessDecision::AllowWithScope(scope);
assert_eq!(classify(&decision), "allow_with_scope");
match decision {
AccessDecision::AllowWithScope(scope) => {
assert_eq!(scope.tenant.as_deref(), Some("tenant-a"));
assert!(matches!(scope.filter, Some(Condition::Comparison(_))));
}
other => panic!("expected AllowWithScope, got {other:?}"),
}
}
#[test]
fn query_operation_kind_all_variants_construct_and_compare() {
let all = [
QueryOperationKind::VectorSearch,
QueryOperationKind::TextSearch,
QueryOperationKind::HybridSearch,
QueryOperationKind::GraphTraversal,
QueryOperationKind::Select,
];
for (i, a) in all.iter().enumerate() {
for (j, b) in all.iter().enumerate() {
assert_eq!(*a == *b, i == j, "variant equality mismatch at {i},{j}");
}
}
}
#[test]
fn query_operation_kind_is_copy() {
let kind = QueryOperationKind::HybridSearch;
let copied = kind; assert_eq!(kind, copied);
}
#[test]
fn access_scope_default_is_fully_unset() {
let scope = AccessScope::default();
assert!(scope.tenant.is_none());
assert!(scope.filter.is_none());
}
#[test]
fn query_access_context_borrows_its_fields() {
let collection = "documents".to_string();
let principal = "user-42".to_string();
let tenant = "tenant-a".to_string();
let ctx = QueryAccessContext {
collection: &collection,
operation: QueryOperationKind::Select,
principal: Some(&principal),
tenant_hint: Some(&tenant),
};
assert_eq!(ctx.collection, "documents");
assert_eq!(ctx.operation, QueryOperationKind::Select);
assert_eq!(ctx.principal, Some("user-42"));
assert_eq!(ctx.tenant_hint, Some("tenant-a"));
}
#[test]
fn query_access_context_optional_hints_can_be_absent() {
let collection = "vectors".to_string();
let ctx = QueryAccessContext {
collection: &collection,
operation: QueryOperationKind::VectorSearch,
principal: None,
tenant_hint: None,
};
assert_eq!(ctx.collection, "vectors");
assert_eq!(ctx.operation, QueryOperationKind::VectorSearch);
assert!(ctx.principal.is_none());
assert!(ctx.tenant_hint.is_none());
}