pub const UNKNOWN_VERSION: &str = "??";
pub trait VersionExt {
fn version_or_unknown(self) -> String;
}
impl VersionExt for &str {
#[inline]
fn version_or_unknown(self) -> String {
let trimmed = self.trim();
if trimmed.is_empty() {
UNKNOWN_VERSION.to_string()
} else {
trimmed.to_string()
}
}
}
impl VersionExt for Option<&str> {
#[inline]
fn version_or_unknown(self) -> String {
self.map(|s| s.trim())
.filter(|s| !s.is_empty())
.unwrap_or(UNKNOWN_VERSION)
.to_string()
}
}
impl VersionExt for Option<String> {
#[inline]
fn version_or_unknown(self) -> String {
self.as_deref().version_or_unknown()
}
}
#[inline]
pub fn normalize_version(output: Vec<u8>) -> String {
String::from_utf8(output)
.ok()
.as_deref()
.version_or_unknown()
}
#[inline]
pub fn is_broken_version(version: &str) -> bool {
let v = version.trim();
v == UNKNOWN_VERSION || v.is_empty()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_version_ext_trait() {
assert_eq!("1.2.3".version_or_unknown(), "1.2.3");
assert_eq!(" 1.2.3 ".version_or_unknown(), "1.2.3");
assert_eq!("".version_or_unknown(), UNKNOWN_VERSION);
assert_eq!(" ".version_or_unknown(), UNKNOWN_VERSION);
assert_eq!(Some("1.2.3").version_or_unknown(), "1.2.3");
assert_eq!(Some(" 1.2.3 ").version_or_unknown(), "1.2.3");
assert_eq!(Some("").version_or_unknown(), UNKNOWN_VERSION);
assert_eq!(None::<&str>.version_or_unknown(), UNKNOWN_VERSION);
assert_eq!(Some("1.2.3".to_string()).version_or_unknown(), "1.2.3");
assert_eq!(None::<String>.version_or_unknown(), UNKNOWN_VERSION);
}
#[test]
fn test_normalize_version() {
assert_eq!(normalize_version(b"1.2.3".to_vec()), "1.2.3");
assert_eq!(normalize_version(b" 1.2.3 ".to_vec()), "1.2.3");
assert_eq!(normalize_version(b"".to_vec()), UNKNOWN_VERSION);
assert_eq!(normalize_version(vec![0xFF, 0xFE]), UNKNOWN_VERSION); }
#[test]
fn test_is_broken_version() {
assert!(is_broken_version(UNKNOWN_VERSION));
assert!(is_broken_version(""));
assert!(is_broken_version(" "));
assert!(!is_broken_version("1.0.0"));
}
}