fix: align code with spec

This commit is contained in:
2026-04-03 15:53:48 +02:00
parent 95c97bce33
commit 897577a369
10 changed files with 141 additions and 20 deletions

View File

@@ -1,4 +1,5 @@
use deunicode::deunicode;
use std::time::{SystemTime, UNIX_EPOCH};
/// Generate a URL-safe slug from a title string.
///
@@ -25,6 +26,30 @@ pub fn slugify(input: &str) -> String {
slug
}
/// Ensure a slug is unique within a project, using the spec's algorithm:
/// tries base, then {slug}-2 .. {slug}-999, then {slug}-{timestamp}.
///
/// `exists` is a predicate that returns true if the candidate slug is already taken.
pub fn ensure_unique<F>(base: &str, exists: F) -> String
where
F: Fn(&str) -> bool,
{
if !exists(base) {
return base.to_string();
}
for n in 2..=999 {
let candidate = format!("{base}-{n}");
if !exists(&candidate) {
return candidate;
}
}
let ts = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_secs();
format!("{base}-{ts}")
}
#[cfg(test)]
mod tests {
use super::*;
@@ -58,4 +83,40 @@ mod tests {
fn consecutive_special_chars() {
assert_eq!(slugify("a --- b"), "a-b");
}
#[test]
fn ensure_unique_base_available() {
let slug = ensure_unique("hello", |_| false);
assert_eq!(slug, "hello");
}
#[test]
fn ensure_unique_base_taken() {
let slug = ensure_unique("hello", |s| s == "hello");
assert_eq!(slug, "hello-2");
}
#[test]
fn ensure_unique_sequential_taken() {
let slug = ensure_unique("hello", |s| s == "hello" || s == "hello-2" || s == "hello-3");
assert_eq!(slug, "hello-4");
}
#[test]
fn ensure_unique_all_999_taken() {
let slug = ensure_unique("x", |s| {
if s == "x" { return true; }
if let Some(suffix) = s.strip_prefix("x-") {
if let Ok(n) = suffix.parse::<u32>() {
return n <= 999;
}
}
false
});
// Should fall back to timestamp-based slug
assert!(slug.starts_with("x-"));
let suffix = slug.strip_prefix("x-").unwrap();
let ts: u64 = suffix.parse().expect("should be a timestamp");
assert!(ts > 1_000_000_000);
}
}