|
1 | 1 | /** |
2 | | - * Verifies that `typia generate` actually transforms each input file. |
| 2 | + * Verifies that `typia generate` transforms its input deterministically. |
3 | 3 | * |
4 | | - * Pins the regression where `typia generate` discarded the transform |
5 | | - * result and copied the original input verbatim into the output. Every |
6 | | - * `src/input/generate_*.ts` fixture contains `typia.*<T>()` call sites, |
7 | | - * so a correctly transformed output can never be byte-identical to its |
8 | | - * input file. |
| 4 | + * Pins two regressions: (1) `typia generate` discarding the transform |
| 5 | + * result and copying the input file verbatim into the output, and (2) |
| 6 | + * non-deterministic emit order caused by unsorted Go map iteration in the |
| 7 | + * native programmers. Every `src/input/generate_*.ts` fixture contains |
| 8 | + * `typia.*<T>()` call sites, so a correct output is never byte-identical |
| 9 | + * to its input and never changes between two generator runs. |
9 | 10 | * |
10 | 11 | * 1. Run `pnpm run generate` then `pnpm run build` (the `start` script). |
11 | | - * 2. For each input file, read the matching generated output file. |
12 | | - * 3. Fail if any output is missing or identical to its input file. |
| 12 | + * 2. Assert each output differs from its input file (it was transformed). |
| 13 | + * 3. Re-run the generator and assert every output is byte-identical. |
13 | 14 | */ |
| 15 | +const cp = require("child_process"); |
14 | 16 | const fs = require("fs"); |
15 | 17 |
|
16 | 18 | const inputDir = `${__dirname}/src/input`; |
17 | 19 | const outputDir = `${__dirname}/src/output`; |
| 20 | +const repeatDir = `${__dirname}/src/output-repeat`; |
18 | 21 |
|
19 | 22 | const main = () => { |
20 | 23 | const files = fs |
21 | 24 | .readdirSync(inputDir) |
22 | 25 | .filter((file) => file.endsWith(".ts")); |
23 | 26 | let failed = false; |
| 27 | + |
| 28 | + // (1) every output must be transformed, not a verbatim copy of its input |
24 | 29 | for (const file of files) { |
25 | | - const input = fs.readFileSync(`${inputDir}/${file}`, "utf8"); |
26 | 30 | const outputPath = `${outputDir}/${file}`; |
27 | 31 | if (fs.existsSync(outputPath) === false) { |
28 | 32 | console.error(`Bug on ${file}: output file was not generated.`); |
29 | 33 | failed = true; |
30 | 34 | continue; |
31 | 35 | } |
32 | | - const output = fs.readFileSync(outputPath, "utf8"); |
33 | | - if (input === output) { |
| 36 | + const input = fs.readFileSync(`${inputDir}/${file}`, "utf8"); |
| 37 | + if (fs.readFileSync(outputPath, "utf8") === input) { |
34 | 38 | console.error( |
35 | 39 | `Bug on ${file}: output is identical to input (not transformed).`, |
36 | 40 | ); |
37 | 41 | failed = true; |
38 | 42 | } |
39 | 43 | } |
| 44 | + |
| 45 | + // (2) re-running the generator must produce byte-identical output |
| 46 | + fs.rmSync(repeatDir, { recursive: true, force: true }); |
| 47 | + cp.execSync("pnpm run generate:repeat", { |
| 48 | + cwd: __dirname, |
| 49 | + stdio: "ignore", |
| 50 | + }); |
| 51 | + for (const file of files) { |
| 52 | + const first = fs.readFileSync(`${outputDir}/${file}`, "utf8"); |
| 53 | + const second = fs.readFileSync(`${repeatDir}/${file}`, "utf8"); |
| 54 | + if (first !== second) { |
| 55 | + console.error(`Bug on ${file}: regeneration is not deterministic.`); |
| 56 | + failed = true; |
| 57 | + } |
| 58 | + } |
| 59 | + fs.rmSync(repeatDir, { recursive: true, force: true }); |
| 60 | + |
40 | 61 | if (failed) process.exit(1); |
41 | | - console.log(`All ${files.length} generate outputs were transformed.`); |
| 62 | + console.log( |
| 63 | + `All ${files.length} generate outputs are transformed and deterministic.`, |
| 64 | + ); |
42 | 65 | }; |
43 | 66 | main(); |
0 commit comments