const MAX_LABEL_LEN: usize = 256;
pub fn sanitize_label(label: &str) -> String {
let cleaned: String = label
.chars()
.filter(|c| !c.is_control())
.take(MAX_LABEL_LEN)
.collect();
cleaned
.replace('&', "&")
.replace('<', "<")
.replace('>', ">")
.replace('"', """)
.replace('\'', "'")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_plain_text_unchanged() {
assert_eq!(sanitize_label("Hello World"), "Hello World");
}
#[test]
fn test_html_entities_escaped() {
assert_eq!(
sanitize_label("<script>alert(\"xss\")</script>"),
"<script>alert("xss")</script>"
);
}
#[test]
fn test_ampersand_escaped() {
assert_eq!(sanitize_label("A & B"), "A & B");
}
#[test]
fn test_single_quote_escaped() {
assert_eq!(sanitize_label("it's"), "it's");
}
#[test]
fn test_control_chars_stripped() {
assert_eq!(sanitize_label("hello\x00world\x07"), "helloworld");
}
#[test]
fn test_newlines_stripped() {
assert_eq!(sanitize_label("line1\nline2\r\n"), "line1line2");
}
#[test]
fn test_tabs_stripped() {
assert_eq!(sanitize_label("col1\tcol2"), "col1col2");
}
#[test]
fn test_truncation() {
let long = "a".repeat(300);
let result = sanitize_label(&long);
assert_eq!(result.len(), 256);
}
#[test]
fn test_truncation_with_entities() {
let input = "<".repeat(300);
let result = sanitize_label(&input);
assert_eq!(result.len(), 256 * 4);
}
#[test]
fn test_empty_string() {
assert_eq!(sanitize_label(""), "");
}
#[test]
fn test_unicode_preserved() {
assert_eq!(sanitize_label("你好世界"), "你好世界");
}
#[test]
fn test_mixed_content() {
assert_eq!(
sanitize_label("Node <A> & \"B\""),
"Node <A> & "B""
);
}
#[test]
fn test_backtick_and_braces() {
assert_eq!(sanitize_label("`{code}`"), "`{code}`");
}
}