UNPKG

13.2 kBPlain TextView Raw
1import * as fse from "fs-extra";
2import { expect } from "chai";
3import path from "./assert_path";
4import helper from "./helper";
5import * as jetpack from "..";
6import { InspectTreeResult } from "../types";
7
8describe("inspectTree", () => {
9 beforeEach(helper.setCleanTestCwd);
10 afterEach(helper.switchBackToCorrectCwd);
11
12 describe("inspects whole tree of files", () => {
13 const preparations = () => {
14 fse.outputFileSync("dir/file.txt", "abc");
15 fse.outputFileSync("dir/subdir/file.txt", "defg");
16 };
17
18 const expectations = (data: InspectTreeResult) => {
19 expect(data).to.eql({
20 name: "dir",
21 type: "dir",
22 size: 7,
23 children: [
24 {
25 name: "file.txt",
26 type: "file",
27 size: 3
28 },
29 {
30 name: "subdir",
31 type: "dir",
32 size: 4,
33 children: [
34 {
35 name: "file.txt",
36 type: "file",
37 size: 4
38 }
39 ]
40 }
41 ]
42 });
43 };
44
45 it("sync", () => {
46 preparations();
47 expectations(jetpack.inspectTree("dir"));
48 });
49
50 it("async", done => {
51 preparations();
52 jetpack.inspectTreeAsync("dir").then(tree => {
53 expectations(tree);
54 done();
55 });
56 });
57 });
58
59 describe("can calculate size of a whole tree", () => {
60 const preparations = () => {
61 fse.mkdirsSync("dir/empty");
62 fse.outputFileSync("dir/empty.txt", "");
63 fse.outputFileSync("dir/file.txt", "abc");
64 fse.outputFileSync("dir/subdir/file.txt", "defg");
65 };
66
67 const expectations = (data: InspectTreeResult) => {
68 // dir
69 expect(data.size).to.equal(7);
70 // dir/empty
71 expect(data.children[0].size).to.equal(0);
72 // dir/empty.txt
73 expect(data.children[1].size).to.equal(0);
74 // dir/file.txt
75 expect(data.children[2].size).to.equal(3);
76 // dir/subdir
77 expect(data.children[3].size).to.equal(4);
78 // dir/subdir/file.txt
79 expect(data.children[3].children[0].size).to.equal(4);
80 };
81
82 it("sync", () => {
83 preparations();
84 expectations(jetpack.inspectTree("dir"));
85 });
86
87 it("async", done => {
88 preparations();
89 jetpack.inspectTreeAsync("dir").then(tree => {
90 expectations(tree);
91 done();
92 });
93 });
94 });
95
96 describe("can output relative path for every tree node", () => {
97 const preparations = () => {
98 fse.outputFileSync("dir/subdir/file.txt", "defg");
99 };
100
101 const expectations = (data: InspectTreeResult) => {
102 // data will look like...
103 // {
104 // name: 'dir',
105 // relativePath: '.',
106 // children: [
107 // {
108 // name: 'subdir',
109 // relativePath: './subdir',
110 // children: [
111 // {
112 // name: 'file.txt',
113 // relativePath: './subdir/file.txt'
114 // }
115 // ]
116 // }
117 // ]
118 // }
119 expect(data.relativePath).to.equal(".");
120 expect(data.children[0].relativePath).to.equal("./subdir");
121 expect(data.children[0].children[0].relativePath).to.equal(
122 "./subdir/file.txt"
123 );
124 };
125
126 it("sync", () => {
127 preparations();
128 expectations(jetpack.inspectTree("dir", { relativePath: true }));
129 });
130
131 it("async", done => {
132 preparations();
133 jetpack.inspectTreeAsync("dir", { relativePath: true }).then(tree => {
134 expectations(tree);
135 done();
136 });
137 });
138 });
139
140 describe("if given path is a file just inspects that file", () => {
141 const preparations = () => {
142 fse.outputFileSync("dir/file.txt", "abc");
143 };
144
145 const expectations = (data: InspectTreeResult) => {
146 expect(data).to.eql({
147 name: "file.txt",
148 type: "file",
149 size: 3
150 });
151 };
152
153 it("sync", () => {
154 preparations();
155 expectations(jetpack.inspectTree("dir/file.txt"));
156 });
157
158 it("async", done => {
159 preparations();
160 jetpack.inspectTreeAsync("dir/file.txt").then(tree => {
161 expectations(tree);
162 done();
163 });
164 });
165 });
166
167 describe("behaves ok with empty directory", () => {
168 const preparations = () => {
169 fse.mkdirsSync("empty");
170 };
171
172 const expectations = (data: InspectTreeResult) => {
173 expect(data).to.eql({
174 name: "empty",
175 type: "dir",
176 size: 0,
177 children: []
178 });
179 };
180
181 it("sync", () => {
182 preparations();
183 expectations(jetpack.inspectTree("empty"));
184 });
185
186 it("async", done => {
187 preparations();
188 jetpack.inspectTreeAsync("empty").then(tree => {
189 expectations(tree);
190 done();
191 });
192 });
193 });
194
195 describe("returns undefined if path doesn't exist", () => {
196 const expectations = (data: InspectTreeResult) => {
197 expect(data).to.equal(undefined);
198 };
199
200 it("sync", () => {
201 expectations(jetpack.inspectTree("nonexistent"));
202 });
203
204 it("async", done => {
205 jetpack.inspectTreeAsync("nonexistent").then(dataAsync => {
206 expectations(dataAsync);
207 done();
208 });
209 });
210 });
211
212 describe("can output file times (ctime, mtime, atime)", () => {
213 const preparations = () => {
214 fse.outputFileSync("dir/file.txt", "abc");
215 };
216
217 const expectations = (data: InspectTreeResult) => {
218 expect(typeof data.accessTime.getTime).to.equal("function");
219 expect(typeof data.modifyTime.getTime).to.equal("function");
220 expect(typeof data.changeTime.getTime).to.equal("function");
221
222 expect(typeof data.children[0].accessTime.getTime).to.equal("function");
223 expect(typeof data.children[0].modifyTime.getTime).to.equal("function");
224 expect(typeof data.children[0].changeTime.getTime).to.equal("function");
225 };
226
227 it("sync", () => {
228 preparations();
229 expectations(jetpack.inspectTree("dir", { times: true }));
230 });
231
232 it("async", done => {
233 preparations();
234 jetpack.inspectTreeAsync("dir", { times: true }).then(data => {
235 expectations(data);
236 done();
237 });
238 });
239 });
240
241 describe("respects internal CWD of jetpack instance", () => {
242 const preparations = () => {
243 fse.outputFileSync("a/b.txt", "abc");
244 };
245
246 const expectations = (data: InspectTreeResult) => {
247 expect(data.name).to.equal("b.txt");
248 };
249
250 it("sync", () => {
251 const jetContext = jetpack.cwd("a");
252 preparations();
253 expectations(jetContext.inspectTree("b.txt"));
254 });
255
256 it("async", done => {
257 const jetContext = jetpack.cwd("a");
258 preparations();
259 jetContext.inspectTreeAsync("b.txt").then(data => {
260 expectations(data);
261 done();
262 });
263 });
264 });
265
266 describe("reports symlinks by default", () => {
267 const preparations = () => {
268 fse.outputFileSync("dir/file.txt", "abc");
269 fse.symlinkSync("file.txt", "dir/symlinked_file.txt");
270 };
271
272 const expectations = (data: InspectTreeResult) => {
273 expect(data).to.eql({
274 name: "dir",
275 type: "dir",
276 size: 3,
277 children: [
278 {
279 name: "file.txt",
280 type: "file",
281 size: 3
282 },
283 {
284 name: "symlinked_file.txt",
285 type: "symlink",
286 pointsAt: "file.txt"
287 }
288 ]
289 });
290 };
291
292 it("sync", () => {
293 preparations();
294 expectations(jetpack.inspectTree("dir")); // implicit
295 expectations(jetpack.inspectTree("dir", { symlinks: "report" })); // explicit
296 });
297
298 it("async", done => {
299 preparations();
300 jetpack
301 .inspectTreeAsync("dir") // implicit
302 .then(tree => {
303 expectations(tree);
304 return jetpack.inspectTreeAsync("dir", { symlinks: "report" }); // explicit
305 })
306 .then(tree => {
307 expectations(tree);
308 done();
309 })
310 .catch(done);
311 });
312 });
313
314 describe("follows symlinks when option specified", () => {
315 const preparations = () => {
316 fse.outputFileSync("dir/file.txt", "abc");
317 fse.symlinkSync("file.txt", "dir/symlinked_file.txt");
318 };
319
320 const expectations = (data: InspectTreeResult) => {
321 expect(data).to.eql({
322 name: "dir",
323 type: "dir",
324 size: 6,
325 children: [
326 {
327 name: "file.txt",
328 type: "file",
329 size: 3
330 },
331 {
332 name: "symlinked_file.txt",
333 type: "file",
334 size: 3
335 }
336 ]
337 });
338 };
339
340 it("sync", () => {
341 preparations();
342 expectations(jetpack.inspectTree("dir", { symlinks: "follow" }));
343 });
344
345 it("async", done => {
346 preparations();
347 jetpack
348 .inspectTreeAsync("dir", { symlinks: "follow" })
349 .then(tree => {
350 expectations(tree);
351 done();
352 })
353 .catch(done);
354 });
355 });
356
357 describe("can compute checksum of a whole tree", () => {
358 const preparations = () => {
359 fse.outputFileSync("dir/a.txt", "abc");
360 fse.outputFileSync("dir/b.txt", "defg");
361 };
362
363 const expectations = (data: InspectTreeResult) => {
364 // md5 of
365 // 'a.txt' + '900150983cd24fb0d6963f7d28e17f72' +
366 // 'b.txt' + '025e4da7edac35ede583f5e8d51aa7ec'
367 expect(data.md5).to.equal("b0ff9df854172efe752cb36b96c8bccd");
368 // md5 of 'abc'
369 expect(data.children[0].md5).to.equal("900150983cd24fb0d6963f7d28e17f72");
370 // md5 of 'defg'
371 expect(data.children[1].md5).to.equal("025e4da7edac35ede583f5e8d51aa7ec");
372 };
373
374 it("sync", () => {
375 preparations();
376 expectations(jetpack.inspectTree("dir", { checksum: "md5" }));
377 });
378
379 it("async", done => {
380 preparations();
381 jetpack.inspectTreeAsync("dir", { checksum: "md5" }).then(tree => {
382 expectations(tree);
383 done();
384 });
385 });
386 });
387
388 describe("can count checksum of empty directory", () => {
389 const preparations = () => {
390 fse.mkdirsSync("empty_dir");
391 };
392
393 const expectations = (data: InspectTreeResult) => {
394 // md5 of empty string
395 expect(data.md5).to.equal("d41d8cd98f00b204e9800998ecf8427e");
396 };
397
398 // SYNC
399 it("sync", () => {
400 preparations();
401 expectations(jetpack.inspectTree("empty_dir", { checksum: "md5" }));
402 });
403
404 it("async", done => {
405 preparations();
406 jetpack.inspectTreeAsync("empty_dir", { checksum: "md5" }).then(tree => {
407 expectations(tree);
408 done();
409 });
410 });
411 });
412
413 describe("input validation", () => {
414 const tests = [
415 {
416 type: "sync",
417 method: jetpack.inspectTree as any,
418 methodName: "inspectTree"
419 },
420 {
421 type: "async",
422 method: jetpack.inspectTreeAsync as any,
423 methodName: "inspectTreeAsync"
424 }
425 ];
426
427 describe('"path" argument', () => {
428 tests.forEach(test => {
429 it(test.type, () => {
430 expect(() => {
431 test.method(undefined);
432 }).to.throw(
433 `Argument "path" passed to ${
434 test.methodName
435 }(path, [options]) must be a string. Received undefined`
436 );
437 });
438 });
439 });
440
441 describe('"options" object', () => {
442 describe('"checksum" argument', () => {
443 tests.forEach(test => {
444 it(test.type, () => {
445 expect(() => {
446 test.method("abc", { checksum: 1 });
447 }).to.throw(
448 `Argument "options.checksum" passed to ${
449 test.methodName
450 }(path, [options]) must be a string. Received number`
451 );
452 });
453 it(test.type, () => {
454 expect(() => {
455 test.method("abc", { checksum: "foo" });
456 }).to.throw(
457 `Argument "options.checksum" passed to ${
458 test.methodName
459 }(path, [options]) must have one of values: md5, sha1, sha256`
460 );
461 });
462 });
463 });
464 describe('"relativePath" argument', () => {
465 tests.forEach(test => {
466 it(test.type, () => {
467 expect(() => {
468 test.method("abc", { relativePath: 1 });
469 }).to.throw(
470 `Argument "options.relativePath" passed to ${
471 test.methodName
472 }(path, [options]) must be a boolean. Received number`
473 );
474 });
475 });
476 });
477 describe('"symlinks" argument', () => {
478 tests.forEach(test => {
479 it(test.type, () => {
480 expect(() => {
481 test.method("abc", { symlinks: 1 });
482 }).to.throw(
483 `Argument "options.symlinks" passed to ${
484 test.methodName
485 }(path, [options]) must be a string. Received number`
486 );
487 });
488 it(test.type, () => {
489 expect(() => {
490 test.method("abc", { symlinks: "foo" });
491 }).to.throw(
492 `Argument "options.symlinks" passed to ${
493 test.methodName
494 }(path, [options]) must have one of values: report, follow`
495 );
496 });
497 });
498 });
499 });
500 });
501});