From 55dcd4d5b5f6f17fafaaaf34c6debdc9047332aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jim=C3=A9nez=20Rivera?= Date: Sat, 1 Feb 2025 01:07:38 +0100 Subject: [PATCH 1/3] Create addon wrapper --- index.ts | 3 +- src/addon-wrapper.ts | 148 +++++++++++++++++++++++++++++++ src/{addon => }/addon-zod.ts | 0 src/addon.ts | 9 +- src/virtual-drive.ts | 138 +++++++++++----------------- src/virtual-drive.unit.test.ts | 2 +- src/watcher/watcher.interface.ts | 2 +- 7 files changed, 206 insertions(+), 96 deletions(-) create mode 100644 src/addon-wrapper.ts rename src/{addon => }/addon-zod.ts (100%) diff --git a/index.ts b/index.ts index f1595145..b814403f 100644 --- a/index.ts +++ b/index.ts @@ -1,5 +1,6 @@ +import { Addon } from "./src/addon-wrapper"; import { QueueManager } from "./src/queue/queue-manager"; import { QueueItem, typeQueue, HandleAction, HandleActions } from "./src/queue/queueManager"; import VirtualDrive from "./src/virtual-drive"; -export { VirtualDrive, QueueItem, typeQueue, HandleAction, HandleActions, QueueManager }; +export { Addon, VirtualDrive, QueueItem, typeQueue, HandleAction, HandleActions, QueueManager }; diff --git a/src/addon-wrapper.ts b/src/addon-wrapper.ts new file mode 100644 index 00000000..9b920e1f --- /dev/null +++ b/src/addon-wrapper.ts @@ -0,0 +1,148 @@ +import { addon } from "./addon"; +import { addonZod } from "./addon-zod"; +import { Callbacks } from "./types/callbacks.type"; + +export class Addon { + syncRootPath!: string; + + private parseAddonZod(fn: keyof typeof addonZod, data: T) { + const schema = addonZod[fn]; + const result = schema.safeParse(data); + if (result.error) console.error(fn, result.error); + return data; + } + + registerSyncRoot({ + syncRootPath, + providerName, + providerVersion, + providerId, + logoPath, + }: { + syncRootPath: string; + providerName: string; + providerVersion: string; + providerId: string; + logoPath: string; + }) { + this.syncRootPath = syncRootPath; + const result = addon.registerSyncRoot(this.syncRootPath, providerName, providerVersion, providerId, logoPath); + return this.parseAddonZod("registerSyncRoot", result); + } + + connectSyncRoot({ callbacks }: { callbacks: Callbacks }) { + const result = addon.connectSyncRoot(this.syncRootPath, callbacks); + return this.parseAddonZod("connectSyncRoot", result); + } + + unregisterSyncRoot({ syncRootPath }: { syncRootPath: string }) { + const result = addon.unregisterSyncRoot(syncRootPath); + return this.parseAddonZod("unregisterSyncRoot", result); + } + + disconnectSyncRoot() { + addon.disconnectSyncRoot(this.syncRootPath); + } + + addLogger({ logPath }: { logPath: string }) { + const result = addon.addLoggerPath(logPath); + return this.parseAddonZod("addLoggerPath", result); + } + + getPlaceholderState({ path }: { path: string }) { + const result = addon.getPlaceholderState(path); + return this.parseAddonZod("getPlaceholderState", result); + } + + getPlaceholderWithStatePending() { + const result = addon.getPlaceholderWithStatePending(this.syncRootPath); + return this.parseAddonZod("getPlaceholderWithStatePending", result); + } + + getFileIdentity({ path }: { path: string }) { + const result = addon.getFileIdentity(path); + return this.parseAddonZod("getFileIdentity", result); + } + + async deleteFileSyncRoot({ path }: { path: string }) { + return addon.deleteFileSyncRoot(path); + } + + createPlaceholderFile({ + fileName, + fileId, + fileSize, + fileAttributes, + creationTime, + lastWriteTime, + lastAccessTime, + basePath, + }: { + fileName: string; + fileId: string; + fileSize: number; + fileAttributes: number; + creationTime: string; + lastWriteTime: string; + lastAccessTime: string; + basePath: string; + }) { + return addon.createPlaceholderFile(fileName, fileId, fileSize, fileAttributes, creationTime, lastWriteTime, lastAccessTime, basePath); + } + + createPlaceholderDirectory({ + itemName, + itemId, + isDirectory, + itemSize, + fileAttributes, + creationTime, + lastWriteTime, + lastAccessTime, + path, + }: { + itemName: string; + itemId: string; + isDirectory: boolean; + itemSize: number; + fileAttributes: number; + creationTime: string; + lastWriteTime: string; + lastAccessTime: string; + path: string; + }) { + return addon.createEntry(itemName, itemId, isDirectory, itemSize, fileAttributes, creationTime, lastWriteTime, lastAccessTime, path); + } + + /** + * @deprecated + */ + updateSyncStatus({ path, isDirectory, sync }: { path: string; isDirectory: boolean; sync: boolean }) { + const result = addon.updateSyncStatus(path, sync, isDirectory); + return this.parseAddonZod("updateSyncStatus", result); + } + + convertToPlaceholder({ path, id }: { path: string; id: string }) { + const result = addon.convertToPlaceholder(path, id); + return this.parseAddonZod("convertToPlaceholder", result); + } + + updateFileIdentity({ path, id, isDirectory }: { path: string; id: string; isDirectory: boolean }) { + addon.updateFileIdentity(path, id, isDirectory); + } + + dehydrateFile({ path }: { path: string }) { + const result = addon.dehydrateFile(path); + return this.parseAddonZod("dehydrateFile", result); + } + + async hydrateFile({ path }: { path: string }) { + const result = await addon.hydrateFile(path); + return this.parseAddonZod("hydrateFile", result); + } + + getPlaceholderAttribute({ path }: { path: string }) { + const result = addon.getPlaceholderAttribute(path); + return this.parseAddonZod("getPlaceholderAttribute", result); + } +} diff --git a/src/addon/addon-zod.ts b/src/addon-zod.ts similarity index 100% rename from src/addon/addon-zod.ts rename to src/addon-zod.ts diff --git a/src/addon.ts b/src/addon.ts index f397e169..685233c4 100644 --- a/src/addon.ts +++ b/src/addon.ts @@ -1,6 +1,6 @@ import { z } from "zod"; -import { addonZod } from "./addon/addon-zod"; +import { addonZod } from "./addon-zod"; import { InputSyncCallbacks } from "./types/callbacks.type"; export const addon: TAddon = require("../addon.node"); @@ -11,7 +11,7 @@ export type TAddon = { fileName: string, fileId: string, fileSize: number, - combinedAttributes: number, + fileAttributes: number, creationTime: string, lastWriteTime: string, lastAccessTime: string, @@ -25,7 +25,7 @@ export type TAddon = { fileAttributes: number, creationTime: string, lastWriteTime: string, - lastAccessTime: number, + lastAccessTime: string, path: string, ): any; hydrateFile(path: string): Promise>; @@ -48,9 +48,8 @@ export type TAddon = { callbacks: any, logoPath: string, ): z.infer; - registerSyncRootWindowsStorageProvider(path: string, providerName: string, providerVersion: string, providerId: string): any; unregisterSyncRoot(path: string): z.infer; - updateSyncStatus(path: string, sync: boolean, isDirectory: boolean): any; + updateSyncStatus(path: string, sync: boolean, isDirectory: boolean): z.infer; /** * TODO: Returns a type in c++ that is not initialized */ diff --git a/src/virtual-drive.ts b/src/virtual-drive.ts index c9a7f31b..fe9f1798 100644 --- a/src/virtual-drive.ts +++ b/src/virtual-drive.ts @@ -1,41 +1,14 @@ -import path, { join } from "path"; +import path, { join, win32 } from "path"; import fs from "fs"; -import { Worker } from "worker_threads"; import { Watcher } from "./watcher/watcher"; import { ExtraCallbacks, InputSyncCallbacks } from "./types/callbacks.type"; import { Status } from "./types/placeholder.type"; import { IQueueManager } from "./queue/queueManager"; -import { addon } from "./addon"; import { createLogger } from "./logger"; +import { Addon } from "./addon-wrapper"; -interface ItemInfo { - path: string; - fileIdentity: string; - isPlaceholder: boolean; -} -interface Addon { - connectSyncRoot(path: string): any; - createPlaceholderFile( - fileName: string, - fileId: string, - fileSize: number, - combinedAttributes: number, - creationTime: string, - lastWriteTime: string, - lastAccessTime: string, - path: string - ): any; - registerSyncRootWindowsStorageProvider( - path: string, - providerName: string, - providerVersion: string, - providerId: string - ): any; - unregisterSyncRoot(path: string): any; - watchAndWait(path: string): any; - getItems(): any; -} +const addon = new Addon(); type Callbacks = InputSyncCallbacks & ExtraCallbacks; class VirtualDrive { @@ -66,12 +39,16 @@ class VirtualDrive { this.addLoggerPath(loggerPath ?? parentPath); } - addLoggerPath(loggerPath: string) { - console.log("loggerPath: ", loggerPath); - addon.addLoggerPath(loggerPath); + addLoggerPath(logPath: string) { + addon.addLogger({ logPath }); + } + + convertToWindowsPath(path: string) { + return path.replaceAll("/", win32.sep); } - private fixPath(path: string) { + fixPath(path: string) { + path = this.convertToWindowsPath(path); if (path.includes(this.syncRootPath)) { return path; } else { @@ -80,11 +57,11 @@ class VirtualDrive { } getPlaceholderState(path: string): Status { - return addon.getPlaceholderState(this.fixPath(path)); + return addon.getPlaceholderState({ path: this.fixPath(path) }); } getPlaceholderWithStatePending(): any { - return addon.getPlaceholderWithStatePending(this.syncRootPath); + return addon.getPlaceholderWithStatePending(); } getInputSyncCallbacks(): InputSyncCallbacks { @@ -130,21 +107,16 @@ class VirtualDrive { return BigInt(jsTime) * 10000n + 116444736000000000n; } - async getFileIdentity(relativePath: string): Promise { - const fullPath = path.join(this.syncRootPath, relativePath); - return addon.getFileIdentity(fullPath); + getFileIdentity(relativePath: string) { + return addon.getFileIdentity({ path: this.fixPath(relativePath) }); } async deleteFileSyncRoot(relativePath: string): Promise { - const fullPath = path.join(this.syncRootPath, relativePath); - return addon.deleteFileSyncRoot(fullPath); + return addon.deleteFileSyncRoot({ path: this.fixPath(relativePath) }); } async connectSyncRoot(): Promise { - return await addon.connectSyncRoot( - this.syncRootPath, - this.getInputSyncCallbacks() - ); + return addon.connectSyncRoot({ callbacks: this.getInputSyncCallbacks() }); } createPlaceholderFile( @@ -157,23 +129,20 @@ class VirtualDrive { lastAccessTime: number, basePath: string ): any { - const combinedAttributes = fileAttributes; const creationTimeStr = this.convertToWindowsTime(creationTime).toString(); - const lastWriteTimeStr = - this.convertToWindowsTime(lastWriteTime).toString(); - const lastAccessTimeStr = - this.convertToWindowsTime(lastAccessTime).toString(); + const lastWriteTimeStr = this.convertToWindowsTime(lastWriteTime).toString(); + const lastAccessTimeStr = this.convertToWindowsTime(lastAccessTime).toString(); - return addon.createPlaceholderFile( + return addon.createPlaceholderFile({ fileName, fileId, fileSize, - combinedAttributes, - creationTimeStr, - lastWriteTimeStr, - lastAccessTimeStr, + fileAttributes, + creationTime: creationTimeStr, + lastWriteTime: lastWriteTimeStr, + lastAccessTime: lastAccessTimeStr, basePath - ); + }); } createPlaceholderDirectory( @@ -188,19 +157,20 @@ class VirtualDrive { path: string ) { const creationTimeStr = this.convertToWindowsTime(creationTime).toString(); - const lastWriteTimeStr = - this.convertToWindowsTime(lastWriteTime).toString(); - return addon.createEntry( + const lastWriteTimeStr = this.convertToWindowsTime(lastWriteTime).toString(); + const lastAccessTimeStr = this.convertToWindowsTime(lastAccessTime).toString(); + + return addon.createPlaceholderDirectory({ itemName, itemId, isDirectory, itemSize, fileAttributes, - creationTimeStr, - lastWriteTimeStr, - lastAccessTime, + creationTime: creationTimeStr, + lastWriteTime: lastWriteTimeStr, + lastAccessTime: lastAccessTimeStr, path - ); + }); } private isValidFolderPath(path: string) { @@ -219,17 +189,17 @@ class VirtualDrive { logoPath: string ): Promise { this.callbacks = callbacks; - return await addon.registerSyncRoot( - this.syncRootPath, + return addon.registerSyncRoot({ + syncRootPath: this.syncRootPath, providerName, providerVersion, providerId, logoPath - ); + }); } static unregisterSyncRoot(syncRootPath: string): any { - const result = addon.unregisterSyncRoot(syncRootPath); + const result = addon.unregisterSyncRoot({ syncRootPath }); return result; } @@ -270,11 +240,11 @@ class VirtualDrive { CfHydrate: this.test, CfNotifyMessage: this.test, CfUpdateItem: this.test, - CfGetPlaceHolderAttributes: addon.getPlaceholderAttribute, - CfUpdateSyncStatus: addon.updateSyncStatus, - CfGetPlaceHolderIdentity: addon.getFileIdentity, - CfGetPlaceHolderState: addon.getPlaceholderState, - CfConverToPlaceholder: addon.convertToPlaceholder, + CfGetPlaceHolderAttributes: this.getPlaceholderAttribute, + CfUpdateSyncStatus: this.updateSyncStatus, + CfGetPlaceHolderIdentity: this.getFileIdentity, + CfGetPlaceHolderState: this.getPlaceholderState, + CfConverToPlaceholder: this.convertToPlaceholder, }; this.watcher.watchAndWait(); @@ -426,7 +396,7 @@ class VirtualDrive { } disconnectSyncRoot(): any { - return addon.disconnectSyncRoot(this.syncRootPath); + return addon.disconnectSyncRoot(); } async updateSyncStatus( @@ -434,34 +404,26 @@ class VirtualDrive { isDirectory: boolean, sync: boolean = true ): Promise { - const isRelative = !itemPath.includes(this.syncRootPath); - - if (isRelative) { - itemPath = path.join(this.syncRootPath, itemPath); - } - return await addon.updateSyncStatus(itemPath, sync, isDirectory); + return await addon.updateSyncStatus({ path: this.fixPath(itemPath), isDirectory, sync }); } convertToPlaceholder(itemPath: string, id: string): boolean { - return addon.convertToPlaceholder(itemPath, id); + return addon.convertToPlaceholder({ path: this.fixPath(itemPath), id }); } updateFileIdentity(itemPath: string, id: string, isDirectory: boolean): void { - if (!itemPath.includes(this.syncRootPath)) { - itemPath = path.join(this.syncRootPath, itemPath); - } - addon.updateFileIdentity(itemPath, id, isDirectory); + addon.updateFileIdentity({ path: this.fixPath(itemPath), id, isDirectory }); } async dehydrateFile(itemPath: string) { - return addon.dehydrateFile(itemPath); + return addon.dehydrateFile({ path: this.fixPath(itemPath) }); } async hydrateFile(itemPath: string): Promise { - return await addon.hydrateFile(itemPath); + return addon.hydrateFile({ path: this.fixPath(itemPath) }); } - async getPlaceholderAttribute(itemPath: string): Promise { - return await addon.getPlaceholderAttribute(itemPath); + getPlaceholderAttribute(itemPath: string) { + return addon.getPlaceholderAttribute({ path: this.fixPath(itemPath) }); } } diff --git a/src/virtual-drive.unit.test.ts b/src/virtual-drive.unit.test.ts index dcc34bc6..5e452e8d 100644 --- a/src/virtual-drive.unit.test.ts +++ b/src/virtual-drive.unit.test.ts @@ -84,7 +84,7 @@ describe("VirtualDrive", () => { }); describe("When call registerSyncRoot", () => { - it("Then it assigns callbacks and calls addon.registerSyncRoot", async () => { + it.only("Then it assigns callbacks and calls addon.registerSyncRoot", async () => { // Arrange const drive = new VirtualDrive(syncRootPath, logPath); const providerName = "MyProvider"; diff --git a/src/watcher/watcher.interface.ts b/src/watcher/watcher.interface.ts index bcdd1c84..83555a26 100644 --- a/src/watcher/watcher.interface.ts +++ b/src/watcher/watcher.interface.ts @@ -1,6 +1,6 @@ import { z } from "zod"; -import { addonZod } from "@/addon/addon-zod"; +import { addonZod } from "@/addon-zod"; export interface IVirtualDriveFunctions { CfHydrate?: () => void; From 41bceb4b217832824bd3130a621d957909482737 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jim=C3=A9nez=20Rivera?= Date: Sat, 1 Feb 2025 01:32:33 +0100 Subject: [PATCH 2/3] Remove virtualDriveFn --- src/addon-wrapper.ts | 2 +- src/addon.ts | 2 +- src/{ => addon}/addon-zod.ts | 0 src/virtual-drive.ts | 15 ++------------- src/virtual-drive.unit.test.ts | 6 +++--- .../detect-context-menu-action.service.ts | 6 +++--- src/watcher/events/on-add-dir.service.ts | 2 +- src/watcher/events/on-add.service.ts | 4 ++-- src/watcher/events/on-add.service.unit.test.ts | 12 ++++++------ src/watcher/watcher.interface.ts | 17 ----------------- src/watcher/watcher.ts | 8 ++++---- src/watcher/watcher.unit.test.ts | 6 +++--- 12 files changed, 26 insertions(+), 54 deletions(-) rename src/{ => addon}/addon-zod.ts (100%) delete mode 100644 src/watcher/watcher.interface.ts diff --git a/src/addon-wrapper.ts b/src/addon-wrapper.ts index 9b920e1f..f6a5827e 100644 --- a/src/addon-wrapper.ts +++ b/src/addon-wrapper.ts @@ -1,5 +1,5 @@ import { addon } from "./addon"; -import { addonZod } from "./addon-zod"; +import { addonZod } from "./addon/addon-zod"; import { Callbacks } from "./types/callbacks.type"; export class Addon { diff --git a/src/addon.ts b/src/addon.ts index 685233c4..2663ab83 100644 --- a/src/addon.ts +++ b/src/addon.ts @@ -1,6 +1,6 @@ import { z } from "zod"; -import { addonZod } from "./addon-zod"; +import { addonZod } from "./addon/addon-zod"; import { InputSyncCallbacks } from "./types/callbacks.type"; export const addon: TAddon = require("../addon.node"); diff --git a/src/addon-zod.ts b/src/addon/addon-zod.ts similarity index 100% rename from src/addon-zod.ts rename to src/addon/addon-zod.ts diff --git a/src/virtual-drive.ts b/src/virtual-drive.ts index fe9f1798..cc56a494 100644 --- a/src/virtual-drive.ts +++ b/src/virtual-drive.ts @@ -234,18 +234,7 @@ class VirtualDrive { usePolling: true, }; - this.watcher.virtualDriveFn = { - CfAddItem: this.test, - CfDehydrate: this.test, - CfHydrate: this.test, - CfNotifyMessage: this.test, - CfUpdateItem: this.test, - CfGetPlaceHolderAttributes: this.getPlaceholderAttribute, - CfUpdateSyncStatus: this.updateSyncStatus, - CfGetPlaceHolderIdentity: this.getFileIdentity, - CfGetPlaceHolderState: this.getPlaceholderState, - CfConverToPlaceholder: this.convertToPlaceholder, - }; + this.watcher.addon = addon; this.watcher.watchAndWait(); } @@ -403,7 +392,7 @@ class VirtualDrive { itemPath: string, isDirectory: boolean, sync: boolean = true - ): Promise { + ) { return await addon.updateSyncStatus({ path: this.fixPath(itemPath), isDirectory, sync }); } diff --git a/src/virtual-drive.unit.test.ts b/src/virtual-drive.unit.test.ts index 5e452e8d..60175771 100644 --- a/src/virtual-drive.unit.test.ts +++ b/src/virtual-drive.unit.test.ts @@ -9,10 +9,10 @@ import VirtualDrive from "./virtual-drive"; vi.mock("fs"); vi.mock("@/addon", () => ({ addon: { - addLoggerPath: vi.fn(), + addLoggerPath: vi.fn().mockReturnValue(true), connectSyncRoot: vi.fn(), createPlaceholderFile: vi.fn(), - registerSyncRoot: vi.fn(), + registerSyncRoot: vi.fn().mockReturnValue(0), }, })); @@ -84,7 +84,7 @@ describe("VirtualDrive", () => { }); describe("When call registerSyncRoot", () => { - it.only("Then it assigns callbacks and calls addon.registerSyncRoot", async () => { + it("Then it assigns callbacks and calls addon.registerSyncRoot", async () => { // Arrange const drive = new VirtualDrive(syncRootPath, logPath); const providerName = "MyProvider"; diff --git a/src/watcher/detect-context-menu-action.service.ts b/src/watcher/detect-context-menu-action.service.ts index 1ed3a4ff..b50420ef 100644 --- a/src/watcher/detect-context-menu-action.service.ts +++ b/src/watcher/detect-context-menu-action.service.ts @@ -9,9 +9,9 @@ export class DetectContextMenuActionService { async execute({ self, details, path, isFolder }: TProps) { const { prev, curr } = details; - const status = self.virtualDriveFn.CfGetPlaceHolderState(path); - const attribute = self.virtualDriveFn.CfGetPlaceHolderAttributes(path); - const itemId = self.virtualDriveFn.CfGetPlaceHolderIdentity(path); + const status = self.addon.getPlaceholderState({ path }); + const attribute = self.addon.getPlaceholderAttribute({ path }); + const itemId = self.addon.getFileIdentity({ path }); const isInDevice = self.fileInDevice.has(path); self.logger.info({ diff --git a/src/watcher/events/on-add-dir.service.ts b/src/watcher/events/on-add-dir.service.ts index 79c630cc..0705ff40 100644 --- a/src/watcher/events/on-add-dir.service.ts +++ b/src/watcher/events/on-add-dir.service.ts @@ -8,7 +8,7 @@ import { Watcher } from "../watcher"; export class OnAddDirService { execute({ self, path }: TProps) { try { - const status = self.virtualDriveFn.CfGetPlaceHolderState(path); + const status = self.addon.getPlaceholderState({ path }); self.logger.info({ fn: "onAddDir", path, status }); if (status.pinState === PinState.AlwaysLocal || status.pinState === PinState.OnlineOnly || status.syncState === SyncState.InSync) { diff --git a/src/watcher/events/on-add.service.ts b/src/watcher/events/on-add.service.ts index ac200f2d..88838f18 100644 --- a/src/watcher/events/on-add.service.ts +++ b/src/watcher/events/on-add.service.ts @@ -10,13 +10,13 @@ export class OnAddService { try { const ext = path.split(".").pop(); const { size, birthtime, mtime } = stats; - const fileIntenty = self.virtualDriveFn.CfGetPlaceHolderIdentity(path); + const fileIntenty = self.addon.getFileIdentity({ path }); self.logger.info({ fn: "onAdd", path, ext, size, birthtime, mtime, fileIntenty }); if (!ext || size === 0 || size > 20 * 1024 * 1024 * 1024) return; - const status = self.virtualDriveFn.CfGetPlaceHolderState(path); + const status = self.addon.getPlaceholderState({ path }); self.logger.info({ fn: "onAdd", path, status }); // Verificar tiempos de creación y modificación diff --git a/src/watcher/events/on-add.service.unit.test.ts b/src/watcher/events/on-add.service.unit.test.ts index cafec510..a503237f 100644 --- a/src/watcher/events/on-add.service.unit.test.ts +++ b/src/watcher/events/on-add.service.unit.test.ts @@ -17,8 +17,8 @@ describe("Watcher onAdd", () => { it('Should enqueue an "add" task if the file is new', () => { // Arrange - watcher.virtualDriveFn.CfGetPlaceHolderIdentity.mockReturnValue(""); - watcher.virtualDriveFn.CfGetPlaceHolderState.mockReturnValue({ + watcher.addon.getFileIdentity.mockReturnValue(""); + watcher.addon.getPlaceholderState.mockReturnValue({ pinState: PinState.Unspecified, syncState: SyncState.NotInSync, }); @@ -30,15 +30,15 @@ describe("Watcher onAdd", () => { onAdd.execute({ self: watcher, path, stats: stats as unknown as Stats }); // Assert - expect(watcher.virtualDriveFn.CfGetPlaceHolderIdentity).toHaveBeenCalledWith(path); - expect(watcher.virtualDriveFn.CfGetPlaceHolderState).toHaveBeenCalledWith(path); + expect(watcher.addon.getFileIdentity).toHaveBeenCalledWith({ path }); + expect(watcher.addon.getPlaceholderState).toHaveBeenCalledWith({ path }); expect(watcher.queueManager.enqueue).toHaveBeenCalledWith({ path, type: typeQueue.add, isFolder: false }); }); it("Should not enqueue if the file is already in AlwaysLocal and InSync states", () => { // Arrange - watcher.virtualDriveFn.CfGetPlaceHolderIdentity.mockReturnValue("existing-file-id"); - watcher.virtualDriveFn.CfGetPlaceHolderState.mockReturnValue({ + watcher.addon.getFileIdentity.mockReturnValue("existing-file-id"); + watcher.addon.getPlaceholderState.mockReturnValue({ pinState: PinState.AlwaysLocal, syncState: SyncState.InSync, }); diff --git a/src/watcher/watcher.interface.ts b/src/watcher/watcher.interface.ts deleted file mode 100644 index 83555a26..00000000 --- a/src/watcher/watcher.interface.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { z } from "zod"; - -import { addonZod } from "@/addon-zod"; - -export interface IVirtualDriveFunctions { - CfHydrate?: () => void; - CfDehydrate?: () => void; - CfAddItem: () => void; - CfNotifyMessage?: () => void; - CfUpdateSyncStatus: (path: string, sync: boolean, isDirectory: boolean) => void; - UpdatePinState?: () => void; - CfUpdateItem?: () => void; - CfGetPlaceHolderState: (path: string) => z.infer; - CfGetPlaceHolderIdentity: (path: string) => z.infer; - CfGetPlaceHolderAttributes: (path: string) => z.infer; - CfConverToPlaceholder: (path: string, fileIdentity: string) => z.infer; -} diff --git a/src/watcher/watcher.ts b/src/watcher/watcher.ts index 00ea814b..1e3f364b 100644 --- a/src/watcher/watcher.ts +++ b/src/watcher/watcher.ts @@ -9,7 +9,7 @@ import { OnAddDirService } from "./events/on-add-dir.service"; import { OnAddService } from "./events/on-add.service"; import { OnAllService } from "./events/on-all.service"; import { OnRawService } from "./events/on-raw.service"; -import { IVirtualDriveFunctions } from "./watcher.interface"; +import { Addon } from "@/addon-wrapper"; export namespace Watcher { export type TOptions = chokidar.WatchOptions; @@ -18,7 +18,7 @@ export namespace Watcher { export class Watcher { syncRootPath!: string; options!: Watcher.TOptions; - virtualDriveFn!: IVirtualDriveFunctions; + addon!: Addon; queueManager!: IQueueManager; logger!: Logger; fileInDevice = new Set(); @@ -35,13 +35,13 @@ export class Watcher { syncRootPath: string, options: chokidar.WatchOptions, logger: Logger, - virtualDriveFn: IVirtualDriveFunctions, + addon: Addon, ) { this.queueManager = queueManager; this.syncRootPath = syncRootPath; this.options = options; this.logger = logger; - this.virtualDriveFn = virtualDriveFn; + this.addon = addon; } private onChange = (path: string, stats?: Stats) => { diff --git a/src/watcher/watcher.unit.test.ts b/src/watcher/watcher.unit.test.ts index dc8ad910..d8d26f83 100644 --- a/src/watcher/watcher.unit.test.ts +++ b/src/watcher/watcher.unit.test.ts @@ -16,10 +16,10 @@ import { OnAddService } from "./events/on-add.service"; import { OnAllService } from "./events/on-all.service"; import { OnRawService } from "./events/on-raw.service"; import { Watcher } from "./watcher"; -import { IVirtualDriveFunctions } from "./watcher.interface"; +import { Addon } from "@/addon-wrapper"; describe("Watcher", () => { - const virtualDriveFn = mockDeep(); + const addon = mockDeep(); const queueManager = mockDeep(); const logger = mockDeep(); const options = {}; @@ -35,7 +35,7 @@ describe("Watcher", () => { } const watcher = new Watcher(onAll, onAdd, onAddDir, onRaw); - watcher.init(queueManager, syncRootPath, options, logger, virtualDriveFn); + watcher.init(queueManager, syncRootPath, options, logger, addon); watcher.watchAndWait(); }; From 411d579eb999bae978c9da80c6befbb20416cdc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jim=C3=A9nez=20Rivera?= Date: Sun, 2 Feb 2025 18:57:06 +0100 Subject: [PATCH 3/3] Add fixPath tests --- src/virtual-drive.unit.test.ts | 47 ++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/virtual-drive.unit.test.ts b/src/virtual-drive.unit.test.ts index 60175771..6496b406 100644 --- a/src/virtual-drive.unit.test.ts +++ b/src/virtual-drive.unit.test.ts @@ -26,6 +26,53 @@ describe("VirtualDrive", () => { vi.clearAllMocks(); }); + describe("When convertToWindowsPath is called", () => { + // Arrange + const drive = new VirtualDrive(syncRootPath, logPath); + + it("When unix path, then convert to windows path", () => { + // Assert + const result = drive.convertToWindowsPath("C:/test-drive/test.txt"); + expect(result).toBe("C:\\test-drive\\test.txt"); + }); + + it("When windows path, then do not modify it", () => { + // Assert + const result = drive.convertToWindowsPath("C:\\test-drive\\test.txt"); + expect(result).toBe("C:\\test-drive\\test.txt"); + }); + }); + + describe("When fixPath is called", () => { + // Arrange + const drive = new VirtualDrive(syncRootPath, logPath); + + it("When absolute windows path, then do not modify it", () => { + // Assert + expect(drive.fixPath("C:\\test-drive\\test.txt")).toBe("C:\\test-drive\\test.txt"); + }); + + it("When absolute unix path, then convert to absolute windows path", () => { + // Assert + expect(drive.fixPath("C:/test-drive/test.txt")).toBe("C:\\test-drive\\test.txt"); + }); + + it("When relative path, then convert to absolute windows path", () => { + // Assert + expect(drive.fixPath("test.txt")).toBe("C:\\test-drive\\test.txt"); + }); + + it("When relative windows path, then convert to absolute windows path", () => { + // Assert + expect(drive.fixPath("\\test.txt")).toBe("C:\\test-drive\\test.txt"); + }); + + it("When relative unix path, then convert to absolute windows path", () => { + // Assert + expect(drive.fixPath("/test.txt")).toBe("C:\\test-drive\\test.txt"); + }); + }); + describe("When VirtualDrive is created", () => { it("When syncRootPath does not exist, then it creates it", () => { // Arrange