Skip to content

Commit 905c7cb

Browse files
authored
Add some tests related to GPUDevice extending EventTarget (#4389)
* Test you can pass Event and CustomEvent through GPUDevice. * Test if you override a method on EventTarget it's called when you call the corresponding method on GPUDevice. * Test if you can pass GPUUncapturedErrorEvent through an EventTarget that is not GPUDevice Note: dawn.node fails these tests. It's not clear if NAPI makes this possible at all :(
1 parent f5816ba commit 905c7cb

File tree

4 files changed

+242
-113
lines changed

4 files changed

+242
-113
lines changed

src/common/framework/fixture.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -346,8 +346,22 @@ export class Fixture<S extends SubcaseBatchState = SubcaseBatchState> {
346346
}
347347
}
348348

349-
/** Expect that a condition is true. */
350-
expect(cond: boolean, msg?: string): boolean {
349+
/**
350+
* Expect that a condition is true.
351+
*
352+
* Note: You can pass a boolean condition, or a function that returns a boolean.
353+
* The advantage to passing a function is that if it's short it is self documenting.
354+
*
355+
* t.expect(size >= maxSize); // prints Expect OK:
356+
* t.expect(() => size >= maxSize) // prints Expect OK: () => size >= maxSize
357+
*/
358+
expect(cond: boolean | (() => boolean), msg?: string): boolean {
359+
if (typeof cond === 'function') {
360+
if (msg === undefined) {
361+
msg = cond.toString();
362+
}
363+
cond = cond();
364+
}
351365
if (cond) {
352366
const m = msg ? ': ' + msg : '';
353367
this.rec.debug(new Error('expect OK' + m));

src/resources/cache/hashes.json

Lines changed: 110 additions & 110 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/webgpu/idl/javascript.spec.ts

Lines changed: 115 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,12 @@ Examples:
1919
import { makeTestGroup } from '../../common/framework/test_group.js';
2020
import { keysOf } from '../../common/util/data_tables.js';
2121
import { getGPU } from '../../common/util/navigator_gpu.js';
22-
import { assert, objectEquals, unreachable } from '../../common/util/util.js';
22+
import {
23+
assert,
24+
objectEquals,
25+
raceWithRejectOnTimeout,
26+
unreachable,
27+
} from '../../common/util/util.js';
2328
import { getDefaultLimitsForDevice, kLimits } from '../capability_info.js';
2429
import { AllFeaturesMaxLimitsGPUTest, GPUTest } from '../gpu_test.js';
2530

@@ -562,3 +567,112 @@ and expect instances of these classes to respond correctly.
562567
const fn = kClassInheritanceTests[t.params.type];
563568
t.expect(fn(), fn.toString());
564569
});
570+
571+
const kDispatchTests = {
572+
async canPassEventThroughDevice(t: GPUTest) {
573+
const result = await raceWithRejectOnTimeout(
574+
new Promise(resolve => {
575+
t.device.addEventListener('foo', resolve, { once: true });
576+
t.device.dispatchEvent(new Event('foo'));
577+
}),
578+
500,
579+
'timeout'
580+
);
581+
const event = result as Event;
582+
t.expect(() => event instanceof Event, 'event');
583+
t.expect(() => event.type === 'foo');
584+
},
585+
async canPassCustomEventThroughDevice(t: GPUTest) {
586+
const result = await raceWithRejectOnTimeout(
587+
new Promise(resolve => {
588+
t.device.addEventListener('bar', resolve, { once: true });
589+
t.device.dispatchEvent(new CustomEvent('bar'));
590+
}),
591+
500,
592+
'timeout'
593+
);
594+
const event = result as CustomEvent;
595+
t.expect(() => event instanceof CustomEvent);
596+
t.expect(() => event instanceof Event);
597+
t.expect(() => event.type === 'bar');
598+
},
599+
async patchingEventTargetAffectsDevice(t: GPUTest) {
600+
let addEventListenerWasCalled = false;
601+
let dispatchEventWasCalled = false;
602+
let removeEventListenerWasCalled = false;
603+
604+
// eslint-disable-next-line @typescript-eslint/unbound-method
605+
const origFnAddEventListener = EventTarget.prototype.addEventListener;
606+
EventTarget.prototype.addEventListener = function (
607+
...args: Parameters<typeof EventTarget.prototype.addEventListener>
608+
) {
609+
addEventListenerWasCalled = true;
610+
return origFnAddEventListener.call(this, ...args);
611+
};
612+
613+
// eslint-disable-next-line @typescript-eslint/unbound-method
614+
const origFnDispatchEvent = EventTarget.prototype.dispatchEvent;
615+
EventTarget.prototype.dispatchEvent = function (event: Event) {
616+
dispatchEventWasCalled = true;
617+
return origFnDispatchEvent.call(this, event);
618+
};
619+
620+
// eslint-disable-next-line @typescript-eslint/unbound-method
621+
const origFnRemoveEventListener = EventTarget.prototype.removeEventListener;
622+
EventTarget.prototype.removeEventListener = function (
623+
...args: Parameters<typeof EventTarget.prototype.removeEventListener>
624+
) {
625+
removeEventListenerWasCalled = true;
626+
return origFnRemoveEventListener.call(this, ...args);
627+
};
628+
629+
try {
630+
await raceWithRejectOnTimeout(
631+
new Promise(resolve => {
632+
t.device.addEventListener('foo', resolve);
633+
t.device.dispatchEvent(new Event('foo'));
634+
t.device.removeEventListener('foo', resolve);
635+
}),
636+
500,
637+
'timeout'
638+
);
639+
} finally {
640+
EventTarget.prototype.addEventListener = origFnAddEventListener;
641+
EventTarget.prototype.dispatchEvent = origFnDispatchEvent;
642+
EventTarget.prototype.removeEventListener = origFnRemoveEventListener;
643+
}
644+
t.expect(addEventListenerWasCalled, 'overriding EventTarget addEventListener worked');
645+
t.expect(dispatchEventWasCalled, 'overriding EventTarget dispatchEvent worked');
646+
t.expect(removeEventListenerWasCalled, 'overriding EventTarget removeEventListener worked');
647+
},
648+
async passingGPUUncapturedErrorEventWorksThoughEventTarget(t: GPUTest) {
649+
const target = new EventTarget();
650+
const result = await raceWithRejectOnTimeout(
651+
new Promise(resolve => {
652+
target.addEventListener('uncapturederror', resolve, { once: true });
653+
target.dispatchEvent(
654+
new GPUUncapturedErrorEvent('uncapturederror', {
655+
error: new GPUValidationError('test error'),
656+
})
657+
);
658+
}),
659+
500,
660+
'timeout'
661+
);
662+
const event = result as GPUUncapturedErrorEvent;
663+
t.expect(() => event instanceof GPUUncapturedErrorEvent);
664+
t.expect(() => event.error instanceof GPUValidationError);
665+
t.expect(() => event.error.message === 'test error');
666+
},
667+
} as const;
668+
669+
g.test('device,EventTarget')
670+
.desc(
671+
`
672+
Test some repercussions of the fact that GPUDevice extends EventTarget
673+
`
674+
)
675+
.params(u => u.combine('test', keysOf(kDispatchTests)))
676+
.fn(async t => {
677+
await kDispatchTests[t.params.test](t);
678+
});

src/webgpu/listing_meta.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -916,6 +916,7 @@
916916
"webgpu:idl,constructable:gpu_errors:*": { "subcaseMS": 0.101 },
917917
"webgpu:idl,constructable:pipeline_errors:*": { "subcaseMS": 0.101 },
918918
"webgpu:idl,constructable:uncaptured_error_event:*": { "subcaseMS": 0.101 },
919+
"webgpu:idl,javascript:device,EventTarget:*": { "subcaseMS": 79.123 },
919920
"webgpu:shader,execution,expression,access,array,index:abstract_scalar:*": { "subcaseMS": 235.962 },
920921
"webgpu:shader,execution,expression,access,array,index:bool:*": { "subcaseMS": 663.038 },
921922
"webgpu:shader,execution,expression,access,array,index:concrete_scalar:*": { "subcaseMS": 1439.796 },

0 commit comments

Comments
 (0)