pub struct TestHtmlBuilder {
title: String,
description: Option<String>,
headings: Vec<String>,
paragraphs: Vec<String>,
links: Vec<(String, String)>, images: Vec<(String, String)>, has_viewport: bool,
}
impl TestHtmlBuilder {
pub fn new() -> Self {
Self {
title: "Test Page".to_string(),
description: None,
headings: Vec::new(),
paragraphs: Vec::new(),
links: Vec::new(),
images: Vec::new(),
has_viewport: false,
}
}
pub fn with_title(mut self, title: &str) -> Self {
self.title = title.to_string();
self
}
pub fn with_description(mut self, description: &str) -> Self {
self.description = Some(description.to_string());
self
}
pub fn add_heading(mut self, text: &str) -> Self {
self.headings.push(text.to_string());
self
}
pub fn add_paragraph(mut self, text: &str) -> Self {
self.paragraphs.push(text.to_string());
self
}
pub fn add_link(mut self, href: &str, text: &str) -> Self {
self.links.push((href.to_string(), text.to_string()));
self
}
pub fn add_image(mut self, src: &str, alt: &str) -> Self {
self.images.push((src.to_string(), alt.to_string()));
self
}
pub fn with_viewport(mut self) -> Self {
self.has_viewport = true;
self
}
pub fn build(self) -> String {
use std::fmt::Write;
let base_capacity = 200;
let content_capacity = self.headings.len() * 50
+ self.paragraphs.len() * 50
+ self.links.len() * 80
+ self.images.len() * 60
+ self.title.len()
+ self.description.as_ref().map_or(0, |d| d.len());
let mut html = String::with_capacity(base_capacity + content_capacity);
html.push_str("<!DOCTYPE html>\n<html>\n<head>\n");
write!(&mut html, " <title>{}</title>\n", self.title)
.expect("Writing to string should not fail");
if let Some(desc) = self.description {
write!(
&mut html,
" <meta name=\"description\" content=\"{}\">\n",
desc
)
.expect("Writing to string should not fail");
}
if self.has_viewport {
html.push_str(
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n",
);
}
html.push_str("</head>\n<body>\n");
for (i, heading) in self.headings.iter().enumerate() {
let level = if i == 0 { 1 } else { 2 };
write!(&mut html, " <h{}>{}</h{}>\n", level, heading, level)
.expect("Writing to string should not fail");
}
for paragraph in &self.paragraphs {
write!(&mut html, " <p>{}</p>\n", paragraph).unwrap();
}
for (href, text) in &self.links {
write!(&mut html, " <a href=\"{}\">{}</a>\n", href, text)
.expect("Writing to string should not fail");
}
for (src, alt) in &self.images {
write!(&mut html, " <img src=\"{}\" alt=\"{}\">\n", src, alt).unwrap();
}
html.push_str("</body>\n</html>");
html
}
}
impl Default for TestHtmlBuilder {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_html_builder_basic() {
let html = TestHtmlBuilder::new()
.with_title("Test Title")
.add_heading("Main Heading")
.add_paragraph("Test paragraph content")
.build();
assert!(html.contains("Test Title"));
assert!(html.contains("Main Heading"));
assert!(html.contains("Test paragraph"));
}
#[test]
fn test_html_builder_with_metadata() {
let html = TestHtmlBuilder::new()
.with_title("Meta Test")
.with_description("Test page for metadata")
.with_viewport()
.build();
assert!(html.contains("Meta Test"));
assert!(html.contains("Test page for metadata"));
assert!(html.contains("viewport"));
}
}