1use std::path::PathBuf;
2
3#[derive(Debug, thiserror::Error, PartialEq)]
13pub enum Error {
14 #[error("Invalid integer (caused by {kind:?})")]
16 InvalidInteger {
17 kind: std::num::IntErrorKind,
19 },
20
21 #[error("Invalid variant ({0})")]
23 InvalidVariant(#[from] strum::ParseError),
24
25 #[error("Invalid e-mail ({0})")]
27 InvalidEmail(#[from] email_address::Error),
28
29 #[error("Invalid URL ({0})")]
31 InvalidUrl(#[from] url::ParseError),
32
33 #[error("Invalid license ({0})")]
35 InvalidLicense(#[from] spdx::ParseError),
36
37 #[error("Invalid semver ({kind})")]
45 InvalidSemver {
46 kind: String,
48 },
49
50 #[error("Value contains invalid characters: {invalid_char:?}")]
52 ValueContainsInvalidChars {
53 invalid_char: char,
55 },
56
57 #[error("Incorrect length, got {length} expected {expected}")]
59 IncorrectLength {
60 length: usize,
62 expected: usize,
64 },
65
66 #[error("Value is missing the required delimiter: {delimiter}")]
68 DelimiterNotFound {
69 delimiter: char,
71 },
72
73 #[error("Does not match the restrictions ({restrictions:?})")]
75 ValueDoesNotMatchRestrictions {
76 restrictions: Vec<String>,
78 },
79
80 #[error("Value '{value}' does not match the '{regex_type}' regex: {regex}")]
82 RegexDoesNotMatch {
83 value: String,
85 regex_type: String,
87 regex: String,
89 },
90
91 #[error("Parser failed with the following error:\n{0}")]
93 ParseError(String),
94
95 #[error("Missing component: {component}")]
97 MissingComponent {
98 component: &'static str,
100 },
101
102 #[error("The path is not absolute: {0}")]
104 PathNotAbsolute(PathBuf),
105
106 #[error("The path is not relative: {0}")]
108 PathNotRelative(PathBuf),
109
110 #[error("File name ({0}) contains invalid characters: {1:?}")]
112 FileNameContainsInvalidChars(PathBuf, char),
113
114 #[error("File name is empty")]
116 FileNameIsEmpty,
117
118 #[error("Deprecated license: {0}")]
120 DeprecatedLicense(String),
121
122 #[error("Invalid component {component} encountered while {context}")]
124 InvalidComponent {
125 component: &'static str,
127 context: &'static str,
132 },
133
134 #[error("Invalid OpenPGP v4 fingerprint, only 40 uppercase hexadecimal characters are allowed")]
136 InvalidOpenPGPv4Fingerprint,
137
138 #[error("The string is not a valid OpenPGP key ID: {0}, must be 16 hexadecimal characters")]
140 InvalidOpenPGPKeyId(String),
141
142 #[error("Invalid shared object name (v1): {0}")]
144 InvalidSonameV1(&'static str),
145
146 #[error("Package error: {0}")]
148 Package(#[from] crate::PackageError),
149
150 #[error("Unknown compression algorithm file extension: {value:?}")]
152 UnknownCompressionAlgorithmFileExtension {
153 value: String,
155 },
156
157 #[error("Unknown file type identifier: {value:?}")]
159 UnknownFileTypeIdentifier {
160 value: String,
162 },
163}
164
165impl From<std::num::ParseIntError> for crate::error::Error {
166 fn from(e: std::num::ParseIntError) -> Self {
168 Self::InvalidInteger {
169 kind: e.kind().clone(),
170 }
171 }
172}
173
174impl<'a> From<winnow::error::ParseError<&'a str, winnow::error::ContextError>>
175 for crate::error::Error
176{
177 fn from(value: winnow::error::ParseError<&'a str, winnow::error::ContextError>) -> Self {
179 Self::ParseError(value.to_string())
180 }
181}
182
183#[cfg(test)]
184mod tests {
185 use std::num::IntErrorKind;
186
187 use rstest::rstest;
188
189 use super::*;
190
191 #[rstest]
192 #[case(
193 "Invalid integer (caused by InvalidDigit)",
194 Error::InvalidInteger {
195 kind: IntErrorKind::InvalidDigit
196 }
197 )]
198 #[case(
199 "Invalid integer (caused by InvalidDigit)",
200 Error::InvalidInteger {
201 kind: IntErrorKind::InvalidDigit
202 }
203 )]
204 #[case(
205 "Invalid integer (caused by PosOverflow)",
206 Error::InvalidInteger {
207 kind: IntErrorKind::PosOverflow
208 }
209 )]
210 #[allow(deprecated)]
211 #[case(
212 "Invalid integer (caused by InvalidDigit)",
213 Error::InvalidInteger {
214 kind: IntErrorKind::InvalidDigit
215 }
216 )]
217 #[case(
218 "Invalid e-mail (Missing separator character '@'.)",
219 email_address::Error::MissingSeparator.into()
220 )]
221 #[case(
222 "Invalid integer (caused by InvalidDigit)",
223 Error::InvalidInteger {
224 kind: IntErrorKind::InvalidDigit
225 }
226 )]
227 fn error_format_string(#[case] error_str: &str, #[case] error: Error) {
228 assert_eq!(error_str, format!("{error}"));
229 }
230}