@procedures/collections 0.56.0 → 0.58.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,8 +6,9 @@
6
6
  * `@procedures/sqlite`. Before, each package copied the cases of `InMemoryStorage`.
7
7
  *
8
8
  * The suite is in the test-only entry `@procedures/collections/testing`. It imports no test
9
- * framework: the caller gives `describe` and `it`, and the checks throw `ContractViolation`. So a
10
- * storage package imports the suite without a cycle, and a runtime entry never loads vitest.
9
+ * framework: the caller gives `describe` and `it`, and the checks throw the `AssertionError` of
10
+ * `node:assert`. So a storage package imports the suite without a cycle, and a runtime entry does
11
+ * not load vitest.
11
12
  *
12
13
  * ```ts
13
14
  * import { describe, it } from "vitest";
@@ -32,7 +33,13 @@
32
33
  * conflicts and their current items, and two writes at the same time.
33
34
  */
34
35
  import { QUERY_OPERATORS, queryEntries, versionConflictsOf, } from "@procedures/client/query";
35
- import { holds, rejects, same, show } from "@mark1russell7/collections/testing";
36
+ import assert from "node:assert/strict";
37
+ import { inspect } from "node:util";
38
+ import { rejects } from "@mark1russell7/rigor-testkit";
39
+ /** This function gives the text of a value for the message of a failed check, on one line. */
40
+ function show(value) {
41
+ return inspect(value, { breakLength: Infinity, depth: null });
42
+ }
36
43
  /**
37
44
  * The version of an item of the suite: `v` and the field `n`. A storage of `createWithVersions`
38
45
  * gives it as its `versionOf` (roadmap CLI-16).
@@ -247,7 +254,7 @@ export function collectionStorageContract(options) {
247
254
  ["getBatch", storage.getBatch(["a"])],
248
255
  ];
249
256
  for (const [name, result] of results)
250
- holds(isPromise(result), `${name}() did not give a promise`);
257
+ assert.ok(isPromise(result), `${name}() did not give a promise`);
251
258
  await Promise.all(results.map(([, result]) => result));
252
259
  for (const [name, start] of [
253
260
  ["set", () => storage.set("a", item("a", 1))],
@@ -257,67 +264,67 @@ export function collectionStorageContract(options) {
257
264
  ["clear", () => storage.clear()],
258
265
  ]) {
259
266
  const result = start();
260
- holds(isPromise(result), `${name}() did not give a promise`);
267
+ assert.ok(isPromise(result), `${name}() did not give a promise`);
261
268
  await result;
262
269
  }
263
270
  }));
264
271
  add("an empty storage has no item", () => withStorage(create, async (storage) => {
265
- same(await storage.size(), 0, "size() of an empty storage");
266
- same(await storage.getAll(), [], "getAll() of an empty storage");
267
- same(await storage.get("a"), undefined, "get() of a missing id");
268
- same(await storage.has("a"), false, "has() of a missing id");
269
- same(await storage.getBatch(["a", "b"]), new Map(), "getBatch() of missing ids");
270
- same(await storage.find(() => true), [], "find() in an empty storage");
271
- same(await storage.delete("a"), false, "delete() of a missing id");
272
- same(await storage.deleteBatch(["a", "b"]), 0, "deleteBatch() of missing ids");
272
+ assert.deepStrictEqual(await storage.size(), 0, "size() of an empty storage");
273
+ assert.deepStrictEqual(await storage.getAll(), [], "getAll() of an empty storage");
274
+ assert.deepStrictEqual(await storage.get("a"), undefined, "get() of a missing id");
275
+ assert.deepStrictEqual(await storage.has("a"), false, "has() of a missing id");
276
+ assert.deepStrictEqual(await storage.getBatch(["a", "b"]), new Map(), "getBatch() of missing ids");
277
+ assert.deepStrictEqual(await storage.find(() => true), [], "find() in an empty storage");
278
+ assert.deepStrictEqual(await storage.delete("a"), false, "delete() of a missing id");
279
+ assert.deepStrictEqual(await storage.deleteBatch(["a", "b"]), 0, "deleteBatch() of missing ids");
273
280
  if (storage.getEntries)
274
- same(await storage.getEntries(), [], "getEntries() of an empty storage");
281
+ assert.deepStrictEqual(await storage.getEntries(), [], "getEntries() of an empty storage");
275
282
  if (storage.getIds)
276
- same(await storage.getIds(), [], "getIds() of an empty storage");
283
+ assert.deepStrictEqual(await storage.getIds(), [], "getIds() of an empty storage");
277
284
  }));
278
285
  add("set() stores an item, and a second set() of the id replaces it", () => withStorage(create, async (storage) => {
279
286
  await storage.set("a", item("a", 1, ["x"]));
280
287
  await storage.set("b", item("b", 2));
281
- same(await storage.get("a"), item("a", 1, ["x"]), "get() after set()");
282
- same(await storage.has("a"), true, "has() after set()");
283
- same(await storage.size(), 2, "size() after two set() calls");
288
+ assert.deepStrictEqual(await storage.get("a"), item("a", 1, ["x"]), "get() after set()");
289
+ assert.deepStrictEqual(await storage.has("a"), true, "has() after set()");
290
+ assert.deepStrictEqual(await storage.size(), 2, "size() after two set() calls");
284
291
  await storage.set("a", item("a", 10));
285
- same(await storage.get("a"), item("a", 10), "get() after a second set() of the id");
286
- same(await storage.size(), 2, "size() after a second set() of an id");
292
+ assert.deepStrictEqual(await storage.get("a"), item("a", 10), "get() after a second set() of the id");
293
+ assert.deepStrictEqual(await storage.size(), 2, "size() after a second set() of an id");
287
294
  }));
288
295
  add("delete() gives true for an item that existed, and deleteBatch() counts the items that existed", () => withStorage(create, async (storage) => {
289
296
  await storage.setBatch([["a", item("a", 1)], ["b", item("b", 2)], ["c", item("c", 3)]]);
290
- same(await storage.delete("a"), true, "delete() of an item");
291
- same(await storage.delete("a"), false, "a second delete() of the id");
292
- same(await storage.has("a"), false, "has() after delete()");
293
- same(await storage.get("a"), undefined, "get() after delete()");
294
- same(await storage.deleteBatch(["b", "missing", "b"]), 1, "deleteBatch() with a missing id and a repeated id");
295
- same(ids(await storage.getAll()), ["c"], "getAll() after the deletes");
297
+ assert.deepStrictEqual(await storage.delete("a"), true, "delete() of an item");
298
+ assert.deepStrictEqual(await storage.delete("a"), false, "a second delete() of the id");
299
+ assert.deepStrictEqual(await storage.has("a"), false, "has() after delete()");
300
+ assert.deepStrictEqual(await storage.get("a"), undefined, "get() after delete()");
301
+ assert.deepStrictEqual(await storage.deleteBatch(["b", "missing", "b"]), 1, "deleteBatch() with a missing id and a repeated id");
302
+ assert.deepStrictEqual(ids(await storage.getAll()), ["c"], "getAll() after the deletes");
296
303
  }));
297
304
  add("setBatch() and getBatch(): the last value of an id wins, a missing id is not in the map, and empty batches change nothing", () => withStorage(create, async (storage) => {
298
305
  await storage.setBatch([["a", item("a", 1)], ["b", item("b", 2)], ["a", item("a", 3)]]);
299
- same(await storage.get("a"), item("a", 3), "get() of an id that setBatch() set two times");
300
- same(await storage.size(), 2, "size() after setBatch() with a repeated id");
301
- same(await storage.getBatch(["b", "missing", "a"]), new Map([["b", item("b", 2)], ["a", item("a", 3)]]), "getBatch() with a missing id");
306
+ assert.deepStrictEqual(await storage.get("a"), item("a", 3), "get() of an id that setBatch() set two times");
307
+ assert.deepStrictEqual(await storage.size(), 2, "size() after setBatch() with a repeated id");
308
+ assert.deepStrictEqual(await storage.getBatch(["b", "missing", "a"]), new Map([["b", item("b", 2)], ["a", item("a", 3)]]), "getBatch() with a missing id");
302
309
  await storage.setBatch([]);
303
- same(await storage.deleteBatch([]), 0, "deleteBatch() of no id");
304
- same(await storage.getBatch([]), new Map(), "getBatch() of no id");
305
- same(await storage.size(), 2, "size() after the empty batches");
310
+ assert.deepStrictEqual(await storage.deleteBatch([]), 0, "deleteBatch() of no id");
311
+ assert.deepStrictEqual(await storage.getBatch([]), new Map(), "getBatch() of no id");
312
+ assert.deepStrictEqual(await storage.size(), 2, "size() after the empty batches");
306
313
  }));
307
314
  add("the entries keep the order of the first set() of each id, as a Map does", () => withStorage(create, async (storage) => {
308
315
  await storage.setBatch([["c", item("c", 3)], ["a", item("a", 1)], ["b", item("b", 2)]]);
309
316
  await storage.set("a", item("a", 10));
310
- same(ids(await storage.getAll()), ["c", "a", "b"], "getAll() after a second set() of an id: the id keeps its place");
317
+ assert.deepStrictEqual(ids(await storage.getAll()), ["c", "a", "b"], "getAll() after a second set() of an id: the id keeps its place");
311
318
  // A delete, then a set: the id goes to the end
312
319
  await storage.delete("c");
313
320
  await storage.set("c", item("c", 30));
314
321
  const expected = [["a", item("a", 10)], ["b", item("b", 2)], ["c", item("c", 30)]];
315
- same(await storage.getAll(), expected.map(([, value]) => value), "getAll() after a delete and a new set() of an id");
316
- same(ids(await storage.find(() => true)), ["a", "b", "c"], "find() keeps the order of the entries");
322
+ assert.deepStrictEqual(await storage.getAll(), expected.map(([, value]) => value), "getAll() after a delete and a new set() of an id");
323
+ assert.deepStrictEqual(ids(await storage.find(() => true)), ["a", "b", "c"], "find() keeps the order of the entries");
317
324
  if (storage.getEntries)
318
- same(await storage.getEntries(), expected, "getEntries() keeps the order of the entries");
325
+ assert.deepStrictEqual(await storage.getEntries(), expected, "getEntries() keeps the order of the entries");
319
326
  if (storage.getIds)
320
- same(await storage.getIds(), ["a", "b", "c"], "getIds() keeps the order of the entries");
327
+ assert.deepStrictEqual(await storage.getIds(), ["a", "b", "c"], "getIds() keeps the order of the entries");
321
328
  }));
322
329
  add("getIds() gives the ids of the entries in their order, as a new array", (context) => withStorage(create, async (storage) => {
323
330
  if (lacks(storage, "getIds", context))
@@ -326,32 +333,32 @@ export function collectionStorageContract(options) {
326
333
  await storage.delete("a");
327
334
  await storage.set("a", item("a", 10));
328
335
  const first = await storage.getIds();
329
- same(first, ["c", "b", "a"], "getIds() after a delete and a new set() of an id");
336
+ assert.deepStrictEqual(first, ["c", "b", "a"], "getIds() after a delete and a new set() of an id");
330
337
  first.splice(0);
331
- same(await storage.getIds(), ["c", "b", "a"], "getIds() after a change of an earlier result");
338
+ assert.deepStrictEqual(await storage.getIds(), ["c", "b", "a"], "getIds() after a change of an earlier result");
332
339
  if (storage.getEntries)
333
- same(await storage.getIds(), (await storage.getEntries()).map(([id]) => id), "getIds() and the ids of getEntries()");
340
+ assert.deepStrictEqual(await storage.getIds(), (await storage.getEntries()).map(([id]) => id), "getIds() and the ids of getEntries()");
334
341
  await storage.clear();
335
- same(await storage.getIds(), [], "getIds() after clear()");
342
+ assert.deepStrictEqual(await storage.getIds(), [], "getIds() after clear()");
336
343
  }));
337
344
  add("find() gives the matching items in order, and an error of the predicate rejects the promise", () => withStorage(create, async (storage) => {
338
345
  await storage.setBatch([["a", item("a", 1)], ["b", item("b", 2)], ["c", item("c", 3)], ["d", item("d", 4)]]);
339
- same(ids(await storage.find((value) => value.n % 2 === 0)), ["b", "d"], "find() of the even items");
340
- same(await storage.find(() => false), [], "find() without a match");
346
+ assert.deepStrictEqual(ids(await storage.find((value) => value.n % 2 === 0)), ["b", "d"], "find() of the even items");
347
+ assert.deepStrictEqual(await storage.find(() => false), [], "find() without a match");
341
348
  const error = await rejects(() => storage.find(() => {
342
349
  throw new Error("the predicate failed");
343
350
  }), "find() with a predicate that throws");
344
- holds(error instanceof Error && error.message.includes("the predicate failed"), `find() must reject with the error of the predicate, not ${show(error instanceof Error ? error.message : error)}`);
351
+ assert.ok(error instanceof Error && error.message.includes("the predicate failed"), `find() must reject with the error of the predicate, not ${show(error instanceof Error ? error.message : error)}`);
345
352
  }));
346
353
  add("clear() deletes every item, and the storage takes new items after it", () => withStorage(create, async (storage) => {
347
354
  await storage.setBatch([["a", item("a", 1)], ["b", item("b", 2)], ["c", item("c", 3)]]);
348
355
  await storage.clear();
349
- same(await storage.size(), 0, "size() after clear()");
350
- same(await storage.getAll(), [], "getAll() after clear()");
351
- same(await storage.has("a"), false, "has() after clear()");
356
+ assert.deepStrictEqual(await storage.size(), 0, "size() after clear()");
357
+ assert.deepStrictEqual(await storage.getAll(), [], "getAll() after clear()");
358
+ assert.deepStrictEqual(await storage.has("a"), false, "has() after clear()");
352
359
  await storage.clear();
353
360
  await storage.set("d", item("d", 4));
354
- same(await storage.getAll(), [item("d", 4)], "getAll() after clear() and set()");
361
+ assert.deepStrictEqual(await storage.getAll(), [item("d", 4)], "getAll() after clear() and set()");
355
362
  }));
356
363
  add("each result is a new array or map: a change of a result does not change the storage", () => withStorage(create, async (storage) => {
357
364
  await storage.setBatch([["a", item("a", 1)], ["b", item("b", 2)]]);
@@ -365,9 +372,9 @@ export function collectionStorageContract(options) {
365
372
  batch.set("z", item("z", 0));
366
373
  if (storage.getEntries)
367
374
  (await storage.getEntries()).splice(0);
368
- same(ids(await storage.getAll()), ["a", "b"], "getAll() after changes of the results");
369
- same(await storage.has("z"), false, "has() of an id that only a result got");
370
- same(await storage.getBatch(["a"]), new Map([["a", item("a", 1)]]), "getBatch() after a change of a result");
375
+ assert.deepStrictEqual(ids(await storage.getAll()), ["a", "b"], "getAll() after changes of the results");
376
+ assert.deepStrictEqual(await storage.has("z"), false, "has() of an id that only a result got");
377
+ assert.deepStrictEqual(await storage.getBatch(["a"]), new Map([["a", item("a", 1)]]), "getBatch() after a change of a result");
371
378
  }));
372
379
  add("the storage keeps copies: a change of a written or a read value does not change the item", () => withStorage(create, async (storage) => {
373
380
  const value = item("a", 1, ["x"]);
@@ -378,8 +385,8 @@ export function collectionStorageContract(options) {
378
385
  await storage.setBatch([["b", batch]]);
379
386
  batch.tags.push("changed after setBatch");
380
387
  const read = (await storage.get("a"));
381
- same(read, item("a", 1, ["x"]), "get() after a change of the value that set() took");
382
- same(await storage.get("b"), item("b", 2, ["y"]), "get() after a change of the value that setBatch() took");
388
+ assert.deepStrictEqual(read, item("a", 1, ["x"]), "get() after a change of the value that set() took");
389
+ assert.deepStrictEqual(await storage.get("b"), item("b", 2, ["y"]), "get() after a change of the value that setBatch() took");
383
390
  read.n = 98;
384
391
  read.tags.push("changed after get");
385
392
  (await storage.getAll())[0].n = 97;
@@ -409,10 +416,10 @@ export function collectionStorageContract(options) {
409
416
  });
410
417
  await storage.set("c", item("c", 3, ["z"]));
411
418
  stop();
412
- same(await storage.get("c"), item("c", 3, ["z"]), "get() after an observer changed the value of a change");
419
+ assert.deepStrictEqual(await storage.get("c"), item("c", 3, ["z"]), "get() after an observer changed the value of a change");
413
420
  }
414
- same(await storage.get("a"), item("a", 1, ["x"]), "get() after changes of the read values");
415
- same(await storage.get("b"), item("b", 2, ["y"]), "get() of the other item after changes of the read values");
421
+ assert.deepStrictEqual(await storage.get("a"), item("a", 1, ["x"]), "get() after changes of the read values");
422
+ assert.deepStrictEqual(await storage.get("b"), item("b", 2, ["y"]), "get() of the other item after changes of the read values");
416
423
  }));
417
424
  add("the storage keeps JSON values, also null", () => withStorage(create, async (typed) => {
418
425
  const storage = typed;
@@ -428,20 +435,20 @@ export function collectionStorageContract(options) {
428
435
  ];
429
436
  await storage.setBatch(values);
430
437
  for (const [id, value] of values)
431
- same(await storage.get(id), value, `get("${id}")`);
432
- same(await storage.getAll(), values.map(([, value]) => value), "getAll() of the JSON values");
433
- same(await storage.getBatch(values.map(([id]) => id)), new Map(values), "getBatch() of the JSON values");
434
- same(await storage.size(), values.length, "size() with the JSON values");
435
- same(await storage.has("null"), true, "has() of an id whose value is null");
438
+ assert.deepStrictEqual(await storage.get(id), value, `get("${id}")`);
439
+ assert.deepStrictEqual(await storage.getAll(), values.map(([, value]) => value), "getAll() of the JSON values");
440
+ assert.deepStrictEqual(await storage.getBatch(values.map(([id]) => id)), new Map(values), "getBatch() of the JSON values");
441
+ assert.deepStrictEqual(await storage.size(), values.length, "size() with the JSON values");
442
+ assert.deepStrictEqual(await storage.has("null"), true, "has() of an id whose value is null");
436
443
  await storage.set("single", null);
437
- same(await storage.get("single"), null, "get() of an id that set() gave the value null");
438
- same(await storage.get("missing"), undefined, "get() of a missing id, next to a stored null");
444
+ assert.deepStrictEqual(await storage.get("single"), null, "get() of an id that set() gave the value null");
445
+ assert.deepStrictEqual(await storage.get("missing"), undefined, "get() of a missing id, next to a stored null");
439
446
  }));
440
447
  add("writes that run at the same time keep each write", () => withStorage(create, async (storage) => {
441
448
  const count = 20;
442
449
  await Promise.all(Array.from({ length: count }, (_, n) => storage.set(`k${n}`, item(`k${n}`, n))));
443
- same(await storage.size(), count, `size() after ${count} writes at the same time`);
444
- same(ids(await storage.getAll()).sort(), Array.from({ length: count }, (_, n) => `k${n}`).sort(), "the ids after the writes at the same time");
450
+ assert.deepStrictEqual(await storage.size(), count, `size() after ${count} writes at the same time`);
451
+ assert.deepStrictEqual(ids(await storage.getAll()).sort(), Array.from({ length: count }, (_, n) => `k${n}`).sort(), "the ids after the writes at the same time");
445
452
  }));
446
453
  add("getChangesSince() without a version gives every item, in the order of the entries", (context) => withStorage(create, async (storage) => {
447
454
  if (lacks(storage, "getChangesSince", context))
@@ -451,10 +458,10 @@ export function collectionStorageContract(options) {
451
458
  await storage.setBatch(entries);
452
459
  await storage.set("c", item("c", 30));
453
460
  const first = await changes();
454
- holds(typeof first.version === "string" && first.version !== "", `the version must be a text that is not empty, not ${show(first.version)}`);
455
- same(first.full, true, "full of the first call");
456
- same(first.changed, [["c", item("c", 30)], ["a", item("a", 1)], ["b", item("b", 2)]], "changed of the first call: every item, in the order of the entries");
457
- same(first.deleted, [], "deleted of a full result");
461
+ assert.ok(typeof first.version === "string" && first.version !== "", `the version must be a text that is not empty, not ${show(first.version)}`);
462
+ assert.deepStrictEqual(first.full, true, "full of the first call");
463
+ assert.deepStrictEqual(first.changed, [["c", item("c", 30)], ["a", item("a", 1)], ["b", item("b", 2)]], "changed of the first call: every item, in the order of the entries");
464
+ assert.deepStrictEqual(first.deleted, [], "deleted of a full result");
458
465
  }));
459
466
  add("getChangesSince(version) gives the items that changed after the version and the ids that were deleted", (context) => withStorage(create, async (storage) => {
460
467
  if (lacks(storage, "getChangesSince", context))
@@ -467,10 +474,10 @@ export function collectionStorageContract(options) {
467
474
  await storage.delete("missing");
468
475
  await storage.set("d", item("d", 4));
469
476
  const delta = await changes(start.version);
470
- same(delta.full, false, "full of a delta");
471
- same(delta.changed, [["a", item("a", 10)], ["d", item("d", 4)]], "changed of a delta");
472
- same(delta.deleted, ["b"], "deleted of a delta");
473
- holds(delta.version !== start.version, "the version must change after a write");
477
+ assert.deepStrictEqual(delta.full, false, "full of a delta");
478
+ assert.deepStrictEqual(delta.changed, [["a", item("a", 10)], ["d", item("d", 4)]], "changed of a delta");
479
+ assert.deepStrictEqual(delta.deleted, ["b"], "deleted of a delta");
480
+ assert.ok(delta.version !== start.version, "the version must change after a write");
474
481
  }));
475
482
  add("getChangesSince(version) gives the changes in the order of the last change of each id", (context) => withStorage(create, async (storage) => {
476
483
  if (lacks(storage, "getChangesSince", context))
@@ -485,13 +492,13 @@ export function collectionStorageContract(options) {
485
492
  await storage.delete("c");
486
493
  await storage.setBatch([["e", item("e", 5)], ["b", item("b", 21)]]);
487
494
  const delta = await changes(start.version);
488
- same({ changed: delta.changed, deleted: delta.deleted }, { changed: [["a", item("a", 10)], ["e", item("e", 5)], ["b", item("b", 21)]], deleted: ["d", "c"] }, "the order of a delta: an id written again after another id comes after it");
495
+ assert.deepStrictEqual({ changed: delta.changed, deleted: delta.deleted }, { changed: [["a", item("a", 10)], ["e", item("e", 5)], ["b", item("b", 21)]], deleted: ["d", "c"] }, "the order of a delta: an id written again after another id comes after it");
489
496
  // A delete of d again is not a change. A new set of c moves it from deleted to changed.
490
497
  await storage.delete("d");
491
498
  await storage.set("c", item("c", 30));
492
499
  await storage.deleteBatch(["e", "a"]);
493
500
  const next = await changes(delta.version);
494
- same({ changed: next.changed, deleted: next.deleted }, { changed: [["c", item("c", 30)]], deleted: ["e", "a"] }, "the order of the next delta");
501
+ assert.deepStrictEqual({ changed: next.changed, deleted: next.deleted }, { changed: [["c", item("c", 30)]], deleted: ["e", "a"] }, "the order of the next delta");
495
502
  }));
496
503
  add("getChangesSince(): a deleted id that comes back is a change, clear() deletes each id in the order of the entries, and no write gives no change", (context) => withStorage(create, async (storage) => {
497
504
  if (lacks(storage, "getChangesSince", context))
@@ -502,13 +509,13 @@ export function collectionStorageContract(options) {
502
509
  await storage.delete("b");
503
510
  await storage.set("b", item("b", 20));
504
511
  const back = await changes(start.version);
505
- same({ full: back.full, changed: back.changed, deleted: back.deleted }, { full: false, changed: [["b", item("b", 20)]], deleted: [] }, "a delete, then a set of the id");
512
+ assert.deepStrictEqual({ full: back.full, changed: back.changed, deleted: back.deleted }, { full: false, changed: [["b", item("b", 20)]], deleted: [] }, "a delete, then a set of the id");
506
513
  // The entries are a, c, b now: b went to the end at its new set
507
514
  await storage.clear();
508
515
  const cleared = await changes(back.version);
509
- same({ full: cleared.full, changed: cleared.changed, deleted: cleared.deleted }, { full: false, changed: [], deleted: ["a", "c", "b"] }, "the changes of clear()");
516
+ assert.deepStrictEqual({ full: cleared.full, changed: cleared.changed, deleted: cleared.deleted }, { full: false, changed: [], deleted: ["a", "c", "b"] }, "the changes of clear()");
510
517
  const quiet = await changes(cleared.version);
511
- same({ full: quiet.full, changed: quiet.changed, deleted: quiet.deleted }, { full: false, changed: [], deleted: [] }, "the changes without a write");
518
+ assert.deepStrictEqual({ full: quiet.full, changed: quiet.changed, deleted: quiet.deleted }, { full: false, changed: [], deleted: [] }, "the changes without a write");
512
519
  }));
513
520
  add("getChangesSince() gives every item for an unknown version and for a version of another storage", (context) => withStorage(create, async (storage) => {
514
521
  if (lacks(storage, "getChangesSince", context))
@@ -518,12 +525,12 @@ export function collectionStorageContract(options) {
518
525
  await changes();
519
526
  for (const unknown of ["not a version", ""]) {
520
527
  const result = await changes(unknown);
521
- same({ full: result.full, changed: result.changed, deleted: result.deleted }, { full: true, changed: [["a", item("a", 1)], ["b", item("b", 2)]], deleted: [] }, `the changes since ${show(unknown)}`);
528
+ assert.deepStrictEqual({ full: result.full, changed: result.changed, deleted: result.deleted }, { full: true, changed: [["a", item("a", 1)], ["b", item("b", 2)]], deleted: [] }, `the changes since ${show(unknown)}`);
522
529
  }
523
530
  await withStorage(create, async (other) => {
524
531
  await other.set("x", item("x", 9));
525
532
  const foreign = (await changesOf(other)()).version;
526
- same((await changes(foreign)).full, true, "full for a version of another storage");
533
+ assert.deepStrictEqual((await changes(foreign)).full, true, "full for a version of another storage");
527
534
  });
528
535
  }));
529
536
  if (options.createWithMaxTombstones) {
@@ -537,12 +544,12 @@ export function collectionStorageContract(options) {
537
544
  // Two deletes fit in the log
538
545
  await storage.deleteBatch(["a", "b"]);
539
546
  const two = await changes(start.version);
540
- same({ full: two.full, changed: two.changed, deleted: two.deleted }, { full: false, changed: [], deleted: ["a", "b"] }, "two deletes in a log of two");
547
+ assert.deepStrictEqual({ full: two.full, changed: two.changed, deleted: two.deleted }, { full: false, changed: [], deleted: ["a", "b"] }, "two deletes in a log of two");
541
548
  // The third delete drops the oldest one: the start version gives all items now
542
549
  await storage.delete("c");
543
550
  const after = await changes(start.version);
544
- same({ full: after.full, changed: after.changed, deleted: after.deleted }, { full: true, changed: [["d", item("d", 4)]], deleted: [] }, "a version older than a dropped delete");
545
- same((await changes(after.version)).full, false, "a version after the dropped deletes still gives a delta");
551
+ assert.deepStrictEqual({ full: after.full, changed: after.changed, deleted: after.deleted }, { full: true, changed: [["d", item("d", 4)]], deleted: [] }, "a version older than a dropped delete");
552
+ assert.deepStrictEqual((await changes(after.version)).full, false, "a version after the dropped deletes still gives a delta");
546
553
  }));
547
554
  }
548
555
  add("a random sequence of writes agrees with a Map, and each version gives the right changes in the right order", () => withStorage(create, async (storage) => {
@@ -576,7 +583,7 @@ export function collectionStorageContract(options) {
576
583
  const existed = model.delete(id);
577
584
  if (existed)
578
585
  note(id, true);
579
- same(await storage.delete(id), existed, `the result of step ${step}: ${label}`);
586
+ assert.deepStrictEqual(await storage.delete(id), existed, `the result of step ${step}: ${label}`);
580
587
  }
581
588
  else if (kind < 15) {
582
589
  const batch = Array.from({ length: 1 + random(3) }, (_, index) => {
@@ -599,7 +606,7 @@ export function collectionStorageContract(options) {
599
606
  note(id, true);
600
607
  return existed;
601
608
  }).length;
602
- same(await storage.deleteBatch(batch), expected, `the result of step ${step}: ${label}`);
609
+ assert.deepStrictEqual(await storage.deleteBatch(batch), expected, `the result of step ${step}: ${label}`);
603
610
  }
604
611
  else if (kind < 19) {
605
612
  label = "clear()";
@@ -613,20 +620,20 @@ export function collectionStorageContract(options) {
613
620
  if (hasChanges)
614
621
  versions.push({ version: (await storage.getChangesSince()).version, entries: new Map(model), at: clock });
615
622
  }
616
- same(await storage.getAll(), [...model.values()], `getAll() after step ${step}: ${label}`);
623
+ assert.deepStrictEqual(await storage.getAll(), [...model.values()], `getAll() after step ${step}: ${label}`);
617
624
  }
618
- same(await storage.size(), model.size, "size() after the sequence");
625
+ assert.deepStrictEqual(await storage.size(), model.size, "size() after the sequence");
619
626
  if (storage.getEntries)
620
- same(await storage.getEntries(), [...model.entries()], "getEntries() after the sequence");
627
+ assert.deepStrictEqual(await storage.getEntries(), [...model.entries()], "getEntries() after the sequence");
621
628
  if (storage.getIds)
622
- same(await storage.getIds(), [...model.keys()], "getIds() after the sequence");
629
+ assert.deepStrictEqual(await storage.getIds(), [...model.keys()], "getIds() after the sequence");
623
630
  if (!hasChanges)
624
631
  return;
625
- holds(versions.length > 0, "the sequence saved no version: change the seed");
632
+ assert.ok(versions.length > 0, "the sequence saved no version: change the seed");
626
633
  for (const [index, saved] of versions.entries()) {
627
634
  const result = await storage.getChangesSince(saved.version);
628
635
  if (result.full) {
629
- same(result.changed, [...model.entries()], `the full changes since version ${index}: every item, in the order of the entries`);
636
+ assert.deepStrictEqual(result.changed, [...model.entries()], `the full changes since version ${index}: every item, in the order of the entries`);
630
637
  continue;
631
638
  }
632
639
  // A delta: the changes after the version, in the order of the last change of each id
@@ -635,13 +642,13 @@ export function collectionStorageContract(options) {
635
642
  changed: after.filter(([, change]) => !change.deleted).map(([id]) => [id, model.get(id)]),
636
643
  deleted: after.filter(([, change]) => change.deleted).map(([id]) => id),
637
644
  };
638
- same({ changed: result.changed, deleted: result.deleted }, expected, `the changes since version ${index}`);
645
+ assert.deepStrictEqual({ changed: result.changed, deleted: result.deleted }, expected, `the changes since version ${index}`);
639
646
  const rebuilt = new Map(saved.entries);
640
647
  for (const id of result.deleted)
641
648
  rebuilt.delete(id);
642
649
  for (const [id, value] of result.changed)
643
650
  rebuilt.set(id, value);
644
- same(rebuilt, new Map(model), `the items of version ${index} with its changes`);
651
+ assert.deepStrictEqual(rebuilt, new Map(model), `the items of version ${index} with its changes`);
645
652
  }
646
653
  }));
647
654
  //
@@ -654,8 +661,8 @@ export function collectionStorageContract(options) {
654
661
  await storage.setBatch([...DOCUMENTS]);
655
662
  for (const [selector, expected] of SELECTOR_CASES) {
656
663
  const result = await storage.query(selector);
657
- same(entryIds(result), expected, `the ids of query(${show(selector)})`);
658
- same(result, queryEntries(DOCUMENTS, selector), `the entries of query(${show(selector)})`);
664
+ assert.deepStrictEqual(entryIds(result), expected, `the ids of query(${show(selector)})`);
665
+ assert.deepStrictEqual(result, queryEntries(DOCUMENTS, selector), `the entries of query(${show(selector)})`);
659
666
  }
660
667
  }));
661
668
  add("query() sorts, then skips, then limits, and items with equal keys keep the order of the entries", (context) => withStorage(create, async (typed) => {
@@ -664,9 +671,9 @@ export function collectionStorageContract(options) {
664
671
  const storage = typed;
665
672
  await storage.setBatch([...DOCUMENTS]);
666
673
  for (const [options, expected] of OPTION_CASES) {
667
- same(entryIds(await storage.query({}, options)), expected, `the ids of query({}, ${show(options)})`);
674
+ assert.deepStrictEqual(entryIds(await storage.query({}, options)), expected, `the ids of query({}, ${show(options)})`);
668
675
  }
669
- same(entryIds(await storage.query({ n: { $exists: true } }, { sort: { n: -1 }, limit: 2 })), ["e", "d"], "a selector with a sort and a limit");
676
+ assert.deepStrictEqual(entryIds(await storage.query({ n: { $exists: true } }, { sort: { n: -1 }, limit: 2 })), ["e", "d"], "a selector with a sort and a limit");
670
677
  }));
671
678
  add("query() rejects a selector or options that are not correct", (context) => withStorage(create, async (typed) => {
672
679
  if (lacks(typed, "query", context))
@@ -714,7 +721,7 @@ export function collectionStorageContract(options) {
714
721
  if (expected === undefined)
715
722
  await rejects(() => storage.query(selector, options), label);
716
723
  else
717
- same(await storage.query(selector, options), expected, label);
724
+ assert.deepStrictEqual(await storage.query(selector, options), expected, label);
718
725
  }
719
726
  }));
720
727
  add("query() refuses $regex without a policy that permits it, and a pattern that repeats a repetition", (context) => withStorage(create, async (typed) => {
@@ -734,8 +741,8 @@ export function collectionStorageContract(options) {
734
741
  await storage.setBatch([...DOCUMENTS]);
735
742
  for (const [selector, expected] of REGEX_CASES) {
736
743
  const result = await storage.query(selector);
737
- same(entryIds(result), expected, `the ids of query(${show(selector)})`);
738
- same(result, queryEntries(DOCUMENTS, selector, {}, REGEX_POLICY), `the entries of query(${show(selector)})`);
744
+ assert.deepStrictEqual(entryIds(result), expected, `the ids of query(${show(selector)})`);
745
+ assert.deepStrictEqual(result, queryEntries(DOCUMENTS, selector, {}, REGEX_POLICY), `the entries of query(${show(selector)})`);
739
746
  }
740
747
  await rejects(() => storage.query(REDOS), `query(${show(REDOS)}) under a policy with $regex`);
741
748
  }));
@@ -776,7 +783,7 @@ export function collectionStorageContract(options) {
776
783
  [{}, { skip: 5 }, ["f", "g"]],
777
784
  ];
778
785
  for (const [selector, query, expected] of permitted) {
779
- same(entryIds(await storage.query(selector, query)), expected, `the ids of query(${show(selector)}, ${show(query)})`);
786
+ assert.deepStrictEqual(entryIds(await storage.query(selector, query)), expected, `the ids of query(${show(selector)}, ${show(query)})`);
780
787
  }
781
788
  }));
782
789
  }
@@ -788,27 +795,27 @@ export function collectionStorageContract(options) {
788
795
  return;
789
796
  const storage = typed;
790
797
  await storage.set("a", { id: "a", n: 1, tags: ["x"], meta: { kind: "k1", score: 10 } });
791
- same(await storage.patch("a", { n: 2 }), { id: "a", n: 2, tags: ["x"], meta: { kind: "k1", score: 10 } }, "patch() of one field");
792
- same(await storage.patch("a", { meta: { score: 11, extra: true }, tags: null }), { id: "a", n: 2, meta: { kind: "k1", score: 11, extra: true } }, "patch() of an object field and a null field");
793
- same(await storage.patch("a", { tags: ["y", "z"], meta: { extra: null } }), { id: "a", n: 2, meta: { kind: "k1", score: 11 }, tags: ["y", "z"] }, "patch() of an array field and a nested null");
794
- same(await storage.get("a"), { id: "a", n: 2, meta: { kind: "k1", score: 11 }, tags: ["y", "z"] }, "get() after the patches");
795
- same(await storage.patch("missing", { n: 1 }), undefined, "patch() of a missing id");
796
- same(await storage.has("missing"), false, "has() of a missing id after patch()");
797
- same(await storage.size(), 1, "size() after patch() of a missing id");
798
+ assert.deepStrictEqual(await storage.patch("a", { n: 2 }), { id: "a", n: 2, tags: ["x"], meta: { kind: "k1", score: 10 } }, "patch() of one field");
799
+ assert.deepStrictEqual(await storage.patch("a", { meta: { score: 11, extra: true }, tags: null }), { id: "a", n: 2, meta: { kind: "k1", score: 11, extra: true } }, "patch() of an object field and a null field");
800
+ assert.deepStrictEqual(await storage.patch("a", { tags: ["y", "z"], meta: { extra: null } }), { id: "a", n: 2, meta: { kind: "k1", score: 11 }, tags: ["y", "z"] }, "patch() of an array field and a nested null");
801
+ assert.deepStrictEqual(await storage.get("a"), { id: "a", n: 2, meta: { kind: "k1", score: 11 }, tags: ["y", "z"] }, "get() after the patches");
802
+ assert.deepStrictEqual(await storage.patch("missing", { n: 1 }), undefined, "patch() of a missing id");
803
+ assert.deepStrictEqual(await storage.has("missing"), false, "has() of a missing id after patch()");
804
+ assert.deepStrictEqual(await storage.size(), 1, "size() after patch() of a missing id");
798
805
  await storage.set("plain", 5);
799
- same(await storage.patch("plain", { n: 1 }), { n: 1 }, "patch() of an item that is not an object");
806
+ assert.deepStrictEqual(await storage.patch("plain", { n: 1 }), { n: 1 }, "patch() of an item that is not an object");
800
807
  for (const fields of [null, [1], "x", 3]) {
801
808
  await rejects(() => storage.patch("a", fields), `patch() with the fields ${show(fields)}`);
802
809
  }
803
- same(await storage.get("a"), { id: "a", n: 2, meta: { kind: "k1", score: 11 }, tags: ["y", "z"] }, "get() after the patches that were not correct");
810
+ assert.deepStrictEqual(await storage.get("a"), { id: "a", n: 2, meta: { kind: "k1", score: 11 }, tags: ["y", "z"] }, "get() after the patches that were not correct");
804
811
  }));
805
812
  add("patch() with the operations $set and $unset sets null and nested paths, and a patch of two forms rejects", (context) => withStorage(create, async (typed) => {
806
813
  if (lacks(typed, "patch", context))
807
814
  return;
808
815
  const storage = typed;
809
816
  await storage.set("a", { id: "a", n: 1, tags: ["x", "y"], meta: { kind: "k1", score: 10 } });
810
- same(await storage.patch("a", { $set: { "meta.kind": "k2", note: null, "tags.1": "z", "deep.new.path": 1 }, $unset: ["meta.score"] }), { id: "a", n: 1, tags: ["x", "z"], meta: { kind: "k2" }, note: null, deep: { new: { path: 1 } } }, "patch() with $set and $unset");
811
- same(await storage.patch("a", { $unset: ["tags.0", "missing.path", "deep"], $set: { "tags.2": "w" } }), { id: "a", n: 1, tags: [null, "z", "w"], meta: { kind: "k2" }, note: null }, "patch() that removes an element of an array, a missing path and a field, and adds an element");
817
+ assert.deepStrictEqual(await storage.patch("a", { $set: { "meta.kind": "k2", note: null, "tags.1": "z", "deep.new.path": 1 }, $unset: ["meta.score"] }), { id: "a", n: 1, tags: ["x", "z"], meta: { kind: "k2" }, note: null, deep: { new: { path: 1 } } }, "patch() with $set and $unset");
818
+ assert.deepStrictEqual(await storage.patch("a", { $unset: ["tags.0", "missing.path", "deep"], $set: { "tags.2": "w" } }), { id: "a", n: 1, tags: [null, "z", "w"], meta: { kind: "k2" }, note: null }, "patch() that removes an element of an array, a missing path and a field, and adds an element");
812
819
  const after = { id: "a", n: 1, tags: [null, "z", "w"], meta: { kind: "k2" }, note: null };
813
820
  const wrong = [
814
821
  ["a patch of two forms", { $set: { n: 2 }, n: 3 }],
@@ -821,17 +828,17 @@ export function collectionStorageContract(options) {
821
828
  ];
822
829
  for (const [what, fields] of wrong)
823
830
  await rejects(() => storage.patch("a", fields), `patch() with ${what}`);
824
- same(await storage.get("a"), after, "get() after the patches that were not correct");
825
- same(await storage.patch("missing", { $set: { n: 1 } }), undefined, "patch() with $set of a missing id");
826
- same(await storage.has("missing"), false, "has() of a missing id after patch() with $set");
831
+ assert.deepStrictEqual(await storage.get("a"), after, "get() after the patches that were not correct");
832
+ assert.deepStrictEqual(await storage.patch("missing", { $set: { n: 1 } }), undefined, "patch() with $set of a missing id");
833
+ assert.deepStrictEqual(await storage.has("missing"), false, "has() of a missing id after patch() with $set");
827
834
  }));
828
835
  add("patch() with $remove and $insert moves the elements of an array, and each index refers to the item before the patch", (context) => withStorage(create, async (typed) => {
829
836
  if (lacks(typed, "patch", context))
830
837
  return;
831
838
  const storage = typed;
832
839
  await storage.set("a", { id: "a", tags: ["a", "b", "c", "d"], rows: [{ n: 1, keys: ["x"] }, { n: 2, keys: ["y"] }], meta: { kind: "k1" } });
833
- same(await storage.patch("a", { $remove: ["tags.1", "tags.3", "meta.kind"], $insert: { "rows.1.keys.0": "w" } }), { id: "a", tags: ["a", "c"], rows: [{ n: 1, keys: ["x"] }, { n: 2, keys: ["w", "y"] }], meta: {} }, "patch() with $remove and $insert");
834
- same(await storage.patch("a", { $insert: { "tags.0": "z", "tags.2": "e" }, $remove: ["rows.0", "missing.0"], $set: { "rows.1.n": 3 } }), { id: "a", tags: ["z", "a", "c", "e"], rows: [{ n: 3, keys: ["w", "y"] }], meta: {} }, "patch() that inserts at the start and at the end, and removes a missing path");
840
+ assert.deepStrictEqual(await storage.patch("a", { $remove: ["tags.1", "tags.3", "meta.kind"], $insert: { "rows.1.keys.0": "w" } }), { id: "a", tags: ["a", "c"], rows: [{ n: 1, keys: ["x"] }, { n: 2, keys: ["w", "y"] }], meta: {} }, "patch() with $remove and $insert");
841
+ assert.deepStrictEqual(await storage.patch("a", { $insert: { "tags.0": "z", "tags.2": "e" }, $remove: ["rows.0", "missing.0"], $set: { "rows.1.n": 3 } }), { id: "a", tags: ["z", "a", "c", "e"], rows: [{ n: 3, keys: ["w", "y"] }], meta: {} }, "patch() that inserts at the start and at the end, and removes a missing path");
835
842
  const after = { id: "a", tags: ["z", "a", "c", "e"], rows: [{ n: 3, keys: ["w", "y"] }], meta: {} };
836
843
  const wrong = [
837
844
  ["a $remove that is not a list of paths", { $remove: "tags" }],
@@ -843,7 +850,7 @@ export function collectionStorageContract(options) {
843
850
  ];
844
851
  for (const [what, fields] of wrong)
845
852
  await rejects(() => storage.patch("a", fields), `patch() with ${what}`);
846
- same(await storage.get("a"), after, "get() after the patches that were not correct");
853
+ assert.deepStrictEqual(await storage.get("a"), after, "get() after the patches that were not correct");
847
854
  }));
848
855
  add("patch() runs in one step: patches of one item at the same time keep each field", (context) => withStorage(create, async (typed) => {
849
856
  if (lacks(typed, "patch", context))
@@ -855,7 +862,7 @@ export function collectionStorageContract(options) {
855
862
  const expected = { id: "a" };
856
863
  for (let n = 0; n < count; n++)
857
864
  expected[`f${n}`] = n;
858
- same(await storage.get("a"), expected, `get() after ${count} patches at the same time`);
865
+ assert.deepStrictEqual(await storage.get("a"), expected, `get() after ${count} patches at the same time`);
859
866
  }));
860
867
  add("patch() is a change: getChangesSince() gives the patched item", (context) => withStorage(create, async (storage) => {
861
868
  if (lacks(storage, "patch", context) || lacks(storage, "getChangesSince", context))
@@ -865,7 +872,7 @@ export function collectionStorageContract(options) {
865
872
  await storage.patch("a", { n: 10 });
866
873
  await storage.patch("missing", { n: 3 });
867
874
  const delta = await storage.getChangesSince(start.version);
868
- same({ full: delta.full, changed: delta.changed, deleted: delta.deleted }, { full: false, changed: [["a", item("a", 10)]], deleted: [] }, "the changes after a patch");
875
+ assert.deepStrictEqual({ full: delta.full, changed: delta.changed, deleted: delta.deleted }, { full: false, changed: [["a", item("a", 10)]], deleted: [] }, "the changes after a patch");
869
876
  }));
870
877
  //
871
878
  // ═══ observe() ═══
@@ -876,7 +883,7 @@ export function collectionStorageContract(options) {
876
883
  const batches = [];
877
884
  const stop = storage.observe((batch) => batches.push(plainBatch(batch)));
878
885
  await storage.set("a", item("a", 1));
879
- same(batches.length, 1, "the batches when set() resolves");
886
+ assert.deepStrictEqual(batches.length, 1, "the batches when set() resolves");
880
887
  await storage.setBatch([["b", item("b", 2)], ["c", item("c", 3)]]);
881
888
  await storage.delete("a");
882
889
  await storage.deleteBatch(["b", "missing"]);
@@ -884,7 +891,7 @@ export function collectionStorageContract(options) {
884
891
  await storage.patch("c", { n: 30 });
885
892
  await storage.clear();
886
893
  stop();
887
- same(batches, [
894
+ assert.deepStrictEqual(batches, [
888
895
  [{ type: "set", id: "a", value: item("a", 1) }],
889
896
  [
890
897
  { type: "set", id: "b", value: item("b", 2) },
@@ -908,7 +915,7 @@ export function collectionStorageContract(options) {
908
915
  await storage.clear();
909
916
  if (storage.patch)
910
917
  await storage.patch("missing", { n: 1 });
911
- same(batches, [], "the batches of the writes that change nothing");
918
+ assert.deepStrictEqual(batches, [], "the batches of the writes that change nothing");
912
919
  await storage.set("a", item("a", 1), { origin: "sync" });
913
920
  await storage.setBatch([["b", item("b", 2)]], { origin: "app" });
914
921
  await storage.delete("a", { origin: "sync" });
@@ -916,7 +923,7 @@ export function collectionStorageContract(options) {
916
923
  await storage.set("c", item("c", 3), {});
917
924
  await storage.clear({ origin: "reset" });
918
925
  stop();
919
- same(batches, [
926
+ assert.deepStrictEqual(batches, [
920
927
  [{ type: "set", id: "a", value: item("a", 1), origin: "sync" }],
921
928
  [{ type: "set", id: "b", value: item("b", 2), origin: "app" }],
922
929
  [{ type: "delete", id: "a", origin: "sync" }],
@@ -938,8 +945,8 @@ export function collectionStorageContract(options) {
938
945
  await storage.delete("a");
939
946
  stopSecond();
940
947
  await storage.set("b", item("b", 2));
941
- same(first, ["set"], "the changes of the first observer");
942
- same(second, ["set", "delete"], "the changes of the second observer");
948
+ assert.deepStrictEqual(first, ["set"], "the changes of the first observer");
949
+ assert.deepStrictEqual(second, ["set", "delete"], "the changes of the second observer");
943
950
  }));
944
951
  add("flush() resolves, and the items stay", (context) => withStorage(create, async (storage) => {
945
952
  if (lacks(storage, "flush", context))
@@ -947,15 +954,15 @@ export function collectionStorageContract(options) {
947
954
  await storage.flush();
948
955
  await storage.set("a", item("a", 1));
949
956
  await storage.flush();
950
- same(await storage.get("a"), item("a", 1), "get() after flush()");
957
+ assert.deepStrictEqual(await storage.get("a"), item("a", 1), "get() after flush()");
951
958
  }));
952
959
  add("getMetadata() gives a known type and the size", (context) => withStorage(create, async (storage) => {
953
960
  if (lacks(storage, "getMetadata", context))
954
961
  return;
955
962
  await storage.setBatch([["a", item("a", 1)], ["b", item("b", 2)]]);
956
963
  const metadata = await storage.getMetadata();
957
- holds(["memory", "api", "hybrid", "synced", "custom"].includes(metadata.type), `getMetadata() gave the unknown type ${show(metadata.type)}`);
958
- same(metadata.size, 2, "the size of getMetadata()");
964
+ assert.ok(["memory", "api", "hybrid", "synced", "custom"].includes(metadata.type), `getMetadata() gave the unknown type ${show(metadata.type)}`);
965
+ assert.deepStrictEqual(metadata.size, 2, "the size of getMetadata()");
959
966
  }));
960
967
  add("after close(), each operation rejects with an error that says that the storage is closed, and a second close() does nothing", () => withStorage(create, async (storage) => {
961
968
  await storage.set("a", item("a", 1));
@@ -993,7 +1000,7 @@ export function collectionStorageContract(options) {
993
1000
  const check = async (when) => {
994
1001
  for (const [name, start] of operations) {
995
1002
  const error = await rejects(start, `${name}() ${when}`);
996
- holds(error instanceof Error && /closed/i.test(error.message), `${name}() ${when} must reject with an Error whose message says "closed", not ${show(error instanceof Error ? error.message : error)}`);
1003
+ assert.ok(error instanceof Error && /closed/i.test(error.message), `${name}() ${when} must reject with an Error whose message says "closed", not ${show(error instanceof Error ? error.message : error)}`);
997
1004
  }
998
1005
  };
999
1006
  const checkObserve = (when) => {
@@ -1006,7 +1013,7 @@ export function collectionStorageContract(options) {
1006
1013
  catch (thrown) {
1007
1014
  error = thrown;
1008
1015
  }
1009
- holds(error instanceof Error && /closed/i.test(error.message), `observe() ${when} must throw an Error whose message says "closed", not ${show(error instanceof Error ? error.message : error)}`);
1016
+ assert.ok(error instanceof Error && /closed/i.test(error.message), `observe() ${when} must throw an Error whose message says "closed", not ${show(error instanceof Error ? error.message : error)}`);
1010
1017
  };
1011
1018
  await check("after close()");
1012
1019
  checkObserve("after close()");
@@ -1024,9 +1031,9 @@ export function collectionStorageContract(options) {
1024
1031
  */
1025
1032
  function conflictsOfRejection(error, what) {
1026
1033
  const code = error?.code;
1027
- holds(code === "VERSION_CONFLICT", `${what}: the error must have the code VERSION_CONFLICT, not ${show(code)} (${show(error instanceof Error ? error.message : error)})`);
1034
+ assert.ok(code === "VERSION_CONFLICT", `${what}: the error must have the code VERSION_CONFLICT, not ${show(code)} (${show(error instanceof Error ? error.message : error)})`);
1028
1035
  const conflicts = versionConflictsOf(error);
1029
- holds(conflicts !== undefined, `${what}: the error must have its conflicts`);
1036
+ assert.ok(conflicts !== undefined, `${what}: the error must have its conflicts`);
1030
1037
  return conflicts;
1031
1038
  }
1032
1039
  /** The cases of the preconditions of the writes (roadmap CLI-16). */
@@ -1036,10 +1043,10 @@ function addPreconditionCases(add, create, createWithVersions) {
1036
1043
  await rejects(() => storage.set("a", item("a", 2), { expectedVersion: "v1" }), "set() with expectedVersion on a storage without versions");
1037
1044
  await rejects(() => storage.delete("a", { expectedVersion: "v1" }), "delete() with expectedVersion on a storage without versions");
1038
1045
  await rejects(() => storage.setBatch([["a", item("a", 3)]], { expectedVersions: [["a", "v1"]] }), "setBatch() with expectedVersions on a storage without versions");
1039
- same(await storage.get("a"), item("a", 1), "the item after the refused writes");
1046
+ assert.deepStrictEqual(await storage.get("a"), item("a", 1), "the item after the refused writes");
1040
1047
  // A write without a precondition is the write of before
1041
1048
  await storage.set("a", item("a", 4));
1042
- same(await storage.get("a"), item("a", 4), "a write without expectedVersion");
1049
+ assert.deepStrictEqual(await storage.get("a"), item("a", 4), "a write without expectedVersion");
1043
1050
  }));
1044
1051
  if (!createWithVersions)
1045
1052
  return;
@@ -1047,11 +1054,11 @@ function addPreconditionCases(add, create, createWithVersions) {
1047
1054
  add("a write with the expected version of the current item writes, and a write without one writes as before", () => withStorage(versioned, async (storage) => {
1048
1055
  await storage.set("a", item("a", 1));
1049
1056
  await storage.set("a", item("a", 2), { expectedVersion: "v1" });
1050
- same(await storage.get("a"), item("a", 2), "the item after set() with the expected version");
1057
+ assert.deepStrictEqual(await storage.get("a"), item("a", 2), "the item after set() with the expected version");
1051
1058
  await storage.set("a", item("a", 3));
1052
- same(await storage.get("a"), item("a", 3), "the item after set() without expectedVersion");
1053
- same(await storage.delete("a", { expectedVersion: "v3" }), true, "delete() with the expected version");
1054
- same(await storage.get("a"), undefined, "the item after delete() with the expected version");
1059
+ assert.deepStrictEqual(await storage.get("a"), item("a", 3), "the item after set() without expectedVersion");
1060
+ assert.deepStrictEqual(await storage.delete("a", { expectedVersion: "v3" }), true, "delete() with the expected version");
1061
+ assert.deepStrictEqual(await storage.get("a"), undefined, "the item after delete() with the expected version");
1055
1062
  }));
1056
1063
  add("a write with another expected version changes nothing, and rejects with VERSION_CONFLICT and the current item", () => withStorage(versioned, async (storage) => {
1057
1064
  await storage.set("a", item("a", 1));
@@ -1062,35 +1069,35 @@ function addPreconditionCases(add, create, createWithVersions) {
1062
1069
  const before = storage.getChangesSince ? (await storage.getChangesSince()).version : undefined;
1063
1070
  const expected = { id: "a", expected: "v2", found: true, value: item("a", 1), version: "v1" };
1064
1071
  const setError = await rejects(() => storage.set("a", item("a", 3), { expectedVersion: "v2" }), "set() with a stale version");
1065
- same(conflictsOfRejection(setError, "set() with a stale version"), [expected], "the conflicts of set() with a stale version");
1072
+ assert.deepStrictEqual(conflictsOfRejection(setError, "set() with a stale version"), [expected], "the conflicts of set() with a stale version");
1066
1073
  const deleteError = await rejects(() => storage.delete("a", { expectedVersion: "v2" }), "delete() with a stale version");
1067
- same(conflictsOfRejection(deleteError, "delete() with a stale version"), [expected], "the conflicts of delete() with a stale version");
1068
- same(await storage.get("a"), item("a", 1), "the item after the refused writes");
1074
+ assert.deepStrictEqual(conflictsOfRejection(deleteError, "delete() with a stale version"), [expected], "the conflicts of delete() with a stale version");
1075
+ assert.deepStrictEqual(await storage.get("a"), item("a", 1), "the item after the refused writes");
1069
1076
  stop?.();
1070
- same(batches, 0, "the batches of observe() for the refused writes");
1077
+ assert.deepStrictEqual(batches, 0, "the batches of observe() for the refused writes");
1071
1078
  if (storage.getChangesSince && before !== undefined) {
1072
1079
  const after = await storage.getChangesSince(before);
1073
- same({ changed: after.changed, deleted: after.deleted }, { changed: [], deleted: [] }, "the changes after the refused writes");
1080
+ assert.deepStrictEqual({ changed: after.changed, deleted: after.deleted }, { changed: [], deleted: [] }, "the changes after the refused writes");
1074
1081
  }
1075
1082
  }));
1076
1083
  add("the expected version null expects no item", () => withStorage(versioned, async (storage) => {
1077
1084
  await storage.set("b", item("b", 1), { expectedVersion: null });
1078
- same(await storage.get("b"), item("b", 1), "set() with expectedVersion null of a missing id");
1085
+ assert.deepStrictEqual(await storage.get("b"), item("b", 1), "set() with expectedVersion null of a missing id");
1079
1086
  const exists = await rejects(() => storage.set("b", item("b", 2), { expectedVersion: null }), "set() with expectedVersion null of an existing id");
1080
- same(conflictsOfRejection(exists, "set() with expectedVersion null of an existing id"), [{ id: "b", expected: null, found: true, value: item("b", 1), version: "v1" }], "the conflict of an existing id");
1087
+ assert.deepStrictEqual(conflictsOfRejection(exists, "set() with expectedVersion null of an existing id"), [{ id: "b", expected: null, found: true, value: item("b", 1), version: "v1" }], "the conflict of an existing id");
1081
1088
  const missing = await rejects(() => storage.set("c", item("c", 1), { expectedVersion: "v1" }), "set() with a version of a missing id");
1082
- same(conflictsOfRejection(missing, "set() with a version of a missing id"), [{ id: "c", expected: "v1", found: false, version: null }], "the conflict of a missing id");
1083
- same(await storage.has("c"), false, "the missing id after the refused set()");
1084
- same(await storage.delete("x", { expectedVersion: null }), false, "delete() with expectedVersion null of a missing id");
1089
+ assert.deepStrictEqual(conflictsOfRejection(missing, "set() with a version of a missing id"), [{ id: "c", expected: "v1", found: false, version: null }], "the conflict of a missing id");
1090
+ assert.deepStrictEqual(await storage.has("c"), false, "the missing id after the refused set()");
1091
+ assert.deepStrictEqual(await storage.delete("x", { expectedVersion: null }), false, "delete() with expectedVersion null of a missing id");
1085
1092
  }));
1086
1093
  add("setBatch() tests the expected version of each id, and a conflict changes no item", () => withStorage(versioned, async (storage) => {
1087
1094
  await storage.setBatch([["a", item("a", 1)], ["b", item("b", 1)]]);
1088
1095
  const error = await rejects(() => storage.setBatch([["a", item("a", 2)], ["b", item("b", 2)], ["c", item("c", 1)]], { expectedVersions: [["a", "v1"], ["b", "v9"]] }), "setBatch() with one stale version");
1089
- same(conflictsOfRejection(error, "setBatch() with one stale version"), [{ id: "b", expected: "v9", found: true, value: item("b", 1), version: "v1" }], "the conflicts of setBatch()");
1090
- same(await storage.getBatch(["a", "b", "c"]), new Map([["a", item("a", 1)], ["b", item("b", 1)]]), "the items after the refused batch");
1096
+ assert.deepStrictEqual(conflictsOfRejection(error, "setBatch() with one stale version"), [{ id: "b", expected: "v9", found: true, value: item("b", 1), version: "v1" }], "the conflicts of setBatch()");
1097
+ assert.deepStrictEqual(await storage.getBatch(["a", "b", "c"]), new Map([["a", item("a", 1)], ["b", item("b", 1)]]), "the items after the refused batch");
1091
1098
  // An id without an expected version has no precondition
1092
1099
  await storage.setBatch([["a", item("a", 2)], ["b", item("b", 2)], ["c", item("c", 1)]], { expectedVersions: [["a", "v1"], ["b", "v1"]] });
1093
- same(await storage.getBatch(["a", "b", "c"]), new Map([["a", item("a", 2)], ["b", item("b", 2)], ["c", item("c", 1)]]), "the items after the batch");
1100
+ assert.deepStrictEqual(await storage.getBatch(["a", "b", "c"]), new Map([["a", item("a", 2)], ["b", item("b", 2)], ["c", item("c", 1)]]), "the items after the batch");
1094
1101
  }));
1095
1102
  add("two writes with the same expected version at the same time: one writes, and the other gets VERSION_CONFLICT", () => withStorage(versioned, async (storage) => {
1096
1103
  await storage.set("a", item("a", 1));
@@ -1099,11 +1106,11 @@ function addPreconditionCases(add, create, createWithVersions) {
1099
1106
  storage.set("a", item("a", 3), { expectedVersion: "v1" }),
1100
1107
  ]);
1101
1108
  const won = results.flatMap((result, index) => (result.status === "fulfilled" ? [index] : []));
1102
- same(won.length, 1, "the number of writes that won");
1109
+ assert.deepStrictEqual(won.length, 1, "the number of writes that won");
1103
1110
  const lost = results.find((result) => result.status === "rejected");
1104
1111
  const conflicts = conflictsOfRejection(lost.reason, "the write that lost");
1105
- same(conflicts.map((conflict) => conflict.id), ["a"], "the conflict of the write that lost");
1106
- same(await storage.get("a"), item("a", won[0] === 0 ? 2 : 3), "the item of the write that won");
1112
+ assert.deepStrictEqual(conflicts.map((conflict) => conflict.id), ["a"], "the conflict of the write that lost");
1113
+ assert.deepStrictEqual(await storage.get("a"), item("a", won[0] === 0 ? 2 : 3), "the item of the write that won");
1107
1114
  }));
1108
1115
  }
1109
1116
  /**