Add Word-validation test fixtures generated by the real formatter
tests/make_word_test_files.py regenerates three fixtures: - tests/word_test_input.docx - tagged mini manuscript (book start through req review, all section roles, <<<>>> scene breaks) - tests/word_test_output.docx - output of format_document() on the above - tests/python_docx_control.docx - untouched python-docx save (baseline) Purpose: bisect the Word-open failure. The full manuscript output is structurally clean by every OOXML check (package rels, content types, sectPr/settings ordering, header/footer parts, fields, hyperlinks, custom parts all validate); the fixtures let Word itself tell us whether the pipeline or the manuscript content is the trigger.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -12,6 +12,7 @@ umbraformat/formatted/
|
||||
|
||||
# Documents / user scratch files (not part of the app source)
|
||||
*.docx
|
||||
!tests/*.docx
|
||||
summary.txt
|
||||
Sections_Tags
|
||||
Word_to_PDF_print_formatting
|
||||
|
||||
125
tests/make_word_test_files.py
Normal file
125
tests/make_word_test_files.py
Normal file
@@ -0,0 +1,125 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Regenerate the Word-validation test fixtures.
|
||||
|
||||
Builds a small but complete manuscript that exercises the real formatting
|
||||
rules (book start -> titlepage/copyright/dedication/epigraph/TOC/prologue/
|
||||
chapters with <<<>>> scene breaks -> back matter / about author / req review),
|
||||
runs it through format_document(), and writes:
|
||||
|
||||
tests/word_test_input.docx - the tagged source manuscript
|
||||
tests/word_test_output.docx - the FORMATTED DOCX to try in Word
|
||||
tests/python_docx_control.docx - plain python-docx save (Word baseline)
|
||||
|
||||
Usage: .venv/bin/python tests/make_word_test_files.py
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
from docx import Document
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from umbraformat.formatter import format_document
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
|
||||
def build_manuscript(path):
|
||||
"""Minimal tagged manuscript mirroring the real book section structure."""
|
||||
d = Document()
|
||||
paras = [
|
||||
"[book start]",
|
||||
"Sidney and Watson: Test Edition",
|
||||
"A Formatting Validation Novella",
|
||||
"B.D. Murphy",
|
||||
"[copyright]",
|
||||
"Copyright 2026 by B.D. Murphy. All rights reserved.",
|
||||
"Published by WorstAuthor LLC. No part of this publication may be "
|
||||
"reproduced in any form without the prior written permission of the "
|
||||
"publisher.",
|
||||
"[dedication]",
|
||||
"For every tester who ever bravely opened a broken file.",
|
||||
"[epigraph]",
|
||||
"\u201cThe formatting rules are the worst ones.\u201d \u2014 The Editor",
|
||||
"[TOC]",
|
||||
"[prologue]",
|
||||
"Prologue \u2014 Some time before the story, the investigation had "
|
||||
"already begun in earnest.",
|
||||
"The second prologue paragraph crossed the gutter calmly and expected "
|
||||
"no indent on its first line.",
|
||||
"[chapter]",
|
||||
"Chapter One: The Beginning",
|
||||
"It was the best of times in the kingdom of formatting. Every page was "
|
||||
"justified, every heading kept with next, and every footer held its "
|
||||
"page number centered in the gutter-safe zone.",
|
||||
"The second paragraph indents on its first line because the paragraph "
|
||||
"above it required no indent at all.",
|
||||
"<<<>>>",
|
||||
"After the scene break, the action resumed with fresh urgency and a "
|
||||
"brand new paragraph of prose.",
|
||||
"[chapter]",
|
||||
"Chapter Two: The Middle",
|
||||
"The middle chapter advanced the plot through mirrored margins, odd "
|
||||
"page starts, and lowercase roman numerals in the front matter.",
|
||||
"A further paragraph of supporting text kept the chapter from ending "
|
||||
"too soon, ensuring the running head had room to breathe.",
|
||||
"[chapter]",
|
||||
"Chapter Three: The Revelation",
|
||||
"The final chapter revealed the truth: the document opens in Word, "
|
||||
"and that is all that matters.",
|
||||
"<<<>>>",
|
||||
"A closing scene break, then a short denouement paragraph.",
|
||||
"And then the story was over, except for the back matter.",
|
||||
"[back matter]",
|
||||
"Appendix: The Appendix",
|
||||
"Reference material of a lengthy and largely optional nature.",
|
||||
"[about author]",
|
||||
"The author lives in a small town and writes at night.",
|
||||
"[req review]",
|
||||
"Reviewer: structure verified, page numbers centered, headers title-"
|
||||
"only, scene breaks preserved.",
|
||||
]
|
||||
for text in paras:
|
||||
d.add_paragraph(text)
|
||||
d.save(path)
|
||||
|
||||
|
||||
def build_control(path):
|
||||
"""Untouched python-docx document: does Word open this at all?"""
|
||||
d = Document()
|
||||
d.add_paragraph("Hello Word. This is a plain python-docx control document.")
|
||||
d.add_paragraph("If this opens but the formatted test file does not, the "
|
||||
"problem is in the formatting pipeline, not python-docx.")
|
||||
d.save(path)
|
||||
|
||||
|
||||
def main():
|
||||
with tempfile.TemporaryDirectory(prefix="umbraformat_word_test_") as tmp:
|
||||
src = os.path.join(tmp, "manuscript.docx")
|
||||
out = os.path.join(tmp, "formatted.docx")
|
||||
build_manuscript(src)
|
||||
format_document(
|
||||
src,
|
||||
out,
|
||||
font_name="Caladea",
|
||||
font_size=11,
|
||||
inner_margin=0.50,
|
||||
trim_size="5.5x8.5",
|
||||
author="B.D. Murphy",
|
||||
imprint="WorstAuthor LLC",
|
||||
strip_problematic_graphics=True,
|
||||
language="en",
|
||||
)
|
||||
shutil.copy(src, os.path.join(HERE, "word_test_input.docx"))
|
||||
shutil.copy(out, os.path.join(HERE, "word_test_output.docx"))
|
||||
build_control(os.path.join(HERE, "python_docx_control.docx"))
|
||||
print("wrote tests/word_test_input.docx, tests/word_test_output.docx, "
|
||||
"tests/python_docx_control.docx")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import shutil
|
||||
|
||||
main()
|
||||
Reference in New Issue
Block a user