docxcraft 0.1.0

Generate editable DOCX documents with rich text, tables, charts and SVG drawings
Documentation
// SPDX-License-Identifier: AGPL-3.0-only
// Copyright (C) 2026 ALGFORCE INC.

use docxcraft::{chart::Chart, document::Document, paragraph::Paragraph};
use std::io::{Cursor, Read};

#[test]
fn standalone_document_exports_text_templates_and_an_embedded_workbook() -> anyhow::Result<()> {
    let locale = String::from("en");
    let mut document = Document::new(&locale);
    document.add_paragraph(Paragraph::new(String::from("Quarterly sales")));
    let option = serde_json::json!({
        "xAxis": { "type": "category", "data": ["Example"] },
        "yAxis": { "type": "value" },
        "series": [{ "name": "Revenue", "type": "bar", "data": [1200] }]
    });
    document.add_chart(Chart::from_echart_option(
        "Sales",
        &option.to_string(),
        None,
    )?);

    let directory = tempfile::tempdir()?;
    let path = directory.path().join("sales.docx");
    document.save(path.to_str().unwrap())?;
    let mut archive = zip::ZipArchive::new(std::fs::File::open(path)?)?;
    for name in [
        "word/settings.xml",
        "word/fontTable.xml",
        "word/webSettings.xml",
        "word/styles.xml",
        "word/numbering.xml",
        "word/charts/chart1.xml",
    ] {
        assert!(archive.by_name(name)?.size() > 0, "missing part: {name}");
    }
    let mut document_xml = String::new();
    archive
        .by_name("word/document.xml")?
        .read_to_string(&mut document_xml)?;
    assert!(document_xml.contains("Quarterly sales"));
    let embedded_name = archive
        .file_names()
        .find(|name| name.starts_with("word/embeddings/") && name.ends_with(".xlsx"))
        .expect("chart must include an editable workbook")
        .to_owned();
    let mut bytes = Vec::new();
    archive.by_name(&embedded_name)?.read_to_end(&mut bytes)?;
    let mut workbook = zip::ZipArchive::new(Cursor::new(bytes))?;
    assert!(workbook.by_name("xl/workbook.xml")?.size() > 0);
    let mut cells = String::new();
    workbook
        .by_name("xl/worksheets/sheet1.xml")?
        .read_to_string(&mut cells)?;
    assert!(cells.contains("<v>1200</v>"));
    Ok(())
}