Make test cases hierarchical, and refactor/cleanup a lot in the process (#181)

* update tests, approximately

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* unittests:loading:* now passes

* passes 63 unittests, but not all are running...

* typechecks!!

* 58 unittests passing

* reenable getStackTrace tests

* wip

* finally all tests and checks pass!

* fixups

* wip

* replace all spaces with underscores in test names

* wip

* wip

* wip

* Dissolve TestLoader (now just use DefaultTestFileLoader)

* tighten ParamSpec type

* rename ParamSpec -> CaseParams

* make kParamSeparator ";", now standalone runner is working!

* add separate icon for leaf run buttons

* file renames

* remove user-select:all (not really needed anymore, triple click works fine now)

* cleanup some tests, add tests for test queries

* split interface for defining and running TestGroups

* more cleanup, fix URL encoding stuff, and standalone HTML

* fix readmes for parents of query

* clean up unused ReadmeFile interface

* dissolve id.ts

* test_suite_listing.ts

* split params_utils into param_utils + stringify_params

* rename encodeURLSelectively again

* add query.isMulti{File,Test,Case}

* fix gen_wpt_cts_html (at least for the simple mode; advanced mode probably still broken

* better run-one icon

* standalone: always make the url bar show the complete url

* revert tasks.json

* fix number out of bounds

* don't drop worker results, report input string on all query parse errors

* update docs/terms.md

* revisions

* more revisions

* make comparePublicParamsPaths order-agnostic (now allows queries against params out of order, but tree will not reorder itself accordingly)

* revise compareQueries, part 1

* revise compareQueries, part 2: compareOneLevel

* remove incorrect comment

* undo fast-glob dependency

* address Austin's comments

* address comments

* pass debug flag into test worker

* typo fixes
diff --git a/src/webgpu/examples.spec.ts b/src/webgpu/examples.spec.ts
index 0e1b0eb..024817f 100644
--- a/src/webgpu/examples.spec.ts
+++ b/src/webgpu/examples.spec.ts
@@ -4,7 +4,7 @@
 Start here when looking for examples of basic framework usage.
 `;
 
-import { TestGroup } from '../common/framework/test_group.js';
+import { makeTestGroup } from '../common/framework/test_group.js';
 
 import { GPUTest } from './gpu_test.js';
 
@@ -18,11 +18,11 @@
 // - ?q=webgpu:examples:basic/
 // - ?q=webgpu:examples:
 
-export const g = new TestGroup(GPUTest);
+export const g = makeTestGroup(GPUTest);
 
 // Note: spaces in test names are replaced with underscores: webgpu:examples:test_name=
 /* eslint-disable-next-line  @typescript-eslint/no-unused-vars */
-g.test('test name').fn(t => {});
+g.test('test_name').fn(t => {});
 
 g.test('basic').fn(t => {
   t.expect(true);
@@ -40,7 +40,7 @@
   );
 });
 
-g.test('basic/async').fn(async t => {
+g.test('basic,async').fn(async t => {
   // shouldReject must be awaited to ensure it can wait for the promise before the test ends.
   t.shouldReject(
     // The expected '.name' of the thrown error.
@@ -69,7 +69,7 @@
 //
 // - webgpu:examples:basic/params={"x":2,"y":4}    runs with t.params = {x: 2, y: 5, _result: 6}.
 // - webgpu:examples:basic/params={"x":-10,"y":18} runs with t.params = {x: -10, y: 18, _result: 8}.
-g.test('basic/params')
+g.test('basic,params')
   .params([
     { x: 2, y: 4, _result: 6 }, //
     { x: -10, y: 18, _result: 8 },
@@ -79,14 +79,14 @@
   });
 // (note the blank comment above to enforce newlines on autoformat)
 
-g.test('gpu/async').fn(async t => {
+g.test('gpu,async').fn(async t => {
   const fence = t.queue.createFence();
   t.queue.signal(fence, 2);
   await fence.onCompletion(1);
   t.expect(fence.getCompletedValue() === 2);
 });
 
-g.test('gpu/buffers').fn(async t => {
+g.test('gpu,buffers').fn(async t => {
   const data = new Uint32Array([0, 1234, 0]);
   const [src, map] = t.device.createBufferMapped({
     size: 12,