cojson 0.19.22 → 0.20.1
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.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +66 -0
- package/dist/PeerState.d.ts +6 -1
- package/dist/PeerState.d.ts.map +1 -1
- package/dist/PeerState.js +18 -3
- package/dist/PeerState.js.map +1 -1
- package/dist/coValueContentMessage.d.ts +0 -2
- package/dist/coValueContentMessage.d.ts.map +1 -1
- package/dist/coValueContentMessage.js +0 -8
- package/dist/coValueContentMessage.js.map +1 -1
- package/dist/coValueCore/SessionMap.d.ts +4 -2
- package/dist/coValueCore/SessionMap.d.ts.map +1 -1
- package/dist/coValueCore/SessionMap.js +30 -0
- package/dist/coValueCore/SessionMap.js.map +1 -1
- package/dist/coValueCore/coValueCore.d.ts +70 -5
- package/dist/coValueCore/coValueCore.d.ts.map +1 -1
- package/dist/coValueCore/coValueCore.js +302 -31
- package/dist/coValueCore/coValueCore.js.map +1 -1
- package/dist/coValueCore/verifiedState.d.ts +6 -1
- package/dist/coValueCore/verifiedState.d.ts.map +1 -1
- package/dist/coValueCore/verifiedState.js +9 -0
- package/dist/coValueCore/verifiedState.js.map +1 -1
- package/dist/coValues/coList.d.ts +4 -2
- package/dist/coValues/coList.d.ts.map +1 -1
- package/dist/coValues/coList.js +3 -0
- package/dist/coValues/coList.js.map +1 -1
- package/dist/coValues/group.d.ts.map +1 -1
- package/dist/coValues/group.js +3 -6
- package/dist/coValues/group.js.map +1 -1
- package/dist/config.d.ts +2 -8
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +4 -12
- package/dist/config.js.map +1 -1
- package/dist/crypto/NapiCrypto.d.ts +1 -2
- package/dist/crypto/NapiCrypto.d.ts.map +1 -1
- package/dist/crypto/NapiCrypto.js +19 -4
- package/dist/crypto/NapiCrypto.js.map +1 -1
- package/dist/crypto/RNCrypto.d.ts.map +1 -1
- package/dist/crypto/RNCrypto.js +19 -4
- package/dist/crypto/RNCrypto.js.map +1 -1
- package/dist/crypto/WasmCrypto.d.ts +11 -4
- package/dist/crypto/WasmCrypto.d.ts.map +1 -1
- package/dist/crypto/WasmCrypto.js +52 -10
- package/dist/crypto/WasmCrypto.js.map +1 -1
- package/dist/crypto/WasmCryptoEdge.d.ts +1 -0
- package/dist/crypto/WasmCryptoEdge.d.ts.map +1 -1
- package/dist/crypto/WasmCryptoEdge.js +4 -1
- package/dist/crypto/WasmCryptoEdge.js.map +1 -1
- package/dist/crypto/crypto.d.ts +3 -3
- package/dist/crypto/crypto.d.ts.map +1 -1
- package/dist/crypto/crypto.js +6 -1
- package/dist/crypto/crypto.js.map +1 -1
- package/dist/exports.d.ts +5 -5
- package/dist/exports.d.ts.map +1 -1
- package/dist/exports.js +4 -3
- package/dist/exports.js.map +1 -1
- package/dist/ids.d.ts +4 -1
- package/dist/ids.d.ts.map +1 -1
- package/dist/ids.js +4 -0
- package/dist/ids.js.map +1 -1
- package/dist/knownState.d.ts +2 -0
- package/dist/knownState.d.ts.map +1 -1
- package/dist/localNode.d.ts +12 -0
- package/dist/localNode.d.ts.map +1 -1
- package/dist/localNode.js +14 -0
- package/dist/localNode.js.map +1 -1
- package/dist/platformUtils.d.ts +3 -0
- package/dist/platformUtils.d.ts.map +1 -0
- package/dist/platformUtils.js +24 -0
- package/dist/platformUtils.js.map +1 -0
- package/dist/queue/LinkedList.d.ts +9 -3
- package/dist/queue/LinkedList.d.ts.map +1 -1
- package/dist/queue/LinkedList.js +30 -1
- package/dist/queue/LinkedList.js.map +1 -1
- package/dist/queue/OutgoingLoadQueue.d.ts +95 -0
- package/dist/queue/OutgoingLoadQueue.d.ts.map +1 -0
- package/dist/queue/OutgoingLoadQueue.js +240 -0
- package/dist/queue/OutgoingLoadQueue.js.map +1 -0
- package/dist/storage/DeletedCoValuesEraserScheduler.d.ts +30 -0
- package/dist/storage/DeletedCoValuesEraserScheduler.d.ts.map +1 -0
- package/dist/storage/DeletedCoValuesEraserScheduler.js +84 -0
- package/dist/storage/DeletedCoValuesEraserScheduler.js.map +1 -0
- package/dist/storage/sqlite/client.d.ts +3 -0
- package/dist/storage/sqlite/client.d.ts.map +1 -1
- package/dist/storage/sqlite/client.js +44 -0
- package/dist/storage/sqlite/client.js.map +1 -1
- package/dist/storage/sqlite/sqliteMigrations.d.ts.map +1 -1
- package/dist/storage/sqlite/sqliteMigrations.js +7 -0
- package/dist/storage/sqlite/sqliteMigrations.js.map +1 -1
- package/dist/storage/sqliteAsync/client.d.ts +3 -0
- package/dist/storage/sqliteAsync/client.d.ts.map +1 -1
- package/dist/storage/sqliteAsync/client.js +42 -0
- package/dist/storage/sqliteAsync/client.js.map +1 -1
- package/dist/storage/storageAsync.d.ts +7 -0
- package/dist/storage/storageAsync.d.ts.map +1 -1
- package/dist/storage/storageAsync.js +48 -0
- package/dist/storage/storageAsync.js.map +1 -1
- package/dist/storage/storageSync.d.ts +6 -0
- package/dist/storage/storageSync.d.ts.map +1 -1
- package/dist/storage/storageSync.js +42 -0
- package/dist/storage/storageSync.js.map +1 -1
- package/dist/storage/types.d.ts +59 -0
- package/dist/storage/types.d.ts.map +1 -1
- package/dist/storage/types.js +12 -1
- package/dist/storage/types.js.map +1 -1
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +66 -43
- package/dist/sync.js.map +1 -1
- package/dist/tests/DeletedCoValuesEraserScheduler.test.d.ts +2 -0
- package/dist/tests/DeletedCoValuesEraserScheduler.test.d.ts.map +1 -0
- package/dist/tests/DeletedCoValuesEraserScheduler.test.js +149 -0
- package/dist/tests/DeletedCoValuesEraserScheduler.test.js.map +1 -0
- package/dist/tests/GarbageCollector.test.js +5 -6
- package/dist/tests/GarbageCollector.test.js.map +1 -1
- package/dist/tests/LinkedList.test.js +90 -0
- package/dist/tests/LinkedList.test.js.map +1 -1
- package/dist/tests/OutgoingLoadQueue.test.d.ts +2 -0
- package/dist/tests/OutgoingLoadQueue.test.d.ts.map +1 -0
- package/dist/tests/OutgoingLoadQueue.test.js +814 -0
- package/dist/tests/OutgoingLoadQueue.test.js.map +1 -0
- package/dist/tests/StorageApiAsync.test.js +484 -152
- package/dist/tests/StorageApiAsync.test.js.map +1 -1
- package/dist/tests/StorageApiSync.test.js +505 -136
- package/dist/tests/StorageApiSync.test.js.map +1 -1
- package/dist/tests/WasmCrypto.test.js +6 -3
- package/dist/tests/WasmCrypto.test.js.map +1 -1
- package/dist/tests/coValueCore.loadFromStorage.test.js +3 -0
- package/dist/tests/coValueCore.loadFromStorage.test.js.map +1 -1
- package/dist/tests/coValueCore.test.js +34 -13
- package/dist/tests/coValueCore.test.js.map +1 -1
- package/dist/tests/coreWasm.test.js +127 -4
- package/dist/tests/coreWasm.test.js.map +1 -1
- package/dist/tests/crypto.test.js +89 -93
- package/dist/tests/crypto.test.js.map +1 -1
- package/dist/tests/deleteCoValue.test.d.ts +2 -0
- package/dist/tests/deleteCoValue.test.d.ts.map +1 -0
- package/dist/tests/deleteCoValue.test.js +313 -0
- package/dist/tests/deleteCoValue.test.js.map +1 -0
- package/dist/tests/group.removeMember.test.js +18 -30
- package/dist/tests/group.removeMember.test.js.map +1 -1
- package/dist/tests/knownState.lazyLoading.test.js +3 -0
- package/dist/tests/knownState.lazyLoading.test.js.map +1 -1
- package/dist/tests/sync.concurrentLoad.test.d.ts +2 -0
- package/dist/tests/sync.concurrentLoad.test.d.ts.map +1 -0
- package/dist/tests/sync.concurrentLoad.test.js +481 -0
- package/dist/tests/sync.concurrentLoad.test.js.map +1 -0
- package/dist/tests/sync.deleted.test.d.ts +2 -0
- package/dist/tests/sync.deleted.test.d.ts.map +1 -0
- package/dist/tests/sync.deleted.test.js +214 -0
- package/dist/tests/sync.deleted.test.js.map +1 -0
- package/dist/tests/sync.mesh.test.js +3 -2
- package/dist/tests/sync.mesh.test.js.map +1 -1
- package/dist/tests/sync.storage.test.js +4 -3
- package/dist/tests/sync.storage.test.js.map +1 -1
- package/dist/tests/sync.test.js +3 -2
- package/dist/tests/sync.test.js.map +1 -1
- package/dist/tests/testStorage.d.ts +3 -0
- package/dist/tests/testStorage.d.ts.map +1 -1
- package/dist/tests/testStorage.js +17 -1
- package/dist/tests/testStorage.js.map +1 -1
- package/dist/tests/testUtils.d.ts +7 -3
- package/dist/tests/testUtils.d.ts.map +1 -1
- package/dist/tests/testUtils.js +19 -4
- package/dist/tests/testUtils.js.map +1 -1
- package/package.json +6 -16
- package/src/PeerState.ts +26 -3
- package/src/coValueContentMessage.ts +0 -14
- package/src/coValueCore/SessionMap.ts +43 -1
- package/src/coValueCore/coValueCore.ts +415 -27
- package/src/coValueCore/verifiedState.ts +26 -3
- package/src/coValues/coList.ts +9 -3
- package/src/coValues/group.ts +5 -6
- package/src/config.ts +4 -13
- package/src/crypto/NapiCrypto.ts +29 -13
- package/src/crypto/RNCrypto.ts +29 -11
- package/src/crypto/WasmCrypto.ts +67 -20
- package/src/crypto/WasmCryptoEdge.ts +5 -1
- package/src/crypto/crypto.ts +16 -4
- package/src/exports.ts +4 -2
- package/src/ids.ts +11 -1
- package/src/localNode.ts +15 -0
- package/src/platformUtils.ts +26 -0
- package/src/queue/LinkedList.ts +34 -4
- package/src/queue/OutgoingLoadQueue.ts +307 -0
- package/src/storage/DeletedCoValuesEraserScheduler.ts +124 -0
- package/src/storage/sqlite/client.ts +77 -0
- package/src/storage/sqlite/sqliteMigrations.ts +7 -0
- package/src/storage/sqliteAsync/client.ts +75 -0
- package/src/storage/storageAsync.ts +62 -0
- package/src/storage/storageSync.ts +58 -0
- package/src/storage/types.ts +69 -0
- package/src/sync.ts +78 -46
- package/src/tests/DeletedCoValuesEraserScheduler.test.ts +185 -0
- package/src/tests/GarbageCollector.test.ts +6 -10
- package/src/tests/LinkedList.test.ts +111 -0
- package/src/tests/OutgoingLoadQueue.test.ts +1129 -0
- package/src/tests/StorageApiAsync.test.ts +572 -162
- package/src/tests/StorageApiSync.test.ts +580 -143
- package/src/tests/WasmCrypto.test.ts +8 -3
- package/src/tests/coValueCore.loadFromStorage.test.ts +6 -0
- package/src/tests/coValueCore.test.ts +49 -14
- package/src/tests/coreWasm.test.ts +319 -10
- package/src/tests/crypto.test.ts +141 -150
- package/src/tests/deleteCoValue.test.ts +528 -0
- package/src/tests/group.removeMember.test.ts +35 -35
- package/src/tests/knownState.lazyLoading.test.ts +6 -0
- package/src/tests/sync.concurrentLoad.test.ts +650 -0
- package/src/tests/sync.deleted.test.ts +294 -0
- package/src/tests/sync.mesh.test.ts +5 -2
- package/src/tests/sync.storage.test.ts +6 -3
- package/src/tests/sync.test.ts +5 -2
- package/src/tests/testStorage.ts +31 -2
- package/src/tests/testUtils.ts +31 -10
- package/dist/crypto/PureJSCrypto.d.ts +0 -77
- package/dist/crypto/PureJSCrypto.d.ts.map +0 -1
- package/dist/crypto/PureJSCrypto.js +0 -236
- package/dist/crypto/PureJSCrypto.js.map +0 -1
- package/dist/tests/PureJSCrypto.test.d.ts +0 -2
- package/dist/tests/PureJSCrypto.test.d.ts.map +0 -1
- package/dist/tests/PureJSCrypto.test.js +0 -145
- package/dist/tests/PureJSCrypto.test.js.map +0 -1
- package/src/crypto/PureJSCrypto.ts +0 -429
- package/src/tests/PureJSCrypto.test.ts +0 -217
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
|
|
2
|
+
import { logger } from "../logger.js";
|
|
3
|
+
import { DeletedCoValuesEraserScheduler } from "../storage/DeletedCoValuesEraserScheduler.js";
|
|
4
|
+
|
|
5
|
+
describe("DeletedCoValuesEraserScheduler", () => {
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
vi.useFakeTimers();
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
afterEach(() => {
|
|
11
|
+
vi.clearAllTimers();
|
|
12
|
+
vi.useRealTimers();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test("scheduleStartupDrain runs once after startupDelayMs (when idle)", async () => {
|
|
16
|
+
let runs = 0;
|
|
17
|
+
const scheduler = new DeletedCoValuesEraserScheduler({
|
|
18
|
+
run: async () => {
|
|
19
|
+
runs += 1;
|
|
20
|
+
return { hasMore: false };
|
|
21
|
+
},
|
|
22
|
+
opts: { throttleMs: 50, startupDelayMs: 10, followUpDelayMs: 10 },
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
scheduler.scheduleStartupDrain();
|
|
26
|
+
|
|
27
|
+
expect(runs).toBe(0);
|
|
28
|
+
await vi.advanceTimersByTimeAsync(10);
|
|
29
|
+
expect(runs).toBe(1);
|
|
30
|
+
scheduler.dispose();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test("onEnqueueDeletedCoValue is throttled (multiple enqueues -> one run)", async () => {
|
|
34
|
+
let runs = 0;
|
|
35
|
+
const scheduler = new DeletedCoValuesEraserScheduler({
|
|
36
|
+
run: async () => {
|
|
37
|
+
runs += 1;
|
|
38
|
+
return { hasMore: false };
|
|
39
|
+
},
|
|
40
|
+
opts: { throttleMs: 30, startupDelayMs: 10, followUpDelayMs: 10 },
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
scheduler.onEnqueueDeletedCoValue();
|
|
44
|
+
scheduler.onEnqueueDeletedCoValue();
|
|
45
|
+
scheduler.onEnqueueDeletedCoValue();
|
|
46
|
+
|
|
47
|
+
expect(runs).toBe(0);
|
|
48
|
+
await vi.advanceTimersByTimeAsync(29);
|
|
49
|
+
expect(runs).toBe(0);
|
|
50
|
+
await vi.advanceTimersByTimeAsync(1);
|
|
51
|
+
expect(runs).toBe(1);
|
|
52
|
+
|
|
53
|
+
// Ensure no second run was scheduled by repeated enqueues in the same throttle window.
|
|
54
|
+
await vi.advanceTimersByTimeAsync(100);
|
|
55
|
+
expect(runs).toBe(1);
|
|
56
|
+
|
|
57
|
+
scheduler.dispose();
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test("schedules follow-up phases while run reports hasMore=true", async () => {
|
|
61
|
+
let remaining = 3;
|
|
62
|
+
let runs = 0;
|
|
63
|
+
const scheduler = new DeletedCoValuesEraserScheduler({
|
|
64
|
+
run: async () => {
|
|
65
|
+
runs += 1;
|
|
66
|
+
remaining -= 1;
|
|
67
|
+
return { hasMore: remaining > 0 };
|
|
68
|
+
},
|
|
69
|
+
opts: { throttleMs: 10, startupDelayMs: 10, followUpDelayMs: 10 },
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
scheduler.onEnqueueDeletedCoValue();
|
|
73
|
+
|
|
74
|
+
await vi.runAllTimersAsync();
|
|
75
|
+
expect(runs).toBe(3);
|
|
76
|
+
scheduler.dispose();
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("never runs run concurrently (re-entrancy guard via internal state machine)", async () => {
|
|
80
|
+
let concurrent = 0;
|
|
81
|
+
let maxConcurrent = 0;
|
|
82
|
+
let remaining = 2;
|
|
83
|
+
|
|
84
|
+
const scheduler = new DeletedCoValuesEraserScheduler({
|
|
85
|
+
run: async () => {
|
|
86
|
+
concurrent += 1;
|
|
87
|
+
maxConcurrent = Math.max(maxConcurrent, concurrent);
|
|
88
|
+
|
|
89
|
+
await new Promise<void>((resolve) => setTimeout(resolve, 30));
|
|
90
|
+
remaining -= 1;
|
|
91
|
+
|
|
92
|
+
concurrent -= 1;
|
|
93
|
+
return { hasMore: remaining > 0 };
|
|
94
|
+
},
|
|
95
|
+
opts: { throttleMs: 10, startupDelayMs: 10, followUpDelayMs: 10 },
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
scheduler.onEnqueueDeletedCoValue();
|
|
99
|
+
await vi.advanceTimersByTimeAsync(10); // start first run
|
|
100
|
+
|
|
101
|
+
// Even if we spam enqueues while active, they should be ignored.
|
|
102
|
+
scheduler.onEnqueueDeletedCoValue();
|
|
103
|
+
scheduler.onEnqueueDeletedCoValue();
|
|
104
|
+
|
|
105
|
+
await vi.runAllTimersAsync();
|
|
106
|
+
expect(remaining).toBe(0);
|
|
107
|
+
expect(maxConcurrent).toBe(1);
|
|
108
|
+
|
|
109
|
+
scheduler.dispose();
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test("ignores enqueues while not idle, but schedules again once idle", async () => {
|
|
113
|
+
let runs = 0;
|
|
114
|
+
const scheduler = new DeletedCoValuesEraserScheduler({
|
|
115
|
+
run: async () => {
|
|
116
|
+
runs += 1;
|
|
117
|
+
return { hasMore: false };
|
|
118
|
+
},
|
|
119
|
+
opts: { throttleMs: 30, startupDelayMs: 10, followUpDelayMs: 10 },
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
scheduler.onEnqueueDeletedCoValue(); // schedules first run
|
|
123
|
+
await vi.advanceTimersByTimeAsync(5);
|
|
124
|
+
scheduler.onEnqueueDeletedCoValue(); // should be ignored (not idle)
|
|
125
|
+
|
|
126
|
+
await vi.advanceTimersByTimeAsync(25);
|
|
127
|
+
expect(runs).toBe(1);
|
|
128
|
+
|
|
129
|
+
// Now idle again; next enqueue should schedule another run.
|
|
130
|
+
scheduler.onEnqueueDeletedCoValue();
|
|
131
|
+
await vi.advanceTimersByTimeAsync(30);
|
|
132
|
+
expect(runs).toBe(2);
|
|
133
|
+
|
|
134
|
+
scheduler.dispose();
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test("dispose cancels any scheduled run", async () => {
|
|
138
|
+
let runs = 0;
|
|
139
|
+
const scheduler = new DeletedCoValuesEraserScheduler({
|
|
140
|
+
run: async () => {
|
|
141
|
+
runs += 1;
|
|
142
|
+
return { hasMore: false };
|
|
143
|
+
},
|
|
144
|
+
opts: { throttleMs: 30, startupDelayMs: 10, followUpDelayMs: 10 },
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
scheduler.onEnqueueDeletedCoValue();
|
|
148
|
+
scheduler.dispose();
|
|
149
|
+
|
|
150
|
+
await vi.advanceTimersByTimeAsync(60);
|
|
151
|
+
expect(runs).toBe(0);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
test("recovers when run throws (logs error and returns to idle so it can run again)", async () => {
|
|
155
|
+
const err = new Error("boom");
|
|
156
|
+
const errorSpy = vi.spyOn(logger, "error").mockImplementation(() => {});
|
|
157
|
+
|
|
158
|
+
let runs = 0;
|
|
159
|
+
const scheduler = new DeletedCoValuesEraserScheduler({
|
|
160
|
+
run: async () => {
|
|
161
|
+
runs += 1;
|
|
162
|
+
if (runs === 1) throw err;
|
|
163
|
+
return { hasMore: false };
|
|
164
|
+
},
|
|
165
|
+
opts: { throttleMs: 10, startupDelayMs: 10, followUpDelayMs: 10 },
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
scheduler.onEnqueueDeletedCoValue();
|
|
169
|
+
await vi.advanceTimersByTimeAsync(10);
|
|
170
|
+
expect(runs).toBe(1);
|
|
171
|
+
|
|
172
|
+
expect(errorSpy).toHaveBeenCalledWith(
|
|
173
|
+
"Error running deleted co values eraser scheduler",
|
|
174
|
+
expect.objectContaining({ err }),
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
// If the scheduler didn't reset back to idle after the error, this enqueue would be ignored.
|
|
178
|
+
scheduler.onEnqueueDeletedCoValue();
|
|
179
|
+
await vi.advanceTimersByTimeAsync(10);
|
|
180
|
+
expect(runs).toBe(2);
|
|
181
|
+
|
|
182
|
+
scheduler.dispose();
|
|
183
|
+
errorSpy.mockRestore();
|
|
184
|
+
});
|
|
185
|
+
});
|
|
@@ -205,6 +205,8 @@ describe("garbage collector", () => {
|
|
|
205
205
|
});
|
|
206
206
|
|
|
207
207
|
test("coValues are not garbage collected if the maxAge is not reached", async () => {
|
|
208
|
+
vi.useFakeTimers();
|
|
209
|
+
|
|
208
210
|
setGarbageCollectorMaxAge(1000);
|
|
209
211
|
|
|
210
212
|
const client = setupTestNode();
|
|
@@ -212,37 +214,31 @@ describe("garbage collector", () => {
|
|
|
212
214
|
client.addStorage({
|
|
213
215
|
ourName: "client",
|
|
214
216
|
});
|
|
215
|
-
client.connectToSyncServer();
|
|
216
217
|
client.node.enableGarbageCollector();
|
|
217
218
|
|
|
218
219
|
const garbageCollector = client.node.garbageCollector;
|
|
219
220
|
|
|
220
221
|
assert(garbageCollector);
|
|
221
222
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
getCurrentTime.mockReturnValue(1);
|
|
223
|
+
await vi.advanceTimersByTimeAsync(100);
|
|
225
224
|
|
|
226
225
|
const group = client.node.createGroup();
|
|
227
226
|
const map1 = group.createMap();
|
|
228
227
|
const map2 = group.createMap();
|
|
229
228
|
|
|
230
|
-
await
|
|
229
|
+
await vi.advanceTimersByTimeAsync(800);
|
|
231
230
|
|
|
231
|
+
// Access map1 again, to prevent it from being garbage collected
|
|
232
232
|
map1.set("hello", "world", "trusting");
|
|
233
233
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
234
|
+
await vi.advanceTimersByTimeAsync(300);
|
|
237
235
|
|
|
238
236
|
garbageCollector.collect();
|
|
239
237
|
|
|
240
238
|
const coValue = client.node.getCoValue(map1.id);
|
|
241
|
-
|
|
242
239
|
expect(coValue.isAvailable()).toBe(true);
|
|
243
240
|
|
|
244
241
|
const coValue2 = client.node.getCoValue(map2.id);
|
|
245
|
-
|
|
246
242
|
expect(coValue2.isAvailable()).toBe(false);
|
|
247
243
|
});
|
|
248
244
|
});
|
|
@@ -76,6 +76,117 @@ describe("LinkedList", () => {
|
|
|
76
76
|
});
|
|
77
77
|
});
|
|
78
78
|
|
|
79
|
+
describe("remove", () => {
|
|
80
|
+
it("should remove the only element in the list", () => {
|
|
81
|
+
const node = list.push(1);
|
|
82
|
+
list.remove(node);
|
|
83
|
+
|
|
84
|
+
expect(list.length).toBe(0);
|
|
85
|
+
expect(list.head).toBeUndefined();
|
|
86
|
+
expect(list.tail).toBeUndefined();
|
|
87
|
+
expect(node.prev).toBeUndefined();
|
|
88
|
+
expect(node.next).toBeUndefined();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("should remove the head element", () => {
|
|
92
|
+
const node1 = list.push(1);
|
|
93
|
+
const node2 = list.push(2);
|
|
94
|
+
const node3 = list.push(3);
|
|
95
|
+
|
|
96
|
+
list.remove(node1);
|
|
97
|
+
|
|
98
|
+
expect(list.length).toBe(2);
|
|
99
|
+
expect(list.head).toBe(node2);
|
|
100
|
+
expect(list.tail).toBe(node3);
|
|
101
|
+
expect(node2.prev).toBeUndefined();
|
|
102
|
+
expect(node1.prev).toBeUndefined();
|
|
103
|
+
expect(node1.next).toBeUndefined();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it("should remove the tail element", () => {
|
|
107
|
+
const node1 = list.push(1);
|
|
108
|
+
const node2 = list.push(2);
|
|
109
|
+
const node3 = list.push(3);
|
|
110
|
+
|
|
111
|
+
list.remove(node3);
|
|
112
|
+
|
|
113
|
+
expect(list.length).toBe(2);
|
|
114
|
+
expect(list.head).toBe(node1);
|
|
115
|
+
expect(list.tail).toBe(node2);
|
|
116
|
+
expect(node2.next).toBeUndefined();
|
|
117
|
+
expect(node3.prev).toBeUndefined();
|
|
118
|
+
expect(node3.next).toBeUndefined();
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("should remove a middle element", () => {
|
|
122
|
+
const node1 = list.push(1);
|
|
123
|
+
const node2 = list.push(2);
|
|
124
|
+
const node3 = list.push(3);
|
|
125
|
+
|
|
126
|
+
list.remove(node2);
|
|
127
|
+
|
|
128
|
+
expect(list.length).toBe(2);
|
|
129
|
+
expect(list.head).toBe(node1);
|
|
130
|
+
expect(list.tail).toBe(node3);
|
|
131
|
+
expect(node1.next).toBe(node3);
|
|
132
|
+
expect(node3.prev).toBe(node1);
|
|
133
|
+
expect(node2.prev).toBeUndefined();
|
|
134
|
+
expect(node2.next).toBeUndefined();
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it("should maintain correct state after multiple removes", () => {
|
|
138
|
+
const node1 = list.push(1);
|
|
139
|
+
const node2 = list.push(2);
|
|
140
|
+
const node3 = list.push(3);
|
|
141
|
+
const node4 = list.push(4);
|
|
142
|
+
|
|
143
|
+
// Remove middle
|
|
144
|
+
list.remove(node2);
|
|
145
|
+
expect(list.length).toBe(3);
|
|
146
|
+
expect(node1.next).toBe(node3);
|
|
147
|
+
expect(node3.prev).toBe(node1);
|
|
148
|
+
|
|
149
|
+
// Remove head
|
|
150
|
+
list.remove(node1);
|
|
151
|
+
expect(list.length).toBe(2);
|
|
152
|
+
expect(list.head).toBe(node3);
|
|
153
|
+
|
|
154
|
+
// Remove tail
|
|
155
|
+
list.remove(node4);
|
|
156
|
+
expect(list.length).toBe(1);
|
|
157
|
+
expect(list.head).toBe(node3);
|
|
158
|
+
expect(list.tail).toBe(node3);
|
|
159
|
+
|
|
160
|
+
// Remove last
|
|
161
|
+
list.remove(node3);
|
|
162
|
+
expect(list.length).toBe(0);
|
|
163
|
+
expect(list.head).toBeUndefined();
|
|
164
|
+
expect(list.tail).toBeUndefined();
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it("should allow shift after remove", () => {
|
|
168
|
+
const node1 = list.push(1);
|
|
169
|
+
list.push(2);
|
|
170
|
+
list.push(3);
|
|
171
|
+
|
|
172
|
+
list.remove(node1);
|
|
173
|
+
|
|
174
|
+
expect(list.shift()).toBe(2);
|
|
175
|
+
expect(list.shift()).toBe(3);
|
|
176
|
+
expect(list.length).toBe(0);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it("should allow push after remove", () => {
|
|
180
|
+
const node1 = list.push(1);
|
|
181
|
+
list.remove(node1);
|
|
182
|
+
|
|
183
|
+
list.push(2);
|
|
184
|
+
expect(list.length).toBe(1);
|
|
185
|
+
expect(list.head?.value).toBe(2);
|
|
186
|
+
expect(list.tail?.value).toBe(2);
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
|
|
79
190
|
describe("edge cases", () => {
|
|
80
191
|
it("should handle push after all elements have been shifted", () => {
|
|
81
192
|
list.push(1);
|