summaryrefslogtreecommitdiffstats
path: root/dom/webgpu/tests/cts/checkout/src/common/tools/gen_wpt_cts_html.ts
blob: 28e8fb4437870aa5907908ecc4c63ce714bee084 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import { promises as fs } from 'fs';

import { DefaultTestFileLoader } from '../internal/file_loader.js';
import { TestQueryMultiFile } from '../internal/query/query.js';
import { assert } from '../util/util.js';

function printUsageAndExit(rc: number): void {
  console.error(`\
Usage:
  tools/gen_wpt_cts_html OUTPUT_FILE TEMPLATE_FILE [ARGUMENTS_PREFIXES_FILE EXPECTATIONS_FILE EXPECTATIONS_PREFIX [SUITE]]
  tools/gen_wpt_cts_html out-wpt/cts.https.html templates/cts.https.html
  tools/gen_wpt_cts_html my/path/to/cts.https.html templates/cts.https.html arguments.txt myexpectations.txt 'path/to/cts.https.html' cts

where arguments.txt is a file containing a list of arguments prefixes to both generate and expect
in the expectations. The entire variant list generation runs *once per prefix*, so this
multiplies the size of the variant list.

  ?worker=0&q=
  ?worker=1&q=

and myexpectations.txt is a file containing a list of WPT paths to suppress, e.g.:

  path/to/cts.https.html?worker=0&q=webgpu:a/foo:bar={"x":1}
  path/to/cts.https.html?worker=1&q=webgpu:a/foo:bar={"x":1}

  path/to/cts.https.html?worker=1&q=webgpu:a/foo:bar={"x":3}
`);
  process.exit(rc);
}

if (process.argv.length !== 4 && process.argv.length !== 7 && process.argv.length !== 8) {
  printUsageAndExit(0);
}

const [
  ,
  ,
  outFile,
  templateFile,
  argsPrefixesFile,
  expectationsFile,
  expectationsPrefix,
  suite = 'webgpu',
] = process.argv;

(async () => {
  let argsPrefixes = [''];
  let expectationLines = new Set<string>();

  if (process.argv.length >= 7) {
    // Prefixes sorted from longest to shortest
    const argsPrefixesFromFile = (await fs.readFile(argsPrefixesFile, 'utf8'))
      .split(/\r?\n/)
      .filter(a => a.length)
      .sort((a, b) => b.length - a.length);
    if (argsPrefixesFromFile.length) argsPrefixes = argsPrefixesFromFile;
    expectationLines = new Set(
      (await fs.readFile(expectationsFile, 'utf8')).split(/\r?\n/).filter(l => l.length)
    );
  }

  const expectations: Map<string, string[]> = new Map();
  for (const prefix of argsPrefixes) {
    expectations.set(prefix, []);
  }

  expLoop: for (const exp of expectationLines) {
    // Take each expectation for the longest prefix it matches.
    for (const argsPrefix of argsPrefixes) {
      const prefix = expectationsPrefix + argsPrefix;
      if (exp.startsWith(prefix)) {
        expectations.get(argsPrefix)!.push(exp.substring(prefix.length));
        continue expLoop;
      }
    }
    console.log('note: ignored expectation: ' + exp);
  }

  const loader = new DefaultTestFileLoader();
  const lines: Array<string | undefined> = [];
  for (const prefix of argsPrefixes) {
    const rootQuery = new TestQueryMultiFile(suite, []);
    const tree = await loader.loadTree(rootQuery, expectations.get(prefix));

    lines.push(undefined); // output blank line between prefixes
    const alwaysExpandThroughLevel = 2; // expand to, at minimum, every test.
    for (const { query } of tree.iterateCollapsedNodes({ alwaysExpandThroughLevel })) {
      const urlQueryString = prefix + query.toString(); // "?worker=0&q=..."
      // Check for a safe-ish path length limit. Filename must be <= 255, and on Windows the whole
      // path must be <= 259. Leave room for e.g.:
      // 'c:\b\s\w\xxxxxxxx\layout-test-results\external\wpt\webgpu\cts_worker=0_q=...-actual.txt'
      assert(
        urlQueryString.length < 185,
        'Generated test variant would produce too-long -actual.txt filename. \
Try broadening suppressions to avoid long test variant names. ' +
          urlQueryString
      );
      lines.push(urlQueryString);
    }
  }
  await generateFile(lines);
})().catch(ex => {
  console.log(ex.stack ?? ex.toString());
  process.exit(1);
});

async function generateFile(lines: Array<string | undefined>): Promise<void> {
  let result = '';
  result += '<!-- AUTO-GENERATED - DO NOT EDIT. See WebGPU CTS: tools/gen_wpt_cts_html. -->\n';

  result += await fs.readFile(templateFile, 'utf8');

  for (const line of lines) {
    if (line === undefined) {
      result += '\n';
    } else {
      result += `<meta name=variant content='${line}'>\n`;
    }
  }

  await fs.writeFile(outFile, result);
}