Some checks failed
makepad-table / model (push) Has been cancelled
makepad-table / widget (push) Has been cancelled
makepad-table / hygiene (push) Has been cancelled
PDF engine / engine (push) Has been cancelled
PDF engine / makepad-integration (push) Has been cancelled
PDF engine / fuzz (push) Has been cancelled
Payment domain, storage, platform and UI / isolated-payment-tests (push) Has been cancelled
Payment domain, storage, platform and UI / payment-ui-tests (push) Has been cancelled
repo hygiene / hygiene (push) Has been cancelled
doc-engine / engine (push) Has been cancelled
doc-engine / coverage (push) Has been cancelled
doc-engine / consumer (push) Has been cancelled
email / gates (push) Has been cancelled
email / email-domain (push) Has been cancelled
email / nigig-email (push) Has been cancelled
email / supply-chain (push) Has been cancelled
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
nigig-build (CAD) / doc-workspace-coverage (push) Has been cancelled
nigig-build (CAD) / cad-widget-coverage (push) Has been cancelled
nigig-map / test (push) Has been cancelled
sms / gates (push) Has been cancelled
sms / robius-sms (push) Has been cancelled
sms / android (push) Has been cancelled
sms / nigig-sms (push) Has been cancelled
sms / supply-chain (push) Has been cancelled
spreadsheet / engine-coverage (push) Has been cancelled
spreadsheet / ui-controller-coverage (push) Has been cancelled
99 lines
4.7 KiB
Markdown
99 lines
4.7 KiB
Markdown
# Doc-workspace source coverage
|
||
|
||
`tools/test-doc-workspace-coverage.sh` measures line/region coverage for the
|
||
**pure** (widget-free) part of this module and enforces floors in CI
|
||
(`.forgejo/workflows/nigig-build.yml`, job `doc-workspace-coverage`). The same
|
||
suite also runs uninstrumented inside `cargo test -p nigig-build --lib`, so
|
||
every test executes twice: once in the real crate and once in the harness.
|
||
|
||
## How it works
|
||
|
||
The script copies the dependency-free sources — `advanced_json.rs`,
|
||
`crdt_bridge.rs`, `mobile_gesture.rs`, `persistence.rs`,
|
||
`projection_layout.rs`, `projection_session.rs`, and the `collaboration/`,
|
||
`editing/`, `layout/`, `model/`, `plugins/` trees — plus `tests_pure.rs`
|
||
byte-for-byte into a temporary host-only crate with the real module path. A 30
|
||
line `makepad-widgets` shim (re-exporting `makepad_math` plus the `log!` /
|
||
`error!` macros) satisfies the only Makepad symbols the pure layer uses
|
||
(`DVec2`, `Rect`, `Vec4f`, `dvec2`, `vec4`).
|
||
`doc-engine` is included as a path dependency because the pure projection code
|
||
sits on top of it.
|
||
|
||
The harness then installs its own pinned toolchain with
|
||
`llvm-tools-preview` into the same temp dir, runs the suite under
|
||
`-C instrument-coverage`, and enforces:
|
||
|
||
* a **total** line floor (`DOC_WS_COVERAGE_TOTAL_FLOOR`), and
|
||
* a **per-file** floor for every instrumented source
|
||
(`DOC_WS_COVERAGE_PER_FILE_FLOORS`).
|
||
|
||
The per-file floors are the point: deleting one file's whole test section
|
||
moves the total by a point or two and a lone number would wave that through.
|
||
Lowering a floor is a reviewable edit to the script, not something to do
|
||
quietly. Everything — toolchain, cargo home, target dir, fetched Makepad
|
||
tree, profraw data — is removed by a shell trap on every exit path; nothing
|
||
is written into the repository or `$HOME` unless `KEEP_COVERAGE=1` is set.
|
||
|
||
## Running it
|
||
|
||
```sh
|
||
./tools/test-doc-workspace-coverage.sh # gated run (CI)
|
||
DOC_WS_COVERAGE_REPORT_ONLY=1 ./tools/test-doc-workspace-coverage.sh # measure only
|
||
KEEP_COVERAGE=1 ./tools/test-doc-workspace-coverage.sh # keep uncovered-lines.txt + report
|
||
```
|
||
|
||
## Latest measurement (2026-08-17)
|
||
|
||
| File | Lines covered |
|
||
| --- | --- |
|
||
| TOTAL | **96.76%** (6170 lines) |
|
||
| advanced_json.rs | 98.02% |
|
||
| crdt_bridge.rs | 95.45% |
|
||
| mobile_gesture.rs | 100% |
|
||
| persistence.rs | 65.85% (see exclusions) |
|
||
| projection_layout.rs | 98.52% |
|
||
| projection_session.rs | 100% |
|
||
| collaboration/* | 100% |
|
||
| editing/commands.rs | 93.39% |
|
||
| editing/controller.rs | 93.39% |
|
||
| editing/history.rs | 95.65% |
|
||
| layout/* | 94–100% |
|
||
| model/* | 91–100% |
|
||
| plugins/mod.rs | 100% |
|
||
|
||
## What is intentionally not measured
|
||
|
||
* **The widget layer** — `mod.rs`, `crdt_widget.rs`, `widgets/`, `render/`,
|
||
`projection_renderer.rs`, `tests.rs`. These need `live_design!`, a `Cx`,
|
||
and an event loop; they are gated by the full `nigig-build` build/test CI
|
||
jobs instead. The split is deliberate: `tests_pure.rs` contains everything
|
||
that can run host-only, and both files are compiled into the crate's normal
|
||
test suite.
|
||
* **`persistence.rs` write paths** — `save_doc_state` / `save_doc_state_as` /
|
||
`load_saved_doc_state` resolve the host's real application-data directory
|
||
and unconditionally write into it. They are thin wrappers over
|
||
`save_doc_state_to` / `load_saved_doc_state_with`, which the tests drive
|
||
with explicit temp paths; the wrappers themselves are covered by the
|
||
widget-runtime tests on device. This is why `persistence.rs` keeps a lower
|
||
floor (55%) — do not lower it further without a genuine new exclusion.
|
||
* **Defensive guards** — cycle guards in RGA/block-order traversal
|
||
(`seen.insert` `continue` arms), unreachable block-id parse failures inside
|
||
`layout_projection` (engine ids always contain `actor:counter`), and the
|
||
`unreachable` canvas-text serialization arm's sibling rejections in
|
||
`advanced_json.rs`. They exist for invariant defense; there is no honest
|
||
public-API path that reaches them.
|
||
|
||
## Defects found by this coverage drive (fixed with tests)
|
||
|
||
1. `editing/commands.rs::ReplaceBlockRange` validated the explicit
|
||
`block_ids` length **after** draining blocks out of the document, so a
|
||
malformed command destroyed content before reporting failure. Validation
|
||
now happens before any mutation; a test pins that a rejected replace
|
||
leaves blocks and ids untouched.
|
||
2. `model/crdt.rs::visit_children` was dead code (a String-collecting
|
||
duplicate of `visit_atoms` with no callers). Removed.
|
||
3. Multi-peer atom-id collisions: two `CrdtMetadata::default()` peers mint
|
||
identical `AtomId`s, so a concurrent insert silently resurrects instead
|
||
of inserting. The sync test now assigns distinct
|
||
`document.crdt.local_actor`s — matching how real peers must be
|
||
provisioned — and pins the convergent `"hi!"` exchange.
|