use cruxi::{CodedError, CruxiError, ValidationError};
use std::error::Error;
#[test]
fn coded_error_display_priority() {
let err = CodedError::new("TEST")
.with_title("Short Title")
.with_reason("Detailed reason message");
assert_eq!(err.to_string(), "Detailed reason message");
}
#[test]
fn coded_error_display_title_when_no_reason() {
let err = CodedError::new("TEST").with_title("Short Title");
assert_eq!(err.to_string(), "Short Title");
}
#[test]
fn coded_error_display_code_fallback() {
let err = CodedError::new("MY_ERROR_CODE");
assert_eq!(err.to_string(), "cruxi: coded error [MY_ERROR_CODE]");
}
#[test]
fn coded_error_code_accessor() {
let err = CodedError::new("USER_NOT_FOUND");
assert_eq!(err.code(), "USER_NOT_FOUND");
}
#[test]
fn coded_error_instance_accessor() {
let err = CodedError::new("TEST").with_instance("req-12345-abc");
assert_eq!(err.instance(), Some("req-12345-abc"));
}
#[test]
fn coded_error_instance_none() {
let err = CodedError::new("TEST");
assert_eq!(err.instance(), None);
}
#[test]
fn coded_error_title_accessor() {
let err = CodedError::new("TEST").with_title("User Not Found");
assert_eq!(err.title(), Some("User Not Found"));
}
#[test]
fn coded_error_title_none() {
let err = CodedError::new("TEST");
assert_eq!(err.title(), None);
}
#[test]
fn coded_error_reason_accessor() {
let err = CodedError::new("TEST").with_reason("The user with ID 123 was not found");
assert_eq!(err.reason(), Some("The user with ID 123 was not found"));
}
#[test]
fn coded_error_reason_none() {
let err = CodedError::new("TEST");
assert_eq!(err.reason(), None);
}
#[test]
fn coded_error_single_source() {
let inner = CodedError::new("DB_CONNECTION_FAILED").with_reason("Connection timed out");
let outer = CodedError::new("USER_FETCH_FAILED")
.with_reason("Could not fetch user")
.with_source(inner);
let source = outer.source();
assert!(source.is_some());
}
#[test]
fn coded_error_chain_three_levels() {
let level1 = CodedError::new("LEVEL1").with_reason("Root cause");
let level2 = CodedError::new("LEVEL2")
.with_reason("Middle cause")
.with_source(level1);
let level3 = CodedError::new("LEVEL3")
.with_reason("Top level error")
.with_source(level2);
let source1 = level3.source().expect("Should have source");
let source2 = source1.source().expect("Should have nested source");
assert!(source2.source().is_none());
}
#[test]
fn coded_error_chain_downcast() {
let inner = CodedError::new("INNER").with_reason("inner cause");
let outer = CodedError::new("OUTER")
.with_reason("outer reason")
.with_source(inner);
let source = outer.source().expect("Should have source");
let inner_coded = source.downcast_ref::<CodedError>();
assert!(inner_coded.is_some());
assert_eq!(inner_coded.unwrap().code(), "INNER");
}
#[test]
fn coded_error_no_source() {
let err = CodedError::new("STANDALONE");
assert!(err.source().is_none());
}
#[test]
fn coded_error_clone_preserves_all_fields() {
let original = CodedError::new("ORIGINAL")
.with_title("Original Title")
.with_reason("Original reason")
.with_instance("req-123");
let cloned = original.clone();
assert_eq!(cloned.code(), "ORIGINAL");
assert_eq!(cloned.title(), Some("Original Title"));
assert_eq!(cloned.reason(), Some("Original reason"));
assert_eq!(cloned.instance(), Some("req-123"));
}
#[test]
fn coded_error_clone_with_source() {
let inner = CodedError::new("INNER");
let outer = CodedError::new("OUTER").with_source(inner);
let cloned = outer.clone();
assert!(cloned.source().is_some());
}
#[test]
fn validation_error_accessors() {
let err = ValidationError::new("email", "must be valid email format");
assert_eq!(err.field(), "email");
assert_eq!(err.message(), "must be valid email format");
}
#[test]
fn validation_error_display() {
let err = ValidationError::new("password", "must be at least 8 characters");
assert_eq!(
err.to_string(),
"cruxi: validation error: password: must be at least 8 characters"
);
}
#[test]
fn validation_error_empty_field_name() {
let err = ValidationError::new("", "field is empty");
assert_eq!(err.to_string(), "cruxi: validation error: : field is empty");
}
#[test]
fn validation_error_empty_message() {
let err = ValidationError::new("field", "");
assert_eq!(err.to_string(), "cruxi: validation error: field: ");
}
#[test]
fn validation_error_clone() {
let original = ValidationError::new("username", "already taken");
let cloned = original.clone();
assert_eq!(cloned.field(), "username");
assert_eq!(cloned.message(), "already taken");
}
#[test]
fn cruxi_error_unauthorized_display() {
let err = CruxiError::Unauthorized;
assert_eq!(err.to_string(), "cruxi: unauthorized");
}
#[test]
fn cruxi_error_equality() {
assert_eq!(CruxiError::Unauthorized, CruxiError::Unauthorized);
}
#[test]
fn cruxi_error_copy() {
let err1 = CruxiError::Unauthorized;
let err2 = err1;
assert_eq!(err1, err2);
}
#[test]
fn coded_error_debug() {
let err = CodedError::new("TEST")
.with_title("Title")
.with_reason("Reason")
.with_instance("inst-1");
let debug = format!("{:?}", err);
assert!(debug.contains("CodedError"));
assert!(debug.contains("TEST"));
assert!(debug.contains("Title"));
assert!(debug.contains("Reason"));
assert!(debug.contains("inst-1"));
}
#[test]
fn validation_error_debug() {
let err = ValidationError::new("field", "message");
let debug = format!("{:?}", err);
assert!(debug.contains("ValidationError"));
assert!(debug.contains("field"));
assert!(debug.contains("message"));
}
#[test]
fn cruxi_error_debug() {
let err = CruxiError::Unauthorized;
let debug = format!("{:?}", err);
assert!(debug.contains("Unauthorized"));
}
#[test]
fn coded_error_builder_chain_order_independent() {
let err1 = CodedError::new("TEST")
.with_title("Title")
.with_reason("Reason")
.with_instance("inst");
let err2 = CodedError::new("TEST")
.with_instance("inst")
.with_reason("Reason")
.with_title("Title");
assert_eq!(err1.code(), err2.code());
assert_eq!(err1.title(), err2.title());
assert_eq!(err1.reason(), err2.reason());
assert_eq!(err1.instance(), err2.instance());
}
#[test]
fn coded_error_overwrite_fields() {
let err = CodedError::new("TEST")
.with_title("First Title")
.with_title("Second Title");
assert_eq!(err.title(), Some("Second Title"));
}