summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/IndexedDB/resources/nested-cloning-common.js
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/IndexedDB/resources/nested-cloning-common.js')
-rw-r--r--testing/web-platform/tests/IndexedDB/resources/nested-cloning-common.js211
1 files changed, 211 insertions, 0 deletions
diff --git a/testing/web-platform/tests/IndexedDB/resources/nested-cloning-common.js b/testing/web-platform/tests/IndexedDB/resources/nested-cloning-common.js
new file mode 100644
index 0000000000..db5f710ceb
--- /dev/null
+++ b/testing/web-platform/tests/IndexedDB/resources/nested-cloning-common.js
@@ -0,0 +1,211 @@
+'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) => {
+ 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 });
+}