use std::io;
use thiserror::Error;
pub type Result<T> = std::result::Result<T, TermTestError>;
#[derive(Debug, Error)]
pub enum TermTestError {
#[error("PTY error: {0}")]
Pty(String),
#[error("I/O error: {0}")]
Io(#[from] io::Error),
#[error("Timeout waiting for condition after {timeout_ms}ms")]
Timeout {
timeout_ms: u64,
},
#[error("Parse error: {0}")]
Parse(String),
#[cfg(feature = "snapshot-insta")]
#[error("Snapshot mismatch: {0}")]
SnapshotMismatch(String),
#[cfg(feature = "sixel")]
#[error("Sixel validation failed: {0}")]
SixelValidation(String),
#[error("Failed to spawn process: {0}")]
SpawnFailed(String),
#[error("Process is already running")]
ProcessAlreadyRunning,
#[error("No process is running")]
NoProcessRunning,
#[error("Invalid terminal dimensions: width={width}, height={height}")]
InvalidDimensions {
width: u16,
height: u16,
},
#[cfg(feature = "bevy")]
#[error("Bevy error: {0}")]
Bevy(String),
}
impl From<anyhow::Error> for TermTestError {
fn from(err: anyhow::Error) -> Self {
TermTestError::Pty(err.to_string())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_io_error_conversion() {
let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "test error");
let term_err: TermTestError = io_err.into();
assert!(matches!(term_err, TermTestError::Io(_)));
assert!(term_err.to_string().contains("test error"));
}
#[test]
fn test_timeout_error_message() {
let err = TermTestError::Timeout { timeout_ms: 5000 };
let msg = err.to_string();
assert!(msg.contains("5000"));
assert!(msg.contains("Timeout"));
}
#[test]
fn test_invalid_dimensions_error() {
let err = TermTestError::InvalidDimensions {
width: 0,
height: 24,
};
let msg = err.to_string();
assert!(msg.contains("Invalid"));
assert!(msg.contains("width=0"));
assert!(msg.contains("height=24"));
}
#[test]
fn test_spawn_failed_error() {
let err = TermTestError::SpawnFailed("command not found".to_string());
let msg = err.to_string();
assert!(msg.contains("Failed to spawn"));
assert!(msg.contains("command not found"));
}
#[test]
fn test_process_already_running_error() {
let err = TermTestError::ProcessAlreadyRunning;
let msg = err.to_string();
assert!(msg.contains("already running"));
}
#[test]
fn test_no_process_running_error() {
let err = TermTestError::NoProcessRunning;
let msg = err.to_string();
assert!(msg.contains("No process"));
}
#[test]
fn test_anyhow_error_conversion() {
let anyhow_err = anyhow::anyhow!("test anyhow error");
let term_err: TermTestError = anyhow_err.into();
assert!(matches!(term_err, TermTestError::Pty(_)));
assert!(term_err.to_string().contains("test anyhow error"));
}
#[cfg(feature = "sixel")]
#[test]
fn test_sixel_validation_error() {
let err = TermTestError::SixelValidation("out of bounds".to_string());
let msg = err.to_string();
assert!(msg.contains("Sixel"));
assert!(msg.contains("out of bounds"));
}
}