use std::sync::OnceLock;
fn truncate_to_chars(text: &mut String, target_size: usize) {
if text.len() <= target_size {
return;
}
let mut end = target_size;
while end > 0 && !text.is_char_boundary(end) {
end -= 1;
}
text.truncate(end);
}
static CACHED_DATA: OnceLock<TestDataCache> = OnceLock::new();
pub struct TestDataCache {
pub emails_1kb: String,
pub emails_10kb: String,
pub emails_100kb: String,
pub urls_1kb: String,
pub urls_10kb: String,
pub urls_100kb: String,
pub logs_1kb: String,
pub logs_10kb: String,
pub logs_100kb: String,
pub json_1kb: String,
pub json_10kb: String,
pub json_100kb: String,
pub ips_1kb: String,
pub ips_10kb: String,
pub ips_100kb: String,
pub html_1kb: String,
pub html_10kb: String,
pub html_100kb: String,
pub text_1kb: String,
pub text_10kb: String,
pub text_100kb: String,
pub code_1kb: String,
pub code_10kb: String,
pub code_100kb: String,
}
pub fn get_test_data() -> &'static TestDataCache {
CACHED_DATA.get_or_init(|| TestDataCache {
emails_1kb: generate_email_data(1024),
emails_10kb: generate_email_data(10 * 1024),
emails_100kb: generate_email_data(100 * 1024),
urls_1kb: generate_url_data(1024),
urls_10kb: generate_url_data(10 * 1024),
urls_100kb: generate_url_data(100 * 1024),
logs_1kb: generate_log_data(1024),
logs_10kb: generate_log_data(10 * 1024),
logs_100kb: generate_log_data(100 * 1024),
json_1kb: generate_json_data(1024),
json_10kb: generate_json_data(10 * 1024),
json_100kb: generate_json_data(100 * 1024),
ips_1kb: generate_ip_data(1024),
ips_10kb: generate_ip_data(10 * 1024),
ips_100kb: generate_ip_data(100 * 1024),
html_1kb: generate_html_data(1024),
html_10kb: generate_html_data(10 * 1024),
html_100kb: generate_html_data(100 * 1024),
text_1kb: generate_text_data(1024),
text_10kb: generate_text_data(10 * 1024),
text_100kb: generate_text_data(100 * 1024),
code_1kb: generate_code_data(1024),
code_10kb: generate_code_data(10 * 1024),
code_100kb: generate_code_data(100 * 1024),
})
}
fn generate_email_data(target_size: usize) -> String {
let valid_emails = [
"john.doe@example.com",
"jane_smith@company.org",
"test+tag@subdomain.example.co.uk",
"user123@test-domain.com",
"contact@mysite.io",
"admin@localhost.localdomain",
];
let invalid_emails = [
"not-an-email",
"@example.com",
"missing@domain",
"spaces in@email.com",
"double@@at.com",
];
let mut result = String::with_capacity(target_size);
let mut toggle = true;
let mut index = 0usize;
while result.len() < target_size {
if toggle {
result.push_str(valid_emails[index % valid_emails.len()]);
} else {
result.push_str(invalid_emails[index % invalid_emails.len()]);
}
index += 1;
result.push_str(" some filler text to pad the data ");
toggle = !toggle;
}
truncate_to_chars(&mut result, target_size);
result
}
fn generate_url_data(target_size: usize) -> String {
let urls = [
"https://www.example.com/path/to/resource",
"http://subdomain.test.org:8080/api/v1/users?id=123",
"https://github.com/user/repo/blob/main/src/file.rs",
"http://localhost:3000/admin/dashboard",
"https://api.service.io/endpoint?key=value&foo=bar",
];
let mut result = String::with_capacity(target_size);
for index in 0.. {
if result.len() >= target_size {
break;
}
result.push_str("Check out this link: ");
result.push_str(urls[index % urls.len()]);
result.push_str(" for more information. ");
}
truncate_to_chars(&mut result, target_size);
result
}
fn generate_log_data(target_size: usize) -> String {
let levels = ["INFO", "WARNING", "ERROR", "CRITICAL", "DEBUG"];
let messages = [
"Request processed successfully",
"Connection timeout after 30s: warning issued to the caller",
"Database query failed with a fatal error while committing",
"User authentication successful",
"Cache miss for key: user_123, critical path fell back to disk",
];
let mut result = String::with_capacity(target_size);
let mut day = 1;
let mut hour = 0;
let mut index = 0usize;
while result.len() < target_size {
result.push_str(&format!(
"2024-01-{:02} {:02}:30:45 [{}] {}\n",
day,
hour,
levels[index % levels.len()],
messages[index % messages.len()]
));
index += 1;
hour = (hour + 1) % 24;
if hour == 0 {
day = (day % 28) + 1;
}
}
truncate_to_chars(&mut result, target_size);
result
}
fn generate_json_data(target_size: usize) -> String {
let mut result = String::with_capacity(target_size);
let mut counter = 0;
result.push_str("{\"users\":[");
while result.len() < target_size - 100 {
if counter > 0 {
result.push(',');
}
result.push_str(&format!(
r#"{{"id":{},"name":"User {}","email":"user{}@example.com","status":"active","data":"Some escaped \"quoted\" text here"}}"#,
counter, counter, counter
));
counter += 1;
}
result.push_str("]}");
truncate_to_chars(&mut result, target_size);
result
}
fn generate_ip_data(target_size: usize) -> String {
let mut result = String::with_capacity(target_size);
let mut octet = 1;
while result.len() < target_size {
result.push_str(&format!(
"Connection from 192.168.{}.{} on port 8080. ",
(octet / 256) % 256,
octet % 256
));
octet += 1;
}
truncate_to_chars(&mut result, target_size);
result
}
fn generate_html_data(target_size: usize) -> String {
let tags = [
"<div class=\"container\">",
"<p>Some paragraph text</p>",
"<a href=\"/link\">Click here</a>",
"<span style=\"color: red;\">Red text</span>",
"<img src=\"image.jpg\" alt=\"description\">",
"</div>",
];
let mut result = String::with_capacity(target_size);
result.push_str("<!DOCTYPE html><html><body>");
for index in 0.. {
if result.len() >= target_size.saturating_sub(100) {
break;
}
result.push_str(tags[index % tags.len()]);
result.push_str(" Some text content between tags. ");
}
result.push_str("</body></html>");
truncate_to_chars(&mut result, target_size);
result
}
fn generate_text_data(target_size: usize) -> String {
let words = [
"the", "quick", "brown", "fox", "jumps", "over", "lazy", "dog", "and", "then", "runs",
"through", "forest", "near", "river", "where", "birds", "sing", "their", "morning",
"songs",
];
let mut result = String::with_capacity(target_size);
for index in 0.. {
if result.len() >= target_size {
break;
}
result.push_str(words[index % words.len()]);
result.push(' ');
}
truncate_to_chars(&mut result, target_size);
result
}
fn generate_code_data(target_size: usize) -> String {
let code_snippets = [
r#"let x = "hello world";"#,
r#"const y = 'single quoted string';"#,
r#"var z = "escaped \"quotes\" inside";"#,
r#"String s = "Java string literal";"#,
r#"str = 'Python string with "nested" quotes';"#,
];
let mut result = String::with_capacity(target_size);
for index in 0.. {
if result.len() >= target_size {
break;
}
result.push_str(code_snippets[index % code_snippets.len()]);
result.push('\n');
}
truncate_to_chars(&mut result, target_size);
result
}
pub fn generate_unicode_data(target_size: usize) -> String {
let texts = vec![
"Hello world", "Bonjour le monde", "Hola mundo", "Привет мир", "こんにちは世界", "你好世界", "مرحبا بالعالم", "שלום עולם", "Γειά σου κόσμε", ];
let mut result = String::with_capacity(target_size);
for index in 0.. {
if result.len() >= target_size {
break;
}
result.push_str(texts[index % texts.len()]);
result.push_str(" • ");
}
truncate_to_chars(&mut result, target_size);
result
}