gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] branch master updated: more WPTs


From: gnunet
Subject: [taler-wallet-core] branch master updated: more WPTs
Date: Tue, 16 Feb 2021 16:23:11 +0100

This is an automated email from the git hooks/post-receive script.

dold pushed a commit to branch master
in repository wallet-core.

The following commit(s) were added to refs/heads/master by this push:
     new b814697f more WPTs
b814697f is described below

commit b814697fc9e4d55fbdb9b60ff82bef0c0c310494
Author: Florian Dold <florian@dold.me>
AuthorDate: Tue Feb 16 16:23:05 2021 +0100

    more WPTs
---
 .../src/idb-wpt-ported/idbcursor-reused.ts         |  76 ++++
 .../idbobjectstore-rename-store.test.ts            | 504 +++++++++++++++++++++
 .../idb-bridge/src/idb-wpt-ported/wptsupport.ts    | 265 ++++++++++-
 3 files changed, 843 insertions(+), 2 deletions(-)

diff --git a/packages/idb-bridge/src/idb-wpt-ported/idbcursor-reused.ts 
b/packages/idb-bridge/src/idb-wpt-ported/idbcursor-reused.ts
new file mode 100644
index 00000000..44a647dc
--- /dev/null
+++ b/packages/idb-bridge/src/idb-wpt-ported/idbcursor-reused.ts
@@ -0,0 +1,76 @@
+import test from "ava";
+import { createdb } from "./wptsupport";
+
+test("WPT idbcursor-reused.htm", async (t) => {
+  await new Promise<void>((resolve, reject) => {
+    var db: any;
+    var open_rq = createdb(t);
+
+    open_rq.onupgradeneeded = function (e: any) {
+      db = e.target.result;
+      var os = db.createObjectStore("test");
+
+      os.add("data", "k");
+      os.add("data2", "k2");
+    };
+
+    open_rq.onsuccess = function (e) {
+      var cursor: any;
+      var count = 0;
+      var rq = db.transaction("test").objectStore("test").openCursor();
+
+      rq.onsuccess = function (e: any) {
+        switch (count) {
+          case 0:
+            cursor = e.target.result;
+
+            t.deepEqual(cursor.value, "data", "prequisite cursor.value");
+            cursor.custom_cursor_value = 1;
+            e.target.custom_request_value = 2;
+
+            cursor.continue();
+            break;
+
+          case 1:
+            t.deepEqual(cursor.value, "data2", "prequisite cursor.value");
+            t.deepEqual(cursor.custom_cursor_value, 1, "custom cursor value");
+            t.deepEqual(
+              e.target.custom_request_value,
+              2,
+              "custom request value",
+            );
+
+            cursor.advance(1);
+            break;
+
+          case 2:
+            t.false(!!e.target.result, "got cursor");
+            t.deepEqual(cursor.custom_cursor_value, 1, "custom cursor value");
+            t.deepEqual(
+              e.target.custom_request_value,
+              2,
+              "custom request value",
+            );
+            break;
+        }
+        count++;
+      };
+
+      rq.transaction.oncomplete = function () {
+        t.deepEqual(count, 3, "cursor callback runs");
+        t.deepEqual(
+          rq.custom_request_value,
+          2,
+          "variable placed on old IDBRequest",
+        );
+        t.deepEqual(
+          cursor.custom_cursor_value,
+          1,
+          "custom cursor value (transaction.complete)",
+        );
+        resolve();
+      };
+    };
+  });
+  t.pass();
+});
diff --git 
a/packages/idb-bridge/src/idb-wpt-ported/idbobjectstore-rename-store.test.ts 
b/packages/idb-bridge/src/idb-wpt-ported/idbobjectstore-rename-store.test.ts
new file mode 100644
index 00000000..0f872fa5
--- /dev/null
+++ b/packages/idb-bridge/src/idb-wpt-ported/idbobjectstore-rename-store.test.ts
@@ -0,0 +1,504 @@
+import test, { ExecutionContext } from "ava";
+import { BridgeIDBRequest } from "..";
+import { EventTarget, IDBDatabase } from "../idbtypes";
+import {
+  checkStoreContents,
+  checkStoreGenerator,
+  checkStoreIndexes,
+  createBooksStore,
+  createDatabase,
+  createdb,
+  createNotBooksStore,
+  migrateDatabase,
+} from "./wptsupport";
+
+// IndexedDB: object store renaming support
+// IndexedDB object store rename in new transaction
+test("WPT idbobjectstore-rename-store.html (subtest 1)", async (t) => {
+  await new Promise<void>((resolve, reject) => {
+    let bookStore: any = null;
+    let bookStore2: any = null;
+    let renamedBookStore: any = null;
+    let renamedBookStore2: any = null;
+
+    return createDatabase(t, (database, transaction) => {
+      bookStore = createBooksStore(t, database);
+    })
+      .then((database) => {
+        t.deepEqual(
+          database.objectStoreNames as any,
+          ["books"],
+          'Test setup should have created a "books" object store',
+        );
+        const transaction = database.transaction("books", "readonly");
+        bookStore2 = transaction.objectStore("books");
+        return checkStoreContents(
+          t,
+          bookStore2,
+          "The store should have the expected contents before any renaming",
+        ).then(() => database.close());
+      })
+      .then(() =>
+        migrateDatabase(t, 2, (database, transaction) => {
+          renamedBookStore = transaction.objectStore("books");
+          renamedBookStore.name = "renamed_books";
+
+          t.deepEqual(
+            renamedBookStore.name,
+            "renamed_books",
+            "IDBObjectStore name should change immediately after a rename",
+          );
+          t.deepEqual(
+            database.objectStoreNames as any,
+            ["renamed_books"],
+            "IDBDatabase.objectStoreNames should immediately reflect the " +
+              "rename",
+          );
+          t.deepEqual(
+            transaction.objectStoreNames as any,
+            ["renamed_books"],
+            "IDBTransaction.objectStoreNames should immediately reflect the " +
+              "rename",
+          );
+          t.deepEqual(
+            transaction.objectStore("renamed_books"),
+            renamedBookStore,
+            "IDBTransaction.objectStore should return the renamed object " +
+              "store when queried using the new name immediately after the " +
+              "rename",
+          );
+          t.throws(
+            () => transaction.objectStore("books"),
+            { name: "NotFoundError" },
+            "IDBTransaction.objectStore should throw when queried using the " +
+              "renamed object store's old name immediately after the rename",
+          );
+        }),
+      )
+      .then((database) => {
+        t.deepEqual(
+          database.objectStoreNames as any,
+          ["renamed_books"],
+          "IDBDatabase.objectStoreNames should still reflect the rename " +
+            "after the versionchange transaction commits",
+        );
+        const transaction = database.transaction("renamed_books", "readonly");
+        renamedBookStore2 = transaction.objectStore("renamed_books");
+        return checkStoreContents(
+          t,
+          renamedBookStore2,
+          "Renaming an object store should not change its records",
+        ).then(() => database.close());
+      })
+      .then(() => {
+        t.deepEqual(
+          bookStore.name,
+          "books",
+          "IDBObjectStore obtained before the rename transaction should " +
+            "not reflect the rename",
+        );
+        t.deepEqual(
+          bookStore2.name,
+          "books",
+          "IDBObjectStore obtained before the rename transaction should " +
+            "not reflect the rename",
+        );
+        t.deepEqual(
+          renamedBookStore.name,
+          "renamed_books",
+          "IDBObjectStore used in the rename transaction should keep " +
+            "reflecting the new name after the transaction is committed",
+        );
+        t.deepEqual(
+          renamedBookStore2.name,
+          "renamed_books",
+          "IDBObjectStore obtained after the rename transaction should " +
+            "reflect the new name",
+        );
+      });
+  });
+  t.pass();
+});
+
+// IndexedDB: object store renaming support
+// IndexedDB object store rename in the transaction where it is created
+test("WPT idbobjectstore-rename-store.html (subtest 2)", async (t) => {
+  await new Promise<void>((resolve, reject) => {
+    let renamedBookStore: any = null,
+      renamedBookStore2: any = null;
+    return createDatabase(t, (database, transaction) => {
+      renamedBookStore = createBooksStore(t, database);
+      renamedBookStore.name = "renamed_books";
+
+      t.deepEqual(
+        renamedBookStore.name,
+        "renamed_books",
+        "IDBObjectStore name should change immediately after a rename",
+      );
+      t.deepEqual(
+        database.objectStoreNames as any,
+        ["renamed_books"],
+        "IDBDatabase.objectStoreNames should immediately reflect the " +
+          "rename",
+      );
+      t.deepEqual(
+        transaction.objectStoreNames as any,
+        ["renamed_books"],
+        "IDBTransaction.objectStoreNames should immediately reflect the " +
+          "rename",
+      );
+      t.deepEqual(
+        transaction.objectStore("renamed_books"),
+        renamedBookStore,
+        "IDBTransaction.objectStore should return the renamed object " +
+          "store when queried using the new name immediately after the " +
+          "rename",
+      );
+      t.throws(
+        () => transaction.objectStore("books"),
+        { name: "NotFoundError" },
+        "IDBTransaction.objectStore should throw when queried using the " +
+          "renamed object store's old name immediately after the rename",
+      );
+    })
+      .then((database) => {
+        t.deepEqual(
+          database.objectStoreNames as any,
+          ["renamed_books"],
+          "IDBDatabase.objectStoreNames should still reflect the rename " +
+            "after the versionchange transaction commits",
+        );
+        const transaction = database.transaction("renamed_books", "readonly");
+        renamedBookStore2 = transaction.objectStore("renamed_books");
+        return checkStoreContents(
+          t,
+          renamedBookStore2,
+          "Renaming an object store should not change its records",
+        ).then(() => database.close());
+      })
+      .then(() => {
+        t.deepEqual(
+          renamedBookStore.name,
+          "renamed_books",
+          "IDBObjectStore used in the rename transaction should keep " +
+            "reflecting the new name after the transaction is committed",
+        );
+        t.deepEqual(
+          renamedBookStore2.name,
+          "renamed_books",
+          "IDBObjectStore obtained after the rename transaction should " +
+            "reflect the new name",
+        );
+      });
+  });
+  t.pass();
+});
+
+// Renames the 'books' store to 'renamed_books'.
+//
+// Returns a promise that resolves to an IndexedDB database. The caller must
+// close the database.
+const renameBooksStore = (testCase: ExecutionContext) => {
+  return migrateDatabase(testCase, 2, (database, transaction) => {
+    const store = transaction.objectStore("books");
+    store.name = "renamed_books";
+  });
+};
+
+// IndexedDB: object store renaming support
+// IndexedDB object store rename covers index
+test("WPT idbobjectstore-rename-store.html (subtest 3)", async (t) => {
+  await createDatabase(t, (database, transaction) => {
+    createBooksStore(t, database);
+  })
+    .then(async (database) => {
+      const transaction = database.transaction("books", "readonly");
+      const store = transaction.objectStore("books");
+      await checkStoreIndexes(
+        t,
+        store,
+        "The object store index should have the expected contens before " +
+          "any renaming",
+      );
+      return database.close();
+    })
+    .then(() => renameBooksStore(t))
+    .then(async (database) => {
+      const transaction = database.transaction("renamed_books", "readonly");
+      const store = transaction.objectStore("renamed_books");
+      await checkStoreIndexes(
+        t,
+        store,
+        "Renaming an object store should not change its indexes",
+      );
+      return database.close();
+    });
+  t.pass();
+});
+
+// IndexedDB: object store renaming support
+// IndexedDB object store rename covers key generator
+test("WPT idbobjectstore-rename-store.html (subtest 4)", async (t) => {
+  await createDatabase(t, (database, transaction) => {
+    createBooksStore(t, database);
+  })
+    .then((database) => {
+      const transaction = database.transaction("books", "readwrite");
+      const store = transaction.objectStore("books");
+      return checkStoreGenerator(
+        t,
+        store,
+        345679,
+        "The object store key generator should have the expected state " +
+          "before any renaming",
+      ).then(() => database.close());
+    })
+    .then(() => renameBooksStore(t))
+    .then((database) => {
+      const transaction = database.transaction("renamed_books", "readwrite");
+      const store = transaction.objectStore("renamed_books");
+      return checkStoreGenerator(
+        t,
+        store,
+        345680,
+        "Renaming an object store should not change the state of its key " +
+          "generator",
+      ).then(() => database.close());
+    });
+  t.pass();
+});
+
+// IndexedDB: object store renaming support
+// IndexedDB object store rename to the name of a deleted store succeeds
+test("WPT idbobjectstore-rename-store.html (subtest 5)", async (t) => {
+  await createDatabase(t, (database, transaction) => {
+    createBooksStore(t, database);
+    createNotBooksStore(t, database);
+  })
+    .then((database) => {
+      database.close();
+    })
+    .then(() =>
+      migrateDatabase(t, 2, (database, transaction) => {
+        const store = transaction.objectStore("books");
+        database.deleteObjectStore("not_books");
+        store.name = "not_books";
+        t.deepEqual(
+          database.objectStoreNames as any,
+          ["not_books"],
+          "IDBDatabase.objectStoreNames should immediately reflect the " +
+            "rename",
+        );
+      }),
+    )
+    .then((database) => {
+      t.deepEqual(
+        database.objectStoreNames as any,
+        ["not_books"],
+        "IDBDatabase.objectStoreNames should still reflect the rename " +
+          "after the versionchange transaction commits",
+      );
+      const transaction = database.transaction("not_books", "readonly");
+      const store = transaction.objectStore("not_books");
+      return checkStoreContents(
+        t,
+        store,
+        "Renaming an object store should not change its records",
+      ).then(() => database.close());
+    });
+  t.pass();
+});
+
+// IndexedDB: object store renaming support
+test("WPT idbobjectstore-rename-store.html (IndexedDB object store swapping 
via renames succeeds)", async (t) => {
+  await createDatabase(t, (database, transaction) => {
+    createBooksStore(t, database);
+    createNotBooksStore(t, database);
+  })
+    .then((database) => {
+      database.close();
+    })
+    .then(() =>
+      migrateDatabase(t, 2, (database, transaction) => {
+        const bookStore = transaction.objectStore("books");
+        const notBookStore = transaction.objectStore("not_books");
+
+        transaction.objectStore("books").name = "tmp";
+        transaction.objectStore("not_books").name = "books";
+        transaction.objectStore("tmp").name = "not_books";
+
+        t.deepEqual(
+          database.objectStoreNames as any,
+          ["books", "not_books"],
+          "IDBDatabase.objectStoreNames should immediately reflect the swap",
+        );
+
+        t.deepEqual(
+          transaction.objectStore("books"),
+          notBookStore,
+          'IDBTransaction.objectStore should return the original "books" ' +
+            'store when queried with "not_books" after the swap',
+        );
+        t.deepEqual(
+          transaction.objectStore("not_books"),
+          bookStore,
+          "IDBTransaction.objectStore should return the original " +
+            '"not_books" store when queried with "books" after the swap',
+        );
+      }),
+    )
+    .then((database) => {
+      t.deepEqual(
+        database.objectStoreNames as any,
+        ["books", "not_books"],
+        "IDBDatabase.objectStoreNames should still reflect the swap " +
+          "after the versionchange transaction commits",
+      );
+      const transaction = database.transaction("not_books", "readonly");
+      const store = transaction.objectStore("not_books");
+      t.deepEqual(
+        store.indexNames as any,
+        ["by_author", "by_title"],
+        '"not_books" index names should still reflect the swap after the ' +
+          "versionchange transaction commits",
+      );
+      return checkStoreContents(
+        t,
+        store,
+        "Swapping two object stores should not change their records",
+      ).then(() => database.close());
+    });
+  t.pass();
+});
+
+// IndexedDB: object store renaming support
+test("WPT idbobjectstore-rename-store.html (IndexedDB object store rename 
stringifies non-string names)", async (t) => {
+  await createDatabase(t, (database, transaction) => {
+    createBooksStore(t, database);
+  })
+    .then((database) => {
+      database.close();
+    })
+    .then(() =>
+      migrateDatabase(t, 2, (database, transaction) => {
+        const store = transaction.objectStore("books");
+        // @ts-expect-error
+        store.name = 42;
+        t.deepEqual(
+          store.name,
+          "42",
+          "IDBObjectStore name should change immediately after a " +
+            "rename to a number",
+        );
+        t.deepEqual(
+          database.objectStoreNames as any,
+          ["42"],
+          "IDBDatabase.objectStoreNames should immediately reflect the " +
+            "stringifying rename",
+        );
+
+        // @ts-expect-error
+        store.name = true;
+        t.deepEqual(
+          store.name,
+          "true",
+          "IDBObjectStore name should change immediately after a " +
+            "rename to a boolean",
+        );
+
+        // @ts-expect-error
+        store.name = {};
+        t.deepEqual(
+          store.name,
+          "[object Object]",
+          "IDBObjectStore name should change immediately after a " +
+            "rename to an object",
+        );
+
+        // @ts-expect-error
+        store.name = () => null;
+        t.deepEqual(
+          store.name,
+          "() => null",
+          "IDBObjectStore name should change immediately after a " +
+            "rename to a function",
+        );
+
+        // @ts-expect-error
+        store.name = undefined;
+        t.deepEqual(
+          store.name,
+          "undefined",
+          "IDBObjectStore name should change immediately after a " +
+            "rename to undefined",
+        );
+      }),
+    )
+    .then((database) => {
+      t.deepEqual(
+        database.objectStoreNames as any,
+        ["undefined"],
+        "IDBDatabase.objectStoreNames should reflect the last rename " +
+          "after the versionchange transaction commits",
+      );
+      const transaction = database.transaction("undefined", "readonly");
+      const store = transaction.objectStore("undefined");
+      return checkStoreContents(
+        t,
+        store,
+        "Renaming an object store should not change its records",
+      ).then(() => database.close());
+    });
+  t.pass();
+});
+
+function rename_test_macro(t: ExecutionContext, escapedName: string) {
+  const name = JSON.parse('"' + escapedName + '"');
+  createDatabase(t, (database, transaction) => {
+    createBooksStore(t, database);
+  })
+    .then((database) => {
+      database.close();
+    })
+    .then(() =>
+      migrateDatabase(t, 2, (database, transaction) => {
+        const store = transaction.objectStore("books");
+
+        store.name = name;
+        t.deepEqual(
+          store.name,
+          name,
+          "IDBObjectStore name should change immediately after the " + 
"rename",
+        );
+        t.deepEqual(
+          database.objectStoreNames as any,
+          [name],
+          "IDBDatabase.objectStoreNames should immediately reflect the " +
+            "rename",
+        );
+      }),
+    )
+    .then((database) => {
+      t.deepEqual(
+        database.objectStoreNames as any,
+        [name],
+        "IDBDatabase.objectStoreNames should reflect the rename " +
+          "after the versionchange transaction commits",
+      );
+      const transaction = database.transaction(name, "readonly");
+      const store = transaction.objectStore(name);
+      return checkStoreContents(
+        t,
+        store,
+        "Renaming an object store should not change its records",
+      ).then(() => database.close());
+    });
+}
+
+for (let escapedName of ["", "\\u0000", "\\uDC00\\uD800"]) {
+  test(
+    'IndexedDB object store can be renamed to "' + escapedName + '"',
+    rename_test_macro,
+    escapedName,
+  );
+}
diff --git a/packages/idb-bridge/src/idb-wpt-ported/wptsupport.ts 
b/packages/idb-bridge/src/idb-wpt-ported/wptsupport.ts
index 5716a7ae..1c25bb8e 100644
--- a/packages/idb-bridge/src/idb-wpt-ported/wptsupport.ts
+++ b/packages/idb-bridge/src/idb-wpt-ported/wptsupport.ts
@@ -1,6 +1,14 @@
-import { ExecutionContext } from "ava";
+import test, { ExecutionContext } from "ava";
 import { BridgeIDBFactory } from "..";
-import { IDBOpenDBRequest } from "../idbtypes";
+import {
+  IDBDatabase,
+  IDBIndex,
+  IDBObjectStore,
+  IDBOpenDBRequest,
+  IDBRequest,
+  IDBTransaction,
+  IDBTransactionMode,
+} from "../idbtypes";
 import { MemoryBackend } from "../MemoryBackend";
 import { compareKeys } from "../util/cmp";
 
@@ -40,3 +48,256 @@ export function assert_equals(actual: any, expected: any) {
     throw Error("assert_equals failed");
   }
 }
+
+function makeDatabaseName(testCase: string): string {
+  return "db-" + testCase;
+}
+
+// Promise that resolves with an IDBRequest's result.
+//
+// The promise only resolves if IDBRequest receives the "success" event. Any
+// other event causes the promise to reject with an error. This is correct in
+// most cases, but insufficient for indexedDB.open(), which issues
+// "upgradeneded" events under normal operation.
+function promiseForRequest<T = any>(
+  t: ExecutionContext,
+  request: IDBRequest<T>,
+): Promise<T> {
+  return new Promise<T>((resolve, reject) => {
+    request.addEventListener("success", (evt: any) => {
+      resolve(evt.target.result);
+    });
+    request.addEventListener("blocked", (evt: any) => 
reject(evt.target.error));
+    request.addEventListener("error", (evt: any) => reject(evt.target.error));
+    request.addEventListener("upgradeneeded", (evt: any) =>
+      reject(evt.target.error),
+    );
+  });
+}
+
+type MigrationCallback = (
+  db: IDBDatabase,
+  tx: IDBTransaction,
+  req: IDBOpenDBRequest,
+) => void;
+
+export async function migrateDatabase(
+  t: ExecutionContext,
+  newVersion: number,
+  migrationCallback: MigrationCallback,
+): Promise<IDBDatabase> {
+  return migrateNamedDatabase(
+    t,
+    makeDatabaseName(t.title),
+    newVersion,
+    migrationCallback,
+  );
+}
+
+export async function migrateNamedDatabase(
+  t: ExecutionContext,
+  databaseName: string,
+  newVersion: number,
+  migrationCallback: MigrationCallback,
+): Promise<IDBDatabase> {
+  return new Promise<IDBDatabase>((resolve, reject) => {
+    const request = self.indexedDB.open(databaseName, newVersion);
+    request.onupgradeneeded = (event: any) => {
+      const database = event.target.result;
+      const transaction = event.target.transaction;
+      let shouldBeAborted = false;
+      let requestEventPromise: any = null;
+
+      // We wrap IDBTransaction.abort so we can set up the correct event
+      // listeners and expectations if the test chooses to abort the
+      // versionchange transaction.
+      const transactionAbort = transaction.abort.bind(transaction);
+      transaction.abort = () => {
+        transaction._willBeAborted();
+        transactionAbort();
+      };
+      transaction._willBeAborted = () => {
+        requestEventPromise = new Promise((resolve, reject) => {
+          request.onerror = (event: any) => {
+            event.preventDefault();
+            resolve(event.target.error);
+          };
+          request.onsuccess = () =>
+            reject(
+              new Error(
+                "indexedDB.open should not succeed for an aborted " +
+                  "versionchange transaction",
+              ),
+            );
+        });
+        shouldBeAborted = true;
+      };
+
+      // If migration callback returns a promise, we'll wait for it to resolve.
+      // This simplifies some tests.
+      const callbackResult = migrationCallback(database, transaction, request);
+      if (!shouldBeAborted) {
+        request.onerror = null;
+        request.onsuccess = null;
+        requestEventPromise = promiseForRequest(t, request);
+      }
+
+      // requestEventPromise needs to be the last promise in the chain, because
+      // we want the event that it resolves to.
+      resolve(Promise.resolve(callbackResult).then(() => requestEventPromise));
+    };
+    request.onerror = (event: any) => reject(event.target.error);
+    request.onsuccess = () => {
+      const database = request.result;
+      t.teardown(() => database.close());
+      reject(
+        new Error(
+          "indexedDB.open should not succeed without creating a " +
+            "versionchange transaction",
+        ),
+      );
+    };
+  });
+}
+
+export async function createDatabase(
+  t: ExecutionContext,
+  setupCallback: MigrationCallback,
+): Promise<IDBDatabase> {
+  const databaseName = makeDatabaseName(t.title);
+  const request = self.indexedDB.deleteDatabase(databaseName);
+  return migrateNamedDatabase(t, databaseName, 1, setupCallback);
+}
+
+// The data in the 'books' object store records in the first example of the
+// IndexedDB specification.
+const BOOKS_RECORD_DATA = [
+  { title: "Quarry Memories", author: "Fred", isbn: 123456 },
+  { title: "Water Buffaloes", author: "Fred", isbn: 234567 },
+  { title: "Bedrock Nights", author: "Barney", isbn: 345678 },
+];
+
+// Creates a 'books' object store whose contents closely resembles the first
+// example in the IndexedDB specification.
+export const createBooksStore = (
+  testCase: ExecutionContext,
+  database: IDBDatabase,
+) => {
+  const store = database.createObjectStore("books", {
+    keyPath: "isbn",
+    autoIncrement: true,
+  });
+  store.createIndex("by_author", "author");
+  store.createIndex("by_title", "title", { unique: true });
+  for (const record of BOOKS_RECORD_DATA) store.put(record);
+  return store;
+};
+
+// Verifies that an object store's contents matches the contents used to create
+// the books store in the test database's version 1.
+//
+// The errorMessage is used if the assertions fail. It can state that the
+// IndexedDB implementation being tested is incorrect, or that the testing code
+// is using it incorrectly.
+export async function checkStoreContents(
+  testCase: ExecutionContext,
+  store: IDBObjectStore,
+  errorMessage: string,
+) {
+  const request = store.get(123456);
+  const result = await promiseForRequest(testCase, request);
+  testCase.deepEqual(result.isbn, BOOKS_RECORD_DATA[0].isbn, errorMessage);
+  testCase.deepEqual(result.author, BOOKS_RECORD_DATA[0].author, errorMessage);
+  testCase.deepEqual(result.title, BOOKS_RECORD_DATA[0].title, errorMessage);
+}
+
+// Verifies that an object store's indexes match the indexes used to create the
+// books store in the test database's version 1.
+//
+// The errorMessage is used if the assertions fail. It can state that the
+// IndexedDB implementation being tested is incorrect, or that the testing code
+// is using it incorrectly.
+export function checkStoreIndexes(
+  testCase: ExecutionContext,
+  store: IDBObjectStore,
+  errorMessage: string,
+) {
+  testCase.deepEqual(
+    store.indexNames as any,
+    ["by_author", "by_title"],
+    errorMessage,
+  );
+  const authorIndex = store.index("by_author");
+  const titleIndex = store.index("by_title");
+  return Promise.all([
+    checkAuthorIndexContents(testCase, authorIndex, errorMessage),
+    checkTitleIndexContents(testCase, titleIndex, errorMessage),
+  ]);
+}
+
+// Verifies that index matches the 'by_author' index used to create the
+// by_author books store in the test database's version 1.
+//
+// The errorMessage is used if the assertions fail. It can state that the
+// IndexedDB implementation being tested is incorrect, or that the testing code
+// is using it incorrectly.
+async function checkAuthorIndexContents(
+  testCase: ExecutionContext,
+  index: IDBIndex,
+  errorMessage: string,
+) {
+  const request = index.get(BOOKS_RECORD_DATA[2].author);
+  const result = await promiseForRequest(testCase, request);
+  testCase.deepEqual(result.isbn, BOOKS_RECORD_DATA[2].isbn, errorMessage);
+  testCase.deepEqual(result.title, BOOKS_RECORD_DATA[2].title, errorMessage);
+}
+
+// Verifies that an index matches the 'by_title' index used to create the books
+// store in the test database's version 1.
+//
+// The errorMessage is used if the assertions fail. It can state that the
+// IndexedDB implementation being tested is incorrect, or that the testing code
+// is using it incorrectly.
+async function checkTitleIndexContents(
+  testCase: ExecutionContext,
+  index: IDBIndex,
+  errorMessage: string,
+) {
+  const request = index.get(BOOKS_RECORD_DATA[2].title);
+  const result = await promiseForRequest(testCase, request);
+  testCase.deepEqual(result.isbn, BOOKS_RECORD_DATA[2].isbn, errorMessage);
+  testCase.deepEqual(result.author, BOOKS_RECORD_DATA[2].author, errorMessage);
+}
+
+// Verifies that an object store's key generator is in the same state as the
+// key generator created for the books store in the test database's version 1.
+//
+// The errorMessage is used if the assertions fail. It can state that the
+// IndexedDB implementation being tested is incorrect, or that the testing code
+// is using it incorrectly.
+export function checkStoreGenerator(
+  testCase: ExecutionContext,
+  store: IDBObjectStore,
+  expectedKey: any,
+  errorMessage: string,
+) {
+  const request = store.put({
+    title: "Bedrock Nights " + expectedKey,
+    author: "Barney",
+  });
+  return promiseForRequest(testCase, request).then((result) => {
+    testCase.deepEqual(result, expectedKey, errorMessage);
+  });
+}
+
+// Creates a 'not_books' object store used to test renaming into existing or
+// deleted store names.
+export function createNotBooksStore(
+  testCase: ExecutionContext,
+  database: IDBDatabase,
+) {
+  const store = database.createObjectStore("not_books");
+  store.createIndex("not_by_author", "author");
+  store.createIndex("not_by_title", "title", { unique: true });
+  return store;
+}

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]