use super::*;
#[test]
fn test_parse_error() {
let err = FraiseQLError::parse("unexpected token");
assert!(err.is_client_error());
assert!(!err.is_server_error());
assert_eq!(err.status_code(), 400);
assert_eq!(err.error_code(), "GRAPHQL_PARSE_FAILED");
}
#[test]
fn test_database_error() {
let err = FraiseQLError::database("connection refused");
assert!(!err.is_client_error());
assert!(err.is_server_error());
assert_eq!(err.status_code(), 500);
}
#[test]
fn test_not_found_error() {
let err = FraiseQLError::not_found("User", "123");
assert!(err.is_client_error());
assert_eq!(err.status_code(), 404);
assert_eq!(err.to_string(), "User not found: 123");
}
#[test]
fn test_retryable_errors() {
assert!(
FraiseQLError::ConnectionPool {
message: "timeout".to_string(),
}
.is_retryable()
);
assert!(
FraiseQLError::Timeout {
timeout_ms: 5000,
query: None,
}
.is_retryable()
);
assert!(!FraiseQLError::parse("bad query").is_retryable());
}
#[test]
fn test_unsupported_is_501() {
let err = FraiseQLError::Unsupported {
message: "execute_function_call not supported on SQLite".to_string(),
};
assert_eq!(err.status_code(), 501);
assert!(err.is_server_error());
assert_eq!(err.error_code(), "UNSUPPORTED_OPERATION");
}
#[test]
fn test_from_serde_error() {
let json_err = serde_json::from_str::<serde_json::Value>("not json")
.expect_err("'not json' must fail to parse");
let err: FraiseQLError = json_err.into();
assert!(matches!(err, FraiseQLError::Parse { .. }));
}
#[test]
fn test_validation_field_error_creation() {
let field_err = ValidationFieldError::new("user.email", "pattern", "Invalid email format");
assert_eq!(field_err.field, "user.email");
assert_eq!(field_err.rule_type, "pattern");
assert_eq!(field_err.message, "Invalid email format");
}
#[test]
fn test_levenshtein_ascii() {
assert_eq!(FraiseQLError::levenshtein_distance("kitten", "sitting"), 3);
assert_eq!(FraiseQLError::levenshtein_distance("", "abc"), 3);
assert_eq!(FraiseQLError::levenshtein_distance("abc", ""), 3);
assert_eq!(FraiseQLError::levenshtein_distance("same", "same"), 0);
}
#[test]
fn test_levenshtein_multibyte_utf8() {
assert_eq!(FraiseQLError::levenshtein_distance("café", "cafe"), 1);
assert_eq!(FraiseQLError::levenshtein_distance("naïve", "naive"), 1);
assert_eq!(FraiseQLError::levenshtein_distance("café", "café"), 0);
}
#[derive(Debug)]
struct SentinelSubsystemError {
kind: &'static str,
}
impl std::fmt::Display for SentinelSubsystemError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "sentinel-subsystem-error: {}", self.kind)
}
}
impl std::error::Error for SentinelSubsystemError {}
fn assert_source_downcasts_to_sentinel(err: &FraiseQLError, expected_kind: &str) {
use std::error::Error as _;
let source = err.source().expect("boxed-payload variants must expose Error::source()");
let downcast = source
.downcast_ref::<SentinelSubsystemError>()
.expect("Error::source() must downcast to the original concrete subsystem type");
assert_eq!(downcast.kind, expected_kind);
}
#[test]
fn auth_variant_source_downcasts_to_subsystem_type() {
let inner = SentinelSubsystemError {
kind: "auth-token-expired",
};
let err = FraiseQLError::Auth(Box::new(inner));
assert_source_downcasts_to_sentinel(&err, "auth-token-expired");
}
#[test]
fn webhook_variant_source_downcasts_to_subsystem_type() {
let inner = SentinelSubsystemError {
kind: "webhook-delivery-refused",
};
let err = FraiseQLError::Webhook(Box::new(inner));
assert_source_downcasts_to_sentinel(&err, "webhook-delivery-refused");
}
#[test]
fn observer_variant_source_downcasts_to_subsystem_type() {
let inner = SentinelSubsystemError {
kind: "observer-dispatch-failed",
};
let err = FraiseQLError::Observer(Box::new(inner));
assert_source_downcasts_to_sentinel(&err, "observer-dispatch-failed");
}