* Prepare @babel/core for asynchronicity * Include regenerator-runtime in standalone build * Fix rollup build
472 lines
12 KiB
JavaScript
472 lines
12 KiB
JavaScript
import gensync from "gensync";
|
|
import { makeStrongCacheSync, makeStrongCache } from "../lib/config/caching";
|
|
import { waitFor } from "../lib/gensync-utils/async";
|
|
|
|
describe("caching API", () => {
|
|
it("should allow permacaching with .forever()", () => {
|
|
let count = 0;
|
|
|
|
const fn = makeStrongCacheSync((arg, cache) => {
|
|
cache.forever();
|
|
return { arg, count: count++ };
|
|
});
|
|
|
|
expect(fn("one")).toEqual({ arg: "one", count: 0 });
|
|
expect(fn("one")).toBe(fn("one"));
|
|
|
|
expect(fn("two")).toEqual({ arg: "two", count: 1 });
|
|
expect(fn("two")).toBe(fn("two"));
|
|
|
|
expect(fn("one")).not.toEqual(fn("two"));
|
|
});
|
|
|
|
it("should allow disabling caching with .never()", () => {
|
|
let count = 0;
|
|
|
|
const fn = makeStrongCacheSync((arg, cache) => {
|
|
cache.never();
|
|
return { arg, count: count++ };
|
|
});
|
|
|
|
expect(fn("one")).toEqual({ arg: "one", count: 0 });
|
|
expect(fn("one")).toEqual({ arg: "one", count: 1 });
|
|
expect(fn("one")).not.toEqual(fn("one"));
|
|
|
|
expect(fn("two")).toEqual({ arg: "two", count: 4 });
|
|
expect(fn("two")).toEqual({ arg: "two", count: 5 });
|
|
expect(fn("two")).not.toEqual(fn("two"));
|
|
|
|
expect(fn("one")).not.toEqual(fn("two"));
|
|
});
|
|
|
|
it("should allow caching based on a value with .using(fn)", () => {
|
|
let count = 0;
|
|
let other = "default";
|
|
|
|
const fn = makeStrongCacheSync((arg, cache) => {
|
|
const val = cache.using(() => other);
|
|
|
|
return { arg, val, count: count++ };
|
|
});
|
|
|
|
expect(fn("one")).toEqual({ arg: "one", val: "default", count: 0 });
|
|
expect(fn("one")).toBe(fn("one"));
|
|
|
|
expect(fn("two")).toEqual({ arg: "two", val: "default", count: 1 });
|
|
expect(fn("two")).toBe(fn("two"));
|
|
|
|
other = "new";
|
|
|
|
expect(fn("one")).toEqual({ arg: "one", val: "new", count: 2 });
|
|
expect(fn("one")).toBe(fn("one"));
|
|
|
|
expect(fn("two")).toEqual({ arg: "two", val: "new", count: 3 });
|
|
expect(fn("two")).toBe(fn("two"));
|
|
|
|
other = "default";
|
|
|
|
expect(fn("one")).toEqual({ arg: "one", val: "default", count: 0 });
|
|
expect(fn("one")).toBe(fn("one"));
|
|
|
|
expect(fn("two")).toEqual({ arg: "two", val: "default", count: 1 });
|
|
expect(fn("two")).toBe(fn("two"));
|
|
|
|
other = "new";
|
|
|
|
expect(fn("one")).toEqual({ arg: "one", val: "new", count: 2 });
|
|
expect(fn("one")).toBe(fn("one"));
|
|
|
|
expect(fn("two")).toEqual({ arg: "two", val: "new", count: 3 });
|
|
expect(fn("two")).toBe(fn("two"));
|
|
});
|
|
|
|
it("should allow invalidation based on a value with .invalidate(fn)", () => {
|
|
let count = 0;
|
|
let other = "default";
|
|
|
|
const fn = makeStrongCacheSync((arg, cache) => {
|
|
const val = cache.invalidate(() => other);
|
|
|
|
return { arg, val, count: count++ };
|
|
});
|
|
|
|
expect(fn("one")).toEqual({ arg: "one", val: "default", count: 0 });
|
|
expect(fn("one")).toBe(fn("one"));
|
|
|
|
expect(fn("two")).toEqual({ arg: "two", val: "default", count: 1 });
|
|
expect(fn("two")).toBe(fn("two"));
|
|
|
|
other = "new";
|
|
|
|
expect(fn("one")).toEqual({ arg: "one", val: "new", count: 2 });
|
|
expect(fn("one")).toBe(fn("one"));
|
|
|
|
expect(fn("two")).toEqual({ arg: "two", val: "new", count: 3 });
|
|
expect(fn("two")).toBe(fn("two"));
|
|
|
|
other = "default";
|
|
|
|
expect(fn("one")).toEqual({ arg: "one", val: "default", count: 4 });
|
|
expect(fn("one")).toBe(fn("one"));
|
|
|
|
expect(fn("two")).toEqual({ arg: "two", val: "default", count: 5 });
|
|
expect(fn("two")).toBe(fn("two"));
|
|
|
|
other = "new";
|
|
|
|
expect(fn("one")).toEqual({ arg: "one", val: "new", count: 6 });
|
|
expect(fn("one")).toBe(fn("one"));
|
|
|
|
expect(fn("two")).toEqual({ arg: "two", val: "new", count: 7 });
|
|
expect(fn("two")).toBe(fn("two"));
|
|
});
|
|
|
|
it("should allow invalidation with .using and .invalidate", () => {
|
|
let count = 0;
|
|
let other = "default";
|
|
let another = "another";
|
|
|
|
const fn = makeStrongCacheSync((arg, cache) => {
|
|
const val = cache.using(() => other);
|
|
const val2 = cache.invalidate(() => another);
|
|
|
|
return { arg, val, val2, count: count++ };
|
|
});
|
|
|
|
expect(fn("one")).toEqual({
|
|
arg: "one",
|
|
val: "default",
|
|
val2: "another",
|
|
count: 0,
|
|
});
|
|
expect(fn("one")).toBe(fn("one"));
|
|
|
|
expect(fn("two")).toEqual({
|
|
arg: "two",
|
|
val: "default",
|
|
val2: "another",
|
|
count: 1,
|
|
});
|
|
expect(fn("two")).toBe(fn("two"));
|
|
|
|
other = "new";
|
|
|
|
expect(fn("one")).toEqual({
|
|
arg: "one",
|
|
val: "new",
|
|
val2: "another",
|
|
count: 2,
|
|
});
|
|
expect(fn("one")).toBe(fn("one"));
|
|
|
|
expect(fn("two")).toEqual({
|
|
arg: "two",
|
|
val: "new",
|
|
val2: "another",
|
|
count: 3,
|
|
});
|
|
expect(fn("two")).toBe(fn("two"));
|
|
|
|
other = "default";
|
|
|
|
expect(fn("one")).toEqual({
|
|
arg: "one",
|
|
val: "default",
|
|
val2: "another",
|
|
count: 4,
|
|
});
|
|
expect(fn("one")).toBe(fn("one"));
|
|
|
|
expect(fn("two")).toEqual({
|
|
arg: "two",
|
|
val: "default",
|
|
val2: "another",
|
|
count: 5,
|
|
});
|
|
expect(fn("two")).toBe(fn("two"));
|
|
|
|
other = "new";
|
|
|
|
expect(fn("one")).toEqual({
|
|
arg: "one",
|
|
val: "new",
|
|
val2: "another",
|
|
count: 6,
|
|
});
|
|
expect(fn("one")).toBe(fn("one"));
|
|
|
|
expect(fn("two")).toEqual({
|
|
arg: "two",
|
|
val: "new",
|
|
val2: "another",
|
|
count: 7,
|
|
});
|
|
expect(fn("two")).toBe(fn("two"));
|
|
|
|
another = "second";
|
|
|
|
expect(fn("one")).toEqual({
|
|
arg: "one",
|
|
val: "new",
|
|
val2: "second",
|
|
count: 8,
|
|
});
|
|
expect(fn("one")).toBe(fn("one"));
|
|
|
|
expect(fn("two")).toEqual({
|
|
arg: "two",
|
|
val: "new",
|
|
val2: "second",
|
|
count: 9,
|
|
});
|
|
expect(fn("two")).toBe(fn("two"));
|
|
});
|
|
|
|
it("should auto-permacache by default", () => {
|
|
let count = 0;
|
|
|
|
const fn = makeStrongCacheSync(arg => ({ arg, count: count++ }));
|
|
|
|
expect(fn("one")).toEqual({ arg: "one", count: 0 });
|
|
expect(fn("one")).toBe(fn("one"));
|
|
|
|
expect(fn("two")).toEqual({ arg: "two", count: 1 });
|
|
expect(fn("two")).toBe(fn("two"));
|
|
|
|
expect(fn("one")).not.toEqual(fn("two"));
|
|
});
|
|
|
|
it("should throw if you set permacaching and use .using", () => {
|
|
const fn = makeStrongCacheSync((arg, cache) => {
|
|
cache.forever();
|
|
|
|
cache.using(() => null);
|
|
});
|
|
|
|
expect(() => fn()).toThrow(/Caching has already been configured/);
|
|
});
|
|
|
|
it("should throw if you set permacaching and use .invalidate", () => {
|
|
const fn = makeStrongCacheSync((arg, cache) => {
|
|
cache.forever();
|
|
|
|
cache.invalidate(() => null);
|
|
});
|
|
|
|
expect(() => fn()).toThrow(/Caching has already been configured/);
|
|
});
|
|
|
|
it("should throw if you set permacaching and use .never", () => {
|
|
const fn = makeStrongCacheSync((arg, cache) => {
|
|
cache.forever();
|
|
|
|
cache.never();
|
|
});
|
|
|
|
expect(() => fn()).toThrow(/Caching has already been configured/);
|
|
});
|
|
|
|
it("should throw if you set no caching and use .using", () => {
|
|
const fn = makeStrongCacheSync((arg, cache) => {
|
|
cache.never();
|
|
|
|
cache.using(() => null);
|
|
});
|
|
|
|
expect(() => fn()).toThrow(/Caching has already been configured/);
|
|
});
|
|
|
|
it("should throw if you set no caching and use .invalidate", () => {
|
|
const fn = makeStrongCacheSync((arg, cache) => {
|
|
cache.never();
|
|
|
|
cache.invalidate(() => null);
|
|
});
|
|
|
|
expect(() => fn()).toThrow(/Caching has already been configured/);
|
|
});
|
|
|
|
it("should throw if you set no caching and use .never", () => {
|
|
const fn = makeStrongCacheSync((arg, cache) => {
|
|
cache.never();
|
|
|
|
cache.using(() => null);
|
|
});
|
|
|
|
expect(() => fn()).toThrow(/Caching has already been configured/);
|
|
});
|
|
|
|
it("should throw if you configure .forever after exiting", () => {
|
|
const fn = makeStrongCacheSync((arg, cache) => cache);
|
|
|
|
expect(() => fn().forever()).toThrow(
|
|
/Cannot change caching after evaluation/,
|
|
);
|
|
});
|
|
|
|
it("should throw if you configure .never after exiting", () => {
|
|
const fn = makeStrongCacheSync((arg, cache) => cache);
|
|
|
|
expect(() => fn().never()).toThrow(
|
|
/Cannot change caching after evaluation/,
|
|
);
|
|
});
|
|
|
|
it("should throw if you configure .using after exiting", () => {
|
|
const fn = makeStrongCacheSync((arg, cache) => cache);
|
|
|
|
expect(() => fn().using(() => null)).toThrow(
|
|
/Cannot change caching after evaluation/,
|
|
);
|
|
});
|
|
|
|
it("should throw if you configure .invalidate after exiting", () => {
|
|
const fn = makeStrongCacheSync((arg, cache) => cache);
|
|
|
|
expect(() => fn().invalidate(() => null)).toThrow(
|
|
/Cannot change caching after evaluation/,
|
|
);
|
|
});
|
|
|
|
describe("simple", () => {
|
|
it("should allow permacaching with cache(true)", () => {
|
|
let count = 0;
|
|
|
|
const fn = makeStrongCacheSync((arg, cache) => {
|
|
cache = cache.simple();
|
|
|
|
cache(true);
|
|
return { arg, count: count++ };
|
|
});
|
|
|
|
expect(fn("one")).toEqual({ arg: "one", count: 0 });
|
|
expect(fn("one")).toBe(fn("one"));
|
|
|
|
expect(fn("two")).toEqual({ arg: "two", count: 1 });
|
|
expect(fn("two")).toBe(fn("two"));
|
|
|
|
expect(fn("one")).not.toEqual(fn("two"));
|
|
});
|
|
|
|
it("should allow disabling caching with cache(false)", () => {
|
|
let count = 0;
|
|
|
|
const fn = makeStrongCacheSync((arg, cache) => {
|
|
cache = cache.simple();
|
|
|
|
cache(false);
|
|
return { arg, count: count++ };
|
|
});
|
|
|
|
expect(fn("one")).toEqual({ arg: "one", count: 0 });
|
|
expect(fn("one")).toEqual({ arg: "one", count: 1 });
|
|
expect(fn("one")).not.toEqual(fn("one"));
|
|
|
|
expect(fn("two")).toEqual({ arg: "two", count: 4 });
|
|
expect(fn("two")).toEqual({ arg: "two", count: 5 });
|
|
expect(fn("two")).not.toEqual(fn("two"));
|
|
|
|
expect(fn("one")).not.toEqual(fn("two"));
|
|
});
|
|
|
|
it("should allow caching based on a value with cache(fn)", () => {
|
|
let count = 0;
|
|
let other = "default";
|
|
|
|
const fn = makeStrongCacheSync((arg, cache) => {
|
|
cache = cache.simple();
|
|
|
|
const val = cache(() => other);
|
|
|
|
return { arg, val, count: count++ };
|
|
});
|
|
|
|
expect(fn("one")).toEqual({ arg: "one", val: "default", count: 0 });
|
|
expect(fn("one")).toBe(fn("one"));
|
|
|
|
expect(fn("two")).toEqual({ arg: "two", val: "default", count: 1 });
|
|
expect(fn("two")).toBe(fn("two"));
|
|
|
|
other = "new";
|
|
|
|
expect(fn("one")).toEqual({ arg: "one", val: "new", count: 2 });
|
|
expect(fn("one")).toBe(fn("one"));
|
|
|
|
expect(fn("two")).toEqual({ arg: "two", val: "new", count: 3 });
|
|
expect(fn("two")).toBe(fn("two"));
|
|
|
|
other = "default";
|
|
|
|
expect(fn("one")).toEqual({ arg: "one", val: "default", count: 0 });
|
|
expect(fn("one")).toBe(fn("one"));
|
|
|
|
expect(fn("two")).toEqual({ arg: "two", val: "default", count: 1 });
|
|
expect(fn("two")).toBe(fn("two"));
|
|
|
|
other = "new";
|
|
|
|
expect(fn("one")).toEqual({ arg: "one", val: "new", count: 2 });
|
|
expect(fn("one")).toBe(fn("one"));
|
|
|
|
expect(fn("two")).toEqual({ arg: "two", val: "new", count: 3 });
|
|
expect(fn("two")).toBe(fn("two"));
|
|
});
|
|
});
|
|
|
|
describe("async", () => {
|
|
const wait = gensync({
|
|
sync: () => {},
|
|
errback: (t, cb) => setTimeout(cb, t),
|
|
});
|
|
|
|
it("should throw if the cache is configured asynchronously", async () => {
|
|
const fn = gensync(
|
|
makeStrongCache(function*(arg, cache) {
|
|
yield* wait(1000);
|
|
cache.never();
|
|
return { arg };
|
|
}),
|
|
).async;
|
|
|
|
await expect(fn("bar")).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
`"Cannot change caching after evaluation has completed."`,
|
|
);
|
|
});
|
|
|
|
it("should allow asynchronous cache invalidation functions", async () => {
|
|
const fn = gensync(
|
|
makeStrongCache(function*(arg, cache) {
|
|
yield* waitFor(
|
|
cache.using(async () => {
|
|
await wait.async(50);
|
|
return "x";
|
|
}),
|
|
);
|
|
return { arg };
|
|
}),
|
|
).async;
|
|
|
|
const [res1, res2] = await Promise.all([fn("foo"), fn("foo")]);
|
|
|
|
expect(res1).toBe(res2);
|
|
});
|
|
|
|
it("should allow synchronous yield before cache configuration", async () => {
|
|
const fn = gensync(
|
|
makeStrongCache(function*(arg, cache) {
|
|
yield* gensync({
|
|
sync: () => 2,
|
|
errback: cb => cb(null, 2),
|
|
})();
|
|
cache.forever();
|
|
return { arg };
|
|
}),
|
|
).async;
|
|
|
|
const [res1, res2] = await Promise.all([fn("foo"), fn("foo")]);
|
|
|
|
expect(res1).toBe(res2);
|
|
});
|
|
});
|
|
});
|