Commit af48854
test(export): validate glTF against Khronos, and read our DXF back with a foreign parser (#3091)
* test(export): check glTF, COLLADA and DXF against the formats, not our own readers
Three export formats had no external validator and no third-party fixture
anywhere in the repo. The only reader of a GLB we write was our own
`parseGLB`; the only reader of a DXF we write was our own `parser.ts`;
COLLADA had no reader at all and every assertion was a substring of the
output. A writer and a reader that agree with each other prove they share
a convention, not that the convention is the format.
Test-only. No exporter behaviour changed, and every check below was
mutation-proved: the writer was broken, the check was confirmed to fail,
and the writer was restored.
glTF - `scripts/test-wasm-contract.mjs` now runs the Khronos glTF-Validator
(`gltf-validator`, the reference implementation, ~400 KB of self-contained
JS, no network at runtime, pinned to an exact version because its output IS
the assertion) over the GLBs the real wasm exporter produces on both entry
points, failing on errors AND warnings. `gltf_tests.rs` has NAMED that
validator in a comment since #1516 without ever invoking it.
It reports 0 errors and 0 warnings on today's output, across the from-bytes
and from-meshes paths and across the committed samples, so a second test
pins that the validator saw real geometry - a clean report over an empty
GLB is the "check that cannot fail" trap, and the validator is perfectly
happy with a file that declares none.
`rust/export/src/gltf_conformance_tests.rs` adds the spec rules that lane
cannot reach: `quantize` and the bounded/streaming assembler have no wasm
binding, and they carry the unusual byte layouts. Checked there and nowhere
else before: accessor TOTAL byteOffset alignment (bufferView offset plus
accessor offset, against component size), declared `min`/`max` recomputed
from the bytes actually written, index values against the primitive's own
vertex count, `mode`/`componentType` legality on the f32 path, and the GLB
chunk framing including which byte each chunk pads with.
Writing it found a test-side trap worth naming: reaching the streaming
assembler by setting `IFC_LITE_GLB_STREAM_THRESHOLD_MB=0` silently exercises
the IN-MEMORY path, because 0 means "disabled" (`usize::MAX`). Only
mutating the bounded assembler's bufferView offsets and seeing nothing fail
revealed it; the test now calls `export_glb_streaming_bounded` directly.
COLLADA - `rust/export/src/collada_conformance_tests.rs` checks the
document's internal agreement: `count=` attributes against the data they
introduce, every `#reference` resolving to a declared `id`, `<p>` indices
inside the accessor they index, and `<input offset>` against the `<p>`
stride. An out-of-range `<p>` index leaves all eleven pre-existing COLLADA
tests green.
DXF - `packages/drawing-2d/src/dxf/writer-interop.test.ts` reads the
writer's output back with `dxf-parser` (npm, MIT), an unrelated third-party
reader, and separately pins the raw group codes against the R12 rules a
lenient reader never needs, because it does not need them: POLYLINE's `66`
vertices-follow flag, the TEXT alignment point `11/21/31` that must
accompany a non-zero `72`/`73`, section/table balance, and the absence of
any post-R12 group code. Dropping the alignment point leaves all 74 other
DXF tests green - our own parser cannot see it.
No CI step gained a network dependency and no fixture was committed: all
three additions run inside lanes that already exist.
* test(drawing-2d): group 5 is not a post-R12 code, so stop asserting it is
The R12 conformance test forbade group 5 (handle) alongside 100/330/370/
410/420 under the rationale that all of them are post-R12. That is wrong
for 5: R12 permits optional entity handles, gated on $HANDLING. The
assertion was right about our output and wrong about the format, and the
comment stated the false half.
Split it. The post-R12 test keeps the five codes that genuinely postdate
AC1009. A separate test pins the absence of handles as what it actually
is — our deliberate choice, carrying the contract a writer would take on
by emitting them ($HANDLING plus a $HANDSEED above every handle used).
No assertion is dropped: group 5 is still required to be absent, and the
new test says what a future writer emitting handles must do instead of
deleting it.
Mutation-checked: emitting `5\n2F` on LINE in writer.ts fails
"emits no entity handles, so no $HANDLING/$HANDSEED contract is implied"
and nothing else. Reverted. drawing-2d 402 passed across 35 files, with
writer-interop 12 -> 13.
---------
Co-authored-by: Louis Trümpler <78563314+louistrue@users.noreply.github.com>1 parent bc2e5e5 commit af48854
10 files changed
Lines changed: 1143 additions & 11 deletions
File tree
- .changeset
- packages/drawing-2d
- src/dxf
- rust/export/src
- scripts
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
90 | 90 | | |
91 | 91 | | |
92 | 92 | | |
| 93 | + | |
93 | 94 | | |
94 | 95 | | |
95 | 96 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
23 | 23 | | |
24 | 24 | | |
25 | 25 | | |
| 26 | + | |
26 | 27 | | |
27 | 28 | | |
28 | 29 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
0 commit comments