use super::*;
#[test]
fn test_heading1_style_applies_defaults() {
let h1_style = docx_rs::Style::new("Heading1", docx_rs::StyleType::Paragraph)
.name("Heading 1")
.outline_lvl(0);
let data = build_docx_bytes_with_styles(
vec![
docx_rs::Paragraph::new()
.add_run(docx_rs::Run::new().add_text("Title"))
.style("Heading1"),
],
vec![h1_style],
);
let parser = DocxParser;
let (doc, _warnings) = parser.parse(&data, &ConvertOptions::default()).unwrap();
let run = first_run(&doc);
assert_eq!(run.style.font_size, Some(24.0));
assert_eq!(run.style.bold, Some(true));
}
#[test]
fn test_heading2_style_applies_defaults() {
let h2_style = docx_rs::Style::new("Heading2", docx_rs::StyleType::Paragraph)
.name("Heading 2")
.outline_lvl(1);
let data = build_docx_bytes_with_styles(
vec![
docx_rs::Paragraph::new()
.add_run(docx_rs::Run::new().add_text("Subtitle"))
.style("Heading2"),
],
vec![h2_style],
);
let parser = DocxParser;
let (doc, _warnings) = parser.parse(&data, &ConvertOptions::default()).unwrap();
let run = first_run(&doc);
assert_eq!(run.style.font_size, Some(20.0));
assert_eq!(run.style.bold, Some(true));
}
#[test]
fn test_heading3_through_6_defaults() {
let expected: Vec<(usize, &str, f64)> = vec![
(2, "Heading3", 16.0),
(3, "Heading4", 14.0),
(4, "Heading5", 12.0),
(5, "Heading6", 11.0),
];
for (outline_lvl, style_id, expected_size) in expected {
let style = docx_rs::Style::new(style_id, docx_rs::StyleType::Paragraph)
.name(format!("Heading {}", outline_lvl + 1))
.outline_lvl(outline_lvl);
let data = build_docx_bytes_with_styles(
vec![
docx_rs::Paragraph::new()
.add_run(docx_rs::Run::new().add_text("Heading text"))
.style(style_id),
],
vec![style],
);
let parser = DocxParser;
let (doc, _warnings) = parser.parse(&data, &ConvertOptions::default()).unwrap();
let run = first_run(&doc);
assert_eq!(
run.style.font_size,
Some(expected_size),
"Heading {} should have size {expected_size}pt",
outline_lvl + 1
);
assert_eq!(
run.style.bold,
Some(true),
"Heading {} should be bold",
outline_lvl + 1
);
}
}
#[test]
fn test_style_with_explicit_formatting() {
let custom = docx_rs::Style::new("CustomStyle", docx_rs::StyleType::Paragraph)
.name("Custom Style")
.size(36)
.bold();
let data = build_docx_bytes_with_styles(
vec![
docx_rs::Paragraph::new()
.add_run(docx_rs::Run::new().add_text("Custom styled"))
.style("CustomStyle"),
],
vec![custom],
);
let parser = DocxParser;
let (doc, _warnings) = parser.parse(&data, &ConvertOptions::default()).unwrap();
let run = first_run(&doc);
assert_eq!(run.style.font_size, Some(18.0));
assert_eq!(run.style.bold, Some(true));
}
#[test]
fn test_explicit_run_formatting_overrides_style() {
let h1_style = docx_rs::Style::new("Heading1", docx_rs::StyleType::Paragraph)
.name("Heading 1")
.outline_lvl(0);
let data = build_docx_bytes_with_styles(
vec![
docx_rs::Paragraph::new()
.add_run(docx_rs::Run::new().add_text("Small heading").size(20))
.style("Heading1"),
],
vec![h1_style],
);
let parser = DocxParser;
let (doc, _warnings) = parser.parse(&data, &ConvertOptions::default()).unwrap();
let run = first_run(&doc);
assert_eq!(run.style.font_size, Some(10.0));
assert_eq!(run.style.bold, Some(true));
}
#[test]
fn test_style_alignment_applied_to_paragraph() {
let centered = docx_rs::Style::new("CenteredStyle", docx_rs::StyleType::Paragraph)
.name("Centered")
.align(docx_rs::AlignmentType::Center);
let data = build_docx_bytes_with_styles(
vec![
docx_rs::Paragraph::new()
.add_run(docx_rs::Run::new().add_text("Centered paragraph"))
.style("CenteredStyle"),
],
vec![centered],
);
let parser = DocxParser;
let (doc, _warnings) = parser.parse(&data, &ConvertOptions::default()).unwrap();
let para = first_paragraph(&doc);
assert_eq!(para.style.alignment, Some(Alignment::Center));
}
#[test]
fn test_normal_style_no_heading_defaults() {
let normal = docx_rs::Style::new("Normal", docx_rs::StyleType::Paragraph).name("Normal");
let data = build_docx_bytes_with_styles(
vec![
docx_rs::Paragraph::new()
.add_run(docx_rs::Run::new().add_text("Normal text"))
.style("Normal"),
],
vec![normal],
);
let parser = DocxParser;
let (doc, _warnings) = parser.parse(&data, &ConvertOptions::default()).unwrap();
let run = first_run(&doc);
assert!(run.style.font_size.is_none());
assert!(run.style.bold.is_none());
}
#[test]
fn test_heading_with_mixed_paragraphs() {
let h1 = docx_rs::Style::new("Heading1", docx_rs::StyleType::Paragraph)
.name("Heading 1")
.outline_lvl(0);
let h2 = docx_rs::Style::new("Heading2", docx_rs::StyleType::Paragraph)
.name("Heading 2")
.outline_lvl(1);
let data = build_docx_bytes_with_styles(
vec![
docx_rs::Paragraph::new()
.add_run(docx_rs::Run::new().add_text("Title"))
.style("Heading1"),
docx_rs::Paragraph::new().add_run(docx_rs::Run::new().add_text("Body text")),
docx_rs::Paragraph::new()
.add_run(docx_rs::Run::new().add_text("Subtitle"))
.style("Heading2"),
],
vec![h1, h2],
);
let parser = DocxParser;
let (doc, _warnings) = parser.parse(&data, &ConvertOptions::default()).unwrap();
let blocks = all_blocks(&doc);
if let Block::Paragraph(p) = &blocks[0] {
assert_eq!(p.runs[0].style.font_size, Some(24.0));
assert_eq!(p.runs[0].style.bold, Some(true));
} else {
panic!("Expected Paragraph");
}
if let Block::Paragraph(p) = &blocks[1] {
assert!(p.runs[0].style.font_size.is_none());
assert!(p.runs[0].style.bold.is_none());
} else {
panic!("Expected Paragraph");
}
if let Block::Paragraph(p) = &blocks[2] {
assert_eq!(p.runs[0].style.font_size, Some(20.0));
assert_eq!(p.runs[0].style.bold, Some(true));
} else {
panic!("Expected Paragraph");
}
}
#[test]
fn test_style_with_color_and_font() {
let custom = docx_rs::Style::new("Fancy", docx_rs::StyleType::Paragraph)
.name("Fancy Style")
.color("FF0000")
.fonts(docx_rs::RunFonts::new().ascii("Georgia"));
let data = build_docx_bytes_with_styles(
vec![
docx_rs::Paragraph::new()
.add_run(docx_rs::Run::new().add_text("Fancy text"))
.style("Fancy"),
],
vec![custom],
);
let parser = DocxParser;
let (doc, _warnings) = parser.parse(&data, &ConvertOptions::default()).unwrap();
let run = first_run(&doc);
assert_eq!(run.style.color, Some(Color::new(255, 0, 0)));
assert_eq!(run.style.font_family, Some("Georgia".to_string()));
}
#[test]
fn test_runs_inherit_document_default_font() {
let styles = docx_rs::Styles::new()
.default_fonts(docx_rs::RunFonts::new().ascii("Raleway"))
.default_size(18);
let link = docx_rs::Hyperlink::new("https://example.com", docx_rs::HyperlinkType::External)
.add_run(
docx_rs::Run::new()
.color("1155cc")
.underline("single")
.add_text("Linked text"),
);
let paragraph = docx_rs::Paragraph::new()
.add_run(docx_rs::Run::new().add_text("Plain text "))
.add_hyperlink(link);
let data = build_docx_bytes_with_stylesheet(vec![paragraph], styles);
let parser = DocxParser;
let (doc, _warnings) = parser.parse(&data, &ConvertOptions::default()).unwrap();
let para = first_paragraph(&doc);
assert_eq!(para.runs.len(), 2);
assert_eq!(para.runs[0].style.font_family.as_deref(), Some("Raleway"));
assert_eq!(para.runs[0].style.font_size, Some(9.0));
assert_eq!(para.runs[1].href.as_deref(), Some("https://example.com"));
assert_eq!(para.runs[1].style.font_family.as_deref(), Some("Raleway"));
assert_eq!(para.runs[1].style.font_size, Some(9.0));
assert_eq!(para.runs[1].style.color, Some(Color::new(17, 85, 204)));
assert_eq!(para.runs[1].style.underline, Some(true));
}