Skip to content

Commit 9d6a80f

Browse files
committed
chore: add fs tests
1 parent a4a0040 commit 9d6a80f

2 files changed

Lines changed: 228 additions & 0 deletions

File tree

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