summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/IndexedDB/key-conversion-exceptions.htm
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/IndexedDB/key-conversion-exceptions.htm')
-rw-r--r--testing/web-platform/tests/IndexedDB/key-conversion-exceptions.htm199
1 files changed, 199 insertions, 0 deletions
diff --git a/testing/web-platform/tests/IndexedDB/key-conversion-exceptions.htm b/testing/web-platform/tests/IndexedDB/key-conversion-exceptions.htm
new file mode 100644
index 0000000000..9fdab58eb1
--- /dev/null
+++ b/testing/web-platform/tests/IndexedDB/key-conversion-exceptions.htm
@@ -0,0 +1,199 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>IndexedDB: Exceptions thrown during key conversion</title>
+<meta name=timeout content=long>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/support.js"></script>
+<script>
+
+// Convenience function for tests that only need to run code in onupgradeneeded.
+function indexeddb_upgrade_only_test(upgrade_callback, description) {
+ indexeddb_test(upgrade_callback, t => { t.done(); }, description);
+}
+
+// Key that throws during conversion.
+function throwing_key(name) {
+ var throws = [];
+ throws.length = 1;
+ const err = new Error('throwing from getter');
+ err.name = name;
+ Object.defineProperty(throws, '0', {get: function() {
+ throw err;
+ }, enumerable: true});
+ return [throws, err];
+}
+
+var valid_key = [];
+var invalid_key = {};
+
+// Calls method on receiver with the specified number of args (default 1)
+// and asserts that the method fails appropriately (rethrowing if
+// conversion throws, or DataError if not a valid key), and that
+// the first argument is fully processed before the second argument
+// (if appropriate).
+function check_method(receiver, method, args) {
+ args = args || 1;
+ if (args < 2) {
+ const [key, err] = throwing_key('getter');
+ assert_throws_exactly(err, () => {
+ receiver[method](key);
+ }, 'key conversion with throwing getter should rethrow');
+
+ assert_throws_dom('DataError', () => {
+ receiver[method](invalid_key);
+ }, 'key conversion with invalid key should throw DataError');
+ } else {
+ const [key1, err1] = throwing_key('getter 1');
+ const [key2, err2] = throwing_key('getter 2');
+ assert_throws_exactly(err1, () => {
+ receiver[method](key1, key2);
+ }, 'first key conversion with throwing getter should rethrow');
+
+ assert_throws_dom('DataError', () => {
+ receiver[method](invalid_key, key2);
+ }, 'first key conversion with invalid key should throw DataError');
+
+ assert_throws_exactly(err2, () => {
+ receiver[method](valid_key, key2);
+ }, 'second key conversion with throwing getter should rethrow');
+
+ assert_throws_dom('DataError', () => {
+ receiver[method](valid_key, invalid_key);
+ }, 'second key conversion with invalid key should throw DataError');
+ }
+}
+
+// Static key comparison utility on IDBFactory.
+test(t => {
+ check_method(indexedDB, 'cmp', 2);
+}, 'IDBFactory cmp() static with throwing/invalid keys');
+
+// Continue methods on IDBCursor.
+indexeddb_upgrade_only_test((t, db) => {
+ var store = db.createObjectStore('store');
+ store.put('a', 1).onerror = t.unreached_func('put should succeed');
+
+ var request = store.openCursor();
+ request.onerror = t.unreached_func('openCursor should succeed');
+ request.onsuccess = t.step_func(() => {
+ var cursor = request.result;
+ assert_not_equals(cursor, null, 'cursor should find a value');
+ check_method(cursor, 'continue');
+ });
+}, 'IDBCursor continue() method with throwing/invalid keys');
+
+indexeddb_upgrade_only_test((t, db) => {
+ var store = db.createObjectStore('store');
+ var index = store.createIndex('index', 'prop');
+ store.put({prop: 'a'}, 1).onerror = t.unreached_func('put should succeed');
+
+ var request = index.openCursor();
+ request.onerror = t.unreached_func('openCursor should succeed');
+ request.onsuccess = t.step_func(() => {
+ var cursor = request.result;
+ assert_not_equals(cursor, null, 'cursor should find a value');
+
+ check_method(cursor, 'continuePrimaryKey', 2);
+ });
+}, null, 'IDBCursor continuePrimaryKey() method with throwing/invalid keys');
+
+// Mutation methods on IDBCursor.
+indexeddb_upgrade_only_test((t, db) => {
+ var store = db.createObjectStore('store', {keyPath: 'prop'});
+ store.put({prop: 1}).onerror = t.unreached_func('put should succeed');
+
+ var request = store.openCursor();
+ request.onerror = t.unreached_func('openCursor should succeed');
+ request.onsuccess = t.step_func(() => {
+ var cursor = request.result;
+ assert_not_equals(cursor, null, 'cursor should find a value');
+
+ var value = {};
+ var err;
+ [value.prop, err] = throwing_key('getter');
+ assert_throws_exactly(err, () => {
+ cursor.update(value);
+ }, 'throwing getter should rethrow during clone');
+
+ // Throwing from the getter during key conversion is
+ // not possible since (1) a clone is used, (2) only own
+ // properties are cloned, and (3) only own properties
+ // are used for key path evaluation.
+
+ value.prop = invalid_key;
+ assert_throws_dom('DataError', () => {
+ cursor.update(value);
+ }, 'key conversion with invalid key should throw DataError');
+ });
+}, 'IDBCursor update() method with throwing/invalid keys');
+
+// Static constructors on IDBKeyRange
+['only', 'lowerBound', 'upperBound'].forEach(method => {
+ test(t => {
+ check_method(IDBKeyRange, method);
+ }, 'IDBKeyRange ' + method + '() static with throwing/invalid keys');
+});
+
+test(t => {
+ check_method(IDBKeyRange, 'bound', 2);
+}, 'IDBKeyRange bound() static with throwing/invalid keys');
+
+// Insertion methods on IDBObjectStore.
+['add', 'put'].forEach(method => {
+ indexeddb_upgrade_only_test((t, db) => {
+ var out_of_line = db.createObjectStore('out-of-line keys');
+ var in_line = db.createObjectStore('in-line keys', {keyPath: 'prop'});
+ var [key, err] = throwing_key('getter');
+ assert_throws_exactly(err, () => {
+ out_of_line[method]('value', key);
+ }, 'key conversion with throwing getter should rethrow');
+
+ assert_throws_dom('DataError', () => {
+ out_of_line[method]('value', invalid_key);
+ }, 'key conversion with invalid key should throw DataError');
+
+ var value = {};
+ [value.prop, err] = throwing_key('getter');
+ assert_throws_exactly(err, () => {
+ in_line[method](value);
+ }, 'throwing getter should rethrow during clone');
+
+ // Throwing from the getter during key conversion is
+ // not possible since (1) a clone is used, (2) only own
+ // properties are cloned, and (3) only own properties
+ // are used for key path evaluation.
+
+ value.prop = invalid_key;
+ assert_throws_dom('DataError', () => {
+ in_line[method](value);
+ }, 'key conversion with invalid key should throw DataError');
+ }, `IDBObjectStore ${method}() method with throwing/invalid keys`);
+});
+
+// Generic (key-or-key-path) methods on IDBObjectStore.
+[
+ 'delete', 'get', 'getKey', 'getAll', 'getAllKeys', 'count', 'openCursor',
+ 'openKeyCursor'
+].forEach(method => {
+ indexeddb_upgrade_only_test((t, db) => {
+ var store = db.createObjectStore('store');
+
+ check_method(store, method);
+ }, `IDBObjectStore ${method}() method with throwing/invalid keys`);
+});
+
+// Generic (key-or-key-path) methods on IDBIndex.
+[
+ 'get', 'getKey', 'getAll', 'getAllKeys', 'count', 'openCursor',
+ 'openKeyCursor'
+].forEach(method => {
+ indexeddb_upgrade_only_test((t, db) => {
+ var store = db.createObjectStore('store');
+ var index = store.createIndex('index', 'keyPath');
+
+ check_method(index, method);
+ }, `IDBIndex ${method}() method with throwing/invalid keys`);
+});
+
+</script>