blob: d8774df0836724eef1bd0135dcb3e6c20afd41a2 [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 Ninomiya8ec39402021-11-01 11:25:52 -070014// - (wpt server url)/webgpu/cts.https.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=
Kai Ninomiya9cbb8002020-05-18 15:33:41 -070025g.test('test_name').fn(t => {});
Kai Ninomiya04ec6b62019-10-25 00:35:32 -070026
Kai Ninomiyafba26302020-11-04 13:38:05 -080027g.test('not_implemented_yet,without_plan').unimplemented();
28g.test('not_implemented_yet,with_plan')
29 .desc(
30 `
31Plan for this test. What it tests. Summary of how it tests that functionality.
32- Description of cases, by describing parameters {a, b, c}
33- x= more parameters {x, y, z}
34`
35 )
36 .unimplemented();
37
Kai Ninomiyafb584a52020-04-16 16:43:24 -070038g.test('basic').fn(t => {
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -070039 t.expect(true);
40 t.expect(true, 'true should be true');
41
42 t.shouldThrow(
Kai Ninomiyabb2e71f2019-08-02 16:25:56 -070043 // The expected '.name' of the thrown error.
44 'TypeError',
45 // This function is run inline inside shouldThrow, and is expected to throw.
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -070046 () => {
Kai Ninomiyabb2e71f2019-08-02 16:25:56 -070047 throw new TypeError();
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -070048 },
Kai Ninomiyabb2e71f2019-08-02 16:25:56 -070049 // Log message.
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -070050 'function should throw Error'
51 );
52});
53
Kai Ninomiya9cbb8002020-05-18 15:33:41 -070054g.test('basic,async').fn(async t => {
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -070055 // shouldReject must be awaited to ensure it can wait for the promise before the test ends.
Kai Ninomiyac42e2982019-10-23 15:44:28 -070056 t.shouldReject(
Kai Ninomiyabb2e71f2019-08-02 16:25:56 -070057 // The expected '.name' of the thrown error.
58 'TypeError',
59 // Promise expected to reject.
60 Promise.reject(new TypeError()),
61 // Log message.
62 'Promise.reject should reject'
63 );
64
65 // Promise can also be an IIFE.
Kai Ninomiyac42e2982019-10-23 15:44:28 -070066 t.shouldReject(
Kai Ninomiyabb2e71f2019-08-02 16:25:56 -070067 'TypeError',
68 (async () => {
69 throw new TypeError();
70 })(),
71 'Promise.reject should reject'
72 );
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -070073});
74
Kai Ninomiya119b9532021-06-03 19:55:56 -070075g.test('basic,plain_cases')
76 .desc(
77 `
78A test can be parameterized with a simple array of objects using .paramsSimple([ ... ]).
79Each such instance of the test is a "case".
Enrico Galli9bec7342021-01-27 15:58:01 -080080
Kai Ninomiya119b9532021-06-03 19:55:56 -070081In this example, the following cases are generated (identified by their "query string"),
82each with just one subcase:
83 - webgpu:examples:basic,cases:x=2;y=2 runs 1 subcase, with t.params set to:
84 - { x: 2, y: 2 }
85 - webgpu:examples:basic,cases:x=-10;y=-10 runs 1 subcase, with t.params set to:
86 - { x: -10, y: -10 }
87 `
88 )
89 .paramsSimple([
90 { x: 2, y: 2 }, //
91 { x: -10, y: -10 },
92 ])
93 .fn(t => {
94 t.expect(t.params.x === t.params.y);
95 });
96
97g.test('basic,plain_cases_private')
98 .desc(
99 `
100Parameters can be public ("x", "y") which means they're part of the case name.
101They can also be private by starting with an underscore ("_result"), which passes
102them into the test but does not make them part of the case name:
103
104In this example, the following cases are generated, each with just one subcase:
105 - webgpu:examples:basic,cases:x=2;y=4 runs 1 subcase, with t.params set to:
106 - { x: 2, y: 4, _result: 6 }
107 - webgpu:examples:basic,cases:x=-10;y=18 runs 1 subcase, with t.params set to:
108 - { x: -10, y: 18, _result: 8 }
109 `
110 )
111 .paramsSimple([
Kai Ninomiyafb584a52020-04-16 16:43:24 -0700112 { x: 2, y: 4, _result: 6 }, //
113 { x: -10, y: 18, _result: 8 },
114 ])
115 .fn(t => {
116 t.expect(t.params.x + t.params.y === t.params._result);
117 });
Kai Ninomiya13820262019-10-17 15:30:56 -0700118// (note the blank comment above to enforce newlines on autoformat)
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -0700119
Kai Ninomiya119b9532021-06-03 19:55:56 -0700120g.test('basic,builder_cases')
121 .desc(
122 `
123A "CaseParamsBuilder" or "SubcaseParamsBuilder" can be passed to .params() instead.
124The params builder provides facilities for generating tests combinatorially (by cartesian
125product). For convenience, the "unit" CaseParamsBuilder is passed as an argument ("u" below).
Enrico Galli9bec7342021-01-27 15:58:01 -0800126
Kai Ninomiya119b9532021-06-03 19:55:56 -0700127In this example, the following cases are generated, each with just one subcase:
128 - webgpu:examples:basic,cases:x=1,y=1 runs 1 subcase, with t.params set to:
129 - { x: 1, y: 1 }
130 - webgpu:examples:basic,cases:x=1,y=2 runs 1 subcase, with t.params set to:
131 - { x: 1, y: 2 }
132 - webgpu:examples:basic,cases:x=2,y=1 runs 1 subcase, with t.params set to:
133 - { x: 2, y: 1 }
134 - webgpu:examples:basic,cases:x=2,y=2 runs 1 subcase, with t.params set to:
135 - { x: 2, y: 2 }
136 `
137 )
138 .params(u =>
139 u //
140 .combineWithParams([{ x: 1 }, { x: 2 }])
141 .combineWithParams([{ y: 1 }, { y: 2 }])
142 )
143 .fn(() => {});
Enrico Galli9bec7342021-01-27 15:58:01 -0800144
Kai Ninomiya119b9532021-06-03 19:55:56 -0700145g.test('basic,builder_cases_subcases')
146 .desc(
147 `
148Each case sub-parameterized using .beginSubcases().
149Each such instance of the test is a "subcase", which cannot be run independently of other
150subcases. It is somewhat like wrapping the entire fn body in a for-loop.
151
152In this example, the following cases are generated:
153 - webgpu:examples:basic,cases:x=1 runs 2 subcases, with t.params set to:
154 - { x: 1, y: 1 }
155 - { x: 1, y: 2 }
156 - webgpu:examples:basic,cases:x=2 runs 2 subcases, with t.params set to:
157 - { x: 2, y: 1 }
158 - { x: 2, y: 2 }
159 `
160 )
161 .params(u =>
162 u //
163 .combineWithParams([{ x: 1 }, { x: 2 }])
164 .beginSubcases()
165 .combineWithParams([{ y: 1 }, { y: 2 }])
166 )
167 .fn(() => {});
168
169g.test('basic,builder_subcases')
170 .desc(
171 `
172In this example, the following single case is generated:
173 - webgpu:examples:basic,cases: runs 4 subcases, with t.params set to:
174 - { x: 1, y: 1 }
175 - { x: 1, y: 2 }
176 - { x: 2, y: 1 }
177 - { x: 2, y: 2 }
178 `
179 )
180 .params(u =>
181 u //
182 .beginSubcases()
183 .combineWithParams([{ x: 1 }, { x: 2 }])
184 .combineWithParams([{ y: 1 }, { y: 2 }])
185 )
186 .fn(() => {});
187
188g.test('basic,builder_subcases_short')
189 .desc(
190 `
191As a shorthand, .paramsSubcasesOnly() can be used.
192
193In this example, the following single case is generated:
194 - webgpu:examples:basic,cases: runs 4 subcases, with t.params set to:
195 - { x: 1, y: 1 }
196 - { x: 1, y: 2 }
197 - { x: 2, y: 1 }
198 - { x: 2, y: 2 }
199 `
200 )
201 .paramsSubcasesOnly(u =>
202 u //
203 .combineWithParams([{ x: 1 }, { x: 2 }])
204 .combineWithParams([{ y: 1 }, { y: 2 }])
Kai Ninomiyad4c4dde2020-12-08 10:54:28 -0800205 )
206 .fn(() => {});
207
Kai Ninomiya9cbb8002020-05-18 15:33:41 -0700208g.test('gpu,async').fn(async t => {
Kai Ninomiya2f242cf2021-04-14 14:12:03 -0700209 const x = await t.queue.onSubmittedWorkDone();
210 t.expect(x === undefined);
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -0700211});
212
Kai Ninomiya9cbb8002020-05-18 15:33:41 -0700213g.test('gpu,buffers').fn(async t => {
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -0700214 const data = new Uint32Array([0, 1234, 0]);
Kai Ninomiya52d01b22021-08-02 20:15:19 -0700215 const src = t.makeBufferWithContents(data, GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST);
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -0700216
Kai Ninomiya52d01b22021-08-02 20:15:19 -0700217 // Use the expectGPUBufferValuesEqual helper to check the actual contents of a GPUBuffer.
218 // This makes a copy and then asynchronously checks the contents. The test fixture will
219 // wait on that result before reporting whether the test passed or failed.
Kai Ninomiya8de9aa52021-06-23 18:25:51 -0700220 t.expectGPUBufferValuesEqual(src, data);
Kai Ninomiya8e4e5dd2019-08-02 14:00:30 -0700221});
Kai Ninomiyafe0cbfa2020-09-25 10:17:24 -0700222
223// One of the following two tests should be skipped on most platforms.
224
225g.test('gpu,with_texture_compression,bc')
Kai Ninomiyafeb406c2020-11-19 15:11:13 -0800226 .desc(
227 `Example of a test using a device descriptor.
228Tests that a BC format passes validation iff the feature is enabled.`
229 )
Kai Ninomiya119b9532021-06-03 19:55:56 -0700230 .params(u => u.combine('textureCompressionBC', [false, true]))
Kai Ninomiyafe0cbfa2020-09-25 10:17:24 -0700231 .fn(async t => {
232 const { textureCompressionBC } = t.params;
233
234 if (textureCompressionBC) {
Kai Ninomiya0d21f752021-04-14 14:41:48 -0700235 await t.selectDeviceOrSkipTestCase('texture-compression-bc');
Kai Ninomiyafe0cbfa2020-09-25 10:17:24 -0700236 }
237
238 const shouldError = !textureCompressionBC;
239 t.expectGPUError(
240 'validation',
241 () => {
242 t.device.createTexture({
243 format: 'bc1-rgba-unorm',
244 size: [4, 4, 1],
Brandon Jones201435f2021-08-12 13:47:21 -0700245 usage: GPUTextureUsage.TEXTURE_BINDING,
Kai Ninomiyafe0cbfa2020-09-25 10:17:24 -0700246 });
247 },
248 shouldError
249 );
250 });
251
Lokbondo Kung0e9ad2d2021-11-16 17:57:05 -0800252g.test('gpu,with_texture_compression,etc2')
Kai Ninomiyafeb406c2020-11-19 15:11:13 -0800253 .desc(
254 `Example of a test using a device descriptor.
Lokbondo Kung0e9ad2d2021-11-16 17:57:05 -0800255Tests that an ETC2 format passes validation iff the feature is enabled.`
Kai Ninomiyafd207592021-11-08 16:18:42 -0800256 )
Lokbondo Kung0e9ad2d2021-11-16 17:57:05 -0800257 .params(u => u.combine('textureCompressionETC2', [false, true]))
Kai Ninomiyafd207592021-11-08 16:18:42 -0800258 .fn(async t => {
Lokbondo Kung0e9ad2d2021-11-16 17:57:05 -0800259 const { textureCompressionETC2 } = t.params;
Kai Ninomiyafd207592021-11-08 16:18:42 -0800260
Lokbondo Kung0e9ad2d2021-11-16 17:57:05 -0800261 if (textureCompressionETC2) {
262 await t.selectDeviceOrSkipTestCase('texture-compression-etc2' as GPUFeatureName);
Kai Ninomiyafe0cbfa2020-09-25 10:17:24 -0700263 }
264
Lokbondo Kung0e9ad2d2021-11-16 17:57:05 -0800265 const shouldError = !textureCompressionETC2;
266 t.expectGPUError(
267 'validation',
268 () => {
269 t.device.createTexture({
270 format: 'etc2-rgb8unorm',
271 size: [4, 4, 1],
272 usage: GPUTextureUsage.TEXTURE_BINDING,
273 });
274 },
275 shouldError
276 );
Kai Ninomiyafe0cbfa2020-09-25 10:17:24 -0700277 });