diff options
Diffstat (limited to 'tools/wpt')
-rw-r--r-- | tools/wpt/expectation.json | 622 | ||||
-rw-r--r-- | tools/wpt/runner.ts | 133 | ||||
-rw-r--r-- | tools/wpt/testharnessreport.js | 12 | ||||
-rw-r--r-- | tools/wpt/utils.ts | 168 |
4 files changed, 935 insertions, 0 deletions
diff --git a/tools/wpt/expectation.json b/tools/wpt/expectation.json new file mode 100644 index 000000000..5bc4d77bc --- /dev/null +++ b/tools/wpt/expectation.json @@ -0,0 +1,622 @@ +{ + "WebCryptoAPI": { + "getRandomValues.any.js": true + }, + "console": { + "console-is-a-namespace.any.js": true, + "console-label-conversion.any.js": true, + "console-namespace-object-class-string.any.js": true, + "console-tests-historical.any.js": true, + "idlharness.any.js": false + }, + "dom": { + "abort": { + "event.any.js": true + }, + "events": { + "AddEventListenerOptions-signal.any.js": true, + "Event-dispatch-listener-order.window.js": true, + "Event-isTrusted.any.js": true, + "EventListener-addEventListener.sub.window.js": true, + "EventTarget-constructible.any.js": true, + "event-global-extra.window.js": true, + "event-global.worker.js": true, + "legacy-pre-activation-behavior.window.js": true, + "relatedTarget.window.js": true + }, + "idlharness.any.js": false, + "idlharness.window.js": false + }, + "encoding": { + "api-basics.any.js": true, + "api-invalid-label.any.js": true, + "api-replacement-encodings.any.js": true, + "api-surrogates-utf8.any.js": true, + "encodeInto.any.js": [ + "encodeInto() into SharedArrayBuffer with Hi and destination length 0, offset 0, filler 0", + "encodeInto() into SharedArrayBuffer with Hi and destination length 0, offset 4, filler 0", + "encodeInto() into SharedArrayBuffer with Hi and destination length 0, offset 0, filler 128", + "encodeInto() into SharedArrayBuffer with Hi and destination length 0, offset 4, filler 128", + "encodeInto() into SharedArrayBuffer with Hi and destination length 0, offset 0, filler random", + "encodeInto() into SharedArrayBuffer with Hi and destination length 0, offset 4, filler random", + "encodeInto() into SharedArrayBuffer with A and destination length 10, offset 0, filler 0", + "encodeInto() into SharedArrayBuffer with A and destination length 10, offset 4, filler 0", + "encodeInto() into SharedArrayBuffer with A and destination length 10, offset 0, filler 128", + "encodeInto() into SharedArrayBuffer with A and destination length 10, offset 4, filler 128", + "encodeInto() into SharedArrayBuffer with A and destination length 10, offset 0, filler random", + "encodeInto() into SharedArrayBuffer with A and destination length 10, offset 4, filler random", + "encodeInto() into SharedArrayBuffer with 𝌆 and destination length 4, offset 0, filler 0", + "encodeInto() into SharedArrayBuffer with 𝌆 and destination length 4, offset 4, filler 0", + "encodeInto() into SharedArrayBuffer with 𝌆 and destination length 4, offset 0, filler 128", + "encodeInto() into SharedArrayBuffer with 𝌆 and destination length 4, offset 4, filler 128", + "encodeInto() into SharedArrayBuffer with 𝌆 and destination length 4, offset 0, filler random", + "encodeInto() into SharedArrayBuffer with 𝌆 and destination length 4, offset 4, filler random", + "encodeInto() into SharedArrayBuffer with 𝌆A and destination length 3, offset 0, filler 0", + "encodeInto() into SharedArrayBuffer with 𝌆A and destination length 3, offset 4, filler 0", + "encodeInto() into SharedArrayBuffer with 𝌆A and destination length 3, offset 0, filler 128", + "encodeInto() into SharedArrayBuffer with 𝌆A and destination length 3, offset 4, filler 128", + "encodeInto() into SharedArrayBuffer with 𝌆A and destination length 3, offset 0, filler random", + "encodeInto() into SharedArrayBuffer with 𝌆A and destination length 3, offset 4, filler random", + "encodeInto() into ArrayBuffer with \ud834A\udf06A¥Hi and destination length 10, offset 0, filler 0", + "encodeInto() into SharedArrayBuffer with \ud834A\udf06A¥Hi and destination length 10, offset 0, filler 0", + "encodeInto() into ArrayBuffer with \ud834A\udf06A¥Hi and destination length 10, offset 4, filler 0", + "encodeInto() into SharedArrayBuffer with \ud834A\udf06A¥Hi and destination length 10, offset 4, filler 0", + "encodeInto() into ArrayBuffer with \ud834A\udf06A¥Hi and destination length 10, offset 0, filler 128", + "encodeInto() into SharedArrayBuffer with \ud834A\udf06A¥Hi and destination length 10, offset 0, filler 128", + "encodeInto() into ArrayBuffer with \ud834A\udf06A¥Hi and destination length 10, offset 4, filler 128", + "encodeInto() into SharedArrayBuffer with \ud834A\udf06A¥Hi and destination length 10, offset 4, filler 128", + "encodeInto() into ArrayBuffer with \ud834A\udf06A¥Hi and destination length 10, offset 0, filler random", + "encodeInto() into SharedArrayBuffer with \ud834A\udf06A¥Hi and destination length 10, offset 0, filler random", + "encodeInto() into ArrayBuffer with \ud834A\udf06A¥Hi and destination length 10, offset 4, filler random", + "encodeInto() into SharedArrayBuffer with \ud834A\udf06A¥Hi and destination length 10, offset 4, filler random", + "encodeInto() into ArrayBuffer with A\udf06 and destination length 4, offset 0, filler 0", + "encodeInto() into SharedArrayBuffer with A\udf06 and destination length 4, offset 0, filler 0", + "encodeInto() into ArrayBuffer with A\udf06 and destination length 4, offset 4, filler 0", + "encodeInto() into SharedArrayBuffer with A\udf06 and destination length 4, offset 4, filler 0", + "encodeInto() into ArrayBuffer with A\udf06 and destination length 4, offset 0, filler 128", + "encodeInto() into SharedArrayBuffer with A\udf06 and destination length 4, offset 0, filler 128", + "encodeInto() into ArrayBuffer with A\udf06 and destination length 4, offset 4, filler 128", + "encodeInto() into SharedArrayBuffer with A\udf06 and destination length 4, offset 4, filler 128", + "encodeInto() into ArrayBuffer with A\udf06 and destination length 4, offset 0, filler random", + "encodeInto() into SharedArrayBuffer with A\udf06 and destination length 4, offset 0, filler random", + "encodeInto() into ArrayBuffer with A\udf06 and destination length 4, offset 4, filler random", + "encodeInto() into SharedArrayBuffer with A\udf06 and destination length 4, offset 4, filler random", + "encodeInto() into SharedArrayBuffer with ¥¥ and destination length 4, offset 0, filler 0", + "encodeInto() into SharedArrayBuffer with ¥¥ and destination length 4, offset 4, filler 0", + "encodeInto() into SharedArrayBuffer with ¥¥ and destination length 4, offset 0, filler 128", + "encodeInto() into SharedArrayBuffer with ¥¥ and destination length 4, offset 4, filler 128", + "encodeInto() into SharedArrayBuffer with ¥¥ and destination length 4, offset 0, filler random", + "encodeInto() into SharedArrayBuffer with ¥¥ and destination length 4, offset 4, filler random", + "encodeInto() and a detached output buffer", + "Invalid encodeInto() destination: DataView, backed by: SharedArrayBuffer", + "Invalid encodeInto() destination: Int8Array, backed by: SharedArrayBuffer", + "Invalid encodeInto() destination: Int16Array, backed by: SharedArrayBuffer", + "Invalid encodeInto() destination: Int32Array, backed by: SharedArrayBuffer", + "Invalid encodeInto() destination: Uint16Array, backed by: SharedArrayBuffer", + "Invalid encodeInto() destination: Uint32Array, backed by: SharedArrayBuffer", + "Invalid encodeInto() destination: Uint8ClampedArray, backed by: SharedArrayBuffer", + "Invalid encodeInto() destination: Float32Array, backed by: SharedArrayBuffer", + "Invalid encodeInto() destination: Float64Array, backed by: SharedArrayBuffer", + "Invalid encodeInto() destination: SharedArrayBuffer" + ], + "idlharness.any.js": false, + "iso-2022-jp-decoder.any.js": false, + "legacy-mb-schinese": { + "gb18030": { + "gb18030-decoder.any.js": true + }, + "gbk": { + "gbk-decoder.any.js": true + } + }, + "replacement-encodings.any.js": false, + "streams": { + "backpressure.any.js": false, + "decode-attributes.any.js": false, + "decode-bad-chunks.any.js": false, + "decode-ignore-bom.any.js": false, + "decode-incomplete-input.any.js": false, + "decode-non-utf8.any.js": false, + "decode-split-character.any.js": false, + "decode-utf8.any.js": false, + "encode-bad-chunks.any.js": false, + "encode-utf8.any.js": false, + "readable-writable-properties.any.js": false, + "realms.window.js": false + }, + "textdecoder-byte-order-marks.any.js": true, + "textdecoder-copy.any.js": [ + "Modify buffer after passing it in (ArrayBuffer)", + "Modify buffer after passing it in (SharedArrayBuffer)" + ], + "textdecoder-fatal-single-byte.any.js": true, + "textdecoder-fatal-streaming.any.js": [ + "Fatal flag, streaming cases" + ], + "textdecoder-fatal.any.js": true, + "textdecoder-ignorebom.any.js": true, + "textdecoder-labels.any.js": [ + "cseucpkdfmtjapanese => EUC-JP", + "euc-jp => EUC-JP", + "x-euc-jp => EUC-JP", + "csiso2022jp => ISO-2022-JP", + "iso-2022-jp => ISO-2022-JP", + "csshiftjis => Shift_JIS", + "ms932 => Shift_JIS", + "ms_kanji => Shift_JIS", + "shift-jis => Shift_JIS", + "shift_jis => Shift_JIS", + "sjis => Shift_JIS", + "windows-31j => Shift_JIS", + "x-sjis => Shift_JIS", + "cseuckr => EUC-KR", + "csksc56011987 => EUC-KR", + "euc-kr => EUC-KR", + "iso-ir-149 => EUC-KR", + "korean => EUC-KR", + "ks_c_5601-1987 => EUC-KR", + "ks_c_5601-1989 => EUC-KR", + "ksc5601 => EUC-KR", + "ksc_5601 => EUC-KR", + "windows-949 => EUC-KR", + "x-user-defined => x-user-defined" + ], + "textdecoder-streaming.any.js": false, + "textdecoder-utf16-surrogates.any.js": true, + "textencoder-constructor-non-utf.any.js": [ + "Encoding argument supported for decode: EUC-JP", + "Encoding argument supported for decode: ISO-2022-JP", + "Encoding argument supported for decode: Shift_JIS", + "Encoding argument supported for decode: EUC-KR", + "Encoding argument supported for decode: x-user-defined" + ], + "textencoder-utf16-surrogates.any.js": true, + "unsupported-encodings.any.js": false + }, + "hr-time": { + "monotonic-clock.any.js": true, + "basic.any.js": [ + "Performance interface extends EventTarget." + ], + "idlharness.any.js": false + }, + "streams": { + "idlharness.any.js": false, + "piping": { + "abort.any.js": [ + "a signal argument 'null' should cause pipeTo() to reject", + "a signal argument 'AbortSignal' should cause pipeTo() to reject", + "a signal argument 'true' should cause pipeTo() to reject", + "a signal argument '-1' should cause pipeTo() to reject", + "a signal argument '[object AbortSignal]' should cause pipeTo() to reject" + ], + "close-propagation-backward.any.js": [ + "Closing must be propagated backward: starts closed; preventCancel = null (falsy); fulfilled cancel promise", + "Closing must be propagated backward: starts closed; preventCancel = 0 (falsy); fulfilled cancel promise", + "Closing must be propagated backward: starts closed; preventCancel = -0 (falsy); fulfilled cancel promise", + "Closing must be propagated backward: starts closed; preventCancel = NaN (falsy); fulfilled cancel promise", + "Closing must be propagated backward: starts closed; preventCancel = (falsy); fulfilled cancel promise", + "Closing must be propagated backward: starts closed; preventCancel = a (truthy)", + "Closing must be propagated backward: starts closed; preventCancel = 1 (truthy)", + "Closing must be propagated backward: starts closed; preventCancel = Symbol() (truthy)", + "Closing must be propagated backward: starts closed; preventCancel = [object Object] (truthy)" + ], + "close-propagation-forward.any.js": [ + "Closing must be propagated forward: starts closed; preventClose = null (falsy); fulfilled close promise", + "Closing must be propagated forward: starts closed; preventClose = 0 (falsy); fulfilled close promise", + "Closing must be propagated forward: starts closed; preventClose = -0 (falsy); fulfilled close promise", + "Closing must be propagated forward: starts closed; preventClose = NaN (falsy); fulfilled close promise", + "Closing must be propagated forward: starts closed; preventClose = (falsy); fulfilled close promise", + "Closing must be propagated forward: starts closed; preventClose = a (truthy)", + "Closing must be propagated forward: starts closed; preventClose = 1 (truthy)", + "Closing must be propagated forward: starts closed; preventClose = Symbol() (truthy)", + "Closing must be propagated forward: starts closed; preventClose = [object Object] (truthy)" + ], + "error-propagation-backward.any.js": [ + "Errors must be propagated backward: becomes errored before piping due to write; preventCancel = null (falsy); fulfilled cancel promise", + "Errors must be propagated backward: becomes errored before piping due to write; preventCancel = 0 (falsy); fulfilled cancel promise", + "Errors must be propagated backward: becomes errored before piping due to write; preventCancel = -0 (falsy); fulfilled cancel promise", + "Errors must be propagated backward: becomes errored before piping due to write; preventCancel = NaN (falsy); fulfilled cancel promise", + "Errors must be propagated backward: becomes errored before piping due to write; preventCancel = (falsy); fulfilled cancel promise", + "Errors must be propagated backward: becomes errored before piping due to write; preventCancel = a (truthy)", + "Errors must be propagated backward: becomes errored before piping due to write; preventCancel = 1 (truthy)", + "Errors must be propagated backward: becomes errored before piping due to write; preventCancel = Symbol() (truthy)", + "Errors must be propagated backward: becomes errored before piping due to write; preventCancel = [object Object] (truthy)" + ], + "error-propagation-forward.any.js": [ + "Errors must be propagated forward: starts errored; preventAbort = null (falsy); fulfilled abort promise", + "Errors must be propagated forward: starts errored; preventAbort = 0 (falsy); fulfilled abort promise", + "Errors must be propagated forward: starts errored; preventAbort = -0 (falsy); fulfilled abort promise", + "Errors must be propagated forward: starts errored; preventAbort = NaN (falsy); fulfilled abort promise", + "Errors must be propagated forward: starts errored; preventAbort = (falsy); fulfilled abort promise", + "Errors must be propagated forward: starts errored; preventAbort = a (truthy)", + "Errors must be propagated forward: starts errored; preventAbort = 1 (truthy)", + "Errors must be propagated forward: starts errored; preventAbort = Symbol() (truthy)", + "Errors must be propagated forward: starts errored; preventAbort = [object Object] (truthy)" + ], + "flow-control.any.js": true, + "general.any.js": [ + "pipeTo must check the brand of its ReadableStream this value", + "pipeTo must check the brand of its WritableStream argument", + "pipeTo() promise should resolve if null is passed" + ], + "multiple-propagation.any.js": true, + "pipe-through.any.js": true, + "then-interception.any.js": true, + "throwing-options.any.js": false, + "transform-streams.any.js": true + }, + "queuing-strategies-size-function-per-global.window.js": false, + "queuing-strategies.any.js": true, + "readable-byte-streams": { + "bad-buffers-and-views.any.js": [ + "ReadableStream with byte source: respond() throws if the BYOB request's buffer has been detached (in the readable state)", + "ReadableStream with byte source: respond() throws if the BYOB request's buffer has been detached (in the closed state)", + "ReadableStream with byte source: respondWithNewView() throws if the supplied view's buffer has been detached (in the readable state)", + "ReadableStream with byte source: respondWithNewView() throws if the supplied view's buffer is zero-length (in the readable state)", + "ReadableStream with byte source: respondWithNewView() throws if the supplied view is zero-length on a non-zero-length buffer (in the readable state)", + "ReadableStream with byte source: respondWithNewView() throws if the supplied view's buffer has been detached (in the closed state)", + "ReadableStream with byte source: respondWithNewView() throws if the supplied view's buffer is zero-length (in the closed state)", + "ReadableStream with byte source: respondWithNewView() throws if the supplied view is zero-length on a non-zero-length buffer (in the closed state)", + "ReadableStream with byte source: read()ing from a closed stream still transfers the buffer", + "ReadableStream with byte source: read()ing from a stream with queued chunks still transfers the buffer", + "ReadableStream with byte source: reading into an already-detached buffer rejects", + "ReadableStream with byte source: reading into a zero-length buffer rejects", + "ReadableStream with byte source: reading into a zero-length view on a non-zero-length buffer rejects" + ], + "construct-byob-request.any.js": false, + "general.any.js": [ + "getReader({mode: \"byob\"}) throws on non-bytes streams", + "ReadableStream with byte source can be constructed with no errors", + "getReader({mode}) must perform ToString()", + "ReadableStream with byte source: autoAllocateChunkSize cannot be 0", + "ReadableStreamBYOBReader can be constructed directly", + "ReadableStreamBYOBReader constructor requires a ReadableStream argument", + "ReadableStreamBYOBReader constructor requires an unlocked ReadableStream", + "ReadableStreamBYOBReader constructor requires a ReadableStream with type \"bytes\"", + "ReadableStream with byte source: getReader() with mode set to byob, then releaseLock()", + "ReadableStream with byte source: Test that closing a stream does not release a BYOB reader automatically", + "ReadableStream with byte source: Test that erroring a stream does not release a BYOB reader automatically", + "ReadableStream with byte source: autoAllocateChunkSize", + "ReadableStream with byte source: Mix of auto allocate and BYOB", + "ReadableStream with byte source: enqueue(), read(view) partially, then read()", + "ReadableStream with byte source: Respond to pull() by enqueue()", + "ReadableStream with byte source: Respond to pull() by enqueue() asynchronously", + "ReadableStream with byte source: Respond to multiple pull() by separate enqueue()", + "ReadableStream with byte source: read(view), then respond()", + "ReadableStream with byte source: read(view), then respond() with a transferred ArrayBuffer", + "ReadableStream with byte source: read(view), then respond() with too big value", + "ReadableStream with byte source: respond(3) to read(view) with 2 element Uint16Array enqueues the 1 byte remainder", + "ReadableStream with byte source: enqueue(), getReader(), then read(view)", + "ReadableStream with byte source: enqueue(), getReader(), then cancel() (mode = BYOB)", + "ReadableStream with byte source: getReader(), read(view), then cancel()", + "ReadableStream with byte source: cancel() with partially filled pending pull() request", + "ReadableStream with byte source: enqueue(), getReader(), then read(view) where view.buffer is not fully covered by view", + "ReadableStream with byte source: Multiple enqueue(), getReader(), then read(view)", + "ReadableStream with byte source: enqueue(), getReader(), then read(view) with a bigger view", + "ReadableStream with byte source: enqueue(), getReader(), then read(view) with smaller views", + "ReadableStream with byte source: enqueue() 1 byte, getReader(), then read(view) with Uint16Array", + "ReadableStream with byte source: enqueue() 3 byte, getReader(), then read(view) with 2-element Uint16Array", + "ReadableStream with byte source: read(view) with Uint16Array on close()-d stream with 1 byte enqueue()-d must fail", + "ReadableStream with byte source: A stream must be errored if close()-d before fulfilling read(view) with Uint16Array", + "ReadableStream with byte source: read(view), then respond() and close() in pull()", + "ReadableStream with byte source: read(view) with Uint32Array, then fill it by multiple respond() calls", + "ReadableStream with byte source: read() twice, then enqueue() twice", + "ReadableStream with byte source: Multiple read(view), close() and respond()", + "ReadableStream with byte source: Multiple read(view), big enqueue()", + "ReadableStream with byte source: Multiple read(view) and multiple enqueue()", + "ReadableStream with byte source: read(view) with passing undefined as view must fail", + "ReadableStream with byte source: read(view) with passing an empty object as view must fail", + "ReadableStream with byte source: Even read(view) with passing ArrayBufferView like object as view must fail", + "ReadableStream with byte source: read(view) on an errored stream", + "ReadableStream with byte source: read(view), then error()", + "ReadableStream with byte source: Throwing in pull function must error the stream", + "ReadableStream with byte source: Throwing in pull in response to read() must be ignored if the stream is errored in it", + "ReadableStream with byte source: Throwing in pull in response to read(view) function must error the stream", + "ReadableStream with byte source: Throwing in pull in response to read(view) must be ignored if the stream is errored in it", + "calling respond() twice on the same byobRequest should throw", + "calling respondWithNewView() twice on the same byobRequest should throw", + "calling respond(0) twice on the same byobRequest should throw even when closed", + "pull() resolving should not make releaseLock() possible", + "ReadableStream with byte source: default reader + autoAllocateChunkSize + byobRequest interaction" + ] + }, + "readable-streams": { + "async-iterator.any.js": [ + "Async iterator instances should have the correct list of properties", + "values() throws if there's already a lock", + "return() should unlock the stream synchronously when preventCancel = false", + "return() should unlock the stream synchronously when preventCancel = true", + "Async-iterating a pull source manually", + "Cancellation behavior when throwing inside loop body; preventCancel = false", + "Cancellation behavior when throwing inside loop body; preventCancel = true", + "Cancellation behavior when breaking inside loop body; preventCancel = false", + "Cancellation behavior when breaking inside loop body; preventCancel = true", + "Cancellation behavior when returning inside loop body; preventCancel = false", + "Cancellation behavior when returning inside loop body; preventCancel = true", + "Cancellation behavior when manually calling return(); preventCancel = false", + "Cancellation behavior when manually calling return(); preventCancel = true", + "next() rejects if the stream errors", + "return() does not rejects if the stream has not errored yet", + "return() rejects if the stream has errored", + "next() that succeeds; next() that reports an error; next()" + ], + "bad-strategies.any.js": true, + "bad-underlying-sources.any.js": true, + "cancel.any.js": false, + "constructor.any.js": false, + "count-queuing-strategy-integration.any.js": true, + "default-reader.any.js": true, + "floating-point-total-queue-size.any.js": true, + "garbage-collection.any.js": true, + "general.any.js": true, + "patched-global.any.js": true, + "reentrant-strategies.any.js": true, + "tee.any.js": true, + "templated.any.js": [ + "ReadableStream (empty) reader: canceling via the stream should fail" + ] + }, + "transform-streams": { + "backpressure.any.js": true, + "errors.any.js": true, + "flush.any.js": true, + "general.any.js": true, + "lipfuzz.any.js": true, + "patched-global.any.js": false, + "properties.any.js": true, + "reentrant-strategies.any.js": true, + "strategies.any.js": true, + "terminate.any.js": [ + "controller.terminate() inside flush() should not prevent writer.close() from succeeding" + ] + }, + "writable-streams": { + "aborting.any.js": false, + "bad-strategies.any.js": [ + "reject any non-function value for strategy.size", + "Writable stream: invalid size beats invalid highWaterMark" + ], + "bad-underlying-sinks.any.js": true, + "byte-length-queuing-strategy.any.js": true, + "close.any.js": false, + "constructor.any.js": [ + "underlyingSink argument should be converted after queuingStrategy argument", + "WritableStreamDefaultController constructor should throw", + "WritableStreamDefaultController constructor should throw when passed an initialised WritableStream", + "WritableStreamDefaultWriter should throw unless passed a WritableStream" + ], + "count-queuing-strategy.any.js": true, + "error.any.js": true, + "floating-point-total-queue-size.any.js": true, + "general.any.js": true, + "properties.any.js": true, + "reentrant-strategy.any.js": true, + "start.any.js": true, + "write.any.js": true + } + }, + "user-timing": { + "buffered-flag.any.js": false, + "case-sensitivity.any.js": false, + "clear_all_marks.any.js": true, + "clear_all_measures.any.js": true, + "clear_non_existent_mark.any.js": true, + "clear_non_existent_measure.any.js": true, + "clear_one_mark.any.js": true, + "clear_one_measure.any.js": true, + "entry_type.any.js": true, + "idlharness.any.js": false, + "mark-entry-constructor.any.js": true, + "mark-errors.any.js": true, + "mark-l3.any.js": false, + "mark-measure-return-objects.any.js": true, + "mark.any.js": true, + "measure-l3.any.js": true, + "measure-with-dict.any.js": [ + "measure entries' detail and start/end are customizable" + ], + "measure_syntax_err.any.js": true, + "structured-serialize-detail.any.js": true, + "supported-usertiming-types.any.js": false, + "user_timing_exists.any.js": true + }, + "wasm": { + "jsapi": { + "constructor": { + "compile.any.js": true, + "instantiate-bad-imports.any.js": false, + "instantiate.any.js": [ + "Synchronous options handling: Buffer argument" + ], + "multi-value.any.js": true, + "toStringTag.any.js": true, + "validate.any.js": true + }, + "global": { + "constructor.any.js": true, + "toString.any.js": true, + "type.tentative.any.js": false, + "value-get-set.any.js": true, + "valueOf.any.js": true + }, + "idlharness.any.js": false, + "instance": { + "constructor-bad-imports.any.js": false, + "constructor-caching.any.js": true, + "constructor.any.js": true, + "exports.any.js": [ + "Setting (sloppy mode)" + ], + "toString.any.js": true + }, + "interface.any.js": [ + "WebAssembly: property descriptor" + ], + "memory": { + "buffer.any.js": [ + "Setting (sloppy mode)" + ], + "constructor.any.js": true, + "grow.any.js": [ + "Growing shared memory does not detach old buffer" + ], + "toString.any.js": true, + "type.tentative.any.js": false + }, + "module": { + "constructor.any.js": true, + "customSections.any.js": true, + "exports.any.js": true, + "imports.any.js": true, + "toString.any.js": true + }, + "prototypes.any.js": false, + "table": { + "constructor.any.js": true, + "get-set.any.js": true, + "grow.any.js": true, + "length.any.js": [ + "Setting (sloppy mode)" + ], + "toString.any.js": true + } + }, + "serialization": { + "arraybuffer": { + "transfer.window.js": false + }, + "module": { + "nested-worker-success.any.js": false, + "serialization-via-idb.any.js": false, + "serialization-via-notifications-api.any.js": false + } + }, + "webapi": { + "abort.any.js": false, + "body.any.js": true, + "contenttype.any.js": [ + "Response with Content-Type \"application/wasm\": compileStreaming", + "Response with Content-Type \"application/wasm\": instantiateStreaming", + "Response with Content-Type \"APPLICATION/wasm\": compileStreaming", + "Response with Content-Type \"APPLICATION/wasm\": instantiateStreaming", + "Response with Content-Type \"APPLICATION/WASM\": compileStreaming", + "Response with Content-Type \"APPLICATION/WASM\": instantiateStreaming" + ], + "empty-body.any.js": false, + "historical.any.js": false, + "idlharness.any.js": false, + "instantiateStreaming-bad-imports.any.js": [ + "Importing a function with an incorrectly-typed value: undefined", + "Importing a function with an incorrectly-typed value: null", + "Importing a function with an incorrectly-typed value: true", + "Importing a function with an incorrectly-typed value: \"\"", + "Importing a function with an incorrectly-typed value: symbol \"Symbol()\"", + "Importing a function with an incorrectly-typed value: 1", + "Importing a function with an incorrectly-typed value: 0.1", + "Importing a function with an incorrectly-typed value: NaN", + "Importing a function with an incorrectly-typed value: object \"[object Object]\"", + "Importing an i32 global with an incorrectly-typed value: undefined", + "Importing an i32 global with an incorrectly-typed value: null", + "Importing an i32 global with an incorrectly-typed value: true", + "Importing an i32 global with an incorrectly-typed value: \"\"", + "Importing an i32 global with an incorrectly-typed value: symbol \"Symbol()\"", + "Importing an i32 global with an incorrectly-typed value: plain object", + "Importing an i32 global with an incorrectly-typed value: WebAssembly.Global", + "Importing an i32 global with an incorrectly-typed value: WebAssembly.Global.prototype", + "Importing an i32 global with an incorrectly-typed value: Object.create(WebAssembly.Global.prototype)", + "Importing an i32 global with an incorrectly-typed value: BigInt", + "Importing an i32 global with an incorrectly-typed value: WebAssembly.Global object (wrong value type)", + "Importing an i64 global with an incorrectly-typed value: undefined", + "Importing an i64 global with an incorrectly-typed value: null", + "Importing an i64 global with an incorrectly-typed value: true", + "Importing an i64 global with an incorrectly-typed value: \"\"", + "Importing an i64 global with an incorrectly-typed value: symbol \"Symbol()\"", + "Importing an i64 global with an incorrectly-typed value: plain object", + "Importing an i64 global with an incorrectly-typed value: WebAssembly.Global", + "Importing an i64 global with an incorrectly-typed value: WebAssembly.Global.prototype", + "Importing an i64 global with an incorrectly-typed value: Object.create(WebAssembly.Global.prototype)", + "Importing an i64 global with an incorrectly-typed value: Number", + "Importing an i64 global with an incorrectly-typed value: WebAssembly.Global object (wrong value type)", + "Importing an f32 global with an incorrectly-typed value: undefined", + "Importing an f32 global with an incorrectly-typed value: null", + "Importing an f32 global with an incorrectly-typed value: true", + "Importing an f32 global with an incorrectly-typed value: \"\"", + "Importing an f32 global with an incorrectly-typed value: symbol \"Symbol()\"", + "Importing an f32 global with an incorrectly-typed value: plain object", + "Importing an f32 global with an incorrectly-typed value: WebAssembly.Global", + "Importing an f32 global with an incorrectly-typed value: WebAssembly.Global.prototype", + "Importing an f32 global with an incorrectly-typed value: Object.create(WebAssembly.Global.prototype)", + "Importing an f32 global with an incorrectly-typed value: BigInt", + "Importing an f32 global with an incorrectly-typed value: WebAssembly.Global object (wrong value type)", + "Importing an f64 global with an incorrectly-typed value: undefined", + "Importing an f64 global with an incorrectly-typed value: null", + "Importing an f64 global with an incorrectly-typed value: true", + "Importing an f64 global with an incorrectly-typed value: \"\"", + "Importing an f64 global with an incorrectly-typed value: symbol \"Symbol()\"", + "Importing an f64 global with an incorrectly-typed value: plain object", + "Importing an f64 global with an incorrectly-typed value: WebAssembly.Global", + "Importing an f64 global with an incorrectly-typed value: WebAssembly.Global.prototype", + "Importing an f64 global with an incorrectly-typed value: Object.create(WebAssembly.Global.prototype)", + "Importing an f64 global with an incorrectly-typed value: BigInt", + "Importing an f64 global with an incorrectly-typed value: WebAssembly.Global object (wrong value type)", + "Importing an i32 mutable global with a primitive value", + "Importing an i32 mutable global with an immutable Global object", + "Importing an i64 mutable global with a primitive value", + "Importing an i64 mutable global with an immutable Global object", + "Importing an f32 mutable global with a primitive value", + "Importing an f32 mutable global with an immutable Global object", + "Importing an f64 mutable global with a primitive value", + "Importing an f64 mutable global with an immutable Global object", + "Importing memory with an incorrectly-typed value: undefined", + "Importing memory with an incorrectly-typed value: null", + "Importing memory with an incorrectly-typed value: true", + "Importing memory with an incorrectly-typed value: \"\"", + "Importing memory with an incorrectly-typed value: symbol \"Symbol()\"", + "Importing memory with an incorrectly-typed value: 1", + "Importing memory with an incorrectly-typed value: 0.1", + "Importing memory with an incorrectly-typed value: NaN", + "Importing memory with an incorrectly-typed value: plain object", + "Importing memory with an incorrectly-typed value: WebAssembly.Memory", + "Importing memory with an incorrectly-typed value: WebAssembly.Memory.prototype", + "Importing memory with an incorrectly-typed value: Object.create(WebAssembly.Memory.prototype)", + "Importing memory with an incorrectly-typed value: WebAssembly.Memory object (too large)", + "Importing table with an incorrectly-typed value: undefined", + "Importing table with an incorrectly-typed value: null", + "Importing table with an incorrectly-typed value: true", + "Importing table with an incorrectly-typed value: \"\"", + "Importing table with an incorrectly-typed value: symbol \"Symbol()\"", + "Importing table with an incorrectly-typed value: 1", + "Importing table with an incorrectly-typed value: 0.1", + "Importing table with an incorrectly-typed value: NaN", + "Importing table with an incorrectly-typed value: plain object", + "Importing table with an incorrectly-typed value: WebAssembly.Table", + "Importing table with an incorrectly-typed value: WebAssembly.Table.prototype", + "Importing table with an incorrectly-typed value: Object.create(WebAssembly.Table.prototype)", + "Importing table with an incorrectly-typed value: WebAssembly.Table object (too large)" + ], + "instantiateStreaming.any.js": false, + "invalid-args.any.js": true, + "invalid-code.any.js": false, + "modified-contenttype.any.js": [ + "compileStreaming with Content-Type set late", + "instantiateStreaming with Content-Type set late" + ], + "origin.sub.any.js": true, + "rejected-arg.any.js": true, + "status.any.js": true + } + }, + "WebIDL": { + "ecmascript-binding": { + "es-exceptions": { + "DOMException-constants.any.js": true, + "DOMException-constructor-and-prototype.any.js": true, + "DOMException-constructor-behavior.any.js": true, + "DOMException-custom-bindings.any.js": [ + "does not inherit from Error: class-side" + ] + } + } + } +}
\ No newline at end of file diff --git a/tools/wpt/runner.ts b/tools/wpt/runner.ts new file mode 100644 index 000000000..28b2db0ee --- /dev/null +++ b/tools/wpt/runner.ts @@ -0,0 +1,133 @@ +import { delay, join, readLines, ROOT_PATH } from "../util.js"; +import { assert, ManifestTestOptions, release, runPy } from "./utils.ts"; +import { DOMParser } from "https://deno.land/x/deno_dom@v0.1.3-alpha2/deno-dom-wasm.ts"; + +export async function runWithTestUtil<T>( + verbose: boolean, + f: () => Promise<T>, +): Promise<T> { + const proc = runPy(["wpt", "serve"], { + stdout: verbose ? "inherit" : "piped", + stderr: verbose ? "inherit" : "piped", + }); + + const start = performance.now(); + while (true) { + await delay(1000); + try { + const req = await fetch("http://localhost:8000/"); + await req.body?.cancel(); + if (req.status == 200) { + break; + } + } catch (err) { + // do nothing if this fails + } + const passedTime = performance.now() - start; + if (passedTime > 15000) { + throw new Error("Timed out while trying to start wpt test util."); + } + } + + if (verbose) console.log(`Started wpt test util.`); + + try { + return await f(); + } finally { + if (verbose) console.log("Killing wpt test util."); + proc.kill(2); + await proc.status(); + proc.close(); + } +} + +export interface TestResult { + cases: TestCaseResult[]; + status: number; + stderr: string; +} + +export interface TestCaseResult { + name: string; + passed: boolean; + status: number; + message: string | null; + stack: string | null; +} + +export async function runSingleTest( + url: URL, + options: ManifestTestOptions, + reporter: (result: TestCaseResult) => void, +): Promise<TestResult> { + const bundle = await generateBundle(url); + const tempFile = await Deno.makeTempFile({ + prefix: "wpt-bundle-", + suffix: ".js", + }); + await Deno.writeTextFile(tempFile, bundle); + + const proc = Deno.run({ + cmd: [ + join(ROOT_PATH, `./target/${release ? "release" : "debug"}/deno`), + "run", + "-A", + "--location", + url.toString(), + tempFile, + "[]", + ], + env: { + NO_COLOR: "1", + }, + stdout: "null", + stderr: "piped", + }); + + const cases = []; + let stderr = ""; + + const lines = readLines(proc.stderr); + for await (const line of lines) { + if (line.startsWith("{")) { + const data = JSON.parse(line); + const result = { ...data, passed: data.status == 0 }; + cases.push(result); + reporter(result); + } else { + stderr += line + "\n"; + } + } + + const { code } = await proc.status(); + return { + status: code, + cases, + stderr, + }; +} + +async function generateBundle(location: URL): Promise<string> { + const res = await fetch(location); + const body = await res.text(); + const doc = new DOMParser().parseFromString(body, "text/html"); + assert(doc, "document should have been parsed"); + const scripts = doc.getElementsByTagName("script"); + const scriptContents = []; + for (const script of scripts) { + const src = script.getAttribute("src"); + if (src === "/resources/testharnessreport.js") { + scriptContents.push( + await Deno.readTextFile( + join(ROOT_PATH, "./tools/wpt/testharnessreport.js"), + ), + ); + } else if (src) { + const res = await fetch(new URL(src, location)); + scriptContents.push(await res.text()); + } else { + scriptContents.push(script.textContent); + } + } + return scriptContents.join("\n"); +} diff --git a/tools/wpt/testharnessreport.js b/tools/wpt/testharnessreport.js new file mode 100644 index 000000000..13c8ef683 --- /dev/null +++ b/tools/wpt/testharnessreport.js @@ -0,0 +1,12 @@ +window.add_result_callback(({ message, name, stack, status }) => { + Deno.writeAllSync( + Deno.stderr, + new TextEncoder().encode( + `${JSON.stringify({ name, status, message, stack })}\n`, + ), + ); +}); + +window.add_completion_callback((tests, harnessStatus) => { + Deno.exit(0); +}); diff --git a/tools/wpt/utils.ts b/tools/wpt/utils.ts new file mode 100644 index 000000000..3efd252b4 --- /dev/null +++ b/tools/wpt/utils.ts @@ -0,0 +1,168 @@ +/// FLAGS + +import { parse } from "https://deno.land/std@0.84.0/flags/mod.ts"; +import { join, ROOT_PATH } from "../util.js"; + +export const { + json, + quiet, + release, + ["--"]: rest, + ["auto-config"]: autoConfig, +} = parse(Deno.args, { + "--": true, + boolean: ["quiet", "release", "no-interactive"], + string: ["json"], +}); + +/// PAGE ROOT + +/// WPT TEST MANIFEST + +export interface Manifest { + items: { + testharness: ManifestFolder; + }; +} +export interface ManifestFolder { + [key: string]: ManifestFolder | ManifestTest; +} +export type ManifestTest = [ + hash: string, + ...variations: ManifestTestVariation[], +]; +export type ManifestTestVariation = [ + path: string, + options: ManifestTestOptions, +]; +export interface ManifestTestOptions { + name?: string; +} + +const MANIFEST_PATH = join(ROOT_PATH, "./tools/wpt/manifest.json"); + +export async function updateManifest() { + const proc = runPy( + ["wpt", "manifest", "--tests-root", ".", "-p", MANIFEST_PATH], + {}, + ); + const status = await proc.status(); + assert(status.success, "updating wpt manifest should succeed"); +} + +export function getManifest(): Manifest { + const manifestText = Deno.readTextFileSync(MANIFEST_PATH); + return JSON.parse(manifestText); +} + +/// WPT TEST EXPECTATIONS + +const EXPECTATION_PATH = join(ROOT_PATH, "./tools/wpt/expectation.json"); + +export interface Expectation { + [key: string]: Expectation | boolean | string[]; +} + +export function getExpectation(): Expectation { + const expectationText = Deno.readTextFileSync(EXPECTATION_PATH); + return JSON.parse(expectationText); +} + +export function saveExpectation(expectation: Expectation) { + Deno.writeTextFileSync( + EXPECTATION_PATH, + JSON.stringify(expectation, undefined, " "), + ); +} + +export function generateTestExpectations(filter: string[]) { + const manifest = getManifest(); + + function walk(folder: ManifestFolder, prefix: string): Expectation { + const expectation: Expectation = {}; + for (const key in folder) { + const path = `${prefix}/${key}`; + const entry = folder[key]; + if (Array.isArray(entry)) { + if (!filter.find((filter) => path.startsWith(filter))) continue; + if (key.endsWith(".js")) { + expectation[key] = false; + } + } else { + if (!filter.find((filter) => `${path}/`.startsWith(filter))) continue; + expectation[key] = walk(entry, path); + } + } + for (const key in expectation) { + const entry = expectation[key]; + if (typeof entry === "object") { + if (Object.keys(expectation[key]).length === 0) { + delete expectation[key]; + } + } + } + return expectation; + } + + return walk(manifest.items.testharness, ""); +} + +export function getExpectFailForCase( + expectation: boolean | string[], + caseName: string, +): boolean { + if (typeof expectation == "boolean") { + return !expectation; + } + return expectation.includes(caseName); +} + +/// UTILS + +class AssertionError extends Error { + name = "AssertionError"; + constructor(message: string) { + super(message); + } +} + +export function assert(condition: unknown, message: string): asserts condition { + if (!condition) { + throw new AssertionError(message); + } +} + +export function runPy( + args: string[], + options: Omit<Omit<Deno.RunOptions, "cmd">, "cwd">, +): Deno.Process { + const cmd = Deno.build.os == "windows" ? "python.exe" : "python3"; + return Deno.run({ + cmd: [cmd, ...args], + cwd: join(ROOT_PATH, "./test_util/wpt/"), + ...options, + }); +} + +export async function checkPy3Available() { + const proc = runPy(["--version"], { stdout: "piped" }); + const status = await proc.status(); + assert(status.success, "failed to run python --version"); + const output = new TextDecoder().decode(await proc.output()); + assert( + output.includes("Python 3."), + `The ${ + Deno.build.os == "windows" ? "python.exe" : "python3" + } in your path is not is not Python 3.`, + ); +} + +export async function cargoBuild() { + const proc = Deno.run({ + cmd: ["cargo", "build", ...(release ? ["--release"] : [])], + cwd: ROOT_PATH, + }); + const status = await proc.status(); + proc.close(); + assert(status.success, "cargo build failed"); +} |