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 OpenApiTypes {
18 path: PathBuf,
19 cause: openapi_types::Error,
20 },
21 Conversion {
22 path: PathBuf,
23 cause: conversions::Error,
24 },
25
26 JoinError {
28 schema_path: PathBuf,
29 cause: JoinError,
30 },
31
32 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}