Skip to content

test(compilers/openapi): consolidate the duplicated test fixtures - #328

Merged
OmarAlJarrah merged 2 commits into
mainfrom
test/openapi-consolidate-scaffolding
Aug 9, 2026
Merged

test(compilers/openapi): consolidate the duplicated test fixtures#328
OmarAlJarrah merged 2 commits into
mainfrom
test/openapi-consolidate-scaffolding

Conversation

@OmarAlJarrah

Copy link
Copy Markdown
Member

Summary

Every test package under compilers/openapi carried its own copy of the same scaffolding.
Before this change there were 84 definitions of helpers that exist once now: sourceOf
five times byte for byte, requireNoErrorDiags seven times, componentSpec four,
countDiagsAt five, indexBy five, and so on down a list of 26 names.

The duplication is worth stating plainly, because the last word on this issue was that it
would resolve itself. The extraction of the compiler into one package per lowering stage was
expected to retire the fixture; it multiplied it instead. Go test files cannot share
unexported helpers across packages, so every package the split created needed the same
scaffolding and got it by copy. newRawLowerer, the specific drift the issue named, went
from one hand-constructed copy to four.

The change adds compilers/openapi/internal/openapitest, holding the vocabulary every one of
those packages needs — building a spec, driving it, and asserting on the diagnostics it
produced — and deletes the copies. Net −660 lines.

What openapitest may hold is bounded by an import rule, not by taste. A helper belongs
there only if every test package under compilers/openapi can import it, internal test
packages included, and an internal test file may not import a package that imports its own.
That caps the imports at ir, compilers, diag and third-party libraries, and it is why
two families stay where they are:

  • parseFull (4 copies). It drives the whole compiler, so it needs compilers/openapi
    — and compilers/openapi's own internal tests could then not import openapitest at all.
    The four are now written identically so a reader comparing them finds no difference to
    account for.
  • The lowerer fixture (4 copies). It needs lowering.Ctx and schema.AnchorIndex,
    which would shut out the internal tests of load, resolve, annotation, schema and
    everything beneath them.

For the second, the issue's actual acceptance criterion is met a different way: within each
of the four packages, newRawLowerer and its sibling entry point now both build on one
field-initialising constructor, so a field added to the struct cannot reach one and miss the
other. That was the drift; hand-construction beside a constructor was the mechanism.

A third family — componentID and typeByName — stays in test files on purpose.
internal/archtest's ID-grammar sweep permits a spelled-out type ID in a test file and
refuses one in a production file, which openapitest's are. Deriving the ID through
compile to satisfy the sweep would make the lookup agree with the compiler by
construction, and a lookup that cannot disagree is no longer an oracle. Both the package doc
and each copy record this.

internal/openapitest gets its own entry in internal/archtest's rules map, with the
import ceiling above written down as the reason the entry is narrow.

Left for #326: the six yaml-node builders internal/nodeview and internal/scan share.
ymerge needs nodeview.MergeTag, so it cannot move; mergeChain is built on it. Splitting
a six-function family across two homes reads worse than the duplication, so the family stayed
whole and the constraint is filed rather than lost.

Test plan

This is a refactor with no behaviour change, so the load-bearing evidence is that no test
changed meaning. Comparing go test ./... -list '.*' before and after, the only difference
is additions — 22 new tests, all in the new package, and zero removals or renames:

$ diff before.names after.names
100a101,104
> TestAssertHasCode_RequiresCodeAndSeverityTogether
> TestAssertInfoDiagAt_MatchesOnSeverityAndPointer
> TestAssertProbeDocsKept_ChecksAllThreeDocumentationKeywords
> TestAssertProbeExample_ChecksTheSingleExampleValue
124a129
> TestBothWrappers_ParseAsYAML
237a243
> TestComponentSpec_WrapsSchemasInAMinimalDocument
292a299
> TestCountDiagsAt_CountsExactMatchesOnly
338a346
> TestDiagMessageAt_ReturnsTheSingleMatchingMessage
356a365
> TestDocDeclaring_DeclaresEveryNamedComponent
381a391
> TestEmptyEitherSchema_IsASchemaWithNoSchema
434a445,446
> TestFindOp_FindsTheOperationBySourceName
> TestFirstDegradedWarning_MatchesTheDegradedCodeAtWarning
435a448
> TestFirstOp_ReturnsTheFirstOperationOfTheFirstGroup
453a467,468
> TestHasDiagCodeAt_RequiresTheExactPointer
> TestHasDiag_MatchesCodeAtAnySeverity
483a499
> TestIndexBy_KeysEveryItem
493a510
> TestInlineProbeBody_WritesEveryKeywordTheProbeAssertsOn
766a784
> TestPathsSpec_WrapsPathsInAMinimalDocument
869a888
> TestRequireNoErrorDiags_FailsOnlyOnAnErrorSeverity
927a947
> TestScalarNode_BuildsABareScalar
982a1003
> TestSourceOf_CarriesTheSpecBytes
1271a1293
> TestYAMLNode_ReturnsTheRootValueNode

(1271 test names before, 1293 after; the raw -list output also differs in per-package
timing lines, which are not test names.)

The new tests were checked against planted defects rather than read:

planted defect result
ComponentSpecVer stops writing paths: {} RED — TestComponentSpec_WrapsSchemasInAMinimalDocument
FindOp returns the first operation whatever the name RED — TestFindOp_FindsTheOperationBySourceName
lowererOver stops initialising operationIDs RED — TestPreserve_AllReasonsReachable in compilers/openapi

The first of those is why an assertion was added: the original test asserted the prefix and
the schemas block but not the paths key, and dropping the key reddened nothing anywhere in
the repository — 3.1 makes paths optional while 3.0 requires it, and callers pass both
versions.

Full gate green, coverage gate at exactly 100% including the new package:

--- [1/5] gofmt
--- [2/5] go vet
--- [3/5] golangci-lint
--- [4/5] go build
--- [5/5] coverage gate (must be exactly 100%)
ok  	github.com/dexpace/morphic/compilers/openapi/internal/openapitest	coverage: 100.0% of statements
Coverage gate passed
### GATE PASSED

The new package needs its own tests rather than riding on its callers': without -coverpkg,
a package is instrumented only by its own test binary, and one with statements and no test
files contributes zero-count blocks to the profile — which fails the gate. That is the same
constraint internal/testspec's doc comment records, verified here by adding a statement to
it and watching the profile.

Closes #87

Nine PRs landed on main after this branch was opened, and two of them added
tests to files this branch rewrites. Git reconciled the two edits without a
textual conflict, so the merged tree compiled nowhere: the new tests call the
package-local helpers this branch deletes.

Resolved by pointing those call sites at the package that now owns them —
26 in operations_test.go and schema_test.go across requireNoErrorDiags,
findOp, hasDiagCodeAt, pathsSpec, componentSpec and propsByWire. The one real
conflict, conformance_test.go's import block, keeps both: the branch added
openapitest and #322 added diag, and the file needs each.

No test was lost in the merge — the name list gains the new package's 22 and
loses nothing against main.
@OmarAlJarrah
OmarAlJarrah merged commit bb8d227 into main Aug 9, 2026
1 check passed
@OmarAlJarrah
OmarAlJarrah deleted the test/openapi-consolidate-scaffolding branch August 9, 2026 10:22
OmarAlJarrah added a commit that referenced this pull request Aug 9, 2026
Clean merge, and a tree that compiled nowhere: #328 consolidated the openapi
test scaffolding into internal/openapitest, and this branch's new tests call
six of those helpers by their old package-local names. Git reconciles both
edits without a conflict, so the failure only shows on a build.

Repointed the eight call sites — componentSpec, requireNoErrorDiags,
propsByWire, emptyEitherSchema — across conformance_test.go, compose_test.go,
schema_test.go and schema_internal_test.go. Signatures are unchanged, so these
are renames.

The archtest pin composed on its own: #331 widened loweringRecursions to see
methods and this branch adds the four-function nullability cycle, and the
merged order already satisfies #331's length-then-first-member comparator.
TestLoweringRecursion_IsOnlyTheKnownCycles passes on the result, which is what
checks that rather than the eye.
OmarAlJarrah added a commit that referenced this pull request Aug 9, 2026
Clean merge, and a tree that compiled nowhere: #328 consolidated the openapi
test scaffolding into internal/openapitest, and this branch's new tests call
six of those helpers by their old package-local names. Git reconciles both
edits without a conflict, so the failure only shows on a build.

Resolved by repointing the eight call sites — componentSpec,
requireNoErrorDiags, propsByWire, emptyEitherSchema — across
conformance_test.go, compose_test.go, schema_test.go and
schema_internal_test.go. The signatures are unchanged, so these are renames.

The archtest pin composed on its own: #331 widened loweringRecursions to see
methods and this branch adds the four-function nullability cycle, and the
merged order already satisfies #331's length-then-first-member comparator.
TestLoweringRecursion_IsOnlyTheKnownCycles passing on the result is what
checks that, rather than the eye.
OmarAlJarrah added a commit that referenced this pull request Aug 9, 2026
The conflict this branch predicted, resolved as it said: #304's
TestDetectCycles_EmptyPointerSegmentIsRefused calls Cycles(0, []byte(src)), and
Cycles now takes a sourceindex.Index, so the call becomes scanBytes(t, ...).

Two the branch could not predict. cycles_test.go: #304 and #310 added a test
where this branch adds a scanIndex helper, both at the same offset sharing a
closing brace — kept both. And #328 consolidated the openapi test scaffolding
into internal/openapitest after this branch was written, so its new
entry_internal_test.go calls sourceOf by the package-local name that no longer
exists; repointed, with the import added.

Byte-identical output re-proven against the merged tree rather than carried over
from the branch: 115 sources under testdata compiled through binaries built from
main and from this merge, capturing document, stderr and exit code each. diff -r
over the two trees is empty.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

openapi: consolidate test scaffolding and retire the edge-case grab-bag files

1 participant