#[allow(unknown_lints, gts_id_hardcoded_prefix)]
pub const DEFAULT_GTS_ID_PREFIX: &str = "gts.";
pub const GTS_ID_PREFIX_ENV: &str = "GTS_ID_PREFIX";
pub const GTS_ID_PREFIX: &str = validate_gts_id_prefix(match option_env!("GTS_ID_PREFIX") {
Some(prefix) => prefix,
None => DEFAULT_GTS_ID_PREFIX,
});
#[allow(clippy::manual_is_ascii_check)]
const fn validate_gts_id_prefix(prefix: &str) -> &str {
let bytes = prefix.as_bytes();
assert!(!bytes.is_empty(), "GTS_ID_PREFIX must not be empty");
assert!(
bytes[bytes.len() - 1] == b'.',
"GTS_ID_PREFIX must end with '.'"
);
assert!(
bytes.len() != 1,
"GTS_ID_PREFIX must contain a token before the final dot"
);
let first = bytes[0];
assert!(
first >= b'a' && first <= b'z',
"GTS_ID_PREFIX must start with a lowercase ASCII letter"
);
let mut i = 1;
while i < bytes.len() - 1 {
let b = bytes[i];
assert!(
(b >= b'a' && b <= b'z') || (b >= b'0' && b <= b'9') || b == b'_',
"GTS_ID_PREFIX must be a lowercase ASCII token followed by '.'"
);
i += 1;
}
prefix
}
#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::expect_used)]
mod tests {
use super::*;
use std::panic::catch_unwind;
#[test]
fn test_valid_prefixes() {
assert_eq!(validate_gts_id_prefix("gts."), "gts.");
assert_eq!(validate_gts_id_prefix("a."), "a.");
assert_eq!(validate_gts_id_prefix("acme."), "acme.");
assert_eq!(validate_gts_id_prefix("a1."), "a1.");
assert_eq!(validate_gts_id_prefix("a_b."), "a_b.");
assert_eq!(validate_gts_id_prefix("abc123_."), "abc123_.");
}
#[test]
fn test_default_prefix_is_in_effect() {
if option_env!("GTS_ID_PREFIX").is_none() {
assert_eq!(GTS_ID_PREFIX, DEFAULT_GTS_ID_PREFIX);
assert_eq!(GTS_ID_PREFIX, "gts.");
}
}
#[test]
fn test_invalid_prefixes_rejected() {
let invalid = [
"", "acme", "Acme.", "acme-prod.", "my.org.", ".", "1bad.", "_.", ];
for prefix in invalid {
let result = catch_unwind(|| validate_gts_id_prefix(prefix));
assert!(
result.is_err(),
"prefix {prefix:?} should be rejected but was accepted"
);
}
}
}