1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
use crate::error::ProgramInternalExecuteError;
/// Represents error types that occur in a chained processing pipeline.
///
/// This enum is used to uniformly encapsulate various exceptions that may
/// occur during the execution of an entire chain, including IO errors and
/// other custom error messages.
#[derive(Debug)]
pub enum ChainProcessError {
/// Other unclassified generic errors, stored as a string description.
Other(String),
/// Errors resulting from a failed IO operation, holding the standard library's [`std::io::Error`]
IO(std::io::Error),
}
impl std::fmt::Display for ChainProcessError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Other(s) => write!(f, "Other error: {s}"),
Self::IO(e) => write!(f, "IO error: {e}"),
}
}
}
impl std::error::Error for ChainProcessError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::IO(e) => Some(e),
Self::Other(_) => None,
}
}
}
impl From<std::io::Error> for ChainProcessError {
fn from(e: std::io::Error) -> Self {
Self::IO(e)
}
}
impl From<ProgramInternalExecuteError> for ChainProcessError {
fn from(value: ProgramInternalExecuteError) -> Self {
match value {
ProgramInternalExecuteError::DispatcherNotFound => {
Self::Other("DispatcherNotFound".into())
}
ProgramInternalExecuteError::RendererNotFound(r) => {
Self::Other(format!("RendererNotFound: {r}"))
}
ProgramInternalExecuteError::Other(e) => Self::Other(e),
ProgramInternalExecuteError::IO(e) => Self::Other(format!("IOError: {e:?}")),
ProgramInternalExecuteError::REPLPanic(program_panic) => {
Self::Other(format!("REPLPanic: {program_panic}"))
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::error::{ProgramInternalExecuteError, ProgramPanic};
use std::error::Error;
#[test]
fn test_chain_process_error_display_other() {
let err = ChainProcessError::Other("something went wrong".into());
assert_eq!(format!("{err}"), "Other error: something went wrong");
}
#[test]
fn test_chain_process_error_display_io() {
let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
let err = ChainProcessError::IO(io_err);
let display = format!("{err}");
assert!(display.contains("IO error"));
assert!(display.contains("file not found"));
}
#[test]
fn test_chain_process_error_source_io() {
let io_err = std::io::Error::new(std::io::ErrorKind::PermissionDenied, "denied");
let err = ChainProcessError::IO(io_err);
assert!(err.source().is_some());
}
#[test]
fn test_chain_process_error_source_other() {
let err = ChainProcessError::Other("msg".into());
assert!(err.source().is_none());
}
#[test]
fn test_from_io_error_into_chain_process_error() {
let io_err = std::io::Error::new(std::io::ErrorKind::TimedOut, "timeout");
let err: ChainProcessError = io_err.into();
assert!(matches!(err, ChainProcessError::IO(_)));
}
#[test]
fn test_from_program_internal_execute_error_dispatcher_not_found() {
let internal = ProgramInternalExecuteError::DispatcherNotFound;
let err: ChainProcessError = internal.into();
assert!(matches!(err, ChainProcessError::Other(_)));
assert_eq!(format!("{err}"), "Other error: DispatcherNotFound");
}
#[test]
fn test_from_program_internal_execute_error_renderer_not_found() {
let internal = ProgramInternalExecuteError::RendererNotFound("json".into());
let err: ChainProcessError = internal.into();
assert_eq!(format!("{err}"), "Other error: RendererNotFound: json");
}
#[test]
fn test_from_program_internal_execute_error_other() {
let internal = ProgramInternalExecuteError::Other("custom error".into());
let err: ChainProcessError = internal.into();
assert_eq!(format!("{err}"), "Other error: custom error");
}
#[test]
fn test_from_program_internal_execute_error_io() {
let io_err = std::io::Error::new(std::io::ErrorKind::ConnectionRefused, "refused");
let internal = ProgramInternalExecuteError::IO(io_err);
let err: ChainProcessError = internal.into();
let display = format!("{err}");
assert!(display.contains("IOError"));
}
#[test]
fn test_from_program_internal_execute_error_repl_panic() {
let panic_payload = ProgramPanic {
payload: Box::new("repl crash"),
};
let internal = ProgramInternalExecuteError::REPLPanic(panic_payload);
let err: ChainProcessError = internal.into();
assert!(format!("{err}").contains("REPLPanic"));
}
}
|