Skip to content

Commit 59ba6d7

Browse files
committed
chore: add fs tests
1 parent d45074e commit 59ba6d7

2 files changed

Lines changed: 269 additions & 0 deletions

File tree

Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
import * as Fs from "@effect/platform/FileSystem";
2+
import { describe, it } from "@effect/vitest";
3+
import { Chunk, Effect, Stream } from "effect";
4+
import * as DenoFileSystem from "../src/DenoFileSystem.ts";
5+
6+
const runPromise = <E, A>(
7+
self: Effect.Effect<A, E, Fs.FileSystem>,
8+
): Promise<A> => Effect.runPromise(Effect.provide(self, DenoFileSystem.layer));
9+
10+
describe.concurrent("FileSystem", () => {
11+
it("readFile", ({ expect }) =>
12+
runPromise(
13+
Effect.gen(function* (_) {
14+
const fs = yield* _(Fs.FileSystem);
15+
const data = yield* _(
16+
fs.readFile(`${import.meta.dirname}/fixtures/text.txt`),
17+
);
18+
const text = new TextDecoder().decode(data);
19+
expect(text.trim()).toEqual("lorem ipsum dolar sit amet");
20+
}),
21+
));
22+
23+
it("makeTempDirectory", ({ expect }) =>
24+
runPromise(
25+
Effect.gen(function* (_) {
26+
const fs = yield* _(Fs.FileSystem);
27+
let dir = "";
28+
yield* _(
29+
Effect.gen(function* (_) {
30+
dir = yield* _(fs.makeTempDirectory());
31+
const stat = yield* _(fs.stat(dir));
32+
expect(stat.type).toEqual("Directory");
33+
}),
34+
Effect.scoped,
35+
);
36+
const stat = yield* _(fs.stat(dir));
37+
expect(stat.type).toEqual("Directory");
38+
}),
39+
));
40+
41+
it("makeTempDirectoryScoped", ({ expect }) =>
42+
runPromise(
43+
Effect.gen(function* (_) {
44+
const fs = yield* _(Fs.FileSystem);
45+
let dir = "";
46+
yield* _(
47+
Effect.gen(function* (_) {
48+
dir = yield* _(fs.makeTempDirectoryScoped());
49+
const stat = yield* _(fs.stat(dir));
50+
expect(stat.type).toEqual("Directory");
51+
}),
52+
Effect.scoped,
53+
);
54+
const error = yield* _(Effect.flip(fs.stat(dir)));
55+
expect(
56+
error._tag === "SystemError" && error.reason === "NotFound",
57+
).toBe(true);
58+
}),
59+
));
60+
61+
it("truncate", ({ expect }) =>
62+
runPromise(
63+
Effect.gen(function* (_) {
64+
const fs = yield* _(Fs.FileSystem);
65+
const file = yield* _(fs.makeTempFile());
66+
67+
const text = "hello world";
68+
yield* _(fs.writeFile(file, new TextEncoder().encode(text)));
69+
70+
const before = yield* _(
71+
fs.readFile(file),
72+
Effect.map((_) => new TextDecoder().decode(_)),
73+
);
74+
expect(before).toEqual(text);
75+
76+
yield* _(fs.truncate(file));
77+
78+
const after = yield* _(
79+
fs.readFile(file),
80+
Effect.map((_) => new TextDecoder().decode(_)),
81+
);
82+
expect(after).toEqual("");
83+
}),
84+
));
85+
86+
it.fails("should track the cursor position when reading", ({ expect }) =>
87+
runPromise(
88+
Effect.gen(function* (_) {
89+
const fs = yield* _(Fs.FileSystem);
90+
91+
yield* _(
92+
Effect.gen(function* (_) {
93+
let text: string;
94+
const file = yield* _(
95+
fs.open(`${import.meta.dirname}/fixtures/text.txt`),
96+
);
97+
98+
text = yield* _(
99+
Effect.flatten(file.readAlloc(Fs.Size(5))),
100+
Effect.map((_) => new TextDecoder().decode(_)),
101+
);
102+
expect(text).toBe("lorem");
103+
104+
yield* _(file.seek(Fs.Size(7), "current"));
105+
text = yield* _(
106+
Effect.flatten(file.readAlloc(Fs.Size(5))),
107+
Effect.map((_) => new TextDecoder().decode(_)),
108+
);
109+
expect(text).toBe("dolar");
110+
111+
yield* _(file.seek(Fs.Size(1), "current"));
112+
text = yield* _(
113+
Effect.flatten(file.readAlloc(Fs.Size(8))),
114+
Effect.map((_) => new TextDecoder().decode(_)),
115+
);
116+
expect(text).toBe("sit amet");
117+
118+
yield* _(file.seek(Fs.Size(0), "start"));
119+
text = yield* _(
120+
Effect.flatten(file.readAlloc(Fs.Size(11))),
121+
Effect.map((_) => new TextDecoder().decode(_)),
122+
);
123+
expect(text).toBe("lorem ipsum");
124+
125+
text = yield* _(
126+
fs.stream(`${import.meta.dirname}/fixtures/text.txt`, {
127+
offset: Fs.Size(6),
128+
bytesToRead: Fs.Size(5),
129+
}),
130+
Stream.map((_) => new TextDecoder().decode(_)),
131+
Stream.runCollect,
132+
Effect.map(Chunk.join("")),
133+
);
134+
expect(text).toBe("ipsum");
135+
}),
136+
Effect.scoped,
137+
);
138+
}),
139+
),
140+
);
141+
142+
it("should track the cursor position when writing", ({ expect }) =>
143+
runPromise(
144+
Effect.gen(function* (_) {
145+
const fs = yield* _(Fs.FileSystem);
146+
147+
yield* _(
148+
Effect.gen(function* (_) {
149+
let text: string;
150+
const path = yield* _(fs.makeTempFileScoped());
151+
const file = yield* _(fs.open(path, { flag: "w+" }));
152+
153+
yield* _(file.write(new TextEncoder().encode("lorem ipsum")));
154+
yield* _(file.write(new TextEncoder().encode(" ")));
155+
yield* _(file.write(new TextEncoder().encode("dolor sit amet")));
156+
text = yield* _(fs.readFileString(path));
157+
expect(text).toBe("lorem ipsum dolor sit amet");
158+
159+
yield* _(file.seek(Fs.Size(-4), "current"));
160+
yield* _(file.write(new TextEncoder().encode("hello world")));
161+
text = yield* _(fs.readFileString(path));
162+
expect(text).toBe("lorem ipsum dolor sit hello world");
163+
164+
yield* _(file.seek(Fs.Size(6), "start"));
165+
yield* _(file.write(new TextEncoder().encode("blabl")));
166+
text = yield* _(fs.readFileString(path));
167+
expect(text).toBe("lorem blabl dolor sit hello world");
168+
}),
169+
Effect.scoped,
170+
);
171+
}),
172+
));
173+
174+
it.fails("should maintain a read cursor in append mode", ({ expect }) =>
175+
runPromise(
176+
Effect.gen(function* (_) {
177+
const fs = yield* _(Fs.FileSystem);
178+
179+
yield* _(
180+
Effect.gen(function* (_) {
181+
let text: string;
182+
const path = yield* _(fs.makeTempFileScoped());
183+
const file = yield* _(fs.open(path, { flag: "a+" }));
184+
185+
yield* _(file.write(new TextEncoder().encode("foo")));
186+
yield* _(file.seek(Fs.Size(0), "start"));
187+
188+
yield* _(file.write(new TextEncoder().encode("bar")));
189+
text = yield* _(fs.readFileString(path));
190+
expect(text).toBe("foobar");
191+
192+
text = yield* _(
193+
Effect.flatten(file.readAlloc(Fs.Size(3))),
194+
Effect.map((_) => new TextDecoder().decode(_)),
195+
);
196+
expect(text).toBe("foo");
197+
198+
yield* _(file.write(new TextEncoder().encode("baz")));
199+
text = yield* _(fs.readFileString(path));
200+
expect(text).toBe("foobarbaz");
201+
202+
text = yield* _(
203+
Effect.flatten(file.readAlloc(Fs.Size(6))),
204+
Effect.map((_) => new TextDecoder().decode(_)),
205+
);
206+
expect(text).toBe("barbaz");
207+
}),
208+
Effect.scoped,
209+
);
210+
}),
211+
),
212+
);
213+
214+
it("should keep the current cursor if truncating doesn't affect it", ({
215+
expect,
216+
}) =>
217+
runPromise(
218+
Effect.gen(function* (_) {
219+
const fs = yield* _(Fs.FileSystem);
220+
221+
yield* _(
222+
Effect.gen(function* (_) {
223+
const path = yield* _(fs.makeTempFileScoped());
224+
const file = yield* _(fs.open(path, { flag: "w+" }));
225+
226+
yield* _(
227+
file.write(
228+
new TextEncoder().encode("lorem ipsum dolor sit amet"),
229+
),
230+
);
231+
yield* _(file.seek(Fs.Size(6), "start"));
232+
yield* _(file.truncate(Fs.Size(11)));
233+
234+
const cursor = yield* _(file.seek(Fs.Size(0), "current"));
235+
expect(cursor).toBe(Fs.Size(6));
236+
}),
237+
Effect.scoped,
238+
);
239+
}),
240+
));
241+
242+
it("should update the current cursor if truncating affects it", ({
243+
expect,
244+
}) =>
245+
runPromise(
246+
Effect.gen(function* (_) {
247+
const fs = yield* _(Fs.FileSystem);
248+
249+
yield* _(
250+
Effect.gen(function* (_) {
251+
const path = yield* _(fs.makeTempFileScoped());
252+
const file = yield* _(fs.open(path, { flag: "w+" }));
253+
254+
yield* _(
255+
file.write(
256+
new TextEncoder().encode("lorem ipsum dolor sit amet"),
257+
),
258+
);
259+
yield* _(file.truncate(Fs.Size(11)));
260+
261+
const cursor = yield* _(file.seek(Fs.Size(0), "current"));
262+
expect(cursor).toBe(Fs.Size(11));
263+
}),
264+
Effect.scoped,
265+
);
266+
}),
267+
));
268+
});
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
lorem ipsum dolar sit amet

0 commit comments

Comments
 (0)