1#[derive(Debug)]
7pub enum RepositoryError {
8 InvalidFormat,
10 InvalidUri,
12 MissingUri,
14 InvalidType,
16 InvalidSignature,
18 YesNoForceFieldInvalid,
20 YesNoFieldInvalid,
22 UnrecognizedFieldName(String),
24 Lossy(deb822_fast::Error),
26 Io(std::io::Error),
28 Url(url::ParseError),
30}
31
32#[derive(Debug)]
34pub enum LoadError {
35 Io {
37 path: std::path::PathBuf,
39 error: std::io::Error,
41 },
42 Parse {
44 path: std::path::PathBuf,
46 error: String,
48 },
49 DirectoryRead {
51 path: std::path::PathBuf,
53 error: std::io::Error,
55 },
56 #[cfg(not(feature = "legacy"))]
57 UnsupportedLegacyFormat,
59}
60
61impl From<std::io::Error> for RepositoryError {
62 fn from(e: std::io::Error) -> Self {
63 Self::Io(e)
64 }
65}
66
67impl From<url::ParseError> for RepositoryError {
68 fn from(e: url::ParseError) -> Self {
69 Self::Url(e)
70 }
71}
72
73impl std::fmt::Display for RepositoryError {
74 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
75 const YNFERRMSG: &str = "The field requiring only `Yes`/`No`/`Force` values is incorrect";
77 const YNERRMSG: &str = "The field requiring only `Yes`/`No` values is incorrect";
78 match self {
79 Self::InvalidFormat => write!(f, "Invalid repository format"),
80 Self::InvalidUri => write!(f, "Invalid repository URI"),
81 Self::MissingUri => write!(f, "Missing repository URI"),
82 Self::InvalidType => write!(f, "Invalid repository type"),
83 Self::InvalidSignature => write!(f, "The field `Signed-By` is incorrect"),
84 Self::YesNoForceFieldInvalid => f.write_str(YNFERRMSG),
85 Self::YesNoFieldInvalid => f.write_str(YNERRMSG),
86 Self::UnrecognizedFieldName(name) => write!(
87 f,
88 "Unrecognized field name: {name} (check `man sources.list`)"
89 ),
90 Self::Lossy(e) => write!(f, "Lossy parser error: {e}"),
91 Self::Io(e) => write!(f, "IO error: {e}"),
92 Self::Url(e) => write!(f, "URL parse error: {e}"),
93 }
94 }
95}
96
97impl std::fmt::Display for LoadError {
98 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
99 match self {
100 Self::Io { path, error } => write!(f, "Failed to read {}: {}", path.display(), error),
101 Self::Parse { path, error } => {
102 write!(f, "Failed to parse {}: {}", path.display(), error)
103 }
104 Self::DirectoryRead { path, error } => {
105 write!(f, "Failed to read directory {}: {}", path.display(), error)
106 }
107 #[cfg(not(feature = "legacy"))]
108 Self::UnsupportedLegacyFormat => {
109 write!(
110 f,
111 "The support for `legacy` format hadn't been enabled at build time"
112 )
113 }
114 }
115 }
116}
117
118impl std::error::Error for RepositoryError {}
119impl std::error::Error for LoadError {}
120
121#[cfg(test)]
122mod tests {
123 use super::*;
124
125 #[test]
126 fn test_repository_error_display() {
127 assert_eq!(
129 RepositoryError::InvalidFormat.to_string(),
130 "Invalid repository format"
131 );
132 assert_eq!(
133 RepositoryError::InvalidUri.to_string(),
134 "Invalid repository URI"
135 );
136 assert_eq!(
137 RepositoryError::MissingUri.to_string(),
138 "Missing repository URI"
139 );
140 assert_eq!(
141 RepositoryError::InvalidType.to_string(),
142 "Invalid repository type"
143 );
144 assert_eq!(
145 RepositoryError::InvalidSignature.to_string(),
146 "The field `Signed-By` is incorrect"
147 );
148
149 assert_eq!(
151 RepositoryError::UnrecognizedFieldName("foo-bar".to_string()).to_string(),
152 "Unrecognized field name: foo-bar (check `man sources.list`)"
153 );
154
155 let lossy_err = deb822_fast::Error::UnexpectedEof;
157 let repo_err = RepositoryError::Lossy(lossy_err);
158 assert!(repo_err.to_string().contains("Lossy parser error:"));
159
160 let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
162 let repo_err = RepositoryError::from(io_err);
163 assert!(repo_err.to_string().contains("IO error:"));
164 }
165
166 #[test]
167 fn test_load_error_display() {
168 use std::path::PathBuf;
169
170 let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
172 let load_err = LoadError::Io {
173 path: PathBuf::from("/test/path"),
174 error: io_err,
175 };
176 assert!(load_err.to_string().contains("Failed to read /test/path"));
177 assert!(load_err.to_string().contains("file not found"));
178
179 let parse_err = LoadError::Parse {
181 path: PathBuf::from("/test/file.list"),
182 error: "Invalid format".to_string(),
183 };
184 assert!(parse_err
185 .to_string()
186 .contains("Failed to parse /test/file.list"));
187 assert!(parse_err.to_string().contains("Invalid format"));
188
189 let dir_err = std::io::Error::new(std::io::ErrorKind::PermissionDenied, "access denied");
191 let load_err = LoadError::DirectoryRead {
192 path: PathBuf::from("/test/dir"),
193 error: dir_err,
194 };
195 assert!(load_err
196 .to_string()
197 .contains("Failed to read directory /test/dir"));
198 assert!(load_err.to_string().contains("access denied"));
199 }
200}