Documentation
¶
Overview ¶
Package conformance generates the conformance summary that docs/conformance-gaps.md publishes, from the measured counts recorded in tests/conformance/results.json.
It exists because the document used to state its own total. It said 168 while its own rows summed to 104, and nothing failed: a prose number is guarded by whoever last read the paragraph. So the total is no longer written anywhere a human can write it. This package adds the rows up and rewrites one marked region of the document; the arithmetic has exactly one implementation, and a stale total is unreachable rather than merely discouraged.
Only the region between the BEGIN and END markers is generated. The rest of docs/conformance-gaps.md is hand-written analysis -- the per-case verdicts, the spec citations, the measured costs -- and is never touched here.
Index ¶
- Constants
- Variables
- func Apply(docPath string, r *Results) (changed bool, err error)
- func DefaultPaths(root string) (results, doc string)
- func Replace(doc string, r *Results) (string, error)
- func ReplaceAll(doc string, regions []Region) (string, error)
- func ReplaceRegion(doc string, g Region) (string, error)
- type Breakdown
- type Case
- type FileResult
- type Region
- type Results
- func (r *Results) ApplyAll(root string, write bool) ([]FileResult, error)
- func (r *Results) Breakdown(id string) Breakdown
- func (r *Results) Count(root string) error
- func (r *Results) Regions() map[string][]Region
- func (r *Results) Render() string
- func (r *Results) RunDates() []string
- func (r *Results) Suite(id string) Suite
- func (r *Results) Total() int
- func (r *Results) TreeCount(id string) TreeCount
- func (r *Results) Validate() error
- type Suite
- type TreeCount
Constants ¶
const ( BeginMarker = "<!-- BEGIN GENERATED CONFORMANCE SUMMARY -->" EndMarker = "<!-- END GENERATED CONFORMANCE SUMMARY -->" )
The markers delimiting the generated region. They are HTML comments so that they are invisible in rendered Markdown but survive every Markdown tool.
Variables ¶
var TreeKinds = []string{"func-test", "func-fuzz", "limits-boundary"}
TreeKinds is the closed set of counting methods Count knows how to run. A kind outside it is a validation error rather than a skipped figure: a generator that silently publishes a zero for a method it does not understand is worse than one that refuses to run.
var Verdicts = []string{
"implementation",
"fixture",
"implementation-defined",
"optional",
"deliberate-divergence",
"not-run",
}
Verdicts is the closed vocabulary a case ID may carry. A verdict outside it is a validation error rather than a passthrough, because the whole value of the file is that the categories mean the same thing in every suite.
Functions ¶
func Apply ¶
Apply rewrites the marked region of doc in place, leaving every other byte alone, and reports whether the file changed.
func DefaultPaths ¶
DefaultPaths resolves the two files relative to the repository root, so that the generator behaves the same from any working directory.
func Replace ¶
Replace swaps the generated region of doc for a freshly rendered one.
A CRLF document is handled rather than rewritten: on Windows a checkout with core.autocrlf=true gives every line a \r, and a generator that emitted LF into it would report a diff on every run for ever. The region is rendered in the line ending the document already uses, and no line outside the region is touched, so the file's convention survives whichever platform regenerates it.
func ReplaceAll ¶
ReplaceAll applies every region belonging to one file.
func ReplaceRegion ¶
ReplaceRegion swaps one named region of doc, by the same rules Replace uses for the conformance summary: only the span between the markers moves, and the document's own line ending is preserved so that a Windows checkout with core.autocrlf=true does not report a diff on every run for ever.
Types ¶
type Breakdown ¶
type Breakdown struct {
ID string `json:"id"`
Label string `json:"label"`
Suite string `json:"suite"`
Of int `json:"of"`
Note string `json:"note,omitempty"`
// Overlap is how many of this breakdown's cases are ALSO enumerated in
// the suite's Cases list. It exists because the two halves were checked
// only against the suite total and never against each other, and so
// summed to 35 of 34 for a year without a gate firing: merge-097sf was
// enumerated while actually being skipped, and su-ascent-902 was counted
// both individually and in the block. Two errors in opposite directions
// left a plausible-looking total, which is the hardest kind to see.
//
// A real overlap is legitimate -- su-ascent-902 belongs to the XTSE3430
// block by symptom and is argued individually because its verdict is not
// the block's -- but it must be DECLARED, so that "the parts do not add
// up" and "the parts overlap on purpose" cannot be confused.
Overlap int `json:"overlap,omitempty"`
}
Breakdown is a named subset of one suite's disagreements: "14 of the 34 XSLT 3.0 failures want an XTSE3430". Both halves are published, so both are recorded, and the whole must not exceed the suite's disagreement count.
type Case ¶
type Case struct {
ID string `json:"id"`
Verdict string `json:"verdict"`
Note string `json:"note,omitempty"`
}
Case is one named disagreement. The list need not be exhaustive -- XSD's 61 are recorded set by set, and XSLT 3.0's XTSE3430 block as a block -- so the enumerated cases are checked against the disagreement count as an upper bound, never as the count itself. Deriving the total from the enumeration would silently under-report every suite whose cases are summarised.
type FileResult ¶
FileResult is what one file's generation did.
type Region ¶
type Region struct {
Name string
Body func() string
// Whole says the file IS the region: it is generated end to end, with no
// hand-written prose around it, so Replace writes the whole file rather
// than looking for markers in it. docs/stats.md is the only one.
Whole bool
// Bare says the body already carries its own "this is generated" header,
// so ReplaceRegion must not prepend the common one. Only the conformance
// summary sets it: its header predates this file and is worded for the
// one region whose defect -- a hand-written Total -- it was built to
// close. Duplicating a header would be the generator adding noise to a
// document on every run, which is the opposite of its contract.
Bare bool
// Inline says the markers sit on the prose line itself, around the
// figure, with no header and no line break: an HTML comment on its own
// line is a block, and a block inside a paragraph or a list item splits
// it in two mid-sentence. A table row can carry the block form; "**577**
// of its 593 test documents" cannot.
Inline bool
}
Region is one generated span of one document.
type Results ¶
type Results struct {
// Decoding is strict (DisallowUnknownFields), so the JSON's own prose --
// the note telling the next editor not to hand-edit the generated table --
// needs a home here or the file will not load.
Comment string `json:"_comment,omitempty"`
GeneratedBy string `json:"generated_by,omitempty"`
Suites []Suite `json:"suites"`
Corpora []Suite `json:"corpora"`
// Tree holds the figures that are DERIVED FROM THE SOURCE TREE rather
// than from a suite run: how many unit tests, fuzz targets and limit
// boundary tests there are. Their values are not in this file and cannot
// be -- see TreeCount in stats.go -- only the counting method is.
Tree []TreeCount `json:"tree"`
// SuiteRevisions is the commit of each vendored W3C suite the figures
// above were measured against, keyed by its directory under testdata/.
//
// Without it a figure in this file is not reproducible. The suites are
// separate checkouts that CI clones at --depth 1 from their default
// branch, so a suite update can move a count with no change to this
// repository at all, and the ratchet would then fail on a commit that
// changed nothing. tests/check.sh has always PRINTED these revisions into
// its provenance, but that is a per-run artifact which expires; this is
// the copy that travels with the numbers it explains.
//
// A suite that is not its own git checkout is absent rather than wrong:
// testdata/relaxng is vendored files, and asking git about it answers
// with THIS repository's HEAD, which would be a revision that means
// nothing. suiterev in tests/check.sh applies the same containment test.
SuiteRevisions map[string]string `json:"suite_revisions,omitempty"`
// Breakdowns are named subsets of a suite's disagreements, such as "14 of
// the 34 XSLT 3.0 failures want an XTSE3430". Both halves get published,
// so both are checked: the subset may not exceed its suite's count.
Breakdowns []Breakdown `json:"breakdowns"`
}
Results is the whole file. Corpora are kept separate from Suites rather than flagged inside one list: DocBook xslTNG and XSpec are real-world stylesheet collections, not W3C conformance suites, and counting them in the total would mean publishing a conformance figure against tests nobody wrote to a specification. Separate types make that impossible to do by accident.
func (*Results) ApplyAll ¶
func (r *Results) ApplyAll(root string, write bool) ([]FileResult, error)
ApplyAll rewrites every generated region in every file, and reports which files moved. With write=false it changes nothing and reports what would move, which is what -check and the gate use: the tree is dirty in most runs, so comparing rather than regenerating-then-diffing is the only reading that does not report the user's work in progress as a failure.
func (*Results) Count ¶
Count fills in every TreeCount by running its method against root.
This is the step that makes the derived figures unforgeable. The generator cannot emit a unit-test count that the tree does not have, because there is nowhere to write one down.
func (*Results) Regions ¶
Regions is every generated region this generator owns, keyed by the file it lives in. Each renders from the loaded Results and nothing else.
A region is small on purpose. The documents around them are long, careful, hand-written English, and the rule is that generation replaces a figure, not a paragraph: the sentence stays the author's, the number stops being theirs.
func (*Results) RunDates ¶
RunDates lists the distinct measurement dates, sorted. A summary drawn from runs on different days is honest about it rather than printing one date.
func (*Results) Total ¶
Total is the number of W3C disagreements: the sum of the suite rows, and nothing else. Corpora are excluded by construction -- they are a different field -- so no caller can pass a total in and no caller can add a corpus to it. This function is the only place the number exists.
func (*Results) TreeCount ¶
TreeCount looks up one derived figure by ID. It panics on an unknown ID rather than returning a zero, because a template that silently prints 0 for a figure it misspelled is exactly the failure this file exists to prevent.
func (*Results) Validate ¶
Validate rejects a file whose arithmetic does not close.
The check that matters is passed + disagreements == total, per suite, named. That is the invariant the document lost: rows whose parts did not add up sat beside a total that agreed with none of them. An unnamed failure would be nearly as useless as no failure, so every message carries the suite ID.
type Suite ¶
type Suite struct {
ID string `json:"id"`
Component string `json:"component"`
Suite string `json:"suite"`
Edition string `json:"edition"`
Passed int `json:"passed"`
Disagreements int `json:"disagreements"`
Total int `json:"total"`
RunDate string `json:"run_date"`
Command string `json:"command"`
Cases []Case `json:"cases"`
// The skipped cases, split by class. Out of scope is what the suite says
// a conforming processor may leave out -- the wrong spec version, a
// Unicode version, an optional numbering language; unimplemented is a
// feature this engine lacks or a dependency the harness does not model.
// Only the XSLT lanes record them (tests/xslts/deps.go draws the line);
// a lane that does not is rendered with an empty cell, not a zero.
SkippedOutOfScope int `json:"skipped_out_of_scope,omitempty"`
SkippedUnimplemented int `json:"skipped_unimplemented,omitempty"`
// Why a suite's cases are not all enumerated above. Rendered nowhere; it
// is here so the JSON explains itself to whoever next edits it.
UnenumeratedNote string `json:"unenumerated_note,omitempty"`
}
Suite is one measured lane: a full run of one suite at one specification edition, with the command and date that produced it.
type TreeCount ¶
type TreeCount struct {
ID string `json:"id"`
Label string `json:"label"`
Method string `json:"method"`
Kind string `json:"kind"`
Value int `json:"-"`
}
TreeCount is a figure derived from the source tree rather than from a suite run: how many unit tests there are, how many fuzz targets, how many limit boundary tests.
The Value field is NOT decoded from JSON -- it has no struct tag -- so a number cannot be typed into results.json and reach a document. It is filled by Count below, which runs the recorded method against the tree. What the JSON carries is Method: the human-readable command, quoted beside every published copy of the number, because a figure whose method is not written down is merely asserted twice.