const MAXIMUM_LENGTH: usize = 250;
const DEVICES: [&str; 4] = ["AUX", "CON", "NUL", "PRN"];
const NUMBERED_DEVICES: [&str; 2] = ["COM", "LPT"];
pub(super) fn is_portable(value: &str) -> bool {
let characters = !value.is_empty()
&& value.len() <= MAXIMUM_LENGTH
&& value
.bytes()
.all(|byte| byte.is_ascii_alphanumeric() || byte == b'-');
characters && !is_device(value)
}
fn is_device(value: &str) -> bool {
let value = value.to_ascii_uppercase();
if DEVICES.contains(&value.as_str()) {
return true;
}
NUMBERED_DEVICES.iter().any(|device| {
value.strip_prefix(device).is_some_and(|number| {
number.len() == 1 && number.bytes().all(|byte| byte.is_ascii_digit())
})
})
}
#[cfg(test)]
mod tests {
#![allow(clippy::missing_panics_doc)]
use super::*;
#[test]
fn is_portable_beyond_the_maximum_length_returns_false() {
assert!(!is_portable(&"a".repeat(251)));
}
#[test]
fn is_portable_with_a_backslash_returns_false() {
assert!(!is_portable(r"example\project"));
}
#[test]
fn is_portable_with_a_colon_returns_false() {
assert!(!is_portable("C:"));
}
#[test]
fn is_portable_with_a_device_in_lower_case_returns_false() {
assert!(!is_portable("nul"));
}
#[test]
fn is_portable_with_a_dot_returns_false() {
assert!(!is_portable("."));
}
#[test]
fn is_portable_with_a_hyphen_returns_true() {
assert!(is_portable("example-project"));
}
#[test]
fn is_portable_with_a_letter_after_the_prefix_of_a_device_returns_true() {
assert!(is_portable("LPTX"));
}
#[test]
fn is_portable_with_a_letter_outside_ascii_returns_false() {
assert!(!is_portable("café"));
}
#[test]
fn is_portable_with_a_numbered_device_in_mixed_case_returns_false() {
assert!(!is_portable("Com9"));
}
#[test]
fn is_portable_with_a_numbered_device_returns_false() {
assert!(!is_portable("LPT0"));
}
#[test]
fn is_portable_with_a_prefix_of_a_device_returns_true() {
assert!(is_portable("COM10"));
}
#[test]
fn is_portable_with_a_slash_returns_false() {
assert!(!is_portable("example/project"));
}
#[test]
fn is_portable_with_a_space_returns_false() {
assert!(!is_portable("example "));
}
#[test]
fn is_portable_with_a_word_that_starts_like_a_device_returns_true() {
assert!(is_portable("console"));
}
#[test]
fn is_portable_with_an_absolute_path_returns_false() {
assert!(!is_portable("/example"));
}
#[test]
fn is_portable_with_an_empty_value_returns_false() {
assert!(!is_portable(""));
}
#[test]
fn is_portable_with_an_underscore_returns_false() {
assert!(!is_portable("example_project"));
}
#[test]
fn is_portable_with_letters_and_digits_returns_true() {
assert!(is_portable("Example2"));
}
#[test]
fn is_portable_with_the_maximum_length_returns_true() {
assert!(is_portable(&"a".repeat(250)));
}
#[test]
fn is_portable_with_two_dots_returns_false() {
assert!(!is_portable(".."));
}
}