diff options
Diffstat (limited to 'testing/web-platform/tests/IndexedDB/keypath-exceptions.htm')
-rw-r--r-- | testing/web-platform/tests/IndexedDB/keypath-exceptions.htm | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/testing/web-platform/tests/IndexedDB/keypath-exceptions.htm b/testing/web-platform/tests/IndexedDB/keypath-exceptions.htm new file mode 100644 index 0000000000..c23d4d2268 --- /dev/null +++ b/testing/web-platform/tests/IndexedDB/keypath-exceptions.htm @@ -0,0 +1,281 @@ +<!doctype html> +<meta charset=utf-8> +<title>IndexedDB: Exceptions in extracting keys from values (ES bindings)</title> +<meta name="help" href="https://w3c.github.io/IndexedDB/#extract-key-from-value"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="resources/support.js"></script> +<script> + +indexeddb_test( + (t, db) => { + db.createObjectStore('store', {autoIncrement: true, keyPath: 'a.b.c'}); + }, + (t, db) => { + const tx = db.transaction('store', 'readwrite', {durability: 'relaxed'}); + assert_throws_dom('DataError', () => { + tx.objectStore('store').put({a: {b: "foo"}}); + }, 'Put should throw if key can not be inserted at key path location.'); + t.done(); + }, + 'The last element of keypath is validated' +); + +const err = Error(); +err.name = 'getter'; + +function throwingGetter() { + throw err; +} + +indexeddb_test( + function(t, db) { + const o = {}; + Object.defineProperty(o, 'throws', {get: throwingGetter, + enumerable: false, configurable: true}); + + // Value should be cloned before key path is evaluated, + // and non-enumerable getter will be ignored. The clone + // will have no such property, so key path evaluation + // will fail. + const s1 = db.createObjectStore('s1', {keyPath: 'throws'}); + assert_throws_dom('DataError', () => { + s1.put(o); + }, 'Key path failing to resolve should throw'); + + // Value should be cloned before key path is evaluated, + // and non-enumerable getter will be ignored. The clone + // will have no such property, so key path evaluation + // will fail. + const s2 = db.createObjectStore('s2', {keyPath: 'throws.x'}); + assert_throws_dom('DataError', () => { + s2.put(o); + }, 'Key path failing to resolve should throw'); + + // Value should be cloned before key path is evaluated, + // and non-enumerable getter will be ignored. The clone + // will have no such property, so generated key can be + // inserted. + const s3 = db.createObjectStore('s3', + {keyPath: 'throws', autoIncrement: true}); + assert_class_string(s3.put(o), 'IDBRequest', + 'Key injectability test at throwing getter should succeed'); + + // Value should be cloned before key path is evaluated, + // and non-enumerable getter will be ignored. The clone + // will have no such property, so intermediate object + // and generated key can be inserted. + const s4 = db.createObjectStore('s4', + {keyPath: 'throws.x', autoIncrement: true}); + assert_class_string(s4.put(o), 'IDBRequest', + 'Key injectability test past throwing getter should succeed'); + }, + (t, db) => { + t.done(); + }, + 'Key path evaluation: Exceptions from non-enumerable getters' +); + +indexeddb_test( + function(t, db) { + const o = {}; + Object.defineProperty(o, 'throws', {get: throwingGetter, + enumerable: true, configurable: true}); + + // Value should be cloned before key path is evaluated, + // and enumerable getter will rethrow. + const s1 = db.createObjectStore('s1', {keyPath: 'throws'}); + assert_throws_exactly(err, () => { + s1.put(o); + }, 'Key path resolving to throwing getter rethrows'); + + // Value should be cloned before key path is evaluated, + // and enumerable getter will rethrow. + const s2 = db.createObjectStore('s2', {keyPath: 'throws.x'}); + assert_throws_exactly(err, () => { + s2.put(o); + }, 'Key path resolving past throwing getter rethrows'); + + // Value should be cloned before key path is evaluated, + // and enumerable getter will rethrow. + const s3 = db.createObjectStore('s3', + {keyPath: 'throws', autoIncrement: true}); + assert_throws_exactly(err, () => { + s3.put(o); + }, 'Key injectability test at throwing getter should rethrow'); + + // Value should be cloned before key path is evaluated, + // and enumerable getter will rethrow. + const s4 = db.createObjectStore('s4', + {keyPath: 'throws.x', autoIncrement: true}); + assert_throws_exactly(err, () => { + s4.put(o); + }, 'Key injectability test past throwing getter should rethrow'); + }, + (t, db) => { + t.done(); + }, + 'Key path evaluation: Exceptions from enumerable getters' +); + +indexeddb_test( + (t, db) => { + // Implemented as function wrapper to clean up + // immediately after use, otherwise it may + // interfere with the test harness. + function with_proto_getter(f) { + return function() { + Object.defineProperty(Object.prototype, 'throws', { + get: throwingGetter, + enumerable: false, configurable: true + }); + try { + f(); + } finally { + delete Object.prototype['throws']; + } + }; + } + + // Value should be cloned before key path is evaluated, + // and non-enumerable getter will be ignored. The clone + // will have no own property, so key path evaluation will + // fail and DataError should be thrown. + const s1 = db.createObjectStore('s1', {keyPath: 'throws'}); + assert_throws_dom('DataError', with_proto_getter(function() { + s1.put({}); + }), 'Key path resolving to no own property throws DataError'); + + // Value should be cloned before key path is evaluated, + // and non-enumerable getter will be ignored. The clone + // will have no own property, so key path evaluation will + // fail and DataError should be thrown. + const s2 = db.createObjectStore('s2', {keyPath: 'throws.x'}); + assert_throws_dom('DataError', with_proto_getter(function() { + s2.put({}); + }), 'Key path resolving past no own property throws DataError'); + + // Value should be cloned before key path is evaluated, + // and non-enumerable getter will be ignored. The clone + // will have no own property, so key path evaluation will + // fail and injection can succeed. + const s3 = db.createObjectStore('s3', + {keyPath: 'throws', autoIncrement: true}); + assert_equals(s3.put({}).readyState, 'pending', + 'put should not throw due to inherited property'); + + // Value should be cloned before key path is evaluated, + // and non-enumerable getter will be ignored. The clone + // will have no own property, so key path evaluation will + // fail and injection can succeed. + const s4 = db.createObjectStore('s4', + {keyPath: 'throws.x', autoIncrement: true}); + assert_equals(s4.put({}).readyState, 'pending', + 'put should not throw due to inherited property'); + }, + (t, db) => { + t.done(); + }, + 'Key path evaluation: Exceptions from non-enumerable getters on prototype' +); + +indexeddb_test( + (t, db) => { + // Implemented as function wrapper to clean up + // immediately after use, otherwise it may + // interfere with the test harness. + function with_proto_getter(f) { + return () => { + Object.defineProperty(Object.prototype, 'throws', { + get: throwingGetter, + enumerable: true, configurable: true + }); + try { + f(); + } finally { + delete Object.prototype['throws']; + } + }; + } + + // Value should be cloned before key path is evaluated. + // The clone will have no own property, so key path + // evaluation will fail and DataError should be thrown. + const s1 = db.createObjectStore('s1', {keyPath: 'throws'}); + assert_throws_dom('DataError', with_proto_getter(function() { + s1.put({}); + }), 'Key path resolving to no own property throws DataError'); + + // Value should be cloned before key path is evaluated. + // The clone will have no own property, so key path + // evaluation will fail and DataError should be thrown. + const s2 = db.createObjectStore('s2', {keyPath: 'throws.x'}); + assert_throws_dom('DataError', with_proto_getter(function() { + s2.put({}); + }), 'Key path resolving past throwing getter rethrows'); + + // Value should be cloned before key path is evaluated. + // The clone will have no own property, so key path + // evaluation will fail and injection can succeed. + var s3 = db.createObjectStore('s3', + {keyPath: 'throws', autoIncrement: true}); + assert_equals(s3.put({}).readyState, 'pending', + 'put should not throw due to inherited property'); + + // Value should be cloned before key path is evaluated. + // The clone will have no own property, so key path + // evaluation will fail and injection can succeed. + var s4 = db.createObjectStore('s4', + {keyPath: 'throws.x', autoIncrement: true}); + assert_equals(s4.put({}).readyState, 'pending', + 'put should not throw due to inherited property'); + }, + (t, db) => { + t.done(); + }, + 'Key path evaluation: Exceptions from enumerable getters on prototype' +); + +indexeddb_test( + (t, db) => { + const store = db.createObjectStore('store'); + store.createIndex('index', 'index0'); + }, + (t, db) => { + const tx = db.transaction('store', 'readwrite', {durability: 'relaxed'}); + + const array = []; + array[99] = 1; + + // Implemented as function wrapper to clean up + // immediately after use, otherwise it may + // interfere with the test harness. + let getter_called = 0; + function with_proto_getter(f) { + const prop = '50'; + Object.defineProperty(Object.prototype, prop, { + enumerable: true, configurable: true, + get: () => { + ++getter_called; + return 'foo'; + } + }); + try { + return f(); + } finally { + delete Object.prototype[prop]; + } + } + + const request = with_proto_getter( + () => tx.objectStore('store').put({index0: array}, 'key')); + request.onerror = t.unreached_func('put should not fail'); + request.onsuccess = t.step_func(function() { + assert_equals(getter_called, 0, 'Prototype getter should not be called'); + t.done(); + }); + }, + 'Array key conversion should not invoke prototype getters' +); + +</script> |