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;
}