pub fn truncate_str(s: &str, max_chars: usize) -> String {
let char_count = s.chars().count();
if char_count <= max_chars {
s.to_string()
} else if max_chars <= 1 {
"…".to_string()
} else {
let mut out: String = s.chars().take(max_chars - 1).collect();
out.push('…');
out
}
}
pub fn path_basename(path: &str) -> &str {
path.rsplit('/').next().unwrap_or(path)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn no_truncation_when_short() {
assert_eq!(truncate_str("hello", 10), "hello");
}
#[test]
fn exact_length_no_truncation() {
assert_eq!(truncate_str("hello", 5), "hello");
}
#[test]
fn truncation_adds_ellipsis() {
assert_eq!(truncate_str("hello world", 5), "hell…");
}
#[test]
fn max_one_gives_ellipsis() {
assert_eq!(truncate_str("hello", 1), "…");
}
#[test]
fn max_zero_gives_ellipsis() {
assert_eq!(truncate_str("hello", 0), "…");
}
#[test]
fn unicode_chars_counted_correctly() {
assert_eq!(truncate_str("😀😁😂😃", 3), "😀😁…");
}
#[test]
fn empty_string() {
assert_eq!(truncate_str("", 5), "");
}
#[test]
fn path_basename_with_slashes() {
assert_eq!(path_basename("src/main.rs"), "main.rs");
}
#[test]
fn path_basename_no_slash() {
assert_eq!(path_basename("hello.txt"), "hello.txt");
}
#[test]
fn path_basename_trailing_slash() {
assert_eq!(path_basename("dir/"), "");
}
#[test]
fn path_basename_empty() {
assert_eq!(path_basename(""), "");
}
#[test]
fn path_basename_deep_path() {
assert_eq!(path_basename("a/b/c/d/file.rs"), "file.rs");
}
}