@clickup/ent-framework
Version:
A PostgreSQL graph-database-alike library with microsharding and row-level security
189 lines (157 loc) • 5.76 kB
text/typescript
/* eslint-disable @typescript-eslint/no-explicit-any */
import { Timeline } from "../../abstract";
import { TimelineStorage } from "../TimelineStorage";
import { VC } from "../VC";
import { VCFlavor } from "../VCFlavor";
import { createVC } from "./test-utils";
class Cache extends Map<unknown, unknown> {
constructor() {
super([]);
}
}
class VCTest1 extends VCFlavor {
constructor(public value: string) {
super();
}
override toDebugString(): string {
return `VCTest1:${this.value}`;
}
}
class VCTest2 extends VCFlavor {
constructor(public value: string) {
super();
}
override toDebugString(): string {
return `VCTest2:${this.value}`;
}
}
class TestTimelineStorage extends TimelineStorage {
private db = new Map<string, string[]>();
override async load(principal: string): Promise<string[]> {
return this.db.get(principal) ?? [];
}
override async save(principal: string, dataStr: string): Promise<void> {
this.db.set(principal, [dataStr]);
}
}
test("VC should be able to clone", () => {
const vc1 = createVC();
vc1.cache(Cache).set("test", 42);
const vc2: VC = Object.assign(Object.create(VC.prototype), vc1);
expect(vc2.cache(Cache).get("test")).toEqual(42);
});
test("root flag of the VC is changed", () => {
const vc1root = createVC() as VC;
expect((vc1root as any).isRoot).toBeTruthy();
const vc2root = vc1root.toOmniDangerous();
expect((vc2root as any).isRoot).toBeTruthy();
expect(
(vc2root as any).timelines === (vc1root as any).timelines,
).toBeTruthy();
const vc3 = vc1root.toLowerInternal("42");
expect((vc3 as any).isRoot).toBeFalsy();
expect((vc3 as any).timelines === (vc1root as any).timelines).toBeFalsy();
const vc4 = vc2root.toLowerInternal("42");
expect((vc4 as any).isRoot).toBeFalsy();
expect((vc4 as any).timelines === (vc2root as any).timelines).toBeFalsy();
const vc5 = vc4.toLowerInternal(null); // -> guest
expect((vc5 as any).isRoot).toBeFalsy();
expect((vc5 as any).timelines === (vc4 as any).timelines).toBeTruthy();
const vc6 = vc5.toLowerInternal("11"); // -> other user
expect((vc6 as any).isRoot).toBeFalsy();
expect((vc6 as any).timelines === (vc5 as any).timelines).toBeTruthy();
});
test("VC flavor prepend and append", () => {
const vc = createVC().withFlavor(new VCTest1("some"));
const vc2 = vc.withFlavor(new VCTest2("t2"));
expect(vc2.toString()).toEqual("vc:guest(VCTest1:some,VCTest2:t2)");
expect(vc2.withFlavor(new VCTest2("tNew")).toString()).toEqual(
"vc:guest(VCTest1:some,VCTest2:tNew)",
);
expect(vc2.withFlavor("prepend", new VCTest2("tNew")).toString()).toEqual(
"vc:guest(VCTest2:tNew,VCTest1:some)",
);
});
describe("VC.withoutFlavor", () => {
test("VC withoutFlavor removes single flavor", () => {
const vc = createVC()
.withFlavor(new VCTest1("test1"))
.withFlavor(new VCTest2("test2"));
const vcCopy = vc.withoutFlavor(VCTest1);
expect(vcCopy.flavor(VCTest1)).toBeNull();
expect(vcCopy.flavor(VCTest2)).toBeInstanceOf(VCTest2);
});
test("VC withoutFlavor removes multiple flavors", () => {
const vc = createVC()
.withFlavor(new VCTest1("test1"))
.withFlavor(new VCTest2("test2"));
const vcCopy = vc.withoutFlavor(VCTest1, VCTest2);
expect(vcCopy.flavor(VCTest1)).toBeNull();
expect(vcCopy.flavor(VCTest2)).toBeNull();
});
test("VC withoutFlavor returns same instance when no flavors removed", () => {
const vc = createVC().withFlavor(new VCTest1("test1"));
const vcCopy = vc.withoutFlavor(VCTest2);
expect(vcCopy).toBe(vc);
});
test("VC withoutFlavor returns same instance when no flavor classes provided", () => {
const vc = createVC().withFlavor(new VCTest1("test1"));
const vcCopy = vc.withoutFlavor();
expect(vcCopy).toBe(vc);
});
test("VC withoutFlavor handles non-existent flavor gracefully", () => {
const vc = createVC();
const vcCopy = vc.withoutFlavor(VCTest1);
expect(vcCopy).toBe(vc);
expect(vcCopy.flavor(VCTest1)).toBeNull();
});
test("VC withoutFlavor should not mutate the original VC", () => {
const vc = createVC().withFlavor(new VCTest1("test1"));
const vcCopy = vc.withoutFlavor(VCTest1);
expect(vcCopy).not.toBe(vc);
expect(vc.flavor(VCTest1)).toBeInstanceOf(VCTest1);
});
});
test("VC saves and loads timelines", async () => {
let vc = createVC()
.toLowerInternal("test")
.deserializeTimelines(
JSON.stringify({
"42:tbl": new Timeline({
pos: BigInt(1),
expiresAt: Number.MAX_SAFE_INTEGER,
}).serialize(),
}),
);
const storage = new TestTimelineStorage({
merge: (dataStrs) => dataStrs.join(";"),
});
const spySave = jest.spyOn(storage, "save");
const spyLoad = jest.spyOn(storage, "load");
await vc.saveTimelines(storage);
await vc.saveTimelines(storage);
expect(spySave).toHaveBeenCalledTimes(1);
expect(spySave).toHaveBeenCalledWith(
"test",
'{"42:tbl":"1:9007199254740991"}',
);
spySave.mockReset();
vc = createVC().toLowerInternal("test");
await vc.loadTimelines(storage);
expect(spyLoad).toHaveBeenCalledWith("test");
await vc.saveTimelines(storage);
expect(spySave).toHaveBeenCalledTimes(0);
});
test("non-logged VC cannot save timelines", async () => {
let vc = createVC();
const storage = new TestTimelineStorage({
merge: (dataStrs) => dataStrs.join(";"),
});
await expect(vc.saveTimelines(storage)).rejects.toThrow(
"One does not simply save timelines for a non-logged VC: vc:guest",
);
vc = vc.toOmniDangerous();
await expect(vc.loadTimelines(storage)).rejects.toThrow(
"One does not simply load timelines for a non-logged VC: vc:omni",
);
});