187 lines
6.2 KiB
HTML
187 lines
6.2 KiB
HTML
<!DOCTYPE html>
|
|
<script src="../../resources/js-test.js"></script>
|
|
<script>
|
|
|
|
description('Tests for leaks caused by reference cycles that pass through the DOM implementation');
|
|
|
|
function checkForNodeLeaks(testFunction, underlyingClass)
|
|
{
|
|
// Bump this number as high as we need to, to get reproducible results.
|
|
const repetitions = 40;
|
|
|
|
gc();
|
|
const beforeCount = internals.numberOfLiveNodes();
|
|
for (var i = 0; i < repetitions; ++i)
|
|
testFunction();
|
|
gc();
|
|
const leaks = internals.numberOfLiveNodes() - beforeCount;
|
|
|
|
if (leaks == repetitions)
|
|
return "leaked";
|
|
if (leaks < repetitions / 10)
|
|
return "did not leak";
|
|
return "leaked an unexpected number of nodes: " + leaks + " leaks in " + repetitions + " runs";
|
|
}
|
|
|
|
function emptyFunction()
|
|
{
|
|
}
|
|
|
|
function createNode()
|
|
{
|
|
document.createTextNode("");
|
|
}
|
|
|
|
function createEventListenerCycle()
|
|
{
|
|
const leakDetectionNode = document.createTextNode("");
|
|
leakDetectionNode.addEventListener("x", function () { return leakDetectionNode; });
|
|
}
|
|
|
|
function createPromiseCycle()
|
|
{
|
|
const leakDetectionNode = document.createTextNode("");
|
|
const promise = new Promise(function (resolve, reject) { });
|
|
promise.cycle = promise;
|
|
promise.leakDetectionNode = leakDetectionNode;
|
|
}
|
|
|
|
function createTreeWalkerNodeCycle()
|
|
{
|
|
const leakDetectionNode = document.createTextNode("");
|
|
leakDetectionNode.treeWalker = document.createTreeWalker(leakDetectionNode);
|
|
}
|
|
|
|
function createTreeWalkerFilterCycle()
|
|
{
|
|
const leakDetectionNode = document.createTextNode("");
|
|
const filter = { leakDetectionNode: leakDetectionNode, acceptNode: function(node) { return leakDetectionNode; } };
|
|
leakDetectionNode.treeWalker = document.createTreeWalker(document, 0, filter);
|
|
}
|
|
|
|
function createRangeCycle()
|
|
{
|
|
const leakDetectionNode = document.createTextNode("");
|
|
const range = new Range();
|
|
range.setStart(leakDetectionNode, 0);
|
|
leakDetectionNode.range = range;
|
|
}
|
|
|
|
function createStaticRangeCycle()
|
|
{
|
|
const leakDetectionNode = document.createTextNode("");
|
|
leakDetectionNode.staticRange = new StaticRange({startContainer: leakDetectionNode, startOffset: 0, endContainer: leakDetectionNode, endOffset: 0});
|
|
}
|
|
|
|
function createCustomEventDetailsCycle()
|
|
{
|
|
const leakDetectionNode = document.createTextNode("");
|
|
leakDetectionNode.event = new CustomEvent("x", { detail: leakDetectionNode });
|
|
}
|
|
|
|
function createErrorEventDataCycle()
|
|
{
|
|
const leakDetectionNode = document.createTextNode("");
|
|
leakDetectionNode.event = new ErrorEvent("x", { error: leakDetectionNode });
|
|
}
|
|
|
|
function createExtendableMessageEventDataCycle()
|
|
{
|
|
const leakDetectionNode = document.createTextNode("");
|
|
leakDetectionNode.event = new ExtendableMessageEvent("x", { data: leakDetectionNode });
|
|
}
|
|
|
|
function createMessageEventDataCycle()
|
|
{
|
|
const leakDetectionNode = document.createTextNode("");
|
|
leakDetectionNode.event = new MessageEvent("x", { data: leakDetectionNode });
|
|
}
|
|
|
|
function createPaymentMethodChangeEventMethodDetailsCycle()
|
|
{
|
|
const leakDetectionNode = document.createTextNode("");
|
|
leakDetectionNode.event = new PaymentMethodChangeEvent("x", { methodDetails: leakDetectionNode });
|
|
}
|
|
|
|
function createPromiseRejectionEventPromiseCycle()
|
|
{
|
|
const leakDetectionNode = document.createTextNode("");
|
|
const promise = new Promise(function (resolve, reject) { });
|
|
promise.leakDetectionNode = leakDetectionNode;
|
|
leakDetectionNode.event = new PromiseRejectionEvent("x", { promise: promise });
|
|
}
|
|
|
|
function createPromiseRejectionEventPromiseFunctionCycle()
|
|
{
|
|
const leakDetectionNode = document.createTextNode("");
|
|
const promise = new Promise(function (resolve, reject) { return leakDetectionNode; });
|
|
leakDetectionNode.event = new PromiseRejectionEvent("x", { promise: promise });
|
|
}
|
|
|
|
function createPromiseRejectionEventReasonCycle()
|
|
{
|
|
const leakDetectionNode = document.createTextNode("");
|
|
const promise = new Promise(function (resolve, reject) { });
|
|
leakDetectionNode.event = new PromiseRejectionEvent("x", { promise: promise, reason: leakDetectionNode });
|
|
}
|
|
|
|
function createPopStateEventStateCycle()
|
|
{
|
|
const leakDetectionNode = document.createTextNode("");
|
|
leakDetectionNode.event = new PopStateEvent("x", { state: leakDetectionNode });
|
|
}
|
|
|
|
// Reference cycle of IDBRequest and IDBCursor is tested in
|
|
// storage/indexeddb/value-cursor-cycle.html and LayoutTests/storage/indexeddb/result-request-cycle.html.
|
|
|
|
// PaymentResponse details reference cycle is tested in
|
|
// http/tests/paymentrequest/payment-response-reference-cycle-leak.https.html.
|
|
|
|
function createRTCStatsReportCycle()
|
|
{
|
|
// FIXME: Need to write this test and reorganize so it can be asynchronous.
|
|
// Get an RTCStatsReport.
|
|
// Get one of the objects from the map.
|
|
// Add a property to that object that references the report.
|
|
// Add another property to that object that references a leak detection node.
|
|
}
|
|
|
|
function runLeakTest(testFunctionName, underlyingClassName)
|
|
{
|
|
if (underlyingClassName && !(underlyingClassName in window))
|
|
debug('---- Did not test ' + underlyingClassName + ' because it is not enabled.');
|
|
else
|
|
shouldBeEqualToString('checkForNodeLeaks(' + testFunctionName + ')', 'did not leak');
|
|
}
|
|
|
|
function startTest()
|
|
{
|
|
if (!window.internals || !internals.numberOfLiveNodes) {
|
|
testFailed('Test requires windows.internals, so must be run inside WebKitTestRunner');
|
|
return;
|
|
}
|
|
|
|
runLeakTest('emptyFunction');
|
|
runLeakTest('createNode');
|
|
runLeakTest('createEventListenerCycle');
|
|
runLeakTest('createTreeWalkerNodeCycle');
|
|
runLeakTest('createTreeWalkerFilterCycle');
|
|
runLeakTest('createRangeCycle');
|
|
runLeakTest('createStaticRangeCycle');
|
|
runLeakTest('createPromiseCycle');
|
|
|
|
runLeakTest('createCustomEventDetailsCycle');
|
|
runLeakTest('createErrorEventDataCycle');
|
|
runLeakTest('createExtendableMessageEventDataCycle', 'ExtendableMessageEvent');
|
|
runLeakTest('createMessageEventDataCycle');
|
|
runLeakTest('createPaymentMethodChangeEventMethodDetailsCycle', 'PaymentMethodChangeEvent');
|
|
runLeakTest('createPopStateEventStateCycle');
|
|
runLeakTest('createPromiseRejectionEventPromiseCycle');
|
|
runLeakTest('createPromiseRejectionEventPromiseFunctionCycle');
|
|
runLeakTest('createPromiseRejectionEventReasonCycle');
|
|
}
|
|
|
|
startTest();
|
|
|
|
</script>
|