[njs] Added fs.Dirent, fs.readdir() and friends.

Dmitry Volyntsev xeioex at nginx.com
Tue Jun 9 16:48:21 UTC 2020


details:   https://hg.nginx.org/njs/rev/b33402f10e82
branches:  
changeset: 1429:b33402f10e82
user:      Artem S. Povalyukhin <artem.povaluhin at gmail.com>
date:      Sun May 31 08:45:41 2020 +0300
description:
Added fs.Dirent, fs.readdir() and friends.

This closes #254 issue on Github.

diffstat:

 src/njs_builtin.c          |    1 +
 src/njs_fs.c               |  415 +++++++++++++++++++++++++++++++++++++++++++++
 src/njs_fs.h               |    1 +
 src/njs_vm.h               |    3 +-
 src/test/njs_unit_test.c   |   41 ++++
 test/js/fs_promises_007.js |  231 +++++++++++++++++++++++++
 test/njs_expect_test.exp   |   14 +-
 7 files changed, 696 insertions(+), 10 deletions(-)

diffs (839 lines):

diff -r 724dedc6be18 -r b33402f10e82 src/njs_builtin.c
--- a/src/njs_builtin.c	Tue Jun 09 12:56:56 2020 +0000
+++ b/src/njs_builtin.c	Sun May 31 08:45:41 2020 +0300
@@ -73,6 +73,7 @@ static const njs_object_type_init_t *con
 
     /* Hidden types. */
 
+    &njs_dirent_type_init,
     &njs_hash_type_init,
     &njs_hmac_type_init,
     &njs_typed_array_type_init,
diff -r 724dedc6be18 -r b33402f10e82 src/njs_fs.c
--- a/src/njs_fs.c	Tue Jun 09 12:56:56 2020 +0000
+++ b/src/njs_fs.c	Sun May 31 08:45:41 2020 +0300
@@ -7,6 +7,31 @@
 
 #include <njs_main.h>
 
+#include <dirent.h>
+
+#if (NJS_SOLARIS)
+
+#define DT_DIR         0
+#define DT_REG         0
+#define DT_CHR         0
+#define DT_LNK         0
+#define DT_BLK         0
+#define DT_FIFO        0
+#define DT_SOCK        0
+#define NJS_DT_INVALID 0xffffffff
+
+#define njs_dentry_type(_dentry)                                             \
+    (NJS_DT_INVALID)
+
+#else
+
+#define NJS_DT_INVALID 0xffffffff
+
+#define njs_dentry_type(_dentry)                                             \
+    ((_dentry)->d_type)
+
+#endif
+
 
 #define njs_fs_magic(calltype, mode)                                         \
     (((mode) << 2) | calltype)
@@ -53,6 +78,8 @@ static njs_fs_encoding_t njs_fs_encoding
 static njs_int_t njs_fs_add_event(njs_vm_t *vm, const njs_value_t *callback,
     const njs_value_t *args, njs_uint_t nargs);
 
+static njs_int_t njs_fs_dirent_create(njs_vm_t *vm, njs_value_t *name,
+    njs_value_t *type, njs_value_t *retval);
 
 static njs_fs_entry_t njs_flags_table[] = {
     { njs_str("r"),   O_RDONLY },
@@ -895,6 +922,163 @@ njs_fs_rmdir(njs_vm_t *vm, njs_value_t *
 
 
 static njs_int_t
+njs_fs_readdir(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+    njs_index_t calltype)
+{
+    DIR                *dir;
+    u_char             *d_name;
+    size_t             size;
+    ssize_t            length;
+    njs_int_t          ret;
+    const char         *dir_path;
+    njs_value_t        encoding, types, ename, etype, retval, *path, *callback,
+                       *options, *value;
+    njs_array_t        *results;
+    struct dirent      *entry;
+    njs_fs_encoding_t  enc;
+
+    static const njs_value_t  string_encoding = njs_string("encoding");
+    static const njs_value_t  string_types = njs_string("withFileTypes");
+
+    path = njs_arg(args, nargs, 1);
+    ret = njs_fs_path_arg(vm, &dir_path, path, &njs_str_value("path"));
+    if (njs_slow_path(ret != NJS_OK)) {
+        return ret;
+    }
+
+    callback = NULL;
+    options = njs_arg(args, nargs, 2);
+
+    if (njs_slow_path(calltype == NJS_FS_CALLBACK)) {
+        callback = njs_arg(args, nargs, njs_min(nargs - 1, 3));
+        if (!njs_is_function(callback)) {
+            njs_type_error(vm, "\"callback\" must be a function");
+            return NJS_ERROR;
+        }
+        if (options == callback) {
+            options = njs_value_arg(&njs_value_undefined);
+        }
+    }
+
+    njs_set_false(&types);
+    njs_set_undefined(&encoding);
+
+    switch (options->type) {
+    case NJS_STRING:
+        encoding = *options;
+        break;
+
+    case NJS_UNDEFINED:
+        break;
+
+    default:
+        if (!njs_is_object(options)) {
+            njs_type_error(vm, "Unknown options type: \"%s\" "
+                           "(a string or object required)",
+                           njs_type_string(options->type));
+            return NJS_ERROR;
+        }
+
+        ret = njs_value_property(vm, options, njs_value_arg(&string_encoding),
+                                 &encoding);
+        if (njs_slow_path(ret == NJS_ERROR)) {
+            return ret;
+        }
+
+        ret = njs_value_property(vm, options, njs_value_arg(&string_types),
+                                 &types);
+        if (njs_slow_path(ret == NJS_ERROR)) {
+            return ret;
+        }
+    }
+
+    enc = njs_fs_encoding(vm, &encoding);
+    if (njs_slow_path(enc == NJS_FS_ENC_INVALID)) {
+        return NJS_ERROR;
+    }
+
+    results = njs_array_alloc(vm, 1, 0, NJS_ARRAY_SPARE);
+    if (njs_slow_path(results == NULL)) {
+        return NJS_ERROR;
+    }
+
+    njs_set_array(&retval, results);
+
+    dir = opendir(dir_path);
+    if (njs_slow_path(dir == NULL)) {
+        ret = njs_fs_error(vm, "opendir", strerror(errno), path, errno,
+                           &retval);
+        goto done;
+    }
+
+    for ( ;; ) {
+        errno = 0;
+        entry = readdir(dir);
+        if (njs_slow_path(entry == NULL)) {
+            if (errno != 0) {
+                ret = njs_fs_error(vm, "readdir", strerror(errno), path, errno,
+                                   &retval);
+            }
+
+            goto done;
+        }
+
+        d_name = (u_char *) entry->d_name;
+
+        size = njs_strlen(d_name);
+        length = njs_utf8_length(d_name, size);
+        if (njs_slow_path(length < 0)) {
+            length = 0;
+        }
+
+        if ((length == 1 && d_name[0] == '.')
+            || (length == 2 && (d_name[0] == '.' && d_name[1] == '.')))
+        {
+            continue;
+        }
+
+        if (njs_fast_path(!njs_is_true(&types))) {
+            ret = njs_array_string_add(vm, results, d_name, size, length);
+            if (njs_slow_path(ret != NJS_OK)) {
+                goto done;
+            }
+
+            continue;
+        }
+
+        ret = njs_string_new(vm, &ename, d_name, size, length);
+        if (njs_slow_path(ret != NJS_OK)) {
+            goto done;
+        }
+
+        njs_set_number(&etype, njs_dentry_type(entry));
+
+        value = njs_array_push(vm, results);
+        if (njs_slow_path(value == NULL)) {
+            goto done;
+        }
+
+        ret = njs_fs_dirent_create(vm, &ename, &etype, value);
+        if (njs_slow_path(ret != NJS_OK)) {
+            goto done;
+        }
+    }
+
+done:
+
+    if (dir != NULL) {
+        (void) closedir(dir);
+    }
+
+    if (ret == NJS_OK) {
+        return njs_fs_result(vm, &retval, calltype, callback, 2);
+    }
+
+    return NJS_ERROR;
+}
+
+
+static njs_int_t
 njs_fs_fd_read(njs_vm_t *vm, int fd, njs_str_t *data)
 {
     u_char   *p, *end, *start;
@@ -1231,6 +1415,205 @@ memory_error:
 }
 
 
+static njs_int_t
+njs_fs_dirent_create(njs_vm_t *vm, njs_value_t *name, njs_value_t *type,
+    njs_value_t *retval)
+{
+    njs_int_t     ret;
+    njs_object_t  *object;
+
+    static const njs_value_t  string_name = njs_string("name");
+    static const njs_value_t  string_type = njs_string("type");
+
+    object = njs_object_alloc(vm);
+    if (njs_slow_path(object == NULL)) {
+        return NJS_ERROR;
+    }
+
+    object->__proto__ = &vm->prototypes[NJS_OBJ_TYPE_FS_DIRENT].object;
+
+    njs_set_object(retval, object);
+
+    ret = njs_value_property_set(vm, retval, njs_value_arg(&string_name),
+                                 name);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return ret;
+    }
+
+    /* TODO: use a private symbol as a key. */
+    ret = njs_value_property_set(vm, retval, njs_value_arg(&string_type),
+                                 type);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return ret;
+    }
+
+    return NJS_OK;
+}
+
+
+static njs_int_t
+njs_dirent_constructor(njs_vm_t *vm, njs_value_t *args,
+    njs_uint_t nargs, njs_index_t unused)
+{
+    if (njs_slow_path(!vm->top_frame->ctor)) {
+        njs_type_error(vm, "the Dirent constructor must be called with new");
+        return NJS_ERROR;
+    }
+
+    return njs_fs_dirent_create(vm, njs_arg(args, nargs, 1),
+                                njs_arg(args, nargs, 2), &vm->retval);
+}
+
+
+static const njs_object_prop_t  njs_dirent_constructor_properties[] =
+{
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("name"),
+        .value = njs_string("Dirent"),
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("length"),
+        .value = njs_value(NJS_NUMBER, 1, 2.0),
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY_HANDLER,
+        .name = njs_string("prototype"),
+        .value = njs_prop_handler(njs_object_prototype_create),
+    },
+};
+
+
+const njs_object_init_t  njs_dirent_constructor_init = {
+    njs_dirent_constructor_properties,
+    njs_nitems(njs_dirent_constructor_properties),
+};
+
+
+static njs_int_t
+njs_fs_dirent_test(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+    njs_index_t testtype)
+{
+    njs_int_t    ret;
+    njs_value_t  type, *this;
+
+    static const njs_value_t  string_type = njs_string("type");
+
+    this = njs_argument(args, 0);
+
+    ret = njs_value_property(vm, this, njs_value_arg(&string_type), &type);
+    if (njs_slow_path(ret == NJS_ERROR)) {
+        return ret;
+    }
+
+    if (njs_slow_path(njs_is_number(&type)
+                      && (njs_number(&type) == NJS_DT_INVALID)))
+    {
+        njs_internal_error(vm, "dentry type is not supported on this platform");
+        return NJS_ERROR;
+    }
+
+    njs_set_boolean(&vm->retval,
+                    njs_is_number(&type) && testtype == njs_number(&type));
+
+    return NJS_OK;
+}
+
+
+static const njs_object_prop_t  njs_dirent_prototype_properties[] =
+{
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_wellknown_symbol(NJS_SYMBOL_TO_STRING_TAG),
+        .value = njs_string("Dirent"),
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY_HANDLER,
+        .name = njs_string("constructor"),
+        .value = njs_prop_handler(njs_object_prototype_create_constructor),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("isDirectory"),
+        .value = njs_native_function2(njs_fs_dirent_test, 0, DT_DIR),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("isFile"),
+        .value = njs_native_function2(njs_fs_dirent_test, 0, DT_REG),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("isBlockDevice"),
+        .value = njs_native_function2(njs_fs_dirent_test, 0, DT_BLK),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_long_string("isCharacterDevice"),
+        .value = njs_native_function2(njs_fs_dirent_test, 0, DT_CHR),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("isSymbolicLink"),
+        .value = njs_native_function2(njs_fs_dirent_test, 0, DT_LNK),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("isFIFO"),
+        .value = njs_native_function2(njs_fs_dirent_test, 0, DT_FIFO),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("isSocket"),
+        .value = njs_native_function2(njs_fs_dirent_test, 0, DT_SOCK),
+        .writable = 1,
+        .configurable = 1,
+    },
+};
+
+
+const njs_object_init_t  njs_dirent_prototype_init = {
+    njs_dirent_prototype_properties,
+    njs_nitems(njs_dirent_prototype_properties),
+};
+
+
+const njs_object_type_init_t  njs_dirent_type_init = {
+    .constructor = njs_native_ctor(njs_dirent_constructor, 2, 0),
+    .prototype_props = &njs_dirent_prototype_init,
+    .constructor_props = &njs_dirent_constructor_init,
+    .prototype_value = { .object = { .type = NJS_OBJECT } },
+};
+
+
 static const njs_object_prop_t  njs_fs_promises_properties[] =
 {
     {
@@ -1293,6 +1676,14 @@ static const njs_object_prop_t  njs_fs_p
 
     {
         .type = NJS_PROPERTY,
+        .name = njs_string("readdir"),
+        .value = njs_native_function2(njs_fs_readdir, 0, NJS_FS_PROMISE),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
         .name = njs_string("symlink"),
         .value = njs_native_function2(njs_fs_symlink, 0, NJS_FS_PROMISE),
         .writable = 1,
@@ -1399,6 +1790,14 @@ static const njs_object_prop_t  njs_fs_o
 
     {
         .type = NJS_PROPERTY,
+        .name = njs_string("Dirent"),
+        .value = _njs_native_function(njs_dirent_constructor, 2, 1, 0),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
         .name = njs_string("access"),
         .value = njs_native_function2(njs_fs_access, 0, NJS_FS_CALLBACK),
         .writable = 1,
@@ -1560,6 +1959,22 @@ static const njs_object_prop_t  njs_fs_o
         .writable = 1,
         .configurable = 1,
     },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("readdir"),
+        .value = njs_native_function2(njs_fs_readdir, 0, NJS_FS_CALLBACK),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("readdirSync"),
+        .value = njs_native_function2(njs_fs_readdir, 0, NJS_FS_DIRECT),
+        .writable = 1,
+        .configurable = 1,
+    },
 };
 
 
diff -r 724dedc6be18 -r b33402f10e82 src/njs_fs.h
--- a/src/njs_fs.h	Tue Jun 09 12:56:56 2020 +0000
+++ b/src/njs_fs.h	Sun May 31 08:45:41 2020 +0300
@@ -10,5 +10,6 @@
 
 extern const njs_object_init_t  njs_fs_object_init;
 
+extern const njs_object_type_init_t  njs_dirent_type_init;
 
 #endif /* _NJS_FS_H_INCLUDED_ */
diff -r 724dedc6be18 -r b33402f10e82 src/njs_vm.h
--- a/src/njs_vm.h	Tue Jun 09 12:56:56 2020 +0000
+++ b/src/njs_vm.h	Sun May 31 08:45:41 2020 +0300
@@ -92,8 +92,9 @@ typedef enum {
     NJS_OBJ_TYPE_PROMISE,
     NJS_OBJ_TYPE_ARRAY_BUFFER,
 
+    NJS_OBJ_TYPE_FS_DIRENT,
+#define NJS_OBJ_TYPE_HIDDEN_MIN    (NJS_OBJ_TYPE_FS_DIRENT)
     NJS_OBJ_TYPE_CRYPTO_HASH,
-#define NJS_OBJ_TYPE_HIDDEN_MIN    (NJS_OBJ_TYPE_CRYPTO_HASH)
     NJS_OBJ_TYPE_CRYPTO_HMAC,
     NJS_OBJ_TYPE_TYPED_ARRAY,
 #define NJS_OBJ_TYPE_HIDDEN_MAX    (NJS_OBJ_TYPE_TYPED_ARRAY + 1)
diff -r 724dedc6be18 -r b33402f10e82 src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c	Tue Jun 09 12:56:56 2020 +0000
+++ b/src/test/njs_unit_test.c	Sun May 31 08:45:41 2020 +0300
@@ -16371,12 +16371,20 @@ static njs_unit_test_t  njs_test[] =
                 "'writeFileSync',"
                 "'appendFile',"
                 "'appendFileSync',"
+                "'rename',"
+                "'renameSync',"
                 "'symlink',"
                 "'symlinkSync',"
                 "'unlink',"
                 "'unlinkSync',"
                 "'realpath',"
                 "'realpathSync',"
+                "'mkdir',"
+                "'mkdirSync',"
+                "'rmdir',"
+                "'rmdirSync',"
+                "'readdir',"
+                "'readdirSync',"
               "],"
               "test = (fname) =>"
                 "[undefined, null, false, NaN, Symbol(), {}, Object('/njs_unknown_path')]"
@@ -16399,9 +16407,13 @@ static njs_unit_test_t  njs_test[] =
                 "'readFile',"
                 "'writeFile',"
                 "'appendFile',"
+                "'rename',"
                 "'symlink',"
                 "'unlink',"
                 "'realpath',"
+                "'mkdir',"
+                "'rmdir',"
+                "'readdir',"
               "];"
               "func.every((x) => typeof fs[x] == 'function')"),
       njs_str("true")},
@@ -16423,6 +16435,35 @@ static njs_unit_test_t  njs_test[] =
               "items.every((x) => typeof fsc[x] == 'number')"),
       njs_str("true")},
 
+    /* require('fs').Dirent */
+
+    { njs_str("var fs = require('fs');"
+              "typeof fs.Dirent"),
+      njs_str("function") },
+
+    { njs_str("var fs = require('fs');"
+              "fs.Dirent('file', 123)"),
+      njs_str("TypeError: the Dirent constructor must be called with new") },
+
+    { njs_str("var fs = require('fs');"
+              "var e = new fs.Dirent('file', 123); [e.name, e.type]"),
+      njs_str("file,123") },
+
+    { njs_str("var "
+              "fs = require('fs'),"
+              "e = new fs.Dirent('file', 0),"
+              "func = ["
+                "'isDirectory',"
+                "'isFile',"
+                "'isBlockDevice',"
+                "'isCharacterDevice',"
+                "'isSymbolicLink',"
+                "'isFIFO',"
+                "'isSocket',"
+              "];"
+              "func.every((x) => typeof e[x] == 'function')"),
+      njs_str("true")},
+
     /* require('crypto').createHash() */
 
     { njs_str("var h = require('crypto').createHash('sha1');"
diff -r 724dedc6be18 -r b33402f10e82 test/js/fs_promises_007.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/js/fs_promises_007.js	Sun May 31 08:45:41 2020 +0300
@@ -0,0 +1,231 @@
+var fs = require('fs');
+var fsp  = fs.promises;
+var dname = './build/test/fs_promises_007';
+var dname_utf8 = './build/test/fs_promises_αβγ_007';
+var fname = (d) => d + '/fs_promises_007_file';
+var lname = (d) => d + '/fs_promises_007_link';
+var cname = (d) => d + '/fs_promises_αβγ_007_dir';
+
+
+var dir_test = [cname(''), lname(''), fname('')].map((x) => x.substring(1));
+var match = (entry) => {
+    var idx = dir_test.indexOf(entry.name);
+
+    try {
+        switch(idx) {
+        case 0:
+            return entry.isDirectory();
+        case 1:
+            return entry.isSymbolicLink();
+        case 2:
+            return entry.isFile();
+        default:
+            return false;
+        }
+    } catch (e) {
+        if (e.name == 'InternalError') {
+            return true;
+        }
+
+        throw e;
+    }
+};
+
+
+var testSync = () => new Promise((resolve, reject) => {
+    try {
+        try { fs.rmdirSync(cname(dname)); } catch (e) {}
+        try { fs.rmdirSync(cname(dname_utf8)); } catch (e) {}
+        try { fs.unlinkSync(lname(dname)); } catch (e) {}
+        try { fs.unlinkSync(lname(dname_utf8)); } catch (e) {}
+        try { fs.unlinkSync(fname(dname)); } catch (e) {}
+        try { fs.unlinkSync(fname(dname_utf8)); } catch (e) {}
+        try { fs.rmdirSync(dname); } catch (e) {}
+        try { fs.rmdirSync(dname_utf8); } catch (e) {}
+
+        try {
+            fs.readdirSync(dname);
+            throw new Error('fs.readdirSync - error 0');
+
+        } catch (e) {
+            if (e.code != 'ENOENT') {
+                // njs: e.syscall == 'opendir'
+                // node: e.syscall == 'scandir'
+                throw e;
+            }
+        }
+
+        fs.mkdirSync(dname);
+        fs.mkdirSync(dname_utf8);
+        fs.writeFileSync(fname(dname), fname(dname));
+        fs.writeFileSync(fname(dname_utf8), fname(dname_utf8));
+        fs.symlinkSync(fname('.'), lname(dname));
+        fs.symlinkSync(fname('.'), lname(dname_utf8));
+        fs.mkdirSync(cname(dname));
+        fs.mkdirSync(cname(dname_utf8));
+
+        var dir = fs.readdirSync(dname);
+        var dir_utf8 = fs.readdirSync(dname_utf8);
+        if (dir.length != dir_utf8.length || dir.length != 3) {
+            throw new Error('fs.readdirSync - error 1');
+        }
+
+        var test = dir.filter((x) => !dir_test.includes(x));
+        if (test.length != 0) {
+            throw new Error('fs.readdirSync - error 2');
+        }
+
+        var test = dir_utf8.filter((x) => !dir_test.includes(x));
+        if (test.length != 0) {
+            throw new Error('fs.readdirSync - error 3');
+        }
+
+        var dir = fs.readdirSync(dname, { withFileTypes: true });
+        var dir_utf8 = fs.readdirSync(dname_utf8, { withFileTypes: true });
+        if (dir.length != dir_utf8.length || dir.length != 3) {
+            throw new Error('fs.readdirSync - error 4');
+        }
+
+        var test = dir.filter((x) => !match(x));
+        if (test.length != 0) {
+            throw new Error('fs.readdirSync - error 5');
+        }
+
+        var test = dir_utf8.filter((x) => !match(x));
+        if (test.length != 0) {
+            throw new Error('fs.readdirSync - error 6');
+        }
+
+        resolve();
+
+    } catch (e) {
+        reject(e);
+    }
+});
+
+
+var testCallback = () => new Promise((resolve, reject) => {
+    try {
+        try { fs.rmdirSync(cname(dname)); } catch (e) {}
+        try { fs.unlinkSync(lname(dname)); } catch (e) {}
+        try { fs.unlinkSync(fname(dname)); } catch (e) {}
+        try { fs.rmdirSync(dname); } catch (e) {}
+
+        fs.readdir(dname, (err, files) => {
+            if (!err || err.code != 'ENOENT') {
+                reject(new Error('fs.readdir - error 1'));
+            }
+
+            try {
+                fs.mkdirSync(dname);
+                fs.writeFileSync(fname(dname), fname(dname));
+                fs.symlinkSync(fname('.'), lname(dname));
+                fs.mkdirSync(cname(dname));
+
+            } catch (e) {
+                reject(e);
+            }
+
+            fs.readdir(dname, (err, dir) => {
+                if (err) {
+                    reject(err);
+                }
+
+                if (dir.length != 3) {
+                    reject(new Error('fs.readdir - error 2'));
+                }
+
+                var test = dir.filter((x) => !dir_test.includes(x));
+                if (test.length != 0) {
+                    reject(new Error('fs.readdir - error 3'));
+                }
+
+                fs.readdir(dname, { withFileTypes: true }, (err, dir) => {
+                    if (err) {
+                        reject(err);
+                    }
+
+                    if (dir.length != 3) {
+                        reject(new Error('fs.readdir - error 4'));
+                    }
+
+                    var test = dir.filter((x) => !match(x));
+                    if (test.length != 0) {
+                        reject(new Error('fs.readdir - error 5'));
+                    }
+
+                    resolve();
+                });
+            });
+        });
+
+    } catch (e) {
+        reject(e);
+    }
+});
+
+
+Promise.resolve()
+.then(testSync)
+.then(() => {
+    console.log('test fs.readdirSync');
+})
+.catch((e) => {
+    console.log('test fs.readdirSync failed', JSON.stringify(e));
+})
+
+.then(testCallback)
+.then(() => {
+    console.log('test fs.readdir');
+})
+.catch((e) => {
+    console.log('test fs.readdir failed', JSON.stringify(e));
+})
+
+.then(() => {
+    try { fs.rmdirSync(cname(dname)); } catch (e) {}
+    try { fs.unlinkSync(lname(dname)); } catch (e) {}
+    try { fs.unlinkSync(fname(dname)); } catch (e) {}
+    try { fs.rmdirSync(dname); } catch (e) {}
+})
+.then(() => fsp.readdir(dname)
+               .then(() => { throw new Error('fsp.readdir - error 1'); }))
+.catch((e) => {
+    if (e.code != 'ENOENT') {
+        throw e;
+    }
+})
+.then(() => {
+    fs.mkdirSync(dname);
+    fs.writeFileSync(fname(dname), fname(dname));
+    fs.symlinkSync(fname('.'), lname(dname));
+    fs.mkdirSync(cname(dname));
+})
+.then(() => fsp.readdir(dname))
+.then((dir) => {
+    if (dir.length != 3) {
+        throw new Error('fsp.readdir - error 2');
+    }
+
+    var test = dir.filter((x) => !dir_test.includes(x));
+    if (test.length != 0) {
+        throw new Error('fsp.readdir - error 3');
+    }
+})
+.then(() => fsp.readdir(dname, { withFileTypes: true }))
+.then((dir) => {
+    if (dir.length != 3) {
+        throw new Error('fsp.readdir - error 4');
+    }
+
+    var test = dir.filter((x) => !match(x));
+    if (test.length != 0) {
+        throw new Error('fsp.readdir - error 5');
+    }
+})
+.then(() => {
+    console.log('test fsp.readdir');
+})
+.catch((e) => {
+    console.log('test fsp.readdir failed', JSON.stringify(e));
+});
diff -r 724dedc6be18 -r b33402f10e82 test/njs_expect_test.exp
--- a/test/njs_expect_test.exp	Tue Jun 09 12:56:56 2020 +0000
+++ b/test/njs_expect_test.exp	Sun May 31 08:45:41 2020 +0300
@@ -459,15 +459,6 @@ njs_test {
      "queue.toString()\r\n'0,1,2,3,4,5'"}
 }
 
-# require('fs')
-
-njs_test {
-    {"var fs = require('fs')\r\n"
-     "undefined\r\n>> "}
-    {"fs.read\t"
-     "fs.read\a*File"}
-}
-
 # require('fs').readFile()
 
 njs_test {
@@ -1144,3 +1135,8 @@ njs_run {"./test/js/fs_promises_006.js"}
 "test fs.renameSync
 test fs.rename
 test fsp.rename"
+
+njs_run {"./test/js/fs_promises_007.js"} \
+"test fs.readdirSync
+test fs.readdir
+test fsp.readdir"


More information about the nginx-devel mailing list