• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict';
2
3const common = require('../common');
4const assert = require('assert');
5const fs = require('fs');
6const fsPromises = fs.promises;
7const pathModule = require('path');
8const tmpdir = require('../common/tmpdir');
9
10const testDir = tmpdir.path;
11
12const fileStructure = [
13  [ 'a', [ 'foo', 'bar' ] ],
14  [ 'b', [ 'foo', 'bar' ] ],
15  [ 'c', [ 'foo', 'bar' ] ],
16  [ 'd', [ 'foo', 'bar' ] ],
17  [ 'e', [ 'foo', 'bar' ] ],
18  [ 'f', [ 'foo', 'bar' ] ],
19  [ 'g', [ 'foo', 'bar' ] ],
20  [ 'h', [ 'foo', 'bar' ] ],
21  [ 'i', [ 'foo', 'bar' ] ],
22  [ 'j', [ 'foo', 'bar' ] ],
23  [ 'k', [ 'foo', 'bar' ] ],
24  [ 'l', [ 'foo', 'bar' ] ],
25  [ 'm', [ 'foo', 'bar' ] ],
26  [ 'n', [ 'foo', 'bar' ] ],
27  [ 'o', [ 'foo', 'bar' ] ],
28  [ 'p', [ 'foo', 'bar' ] ],
29  [ 'q', [ 'foo', 'bar' ] ],
30  [ 'r', [ 'foo', 'bar' ] ],
31  [ 's', [ 'foo', 'bar' ] ],
32  [ 't', [ 'foo', 'bar' ] ],
33  [ 'u', [ 'foo', 'bar' ] ],
34  [ 'v', [ 'foo', 'bar' ] ],
35  [ 'w', [ 'foo', 'bar' ] ],
36  [ 'x', [ 'foo', 'bar' ] ],
37  [ 'y', [ 'foo', 'bar' ] ],
38  [ 'z', [ 'foo', 'bar' ] ],
39  [ 'aa', [ 'foo', 'bar' ] ],
40  [ 'bb', [ 'foo', 'bar' ] ],
41  [ 'cc', [ 'foo', 'bar' ] ],
42  [ 'dd', [ 'foo', 'bar' ] ],
43  [ 'ee', [ 'foo', 'bar' ] ],
44  [ 'ff', [ 'foo', 'bar' ] ],
45  [ 'gg', [ 'foo', 'bar' ] ],
46  [ 'hh', [ 'foo', 'bar' ] ],
47  [ 'ii', [ 'foo', 'bar' ] ],
48  [ 'jj', [ 'foo', 'bar' ] ],
49  [ 'kk', [ 'foo', 'bar' ] ],
50  [ 'll', [ 'foo', 'bar' ] ],
51  [ 'mm', [ 'foo', 'bar' ] ],
52  [ 'nn', [ 'foo', 'bar' ] ],
53  [ 'oo', [ 'foo', 'bar' ] ],
54  [ 'pp', [ 'foo', 'bar' ] ],
55  [ 'qq', [ 'foo', 'bar' ] ],
56  [ 'rr', [ 'foo', 'bar' ] ],
57  [ 'ss', [ 'foo', 'bar' ] ],
58  [ 'tt', [ 'foo', 'bar' ] ],
59  [ 'uu', [ 'foo', 'bar' ] ],
60  [ 'vv', [ 'foo', 'bar' ] ],
61  [ 'ww', [ 'foo', 'bar' ] ],
62  [ 'xx', [ 'foo', 'bar' ] ],
63  [ 'yy', [ 'foo', 'bar' ] ],
64  [ 'zz', [ 'foo', 'bar' ] ],
65  [ 'abc', [ ['def', [ 'foo', 'bar' ] ], ['ghi', [ 'foo', 'bar' ] ] ] ],
66];
67
68function createFiles(path, fileStructure) {
69  for (const fileOrDir of fileStructure) {
70    if (typeof fileOrDir === 'string') {
71      fs.writeFileSync(pathModule.join(path, fileOrDir), '');
72    } else {
73      const dirPath = pathModule.join(path, fileOrDir[0]);
74      fs.mkdirSync(dirPath);
75      createFiles(dirPath, fileOrDir[1]);
76    }
77  }
78}
79
80// Make sure tmp directory is clean
81tmpdir.refresh();
82
83createFiles(testDir, fileStructure);
84const symlinksRootPath = pathModule.join(testDir, 'symlinks');
85const symlinkTargetFile = pathModule.join(symlinksRootPath, 'symlink-target-file');
86const symlinkTargetDir = pathModule.join(symlinksRootPath, 'symlink-target-dir');
87fs.mkdirSync(symlinksRootPath);
88fs.writeFileSync(symlinkTargetFile, '');
89fs.mkdirSync(symlinkTargetDir);
90fs.symlinkSync(symlinkTargetFile, pathModule.join(symlinksRootPath, 'symlink-src-file'));
91fs.symlinkSync(symlinkTargetDir, pathModule.join(symlinksRootPath, 'symlink-src-dir'));
92
93const expected = [
94  'a', 'a/bar', 'a/foo', 'aa', 'aa/bar', 'aa/foo',
95  'abc', 'abc/def', 'abc/def/bar', 'abc/def/foo', 'abc/ghi', 'abc/ghi/bar', 'abc/ghi/foo',
96  'b', 'b/bar', 'b/foo', 'bb', 'bb/bar', 'bb/foo',
97  'c', 'c/bar', 'c/foo', 'cc', 'cc/bar', 'cc/foo',
98  'd', 'd/bar', 'd/foo', 'dd', 'dd/bar', 'dd/foo',
99  'e', 'e/bar', 'e/foo', 'ee', 'ee/bar', 'ee/foo',
100  'f', 'f/bar', 'f/foo', 'ff', 'ff/bar', 'ff/foo',
101  'g', 'g/bar', 'g/foo', 'gg', 'gg/bar', 'gg/foo',
102  'h', 'h/bar', 'h/foo', 'hh', 'hh/bar', 'hh/foo',
103  'i', 'i/bar', 'i/foo', 'ii', 'ii/bar', 'ii/foo',
104  'j', 'j/bar', 'j/foo', 'jj', 'jj/bar', 'jj/foo',
105  'k', 'k/bar', 'k/foo', 'kk', 'kk/bar', 'kk/foo',
106  'l', 'l/bar', 'l/foo', 'll', 'll/bar', 'll/foo',
107  'm', 'm/bar', 'm/foo', 'mm', 'mm/bar', 'mm/foo',
108  'n', 'n/bar', 'n/foo', 'nn', 'nn/bar', 'nn/foo',
109  'o', 'o/bar', 'o/foo', 'oo', 'oo/bar', 'oo/foo',
110  'p', 'p/bar', 'p/foo', 'pp', 'pp/bar', 'pp/foo',
111  'q', 'q/bar', 'q/foo', 'qq', 'qq/bar', 'qq/foo',
112  'r', 'r/bar', 'r/foo', 'rr', 'rr/bar', 'rr/foo',
113  's', 's/bar', 's/foo', 'ss', 'ss/bar', 'ss/foo',
114  'symlinks', 'symlinks/symlink-src-dir', 'symlinks/symlink-src-file',
115  'symlinks/symlink-target-dir', 'symlinks/symlink-target-file',
116  't', 't/bar', 't/foo', 'tt', 'tt/bar', 'tt/foo',
117  'u', 'u/bar', 'u/foo', 'uu', 'uu/bar', 'uu/foo',
118  'v', 'v/bar', 'v/foo', 'vv', 'vv/bar', 'vv/foo',
119  'w', 'w/bar', 'w/foo', 'ww', 'ww/bar', 'ww/foo',
120  'x', 'x/bar', 'x/foo', 'xx', 'xx/bar', 'xx/foo',
121  'y', 'y/bar', 'y/foo', 'yy', 'yy/bar', 'yy/foo',
122  'z', 'z/bar', 'z/foo', 'zz', 'zz/bar', 'zz/foo',
123];
124
125// Normalize paths once for non POSIX platforms
126for (let i = 0; i < expected.length; i++) {
127  expected[i] = pathModule.normalize(expected[i]);
128}
129
130function getDirentPath(dirent) {
131  return pathModule.relative(testDir, dirent.path);
132}
133
134function assertDirents(dirents) {
135  dirents.sort((a, b) => (getDirentPath(a) < getDirentPath(b) ? -1 : 1));
136  for (const [i, dirent] of dirents.entries()) {
137    assert(dirent instanceof fs.Dirent);
138    assert.strictEqual(getDirentPath(dirent), expected[i]);
139  }
140}
141
142function processDirSync(dir) {
143  const dirents = [];
144  let dirent = dir.readSync();
145  while (dirent !== null) {
146    dirents.push(dirent);
147    dirent = dir.readSync();
148  }
149  assertDirents(dirents);
150}
151
152// Opendir read results sync
153
154{
155  const dir = fs.opendirSync(testDir, { recursive: true });
156  processDirSync(dir);
157  dir.closeSync();
158}
159
160{
161  fs.opendir(testDir, { recursive: true }, common.mustSucceed((dir) => {
162    processDirSync(dir);
163    dir.close(common.mustSucceed());
164  }));
165}
166
167// Opendir read result using callback
168
169function processDirCb(dir, cb) {
170  const acc = [];
171
172  function _process(dir, acc, cb) {
173    dir.read((err, dirent) => {
174      if (err) {
175        return cb(err);
176      }
177
178      if (dirent !== null) {
179        acc.push(dirent);
180        _process(dir, acc, cb);
181      } else {
182        cb(null, acc);
183      }
184    });
185  }
186
187  _process(dir, acc, cb);
188}
189
190{
191  const dir = fs.opendirSync(testDir, { recursive: true });
192  processDirCb(dir, common.mustSucceed((dirents) => {
193    assertDirents(dirents);
194    dir.close(common.mustSucceed());
195  }));
196}
197
198{
199  fs.opendir(testDir, { recursive: true }, common.mustSucceed((dir) => {
200    processDirCb(dir, common.mustSucceed((dirents) => {
201      assertDirents(dirents);
202      dir.close(common.mustSucceed());
203    }));
204  }));
205}
206
207// Opendir read result using AsyncIterator
208
209{
210  async function test() {
211    const dir = await fsPromises.opendir(testDir, { recursive: true });
212    const dirents = [];
213    for await (const dirent of dir) {
214      dirents.push(dirent);
215    }
216    assertDirents(dirents);
217  }
218
219  test().then(common.mustCall());
220}
221