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