diff options
Diffstat (limited to 'testing/web-platform/tests/IndexedDB/key-conversion-exceptions.htm')
-rw-r--r-- | testing/web-platform/tests/IndexedDB/key-conversion-exceptions.htm | 199 |
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> |