church-core/tests/error_handling_tests.rs
RTSDA 4d6b23beb3
Some checks are pending
iOS UniFFI Build / build-ios (push) Waiting to run
Initial commit: Church Core Rust library
Add church management API library with cross-platform support for iOS, Android, and WASM.
Features include event management, bulletin handling, contact forms, and authentication.
2025-08-16 19:25:01 -04:00

208 lines
6.9 KiB
Rust

use church_core::{
ChurchApiClient, ChurchCoreConfig,
error::ChurchApiError,
};
use mockito::{self, mock};
use serde_json::json;
use std::time::Duration;
#[cfg(test)]
mod error_handling_tests {
use super::*;
fn create_test_client() -> ChurchApiClient {
let config = ChurchCoreConfig::new()
.with_base_url(&mockito::server_url())
.with_timeout(Duration::from_millis(100))
.with_retry_attempts(1)
.with_offline_mode(false);
ChurchApiClient::new(config).unwrap()
}
#[tokio::test]
async fn test_http_404_error() {
let _m = mock("GET", "/events/nonexistent")
.with_status(404)
.with_header("content-type", "application/json")
.with_body(json!({
"success": false,
"error": "Not found"
}).to_string())
.create();
let client = create_test_client();
let result = client.get_event("nonexistent").await;
// For get_event, 404 should return None, not an error
assert!(result.is_ok());
assert!(result.unwrap().is_none());
}
#[tokio::test]
async fn test_http_401_unauthorized() {
let _m = mock("POST", "/events")
.with_status(401)
.with_header("content-type", "application/json")
.with_body(json!({
"success": false,
"error": "Unauthorized access"
}).to_string())
.create();
let client = create_test_client();
let new_event = church_core::models::NewEvent {
title: "Protected Event".to_string(),
description: "Requires authentication".to_string(),
start_time: chrono::Utc::now(),
end_time: chrono::Utc::now() + chrono::Duration::hours(1),
location: "Secure Location".to_string(),
location_url: None,
image: None,
category: church_core::models::EventCategory::Other,
is_featured: false,
recurring_type: None,
tags: None,
contact_email: None,
contact_phone: None,
registration_url: None,
max_attendees: None,
};
let result = client.create_event(new_event).await;
assert!(result.is_err());
if let Err(error) = result {
assert!(matches!(error, ChurchApiError::Auth(_)));
assert!(error.is_auth_error());
}
}
#[tokio::test]
async fn test_http_403_forbidden() {
let _m = mock("PUT", "/config")
.with_status(403)
.with_header("content-type", "application/json")
.with_body(json!({
"success": false,
"error": "Forbidden - insufficient permissions"
}).to_string())
.create();
let client = create_test_client();
let config = church_core::models::ChurchConfig {
church_name: Some("Test Church".to_string()),
church_address: None,
contact_phone: None,
contact_email: None,
website_url: None,
google_maps_url: None,
facebook_url: None,
youtube_url: None,
instagram_url: None,
about_text: None,
mission_statement: None,
service_times: None,
pastoral_staff: None,
ministries: None,
app_settings: None,
emergency_contacts: None,
};
let result = client.update_config(config).await;
assert!(result.is_err());
if let Err(error) = result {
assert!(matches!(error, ChurchApiError::PermissionDenied));
assert!(error.is_auth_error());
}
}
#[tokio::test]
async fn test_http_500_server_error() {
let _m = mock("GET", "/events/upcoming")
.with_status(500)
.with_header("content-type", "application/json")
.with_body(json!({
"success": false,
"error": "Internal server error"
}).to_string())
.create();
let client = create_test_client();
let result = client.get_upcoming_events(None).await;
assert!(result.is_err());
if let Err(error) = result {
assert!(matches!(error, ChurchApiError::Http(_)));
assert!(error.is_network_error());
}
}
#[tokio::test]
async fn test_invalid_json_response() {
let _m = mock("GET", "/events/upcoming")
.with_status(200)
.with_header("content-type", "application/json")
.with_body("invalid json {")
.create();
let client = create_test_client();
let result = client.get_upcoming_events(None).await;
assert!(result.is_err());
// Invalid JSON will likely cause an HTTP parsing error instead of JSON error
// since the response can't be properly parsed as JSON
if let Err(error) = result {
// Could be either JSON or HTTP error depending on how reqwest handles it
assert!(matches!(error, ChurchApiError::Json(_)) || matches!(error, ChurchApiError::Http(_)));
}
}
#[tokio::test]
async fn test_api_error_response() {
let _m = mock("GET", "/events/upcoming")
.with_status(200)
.with_header("content-type", "application/json")
.with_body(json!({
"success": false,
"data": null,
"error": "Custom API error message"
}).to_string())
.create();
let client = create_test_client();
let result = client.get_upcoming_events(None).await;
assert!(result.is_err());
if let Err(error) = result {
assert!(matches!(error, ChurchApiError::Api(_)));
if let ChurchApiError::Api(message) = error {
assert_eq!(message, "Custom API error message");
}
}
}
#[test]
fn test_error_classification() {
let auth_error = ChurchApiError::Auth("Invalid token".to_string());
assert!(!auth_error.is_network_error());
assert!(!auth_error.is_temporary());
assert!(auth_error.is_auth_error());
let rate_limit_error = ChurchApiError::RateLimit;
assert!(!rate_limit_error.is_network_error());
assert!(rate_limit_error.is_temporary());
assert!(!rate_limit_error.is_auth_error());
let permission_error = ChurchApiError::PermissionDenied;
assert!(!permission_error.is_network_error());
assert!(!permission_error.is_temporary());
assert!(permission_error.is_auth_error());
let not_found_error = ChurchApiError::NotFound;
assert!(!not_found_error.is_network_error());
assert!(!not_found_error.is_temporary());
assert!(!not_found_error.is_auth_error());
}
}