From 615b20b177f3d20af0b569727c91994798bc4677 Mon Sep 17 00:00:00 2001 From: Mark Probst Date: Mon, 20 Jul 2026 12:22:18 -0400 Subject: [PATCH] test: expected-output fixtures for JSON inputs The JSON fixture harness asserts round-trip output ~ input, with unconditional leniency: extra null properties in the output are always allowed, and allowMissingNull languages may drop nulls. Correct behaviors where the output legitimately differs from the input were therefore untestable -- concretely, that Go's omitempty drops null fields. Port the JSON Schema fixtures' `.out..json` convention to JSON inputs: an input `foo.json` may come with an expected-output file `foo.out..json`, which applies to a run when `` is one of the language's `features` or the name of a renderer option that the particular run sets (via a pinned `quickTestRendererOptions` entry). When it applies, the output must match strictly, without the null leniency; when absent, behavior is unchanged. `.out.` files are excluded from test-input enumeration. Use it to assert the omit-empty behavior from #2509: a pinned Go run of priority/omit-empty.json with omit-empty enabled must drop the null field, per omit-empty.out.omit-empty.json. The input is in priority/ (not misc/) so it also runs under QUICKTEST in CI. Salvaged from #2509; the test case is Adam724's. Co-authored-by: Adam724 Co-Authored-By: Claude Fable 5 --- test/fixtures.ts | 33 ++++++++++++++++--- test/inputs/json/priority/omit-empty.json | 11 +++++++ .../priority/omit-empty.out.omit-empty.json | 10 ++++++ test/languages.ts | 7 +++- test/utils.ts | 6 +++- 5 files changed, 61 insertions(+), 6 deletions(-) create mode 100644 test/inputs/json/priority/omit-empty.json create mode 100644 test/inputs/json/priority/omit-empty.out.omit-empty.json diff --git a/test/fixtures.ts b/test/fixtures.ts index dece181ef6..45f51eb937 100644 --- a/test/fixtures.ts +++ b/test/fixtures.ts @@ -359,14 +359,39 @@ class JSONFixture extends LanguageFixture { return 0; } - compareJsonFileToJson( - comparisonArgs( + // The analog of the JSON Schema fixture's `.out..json` + // convention: a JSON input `foo.json` can come with an expected-output + // file `foo.out..json`, which applies when `` is one of the + // language's `features`, or the name of a renderer option this + // particular run sets (via `quickTestRendererOptions`). When it + // applies, the output must match it exactly, without the usual + // round-trip leniency for null properties. This is how output that + // legitimately differs from the input — e.g. Go's `omitempty` + // dropping null fields — gets asserted. + let expectedFilename = filename; + let strict = false; + const expectedOutputKeys = [ + ...this.language.features, + ...Object.keys(additionalRendererOptions), + ]; + for (const key of expectedOutputKeys) { + const outFilename = filename.replace(/\.json$/, `.out.${key}.json`); + if (fs.existsSync(outFilename)) { + expectedFilename = outFilename; + strict = true; + break; + } + } + + compareJsonFileToJson({ + ...comparisonArgs( this.language, filename, - filename, + expectedFilename, additionalRendererOptions, ), - ); + strict, + }); if ( this.language.diffViaSchema && diff --git a/test/inputs/json/priority/omit-empty.json b/test/inputs/json/priority/omit-empty.json new file mode 100644 index 0000000000..56425f9b78 --- /dev/null +++ b/test/inputs/json/priority/omit-empty.json @@ -0,0 +1,11 @@ +{ + "results": [ + { + "age": 52, + "name": null + }, + { + "age": 27 + } + ] +} diff --git a/test/inputs/json/priority/omit-empty.out.omit-empty.json b/test/inputs/json/priority/omit-empty.out.omit-empty.json new file mode 100644 index 0000000000..809e3cfa02 --- /dev/null +++ b/test/inputs/json/priority/omit-empty.out.omit-empty.json @@ -0,0 +1,10 @@ +{ + "results": [ + { + "age": 52 + }, + { + "age": 27 + } + ] +} diff --git a/test/languages.ts b/test/languages.ts index 6bcfd43611..1aedcb4024 100644 --- a/test/languages.ts +++ b/test/languages.ts @@ -500,7 +500,12 @@ export const GoLanguage: Language = { "postman-collection.schema", ], rendererOptions: {}, - quickTestRendererOptions: [], + quickTestRendererOptions: [ + // Runs against the expected-output file + // `omit-empty.out.omit-empty.json`, which asserts that `omitempty` + // actually drops the null field. + ["omit-empty.json", { "omit-empty": "true" }], + ], sourceFiles: ["src/language/Golang/index.ts"], }; diff --git a/test/utils.ts b/test/utils.ts index db98e3101b..3a6d1f4bc2 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -186,7 +186,11 @@ export async function inDir(dir: string, work: () => Promise) { } export function testsInDir(dir: string, extension: string): string[] { - return shell.ls(`${dir}/*.${extension}`); + // Expected-output files (`foo.out..json`) accompany test inputs; + // they are never test inputs themselves. + return shell + .ls(`${dir}/*.${extension}`) + .filter((fn) => !/\.out\.[^./]+\.[^./]+$/.test(fn)); } export interface Sample {