use prodigy::error::ProdigyError;
use std::path::PathBuf;
#[test]
fn test_context_chain_preservation() {
let result = simulate_layered_operation();
assert!(result.is_err());
let error = result.unwrap_err();
let dev_message = error.developer_message();
assert!(
dev_message.contains("Failed to process workflow"),
"Missing top-level context"
);
assert!(
dev_message.contains("Failed to read configuration"),
"Missing mid-level context"
);
assert!(
dev_message.contains("File operation failed"),
"Missing bottom-level context"
);
}
#[test]
fn test_context_with_location() {
let error = create_error_with_location();
let dev_message = error.developer_message();
assert!(
dev_message.contains("error_context_preservation_test.rs"),
"Missing file location in context"
);
}
#[test]
fn test_user_vs_developer_messages() {
let error = simulate_storage_error();
let user_message = error.user_message();
let dev_message = error.developer_message();
assert!(
user_message.len() < 200,
"User message too verbose: {}",
user_message
);
assert!(
dev_message.len() > user_message.len(),
"Developer message should be more detailed than user message"
);
assert!(
dev_message.contains("Context:") || dev_message.contains("Checkpoint operation failed"),
"Developer message missing context section. Got: {}",
dev_message
);
}
#[test]
fn test_context_in_batch_operations() {
let items = vec!["item1", "item2", "item3"];
let result = process_items_with_context(items);
assert!(result.is_err());
let error = result.unwrap_err();
let dev_message = error.developer_message();
assert!(
dev_message.contains("item2"),
"Missing item-specific context in batch operation"
);
assert!(
dev_message.contains("Failed to process batch"),
"Missing batch-level context"
);
}
#[test]
fn test_serialization_preserves_context() {
use prodigy::error::SerializableError;
let error = simulate_layered_operation().unwrap_err();
let serializable = SerializableError::from(&error);
assert!(
!serializable.context.is_empty(),
"Context not preserved in serialization"
);
assert!(
serializable.context.len() >= 2,
"Expected multiple context entries, got {}",
serializable.context.len()
);
let json = serde_json::to_string(&serializable).expect("Failed to serialize to JSON");
assert!(json.contains("context"), "JSON missing context");
}
#[test]
fn test_anyhow_conversion_preserves_context() {
let prodigy_error = simulate_layered_operation().unwrap_err();
let anyhow_error: anyhow::Error = prodigy_error.into();
let error_string = anyhow_error.to_string();
assert!(
!error_string.is_empty(),
"Error message lost in anyhow conversion"
);
}
#[test]
fn test_from_conversion_with_context() {
let io_error = std::io::Error::new(std::io::ErrorKind::NotFound, "test.txt not found");
let prodigy_error = ProdigyError::from(io_error).context("Failed to open configuration file");
let dev_message = prodigy_error.developer_message();
assert!(
dev_message.contains("Failed to open configuration file"),
"Missing context in: {}",
dev_message
);
}
#[allow(clippy::result_large_err)]
fn simulate_layered_operation() -> Result<(), ProdigyError> {
let _ = read_config_file().map_err(|e| e.context("Failed to process workflow"))?;
Ok(())
}
#[allow(clippy::result_large_err)]
fn read_config_file() -> Result<String, ProdigyError> {
perform_file_operation().map_err(|e| e.context("Failed to read configuration"))?;
Ok("config".to_string())
}
#[allow(clippy::result_large_err)]
fn perform_file_operation() -> Result<(), ProdigyError> {
Err(ProdigyError::storage("File operation failed"))
}
fn create_error_with_location() -> ProdigyError {
ProdigyError::execution("Test error").with_context(format!(
"Operation context at {}:{}",
file!(),
line!()
))
}
fn simulate_storage_error() -> ProdigyError {
use prodigy::error::ErrorCode;
let base_error = ProdigyError::storage_with_code(
ErrorCode::STORAGE_IO_ERROR,
"Failed to write checkpoint",
Some(PathBuf::from("/tmp/checkpoint.json")),
);
base_error
.context("Failed to persist workflow state")
.context("Checkpoint operation failed")
}
#[allow(clippy::result_large_err)]
fn process_items_with_context(items: Vec<&str>) -> Result<Vec<String>, ProdigyError> {
items
.iter()
.map(|item| {
if *item == "item2" {
Err(ProdigyError::validation("Invalid item")
.with_context(format!("Failed to process {}", item)))
} else {
Ok(item.to_string())
}
})
.collect::<Result<Vec<_>, _>>()
.map_err(|e| e.context("Failed to process batch"))
}