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 Fn(conversions::Error) -> Self {
107        let path = path.into();
108        move |cause| Self::Conversion {
109            path: path.clone(),
110            cause,
111        }
112    }
113    pub fn openapi<A: Into<PathBuf>>(path: A) -> impl Fn(openapi_types::Error) -> Self {
114        let path = path.into();
115        move |cause| Self::OpenApiTypes {
116            path: path.clone(),
117            cause,
118        }
119    }
120    pub fn dump(&self) -> String {
121        self.detail(ErrorTheme::Test)
122    }
123}
124
125#[derive(Copy, Clone)]
126pub enum ErrorTheme {
127    Test,
128    Overwrite,
129}
130
131pub struct DiffStyle {
132    src_lines: StyledObject<&'static str>,
133    dst_lines: StyledObject<&'static str>,
134}
135
136impl ErrorTheme {
137    pub fn diff_style(&self) -> DiffStyle {
138        match self {
139            ErrorTheme::Test => DiffStyle {
140                src_lines: Style::new().red().apply_to("- actual"),
141                dst_lines: Style::new().green().apply_to("+ expected"),
142            },
143            ErrorTheme::Overwrite => DiffStyle {
144                src_lines: Style::new().red().apply_to("- current"),
145                dst_lines: Style::new().green().apply_to("+ modified"),
146            },
147        }
148    }
149}