From 47bbbfc7ddd0aabac8c6a10062661f4612d2a59b Mon Sep 17 00:00:00 2001 From: Steffen Becker Date: Sat, 15 Aug 2026 22:53:36 +0200 Subject: [PATCH] test: cross-format fuzz leg, ODT vs DOCX round-trip The same seeded documents go through buildOdt->importOdt and buildDocx->importDocx; the two imports must agree, so one exporter silently losing what the other keeps now fails with the seed named. Column widths are ignored here (ODT leaves defaults implicit, DOCX always writes w:tcW); each format's own leg still covers them. --- tests/fuzz-roundtrip.test.ts | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/fuzz-roundtrip.test.ts b/tests/fuzz-roundtrip.test.ts index 16a9ee9..164db4b 100644 --- a/tests/fuzz-roundtrip.test.ts +++ b/tests/fuzz-roundtrip.test.ts @@ -3,6 +3,8 @@ import { describe, it, expect } from 'vitest'; import { buildOdt } from '../src/lib/export/odt'; import { importOdt } from '../src/lib/import/odt'; +import { buildDocx } from '../src/lib/export/docx'; +import { importDocx } from '../src/lib/import/docx'; import { normalize, firstDiff } from './normalize'; import { genDoc, mulberry32 } from './fuzzDoc'; @@ -30,4 +32,28 @@ describe('fuzz round-trip: editor → buildOdt → importOdt', () => { expect.soft(diff, `seed ${seed} (re-run genDoc(mulberry32(${seed})) to reproduce)`).toBeNull(); } }, 120_000); + + // ODT leaves default column widths implicit where DOCX always writes w:tcW; ignore + // them in the cross-format comparison (each format's own leg still covers widths). + function stripColwidth(node: any): any { + if (node.attrs?.colwidth) { + delete node.attrs.colwidth; + if (!Object.keys(node.attrs).length) delete node.attrs; + } + for (const c of node.content ?? []) stripColwidth(c); + return node; + } + + // Cross-format: the same document through both pipelines must import identically — + // catches one exporter silently losing what the other keeps. + it('50 seeded documents agree between the ODT and DOCX round-trips', async () => { + for (let seed = 1; seed <= 50; seed++) { + const doc = genDoc(mulberry32(seed)); + const viaOdt = importOdt(await buildOdt(doc, margins, 'portrait')).content; + const viaDocx = importDocx(await buildDocx(doc, margins, 'portrait')).content; + const diff = firstDiff(stripColwidth(stripFontHoist(normalize(viaOdt))), + stripColwidth(stripFontHoist(normalize(viaDocx)))); + expect.soft(diff, `seed ${seed}: ODT vs DOCX import (genDoc(mulberry32(${seed})))`).toBeNull(); + } + }, 120_000); });