tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

keygenerator.any.js (13091B)


      1 // META: global=window,worker
      2 // META: script=resources/support.js
      3 
      4 'use strict';
      5 
      6 function keygenerator(objects, expected_keys, desc, func) {
      7    let db;
      8    let t = async_test("Keygenerator" + " - " + desc);
      9    let open_rq = createdb(t);
     10    open_rq.onupgradeneeded = function(e) {
     11        db = e.target.result;
     12        let objStore = db.createObjectStore("store", { keyPath: "id", autoIncrement: true });
     13        for (let i = 0; i < objects.length; i++)
     14        {
     15            if (objects[i] === null)
     16                objStore.add({});
     17            else
     18                objStore.add({ id: objects[i] });
     19        }
     20    };
     21 
     22    open_rq.onsuccess = function(e) {
     23        let actual_keys = [];
     24        let rq = db.transaction("store", "readonly")
     25                  .objectStore("store")
     26                  .openCursor();
     27        rq.onsuccess = t.step_func(function(e) {
     28            let cursor = e.target.result;
     29            if (cursor) {
     30                actual_keys.push(cursor.key.valueOf());
     31                cursor.continue();
     32            }
     33            else {
     34                assert_key_equals(actual_keys, expected_keys, "keygenerator array - " + desc);
     35                t.done();
     36            }
     37        });
     38    };
     39 }
     40 keygenerator([null, null, null, null],  [1, 2, 3, 4],
     41    "starts at one, and increments by one");
     42 
     43 keygenerator([2, null, 5, null, 6.66, 7],  [2, 3, 5, 6, 6.66, 7],
     44    "increments by one from last set key");
     45 
     46 keygenerator([-10, null, "6", 6.3, [10], -2, 4, null],   [-10, -2, 1, 4, 6.3, 7, "6", [10]],
     47    "don't increment when new key is not bigger than current");
     48 
     49 async_test(t => {
     50    let db;
     51    let objects = [1, null, { id: 2 }, null, 2.00001, 5, null, { id: 6 }];
     52    let expected = [1, 2, 2.00001, 3, 5, 6];
     53    let errors = 0;
     54    let open_rq = createdb(t);
     55    open_rq.onupgradeneeded = function(e) {
     56        db = e.target.result;
     57        let objStore = db.createObjectStore("store", { keyPath: "id", autoIncrement: true });
     58 
     59        for (let i = 0; i < objects.length; i++)
     60        {
     61            if (objects[i] === null)
     62            {
     63                objStore.add({});
     64            }
     65            else if (typeof objects[i] === "object")
     66            {
     67                let rq = objStore.add(objects[i]);
     68                rq.onerror = t.step_func(function(e) {
     69                    errors++;
     70                    assert_equals(e.target.error.name, "ConstraintError");
     71                    assert_equals(e.type, "error");
     72                    e.stopPropagation();
     73                    e.preventDefault();
     74                });
     75                rq.onsuccess = t.step_func(function(e) {
     76                    assert_unreached("Got rq.success when adding duplicate id " + objects[i]);
     77                });
     78            }
     79            else
     80                objStore.add({ id: objects[i] });
     81        }
     82    };
     83 
     84    open_rq.onsuccess = function(e) {
     85        let actual_keys = [];
     86        let rq = db.transaction("store", "readonly")
     87                 .objectStore("store")
     88                 .openCursor();
     89        rq.onsuccess = t.step_func(function(e) {
     90            let cursor = e.target.result;
     91            if (cursor) {
     92                actual_keys.push(cursor.key.valueOf());
     93                cursor.continue();
     94            }
     95            else {
     96                assert_equals(errors, 2, "expected ConstraintError's");
     97                assert_array_equals(actual_keys, expected, "keygenerator array");
     98                t.done();
     99            }
    100        });
    101    };
    102 
    103 }, "Keygenerator ConstraintError when using same id as already generated");
    104 
    105 function big_key_test(key, description) {
    106  indexeddb_test(
    107    (t, db) => {
    108      assert_equals(indexedDB.cmp(key, key), 0, 'Key is valid');
    109      db.createObjectStore('store', {autoIncrement: true});
    110    },
    111    (t, db) => {
    112      const tx = db.transaction('store', 'readwrite');
    113      const store = tx.objectStore('store');
    114      const value = 0;
    115      let request;
    116      request = store.put(value);
    117      request.onerror = t.unreached_func('put should succeed');
    118      request.onsuccess = t.step_func(e => {
    119        assert_equals(e.target.result, 1,
    120                      'Key generator should initially be 1');
    121      });
    122 
    123      request = store.put(value);
    124      request.onerror = t.unreached_func('put should succeed');
    125      request.onsuccess = t.step_func(e => {
    126        assert_equals(e.target.result, 2,
    127                      'Key generator should increment');
    128      });
    129 
    130      request = store.put(value, 1000);
    131      request.onerror = t.unreached_func('put should succeed');
    132      request.onsuccess = t.step_func(e => {
    133        assert_equals(e.target.result, 1000,
    134                      'Explicit key should be used');
    135      });
    136 
    137      request = store.put(value);
    138      request.onerror = t.unreached_func('put should succeed');
    139      request.onsuccess = t.step_func(e => {
    140        assert_equals(e.target.result, 1001,
    141                      'Key generator should have updated');
    142      });
    143 
    144      request = store.put(value, key);
    145      request.onerror = t.unreached_func('put should succeed');
    146      request.onsuccess = t.step_func(e => {
    147        assert_equals(e.target.result, key,
    148                      'Explicit key should be used');
    149      });
    150 
    151      if (key >= 0) {
    152        // Large positive values will max out the key generator, so it
    153        // can no longer produce keys.
    154        request = store.put(value);
    155        request.onsuccess = t.unreached_func('put should fail');
    156        request.onerror = t.step_func(e => {
    157          e.preventDefault();
    158          assert_equals(e.target.error.name, 'ConstraintError',
    159                        'Key generator should have returned failure');
    160        });
    161      } else {
    162        // Large negative values are always lower than the key generator's
    163        // current number, so have no effect on the generator.
    164        request = store.put(value);
    165        request.onerror = t.unreached_func('put should succeed');
    166        request.onsuccess = t.step_func(e => {
    167          assert_equals(e.target.result, 1002,
    168                        'Key generator should have updated');
    169        });
    170      }
    171 
    172      request = store.put(value, 2000);
    173      request.onerror = t.unreached_func('put should succeed');
    174      request.onsuccess = t.step_func(e => {
    175        assert_equals(e.target.result, 2000,
    176                      'Explicit key should be used');
    177      });
    178      tx.onabort = t.step_func(() => {
    179        assert_unreached(`Transaction aborted: ${tx.error.message}`);
    180      });
    181      tx.oncomplete = t.step_func(() => { t.done(); });
    182    },
    183    description);
    184 }
    185 
    186 [
    187  {
    188    key: Number.MAX_SAFE_INTEGER + 1,
    189    description: '53 bits'
    190  },
    191  {
    192    key: Math.pow(2, 60),
    193    description: 'greater than 53 bits, less than 64 bits'
    194  },
    195  {
    196    key: -Math.pow(2, 60),
    197    description: 'greater than 53 bits, less than 64 bits (negative)'
    198  },
    199  {
    200    key: Math.pow(2, 63),
    201    description: '63 bits'
    202  },
    203  {
    204    key: -Math.pow(2, 63),
    205    description: '63 bits (negative)'
    206  },
    207  {
    208    key: Math.pow(2, 64),
    209    description: '64 bits'
    210  },
    211  {
    212    key: -Math.pow(2, 64),
    213    description: '64 bits (negative)'
    214  },
    215  {
    216    key: Math.pow(2, 70),
    217    description: 'greater than 64 bits, but still finite'
    218  },
    219  {
    220    key: -Math.pow(2, 70),
    221    description: 'greater than 64 bits, but still finite (negative)'
    222  },
    223  {
    224    key: Infinity,
    225    description: 'equal to Infinity'
    226  },
    227  {
    228    key: -Infinity,
    229    description: 'equal to -Infinity'
    230  }
    231 ].forEach(function(testCase) {
    232  big_key_test(testCase.key,
    233               `Key generator vs. explicit key ${testCase.description}`);
    234 });
    235 
    236 indexeddb_test(
    237  (t, db) => {
    238    db.createObjectStore('store', {autoIncrement: true, keyPath: 'id'});
    239  },
    240  (t, db) => {
    241    const tx = db.transaction('store', 'readwrite');
    242    t.onabort = t.unreached_func('transaction should not abort');
    243    const store = tx.objectStore('store');
    244    store.put({name: 'n'}).onsuccess = t.step_func(e => {
    245      const key = e.target.result;
    246      assert_equals(key, 1, 'Key generator initial value should be 1');
    247      store.get(key).onsuccess = t.step_func(e => {
    248        const value = e.target.result;
    249        assert_equals(typeof value, 'object', 'Result should be object');
    250        assert_equals(value.name, 'n', 'Result should have name property');
    251        assert_equals(value.id, key, 'Key should be injected');
    252        t.done();
    253      });
    254    });
    255  },
    256  'Key is injected into value - single segment path');
    257 
    258 indexeddb_test(
    259  (t, db) => {
    260    db.createObjectStore('store', {autoIncrement: true, keyPath: 'a.b.id'});
    261  },
    262  (t, db) => {
    263    const tx = db.transaction('store', 'readwrite');
    264    t.onabort = t.unreached_func('transaction should not abort');
    265    const store = tx.objectStore('store');
    266    store.put({name: 'n'}).onsuccess = t.step_func(e => {
    267      const key = e.target.result;
    268      assert_equals(key, 1, 'Key generator initial value should be 1');
    269      store.get(key).onsuccess = t.step_func(e => {
    270        const value = e.target.result;
    271        assert_equals(typeof value, 'object', 'Result should be object');
    272        assert_equals(value.name, 'n', 'Result should have name property');
    273        assert_equals(value.a.b.id, key, 'Key should be injected');
    274        t.done();
    275      });
    276    });
    277  },
    278  'Key is injected into value - multi-segment path');
    279 
    280 indexeddb_test(
    281  (t, db) => {
    282    db.createObjectStore('store', {autoIncrement: true, keyPath: 'a.b.id'});
    283  },
    284  (t, db) => {
    285    const tx = db.transaction('store', 'readwrite');
    286    t.onabort = t.unreached_func('transaction should not abort');
    287    const store = tx.objectStore('store');
    288    store.put({name: 'n1', b: {name: 'n2'}}).onsuccess = t.step_func(e => {
    289      const key = e.target.result;
    290      assert_equals(key, 1, 'Key generator initial value should be 1');
    291      store.get(key).onsuccess = t.step_func(e => {
    292        const value = e.target.result;
    293        assert_equals(typeof value, 'object', 'Result should be object');
    294        assert_equals(value.name, 'n1', 'Result should have name property');
    295        assert_equals(value.b.name, 'n2', 'Result should have name property');
    296        assert_equals(value.a.b.id, key, 'Key should be injected');
    297        t.done();
    298      });
    299    });
    300  },
    301  'Key is injected into value - multi-segment path, partially populated');
    302 
    303 indexeddb_test(
    304  (t, db) => {
    305    db.createObjectStore('store', {autoIncrement: true, keyPath: 'id'});
    306  },
    307  (t, db) => {
    308    const tx = db.transaction('store', 'readwrite');
    309    const store = tx.objectStore('store');
    310 
    311    assert_throws_dom('DataError', () => {
    312      store.put(123);
    313    }, 'Key path should be checked against value');
    314 
    315    t.done();
    316  },
    317  'put() throws if key cannot be injected - single segment path');
    318 
    319 indexeddb_test(
    320  (t, db) => {
    321    db.createObjectStore('store', {autoIncrement: true, keyPath: 'a.b.id'});
    322  },
    323  (t, db) => {
    324    const tx = db.transaction('store', 'readwrite');
    325    const store = tx.objectStore('store');
    326 
    327    assert_throws_dom('DataError', () => {
    328      store.put({a: 123});
    329    }, 'Key path should be checked against value');
    330 
    331    assert_throws_dom('DataError', () => {
    332      store.put({a: {b: 123} });
    333    }, 'Key path should be checked against value');
    334 
    335    t.done();
    336  },
    337  'put() throws if key cannot be injected - multi-segment path');
    338 
    339 async_test(t => {
    340    let db;
    341    let overflow_error_fired = false;
    342    let objects = [9007199254740991, null, "error", 2, "error"];
    343    let expected_keys = [2, 9007199254740991, 9007199254740992];
    344    let open_rq = createdb(t);
    345    open_rq.onupgradeneeded = function(e) {
    346        db = e.target.result;
    347        let objStore = db.createObjectStore("store", { keyPath: "id", autoIncrement: true });
    348        for (let i = 0; i < objects.length; i++)
    349        {
    350            if (objects[i] === null)
    351            {
    352                objStore.add({});
    353            }
    354            else if (objects[i] === "error")
    355            {
    356                let rq = objStore.add({});
    357                rq.onsuccess = fail(t, 'When "current number" overflows, error event is expected');
    358                rq.onerror = t.step_func(function(e) {
    359                    overflow_error_fired = true;
    360                    assert_equals(e.target.error.name, "ConstraintError", "error name");
    361                    e.preventDefault();
    362                    e.stopPropagation();
    363                });
    364            }
    365            else
    366                objStore.add({ id: objects[i] });
    367        }
    368    };
    369 
    370    open_rq.onsuccess = function(e) {
    371        let actual_keys = [];
    372        let rq = db.transaction("store", "readonly")
    373                 .objectStore("store")
    374                 .openCursor();
    375        rq.onsuccess = t.step_func(function(e) {
    376            let cursor = e.target.result;
    377            if (cursor) {
    378                actual_keys.push(cursor.key.valueOf());
    379                cursor.continue();
    380            }
    381            else {
    382                assert_true(overflow_error_fired, "error fired on 'current number' overflow");
    383                assert_array_equals(actual_keys, expected_keys, "keygenerator array");
    384 
    385                t.done();
    386            }
    387        });
    388    };
    389 }, "Keygenerator overflow");