summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/IndexedDB/keypath-exceptions.htm
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/IndexedDB/keypath-exceptions.htm')
-rw-r--r--testing/web-platform/tests/IndexedDB/keypath-exceptions.htm281
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>