#![allow(clippy::unwrap_used)]
#![allow(clippy::no_effect_underscore_binding)] #![allow(missing_docs)] #![allow(clippy::format_push_string)] #![allow(clippy::needless_collect)] use fraiseql_core::{
db::{WhereClause, WhereOperator},
security::{QueryValidator, QueryValidatorConfig},
};
use serde_json::json;
#[test]
fn test_deeply_nested_query_rejected() {
let validator = QueryValidator::from_config(QueryValidatorConfig {
max_depth: 10,
max_complexity: 10_000,
max_size_bytes: 1_000_000,
max_aliases: 100,
});
let mut query = String::new();
for _ in 0..50 {
query.push_str("{ nested ");
}
query.push_str("{ leaf }");
for _ in 0..50 {
query.push_str(" }");
}
let result = validator.validate(&query);
assert!(result.is_err(), "50-level nested query should be rejected");
}
#[test]
fn test_very_high_complexity_query_rejected() {
let validator = QueryValidator::from_config(QueryValidatorConfig {
max_depth: 100,
max_complexity: 100,
max_size_bytes: 10_000_000,
max_aliases: 100,
});
let mut query = String::from("{ ");
for i in 0..200 {
query.push_str(&format!("field_{i} "));
}
query.push('}');
let result = validator.validate(&query);
assert!(
result.is_err(),
"200-field query should exceed complexity limit of 100, got Ok({result:?})"
);
}
#[test]
fn test_empty_query_handled() {
let validator = QueryValidator::standard();
let result = validator.validate("");
let _ = result;
}
#[test]
fn test_malformed_graphql_handled() {
let validator = QueryValidator::standard();
let result = validator.validate("{ user { name }");
let _ = result;
let result = validator.validate("))){{{{}}}}(((");
let _ = result;
}
#[test]
fn test_query_exceeding_size_limit_rejected() {
let validator = QueryValidator::from_config(QueryValidatorConfig {
max_depth: 10,
max_complexity: 1000,
max_size_bytes: 100,
max_aliases: 30,
});
let large_query = "{ ".to_string() + &"a ".repeat(100) + "}";
let result = validator.validate(&large_query);
assert!(result.is_err(), "query exceeding size limit should be rejected");
}
#[test]
fn test_where_clause_with_empty_path() {
let clause = WhereClause::Field {
path: vec![],
operator: WhereOperator::Eq,
value: json!(1),
};
let serialized = serde_json::to_string(&clause).unwrap();
assert!(serialized.contains("\"path\":[]"));
}
#[test]
fn test_where_clause_with_very_long_field_name() {
let long_name = "x".repeat(10_000);
let clause = WhereClause::Field {
path: vec![long_name],
operator: WhereOperator::Eq,
value: json!("test"),
};
let serialized = serde_json::to_string(&clause).unwrap();
let deserialized: WhereClause = serde_json::from_str(&serialized).unwrap();
match deserialized {
WhereClause::Field { path, .. } => assert_eq!(path[0].len(), 10_000),
other => panic!("expected Field variant, got {other:?}"),
}
}
#[test]
fn test_where_clause_with_null_value() {
let clause = WhereClause::Field {
path: vec!["status".to_string()],
operator: WhereOperator::Eq,
value: json!(null),
};
let serialized = serde_json::to_string(&clause).unwrap();
let deserialized: WhereClause = serde_json::from_str(&serialized).unwrap();
match deserialized {
WhereClause::Field { value, .. } => assert!(value.is_null()),
other => panic!("expected Field variant, got {other:?}"),
}
}
#[test]
fn test_where_clause_with_deeply_nested_and_or() {
let mut clause = WhereClause::Field {
path: vec!["id".to_string()],
operator: WhereOperator::Eq,
value: json!(1),
};
for i in 0..100 {
clause = if i % 2 == 0 {
WhereClause::And(vec![clause])
} else {
WhereClause::Or(vec![clause])
};
}
let serialized = serde_json::to_string(&clause).unwrap();
assert!(!serialized.is_empty());
let deser_result = serde_json::from_str::<WhereClause>(&serialized);
assert!(
deser_result.is_err(),
"100-level nested WhereClause should hit serde_json recursion limit"
);
}
#[test]
fn test_where_clause_moderate_nesting_roundtrips() {
let mut clause = WhereClause::Field {
path: vec!["id".to_string()],
operator: WhereOperator::Eq,
value: json!(1),
};
for i in 0..20 {
clause = if i % 2 == 0 {
WhereClause::And(vec![clause])
} else {
WhereClause::Or(vec![clause])
};
}
let serialized = serde_json::to_string(&clause).unwrap();
let deserialized: WhereClause = serde_json::from_str(&serialized).unwrap();
let re_serialized = serde_json::to_string(&deserialized).unwrap();
assert_eq!(serialized, re_serialized);
}
#[test]
fn test_where_clause_not_wrapping() {
let inner = WhereClause::Field {
path: vec!["active".to_string()],
operator: WhereOperator::Eq,
value: json!(true),
};
let clause = WhereClause::Not(Box::new(inner));
let serialized = serde_json::to_string(&clause).unwrap();
let deserialized: WhereClause = serde_json::from_str(&serialized).unwrap();
assert!(matches!(deserialized, WhereClause::Not(_)));
}