test
Tests that span the package rather than one module, and the tools that serve them. The
statement of the dialect is docs/grammar.md. Here are the inputs, the
harness that reads and judges them, the checks, and the tools that measure markz and show it.
examples/: examples, each a small input with what it must give.upstream/holds the vendored suites, one file each, with the sweeps curation keeps off the Quality page inupstream/stress/.markz/holds markz's own, one file per construct and one for the Not supported rows, numbered asmarkz:17, some labelled with the edge they try.documents/: real documents written by people and by agents, vendored and pinned. markz's own docs join them as a tier, read in place. The variants built from them are never committed.harness/: the machinery the checks and the Quality page share, with no tests of its own: the grammar, the examples and their filing, the oracles, the cases at each construct's edges, generation and soundness.
The checks:
dialect.test.ts: what the others stand on. The grammar is well formed and issyntax.md's, every warning is named there, the filing names real examples and numbers markz's own once, each vendored file is asfences.tswrites it, and the oracles match the suites' own answers.constructs.test.ts: each construct in its owndescribe, held to its upstream examples, its own examples by edge, and the cases generated at its edges; each Not supported row to its examples.robustness.test.ts: noise, mutated examples and documents written from the grammar, each held to being sound, and the CommonMark and GFM ones to the oracle; and the upstream sweeps, held to finishing, a valid tree and a warning for every bare URL GFM links.documents.test.ts: each real document, sound as written and formatted, its common blocks as micromark reads them, meaning the same after oxfmt, and warning as its snapshot in__snapshots__/says.docs.test.ts: each page indocs/read without a warning, and its relative links going to files that exist.complexity.test.ts: every adversarial pattern, and a multi-megabyte document, held to linear time. It runs last, on its own.
The tools are plain Node scripts, each a pnpm command. They aren't part of pnpm test.
size.tsispnpm size, the 20 KB gzip budget and the memory a tree holds. CI runs it on every PR, and it fails above the budget.speed.tsispnpm speed: markz alone, in MB/s per document tier and per construct, the working tree againstorigin/main. It is alsopnpm hotspots, where the time goes, andpnpm compare, beside other parsers for our own insight.harness/node.tslets it loadsrc/and the harness.vendor.tsispnpm vendor. It turns an upstream suite's tests into examples forexamples/upstream/, from a local clone at the pinned commit. It is run by hand when a suite is re-pinned.quality/ispnpm quality, the Quality page that the site shows beside prose's pages.
pnpm test searches from a fixed seed. pnpm fuzz runs the construct and robustness checks
fifty times as far from a random one, and SEARCH and SEED set both by hand. When and how to
run it, and what to do with what it finds, is in Development.
Unit tests of offsets and node data live next to their module in src/.
Folders
- documents/
Real documents written by people and by agents, vendored as they were at the commit named, and never edited:
../documents.test.tsholds markz to each, and the benchmark times them. They are excluded from the repo's formatter, so they stay exactly as their authors store them. The tier each folder is, and the variants built from them, are in../harness/corpus.ts. markz's own docs are a tier too, read where they live and never copied here. - examples/
Every example markz is held to that is kept as a file, in the one fence format
fences.tsreads. - harness/
What the checks in
../and the Quality page read and judge with. No tests live here, so one change to how an example is filed or judged reaches both at once. - quality/
The Quality page: the test suite made browsable, as one HTML file beside the site. It shows what markz is held to, what it costs to ship and hold, and how long it takes, all measured on the commit it is built from.
pnpm qualitywrites it, afterprose buildwrites the rest of the site.
Code
- complexity.test.ts
markz is linear in its input, and these tests hold it there. Each adversarial pattern is parsed and rendered at a size and at four times that size, and the larger must take less than eight times as long: linear work takes about four, and quadratic work sixteen, so the check sits between them with room for a noisy machine. Each size is timed at its best of three after a warm-up, so a garbage collection or a cold JIT doesn't decide it, and a few milliseconds of slack keeps a fast pattern from failing on timer noise alone.
- constructs.test.ts
Each construct in its own
describe, by its id, held to everything that tries it: its upstream examples against their oracle, its own examples to their expected output, labelled with the edge each tries, and the cases generated at its edges from the grammar. A Not supported row is held the same way to its examples. A red run names the construct first, whatever caught it. - dialect.test.ts
What every other check stands on, checked before anything is held to it: the statement, the filing and the judges.
- docs.test.ts
The root
README.mdand the documents indocs/are the site's pages, andprose buildlinks them by repo path, so two things keep the site from drifting: each is read by this commit's markz without a warning (duplicate-idexcepted in the grammar, which repeats a heading's id by design: a construct and its side rules), and each relative link in its text goes to a file that exists. The Reference page names every export,Documentmember and node type the package has, so a new one can't ship undocumented. - documents.test.ts
Every real document in the corpus (
harness/corpus.ts), in its owndescribe, held to what an example can't show: whole documents as people and agents write them. Each must be sound as written and after oxfmt. The blocks of its common variant, which every parser reads alike, must each read as micromark reads them, unless the oracle can't judge one (APART). Formatting must not change what it means: the common variant always, and the whole document when markz cut nothing in it, compared as HTML with the code inside fences and runs of spaces set aside, which oxfmt rewrites and HTML ignores. A document with cut forms is left out of that last check whole, since oxfmt rewrites some of them into what the dialect keeps (*a*to_a_), which is the point of the cut. - robustness.test.ts
Input no example chose, held to what must always be true of any document. Three generated sources feed the same properties: noise drawn from Markdown's characters, known examples with a few random edits, and documents written from the dialect's own grammar. Each must be sound (
harness/sound.ts). Where the grammar writes only CommonMark and GFM constructs, from plain letters, markz must also match the oracle, unless it raised a Not supported warning: the side rules often turn a generated document into a form the dialect cuts (a lazy line,*emphasis), which markz reads differently on purpose and reports. Two rules differ without a warning. Emphasis runs never split, and a document that needs one is left out, as the spec examples that need one differ. A*run between digits is text (star-digits), so the oracle's alphabet holds a digit, and a document with one is left out. - size.ts
pnpm size: what markz costs. The 20 KB budget is measured the way a consumer pays for it: everythingsrc/index.tspulls in, bundled and minified, then gzipped (design: Performance and size). Run as a script, it fails the build above the budget, so growth shows up in the PR that causes it rather than at the end. Brotli is printed for reference only. It also prints what holding the CommonMark spec's tree costs, as a multiple of its source. The Quality page measures both the same way. - speed.ts
pnpm speed: markz alone, this working tree'ssrc/againstorigin/main's, in seconds. It answers one question while you work: did this change move it? Each cell is parse + HTML over some text, in MB/s: each document tier read whole, and each construct over its own examples, repeated to a size (examples/markz/<id>.md), so a slower construct shows by name. What a tree holds in memory is a cost, sopnpm sizeprints it. - vendor.ts
Turns an upstream project's own tests into examples for
test/examples/upstream/, in the fence formattest/harness/fences.tsreads and writes, from a local clone at the commit its README pins: a micromark extension's, the yaml-test-suite or github-slugger's (below). What markz is held to is the input: every example is compared with markz's oracle, not with the HTML the suite expected, so a test that only configures the HTML side (a directive handler,allowDangerousHtml) keeps its input. A test whose options change the syntax (disable,singleTilde, a frontmatter preset or custom matter) is dropped, as is anything whose input isn't a literal.
No prose yet