<!DOCTYPE html> <!-- webkit-test-runner [ UndoManagerAPIEnabled=true ] -->
<html>
    <meta charset="utf8">
    <head>
        <script src="../../resources/js-test.js"></script>
        <script src="../editing.js"></script>
        <script>
        jsTestIsAsync = true;

        function objectCountAfterSimulatingMemoryPressureAndGarbageCollection() {
            internals.beginSimulatedMemoryPressure();
            internals.endSimulatedMemoryPressure();
            GCController.collect();
            return GCController.getJSObjectCount();
        }

        async function runTest() {
            description("Verifies that JSUndoItems are deleted when they are no longer needed by the platform clipboard. This test requires WebKitTestRunner.");

            if (!window.GCController)
                return;

            editor = document.getElementById("editor");
            editor.focus();

            const undoItemCount = 1000;

            for (let i = 0; i < undoItemCount; ++i) {
                document.undoManager.addItem(new UndoItem({
                    label: "",
                    undo: () => { },
                    redo: () => { }
                }));
            }

            for (let i = 0; i < undoItemCount; ++i)
                document.execCommand("Undo");

            objectCountBeforeClearingUndoStack = objectCountAfterSimulatingMemoryPressureAndGarbageCollection();

            selectAllCommand();
            typeCharacterCommand("E");

            // Wait until almost all of the wrappers are collected. For each UndoItem, we expect a total of 3 wrappers:
            // one each for the undo and redo handlers, and one for the UndoItem itself. However, we also give ourselves
            // some wiggle room for additional wrappers created when calling some testing helper functions. This is
            // still a useful test, since it will time out in the case where either our undo items or their undo/redo
            // handlers are not properly relinquished once they're no longer needed.
            const minimumNumberOfWrappersToCollectBeforePassing = 3 * undoItemCount - 300;
            objectCountAfterClearingUndoStack = objectCountBeforeClearingUndoStack;
            var tries = 0;
            while (objectCountBeforeClearingUndoStack - objectCountAfterClearingUndoStack < minimumNumberOfWrappersToCollectBeforePassing) {
                await new Promise(resolve => setTimeout(resolve, 100));
                objectCountAfterClearingUndoStack = objectCountAfterSimulatingMemoryPressureAndGarbageCollection();
                if (tries++ > 10)
                    break;
            }

            shouldBeGreaterThanOrEqual("objectCountBeforeClearingUndoStack - objectCountAfterClearingUndoStack", `${minimumNumberOfWrappersToCollectBeforePassing}`);
            finishJSTest();
        }
        </script>
    </head>
    <body onload="runTest()">
        <div contenteditable id="editor"></div>
        <pre id="description"></pre>
        <pre id="console"></pre>
    </body>
</html>
