use std::str::FromStr;
use nulid::Nulid;
use crate::parser::ParseError;
pub fn resolve_id(stored: Option<&str>, line: usize) -> Result<(Nulid, bool), ParseError> {
match stored {
Some(s) if !s.is_empty() => {
let id = Nulid::from_str(s).map_err(|_| ParseError {
line,
message: format!("invalid NULID: {s:?}"),
})?;
Ok((id, false))
}
_ => {
let id = Nulid::new().map_err(|e| ParseError {
line,
message: format!("failed to generate NULID: {e}"),
})?;
Ok((id, true))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn resolve_stored_id() {
let id = Nulid::new().unwrap();
let s = id.to_string();
let (resolved, generated) = resolve_id(Some(&s), 1).unwrap();
assert_eq!(resolved, id);
assert!(!generated);
}
#[test]
fn resolve_missing_id_generates() {
let (id, generated) = resolve_id(None, 1).unwrap();
assert!(generated);
assert_eq!(id.to_string().len(), 26);
}
#[test]
fn resolve_empty_id_generates() {
let (id, generated) = resolve_id(Some(""), 1).unwrap();
assert!(generated);
assert_eq!(id.to_string().len(), 26);
}
#[test]
fn resolve_invalid_id_errors() {
let result = resolve_id(Some("not-a-nulid"), 5);
assert!(result.is_err());
let err = result.unwrap_err();
assert!(err.message.contains("invalid NULID"));
assert_eq!(err.line, 5);
}
#[test]
fn generated_ids_are_unique() {
let (a, _) = resolve_id(None, 1).unwrap();
let (b, _) = resolve_id(None, 1).unwrap();
assert_ne!(a, b);
}
#[test]
fn nulid_is_valid_string() {
let (id, _) = resolve_id(None, 1).unwrap();
let s = id.to_string();
assert_eq!(s.len(), 26);
assert!(s.chars().all(|c| c.is_ascii_alphanumeric()));
}
}