use thiserror::Error;
#[derive(Debug, Error)]
pub enum CargoFreshError {
#[error("`cargo install --list` failed: {source}")]
CargoListFailed {
#[source]
source: anyhow::Error,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Hint {
CargoListFailed,
NetworkConnectTimeout,
InvalidGlob,
}
impl Hint {
pub fn locale_key(self) -> &'static str {
match self {
Hint::CargoListFailed => "hint_cargo_list_failed",
Hint::NetworkConnectTimeout => "hint_network_connect_timeout",
Hint::InvalidGlob => "hint_invalid_glob",
}
}
}
pub fn hint_for(err: &anyhow::Error) -> Option<Hint> {
for cause in err.chain() {
if cause.downcast_ref::<CargoFreshError>().is_some() {
return Some(Hint::CargoListFailed);
}
if let Some(re) = cause.downcast_ref::<reqwest::Error>() {
if re.is_connect() || re.is_timeout() {
return Some(Hint::NetworkConnectTimeout);
}
}
if cause.downcast_ref::<globset::Error>().is_some() {
return Some(Hint::InvalidGlob);
}
}
None
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn hint_for_cargo_list_failed() {
let err: anyhow::Error = CargoFreshError::CargoListFailed {
source: anyhow::anyhow!("exit code 101"),
}
.into();
assert_eq!(hint_for(&err), Some(Hint::CargoListFailed));
}
#[test]
fn hint_for_wrapped_cargo_fresh_error() {
let err = anyhow::Error::from(CargoFreshError::CargoListFailed {
source: anyhow::anyhow!("exit code 101"),
})
.context("while listing installed packages");
assert_eq!(hint_for(&err), Some(Hint::CargoListFailed));
}
#[test]
fn hint_for_unrelated_error_returns_none() {
let err = anyhow::anyhow!("something else entirely");
assert!(hint_for(&err).is_none());
}
#[test]
fn hint_for_invalid_glob() {
let mut packages = Vec::new();
let err = crate::package::filter_packages(&mut packages, "[unclosed")
.expect_err("unclosed bracket should be an invalid glob");
assert_eq!(hint_for(&err), Some(Hint::InvalidGlob));
}
#[test]
fn every_hint_has_bilingual_text() {
use crate::locale::texts::{get_chinese_text, get_english_text};
for hint in [
Hint::CargoListFailed,
Hint::NetworkConnectTimeout,
Hint::InvalidGlob,
] {
let key = hint.locale_key();
assert!(!get_english_text(key).is_empty(), "missing EN for {key}");
assert!(!get_chinese_text(key).is_empty(), "missing ZH for {key}");
}
}
}