Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

/**
* Any copyright is dedicated to the Public Domain.
*/
/* exported testGenerator */
var testGenerator = testSteps();
// helper function that ensures that ArrayBuffer instances are meaningfully
// displayed (not just as 'object ArrayBuffer')
// TODO better move to helpers.js?
function showKey(key) {
if (key instanceof Array) {
return key.map(x => showKey(x)).toString();
}
if (key instanceof ArrayBuffer) {
return "ArrayBuffer([" + new Uint8Array(key).toString() + "])";
}
return key.toString();
}
function* testSteps() {
const dbname = this.window ? window.location.pathname : "Splendid Test";
let openRequest = indexedDB.open(dbname, 1);
openRequest.onerror = errorHandler;
openRequest.onupgradeneeded = grabEventAndContinueHandler;
openRequest.onsuccess = unexpectedSuccessHandler;
let event = yield undefined;
let db = event.target.result;
// Create test stores
let store = db.createObjectStore("store");
let enc = new TextEncoder();
// Test simple inserts
// Note: the keys must be in order
var keys = [
-1 / 0,
-1.7e308,
-10000,
-2,
-1.5,
-1,
-1.00001e-200,
-1e-200,
0,
1e-200,
1.00001e-200,
1,
2,
10000,
1.7e308,
1 / 0,
new Date("1750-01-02"),
new Date("1800-12-31T12:34:56.001"),
new Date(-1000),
new Date(-10),
new Date(-1),
new Date(0),
new Date(1),
new Date(2),
new Date(1000),
new Date("1971-01-01"),
new Date("1971-01-01T01:01:01Z"),
new Date("1971-01-01T01:01:01.001Z"),
new Date("1971-01-01T01:01:01.01Z"),
new Date("1971-01-01T01:01:01.1Z"),
new Date("1980-02-02"),
new Date("3333-03-19T03:33:33.333"),
"",
"\x00",
"\x00\x00",
"\x00\x01",
"\x01",
"\x02",
"\x03",
"\x04",
"\x07",
"\x08",
"\x0F",
"\x10",
"\x1F",
"\x20",
"01234",
"\x3F",
"\x40",
"A",
"A\x00",
"A1",
"ZZZZ",
"a",
"a\x00",
"aa",
"azz",
"}",
"\x7E",
"\x7F",
"\x80",
"\xFF",
"\u0100",
"\u01FF",
"\u0200",
"\u03FF",
"\u0400",
"\u07FF",
"\u0800",
"\u0FFF",
"\u1000",
"\u1FFF",
"\u2000",
"\u3FFF",
"\u4000",
"\u7FFF",
"\u8000",
"\uD800",
"\uD800a",
"\uD800\uDC01",
"\uDBFF",
"\uDC00",
"\uDFFF\uD800",
"\uFFFE",
"\uFFFF",
"\uFFFF\x00",
"\uFFFFZZZ",
// Note: enc.encode returns an Uint8Array, which is a valid key, but when
// converting it back and forth, the result will be a plain ArrayBuffer,
// which is expected in comparisons below
// TODO is it ok that the information that the original key was an
// Uint8Array is lost?
new ArrayBuffer(0),
Uint8Array.from([0]).buffer,
Uint8Array.from([0, 0]).buffer,
Uint8Array.from([0, 1]).buffer,
Uint8Array.from([0, 1, 0]).buffer,
enc.encode("abc").buffer,
enc.encode("abcd").buffer,
enc.encode("xyz").buffer,
Uint8Array.from([0x80]).buffer,
[],
[-1 / 0],
[-1],
[0],
[1],
[1, "a"],
[1, []],
[1, [""]],
[2, 3],
[2, 3.0000000000001],
[12, [[]]],
[12, [[[]]]],
[12, [[[""]]]],
[12, [[["foo"]]]],
[12, [[[[[3]]]]]],
[12, [[[[[[3]]]]]]],
[new Date(-1)],
[new Date(1)],
[""],
["", [[]]],
["", [[[]]]],
["abc"],
["abc", "def"],
["abc\x00"],
["abc\x00", "\x00\x01"],
["abc\x00", "\x00def"],
["abc\x00\x00def"],
["x", [[]]],
["x", [[[]]]],
// see comment on scalar ArrayBuffers above
[new ArrayBuffer(0)],
[new ArrayBuffer(0), "abc"],
[new ArrayBuffer(0), new ArrayBuffer(0)],
[new ArrayBuffer(0), enc.encode("abc").buffer],
[enc.encode("abc").buffer],
[enc.encode("abc").buffer, new ArrayBuffer(0)],
[enc.encode("abc").buffer, enc.encode("xyz").buffer],
[enc.encode("xyz").buffer],
[[]],
[[], "foo"],
[[], []],
[[[]]],
[[[]], []],
[[[]], [[]]],
[[[]], [[1]]],
[[[]], [[[]]]],
[[[1]]],
[[[[]], []]],
];
for (var i = 0; i < keys.length; ++i) {
let keyI = keys[i];
is(indexedDB.cmp(keyI, keyI), 0, i + " compared to self");
function doCompare(keyI) {
for (var j = i - 1; j >= i - 10 && j >= 0; --j) {
is(indexedDB.cmp(keyI, keys[j]), 1, i + " compared to " + j);
is(indexedDB.cmp(keys[j], keyI), -1, j + " compared to " + i);
}
}
doCompare(keyI);
store.add(i, keyI).onsuccess = function (e) {
is(
indexedDB.cmp(e.target.result, keyI),
0,
"Returned key should cmp as equal; index = " +
i +
", input = " +
showKey(keyI) +
", returned = " +
showKey(e.target.result)
);
ok(
compareKeys(e.target.result, keyI),
"Returned key should actually be equal; index = " +
i +
", input = " +
showKey(keyI) +
", returned = " +
showKey(e.target.result)
);
};
// Test that -0 compares the same as 0
if (keyI === 0) {
doCompare(-0);
let req = store.add(i, -0);
req.addEventListener("error", new ExpectError("ConstraintError", true));
req.onsuccess = unexpectedSuccessHandler;
yield undefined;
} else if (Array.isArray(keyI) && keyI.length === 1 && keyI[0] === 0) {
doCompare([-0]);
let req = store.add(i, [-0]);
req.addEventListener("error", new ExpectError("ConstraintError", true));
req.onsuccess = unexpectedSuccessHandler;
yield undefined;
}
}
store.openCursor().onsuccess = grabEventAndContinueHandler;
for (i = 0; i < keys.length; ++i) {
event = yield undefined;
let cursor = event.target.result;
is(
indexedDB.cmp(cursor.key, keys[i]),
0,
"Read back key should cmp as equal; index = " +
i +
", input = " +
showKey(keys[i]) +
", readBack = " +
showKey(cursor.key)
);
ok(
compareKeys(cursor.key, keys[i]),
"Read back key should actually be equal; index = " +
i +
", input = " +
showKey(keys[i]) +
", readBack = " +
showKey(cursor.key)
);
is(cursor.value, i, "Stored with right value");
cursor.continue();
}
event = yield undefined;
is(event.target.result, null, "no more results expected");
// Note that nan is defined below as '0 / 0'.
var invalidKeys = [
"nan",
"undefined",
"null",
"/x/",
"{}",
"new Date(NaN)",
'new Date("foopy")',
"[nan]",
"[undefined]",
"[null]",
"[/x/]",
"[{}]",
"[new Date(NaN)]",
"[1, nan]",
"[1, undefined]",
"[1, null]",
"[1, /x/]",
"[1, {}]",
"[1, [nan]]",
"[1, [undefined]]",
"[1, [null]]",
"[1, [/x/]]",
"[1, [{}]]",
// ATTENTION, the following key allocates 2GB of memory and might cause
// subtle failures in some environments, see bug 1796753. We might
// want to have some common way between IndexeDB mochitests and
// xpcshell tests how to access AppConstants in order to dynamically
// exclude this key from some environments, rather than disabling the
// entire xpcshell variant of this test for ASAN/TSAN.
"new Uint8Array(2147483647)",
];
function checkInvalidKeyException(ex, i, callText) {
let suffix = ` during ${callText} with invalid key ${i}: ${invalidKeys[i]}`;
// isInstance() is not available in mochitest, and we use this JS also as mochitest.
// eslint-disable-next-line mozilla/use-isInstance
ok(ex instanceof DOMException, "Threw DOMException" + suffix);
is(ex.name, "DataError", "Threw right DOMException" + suffix);
is(ex.code, 0, "Threw with right code" + suffix);
}
for (i = 0; i < invalidKeys.length; ++i) {
let key_fn = Function(
`"use strict"; var nan = 0 / 0; let k = (${invalidKeys[i]}); return k;`
);
let key;
try {
key = key_fn();
} catch (e) {
// If we cannot instantiate the key, we are most likely on a 32 Bit
// platform with insufficient memory. Just skip it.
info("Key instantiation failed, skipping");
continue;
}
try {
indexedDB.cmp(key, 1);
ok(false, "didn't throw");
} catch (ex) {
checkInvalidKeyException(ex, i, "cmp(key, 1)");
}
try {
indexedDB.cmp(1, key);
ok(false, "didn't throw2");
} catch (ex) {
checkInvalidKeyException(ex, i, "cmp(1, key)");
}
try {
store.put(1, key);
ok(false, "didn't throw3");
} catch (ex) {
checkInvalidKeyException(ex, i, "store.put(1, key)");
}
}
openRequest.onsuccess = grabEventAndContinueHandler;
yield undefined;
finishTest();
}