# Test Organization## `src/webgpu/`Because of the glorious amount of test needed, the WebGPU CTS is organized as a tree of arbitrarydepth (a filesystem with multiple tests per file).Each directory may have a `README.txt` describing its contents.Tests are grouped in large families (each of which has a `README.txt`);the root and first few levels looks like the following (some nodes omitted for simplicity):- **`api`** with tests for full coverage of the Javascript API surface of WebGPU.- **`validation`** with positive and negative tests for all the validation rules of the API.- **`operation`** with tests that checks the result of performing valid WebGPU operations,taking advantage of parametrization to exercise interactions between parts of the API.- **`regression`** for one-off tests that reproduce bugs found in implementations to preventthe bugs from appearing again.- **`shader`** with tests for full coverage of the shaders that can be passed to WebGPU.- **`validation`**.- **`execution`** similar to `api/operation`.- **`regression`**.- **`idl`** with tests to check that the WebGPU IDL is correctly implemented, for examples thatobjects exposed exactly the correct members, and that methods throw when passed incompletedictionaries.- **`web-platform`** with tests for Web platform-specific interactions like `GPUSwapChain` and`<canvas>`, WebXR and `GPUQueue.copyExternalImageToTexture`.At the same time test hierarchies can be used to split the testing of a single sub-object intoseveral file for maintainability. For example `GPURenderPipeline` has a large descriptor and someparts could be tested independently like `vertex_input` vs. `primitive_topology` vs. `blending`but all live under the `render_pipeline` directory.In addition to the test tree, each test can be parameterized. For coverage it is important totest all enums values, for example for `GPUTextureFormat`. Instead of having a loop to iterateover all the `GPUTextureFormat`, it is better to parameterize the test over them. Each formatwill have a different entry in the test list which will help WebGPU implementers debug the test,or suppress the failure without losing test coverage while they fix the bug.Extra capabilities (limits and features) are often tested in the same files as the rest of the API.For example, a compressed texture format capability would simply add a `GPUTextureFormat` to theparametrization lists of many tests, while a capability adding significant new functionalitylike ray-tracing could have a separate subtree.Operation tests for optional features should be skipped using `t.selectDeviceOrSkipTestCase()` or`t.skip()`. Validation tests should be written that test the behavior with and without thecapability enabled via `t.selectDeviceOrSkipTestCase()`, to ensure the functionality is validonly with the capability enabled.### Validation testsValidation tests check the validation rules that are (or will be) set by theWebGPU spec. Validation tests try to carefully trigger the individual validationrules in the spec, without simultaneously triggering other rules.Validation errors *generally* generate WebGPU errors, not exceptions.But check the spec on a case-by-case basis.Like all `GPUTest`s, `ValidationTest`s are wrapped in both types of error scope. These"catch-all" error scopes look for any errors during the test, and report them as test failures.Since error scopes can be nested, validation tests can nest an error scope to expect that there*are* errors from specific operations.#### ParameterizationTest parameterization can help write many validation tests more succinctly,while making it easier for both authors and reviewers to be confident thatan aspect of the API is tested fully. Examples:- [`webgpu:api,validation,render_pass,resolve:resolve_attachment:*`](https://github.com/gpuweb/cts/blob/ded3b7c8a4680a1a01621a8ac859facefadf32d0/src/webgpu/api/validation/render_pass/resolve.spec.ts#L35)- [`webgpu:api,validation,createBindGroupLayout:bindingTypeSpecific_optional_members:*`](https://github.com/gpuweb/cts/blob/ded3b7c8a4680a1a01621a8ac859facefadf32d0/src/webgpu/api/validation/createBindGroupLayout.spec.ts#L68)Combinatorial explosions make it easy to over-parameterize tests. Be intentional about thecombinations of parameters being tested. For example, for validation tests, avoid (sub)casesthat trigger multiple validation errors at once. In general, avoid combining over parametersthat shouldn't have any significant interaction in an implementation.- Instead of:```tsu// valid and invalid values for x/y.combine('x', [0, 1, 4, 5, 100]).combine('y', [0, 1, 4, 5, 100])```- Try:```tsu.combineWithParams([// control case{ x: 4, y: 4 },// invalid values of x{ x: 0, y: 4 },{ x: 5, y: 4 },// invalid values of y{ x: 4, y: 0 },{ x: 4, y: 5 },])```- Or even:```tsu.combineWithParams([// control case{ x: 4, y: 4 },// invalid values of x...u.combine('y', [4]).combine('x', [0, 5])// invalid values of y...u.combine('x', [4]).combine('y', [0, 5])])```Use your own discretion when deciding to heavily parameterize a test, use amore targeted parameterization, or write multiple separate tests.#### GuidelinesThere are many aspects that should be tested in all validation tests:- each individual argument to a method call (including `this`) or member of a descriptordictionary should be tested including:- what happens when an error object is passed.- what happens when an optional feature enum or method is used.- what happens for numeric values when they are at 0, too large, too small, etc.- each validation rule in the specification should be checked both with a control success case,and error cases.- each set of arguments or state that interact for validation.When testing numeric values, it is important to check on both sides of the boundary: if the errorhappens for value N and not N - 1, both should be tested. Alignment of integer values should alsobe tested but boundary testing of alignment should be between a value aligned to 2^N and a valuealigned to 2^(N-1).Finally, this is probably also where we would test that extensions follow the rule that: if thebrowser supports a feature but it is not enabled on the device, then calling methods from thatfeature throws `TypeError`.- Test providing unknown properties *that are definitely not part of any feature* arevalid/ignored. (Unfortunately, due to the rules of IDL, adding a member to a dictionary isalways a breaking change. So this is how we have to test this unless we can get a "strict"dictionary type in IDL. We can't test adding members from non-enabled extensions.)### Operation testsOperation tests test the actual results of using the API. They execute(sometimes significant) code and check that the result is within the expectedset of behaviors (which can be quite complex to compute).Note that operation tests need to test a lot of interactions between differentparts of the API, and so can become quite complex. Try to reduce the complexity byutilizing combinatorics and [helpers](./helper_index.txt), and splitting/merging test files as needed.#### ErrorsOperation tests are usually `GPUTest`s. As a result, they automatically fail on any validationerrors that occur during the test.When it's easier to write an operation test with invalid cases, use`ParamsBuilder.filter`/`.unless` to avoid invalid cases, or detect and`expect` validation errors in some cases.#### ImplementationUse helpers like `expectContents` (and more to come) to check the values of data on the GPU.(These are "eventual expectations" - the harness will wait for them to finish at the end).When testing something inside a shader, it's not always necessary to output the result to arender output. In fragment shaders, you can output to a storage buffer. In vertex shaders, youcan't - but you can render with points (simplest), send the result to the fragment shader, andoutput it from there. (Someday, we may end up wanting a helper for this.)#### Testing Default ValuesDefault value tests (for arguments and dictionary members) should usually be operation tests -all you have to do is include `undefined` in parameterizations of other tests to make sure thebehavior with `undefined` has the same expected result that you have when the default value isspecified explicitly.### IDL testsTODO: figure out how to implement these. https://github.com/gpuweb/cts/issues/332These tests test only rules that come directly from WebIDL. For example:- Values out of range for `[EnforceRange]` cause exceptions.- Required function arguments and dictionary members cause exceptions if omitted.- Arguments and dictionary members cause exceptions if passed the wrong type.They may also test positive cases like the following, but the behavior of these should be tested inoperation tests.- OK to omit optional arguments/members.- OK to pass the correct argument/member type (or of any type in a union type).Every overload of every method should be tested.## `src/stress/`, `src/manual/`Stress tests and manual tests for WebGPU that are not intended to be run in an automated way.## `src/unittests/`Unit tests for the test framework (`src/common/framework/`).## `src/demo/`A demo of test hierarchies for the purpose of testing the `standalone` test runner page.