blob: b98527953621aa0e8cf690f77c7a74bbb8f6f18f [file] [log] [blame]
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -07001export const description = `
2Examples of writing CTS tests with various features.
Kai Ninomiyacb13fba2019-10-24 16:59:36 -07003
4Start here when looking for examples of basic framework usage.
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -07005`;
6
Kai Ninomiya9cbb8002020-05-18 15:33:41 -07007import { makeTestGroup } from '../common/framework/test_group.js';
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -07008
9import { GPUTest } from './gpu_test.js';
10
Kai Ninomiyae7561052021-04-29 15:37:09 -070011// To run these tests in the standalone runner, run `npm start` then open:
Kai Ninomiya119b9532021-06-03 19:55:56 -070012// - http://localhost:XXXX/standalone/?runnow=1&q=webgpu:examples:*
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -070013// To run in WPT, copy/symlink the out-wpt/ directory as the webgpu/ directory in WPT, then open:
Kai Ninomiya20bc11b2020-03-31 14:45:44 -070014// - (wpt server url)/webgpu/cts.html?q=webgpu:examples:
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -070015//
16// Tests here can be run individually or in groups:
Kai Ninomiyae7561052021-04-29 15:37:09 -070017// - ?q=webgpu:examples:basic,async:
18// - ?q=webgpu:examples:basic,async:*
19// - ?q=webgpu:examples:basic,*
20// - ?q=webgpu:examples:*
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -070021
Kai Ninomiya9cbb8002020-05-18 15:33:41 -070022export const g = makeTestGroup(GPUTest);
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -070023
Kai Ninomiya20bc11b2020-03-31 14:45:44 -070024// Note: spaces in test names are replaced with underscores: webgpu:examples:test_name=
Austin Eng639527e2020-04-14 16:20:36 -070025/* eslint-disable-next-line @typescript-eslint/no-unused-vars */
Kai Ninomiya9cbb8002020-05-18 15:33:41 -070026g.test('test_name').fn(t => {});
Kai Ninomiya04ec6b62019-10-25 00:35:32 -070027
Kai Ninomiyafba26302020-11-04 13:38:05 -080028g.test('not_implemented_yet,without_plan').unimplemented();
29g.test('not_implemented_yet,with_plan')
30 .desc(
31 `
32Plan for this test. What it tests. Summary of how it tests that functionality.
33- Description of cases, by describing parameters {a, b, c}
34- x= more parameters {x, y, z}
35`
36 )
37 .unimplemented();
38
Kai Ninomiyafb584a52020-04-16 16:43:24 -070039g.test('basic').fn(t => {
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -070040 t.expect(true);
41 t.expect(true, 'true should be true');
42
43 t.shouldThrow(
Kai Ninomiyabb2e71f2019-08-02 16:25:56 -070044 // The expected '.name' of the thrown error.
45 'TypeError',
46 // This function is run inline inside shouldThrow, and is expected to throw.
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -070047 () => {
Kai Ninomiyabb2e71f2019-08-02 16:25:56 -070048 throw new TypeError();
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -070049 },
Kai Ninomiyabb2e71f2019-08-02 16:25:56 -070050 // Log message.
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -070051 'function should throw Error'
52 );
53});
54
Kai Ninomiya9cbb8002020-05-18 15:33:41 -070055g.test('basic,async').fn(async t => {
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -070056 // shouldReject must be awaited to ensure it can wait for the promise before the test ends.
Kai Ninomiyac42e2982019-10-23 15:44:28 -070057 t.shouldReject(
Kai Ninomiyabb2e71f2019-08-02 16:25:56 -070058 // The expected '.name' of the thrown error.
59 'TypeError',
60 // Promise expected to reject.
61 Promise.reject(new TypeError()),
62 // Log message.
63 'Promise.reject should reject'
64 );
65
66 // Promise can also be an IIFE.
Kai Ninomiyac42e2982019-10-23 15:44:28 -070067 t.shouldReject(
Kai Ninomiyabb2e71f2019-08-02 16:25:56 -070068 'TypeError',
69 (async () => {
70 throw new TypeError();
71 })(),
72 'Promise.reject should reject'
73 );
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -070074});
75
Kai Ninomiya119b9532021-06-03 19:55:56 -070076g.test('basic,plain_cases')
77 .desc(
78 `
79A test can be parameterized with a simple array of objects using .paramsSimple([ ... ]).
80Each such instance of the test is a "case".
Enrico Galli9bec7342021-01-27 15:58:01 -080081
Kai Ninomiya119b9532021-06-03 19:55:56 -070082In this example, the following cases are generated (identified by their "query string"),
83each with just one subcase:
84 - webgpu:examples:basic,cases:x=2;y=2 runs 1 subcase, with t.params set to:
85 - { x: 2, y: 2 }
86 - webgpu:examples:basic,cases:x=-10;y=-10 runs 1 subcase, with t.params set to:
87 - { x: -10, y: -10 }
88 `
89 )
90 .paramsSimple([
91 { x: 2, y: 2 }, //
92 { x: -10, y: -10 },
93 ])
94 .fn(t => {
95 t.expect(t.params.x === t.params.y);
96 });
97
98g.test('basic,plain_cases_private')
99 .desc(
100 `
101Parameters can be public ("x", "y") which means they're part of the case name.
102They can also be private by starting with an underscore ("_result"), which passes
103them into the test but does not make them part of the case name:
104
105In this example, the following cases are generated, each with just one subcase:
106 - webgpu:examples:basic,cases:x=2;y=4 runs 1 subcase, with t.params set to:
107 - { x: 2, y: 4, _result: 6 }
108 - webgpu:examples:basic,cases:x=-10;y=18 runs 1 subcase, with t.params set to:
109 - { x: -10, y: 18, _result: 8 }
110 `
111 )
112 .paramsSimple([
Kai Ninomiyafb584a52020-04-16 16:43:24 -0700113 { x: 2, y: 4, _result: 6 }, //
114 { x: -10, y: 18, _result: 8 },
115 ])
116 .fn(t => {
117 t.expect(t.params.x + t.params.y === t.params._result);
118 });
Kai Ninomiya13820262019-10-17 15:30:56 -0700119// (note the blank comment above to enforce newlines on autoformat)
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -0700120
Kai Ninomiya119b9532021-06-03 19:55:56 -0700121g.test('basic,builder_cases')
122 .desc(
123 `
124A "CaseParamsBuilder" or "SubcaseParamsBuilder" can be passed to .params() instead.
125The params builder provides facilities for generating tests combinatorially (by cartesian
126product). For convenience, the "unit" CaseParamsBuilder is passed as an argument ("u" below).
Enrico Galli9bec7342021-01-27 15:58:01 -0800127
Kai Ninomiya119b9532021-06-03 19:55:56 -0700128In this example, the following cases are generated, each with just one subcase:
129 - webgpu:examples:basic,cases:x=1,y=1 runs 1 subcase, with t.params set to:
130 - { x: 1, y: 1 }
131 - webgpu:examples:basic,cases:x=1,y=2 runs 1 subcase, with t.params set to:
132 - { x: 1, y: 2 }
133 - webgpu:examples:basic,cases:x=2,y=1 runs 1 subcase, with t.params set to:
134 - { x: 2, y: 1 }
135 - webgpu:examples:basic,cases:x=2,y=2 runs 1 subcase, with t.params set to:
136 - { x: 2, y: 2 }
137 `
138 )
139 .params(u =>
140 u //
141 .combineWithParams([{ x: 1 }, { x: 2 }])
142 .combineWithParams([{ y: 1 }, { y: 2 }])
143 )
144 .fn(() => {});
Enrico Galli9bec7342021-01-27 15:58:01 -0800145
Kai Ninomiya119b9532021-06-03 19:55:56 -0700146g.test('basic,builder_cases_subcases')
147 .desc(
148 `
149Each case sub-parameterized using .beginSubcases().
150Each such instance of the test is a "subcase", which cannot be run independently of other
151subcases. It is somewhat like wrapping the entire fn body in a for-loop.
152
153In this example, the following cases are generated:
154 - webgpu:examples:basic,cases:x=1 runs 2 subcases, with t.params set to:
155 - { x: 1, y: 1 }
156 - { x: 1, y: 2 }
157 - webgpu:examples:basic,cases:x=2 runs 2 subcases, with t.params set to:
158 - { x: 2, y: 1 }
159 - { x: 2, y: 2 }
160 `
161 )
162 .params(u =>
163 u //
164 .combineWithParams([{ x: 1 }, { x: 2 }])
165 .beginSubcases()
166 .combineWithParams([{ y: 1 }, { y: 2 }])
167 )
168 .fn(() => {});
169
170g.test('basic,builder_subcases')
171 .desc(
172 `
173In this example, the following single case is generated:
174 - webgpu:examples:basic,cases: runs 4 subcases, with t.params set to:
175 - { x: 1, y: 1 }
176 - { x: 1, y: 2 }
177 - { x: 2, y: 1 }
178 - { x: 2, y: 2 }
179 `
180 )
181 .params(u =>
182 u //
183 .beginSubcases()
184 .combineWithParams([{ x: 1 }, { x: 2 }])
185 .combineWithParams([{ y: 1 }, { y: 2 }])
186 )
187 .fn(() => {});
188
189g.test('basic,builder_subcases_short')
190 .desc(
191 `
192As a shorthand, .paramsSubcasesOnly() can be used.
193
194In this example, the following single case is generated:
195 - webgpu:examples:basic,cases: runs 4 subcases, with t.params set to:
196 - { x: 1, y: 1 }
197 - { x: 1, y: 2 }
198 - { x: 2, y: 1 }
199 - { x: 2, y: 2 }
200 `
201 )
202 .paramsSubcasesOnly(u =>
203 u //
204 .combineWithParams([{ x: 1 }, { x: 2 }])
205 .combineWithParams([{ y: 1 }, { y: 2 }])
Kai Ninomiyad4c4dde2020-12-08 10:54:28 -0800206 )
207 .fn(() => {});
208
Kai Ninomiya9cbb8002020-05-18 15:33:41 -0700209g.test('gpu,async').fn(async t => {
Kai Ninomiya2f242cf2021-04-14 14:12:03 -0700210 const x = await t.queue.onSubmittedWorkDone();
211 t.expect(x === undefined);
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -0700212});
213
Kai Ninomiya9cbb8002020-05-18 15:33:41 -0700214g.test('gpu,buffers').fn(async t => {
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -0700215 const data = new Uint32Array([0, 1234, 0]);
Kai Ninomiyabe420af2020-07-24 18:32:40 -0700216 const src = t.device.createBuffer({
217 mappedAtCreation: true,
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -0700218 size: 12,
219 usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
220 });
Kai Ninomiyabe420af2020-07-24 18:32:40 -0700221 new Uint32Array(src.getMappedRange()).set(data);
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -0700222 src.unmap();
223
224 // Use the expectContents helper to check the actual contents of a GPUBuffer.
225 // Like shouldReject, it must be awaited.
Kai Ninomiyac42e2982019-10-23 15:44:28 -0700226 t.expectContents(src, data);
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -0700227});
Kai Ninomiyafe0cbfa2020-09-25 10:17:24 -0700228
229// One of the following two tests should be skipped on most platforms.
230
231g.test('gpu,with_texture_compression,bc')
Kai Ninomiyafeb406c2020-11-19 15:11:13 -0800232 .desc(
233 `Example of a test using a device descriptor.
234Tests that a BC format passes validation iff the feature is enabled.`
235 )
Kai Ninomiya119b9532021-06-03 19:55:56 -0700236 .params(u => u.combine('textureCompressionBC', [false, true]))
Kai Ninomiyafe0cbfa2020-09-25 10:17:24 -0700237 .fn(async t => {
238 const { textureCompressionBC } = t.params;
239
240 if (textureCompressionBC) {
Kai Ninomiya0d21f752021-04-14 14:41:48 -0700241 await t.selectDeviceOrSkipTestCase('texture-compression-bc');
Kai Ninomiyafe0cbfa2020-09-25 10:17:24 -0700242 }
243
244 const shouldError = !textureCompressionBC;
245 t.expectGPUError(
246 'validation',
247 () => {
248 t.device.createTexture({
249 format: 'bc1-rgba-unorm',
250 size: [4, 4, 1],
251 usage: GPUTextureUsage.SAMPLED,
252 });
253 },
254 shouldError
255 );
256 });
257
258g.test('gpu,with_texture_compression,etc')
Kai Ninomiyafeb406c2020-11-19 15:11:13 -0800259 .desc(
260 `Example of a test using a device descriptor.
261
262TODO: Test that an ETC format passes validation iff the feature is enabled.`
263 )
Kai Ninomiya119b9532021-06-03 19:55:56 -0700264 .params(u => u.combine('textureCompressionETC', [false, true]))
Kai Ninomiyafe0cbfa2020-09-25 10:17:24 -0700265 .fn(async t => {
266 const { textureCompressionETC } = t.params;
267
268 if (textureCompressionETC) {
Kai Ninomiya2f242cf2021-04-14 14:12:03 -0700269 await t.selectDeviceOrSkipTestCase('texture-compression-etc' as GPUFeatureName);
Kai Ninomiyafe0cbfa2020-09-25 10:17:24 -0700270 }
271
Kai Ninomiyafe0cbfa2020-09-25 10:17:24 -0700272 // TODO: Should actually test createTexture with an ETC format here.
273 });