212 lines
7.7 KiB
JavaScript
212 lines
7.7 KiB
JavaScript
'use strict';
|
|
|
|
// Should be large enough to trigger large value handling in the IndexedDB
|
|
// engines that have special code paths for large values.
|
|
const wrapThreshold = 128 * 1024;
|
|
|
|
// Returns an IndexedDB value created from a descriptor.
|
|
//
|
|
// See the bottom of the file for descriptor samples.
|
|
function createValue(descriptor) {
|
|
if (typeof(descriptor) != 'object')
|
|
return descriptor;
|
|
|
|
if (Array.isArray(descriptor))
|
|
return descriptor.map((element) => createValue(element));
|
|
|
|
if (!descriptor.hasOwnProperty('type')) {
|
|
const value = {};
|
|
for (let property of Object.getOwnPropertyNames(descriptor))
|
|
value[property] = createValue(descriptor[property]);
|
|
return value;
|
|
}
|
|
|
|
switch (descriptor.type) {
|
|
case 'blob':
|
|
return new Blob(
|
|
[largeValue(descriptor.size, descriptor.seed)],
|
|
{ type: descriptor.mimeType });
|
|
case 'buffer':
|
|
return largeValue(descriptor.size, descriptor.seed);
|
|
}
|
|
}
|
|
|
|
// Checks an IndexedDB value against a descriptor.
|
|
//
|
|
// Returns a Promise that resolves if the value passes the check.
|
|
//
|
|
// See the bottom of the file for descriptor samples.
|
|
function checkValue(testCase, value, descriptor) {
|
|
if (typeof(descriptor) != 'object') {
|
|
assert_equals(
|
|
descriptor, value,
|
|
'IndexedDB result should match put() argument');
|
|
return Promise.resolve();
|
|
}
|
|
|
|
if (Array.isArray(descriptor)) {
|
|
assert_true(
|
|
Array.isArray(value),
|
|
'IndexedDB result type should match put() argument');
|
|
assert_equals(
|
|
descriptor.length, value.length,
|
|
'IndexedDB result array size should match put() argument');
|
|
|
|
const subChecks = [];
|
|
for (let i = 0; i < descriptor.length; ++i)
|
|
subChecks.push(checkValue(testCase, value[i], descriptor[i]));
|
|
return Promise.all(subChecks);
|
|
}
|
|
|
|
if (!descriptor.hasOwnProperty('type')) {
|
|
assert_array_equals(
|
|
Object.getOwnPropertyNames(value).sort(),
|
|
Object.getOwnPropertyNames(descriptor).sort(),
|
|
'IndexedDB result object properties should match put() argument');
|
|
const subChecks = [];
|
|
return Promise.all(Object.getOwnPropertyNames(descriptor).map(property =>
|
|
checkValue(testCase, value[property], descriptor[property])));
|
|
}
|
|
|
|
switch (descriptor.type) {
|
|
case 'blob':
|
|
assert_class_string(
|
|
value, 'Blob',
|
|
'IndexedDB result class should match put() argument');
|
|
assert_equals(
|
|
descriptor.mimeType, value.type,
|
|
'IndexedDB result Blob MIME type should match put() argument');
|
|
assert_equals(descriptor.size, value.size, 'incorrect Blob size');
|
|
return new Promise((resolve, reject) => {
|
|
const reader = new FileReader();
|
|
reader.onloadend = testCase.step_func(() => {
|
|
if (reader.error) {
|
|
reject(reader.error);
|
|
return;
|
|
}
|
|
const view = new Uint8Array(reader.result);
|
|
assert_equals(
|
|
view.join(','),
|
|
largeValue(descriptor.size, descriptor.seed).join(','),
|
|
'IndexedDB result Blob content should match put() argument');
|
|
resolve();
|
|
});
|
|
reader.readAsArrayBuffer(value);
|
|
});
|
|
|
|
case 'buffer':
|
|
assert_class_string(
|
|
value, 'Uint8Array',
|
|
'IndexedDB result type should match put() argument');
|
|
assert_equals(
|
|
value.join(','),
|
|
largeValue(descriptor.size, descriptor.seed).join(','),
|
|
'IndexedDB result typed array content should match put() argument');
|
|
return Promise.resolve();
|
|
}
|
|
}
|
|
|
|
function cloningTestInternal(label, valueDescriptors, options) {
|
|
promise_test(testCase => {
|
|
return createDatabase(testCase, (database, transaction) => {
|
|
testCase.add_cleanup(() => database.close());
|
|
let store;
|
|
if (options.useKeyGenerator) {
|
|
store = database.createObjectStore(
|
|
'test-store', { keyPath: 'primaryKey', autoIncrement: true });
|
|
} else {
|
|
store = database.createObjectStore('test-store');
|
|
}
|
|
for (let i = 0; i < valueDescriptors.length; ++i) {
|
|
if (options.useKeyGenerator) {
|
|
store.put(createValue(valueDescriptors[i]));
|
|
} else {
|
|
store.put(createValue(valueDescriptors[i]), i + 1);
|
|
}
|
|
}
|
|
}).then(database => {
|
|
const transaction = database.transaction(['test-store'], 'readonly');
|
|
const store = transaction.objectStore('test-store');
|
|
const subChecks = [];
|
|
let resultIndex = 0;
|
|
for (let i = 0; i < valueDescriptors.length; ++i) {
|
|
subChecks.push(new Promise((resolve, reject) => {
|
|
const requestIndex = i;
|
|
const primaryKey = requestIndex + 1;
|
|
const request = store.get(primaryKey);
|
|
request.onerror =
|
|
testCase.step_func(() => { reject(request.error); });
|
|
request.onsuccess = testCase.step_func(() => {
|
|
assert_equals(
|
|
resultIndex, requestIndex,
|
|
'IDBRequest success events should be fired in request order');
|
|
++resultIndex;
|
|
|
|
const result = request.result;
|
|
if (options.useKeyGenerator) {
|
|
assert_equals(
|
|
result.primaryKey, primaryKey,
|
|
'IndexedDB result should have auto-incremented primary key');
|
|
delete result.primaryKey;
|
|
}
|
|
resolve(checkValue(
|
|
testCase, result, valueDescriptors[requestIndex]));
|
|
});
|
|
}));
|
|
}
|
|
|
|
subChecks.push(new Promise((resolve, reject) => {
|
|
const requestIndex = valueDescriptors.length;
|
|
const request = store.getAll();
|
|
request.onerror =
|
|
testCase.step_func(() => { reject(request.error); });
|
|
request.onsuccess = testCase.step_func(() => {
|
|
assert_equals(
|
|
resultIndex, requestIndex,
|
|
'IDBRequest success events should be fired in request order');
|
|
++resultIndex;
|
|
const result = request.result;
|
|
if (options.useKeyGenerator) {
|
|
for (let i = 0; i < valueDescriptors.length; ++i) {
|
|
const primaryKey = i + 1;
|
|
assert_equals(
|
|
result[i].primaryKey, primaryKey,
|
|
'IndexedDB result should have auto-incremented primary key');
|
|
delete result[i].primaryKey;
|
|
}
|
|
}
|
|
resolve(checkValue(testCase, result, valueDescriptors));
|
|
});
|
|
}));
|
|
|
|
return Promise.all(subChecks);
|
|
});
|
|
}, label);
|
|
}
|
|
|
|
// Performs a series of put()s and verifies that get()s and getAll() match.
|
|
//
|
|
// Each element of the valueDescriptors array is fed into createValue(), and the
|
|
// resulting value is written to IndexedDB via a put() request. After the writes
|
|
// complete, the values are read in the same order in which they were written.
|
|
// Last, all the results are read one more time via a getAll().
|
|
//
|
|
// The test verifies that the get() / getAll() results match the arguments to
|
|
// put() and that the order in which the get() result events are fired matches
|
|
// the order of the get() requests.
|
|
function cloningTest(label, valueDescriptors) {
|
|
cloningTestInternal(label, valueDescriptors, { useKeyGenerator: false });
|
|
}
|
|
|
|
// cloningTest, with coverage for key generators.
|
|
//
|
|
// This creates two tests. One test performs a series of put()s and verifies
|
|
// that get()s and getAll() match, exactly like cloningTestWithoutKeyGenerator.
|
|
// The other test performs the same put()s in an object store with a key
|
|
// generator, and checks that the key generator works properly.
|
|
function cloningTestWithKeyGenerator(label, valueDescriptors) {
|
|
cloningTestInternal(label, valueDescriptors, { useKeyGenerator: false });
|
|
cloningTestInternal(
|
|
label + " with key generator", valueDescriptors,
|
|
{ useKeyGenerator: true });
|
|
}
|