summaryrefslogtreecommitdiffstats
path: root/dom/webgpu/tests/cts/checkout/src/common/internal/file_loader.ts
blob: 922d6a09dd6e1ab5761340048a19fd6431eb4738 (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
import { IterableTestGroup } from '../internal/test_group.js';
import { assert } from '../util/util.js';

import { parseQuery } from './query/parseQuery.js';
import { TestQuery } from './query/query.js';
import { TestSuiteListing } from './test_suite_listing.js';
import { loadTreeForQuery, TestTree, TestTreeLeaf } from './tree.js';

// A listing file, e.g. either of:
// - `src/webgpu/listing.ts` (which is dynamically computed, has a Promise<TestSuiteListing>)
// - `out/webgpu/listing.js` (which is pre-baked, has a TestSuiteListing)
interface ListingFile {
  listing: Promise<TestSuiteListing> | TestSuiteListing;
}

// A .spec.ts file, as imported.
export interface SpecFile {
  readonly description: string;
  readonly g: IterableTestGroup;
}

export interface ImportInfo {
  url: string;
}

interface TestFileLoaderEventMap {
  import: MessageEvent<ImportInfo>;
  finish: MessageEvent<void>;
}

export interface TestFileLoader extends EventTarget {
  addEventListener<K extends keyof TestFileLoaderEventMap>(
    type: K,
    listener: (this: TestFileLoader, ev: TestFileLoaderEventMap[K]) => void,
    options?: boolean | AddEventListenerOptions
  ): void;
  addEventListener(
    type: string,
    listener: EventListenerOrEventListenerObject,
    options?: boolean | AddEventListenerOptions
  ): void;
  removeEventListener<K extends keyof TestFileLoaderEventMap>(
    type: K,
    listener: (this: TestFileLoader, ev: TestFileLoaderEventMap[K]) => void,
    options?: boolean | EventListenerOptions
  ): void;
  removeEventListener(
    type: string,
    listener: EventListenerOrEventListenerObject,
    options?: boolean | EventListenerOptions
  ): void;
}

// Base class for DefaultTestFileLoader and FakeTestFileLoader.
export abstract class TestFileLoader extends EventTarget {
  abstract listing(suite: string): Promise<TestSuiteListing>;
  protected abstract import(path: string): Promise<SpecFile>;

  importSpecFile(suite: string, path: string[]): Promise<SpecFile> {
    const url = `${suite}/${path.join('/')}.spec.js`;
    this.dispatchEvent(
      new MessageEvent<ImportInfo>('import', { data: { url } })
    );
    return this.import(url);
  }

  async loadTree(query: TestQuery, subqueriesToExpand: string[] = []): Promise<TestTree> {
    const tree = await loadTreeForQuery(
      this,
      query,
      subqueriesToExpand.map(s => {
        const q = parseQuery(s);
        assert(q.level >= 2, () => `subqueriesToExpand entries should not be multi-file:\n  ${q}`);
        return q;
      })
    );
    this.dispatchEvent(new MessageEvent<void>('finish'));
    return tree;
  }

  async loadCases(query: TestQuery): Promise<IterableIterator<TestTreeLeaf>> {
    const tree = await this.loadTree(query);
    return tree.iterateLeaves();
  }
}

export class DefaultTestFileLoader extends TestFileLoader {
  async listing(suite: string): Promise<TestSuiteListing> {
    return ((await import(`../../${suite}/listing.js`)) as ListingFile).listing;
  }

  import(path: string): Promise<SpecFile> {
    return import(`../../${path}`);
  }
}