Performance, security and provenance hardening (ann/io/migrate/agent) + two audit fixes #2
@@ -144,7 +144,8 @@ fn truncate(s: &str) -> String {
|
|||||||
if s.len() <= 40 {
|
if s.len() <= 40 {
|
||||||
s.to_string()
|
s.to_string()
|
||||||
} else {
|
} else {
|
||||||
format!("{}…", &s[..40])
|
let cut = s.char_indices().nth(40).map(|(i, _)| i).unwrap_or(s.len());
|
||||||
|
format!("{}…", &s[..cut])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,3 +162,31 @@ fn sample_indices(n: usize, full: bool) -> Vec<usize> {
|
|||||||
idx.dedup();
|
idx.dedup();
|
||||||
idx
|
idx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn truncate_short_string_unchanged() {
|
||||||
|
assert_eq!(truncate("hello"), "hello");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A multi-byte character straddling byte offset 40 must not panic a
|
||||||
|
/// byte-index slice — this is arbitrary UTF-8 chunk text from an
|
||||||
|
/// untrusted source database, not test-only input.
|
||||||
|
#[test]
|
||||||
|
fn truncate_multibyte_char_at_boundary_does_not_panic() {
|
||||||
|
// 39 ASCII bytes then a 4-byte emoji straddling the byte-40 cut point.
|
||||||
|
let s = format!("{}{}", "a".repeat(39), "😀".repeat(5));
|
||||||
|
let result = truncate(&s);
|
||||||
|
assert!(result.ends_with('…'));
|
||||||
|
assert!(result.chars().count() < s.chars().count());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn truncate_exactly_at_limit_unchanged() {
|
||||||
|
let s = "a".repeat(40);
|
||||||
|
assert_eq!(truncate(&s), s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user