aboutsummaryrefslogtreecommitdiff
path: root/mingling_core/src/asset/chain/error.rs
blob: ad641952f030d6c79c1a9c866360c87f7e37e37b (plain) (blame)
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
use crate::error::ProgramInternalExecuteError;

/// Represents errors that can occur during chain processing.
#[derive(Debug)]
pub enum ChainProcessError {
    /// An error with a custom description.
    Other(String),

    /// An I/O error that occurred during chain processing.
    IO(std::io::Error),
}

impl std::fmt::Display for ChainProcessError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            ChainProcessError::Other(s) => write!(f, "Other error: {s}"),
            ChainProcessError::IO(e) => write!(f, "IO error: {e}"),
        }
    }
}

impl std::error::Error for ChainProcessError {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        match self {
            ChainProcessError::IO(e) => Some(e),
            ChainProcessError::Other(_) => None,
        }
    }
}

impl From<std::io::Error> for ChainProcessError {
    fn from(e: std::io::Error) -> Self {
        ChainProcessError::IO(e)
    }
}

impl From<ProgramInternalExecuteError> for ChainProcessError {
    fn from(value: ProgramInternalExecuteError) -> Self {
        match value {
            ProgramInternalExecuteError::DispatcherNotFound => {
                ChainProcessError::Other("DispatcherNotFound".into())
            }
            ProgramInternalExecuteError::RendererNotFound(r) => {
                ChainProcessError::Other(format!("RendererNotFound: {r}"))
            }
            ProgramInternalExecuteError::Other(e) => ChainProcessError::Other(e),
            ProgramInternalExecuteError::IO(e) => {
                ChainProcessError::Other(format!("IOError: {e:?}"))
            }
            ProgramInternalExecuteError::REPLPanic(program_panic) => {
                ChainProcessError::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"));
    }
}