diff options
Diffstat (limited to 'dom/webgpu/tests/cts/checkout/src/unittests/loaders_and_trees.spec.ts')
-rw-r--r-- | dom/webgpu/tests/cts/checkout/src/unittests/loaders_and_trees.spec.ts | 978 |
1 files changed, 978 insertions, 0 deletions
diff --git a/dom/webgpu/tests/cts/checkout/src/unittests/loaders_and_trees.spec.ts b/dom/webgpu/tests/cts/checkout/src/unittests/loaders_and_trees.spec.ts new file mode 100644 index 0000000000..a22c06e669 --- /dev/null +++ b/dom/webgpu/tests/cts/checkout/src/unittests/loaders_and_trees.spec.ts @@ -0,0 +1,978 @@ +export const description = ` +Tests for queries/filtering, loading, and running. +`; + +import { Fixture } from '../common/framework/fixture.js'; +import { makeTestGroup } from '../common/framework/test_group.js'; +import { TestFileLoader, SpecFile } from '../common/internal/file_loader.js'; +import { Logger } from '../common/internal/logging/logger.js'; +import { Status } from '../common/internal/logging/result.js'; +import { parseQuery } from '../common/internal/query/parseQuery.js'; +import { + TestQuery, + TestQuerySingleCase, + TestQueryMultiCase, + TestQueryMultiTest, + TestQueryMultiFile, + TestQueryWithExpectation, +} from '../common/internal/query/query.js'; +import { makeTestGroupForUnitTesting } from '../common/internal/test_group.js'; +import { TestSuiteListing, TestSuiteListingEntry } from '../common/internal/test_suite_listing.js'; +import { ExpandThroughLevel, TestTreeLeaf } from '../common/internal/tree.js'; +import { assert, objectEquals } from '../common/util/util.js'; + +import { UnitTest } from './unit_test.js'; + +const listingData: { [k: string]: TestSuiteListingEntry[] } = { + suite1: [ + { file: [], readme: 'desc 1a' }, + { file: ['foo'] }, + { file: ['bar'], readme: 'desc 1h' }, + { file: ['bar', 'biz'] }, + { file: ['bar', 'buzz', 'buzz'] }, + { file: ['baz'] }, + { file: ['empty'], readme: 'desc 1z' }, // directory with no files + ], + suite2: [{ file: [], readme: 'desc 2a' }, { file: ['foof'] }], +}; + +const specsData: { [k: string]: SpecFile } = { + 'suite1/foo.spec.js': { + description: 'desc 1b', + g: (() => { + const g = makeTestGroupForUnitTesting(UnitTest); + g.test('hello').fn(() => {}); + g.test('bonjour').fn(() => {}); + g.test('hola') + .desc('TODO TODO') + .fn(() => {}); + return g; + })(), + }, + 'suite1/bar/biz.spec.js': { + description: 'desc 1f TODO TODO', + g: makeTestGroupForUnitTesting(UnitTest), // file with no tests + }, + 'suite1/bar/buzz/buzz.spec.js': { + description: 'desc 1d TODO', + g: (() => { + const g = makeTestGroupForUnitTesting(UnitTest); + g.test('zap').fn(() => {}); + return g; + })(), + }, + 'suite1/baz.spec.js': { + description: 'desc 1e', + g: (() => { + const g = makeTestGroupForUnitTesting(UnitTest); + g.test('wye') + .paramsSimple([{}, { x: 1 }]) + .fn(() => {}); + g.test('zed') + .paramsSimple([ + { a: 1, b: 2, _c: 0 }, + { b: 3, a: 1, _c: 0 }, + ]) + .fn(() => {}); + g.test('batched') + // creates two cases: one for subcases 1,2 and one for subcase 3 + .paramsSubcasesOnly(u => u.combine('x', [1, 2, 3])) + .batch(2) + .fn(() => {}); + return g; + })(), + }, + 'suite2/foof.spec.js': { + description: 'desc 2b', + g: (() => { + const g = makeTestGroupForUnitTesting(UnitTest); + g.test('blah').fn(t => { + t.debug('OK'); + }); + g.test('bleh') + .paramsSimple([{ a: 1 }]) + .fn(t => { + t.debug('OK'); + t.debug('OK'); + }); + g.test('bluh,a').fn(t => { + t.fail('goodbye'); + }); + return g; + })(), + }, +}; + +class FakeTestFileLoader extends TestFileLoader { + listing(suite: string): Promise<TestSuiteListing> { + return Promise.resolve(listingData[suite]); + } + + import(path: string): Promise<SpecFile> { + assert(path in specsData, '[test] mock file ' + path + ' does not exist'); + return Promise.resolve(specsData[path]); + } +} + +class LoadingTest extends UnitTest { + loader: FakeTestFileLoader = new FakeTestFileLoader(); + events: (string | null)[] = []; + private isListenersAdded = false; + + collectEvents(): void { + this.events = []; + if (!this.isListenersAdded) { + this.isListenersAdded = true; + this.loader.addEventListener('import', ev => this.events.push(ev.data.url)); + this.loader.addEventListener('finish', _ev => this.events.push(null)); + } + } + + async load(query: string): Promise<TestTreeLeaf[]> { + return Array.from(await this.loader.loadCases(parseQuery(query))); + } + + async loadNames(query: string): Promise<string[]> { + return (await this.load(query)).map(c => c.query.toString()); + } +} + +export const g = makeTestGroup(LoadingTest); + +g.test('suite').fn(t => { + t.shouldReject('Error', t.load('suite1')); + t.shouldReject('Error', t.load('suite1:')); +}); + +g.test('group').fn(async t => { + t.collectEvents(); + t.expect((await t.load('suite1:*')).length === 10); + t.expect( + objectEquals(t.events, [ + 'suite1/foo.spec.js', + 'suite1/bar/biz.spec.js', + 'suite1/bar/buzz/buzz.spec.js', + 'suite1/baz.spec.js', + null, + ]) + ); + + t.collectEvents(); + t.expect((await t.load('suite1:foo,*')).length === 3); // x:foo,* matches x:foo: + t.expect(objectEquals(t.events, ['suite1/foo.spec.js', null])); + + t.collectEvents(); + t.expect((await t.load('suite1:bar,*')).length === 1); + t.expect( + objectEquals(t.events, ['suite1/bar/biz.spec.js', 'suite1/bar/buzz/buzz.spec.js', null]) + ); + + t.collectEvents(); + t.expect((await t.load('suite1:bar,buzz,buzz,*')).length === 1); + t.expect(objectEquals(t.events, ['suite1/bar/buzz/buzz.spec.js', null])); + + t.shouldReject('Error', t.load('suite1:f*')); + + { + const s = new TestQueryMultiFile('suite1', ['bar', 'buzz']).toString(); + t.collectEvents(); + t.expect((await t.load(s)).length === 1); + t.expect(objectEquals(t.events, ['suite1/bar/buzz/buzz.spec.js', null])); + } +}); + +g.test('test').fn(async t => { + t.shouldReject('Error', t.load('suite1::')); + t.shouldReject('Error', t.load('suite1:bar:')); + t.shouldReject('Error', t.load('suite1:bar,:')); + + t.shouldReject('Error', t.load('suite1::*')); + t.shouldReject('Error', t.load('suite1:bar,:*')); + t.shouldReject('Error', t.load('suite1:bar:*')); + + t.expect((await t.load('suite1:foo:*')).length === 3); + t.expect((await t.load('suite1:bar,buzz,buzz:*')).length === 1); + t.expect((await t.load('suite1:baz:*')).length === 6); + + t.expect((await t.load('suite2:foof:bluh,*')).length === 1); + t.expect((await t.load('suite2:foof:bluh,a,*')).length === 1); + + { + const s = new TestQueryMultiTest('suite2', ['foof'], ['bluh']).toString(); + t.expect((await t.load(s)).length === 1); + } +}); + +g.test('case').fn(async t => { + t.shouldReject('Error', t.load('suite1:foo::')); + t.shouldReject('Error', t.load('suite1:bar:zed,:')); + + t.shouldReject('Error', t.load('suite1:foo:h*')); + + t.shouldReject('Error', t.load('suite1:foo::*')); + t.shouldReject('Error', t.load('suite1:baz::*')); + t.shouldReject('Error', t.load('suite1:baz:zed,:*')); + + t.shouldReject('Error', t.load('suite1:baz:zed:')); + t.shouldReject('Error', t.load('suite1:baz:zed:a=1')); + t.shouldReject('Error', t.load('suite1:baz:zed:a=1;b=2*')); + t.shouldReject('Error', t.load('suite1:baz:zed:a=1;b=2;')); + t.shouldReject('SyntaxError', t.load('suite1:baz:zed:a=1;b=2,')); // tries to parse '2,' as JSON + t.shouldReject('Error', t.load('suite1:baz:zed:a=1,b=2')); // '=' not allowed in value '1,b=2' + t.shouldReject('Error', t.load('suite1:baz:zed:b=2*')); + t.shouldReject('Error', t.load('suite1:baz:zed:b=2;a=1;_c=0')); + t.shouldReject('Error', t.load('suite1:baz:zed:a=1,*')); + + t.expect((await t.load('suite1:baz:zed:*')).length === 2); + t.expect((await t.load('suite1:baz:zed:a=1;*')).length === 2); + t.expect((await t.load('suite1:baz:zed:a=1;b=2')).length === 1); + t.expect((await t.load('suite1:baz:zed:a=1;b=2;*')).length === 1); + t.expect((await t.load('suite1:baz:zed:b=2;*')).length === 1); + t.expect((await t.load('suite1:baz:zed:b=2;a=1')).length === 1); + t.expect((await t.load('suite1:baz:zed:b=2;a=1;*')).length === 1); + t.expect((await t.load('suite1:baz:zed:b=3;a=1')).length === 1); + t.expect((await t.load('suite1:baz:zed:a=1;b=3')).length === 1); + t.expect((await t.load('suite1:foo:hello:')).length === 1); + + { + const s = new TestQueryMultiCase('suite1', ['baz'], ['zed'], { a: 1, b: 2 }).toString(); + t.expect((await t.load(s)).length === 1); + } + { + const s = new TestQuerySingleCase('suite1', ['baz'], ['zed'], { a: 1, b: 2 }).toString(); + t.expect((await t.load(s)).length === 1); + } +}); + +g.test('batching').fn(async t => { + t.expect((await t.load('suite1:baz:batched,*')).length === 2); + t.expect((await t.load('suite1:baz:batched:*')).length === 2); + t.expect((await t.load('suite1:baz:batched:batch__=1;*')).length === 1); + t.expect((await t.load('suite1:baz:batched:batch__=1')).length === 1); +}); + +async function runTestcase( + t: Fixture, + log: Logger, + testcases: TestTreeLeaf[], + i: number, + query: TestQuery, + expectations: TestQueryWithExpectation[], + status: Status, + logs: (s: string[]) => boolean +) { + t.expect(objectEquals(testcases[i].query, query)); + const name = testcases[i].query.toString(); + const [rec, res] = log.record(name); + await testcases[i].run(rec, expectations); + + t.expect(log.results.get(name) === res); + t.expect(res.status === status); + t.expect(res.timems >= 0); + assert(res.logs !== undefined); // only undefined while pending + t.expect(logs(res.logs.map(l => JSON.stringify(l)))); +} + +g.test('end2end').fn(async t => { + const l = await t.load('suite2:foof:*'); + assert(l.length === 3, 'listing length'); + + const log = new Logger({ overrideDebugMode: true }); + + await runTestcase( + t, + log, + l, + 0, + new TestQuerySingleCase('suite2', ['foof'], ['blah'], {}), + [], + 'pass', + logs => objectEquals(logs, ['"DEBUG: OK"']) + ); + await runTestcase( + t, + log, + l, + 1, + new TestQuerySingleCase('suite2', ['foof'], ['bleh'], { a: 1 }), + [], + 'pass', + logs => objectEquals(logs, ['"DEBUG: OK"', '"DEBUG: OK"']) + ); + await runTestcase( + t, + log, + l, + 2, + new TestQuerySingleCase('suite2', ['foof'], ['bluh', 'a'], {}), + [], + 'fail', + logs => + logs.length === 1 && + logs[0].startsWith('"EXPECTATION FAILED: goodbye\\n') && + logs[0].indexOf('loaders_and_trees.spec.') !== -1 + ); +}); + +g.test('expectations,single_case').fn(async t => { + const log = new Logger({ overrideDebugMode: true }); + const zedCases = await t.load('suite1:baz:zed:*'); + + // Single-case. Covers one case. + const zedExpectationsSkipA1B2 = [ + { + query: new TestQuerySingleCase('suite1', ['baz'], ['zed'], { a: 1, b: 2 }), + expectation: 'skip' as const, + }, + ]; + + await runTestcase( + t, + log, + zedCases, + 0, + new TestQuerySingleCase('suite1', ['baz'], ['zed'], { a: 1, b: 2 }), + zedExpectationsSkipA1B2, + 'skip', + logs => logs.length === 1 && logs[0].startsWith('"SKIP: Skipped by expectations"') + ); + + await runTestcase( + t, + log, + zedCases, + 1, + new TestQuerySingleCase('suite1', ['baz'], ['zed'], { a: 1, b: 3 }), + zedExpectationsSkipA1B2, + 'pass', + logs => logs.length === 0 + ); +}); + +g.test('expectations,single_case,none').fn(async t => { + const log = new Logger({ overrideDebugMode: true }); + const zedCases = await t.load('suite1:baz:zed:*'); + // Single-case. Doesn't cover any cases. + const zedExpectationsSkipA1B0 = [ + { + query: new TestQuerySingleCase('suite1', ['baz'], ['zed'], { a: 1, b: 0 }), + expectation: 'skip' as const, + }, + ]; + + await runTestcase( + t, + log, + zedCases, + 0, + new TestQuerySingleCase('suite1', ['baz'], ['zed'], { a: 1, b: 2 }), + zedExpectationsSkipA1B0, + 'pass', + logs => logs.length === 0 + ); + + await runTestcase( + t, + log, + zedCases, + 1, + new TestQuerySingleCase('suite1', ['baz'], ['zed'], { a: 1, b: 3 }), + zedExpectationsSkipA1B0, + 'pass', + logs => logs.length === 0 + ); +}); + +g.test('expectations,multi_case').fn(async t => { + const log = new Logger({ overrideDebugMode: true }); + const zedCases = await t.load('suite1:baz:zed:*'); + // Multi-case, not all cases covered. + const zedExpectationsSkipB3 = [ + { + query: new TestQueryMultiCase('suite1', ['baz'], ['zed'], { b: 3 }), + expectation: 'skip' as const, + }, + ]; + + await runTestcase( + t, + log, + zedCases, + 0, + new TestQuerySingleCase('suite1', ['baz'], ['zed'], { a: 1, b: 2 }), + zedExpectationsSkipB3, + 'pass', + logs => logs.length === 0 + ); + + await runTestcase( + t, + log, + zedCases, + 1, + new TestQuerySingleCase('suite1', ['baz'], ['zed'], { a: 1, b: 3 }), + zedExpectationsSkipB3, + 'skip', + logs => logs.length === 1 && logs[0].startsWith('"SKIP: Skipped by expectations"') + ); +}); + +g.test('expectations,multi_case_all').fn(async t => { + const log = new Logger({ overrideDebugMode: true }); + const zedCases = await t.load('suite1:baz:zed:*'); + // Multi-case, all cases covered. + const zedExpectationsSkipA1 = [ + { + query: new TestQueryMultiCase('suite1', ['baz'], ['zed'], { a: 1 }), + expectation: 'skip' as const, + }, + ]; + + await runTestcase( + t, + log, + zedCases, + 0, + new TestQuerySingleCase('suite1', ['baz'], ['zed'], { a: 1, b: 2 }), + zedExpectationsSkipA1, + 'skip', + logs => logs.length === 1 && logs[0].startsWith('"SKIP: Skipped by expectations"') + ); + + await runTestcase( + t, + log, + zedCases, + 1, + new TestQuerySingleCase('suite1', ['baz'], ['zed'], { a: 1, b: 3 }), + zedExpectationsSkipA1, + 'skip', + logs => logs.length === 1 && logs[0].startsWith('"SKIP: Skipped by expectations"') + ); +}); + +g.test('expectations,multi_case_none').fn(async t => { + const log = new Logger({ overrideDebugMode: true }); + const zedCases = await t.load('suite1:baz:zed:*'); + // Multi-case, no params, all cases covered. + const zedExpectationsSkipZed = [ + { + query: new TestQueryMultiCase('suite1', ['baz'], ['zed'], {}), + expectation: 'skip' as const, + }, + ]; + + await runTestcase( + t, + log, + zedCases, + 0, + new TestQuerySingleCase('suite1', ['baz'], ['zed'], { a: 1, b: 2 }), + zedExpectationsSkipZed, + 'skip', + logs => logs.length === 1 && logs[0].startsWith('"SKIP: Skipped by expectations"') + ); + + await runTestcase( + t, + log, + zedCases, + 1, + new TestQuerySingleCase('suite1', ['baz'], ['zed'], { a: 1, b: 3 }), + zedExpectationsSkipZed, + 'skip', + logs => logs.length === 1 && logs[0].startsWith('"SKIP: Skipped by expectations"') + ); +}); + +g.test('expectations,multi_test').fn(async t => { + const log = new Logger({ overrideDebugMode: true }); + const suite1Cases = await t.load('suite1:*'); + + // Multi-test, all cases covered. + const expectationsSkipAllInBaz = [ + { + query: new TestQueryMultiTest('suite1', ['baz'], []), + expectation: 'skip' as const, + }, + ]; + + await runTestcase( + t, + log, + suite1Cases, + 4, + new TestQuerySingleCase('suite1', ['baz'], ['wye'], {}), + expectationsSkipAllInBaz, + 'skip', + logs => logs.length === 1 && logs[0].startsWith('"SKIP: Skipped by expectations"') + ); + + await runTestcase( + t, + log, + suite1Cases, + 6, + new TestQuerySingleCase('suite1', ['baz'], ['zed'], { a: 1, b: 2 }), + expectationsSkipAllInBaz, + 'skip', + logs => logs.length === 1 && logs[0].startsWith('"SKIP: Skipped by expectations"') + ); +}); + +g.test('expectations,multi_test,none').fn(async t => { + const log = new Logger({ overrideDebugMode: true }); + const suite1Cases = await t.load('suite1:*'); + + // Multi-test, no cases covered. + const expectationsSkipAllInFoo = [ + { + query: new TestQueryMultiTest('suite1', ['foo'], []), + expectation: 'skip' as const, + }, + ]; + + await runTestcase( + t, + log, + suite1Cases, + 4, + new TestQuerySingleCase('suite1', ['baz'], ['wye'], {}), + expectationsSkipAllInFoo, + 'pass', + logs => logs.length === 0 + ); + + await runTestcase( + t, + log, + suite1Cases, + 6, + new TestQuerySingleCase('suite1', ['baz'], ['zed'], { a: 1, b: 2 }), + expectationsSkipAllInFoo, + 'pass', + logs => logs.length === 0 + ); +}); + +g.test('expectations,multi_file').fn(async t => { + const log = new Logger({ overrideDebugMode: true }); + const suite1Cases = await t.load('suite1:*'); + + // Multi-file + const expectationsSkipAll = [ + { + query: new TestQueryMultiFile('suite1', []), + expectation: 'skip' as const, + }, + ]; + + await runTestcase( + t, + log, + suite1Cases, + 0, + new TestQuerySingleCase('suite1', ['foo'], ['hello'], {}), + expectationsSkipAll, + 'skip', + logs => logs.length === 1 && logs[0].startsWith('"SKIP: Skipped by expectations"') + ); + + await runTestcase( + t, + log, + suite1Cases, + 3, + new TestQuerySingleCase('suite1', ['bar', 'buzz', 'buzz'], ['zap'], {}), + expectationsSkipAll, + 'skip', + logs => logs.length === 1 && logs[0].startsWith('"SKIP: Skipped by expectations"') + ); +}); + +g.test('expectations,catches_failure').fn(async t => { + const log = new Logger({ overrideDebugMode: true }); + const suite2Cases = await t.load('suite2:*'); + + // Catches failure + const expectedFailures = [ + { + query: new TestQueryMultiCase('suite2', ['foof'], ['bluh', 'a'], {}), + expectation: 'fail' as const, + }, + ]; + + await runTestcase( + t, + log, + suite2Cases, + 0, + new TestQuerySingleCase('suite2', ['foof'], ['blah'], {}), + expectedFailures, + 'pass', + logs => objectEquals(logs, ['"DEBUG: OK"']) + ); + + // Status is passed, but failure is logged. + await runTestcase( + t, + log, + suite2Cases, + 2, + new TestQuerySingleCase('suite2', ['foof'], ['bluh', 'a'], {}), + expectedFailures, + 'pass', + logs => logs.length === 1 && logs[0].startsWith('"EXPECTATION FAILED: goodbye\\n') + ); +}); + +g.test('expectations,skip_dominates_failure').fn(async t => { + const log = new Logger({ overrideDebugMode: true }); + const suite2Cases = await t.load('suite2:*'); + + const expectedFailures = [ + { + query: new TestQueryMultiCase('suite2', ['foof'], ['bluh', 'a'], {}), + expectation: 'fail' as const, + }, + { + query: new TestQueryMultiCase('suite2', ['foof'], ['bluh', 'a'], {}), + expectation: 'skip' as const, + }, + ]; + + await runTestcase( + t, + log, + suite2Cases, + 2, + new TestQuerySingleCase('suite2', ['foof'], ['bluh', 'a'], {}), + expectedFailures, + 'skip', + logs => logs.length === 1 && logs[0].startsWith('"SKIP: Skipped by expectations"') + ); +}); + +g.test('expectations,skip_inside_failure').fn(async t => { + const log = new Logger({ overrideDebugMode: true }); + const suite2Cases = await t.load('suite2:*'); + + const expectedFailures = [ + { + query: new TestQueryMultiFile('suite2', []), + expectation: 'fail' as const, + }, + { + query: new TestQueryMultiCase('suite2', ['foof'], ['blah'], {}), + expectation: 'skip' as const, + }, + ]; + + await runTestcase( + t, + log, + suite2Cases, + 0, + new TestQuerySingleCase('suite2', ['foof'], ['blah'], {}), + expectedFailures, + 'skip', + logs => logs.length === 1 && logs[0].startsWith('"SKIP: Skipped by expectations"') + ); + + await runTestcase( + t, + log, + suite2Cases, + 2, + new TestQuerySingleCase('suite2', ['foof'], ['bluh', 'a'], {}), + expectedFailures, + 'pass', + logs => logs.length === 1 && logs[0].startsWith('"EXPECTATION FAILED: goodbye\\n') + ); +}); + +async function testIterateCollapsed( + t: LoadingTest, + alwaysExpandThroughLevel: ExpandThroughLevel, + expectations: string[], + expectedResult: 'throws' | string[] | [string, number | undefined][], + includeEmptySubtrees = false +) { + t.debug(`expandThrough=${alwaysExpandThroughLevel} expectations=${expectations}`); + const treePromise = t.loader.loadTree(new TestQueryMultiFile('suite1', []), { + subqueriesToExpand: expectations, + }); + if (expectedResult === 'throws') { + t.shouldReject('Error', treePromise, { + // Some errors here use StacklessError to print nicer command line outputs. + allowMissingStack: true, + }); + return; + } + const tree = await treePromise; + const actualIter = tree.iterateCollapsedNodes({ + includeEmptySubtrees, + alwaysExpandThroughLevel, + }); + const testingTODOs = expectedResult.length > 0 && expectedResult[0] instanceof Array; + const actual = Array.from(actualIter, ({ query, subtreeCounts }) => + testingTODOs ? [query.toString(), subtreeCounts?.nodesWithTODO] : query.toString() + ); + if (!objectEquals(actual, expectedResult)) { + t.fail( + `iterateCollapsed failed: + got ${JSON.stringify(actual)} + exp ${JSON.stringify(expectedResult)} +${tree.toString()}` + ); + } +} + +g.test('print').fn(async t => { + const tree = await t.loader.loadTree(new TestQueryMultiFile('suite1', [])); + tree.toString(); +}); + +g.test('iterateCollapsed').fn(async t => { + await testIterateCollapsed( + t, + 1, + [], + [ + ['suite1:foo:*', 1], // to-do propagated up from foo:hola + ['suite1:bar,buzz,buzz:*', 1], // to-do in file description + ['suite1:baz:*', 0], + ] + ); + await testIterateCollapsed( + t, + 2, + [], + [ + ['suite1:foo:hello:*', 0], + ['suite1:foo:bonjour:*', 0], + ['suite1:foo:hola:*', 1], // to-do in test description + ['suite1:bar,buzz,buzz:zap:*', 0], + ['suite1:baz:wye:*', 0], + ['suite1:baz:zed:*', 0], + ['suite1:baz:batched:*', 0], + ] + ); + await testIterateCollapsed( + t, + 3, + [], + [ + ['suite1:foo:hello:', undefined], + ['suite1:foo:bonjour:', undefined], + ['suite1:foo:hola:', undefined], + ['suite1:bar,buzz,buzz:zap:', undefined], + ['suite1:baz:wye:', undefined], + ['suite1:baz:wye:x=1', undefined], + ['suite1:baz:zed:a=1;b=2', undefined], + ['suite1:baz:zed:b=3;a=1', undefined], + ['suite1:baz:batched:batch__=0', undefined], + ['suite1:baz:batched:batch__=1', undefined], + ] + ); + + // Expectations lists that have no effect + await testIterateCollapsed( + t, + 1, + ['suite1:foo:*'], + ['suite1:foo:*', 'suite1:bar,buzz,buzz:*', 'suite1:baz:*'] + ); + await testIterateCollapsed( + t, + 1, + ['suite1:bar,buzz,buzz:*'], + ['suite1:foo:*', 'suite1:bar,buzz,buzz:*', 'suite1:baz:*'] + ); + await testIterateCollapsed( + t, + 2, + ['suite1:baz:wye:*'], + [ + 'suite1:foo:hello:*', + 'suite1:foo:bonjour:*', + 'suite1:foo:hola:*', + 'suite1:bar,buzz,buzz:zap:*', + 'suite1:baz:wye:*', + 'suite1:baz:zed:*', + 'suite1:baz:batched:*', + ] + ); + // Test with includeEmptySubtrees=true + await testIterateCollapsed( + t, + 1, + [], + [ + 'suite1:foo:*', + 'suite1:bar,biz:*', + 'suite1:bar,buzz,buzz:*', + 'suite1:baz:*', + 'suite1:empty,*', + ], + true + ); + await testIterateCollapsed( + t, + 2, + [], + [ + 'suite1:foo:hello:*', + 'suite1:foo:bonjour:*', + 'suite1:foo:hola:*', + 'suite1:bar,biz:*', + 'suite1:bar,buzz,buzz:zap:*', + 'suite1:baz:wye:*', + 'suite1:baz:zed:*', + 'suite1:baz:batched:*', + 'suite1:empty,*', + ], + true + ); + + // Expectations lists that have some effect + await testIterateCollapsed( + t, + 1, + ['suite1:baz:wye:*'], + [ + 'suite1:foo:*', + 'suite1:bar,buzz,buzz:*', + 'suite1:baz:wye:*', + 'suite1:baz:zed,*', + 'suite1:baz:batched,*', + ] + ); + await testIterateCollapsed( + t, + 1, + ['suite1:baz:zed:*'], + [ + 'suite1:foo:*', + 'suite1:bar,buzz,buzz:*', + 'suite1:baz:wye,*', + 'suite1:baz:zed:*', + 'suite1:baz:batched,*', + ] + ); + await testIterateCollapsed( + t, + 1, + ['suite1:baz:wye:*', 'suite1:baz:zed:*'], + [ + 'suite1:foo:*', + 'suite1:bar,buzz,buzz:*', + 'suite1:baz:wye:*', + 'suite1:baz:zed:*', + 'suite1:baz:batched,*', + ] + ); + await testIterateCollapsed( + t, + 1, + ['suite1:baz:wye:'], + [ + 'suite1:foo:*', + 'suite1:bar,buzz,buzz:*', + 'suite1:baz:wye:', + 'suite1:baz:wye:x=1;*', + 'suite1:baz:zed,*', + 'suite1:baz:batched,*', + ] + ); + await testIterateCollapsed( + t, + 1, + ['suite1:baz:wye:x=1'], + [ + 'suite1:foo:*', + 'suite1:bar,buzz,buzz:*', + 'suite1:baz:wye:', + 'suite1:baz:wye:x=1', + 'suite1:baz:zed,*', + 'suite1:baz:batched,*', + ] + ); + await testIterateCollapsed( + t, + 1, + ['suite1:foo:*', 'suite1:baz:wye:'], + [ + 'suite1:foo:*', + 'suite1:bar,buzz,buzz:*', + 'suite1:baz:wye:', + 'suite1:baz:wye:x=1;*', + 'suite1:baz:zed,*', + 'suite1:baz:batched,*', + ] + ); + await testIterateCollapsed( + t, + 2, + ['suite1:baz:wye:'], + [ + 'suite1:foo:hello:*', + 'suite1:foo:bonjour:*', + 'suite1:foo:hola:*', + 'suite1:bar,buzz,buzz:zap:*', + 'suite1:baz:wye:', + 'suite1:baz:wye:x=1;*', + 'suite1:baz:zed:*', + 'suite1:baz:batched:*', + ] + ); + await testIterateCollapsed( + t, + 2, + ['suite1:baz:wye:x=1'], + [ + 'suite1:foo:hello:*', + 'suite1:foo:bonjour:*', + 'suite1:foo:hola:*', + 'suite1:bar,buzz,buzz:zap:*', + 'suite1:baz:wye:', + 'suite1:baz:wye:x=1', + 'suite1:baz:zed:*', + 'suite1:baz:batched:*', + ] + ); + await testIterateCollapsed( + t, + 2, + ['suite1:foo:hello:*', 'suite1:baz:wye:'], + [ + 'suite1:foo:hello:*', + 'suite1:foo:bonjour:*', + 'suite1:foo:hola:*', + 'suite1:bar,buzz,buzz:zap:*', + 'suite1:baz:wye:', + 'suite1:baz:wye:x=1;*', + 'suite1:baz:zed:*', + 'suite1:baz:batched:*', + ] + ); + + // Invalid expectation queries + await testIterateCollapsed(t, 1, ['*'], 'throws'); + await testIterateCollapsed(t, 1, ['garbage'], 'throws'); + await testIterateCollapsed(t, 1, ['garbage*'], 'throws'); + await testIterateCollapsed(t, 1, ['suite1*'], 'throws'); + await testIterateCollapsed(t, 1, ['suite1:foo*'], 'throws'); + await testIterateCollapsed(t, 1, ['suite1:foo:he*'], 'throws'); + + // Valid expectation queries but they don't match anything + await testIterateCollapsed(t, 1, ['garbage:*'], 'throws'); + await testIterateCollapsed(t, 1, ['suite1:doesntexist:*'], 'throws'); + await testIterateCollapsed(t, 1, ['suite2:foo:*'], 'throws'); + // Can't expand subqueries bigger than one file. + await testIterateCollapsed(t, 1, ['suite1:*'], 'throws'); + await testIterateCollapsed(t, 1, ['suite1:bar,*'], 'throws'); + await testIterateCollapsed(t, 1, ['suite1:*'], 'throws'); + await testIterateCollapsed(t, 1, ['suite1:bar:hello,*'], 'throws'); + await testIterateCollapsed(t, 1, ['suite1:baz,*'], 'throws'); +}); |