summaryrefslogtreecommitdiffstats
path: root/dom/webgpu/tests/cts/checkout/src/common/runtime/cmdline.ts
diff options
context:
space:
mode:
Diffstat (limited to 'dom/webgpu/tests/cts/checkout/src/common/runtime/cmdline.ts')
-rw-r--r--dom/webgpu/tests/cts/checkout/src/common/runtime/cmdline.ts278
1 files changed, 278 insertions, 0 deletions
diff --git a/dom/webgpu/tests/cts/checkout/src/common/runtime/cmdline.ts b/dom/webgpu/tests/cts/checkout/src/common/runtime/cmdline.ts
new file mode 100644
index 0000000000..463546c06d
--- /dev/null
+++ b/dom/webgpu/tests/cts/checkout/src/common/runtime/cmdline.ts
@@ -0,0 +1,278 @@
+/* eslint no-console: "off" */
+
+import * as fs from 'fs';
+
+import { dataCache } from '../framework/data_cache.js';
+import { globalTestConfig } from '../framework/test_config.js';
+import { DefaultTestFileLoader } from '../internal/file_loader.js';
+import { prettyPrintLog } from '../internal/logging/log_message.js';
+import { Logger } from '../internal/logging/logger.js';
+import { LiveTestCaseResult } from '../internal/logging/result.js';
+import { parseQuery } from '../internal/query/parseQuery.js';
+import { parseExpectationsForTestQuery } from '../internal/query/query.js';
+import { Colors } from '../util/colors.js';
+import { setGPUProvider } from '../util/navigator_gpu.js';
+import { assert, unreachable } from '../util/util.js';
+
+import sys from './helper/sys.js';
+
+function usage(rc: number): never {
+ console.log(`Usage:
+ tools/run_${sys.type} [OPTIONS...] QUERIES...
+ tools/run_${sys.type} 'unittests:*' 'webgpu:buffers,*'
+Options:
+ --colors Enable ANSI colors in output.
+ --coverage Emit coverage data.
+ --verbose Print result/log of every test as it runs.
+ --list Print all testcase names that match the given query and exit.
+ --debug Include debug messages in logging.
+ --print-json Print the complete result JSON in the output.
+ --expectations Path to expectations file.
+ --gpu-provider Path to node module that provides the GPU implementation.
+ --gpu-provider-flag Flag to set on the gpu-provider as <flag>=<value>
+ --unroll-const-eval-loops Unrolls loops in constant-evaluation shader execution tests
+ --quiet Suppress summary information in output
+`);
+ return sys.exit(rc);
+}
+
+// The interface that exposes creation of the GPU, and optional interface to code coverage.
+interface GPUProviderModule {
+ // @returns a GPU with the given flags
+ create(flags: string[]): GPU;
+ // An optional interface to a CodeCoverageProvider
+ coverage?: CodeCoverageProvider;
+}
+
+interface CodeCoverageProvider {
+ // Starts collecting code coverage
+ begin(): void;
+ // Ends collecting of code coverage, returning the coverage data.
+ // This data is opaque (implementation defined).
+ end(): string;
+}
+
+type listModes = 'none' | 'cases' | 'unimplemented';
+
+Colors.enabled = false;
+
+let verbose = false;
+let emitCoverage = false;
+let listMode: listModes = 'none';
+let debug = false;
+let printJSON = false;
+let quiet = false;
+let loadWebGPUExpectations: Promise<unknown> | undefined = undefined;
+let gpuProviderModule: GPUProviderModule | undefined = undefined;
+let dataPath: string | undefined = undefined;
+
+const queries: string[] = [];
+const gpuProviderFlags: string[] = [];
+for (let i = 0; i < sys.args.length; ++i) {
+ const a = sys.args[i];
+ if (a.startsWith('-')) {
+ if (a === '--colors') {
+ Colors.enabled = true;
+ } else if (a === '--coverage') {
+ emitCoverage = true;
+ } else if (a === '--verbose') {
+ verbose = true;
+ } else if (a === '--list') {
+ listMode = 'cases';
+ } else if (a === '--list-unimplemented') {
+ listMode = 'unimplemented';
+ } else if (a === '--debug') {
+ debug = true;
+ } else if (a === '--data') {
+ dataPath = sys.args[++i];
+ } else if (a === '--print-json') {
+ printJSON = true;
+ } else if (a === '--expectations') {
+ const expectationsFile = new URL(sys.args[++i], `file://${sys.cwd()}`).pathname;
+ loadWebGPUExpectations = import(expectationsFile).then(m => m.expectations);
+ } else if (a === '--gpu-provider') {
+ const modulePath = sys.args[++i];
+ gpuProviderModule = require(modulePath);
+ } else if (a === '--gpu-provider-flag') {
+ gpuProviderFlags.push(sys.args[++i]);
+ } else if (a === '--quiet') {
+ quiet = true;
+ } else if (a === '--unroll-const-eval-loops') {
+ globalTestConfig.unrollConstEvalLoops = true;
+ } else {
+ console.log('unrecognized flag: ', a);
+ usage(1);
+ }
+ } else {
+ queries.push(a);
+ }
+}
+
+let codeCoverage: CodeCoverageProvider | undefined = undefined;
+
+if (gpuProviderModule) {
+ setGPUProvider(() => gpuProviderModule!.create(gpuProviderFlags));
+ if (emitCoverage) {
+ codeCoverage = gpuProviderModule.coverage;
+ if (codeCoverage === undefined) {
+ console.error(
+ `--coverage specified, but the GPUProviderModule does not support code coverage.
+Did you remember to build with code coverage instrumentation enabled?`
+ );
+ sys.exit(1);
+ }
+ }
+}
+
+if (dataPath !== undefined) {
+ dataCache.setStore({
+ load: (path: string) => {
+ return new Promise<string>((resolve, reject) => {
+ fs.readFile(`${dataPath}/${path}`, 'utf8', (err, data) => {
+ if (err !== null) {
+ reject(err.message);
+ } else {
+ resolve(data);
+ }
+ });
+ });
+ },
+ });
+}
+if (verbose) {
+ dataCache.setDebugLogger(console.log);
+}
+
+if (queries.length === 0) {
+ console.log('no queries specified');
+ usage(0);
+}
+
+(async () => {
+ const loader = new DefaultTestFileLoader();
+ assert(queries.length === 1, 'currently, there must be exactly one query on the cmd line');
+ const filterQuery = parseQuery(queries[0]);
+ const testcases = await loader.loadCases(filterQuery);
+ const expectations = parseExpectationsForTestQuery(
+ await (loadWebGPUExpectations ?? []),
+ filterQuery
+ );
+
+ Logger.globalDebugMode = debug;
+ const log = new Logger();
+
+ const failed: Array<[string, LiveTestCaseResult]> = [];
+ const warned: Array<[string, LiveTestCaseResult]> = [];
+ const skipped: Array<[string, LiveTestCaseResult]> = [];
+
+ let total = 0;
+
+ if (codeCoverage !== undefined) {
+ codeCoverage.begin();
+ }
+
+ for (const testcase of testcases) {
+ const name = testcase.query.toString();
+ switch (listMode) {
+ case 'cases':
+ console.log(name);
+ continue;
+ case 'unimplemented':
+ if (testcase.isUnimplemented) {
+ console.log(name);
+ }
+ continue;
+ default:
+ break;
+ }
+
+ const [rec, res] = log.record(name);
+ await testcase.run(rec, expectations);
+
+ if (verbose) {
+ printResults([[name, res]]);
+ }
+
+ total++;
+ switch (res.status) {
+ case 'pass':
+ break;
+ case 'fail':
+ failed.push([name, res]);
+ break;
+ case 'warn':
+ warned.push([name, res]);
+ break;
+ case 'skip':
+ skipped.push([name, res]);
+ break;
+ default:
+ unreachable('unrecognized status');
+ }
+ }
+
+ if (codeCoverage !== undefined) {
+ const coverage = codeCoverage.end();
+ console.log(`Code-coverage: [[${coverage}]]`);
+ }
+
+ if (listMode !== 'none') {
+ return;
+ }
+
+ assert(total > 0, 'found no tests!');
+
+ // MAINTENANCE_TODO: write results out somewhere (a file?)
+ if (printJSON) {
+ console.log(log.asJSON(2));
+ }
+
+ if (!quiet) {
+ if (skipped.length) {
+ console.log('');
+ console.log('** Skipped **');
+ printResults(skipped);
+ }
+ if (warned.length) {
+ console.log('');
+ console.log('** Warnings **');
+ printResults(warned);
+ }
+ if (failed.length) {
+ console.log('');
+ console.log('** Failures **');
+ printResults(failed);
+ }
+
+ const passed = total - warned.length - failed.length - skipped.length;
+ const pct = (x: number) => ((100 * x) / total).toFixed(2);
+ const rpt = (x: number) => {
+ const xs = x.toString().padStart(1 + Math.log10(total), ' ');
+ return `${xs} / ${total} = ${pct(x).padStart(6, ' ')}%`;
+ };
+ console.log('');
+ console.log(`** Summary **
+Passed w/o warnings = ${rpt(passed)}
+Passed with warnings = ${rpt(warned.length)}
+Skipped = ${rpt(skipped.length)}
+Failed = ${rpt(failed.length)}`);
+ }
+
+ if (failed.length || warned.length) {
+ sys.exit(1);
+ }
+})().catch(ex => {
+ console.log(ex.stack ?? ex.toString());
+ sys.exit(1);
+});
+
+function printResults(results: Array<[string, LiveTestCaseResult]>): void {
+ for (const [name, r] of results) {
+ console.log(`[${r.status}] ${name} (${r.timems}ms). Log:`);
+ if (r.logs) {
+ for (const l of r.logs) {
+ console.log(prettyPrintLog(l));
+ }
+ }
+ }
+}