#![allow(dead_code)]
#[allow(dead_code)]
#[derive(Debug, Clone, Default)]
pub struct HtmlExport {
pub title: String,
pub sections: Vec<HtmlSection>,
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct HtmlSection {
pub heading: String,
pub rows: Vec<[String; 2]>,
}
#[allow(dead_code)]
pub fn new_html_export(title: &str) -> HtmlExport {
HtmlExport {
title: title.to_string(),
sections: Vec::new(),
}
}
#[allow(dead_code)]
pub fn add_html_section(doc: &mut HtmlExport, heading: &str) {
doc.sections.push(HtmlSection {
heading: heading.to_string(),
rows: Vec::new(),
});
}
#[allow(dead_code)]
pub fn add_html_row(doc: &mut HtmlExport, key: &str, value: &str) {
if let Some(sec) = doc.sections.last_mut() {
sec.rows.push([key.to_string(), value.to_string()]);
}
}
#[allow(dead_code)]
pub fn total_row_count(doc: &HtmlExport) -> usize {
doc.sections.iter().map(|s| s.rows.len()).sum()
}
#[allow(dead_code)]
pub fn section_count(doc: &HtmlExport) -> usize {
doc.sections.len()
}
#[allow(dead_code)]
pub fn to_html_string(doc: &HtmlExport) -> String {
let mut out = format!(
"<!DOCTYPE html>\n<html>\n<head><title>{}</title></head>\n<body>\n<h1>{}</h1>\n",
doc.title, doc.title
);
for sec in &doc.sections {
out.push_str(&format!("<h2>{}</h2>\n<table border=\"1\">\n", sec.heading));
for row in &sec.rows {
out.push_str(&format!(
"<tr><td>{}</td><td>{}</td></tr>\n",
row[0], row[1]
));
}
out.push_str("</table>\n");
}
out.push_str("</body>\n</html>");
out
}
#[allow(dead_code)]
pub fn export_mesh_stats_html(vertex_count: usize, index_count: usize, name: &str) -> String {
let mut doc = new_html_export("Mesh Stats");
add_html_section(&mut doc, name);
add_html_row(&mut doc, "Vertices", &vertex_count.to_string());
add_html_row(&mut doc, "Indices", &index_count.to_string());
add_html_row(&mut doc, "Triangles", &(index_count / 3).to_string());
to_html_string(&doc)
}
#[allow(dead_code)]
pub fn html_escape(s: &str) -> String {
s.replace('&', "&")
.replace('<', "<")
.replace('>', ">")
.replace('"', """)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_html_export_empty() {
let doc = new_html_export("Test");
assert_eq!(section_count(&doc), 0);
assert_eq!(total_row_count(&doc), 0);
}
#[test]
fn test_add_section() {
let mut doc = new_html_export("T");
add_html_section(&mut doc, "Section 1");
assert_eq!(section_count(&doc), 1);
}
#[test]
fn test_add_row() {
let mut doc = new_html_export("T");
add_html_section(&mut doc, "S");
add_html_row(&mut doc, "key", "val");
assert_eq!(total_row_count(&doc), 1);
}
#[test]
fn test_to_html_contains_title() {
let doc = new_html_export("My Page");
let s = to_html_string(&doc);
assert!(s.contains("My Page"));
}
#[test]
fn test_to_html_contains_table() {
let mut doc = new_html_export("T");
add_html_section(&mut doc, "S");
add_html_row(&mut doc, "k", "v");
let s = to_html_string(&doc);
assert!(s.contains("<table"));
}
#[test]
fn test_to_html_contains_row_data() {
let mut doc = new_html_export("T");
add_html_section(&mut doc, "S");
add_html_row(&mut doc, "vertices", "512");
let s = to_html_string(&doc);
assert!(s.contains("512"));
}
#[test]
fn test_export_mesh_stats_html() {
let s = export_mesh_stats_html(100, 300, "head");
assert!(s.contains("Vertices"));
assert!(s.contains("head"));
}
#[test]
fn test_html_escape_ampersand() {
assert_eq!(html_escape("a & b"), "a & b");
}
#[test]
fn test_html_escape_angle_brackets() {
assert_eq!(html_escape("<tag>"), "<tag>");
}
#[test]
fn test_doctype_in_output() {
let doc = new_html_export("T");
let s = to_html_string(&doc);
assert!(s.starts_with("<!DOCTYPE html>"));
}
}