Skip to content

test(odt): stronger validation assertions, coverage for validator/styles/package, LibreOffice-authored fixtures - #230

Merged
vaceslav merged 1 commit into
mainfrom
test/odt-quality
Sep 26, 2026
Merged

vaceslav merged 1 commit into
mainfrom
test/odt-quality

Conversation

@vaceslav

Copy link
Copy Markdown
Contributor

Test-quality items from the OpenDocument review (#138). These tests found four library bugs. Each was fixed in its own PR, already merged: #226, #227, #228, #229.

Changes

Stronger validation assertions (OdtValidationTests)

  • Tests use Assert.Single / Assert.Equal on error types, counts, exact messages and locations, and on AllPlaceholders / MissingVariables / warnings, instead of mostly Contains.
  • New cases: invalid condition location and deduplication, {{#elseif}} after {{#else}}, the ReservedWordAsVariable warning (text and location), WarnOnEmptyLoopCollections = false, and single reports for unmatched list-item/row markers.

Validator coverage

  • OdtValidationParityTests: 21 paragraph templates validated as .docx and .odt, without and with data. They must give identical errors (type and message), warnings, AllPlaceholders, MissingVariables and IsValid. The cases cover placeholders, syntax errors, orphan end markers, invalid and nested invalid iteration variables, reserved words, condition variables, named and implicit nested loops, empty, missing, null and scalar collections, JSON data, POCO items with nulls, conditionals in loops, inline conditionals and unmatched loops with bodies.
  • OdtValidationScopeTests (18 tests) cover the scope walker:
    • loops nested in table cells of row loops, row loops inside paragraph loops, list-item loops with nested loops, and loops in sections, text boxes, notes, headers and footers, index bodies and row groups
    • page-anchored shapes, empty containers, item-relative missing collections, nested empty collections
    • conditionals on item properties, JSON arrays and objects, POCO items with nulls
    • unmatched loops with data, annotations and tracked deletions (not validated), and an IOException while reading (InvalidDocument)

Styles, package, engine

  • OdtTextStylesTests: no formatting, part without root, reuse of a LibreOffice-written style, seven styles that must not be reused (parent, extra property, partial bold, extra child, nested child, other family, empty name), names blocked by any style name of the part and by reserved names, combined formatting, per-part cache, and creation of office:automatic-styles in schema order.
  • OdtPackageBranchTests:
    • .ott without a manifest (and with a thumbnail)
    • no mimetype with a malformed manifest ("media type: none")
    • added parts listed or not listed in the manifest
    • GetXml of a non-XML entry
    • a seekable output that cannot change its length
    • the 65,535-entry limit
    • the MB wording of the part size limit
  • OdtEngineBranchTests: index bodies (the source is untouched), shapes with paragraphs in the body, row groups emptied by conditionals, tables whose rows are all in groups, list items emptied by in-item conditionals, leftover markers (compared with the Word output), and lists in annotations inside loops.

LibreOffice-authored fixtures (TriasDev.Templify.Tests/Odt/Fixtures/*.odt, copied to the output)

  • lo-invoice.odt: header and footer (split placeholder in the header with LibreOffice's MT1 style, page-number field), rsid spans (officeooo:rsid), text:s runs, a header-rows table with a named row loop, @number, a covered cell, if/elseif/else, markdown.
  • lo-containers.odt: bullet list-item loop with an inline conditional, numbered list with a list-item conditional, text box (frame) with a loop, footnote, protected section with a conditional.
  • lo-long-document.odt: several pages. LibreOffice wrote text:soft-page-break elements inside paragraphs, including one inside the loop body, and there is a long table with a row loop.
  • lo-from-word.odt: a .docx with rsid-split runs converted by LibreOffice (bold style without complex-script weight).
  • Sources are in Odt/Fixtures/Sources (.fodt files and the .docx). The fixtures were saved by LibreOffice 26.8 with a layout pass, a Basic macro that calls jumpToLastPage and then storeToURL. A plain --convert-to odt writes no soft page breaks. OdtLibreOfficeFixtureTests (12 tests) processes and validates them without LibreOffice, so they run in CI. OdtLibreOfficeRoundTripTests.LibreOfficeFixtures_ProcessedOutput_IsReadBackUnchanged (LibreOffice trait, local) resaves each processed fixture in LibreOffice and compares all paragraph, header and footer texts.
  • Helpers: OdtDocumentVerifier.ToBytes().

Tests

Coverage of TriasDev.Templify.Tests on net10.0 (coverlet, lines of each file):

Class Line before Line after Branch before Branch after
OdtTemplateValidator 83.5% 96.9% 78.3% 94.5%
OdtTextStyles 81.5% 100% 72.7% 100%
OdtPackage 93.9% 99.4% 83.1% 89.0%
OdtTemplateEngine 94.4% 98.7% 86.5% 92.2%
OpenDocument + facade total 93.9% 97.3% 86.7% 91.8%

Still uncovered:

  • the validator's JSON-element branches. Data is converted before it reaches them; the same code exists in the Word validator.
  • the generic "Validation failed" catch
  • an entry whose inflated size exceeds its declared size

Local runs: Release CI build (-p:ContinuousIntegrationBuild=true, 0 warnings); TriasDev.Templify.Tests net10/9/8 (2,230 each, LibreOffice round trips included); Tools.Tests 63; Converter.Tests 95; dotnet format --verify-no-changes; dotnet pack.

Public API impact

None. Only test code, test helpers and test fixtures change. The csproj copies Odt/Fixtures/*.odt to the test output.

…les/package, LibreOffice-authored fixtures

Exact error types, counts and messages in OdtValidationTests; ODT/Word validation parity tests; scope tests for loops in tables, lists, sections, text boxes, notes, indexes and headers; OdtTextStyles, OdtPackage and engine branch tests; four LibreOffice-written fixtures (Odt/Fixtures) processed without LibreOffice, plus local LibreOffice round trips (#138).
@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@vaceslav
vaceslav merged commit a6bcb8f into main Sep 26, 2026
12 checks passed
@vaceslav
vaceslav deleted the test/odt-quality branch September 26, 2026 17:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants