Upload Kmake

This commit is contained in:
Gorochu
2026-05-26 23:36:42 -07:00
parent ba051b2f74
commit 555ec72358
41615 changed files with 13344630 additions and 1 deletions

View File

@ -0,0 +1,55 @@
// Create a credentialless iframe. The new document will execute any scripts
// sent toward the token it returns.
const newIframeCredentialless = (child_origin, opt_headers) => {
opt_headers ||= "";
const sub_document_token = token();
let iframe = document.createElement('iframe');
iframe.src = child_origin + executor_path + opt_headers +
`&uuid=${sub_document_token}`;
iframe.credentialless = true;
document.body.appendChild(iframe);
return sub_document_token;
};
// Create a normal iframe. The new document will execute any scripts sent
// toward the token it returns.
const newIframe = (child_origin) => {
const sub_document_token = token();
let iframe = document.createElement('iframe');
iframe.src = child_origin + executor_path + `&uuid=${sub_document_token}`;
iframe.credentialless = false
document.body.appendChild(iframe);
return sub_document_token;
};
// Create a popup. The new document will execute any scripts sent toward the
// token it returns.
const newPopup = (test, origin) => {
const popup_token = token();
const popup = window.open(origin + executor_path + `&uuid=${popup_token}`);
test.add_cleanup(() => popup.close());
return popup_token;
}
// Create a fenced frame. The new document will execute any scripts sent
// toward the token it returns.
const newFencedFrame = async (child_origin) => {
const support_loading_mode_fenced_frame =
"|header(Supports-Loading-Mode,fenced-frame)";
const sub_document_token = token();
const url = child_origin + executor_path +
support_loading_mode_fenced_frame +
`&uuid=${sub_document_token}`;
const urn = await generateURNFromFledge(url, []);
attachFencedFrame(urn);
return sub_document_token;
};
const importScript = (url) => {
const script = document.createElement("script");
script.type = "text/javascript";
script.src = url;
const loaded = new Promise(resolve => script.onload = resolve);
document.body.appendChild(script);
return loaded;
}

View File

@ -0,0 +1,134 @@
const executor_path = '/common/dispatcher/executor.html?pipe=';
const executor_worker_path = '/common/dispatcher/executor-worker.js?pipe=';
const executor_service_worker_path = '/common/dispatcher/executor-service-worker.js?pipe=';
// COEP
const coep_none =
'|header(Cross-Origin-Embedder-Policy,none)';
const coep_credentialless =
'|header(Cross-Origin-Embedder-Policy,credentialless)';
const coep_require_corp =
'|header(Cross-Origin-Embedder-Policy,require-corp)';
// COEP-Report-Only
const coep_report_only_credentialless =
'|header(Cross-Origin-Embedder-Policy-Report-Only,credentialless)';
// COOP
const coop_same_origin =
'|header(Cross-Origin-Opener-Policy,same-origin)';
// CORP
const corp_cross_origin =
'|header(Cross-Origin-Resource-Policy,cross-origin)';
const cookie_same_site_none = ';SameSite=None;Secure';
// Test using the modern async/await primitives are easier to read/write.
// However they run sequentially, contrary to async_test. This is the parallel
// version, to avoid timing out.
let promise_test_parallel = (promise, description) => {
async_test(test => {
promise(test)
.then(() => test.done())
.catch(test.step_func(error => { throw error; }));
}, description);
};
// Add a cookie |cookie_key|=|cookie_value| on an |origin|.
// Note: cookies visibility depends on the path of the document. Those are set
// from a document from: /html/cross-origin-embedder-policy/credentialless/. So
// the cookie is visible to every path underneath.
const setCookie = async (origin, cookie_key, cookie_value) => {
const popup_token = token();
const popup_url = origin + executor_path + `&uuid=${popup_token}`;
const popup = window.open(popup_url);
const reply_token = token();
send(popup_token, `
document.cookie = "${cookie_key}=${cookie_value}";
send("${reply_token}", "done");
`);
assert_equals(await receive(reply_token), "done");
popup.close();
}
let parseCookies = function(headers_json) {
if (!headers_json["cookie"])
return {};
return headers_json["cookie"]
.split(';')
.map(v => v.split('='))
.reduce((acc, v) => {
acc[v[0].trim()] = v[1].trim();
return acc;
}, {});
}
// Open a new window with a given |origin|, loaded with COEP:credentialless. The
// new document will execute any scripts sent toward the token it returns.
const newCredentiallessWindow = (origin) => {
const main_document_token = token();
const url = origin + executor_path + coep_credentialless +
`&uuid=${main_document_token}`;
const context = window.open(url);
add_completion_callback(() => w.close());
return main_document_token;
};
// Create a new iframe, loaded with COEP:credentialless.
// The new document will execute any scripts sent toward the token it returns.
const newCredentiallessIframe = (parent_token, child_origin) => {
const sub_document_token = token();
const iframe_url = child_origin + executor_path + coep_credentialless +
`&uuid=${sub_document_token}`;
send(parent_token, `
let iframe = document.createElement("iframe");
iframe.src = "${iframe_url}";
document.body.appendChild(iframe);
`)
return sub_document_token;
};
// A common interface for building the 4 type of execution contexts:
// It outputs: [
// - The token to communicate with the environment.
// - A promise resolved when the environment encounters an error.
// ]
const environments = {
document: headers => {
const tok = token();
const url = window.origin + executor_path + headers + `&uuid=${tok}`;
const context = window.open(url);
add_completion_callback(() => context.close());
return [tok, new Promise(resolve => {})];
},
dedicated_worker: headers => {
const tok = token();
const url = window.origin + executor_worker_path + headers + `&uuid=${tok}`;
const context = new Worker(url);
return [tok, new Promise(resolve => context.onerror = resolve)];
},
shared_worker: headers => {
const tok = token();
const url = window.origin + executor_worker_path + headers + `&uuid=${tok}`;
const context = new SharedWorker(url);
return [tok, new Promise(resolve => context.onerror = resolve)];
},
service_worker: headers => {
const tok = token();
const url = window.origin + executor_worker_path + headers + `&uuid=${tok}`;
const scope = url; // Generate a one-time scope for service worker.
const error = new Promise(resolve => {
navigator.serviceWorker.register(url, {scope: scope})
.then(registration => {
add_completion_callback(() => registration.unregister());
}, /* catch */ resolve);
});
return [tok, error];
},
};

View File

@ -0,0 +1,163 @@
/**
* btoa() as defined by the HTML5 spec, which mostly just references RFC4648.
*/
function mybtoa(s) {
// String conversion as required by WebIDL.
s = String(s);
// "The btoa() method must throw an INVALID_CHARACTER_ERR exception if the
// method's first argument contains any character whose code point is
// greater than U+00FF."
for (var i = 0; i < s.length; i++) {
if (s.charCodeAt(i) > 255) {
return "INVALID_CHARACTER_ERR";
}
}
var out = "";
for (var i = 0; i < s.length; i += 3) {
var groupsOfSix = [undefined, undefined, undefined, undefined];
groupsOfSix[0] = s.charCodeAt(i) >> 2;
groupsOfSix[1] = (s.charCodeAt(i) & 0x03) << 4;
if (s.length > i + 1) {
groupsOfSix[1] |= s.charCodeAt(i + 1) >> 4;
groupsOfSix[2] = (s.charCodeAt(i + 1) & 0x0f) << 2;
}
if (s.length > i + 2) {
groupsOfSix[2] |= s.charCodeAt(i + 2) >> 6;
groupsOfSix[3] = s.charCodeAt(i + 2) & 0x3f;
}
for (var j = 0; j < groupsOfSix.length; j++) {
if (typeof groupsOfSix[j] == "undefined") {
out += "=";
} else {
out += btoaLookup(groupsOfSix[j]);
}
}
}
return out;
}
/**
* Lookup table for mybtoa(), which converts a six-bit number into the
* corresponding ASCII character.
*/
function btoaLookup(idx) {
if (idx < 26) {
return String.fromCharCode(idx + 'A'.charCodeAt(0));
}
if (idx < 52) {
return String.fromCharCode(idx - 26 + 'a'.charCodeAt(0));
}
if (idx < 62) {
return String.fromCharCode(idx - 52 + '0'.charCodeAt(0));
}
if (idx == 62) {
return '+';
}
if (idx == 63) {
return '/';
}
// Throw INVALID_CHARACTER_ERR exception here -- won't be hit in the tests.
}
function btoaException(input) {
input = String(input);
for (var i = 0; i < input.length; i++) {
if (input.charCodeAt(i) > 255) {
return true;
}
}
return false;
}
function testBtoa(input) {
// "The btoa() method must throw an INVALID_CHARACTER_ERR exception if the
// method's first argument contains any character whose code point is
// greater than U+00FF."
var normalizedInput = String(input);
for (var i = 0; i < normalizedInput.length; i++) {
if (normalizedInput.charCodeAt(i) > 255) {
assert_throws_dom("InvalidCharacterError", function() { btoa(input); },
"Code unit " + i + " has value " + normalizedInput.charCodeAt(i) + ", which is greater than 255");
return;
}
}
assert_equals(btoa(input), mybtoa(input));
assert_equals(atob(btoa(input)), String(input), "atob(btoa(input)) must be the same as String(input)");
}
var tests = ["עברית", "", "ab", "abc", "abcd", "abcde",
// This one is thrown in because IE9 seems to fail atob(btoa()) on it. Or
// possibly to fail btoa(). I actually can't tell what's happening here,
// but it doesn't hurt.
"\xff\xff\xc0",
// Is your DOM implementation binary-safe?
"\0a", "a\0b",
// WebIDL tests.
undefined, null, 7, 12, 1.5, true, false, NaN, +Infinity, -Infinity, 0, -0,
{toString: function() { return "foo" }},
];
for (var i = 0; i < 258; i++) {
tests.push(String.fromCharCode(i));
}
tests.push(String.fromCharCode(10000));
tests.push(String.fromCharCode(65534));
tests.push(String.fromCharCode(65535));
// This is supposed to be U+10000.
tests.push(String.fromCharCode(0xd800, 0xdc00));
tests = tests.map(
function(elem) {
var expected = mybtoa(elem);
if (expected === "INVALID_CHARACTER_ERR") {
return ["btoa(" + format_value(elem) + ") must raise INVALID_CHARACTER_ERR", elem];
}
return ["btoa(" + format_value(elem) + ") == " + format_value(mybtoa(elem)), elem];
}
);
var everything = "";
for (var i = 0; i < 256; i++) {
everything += String.fromCharCode(i);
}
tests.push(["btoa(first 256 code points concatenated)", everything]);
generate_tests(testBtoa, tests);
promise_test(() => fetch("../../../fetch/data-urls/resources/base64.json").then(res => res.json()).then(runAtobTests), "atob() setup.");
const idlTests = [
[undefined, null],
[null, [158, 233, 101]],
[7, null],
[12, [215]],
[1.5, null],
[true, [182, 187]],
[false, null],
[NaN, [53, 163]],
[+Infinity, [34, 119, 226, 158, 43, 114]],
[-Infinity, null],
[0, null],
[-0, null],
[{toString: function() { return "foo" }}, [126, 138]],
[{toString: function() { return "abcd" }}, [105, 183, 29]]
];
function runAtobTests(tests) {
const allTests = tests.concat(idlTests);
for(let i = 0; i < allTests.length; i++) {
const input = allTests[i][0],
output = allTests[i][1];
test(() => {
if(output === null) {
assert_throws_dom("InvalidCharacterError", () => globalThis.atob(input));
} else {
const result = globalThis.atob(input);
for(let ii = 0; ii < output.length; ii++) {
assert_equals(result.charCodeAt(ii), output[ii]);
}
}
}, "atob(" + format_value(input) + ")");
}
}

View File

@ -0,0 +1,15 @@
// META: global=window,worker
"use strict";
setup({
allow_uncaught_exception: true
});
async_test(t => {
const error = new Error("boo");
self.addEventListener("error", t.step_func_done(ev => {
assert_equals(ev.error, error);
}));
queueMicrotask(() => { throw error; });
}, "It rethrows exceptions");

View File

@ -0,0 +1,39 @@
// META: global=window,worker
"use strict";
test(() => {
assert_equals(typeof queueMicrotask, "function");
}, "It exists and is a function");
test(() => {
assert_throws_js(TypeError, () => queueMicrotask(), "no argument");
assert_throws_js(TypeError, () => queueMicrotask(undefined), "undefined");
assert_throws_js(TypeError, () => queueMicrotask(null), "null");
assert_throws_js(TypeError, () => queueMicrotask(0), "0");
assert_throws_js(TypeError, () => queueMicrotask({ handleEvent() { } }), "an event handler object");
assert_throws_js(TypeError, () => queueMicrotask("window.x = 5;"), "a string");
}, "It throws when given non-functions");
async_test(t => {
let called = false;
queueMicrotask(t.step_func_done(() => {
called = true;
}));
assert_false(called);
}, "It calls the callback asynchronously");
async_test(t => {
queueMicrotask(t.step_func_done(function () { // note: intentionally not an arrow function
assert_array_equals(arguments, []);
}), "x", "y");
}, "It does not pass any arguments");
async_test(t => {
const happenings = [];
Promise.resolve().then(() => happenings.push("a"));
queueMicrotask(() => happenings.push("b"));
Promise.reject().catch(() => happenings.push("c"));
queueMicrotask(t.step_func_done(() => {
assert_array_equals(happenings, ["a", "b", "c"]);
}));
}, "It interleaves with promises as expected");

View File

@ -0,0 +1,45 @@
"use strict";
// This does not work as you expect because mutation observer compound microtasks are confusing.
// Basically you can only use it once per test.
function queueMicrotaskViaMO(cb) {
const observer = new MutationObserver(cb);
const node = document.createTextNode("");
observer.observe(node, { characterData: true });
node.data = "foo";
}
// Need to use promise_test to get sequential ordering; otherwise the global mutation observer
// compound microtask business screws us over.
promise_test(() => {
return new Promise(resolve => {
const happenings = [];
queueMicrotaskViaMO(() => happenings.push("x"));
queueMicrotask(() => happenings.push("a"));
queueMicrotask(() => {
assert_array_equals(happenings, ["x", "a"]);
resolve();
});
});
}, "It interleaves with MutationObservers as expected");
promise_test(() => {
return new Promise(resolve => {
const happenings = [];
queueMicrotask(() => happenings.push("a"));
Promise.reject().catch(() => happenings.push("x"));
queueMicrotaskViaMO(() => happenings.push(1));
Promise.resolve().then(() => happenings.push("y"));
queueMicrotask(() => happenings.push("b"));
queueMicrotask(() => happenings.push("c"));
queueMicrotask(() => {
assert_array_equals(happenings, ["a", "x", 1, "y", "b", "c"]);
resolve();
});
});
}, "It interleaves with MutationObservers and promises together as expected");

View File

@ -0,0 +1,44 @@
/**
* Runs a collection of tests that determine if an API implements structured clone
* correctly.
*
* The `runner` parameter has the following properties:
* - `setup()`: An optional function run once before testing starts
* - `teardown()`: An option function run once after all tests are done
* - `preTest()`: An optional, async function run before a test
* - `postTest()`: An optional, async function run after a test is done
* - `structuredClone(obj, transferList)`: Required function that somehow
* structurally clones an object.
* - `hasDocument`: When true, disables tests that require a document. True by default.
*/
function runStructuredCloneBatteryOfTests(runner) {
const defaultRunner = {
setup() {},
preTest() {},
postTest() {},
teardown() {},
hasDocument: true
};
runner = Object.assign({}, defaultRunner, runner);
let setupPromise = runner.setup();
const allTests = structuredCloneBatteryOfTests.map(test => {
if (!runner.hasDocument && test.requiresDocument) {
return;
}
return new Promise(resolve => {
promise_test(async _ => {
test = await test;
await setupPromise;
await runner.preTest(test);
await test.f(runner)
await runner.postTest(test);
resolve();
}, test.description);
}).catch(_ => {});
});
Promise.all(allTests).then(_ => runner.teardown());
}

View File

@ -0,0 +1,22 @@
structuredCloneBatteryOfTests.push({
description: 'ArrayBuffer',
async f(runner) {
const buffer = new Uint8Array([1]).buffer;
const copy = await runner.structuredClone(buffer, [buffer]);
assert_equals(buffer.byteLength, 0);
assert_equals(copy.byteLength, 1);
}
});
structuredCloneBatteryOfTests.push({
description: 'MessagePort',
async f(runner) {
const {port1, port2} = new MessageChannel();
const copy = await runner.structuredClone(port2, [port2]);
const msg = new Promise(resolve => port1.onmessage = resolve);
copy.postMessage('ohai');
assert_equals((await msg).data, 'ohai');
}
});
// TODO: ImageBitmap

View File

@ -0,0 +1,618 @@
/* This file is mostly a remix of @zcorpan’s web worker test suite */
structuredCloneBatteryOfTests = [];
function check(description, input, callback, requiresDocument = false) {
testObjMock = {
done() {},
step_func(f) {return _ => f()},
};
structuredCloneBatteryOfTests.push({
description,
async f(runner) {
let newInput = input;
if (typeof input === 'function') {
newInput = input();
}
const copy = await runner.structuredClone(newInput);
await callback(copy, newInput, testObjMock);
},
requiresDocument
});
}
function compare_primitive(actual, input, test_obj) {
assert_equals(actual, input);
if (test_obj)
test_obj.done();
}
function compare_Array(callback, callback_is_async) {
return function(actual, input, test_obj) {
if (typeof actual === 'string')
assert_unreached(actual);
assert_true(actual instanceof Array, 'instanceof Array');
assert_not_equals(actual, input);
assert_equals(actual.length, input.length, 'length');
callback(actual, input);
if (test_obj && !callback_is_async)
test_obj.done();
}
}
function compare_Object(callback, callback_is_async) {
return function(actual, input, test_obj) {
if (typeof actual === 'string')
assert_unreached(actual);
assert_true(actual instanceof Object, 'instanceof Object');
assert_false(actual instanceof Array, 'instanceof Array');
assert_not_equals(actual, input);
callback(actual, input);
if (test_obj && !callback_is_async)
test_obj.done();
}
}
function enumerate_props(compare_func, test_obj) {
return function(actual, input) {
for (const x in input) {
compare_func(actual[x], input[x], test_obj);
}
};
}
check('primitive undefined', undefined, compare_primitive);
check('primitive null', null, compare_primitive);
check('primitive true', true, compare_primitive);
check('primitive false', false, compare_primitive);
check('primitive string, empty string', '', compare_primitive);
check('primitive string, lone high surrogate', '\uD800', compare_primitive);
check('primitive string, lone low surrogate', '\uDC00', compare_primitive);
check('primitive string, NUL', '\u0000', compare_primitive);
check('primitive string, astral character', '\uDBFF\uDFFD', compare_primitive);
check('primitive number, 0.2', 0.2, compare_primitive);
check('primitive number, 0', 0, compare_primitive);
check('primitive number, -0', -0, compare_primitive);
check('primitive number, NaN', NaN, compare_primitive);
check('primitive number, Infinity', Infinity, compare_primitive);
check('primitive number, -Infinity', -Infinity, compare_primitive);
check('primitive number, 9007199254740992', 9007199254740992, compare_primitive);
check('primitive number, -9007199254740992', -9007199254740992, compare_primitive);
check('primitive number, 9007199254740994', 9007199254740994, compare_primitive);
check('primitive number, -9007199254740994', -9007199254740994, compare_primitive);
check('primitive BigInt, 0n', 0n, compare_primitive);
check('primitive BigInt, -0n', -0n, compare_primitive);
check('primitive BigInt, -9007199254740994000n', -9007199254740994000n, compare_primitive);
check('primitive BigInt, -9007199254740994000900719925474099400090071992547409940009007199254740994000n', -9007199254740994000900719925474099400090071992547409940009007199254740994000n, compare_primitive);
check('Array primitives', [undefined,
null,
true,
false,
'',
'\uD800',
'\uDC00',
'\u0000',
'\uDBFF\uDFFD',
0.2,
0,
-0,
NaN,
Infinity,
-Infinity,
9007199254740992,
-9007199254740992,
9007199254740994,
-9007199254740994,
-12n,
-0n,
0n], compare_Array(enumerate_props(compare_primitive)));
check('Object primitives', {'undefined':undefined,
'null':null,
'true':true,
'false':false,
'empty':'',
'high surrogate':'\uD800',
'low surrogate':'\uDC00',
'nul':'\u0000',
'astral':'\uDBFF\uDFFD',
'0.2':0.2,
'0':0,
'-0':-0,
'NaN':NaN,
'Infinity':Infinity,
'-Infinity':-Infinity,
'9007199254740992':9007199254740992,
'-9007199254740992':-9007199254740992,
'9007199254740994':9007199254740994,
'-9007199254740994':-9007199254740994}, compare_Object(enumerate_props(compare_primitive)));
function compare_Boolean(actual, input, test_obj) {
if (typeof actual === 'string')
assert_unreached(actual);
assert_true(actual instanceof Boolean, 'instanceof Boolean');
assert_equals(String(actual), String(input), 'converted to primitive');
assert_not_equals(actual, input);
if (test_obj)
test_obj.done();
}
check('Boolean true', new Boolean(true), compare_Boolean);
check('Boolean false', new Boolean(false), compare_Boolean);
check('Array Boolean objects', [new Boolean(true), new Boolean(false)], compare_Array(enumerate_props(compare_Boolean)));
check('Object Boolean objects', {'true':new Boolean(true), 'false':new Boolean(false)}, compare_Object(enumerate_props(compare_Boolean)));
function compare_obj(what) {
const Type = self[what];
return function(actual, input, test_obj) {
if (typeof actual === 'string')
assert_unreached(actual);
assert_true(actual instanceof Type, 'instanceof '+what);
assert_equals(Type(actual), Type(input), 'converted to primitive');
assert_not_equals(actual, input);
if (test_obj)
test_obj.done();
};
}
check('String empty string', new String(''), compare_obj('String'));
check('String lone high surrogate', new String('\uD800'), compare_obj('String'));
check('String lone low surrogate', new String('\uDC00'), compare_obj('String'));
check('String NUL', new String('\u0000'), compare_obj('String'));
check('String astral character', new String('\uDBFF\uDFFD'), compare_obj('String'));
check('Array String objects', [new String(''),
new String('\uD800'),
new String('\uDC00'),
new String('\u0000'),
new String('\uDBFF\uDFFD')], compare_Array(enumerate_props(compare_obj('String'))));
check('Object String objects', {'empty':new String(''),
'high surrogate':new String('\uD800'),
'low surrogate':new String('\uDC00'),
'nul':new String('\u0000'),
'astral':new String('\uDBFF\uDFFD')}, compare_Object(enumerate_props(compare_obj('String'))));
check('Number 0.2', new Number(0.2), compare_obj('Number'));
check('Number 0', new Number(0), compare_obj('Number'));
check('Number -0', new Number(-0), compare_obj('Number'));
check('Number NaN', new Number(NaN), compare_obj('Number'));
check('Number Infinity', new Number(Infinity), compare_obj('Number'));
check('Number -Infinity', new Number(-Infinity), compare_obj('Number'));
check('Number 9007199254740992', new Number(9007199254740992), compare_obj('Number'));
check('Number -9007199254740992', new Number(-9007199254740992), compare_obj('Number'));
check('Number 9007199254740994', new Number(9007199254740994), compare_obj('Number'));
check('Number -9007199254740994', new Number(-9007199254740994), compare_obj('Number'));
// BigInt does not have a non-throwing constructor
check('BigInt -9007199254740994n', Object(-9007199254740994n), compare_obj('BigInt'));
check('Array Number objects', [new Number(0.2),
new Number(0),
new Number(-0),
new Number(NaN),
new Number(Infinity),
new Number(-Infinity),
new Number(9007199254740992),
new Number(-9007199254740992),
new Number(9007199254740994),
new Number(-9007199254740994)], compare_Array(enumerate_props(compare_obj('Number'))));
check('Object Number objects', {'0.2':new Number(0.2),
'0':new Number(0),
'-0':new Number(-0),
'NaN':new Number(NaN),
'Infinity':new Number(Infinity),
'-Infinity':new Number(-Infinity),
'9007199254740992':new Number(9007199254740992),
'-9007199254740992':new Number(-9007199254740992),
'9007199254740994':new Number(9007199254740994),
'-9007199254740994':new Number(-9007199254740994)}, compare_Object(enumerate_props(compare_obj('Number'))));
function compare_Date(actual, input, test_obj) {
if (typeof actual === 'string')
assert_unreached(actual);
assert_true(actual instanceof Date, 'instanceof Date');
assert_equals(Number(actual), Number(input), 'converted to primitive');
assert_not_equals(actual, input);
if (test_obj)
test_obj.done();
}
check('Date 0', new Date(0), compare_Date);
check('Date -0', new Date(-0), compare_Date);
check('Date -8.64e15', new Date(-8.64e15), compare_Date);
check('Date 8.64e15', new Date(8.64e15), compare_Date);
check('Array Date objects', [new Date(0),
new Date(-0),
new Date(-8.64e15),
new Date(8.64e15)], compare_Array(enumerate_props(compare_Date)));
check('Object Date objects', {'0':new Date(0),
'-0':new Date(-0),
'-8.64e15':new Date(-8.64e15),
'8.64e15':new Date(8.64e15)}, compare_Object(enumerate_props(compare_Date)));
function compare_RegExp(expected_source) {
// XXX ES6 spec doesn't define exact serialization for `source` (it allows several ways to escape)
return function(actual, input, test_obj) {
if (typeof actual === 'string')
assert_unreached(actual);
assert_true(actual instanceof RegExp, 'instanceof RegExp');
assert_equals(actual.global, input.global, 'global');
assert_equals(actual.ignoreCase, input.ignoreCase, 'ignoreCase');
assert_equals(actual.multiline, input.multiline, 'multiline');
assert_equals(actual.source, expected_source, 'source');
assert_equals(actual.sticky, input.sticky, 'sticky');
assert_equals(actual.unicode, input.unicode, 'unicode');
assert_equals(actual.lastIndex, 0, 'lastIndex');
assert_not_equals(actual, input);
if (test_obj)
test_obj.done();
}
}
function func_RegExp_flags_lastIndex() {
const r = /foo/gim;
r.lastIndex = 2;
return r;
}
function func_RegExp_sticky() {
return new RegExp('foo', 'y');
}
function func_RegExp_unicode() {
return new RegExp('foo', 'u');
}
check('RegExp flags and lastIndex', func_RegExp_flags_lastIndex, compare_RegExp('foo'));
check('RegExp sticky flag', func_RegExp_sticky, compare_RegExp('foo'));
check('RegExp unicode flag', func_RegExp_unicode, compare_RegExp('foo'));
check('RegExp empty', new RegExp(''), compare_RegExp('(?:)'));
check('RegExp slash', new RegExp('/'), compare_RegExp('\\/'));
check('RegExp new line', new RegExp('\n'), compare_RegExp('\\n'));
check('Array RegExp object, RegExp flags and lastIndex', [func_RegExp_flags_lastIndex()], compare_Array(enumerate_props(compare_RegExp('foo'))));
check('Array RegExp object, RegExp sticky flag', function() { return [func_RegExp_sticky()]; }, compare_Array(enumerate_props(compare_RegExp('foo'))));
check('Array RegExp object, RegExp unicode flag', function() { return [func_RegExp_unicode()]; }, compare_Array(enumerate_props(compare_RegExp('foo'))));
check('Array RegExp object, RegExp empty', [new RegExp('')], compare_Array(enumerate_props(compare_RegExp('(?:)'))));
check('Array RegExp object, RegExp slash', [new RegExp('/')], compare_Array(enumerate_props(compare_RegExp('\\/'))));
check('Array RegExp object, RegExp new line', [new RegExp('\n')], compare_Array(enumerate_props(compare_RegExp('\\n'))));
check('Object RegExp object, RegExp flags and lastIndex', {'x':func_RegExp_flags_lastIndex()}, compare_Object(enumerate_props(compare_RegExp('foo'))));
check('Object RegExp object, RegExp sticky flag', function() { return {'x':func_RegExp_sticky()}; }, compare_Object(enumerate_props(compare_RegExp('foo'))));
check('Object RegExp object, RegExp unicode flag', function() { return {'x':func_RegExp_unicode()}; }, compare_Object(enumerate_props(compare_RegExp('foo'))));
check('Object RegExp object, RegExp empty', {'x':new RegExp('')}, compare_Object(enumerate_props(compare_RegExp('(?:)'))));
check('Object RegExp object, RegExp slash', {'x':new RegExp('/')}, compare_Object(enumerate_props(compare_RegExp('\\/'))));
check('Object RegExp object, RegExp new line', {'x':new RegExp('\n')}, compare_Object(enumerate_props(compare_RegExp('\\n'))));
async function compare_Blob(actual, input, test_obj, expect_File) {
if (typeof actual === 'string')
assert_unreached(actual);
assert_true(actual instanceof Blob, 'instanceof Blob');
if (!expect_File)
assert_false(actual instanceof File, 'instanceof File');
assert_equals(actual.size, input.size, 'size');
assert_equals(actual.type, input.type, 'type');
assert_not_equals(actual, input);
const ab1 = await new Response(actual).arrayBuffer();
const ab2 = await new Response(input).arrayBuffer();
assert_equals(ab1.byteLength, ab2.byteLength, 'byteLength');
const ta1 = new Uint8Array(ab1);
const ta2 = new Uint8Array(ab2);
for(let i = 0; i < ta1.size; i++) {
assert_equals(ta1[i], ta2[i]);
}
}
function func_Blob_basic() {
return new Blob(['foo'], {type:'text/x-bar'});
}
check('Blob basic', func_Blob_basic, compare_Blob);
function b(str) {
return parseInt(str, 2);
}
function encode_cesu8(codeunits) {
// http://www.unicode.org/reports/tr26/ section 2.2
// only the 3-byte form is supported
const rv = [];
codeunits.forEach(function(codeunit) {
rv.push(b('11100000') + ((codeunit & b('1111000000000000')) >> 12));
rv.push(b('10000000') + ((codeunit & b('0000111111000000')) >> 6));
rv.push(b('10000000') + (codeunit & b('0000000000111111')));
});
return rv;
}
function func_Blob_bytes(arr) {
return function() {
const buffer = new ArrayBuffer(arr.length);
const view = new DataView(buffer);
for (let i = 0; i < arr.length; ++i) {
view.setUint8(i, arr[i]);
}
return new Blob([view]);
};
}
check('Blob unpaired high surrogate (invalid utf-8)', func_Blob_bytes(encode_cesu8([0xD800])), compare_Blob);
check('Blob unpaired low surrogate (invalid utf-8)', func_Blob_bytes(encode_cesu8([0xDC00])), compare_Blob);
check('Blob paired surrogates (invalid utf-8)', func_Blob_bytes(encode_cesu8([0xD800, 0xDC00])), compare_Blob);
function func_Blob_empty() {
return new Blob(['']);
}
check('Blob empty', func_Blob_empty , compare_Blob);
function func_Blob_NUL() {
return new Blob(['\u0000']);
}
check('Blob NUL', func_Blob_NUL, compare_Blob);
check('Array Blob object, Blob basic', [func_Blob_basic()], compare_Array(enumerate_props(compare_Blob), true));
check('Array Blob object, Blob unpaired high surrogate (invalid utf-8)', [func_Blob_bytes([0xD800])()], compare_Array(enumerate_props(compare_Blob), true));
check('Array Blob object, Blob unpaired low surrogate (invalid utf-8)', [func_Blob_bytes([0xDC00])()], compare_Array(enumerate_props(compare_Blob), true));
check('Array Blob object, Blob paired surrogates (invalid utf-8)', [func_Blob_bytes([0xD800, 0xDC00])()], compare_Array(enumerate_props(compare_Blob), true));
check('Array Blob object, Blob empty', [func_Blob_empty()], compare_Array(enumerate_props(compare_Blob), true));
check('Array Blob object, Blob NUL', [func_Blob_NUL()], compare_Array(enumerate_props(compare_Blob), true));
check('Array Blob object, two Blobs', [func_Blob_basic(), func_Blob_empty()], compare_Array(enumerate_props(compare_Blob), true));
check('Object Blob object, Blob basic', {'x':func_Blob_basic()}, compare_Object(enumerate_props(compare_Blob), true));
check('Object Blob object, Blob unpaired high surrogate (invalid utf-8)', {'x':func_Blob_bytes([0xD800])()}, compare_Object(enumerate_props(compare_Blob), true));
check('Object Blob object, Blob unpaired low surrogate (invalid utf-8)', {'x':func_Blob_bytes([0xDC00])()}, compare_Object(enumerate_props(compare_Blob), true));
check('Object Blob object, Blob paired surrogates (invalid utf-8)', {'x':func_Blob_bytes([0xD800, 0xDC00])() }, compare_Object(enumerate_props(compare_Blob), true));
check('Object Blob object, Blob empty', {'x':func_Blob_empty()}, compare_Object(enumerate_props(compare_Blob), true));
check('Object Blob object, Blob NUL', {'x':func_Blob_NUL()}, compare_Object(enumerate_props(compare_Blob), true));
function compare_File(actual, input, test_obj) {
assert_true(actual instanceof File, 'instanceof File');
assert_equals(actual.name, input.name, 'name');
assert_equals(actual.lastModified, input.lastModified, 'lastModified');
compare_Blob(actual, input, test_obj, true);
}
function func_File_basic() {
return new File(['foo'], 'bar', {type:'text/x-bar', lastModified:42});
}
check('File basic', func_File_basic, compare_File);
function compare_FileList(actual, input, test_obj) {
if (typeof actual === 'string')
assert_unreached(actual);
assert_true(actual instanceof FileList, 'instanceof FileList');
assert_equals(actual.length, input.length, 'length');
assert_not_equals(actual, input);
// XXX when there's a way to populate or construct a FileList,
// check the items in the FileList
if (test_obj)
test_obj.done();
}
function func_FileList_empty() {
const input = document.createElement('input');
input.type = 'file';
return input.files;
}
check('FileList empty', func_FileList_empty, compare_FileList, true);
check('Array FileList object, FileList empty', () => ([func_FileList_empty()]), compare_Array(enumerate_props(compare_FileList)), true);
check('Object FileList object, FileList empty', () => ({'x':func_FileList_empty()}), compare_Object(enumerate_props(compare_FileList)), true);
function compare_ArrayBufferView(view) {
const Type = self[view];
return function(actual, input, test_obj) {
if (typeof actual === 'string')
assert_unreached(actual);
assert_true(actual instanceof Type, 'instanceof '+view);
assert_equals(actual.length, input.length, 'length');
assert_not_equals(actual.buffer, input.buffer, 'buffer');
for (let i = 0; i < actual.length; ++i) {
assert_equals(actual[i], input[i], 'actual['+i+']');
}
if (test_obj)
test_obj.done();
};
}
function compare_ImageData(actual, input, test_obj) {
if (typeof actual === 'string')
assert_unreached(actual);
assert_equals(actual.width, input.width, 'width');
assert_equals(actual.height, input.height, 'height');
assert_not_equals(actual.data, input.data, 'data');
compare_ArrayBufferView('Uint8ClampedArray')(actual.data, input.data, null);
if (test_obj)
test_obj.done();
}
function func_ImageData_1x1_transparent_black() {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
return ctx.createImageData(1, 1);
}
check('ImageData 1x1 transparent black', func_ImageData_1x1_transparent_black, compare_ImageData, true);
function func_ImageData_1x1_non_transparent_non_black() {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const imagedata = ctx.createImageData(1, 1);
imagedata.data[0] = 100;
imagedata.data[1] = 101;
imagedata.data[2] = 102;
imagedata.data[3] = 103;
return imagedata;
}
check('ImageData 1x1 non-transparent non-black', func_ImageData_1x1_non_transparent_non_black, compare_ImageData, true);
check('Array ImageData object, ImageData 1x1 transparent black', () => ([func_ImageData_1x1_transparent_black()]), compare_Array(enumerate_props(compare_ImageData)), true);
check('Array ImageData object, ImageData 1x1 non-transparent non-black', () => ([func_ImageData_1x1_non_transparent_non_black()]), compare_Array(enumerate_props(compare_ImageData)), true);
check('Object ImageData object, ImageData 1x1 transparent black', () => ({'x':func_ImageData_1x1_transparent_black()}), compare_Object(enumerate_props(compare_ImageData)), true);
check('Object ImageData object, ImageData 1x1 non-transparent non-black', () => ({'x':func_ImageData_1x1_non_transparent_non_black()}), compare_Object(enumerate_props(compare_ImageData)), true);
check('Array sparse', new Array(10), compare_Array(enumerate_props(compare_primitive)));
check('Array with non-index property', function() {
const rv = [];
rv.foo = 'bar';
return rv;
}, compare_Array(enumerate_props(compare_primitive)));
check('Object with index property and length', {'0':'foo', 'length':1}, compare_Object(enumerate_props(compare_primitive)));
function check_circular_property(prop) {
return function(actual) {
assert_equals(actual[prop], actual);
};
}
check('Array with circular reference', function() {
const rv = [];
rv[0] = rv;
return rv;
}, compare_Array(check_circular_property('0')));
check('Object with circular reference', function() {
const rv = {};
rv['x'] = rv;
return rv;
}, compare_Object(check_circular_property('x')));
function check_identical_property_values(prop1, prop2) {
return function(actual) {
assert_equals(actual[prop1], actual[prop2]);
};
}
check('Array with identical property values', function() {
const obj = {}
return [obj, obj];
}, compare_Array(check_identical_property_values('0', '1')));
check('Object with identical property values', function() {
const obj = {}
return {'x':obj, 'y':obj};
}, compare_Object(check_identical_property_values('x', 'y')));
function check_absent_property(prop) {
return function(actual) {
assert_false(prop in actual);
};
}
check('Object with property on prototype', function() {
const Foo = function() {};
Foo.prototype = {'foo':'bar'};
return new Foo();
}, compare_Object(check_absent_property('foo')));
check('Object with non-enumerable property', function() {
const rv = {};
Object.defineProperty(rv, 'foo', {value:'bar', enumerable:false, writable:true, configurable:true});
return rv;
}, compare_Object(check_absent_property('foo')));
function check_writable_property(prop) {
return function(actual, input) {
assert_equals(actual[prop], input[prop]);
actual[prop] += ' baz';
assert_equals(actual[prop], input[prop] + ' baz');
};
}
check('Object with non-writable property', function() {
const rv = {};
Object.defineProperty(rv, 'foo', {value:'bar', enumerable:true, writable:false, configurable:true});
return rv;
}, compare_Object(check_writable_property('foo')));
function check_configurable_property(prop) {
return function(actual, input) {
assert_equals(actual[prop], input[prop]);
delete actual[prop];
assert_false('prop' in actual);
};
}
check('Object with non-configurable property', function() {
const rv = {};
Object.defineProperty(rv, 'foo', {value:'bar', enumerable:true, writable:true, configurable:false});
return rv;
}, compare_Object(check_configurable_property('foo')));
/* The tests below are inspired by @zcorpan’s work but got some
more substantial changed due to their previous async setup */
function get_canvas_1x1_transparent_black() {
const canvas = document.createElement('canvas');
canvas.width = 1;
canvas.height = 1;
return canvas;
}
function get_canvas_1x1_non_transparent_non_black() {
const canvas = document.createElement('canvas');
canvas.width = 1;
canvas.height = 1;
const ctx = canvas.getContext('2d');
const imagedata = ctx.getImageData(0, 0, 1, 1);
imagedata.data[0] = 100;
imagedata.data[1] = 101;
imagedata.data[2] = 102;
imagedata.data[3] = 103;
return canvas;
}
function compare_ImageBitmap(actual, input) {
if (typeof actual === 'string')
assert_unreached(actual);
assert_true(actual instanceof ImageBitmap, 'instanceof ImageBitmap');
assert_not_equals(actual, input);
// XXX paint the ImageBitmap on a canvas and check the data
}
structuredCloneBatteryOfTests.push({
description: 'ImageBitmap 1x1 transparent black',
async f(runner) {
const canvas = get_canvas_1x1_transparent_black();
const bm = await createImageBitmap(canvas);
const copy = await runner.structuredClone(bm);
compare_ImageBitmap(bm, copy);
},
requiresDocument: true
});
structuredCloneBatteryOfTests.push({
description: 'ImageBitmap 1x1 non-transparent non-black',
async f(runner) {
const canvas = get_canvas_1x1_non_transparent_non_black();
const bm = await createImageBitmap(canvas);
const copy = await runner.structuredClone(bm);
compare_ImageBitmap(bm, copy);
},
requiresDocument: true
});
structuredCloneBatteryOfTests.push({
description: 'Array ImageBitmap object, ImageBitmap 1x1 transparent black',
async f(runner) {
const canvas = get_canvas_1x1_transparent_black();
const bm = [await createImageBitmap(canvas)];
const copy = await runner.structuredClone(bm);
compare_Array(enumerate_props(compare_ImageBitmap))(bm, copy);
},
requiresDocument: true
});
structuredCloneBatteryOfTests.push({
description: 'Array ImageBitmap object, ImageBitmap 1x1 transparent non-black',
async f(runner) {
const canvas = get_canvas_1x1_non_transparent_non_black();
const bm = [await createImageBitmap(canvas)];
const copy = await runner.structuredClone(bm);
compare_Array(enumerate_props(compare_ImageBitmap))(bm, copy);
},
requiresDocument: true
});
structuredCloneBatteryOfTests.push({
description: 'Object ImageBitmap object, ImageBitmap 1x1 transparent black',
async f(runner) {
const canvas = get_canvas_1x1_transparent_black();
const bm = {x: await createImageBitmap(canvas)};
const copy = await runner.structuredClone(bm);
compare_Object(enumerate_props(compare_ImageBitmap))(bm, copy);
},
requiresDocument: true
});
structuredCloneBatteryOfTests.push({
description: 'Object ImageBitmap object, ImageBitmap 1x1 transparent non-black',
async f(runner) {
const canvas = get_canvas_1x1_non_transparent_non_black();
const bm = {x: await createImageBitmap(canvas)};
const copy = await runner.structuredClone(bm);
compare_Object(enumerate_props(compare_ImageBitmap))(bm, copy);
},
requiresDocument: true
});
check('ObjectPrototype must lose its exotic-ness when cloned',
() => Object.prototype,
(copy, original) => {
assert_not_equals(copy, original);
assert_true(copy instanceof Object);
const newProto = { some: 'proto' };
// Must not throw:
Object.setPrototypeOf(copy, newProto);
assert_equals(Object.getPrototypeOf(copy), newProto);
}
);

View File

@ -0,0 +1,9 @@
// META: title=structuredClone() tests
// META: script=/html/webappapis/structured-clone/structured-clone-battery-of-tests.js
// META: script=/html/webappapis/structured-clone/structured-clone-battery-of-tests-with-transferables.js
// META: script=/html/webappapis/structured-clone/structured-clone-battery-of-tests-harness.js
runStructuredCloneBatteryOfTests({
structuredClone: (obj, transfer) => self.structuredClone(obj, { transfer }),
hasDocument: typeof document !== "undefined",
});

View File

@ -0,0 +1,29 @@
async_test((t) => {
const handle = setTimeout(
t.step_func(() => {
assert_unreached("Timeout was not canceled");
}),
0
);
clearInterval(handle);
setTimeout(() => {
t.done();
}, 100);
}, "Clear timeout with clearInterval");
async_test((t) => {
const handle = setInterval(
t.step_func(() => {
assert_unreached("Interval was not canceled");
}),
0
);
clearTimeout(handle);
setTimeout(() => {
t.done();
}, 100);
}, "Clear interval with clearTimeout");

View File

@ -0,0 +1,23 @@
<!doctype html>
<title>Interaction of setTimeout and WebIDL</title>
<link rel="author" title="Ian Hickson" href="mailto:ian@hixie.ch">
<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com">
<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-windowtimers-settimeout">
<link rel="help" href="https://heycam.github.io/webidl/#es-operations">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<script>
var t = async_test()
function finishTest() {
assert_equals(log, "ONE TWO ")
t.done()
}
var log = '';
function logger(s) { log += s + ' '; }
setTimeout({ toString: function () {
setTimeout("logger('ONE')", 100);
return "logger('TWO'); t.step(finishTest)";
} }, 100);
</script>

View File

@ -0,0 +1,34 @@
function timeout_trampoline(t, timeout, message) {
t.step_timeout(function() {
// Yield in case we managed to be called before the second interval callback.
t.step_timeout(function() {
assert_unreached(message);
}, timeout);
}, timeout);
}
async_test(function(t) {
let ctr = 0;
let h = setInterval(t.step_func(function() {
if (++ctr == 2) {
clearInterval(h);
t.done();
return;
}
}) /* no interval */);
timeout_trampoline(t, 100, "Expected setInterval callback to be called two times");
}, "Calling setInterval with no interval should be the same as if called with 0 interval");
async_test(function(t) {
let ctr = 0;
let h = setInterval(t.step_func(function() {
if (++ctr == 2) {
clearInterval(h);
t.done();
return;
}
}), undefined);
timeout_trampoline(t, 100, "Expected setInterval callback to be called two times");
}, "Calling setInterval with undefined interval should be the same as if called with 0 interval");

View File

@ -0,0 +1,12 @@
setup({ single_test: true });
var i = 0;
var interval;
function next() {
i++;
if (i === 20) {
clearInterval(interval);
done();
}
}
setTimeout(assert_unreached, 1000);
interval = setInterval(next, -100);

View File

@ -0,0 +1,3 @@
setup({ single_test: true });
setTimeout(done, -100);
setTimeout(assert_unreached, 10);

View File

@ -0,0 +1,8 @@
setup({ single_test: true });
var interval;
function next() {
clearInterval(interval);
done();
}
interval = setInterval(next, Math.pow(2, 32));
setTimeout(assert_unreached, 100);

View File

@ -0,0 +1,3 @@
setup({ single_test: true });
setTimeout(done, Math.pow(2, 32));
setTimeout(assert_unreached, 100);