2023-12-13 02:25:00 +00:00
|
|
|
import { describe, expect, it } from "vitest";
|
2024-03-30 03:38:24 +00:00
|
|
|
import { Loro, LoroList, LoroMap, LoroText, VersionVector } from "../src";
|
2023-05-11 03:59:48 +00:00
|
|
|
import { expectTypeOf } from "vitest";
|
2023-10-30 10:32:36 +00:00
|
|
|
|
2023-04-03 01:29:25 +00:00
|
|
|
function assertEquals(a: any, b: any) {
|
|
|
|
expect(a).toStrictEqual(b);
|
|
|
|
}
|
|
|
|
|
|
|
|
describe("transaction", () => {
|
|
|
|
it("transaction", async () => {
|
|
|
|
const loro = new Loro();
|
|
|
|
const text = loro.getText("text");
|
|
|
|
let count = 0;
|
|
|
|
const sub = loro.subscribe(() => {
|
|
|
|
count += 1;
|
|
|
|
loro.unsubscribe(sub);
|
|
|
|
});
|
2023-10-30 10:32:36 +00:00
|
|
|
expect(count).toBe(0);
|
|
|
|
text.insert(0, "hello world");
|
|
|
|
expect(count).toBe(0);
|
|
|
|
text.insert(0, "hello world");
|
|
|
|
assertEquals(count, 0);
|
|
|
|
loro.commit();
|
2023-11-16 13:04:31 +00:00
|
|
|
await one_ms();
|
2023-04-03 01:29:25 +00:00
|
|
|
assertEquals(count, 1);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("transaction origin", async () => {
|
|
|
|
const loro = new Loro();
|
|
|
|
const text = loro.getText("text");
|
|
|
|
let count = 0;
|
|
|
|
const sub = loro.subscribe((event: { origin: string }) => {
|
|
|
|
count += 1;
|
|
|
|
loro.unsubscribe(sub);
|
|
|
|
assertEquals(event.origin, "origin");
|
|
|
|
});
|
2023-10-30 10:32:36 +00:00
|
|
|
|
|
|
|
assertEquals(count, 0);
|
|
|
|
text.insert(0, "hello world");
|
|
|
|
assertEquals(count, 0);
|
|
|
|
text.insert(0, "hello world");
|
|
|
|
assertEquals(count, 0);
|
|
|
|
loro.commit("origin");
|
2023-11-16 13:04:31 +00:00
|
|
|
await one_ms();
|
2023-04-03 01:29:25 +00:00
|
|
|
assertEquals(count, 1);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe("subscribe", () => {
|
|
|
|
it("subscribe_lock", async () => {
|
|
|
|
const loro = new Loro();
|
|
|
|
const text = loro.getText("text");
|
|
|
|
const list = loro.getList("list");
|
|
|
|
let count = 0;
|
|
|
|
let i = 1;
|
|
|
|
const sub = loro.subscribe(() => {
|
|
|
|
if (i > 0) {
|
2023-10-30 10:32:36 +00:00
|
|
|
list.insert(0, i);
|
|
|
|
loro.commit();
|
|
|
|
i--;
|
2023-04-03 01:29:25 +00:00
|
|
|
}
|
2023-07-30 08:30:41 +00:00
|
|
|
|
2023-04-03 01:29:25 +00:00
|
|
|
count += 1;
|
|
|
|
});
|
2023-10-30 10:32:36 +00:00
|
|
|
|
|
|
|
text.insert(0, "hello world");
|
|
|
|
loro.commit();
|
2023-11-16 13:04:31 +00:00
|
|
|
await one_ms();
|
2023-07-30 08:30:41 +00:00
|
|
|
|
2023-04-03 01:29:25 +00:00
|
|
|
assertEquals(count, 2);
|
2023-10-30 10:32:36 +00:00
|
|
|
text.insert(0, "hello world");
|
|
|
|
loro.commit();
|
2023-11-16 13:04:31 +00:00
|
|
|
await one_ms();
|
2023-04-03 01:29:25 +00:00
|
|
|
assertEquals(count, 3);
|
|
|
|
loro.unsubscribe(sub);
|
2023-10-30 10:32:36 +00:00
|
|
|
text.insert(0, "hello world");
|
|
|
|
loro.commit();
|
2023-11-16 13:04:31 +00:00
|
|
|
await one_ms();
|
2023-04-03 01:29:25 +00:00
|
|
|
assertEquals(count, 3);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("subscribe_lock2", async () => {
|
|
|
|
const loro = new Loro();
|
|
|
|
const text = loro.getText("text");
|
|
|
|
let count = 0;
|
|
|
|
const sub = loro.subscribe(() => {
|
|
|
|
count += 1;
|
|
|
|
loro.unsubscribe(sub);
|
|
|
|
});
|
|
|
|
assertEquals(count, 0);
|
2023-10-30 10:32:36 +00:00
|
|
|
text.insert(0, "hello world");
|
|
|
|
loro.commit();
|
2023-11-16 13:04:31 +00:00
|
|
|
await one_ms();
|
2023-07-30 08:30:41 +00:00
|
|
|
|
2023-04-03 01:29:25 +00:00
|
|
|
assertEquals(count, 1);
|
2023-10-30 10:32:36 +00:00
|
|
|
text.insert(0, "hello world");
|
|
|
|
loro.commit();
|
2023-11-16 13:04:31 +00:00
|
|
|
await one_ms();
|
2023-07-30 08:30:41 +00:00
|
|
|
|
2023-04-03 01:29:25 +00:00
|
|
|
assertEquals(count, 1);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("subscribe", async () => {
|
|
|
|
const loro = new Loro();
|
|
|
|
const text = loro.getText("text");
|
|
|
|
let count = 0;
|
|
|
|
const sub = loro.subscribe(() => {
|
|
|
|
count += 1;
|
|
|
|
});
|
2023-10-30 10:32:36 +00:00
|
|
|
text.insert(0, "hello world");
|
|
|
|
loro.commit();
|
2023-11-16 13:04:31 +00:00
|
|
|
await one_ms();
|
2023-04-03 01:29:25 +00:00
|
|
|
assertEquals(count, 1);
|
2023-10-30 10:32:36 +00:00
|
|
|
text.insert(0, "hello world");
|
|
|
|
loro.commit();
|
2023-11-16 13:04:31 +00:00
|
|
|
await one_ms();
|
2023-04-03 01:29:25 +00:00
|
|
|
assertEquals(count, 2);
|
|
|
|
loro.unsubscribe(sub);
|
2023-10-30 10:32:36 +00:00
|
|
|
text.insert(0, "hello world");
|
|
|
|
loro.commit();
|
2023-11-16 13:04:31 +00:00
|
|
|
await one_ms();
|
2023-04-03 01:29:25 +00:00
|
|
|
assertEquals(count, 2);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe("sync", () => {
|
|
|
|
it("two insert at beginning", async () => {
|
|
|
|
const a = new Loro();
|
|
|
|
const b = new Loro();
|
2024-01-18 05:28:28 +00:00
|
|
|
let a_version: undefined | VersionVector = undefined;
|
|
|
|
let b_version: undefined | VersionVector = undefined;
|
2023-04-03 01:29:25 +00:00
|
|
|
a.subscribe((e: { local: boolean }) => {
|
|
|
|
if (e.local) {
|
|
|
|
const exported = a.exportFrom(a_version);
|
|
|
|
b.import(exported);
|
|
|
|
a_version = a.version();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
b.subscribe((e: { local: boolean }) => {
|
|
|
|
if (e.local) {
|
|
|
|
const exported = b.exportFrom(b_version);
|
|
|
|
a.import(exported);
|
|
|
|
b_version = b.version();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
const aText = a.getText("text");
|
|
|
|
const bText = b.getText("text");
|
2023-10-30 10:32:36 +00:00
|
|
|
aText.insert(0, "abc");
|
|
|
|
a.commit();
|
2023-11-16 13:04:31 +00:00
|
|
|
await one_ms();
|
2023-07-30 08:30:41 +00:00
|
|
|
|
2023-04-03 01:29:25 +00:00
|
|
|
assertEquals(aText.toString(), bText.toString());
|
|
|
|
});
|
|
|
|
|
|
|
|
it("sync", () => {
|
|
|
|
const loro = new Loro();
|
|
|
|
const text = loro.getText("text");
|
2023-10-30 10:32:36 +00:00
|
|
|
text.insert(0, "hello world");
|
2023-07-30 08:30:41 +00:00
|
|
|
|
2023-04-03 01:29:25 +00:00
|
|
|
const loro_bk = new Loro();
|
|
|
|
loro_bk.import(loro.exportFrom(undefined));
|
|
|
|
assertEquals(loro_bk.toJson(), loro.toJson());
|
|
|
|
const text_bk = loro_bk.getText("text");
|
|
|
|
assertEquals(text_bk.toString(), "hello world");
|
2023-10-30 10:32:36 +00:00
|
|
|
text_bk.insert(0, "a ");
|
2023-07-30 08:30:41 +00:00
|
|
|
|
2023-04-03 01:29:25 +00:00
|
|
|
loro.import(loro_bk.exportFrom(undefined));
|
|
|
|
assertEquals(text.toString(), "a hello world");
|
|
|
|
const map = loro.getMap("map");
|
2023-10-30 10:32:36 +00:00
|
|
|
map.set("key", "value");
|
2023-04-03 01:29:25 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe("wasm", () => {
|
|
|
|
const loro = new Loro();
|
|
|
|
const a = loro.getText("ha");
|
2023-10-30 10:32:36 +00:00
|
|
|
a.insert(0, "hello world");
|
|
|
|
a.delete(6, 5);
|
|
|
|
a.insert(6, "everyone");
|
|
|
|
loro.commit();
|
2023-07-30 08:30:41 +00:00
|
|
|
|
2023-04-03 01:29:25 +00:00
|
|
|
const b = loro.getMap("ha");
|
2023-10-30 10:32:36 +00:00
|
|
|
b.set("ab", 123);
|
|
|
|
loro.commit();
|
2023-04-03 01:29:25 +00:00
|
|
|
|
2024-03-30 03:38:24 +00:00
|
|
|
const bText = b.setContainer("hh", new LoroText());
|
2023-10-30 10:32:36 +00:00
|
|
|
loro.commit();
|
2023-04-03 01:29:25 +00:00
|
|
|
|
|
|
|
it("map get", () => {
|
|
|
|
assertEquals(b.get("ab"), 123);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("getValueDeep", () => {
|
2023-10-30 10:32:36 +00:00
|
|
|
bText.insert(0, "hello world Text");
|
2023-11-27 09:53:02 +00:00
|
|
|
assertEquals(b.toJson(), { ab: 123, hh: "hello world Text" });
|
2023-04-03 01:29:25 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
it("get container by id", () => {
|
|
|
|
const id = b.id;
|
|
|
|
const b2 = loro.getContainerById(id) as LoroMap;
|
2023-11-27 09:53:02 +00:00
|
|
|
assertEquals(b2.toJson(), b.toJson());
|
2023-04-03 01:29:25 +00:00
|
|
|
assertEquals(b2.id, id);
|
2023-10-30 10:32:36 +00:00
|
|
|
b2.set("0", 12);
|
2023-07-30 08:30:41 +00:00
|
|
|
|
2023-11-27 09:53:02 +00:00
|
|
|
assertEquals(b2.toJson(), b.toJson());
|
2023-04-03 01:29:25 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2023-05-11 03:59:48 +00:00
|
|
|
describe("type", () => {
|
|
|
|
it("test map type", () => {
|
|
|
|
const loro = new Loro<{ map: LoroMap<{ name: "he" }> }>();
|
|
|
|
const map = loro.getTypedMap("map");
|
|
|
|
const v = map.getTyped(loro, "name");
|
|
|
|
expectTypeOf(v).toEqualTypeOf<"he">();
|
|
|
|
});
|
|
|
|
|
|
|
|
it("test recursive map type", () => {
|
|
|
|
const loro = new Loro<{ map: LoroMap<{ map: LoroMap<{ name: "he" }> }> }>();
|
|
|
|
const map = loro.getTypedMap("map");
|
2024-03-30 03:38:24 +00:00
|
|
|
map.setContainer("map", new LoroMap());
|
2023-07-30 08:30:41 +00:00
|
|
|
|
2023-05-11 03:59:48 +00:00
|
|
|
const subMap = map.getTyped(loro, "map");
|
|
|
|
const name = subMap.getTyped(loro, "name");
|
|
|
|
expectTypeOf(name).toEqualTypeOf<"he">();
|
|
|
|
});
|
|
|
|
|
|
|
|
it("works for list type", () => {
|
|
|
|
const loro = new Loro<{ list: LoroList<[string, number]> }>();
|
|
|
|
const list = loro.getTypedList("list");
|
2023-10-30 10:32:36 +00:00
|
|
|
list.insertTyped(0, "123");
|
|
|
|
list.insertTyped(1, 123);
|
2023-05-11 03:59:48 +00:00
|
|
|
const v0 = list.getTyped(loro, 0);
|
|
|
|
expectTypeOf(v0).toEqualTypeOf<string>();
|
|
|
|
const v1 = list.getTyped(loro, 1);
|
|
|
|
expectTypeOf(v1).toEqualTypeOf<number>();
|
|
|
|
});
|
2023-09-12 07:57:06 +00:00
|
|
|
|
|
|
|
it("test binary type", () => {
|
2023-10-30 10:32:36 +00:00
|
|
|
// const loro = new Loro<{ list: LoroList<[string, number]> }>();
|
|
|
|
// const list = loro.getTypedList("list");
|
|
|
|
// console.dir((list as any).__proto__);
|
|
|
|
// list.insertTyped(0, new Uint8Array(10));
|
|
|
|
// const v0 = list.getTyped(loro, 0);
|
|
|
|
// expectTypeOf(v0).toEqualTypeOf<Uint8Array>();
|
2023-09-12 07:57:06 +00:00
|
|
|
});
|
2023-05-11 03:59:48 +00:00
|
|
|
});
|
|
|
|
|
2023-10-30 03:13:52 +00:00
|
|
|
describe("tree", () => {
|
|
|
|
const loro = new Loro();
|
|
|
|
const tree = loro.getTree("root");
|
2023-10-30 10:32:36 +00:00
|
|
|
|
2024-01-30 01:54:54 +00:00
|
|
|
it("create", () => {
|
|
|
|
const root = tree.createNode();
|
|
|
|
const child = root.createNode();
|
|
|
|
assertEquals(child.parent()!.id, root.id);
|
2023-11-02 09:13:08 +00:00
|
|
|
});
|
2023-10-30 03:13:52 +00:00
|
|
|
|
2024-03-30 03:38:24 +00:00
|
|
|
it("move", () => {
|
2024-01-30 01:54:54 +00:00
|
|
|
const root = tree.createNode();
|
|
|
|
const child = root.createNode();
|
|
|
|
const child2 = root.createNode();
|
|
|
|
assertEquals(child2.parent()!.id, root.id);
|
|
|
|
child2.moveTo(child);
|
|
|
|
assertEquals(child2.parent()!.id, child.id);
|
|
|
|
assertEquals(child.children()[0].id, child2.id);
|
2024-03-30 03:38:24 +00:00
|
|
|
});
|
2024-01-30 01:54:54 +00:00
|
|
|
|
2023-10-30 10:32:36 +00:00
|
|
|
it("meta", () => {
|
2024-01-30 01:54:54 +00:00
|
|
|
const root = tree.createNode();
|
|
|
|
root.data.set("a", 123);
|
|
|
|
assertEquals(root.data.get("a"), 123);
|
2023-11-02 09:13:08 +00:00
|
|
|
});
|
|
|
|
});
|
2023-10-30 03:13:52 +00:00
|
|
|
|
2023-04-03 01:29:25 +00:00
|
|
|
function one_ms(): Promise<void> {
|
|
|
|
return new Promise((resolve) => setTimeout(resolve, 1));
|
|
|
|
}
|