Skip to content

Commit ba9b284

Browse files
committed
Add tests for unzipToDirectory
1 parent 1055515 commit ba9b284

2 files changed

Lines changed: 124 additions & 2 deletions

File tree

extensions/ql-vscode/src/common/files.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,18 +91,23 @@ export async function readDirFullPaths(path: string): Promise<string[]> {
9191
* Symbolic links are ignored.
9292
*
9393
* @param dir the directory to walk
94+
* @param includeDirectories whether to include directories in the results
9495
*
9596
* @return An iterator of the full path to all files recursively found in the directory.
9697
*/
9798
export async function* walkDirectory(
9899
dir: string,
100+
includeDirectories = false,
99101
): AsyncIterableIterator<string> {
100102
const seenFiles = new Set<string>();
101103
for await (const d of await opendir(dir)) {
102104
const entry = join(dir, d.name);
103105
seenFiles.add(entry);
104106
if (d.isDirectory()) {
105-
yield* walkDirectory(entry);
107+
if (includeDirectories) {
108+
yield entry;
109+
}
110+
yield* walkDirectory(entry, includeDirectories);
106111
} else if (d.isFile()) {
107112
yield entry;
108113
}

extensions/ql-vscode/test/unit-tests/common/unzip.test.ts

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,21 @@
1-
import { resolve } from "path";
1+
import { createHash } from "crypto";
2+
import { join, relative, resolve } from "path";
3+
import {
4+
createReadStream,
5+
pathExists,
6+
readdir,
7+
readFile,
8+
stat,
9+
} from "fs-extra";
10+
import { dir, DirectoryResult } from "tmp-promise";
211
import {
312
excludeDirectories,
413
openZip,
514
openZipBuffer,
615
readZipEntries,
16+
unzipToDirectory,
717
} from "../../../src/common/unzip";
18+
import { walkDirectory } from "../../../src/common/files";
819

920
const zipPath = resolve(__dirname, "../data/unzip/test-zip.zip");
1021

@@ -81,3 +92,109 @@ describe("openZipBuffer", () => {
8192
expect(buffer.toString("utf8")).toEqual("I am a file\n\n");
8293
});
8394
});
95+
96+
describe("unzipToDirectory", () => {
97+
let tmpDir: DirectoryResult;
98+
99+
beforeEach(async () => {
100+
tmpDir = await dir({
101+
unsafeCleanup: true,
102+
});
103+
});
104+
105+
afterEach(async () => {
106+
await tmpDir?.cleanup();
107+
});
108+
109+
it("extracts all files", async () => {
110+
await unzipToDirectory(zipPath, tmpDir.path);
111+
112+
const allFiles = [];
113+
for await (const file of walkDirectory(tmpDir.path, true)) {
114+
allFiles.push(file);
115+
}
116+
117+
expect(
118+
allFiles.map((filePath) => relative(tmpDir.path, filePath)).sort(),
119+
).toEqual([
120+
"directory",
121+
"directory/file.txt",
122+
"directory/file2.txt",
123+
"directory2",
124+
"directory2/file.txt",
125+
"empty-directory",
126+
"tools",
127+
"tools/osx64",
128+
"tools/osx64/java-aarch64",
129+
"tools/osx64/java-aarch64/bin",
130+
"tools/osx64/java-aarch64/bin/java",
131+
]);
132+
133+
await expectFile(join(tmpDir.path, "directory", "file.txt"), {
134+
mode: 0o100644,
135+
contents: "I am a file\n\n",
136+
});
137+
await expectFile(join(tmpDir.path, "directory", "file2.txt"), {
138+
mode: 0o100644,
139+
contents: "I am another file\n\n",
140+
});
141+
await expectFile(join(tmpDir.path, "directory2", "file.txt"), {
142+
mode: 0o100600,
143+
contents: "I am secret\n",
144+
});
145+
await expectFile(
146+
join(tmpDir.path, "tools", "osx64", "java-aarch64", "bin", "java"),
147+
{
148+
mode: 0o100755,
149+
hash: "68b832b5c0397c5baddbbb0a76cf5407b7ea5eee8f84f9ab9488f04a52e529eb",
150+
},
151+
);
152+
153+
expect(await pathExists(join(tmpDir.path, "empty-directory"))).toBe(true);
154+
expect(await readdir(join(tmpDir.path, "empty-directory"))).toEqual([]);
155+
});
156+
});
157+
158+
async function expectFile(
159+
filePath: string,
160+
{
161+
mode: expectedMode,
162+
hash: expectedHash,
163+
contents: expectedContents,
164+
}: {
165+
mode: number;
166+
hash?: string;
167+
contents?: string;
168+
},
169+
) {
170+
const stats = await stat(filePath);
171+
expect(stats.mode).toEqual(expectedMode);
172+
173+
if (expectedHash) {
174+
const hash = await computeHash(filePath);
175+
expect(hash).toEqual(expectedHash);
176+
}
177+
178+
if (expectedContents) {
179+
const contents = await readFile(filePath);
180+
expect(contents.toString("utf-8")).toEqual(expectedContents);
181+
}
182+
}
183+
184+
async function computeHash(filePath: string) {
185+
const input = createReadStream(filePath);
186+
const hash = createHash("sha256");
187+
188+
input.pipe(hash);
189+
190+
await new Promise((resolve, reject) => {
191+
input.on("error", (err) => {
192+
reject(err);
193+
});
194+
input.on("end", () => {
195+
resolve(undefined);
196+
});
197+
});
198+
199+
return hash.digest("hex");
200+
}

0 commit comments

Comments
 (0)