office-toolkit 1.0.0

A Rust library to create, read, and modify Microsoft Office documents (Word/Excel/PowerPoint) in the modern Open XML (OOXML) format.
Documentation
//! Smoke tests for the `office-toolkit` facade itself — not a re-test of any format's own
//! read/write logic (each format crate already has its own extensive round-trip suite for that).
//! These only prove the facade's own plumbing is wired correctly: the `prelude` re-exports resolve,
//! `OpenFile`/`SaveToFile` actually round-trip through a real file on disk, and `open`'s format
//! auto-detection picks the right variant (and correctly rejects a file that matches none of the
//! three).

use std::path::PathBuf;

use office_toolkit::prelude::*;
use office_toolkit::{Error, OfficeDocument, OpenFile, SaveToFile};

/// A process-unique path under the system temp directory — `office-toolkit` itself never touches
/// the filesystem outside of what a test explicitly asks for, so each test cleans up after itself
/// rather than relying on a shared fixtures directory.
fn temp_path(name: &str) -> PathBuf {
    let mut path = std::env::temp_dir();
    path.push(format!(
        "office-toolkit-facade-test-{}-{}",
        std::process::id(),
        name
    ));
    path
}

#[test]
fn prelude_gives_direct_access_to_the_three_entry_points() {
    // Compiles at all is the actual assertion here — `Document`/`Workbook`/ `Presentation`
    // resolving unprefixed, straight from `prelude::*`.
    let _document = Document::new();
    let _workbook = Workbook::new();
    let _presentation = Presentation::new();
    let _properties = ShapeProperties::new();
    // chantier 7 — `Cell` was added to the prelude too.
    let _cell = Cell::text("Bonjour");
}

#[test]
fn round_trips_a_word_document_through_save_and_open_file() {
    let path = temp_path("word.docx");
    let document = Document::new();
    document.save_to_file(&path).expect("saving should succeed");

    let read_back = Document::open_file(&path).expect("opening should succeed");
    assert_eq!(read_back.paragraphs().count(), 0);

    std::fs::remove_file(&path).ok();
}

#[test]
fn round_trips_an_excel_workbook_through_save_and_open_file() {
    let path = temp_path("excel.xlsx");
    let workbook = Workbook::new().with_sheet(office_toolkit::excel::Sheet::new("Feuil1"));
    workbook.save_to_file(&path).expect("saving should succeed");

    let read_back = Workbook::open_file(&path).expect("opening should succeed");
    assert_eq!(read_back.sheets.len(), 1);
    assert_eq!(read_back.sheets[0].name, "Feuil1");

    std::fs::remove_file(&path).ok();
}

#[test]
fn round_trips_a_powerpoint_presentation_through_save_and_open_file() {
    let path = temp_path("powerpoint.pptx");
    let presentation = Presentation::new().with_slide(office_toolkit::powerpoint::Slide::new());
    presentation
        .save_to_file(&path)
        .expect("saving should succeed");

    let read_back = Presentation::open_file(&path).expect("opening should succeed");
    assert_eq!(read_back.slides.len(), 1);

    std::fs::remove_file(&path).ok();
}

#[test]
fn open_auto_detects_a_word_document() {
    let path = temp_path("auto-word.docx");
    Document::new()
        .save_to_file(&path)
        .expect("saving should succeed");

    let opened = office_toolkit::open(&path).expect("opening should succeed");
    assert!(matches!(opened, OfficeDocument::Word(_)));

    std::fs::remove_file(&path).ok();
}

#[test]
fn open_auto_detects_an_excel_workbook() {
    let path = temp_path("auto-excel.xlsx");
    Workbook::new()
        .with_sheet(office_toolkit::excel::Sheet::new("Feuil1"))
        .save_to_file(&path)
        .expect("saving should succeed");

    let opened = office_toolkit::open(&path).expect("opening should succeed");
    assert!(matches!(opened, OfficeDocument::Excel(_)));

    std::fs::remove_file(&path).ok();
}

#[test]
fn open_auto_detects_a_powerpoint_presentation() {
    let path = temp_path("auto-powerpoint.pptx");
    Presentation::new()
        .with_slide(office_toolkit::powerpoint::Slide::new())
        .save_to_file(&path)
        .expect("saving should succeed");

    let opened = office_toolkit::open(&path).expect("opening should succeed");
    assert!(matches!(opened, OfficeDocument::Powerpoint(_)));

    std::fs::remove_file(&path).ok();
}

#[test]
fn open_and_save_to_file_round_trip_through_the_unified_enum() {
    let source_path = temp_path("enum-source.pptx");
    let resaved_path = temp_path("enum-resaved.pptx");
    Presentation::new()
        .with_slide(office_toolkit::powerpoint::Slide::new())
        .save_to_file(&source_path)
        .expect("saving should succeed");

    let opened = office_toolkit::open(&source_path).expect("opening should succeed");
    opened
        .save_to_file(&resaved_path)
        .expect("re-saving via the unified enum should succeed");

    let read_back = office_toolkit::powerpoint::Presentation::open_file(&resaved_path)
        .expect("re-opening should succeed");
    assert_eq!(read_back.slides.len(), 1);

    std::fs::remove_file(&source_path).ok();
    std::fs::remove_file(&resaved_path).ok();
}

/// A well-formed OPC/ZIP package that carries none of the three main parts `open` looks for — the
/// file `open` should never be fooled into accepting, however superficially "package-shaped" it is.
#[test]
fn open_rejects_a_package_with_none_of_the_three_known_main_parts() {
    let path = temp_path("unrecognized.zip");
    let mut package = opc::Package::new();
    package.add_part(opc::Part::new(
        "/not/a/recognized/part.xml",
        "application/xml",
        b"<nothing/>".to_vec(),
    ));
    let file = std::fs::File::create(&path).expect("creating the file should succeed");
    package
        .write_to(file)
        .expect("writing the package should succeed");

    let result = office_toolkit::open(&path);
    assert!(matches!(result, Err(Error::UnrecognizedFormat)));

    std::fs::remove_file(&path).ok();
}