tor-browser

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

nested-cloning-common.js (7855B)


      1 'use strict';
      2 
      3 // Should be large enough to trigger large value handling in the IndexedDB
      4 // engines that have special code paths for large values.
      5 const wrapThreshold = 128 * 1024;
      6 
      7 // Returns an IndexedDB value created from a descriptor.
      8 //
      9 // See the bottom of the file for descriptor samples.
     10 function createValue(descriptor) {
     11  if (typeof(descriptor) != 'object')
     12    return descriptor;
     13 
     14  if (Array.isArray(descriptor))
     15    return descriptor.map((element) => createValue(element));
     16 
     17  if (!descriptor.hasOwnProperty('type')) {
     18    const value = {};
     19    for (let property of Object.getOwnPropertyNames(descriptor))
     20      value[property] = createValue(descriptor[property]);
     21    return value;
     22  }
     23 
     24  switch (descriptor.type) {
     25    case 'blob':
     26      return new Blob(
     27          [largeValue(descriptor.size, descriptor.seed)],
     28          { type: descriptor.mimeType });
     29    case 'buffer':
     30      return largeValue(descriptor.size, descriptor.seed);
     31  }
     32 }
     33 
     34 // Checks an IndexedDB value against a descriptor.
     35 //
     36 // Returns a Promise that resolves if the value passes the check.
     37 //
     38 // See the bottom of the file for descriptor samples.
     39 function checkValue(testCase, value, descriptor) {
     40  if (typeof(descriptor) != 'object') {
     41    assert_equals(
     42        descriptor, value,
     43        'IndexedDB result should match put() argument');
     44    return Promise.resolve();
     45  }
     46 
     47  if (Array.isArray(descriptor)) {
     48    assert_true(
     49        Array.isArray(value),
     50        'IndexedDB result type should match put() argument');
     51    assert_equals(
     52        descriptor.length, value.length,
     53        'IndexedDB result array size should match put() argument');
     54 
     55    const subChecks = [];
     56    for (let i = 0; i < descriptor.length; ++i)
     57      subChecks.push(checkValue(testCase, value[i], descriptor[i]));
     58    return Promise.all(subChecks);
     59  }
     60 
     61  if (!descriptor.hasOwnProperty('type')) {
     62    assert_array_equals(
     63        Object.getOwnPropertyNames(value).sort(),
     64        Object.getOwnPropertyNames(descriptor).sort(),
     65        'IndexedDB result object properties should match put() argument');
     66    const subChecks = [];
     67    return Promise.all(Object.getOwnPropertyNames(descriptor).map(property =>
     68        checkValue(testCase, value[property], descriptor[property])));
     69  }
     70 
     71  switch (descriptor.type) {
     72    case 'blob':
     73      assert_class_string(
     74          value, 'Blob',
     75          'IndexedDB result class should match put() argument');
     76      assert_equals(
     77          descriptor.mimeType, value.type,
     78          'IndexedDB result Blob MIME type should match put() argument');
     79      assert_equals(descriptor.size, value.size, 'incorrect Blob size');
     80      return new Promise((resolve, reject) => {
     81        const reader = new FileReader();
     82        reader.onloadend = testCase.step_func(() => {
     83          if (reader.error) {
     84            reject(reader.error);
     85            return;
     86          }
     87          const view = new Uint8Array(reader.result);
     88          assert_equals(
     89              view.join(','),
     90              largeValue(descriptor.size, descriptor.seed).join(','),
     91              'IndexedDB result Blob content should match put() argument');
     92          resolve();
     93        });
     94        reader.readAsArrayBuffer(value);
     95      });
     96 
     97    case 'buffer':
     98      assert_class_string(
     99          value, 'Uint8Array',
    100          'IndexedDB result type should match put() argument');
    101      assert_equals(
    102          value.join(','),
    103          largeValue(descriptor.size, descriptor.seed).join(','),
    104          'IndexedDB result typed array content should match put() argument');
    105      return Promise.resolve();
    106  }
    107 }
    108 
    109 function cloningTestInternal(label, valueDescriptors, options) {
    110  promise_test(testCase => {
    111    return createDatabase(testCase, (database, transaction) => {
    112      testCase.add_cleanup(() => database.close());
    113      let store;
    114      if (options.useKeyGenerator) {
    115        store = database.createObjectStore(
    116            'test-store', { keyPath: 'primaryKey', autoIncrement: true });
    117      } else {
    118        store = database.createObjectStore('test-store');
    119      }
    120      for (let i = 0; i < valueDescriptors.length; ++i) {
    121        if (options.useKeyGenerator) {
    122          store.put(createValue(valueDescriptors[i]));
    123        } else {
    124          store.put(createValue(valueDescriptors[i]), i + 1);
    125        }
    126      }
    127    }).then(database => {
    128      const transaction = database.transaction(['test-store'], 'readonly');
    129      const store = transaction.objectStore('test-store');
    130      const subChecks = [];
    131      let resultIndex = 0;
    132      for (let i = 0; i < valueDescriptors.length; ++i) {
    133        subChecks.push(new Promise((resolve, reject) => {
    134          const requestIndex = i;
    135          const primaryKey = requestIndex + 1;
    136          const request = store.get(primaryKey);
    137          request.onerror =
    138              testCase.step_func(() => { reject(request.error); });
    139          request.onsuccess = testCase.step_func(() => {
    140            assert_equals(
    141                resultIndex, requestIndex,
    142                'IDBRequest success events should be fired in request order');
    143            ++resultIndex;
    144 
    145            const result = request.result;
    146            if (options.useKeyGenerator) {
    147              assert_equals(
    148                  result.primaryKey, primaryKey,
    149                  'IndexedDB result should have auto-incremented primary key');
    150              delete result.primaryKey;
    151            }
    152            resolve(checkValue(
    153                testCase, result, valueDescriptors[requestIndex]));
    154          });
    155        }));
    156      }
    157 
    158      subChecks.push(new Promise((resolve, reject) => {
    159        const requestIndex = valueDescriptors.length;
    160        const request = store.getAll();
    161        request.onerror =
    162            testCase.step_func(() => { reject(request.error); });
    163        request.onsuccess = testCase.step_func(() => {
    164          assert_equals(
    165              resultIndex, requestIndex,
    166              'IDBRequest success events should be fired in request order');
    167          ++resultIndex;
    168          const result = request.result;
    169          if (options.useKeyGenerator) {
    170            for (let i = 0; i < valueDescriptors.length; ++i) {
    171              const primaryKey = i + 1;
    172              assert_equals(
    173                  result[i].primaryKey, primaryKey,
    174                  'IndexedDB result should have auto-incremented primary key');
    175              delete result[i].primaryKey;
    176            }
    177          }
    178          resolve(checkValue(testCase, result, valueDescriptors));
    179        });
    180      }));
    181 
    182      return Promise.all(subChecks);
    183    });
    184  }, label);
    185 }
    186 
    187 // Performs a series of put()s and verifies that get()s and getAll() match.
    188 //
    189 // Each element of the valueDescriptors array is fed into createValue(), and the
    190 // resulting value is written to IndexedDB via a put() request. After the writes
    191 // complete, the values are read in the same order in which they were written.
    192 // Last, all the results are read one more time via a getAll().
    193 //
    194 // The test verifies that the get() / getAll() results match the arguments to
    195 // put() and that the order in which the get() result events are fired matches
    196 // the order of the get() requests.
    197 function cloningTest(label, valueDescriptors) {
    198  cloningTestInternal(label, valueDescriptors, { useKeyGenerator: false });
    199 }
    200 
    201 // cloningTest, with coverage for key generators.
    202 //
    203 // This creates two tests. One test performs a series of put()s and verifies
    204 // that get()s and getAll() match, exactly like cloningTestWithoutKeyGenerator.
    205 // The other test performs the same put()s in an object store with a key
    206 // generator, and checks that the key generator works properly.
    207 function cloningTestWithKeyGenerator(label, valueDescriptors) {
    208  cloningTestInternal(label, valueDescriptors, { useKeyGenerator: false });
    209  cloningTestInternal(
    210      label + " with key generator", valueDescriptors,
    211      { useKeyGenerator: true });
    212 }