Bug 1596756 - Add browser tests for FinalizationGroup r=mccr8

These are mochitests because there's currently no way to trigger a GC from WPT. I tried to do this with xpcshell tests but I couldn't get the pref to enable weak refs to work.

Differential Revision: https://phabricator.services.mozilla.com/D59375

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Jon Coppeard 2020-01-10 17:20:59 +00:00
Родитель 18a075eec7
Коммит 0f4b542755
4 изменённых файлов: 255 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,96 @@
let holdings1 = [];
let holdings2 = [];
let holdings3 = [];
let holdings4 = [];
let holdings5 = [];
onmessage = (event) => {
switch (event.data) {
case 'startTest':
startTest();
break;
case 'checkResults':
checkResults();
break;
default:
throw "Unknown message";
}
};
function startTest() {
// Group with no registered objects.
let group1 = new FinalizationGroup(i => holdings1 = [...i]);
// Group with three registered objects.
let group2 = new FinalizationGroup(i => holdings2 = [...i]);
group2.register({}, 1);
group2.register({}, 2);
group2.register({}, 3);
// Group with registered object that is then unregistered.
let group3 = new FinalizationGroup(i => holdings3 = [...i]);
let token3 = {}
group3.register({}, 1, token3);
group3.unregister(token3);
// Group with registered object that doesn't die.
let group4 = new FinalizationGroup(i => holdings4 = [...i]);
let object4 = {};
group4.register(object4, 1);
// Group observing cyclic JS data structure.
let group5 = new FinalizationGroup(i => holdings5 = [...i]);
group5.register(makeJSCycle(4), 5);
const { gc } = getJSTestingFunctions();
gc();
Promise.resolve().then(() => {
checkNoCallbacks();
});
postMessage('started');
}
function checkNoCallbacks() {
is(holdings1.length, 0);
is(holdings2.length, 0);
is(holdings3.length, 0);
is(holdings4.length, 0);
is(holdings5.length, 0);
}
function checkResults() {
is(holdings1.length, 0);
let result = holdings2.sort((a, b) => a - b);
is(result.length, 3);
is(result[0], 1);
is(result[1], 2);
is(result[2], 3);
is(holdings3.length, 0);
is(holdings4.length, 0);
is(holdings5.length, 1);
is(holdings5[0], 5);
postMessage('passed');
}
function is(a, b) {
if (a !== b) {
throw `Expected ${b} but got ${a}`;
}
}
function makeJSCycle(size) {
let first = {};
let current = first;
for (let i = 0; i < size; i++) {
current.next = {};
current = current.next;
}
current.next = first;
return first;
}

Просмотреть файл

@ -36,6 +36,9 @@ support-files =
inner.html
test1_bug629331.html
test2_bug629331.html
finalizationGroup_worker.js
prefs =
javascript.options.experimental.weakrefs=true
[test_bug384632.html]
[test_bug390488.html]
@ -110,3 +113,7 @@ skip-if = (debug == false)
support-files =
../../../../dom/tests/mochitest/fetch/test_fetch_basic.js
[test_weakmaps.html]
[test_finalizationGroup.html]
skip-if = !nightly_build
[test_finalizationGroupInWorker.html]
skip-if = !nightly_build

Просмотреть файл

@ -0,0 +1,112 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test FinalizationGroup works in the browser</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript">
function go() {
SimpleTest.waitForExplicitFinish();
// Group with no registered objects.
let holdings1 = [];
let group1 = new FinalizationGroup(i => holdings1 = [...i]);
// Group with three registered objects.
let holdings2 = [];
let group2 = new FinalizationGroup(i => holdings2 = [...i]);
group2.register({}, 1);
group2.register({}, 2);
group2.register({}, 3);
// Group with registered object that is then unregistered.
let holdings3 = [];
let group3 = new FinalizationGroup(i => holdings3 = [...i]);
let token3 = {}
group3.register({}, 1, token3);
group3.unregister(token3);
// Group with registered object that doesn't die.
let holdings4 = [];
let group4 = new FinalizationGroup(i => holdings4 = [...i]);
let object4 = {};
group4.register(object4, 1);
// Group observing cyclic JS data structure.
let holdings5 = [];
let group5 = new FinalizationGroup(i => holdings5 = [...i]);
group5.register(makeJSCycle(4), 5);
// Group observing cyclic DOM/JS data structure.
let holdings6 = [];
let group6 = new FinalizationGroup(i => holdings6 = [...i]);
group6.register(makeDOMCycle(4), 6);
// Need to run full GC/CC/GC cycle to collect cyclic garbage through DOM
// and JS heaps.
SpecialPowers.DOMWindowUtils.garbageCollect();
SpecialPowers.DOMWindowUtils.cycleCollect();
SpecialPowers.DOMWindowUtils.garbageCollect();
// Microtasks are run before cleanup callbacks.
Promise.resolve().then(() => {
is(holdings1.length, 0);
is(holdings2.length, 0);
is(holdings3.length, 0);
is(holdings4.length, 0);
is(holdings5.length, 0);
is(holdings6.length, 0);
});
// setTimeout queues a task which will run after cleanup callbacks.
setTimeout(() => {
is(holdings1.length, 0);
let result = holdings2.sort((a, b) => a - b);
is(result.length, 3);
is(result[0], 1);
is(result[1], 2);
is(result[2], 3);
is(holdings3.length, 0);
is(holdings4.length, 0);
is(holdings5.length, 1);
is(holdings5[0], 5);
is(holdings6.length, 1);
is(holdings6[0], 6);
SimpleTest.finish();
}, 0);
}
function makeJSCycle(size) {
let first = {};
let current = first;
for (let i = 0; i < size; i++) {
current.next = {};
current = current.next;
}
current.next = first;
return first;
}
function makeDOMCycle(size) {
let first = {};
let current = first;
for (let i = 0; i < size; i++) {
if (i % 2 === 0) {
current.next = document.createElement("div");
} else {
current.next = {};
}
current = current.next;
}
current.next = first;
return first;
}
</script>
</head>
<body onload="go()"></body>
</html>

Просмотреть файл

@ -0,0 +1,40 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test FinalizationGroup works in workers</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript">
function go() {
SimpleTest.waitForExplicitFinish();
let worker = new Worker('finalizationGroup_worker.js');
worker.onevent = (event) => {
console.log(event.message);
throw event.error;
};
worker.onmessage = (event) => {
switch (event.data) {
case 'started':
worker.postMessage('checkResults');
break;
case 'passed':
ok(true, "Tests passed");
SimpleTest.finish();
break;
default:
console.log(event.data);
break;
}
};
worker.postMessage('startTest');
}
</script>
</head>
<body onload="go()"></body>
</html>