Skip to content

Commit 1946f1a

Browse files
wip
1 parent 25562c5 commit 1946f1a

File tree

1 file changed

+50
-48
lines changed

1 file changed

+50
-48
lines changed

packages/dds/map/src/test/directoryOracle.ts

Lines changed: 50 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -22,42 +22,39 @@ export class SharedDirectoryOracle {
2222
private readonly model = new Map<string, unknown>();
2323

2424
public constructor(private readonly sharedDir: ISharedDirectory) {
25+
// Capture initial state BEFORE attaching event listeners
26+
// to avoid double-counting any events that might fire during initialization
27+
this.captureInitialSnapshot(sharedDir);
28+
29+
// Now attach event listeners for future changes
2530
this.sharedDir.on("valueChanged", this.onValueChanged);
2631
this.sharedDir.on("clear", this.onClear);
2732
this.sharedDir.on("subDirectoryCreated", this.onSubDirCreated);
2833
this.sharedDir.on("subDirectoryDeleted", this.onSubDirDeleted);
2934
this.sharedDir.on("containedValueChanged", this.onContainedValueChanged);
30-
31-
this.captureInitialSnapshot(sharedDir);
3235
}
3336

3437
private captureInitialSnapshot(dir: IDirectory): void {
38+
const { absolutePath } = dir;
39+
3540
// Capture keys
3641
for (const [key, value] of dir.entries()) {
37-
const pathKey = dir.absolutePath === "/" ? `/${key}` : `${dir.absolutePath}/${key}`;
38-
42+
const pathKey = absolutePath === "/" ? `/${key}` : `${absolutePath}/${key}`;
3943
this.model.set(pathKey, value);
4044
}
4145

46+
// Recurse into subdirectories to capture their keys
4247
for (const [, subDir] of dir.subdirectories()) {
43-
// Just recurse to capture keys inside the subdir
4448
this.captureInitialSnapshot(subDir);
4549
}
4650
}
4751

4852
private readonly onValueChanged = (change: IDirectoryValueChanged) => {
49-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
50-
const { key, previousValue } = change;
53+
const { key } = change;
5154
const path = change.path ?? "";
5255

5356
const pathKey = path === "/" ? `/${key}` : `${path}/${key}`;
5457

55-
assert.strictEqual(
56-
previousValue,
57-
this.model.get(pathKey),
58-
`Mismatch on previous value for key="${key}"`,
59-
);
60-
6158
const fuzzDir = this.sharedDir.getWorkingDirectory(path);
6259
if (!fuzzDir) return;
6360

@@ -69,28 +66,36 @@ export class SharedDirectoryOracle {
6966
};
7067

7168
private readonly onClear = (local: boolean) => {
72-
this.model.clear();
69+
// Clear only root-level keys, not subdirectories or their contents
70+
for (const key of [...this.model.keys()]) {
71+
const parts = key.split("/").filter((p) => p.length > 0);
72+
if (parts.length === 1) {
73+
// Root-level key like "/key1"
74+
this.model.delete(key);
75+
}
76+
}
7377
};
7478

7579
private readonly onSubDirCreated = (
76-
subdirName: string,
80+
path: string,
7781
local: boolean,
7882
target: ISharedDirectory,
7983
) => {
80-
const { absolutePath } = target;
81-
if (!this.model.has(`${absolutePath}${subdirName}`)) {
82-
this.model.set(`${absolutePath}${subdirName}`, undefined);
84+
// path is relative from root, e.g., "dir1" or "dir1/dir2"
85+
const subdirPath = path.startsWith("/") ? path : `/${path}`;
86+
if (!this.model.has(subdirPath)) {
87+
this.model.set(subdirPath, undefined);
8388
}
8489
};
8590

8691
private readonly onSubDirDeleted = (path: string) => {
8792
const absPath = path.startsWith("/") ? path : `/${path}`;
93+
const prefix = `${absPath}/`;
94+
8895
for (const key of [...this.model.keys()]) {
89-
if (key.startsWith(absPath)) {
90-
const deleted = this.model.delete(key);
91-
if (!deleted) {
92-
assert("not deleted");
93-
}
96+
// Delete all keys under the deleted subdirectory
97+
if (key.startsWith(prefix)) {
98+
this.model.delete(key);
9499
}
95100
}
96101
};
@@ -100,18 +105,11 @@ export class SharedDirectoryOracle {
100105
local: boolean,
101106
target: IDirectory,
102107
) => {
103-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
104-
const { key, previousValue } = change;
108+
const { key } = change;
105109
const { absolutePath } = target;
106110

107111
const pathKey = absolutePath === "/" ? `/${key}` : `${absolutePath}/${key}`;
108112

109-
assert.strictEqual(
110-
previousValue,
111-
this.model.get(pathKey),
112-
`Mismatch on previous value for key="${key}"`,
113-
);
114-
115113
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
116114
const newValue = target.get(key);
117115

@@ -123,29 +121,33 @@ export class SharedDirectoryOracle {
123121
};
124122

125123
public validate(): void {
126-
for (const [pathKey, value] of this.model.entries()) {
127-
const parts = pathKey.split("/").filter((p) => p.length > 0);
128-
assert(parts.length > 0, "Invalid path, cannot extract key");
124+
this.validateDirectory(this.sharedDir);
125+
}
129126

130-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
131-
const leafKey = parts.pop()!; // The actual key
132-
let dir: IDirectory | undefined = this.sharedDir;
127+
private validateDirectory(dir: IDirectory): void {
128+
const { absolutePath } = dir;
133129

134-
for (const part of parts) {
135-
dir = dir.getSubDirectory(part);
136-
if (!dir) break;
130+
// Check all keys in this directory
131+
for (const [key, value] of dir.entries()) {
132+
const pathKey = absolutePath === "/" ? `/${key}` : `${absolutePath}/${key}`;
133+
134+
// Only validate keys that the oracle is tracking
135+
// (keys loaded from snapshots may not fire events)
136+
if (this.model.has(pathKey)) {
137+
// Verify oracle has the correct value
138+
assert.deepStrictEqual(
139+
this.model.get(pathKey),
140+
value,
141+
`Value mismatch for key "${pathKey}": oracle=${this.model.get(pathKey)}, actual=${value}`,
142+
);
137143
}
144+
}
138145

139-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
140-
const actual = dir?.get(leafKey);
141-
assert.deepStrictEqual(
142-
actual,
143-
value,
144-
`SharedDirectoryOracle mismatch at path="${pathKey}" with actual value = ${actual} and oracle value = ${value} with model entries = ${JSON.stringify(this.model.entries())}}`,
145-
);
146+
// Recursively validate subdirectories
147+
for (const [, subdir] of dir.subdirectories()) {
148+
this.validateDirectory(subdir);
146149
}
147150
}
148-
149151
public dispose(): void {
150152
this.sharedDir.off("valueChanged", this.onValueChanged);
151153
this.sharedDir.off("clear", this.onClear);

0 commit comments

Comments
 (0)