Skip to content

Commit b7d64eb

Browse files
committed
perf(fs): optimize routine to get spies
1 parent 8d1a1e6 commit b7d64eb

File tree

5 files changed

+42
-89
lines changed

5 files changed

+42
-89
lines changed

README.md

+8
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,14 @@ assertSpyCalls(cwd.readTextFile, 1);
196196
assertSpyCalls(src.readTextFile, 0);
197197
```
198198

199+
Accept a URL:
200+
201+
```typescript
202+
const spy = fs.spy(new URL("..", import.meta.url));
203+
await fs.use(() => Deno.readTextFile("./README.md"));
204+
assertSpyCalls(spy.readTextFile, 1);
205+
```
206+
199207
#### `stub`
200208

201209
Not write to the original path:

src/fs.ts

+26-6
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
*/
66

77
import { mapValues, pick } from "@std/collections";
8-
import { join } from "@std/path";
8+
import { dirname, fromFileUrl, join, resolve } from "@std/path";
99
import type { Spy } from "@std/testing/mock";
1010
import * as std from "@std/testing/mock";
11-
import { isUnder, relative, tryCatch, tryFinally } from "./internal.ts";
11+
import { relative, tryCatch, tryFinally } from "./internal.ts";
1212

1313
/**
1414
* The base names of Deno's APIs related to file system operations that takes
@@ -117,7 +117,7 @@ export interface FileSystemStub extends FileSystemSpy {
117117
* to a temporary directory.
118118
*/
119119
function createFsFake(
120-
base: string | URL,
120+
base: string,
121121
temp: string,
122122
readThrough: boolean,
123123
): Fs {
@@ -156,8 +156,16 @@ function createFsFake(
156156
*/
157157
const spies = new class extends Map<string | URL, FileSystemSpy> {
158158
/** Returns the spy for the path that is under the given path. */
159-
override get(key: string | URL) {
160-
return Array.from(this.entries()).find(([path]) => isUnder(key, path))?.[1];
159+
override get(path: string | URL): FileSystemSpy | undefined {
160+
const spy = super.get(path);
161+
if (spy) {
162+
return spy;
163+
}
164+
path = path.toString();
165+
if (path === "." || path === ".." || path === "/") {
166+
return;
167+
}
168+
return this.get(dirname(path));
161169
}
162170
}();
163171

@@ -189,6 +197,7 @@ export function stub(
189197
path: string | URL,
190198
fakeOrOptions?: Partial<Fs> | StubOptions,
191199
): FileSystemStub {
200+
path = normalize(path);
192201
const temp = Deno.makeTempDirSync();
193202

194203
const fake = isStubOptions(fakeOrOptions)
@@ -231,7 +240,8 @@ export function mock(): Disposable {
231240
function mockFsFn<T extends FsFnName>(name: T) {
232241
Deno[name] = new Proxy(Deno[name], {
233242
apply(target, thisArg, args) {
234-
const spy = spies.get(args[0])?.[name];
243+
const path = normalize(args[0]);
244+
const spy = spies.get(path)?.[name];
235245
if (spy) {
236246
return Reflect.apply(spy, thisArg, args);
237247
}
@@ -260,3 +270,13 @@ function restoreFsFn<T extends FsFnName>(
260270
) {
261271
Deno[name] = fn;
262272
}
273+
274+
/** Normalize a path or file URL to an absolute path */
275+
function normalize(path: string | URL): string {
276+
if (path instanceof URL) {
277+
path = path.protocol === "file:" ? fromFileUrl(path) : path.href;
278+
} else {
279+
path = resolve(path);
280+
}
281+
return path.endsWith("/") ? path.slice(0, -1) : path;
282+
}

src/fs_test.ts

+6-4
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,10 @@ describe("use", () => {
3939
});
4040

4141
describe("spy", () => {
42-
let cwd: string;
43-
4442
beforeAll(() => {
45-
cwd = Deno.cwd();
4643
Deno.chdir(new URL("../", import.meta.url));
4744
});
4845
afterEach(() => fs.dispose());
49-
afterAll(() => Deno.chdir(cwd));
5046

5147
it("should spy file system functions", async () => {
5248
const spy = fs.spy(".");
@@ -61,6 +57,12 @@ describe("spy", () => {
6157
assertSpyCalls(cwd.readTextFile, 1);
6258
assertSpyCalls(src.readTextFile, 0);
6359
});
60+
61+
it("should accept a URL", async () => {
62+
const spy = fs.spy(new URL("..", import.meta.url));
63+
await fs.use(() => Deno.readTextFile("./README.md"));
64+
assertSpyCalls(spy.readTextFile, 1);
65+
});
6466
});
6567

6668
describe("stub", () => {

src/internal.ts

-10
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,6 @@
11
import { toPath } from "@molt/lib/path";
22
import * as std from "@std/path";
33

4-
/**
5-
* Check if a path is under a base path.
6-
*/
7-
export function isUnder(
8-
path: string | URL,
9-
base: string | URL,
10-
): boolean {
11-
return toPath(path).startsWith(toPath(base));
12-
}
13-
144
/**
155
* Return the relative path from the first path to the second path.
166
*/

src/internal_test.ts

+2-69
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { assert, assertEquals, assertFalse } from "@std/assert";
1+
import { assert, assertEquals } from "@std/assert";
22
import { afterAll, beforeAll, describe, it } from "@std/testing/bdd";
3-
import { isUnder, relative, tryCatchFinally } from "./internal.ts";
3+
import { relative, tryCatchFinally } from "./internal.ts";
44

55
describe("tryCatchFinally", () => {
66
it("should execute the function and return the result", () => {
@@ -122,70 +122,3 @@ describe("relative", () => {
122122
);
123123
});
124124
});
125-
126-
describe("isUnder", () => {
127-
let cwd: string;
128-
129-
beforeAll(() => {
130-
cwd = Deno.cwd();
131-
Deno.chdir(new URL(".", import.meta.url));
132-
});
133-
134-
afterAll(() => {
135-
Deno.chdir(cwd);
136-
});
137-
138-
it("should return true if the first path is under the second path", () => {
139-
assert(
140-
isUnder(
141-
new URL("../README.md", import.meta.url),
142-
new URL("..", import.meta.url),
143-
),
144-
);
145-
assert(
146-
isUnder(
147-
"../README.md",
148-
"..",
149-
),
150-
);
151-
assert(
152-
isUnder(
153-
"../README.md",
154-
new URL("..", import.meta.url),
155-
),
156-
);
157-
assert(
158-
isUnder(
159-
new URL("../README.md", import.meta.url),
160-
"..",
161-
),
162-
);
163-
});
164-
165-
it("should return false if the first path is not under the second path", () => {
166-
assertFalse(
167-
isUnder(
168-
new URL("../README.md", import.meta.url),
169-
new URL(".", import.meta.url),
170-
),
171-
);
172-
assertFalse(
173-
isUnder(
174-
"../README.md",
175-
".",
176-
),
177-
);
178-
assertFalse(
179-
isUnder(
180-
"../README.md",
181-
new URL(".", import.meta.url),
182-
),
183-
);
184-
assert(
185-
isUnder(
186-
new URL("../README.md", import.meta.url),
187-
"..",
188-
),
189-
);
190-
});
191-
});

0 commit comments

Comments
 (0)