Skip to content

Commit f5ee649

Browse files
committed
add additional tests for double slashes to providers
1 parent 57bd0ca commit f5ee649

6 files changed

Lines changed: 123 additions & 0 deletions

File tree

packages/filesystem/baidu/baidu.test.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,24 @@ describe("BaiduFileSystem", () => {
3232
);
3333
expect(updateDynamicRulesMock).not.toHaveBeenCalled();
3434
});
35+
36+
it("create should normalize double slashes in paths", async () => {
37+
const fs = new BaiduFileSystem("/apps//ScriptCat", "token");
38+
39+
const writer = await fs.create("dir//file.user.js");
40+
41+
expect((writer as any).path).toBe("/apps/ScriptCat/dir/file.user.js");
42+
});
43+
44+
it("delete should normalize double slashes in filelist payload", async () => {
45+
const fs = new BaiduFileSystem("/apps//ScriptCat", "token");
46+
const request = vi.spyOn(fs, "request").mockResolvedValue({ errno: 0 });
47+
48+
await fs.delete("dir//file.user.js");
49+
50+
const [, config] = request.mock.calls[0];
51+
expect((config as RequestInit).body).toBe(
52+
`async=0&filelist=${encodeURIComponent(JSON.stringify(["/apps/ScriptCat/dir/file.user.js"]))}`
53+
);
54+
});
3555
});

packages/filesystem/dropbox/dropbox.test.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,29 @@ describe("DropboxFileSystem", () => {
3030

3131
await expect(fs.exists("/test.txt")).rejects.toThrow("invalid_access_token");
3232
});
33+
34+
it("create should normalize double slashes after the Dropbox app root", async () => {
35+
const fs = new DropboxFileSystem("/ScriptCat//sync", "token");
36+
37+
const writer = await fs.create("dir//file.user.js");
38+
39+
expect((writer as any).path).toBe("/sync/dir/file.user.js");
40+
});
41+
42+
it("delete should normalize double slashes after the Dropbox app root", async () => {
43+
const fs = new DropboxFileSystem("/ScriptCat//sync", "token");
44+
const request = vi.spyOn(fs, "request").mockResolvedValue({});
45+
46+
await fs.delete("dir//file.user.js");
47+
48+
expect(request).toHaveBeenCalledWith(
49+
"https://api.dropboxapi.com/2/files/delete_v2",
50+
expect.objectContaining({
51+
method: "POST",
52+
body: JSON.stringify({
53+
path: "/sync/dir/file.user.js",
54+
}),
55+
})
56+
);
57+
});
3358
});

packages/filesystem/googledrive/googledrive.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
22
import { LocalStorageDAO } from "@App/app/repo/localStorage";
33
import { FileSystemError, isAuthError, isConflictError, isNotFoundError, isRateLimitError } from "../error";
4+
import { joinPath } from "../utils";
45
import GoogleDriveFileSystem from "./googledrive";
56

67
function createMockResponse(options: { ok?: boolean; status?: number; text?: string; json?: any }): Response {
@@ -82,6 +83,21 @@ describe("GoogleDriveFileSystem", () => {
8283
expect(requestSpy).toHaveBeenCalledTimes(1);
8384
});
8485

86+
it("create should normalize double slashes in paths", async () => {
87+
const fs = new GoogleDriveFileSystem("/ScriptCat//sync", "token");
88+
89+
const writer = await fs.create("dir//file.user.js");
90+
91+
expect((writer as any).path).toBe("/ScriptCat/sync/dir/file.user.js");
92+
});
93+
94+
it("clearPathCache should accept normalized paths derived from duplicate slashes", () => {
95+
const fs = new GoogleDriveFileSystem("/ScriptCat//sync", "token");
96+
97+
expect(joinPath("/ScriptCat//sync", "dir//file.user.js")).toBe("/ScriptCat/sync/dir/file.user.js");
98+
expect(() => fs.clearPathCache("/ScriptCat//sync/dir")).not.toThrow();
99+
});
100+
85101
it("writer should clear stale path cache and retry once on provider 404", async () => {
86102
const fs = new GoogleDriveFileSystem("/", "token");
87103
const notFoundError = new FileSystemError({

packages/filesystem/onedrive/onedrive.test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,27 @@ describe("OneDriveFileSystem", () => {
9595
await expect(fs.delete("missing.txt")).resolves.toBeUndefined();
9696
});
9797

98+
it("create should normalize double slashes in paths", async () => {
99+
const fs = new OneDriveFileSystem("/ScriptCat//sync", "token");
100+
101+
const writer = await fs.create("dir//file.user.js");
102+
103+
expect((writer as any).path).toBe("/ScriptCat/sync/dir/file.user.js");
104+
});
105+
106+
it("delete should normalize double slashes in URL paths", async () => {
107+
const fs = new OneDriveFileSystem("/ScriptCat//sync", "token");
108+
const request = vi.spyOn(fs, "request").mockResolvedValue({ status: 204 });
109+
110+
await fs.delete("dir//file.user.js");
111+
112+
expect(request).toHaveBeenCalledWith(
113+
"https://graph.microsoft.com/v1.0/me/drive/special/approot:/ScriptCat/sync/dir/file.user.js",
114+
{ method: "DELETE" },
115+
true
116+
);
117+
});
118+
98119
it("createDir should create nested directories from root", async () => {
99120
const fs = new OneDriveFileSystem("/", "token");
100121
const requestSpy = vi.spyOn(fs, "request").mockResolvedValue({});

packages/filesystem/s3/s3.test.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,14 @@ describe("S3FileSystem", () => {
202202
})
203203
);
204204
});
205+
206+
it("normalizes double slashes in object keys", async () => {
207+
const subFs = new S3FileSystem("test-bucket", mockClient, "/ScriptCat//sync");
208+
209+
const writer = await subFs.create("dir//file.user.js");
210+
211+
expect((writer as any).key).toBe("ScriptCat/sync/dir/file.user.js");
212+
});
205213
});
206214

207215
// ---- createDir ----
@@ -235,6 +243,15 @@ describe("S3FileSystem", () => {
235243

236244
await expect(fs.delete("test.txt")).rejects.toThrow();
237245
});
246+
247+
it("normalizes double slashes in object keys", async () => {
248+
const subFs = new S3FileSystem("test-bucket", mockClient, "/ScriptCat//sync");
249+
(mockClient.request as ReturnType<typeof vi.fn>).mockResolvedValue(createMockResponse({ ok: true, status: 204 }));
250+
251+
await subFs.delete("dir//file.user.js");
252+
253+
expect(mockClient.request).toHaveBeenCalledWith("DELETE", "test-bucket", "ScriptCat/sync/dir/file.user.js");
254+
});
238255
});
239256

240257
// ---- list ----

packages/filesystem/webdav/webdav.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,17 @@ describe("WebDAVFileSystem", () => {
206206
expect(mockClient.deleteFile).toHaveBeenCalledWith("/test.txt");
207207
});
208208

209+
it("normalizes double slashes in paths", async () => {
210+
const fs = WebDAVFileSystem.fromSameClient(
211+
{ client: mockClient, url: "https://dav.example.com", basePath: "/ScriptCat//sync" } as any,
212+
"/ScriptCat//sync"
213+
);
214+
215+
await fs.delete("dir//file.user.js");
216+
217+
expect(mockClient.deleteFile).toHaveBeenCalledWith("/ScriptCat/sync/dir/file.user.js");
218+
});
219+
209220
it("应当在 404 时静默成功(幂等删除)", async () => {
210221
(mockClient.deleteFile as ReturnType<typeof vi.fn>).mockRejectedValue({
211222
response: { status: 404 },
@@ -217,6 +228,19 @@ describe("WebDAVFileSystem", () => {
217228
});
218229
});
219230

231+
describe("create", () => {
232+
it("normalizes double slashes in paths", async () => {
233+
const fs = WebDAVFileSystem.fromSameClient(
234+
{ client: mockClient, url: "https://dav.example.com", basePath: "/ScriptCat//sync" } as any,
235+
"/ScriptCat//sync"
236+
);
237+
238+
const writer = await fs.create("dir//file.user.js");
239+
240+
expect((writer as any).path).toBe("/ScriptCat/sync/dir/file.user.js");
241+
});
242+
});
243+
220244
describe("list", () => {
221245
it("应当列出文件并过滤目录", async () => {
222246
(mockClient.getDirectoryContents as ReturnType<typeof vi.fn>).mockResolvedValue([

0 commit comments

Comments
 (0)