Conversation
Mearman
force-pushed
the
feat/100-percent-mutation-document-cli
branch
2 times, most recently
from
September 14, 2026 18:46
93330af to
be0379d
Compare
createRuntimeSignal, readInput/writeOutput/resolveDefaultOutputPath, loadProvidedFonts, the diagnostic/font-substitution reporters and their raw-callback adapters, and the filesystem markdown image resolver had no direct unit tests at all -- every branch in them (SIGINT vs timeout precedence, stdin abort/non-buffer-chunk handling, json/quiet interaction in both the reporter and the summary line, the data:/scheme-URL/empty-destination guards) was reachable only through whatever an integration-level command test happened to exercise, if anything.
…ates isEditableFormat/isWritableFormat and their document-level wrappers, selectionKeyFor's per-screen-kind key derivation, selectedIndexFor's absent-vs-zero distinction, currentScreen's empty-stack invariant, rootScreenForFormat's per-format routing, and anyOverlayOpen's flag enumeration had no direct unit tests -- every screen-component test that happened to exercise one of these functions only ever hit whichever branch its own scenario needed.
…-message test FontSubstitution.reason is a closed union of "missing-face" | "vendored-substitute" (document-schema.js's own font-port types) -- "style-fallback" was never a valid value and only typechecked because the surrounding object literal had not yet been checked against it.
…on registrars The formats command's own table/JSON output and trailing not-covered line, and options.ts's addOutOption/addTimeoutOption/addJsonOption/ addQuietOption/addVerboseOption/addDumpPackageOption/addFontOptions/ addDelimiterOption/addSheetOption/addPageOption registrars, had no direct tests -- each option's flag string, short alias, default value, and coercion function were only ever reachable through whichever command happened to apply that helper and whichever flag a downstream test happened to pass.
formatSqlResultSetTable had no direct test: column-width derivation (header vs longest cell), the two-space gap, trailing-padding trim, the singular/plural row-count summary, and every ContentCellValue kind's own display text were only reachable through a real .odb fixture driven via the odb-query command.
…covers The HsqldbSql*Error branch and the PdfEncryptedError/PdfParseError branch each returned EXIT_INPUT_ERROR, identically to the function's own final fallthrough -- every mutation of either condition still produced the same exit code, since removing the branch entirely changes nothing observable. Folded both into the fallthrough's own comment instead of leaving an unkillable instanceof check standing, and added the missing test for UnsupportedFontSourceFormatError's own real EXIT_USAGE_ERROR branch plus direct tests for the three Hsqldb SQL error classes now reached only through that fallthrough.
metadataFor's own switch had no direct test: every editor-backed format's readXContent(doc.editor.toPackage()) call, doc/xls/ppt's and pdf's direct doc.editor.metadata/doc.layout.metadata reads, every read-only-preview format's identical doc.layout.metadata read, and odb's own no-metadata-concept throw were only reachable through whichever screen test happened to open that particular format. Also adds a direct test for detectFormat, the one-line named seam over inferFormatFromExtension.
renderOdbReportTo had no direct test: the destination-extension dispatch to docx/odt/pdf, the unknown-report-name failure naming the available reports, the extension-outside-docx/odt/pdf rejection, and fontFiles threading through to the pdf branch alone were only reachable through the odb-render-report CLI command's own tests, which exercise a structurally similar but separate code path (commands/odb.ts), not this TUI-side pipeline.
…ble helpers layoutColorToHex/isValidHexColorInput/parseHexColorInput, truncatePreview/parsePositiveIntField/parseNonNegativeIntField/ parseNumberField, and resolveSlideTable/slideTableCellText/ summarizeSlideTables had no direct tests -- byte-padding, the zero-vs-negative-vs-fallback boundaries each numeric field parser draws differently, the empty-preview marker, and the pptx/odp content dispatch (plus its out-of-range slide/table-index cases) were only reachable through whichever screen-component test happened to render a matching scenario.
parseColorField/parseStrokeField/defaultTriangleSubpaths and the six FORMULA_PRESETS entries had no direct tests -- the component-count and finite-value guards each parser draws, and every MathML string literal and tree shape in the presets, were only reachable through whichever odg/pptx/docx screen test happened to type a matching value.
odsDocument, resolveSheet, sheetExtent's floor/derive-from-cells/ derive-from-declared-rows-columns branches, cellKey, cellLookup, rawEditableText's per-kind rendering, inferKind's boolean/number/ string classification, and buildCellValue's per-kind parse-or-reject logic had no direct tests -- each was only reachable through whichever combination a spreadsheet-grid or cell-detail screen test happened to drive.
requirePdfDocument/isEditablePdfDocument, formatSize/formatPt/ formatColor/formatStroke, parseRequiredColorField's fallback, parseFontWeight/parseFontStyle, parseOptionalNumberField's blank-to- undefined behaviour, defaultTriangleLayoutSubpaths, inferImageFormat, and requireOdbDocument had no direct tests -- each was only reachable through whichever pdf/xlsx/csv/svg/rtf/wpd/epub or odb screen test happened to exercise a matching branch.
…ion-input hook GLOBAL_KEYS' own literal binding list, and useNavigationInput's clamped up/down/page/home/end movement, its Enter/Right/l select (including the itemCount === 0 no-op), its Escape/Left/h back call, and its optional onAppend branch had no direct tests -- reachable before only through whichever screen-component test happened to send a matching key sequence to whichever list screen it was testing.
…pper describeError's Error-vs-non-Error branches and saveOpenDocumentAction's SAVE_SUCCESS/SAVE_ERROR mapping (including the error message actually naming the destination path) had no direct tests -- only reachable before through whichever app-shell-level scenario a screen test happened to drive as far as an actual save attempt.
runGenericConvert's .odm/.odb rejection (each naming its real alternative command), the unresolvable-source and unresolvable-target failures, and --to winning over the output path's own extension had no direct test -- only the csv/svg selection-flag threading through this same command was previously exercised.
commands/odm.ts had no test at all: chapter resolution via --chapters-dir (matched by href basename) and via an explicit --chapter href=file override, the unresolved-chapter failure naming both flags, the malformed --chapter InvalidArgumentError, the conflicting-destination usage error, and the --json result summary were all unreachable. Adds a minimal hand-authored .odm fixture (test-support/odm-fixture.ts, mirroring documents.js's own internal odm test-support) since no .odm writer exists anywhere in this ecosystem to build one with.
…eens Adds ink-testing-library coverage for XlsSheetListScreen (default sheet render, add-sheet prompt including the blank-name warning and Escape cancel, and pushing the spreadsheetGrid screen) and XlsSpreadsheetGridScreen (hjkl/arrow cursor movement with origin clamping, double-letter column addressing past Z, editing an existing versus an empty cell, cancelling an edit, popping the screen on Escape, the compact non-empty-cells toggle, and the missing-sheet guard).
Adds ink-testing-library coverage for PptSlideListScreen (the empty presentation message, adding a slide via ADD_SLIDE, and pushing slideDetail on Enter) and PptSlideDetailScreen (shape geometry/text rows, the empty-shape placeholder, the trailing notes row and its default/populated text, the shape text editor's commit and cancel paths, the "n" notes hotkey and selecting the notes row directly, the add-text-box field wizard's default-accepting happy path and its Escape cancel, the missing-slide guard, and popping the screen on Escape while browsing).
Adds ink-testing-library coverage for CommandPalette: the full command list and its live filtering, exact-name-over-prefix resolution, unknown-command warnings, and every :save/:saveas/:export/:new/:open/ :close/:undo/:view-source/:help/:quit branch, including real round-trips through the filesystem (save, export to PDF, open) and their failure paths. A harness mirrors app.tsx's own overlay wiring (mount only while the overlay is open, reopen on ":") so each command starts from the palette's real closed-to-open lifecycle rather than a permanently mounted instance.
overlays and the status line Adds ink-testing-library coverage for six previously untested shared components: ConfirmDialog (every y/Y/Enter/n/N/Esc branch, and no-op on an unrelated key), HelpOverlay (renders every GLOBAL_KEYS row, closes on Esc/?/Enter), DiagnosticsPanel (page-scoped vs plain diagnostic formatting, the empty-list message, dismissing the selected entry, closing the panel), ErrorDetail (message plus optional detail line, dismiss on Esc/Enter, the empty-box case with no error set), and SearchOverlay (live query updates, keep-on-submit vs clear-on-cancel, starting pre-filled). StatusLine gets its own statusColour helper exported for a direct unit test (ink strips ANSI colour codes from a non-TTY render, so a rendered frame can never distinguish colours) plus real-time-driven coverage of its transient-status TTL: an info/warning status clears itself after TRANSIENT_STATUS_TTL_MS (now exported so the test derives its wait from the real constant) and an error status never does.
The prior 6-second buffer over the transient-status TTL occasionally missed the frame update under heavy concurrent CPU load on this shared machine, since the effect's real setTimeout can fire well past its nominal delay when the process is starved of CPU time. Widen the margin so the wait comfortably outlasts realistic scheduling delay.
Multiple concurrent checker/test-runner processes were crashing with SIGSEGV under this shared machine's own heavy concurrent load. Pinning concurrency to 1 trades throughput for a run that actually completes.
This reverts commit 50493de.
loadProvidedFonts, readInput, and renderOdbReportTo each forward options.signal into node:fs/promises' readFile, but nothing exercised the signal actually reaching that call: an already-aborted controller now causes each of them to reject instead of silently reading the file to completion.
… and its local query echo TextField only wires its Escape-to-cancel useInput handler while isFocused is true; nothing exercised the unfocused case, where Escape must reach neither onCancel nor anything else. SearchOverlay separately mirrors every keystroke into its own local `query` state (rendered by its child TextField) as well as into dispatched state -- only the dispatched half had a covering assertion, leaving the local echo free to silently stop updating without any test noticing.
… colour and its --help text DiagnosticsPanel colours only the selected row's Text cyan; nothing distinguished that from every row (or none) getting the same treatment. The formats command's own --help text was likewise never read back anywhere, leaving its description and --json option strings free to change without any test noticing.
…idation's isValidHexColorInput's internal trim already covered the validation half; a leading/trailing-whitespace hex string previously reached rgbHexToColor untrimmed once past validation, relying on trim only being read, never proven load-bearing at the point that actually matters.
…/pptx slide-list guard throws RotationField's non-editing row colours itself cyan only while selected, mirroring the same pattern already covered elsewhere in this suite. OdpSlideListScreen and PptxSlideListScreen each guard against rendering with the wrong (or no) open document, a throw ink's own render() swallows entirely via its no-op onUncaughtError callback -- renderToString propagates it instead, so it is the only way to prove these guards actually fire.
…own live-view editors UNDO's own format switch still treated doc/xls/ppt as the read-only, no-live-editor formats they used to be, so a document opened as one of these accumulated real undo snapshots via mutate() on every edit but could never pop one back off -- UNDO reported "read-only, so it has no history to undo" even immediately after a genuine, undoable edit. These three formats gained real live-view editors and their own reopenEditable case in the same change that widened EditableOpenDocument to include them; the UNDO exclusion list was never updated to match.
…ormat branch Adds reducer-level coverage for the PDF ADD_PDF_ELLIPSE/LINE/PATH/IMAGE/ LINK actions, field edits on every non-text PDF item kind (rect, ellipse, line, path, image, link) including their own wrong-kind warning paths, the remaining SET_PDF_TEXT_* fields and the underline toggle's on/off round trip, and reopenEditable's pptx/odt/odp/ods/odg/doc/xls/ppt undo branches -- previously only docx and pdf were exercised there.
These three commands had no test coverage at all: default and explicit output path resolution, the --out flag, the conflicting-destination usage error (including the equal-values non-conflict case), --table selection and its not-found error, and odb-tables' plain-text and --json report forms.
Only --full had any coverage. Adds the plain-text report (page count singular/plural, the per-page item-kind histogram and its empty-page omission, the metadata and images-by-format sections and their all-empty omission), the --json summary shape, and the non-PDF-input error path.
…gets, and version-gate errors Adds coverage for the positional/--out conflict and agreement checks, the --out flag on its own, a genuine SchemaVersionMismatchError (a document-tree.schema.json dump pinned to a major other than the installed one, distinct from the rename/demotion tombstones already covered), invalid-UTF-8 input bytes, and the csv/svg target branches with --delimiter/--page threaded through, plus --json/--quiet output.
cli-main.ts had no test coverage at all. Adds the bare-invocation TTY gate (launches the TUI vs. shows help), the explicit 'tui' token's own TTY refusal and start-path resolution (skipping leading flag tokens), launchTui's own error-to-exit-code mapping, and both the registered 'tui [file]' subcommand and the CommanderError-vs-genuine-bug split in the ordinary command dispatch path.
…y branch The odt branch (a real OdtList) already had its own describe block; this action's other branch -- appending a new paragraph and copying the anchor paragraph's own list membership, the docx/markdown path with no separate list object -- had no dispatch anywhere, including its two warning paths (no paragraph at blockIndex, and an anchor not part of a list).
…on reporting --out on its own (only the positional-vs-flag conflict was covered before) and the reportFontSubstitution branch (a Calibri-styled chapter substituted to the vendored carlito face under --report-font-substitutions, and silent without it), mirroring the identical scenario convert-fonts.test.ts already covers for the other <format>-to-pdf commands.
… module constant Stryker's per-test coverage instrumentation attributes a module-scope constant's one-time initialisation to whichever test happens to trigger the very first import of the module across the whole suite, since module caching means every later importer just reads the already-built array. A mutant in the literal was therefore only ever re-verified against that unrelated first-importing test, never against formula-presets.test.ts's own assertions. Rebuilding the array inside a function makes each call site's own execution the thing coverage attributes to, so this file's exhaustive tests are what actually re-run against a mutant.
…ormat table isDocumentFormat, inferFormatFromExtension, and formatToExtension were only exercised for the earlier office/markup formats; wpd, doc, xls, ppt, and epub had no case asserting their own membership, extension inference, or round-trip extension.
xmlDeclaration, txt, and el had no direct test of their own; every existing use only exercised them indirectly through the fixtures that call them, leaving each builder's own default-argument and attribute- ordering behaviour unasserted.
…run timeout document-cli's TUI suite spawns and manages child processes and pseudo- terminals; running mutants at the default concurrency let sibling workers race over the same terminal/process resources and produced flaky, environment-dependent failures unrelated to the mutated code. Concurrency of 1 and a longer dry-run timeout make a run reproducible at the cost of wall-clock time.
FORMAT_TO_EXTENSION was a module-scope object literal, so Stryker's per-test coverage instrumentation attributed its one-time initialisation to whichever test happened to trigger the first import of format.ts in the whole suite, never to the tests that actually call formatToExtension with a given format. A mutated extension value therefore survived even though formatToExtension's own exhaustive test asserts on every entry. Rebuilding the table inside a function called on every lookup makes each call site's own execution the thing coverage attributes to.
… its table is gone The useInput handler returned before reaching any key check whenever resolveSlideTable came back undefined, so the fallback view's own "press Esc to go back" text was a lie: no key, Escape included, ever did anything. Esc now still pops the screen in that state; every other key remains a no-op since there is no grid left to act on.
…-clamp paths Adds coverage for branches no existing test touched: the table-no-longer-exists fallback (and that Esc, uniquely, still works there), cursor clamping at every edge of the grid via individual h/j/k/l presses, and committing a pending merge with Enter rather than a second 'm'.
Nothing exercised the outside-screen guard, the no-open-document guard, or the out-of-range blockIndex guard -- all three early returns above the screen's real render path were dead as far as the suite could tell.
UNDO's read-only branch names one of seven formats (odb/xlsx/csv/svg/ rtf/wpd/epub) in its warning text, but nothing dispatched UNDO against any of them -- every existing undo test opened an editable format instead, leaving the whole seven-way format check and its templated message unexercised.
…maining format/kind guards Covers withShape's "page" wording for an odg missing-shape warning, previously only exercised via the pptx "slide" branch, each of the nine formats OPEN_FILE_SUCCESS names individually in its read-only-PDF-preview note, and the wrong-kind guards for SET_PDF_INTERNAL_LINK_DESTINATION and SET_PDF_INTERNAL_LINK_FRAME.
…e literal 'main' actions/checkout leaves a detached HEAD with no local main branch (only origin/main), so turbo's --affected fell back to "assume all files have changed" on every pull_request run, sharding the entire 23-package workspace regardless of how narrow the actual diff was. Setting TURBO_SCM_BASE to the PR's base commit sha, mirroring ci.yml's own working setup, lets turbo resolve the real diff range instead of guessing.
…format union arms Adds exact-boundary tests for mergePptxTableCells's row/column overrun checks (a merge landing exactly on the table's last row/column must succeed, not throw), direct hMerge/ vMerge attribute assertions distinguishing the row-loop and column-loop merge flags from each other, and loop-boundary checks proving cells past rowSpan/colSpan are never touched. Also covers wrongDocument's "no document" wording when nothing is open at all, and the doc-format arm of wordprocessingDocument/styledWordprocessingDocument, which nothing else in this suite previously exercised through APPEND_PARAGRAPH or TOGGLE_RUN_BOLD.
…d wrong-doc-type warnings Pins the literal warning text for the missing-paragraph-index, missing-page-index, and markdown-wrong-document-type branches so a StringLiteral mutant on any of these messages fails the assertion instead of surviving on severity alone.
…ranch withPdfItemMatching's kindLabel string is a separate literal at every call site, so the existing FRAME/FILL/one-per-kind wrong-kind tests only killed the mutant at their own call site. Adds a data-driven case per action that had none (text's own text/position/color/ width/underline setters, rect's stroke, ellipse's frame/stroke, all three line setters, path's fill/stroke, image's frame/source, and link's frame), each asserting the exact kindLabel substring so a StringLiteral mutant on any of them fails the assertion.
…-doc guard mutableMathMlNode had no coverage at all before this: an element/text node is rebuilt as a fresh mutable tree so document-schema.js's mutable MathMlNode type-checks with no cast, and the four kinds MathML content never carries (cdata/comment/declaration/pi) collapse to the documented empty stand-in each schema variant requires. Reads the round-tripped formula back through readOdtContent/formulaOfBlock to assert on the real embedded package, plus a second case for the wrong-document-format warning.
The odg branch's own inner switch (addRect/addEllipse/addLine/addPath) had only ever been reached via ADD_RECT; each case is a separate switch-statement mutant, so nothing proved removing the ellipse/line/path cases would still pass. Adds each kind through the page's own vectors() accessor, mirroring the equivalent odp coverage already in this file.
CANCEL_QUIT had no coverage at all -- its own confirmQuit-overlay-false write and isExiting-stays-false behaviour were unproven, and CONFIRM_QUIT's sibling write to the same overlay field was reached but never asserted. SAVE_ERROR likewise had no test: it now asserts the exact error message surfaces as status text with hasUnsavedChanges left untouched.
withWideShape's identical ternary was already covered via SET_SHAPE_TEXT, but withShape is a separate function with its own copy of the same literal, reached only by SET_SHAPE_ROTATION. Adds the missing odg case so removing withShape's own page/slide branch fails too.
OPEN_FILE_ERROR, SAVE_AS_REQUEST, SET_SEARCH_QUERY, CLEAR_STATUS, DISMISS_ERROR_DETAIL and SET_RUN_TEXT had no coverage anywhere in the suite -- each is a plain state-field write with no format branching, so one direct dispatch per action proves the write.
…uards Nothing in the suite ever dispatched SET_TABLE_CELL_TEXT before this: the missing-table and missing-cell warnings, and the actual cell-text write itself (verified through a real readDocxContent round trip), all had zero coverage.
ADD_PDF_TEXT (add a second real text item, round-tripped through toBytes()/openPdf()) and INSERT_DOCX_FORMULA (both the written-OMML happy path, read back through readDocxContent's own embedded-formula splice, and the no-OMML-content warning branch) had no coverage anywhere in the suite before this, plus INSERT_DOCX_FORMULA's missing-paragraph and wrong-document-format guards.
…tions None of ADD_SLIDE, ADD_PAGE, ADD_TEXTBOX, ADD_IMAGE, SET_SHAPE_FRAME or SET_SHEET_PRINT_SETTINGS had any coverage anywhere in the suite. Adds a real happy-path dispatch per action on pptx and/or odg, plus the missing-page/slide and wrong-document-format guards for the two dual-branch actions (ADD_TEXTBOX, ADD_IMAGE).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds unit tests for document-cli covering command dispatch (convert, odm-to-pdf), error description helpers, the async save-action wrapper, the global key table, the shared navigation-input hook, and shared PDF/ODB editor screen helpers.
Current state: work in progress toward a genuine 100% Stryker mutation score for this package (breakThreshold currently 32, derived from a 33.33% baseline of 6241 valid mutants). Not yet at 100%; more survived/no-coverage mutants remain to be addressed before breakThreshold can be raised further.