diff --git a/frontend/sync-client/src/file-operations/file-operations.test.ts b/frontend/sync-client/src/file-operations/file-operations.test.ts index 85364eb2..1fd99aea 100644 --- a/frontend/sync-client/src/file-operations/file-operations.test.ts +++ b/frontend/sync-client/src/file-operations/file-operations.test.ts @@ -1,17 +1,26 @@ -import { FileSystemOperations } from "sync-client"; -import type { RelativePath } from "../persistence/database"; +import type { FileSystemOperations } from "sync-client"; +import type { Database, RelativePath } from "../persistence/database"; import { FileOperations } from "./file-operations"; import { Logger } from "../tracing/logger"; -import assert from "assert"; +import { assertSetContainsExactly } from "src/utils/assert-set-contains-exactly"; describe("File operations", () => { + class MockDatabase { + public async updatePath( + _oldRelativePath: RelativePath, + _newRelativePath: RelativePath + ): Promise { + // this is called but irrelevant for this mock + } + } + class FakeFileSystemOperations implements FileSystemOperations { public readonly names = new Set(); - public listAllFiles(): Promise { + public async listAllFiles(): Promise { throw new Error("Method not implemented."); } - public read(path: RelativePath): Promise { + public async read(_path: RelativePath): Promise { throw new Error("Method not implemented."); } public async write( @@ -20,23 +29,25 @@ describe("File operations", () => { ): Promise { this.names.add(path); } - public atomicUpdateText( - path: RelativePath, - updater: (currentContent: string) => string + public async atomicUpdateText( + _path: RelativePath, + _updater: (currentContent: string) => string ): Promise { throw new Error("Method not implemented."); } - public getFileSize(path: RelativePath): Promise { + public async getFileSize(_path: RelativePath): Promise { throw new Error("Method not implemented."); } - public getModificationTime(path: RelativePath): Promise { + public async getModificationTime(_path: RelativePath): Promise { throw new Error("Method not implemented."); } public async exists(path: RelativePath): Promise { return this.names.has(path); } - public async createDirectory(path: RelativePath): Promise {} - public delete(path: RelativePath): Promise { + public async createDirectory(_path: RelativePath): Promise { + // this is called but irrelevant for this mock + } + public async delete(_path: RelativePath): Promise { throw new Error("Method not implemented."); } public async rename( @@ -49,54 +60,54 @@ describe("File operations", () => { } test("should deconflict renames", async () => { - let fs = new FakeFileSystemOperations(); - let fileOperations = new FileOperations(new Logger(), fs); + const fs = new FakeFileSystemOperations(); + const fileOperations = new FileOperations( + new Logger(), + new MockDatabase() as Database, // eslint-disable-line @typescript-eslint/no-unsafe-type-assertion + fs + ); await fileOperations.create("a", new Uint8Array()); - assertSetOnlyContains(fs.names, "a"); + assertSetContainsExactly(fs.names, "a"); await fileOperations.move("a", "b"); - assertSetOnlyContains(fs.names, "b"); + assertSetContainsExactly(fs.names, "b"); await fileOperations.create("c", new Uint8Array()); - assertSetOnlyContains(fs.names, "b", "c"); + assertSetContainsExactly(fs.names, "b", "c"); await fileOperations.move("c", "b"); - assertSetOnlyContains(fs.names, "b", "b (1)"); + assertSetContainsExactly(fs.names, "b", "b (1)"); await fileOperations.create("c", new Uint8Array()); await fileOperations.move("c", "b"); - assertSetOnlyContains(fs.names, "b", "b (1)", "b (2)"); + assertSetContainsExactly(fs.names, "b", "b (1)", "b (2)"); }); test("should deconflict renames with file extension", async () => { - let fs = new FakeFileSystemOperations(); - let fileOperations = new FileOperations(new Logger(), fs); + const fs = new FakeFileSystemOperations(); + const fileOperations = new FileOperations( + new Logger(), + new MockDatabase() as Database, // eslint-disable-line @typescript-eslint/no-unsafe-type-assertion + fs + ); await fileOperations.create("b.md", new Uint8Array()); await fileOperations.create("c.md", new Uint8Array()); await fileOperations.move("c.md", "b.md"); - assertSetOnlyContains(fs.names, "b.md", "b (1).md"); + assertSetContainsExactly(fs.names, "b.md", "b (1).md"); }); test("should deconflict renames with paths", async () => { - let fs = new FakeFileSystemOperations(); - let fileOperations = new FileOperations(new Logger(), fs); + const fs = new FakeFileSystemOperations(); + const fileOperations = new FileOperations( + new Logger(), + new MockDatabase() as Database, // eslint-disable-line @typescript-eslint/no-unsafe-type-assertion + fs + ); await fileOperations.create("a/b.c/d", new Uint8Array()); await fileOperations.create("a/b.c/e", new Uint8Array()); await fileOperations.move("a/b.c/d", "a/b.c/e"); - assertSetOnlyContains(fs.names, "a/b.c/e", "a/b.c/e (1)"); + assertSetContainsExactly(fs.names, "a/b.c/e", "a/b.c/e (1)"); }); }); - -function assertSetOnlyContains(set: Set, ...values: T[]) { - assert( - set.size === values.length && - Array.from(set).every((value) => values.includes(value)), - `Expected set to contain only ${values.map((v) => '"' + v + '"').join(", ")}, but it contained ${Array.from( - set - ) - .map((v) => '"' + v + '"') - .join(", ")}` - ); -} diff --git a/frontend/sync-client/src/utils/assert-set-contains-exactly.ts b/frontend/sync-client/src/utils/assert-set-contains-exactly.ts new file mode 100644 index 00000000..9682044e --- /dev/null +++ b/frontend/sync-client/src/utils/assert-set-contains-exactly.ts @@ -0,0 +1,13 @@ +import assert from "assert"; + +export function assertSetContainsExactly(set: Set, ...values: T[]): void { + assert( + set.size === values.length && + Array.from(set).every((value) => values.includes(value)), + `Expected set to contain only ${values.map((v) => '"' + v + '"').join(", ")}, but it contained ${Array.from( + set + ) + .map((v) => '"' + v + '"') + .join(", ")}` + ); +}