gesha_core/
error.rs

1use crate::conversions;
2use console::{Style, StyledObject};
3use std::path::PathBuf;
4use tokio::task::JoinError;
5
6pub type Result<A> = std::result::Result<A, Error>;
7
8pub type Output<A> = openapi_types::core::Output<A, Error>;
9
10#[derive(Debug)]
11pub enum Error {
12    UnknownTestCase {
13        path: String,
14    },
15
16    // inherited errors
17    OpenApiTypes {
18        path: PathBuf,
19        cause: openapi_types::Error,
20    },
21    Conversion {
22        path: PathBuf,
23        cause: conversions::Error,
24    },
25
26    // thread errors
27    JoinError {
28        schema_path: PathBuf,
29        cause: JoinError,
30    },
31
32    // module errors
33    DiffDetected {
34        output: String,
35        actual: PathBuf,
36        expected: PathBuf,
37    },
38    FormatFailed {
39        path: PathBuf,
40        detail: String,
41    },
42    CannotCreateFile {
43        path: PathBuf,
44        detail: String,
45    },
46    CannotReadFile {
47        path: PathBuf,
48        detail: String,
49    },
50    CannotCopyFile {
51        from: PathBuf,
52        to: PathBuf,
53        detail: String,
54    },
55    CannotRender {
56        path: PathBuf,
57        detail: String,
58    },
59    Errors(Vec<Self>),
60    ThreadNotFound(String),
61    UnsupportedExampleLocation(String),
62}
63
64impl Error {
65    pub fn detail(&self, theme: ErrorTheme) -> String {
66        match self {
67            Error::DiffDetected {
68                output,
69                actual,
70                expected,
71            } => {
72                let style = theme.diff_style();
73                format!(
74                    "\n {: <10} : {}\n {} : {}\n\n{}",
75                    style.src_lines,
76                    actual.to_string_lossy(),
77                    style.dst_lines,
78                    expected.to_string_lossy(),
79                    output
80                )
81            }
82            Error::FormatFailed { detail, .. } => {
83                format!("rustfmt>\n{}", detail)
84            }
85            Error::Conversion {
86                path,
87                cause: conversions::Error::TransformBroken { detail },
88            } => {
89                format!(
90                    "internal error: transform broken.\n{}\n{}",
91                    path.display(),
92                    detail,
93                )
94            }
95            Error::Errors(errors) => errors
96                .iter()
97                .map(|e| e.detail(theme))
98                .collect::<Vec<_>>()
99                .join("\n"),
100
101            _ => {
102                format!("{:#?}", self)
103            }
104        }
105    }
106    pub fn conversion<A: Into<PathBuf>>(path: A) -> impl FnOnce(conversions::Error) -> Self {
107        |cause| Self::Conversion {
108            path: path.into(),
109            cause,
110        }
111    }
112    pub fn openapi<A: Into<PathBuf>>(path: A) -> impl FnOnce(openapi_types::Error) -> Self {
113        |cause| Self::OpenApiTypes {
114            path: path.into(),
115            cause,
116        }
117    }
118    pub fn dump(&self) -> String {
119        self.detail(ErrorTheme::Test)
120    }
121}
122
123#[derive(Copy, Clone)]
124pub enum ErrorTheme {
125    Test,
126    Overwrite,
127}
128
129pub struct DiffStyle {
130    src_lines: StyledObject<&'static str>,
131    dst_lines: StyledObject<&'static str>,
132}
133
134impl ErrorTheme {
135    pub fn diff_style(&self) -> DiffStyle {
136        match self {
137            ErrorTheme::Test => DiffStyle {
138                src_lines: Style::new().red().apply_to("- actual"),
139                dst_lines: Style::new().green().apply_to("+ expected"),
140            },
141            ErrorTheme::Overwrite => DiffStyle {
142                src_lines: Style::new().red().apply_to("- current"),
143                dst_lines: Style::new().green().apply_to("+ modified"),
144            },
145        }
146    }
147}