https://github.com/web-platform-tests/wpt
Raw File
Tip revision: e7a74e0f25307a8000cd281d8214be233981187b authored by Joanmarie Diggs on 11 April 2018, 17:02:30 UTC
accname: Updated tests
Tip revision: e7a74e0
keypath-exceptions.htm
<!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="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');
    assert_throws({name: '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'
);

function throws(name) {
  return () => {
    const err = Error();
    err.name = name;
    throw err;
  };
}

indexeddb_test(
  function(t, db) {
    const o = {};
    Object.defineProperty(o, 'throws', {get: throws('getter'),
        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('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('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: throws('getter'),
        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({name: 'getter'}, () => {
      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({name: 'getter'}, () => {
      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({name: 'getter'}, () => {
      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({name: 'getter'}, () => {
      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: throws('getter'),
          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('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('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: throws('getter'),
          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('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('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');

    const array = [];
    array[99] = 1;

    let getter_called = 0;
    const prop = '50';
    Object.defineProperty(Object.prototype, prop, {
      enumerable: true, configurable: true,
      get: () => {
        ++getter_called;
        return 'foo';
      },
    });

    const request = 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');
      delete Object.prototype[prop];
      t.done();
    });
  },
  'Array key conversion should not invoke prototype getters'
);

</script>
back to top