mod common;
use std::path::PathBuf;
use office2pdf::config::ConvertOptions;
use office2pdf::ir::{Block, FixedElementKind, FixedPage, Page};
use office2pdf::parser::Parser;
use office2pdf::parser::pptx::PptxParser;
fn fixture_path(name: &str) -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../../tests/fixtures/pptx")
.join(name)
}
fn load_fixture(name: &str) -> Vec<u8> {
std::fs::read(fixture_path(name)).expect("fixture file should exist")
}
fn assert_produces_valid_pdf(name: &str) {
let path = fixture_path(name);
match office2pdf::convert(&path) {
Ok(result) => {
assert!(!result.pdf.is_empty(), "PDF output should not be empty");
assert!(
result.pdf.starts_with(b"%PDF"),
"output should start with PDF magic bytes"
);
common::validate_pdf_with_qpdf(&result.pdf);
}
Err(e) => {
eprintln!("[WARN] {name}: conversion error (non-panic): {e}");
}
}
}
fn fixed_pages(name: &str) -> Vec<FixedPage> {
let data = load_fixture(name);
let (doc, _warnings) = PptxParser.parse(&data, &ConvertOptions::default()).unwrap();
doc.pages
.into_iter()
.filter_map(|p| match p {
Page::Fixed(fp) => Some(fp),
_ => None,
})
.collect()
}
fn has_fixed_image(pages: &[FixedPage]) -> bool {
pages
.iter()
.flat_map(|p| p.elements.iter())
.any(|e| matches!(e.kind, FixedElementKind::Image(_)))
}
fn has_textbox_with_content(pages: &[FixedPage]) -> bool {
pages
.iter()
.flat_map(|p| p.elements.iter())
.any(|e| match &e.kind {
FixedElementKind::TextBox(text_box) => text_box.content.iter().any(|b| match b {
Block::Paragraph(para) => para.runs.iter().any(|r| !r.text.is_empty()),
_ => false,
}),
_ => false,
})
}
#[test]
fn smoke_minimal() {
assert_produces_valid_pdf("minimal.pptx");
}
#[test]
fn structure_minimal() {
let data = load_fixture("minimal.pptx");
let result = PptxParser.parse(&data, &ConvertOptions::default());
match result {
Ok((doc, _)) => {
let slides: Vec<_> = doc
.pages
.iter()
.filter(|p| matches!(p, Page::Fixed(_)))
.collect();
assert!(
slides.is_empty(),
"minimal.pptx has no actual slides, expected 0 pages"
);
}
Err(_) => {
}
}
}
#[test]
fn smoke_no_slides() {
let path = fixture_path("no-slides.pptx");
let _ = office2pdf::convert(&path);
}
#[test]
fn structure_no_slides() {
let data = load_fixture("no-slides.pptx");
match PptxParser.parse(&data, &ConvertOptions::default()) {
Ok((doc, _)) => {
let slide_count = doc
.pages
.iter()
.filter(|p| matches!(p, Page::Fixed(_)))
.count();
assert_eq!(slide_count, 0, "no-slides file should produce 0 pages");
}
Err(_) => {
}
}
}
#[test]
fn smoke_powerpoint_sample() {
assert_produces_valid_pdf("powerpoint_sample.pptx");
}
#[test]
fn structure_powerpoint_sample() {
let pages = fixed_pages("powerpoint_sample.pptx");
assert!(pages.len() >= 2, "should have >= 2 slides");
assert!(has_textbox_with_content(&pages), "should have text content");
}
#[test]
fn smoke_powerpoint_with_image() {
assert_produces_valid_pdf("powerpoint_with_image.pptx");
}
#[test]
fn structure_powerpoint_with_image() {
let pages = fixed_pages("powerpoint_with_image.pptx");
assert!(
has_fixed_image(&pages),
"should have FixedElementKind::Image"
);
}
#[test]
fn smoke_test_slides() {
assert_produces_valid_pdf("test_slides.pptx");
}
#[test]
fn structure_test_slides() {
let pages = fixed_pages("test_slides.pptx");
assert!(!pages.is_empty(), "should have at least 1 slide");
}
#[test]
fn smoke_test() {
assert_produces_valid_pdf("test.pptx");
}
#[test]
fn structure_test() {
let pages = fixed_pages("test.pptx");
assert!(!pages.is_empty(), "should have at least one slide");
assert!(has_textbox_with_content(&pages), "should have text content");
}
fn pdf_text(name: &str) -> String {
let path = fixture_path(name);
let result = office2pdf::convert(&path).expect("conversion should succeed");
common::extract_pdf_text(&result.pdf)
}
#[test]
fn text_content_powerpoint_sample() {
let text = pdf_text("powerpoint_sample.pptx");
assert!(
text.contains("slide title") || text.contains("Slide Title") || text.contains("Test"),
"PDF should contain slide title text"
);
}
#[test]
fn text_content_test() {
let text = pdf_text("test.pptx");
assert!(
text.contains("Presentation Title") || text.contains("Title"),
"PDF should contain presentation title"
);
}
#[test]
fn text_content_test_slides() {
let text = pdf_text("test_slides.pptx");
assert!(
text.contains("Test text") || text.contains("Box"),
"PDF should contain slide text content"
);
}
macro_rules! pptx_fixture_tests {
($test_name:ident, $file:expr) => {
paste::paste! {
#[test]
fn [<smoke_ $test_name>]() {
assert_produces_valid_pdf($file);
}
#[test]
fn [<structure_ $test_name>]() {
let data = load_fixture($file);
match PptxParser.parse(&data, &ConvertOptions::default()) {
Ok((doc, _)) => {
let _ = doc.pages.len();
}
Err(e) => {
eprintln!("[WARN] {}: parse error (non-panic): {e}", $file);
}
}
}
}
};
}
pptx_fixture_tests!(ffc, "ffc.pptx");
pptx_fixture_tests!(one_slide, "1-slide.pptx");
pptx_fixture_tests!(five_slides, "5-slides.pptx");
pptx_fixture_tests!(ten_slides, "10-slides.pptx");
pptx_fixture_tests!(bar_chart, "bar-chart.pptx");
pptx_fixture_tests!(pie_chart, "pie-chart.pptx");
pptx_fixture_tests!(line_chart, "line-chart.pptx");
pptx_fixture_tests!(scatter_chart, "scatter-chart.pptx");
pptx_fixture_tests!(radar_chart, "radar-chart.pptx");
pptx_fixture_tests!(chart_picture_bg, "chart-picture-bg.pptx");
pptx_fixture_tests!(table_test_poi, "table_test.pptx");
pptx_fixture_tests!(table_test2, "table_test2.pptx");
pptx_fixture_tests!(table_with_theme, "table-with-theme.pptx");
pptx_fixture_tests!(backgrounds, "backgrounds.pptx");
pptx_fixture_tests!(themes, "themes.pptx");
pptx_fixture_tests!(smart_art, "SmartArt.pptx");
pptx_fixture_tests!(smart_art_simple, "smartart-simple.pptx");
pptx_fixture_tests!(embedded_audio, "EmbeddedAudio.pptx");
pptx_fixture_tests!(embedded_video, "EmbeddedVideo.pptx");
pptx_fixture_tests!(with_japanese, "with_japanese.pptx");
pptx_fixture_tests!(with_master, "WithMaster.pptx");
pptx_fixture_tests!(comment_45545, "45545_Comment.pptx");
pptx_fixture_tests!(keyframes, "keyframes.pptx");
pptx_fixture_tests!(layouts, "layouts.pptx");
pptx_fixture_tests!(shapes, "shapes.pptx");
pptx_fixture_tests!(custom_geo, "customGeo.pptx");
pptx_fixture_tests!(highlight, "highlight-test-case.pptx");
pptx_fixture_tests!(picture_transparency, "picture-transparency.pptx");
pptx_fixture_tests!(poi_sample, "poi_sample.pptx");
pptx_fixture_tests!(present1, "present1.pptx");
pptx_fixture_tests!(rain, "rain.pptx");
pptx_fixture_tests!(copy_slide_demo, "copy-slide-demo.pptx");
pptx_fixture_tests!(oxp_presentation, "oxp_Presentation.pptx");
pptx_fixture_tests!(oxp_chart_cached, "oxp_CU018-Chart-Cached-Data-41.pptx");
pptx_fixture_tests!(oxp_chart_embedded, "oxp_CU019-Chart-Embedded-Xlsx-41.pptx");
pptx_fixture_tests!(oxp_pb001_input1, "oxp_PB001-Input1.pptx");
pptx_fixture_tests!(oxp_pb001_input2, "oxp_PB001-Input2.pptx");
pptx_fixture_tests!(oxp_pb001_input3, "oxp_PB001-Input3.pptx");
pptx_fixture_tests!(oxp_videos, "oxp_PP006-Videos.pptx");