tor-browser

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

idbobjectstore-rename-store.any.js (18924B)


      1 // META: global=window,worker
      2 // META: title=IndexedDB: object store renaming support
      3 // META: script=resources/support-promises.js
      4 
      5 // Spec: https://w3c.github.io/IndexedDB/#dom-idbobjectstore-name
      6 
      7 'use strict';
      8 
      9 // Renames the 'books' store to 'renamed_books'.
     10 //
     11 // Returns a promise that resolves to an IndexedDB database. The caller must
     12 // close the database.
     13 const renameBooksStore = (testCase) => {
     14  return migrateDatabase(testCase, 2, (database, transaction) => {
     15    const store = transaction.objectStore('books');
     16    store.name = 'renamed_books';
     17  });
     18 };
     19 
     20 promise_test(testCase => {
     21  let bookStore = null;
     22  let bookStore2 = null;
     23  let renamedBookStore = null;
     24  let renamedBookStore2 = null;
     25  return createDatabase(
     26             testCase,
     27             (database, transaction) => {
     28               bookStore = createBooksStore(testCase, database);
     29             })
     30      .then(database => {
     31        assert_array_equals(
     32            database.objectStoreNames, ['books'],
     33            'Test setup should have created a "books" object store');
     34        const transaction = database.transaction('books', 'readonly');
     35        bookStore2 = transaction.objectStore('books');
     36        return checkStoreContents(
     37                   testCase, bookStore2,
     38                   'The store should have the expected contents before any renaming')
     39            .then(() => database.close());
     40      })
     41      .then(
     42          () => migrateDatabase(
     43              testCase, 2,
     44              (database, transaction) => {
     45                renamedBookStore = transaction.objectStore('books');
     46                renamedBookStore.name = 'renamed_books';
     47 
     48                assert_equals(
     49                    renamedBookStore.name, 'renamed_books',
     50                    'IDBObjectStore name should change immediately after a rename');
     51                assert_array_equals(
     52                    database.objectStoreNames, ['renamed_books'],
     53                    'IDBDatabase.objectStoreNames should immediately reflect the ' +
     54                        'rename');
     55                assert_array_equals(
     56                    transaction.objectStoreNames, ['renamed_books'],
     57                    'IDBTransaction.objectStoreNames should immediately reflect the ' +
     58                        'rename');
     59                assert_equals(
     60                    transaction.objectStore('renamed_books'), renamedBookStore,
     61                    'IDBTransaction.objectStore should return the renamed object ' +
     62                        'store when queried using the new name immediately after the ' +
     63                        'rename');
     64                assert_throws_dom(
     65                    'NotFoundError', () => transaction.objectStore('books'),
     66                    'IDBTransaction.objectStore should throw when queried using the ' +
     67                        'renamed object store\'s old name immediately after the rename');
     68              }))
     69      .then(database => {
     70        assert_array_equals(
     71            database.objectStoreNames, ['renamed_books'],
     72            'IDBDatabase.objectStoreNames should still reflect the rename ' +
     73                'after the versionchange transaction commits');
     74        const transaction = database.transaction('renamed_books', 'readonly');
     75        renamedBookStore2 = transaction.objectStore('renamed_books');
     76        return checkStoreContents(
     77                   testCase, renamedBookStore2,
     78                   'Renaming an object store should not change its records')
     79            .then(() => database.close());
     80      })
     81      .then(() => {
     82        assert_equals(
     83            bookStore.name, 'books',
     84            'IDBObjectStore obtained before the rename transaction should ' +
     85                'not reflect the rename');
     86        assert_equals(
     87            bookStore2.name, 'books',
     88            'IDBObjectStore obtained before the rename transaction should ' +
     89                'not reflect the rename');
     90        assert_equals(
     91            renamedBookStore.name, 'renamed_books',
     92            'IDBObjectStore used in the rename transaction should keep ' +
     93                'reflecting the new name after the transaction is committed');
     94        assert_equals(
     95            renamedBookStore2.name, 'renamed_books',
     96            'IDBObjectStore obtained after the rename transaction should ' +
     97                'reflect the new name');
     98      });
     99 }, 'IndexedDB object store rename in new transaction');
    100 
    101 promise_test(testCase => {
    102  let renamedBookStore = null;
    103  let renamedBookStore2 = null;
    104  return createDatabase(
    105             testCase,
    106             (database, transaction) => {
    107               renamedBookStore = createBooksStore(testCase, database);
    108               renamedBookStore.name = 'renamed_books';
    109 
    110               assert_equals(
    111                   renamedBookStore.name, 'renamed_books',
    112                   'IDBObjectStore name should change immediately after a rename');
    113               assert_array_equals(
    114                   database.objectStoreNames, ['renamed_books'],
    115                   'IDBDatabase.objectStoreNames should immediately reflect the ' +
    116                       'rename');
    117               assert_array_equals(
    118                   transaction.objectStoreNames, ['renamed_books'],
    119                   'IDBTransaction.objectStoreNames should immediately reflect the ' +
    120                       'rename');
    121               assert_equals(
    122                   transaction.objectStore('renamed_books'), renamedBookStore,
    123                   'IDBTransaction.objectStore should return the renamed object ' +
    124                       'store when queried using the new name immediately after the ' +
    125                       'rename');
    126               assert_throws_dom(
    127                   'NotFoundError', () => transaction.objectStore('books'),
    128                   'IDBTransaction.objectStore should throw when queried using the ' +
    129                       'renamed object store\'s old name immediately after the rename');
    130             })
    131      .then(database => {
    132        assert_array_equals(
    133            database.objectStoreNames, ['renamed_books'],
    134            'IDBDatabase.objectStoreNames should still reflect the rename ' +
    135                'after the versionchange transaction commits');
    136        const transaction = database.transaction('renamed_books', 'readonly');
    137        renamedBookStore2 = transaction.objectStore('renamed_books');
    138        return checkStoreContents(
    139                   testCase, renamedBookStore2,
    140                   'Renaming an object store should not change its records')
    141            .then(() => database.close());
    142      })
    143      .then(() => {
    144        assert_equals(
    145            renamedBookStore.name, 'renamed_books',
    146            'IDBObjectStore used in the rename transaction should keep ' +
    147                'reflecting the new name after the transaction is committed');
    148        assert_equals(
    149            renamedBookStore2.name, 'renamed_books',
    150            'IDBObjectStore obtained after the rename transaction should ' +
    151                'reflect the new name');
    152      });
    153 }, 'IndexedDB object store rename in the transaction where it is created');
    154 
    155 promise_test(testCase => {
    156  return createDatabase(
    157             testCase,
    158             (database, transaction) => {
    159               createBooksStore(testCase, database);
    160             })
    161      .then(database => {
    162        const transaction = database.transaction('books', 'readonly');
    163        const store = transaction.objectStore('books');
    164        return checkStoreIndexes(
    165                   testCase, store,
    166                   'The object store index should have the expected contens before ' +
    167                       'any renaming')
    168            .then(() => database.close());
    169      })
    170      .then(() => renameBooksStore(testCase))
    171      .then(database => {
    172        const transaction = database.transaction('renamed_books', 'readonly');
    173        const store = transaction.objectStore('renamed_books');
    174        return checkStoreIndexes(
    175                   testCase, store,
    176                   'Renaming an object store should not change its indexes')
    177            .then(() => database.close());
    178      });
    179 }, 'IndexedDB object store rename covers index');
    180 
    181 promise_test(testCase => {
    182  return createDatabase(
    183             testCase,
    184             (database, transaction) => {
    185               createBooksStore(testCase, database);
    186             })
    187      .then(database => {
    188        const transaction = database.transaction('books', 'readwrite');
    189        const store = transaction.objectStore('books');
    190        return checkStoreGenerator(
    191                   testCase, store, 345679,
    192                   'The object store key generator should have the expected state ' +
    193                       'before any renaming')
    194            .then(() => database.close());
    195      })
    196      .then(() => renameBooksStore(testCase))
    197      .then(database => {
    198        const transaction = database.transaction('renamed_books', 'readwrite');
    199        const store = transaction.objectStore('renamed_books');
    200        return checkStoreGenerator(
    201                   testCase, store, 345680,
    202                   'Renaming an object store should not change the state of its key ' +
    203                       'generator')
    204            .then(() => database.close());
    205      });
    206 }, 'IndexedDB object store rename covers key generator');
    207 
    208 promise_test(testCase => {
    209  return createDatabase(
    210             testCase,
    211             (database, transaction) => {
    212               createBooksStore(testCase, database);
    213             })
    214      .then(database => {
    215        database.close();
    216      })
    217      .then(
    218          () => migrateDatabase(
    219              testCase, 2,
    220              (database, transaction) => {
    221                const store = transaction.objectStore('books');
    222                store.name = 'books';
    223                assert_array_equals(
    224                    database.objectStoreNames, ['books'],
    225                    'Renaming a store to the same name should not change ' +
    226                        'the store\'s IDBDatabase.objectStoreNames');
    227              }))
    228      .then(database => {
    229        assert_array_equals(
    230            database.objectStoreNames, ['books'],
    231            'Committing a transaction that renames a store to the same name ' +
    232                'should not change the store\'s IDBDatabase.objectStoreNames');
    233        const transaction = database.transaction('books', 'readonly');
    234        const store = transaction.objectStore('books');
    235        return checkStoreContents(
    236                   testCase, store,
    237                   'Committing a transaction that renames a store to the same name ' +
    238                       'should not change the store\'s contents')
    239            .then(() => database.close());
    240      });
    241 }, 'IndexedDB object store rename to the same name succeeds');
    242 
    243 promise_test(testCase => {
    244  return createDatabase(
    245             testCase,
    246             (database, transaction) => {
    247               createBooksStore(testCase, database);
    248               createNotBooksStore(testCase, database);
    249             })
    250      .then(database => {
    251        database.close();
    252      })
    253      .then(
    254          () => migrateDatabase(
    255              testCase, 2,
    256              (database, transaction) => {
    257                const store = transaction.objectStore('books');
    258                database.deleteObjectStore('not_books');
    259                store.name = 'not_books';
    260                assert_array_equals(
    261                    database.objectStoreNames, ['not_books'],
    262                    'IDBDatabase.objectStoreNames should immediately reflect the ' +
    263                        'rename');
    264              }))
    265      .then(database => {
    266        assert_array_equals(
    267            database.objectStoreNames, ['not_books'],
    268            'IDBDatabase.objectStoreNames should still reflect the rename ' +
    269                'after the versionchange transaction commits');
    270        const transaction = database.transaction('not_books', 'readonly');
    271        const store = transaction.objectStore('not_books');
    272        return checkStoreContents(
    273                   testCase, store,
    274                   'Renaming an object store should not change its records')
    275            .then(() => database.close());
    276      });
    277 }, 'IndexedDB object store rename to the name of a deleted store succeeds');
    278 
    279 promise_test(testCase => {
    280  return createDatabase(
    281             testCase,
    282             (database, transaction) => {
    283               createBooksStore(testCase, database);
    284               createNotBooksStore(testCase, database);
    285             })
    286      .then(database => {
    287        database.close();
    288      })
    289      .then(
    290          () => migrateDatabase(
    291              testCase, 2,
    292              (database, transaction) => {
    293                const bookStore = transaction.objectStore('books');
    294                const notBookStore = transaction.objectStore('not_books');
    295 
    296                transaction.objectStore('books').name = 'tmp';
    297                transaction.objectStore('not_books').name = 'books';
    298                transaction.objectStore('tmp').name = 'not_books';
    299 
    300                assert_array_equals(
    301                    database.objectStoreNames, ['books', 'not_books'],
    302                    'IDBDatabase.objectStoreNames should immediately reflect the swap');
    303 
    304                assert_equals(
    305                    transaction.objectStore('books'), notBookStore,
    306                    'IDBTransaction.objectStore should return the original "books" ' +
    307                        'store when queried with "not_books" after the swap');
    308                assert_equals(
    309                    transaction.objectStore('not_books'), bookStore,
    310                    'IDBTransaction.objectStore should return the original ' +
    311                        '"not_books" store when queried with "books" after the swap');
    312              }))
    313      .then(database => {
    314        assert_array_equals(
    315            database.objectStoreNames, ['books', 'not_books'],
    316            'IDBDatabase.objectStoreNames should still reflect the swap ' +
    317                'after the versionchange transaction commits');
    318        const transaction = database.transaction('not_books', 'readonly');
    319        const store = transaction.objectStore('not_books');
    320        assert_array_equals(
    321            store.indexNames, ['by_author', 'by_title'],
    322            '"not_books" index names should still reflect the swap after the ' +
    323                'versionchange transaction commits');
    324        return checkStoreContents(
    325                   testCase, store,
    326                   'Swapping two object stores should not change their records')
    327            .then(() => database.close());
    328      });
    329 }, 'IndexedDB object store swapping via renames succeeds');
    330 
    331 promise_test(testCase => {
    332  return createDatabase(
    333             testCase,
    334             (database, transaction) => {
    335               createBooksStore(testCase, database);
    336             })
    337      .then(database => {
    338        database.close();
    339      })
    340      .then(
    341          () => migrateDatabase(
    342              testCase, 2,
    343              (database, transaction) => {
    344                const store = transaction.objectStore('books');
    345 
    346                store.name = 42;
    347                assert_equals(
    348                    store.name, '42',
    349                    'IDBObjectStore name should change immediately after a ' +
    350                        'rename to a number');
    351                assert_array_equals(
    352                    database.objectStoreNames, ['42'],
    353                    'IDBDatabase.objectStoreNames should immediately reflect the ' +
    354                        'stringifying rename');
    355 
    356                store.name = true;
    357                assert_equals(
    358                    store.name, 'true',
    359                    'IDBObjectStore name should change immediately after a ' +
    360                        'rename to a boolean');
    361 
    362                store.name = {};
    363                assert_equals(
    364                    store.name, '[object Object]',
    365                    'IDBObjectStore name should change immediately after a ' +
    366                        'rename to an object');
    367 
    368                store.name = () => null;
    369                assert_equals(
    370                    store.name, '() => null',
    371                    'IDBObjectStore name should change immediately after a ' +
    372                        'rename to a function');
    373 
    374                store.name = undefined;
    375                assert_equals(
    376                    store.name, 'undefined',
    377                    'IDBObjectStore name should change immediately after a ' +
    378                        'rename to undefined');
    379              }))
    380      .then(database => {
    381        assert_array_equals(
    382            database.objectStoreNames, ['undefined'],
    383            'IDBDatabase.objectStoreNames should reflect the last rename ' +
    384                'after the versionchange transaction commits');
    385        const transaction = database.transaction('undefined', 'readonly');
    386        const store = transaction.objectStore('undefined');
    387        return checkStoreContents(
    388                   testCase, store,
    389                   'Renaming an object store should not change its records')
    390            .then(() => database.close());
    391      });
    392 }, 'IndexedDB object store rename stringifies non-string names');
    393 
    394 for (let escapedName of ['', '\\u0000', '\\uDC00\\uD800'])
    395  ((escapedName) => {
    396    const name = JSON.parse('"' + escapedName + '"');
    397    promise_test(testCase => {
    398      return createDatabase(
    399                 testCase,
    400                 (database, transaction) => {
    401                   createBooksStore(testCase, database);
    402                 })
    403          .then(database => {
    404            database.close();
    405          })
    406          .then(
    407              () => migrateDatabase(
    408                  testCase, 2,
    409                  (database, transaction) => {
    410                    const store = transaction.objectStore('books');
    411 
    412                    store.name = name;
    413                    assert_equals(
    414                        store.name, name,
    415                        'IDBObjectStore name should change immediately after the ' +
    416                            'rename');
    417                    assert_array_equals(
    418                        database.objectStoreNames, [name],
    419                        'IDBDatabase.objectStoreNames should immediately reflect the ' +
    420                            'rename');
    421                  }))
    422          .then(database => {
    423            assert_array_equals(
    424                database.objectStoreNames, [name],
    425                'IDBDatabase.objectStoreNames should reflect the rename ' +
    426                    'after the versionchange transaction commits');
    427            const transaction = database.transaction(name, 'readonly');
    428            const store = transaction.objectStore(name);
    429            return checkStoreContents(
    430                       testCase, store,
    431                       'Renaming an object store should not change its records')
    432                .then(() => database.close());
    433          });
    434    }, 'IndexedDB object store can be renamed to "' + escapedName + '"');
    435  })(escapedName);