Skip to content

Commit 46575b6

Browse files
authored
test: foreign-revision fixtures and scenarios (ISSUES.md #13) (#32)
* test: add foreign track-changes fixtures from docx-revisions (MIT) Two real-world fixtures copied from https://github.com/balalofernandez/docx-revisions: - OXML_TrackChanges_Test.docx: 8 revisions (4 w:ins + 4 w:del) from 6 authors, covering a del+ins replacement pair, an em-dash insertion next to smart-quote runs, and identical text inserted by one author and deleted by another in the same paragraph. - tricky-track-changes.docx: no revisions, but heavily fragmented runs (proofErr, bookmarks, lastRenderedPageBreak, formatting splits) that exercise cross-run search the way real Word output does. THIRD_PARTY_NOTICES records the source and reproduces the upstream MIT license. * test: promote replace_document_xml helper to conftest Move the word/document.xml swap helper from test_paragraph_location.py to conftest.py under a public name so other test modules can build synthetic .docx files without duplicating it. No behavior change. * test: cover foreign revisions, table lifecycle, fragmented-run search Closes ISSUES.md #13. New tests against the foreign fixtures plus synthetic documents: - parse all 8 foreign revisions with exact id/type/author/text/date, per-author filters, em-dash and smart-quote survival - accept_all/reject_all end-to-end, per-author accept/reject, and the conflicting insert/delete pair over identical text - partial accept survives save + reopen with the rest intact - rejecting a deletion keeps xml:space="preserve" on the restored w:t (Word-realistic delText) and attribute-less foreign delText still round-trips - tracked edits in table cells and nested tables accept/reject cleanly - cross-run search over real Word fragmentation (proofErr, bookmarks, superscript splits), plus find_in_text_map unit tests for many- fragment matches and matches ending mid-run Note: the fixture holds 4 w:ins + 4 w:del = 8 revisions total (the task description's "4 ins + 8 del" was wrong). * test: make fixture text assertions note-proof, compare Revision objects Review findings from the multi-reviewer pass: - The fixture's bracketed note runs quote expected outcomes verbatim, so several get_visible_text() substring assertions were satisfiable by a note instead of the body they meant to check. Route all such assertions through a _body_text() helper that strips the note runs; the reject-path and round-trip assertions are now genuinely discriminating and the accept-path assertions can no longer be satisfied by note text. - Replace the hand-ordered (id, type, author, text, date) tuples with Revision instances compared via the dataclass's own __eq__, removing the silent field reordering against the dataclass definition. - Simplify the reject_all em-dash check: with notes stripped, '— or is it?' must be absent outright. * test: address second review round in foreign-revision tests - Route the two remaining get_visible_text() assertions (smart-quote parsing check, tricky-fixture replace integration) through _body_text() so note runs can't satisfy them. - Assert revisions 1007/1008 actually leave list_revisions() after the conflicting-pair accepts. - Construct EXPECTED_REVISIONS with keyword arguments, matching the Revision construction convention in test_track_changes.py. - Fix inaccurate comments/docstrings: the pending-state body reads 'This sentence remains.' (single space); 'Quick Brown' has no note occurrence; the notes describe outcomes approximately, not verbatim. * test: apply final review-round nits - Guard against a doubled DRAFT after accept_all. - Verify Test Author's rejected insertion is gone from the body in the author-filtered reject test, not just the restored deletion. - Correct the 'Quick Brown' comment/docstring: it is a single-run match guarding against the note's 'ick Brown', not a fragmented one.
1 parent e580508 commit 46575b6

7 files changed

Lines changed: 479 additions & 24 deletions

‎tests/conftest.py‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import shutil
44
import tempfile
5+
import zipfile
56
from pathlib import Path
67

78
import defusedxml.minidom
@@ -16,6 +17,17 @@ def find_ref(doc, text):
1617
raise ValueError(f"Paragraph containing '{text}' not found")
1718

1819

20+
def replace_document_xml(src: Path, dest: Path, new_doc_xml: str) -> None:
21+
"""Copy ``src`` to ``dest``, swapping ``word/document.xml`` for ``new_doc_xml``."""
22+
with (
23+
zipfile.ZipFile(src, "r") as z_in,
24+
zipfile.ZipFile(dest, "w", zipfile.ZIP_DEFLATED) as z_out,
25+
):
26+
for item in z_in.infolist():
27+
data = new_doc_xml.encode("utf-8") if item.filename == "word/document.xml" else z_in.read(item.filename)
28+
z_out.writestr(item, data)
29+
30+
1931
NS = 'xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"'
2032

2133

9.92 KB
Binary file not shown.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
Third-party test fixtures
2+
=========================
3+
4+
The following files were copied from the docx-revisions project
5+
(https://github.com/balalofernandez/docx-revisions) and are distributed
6+
under the MIT license reproduced below:
7+
8+
- OXML_TrackChanges_Test.docx
9+
- tricky-track-changes.docx
10+
11+
-------------------------------------------------------------------------------
12+
13+
MIT License
14+
15+
Copyright (c) 2026 balalofernandez
16+
17+
Permission is hereby granted, free of charge, to any person obtaining a copy
18+
of this software and associated documentation files (the "Software"), to deal
19+
in the Software without restriction, including without limitation the rights
20+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
21+
copies of the Software, and to permit persons to whom the Software is
22+
furnished to do so, subject to the following conditions:
23+
24+
The above copyright notice and this permission notice shall be included in all
25+
copies or substantial portions of the Software.
26+
27+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
32+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33+
SOFTWARE.
14.1 KB
Binary file not shown.

0 commit comments

Comments
 (0)