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 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}