1use std::path::PathBuf;
2
3use fluent_i18n::t;
4use winnow::error::{ContextError, ParseError};
5
6use crate::Architecture;
7
8#[derive(Debug, thiserror::Error, PartialEq)]
18pub enum Error {
19 #[error("{msg}", msg = t!("error-invalid-architectures", {
21 "architectures" => format!("{architectures:?}"),
22 "context" => context
23 }))]
24 InvalidArchitectures {
25 architectures: Vec<Architecture>,
27 context: &'static str,
29 },
30
31 #[error("{msg}", msg = t!("error-invalid-integer", { "kind" => format!("{kind:?}") }))]
33 InvalidInteger {
34 kind: std::num::IntErrorKind,
36 },
37
38 #[error("{msg}", msg = t!("error-invalid-variant", { "error" => .0.to_string() }))]
40 InvalidVariant(#[from] strum::ParseError),
41
42 #[error("{msg}", msg = t!("error-invalid-email", { "error" => .0.to_string() }))]
44 InvalidEmail(#[from] email_address::Error),
45
46 #[error("{msg}", msg = t!("error-invalid-url", { "error" => .0.to_string() }))]
48 InvalidUrl(#[from] url::ParseError),
49
50 #[error("{msg}", msg = t!("error-invalid-license", { "error" => .0.to_string() }))]
52 InvalidLicense(#[from] spdx::ParseError),
53
54 #[error("{msg}", msg = t!("error-invalid-semver", { "kind" => kind }))]
62 InvalidSemver {
63 kind: String,
65 },
66
67 #[error("{msg}", msg = t!("error-invalid-chars", { "invalid_char" => invalid_char.to_string() }))]
69 ValueContainsInvalidChars {
70 invalid_char: char,
72 },
73
74 #[error("{msg}", msg = t!("error-incorrect-length", { "length" => length, "expected" => expected }))]
76 IncorrectLength {
77 length: usize,
79 expected: usize,
81 },
82
83 #[error("{msg}", msg = t!("error-delimiter-not-found", { "delimiter" => delimiter.to_string() }))]
85 DelimiterNotFound {
86 delimiter: char,
88 },
89
90 #[error("{msg}", msg = t!("error-restrictions-not-met", {
92 "restrictions" => format!("{restrictions:?}")
93 }))]
94 ValueDoesNotMatchRestrictions {
95 restrictions: Vec<String>,
97 },
98
99 #[error("{msg}", msg = t!("error-regex-mismatch", {
101 "value" => value,
102 "regex_type" => regex_type,
103 "regex" => regex
104 }))]
105 RegexDoesNotMatch {
106 value: String,
108 regex_type: String,
110 regex: String,
112 },
113
114 #[error("{msg}", msg = t!("error-parse", { "error" => .0 }))]
116 ParseError(String),
117
118 #[error("{msg}", msg = t!("error-missing-component", { "component" => component }))]
120 MissingComponent {
121 component: &'static str,
123 },
124
125 #[error("{msg}", msg = t!("error-path-not-absolute", { "path" => .0 }))]
127 PathNotAbsolute(PathBuf),
128
129 #[error("{msg}", msg = t!("error-path-not-relative", { "path" => .0 }))]
131 PathNotRelative(PathBuf),
132
133 #[error("{msg}", msg = t!("error-path-not-file", { "path" => .0 }))]
135 PathIsNotAFile(PathBuf),
136
137 #[error("{msg}", msg = t!("error-filename-invalid-chars", {
139 "path" => .0,
140 "invalid_char" => .1.to_string()
141 }))]
142 FileNameContainsInvalidChars(PathBuf, char),
143
144 #[error("{msg}", msg = t!("error-filename-empty"))]
146 FileNameIsEmpty,
147
148 #[error("{msg}", msg = t!("error-deprecated-license", { "license" => .0 }))]
150 DeprecatedLicense(String),
151
152 #[error("{msg}", msg = t!("error-invalid-component", {
154 "component" => component,
155 "context" => context
156 }))]
157 InvalidComponent {
158 component: &'static str,
160 context: String,
165 },
166
167 #[error("{msg}", msg = t!("error-invalid-pgp-fingerprint"))]
169 InvalidOpenPGPv4Fingerprint,
170
171 #[error("{msg}", msg = t!("error-invalid-pgp-keyid", { "keyid" => .0 }))]
173 InvalidOpenPGPKeyId(String),
174
175 #[error("{msg}", msg = t!("error-invalid-base64-encoding", { "expected_item" => expected_item }))]
177 InvalidBase64Encoding {
178 expected_item: String,
180 },
181
182 #[error("{msg}", msg = t!("error-invalid-soname-v1", { "name" => .0 }))]
184 InvalidSonameV1(&'static str),
185
186 #[error("{msg}", msg = t!("error-package", { "error" => .0.to_string() }))]
188 Package(#[from] crate::PackageError),
189
190 #[error("{msg}", msg = t!("error-unknown-compression", { "value" => value }))]
192 UnknownCompressionAlgorithmFileExtension {
193 value: String,
195 },
196
197 #[error("{msg}", msg = t!("error-unknown-filetype", { "value" => value }))]
199 UnknownFileTypeIdentifier {
200 value: String,
202 },
203}
204
205impl From<std::num::ParseIntError> for crate::error::Error {
206 fn from(e: std::num::ParseIntError) -> Self {
208 Self::InvalidInteger { kind: *e.kind() }
209 }
210}
211
212impl<'a> From<ParseError<&'a str, ContextError>> for crate::error::Error {
213 fn from(value: ParseError<&'a str, ContextError>) -> Self {
215 Self::ParseError(value.to_string())
216 }
217}
218
219#[cfg(test)]
220mod tests {
221 use std::num::IntErrorKind;
222
223 use rstest::rstest;
224
225 use super::*;
226
227 #[rstest]
228 #[case(
229 "Invalid integer (caused by InvalidDigit)",
230 Error::InvalidInteger {
231 kind: IntErrorKind::InvalidDigit
232 }
233 )]
234 #[case(
235 "Invalid integer (caused by InvalidDigit)",
236 Error::InvalidInteger {
237 kind: IntErrorKind::InvalidDigit
238 }
239 )]
240 #[case(
241 "Invalid integer (caused by PosOverflow)",
242 Error::InvalidInteger {
243 kind: IntErrorKind::PosOverflow
244 }
245 )]
246 #[allow(deprecated)]
247 #[case(
248 "Invalid integer (caused by InvalidDigit)",
249 Error::InvalidInteger {
250 kind: IntErrorKind::InvalidDigit
251 }
252 )]
253 #[case(
254 "Invalid e-mail (Missing separator character '@'.)",
255 email_address::Error::MissingSeparator.into()
256 )]
257 #[case(
258 "Invalid integer (caused by InvalidDigit)",
259 Error::InvalidInteger {
260 kind: IntErrorKind::InvalidDigit
261 }
262 )]
263 fn error_format_string(#[case] error_str: &str, #[case] error: Error) {
264 assert_eq!(error_str, format!("{error}"));
265 }
266}