<html> <head> <link rel="stylesheet" href="../../fast/js/resources/js-test-style.css"> <script src="../../fast/js/resources/js-test-pre.js"></script> <script src="../../fast/js/resources/js-test-post-function.js"></script> <script src="resources/shared.js"></script> </head> <body> <p id="description"></p> <div id="console"></div> <script> description("Test IndexedDB's cursor skips deleted entries."); if (window.layoutTestController) layoutTestController.waitUntilDone(); var names = ['Alpha', 'Bravo', 'Charlie', 'Delta', 'Echo', 'Foxtrot', 'Golf', 'Hotel', 'India', 'Juliet', 'Kilo', 'Lima', 'Mike', 'November', 'Oscar', 'Papa', 'Quebec', 'Romeo', 'Sierra', 'Tango', 'Uniform', 'Victor', 'Whiskey', 'X-ray', 'Yankee', 'Zulu']; test(); function test() { request = evalAndLog("webkitIndexedDB.open('cursor-skip-deleted')"); request.onsuccess = openSuccess; request.onerror = unexpectedErrorCallback; } function openSuccess() { var db = evalAndLog("db = event.target.result"); request = evalAndLog("db.setVersion('new version')"); request.onsuccess = setVersionSuccess; request.onerror = unexpectedErrorCallback; } function setVersionSuccess() { debug("setVersionSuccess():"); window.trans = evalAndLog("trans = event.target.result"); shouldBeTrue("trans !== null"); trans.onabort = unexpectedAbortCallback; trans.oncomplete = basicCursorTest; deleteAllObjectStores(db); var objectStore = evalAndLog("objectStore = db.createObjectStore('store', {keyPath: 'id'})"); evalAndLog("objectStore.createIndex('nameIndex', 'name')"); resetObjectStore(function() {}); } var silentErrorHandler = function() { event.preventDefault(); } function resetObjectStore(callback) { debug("\nresetObjectStore():"); if (callback === undefined) callback = function () {}; var objectStore = trans.objectStore('store'); for (var i = 0; i < names.length; i++) objectStore.delete(i).onerror = silentErrorHandler; for (var i = 0; i < names.length; i++) objectStore.add({id: i, name: names[i]}).onerror = unexpectedErrorCallback; debug(""); callback(); } function contains(arr, obj) { for (var i = 0; i < arr.length; i++) { if (arr[i] == obj) return true; } return false; } var cursor; var deleted; var seen; function testCursor(deleteList, createCursorCommand, callback) { debug("\ntestCursor():"); deleted = []; seen = []; // Create the cursor. request = evalAndLog(createCursorCommand); request.onerror = unexpectedErrorCallback; request.onsuccess = function () { if (event.target.result == null) { // Make sure we have seen every non-deleted item. for (var i = 0; i < names.length; i++) { if (contains(deleted, i)) continue; if (!contains(seen, i)) testFailed("Cursor did not see item with id: " + i); } // Make sure we used every rule in |deleteList|. for (var i = 0; i < deleteList.length; i++) { if (!contains(seen, deleteList[i].id)) testFailed("deleteList rule with id: " + deleteList[i].id + " was never used."); } debug(""); callback(); return; } cursor = event.target.result; debug(event.target.result.value.id + ": " + event.target.result.value.name); seen.push(event.target.result.value.id); // Make sure we don't see any deleted items. if (contains(deleted, event.target.result.value.id)) testFailed("Cursor hit previously deleted element."); for (var i = 0; i < deleteList.length; i++) { if (event.target.result.value.id == deleteList[i].id) { // Delete objects targeted by this id. var targets = deleteList[i].targets; for (var j = 0; j < targets.length; j++) { deleted.push(targets[j]); request = evalAndLog("request = trans.objectStore('store').delete(" + targets[j] + ")"); request.onerror = unexpectedErrorCallback; if (j == targets.length - 1) request.onsuccess = function() { cursor.continue(); } } return; } } cursor.continue(); } } function basicCursorTest() { debug("basicCursorTest()"); evalAndLog("trans = db.transaction([], webkitIDBTransaction.READ_WRITE)"); trans.onabort = unexpectedAbortCallback; trans.oncomplete = transactionComplete; var deletes = [{id: 1, targets: [0]}, {id: 2, targets: [names.length - 1]}, {id: 3, targets: [5,6,7]}, {id: 10, targets: [10]}, {id: 12, targets: [13]}, {id: 15, targets: [14]}, {id: 20, targets: [17,18]} ]; testCursor(deletes, "trans.objectStore('store').openCursor(webkitIDBKeyRange.lowerBound(0))", function() { resetObjectStore(reverseCursorTest); }); } function reverseCursorTest() { debug("reverseCursorTest():"); var deletes = [{id: 24, targets: [names.length - 1]}, {id: 23, targets: [0]}, {id: 22, targets: [20, 19, 18]}, {id: 15, targets: [15]}, {id: 13, targets: [12]}, {id: 10, targets: [11]}, {id: 5, targets: [7,8]} ]; testCursor(deletes, "trans.objectStore('store').openCursor(webkitIDBKeyRange.lowerBound(0), webkitIDBCursor.PREV)", function() { resetObjectStore(indexCursorTest); }); } function indexCursorTest() { debug("indexCursorTest():"); var deletes = [{id: 1, targets: [0]}, {id: 2, targets: [names.length - 1]}, {id: 3, targets: [5,6,7]}, {id: 10, targets: [10]}, {id: 12, targets: [13]}, {id: 15, targets: [14]}, {id: 20, targets: [17,18]} ]; testCursor(deletes, "trans.objectStore('store').index('nameIndex').openCursor(webkitIDBKeyRange.lowerBound('Alpha'))", function() { }); } function transactionComplete() { debug("transactionComplete():"); done(); } var successfullyParsed = true; </script> </body> </html>