| if (this.importScripts) { |
| importScripts('../../../resources/js-test.js'); |
| importScripts('shared.js'); |
| } |
| |
| description("Test IndexedDB cursor.advance()."); |
| |
| var objectStoreData = [ |
| { key: "237-23-7732", value: { name: "Bob", height: 60, weight: 120 } }, |
| { key: "237-23-7733", value: { name: "Ann", height: 52, weight: 110 } }, |
| { key: "237-23-7734", value: { name: "Ron", height: 73, weight: 180 } }, |
| { key: "237-23-7735", value: { name: "Sue", height: 58, weight: 130 } }, |
| { key: "237-23-7736", value: { name: "Joe", height: 65, weight: 150 } }, |
| { key: "237-23-7737", value: { name: "Pat", height: 65, weight: 100 } }, |
| { key: "237-23-7738", value: { name: "Leo", height: 65, weight: 180 } }, |
| { key: "237-23-7739", value: { name: "Jef", height: 65, weight: 120 } }, |
| { key: "237-23-7740", value: { name: "Sam", height: 71, weight: 110 } }, |
| { key: "237-23-7741", value: { name: "Bug", height: 63, weight: 100 } }, |
| { key: "237-23-7742", value: { name: "Tub", height: 69, weight: 180 } }, |
| { key: "237-23-7743", value: { name: "Rug", height: 77, weight: 120 } }, |
| { key: "237-23-7744", value: { name: "Pug", height: 66, weight: 110 } }, |
| ]; |
| |
| var indexData = [ |
| { name: "name", keyPath: "name", options: { unique: true } }, |
| { name: "height", keyPath: "height", options: { } }, |
| { name: "weight", keyPath: "weight", options: { unique: false } } |
| ]; |
| |
| indexedDBTest(prepareDatabase, onOpen); |
| function prepareDatabase(evt) |
| { |
| preamble(evt); |
| db = event.target.result; |
| objectStoreName = "People"; |
| objectStore = evalAndLog("objectStore = db.createObjectStore(objectStoreName);"); |
| createIndexes(); |
| } |
| |
| function onOpen() |
| { |
| evalAndLog("trans = db.transaction(objectStoreName, 'readwrite')"); |
| evalAndLog("objectStore = trans.objectStore(objectStoreName)"); |
| populateObjectStore(); |
| } |
| |
| function populateObjectStore() |
| { |
| debug("First, add all our data to the object store."); |
| addedData = 0; |
| for (i in objectStoreData) { |
| request = evalAndLog("request = objectStore.add(objectStoreData[i].value, objectStoreData[i].key);"); |
| request.onerror = unexpectedErrorCallback; |
| } |
| trans.oncomplete = testSimple; |
| } |
| |
| function createIndexes() |
| { |
| debug("Now create the indexes."); |
| for (i in indexData) { |
| evalAndLog("objectStore.createIndex(indexData[i].name, indexData[i].keyPath, indexData[i].options);"); |
| } |
| } |
| |
| // Make a test that uses continue() to get to startPos, then passes |
| // 'count' to get to a position. |
| function makeAdvanceTest(startPos, direction, count, expectedValue, indexName) |
| { |
| result = {}; |
| evalAndLog("trans = db.transaction(objectStoreName)"); |
| store = evalAndLog("store = trans.objectStore(objectStoreName)"); |
| if (indexName) |
| store = store.index(indexName); |
| |
| if (direction) |
| evalAndLog("request = store.openCursor(null, " + direction + ")"); |
| else |
| evalAndLog("request = store.openCursor()"); |
| var currentPos = 0; |
| function continueToTest(event) |
| { |
| cursor = event.target.result; |
| if (currentPos == startPos) { |
| evalAndLog("cursor.advance(" + count + ")"); |
| } else if (currentPos == startPos + 1) { |
| runTest(cursor, expectedValue); |
| result.onsuccess(); |
| } else { |
| if (cursor == null) |
| result.onsuccess(); |
| else { |
| evalAndLog("cursor.continue();"); |
| } |
| } |
| currentPos++; |
| } |
| |
| request.onsuccess = continueToTest; |
| request.onerror = function(e) |
| { |
| result.onerror(e); |
| }; |
| |
| return result; |
| } |
| |
| function simplifyCursor(cursor) |
| { |
| var obj = {}; |
| if (cursor === null) { |
| return null; |
| } |
| if ('key' in cursor) { |
| obj.key = cursor.key; |
| } |
| |
| if ('value' in cursor) { |
| obj.value = cursor.value; |
| } |
| |
| if ('primaryKey' in cursor) { |
| obj.primaryKey = cursor.primaryKey; |
| } |
| return obj; |
| } |
| |
| function runTest(cursor, expectedValue) |
| { |
| expected = JSON.stringify(expectedValue); |
| shouldBeEqualToString("expected", JSON.stringify(simplifyCursor(cursor))); |
| } |
| |
| |
| function testSimple() |
| { |
| debug("testSimple()"); |
| makeAdvanceTest(0, null, 1, |
| {key: objectStoreData[1].key, |
| value: objectStoreData[1].value, |
| primaryKey: objectStoreData[1].key}) |
| .onsuccess= testContinueThenAdvance; |
| } |
| |
| function testContinueThenAdvance() |
| { |
| debug("testContinueThenAdvance()"); |
| makeAdvanceTest(3, null, 1, |
| // Joe |
| {key: objectStoreData[4].key, |
| value: objectStoreData[4].value, |
| primaryKey: objectStoreData[4].key}) |
| .onsuccess= testAdvanceMultiple; |
| } |
| |
| function testAdvanceMultiple() |
| { |
| debug("testAdvanceMultiple()"); |
| makeAdvanceTest(0, null, 3, |
| {key: objectStoreData[3].key, |
| value: objectStoreData[3].value, |
| primaryKey: objectStoreData[3].key}) |
| .onsuccess = testAdvanceIndex; |
| } |
| |
| function testAdvanceIndex() |
| { |
| debug("testAdvanceIndex()"); |
| makeAdvanceTest(0, null, 3, |
| // Jef |
| {key: objectStoreData[7].value.name, |
| value: objectStoreData[7].value, |
| primaryKey: objectStoreData[7].key}, |
| "name").onsuccess = testAdvanceIndexNoDupe; |
| } |
| |
| function testAdvanceIndexNoDupe() |
| { |
| debug("testAdvanceIndexNoDupe()"); |
| makeAdvanceTest(0, "'nextunique'", 3, |
| // Sue (weight 130 - skipping weight 100, 110, 120) |
| {key: objectStoreData[3].value.weight, |
| value: objectStoreData[3].value, |
| primaryKey: objectStoreData[3].key}, |
| "weight").onsuccess = testAdvanceIndexPrev; |
| } |
| |
| function testAdvanceIndexPrev() |
| { |
| debug("testAdvanceIndexPrev()"); |
| makeAdvanceTest(0, "'prev'", 3, |
| // Joe (weight 150 - skipping 180, 180, 180) |
| {key: objectStoreData[4].value.weight, |
| value: objectStoreData[4].value, |
| primaryKey: objectStoreData[4].key}, |
| "weight").onsuccess = testAdvanceIndexPrevNoDupe; |
| } |
| |
| function testAdvanceIndexPrevNoDupe() |
| { |
| debug("testAdvanceIndexPrevNoDupe()"); |
| makeAdvanceTest(0, "'prevunique'", 3, |
| // Bob (weight 120 - skipping weights 180, 150, 130) |
| {key: objectStoreData[0].value.weight, |
| value: objectStoreData[0].value, |
| primaryKey: objectStoreData[0].key}, |
| "weight").onsuccess = testAdvanceToEnd; |
| } |
| |
| function testAdvanceToEnd() |
| { |
| debug("testAdvanceToEnd()"); |
| makeAdvanceTest(0, null, 100, null) |
| .onsuccess = testPrefetchInRange; |
| } |
| |
| // Make sure the prefetching that exists on some platforms (chromium) |
| // doesn't mess with advance(), or vice versa. |
| function testPrefetchInRange() |
| { |
| debug("testPrefetchInRange()"); |
| var kPrefetchContinueThreshold = 2; |
| evalAndLog("trans = db.transaction(objectStoreName)"); |
| objectStore = evalAndLog("objectStore = trans.objectStore(objectStoreName)"); |
| |
| evalAndLog("request = objectStore.openCursor()"); |
| |
| var currentPos = 0; |
| function prefetch(evt) |
| { |
| preamble(evt); |
| cursor = event.target.result; |
| |
| if (!cursor) { |
| testPrefetchOutOfRange(); |
| return; |
| } |
| |
| runTest(cursor, {key: objectStoreData[currentPos].key, |
| value: objectStoreData[currentPos].value, |
| primaryKey: objectStoreData[currentPos].key}); |
| |
| // force some prefetching, |
| if (currentPos < (kPrefetchContinueThreshold+1)) { |
| evalAndLog("cursor.continue()"); |
| currentPos++; |
| } else if (currentPos == (kPrefetchContinueThreshold+1)) { |
| // stay within the prefetch range |
| evalAndLog("cursor.advance(2)"); |
| currentPos += 2; |
| } else { |
| // we're just past the threshold |
| evalAndLog("cursor.continue()"); |
| currentPos++; |
| } |
| } |
| request.onsuccess = prefetch; |
| request.onerror = unexpectedErrorCallback; |
| } |
| |
| // Make sure the prefetching that exists on some platforms (chromium) |
| // doesn't mess with advance(), or vice versa. |
| function testPrefetchOutOfRange() |
| { |
| debug("testPrefetchOutOfRange()"); |
| var kPrefetchContinueThreshold = 2; |
| evalAndLog("trans = db.transaction(objectStoreName)"); |
| objectStore = evalAndLog("objectStore = trans.objectStore(objectStoreName)"); |
| |
| evalAndLog("request = objectStore.openCursor()"); |
| |
| var currentPos = 0; |
| function prefetch(evt) |
| { |
| preamble(evt); |
| cursor = event.target.result; |
| |
| if (!cursor) { |
| testBadAdvance(); |
| return; |
| } |
| |
| runTest(cursor, {key: objectStoreData[currentPos].key, |
| value: objectStoreData[currentPos].value, |
| primaryKey: objectStoreData[currentPos].key}); |
| |
| // force some prefetching, |
| if (currentPos < (kPrefetchContinueThreshold+1)) { |
| evalAndLog("cursor.continue()"); |
| currentPos++; |
| } else if (currentPos == (kPrefetchContinueThreshold+1)) { |
| // advance past the prefetch range |
| evalAndLog("cursor.advance(7)"); |
| currentPos += 7; |
| } else { |
| // we're past the threshold |
| evalAndLog("cursor.continue()"); |
| currentPos++; |
| } |
| } |
| request.onsuccess = prefetch; |
| request.onerror = unexpectedErrorCallback; |
| } |
| |
| function testBadAdvance() |
| { |
| debug("testBadAdvance()"); |
| evalAndLog("trans = db.transaction(objectStoreName, 'readwrite')"); |
| objectStore = evalAndLog("objectStore = trans.objectStore(objectStoreName)"); |
| |
| evalAndLog("request = objectStore.openCursor()"); |
| |
| function advanceBadly(evt) |
| { |
| preamble(evt); |
| cursor = event.target.result; |
| |
| evalAndExpectExceptionClass("cursor.advance(0)", "TypeError"); |
| evalAndExpectExceptionClass("cursor.advance(-1)", "TypeError"); |
| evalAndExpectExceptionClass("cursor.advance(0x100000000)", "TypeError"); |
| evalAndExpectExceptionClass("cursor.advance(0x20000000000000)", "TypeError"); |
| testEdges(); |
| } |
| request.onsuccess = advanceBadly; |
| request.onerror = unexpectedErrorCallback; |
| } |
| |
| function testEdges() |
| { |
| preamble(); |
| evalAndLog("trans = db.transaction(objectStoreName, 'readonly')"); |
| trans.onabort = unexpectedAbortCallback; |
| |
| objectStore = evalAndLog("objectStore = trans.objectStore(objectStoreName)"); |
| evalAndLog("request = objectStore.openCursor()"); |
| request.onerror = unexpectedErrorCallback; |
| |
| firstSuccess = true; |
| request.onsuccess = function onSuccess(evt) { |
| preamble(evt); |
| evalAndLog("cursor = event.target.result"); |
| if (firstSuccess) { |
| shouldBeNonNull("cursor"); |
| firstSuccess = false; |
| evalAndLog("cursor.advance(0xffffffff)"); |
| } else { |
| shouldBeNull("cursor"); |
| } |
| }; |
| |
| trans.oncomplete = testDelete; |
| } |
| |
| function testDelete() |
| { |
| debug("testDelete()"); |
| evalAndLog("trans = db.transaction(objectStoreName, 'readwrite')"); |
| objectStore = evalAndLog("objectStore = trans.objectStore(objectStoreName)"); |
| |
| evalAndLog("request = objectStore.openCursor()"); |
| |
| var currentPos = 0; |
| function deleteSecond(evt) |
| { |
| preamble(evt); |
| cursor = event.target.result; |
| |
| if (!cursor) { |
| finishJSTest(); |
| return; |
| } |
| |
| runTest(cursor, {key: objectStoreData[currentPos].key, |
| value: objectStoreData[currentPos].value, |
| primaryKey: objectStoreData[currentPos].key}); |
| |
| |
| // this is in the middle of the data, so it will test validity |
| if (currentPos == 2) { |
| evalAndLog("cursor.delete()"); |
| cursor.advance(4); |
| currentPos += 4; |
| } else { |
| evalAndLog("cursor.advance(1)"); |
| currentPos++; |
| } |
| |
| } |
| request.onsuccess = deleteSecond; |
| request.onerror = unexpectedErrorCallback; |
| } |