]> git.kaiwu.me - njs.git/commitdiff
Tests: moving module tests into separate test suites.
authorDmitry Volyntsev <xeioex@nginx.com>
Tue, 21 Dec 2021 15:49:13 +0000 (15:49 +0000)
committerDmitry Volyntsev <xeioex@nginx.com>
Tue, 21 Dec 2021 15:49:13 +0000 (15:49 +0000)
src/test/njs_unit_test.c

index aa296d460748b3e4ab0a8b58bf8ab0283d4fcab5..4f13f14c4e957bbee8af564c002864f228288d3c 100644 (file)
@@ -17710,2952 +17710,2957 @@ static njs_unit_test_t  njs_test[] =
     { njs_str("require.hasOwnProperty('length')"),
       njs_str("true") },
 
-    { njs_str("var fs = require('fs'); typeof fs"),
-      njs_str("object") },
-
-    { njs_str("var fs = require('fs'); Object.isExtensible(fs)"),
-      njs_str("true") },
+    /* setTimeout(). */
 
-    { njs_str("require('fs') === require('fs')"),
-      njs_str("true") },
+    { njs_str("setTimeout()"),
+      njs_str("TypeError: too few arguments") },
 
-    { njs_str("require('fs').a = 1; require('fs').a"),
-      njs_str("1") },
+    { njs_str("setTimeout(function(){})"),
+      njs_str("InternalError: not supported by host environment") },
 
-    /* require('fs').readFile() */
+    { njs_str("setTimeout(function(){}, 12)"),
+      njs_str("InternalError: not supported by host environment") },
 
-    { njs_str("var fs = require('fs');"
-              "fs.readFile()"),
-      njs_str("TypeError: \"path\" must be a string or Buffer") },
+    /* clearTimeout(). */
 
-    { njs_str("var fs = require('fs');"
-              "var path = Buffer.from('/broken'); path[3] = 0;"
-              "fs.readFile(path)"),
-      njs_str("TypeError: \"path\" must be a Buffer without null bytes") },
+    { njs_str("clearTimeout()"),
+      njs_str("undefined") },
 
-    { njs_str("var fs = require('fs');"
-              "fs.readFile('/njs_unknown_path')"),
-      njs_str("TypeError: \"callback\" must be a function") },
+    { njs_str("clearTimeout(123)"),
+      njs_str("undefined") },
 
-    { njs_str("var fs = require('fs');"
-              "fs.readFile('/njs_unknown_path', 'utf8')"),
-      njs_str("TypeError: \"callback\" must be a function") },
+    /* Trick: number to boolean. */
 
-    { njs_str("var fs = require('fs');"
-              "fs.readFile('/njs_unknown_path', {flag:'xx'})"),
-      njs_str("TypeError: \"callback\" must be a function") },
+    { njs_str("var a = 0; !!a"),
+      njs_str("false") },
 
-    { njs_str("var fs = require('fs');"
-              "fs.readFile('/njs_unknown_path', {flag:'xx'}, 1)"),
-      njs_str("TypeError: \"callback\" must be a function") },
+    { njs_str("var a = 5; !!a"),
+      njs_str("true") },
 
-    { njs_str("var fs = require('fs');"
-              "fs.readFile('/njs_unknown_path', {flag:'xx'}, function () {})"),
-      njs_str("TypeError: Unknown file open flags: \"xx\"") },
+    /* Trick: flooring. */
 
-    { njs_str("var fs = require('fs');"
-              "fs.readFile('/njs_unknown_path', {encoding:'ascii'}, function () {})"),
-      njs_str("TypeError: \"ascii\" encoding is not supported") },
+    { njs_str("var n = -10.12345; ~~n"),
+      njs_str("-10") },
 
-    { njs_str("var fs = require('fs');"
-              "fs.readFile('/njs_unknown_path', 'ascii', function () {})"),
-      njs_str("TypeError: \"ascii\" encoding is not supported") },
+    { njs_str("var n = 10.12345; ~~n"),
+      njs_str("10") },
 
-    /* require('fs').readFileSync() */
+    /* es5id: 8.2_A1_T1 */
+    /* es5id: 8.2_A1_T2 */
 
-    { njs_str("var fs = require('fs');"
-              "fs.readFileSync()"),
-      njs_str("TypeError: \"path\" must be a string or Buffer") },
+    { njs_str("var x = null;"),
+      njs_str("undefined") },
 
-    { njs_str("var fs = require('fs');"
-              "fs.readFileSync({})"),
-      njs_str("TypeError: \"path\" must be a string or Buffer") },
+    /* es5id: 8.2_A2 */
 
-    { njs_str("var fs = require('fs');"
-              "fs.readFileSync('/njs_unknown_path', {flag:'xx'})"),
-      njs_str("TypeError: Unknown file open flags: \"xx\"") },
+    { njs_str("var null;"),
+      njs_str("SyntaxError: Unexpected token \"null\" in 1") },
 
-    { njs_str("var fs = require('fs');"
-              "fs.readFileSync(Buffer.from('/njs_unknown_path'), {encoding:'ascii'})"),
-      njs_str("TypeError: \"ascii\" encoding is not supported") },
+    /* es5id: 8.2_A3 */
 
-    { njs_str("var fs = require('fs');"
-              "fs.readFileSync('/njs_unknown_path', 'ascii')"),
-      njs_str("TypeError: \"ascii\" encoding is not supported") },
+    { njs_str("typeof(null) === \"object\""),
+      njs_str("true") },
 
-    { njs_str("var fs = require('fs');"
-              "fs.readFileSync('/njs_unknown_path', true)"),
-      njs_str("TypeError: Unknown options type: \"boolean\" (a string or object required)") },
+    /* Module. */
 
+    { njs_str("import;"),
+      njs_str("SyntaxError: Non-default import is not supported in 1") },
 
-    /* require('fs').writeFile() */
+    { njs_str("import {x} from y"),
+      njs_str("SyntaxError: Non-default import is not supported in 1") },
 
-    { njs_str("var fs = require('fs');"
-              "fs.writeFile()"),
-      njs_str("TypeError: \"path\" must be a string or Buffer") },
+    { njs_str("import x from y"),
+      njs_str("SyntaxError: Unexpected token \"y\" in 1") },
 
-    { njs_str("var fs = require('fs');"
-              "fs.writeFile({}, '', function () {})"),
-      njs_str("TypeError: \"path\" must be a string or Buffer") },
+    { njs_str("import x from {"),
+      njs_str("SyntaxError: Unexpected token \"{\" in 1") },
 
-    { njs_str("var fs = require('fs');"
-              "fs.writeFile('/njs_unknown_path')"),
-      njs_str("TypeError: \"callback\" must be a function") },
+    { njs_str("import x from ''"),
+      njs_str("SyntaxError: Cannot find module \"\" in 1") },
 
-    { njs_str("var fs = require('fs');"
-              "fs.writeFile('/njs_unknown_path', '')"),
-      njs_str("TypeError: \"callback\" must be a function") },
+    { njs_str("import x from 'crypto'"),
+      njs_str("undefined") },
 
-    { njs_str("var fs = require('fs');"
-              "fs.writeFile('/njs_unknown_path', '', undefined)"),
-      njs_str("TypeError: \"callback\" must be a function") },
+    { njs_str("import x from 'crypto' 1"),
+      njs_str("SyntaxError: Unexpected token \"1\" in 1") },
 
-    { njs_str("var fs = require('fs');"
-              "fs.writeFile('/njs_unknown_path', '', 'utf8')"),
-      njs_str("TypeError: \"callback\" must be a function") },
+    { njs_str("if (1) {import x from 'crypto'}"),
+      njs_str("SyntaxError: Illegal import statement in 1") },
 
-    { njs_str("var fs = require('fs');"
-              "fs.writeFile('/njs_unknown_path', '', {flag:'xx'}, function () {})"),
-      njs_str("TypeError: Unknown file open flags: \"xx\"") },
+    { njs_str("export"),
+      njs_str("SyntaxError: Illegal export statement in 1") },
 
-    { njs_str("var fs = require('fs');"
-              "fs.writeFile('/njs_unknown_path', '', {encoding:'ascii'}, function () {})"),
-      njs_str("TypeError: \"ascii\" encoding is not supported") },
+    { njs_str("Object.assign(undefined)"),
+      njs_str("TypeError: cannot convert null or undefined to object") },
 
-    { njs_str("var fs = require('fs');"
-              "fs.writeFile('/njs_unknown_path', '', 'ascii', function () {})"),
-      njs_str("TypeError: \"ascii\" encoding is not supported") },
+    { njs_str("Object.assign(null)"),
+      njs_str("TypeError: cannot convert null or undefined to object") },
 
-    { njs_str("var fs = require('fs');"
-              "fs.writeFile('/njs_unknown_path', '', true, function () {})"),
-      njs_str("TypeError: Unknown options type: \"boolean\" (a string or object required)") },
+    { njs_str("Object.assign({x:123}).toString()"),
+      njs_str("[object Object]") },
 
-    /* require('fs').writeFileSync() */
+    { njs_str("Object.assign({x:123}).x"),
+      njs_str("123") },
 
-    { njs_str("var fs = require('fs');"
-              "fs.writeFileSync()"),
-      njs_str("TypeError: \"path\" must be a string or Buffer") },
+    { njs_str("Object.assign(true)"),
+      njs_str("true") },
 
-    { njs_str("var fs = require('fs');"
-              "fs.writeFileSync({}, '')"),
-      njs_str("TypeError: \"path\" must be a string or Buffer") },
+    { njs_str("Object.assign(123)"),
+      njs_str("123") },
 
-    { njs_str("var fs = require('fs');"
-              "fs.writeFileSync('/njs_unknown_path', '', {flag:'xx'})"),
-      njs_str("TypeError: Unknown file open flags: \"xx\"") },
+    { njs_str("var o1 = {a:1, b:1, c:1}; var o2 = {b:2, c:2}; "
+                 "var o3 = {c:3}; var obj = Object.assign({}, o1, o2, o3); "
+                 "Object.values(obj);"),
+      njs_str("1,2,3") },
 
-    { njs_str("var fs = require('fs');"
-              "fs.writeFileSync('/njs_unknown_path', '', {encoding:'ascii'})"),
-      njs_str("TypeError: \"ascii\" encoding is not supported") },
+    { njs_str("var v1 = 'abc'; var v2 = true; var v3 = 10; "
+                 "var obj = Object.assign({}, v1, null, v2, undefined, v3); "
+                 "Object.values(obj);"),
+      njs_str("a,b,c") },
 
-    { njs_str("var fs = require('fs');"
-              "fs.writeFileSync('/njs_unknown_path', '', 'ascii')"),
-      njs_str("TypeError: \"ascii\" encoding is not supported") },
+    { njs_str("Object.assign(true, {a:123})"),
+      njs_str("true") },
 
-    { njs_str("var fs = require('fs');"
-              "fs.writeFileSync('/njs_unknown_path', '', true)"),
-      njs_str("TypeError: Unknown options type: \"boolean\" (a string or object required)") },
+    { njs_str("Object.assign(true, {a:123}).a"),
+      njs_str("123") },
 
-    /* require('fs').renameSync() */
+    { njs_str("var y = Object.create({s:123}); y.z = 456;"
+                 "Object.assign({}, y).s;"),
+      njs_str("undefined") },
 
-    { njs_str("var fs = require('fs');"
-              "fs.renameSync()"),
-      njs_str("TypeError: \"oldPath\" must be a string or Buffer") },
+    { njs_str("var obj = {s:123}; Object.defineProperty(obj,"
+                 "'p1', {value:12, enumerable:false});"
+                 "Object.assign({}, obj).p1"),
+      njs_str("undefined") },
 
-    { njs_str("var fs = require('fs');"
-              "fs.renameSync('/njs_unknown_path')"),
-      njs_str("TypeError: \"newPath\" must be a string or Buffer") },
+    { njs_str("var obj = {s:123}; Object.defineProperty(obj,"
+                 "'x', {value:12, writable:false});"
+                 "Object.assign(obj, {x:4})"),
+      njs_str("TypeError: Cannot assign to read-only property \"x\" of object") },
 
-    { njs_str("var fs = require('fs');"
-              "[undefined, null, false, NaN, Symbol(), {}, Object('/njs_unknown_path')]"
-              ".map((x) => { try { fs.renameSync(x, '/njs_unknown_path'); } "
-              "              catch (e) { return (e instanceof TypeError); } })"
-              ".every((x) => x === true)"),
-      njs_str("true")},
+    { njs_str("var obj = {foo:1, get bar() {return 2;}};"
+                 "var copy = Object.assign({}, obj);"
+                 "Object.getOwnPropertyDescriptor(copy, 'bar').get"),
+      njs_str("undefined") },
 
-    { njs_str("var fs = require('fs');"
-              "[undefined, null, false, NaN, Symbol(), {}, Object('/njs_unknown_path')]"
-              ".map((x) => { try { fs.renameSync('/njs_unknown_path', x); } "
-              "              catch (e) { return (e instanceof TypeError); } })"
-              ".every((x) => x === true)"),
-      njs_str("true")},
+    { njs_str("try{var x = Object.defineProperty({}, 'foo',"
+                 "{value:1, writable:false});"
+                 "Object.assign(x, {bar:2}, {foo:2});}catch(error){};"
+                 "x.bar"),
+      njs_str("2") },
 
-    /* require('fs').access() */
+    { njs_str("var a = Object.defineProperty({}, 'a',"
+                 "{get(){Object.defineProperty(this, 'b',"
+                 "{value:2,enumerable:false});"
+                 "return 1}, enumerable:1}); a.b =1;"
+                 "var x = Object.assign({}, a);x.b;"),
+      njs_str("undefined") },
 
-    { njs_str("var fs = require('fs');"
-              "fs.access()"),
-      njs_str("TypeError: \"path\" must be a string or Buffer") },
+    /* let and const */
 
-    { njs_str("var fs = require('fs');"
-              "fs.access('/njs_unknown_path')"),
-      njs_str("TypeError: \"callback\" must be a function") },
+    { njs_str("var let = 123;"
+              "let"),
+      njs_str("SyntaxError: Unexpected token \"let\" in 1") },
 
-    { njs_str("var fs = require('fs');"
-              "fs.access('/njs_unknown_path', fs.constants.F_OK)"),
-      njs_str("TypeError: \"callback\" must be a function") },
+    { njs_str("var const = 123"),
+      njs_str("SyntaxError: Unexpected token \"const\" in 1") },
 
-    { njs_str("var fs = require('fs');"
-              "fs.access('/njs_unknown_path', 'fail', function () {})"),
-      njs_str("TypeError: \"mode\" must be a number") },
+    /* Async */
 
-    /* require('fs').accessSync() */
+    { njs_str("var async;"
+              "function f() {"
+              "    async\n"
+              "    function foo() {}"
+              "}"
+              "f()"),
+      njs_str("undefined") },
 
-    { njs_str("var fs = require('fs');"
-              "fs.accessSync()"),
-      njs_str("TypeError: \"path\" must be a string or Buffer") },
+    { njs_str("var async;"
+              "function f() {"
+              "    async;"
+              "    function foo() {}"
+              "}"
+              "f()"),
+      njs_str("undefined") },
 
-    { njs_str("var fs = require('fs');"
-              "fs.accessSync('/njs_unknown_path', 'fail')"),
-      njs_str("TypeError: \"mode\" must be a number") },
+    { njs_str("var async;"
+              "async\n"
+              "function foo() {}"),
+      njs_str("undefined") },
 
-    { njs_str("var "
-              "fs = require('fs'),"
-              "func = ["
-                "'access',"
-                "'accessSync',"
-                "'readFile',"
-                "'readFileSync',"
-                "'writeFile',"
-                "'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')]"
-                ".map((x) => { try { fs[fname](x); } "
-                "              catch (e) { return (e instanceof TypeError); } })"
-                ".every((x) => x === true);"
-              "func.map(test).every((x) => x)"),
-      njs_str("true")},
+    { njs_str("new\""),
+      njs_str("SyntaxError: Unterminated string \"\"\" in 1") },
 
-    /* require('fs').promises */
+    { njs_str("new\"\\UFFFF"),
+      njs_str("SyntaxError: Unterminated string \"\"\\UFFFF\" in 1") },
 
-    { njs_str("var fs = require('fs');"
-              "typeof fs.promises"),
-      njs_str("object") },
+    { njs_str("new/la"),
+      njs_str("SyntaxError: Unterminated RegExp \"/la\" in 1") },
 
-    { njs_str("var "
-              "fs = require('fs').promises,"
-              "func = ["
-                "'access',"
-                "'readFile',"
-                "'writeFile',"
-                "'appendFile',"
-                "'rename',"
-                "'symlink',"
-                "'unlink',"
-                "'realpath',"
-                "'mkdir',"
-                "'rmdir',"
-                "'readdir',"
-              "];"
-              "func.every((x) => typeof fs[x] == 'function')"),
-      njs_str("true")},
+    { njs_str("{name; {/ / /}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    /* require('fs').constants */
+    { njs_str("[(]"),
+      njs_str("SyntaxError: Unexpected token \"]\" in 1") },
 
-    { njs_str("var fs = require('fs');"
-              "typeof fs.constants"),
-      njs_str("object") },
+    { njs_str("[...]"),
+      njs_str("SyntaxError: Unexpected token \"]\" in 1") },
 
-    { njs_str("var "
-              "fsc = require('fs').constants,"
-              "items = ["
-                "'F_OK',"
-                "'R_OK',"
-                "'W_OK',"
-                "'X_OK',"
-              "];"
-              "items.every((x) => typeof fsc[x] == 'number')"),
-      njs_str("true")},
+    { njs_str("switch () {}"),
+      njs_str("SyntaxError: Unexpected token \")\" in 1") },
 
-    /* require('fs').Dirent */
+    { njs_str("switch ([(]) {}"),
+      njs_str("SyntaxError: Unexpected token \"]\" in 1") },
 
-    { njs_str("var fs = require('fs');"
-              "typeof fs.Dirent"),
-      njs_str("function") },
+    { njs_str("{{}{-}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { njs_str("var fs = require('fs');"
-              "fs.Dirent('file', 123)"),
-      njs_str("TypeError: the Dirent constructor must be called with new") },
+    { njs_str("{{}{+}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { njs_str("var fs = require('fs');"
-              "var e = new fs.Dirent('file', 123); [e.name, e.type]"),
-      njs_str("file,123") },
+    { njs_str("{{}{delete}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { 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")},
+    { njs_str("{{}{++}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    /* require('crypto').createHash() */
+    { njs_str("{{}{++1}"),
+      njs_str("ReferenceError: Invalid left-hand side in prefix operation in 1") },
 
-    { njs_str("var h = require('crypto').createHash('sha1');"
-              "[Object.prototype.toString.call(h), njs.dump(h),h]"),
-      njs_str("[object Hash],Hash {},[object Hash]") },
+    { njs_str("{{}{1++}"),
+      njs_str("ReferenceError: Invalid left-hand side in postfix operation in 1") },
 
-    { njs_str("var h = require('crypto').createHash('sha1');"
-              "var Hash = h.constructor; "
-              "Hash('sha1').update('AB').digest('hex')"),
-      njs_str("06d945942aa26a61be18c3e22bf19bbca8dd2b5d") },
+    { njs_str("{{}{1/}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { njs_str("var h = require('crypto').createHash('sha1');"
-              "h.constructor.name"),
-      njs_str("Hash") },
+    { njs_str("{{}{1>>}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { njs_str("var hash = require('crypto').createHash.bind(undefined, 'md5');"
-              "['hex', 'base64', 'base64url'].map(e => {"
-              "   var h = hash().update('AB').digest().toString(e);"
-              "   var h2 = hash().update(Buffer.from('XABX').subarray(1,3)).digest(e);"
-              "   var h3 = hash().update('A').update('B').digest(e);"
-              "   if (h !== h2) {throw new Error(`digest().toString($e):$h != digest($e):$h2`)};"
-              "   if (h !== h3) {throw new Error(`digest().toString($e):$h != update('A').update('B').digest($e):$h3`)};"
-              "   return h;"
-              "})"),
-      njs_str("b86fc6b051f63d73de262d4c34e3a0a9,"
-              "uG/GsFH2PXPeJi1MNOOgqQ==,"
-              "uG_GsFH2PXPeJi1MNOOgqQ") },
+    { njs_str("{{}{r=}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { njs_str("var hash = require('crypto').createHash.bind(undefined, 'sha1');"
-              "['hex', 'base64', 'base64url'].map(e => {"
-              "   var h = hash().update('4142', 'hex').digest().toString(e);"
-              "   var h2 = hash().update(Buffer.from('XABX').subarray(1,3)).digest(e);"
-              "   var h3 = hash().update('A').update('B').digest(e);"
-              "   if (h !== h2) {throw new Error(`digest().toString($e):$h != digest($e):$h2`)};"
-              "   if (h !== h3) {throw new Error(`digest().toString($e):$h != update('A').update('B').digest($e):$h3`)};"
-              "   return h;"
-              "})"),
-      njs_str("06d945942aa26a61be18c3e22bf19bbca8dd2b5d,"
-              "BtlFlCqiamG+GMPiK/GbvKjdK10=,"
-              "BtlFlCqiamG-GMPiK_GbvKjdK10") },
+    { njs_str("{{}{var a = }"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { njs_str("var hash = require('crypto').createHash.bind(undefined, 'sha1');"
-              "['hex', 'base64', 'base64url'].every(e => {"
-              "   var h = hash().digest(e);"
-              "   var h2 = hash().update('').digest(e);"
-              "   if (h !== h2) {throw new Error(`digest($e):$h != update('').digest($e):$h2`)};"
-              "   return true;"
-              "})"),
-      njs_str("true") },
+    { njs_str("{{}T=>}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { njs_str("var hash = require('crypto').createHash.bind(undefined, 'sha1');"
-              "["
-              " ['AB'],"
-              " ['4142', 'hex'],"
-              " ['QUI=', 'base64'],"
-              " ['QUI', 'base64url']"
-              "].every(args => {"
-              "        return hash().update(args[0], args[1]).digest('hex') === '06d945942aa26a61be18c3e22bf19bbca8dd2b5d';"
-              "})"),
-      njs_str("true") },
+    { njs_str("{{}a = b +}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { njs_str("var hash = require('crypto').createHash.bind(undefined, 'sha256');"
-              "['hex', 'base64', 'base64url'].map(e => {"
-              "   var h = hash().update('AB').digest().toString(e);"
-              "   var h2 = hash().update(Buffer.from('XABX').subarray(1,3)).digest(e);"
-              "   var h3 = hash().update('A').update('B').digest(e);"
-              "   if (h !== h2) {throw new Error(`digest().toString($e):$h != digest($e):$h2`)};"
-              "   if (h !== h3) {throw new Error(`digest().toString($e):$h != update('A').update('B').digest($e):$h3`)};"
-              "   return h;"
-              "})"),
-      njs_str("38164fbd17603d73f696b8b4d72664d735bb6a7c88577687fd2ae33fd6964153,"
-              "OBZPvRdgPXP2lri01yZk1zW7anyIV3aH/SrjP9aWQVM=,"
-              "OBZPvRdgPXP2lri01yZk1zW7anyIV3aH_SrjP9aWQVM") },
+    { njs_str("{{}a = b -}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { njs_str("var hash = require('crypto').createHash;"
-              "njs.dump(['', 'abc'.repeat(100)].map(v => {"
-              "    return ['md5', 'sha1', 'sha256'].map(h => {"
-              "        return hash(h).update(v).digest('hex');"
-              "     })"
-              "}))"),
-      njs_str("[['d41d8cd98f00b204e9800998ecf8427e',"
-              "'da39a3ee5e6b4b0d3255bfef95601890afd80709',"
-              "'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'],"
-              "['f571117acbd8153c8dc3c81b8817773a',"
-              "'c95466320eaae6d19ee314ae4f135b12d45ced9a',"
-              "'d9f5aeb06abebb3be3f38adec9a2e3b94228d52193be923eb4e24c9b56ee0930']]") },
+    { njs_str("{{}a = b *}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { njs_str("var h = require('crypto').createHash()"),
-      njs_str("TypeError: algorithm must be a string") },
+    { njs_str("{{}a = b /}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { njs_str("var h = require('crypto').createHash([])"),
-      njs_str("TypeError: algorithm must be a string") },
+    { njs_str("{{}a = b %}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { njs_str("var h = require('crypto').createHash('sha512')"),
-      njs_str("TypeError: not supported algorithm: \"sha512\"") },
+    { njs_str("{{}a = b++}"),
+      njs_str("ReferenceError: \"a\" is not defined") },
 
-    { njs_str("var h = require('crypto').createHash('sha1');"
-              "h.update()"),
-      njs_str("TypeError: data argument \"undefined\" is not a string or Buffer-like object") },
+    { njs_str("{{}a = b--}"),
+      njs_str("ReferenceError: \"a\" is not defined") },
 
-    { njs_str("var h = require('crypto').createHash('sha1');"
-              "h.update({})"),
-      njs_str("TypeError: data argument \"object\" is not a string or Buffer-like object") },
+    { njs_str("{{}a =}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { njs_str("var h = require('crypto').createHash('sha1');"
-              "h.update('A').digest('latin1')"),
-      njs_str("TypeError: Unknown digest encoding: \"latin1\"") },
+    { njs_str("{{}a +=}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { njs_str("require('crypto').createHash('sha1').digest() instanceof Buffer"),
-      njs_str("true") },
-
-    { njs_str("var h = require('crypto').createHash('sha1');"
-              "h.update('A').digest('hex'); h.digest('hex')"),
-      njs_str("Error: Digest already called") },
+    { njs_str("{{}a -=}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { njs_str("var h = require('crypto').createHash('sha1');"
-              "h.update('A').digest('hex'); h.update('B')"),
-      njs_str("Error: Digest already called") },
+    { njs_str("{{}a *=}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { njs_str("typeof require('crypto').createHash('md5')"),
-      njs_str("object") },
+    { njs_str("{{}a /=}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    /* require('crypto').createHmac() */
+    { njs_str("{{}a %=}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { njs_str("var h = require('crypto').createHmac('sha1', '');"
-              "[Object.prototype.toString.call(h), njs.dump(h),h]"),
-      njs_str("[object Hmac],Hmac {},[object Hmac]") },
+    { njs_str("{{}a ===}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { njs_str("var hmac = require('crypto').createHmac.bind(undefined, 'md5', '');"
-              "['hex', 'base64', 'base64url'].map(e => {"
-              "   var h = hmac().update('AB').digest().toString(e);"
-              "   var h2 = hmac().update(Buffer.from('XABX').subarray(1,3)).digest(e);"
-              "   var h3 = hmac().update('A').update('B').digest(e);"
-              "   if (h !== h2) {throw new Error(`digest().toString($e):$h != digest($e):$h2`)};"
-              "   if (h !== h3) {throw new Error(`digest().toString($e):$h != update('A').update('B').digest($e):$h3`)};"
-              "   return h;"
-              "})"),
-      njs_str("9e0e9e545ef63d41dfb653daecf8ebc7,"
-              "ng6eVF72PUHftlPa7Pjrxw==,"
-              "ng6eVF72PUHftlPa7Pjrxw") },
+    { njs_str("{{}a ==}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { njs_str("var hmac = require('crypto').createHmac.bind(undefined, 'sha1', '');"
-              "['hex', 'base64', 'base64url'].map(e => {"
-              "   var h = hmac().update('AB').digest().toString(e);"
-              "   var h2 = hmac().update(Buffer.from('XABX').subarray(1,3)).digest(e);"
-              "   var h3 = hmac().update('A').update('B').digest(e);"
-              "   if (h !== h2) {throw new Error(`digest().toString($e):$h != digest($e):$h2`)};"
-              "   if (h !== h3) {throw new Error(`digest().toString($e):$h != update('A').update('B').digest($e):$h3`)};"
-              "   return h;"
-              "})"),
-      njs_str("d32c0b6637cc2dfe4670f3fe48ef4434123c4810,"
-              "0ywLZjfMLf5GcPP+SO9ENBI8SBA=,"
-              "0ywLZjfMLf5GcPP-SO9ENBI8SBA") },
+    { njs_str("{{}a !=}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { njs_str("var hash = require('crypto').createHmac.bind(undefined, 'sha1', '');"
-              "["
-              " ['AB'],"
-              " ['4142', 'hex'],"
-              " ['QUI=', 'base64'],"
-              " ['QUI', 'base64url']"
-              "].every(args => {"
-              "        return hash().update(args[0], args[1]).digest('hex') === 'd32c0b6637cc2dfe4670f3fe48ef4434123c4810';"
-              "})"),
-      njs_str("true") },
+    { njs_str("{{}a !==}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { njs_str("var hmac = require('crypto').createHmac.bind(undefined, 'sha256', '');"
-              "['hex', 'base64', 'base64url'].map(e => {"
-              "   var h = hmac().update('AB').digest().toString(e);"
-              "   var h2 = hmac().update(Buffer.from('AB')).digest(e);"
-              "   var h3 = hmac().update('A').update('B').digest(e);"
-              "   if (h !== h2) {throw new Error(`digest().toString($e):$h != digest($e):$h2`)};"
-              "   if (h !== h3) {throw new Error(`digest().toString($e):$h != update('A').update('B').digest($e):$h3`)};"
-              "   return h;"
-              "})"),
-      njs_str("d53400095496267cf02e5dbd4b0bf9fbfb5f36f311ea7d9809af5487421743e3,"
-              "1TQACVSWJnzwLl29Swv5+/tfNvMR6n2YCa9Uh0IXQ+M=,"
-              "1TQACVSWJnzwLl29Swv5-_tfNvMR6n2YCa9Uh0IXQ-M") },
+    { njs_str("{{}a >}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { njs_str("var hmac = require('crypto').createHmac;"
-              "njs.dump(['', 'abc'.repeat(100)].map(v => {"
-              "    return ['md5', 'sha1', 'sha256'].map(h => {"
-              "        return hmac(h, Buffer.from('secret')).update(v).digest('hex');"
-              "     })"
-              "}))"),
-      njs_str("[['5c8db03f04cec0f43bcb060023914190',"
-              "'25af6174a0fcecc4d346680a72b7ce644b9a88e8',"
-              "'f9e66e179b6747ae54108f82f8ade8b3c25d76fd30afde6c395822c530196169'],"
-              "['91eb74a225cdd3bbfccc34396c6e3ac5',"
-              "'0aac71e3a813a7acc4a809cfdedb2ecba04ffc5e',"
-              "'8660d2d51d6f20f61d5aadfb6c43df7fd05fc2fc4967d8aec1846f3d9ec03987']]") },
+    { njs_str("{{}a <}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { njs_str("var h = require('crypto').createHmac('sha1', '');"
-              "var Hmac = h.constructor; "
-              "Hmac('sha1', '').digest('hex')"),
-      njs_str("fbdb1d1b18aa6c08324b7d64b71fb76370690e1d") },
+    { njs_str("{{}a <=}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { njs_str("var h = require('crypto').createHmac('sha1', '');"
-              "h.constructor.name"),
-      njs_str("Hmac") },
+    { njs_str("{{}a &&}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { njs_str("require('crypto').createHmac('sha1', '').digest() instanceof Buffer"),
-      njs_str("true") },
+    { njs_str("{{}a ||}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { njs_str("var h = require('crypto').createHmac('sha256', 'A'.repeat(64));"
-              "h.update('AB').digest('hex')"),
-      njs_str("ee9dce43b12eb3e865614ad9c1a8d4fad4b6eac2b64647bd24cd192888d3f367") },
+    { njs_str("{{}a ??}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { njs_str("var h = require('crypto').createHmac('sha256', 'A'.repeat(100));"
-              "h.update('AB').digest('hex')"),
-      njs_str("5647b6c429701ff512f0f18232b4507065d2376ca8899a816a0a6e721bf8ddcc") },
+    { njs_str("{{}a &}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { njs_str("var h = require('crypto').createHmac()"),
-      njs_str("TypeError: algorithm must be a string") },
+    { njs_str("{{}a |}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { njs_str("var h = require('crypto').createHmac([])"),
-      njs_str("TypeError: algorithm must be a string") },
+    { njs_str("{{}a ^}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { njs_str("var h = require('crypto').createHmac('sha512', '')"),
-      njs_str("TypeError: not supported algorithm: \"sha512\"") },
+    { njs_str("{{}a <<}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { njs_str("var h = require('crypto').createHmac('sha1', [])"),
-      njs_str("TypeError: key argument \"array\" is not a string or Buffer-like object") },
+    { njs_str("{{}a >>}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { njs_str("var h = require('crypto').createHmac('sha1', 'secret key');"
-              "h.update('A').digest('hex'); h.digest('hex')"),
-      njs_str("Error: Digest already called") },
+    { njs_str("{{}new}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { njs_str("var h = require('crypto').createHmac('sha1', 'secret key');"
-              "h.update('A').digest('hex'); h.update('B')"),
-      njs_str("Error: Digest already called") },
+    { njs_str("{{}delete}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { njs_str("typeof require('crypto').createHmac('md5', 'a')"),
-      njs_str("object") },
+    { njs_str("{{}void}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { njs_str("var cr = require('crypto'); var h = cr.createHash('sha1');"
-              "h.update.call(cr.createHmac('sha1', 's'), '')"),
-      njs_str("TypeError: \"this\" is not a hash object") },
+    { njs_str("{{}typeof}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    /* setTimeout(). */
+    { njs_str("{{} ({a: 1, b: {}\n}\n})\n}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 3") },
 
-    { njs_str("setTimeout()"),
-      njs_str("TypeError: too few arguments") },
+    { njs_str("object?."),
+      njs_str("SyntaxError: Unexpected end of input in 1") },
 
-    { njs_str("setTimeout(function(){})"),
-      njs_str("InternalError: not supported by host environment") },
+    { njs_str("`${{a: 1, b}}`"),
+      njs_str("ReferenceError: \"b\" is not defined") },
 
-    { njs_str("setTimeout(function(){}, 12)"),
-      njs_str("InternalError: not supported by host environment") },
+    { njs_str("`${{a: 1, b:}}`"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    /* clearTimeout(). */
+    { njs_str("`${{a: 1, b:,}}`"),
+      njs_str("SyntaxError: Unexpected token \",\" in 1") },
 
-    { njs_str("clearTimeout()"),
-      njs_str("undefined") },
+    { njs_str("`${{a: 1, b: 2,}}`"),
+      njs_str("[object Object]") },
 
-    { njs_str("clearTimeout(123)"),
-      njs_str("undefined") },
+    { njs_str("`${{a: 1,, b: 2}}`"),
+      njs_str("SyntaxError: Unexpected token \",\" in 1") },
 
-    /* Trick: number to boolean. */
+    { njs_str("`${{f(){-} - {}}`"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { njs_str("var a = 0; !!a"),
-      njs_str("false") },
+    { njs_str("for (;1-;) {}"),
+      njs_str("SyntaxError: Unexpected token \";\" in 1") },
 
-    { njs_str("var a = 5; !!a"),
-      njs_str("true") },
+    { njs_str("var str = String(str); str"),
+      njs_str("undefined") },
 
-    /* Trick: flooring. */
+    { njs_str("var t = \"123\"; t = parseInt(t); t"),
+      njs_str("123") },
 
-    { njs_str("var n = -10.12345; ~~n"),
-      njs_str("-10") },
+    /* TextEncoder. */
 
-    { njs_str("var n = 10.12345; ~~n"),
-      njs_str("10") },
+    { njs_str("var en = new TextEncoder(); typeof en.encode()"),
+      njs_str("object") },
 
-    /* es5id: 8.2_A1_T1 */
-    /* es5id: 8.2_A1_T2 */
+    { njs_str("var en = new TextEncoder(); en.encode()"),
+      njs_str("") },
 
-    { njs_str("var x = null;"),
-      njs_str("undefined") },
+    { njs_str("var en = new TextEncoder(); var res = en.encode('α'); res"),
+      njs_str("206,177") },
 
-    /* es5id: 8.2_A2 */
+    { njs_str("var en = new TextEncoder(); var res = en.encode('α1α'); res[2]"),
+      njs_str("49") },
 
-    { njs_str("var null;"),
-      njs_str("SyntaxError: Unexpected token \"null\" in 1") },
+    { njs_str("var en = new TextEncoder(); en.encode(String.bytesFrom([0xCE]))"),
+      njs_str("239,191,189") },
 
-    /* es5id: 8.2_A3 */
+    { njs_str("var en = new TextEncoder();"
+              "en.encode(String.bytesFrom([0xCE, 0xB1, 0xCE]))"),
+      njs_str("206,177,239,191,189") },
 
-    { njs_str("typeof(null) === \"object\""),
-      njs_str("true") },
+    { njs_str("var en = new TextEncoder();"
+              "en.encode(String.bytesFrom([0xCE, 0xCE, 0xB1]))"),
+      njs_str("239,191,189,206,177") },
 
-    /* Module. */
+    { njs_str("var en = new TextEncoder(); en.encoding"),
+      njs_str("utf-8") },
 
-    { njs_str("import;"),
-      njs_str("SyntaxError: Non-default import is not supported in 1") },
+    { njs_str("TextEncoder.prototype.encode.apply({}, [])"),
+      njs_str("TypeError: \"this\" is not a TextEncoder") },
 
-    { njs_str("import {x} from y"),
-      njs_str("SyntaxError: Non-default import is not supported in 1") },
+    { njs_str("var en = new TextEncoder();"
+              "var utf8 = new Uint8Array(5);"
+              "var res = en.encodeInto('ααααα', utf8); njs.dump(res)"),
+      njs_str("{read:2,written:4}") },
 
-    { njs_str("import x from y"),
-      njs_str("SyntaxError: Unexpected token \"y\" in 1") },
+    { njs_str("var en = new TextEncoder();"
+              "var utf8 = new Uint8Array(10);"
+              "var res = en.encodeInto('ααααα', utf8); njs.dump(res)"),
+      njs_str("{read:5,written:10}") },
 
-    { njs_str("import x from {"),
-      njs_str("SyntaxError: Unexpected token \"{\" in 1") },
+    { njs_str("var en = new TextEncoder();"
+              "var utf8 = new Uint8Array(10);"
+              "en.encodeInto('ααααα', utf8.subarray(2)); utf8[0]"),
+      njs_str("0") },
 
-    { njs_str("import x from ''"),
-      njs_str("SyntaxError: Cannot find module \"\" in 1") },
+    { njs_str("var str = String.bytesFrom([0xCE]);"
+              "var en = new TextEncoder();"
+              "var utf8 = new Uint8Array(3);"
+              "var res = en.encodeInto(str, utf8); "
+              "[njs.dump(res), utf8]"),
+      njs_str("{read:1,written:3},239,191,189") },
 
-    { njs_str("import x from 'crypto'"),
-      njs_str("undefined") },
-
-    { njs_str("import x from 'crypto' 1"),
-      njs_str("SyntaxError: Unexpected token \"1\" in 1") },
+    { njs_str("var str = String.bytesFrom([0xCE]);"
+              "var en = new TextEncoder();"
+              "var utf8 = new Uint8Array(5);"
+              "en.encodeInto(str, utf8); utf8"),
+      njs_str("239,191,189,0,0") },
 
-    { njs_str("if (1) {import x from 'crypto'}"),
-      njs_str("SyntaxError: Illegal import statement in 1") },
+    { njs_str("var str = String.bytesFrom([0xCE, 0xB1, 0xCE]);"
+              "var en = new TextEncoder();"
+              "var utf8 = new Uint8Array(5);"
+              "var res = en.encodeInto(str, utf8);"
+              "[njs.dump(res), utf8]"),
+      njs_str("{read:2,written:5},206,177,239,191,189") },
 
-    { njs_str("export"),
-      njs_str("SyntaxError: Illegal export statement in 1") },
+    { njs_str("var str = String.bytesFrom([0xCE, 0xCE, 0xB1]);"
+              "var en = new TextEncoder();"
+              "var utf8 = new Uint8Array(5);"
+              "var res = en.encodeInto(str, utf8);"
+              "[njs.dump(res), utf8]"),
+      njs_str("{read:2,written:5},239,191,189,206,177") },
 
-    { njs_str("Object.assign(undefined)"),
-      njs_str("TypeError: cannot convert null or undefined to object") },
+    { njs_str("TextEncoder.prototype.encodeInto.apply({}, [])"),
+      njs_str("TypeError: \"this\" is not a TextEncoder") },
 
-    { njs_str("Object.assign(null)"),
-      njs_str("TypeError: cannot convert null or undefined to object") },
+    { njs_str("(new TextEncoder()).encodeInto('', 0.12) "),
+      njs_str("TypeError: The \"destination\" argument must be an instance of Uint8Array") },
 
-    { njs_str("Object.assign({x:123}).toString()"),
-      njs_str("[object Object]") },
+    /* TextDecoder. */
 
-    { njs_str("Object.assign({x:123}).x"),
-      njs_str("123") },
+    { njs_str("var de = new TextDecoder();"
+              "var u8arr = new Uint8Array([240, 160, 174, 183]);"
+              "var u16arr = new Uint16Array(u8arr.buffer);"
+              "var u32arr = new Uint32Array(u8arr.buffer);"
+              "[u8arr, u16arr, u32arr].map(v=>de.decode(v)).join(',')"),
+      njs_str("𠮷,𠮷,𠮷") },
 
-    { njs_str("Object.assign(true)"),
-      njs_str("true") },
+    { njs_str("var de = new TextDecoder();"
+              "[new Uint8Array([240, 160]), "
+              " new Uint8Array([174]), "
+              " new Uint8Array([183])].map(v=>de.decode(v, {stream: 1}))[2]"),
+      njs_str("𠮷") },
 
-    { njs_str("Object.assign(123)"),
-      njs_str("123") },
+    { njs_str("var de = new TextDecoder();"
+              "de.decode(new Uint8Array([240, 160]), {stream: 1});"
+              "de.decode(new Uint8Array([174]), {stream: 1});"
+              "de.decode(new Uint8Array([183]))"),
+      njs_str("𠮷") },
 
-    { njs_str("var o1 = {a:1, b:1, c:1}; var o2 = {b:2, c:2}; "
-                 "var o3 = {c:3}; var obj = Object.assign({}, o1, o2, o3); "
-                 "Object.values(obj);"),
-      njs_str("1,2,3") },
+    { njs_str("var de = new TextDecoder();"
+              "de.decode(new Uint8Array([240, 160]), {stream: 1});"
+              "de.decode()"),
+      njs_str("") },
 
-    { njs_str("var v1 = 'abc'; var v2 = true; var v3 = 10; "
-                 "var obj = Object.assign({}, v1, null, v2, undefined, v3); "
-                 "Object.values(obj);"),
-      njs_str("a,b,c") },
+    { njs_str("var de = new TextDecoder('utf-8', {fatal: true});"
+              "de.decode(new Uint8Array([240, 160]))"),
+      njs_str("TypeError: The encoded data was not valid") },
 
-    { njs_str("Object.assign(true, {a:123})"),
-      njs_str("true") },
+    { njs_str("var de = new TextDecoder('utf-8', {fatal: false});"
+              "de.decode(new Uint8Array([240, 160]))"),
+      njs_str("�") },
 
-    { njs_str("Object.assign(true, {a:123}).a"),
-      njs_str("123") },
+    { njs_str("var en = new TextEncoder();"
+              "var de = new TextDecoder('utf-8', {ignoreBOM: true});"
+              "en.encode(de.decode(new Uint8Array([239, 187, 191, 50])))"),
+      njs_str("239,187,191,50") },
 
-    { njs_str("var y = Object.create({s:123}); y.z = 456;"
-                 "Object.assign({}, y).s;"),
-      njs_str("undefined") },
+    { njs_str("var en = new TextEncoder();"
+              "var de = new TextDecoder('utf-8', {ignoreBOM: false});"
+              "en.encode(de.decode(new Uint8Array([239, 187, 191, 50])))"),
+      njs_str("50") },
 
-    { njs_str("var obj = {s:123}; Object.defineProperty(obj,"
-                 "'p1', {value:12, enumerable:false});"
-                 "Object.assign({}, obj).p1"),
-      njs_str("undefined") },
+    { njs_str("var en = new TextEncoder(); var de = new TextDecoder();"
+              "en.encode(de.decode(new Uint8Array([239, 187, 191, 50])))"),
+      njs_str("50") },
 
-    { njs_str("var obj = {s:123}; Object.defineProperty(obj,"
-                 "'x', {value:12, writable:false});"
-                 "Object.assign(obj, {x:4})"),
-      njs_str("TypeError: Cannot assign to read-only property \"x\" of object") },
+    { njs_str("var de = new TextDecoder(); de.decode('')"),
+      njs_str("TypeError: The \"input\" argument must be an instance of TypedArray") },
 
-    { njs_str("var obj = {foo:1, get bar() {return 2;}};"
-                 "var copy = Object.assign({}, obj);"
-                 "Object.getOwnPropertyDescriptor(copy, 'bar').get"),
-      njs_str("undefined") },
+    { njs_str("var de = new TextDecoder({})"),
+      njs_str("RangeError: The \"[object Object]\" encoding is not supported") },
 
-    { njs_str("try{var x = Object.defineProperty({}, 'foo',"
-                 "{value:1, writable:false});"
-                 "Object.assign(x, {bar:2}, {foo:2});}catch(error){};"
-                 "x.bar"),
-      njs_str("2") },
+    { njs_str("var de = new TextDecoder('foo')"),
+      njs_str("RangeError: The \"foo\" encoding is not supported") },
 
-    { njs_str("var a = Object.defineProperty({}, 'a',"
-                 "{get(){Object.defineProperty(this, 'b',"
-                 "{value:2,enumerable:false});"
-                 "return 1}, enumerable:1}); a.b =1;"
-                 "var x = Object.assign({}, a);x.b;"),
-      njs_str("undefined") },
+    { njs_str("var de = new TextDecoder(); de.encoding"),
+      njs_str("utf-8") },
 
-    /* let and const */
+    { njs_str("var de = new TextDecoder(); de.fatal"),
+      njs_str("false") },
 
-    { njs_str("var let = 123;"
-              "let"),
-      njs_str("SyntaxError: Unexpected token \"let\" in 1") },
+    { njs_str("var de = new TextDecoder(); de.ignoreBOM"),
+      njs_str("false") },
 
-    { njs_str("var const = 123"),
-      njs_str("SyntaxError: Unexpected token \"const\" in 1") },
+    { njs_str("TextDecoder.prototype.decode.apply({}, new Uint8Array([1]))"),
+      njs_str("TypeError: \"this\" is not a TextDecoder") },
 
-    /* Async */
+    { njs_str("var de = new TextDecoder();"
+              "var buf = new Uint32Array([1,2,3]).buffer;"
+              "var en = new TextEncoder();"
+              "njs.dump(new Uint32Array(en.encode(de.decode(buf)).buffer))"),
+      njs_str("Uint32Array [1,2,3]") },
 
-    { njs_str("var async;"
-              "function f() {"
-              "    async\n"
-              "    function foo() {}"
-              "}"
-              "f()"),
-      njs_str("undefined") },
+    { njs_str("var de = new TextDecoder();"
+              "var buf = new Uint32Array([1,2,3]).subarray(1,2);"
+              "var en = new TextEncoder();"
+              "njs.dump(new Uint32Array(en.encode(de.decode(buf)).buffer))"),
+      njs_str("Uint32Array [2]") },
 
-    { njs_str("var async;"
-              "function f() {"
-              "    async;"
-              "    function foo() {}"
-              "}"
-              "f()"),
-      njs_str("undefined") },
+    /* let */
 
-    { njs_str("var async;"
-              "async\n"
-              "function foo() {}"),
+    { njs_str("let x"),
       njs_str("undefined") },
 
-    { njs_str("new\""),
-      njs_str("SyntaxError: Unterminated string \"\"\" in 1") },
+    { njs_str("let x = 123; x"),
+      njs_str("123") },
 
-    { njs_str("new\"\\UFFFF"),
-      njs_str("SyntaxError: Unterminated string \"\"\\UFFFF\" in 1") },
+    { njs_str("let x = [123]; x"),
+      njs_str("123") },
 
-    { njs_str("new/la"),
-      njs_str("SyntaxError: Unterminated RegExp \"/la\" in 1") },
+    { njs_str("let x = () => x; x()"),
+      njs_str("[object Function]") },
 
-    { njs_str("{name; {/ / /}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("let x = (() => x)()"),
+      njs_str("ReferenceError: cannot access variable before initialization") },
 
-    { njs_str("[(]"),
-      njs_str("SyntaxError: Unexpected token \"]\" in 1") },
+    { njs_str("x; let x"),
+      njs_str("ReferenceError: cannot access variable before initialization") },
 
-    { njs_str("[...]"),
-      njs_str("SyntaxError: Unexpected token \"]\" in 1") },
+    { njs_str("x; let x = 123"),
+      njs_str("ReferenceError: cannot access variable before initialization") },
 
-    { njs_str("switch () {}"),
-      njs_str("SyntaxError: Unexpected token \")\" in 1") },
+    { njs_str("let x = x + 123"),
+      njs_str("ReferenceError: cannot access variable before initialization") },
 
-    { njs_str("switch ([(]) {}"),
-      njs_str("SyntaxError: Unexpected token \"]\" in 1") },
+    { njs_str("let x = (x, 1)"),
+      njs_str("ReferenceError: cannot access variable before initialization") },
 
-    { njs_str("{{}{-}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("let x = x"),
+      njs_str("ReferenceError: cannot access variable before initialization") },
 
-    { njs_str("{{}{+}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("let x; var x"),
+      njs_str("SyntaxError: \"x\" has already been declared in 1") },
 
-    { njs_str("{{}{delete}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("var x; let x"),
+      njs_str("SyntaxError: \"x\" has already been declared in 1") },
 
-    { njs_str("{{}{++}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("let x; function x() {}"),
+      njs_str("SyntaxError: \"x\" has already been declared in 1") },
 
-    { njs_str("{{}{++1}"),
-      njs_str("ReferenceError: Invalid left-hand side in prefix operation in 1") },
+    { njs_str("function x() {} let x"),
+      njs_str("SyntaxError: \"x\" has already been declared in 1") },
 
-    { njs_str("{{}{1++}"),
-      njs_str("ReferenceError: Invalid left-hand side in postfix operation in 1") },
+    { njs_str("function x() {let x; var x}"),
+      njs_str("SyntaxError: \"x\" has already been declared in 1") },
 
-    { njs_str("{{}{1/}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("function x() {var x; let x}"),
+      njs_str("SyntaxError: \"x\" has already been declared in 1") },
 
-    { njs_str("{{}{1>>}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("var x = function f() {let f}"),
+      njs_str("undefined") },
 
-    { njs_str("{{}{r=}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("let a; let x = 1;"
+              "{let x = 2; a = x}"
+              "[x, a]"),
+      njs_str("1,2") },
 
-    { njs_str("{{}{var a = }"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("let a; let x = 1;"
+              "if (true) {let x = 2; a = x}"
+              "[x, a]"),
+      njs_str("1,2") },
 
-    { njs_str("{{}T=>}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("var a = 5, b = 10, arr = [];"
+              "{let a = 4; var b = 1; arr.push(a); arr.push(b)}"
+              "arr.push(a); arr.push(b); arr"),
+      njs_str("4,1,5,1") },
 
-    { njs_str("{{}a = b +}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("function func() {return x}"
+              "let x = 123;"
+              "func()"),
+      njs_str("123") },
 
-    { njs_str("{{}a = b -}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("function func() {return x}"
+              "func();"
+              "let x = 123"),
+      njs_str("ReferenceError: cannot access variable before initialization") },
 
-    { njs_str("{{}a = b *}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("function func() {return () => x}"
+              "let x = 123;"
+              "func()()"),
+      njs_str("123") },
 
-    { njs_str("{{}a = b /}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("function func() {x = x + 1; let x}"),
+      njs_str("undefined") },
 
-    { njs_str("{{}a = b %}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("function func() {return () => x}"
+              "func()();"
+              "let x = 123;"),
+      njs_str("ReferenceError: cannot access variable before initialization") },
 
-    { njs_str("{{}a = b++}"),
-      njs_str("ReferenceError: \"a\" is not defined") },
+    { njs_str("var arr = [];"
+              ""
+              "for (var i = 0; i < 10; i++) {"
+              "    let x = i;"
+              ""
+              "    arr.push( (n) => {x += n; return x} );"
+              "}"
+              ""
+              "["
+              "    arr[0](2), arr[1](1), arr[2](4), arr[3](7), arr[4](0),"
+              "    arr[5](1), arr[6](2), arr[7](5), arr[8](8), arr[9](10)"
+              "]"),
+      njs_str("2,2,6,10,4,6,8,12,16,19") },
 
-    { njs_str("{{}a = b--}"),
-      njs_str("ReferenceError: \"a\" is not defined") },
+    { njs_str("var arr = [];"
+              ""
+              "for (let i = 0; i < 10; i++) {"
+              "    arr.push( (n) => {i += n; return i} );"
+              "}"
+              ""
+              "["
+              "    arr[0](2), arr[1](1), arr[2](4), arr[3](7), arr[4](0),"
+              "    arr[5](1), arr[6](2), arr[7](5), arr[8](8), arr[9](10)"
+              "]"),
+      njs_str("2,2,6,10,4,6,8,12,16,19") },
 
-    { njs_str("{{}a =}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("for (let i = 0; i < 1; i++) {"
+              "    let i = i + 2;"
+              "}"),
+      njs_str("ReferenceError: cannot access variable before initialization") },
 
-    { njs_str("{{}a +=}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("let arr = [], res = [];"
+              "for (let i = 0, f = function() { return i }; i < 5; i++) {"
+              "    arr.push(f);"
+              "}"
+              "for (let i = 0; i < 5; i++) {"
+              "    res.push(arr[i]());"
+              "} res"),
+      njs_str("0,0,0,0,0") },
 
-    { njs_str("{{}a -=}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("let arr = [], res = [];"
+              "for (let i = 0; arr.push(() => i), i < 10; i++) {}"
+              "for (let k = 0; k < 10; k++) {res.push(arr[k]())}"
+              "res"),
+      njs_str("0,1,2,3,4,5,6,7,8,9") },
 
-    { njs_str("{{}a *=}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("let res = [];"
+              "for (let n in [1,2,3]) {res.push(n)}"
+              "res"),
+      njs_str("0,1,2") },
 
-    { njs_str("{{}a /=}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("let arr = [], res = [];"
+              ""
+              "for (let n in [1,2,3]) {"
+              "    arr.push(() => n);"
+              "}"
+              ""
+              "for (let n in arr) {"
+              "    res.push(arr[n]());"
+              "}"
+              "res"),
+      njs_str("0,1,2") },
 
-    { njs_str("{{}a %=}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("let arr = [];"
+              ""
+              "for (let n in [1,2,3]) {"
+              "    let n = 1;"
+              "    arr.push(n);"
+              "}"
+              "arr"),
+      njs_str("1,1,1") },
 
-    { njs_str("{{}a ===}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("for (let n in [1,2,3]) {"
+              "    let n = n + 1;"
+              "}"),
+      njs_str("ReferenceError: cannot access variable before initialization") },
 
-    { njs_str("{{}a ==}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("for (let n in [1,2,3]) {}"
+              "n"),
+      njs_str("ReferenceError: \"n\" is not defined") },
 
-    { njs_str("{{}a !=}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("for (let n in [1,n,3]) {}"),
+      njs_str("ReferenceError: cannot access variable before initialization") },
 
-    { njs_str("{{}a !==}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("(function() {"
+              "function f() {return x + 1}"
+              "function abc() {f()};"
+              "abc();"
+              "let x;"
+              "}())"),
+      njs_str("ReferenceError: cannot access variable before initialization") },
 
-    { njs_str("{{}a >}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("function func() {var x = 1; {let x = x + 1} } func()"),
+      njs_str("ReferenceError: cannot access variable before initialization") },
 
-    { njs_str("{{}a <}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("if (false) let x = 1"),
+      njs_str("SyntaxError: let declaration cannot appear in a single-statement context in 1") },
 
-    { njs_str("{{}a <=}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("while (false) let x = 1"),
+      njs_str("SyntaxError: let declaration cannot appear in a single-statement context in 1") },
 
-    { njs_str("{{}a &&}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("for (;;) let x = 1"),
+      njs_str("SyntaxError: let declaration cannot appear in a single-statement context in 1") },
 
-    { njs_str("{{}a ||}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("try {} catch (e) {let e}"),
+      njs_str("SyntaxError: \"e\" has already been declared in 1") },
 
-    { njs_str("{{}a ??}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("let arr = [], x = 2;"
+              "switch(true) {default: let x = 1; arr.push(x)}"
+              "arr.push(x); arr"),
+      njs_str("1,2") },
 
-    { njs_str("{{}a &}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("switch(true) {case false: let x = 1; default: x = 2}"),
+      njs_str("ReferenceError: cannot access variable before initialization") },
 
-    { njs_str("{{}a |}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("let res;"
+              "switch(true) {case true: let x = 1; default: x = 2; res = x} res"),
+      njs_str("2") },
 
-    { njs_str("{{}a ^}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("let null"),
+      njs_str("SyntaxError: Unexpected token \"null\" in 1") },
 
-    { njs_str("{{}a <<}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("let continue"),
+      njs_str("SyntaxError: Unexpected token \"continue\" in 1") },
 
-    { njs_str("{{}a >>}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("let undefined"),
+      njs_str("SyntaxError: \"undefined\" has already been declared in 1") },
 
-    { njs_str("{{}new}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("let a = 1; globalThis.a"),
+      njs_str("undefined") },
 
-    { njs_str("{{}delete}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("if (false) {x = 2} else {x = 1} let x;"),
+      njs_str("ReferenceError: cannot access variable before initialization") },
 
-    { njs_str("{{}void}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("let let"),
+      njs_str("SyntaxError: Unexpected token \"let\" in 1") },
 
-    { njs_str("{{}typeof}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("let null"),
+      njs_str("SyntaxError: Unexpected token \"null\" in 1") },
 
-    { njs_str("{{} ({a: 1, b: {}\n}\n})\n}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 3") },
+    { njs_str("function let() {}"),
+      njs_str("SyntaxError: Unexpected token \"let\" in 1") },
 
-    { njs_str("object?."),
-      njs_str("SyntaxError: Unexpected end of input in 1") },
+    { njs_str("function static() {}"),
+      njs_str("SyntaxError: Unexpected token \"static\" in 1") },
 
-    { njs_str("`${{a: 1, b}}`"),
-      njs_str("ReferenceError: \"b\" is not defined") },
+    /* const */
 
-    { njs_str("`${{a: 1, b:}}`"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("const x"),
+      njs_str("SyntaxError: missing initializer in const declaration") },
 
-    { njs_str("`${{a: 1, b:,}}`"),
-      njs_str("SyntaxError: Unexpected token \",\" in 1") },
+    { njs_str("const x = 1; x"),
+      njs_str("1") },
 
-    { njs_str("`${{a: 1, b: 2,}}`"),
-      njs_str("[object Object]") },
+    { njs_str("const x = 1; x = 1"),
+      njs_str("TypeError: assignment to constant variable") },
 
-    { njs_str("`${{a: 1,, b: 2}}`"),
-      njs_str("SyntaxError: Unexpected token \",\" in 1") },
+    { njs_str("function abc() {const x}"),
+      njs_str("SyntaxError: missing initializer in const declaration") },
 
-    { njs_str("`${{f(){-} - {}}`"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("const x = [123]; x"),
+      njs_str("123") },
 
-    { njs_str("for (;1-;) {}"),
-      njs_str("SyntaxError: Unexpected token \";\" in 1") },
+    { njs_str("const x = () => x; x()"),
+      njs_str("[object Function]") },
 
-    { njs_str("var str = String(str); str"),
-      njs_str("undefined") },
+    { njs_str("const x = (() => x)()"),
+      njs_str("ReferenceError: cannot access variable before initialization") },
 
-    { njs_str("var t = \"123\"; t = parseInt(t); t"),
-      njs_str("123") },
+    { njs_str("x; const x = 123"),
+      njs_str("ReferenceError: cannot access variable before initialization") },
 
-    /* Query String */
+    { njs_str("const x = x + 123"),
+      njs_str("ReferenceError: cannot access variable before initialization") },
 
-    { njs_str("var qs = require('querystring');"
-              "var obj = qs.parse('baz=fuz');"
-              "njs.dump(obj)"),
-      njs_str("{baz:'fuz'}") },
+    { njs_str("const x; var x"),
+      njs_str("SyntaxError: \"x\" has already been declared in 1") },
 
-    { njs_str("var qs = require('querystring');"
-              "var obj = qs.parse('baz=');"
-              "njs.dump(obj)"),
-      njs_str("{baz:''}") },
+    { njs_str("const x; let x"),
+      njs_str("SyntaxError: \"x\" has already been declared in 1") },
 
-    { njs_str("var qs = require('querystring');"
-              "var obj = qs.parse('baz=fuz&muz=tax');"
-              "njs.dump(obj)"),
-      njs_str("{baz:'fuz',muz:'tax'}") },
+    { njs_str("let x; const x"),
+      njs_str("SyntaxError: \"x\" has already been declared in 1") },
 
-    { njs_str("var qs = require('querystring');"
-              "var obj = qs.parse('baz=fuz&');"
-              "njs.dump(obj)"),
-      njs_str("{baz:'fuz'}") },
+    { njs_str("const x = 1; function x() {}"),
+      njs_str("SyntaxError: \"x\" has already been declared in 1") },
 
-    { njs_str("var qs = require('querystring');"
-              "var obj = qs.parse('&baz=fuz');"
-              "njs.dump(obj)"),
-      njs_str("{baz:'fuz'}") },
+    { njs_str("function x() {} const x = 1"),
+      njs_str("SyntaxError: \"x\" has already been declared in 1") },
 
-    { njs_str("var qs = require('querystring');"
-              "var obj = qs.parse('&&&&&baz=fuz');"
-              "njs.dump(obj)"),
-      njs_str("{baz:'fuz'}") },
+    { njs_str("function x() {const x; var x}"),
+      njs_str("SyntaxError: \"x\" has already been declared in 1") },
 
-    { njs_str("var qs = require('querystring');"
-              "var obj = qs.parse('=fuz');"
-              "njs.dump(obj)"),
-      njs_str("{:'fuz'}") },
+    { njs_str("function x() {var x; const x}"),
+      njs_str("SyntaxError: \"x\" has already been declared in 1") },
 
-    { njs_str("var qs = require('querystring');"
-              "var obj = qs.parse('=fuz=');"
-              "njs.dump(obj)"),
-      njs_str("{:'fuz='}") },
+    { njs_str("const x = function f() {const f = 1}"),
+      njs_str("undefined") },
 
-    { njs_str("var qs = require('querystring');"
-              "var obj = qs.parse('===fu=z');"
-              "njs.dump(obj)"),
-      njs_str("{:'==fu=z'}") },
+    { njs_str("let res; const x = 1;"
+              "{const x = 2; res = x}"
+              "[x, res]"),
+      njs_str("1,2") },
 
-    { njs_str("var qs = require('querystring');"
-              "var obj = qs.parse('baz=fuz&baz=tax');"
-              "njs.dump(obj)"),
-      njs_str("{baz:['fuz','tax']}") },
+    { njs_str("let res; const x = 1;"
+              "if (true) {const x = 2; res = x}"
+              "[x, res]"),
+      njs_str("1,2") },
 
-    { njs_str("var qs = require('querystring');"
-              "var obj = qs.parse('freespace');"
-              "njs.dump(obj)"),
-      njs_str("{freespace:''}") },
+    { njs_str("function func() {return x}"
+              "const x = 123;"
+              "func()"),
+      njs_str("123") },
 
-    { njs_str("var qs = require('querystring');"
-              "var obj = qs.parse('name&value=12');"
-              "njs.dump(obj)"),
-      njs_str("{name:'',value:'12'}") },
+    { njs_str("function func() {return x}"
+              "func();"
+              "const x = 123"),
+      njs_str("ReferenceError: cannot access variable before initialization") },
 
-    { njs_str("var qs = require('querystring');"
-              "var obj = qs.parse('baz=fuz&muz=tax', 'fuz');"
-              "njs.dump(obj)"),
-      njs_str("{baz:'',&muz:'tax'}") },
+    { njs_str("function func() {return () => x}"
+              "const x = 123;"
+              "func()()"),
+      njs_str("123") },
 
-    { njs_str("var qs = require('querystring');"
-              "var obj = qs.parse('baz=fuz&muz=tax', '');"
-              "njs.dump(obj)"),
-      njs_str("{baz:'fuz',muz:'tax'}") },
+    { njs_str("function func() {return () => x++}"
+              "const x = 123;"
+              "func()()"),
+      njs_str("TypeError: assignment to constant variable") },
 
-    { njs_str("var qs = require('querystring');"
-              "var obj = qs.parse('baz=fuz&muz=tax', null);"
-              "njs.dump(obj)"),
-      njs_str("{baz:'fuz',muz:'tax'}") },
+    { njs_str("for (const i = 0; i < 1; i++) {}"),
+      njs_str("TypeError: assignment to constant variable") },
 
-    { njs_str("var qs = require('querystring');"
-              "var obj = qs.parse('baz=fuz&muz=tax', undefined);"
-              "njs.dump(obj)"),
-      njs_str("{baz:'fuz',muz:'tax'}") },
+    { njs_str("let res = [];"
+              "for (const n in [1,2,3]) {res.push(n)}"
+              "res"),
+      njs_str("0,1,2") },
 
-    { njs_str("var qs = require('querystring');"
-              "var obj = qs.parse('baz=fuz123muz=tax', 123);"
-              "njs.dump(obj)"),
-      njs_str("{baz:'fuz',muz:'tax'}") },
+    { njs_str("let arr = [], res = [];"
+              ""
+              "for (const n in [1,2,3]) {"
+              "    arr.push(() => n);"
+              "}"
+              ""
+              "for (let n in arr) {"
+              "    res.push(arr[n]());"
+              "}"
+              "res"),
+      njs_str("0,1,2") },
 
-    { njs_str("var qs = require('querystring');"
-              "var obj = qs.parse('baz=fuzαααmuz=tax', 'ααα');"
-              "njs.dump(obj)"),
-      njs_str("{baz:'fuz',muz:'tax'}") },
+    { njs_str("let arr = [];"
+              ""
+              "for (const n in [1,2,3]) {"
+              "    let n = 1;"
+              "    arr.push(n);"
+              "}"
+              "arr"),
+      njs_str("1,1,1") },
 
-    { njs_str("var qs = require('querystring');"
-              "var obj = qs.parse('baz=fuz&muz=tax', '=');"
-              "njs.dump(obj)"),
-      njs_str("{baz:'',fuz&muz:'',tax:''}") },
+    { njs_str("for (const n in [1,2,3]) {"
+              "    let n = n + 1;"
+              "}"),
+      njs_str("ReferenceError: cannot access variable before initialization") },
 
-    { njs_str("var qs = require('querystring');"
-              "var obj = qs.parse('baz=fuz&muz=tax', null, 'fuz');"
-              "njs.dump(obj)"),
-      njs_str("{baz=:'',muz=tax:''}") },
+    { njs_str("for (const n in [1,2,3]) {}"
+              "n"),
+      njs_str("ReferenceError: \"n\" is not defined") },
 
-    { njs_str("var qs = require('querystring');"
-              "var obj = qs.parse('baz=fuz&muz=tax', null, '&');"
-              "njs.dump(obj)"),
-      njs_str("{baz=fuz:'',muz=tax:''}") },
+    { njs_str("for (const n in [1,n,3]) {}"),
+      njs_str("ReferenceError: cannot access variable before initialization") },
 
-    { njs_str("var qs = require('querystring');"
-              "var obj = qs.parse('baz123fuz&muz123tax', null, 123);"
-              "njs.dump(obj)"),
-      njs_str("{baz:'fuz',muz:'tax'}") },
+    { njs_str("(function() {"
+              "function f() {return x + 1}"
+              "function abc() {f()};"
+              "abc();"
+              "const x = 1;"
+              "}())"),
+      njs_str("ReferenceError: cannot access variable before initialization") },
 
-    { njs_str("var qs = require('querystring');"
-              "var obj = qs.parse('bazαααfuz&muzαααtax', null, 'ααα');"
-              "njs.dump(obj)"),
-      njs_str("{baz:'fuz',muz:'tax'}") },
+    { njs_str("if (false) const x = 1"),
+      njs_str("SyntaxError: const declaration cannot appear in a single-statement context in 1") },
 
-    { njs_str("var qs = require('querystring');"
-              "var obj = qs.parse('baz=fuz&muz=tax', null, null, {maxKeys: 1});"
-              "njs.dump(obj)"),
-      njs_str("{baz:'fuz'}") },
+    { njs_str("while (false) const x = 1"),
+      njs_str("SyntaxError: const declaration cannot appear in a single-statement context in 1") },
 
-    { njs_str("var qs = require('querystring'); var out = [];"
-              "var obj = qs.parse('baz=fuz&muz=tax', null, null, {decodeURIComponent: (key) => {out.push(key)}});"
-              "out.join('; ');"),
-      njs_str("baz; fuz; muz; tax") },
+    { njs_str("for (;;) const x = 1"),
+      njs_str("SyntaxError: const declaration cannot appear in a single-statement context in 1") },
 
-    { njs_str("var qs = require('querystring'); var i = 0;"
-              "var obj = qs.parse('baz=fuz&muz=tax', null, null, {decodeURIComponent: (key) => 'α' + i++});"
-              "njs.dump(obj);"),
-      njs_str("{α0:'α1',α2:'α3'}") },
+    { njs_str("try {} catch (e) {const e = 1}"),
+      njs_str("SyntaxError: \"e\" has already been declared in 1") },
 
-    { njs_str("var qs = require('querystring');"
-              "qs.parse('baz=fuz&muz=tax', null, null, {decodeURIComponent: 123});"),
-      njs_str("TypeError: option decodeURIComponent is not a function") },
+    { njs_str("let arr = []; const x = 2;"
+              "switch(true) {default: const x = 1; arr.push(x)}"
+              "arr.push(x); arr"),
+      njs_str("1,2") },
 
-    { njs_str("var qs = require('querystring');"
-              "qs.unescape = 123;"
-              "qs.parse('baz=fuz&muz=tax');"),
-    njs_str("TypeError: QueryString.unescape is not a function") },
+    { njs_str("let res;"
+              "switch(true) {case true: const x = 1; default: x = 2; res = x} res"),
+      njs_str("TypeError: assignment to constant variable") },
 
-    { njs_str("var qs = require('querystring'); var out = [];"
-              "qs.unescape = (key) => {out.push(key)};"
-              "qs.parse('baz=fuz&muz=tax');"
-              "out.join('; ');"),
-      njs_str("baz; fuz; muz; tax") },
+    { njs_str("const null"),
+      njs_str("SyntaxError: Unexpected token \"null\" in 1") },
 
-    { njs_str("var qs = require('querystring');"
-              "var obj = qs.parse('ba%32z=f%32uz');"
-              "njs.dump(obj)"),
-      njs_str("{ba2z:'f2uz'}") },
+    { njs_str("const continue"),
+      njs_str("SyntaxError: Unexpected token \"continue\" in 1") },
 
-    { njs_str("var qs = require('querystring');"
-              "var obj = qs.parse('ba%32z=f%32uz');"
-              "njs.dump(obj)"),
-      njs_str("{ba2z:'f2uz'}") },
+    { njs_str("const undefined"),
+      njs_str("SyntaxError: \"undefined\" has already been declared in 1") },
 
-    { njs_str("var qs = require('querystring');"
-              "var obj = qs.parse('ba%F0%9F%92%A9z=f%F0%9F%92%A9uz');"
-              "njs.dump(obj)"),
-      njs_str("{ba💩z:'f💩uz'}") },
+    { njs_str("const a = 1; globalThis.a"),
+      njs_str("undefined") },
 
-    { njs_str("var qs = require('querystring');"
-              "var obj = qs.parse('======');"
-              "njs.dump(obj)"),
-      njs_str("{:'====='}") },
+    { njs_str("if (false) {x = 2} else {x = 1} const x = 0"),
+      njs_str("ReferenceError: cannot access variable before initialization") },
 
-    { njs_str("var qs = require('querystring');"
-              "var obj = qs.parse('baz=%F0%9F%A9');"
-              "njs.dump(obj)"),
-      njs_str("{baz:'�'}") },
+    { njs_str("const const"),
+      njs_str("SyntaxError: Unexpected token \"const\" in 1") },
 
-    { njs_str("var qs = require('querystring');"
-              "var obj = qs.parse('baz=αααααα%\x00\x01\x02αααα');"
-              "njs.dump(obj)"),
-      njs_str("{baz:'αααααα%\\u0000\\u0001\\u0002αααα'}") },
+    /* Async/Await */
 
-    { njs_str("var qs = require('querystring');"
-              "var obj = qs.parse('baz=%F6α');"
-              "njs.dump(obj)"),
-      njs_str("{baz:'�α'}") },
+    { njs_str("async function f() {}; f.prototype"),
+      njs_str("undefined") },
 
-    { njs_str("var qs = require('querystring');"
-              "var obj = qs.parse('baz=%F6');"
-              "njs.dump(obj)"),
-      njs_str("{baz:'�'}") },
+    { njs_str("async function f() {await 1}"),
+      njs_str("undefined") },
 
-    { njs_str("var qs = require('querystring');"
-              "var obj = qs.parse('baz=%FG');"
-              "njs.dump(obj)"),
-      njs_str("{baz:'%FG'}") },
+    { njs_str("function f() {await 1}"),
+      njs_str("SyntaxError: await is only valid in async functions in 1") },
 
-    { njs_str("var qs = require('querystring');"
-              "var obj = qs.parse('baz=%F');"
-              "njs.dump(obj)"),
-      njs_str("{baz:'%F'}") },
+    { njs_str("async function f() {function a() {await 1}}"),
+      njs_str("SyntaxError: await is only valid in async functions in 1") },
 
-    { njs_str("var qs = require('querystring');"
-              "var obj = qs.parse('baz=%');"
-              "njs.dump(obj)"),
-      njs_str("{baz:'%'}") },
+    { njs_str("async function f() {() => {await 1}}"),
+      njs_str("SyntaxError: await is only valid in async functions in 1") },
 
-    { njs_str("var qs = require('querystring');"
-              "var obj = qs.parse('ba+z=f+uz');"
-              "njs.dump(obj)"),
-      njs_str("{ba z:'f uz'}") },
-
-
-    { njs_str("var qs = require('querystring');"
-              "qs.parse('X='+'α'.repeat(33)).X.length"),
-      njs_str("33") },
+    { njs_str("function f() {async () => {await 1}}"),
+      njs_str("undefined") },
 
-    { njs_str("var qs = require('querystring');"
-              "var x = qs.parse('X='+'α1'.repeat(33)).X;"
-              "[x.length, x[33], x[34]]"),
-      njs_str("66,1,α") },
+    { njs_str("let f = async () => {await 1}"),
+      njs_str("undefined") },
 
-    { njs_str("var qs = require('querystring');"
-              "var s = qs.parse('X='+String.bytesFrom(Array(16).fill(0x9d))).X;"
-              "[s.length, s.toUTF8().length, s[15]]"),
-      njs_str("16,48,�") },
+    { njs_str("let f = () => {await 1}"),
+      njs_str("SyntaxError: await is only valid in async functions in 1") },
 
-    { njs_str("var qs = require('querystring');"
-              "qs.stringify({'baz': 'fuz'})"),
-      njs_str("baz=fuz") },
+    { njs_str("(async function() {await 1})"),
+      njs_str("[object AsyncFunction]") },
 
-    { njs_str("var qs = require('querystring');"
-              "qs.stringify({'baz': 'fuz', 'muz': 'tax'})"),
-      njs_str("baz=fuz&muz=tax") },
+    { njs_str("(function() {await 1})"),
+      njs_str("SyntaxError: await is only valid in async functions in 1") },
 
-    { njs_str("var qs = require('querystring');"
-              "qs.stringify({'baαz': 'fαuz', 'muαz': 'tαax'});"),
-      njs_str("ba%CE%B1z=f%CE%B1uz&mu%CE%B1z=t%CE%B1ax") },
+    { njs_str("let ctor = Object.getPrototypeOf(async function(){}).constructor;"
+              "ctor"),
+      njs_str("[object Function]") },
 
-    { njs_str("var qs = require('querystring');"
-              "qs.stringify({'baz': ['fuz', 'tax']})"),
-      njs_str("baz=fuz&baz=tax") },
+    { njs_str("let ctor = Object.getPrototypeOf(async function(){}).constructor;"
+              "ctor()"),
+      njs_str("[object AsyncFunction]") },
 
-    { njs_str("var qs = require('querystring');"
-              njs_declare_sparse_array("arr", 2)
-              "arr[0] = 0; arr[1] = 1.5;"
-              "qs.stringify({'baz': arr})"),
-      njs_str("baz=0&baz=1.5") },
+    { njs_str("let ctor = Object.getPrototypeOf(async function(){}).constructor;"
+              "new ctor();"),
+      njs_str("[object AsyncFunction]") },
 
-    { njs_str("var qs = require('querystring'); var out = [];"
-              "qs.stringify({'baz': 'fuz', 'muz': 'tax'}, null, null, {encodeURIComponent: (key) => {out.push(key)}});"
-              "out.join('; ')"),
-      njs_str("baz; fuz; muz; tax") },
+    { njs_str("let f = new Function('x', 'await 1; return x'); f(1)"),
+      njs_str("SyntaxError: await is only valid in async functions in runtime:1") },
 
-    { njs_str("var qs = require('querystring'); "
-              "qs.stringify({a: 'b'}, null, null, "
-              "             {encodeURIComponent: () => String.bytesFrom([0x9d])})"),
-      njs_str("TypeError: got non-UTF8 string from encoder") },
+    { njs_str("new AsyncFunction()"),
+      njs_str("ReferenceError: \"AsyncFunction\" is not defined") },
 
-    { njs_str("var qs = require('querystring');"
-              "qs.stringify({'baz': 'fuz', 'muz': 'tax'}, null, null, {encodeURIComponent: 123});"
-              "out.join('; ')"),
-      njs_str("TypeError: option encodeURIComponent is not a function") },
+    { njs_str("(async function() {console.log(await 111)})"),
+      njs_str("SyntaxError: await in arguments not supported in 1") },
 
-    { njs_str("var qs = require('querystring');"
-              "qs.escape = 123;"
-              "qs.stringify({'baz': 'fuz', 'muz': 'tax'})"),
-      njs_str("TypeError: QueryString.escape is not a function") },
+    { njs_str("(async function() {console.log('Number: ' + await 111)})"),
+      njs_str("SyntaxError: await in arguments not supported in 1") },
 
-    { njs_str("var qs = require('querystring'); var out = [];"
-              "qs.escape = (key) => {out.push(key)};"
-              "qs.stringify({'baz': 'fuz', 'muz': 'tax'});"
-              "out.join('; ')"),
-      njs_str("baz; fuz; muz; tax") },
+    { njs_str("function f(a) {}"
+              "(async function() {f(await 111)})"),
+      njs_str("SyntaxError: await in arguments not supported in 1") },
 
-    { njs_str("var qs = require('querystring');"
-              "qs.stringify({'baz': 'fuz', 'muz': 'tax'}, '****')"),
-      njs_str("baz=fuz****muz=tax") },
+    { njs_str("async () => [await x(1)(),]; async () => [await x(1)()]"),
+      njs_str("[object AsyncFunction]") },
 
-    { njs_str("var qs = require('querystring');"
-              "qs.stringify({'baz': 'fuz', 'muz': 'tax'}, null, '^^^^')"),
-      njs_str("baz^^^^fuz&muz^^^^tax") },
+    { njs_str("function f(a, b, c) {}"
+              "(async function() {f(1, 'a', await 111)})"),
+      njs_str("SyntaxError: await in arguments not supported in 1") },
 
-    { njs_str("var qs = require('querystring');"
-              "var obj = {A:'α'}; obj['δ'] = 'D';"
-              "var s = qs.stringify(obj,'γ=','&β'); [s, s.length]"),
-      njs_str("A&β%CE%B1γ=%CE%B4&βD,20") },
+    { njs_str("function f(a) {}"
+              "(async function() {f('Number: ' + await 111)})"),
+      njs_str("SyntaxError: await in arguments not supported in 1") },
 
-    { njs_str("var qs = require('querystring');"
-              "qs.stringify({'baz': 'fuz', 'muz': 'tax'}, '', '')"),
-      njs_str("baz=fuz&muz=tax") },
+    { njs_str("async function af() {await encrypt({},}"),
+      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
 
-    { njs_str("var qs = require('querystring');"
-              "qs.stringify({'baz': 'fuz', 'muz': 'tax'}, undefined, undefined)"),
-      njs_str("baz=fuz&muz=tax") },
+    { njs_str("let x = {async af() {await Promise.resolve(1)}}; x.af"),
+      njs_str("[object AsyncFunction]") },
 
-    { njs_str("var qs = require('querystring');"
-              "qs.stringify({'baz': 'fuz', 'muz': 'tax'}, '?', '/')"),
-      njs_str("baz/fuz?muz/tax") },
+    { njs_str("let name = 'af', x = {async [name]() {await Promise.resolve(1)}}; x.af"),
+      njs_str("[object AsyncFunction]") },
+};
 
-    { njs_str("var qs = require('querystring');"
-              "qs.stringify('123')"),
-      njs_str("") },
 
-    { njs_str("var qs = require('querystring');"
-              "qs.stringify(123)"),
-      njs_str("") },
+static njs_unit_test_t  njs_safe_test[] =
+{
+    { njs_str("(new Function('return this'))() === globalThis"),
+      njs_str("true") },
 
-    { njs_str("var qs = require('querystring');"
-              "qs.stringify({X: String.bytesFrom(Array(4).fill(0x9d))})"),
-      njs_str("X=%9D%9D%9D%9D") },
+    { njs_str("(new Function('return this;'))() === globalThis"),
+      njs_str("true") },
 
-    { njs_str("var qs = require('querystring');"
-              "qs.stringify({X:{toString(){return 3}}})"),
-      njs_str("X=") },
+    { njs_str("(new Function('return    this  '))() === globalThis"),
+      njs_str("true") },
 
-    { njs_str("var qs = require('querystring');"
-              "qs.stringify({ name: undefined, age: 12 })"),
-      njs_str("name=&age=12") },
+    { njs_str("(new Function('return thi'))()"),
+      njs_str("TypeError: function constructor is disabled in \"safe\" mode") },
 
-    { njs_str("var qs = require('querystring');"
-              "qs.stringify(Object.create({ name: undefined, age: 12 }))"),
-      njs_str("") },
+    { njs_str("(new Function('){return 1337})//', 'return this'))()"),
+      njs_str("TypeError: function constructor is disabled in \"safe\" mode") },
+};
 
-    { njs_str("var qs = require('querystring');"
-              "qs.stringify([])"),
-      njs_str("") },
 
-    { njs_str("var qs = require('querystring');"
-              "qs.stringify(['','',''])"),
-      njs_str("0=&1=&2=") },
+static njs_unit_test_t  njs_denormals_test[] =
+{
+    { njs_str("2.2250738585072014e-308"),
+      njs_str("2.2250738585072014e-308") },
 
-    { njs_str("var qs = require('querystring');"
-              "qs.stringify([undefined, null, Symbol(), Object(0), Object('test'), Object(false),,,])"),
-      njs_str("0=&1=&2=&3=&4=&5=") },
+#ifndef NJS_SUNC
+    { njs_str("2.2250738585072014E-308.toString(2) == ('0.' + '0'.repeat(1021) + '1')"),
+      njs_str("true") },
 
-#if 0
-    { njs_str("var qs = require('querystring');"
-              "qs.stringify([NaN, Infinity, -Infinity, 2**69, 2**70])"),
-      njs_str("0=&1=&2=&3=590295810358705700000&4=1.1805916207174113e%2B21") },
-#else
-    { njs_str("var qs = require('querystring');"
-              "qs.stringify([NaN, Infinity, -Infinity, 2**69, 2**70])"),
-      njs_str("0=&1=&2=&3=590295810358705700000&4=1.1805916207174114e%2B21") },
-#endif
+    { njs_str("Number('2.2250738585072014E-323')"),
+      njs_str("2.5e-323") },
 
-    { njs_str("var qs = require('querystring');"
-              "qs.stringify([[1,2,3],[4,5,6]])"),
-      njs_str("0=1&0=2&0=3&1=4&1=5&1=6") },
+    { njs_str("Number('2.2250738585072014E-323') + 0"),
+      njs_str("2.5e-323") },
 
-    { njs_str("var qs = require('querystring');"
-              "qs.stringify([['a',,,],['b',,,]])"),
-      njs_str("0=a&0=&0=&1=b&1=&1=") },
+    /* Smallest positive double (next_double(0)). */
+    { njs_str("5E-324.toString(36) === '0.' + '0'.repeat(207) + '3'"),
+      njs_str("true") },
 
-    { njs_str("var qs = require('querystring');"
-              "qs.stringify([[,'a','b',,]])"),
-      njs_str("0=&0=a&0=b&0=") },
+    /* Maximum fraction length. */
+    { njs_str("2.2250738585072014E-323.toString(2) == ('0.' + '0'.repeat(1071) + '101')"),
+      njs_str("true") },
 
-    { njs_str("var qs = require('querystring');"
-              "qs.escape('abcααααdef')"),
-      njs_str("abc%CE%B1%CE%B1%CE%B1%CE%B1def") },
+    /* Denormals. */
+    { njs_str("var zeros = count => '0'.repeat(count);"
+              "["
+              "  [1.8858070859709815e-308, `0.${zeros(1022)}1101100011110111011100000100011001111101110001010111`],"
+              // FIXME: "  [Number.MIN_VALUE, `0.${zeros(1073)}1`]"
+              "  [-5.06631661953108e-309, `-0.${zeros(1024)}11101001001010000001101111010101011111111011010111`],"
+              "  [6.22574126804e-313, `0.${zeros(1037)}11101010101101100111000110100111001`],"
+              "  [-4e-323, `-0.${zeros(1070)}1`],"
+              "].every(t=>t[0].toString(2) === t[1])"),
+      njs_str("true") },
 
-    { njs_str("var qs = require('querystring');"
-              "qs.unescape('abc%CE%B1%CE%B1%CE%B1%CE%B1def')"),
-      njs_str("abcααααdef") },
+    { njs_str("4.94065645841246544176568792868e-324.toExponential()"),
+      njs_str("5e-324") },
 
-    /* TextEncoder. */
+    { njs_str("4.94065645841246544176568792868e-324.toExponential(10)"),
+      njs_str("4.9406564584e-324") },
+#endif
 
-    { njs_str("var en = new TextEncoder(); typeof en.encode()"),
-      njs_str("object") },
+};
 
-    { njs_str("var en = new TextEncoder(); en.encode()"),
-      njs_str("") },
 
-    { njs_str("var en = new TextEncoder(); var res = en.encode('α'); res"),
-      njs_str("206,177") },
+static njs_unit_test_t  njs_disabled_denormals_test[] =
+{
+    { njs_str("Number('2.2250738585072014E-323')"),
+      njs_str("0") },
 
-    { njs_str("var en = new TextEncoder(); var res = en.encode('α1α'); res[2]"),
-      njs_str("49") },
+    { njs_str("Number('2.2250738585072014E-323') + 0"),
+      njs_str("0") },
 
-    { njs_str("var en = new TextEncoder(); en.encode(String.bytesFrom([0xCE]))"),
-      njs_str("239,191,189") },
+    /* Smallest positive double (next_double(0)). */
+    { njs_str("5E-324.toString(36)"),
+      njs_str("0") },
 
-    { njs_str("var en = new TextEncoder();"
-              "en.encode(String.bytesFrom([0xCE, 0xB1, 0xCE]))"),
-      njs_str("206,177,239,191,189") },
+    { njs_str("2.2250738585072014E-323.toString(2)"),
+      njs_str("0") },
 
-    { njs_str("var en = new TextEncoder();"
-              "en.encode(String.bytesFrom([0xCE, 0xCE, 0xB1]))"),
-      njs_str("239,191,189,206,177") },
+    /* Smallest normal double. */
 
-    { njs_str("var en = new TextEncoder(); en.encoding"),
-      njs_str("utf-8") },
+    { njs_str("2.2250738585072014e-308"),
+      njs_str("2.2250738585072014e-308") },
 
-    { njs_str("TextEncoder.prototype.encode.apply({}, [])"),
-      njs_str("TypeError: \"this\" is not a TextEncoder") },
+    { njs_str("2.2250738585072014e-308/2"),
+      njs_str("0") },
 
-    { njs_str("var en = new TextEncoder();"
-              "var utf8 = new Uint8Array(5);"
-              "var res = en.encodeInto('ααααα', utf8); njs.dump(res)"),
-      njs_str("{read:2,written:4}") },
-
-    { njs_str("var en = new TextEncoder();"
-              "var utf8 = new Uint8Array(10);"
-              "var res = en.encodeInto('ααααα', utf8); njs.dump(res)"),
-      njs_str("{read:5,written:10}") },
-
-    { njs_str("var en = new TextEncoder();"
-              "var utf8 = new Uint8Array(10);"
-              "en.encodeInto('ααααα', utf8.subarray(2)); utf8[0]"),
-      njs_str("0") },
+    /* Denormals. */
+    { njs_str("["
+              "1.8858070859709815e-308,"
+              "-5.06631661953108e-309,"
+              "6.22574126804e-313,"
+              "-4e-323,"
+              "].map(v=>v.toString(2))"),
+      njs_str("0,0,0,0") },
+};
 
-    { njs_str("var str = String.bytesFrom([0xCE]);"
-              "var en = new TextEncoder();"
-              "var utf8 = new Uint8Array(3);"
-              "var res = en.encodeInto(str, utf8); "
-              "[njs.dump(res), utf8]"),
-      njs_str("{read:1,written:3},239,191,189") },
 
-    { njs_str("var str = String.bytesFrom([0xCE]);"
-              "var en = new TextEncoder();"
-              "var utf8 = new Uint8Array(5);"
-              "en.encodeInto(str, utf8); utf8"),
-      njs_str("239,191,189,0,0") },
+static njs_unit_test_t  njs_fs_module_test[] =
+{
+    { njs_str("var fs = require('fs'); typeof fs"),
+      njs_str("object") },
 
-    { njs_str("var str = String.bytesFrom([0xCE, 0xB1, 0xCE]);"
-              "var en = new TextEncoder();"
-              "var utf8 = new Uint8Array(5);"
-              "var res = en.encodeInto(str, utf8);"
-              "[njs.dump(res), utf8]"),
-      njs_str("{read:2,written:5},206,177,239,191,189") },
+    { njs_str("var fs = require('fs'); Object.isExtensible(fs)"),
+      njs_str("true") },
 
-    { njs_str("var str = String.bytesFrom([0xCE, 0xCE, 0xB1]);"
-              "var en = new TextEncoder();"
-              "var utf8 = new Uint8Array(5);"
-              "var res = en.encodeInto(str, utf8);"
-              "[njs.dump(res), utf8]"),
-      njs_str("{read:2,written:5},239,191,189,206,177") },
+    { njs_str("require('fs') === require('fs')"),
+      njs_str("true") },
 
-    { njs_str("TextEncoder.prototype.encodeInto.apply({}, [])"),
-      njs_str("TypeError: \"this\" is not a TextEncoder") },
+    { njs_str("require('fs').a = 1; require('fs').a"),
+      njs_str("1") },
 
-    { njs_str("(new TextEncoder()).encodeInto('', 0.12) "),
-      njs_str("TypeError: The \"destination\" argument must be an instance of Uint8Array") },
+    { njs_str("var fs = require('fs');"
+              "fs.readFile()"),
+      njs_str("TypeError: \"path\" must be a string or Buffer") },
 
-    /* TextDecoder. */
+    { njs_str("var fs = require('fs');"
+              "var path = Buffer.from('/broken'); path[3] = 0;"
+              "fs.readFile(path)"),
+      njs_str("TypeError: \"path\" must be a Buffer without null bytes") },
 
-    { njs_str("var de = new TextDecoder();"
-              "var u8arr = new Uint8Array([240, 160, 174, 183]);"
-              "var u16arr = new Uint16Array(u8arr.buffer);"
-              "var u32arr = new Uint32Array(u8arr.buffer);"
-              "[u8arr, u16arr, u32arr].map(v=>de.decode(v)).join(',')"),
-      njs_str("𠮷,𠮷,𠮷") },
+    { njs_str("var fs = require('fs');"
+              "fs.readFile('/njs_unknown_path')"),
+      njs_str("TypeError: \"callback\" must be a function") },
 
-    { njs_str("var de = new TextDecoder();"
-              "[new Uint8Array([240, 160]), "
-              " new Uint8Array([174]), "
-              " new Uint8Array([183])].map(v=>de.decode(v, {stream: 1}))[2]"),
-      njs_str("𠮷") },
+    { njs_str("var fs = require('fs');"
+              "fs.readFile('/njs_unknown_path', 'utf8')"),
+      njs_str("TypeError: \"callback\" must be a function") },
 
-    { njs_str("var de = new TextDecoder();"
-              "de.decode(new Uint8Array([240, 160]), {stream: 1});"
-              "de.decode(new Uint8Array([174]), {stream: 1});"
-              "de.decode(new Uint8Array([183]))"),
-      njs_str("𠮷") },
+    { njs_str("var fs = require('fs');"
+              "fs.readFile('/njs_unknown_path', {flag:'xx'})"),
+      njs_str("TypeError: \"callback\" must be a function") },
 
-    { njs_str("var de = new TextDecoder();"
-              "de.decode(new Uint8Array([240, 160]), {stream: 1});"
-              "de.decode()"),
-      njs_str("�") },
+    { njs_str("var fs = require('fs');"
+              "fs.readFile('/njs_unknown_path', {flag:'xx'}, 1)"),
+      njs_str("TypeError: \"callback\" must be a function") },
 
-    { njs_str("var de = new TextDecoder('utf-8', {fatal: true});"
-              "de.decode(new Uint8Array([240, 160]))"),
-      njs_str("TypeError: The encoded data was not valid") },
+    { njs_str("var fs = require('fs');"
+              "fs.readFile('/njs_unknown_path', {flag:'xx'}, function () {})"),
+      njs_str("TypeError: Unknown file open flags: \"xx\"") },
 
-    { njs_str("var de = new TextDecoder('utf-8', {fatal: false});"
-              "de.decode(new Uint8Array([240, 160]))"),
-      njs_str("") },
+    { njs_str("var fs = require('fs');"
+              "fs.readFile('/njs_unknown_path', {encoding:'ascii'}, function () {})"),
+      njs_str("TypeError: \"ascii\" encoding is not supported") },
 
-    { njs_str("var en = new TextEncoder();"
-              "var de = new TextDecoder('utf-8', {ignoreBOM: true});"
-              "en.encode(de.decode(new Uint8Array([239, 187, 191, 50])))"),
-      njs_str("239,187,191,50") },
+    { njs_str("var fs = require('fs');"
+              "fs.readFile('/njs_unknown_path', 'ascii', function () {})"),
+      njs_str("TypeError: \"ascii\" encoding is not supported") },
 
-    { njs_str("var en = new TextEncoder();"
-              "var de = new TextDecoder('utf-8', {ignoreBOM: false});"
-              "en.encode(de.decode(new Uint8Array([239, 187, 191, 50])))"),
-      njs_str("50") },
+    /* require('fs').readFileSync() */
 
-    { njs_str("var en = new TextEncoder(); var de = new TextDecoder();"
-              "en.encode(de.decode(new Uint8Array([239, 187, 191, 50])))"),
-      njs_str("50") },
+    { njs_str("var fs = require('fs');"
+              "fs.readFileSync()"),
+      njs_str("TypeError: \"path\" must be a string or Buffer") },
 
-    { njs_str("var de = new TextDecoder(); de.decode('')"),
-      njs_str("TypeError: The \"input\" argument must be an instance of TypedArray") },
+    { njs_str("var fs = require('fs');"
+              "fs.readFileSync({})"),
+      njs_str("TypeError: \"path\" must be a string or Buffer") },
 
-    { njs_str("var de = new TextDecoder({})"),
-      njs_str("RangeError: The \"[object Object]\" encoding is not supported") },
+    { njs_str("var fs = require('fs');"
+              "fs.readFileSync('/njs_unknown_path', {flag:'xx'})"),
+      njs_str("TypeError: Unknown file open flags: \"xx\"") },
 
-    { njs_str("var de = new TextDecoder('foo')"),
-      njs_str("RangeError: The \"foo\" encoding is not supported") },
+    { njs_str("var fs = require('fs');"
+              "fs.readFileSync(Buffer.from('/njs_unknown_path'), {encoding:'ascii'})"),
+      njs_str("TypeError: \"ascii\" encoding is not supported") },
 
-    { njs_str("var de = new TextDecoder(); de.encoding"),
-      njs_str("utf-8") },
+    { njs_str("var fs = require('fs');"
+              "fs.readFileSync('/njs_unknown_path', 'ascii')"),
+      njs_str("TypeError: \"ascii\" encoding is not supported") },
 
-    { njs_str("var de = new TextDecoder(); de.fatal"),
-      njs_str("false") },
+    { njs_str("var fs = require('fs');"
+              "fs.readFileSync('/njs_unknown_path', true)"),
+      njs_str("TypeError: Unknown options type: \"boolean\" (a string or object required)") },
 
-    { njs_str("var de = new TextDecoder(); de.ignoreBOM"),
-      njs_str("false") },
 
-    { njs_str("TextDecoder.prototype.decode.apply({}, new Uint8Array([1]))"),
-      njs_str("TypeError: \"this\" is not a TextDecoder") },
+    /* require('fs').writeFile() */
 
-    { njs_str("var de = new TextDecoder();"
-              "var buf = new Uint32Array([1,2,3]).buffer;"
-              "var en = new TextEncoder();"
-              "njs.dump(new Uint32Array(en.encode(de.decode(buf)).buffer))"),
-      njs_str("Uint32Array [1,2,3]") },
+    { njs_str("var fs = require('fs');"
+              "fs.writeFile()"),
+      njs_str("TypeError: \"path\" must be a string or Buffer") },
 
-    { njs_str("var de = new TextDecoder();"
-              "var buf = new Uint32Array([1,2,3]).subarray(1,2);"
-              "var en = new TextEncoder();"
-              "njs.dump(new Uint32Array(en.encode(de.decode(buf)).buffer))"),
-      njs_str("Uint32Array [2]") },
+    { njs_str("var fs = require('fs');"
+              "fs.writeFile({}, '', function () {})"),
+      njs_str("TypeError: \"path\" must be a string or Buffer") },
 
-    /* Buffer */
+    { njs_str("var fs = require('fs');"
+              "fs.writeFile('/njs_unknown_path')"),
+      njs_str("TypeError: \"callback\" must be a function") },
 
-    { njs_str("new Buffer();"),
-      njs_str("TypeError: Buffer is not a constructor") },
+    { njs_str("var fs = require('fs');"
+              "fs.writeFile('/njs_unknown_path', '')"),
+      njs_str("TypeError: \"callback\" must be a function") },
 
-    { njs_str("var buf = Buffer.alloc();"),
-      njs_str("TypeError: \"size\" argument must be of type number") },
+    { njs_str("var fs = require('fs');"
+              "fs.writeFile('/njs_unknown_path', '', undefined)"),
+      njs_str("TypeError: \"callback\" must be a function") },
 
-    { njs_str("var buf = Buffer.alloc('best buffer');"),
-      njs_str("TypeError: \"size\" argument must be of type number") },
+    { njs_str("var fs = require('fs');"
+              "fs.writeFile('/njs_unknown_path', '', 'utf8')"),
+      njs_str("TypeError: \"callback\" must be a function") },
 
-    { njs_str("var buf = Buffer.alloc(-1);"),
-      njs_str("RangeError: invalid size") },
+    { njs_str("var fs = require('fs');"
+              "fs.writeFile('/njs_unknown_path', '', {flag:'xx'}, function () {})"),
+      njs_str("TypeError: Unknown file open flags: \"xx\"") },
 
-    { njs_str("var buf = Buffer.alloc(4); njs.dump(buf)"),
-      njs_str("Buffer [0,0,0,0]") },
+    { njs_str("var fs = require('fs');"
+              "fs.writeFile('/njs_unknown_path', '', {encoding:'ascii'}, function () {})"),
+      njs_str("TypeError: \"ascii\" encoding is not supported") },
 
-    { njs_str("var buf = Buffer.alloc(4, 88); buf"),
-      njs_str("XXXX") },
+    { njs_str("var fs = require('fs');"
+              "fs.writeFile('/njs_unknown_path', '', 'ascii', function () {})"),
+      njs_str("TypeError: \"ascii\" encoding is not supported") },
 
-    { njs_str("var buf = Buffer.alloc(4, 945); njs.dump(buf)"),
-      njs_str("Buffer [177,177,177,177]") },
+    { njs_str("var fs = require('fs');"
+              "fs.writeFile('/njs_unknown_path', '', true, function () {})"),
+      njs_str("TypeError: Unknown options type: \"boolean\" (a string or object required)") },
 
-    { njs_str("var buf = Buffer.alloc(4, -1); njs.dump(buf)"),
-      njs_str("Buffer [255,255,255,255]") },
+    /* require('fs').writeFileSync() */
 
-    { njs_str("var buf = Buffer.alloc(4, -1, 'utf-128'); njs.dump(buf)"),
-      njs_str("Buffer [255,255,255,255]") },
+    { njs_str("var fs = require('fs');"
+              "fs.writeFileSync()"),
+      njs_str("TypeError: \"path\" must be a string or Buffer") },
 
-    { njs_str("var buf = Buffer.alloc(10, 'α'); buf"),
-      njs_str("ααααα") },
+    { njs_str("var fs = require('fs');"
+              "fs.writeFileSync({}, '')"),
+      njs_str("TypeError: \"path\" must be a string or Buffer") },
 
-    { njs_str("var buf = Buffer.alloc(4, 'α'); njs.dump(buf)"),
-      njs_str("Buffer [206,177,206,177]") },
+    { njs_str("var fs = require('fs');"
+              "fs.writeFileSync('/njs_unknown_path', '', {flag:'xx'})"),
+      njs_str("TypeError: Unknown file open flags: \"xx\"") },
 
-    { njs_str("var buf = Buffer.alloc(2, 'ααααα'); njs.dump(buf)"),
-      njs_str("Buffer [206,177]") },
+    { njs_str("var fs = require('fs');"
+              "fs.writeFileSync('/njs_unknown_path', '', {encoding:'ascii'})"),
+      njs_str("TypeError: \"ascii\" encoding is not supported") },
 
-    { njs_str("var buf = Buffer.alloc(1, 'α'); njs.dump(buf)"),
-      njs_str("Buffer [206]") },
+    { njs_str("var fs = require('fs');"
+              "fs.writeFileSync('/njs_unknown_path', '', 'ascii')"),
+      njs_str("TypeError: \"ascii\" encoding is not supported") },
 
-    { njs_str("var buf = Buffer.alloc(4, 'ZXZpbA==', 'base64'); buf"),
-      njs_str("evil") },
+    { njs_str("var fs = require('fs');"
+              "fs.writeFileSync('/njs_unknown_path', '', true)"),
+      njs_str("TypeError: Unknown options type: \"boolean\" (a string or object required)") },
 
-    { njs_str("var buf = Buffer.alloc(8, 'ZXZpbA==', 'base64'); buf"),
-      njs_str("evilevil") },
+    /* require('fs').renameSync() */
 
-    { njs_str("var buf = Buffer.alloc(8, 'evil', 'utf-128'); buf"),
-      njs_str("TypeError: \"utf-128\" encoding is not supported") },
+    { njs_str("var fs = require('fs');"
+              "fs.renameSync()"),
+      njs_str("TypeError: \"oldPath\" must be a string or Buffer") },
 
-    { njs_str("var foo = new Uint8Array(10).fill(88);"
-              "var buf = Buffer.alloc(8, foo); buf"),
-      njs_str("XXXXXXXX") },
+    { njs_str("var fs = require('fs');"
+              "fs.renameSync('/njs_unknown_path')"),
+      njs_str("TypeError: \"newPath\" must be a string or Buffer") },
 
-    { njs_str("[1,2,10,20].every(v => {"
-              "     var src = new Uint16Array(v).fill(0xB1CE);"
-              "     var buf = Buffer.alloc(10, src);"
-              "     return buf.toString() === " njs_evar("'ααααα'", "'�αααα�'")
-              "})"),
-      njs_str("true") },
+    { njs_str("var fs = require('fs');"
+              "[undefined, null, false, NaN, Symbol(), {}, Object('/njs_unknown_path')]"
+              ".map((x) => { try { fs.renameSync(x, '/njs_unknown_path'); } "
+              "              catch (e) { return (e instanceof TypeError); } })"
+              ".every((x) => x === true)"),
+      njs_str("true")},
 
-    { njs_str("var foo = Buffer.alloc(10, 'α');"
-              "var buf = Buffer.alloc(4, foo); buf"),
-      njs_str("αα") },
+    { njs_str("var fs = require('fs');"
+              "[undefined, null, false, NaN, Symbol(), {}, Object('/njs_unknown_path')]"
+              ".map((x) => { try { fs.renameSync('/njs_unknown_path', x); } "
+              "              catch (e) { return (e instanceof TypeError); } })"
+              ".every((x) => x === true)"),
+      njs_str("true")},
 
-    { njs_str("var buf = Buffer.allocUnsafe(10).fill('α'); buf"),
-      njs_str("ααααα") },
+    /* require('fs').access() */
 
-    { njs_str("var buf = Buffer.allocUnsafe(-1)"),
-      njs_str("RangeError: invalid size") },
+    { njs_str("var fs = require('fs');"
+              "fs.access()"),
+      njs_str("TypeError: \"path\" must be a string or Buffer") },
 
-    { njs_str("["
-             " ['6576696c', 'hex', 4],"
-             " ['6576696', 'hex', 3],"
-             " ['', 'hex', 0],"
-             " ['', 'base64', 0],"
-             " ['ZXZpbA==', 'base64', 4],"
-             " ['ZXZpbA', 'base64url', 4],"
-             " ['ααααα', undefined, 10],"
-             "].every(args => Buffer.byteLength(args[0], args[1])  == args[2])"),
-      njs_str("true") },
+    { njs_str("var fs = require('fs');"
+              "fs.access('/njs_unknown_path')"),
+      njs_str("TypeError: \"callback\" must be a function") },
 
-    { njs_str("Buffer.from([])"),
-      njs_str("") },
+    { njs_str("var fs = require('fs');"
+              "fs.access('/njs_unknown_path', fs.constants.F_OK)"),
+      njs_str("TypeError: \"callback\" must be a function") },
 
-    { njs_str("Buffer.from([0x62, 0x75, 0x66, 0x66, 0x65, 0x72])"),
-      njs_str("buffer") },
+    { njs_str("var fs = require('fs');"
+              "fs.access('/njs_unknown_path', 'fail', function () {})"),
+      njs_str("TypeError: \"mode\" must be a number") },
 
-    { njs_str(njs_declare_sparse_array("arr", 6)
-              "[0x62, 0x75, 0x66, 0x66, 0x65, 0x72].map((v, i) => {arr[i] = v;});"
-              "Buffer.from(arr)"),
-      njs_str("buffer") },
+    /* require('fs').accessSync() */
 
-    { njs_str("Buffer.from({length:3, 0:0x62, 1:0x75, 2:0x66})"),
-      njs_str("buf") },
+    { njs_str("var fs = require('fs');"
+              "fs.accessSync()"),
+      njs_str("TypeError: \"path\" must be a string or Buffer") },
 
-    { njs_str("njs.dump(Buffer.from([-1,1,255,22323,-Infinity,Infinity,NaN]))"),
-      njs_str("Buffer [255,1,255,51,0,0,0]") },
+    { njs_str("var fs = require('fs');"
+              "fs.accessSync('/njs_unknown_path', 'fail')"),
+      njs_str("TypeError: \"mode\" must be a number") },
 
-    { njs_str("var buf = Buffer.from([0x62, 0x75, 0x66, 0x66, 0x65, 0x72]); njs.dump(buf)"),
-      njs_str("Buffer [98,117,102,102,101,114]") },
+    { njs_str("var "
+              "fs = require('fs'),"
+              "func = ["
+                "'access',"
+                "'accessSync',"
+                "'readFile',"
+                "'readFileSync',"
+                "'writeFile',"
+                "'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')]"
+                ".map((x) => { try { fs[fname](x); } "
+                "              catch (e) { return (e instanceof TypeError); } })"
+                ".every((x) => x === true);"
+              "func.map(test).every((x) => x)"),
+      njs_str("true")},
 
-    { njs_str("var buf = Buffer.from([1,2,3]); njs.dump(Buffer.from(buf.toJSON()))"),
-      njs_str("Buffer [1,2,3]") },
+    /* require('fs').promises */
 
-    { njs_str("["
-              " {type: 'B'},"
-              " {type: undefined},"
-              " {type:'Buffer'},"
-              " {type:'Buffer', data:null},"
-              " {type:'Buffer', data:{}},"
-              "].every(v=>{ try { Buffer.from(v)} catch(e) {return e.name == 'TypeError'}})"),
-      njs_str("true") },
+    { njs_str("var fs = require('fs');"
+              "typeof fs.promises"),
+      njs_str("object") },
 
-    { njs_str("var foo = new Uint16Array(2);"
-              "foo[0] = 5000; foo[1] = 4000;"
-              "var buf = Buffer.from(foo.buffer);"
-              "foo[1] = 6000;"
-              "njs.dump(buf)"),
-      njs_str("Buffer [" njs_evar("136,19,112,23", "19,136,23,112") "]") },
+    { njs_str("var "
+              "fs = require('fs').promises,"
+              "func = ["
+                "'access',"
+                "'readFile',"
+                "'writeFile',"
+                "'appendFile',"
+                "'rename',"
+                "'symlink',"
+                "'unlink',"
+                "'realpath',"
+                "'mkdir',"
+                "'rmdir',"
+                "'readdir',"
+              "];"
+              "func.every((x) => typeof fs[x] == 'function')"),
+      njs_str("true")},
 
-    { njs_str("var foo = new Uint16Array(2).fill(950);"
-              "var buf = Buffer.from(foo.buffer, 1); njs.dump(buf)"),
-      njs_str("Buffer [" njs_evar("3,182,3", "182,3,182") "]") },
+    /* require('fs').constants */
 
-    { njs_str("var foo = new Uint16Array(2).fill(950);"
-              "var buf = Buffer.from(foo.buffer, -1); njs.dump(buf)"),
-      njs_str("RangeError: invalid index") },
+    { njs_str("var fs = require('fs');"
+              "typeof fs.constants"),
+      njs_str("object") },
 
-    { njs_str("var foo = new Uint16Array(2).fill(950);"
-              "var buf = Buffer.from(foo.buffer, 5); njs.dump(buf)"),
-      njs_str("RangeError: \"offset\" is outside of buffer bounds") },
+    { njs_str("var "
+              "fsc = require('fs').constants,"
+              "items = ["
+                "'F_OK',"
+                "'R_OK',"
+                "'W_OK',"
+                "'X_OK',"
+              "];"
+              "items.every((x) => typeof fsc[x] == 'number')"),
+      njs_str("true")},
 
-    { njs_str("var foo = new Uint16Array(2).fill(950);"
-              "var buf = Buffer.from(foo.buffer, 2, 1); njs.dump(buf)"),
-      njs_str("Buffer [" njs_evar("182", "3") "]") },
+    /* require('fs').Dirent */
 
-    { njs_str("var foo = new Uint16Array(2).fill(950);"
-              "var buf = Buffer.from(foo.buffer, 2, -1); njs.dump(buf)"),
-      njs_str("Buffer []") },
+    { njs_str("var fs = require('fs');"
+              "typeof fs.Dirent"),
+      njs_str("function") },
 
-    { njs_str("var foo = new Uint16Array(2).fill(950);"
-              "var buf = Buffer.from(foo.buffer, 2, 3); njs.dump(buf)"),
-      njs_str("RangeError: \"length\" is outside of buffer bounds") },
+    { njs_str("var fs = require('fs');"
+              "fs.Dirent('file', 123)"),
+      njs_str("TypeError: the Dirent constructor must be called with new") },
 
-    { njs_str("var foo = new Uint16Array(2).fill(950);"
-              "var buf = Buffer.from(foo.buffer, 2, 0); njs.dump(buf)"),
-      njs_str("Buffer []") },
+    { njs_str("var fs = require('fs');"
+              "var e = new fs.Dirent('file', 123); [e.name, e.type]"),
+      njs_str("file,123") },
 
-    { njs_str("var foo = new Uint16Array(2).fill(950);"
-              "var buf = Buffer.from(foo.buffer, 2, 2); njs.dump(buf)"),
-      njs_str("Buffer [" njs_evar("182,3", "3,182") "]") },
+    { 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")},
+};
 
-    { njs_str("var foo = new Uint16Array(2).fill(950);"
-              "var buf = Buffer.from(foo.buffer, '2', '2'); njs.dump(buf)"),
-      njs_str("Buffer [" njs_evar("182,3", "3,182") "]") },
 
-    { njs_str("var foo = new Uint32Array(1).fill(0xF1F2F3F4);"
-              "var buf = Buffer.from(foo); njs.dump(buf)"),
-      njs_str("Buffer [244]") },
+static njs_unit_test_t  njs_crypto_module_test[] =
+{
+    { njs_str("var h = require('crypto').createHash('sha1');"
+              "[Object.prototype.toString.call(h), njs.dump(h),h]"),
+      njs_str("[object Hash],Hash {},[object Hash]") },
 
-    { njs_str("var foo = new Uint32Array(2).fill(0xF1F2F3F4);"
-              "var buf = Buffer.from(foo); njs.dump(buf)"),
-      njs_str("Buffer [244,244]") },
+    { njs_str("var h = require('crypto').createHash('sha1');"
+              "var Hash = h.constructor; "
+              "Hash('sha1').update('AB').digest('hex')"),
+      njs_str("06d945942aa26a61be18c3e22bf19bbca8dd2b5d") },
 
-    { njs_str("var foo = new Uint8Array(5);"
-              "foo[0] = 1; foo[1] = 2; foo[2] = 3; foo[3] = 4; foo[4] = 5;"
-              "foo = foo.subarray(1, 3);"
-              "var buf = Buffer.from(foo); njs.dump(buf)"),
-      njs_str("Buffer [2,3]") },
+    { njs_str("var h = require('crypto').createHash('sha1');"
+              "h.constructor.name"),
+      njs_str("Hash") },
 
-    { njs_str("var buf = Buffer.from(''); njs.dump(buf)"),
-      njs_str("Buffer []") },
+    { njs_str("var hash = require('crypto').createHash.bind(undefined, 'md5');"
+              "['hex', 'base64', 'base64url'].map(e => {"
+              "   var h = hash().update('AB').digest().toString(e);"
+              "   var h2 = hash().update(Buffer.from('XABX').subarray(1,3)).digest(e);"
+              "   var h3 = hash().update('A').update('B').digest(e);"
+              "   if (h !== h2) {throw new Error(`digest().toString($e):$h != digest($e):$h2`)};"
+              "   if (h !== h3) {throw new Error(`digest().toString($e):$h != update('A').update('B').digest($e):$h3`)};"
+              "   return h;"
+              "})"),
+      njs_str("b86fc6b051f63d73de262d4c34e3a0a9,"
+              "uG/GsFH2PXPeJi1MNOOgqQ==,"
+              "uG_GsFH2PXPeJi1MNOOgqQ") },
 
-    { njs_str("var buf = Buffer.from('α'); njs.dump(buf)"),
-      njs_str("Buffer [206,177]") },
+    { njs_str("var hash = require('crypto').createHash.bind(undefined, 'sha1');"
+              "['hex', 'base64', 'base64url'].map(e => {"
+              "   var h = hash().update('4142', 'hex').digest().toString(e);"
+              "   var h2 = hash().update(Buffer.from('XABX').subarray(1,3)).digest(e);"
+              "   var h3 = hash().update('A').update('B').digest(e);"
+              "   if (h !== h2) {throw new Error(`digest().toString($e):$h != digest($e):$h2`)};"
+              "   if (h !== h3) {throw new Error(`digest().toString($e):$h != update('A').update('B').digest($e):$h3`)};"
+              "   return h;"
+              "})"),
+      njs_str("06d945942aa26a61be18c3e22bf19bbca8dd2b5d,"
+              "BtlFlCqiamG+GMPiK/GbvKjdK10=,"
+              "BtlFlCqiamG-GMPiK_GbvKjdK10") },
 
-    { njs_str("var arr = new Array(1,2,3); arr.valueOf = () => arr;"
-              "njs.dump(Buffer.from(arr))"),
-      njs_str("Buffer [1,2,3]") },
+    { njs_str("var hash = require('crypto').createHash.bind(undefined, 'sha1');"
+              "['hex', 'base64', 'base64url'].every(e => {"
+              "   var h = hash().digest(e);"
+              "   var h2 = hash().update('').digest(e);"
+              "   if (h !== h2) {throw new Error(`digest($e):$h != update('').digest($e):$h2`)};"
+              "   return true;"
+              "})"),
+      njs_str("true") },
 
-    { njs_str("var obj = new Object(); obj.valueOf = () => obj;"
-              "Buffer.from(obj)"),
-      njs_str("TypeError: first argument object is not a string or Buffer-like object") },
+    { njs_str("var hash = require('crypto').createHash.bind(undefined, 'sha1');"
+              "["
+              " ['AB'],"
+              " ['4142', 'hex'],"
+              " ['QUI=', 'base64'],"
+              " ['QUI', 'base64url']"
+              "].every(args => {"
+              "        return hash().update(args[0], args[1]).digest('hex') === '06d945942aa26a61be18c3e22bf19bbca8dd2b5d';"
+              "})"),
+      njs_str("true") },
 
-    { njs_str("var obj = new Object(); obj.valueOf = () => undefined;"
-              "njs.dump(Buffer.from(obj))"),
-      njs_str("TypeError: first argument undefined is not a string or Buffer-like object") },
+    { njs_str("var hash = require('crypto').createHash.bind(undefined, 'sha256');"
+              "['hex', 'base64', 'base64url'].map(e => {"
+              "   var h = hash().update('AB').digest().toString(e);"
+              "   var h2 = hash().update(Buffer.from('XABX').subarray(1,3)).digest(e);"
+              "   var h3 = hash().update('A').update('B').digest(e);"
+              "   if (h !== h2) {throw new Error(`digest().toString($e):$h != digest($e):$h2`)};"
+              "   if (h !== h3) {throw new Error(`digest().toString($e):$h != update('A').update('B').digest($e):$h3`)};"
+              "   return h;"
+              "})"),
+      njs_str("38164fbd17603d73f696b8b4d72664d735bb6a7c88577687fd2ae33fd6964153,"
+              "OBZPvRdgPXP2lri01yZk1zW7anyIV3aH/SrjP9aWQVM=,"
+              "OBZPvRdgPXP2lri01yZk1zW7anyIV3aH_SrjP9aWQVM") },
 
-    { njs_str("var arr = new Array(1,2,3); arr.valueOf = () => null;"
-              "njs.dump(Buffer.from(arr))"),
-      njs_str("Buffer [1,2,3]") },
+    { njs_str("var hash = require('crypto').createHash;"
+              "njs.dump(['', 'abc'.repeat(100)].map(v => {"
+              "    return ['md5', 'sha1', 'sha256'].map(h => {"
+              "        return hash(h).update(v).digest('hex');"
+              "     })"
+              "}))"),
+      njs_str("[['d41d8cd98f00b204e9800998ecf8427e',"
+              "'da39a3ee5e6b4b0d3255bfef95601890afd80709',"
+              "'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'],"
+              "['f571117acbd8153c8dc3c81b8817773a',"
+              "'c95466320eaae6d19ee314ae4f135b12d45ced9a',"
+              "'d9f5aeb06abebb3be3f38adec9a2e3b94228d52193be923eb4e24c9b56ee0930']]") },
 
-    { njs_str("var obj = new Object(); obj.valueOf = () => new Array(1,2,3);"
-              "njs.dump(Buffer.from(obj))"),
-      njs_str("Buffer [1,2,3]") },
+    { njs_str("var h = require('crypto').createHash()"),
+      njs_str("TypeError: algorithm must be a string") },
 
-    { njs_str("njs.dump(Buffer.from(new String('test')))"),
-      njs_str("Buffer [116,101,115,116]") },
+    { njs_str("var h = require('crypto').createHash([])"),
+      njs_str("TypeError: algorithm must be a string") },
 
-    { njs_str("["
-             " ['6576696c', 'hex'],"
-             " ['ZXZpbA==', 'base64'],"
-             " ['ZXZpbA==#', 'base64'],"
-             " ['ZXZpbA', 'base64url'],"
-             " ['ZXZpbA##', 'base64url'],"
-             "].every(args => Buffer.from(args[0], args[1]) == 'evil')"),
+    { njs_str("var h = require('crypto').createHash('sha512')"),
+      njs_str("TypeError: not supported algorithm: \"sha512\"") },
+
+    { njs_str("var h = require('crypto').createHash('sha1');"
+              "h.update()"),
+      njs_str("TypeError: data argument \"undefined\" is not a string or Buffer-like object") },
+
+    { njs_str("var h = require('crypto').createHash('sha1');"
+              "h.update({})"),
+      njs_str("TypeError: data argument \"object\" is not a string or Buffer-like object") },
+
+    { njs_str("var h = require('crypto').createHash('sha1');"
+              "h.update('A').digest('latin1')"),
+      njs_str("TypeError: Unknown digest encoding: \"latin1\"") },
+
+    { njs_str("require('crypto').createHash('sha1').digest() instanceof Buffer"),
       njs_str("true") },
 
-    { njs_str("var buf = Buffer.from(String.bytesFrom([0xF3])); buf"),
-      njs_str("�") },
+    { njs_str("var h = require('crypto').createHash('sha1');"
+              "h.update('A').digest('hex'); h.digest('hex')"),
+      njs_str("Error: Digest already called") },
 
-    { njs_str("Buffer.from('', 'utf-128')"),
-      njs_str("TypeError: \"utf-128\" encoding is not supported") },
+    { njs_str("var h = require('crypto').createHash('sha1');"
+              "h.update('A').digest('hex'); h.update('B')"),
+      njs_str("Error: Digest already called") },
 
-    { njs_str("[Buffer.from('α'), new Uint8Array(10), {}, 1]"
-              ".map(v=>Buffer.isBuffer(v))"),
-      njs_str("true,false,false,false") },
+    { njs_str("typeof require('crypto').createHash('md5')"),
+      njs_str("object") },
 
-    { njs_str("['utf8', 'utf-8', 'hex', 'base64', 'base64url', 'utf-88', '1hex']"
-              ".map(v=>Buffer.isEncoding(v))"),
-      njs_str("true,true,true,true,true,false,false") },
+    { njs_str("var h = require('crypto').createHmac('sha1', '');"
+              "[Object.prototype.toString.call(h), njs.dump(h),h]"),
+      njs_str("[object Hmac],Hmac {},[object Hmac]") },
 
-    { njs_str("["
-              " ['ABC', 'ABCD', -1],"
-              " ['ABCD', 'ABC', 1],"
-              " ['ABC', 'ACB', -1],"
-              " ['ACB', 'ABC', 1],"
-              " ['ABC', 'ABC', 0],"
-              " ['', 'ABC', -1],"
-              " ['', '', 0],"
-              "].every(args => {"
-              "   if (Buffer.compare(Buffer.from(args[0]), Buffer.from(args[1])) != args[2]) {"
-              "       throw new TypeError("
-              "            `Buffer.compare(Buffer.from(${args[0]}), Buffer.from(${args[1]})) != ${args[2]}`);"
-              "   }"
-              "   return true;"
+    { njs_str("var hmac = require('crypto').createHmac.bind(undefined, 'md5', '');"
+              "['hex', 'base64', 'base64url'].map(e => {"
+              "   var h = hmac().update('AB').digest().toString(e);"
+              "   var h2 = hmac().update(Buffer.from('XABX').subarray(1,3)).digest(e);"
+              "   var h3 = hmac().update('A').update('B').digest(e);"
+              "   if (h !== h2) {throw new Error(`digest().toString($e):$h != digest($e):$h2`)};"
+              "   if (h !== h3) {throw new Error(`digest().toString($e):$h != update('A').update('B').digest($e):$h3`)};"
+              "   return h;"
               "})"),
-      njs_str("true") },
+      njs_str("9e0e9e545ef63d41dfb653daecf8ebc7,"
+              "ng6eVF72PUHftlPa7Pjrxw==,"
+              "ng6eVF72PUHftlPa7Pjrxw") },
 
-    { njs_str("["
-              " ['ABC', 'ABCD', -1],"
-              " ['ABCD', 'ABC', 1],"
-              " ['ABC', 'ACB', -1],"
-              " ['ACB', 'ABC', 1],"
-              " ['ABC', 'ABC', 0],"
-              " ['', 'ABC', -1],"
-              " ['', '', 0],"
-              "].every(args => {"
-              "   if (Buffer.from(args[0]).compare(Buffer.from(args[1])) != args[2]) {"
-              "       throw new TypeError("
-              "            `Buffer.from(${args[0]}).compare(Buffer.from(${args[1]})) != ${args[2]}`);"
-              "   }"
-              "   return true;"
+    { njs_str("var hmac = require('crypto').createHmac.bind(undefined, 'sha1', '');"
+              "['hex', 'base64', 'base64url'].map(e => {"
+              "   var h = hmac().update('AB').digest().toString(e);"
+              "   var h2 = hmac().update(Buffer.from('XABX').subarray(1,3)).digest(e);"
+              "   var h3 = hmac().update('A').update('B').digest(e);"
+              "   if (h !== h2) {throw new Error(`digest().toString($e):$h != digest($e):$h2`)};"
+              "   if (h !== h3) {throw new Error(`digest().toString($e):$h != update('A').update('B').digest($e):$h3`)};"
+              "   return h;"
               "})"),
-      njs_str("true") },
+      njs_str("d32c0b6637cc2dfe4670f3fe48ef4434123c4810,"
+              "0ywLZjfMLf5GcPP+SO9ENBI8SBA=,"
+              "0ywLZjfMLf5GcPP-SO9ENBI8SBA") },
 
-    { njs_str("var buf = Buffer.from('ABCD');"
+    { njs_str("var hash = require('crypto').createHmac.bind(undefined, 'sha1', '');"
               "["
-              " [0,3,0,2, -1],"
-              " [0,2,0,3, 1],"
-              " [3,4,3,4, 0],"
-              " [undefined, undefined, undefined, undefined, 0],"
-              " [-1, undefined, undefined, undefined, 'invalid index'],"
-              " [0, -1, undefined, undefined, 'invalid index'],"
-              " [0, 0, -1, undefined, 'invalid index'],"
-              " [0, 0, 0, -1, 'invalid index'],"
-              "]"
-              ".every(as => {"
-              "   try {"
-              "       if (buf.compare(buf, as[0], as[1], as[2], as[3]) != as[4]) {"
-              "           throw new TypeError("
-              "                `buf.compare(${as[0]}, ${as[1]}, ${as[2]}, ${as[3]}) != ${as[4]}`);"
-              "       }"
-              "   } catch (e) { return e.message == as[4]}"
-              "   return true;"
+              " ['AB'],"
+              " ['4142', 'hex'],"
+              " ['QUI=', 'base64'],"
+              " ['QUI', 'base64url']"
+              "].every(args => {"
+              "        return hash().update(args[0], args[1]).digest('hex') === 'd32c0b6637cc2dfe4670f3fe48ef4434123c4810';"
               "})"),
       njs_str("true") },
 
-    { njs_str("var buf1 = Buffer.from('ABCD');"
-              "var buf2 = Buffer.from('ABCD');"
-              "buf1.compare(buf2, 5)"),
-      njs_str("RangeError: \"targetStart\" is out of range: 5") },
-
-    { njs_str("var buf1 = Buffer.from('ABCD');"
-              "var buf2 = Buffer.from('ABCD');"
-              "buf1.compare(buf2, 0, 3, 5)"),
-      njs_str("RangeError: \"sourceStart\" is out of range: 5") },
+    { njs_str("var hmac = require('crypto').createHmac.bind(undefined, 'sha256', '');"
+              "['hex', 'base64', 'base64url'].map(e => {"
+              "   var h = hmac().update('AB').digest().toString(e);"
+              "   var h2 = hmac().update(Buffer.from('AB')).digest(e);"
+              "   var h3 = hmac().update('A').update('B').digest(e);"
+              "   if (h !== h2) {throw new Error(`digest().toString($e):$h != digest($e):$h2`)};"
+              "   if (h !== h3) {throw new Error(`digest().toString($e):$h != update('A').update('B').digest($e):$h3`)};"
+              "   return h;"
+              "})"),
+      njs_str("d53400095496267cf02e5dbd4b0bf9fbfb5f36f311ea7d9809af5487421743e3,"
+              "1TQACVSWJnzwLl29Swv5+/tfNvMR6n2YCa9Uh0IXQ+M=,"
+              "1TQACVSWJnzwLl29Swv5-_tfNvMR6n2YCa9Uh0IXQ-M") },
 
-    { njs_str("var arr = new Uint8Array(4);"
-              "arr[0] = 0x41; arr[1] = 0x42; arr[2] = 0x43; arr[3] = 0x44;"
-              "arr = arr.subarray(1, 4);"
-              "var buf = Buffer.from('ABCD');"
-              "buf.compare(arr, 0, 3, 1, 4)"),
-      njs_str("0") },
+    { njs_str("var hmac = require('crypto').createHmac;"
+              "njs.dump(['', 'abc'.repeat(100)].map(v => {"
+              "    return ['md5', 'sha1', 'sha256'].map(h => {"
+              "        return hmac(h, Buffer.from('secret')).update(v).digest('hex');"
+              "     })"
+              "}))"),
+      njs_str("[['5c8db03f04cec0f43bcb060023914190',"
+              "'25af6174a0fcecc4d346680a72b7ce644b9a88e8',"
+              "'f9e66e179b6747ae54108f82f8ade8b3c25d76fd30afde6c395822c530196169'],"
+              "['91eb74a225cdd3bbfccc34396c6e3ac5',"
+              "'0aac71e3a813a7acc4a809cfdedb2ecba04ffc5e',"
+              "'8660d2d51d6f20f61d5aadfb6c43df7fd05fc2fc4967d8aec1846f3d9ec03987']]") },
 
-    { njs_str("['123', 'abc', '124', '', 'AB', 'ABCD']"
-              ".map(v=>Buffer.from(v)).sort(Buffer.compare).map(v=>v.toString())"),
-      njs_str(",123,124,AB,ABCD,abc") },
+    { njs_str("var h = require('crypto').createHmac('sha1', '');"
+              "var Hmac = h.constructor; "
+              "Hmac('sha1', '').digest('hex')"),
+      njs_str("fbdb1d1b18aa6c08324b7d64b71fb76370690e1d") },
 
-    { njs_str("Buffer.compare(Buffer.alloc(1), 'text')"),
-      njs_str("TypeError: \"target\" argument must be an instance of Buffer or Uint8Array") },
+    { njs_str("var h = require('crypto').createHmac('sha1', '');"
+              "h.constructor.name"),
+      njs_str("Hmac") },
 
-    { njs_str("Buffer.compare('text', Buffer.from('ACB'))"),
-      njs_str("TypeError: \"source\" argument must be an instance of Buffer or Uint8Array") },
+    { njs_str("require('crypto').createHmac('sha1', '').digest() instanceof Buffer"),
+      njs_str("true") },
 
-    { njs_str("Buffer.concat()"),
-      njs_str("TypeError: \"list\" argument must be an instance of Array") },
+    { njs_str("var h = require('crypto').createHmac('sha256', 'A'.repeat(64));"
+              "h.update('AB').digest('hex')"),
+      njs_str("ee9dce43b12eb3e865614ad9c1a8d4fad4b6eac2b64647bd24cd192888d3f367") },
 
-    { njs_str("Buffer.concat([])"),
-      njs_str("") },
+    { njs_str("var h = require('crypto').createHmac('sha256', 'A'.repeat(100));"
+              "h.update('AB').digest('hex')"),
+      njs_str("5647b6c429701ff512f0f18232b4507065d2376ca8899a816a0a6e721bf8ddcc") },
 
-    { njs_str("Buffer.concat([new Uint16Array(10)])"),
-      njs_str("TypeError: \"list[0]\" argument must be an instance of Buffer or Uint8Array") },
+    { njs_str("var h = require('crypto').createHmac()"),
+      njs_str("TypeError: algorithm must be a string") },
 
-    { njs_str("Buffer.concat([new Uint8Array(2), new Uint8Array(1)]).fill('abc')"),
-      njs_str("abc") },
+    { njs_str("var h = require('crypto').createHmac([])"),
+      njs_str("TypeError: algorithm must be a string") },
 
-    { njs_str("Buffer.concat([Buffer.from('AB'), Buffer.from('CD')])"),
-      njs_str("ABCD") },
-
-    { njs_str("Buffer.concat([new Uint8Array(2), new Uint8Array(1)], 2).fill('abc')"),
-      njs_str("ab") },
+    { njs_str("var h = require('crypto').createHmac('sha512', '')"),
+      njs_str("TypeError: not supported algorithm: \"sha512\"") },
 
-    { njs_str("Buffer.concat([new Uint8Array(2), new Uint8Array(1)], 6).fill('abc')"),
-      njs_str("abcabc") },
+    { njs_str("var h = require('crypto').createHmac('sha1', [])"),
+      njs_str("TypeError: key argument \"array\" is not a string or Buffer-like object") },
 
-    { njs_str(njs_declare_sparse_array("list", 2)
-              "list[0] = new Uint8Array(2); list[1] = new Uint8Array(3);"
-              "Buffer.concat(list).fill('ab');"),
-      njs_str("ababa") },
+    { njs_str("var h = require('crypto').createHmac('sha1', 'secret key');"
+              "h.update('A').digest('hex'); h.digest('hex')"),
+      njs_str("Error: Digest already called") },
 
-    { njs_str("Buffer.concat([], '123')"),
-      njs_str("TypeError: \"length\" argument must be of type number") },
+    { njs_str("var h = require('crypto').createHmac('sha1', 'secret key');"
+              "h.update('A').digest('hex'); h.update('B')"),
+      njs_str("Error: Digest already called") },
 
-    { njs_str("Buffer.concat([], -1)"),
-      njs_str("RangeError: \"length\" is out of range") },
+    { njs_str("typeof require('crypto').createHmac('md5', 'a')"),
+      njs_str("object") },
 
-    { njs_str("var buf = Buffer.from('α'); buf[1]"),
-      njs_str("177") },
+    { njs_str("var cr = require('crypto'); var h = cr.createHash('sha1');"
+              "h.update.call(cr.createHmac('sha1', 's'), '')"),
+      njs_str("TypeError: \"this\" is not a hash object") },
+};
 
-    { njs_str("var buf = Buffer.from('α'); buf[1] = 1; njs.dump(buf)"),
-      njs_str("Buffer [206,1]") },
+static njs_unit_test_t  njs_querystring_module_test[] =
+{
+    { njs_str("var qs = require('querystring');"
+              "var obj = qs.parse('baz=fuz');"
+              "njs.dump(obj)"),
+      njs_str("{baz:'fuz'}") },
 
-    { njs_str("var arrBuf = new ArrayBuffer(16);"
-              "var buf = Buffer.from(arrBuf); buf.buffer === arrBuf"),
-      njs_str("true") },
+    { njs_str("var qs = require('querystring');"
+              "var obj = qs.parse('baz=');"
+              "njs.dump(obj)"),
+      njs_str("{baz:''}") },
 
-    { njs_str("["
-              " [[0], 4, '65,66,67,68,0,0,0,0,0,0'],"
-              " [[5], 4, '0,0,0,0,0,65,66,67,68,0'],"
-              " [[8], 2, '0,0,0,0,0,0,0,0,65,66'],"
-              " [[8,2,4], 2, '0,0,0,0,0,0,0,0,67,68'],"
-              " [[10], 0, '0,0,0,0,0,0,0,0,0,0'],"
-              "]"
-              ".every(args => {"
-              " var buf1 = Buffer.from('ABCD');"
-              " var buf2 = Buffer.alloc(10, 0);"
-              " var as = args[0];"
-              " var length = buf1.copy(buf2, as[0], as[1], as[2]);"
-              ""
-              " if (length != args[1]) {"
-              "   throw new TypeError(`buf1.copy(buf2, ${as[0]}, ${as[1]}, ${as[2]}): ${length} != ${args[1]}`)"
-              " }"
-              ""
-              " if (njs.dump(buf2) != `Buffer [${args[2]}]`) {"
-              "   throw new TypeError("
-              "     `buf1.copy(buf2, ${as[0]}, ${as[1]}, ${as[2]}): ${njs.dump(buf2)} != Buffer [${args[2]}]`);"
-              " }"
-              " return true;"
-              "})"),
-      njs_str("true") },
+    { njs_str("var qs = require('querystring');"
+              "var obj = qs.parse('baz=fuz&muz=tax');"
+              "njs.dump(obj)"),
+      njs_str("{baz:'fuz',muz:'tax'}") },
 
-    { njs_str("["
-              " [[0], 'ABCDEF'],"
-              " [[0,2], 'CDEFEF'],"
-              " [[0,2,6], 'CDEFEF'],"
-              " [[1,2,4], 'ACDDEF'],"
-              " [[1,2,3], 'ACCDEF']"
-              "]"
-              ".every(args => {"
-              " var buf = Buffer.from('ABCDEF');"
-              " var as = args[0];"
-              " buf.copy(buf, as[0], as[1], as[2]);"
-              ""
-              " if (buf.toString() != args[1]) {"
-              "   throw new TypeError("
-              "     `buf.copy(buf, ${as[0]}, ${as[1]}, ${as[2]}): buf.toString() != ${args[1]}`);"
-              " }"
-              " return true;"
-              "})"),
-      njs_str("true") },
+    { njs_str("var qs = require('querystring');"
+              "var obj = qs.parse('baz=fuz&');"
+              "njs.dump(obj)"),
+      njs_str("{baz:'fuz'}") },
 
-    { njs_str("var buf1 = Buffer.from('ABCD');"
-              "var buf2 = Buffer.alloc(10, 0);"
-              "buf1.copy(buf2, -1)"),
-      njs_str("RangeError: invalid index") },
+    { njs_str("var qs = require('querystring');"
+              "var obj = qs.parse('&baz=fuz');"
+              "njs.dump(obj)"),
+      njs_str("{baz:'fuz'}") },
 
-    { njs_str("var buf1 = Buffer.from('ABCD');"
-              "var buf2 = Buffer.alloc(10, 0);"
-              "buf1.copy(buf2, 0, -1)"),
-      njs_str("RangeError: invalid index") },
+    { njs_str("var qs = require('querystring');"
+              "var obj = qs.parse('&&&&&baz=fuz');"
+              "njs.dump(obj)"),
+      njs_str("{baz:'fuz'}") },
 
-    { njs_str("var buf1 = Buffer.from('ABCD');"
-              "var buf2 = Buffer.alloc(10, 0);"
-              "buf1.copy(buf2, 0, 5)"),
-      njs_str("RangeError: \"sourceStart\" is out of range: 5") },
+    { njs_str("var qs = require('querystring');"
+              "var obj = qs.parse('=fuz');"
+              "njs.dump(obj)"),
+      njs_str("{:'fuz'}") },
 
-    { njs_str("var arr = new Uint8Array(4);"
-              "arr[0] = 0x41; arr[1] = 0x42; arr[2] = 0x43; arr[3] = 0x44;"
-              "arr = arr.subarray(1, 4);"
-              "var buf1 = Buffer.from(arr);"
-              "var buf2 = Buffer.alloc(10, 0);"
-              "var length = buf1.copy(buf2, 1, 1, 2); [length, njs.dump(buf2)]"),
-      njs_str("1,Buffer [0,67,0,0,0,0,0,0,0,0]") },
+    { njs_str("var qs = require('querystring');"
+              "var obj = qs.parse('=fuz=');"
+              "njs.dump(obj)"),
+      njs_str("{:'fuz='}") },
 
-    { njs_str("var arr = new Uint8Array(4);"
-              "arr[0] = 0x41; arr[1] = 0x42; arr[2] = 0x43; arr[3] = 0x44;"
-              "arr = arr.subarray(1, 4);"
-              "var buf1 = Buffer.from(arr);"
-              "var buf2 = Buffer.alloc(10, 0);"
-              "var length = buf1.copy(buf2, 1, 1, 2); [length, njs.dump(buf2)]"),
-      njs_str("1,Buffer [0,67,0,0,0,0,0,0,0,0]") },
+    { njs_str("var qs = require('querystring');"
+              "var obj = qs.parse('===fu=z');"
+              "njs.dump(obj)"),
+      njs_str("{:'==fu=z'}") },
 
-    { njs_str("["
-              " ['ABC', 'ABCD', false],"
-              " ['ABCD', 'ABC', false],"
-              " ['ABC', 'ACB', false],"
-              " ['ACB', 'ABC', false],"
-              " ['ABC', 'ABC', true],"
-              " ['', 'ABC', false],"
-              " ['', '', true],"
-              "].every(args => {"
-              "   if (Buffer.from(args[0]).equals(Buffer.from(args[1])) != args[2]) {"
-              "       throw new TypeError("
-              "            `Buffer.from(${args[0]}).compare(Buffer.from(${args[1]})) != ${args[2]}`);"
-              "   }"
-              "   return true;"
-              "})"),
-      njs_str("true") },
+    { njs_str("var qs = require('querystring');"
+              "var obj = qs.parse('baz=fuz&baz=tax');"
+              "njs.dump(obj)"),
+      njs_str("{baz:['fuz','tax']}") },
 
-    { njs_str("Buffer.from([1,2]).equals(new ArrayBuffer(1))"),
-      njs_str("TypeError: \"target\" argument must be an instance of Buffer or Uint8Array") },
+    { njs_str("var qs = require('querystring');"
+              "var obj = qs.parse('freespace');"
+              "njs.dump(obj)"),
+      njs_str("{freespace:''}") },
 
-    { njs_str("Buffer.from([1,2]).equals(1)"),
-      njs_str("TypeError: \"target\" argument must be an instance of Buffer or Uint8Array") },
+    { njs_str("var qs = require('querystring');"
+              "var obj = qs.parse('name&value=12');"
+              "njs.dump(obj)"),
+      njs_str("{name:'',value:'12'}") },
 
-    { njs_str("var buf = Buffer.alloc(4);"
-              "buf.fill('ZXZpbA==', 'base64')"),
-      njs_str("evil") },
+    { njs_str("var qs = require('querystring');"
+              "var obj = qs.parse('baz=fuz&muz=tax', 'fuz');"
+              "njs.dump(obj)"),
+      njs_str("{baz:'',&muz:'tax'}") },
 
-    { njs_str("var buf = Buffer.alloc(4);"
-              "buf.fill('6576696c', 'hex')"),
-      njs_str("evil") },
+    { njs_str("var qs = require('querystring');"
+              "var obj = qs.parse('baz=fuz&muz=tax', '');"
+              "njs.dump(obj)"),
+      njs_str("{baz:'fuz',muz:'tax'}") },
 
-    { njs_str("var buf = Buffer.alloc(4);"
-              "buf.fill('ZXZpbA==', '')"),
-      njs_str("TypeError: \"\" encoding is not supported") },
+    { njs_str("var qs = require('querystring');"
+              "var obj = qs.parse('baz=fuz&muz=tax', null);"
+              "njs.dump(obj)"),
+      njs_str("{baz:'fuz',muz:'tax'}") },
 
-    { njs_str("var buf = Buffer.alloc(8);"
-              "buf.fill('6576696c', 'hex')"),
-      njs_str("evilevil") },
+    { njs_str("var qs = require('querystring');"
+              "var obj = qs.parse('baz=fuz&muz=tax', undefined);"
+              "njs.dump(obj)"),
+      njs_str("{baz:'fuz',muz:'tax'}") },
 
-    { njs_str("var buf = Buffer.alloc(10);"
-              "buf.fill('evil')"),
-      njs_str("evilevilev") },
+    { njs_str("var qs = require('querystring');"
+              "var obj = qs.parse('baz=fuz123muz=tax', 123);"
+              "njs.dump(obj)"),
+      njs_str("{baz:'fuz',muz:'tax'}") },
 
-    { njs_str("var buf = Buffer.allocUnsafe(5);"
-              "buf[3] = 1;"
-              "buf.fill(''); njs.dump(buf)"),
-      njs_str("Buffer [0,0,0,0,0]") },
+    { njs_str("var qs = require('querystring');"
+              "var obj = qs.parse('baz=fuzαααmuz=tax', 'ααα');"
+              "njs.dump(obj)"),
+      njs_str("{baz:'fuz',muz:'tax'}") },
 
-    { njs_str("var arr = new Uint8Array(4);"
-              "arr[0] = 0x41; arr[1] = 0x42; arr[2] = 0x43; arr[3] = 0x44;"
-              "arr = arr.subarray(1, 4);"
-              "var buf = Buffer.allocUnsafe(6);"
-              "buf.fill(arr); njs.dump(buf)"),
-      njs_str("Buffer [66,67,68,66,67,68]") },
+    { njs_str("var qs = require('querystring');"
+              "var obj = qs.parse('baz=fuz&muz=tax', '=');"
+              "njs.dump(obj)"),
+      njs_str("{baz:'',fuz&muz:'',tax:''}") },
 
-    { njs_str("var buf = Buffer.alloc(6, 'ABCDEF');"
-              "buf.fill(buf, 2, 6)"),
-      njs_str("ABABCD") },
+    { njs_str("var qs = require('querystring');"
+              "var obj = qs.parse('baz=fuz&muz=tax', null, 'fuz');"
+              "njs.dump(obj)"),
+      njs_str("{baz=:'',muz=tax:''}") },
 
-    { njs_str("Buffer.alloc(6).fill(0x41)"),
-      njs_str("AAAAAA") },
+    { njs_str("var qs = require('querystring');"
+              "var obj = qs.parse('baz=fuz&muz=tax', null, '&');"
+              "njs.dump(obj)"),
+      njs_str("{baz=fuz:'',muz=tax:''}") },
 
-    { njs_str("Buffer.alloc(6).fill({valueOf(){return 0x42}})"),
-      njs_str("BBBBBB") },
+    { njs_str("var qs = require('querystring');"
+              "var obj = qs.parse('baz123fuz&muz123tax', null, 123);"
+              "njs.dump(obj)"),
+      njs_str("{baz:'fuz',muz:'tax'}") },
 
-    { njs_str("njs.dump(Buffer.alloc(3).fill(-1))"),
-      njs_str("Buffer [255,255,255]") },
+    { njs_str("var qs = require('querystring');"
+              "var obj = qs.parse('bazαααfuz&muzαααtax', null, 'ααα');"
+              "njs.dump(obj)"),
+      njs_str("{baz:'fuz',muz:'tax'}") },
 
-    { njs_str("[NaN, Infinity, -Infinity, undefined, null, {}]"
-              ".every(v => njs.dump(Buffer.alloc(3).fill(v)) == 'Buffer [0,0,0]')"),
-      njs_str("true") },
-
-    { njs_str("njs.dump(Buffer.alloc(6).fill({valueOf(){throw 'Oops'}}, 4,3))"),
-      njs_str("Buffer [0,0,0,0,0,0]") },
-
-    { njs_str("njs.dump(Buffer.alloc(6).fill({valueOf(){throw 'Oops'}}, 3,3))"),
-      njs_str("Buffer [0,0,0,0,0,0]") },
-
-    { njs_str("njs.dump(Buffer.alloc(6).fill({valueOf(){throw 'Oops'}}, 2,3))"),
-      njs_str("Oops") },
-
-    { njs_str("njs.dump(Buffer.alloc(5).fill('α'))"),
-      njs_str("Buffer [206,177,206,177,206]") },
-
-    { njs_str("Buffer.alloc(4).fill('ABCD', -1)"),
-      njs_str("RangeError: invalid index") },
-
-    { njs_str("Buffer.alloc(4).fill('ABCD', 5)"),
-      njs_str("RangeError: \"offset\" is out of range") },
-
-    { njs_str("Buffer.alloc(4).fill('ABCD', 0, -1)"),
-      njs_str("RangeError: invalid index") },
-
-    { njs_str("Buffer.alloc(4).fill('ABCD', 0, 5)"),
-      njs_str("RangeError: \"end\" is out of range") },
-
-    { njs_str("Buffer.alloc(513).fill('A'.repeat(512)).length"),
-      njs_str("513") },
-
-    { njs_str("njs.dump(Buffer.alloc(4).fill((new Uint8Array(5)).fill(1)))"),
-      njs_str("Buffer [1,1,1,1]") },
-
-    { njs_str("var src = new Uint8Array(10).fill(255);"
-              "var u8 = new Uint8Array(src.buffer, 1, 8);"
-              "u8.set([1,2,3,4,5,6,7,8]);"
-              "njs.dump(Buffer.alloc(9).fill(u8))"),
-      njs_str("Buffer [1,2,3,4,5,6,7,8,1]") },
-
-    { njs_str("Buffer.alloc(513).fill((new Uint8Array(512)).fill(1)).length"),
-      njs_str("513") },
-
-    { njs_str("Buffer.alloc(4).fill('ABCD', undefined, undefined, 'utf-128')"),
-      njs_str("TypeError: \"utf-128\" encoding is not supported") },
-
-    { njs_str("var buf1 = Buffer.from('ABCD').subarray(1, 3);"
-              "buf1.fill('B', 1, 2); njs.dump(buf1)"),
-      njs_str("Buffer [66,66]") },
-
-    { njs_str("var buf1 = Buffer.from('ABCD').subarray(1, 3);"
-              "buf1.fill(0x42, 1, 2); njs.dump(buf1)"),
-      njs_str("Buffer [66,66]") },
-
-    { njs_str("var buf1 = Buffer.from('ABCD').subarray(1, 2);"
-              "var buf2 = Buffer.from('ABCD').subarray(1, 3);"
-              "buf2.fill(buf1, 1, 2); njs.dump(buf2)"),
-      njs_str("Buffer [66,66]") },
-
-    { njs_str("var buf = Buffer.from('ABCD');"
-              "['BC', 'CB', 'ABCD', 'ABCDE', ''].map(v=>buf.indexOf(v))"),
-      njs_str("1,-1,0,-1,0") },
+    { njs_str("var qs = require('querystring');"
+              "var obj = qs.parse('baz=fuz&muz=tax', null, null, {maxKeys: 1});"
+              "njs.dump(obj)"),
+      njs_str("{baz:'fuz'}") },
 
-    { njs_str("var buf = Buffer.from('ABCD');"
-              "[0,5,-2,-1].map(v=>buf.indexOf('C', v))"),
-      njs_str("2,-1,2,-1") },
+    { njs_str("var qs = require('querystring'); var out = [];"
+              "var obj = qs.parse('baz=fuz&muz=tax', null, null, {decodeURIComponent: (key) => {out.push(key)}});"
+              "out.join('; ');"),
+      njs_str("baz; fuz; muz; tax") },
 
-    { njs_str("var buf = Buffer.from('evil');"
-              "buf.indexOf('ZXZpbA==', undefined, 'base64')"),
-      njs_str("0") },
+    { njs_str("var qs = require('querystring'); var i = 0;"
+              "var obj = qs.parse('baz=fuz&muz=tax', null, null, {decodeURIComponent: (key) => 'α' + i++});"
+              "njs.dump(obj);"),
+      njs_str("{α0:'α1',α2:'α3'}") },
 
-    { njs_str("var buf = Buffer.from('evil');"
-              "buf.indexOf('6576696c', undefined, 'hex')"),
-      njs_str("0") },
+    { njs_str("var qs = require('querystring');"
+              "qs.parse('baz=fuz&muz=tax', null, null, {decodeURIComponent: 123});"),
+      njs_str("TypeError: option decodeURIComponent is not a function") },
 
-    { njs_str("var buf = Buffer.from('ABCD');"
-              "buf.indexOf('C', undefined, 'utf-128')"),
-      njs_str("TypeError: \"utf-128\" encoding is not supported") },
+    { njs_str("var qs = require('querystring');"
+              "qs.unescape = 123;"
+              "qs.parse('baz=fuz&muz=tax');"),
+    njs_str("TypeError: QueryString.unescape is not a function") },
 
-    { njs_str("var buf = Buffer.from('ABCDABC');"
-              "['BC', 'CB', 'ABCD', 'ABCDE', '', 'C', 'ABCDABCD'].map(v=>buf.indexOf(Buffer.from(v)))"),
-      njs_str("1,-1,0,-1,0,2,-1") },
+    { njs_str("var qs = require('querystring'); var out = [];"
+              "qs.unescape = (key) => {out.push(key)};"
+              "qs.parse('baz=fuz&muz=tax');"
+              "out.join('; ');"),
+      njs_str("baz; fuz; muz; tax") },
 
-    { njs_str("var buf = Buffer.from('ABCDABC');"
-              "['BC', 'CB', 'ABCD', 'ABCDE', '', 'C', 'ABCDABCD'].map(v=>buf.includes(Buffer.from(v)))"),
-      njs_str("true,false,true,false,true,true,false") },
+    { njs_str("var qs = require('querystring');"
+              "var obj = qs.parse('ba%32z=f%32uz');"
+              "njs.dump(obj)"),
+      njs_str("{ba2z:'f2uz'}") },
 
-    { njs_str("var buf = Buffer.from('ZABCDABC').subarray(1);"
-              "['BC', 'CB', 'ABCD', 'ABCDE', '', 'C', 'ABCDABCD'].map(v=>buf.indexOf(Buffer.from(v)))"),
-      njs_str("1,-1,0,-1,0,2,-1") },
+    { njs_str("var qs = require('querystring');"
+              "var obj = qs.parse('ba%32z=f%32uz');"
+              "njs.dump(obj)"),
+      njs_str("{ba2z:'f2uz'}") },
 
-    { njs_str("var buf = Buffer.from('ABCD');"
-              "buf.indexOf(0x43)"),
-      njs_str("2") },
+    { njs_str("var qs = require('querystring');"
+              "var obj = qs.parse('ba%F0%9F%92%A9z=f%F0%9F%92%A9uz');"
+              "njs.dump(obj)"),
+      njs_str("{ba💩z:'f💩uz'}") },
 
-    { njs_str("var buf = Buffer.from('ABCD');"
-              "buf.indexOf(0x43, -2)"),
-      njs_str("2") },
+    { njs_str("var qs = require('querystring');"
+              "var obj = qs.parse('======');"
+              "njs.dump(obj)"),
+      njs_str("{:'====='}") },
 
-    { njs_str("var buf = Buffer.from('ABCD');"
-              "buf.indexOf(0x43, -1)"),
-      njs_str("-1") },
+    { njs_str("var qs = require('querystring');"
+              "var obj = qs.parse('baz=%F0%9F%A9');"
+              "njs.dump(obj)"),
+      njs_str("{baz:'�'}") },
 
-    { njs_str("var buf1 = Buffer.from('ABCD');"
-              "var buf2 = Buffer.from('XXCX').subarray(2, 3);"
-              "buf1.indexOf(buf2)"),
-      njs_str("2") },
+    { njs_str("var qs = require('querystring');"
+              "var obj = qs.parse('baz=αααααα%\x00\x01\x02αααα');"
+              "njs.dump(obj)"),
+      njs_str("{baz:'αααααα%\\u0000\\u0001\\u0002αααα'}") },
 
-    { njs_str("var buf1 = Buffer.from('ABCD').subarray(1, 4);"
-              "buf1.indexOf(0x43)"),
-      njs_str("1") },
+    { njs_str("var qs = require('querystring');"
+              "var obj = qs.parse('baz=%F6α');"
+              "njs.dump(obj)"),
+      njs_str("{baz:'�α'}") },
 
-    { njs_str("var buf1 = Buffer.from('ABCD').subarray(1, 4);"
-              "buf1.indexOf('C')"),
-      njs_str("1") },
+    { njs_str("var qs = require('querystring');"
+              "var obj = qs.parse('baz=%F6');"
+              "njs.dump(obj)"),
+      njs_str("{baz:'�'}") },
 
-    { njs_str("var buf = Buffer.from('ABCDABC');"
-              "['BC', 'CB', 'ABCD', 'ABCDE', '', 'C', 'ABCDABCD'].map(v=>buf.lastIndexOf(v))"),
-      njs_str("5,-1,0,-1,7,6,-1") },
+    { njs_str("var qs = require('querystring');"
+              "var obj = qs.parse('baz=%FG');"
+              "njs.dump(obj)"),
+      njs_str("{baz:'%FG'}") },
 
-    { njs_str("var buf = Buffer.from('ABCDABC');"
-              "['BC', 'CB', 'ABCD', 'ABCDE', '', 'C', 'ABCDABCD'].map(v=>buf.lastIndexOf(Buffer.from(v)))"),
-      njs_str("5,-1,0,-1,7,6,-1") },
+    { njs_str("var qs = require('querystring');"
+              "var obj = qs.parse('baz=%F');"
+              "njs.dump(obj)"),
+      njs_str("{baz:'%F'}") },
 
-    { njs_str("var buf = Buffer.from('ZABCDABC').subarray(1);"
-              "['BC', 'CB', 'ABCD', 'ABCDE', '', 'C', 'ABCDABCD'].map(v=>buf.lastIndexOf(v))"),
-      njs_str("5,-1,0,-1,7,6,-1") },
+    { njs_str("var qs = require('querystring');"
+              "var obj = qs.parse('baz=%');"
+              "njs.dump(obj)"),
+      njs_str("{baz:'%'}") },
 
-    { njs_str("var buf = Buffer.from('ZABCDABC').subarray(1);"
-              "['BC', 'CB', 'ABCD', 'ABCDE', '', 'C', 'ABCDABCD'].map(v=>buf.lastIndexOf(Buffer.from(v)))"),
-      njs_str("5,-1,0,-1,7,6,-1") },
+    { njs_str("var qs = require('querystring');"
+              "var obj = qs.parse('ba+z=f+uz');"
+              "njs.dump(obj)"),
+      njs_str("{ba z:'f uz'}") },
 
-    { njs_str("var buf = Buffer.from('CABCD');"
-              "[2,-2,1,-10,10,-5,-4,0].map(v=>buf.lastIndexOf('C', v))"),
-      njs_str("0,3,0,-1,3,0,0,0") },
 
-    { njs_str("var buf = Buffer.from('CABCD');"
-              "[2,-2,1,-10,10,-5,-4,0].map(v=>buf.lastIndexOf(Buffer.from('CZ').subarray(0,1), v))"),
-      njs_str("0,3,0,-1,3,0,0,0") },
+    { njs_str("var qs = require('querystring');"
+              "qs.parse('X='+'α'.repeat(33)).X.length"),
+      njs_str("33") },
 
-    { njs_str("var buf = Buffer.from('CABCD');"
-              "buf.lastIndexOf(0x43)"),
-      njs_str("3") },
+    { njs_str("var qs = require('querystring');"
+              "var x = qs.parse('X='+'α1'.repeat(33)).X;"
+              "[x.length, x[33], x[34]]"),
+      njs_str("66,1,α") },
 
-    { njs_str("var buf = Buffer.from('CABCD');"
-              "[2,1,0,4,5,-1,-5].map(v=>buf.lastIndexOf(0x43, v))"),
-      njs_str("0,0,0,3,3,3,0") },
+    { njs_str("var qs = require('querystring');"
+              "var s = qs.parse('X='+String.bytesFrom(Array(16).fill(0x9d))).X;"
+              "[s.length, s.toUTF8().length, s[15]]"),
+      njs_str("16,48,�") },
 
-    { njs_str("var buf1 = Buffer.from('ACBCD').subarray(1, 4);"
-              "var buf2 = Buffer.from('C');"
-              "buf1.lastIndexOf(buf2)"),
-      njs_str("2") },
+    { njs_str("var qs = require('querystring');"
+              "qs.stringify({'baz': 'fuz'})"),
+      njs_str("baz=fuz") },
 
-    { njs_str("var buf1 = Buffer.from('XXCXX').subarray(2,3);"
-              "buf1.lastIndexOf(Buffer.from('X'))"),
-      njs_str("-1") },
+    { njs_str("var qs = require('querystring');"
+              "qs.stringify({'baz': 'fuz', 'muz': 'tax'})"),
+      njs_str("baz=fuz&muz=tax") },
 
-    { njs_str("var buf = Buffer.from('ACBCD').subarray(1, 4);"
-              "buf.lastIndexOf(0x43)"),
-      njs_str("2") },
+    { njs_str("var qs = require('querystring');"
+              "qs.stringify({'baαz': 'fαuz', 'muαz': 'tαax'});"),
+      njs_str("ba%CE%B1z=f%CE%B1uz&mu%CE%B1z=t%CE%B1ax") },
 
-    { njs_str("var buf = Buffer.from('ACBCD').subarray(1, 4);"
-              "buf.lastIndexOf('C')"),
-      njs_str("2") },
+    { njs_str("var qs = require('querystring');"
+              "qs.stringify({'baz': ['fuz', 'tax']})"),
+      njs_str("baz=fuz&baz=tax") },
 
-    { njs_str("['swap16', 'swap32', 'swap64'].every(method => {"
-              "    var buf = Buffer.from([]);"
-              "    buf[method]();"
-              "    return njs.dump(buf) === 'Buffer []';"
-              "})"),
-      njs_str("true") },
+    { njs_str("var qs = require('querystring');"
+              njs_declare_sparse_array("arr", 2)
+              "arr[0] = 0; arr[1] = 1.5;"
+              "qs.stringify({'baz': arr})"),
+      njs_str("baz=0&baz=1.5") },
 
-    { njs_str("['swap16', 'swap32', 'swap64'].every(method => {"
-              "    var buf = Buffer.from([1,2,3]);"
-              "    try { buf[method]() } "
-              "    catch(e) {return e.message === `Buffer size must be a multiple of ${method.substr(4)}-bits`};"
-              "})"),
-      njs_str("true") },
+    { njs_str("var qs = require('querystring'); var out = [];"
+              "qs.stringify({'baz': 'fuz', 'muz': 'tax'}, null, null, {encodeURIComponent: (key) => {out.push(key)}});"
+              "out.join('; ')"),
+      njs_str("baz; fuz; muz; tax") },
 
-    { njs_str("['swap16', 'swap32', 'swap64'].map(method => {"
-              "    var buf = Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]);"
-              "    buf[method]();"
-              "    return njs.dump(buf);"
-              "})"),
-      njs_str("Buffer [2,1,4,3,6,5,8,7],"
-              "Buffer [4,3,2,1,8,7,6,5],"
-              "Buffer [8,7,6,5,4,3,2,1]") },
+    { njs_str("var qs = require('querystring'); "
+              "qs.stringify({a: 'b'}, null, null, "
+              "             {encodeURIComponent: () => String.bytesFrom([0x9d])})"),
+      njs_str("TypeError: got non-UTF8 string from encoder") },
 
-    { njs_str("['swap16', 'swap32', 'swap64'].map(method => {"
-              "    var u8 = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8]);"
-              "    var buf = Buffer.from(u8.buffer, 1);"
-              "    buf[method]();"
-              "    return njs.dump(buf);"
-              "})"),
-      njs_str("Buffer [2,1,4,3,6,5,8,7],"
-              "Buffer [4,3,2,1,8,7,6,5],"
-              "Buffer [8,7,6,5,4,3,2,1]") },
+    { njs_str("var qs = require('querystring');"
+              "qs.stringify({'baz': 'fuz', 'muz': 'tax'}, null, null, {encodeURIComponent: 123});"
+              "out.join('; ')"),
+      njs_str("TypeError: option encodeURIComponent is not a function") },
 
-    { njs_str("njs.dump(Buffer.from('αααα').toJSON())"),
-      njs_str("{type:'Buffer',data:[206,177,206,177,206,177,206,177]}") },
+    { njs_str("var qs = require('querystring');"
+              "qs.escape = 123;"
+              "qs.stringify({'baz': 'fuz', 'muz': 'tax'})"),
+      njs_str("TypeError: QueryString.escape is not a function") },
 
-    { njs_str("njs.dump(Buffer.from('').toJSON())"),
-      njs_str("{type:'Buffer',data:[]}") },
+    { njs_str("var qs = require('querystring'); var out = [];"
+              "qs.escape = (key) => {out.push(key)};"
+              "qs.stringify({'baz': 'fuz', 'muz': 'tax'});"
+              "out.join('; ')"),
+      njs_str("baz; fuz; muz; tax") },
 
-    { njs_str("["
-              " [['base64'], 'ZXZpbA=='],"
-              " [['base64url'], 'ZXZpbA'],"
-              " [['hex'], '6576696c'],"
-              " [[undefined,1,3], 'vi'],"
-              " [[undefined,5], ''],"
-              " [[undefined,undefined,5], 'evil'],"
-              " [[undefined,undefined,undefined], 'evil'],"
-              "].every(args => {"
-              "   var buf = Buffer.from('evil');"
-              "   var as = args[0];"
-              "   if (buf.toString(as[0], as[1], as[2]) != args[1]) {"
-              "       throw new TypeError("
-              "            `buf.toString(${as[0]}, ${as[1]}, ${as[2]}) != ${args[1]}`);"
-              "   }"
-              "   return true;"
-              "})"),
-      njs_str("true") },
+    { njs_str("var qs = require('querystring');"
+              "qs.stringify({'baz': 'fuz', 'muz': 'tax'}, '****')"),
+      njs_str("baz=fuz****muz=tax") },
 
-    { njs_str("Buffer.from('evil').toString('utf-128')"),
-      njs_str("TypeError: \"utf-128\" encoding is not supported") },
+    { njs_str("var qs = require('querystring');"
+              "qs.stringify({'baz': 'fuz', 'muz': 'tax'}, null, '^^^^')"),
+      njs_str("baz^^^^fuz&muz^^^^tax") },
 
-    { njs_str("var buf = Buffer.allocUnsafe(4);"
-              "var len = buf.write('ZXZpbA==', 'base64'); [len, buf]"),
-      njs_str("4,evil") },
+    { njs_str("var qs = require('querystring');"
+              "var obj = {A:'α'}; obj['δ'] = 'D';"
+              "var s = qs.stringify(obj,'γ=','&β'); [s, s.length]"),
+      njs_str("A&β%CE%B1γ=%CE%B4&βD,20") },
 
-    { njs_str("var buf = Buffer.allocUnsafe(4);"
-              "var len = buf.write('ZXZpbA==', undefined, 'base64'); [len, buf]"),
-      njs_str("4,evil") },
+    { njs_str("var qs = require('querystring');"
+              "qs.stringify({'baz': 'fuz', 'muz': 'tax'}, '', '')"),
+      njs_str("baz=fuz&muz=tax") },
 
-    { njs_str("var buf = Buffer.allocUnsafe(4);"
-              "var len = buf.write('ZXZpbA==', undefined, undefined, 'base64'); [len, buf]"),
-      njs_str("4,evil") },
+    { njs_str("var qs = require('querystring');"
+              "qs.stringify({'baz': 'fuz', 'muz': 'tax'}, undefined, undefined)"),
+      njs_str("baz=fuz&muz=tax") },
 
-    { njs_str("Buffer.allocUnsafe(4).write()"),
-      njs_str("TypeError: first argument must be a string") },
+    { njs_str("var qs = require('querystring');"
+              "qs.stringify({'baz': 'fuz', 'muz': 'tax'}, '?', '/')"),
+      njs_str("baz/fuz?muz/tax") },
 
-    { njs_str("Buffer.allocUnsafe(4).write({a: 1})"),
-      njs_str("TypeError: first argument must be a string") },
+    { njs_str("var qs = require('querystring');"
+              "qs.stringify('123')"),
+      njs_str("") },
 
-    { njs_str("Buffer.alloc(4).write('evil', 4, 1);"),
-      njs_str("RangeError: \"offset\" is out of range") },
+    { njs_str("var qs = require('querystring');"
+              "qs.stringify(123)"),
+      njs_str("") },
 
-    { njs_str("Buffer.alloc(4).write('evil', -1);"),
-      njs_str("RangeError: invalid index") },
+    { njs_str("var qs = require('querystring');"
+              "qs.stringify({X: String.bytesFrom(Array(4).fill(0x9d))})"),
+      njs_str("X=%9D%9D%9D%9D") },
 
-    { njs_str("var buf = Buffer.alloc(4);"
-              "var len = buf.write('evil', 3, 1); [len, njs.dump(buf)]"),
-      njs_str("1,Buffer [0,0,0,101]") },
+    { njs_str("var qs = require('querystring');"
+              "qs.stringify({X:{toString(){return 3}}})"),
+      njs_str("X=") },
 
-    { njs_str("var buf = Buffer.alloc(4);"
-              "var len = buf.write('evil', 0, 5); [len, buf]"),
-      njs_str("4,evil") },
+    { njs_str("var qs = require('querystring');"
+              "qs.stringify({ name: undefined, age: 12 })"),
+      njs_str("name=&age=12") },
 
-    { njs_str("Buffer.alloc(4).write('evil', undefined, -1);"),
-      njs_str("RangeError: invalid index") },
+    { njs_str("var qs = require('querystring');"
+              "qs.stringify(Object.create({ name: undefined, age: 12 }))"),
+      njs_str("") },
 
-    { njs_str("var buf = Buffer.from([0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0xF9, 0xf8]);"
-              "[1,2,3,4,5,6].map(byte => [buf.readUIntLE(0, byte), buf.readUIntLE(1, byte)])"),
-      njs_str("250,251,"
-              "64506,64763,"
-              "16579578,16645371,"
-              "4261215226,4278058235,"
-              "1095182908410,1099494718715,"
-              "281470647991290,274877890034939") },
+    { njs_str("var qs = require('querystring');"
+              "qs.stringify([])"),
+      njs_str("") },
 
-    { njs_str("var buf = Buffer.from([0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0xF9, 0xf8]);"
-              "[1,2,3,4,5,6].map(byte => [buf.readIntLE(0, byte), buf.readIntLE(1, byte)])"),
-      njs_str("-6,-5,"
-              "-1030,-773,"
-              "-197638,-131845,"
-              "-33752070,-16909061,"
-              "-4328719366,-16909061,"
-              "-4328719366,-6597086675717") },
+    { njs_str("var qs = require('querystring');"
+              "qs.stringify(['','',''])"),
+      njs_str("0=&1=&2=") },
 
-    { njs_str("var buf = Buffer.from([0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0xF9, 0xf8]);"
-              "[1,2,3,4,5,6].map(byte => [buf.readUIntBE(0, byte), buf.readUIntBE(1, byte)])"),
-      njs_str("250,251,"
-              "64251,64508,"
-              "16448508,16514301,"
-              "4210818301,4227661310,"
-              "1077969485310,1082281295615,"
-              "275960188239615,277064011677689") },
+    { njs_str("var qs = require('querystring');"
+              "qs.stringify([undefined, null, Symbol(), Object(0), Object('test'), Object(false),,,])"),
+      njs_str("0=&1=&2=&3=&4=&5=") },
 
-    { njs_str("var buf = Buffer.from([0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0xF9, 0xf8]);"
-              "[1,2,3,4,5,6].map(byte => [buf.readIntBE(0, byte), buf.readIntBE(1, byte)])"),
-      njs_str("-6,-5,"
-              "-1285,-1028,"
-              "-328708,-262915,"
-              "-84148995,-67305986,"
-              "-21542142466,-17230332161,"
-              "-5514788471041,-4410965032967") },
+#if 0
+    { njs_str("var qs = require('querystring');"
+              "qs.stringify([NaN, Infinity, -Infinity, 2**69, 2**70])"),
+      njs_str("0=&1=&2=&3=590295810358705700000&4=1.1805916207174113e%2B21") },
+#else
+    { njs_str("var qs = require('querystring');"
+              "qs.stringify([NaN, Infinity, -Infinity, 2**69, 2**70])"),
+      njs_str("0=&1=&2=&3=590295810358705700000&4=1.1805916207174114e%2B21") },
+#endif
 
-    { njs_str("var buf = Buffer.from([0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0xF9, 0xf8]);"
-              "function t(sign, endianness, offset) { "
-              "    return [1,2,4].every(size => {"
-              "        var method = `read${sign}Int${size * 8}`;"
-              "        if (size > 1) { method += endianness};"
-              "        var gmethod = `read${sign}Int${endianness}`;"
-              "        var gv = buf[gmethod](offset, size);"
-              "        var sv = buf[method](offset);"
-              "        if (gv != sv) {throw Error(`${gmethod}(${offset},${size}):${gv} != ${method}(${offset}):${sv}`)}"
-              "        return true;"
-              "   });"
-              "}; "
-              "t('U', 'LE', 0) && t('U', 'LE', 1)"
-              "&& t('', 'LE', 0) && t('', 'LE', 1)"
-              "&& t('U', 'BE', 0) && t('U', 'BE', 1)"
-              "&& t('', 'BE', 0) && t('', 'BE', 1)"),
-      njs_str("true") },
+    { njs_str("var qs = require('querystring');"
+              "qs.stringify([[1,2,3],[4,5,6]])"),
+      njs_str("0=1&0=2&0=3&1=4&1=5&1=6") },
 
-    { njs_str("var buf = Buffer.alloc(9);"
-              "function t(sign, endianness, offset) { "
-              "    return [1,2,4].every(size => {"
-              "        var rgmethod = `read${sign}Int${endianness}`;"
-              "        var wgmethod = `write${sign}Int${endianness}`;"
-              "        var rmethod = `read${sign}Int${size * 8}`;"
-              "        var wmethod = `write${sign}Int${size * 8}`;"
-              "        if (size > 1) { rmethod += endianness; wmethod += endianness; };"
-              "        var v = 0x7abbccddeeff & (size * 8 - 1);"
-              ""
-              "        var ret = buf[wgmethod](v, offset, size);"
-              "        if(ret !== offset + size) {"
-              "            throw Error(`${wgmethod} returned ${ret}, need ${offset + size}`);"
-              "        }"
-              ""
-              "        var gv = buf[rgmethod](offset, size);"
-              ""
-              "        buf.fill(0);"
-              "        buf[wmethod](v, offset);"
-              "        var sv = buf[rmethod](offset);"
-              "        if (gv != sv) {throw Error(`${wmethod}(${v}, ${offset}):${sv} != ${wgmethod}(${v},${offset}):${gv}`)}"
-              "        return true;"
-              "   });"
-              "}; "
-              "t('U', 'LE', 0) && t('U', 'LE', 1)"
-              "&& t('', 'LE', 0) && t('', 'LE', 1)"
-              "&& t('U', 'BE', 0) && t('U', 'BE', 1)"
-              "&& t('', 'BE', 0) && t('', 'BE', 1)"),
-      njs_str("true") },
+    { njs_str("var qs = require('querystring');"
+              "qs.stringify([['a',,,],['b',,,]])"),
+      njs_str("0=a&0=&0=&1=b&1=&1=") },
 
-    { njs_str(njs_buffer_byte_map("writeUIntLE", "+", 1)),
-      njs_str("Buffer [128,0,0,0,0,0],"
-              "Buffer [0,64,0,0,0,0],"
-              "Buffer [0,0,32,0,0,0],"
-              "Buffer [0,0,0,16,0,0],"
-              "Buffer [0,0,0,0,8,0],"
-              "Buffer [0,0,0,0,0,4]") },
+    { njs_str("var qs = require('querystring');"
+              "qs.stringify([[,'a','b',,]])"),
+      njs_str("0=&0=a&0=b&0=") },
 
-    { njs_str(njs_buffer_byte_map("writeUIntBE", "+", 1)),
-      njs_str("Buffer [128,0,0,0,0,0],"
-              "Buffer [64,0,0,0,0,0],"
-              "Buffer [32,0,0,0,0,0],"
-              "Buffer [16,0,0,0,0,0],"
-              "Buffer [8,0,0,0,0,0],"
-              "Buffer [4,0,0,0,0,0]") },
+    { njs_str("var qs = require('querystring');"
+              "qs.escape('abcααααdef')"),
+      njs_str("abc%CE%B1%CE%B1%CE%B1%CE%B1def") },
 
-    { njs_str(njs_buffer_byte_map("writeIntLE", "-", 2)),
-      njs_str("Buffer [192,0,0,0,0,0],"
-              "Buffer [0,224,0,0,0,0],"
-              "Buffer [0,0,240,0,0,0],"
-              "Buffer [0,0,0,248,0,0],"
-              "Buffer [0,0,0,0,252,0],"
-              "Buffer [0,0,0,0,0,254]") },
+    { njs_str("var qs = require('querystring');"
+              "qs.unescape('abc%CE%B1%CE%B1%CE%B1%CE%B1def')"),
+      njs_str("abcααααdef") },
+};
 
-    { njs_str(njs_buffer_byte_map("writeIntBE", "-", 2)),
-      njs_str("Buffer [192,0,0,0,0,0],"
-              "Buffer [224,0,0,0,0,0],"
-              "Buffer [240,0,0,0,0,0],"
-              "Buffer [248,0,0,0,0,0],"
-              "Buffer [252,0,0,0,0,0],"
-              "Buffer [254,0,0,0,0,0]") },
 
-    { njs_str("Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]).readDoubleBE()"),
-      njs_str("8.20788039913184e-304") },
+static njs_unit_test_t  njs_buffer_module_test[] =
+{
+    { njs_str("new Buffer();"),
+      njs_str("TypeError: Buffer is not a constructor") },
 
-    { njs_str("Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]).readDoubleLE()"),
-      njs_str("5.447603722011605e-270") },
+    { njs_str("var buf = Buffer.alloc();"),
+      njs_str("TypeError: \"size\" argument must be of type number") },
 
-    { njs_str("Buffer.from([1, 2, 3, 4]).readFloatBE()"),
-      njs_str("2.387939260590663e-38") },
+    { njs_str("var buf = Buffer.alloc('best buffer');"),
+      njs_str("TypeError: \"size\" argument must be of type number") },
 
-    { njs_str("Buffer.from([1, 2, 3, 4]).readFloatLE()"),
-      njs_str("1.539989614439558e-36") },
+    { njs_str("var buf = Buffer.alloc(-1);"),
+      njs_str("RangeError: invalid size") },
 
-    { njs_str("Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]).readDoubleBE(1)"),
-      njs_str("RangeError: index 1 is outside the bound of the buffer") },
+    { njs_str("var buf = Buffer.alloc(4); njs.dump(buf)"),
+      njs_str("Buffer [0,0,0,0]") },
 
-    { njs_str("Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]).readDoubleLE(1)"),
-      njs_str("RangeError: index 1 is outside the bound of the buffer") },
+    { njs_str("var buf = Buffer.alloc(4, 88); buf"),
+      njs_str("XXXX") },
 
-    { njs_str("Buffer.from([1, 2, 3, 4]).readFloatBE(1)"),
-      njs_str("RangeError: index 1 is outside the bound of the buffer") },
+    { njs_str("var buf = Buffer.alloc(4, 945); njs.dump(buf)"),
+      njs_str("Buffer [177,177,177,177]") },
 
-    { njs_str("Buffer.from([1, 2, 3, 4]).readFloatLE(1)"),
-      njs_str("RangeError: index 1 is outside the bound of the buffer") },
+    { njs_str("var buf = Buffer.alloc(4, -1); njs.dump(buf)"),
+      njs_str("Buffer [255,255,255,255]") },
 
-    { njs_str("var buf = Buffer.allocUnsafe(8);"
-              "buf.writeDoubleBE(123.456); njs.dump(buf)"),
-      njs_str("Buffer [64,94,221,47,26,159,190,119]") },
+    { njs_str("var buf = Buffer.alloc(4, -1, 'utf-128'); njs.dump(buf)"),
+      njs_str("Buffer [255,255,255,255]") },
 
-    { njs_str("var buf = Buffer.allocUnsafe(8);"
-              "buf.writeDoubleLE(123.456); njs.dump(buf)"),
-      njs_str("Buffer [119,190,159,26,47,221,94,64]") },
+    { njs_str("var buf = Buffer.alloc(10, 'α'); buf"),
+      njs_str("ααααα") },
 
-    { njs_str("var buf = Buffer.allocUnsafe(4);"
-              "buf.writeFloatBE(123.456); njs.dump(buf)"),
-      njs_str("Buffer [66,246,233,121]") },
+    { njs_str("var buf = Buffer.alloc(4, 'α'); njs.dump(buf)"),
+      njs_str("Buffer [206,177,206,177]") },
 
-    { njs_str("var buf = Buffer.allocUnsafe(4);"
-              "buf.writeFloatLE(123.456); njs.dump(buf)"),
-      njs_str("Buffer [121,233,246,66]") },
+    { njs_str("var buf = Buffer.alloc(2, 'ααααα'); njs.dump(buf)"),
+      njs_str("Buffer [206,177]") },
 
-    { njs_str("var buf = Buffer.allocUnsafe(8).writeDoubleBE(123.456, 1)"),
-      njs_str("RangeError: index 1 is outside the bound of the buffer") },
+    { njs_str("var buf = Buffer.alloc(1, 'α'); njs.dump(buf)"),
+      njs_str("Buffer [206]") },
 
-    { njs_str("var buf = Buffer.allocUnsafe(8).writeDoubleLE(123.456, 1)"),
-      njs_str("RangeError: index 1 is outside the bound of the buffer") },
+    { njs_str("var buf = Buffer.alloc(4, 'ZXZpbA==', 'base64'); buf"),
+      njs_str("evil") },
 
-    { njs_str("var buf = Buffer.allocUnsafe(4).writeFloatBE(123.456, 1)"),
-      njs_str("RangeError: index 1 is outside the bound of the buffer") },
+    { njs_str("var buf = Buffer.alloc(8, 'ZXZpbA==', 'base64'); buf"),
+      njs_str("evilevil") },
 
-    { njs_str("var buf = Buffer.allocUnsafe(4).writeFloatLE(123.456, 1)"),
-      njs_str("RangeError: index 1 is outside the bound of the buffer") },
+    { njs_str("var buf = Buffer.alloc(8, 'evil', 'utf-128'); buf"),
+      njs_str("TypeError: \"utf-128\" encoding is not supported") },
 
-    { njs_str("var buffer = require('buffer');"
-              "buffer.Buffer.alloc(5).fill('ABC')"),
-      njs_str("ABCAB") },
+    { njs_str("var foo = new Uint8Array(10).fill(88);"
+              "var buf = Buffer.alloc(8, foo); buf"),
+      njs_str("XXXXXXXX") },
 
-    { njs_str("var buffer = require('buffer');"
-              "typeof buffer.kMaxLength === 'number' "),
+    { njs_str("[1,2,10,20].every(v => {"
+              "     var src = new Uint16Array(v).fill(0xB1CE);"
+              "     var buf = Buffer.alloc(10, src);"
+              "     return buf.toString() === " njs_evar("'ααααα'", "'�αααα�'")
+              "})"),
       njs_str("true") },
 
-    { njs_str("var buffer = require('buffer');"
-              "typeof buffer.constants.MAX_LENGTH === 'number' "),
+    { njs_str("var foo = Buffer.alloc(10, 'α');"
+              "var buf = Buffer.alloc(4, foo); buf"),
+      njs_str("αα") },
+
+    { njs_str("var buf = Buffer.allocUnsafe(10).fill('α'); buf"),
+      njs_str("ααααα") },
+
+    { njs_str("var buf = Buffer.allocUnsafe(-1)"),
+      njs_str("RangeError: invalid size") },
+
+    { njs_str("["
+             " ['6576696c', 'hex', 4],"
+             " ['6576696', 'hex', 3],"
+             " ['', 'hex', 0],"
+             " ['', 'base64', 0],"
+             " ['ZXZpbA==', 'base64', 4],"
+             " ['ZXZpbA', 'base64url', 4],"
+             " ['ααααα', undefined, 10],"
+             "].every(args => Buffer.byteLength(args[0], args[1])  == args[2])"),
       njs_str("true") },
 
-    { njs_str("var buffer = require('buffer');"
-              "typeof buffer.constants.MAX_STRING_LENGTH === 'number' "),
+    { njs_str("Buffer.from([])"),
+      njs_str("") },
+
+    { njs_str("Buffer.from([0x62, 0x75, 0x66, 0x66, 0x65, 0x72])"),
+      njs_str("buffer") },
+
+    { njs_str(njs_declare_sparse_array("arr", 6)
+              "[0x62, 0x75, 0x66, 0x66, 0x65, 0x72].map((v, i) => {arr[i] = v;});"
+              "Buffer.from(arr)"),
+      njs_str("buffer") },
+
+    { njs_str("Buffer.from({length:3, 0:0x62, 1:0x75, 2:0x66})"),
+      njs_str("buf") },
+
+    { njs_str("njs.dump(Buffer.from([-1,1,255,22323,-Infinity,Infinity,NaN]))"),
+      njs_str("Buffer [255,1,255,51,0,0,0]") },
+
+    { njs_str("var buf = Buffer.from([0x62, 0x75, 0x66, 0x66, 0x65, 0x72]); njs.dump(buf)"),
+      njs_str("Buffer [98,117,102,102,101,114]") },
+
+    { njs_str("var buf = Buffer.from([1,2,3]); njs.dump(Buffer.from(buf.toJSON()))"),
+      njs_str("Buffer [1,2,3]") },
+
+    { njs_str("["
+              " {type: 'B'},"
+              " {type: undefined},"
+              " {type:'Buffer'},"
+              " {type:'Buffer', data:null},"
+              " {type:'Buffer', data:{}},"
+              "].every(v=>{ try { Buffer.from(v)} catch(e) {return e.name == 'TypeError'}})"),
       njs_str("true") },
 
-    /* let */
+    { njs_str("var foo = new Uint16Array(2);"
+              "foo[0] = 5000; foo[1] = 4000;"
+              "var buf = Buffer.from(foo.buffer);"
+              "foo[1] = 6000;"
+              "njs.dump(buf)"),
+      njs_str("Buffer [" njs_evar("136,19,112,23", "19,136,23,112") "]") },
 
-    { njs_str("let x"),
-      njs_str("undefined") },
+    { njs_str("var foo = new Uint16Array(2).fill(950);"
+              "var buf = Buffer.from(foo.buffer, 1); njs.dump(buf)"),
+      njs_str("Buffer [" njs_evar("3,182,3", "182,3,182") "]") },
 
-    { njs_str("let x = 123; x"),
-      njs_str("123") },
+    { njs_str("var foo = new Uint16Array(2).fill(950);"
+              "var buf = Buffer.from(foo.buffer, -1); njs.dump(buf)"),
+      njs_str("RangeError: invalid index") },
 
-    { njs_str("let x = [123]; x"),
-      njs_str("123") },
+    { njs_str("var foo = new Uint16Array(2).fill(950);"
+              "var buf = Buffer.from(foo.buffer, 5); njs.dump(buf)"),
+      njs_str("RangeError: \"offset\" is outside of buffer bounds") },
 
-    { njs_str("let x = () => x; x()"),
-      njs_str("[object Function]") },
+    { njs_str("var foo = new Uint16Array(2).fill(950);"
+              "var buf = Buffer.from(foo.buffer, 2, 1); njs.dump(buf)"),
+      njs_str("Buffer [" njs_evar("182", "3") "]") },
 
-    { njs_str("let x = (() => x)()"),
-      njs_str("ReferenceError: cannot access variable before initialization") },
+    { njs_str("var foo = new Uint16Array(2).fill(950);"
+              "var buf = Buffer.from(foo.buffer, 2, -1); njs.dump(buf)"),
+      njs_str("Buffer []") },
 
-    { njs_str("x; let x"),
-      njs_str("ReferenceError: cannot access variable before initialization") },
+    { njs_str("var foo = new Uint16Array(2).fill(950);"
+              "var buf = Buffer.from(foo.buffer, 2, 3); njs.dump(buf)"),
+      njs_str("RangeError: \"length\" is outside of buffer bounds") },
 
-    { njs_str("x; let x = 123"),
-      njs_str("ReferenceError: cannot access variable before initialization") },
+    { njs_str("var foo = new Uint16Array(2).fill(950);"
+              "var buf = Buffer.from(foo.buffer, 2, 0); njs.dump(buf)"),
+      njs_str("Buffer []") },
 
-    { njs_str("let x = x + 123"),
-      njs_str("ReferenceError: cannot access variable before initialization") },
+    { njs_str("var foo = new Uint16Array(2).fill(950);"
+              "var buf = Buffer.from(foo.buffer, 2, 2); njs.dump(buf)"),
+      njs_str("Buffer [" njs_evar("182,3", "3,182") "]") },
 
-    { njs_str("let x = (x, 1)"),
-      njs_str("ReferenceError: cannot access variable before initialization") },
+    { njs_str("var foo = new Uint16Array(2).fill(950);"
+              "var buf = Buffer.from(foo.buffer, '2', '2'); njs.dump(buf)"),
+      njs_str("Buffer [" njs_evar("182,3", "3,182") "]") },
 
-    { njs_str("let x = x"),
-      njs_str("ReferenceError: cannot access variable before initialization") },
+    { njs_str("var foo = new Uint32Array(1).fill(0xF1F2F3F4);"
+              "var buf = Buffer.from(foo); njs.dump(buf)"),
+      njs_str("Buffer [244]") },
+
+    { njs_str("var foo = new Uint32Array(2).fill(0xF1F2F3F4);"
+              "var buf = Buffer.from(foo); njs.dump(buf)"),
+      njs_str("Buffer [244,244]") },
+
+    { njs_str("var foo = new Uint8Array(5);"
+              "foo[0] = 1; foo[1] = 2; foo[2] = 3; foo[3] = 4; foo[4] = 5;"
+              "foo = foo.subarray(1, 3);"
+              "var buf = Buffer.from(foo); njs.dump(buf)"),
+      njs_str("Buffer [2,3]") },
+
+    { njs_str("var buf = Buffer.from(''); njs.dump(buf)"),
+      njs_str("Buffer []") },
+
+    { njs_str("var buf = Buffer.from('α'); njs.dump(buf)"),
+      njs_str("Buffer [206,177]") },
+
+    { njs_str("var arr = new Array(1,2,3); arr.valueOf = () => arr;"
+              "njs.dump(Buffer.from(arr))"),
+      njs_str("Buffer [1,2,3]") },
+
+    { njs_str("var obj = new Object(); obj.valueOf = () => obj;"
+              "Buffer.from(obj)"),
+      njs_str("TypeError: first argument object is not a string or Buffer-like object") },
+
+    { njs_str("var obj = new Object(); obj.valueOf = () => undefined;"
+              "njs.dump(Buffer.from(obj))"),
+      njs_str("TypeError: first argument undefined is not a string or Buffer-like object") },
+
+    { njs_str("var arr = new Array(1,2,3); arr.valueOf = () => null;"
+              "njs.dump(Buffer.from(arr))"),
+      njs_str("Buffer [1,2,3]") },
+
+    { njs_str("var obj = new Object(); obj.valueOf = () => new Array(1,2,3);"
+              "njs.dump(Buffer.from(obj))"),
+      njs_str("Buffer [1,2,3]") },
 
-    { njs_str("let x; var x"),
-      njs_str("SyntaxError: \"x\" has already been declared in 1") },
+    { njs_str("njs.dump(Buffer.from(new String('test')))"),
+      njs_str("Buffer [116,101,115,116]") },
 
-    { njs_str("var x; let x"),
-      njs_str("SyntaxError: \"x\" has already been declared in 1") },
+    { njs_str("["
+             " ['6576696c', 'hex'],"
+             " ['ZXZpbA==', 'base64'],"
+             " ['ZXZpbA==#', 'base64'],"
+             " ['ZXZpbA', 'base64url'],"
+             " ['ZXZpbA##', 'base64url'],"
+             "].every(args => Buffer.from(args[0], args[1]) == 'evil')"),
+      njs_str("true") },
 
-    { njs_str("let x; function x() {}"),
-      njs_str("SyntaxError: \"x\" has already been declared in 1") },
+    { njs_str("var buf = Buffer.from(String.bytesFrom([0xF3])); buf"),
+      njs_str("") },
 
-    { njs_str("function x() {} let x"),
-      njs_str("SyntaxError: \"x\" has already been declared in 1") },
+    { njs_str("Buffer.from('', 'utf-128')"),
+      njs_str("TypeError: \"utf-128\" encoding is not supported") },
 
-    { njs_str("function x() {let x; var x}"),
-      njs_str("SyntaxError: \"x\" has already been declared in 1") },
+    { njs_str("[Buffer.from('α'), new Uint8Array(10), {}, 1]"
+              ".map(v=>Buffer.isBuffer(v))"),
+      njs_str("true,false,false,false") },
 
-    { njs_str("function x() {var x; let x}"),
-      njs_str("SyntaxError: \"x\" has already been declared in 1") },
+    { njs_str("['utf8', 'utf-8', 'hex', 'base64', 'base64url', 'utf-88', '1hex']"
+              ".map(v=>Buffer.isEncoding(v))"),
+      njs_str("true,true,true,true,true,false,false") },
 
-    { njs_str("var x = function f() {let f}"),
-      njs_str("undefined") },
+    { njs_str("["
+              " ['ABC', 'ABCD', -1],"
+              " ['ABCD', 'ABC', 1],"
+              " ['ABC', 'ACB', -1],"
+              " ['ACB', 'ABC', 1],"
+              " ['ABC', 'ABC', 0],"
+              " ['', 'ABC', -1],"
+              " ['', '', 0],"
+              "].every(args => {"
+              "   if (Buffer.compare(Buffer.from(args[0]), Buffer.from(args[1])) != args[2]) {"
+              "       throw new TypeError("
+              "            `Buffer.compare(Buffer.from(${args[0]}), Buffer.from(${args[1]})) != ${args[2]}`);"
+              "   }"
+              "   return true;"
+              "})"),
+      njs_str("true") },
 
-    { njs_str("let a; let x = 1;"
-              "{let x = 2; a = x}"
-              "[x, a]"),
-      njs_str("1,2") },
+    { njs_str("["
+              " ['ABC', 'ABCD', -1],"
+              " ['ABCD', 'ABC', 1],"
+              " ['ABC', 'ACB', -1],"
+              " ['ACB', 'ABC', 1],"
+              " ['ABC', 'ABC', 0],"
+              " ['', 'ABC', -1],"
+              " ['', '', 0],"
+              "].every(args => {"
+              "   if (Buffer.from(args[0]).compare(Buffer.from(args[1])) != args[2]) {"
+              "       throw new TypeError("
+              "            `Buffer.from(${args[0]}).compare(Buffer.from(${args[1]})) != ${args[2]}`);"
+              "   }"
+              "   return true;"
+              "})"),
+      njs_str("true") },
 
-    { njs_str("let a; let x = 1;"
-              "if (true) {let x = 2; a = x}"
-              "[x, a]"),
-      njs_str("1,2") },
+    { njs_str("var buf = Buffer.from('ABCD');"
+              "["
+              " [0,3,0,2, -1],"
+              " [0,2,0,3, 1],"
+              " [3,4,3,4, 0],"
+              " [undefined, undefined, undefined, undefined, 0],"
+              " [-1, undefined, undefined, undefined, 'invalid index'],"
+              " [0, -1, undefined, undefined, 'invalid index'],"
+              " [0, 0, -1, undefined, 'invalid index'],"
+              " [0, 0, 0, -1, 'invalid index'],"
+              "]"
+              ".every(as => {"
+              "   try {"
+              "       if (buf.compare(buf, as[0], as[1], as[2], as[3]) != as[4]) {"
+              "           throw new TypeError("
+              "                `buf.compare(${as[0]}, ${as[1]}, ${as[2]}, ${as[3]}) != ${as[4]}`);"
+              "       }"
+              "   } catch (e) { return e.message == as[4]}"
+              "   return true;"
+              "})"),
+      njs_str("true") },
 
-    { njs_str("var a = 5, b = 10, arr = [];"
-              "{let a = 4; var b = 1; arr.push(a); arr.push(b)}"
-              "arr.push(a); arr.push(b); arr"),
-      njs_str("4,1,5,1") },
+    { njs_str("var buf1 = Buffer.from('ABCD');"
+              "var buf2 = Buffer.from('ABCD');"
+              "buf1.compare(buf2, 5)"),
+      njs_str("RangeError: \"targetStart\" is out of range: 5") },
 
-    { njs_str("function func() {return x}"
-              "let x = 123;"
-              "func()"),
-      njs_str("123") },
+    { njs_str("var buf1 = Buffer.from('ABCD');"
+              "var buf2 = Buffer.from('ABCD');"
+              "buf1.compare(buf2, 0, 3, 5)"),
+      njs_str("RangeError: \"sourceStart\" is out of range: 5") },
 
-    { njs_str("function func() {return x}"
-              "func();"
-              "let x = 123"),
-      njs_str("ReferenceError: cannot access variable before initialization") },
+    { njs_str("var arr = new Uint8Array(4);"
+              "arr[0] = 0x41; arr[1] = 0x42; arr[2] = 0x43; arr[3] = 0x44;"
+              "arr = arr.subarray(1, 4);"
+              "var buf = Buffer.from('ABCD');"
+              "buf.compare(arr, 0, 3, 1, 4)"),
+      njs_str("0") },
 
-    { njs_str("function func() {return () => x}"
-              "let x = 123;"
-              "func()()"),
-      njs_str("123") },
+    { njs_str("['123', 'abc', '124', '', 'AB', 'ABCD']"
+              ".map(v=>Buffer.from(v)).sort(Buffer.compare).map(v=>v.toString())"),
+      njs_str(",123,124,AB,ABCD,abc") },
 
-    { njs_str("function func() {x = x + 1; let x}"),
-      njs_str("undefined") },
+    { njs_str("Buffer.compare(Buffer.alloc(1), 'text')"),
+      njs_str("TypeError: \"target\" argument must be an instance of Buffer or Uint8Array") },
 
-    { njs_str("function func() {return () => x}"
-              "func()();"
-              "let x = 123;"),
-      njs_str("ReferenceError: cannot access variable before initialization") },
+    { njs_str("Buffer.compare('text', Buffer.from('ACB'))"),
+      njs_str("TypeError: \"source\" argument must be an instance of Buffer or Uint8Array") },
 
-    { njs_str("var arr = [];"
-              ""
-              "for (var i = 0; i < 10; i++) {"
-              "    let x = i;"
-              ""
-              "    arr.push( (n) => {x += n; return x} );"
-              "}"
-              ""
-              "["
-              "    arr[0](2), arr[1](1), arr[2](4), arr[3](7), arr[4](0),"
-              "    arr[5](1), arr[6](2), arr[7](5), arr[8](8), arr[9](10)"
-              "]"),
-      njs_str("2,2,6,10,4,6,8,12,16,19") },
+    { njs_str("Buffer.concat()"),
+      njs_str("TypeError: \"list\" argument must be an instance of Array") },
 
-    { njs_str("var arr = [];"
-              ""
-              "for (let i = 0; i < 10; i++) {"
-              "    arr.push( (n) => {i += n; return i} );"
-              "}"
-              ""
-              "["
-              "    arr[0](2), arr[1](1), arr[2](4), arr[3](7), arr[4](0),"
-              "    arr[5](1), arr[6](2), arr[7](5), arr[8](8), arr[9](10)"
-              "]"),
-      njs_str("2,2,6,10,4,6,8,12,16,19") },
+    { njs_str("Buffer.concat([])"),
+      njs_str("") },
 
-    { njs_str("for (let i = 0; i < 1; i++) {"
-              "    let i = i + 2;"
-              "}"),
-      njs_str("ReferenceError: cannot access variable before initialization") },
+    { njs_str("Buffer.concat([new Uint16Array(10)])"),
+      njs_str("TypeError: \"list[0]\" argument must be an instance of Buffer or Uint8Array") },
 
-    { njs_str("let arr = [], res = [];"
-              "for (let i = 0, f = function() { return i }; i < 5; i++) {"
-              "    arr.push(f);"
-              "}"
-              "for (let i = 0; i < 5; i++) {"
-              "    res.push(arr[i]());"
-              "} res"),
-      njs_str("0,0,0,0,0") },
+    { njs_str("Buffer.concat([new Uint8Array(2), new Uint8Array(1)]).fill('abc')"),
+      njs_str("abc") },
 
-    { njs_str("let arr = [], res = [];"
-              "for (let i = 0; arr.push(() => i), i < 10; i++) {}"
-              "for (let k = 0; k < 10; k++) {res.push(arr[k]())}"
-              "res"),
-      njs_str("0,1,2,3,4,5,6,7,8,9") },
+    { njs_str("Buffer.concat([Buffer.from('AB'), Buffer.from('CD')])"),
+      njs_str("ABCD") },
 
-    { njs_str("let res = [];"
-              "for (let n in [1,2,3]) {res.push(n)}"
-              "res"),
-      njs_str("0,1,2") },
+    { njs_str("Buffer.concat([new Uint8Array(2), new Uint8Array(1)], 2).fill('abc')"),
+      njs_str("ab") },
 
-    { njs_str("let arr = [], res = [];"
-              ""
-              "for (let n in [1,2,3]) {"
-              "    arr.push(() => n);"
-              "}"
-              ""
-              "for (let n in arr) {"
-              "    res.push(arr[n]());"
-              "}"
-              "res"),
-      njs_str("0,1,2") },
+    { njs_str("Buffer.concat([new Uint8Array(2), new Uint8Array(1)], 6).fill('abc')"),
+      njs_str("abcabc") },
 
-    { njs_str("let arr = [];"
-              ""
-              "for (let n in [1,2,3]) {"
-              "    let n = 1;"
-              "    arr.push(n);"
-              "}"
-              "arr"),
-      njs_str("1,1,1") },
+    { njs_str(njs_declare_sparse_array("list", 2)
+              "list[0] = new Uint8Array(2); list[1] = new Uint8Array(3);"
+              "Buffer.concat(list).fill('ab');"),
+      njs_str("ababa") },
 
-    { njs_str("for (let n in [1,2,3]) {"
-              "    let n = n + 1;"
-              "}"),
-      njs_str("ReferenceError: cannot access variable before initialization") },
+    { njs_str("Buffer.concat([], '123')"),
+      njs_str("TypeError: \"length\" argument must be of type number") },
 
-    { njs_str("for (let n in [1,2,3]) {}"
-              "n"),
-      njs_str("ReferenceError: \"n\" is not defined") },
+    { njs_str("Buffer.concat([], -1)"),
+      njs_str("RangeError: \"length\" is out of range") },
 
-    { njs_str("for (let n in [1,n,3]) {}"),
-      njs_str("ReferenceError: cannot access variable before initialization") },
+    { njs_str("var buf = Buffer.from('α'); buf[1]"),
+      njs_str("177") },
 
-    { njs_str("(function() {"
-              "function f() {return x + 1}"
-              "function abc() {f()};"
-              "abc();"
-              "let x;"
-              "}())"),
-      njs_str("ReferenceError: cannot access variable before initialization") },
+    { njs_str("var buf = Buffer.from('α'); buf[1] = 1; njs.dump(buf)"),
+      njs_str("Buffer [206,1]") },
 
-    { njs_str("function func() {var x = 1; {let x = x + 1} } func()"),
-      njs_str("ReferenceError: cannot access variable before initialization") },
+    { njs_str("var arrBuf = new ArrayBuffer(16);"
+              "var buf = Buffer.from(arrBuf); buf.buffer === arrBuf"),
+      njs_str("true") },
 
-    { njs_str("if (false) let x = 1"),
-      njs_str("SyntaxError: let declaration cannot appear in a single-statement context in 1") },
+    { njs_str("["
+              " [[0], 4, '65,66,67,68,0,0,0,0,0,0'],"
+              " [[5], 4, '0,0,0,0,0,65,66,67,68,0'],"
+              " [[8], 2, '0,0,0,0,0,0,0,0,65,66'],"
+              " [[8,2,4], 2, '0,0,0,0,0,0,0,0,67,68'],"
+              " [[10], 0, '0,0,0,0,0,0,0,0,0,0'],"
+              "]"
+              ".every(args => {"
+              " var buf1 = Buffer.from('ABCD');"
+              " var buf2 = Buffer.alloc(10, 0);"
+              " var as = args[0];"
+              " var length = buf1.copy(buf2, as[0], as[1], as[2]);"
+              ""
+              " if (length != args[1]) {"
+              "   throw new TypeError(`buf1.copy(buf2, ${as[0]}, ${as[1]}, ${as[2]}): ${length} != ${args[1]}`)"
+              " }"
+              ""
+              " if (njs.dump(buf2) != `Buffer [${args[2]}]`) {"
+              "   throw new TypeError("
+              "     `buf1.copy(buf2, ${as[0]}, ${as[1]}, ${as[2]}): ${njs.dump(buf2)} != Buffer [${args[2]}]`);"
+              " }"
+              " return true;"
+              "})"),
+      njs_str("true") },
 
-    { njs_str("while (false) let x = 1"),
-      njs_str("SyntaxError: let declaration cannot appear in a single-statement context in 1") },
+    { njs_str("["
+              " [[0], 'ABCDEF'],"
+              " [[0,2], 'CDEFEF'],"
+              " [[0,2,6], 'CDEFEF'],"
+              " [[1,2,4], 'ACDDEF'],"
+              " [[1,2,3], 'ACCDEF']"
+              "]"
+              ".every(args => {"
+              " var buf = Buffer.from('ABCDEF');"
+              " var as = args[0];"
+              " buf.copy(buf, as[0], as[1], as[2]);"
+              ""
+              " if (buf.toString() != args[1]) {"
+              "   throw new TypeError("
+              "     `buf.copy(buf, ${as[0]}, ${as[1]}, ${as[2]}): buf.toString() != ${args[1]}`);"
+              " }"
+              " return true;"
+              "})"),
+      njs_str("true") },
 
-    { njs_str("for (;;) let x = 1"),
-      njs_str("SyntaxError: let declaration cannot appear in a single-statement context in 1") },
+    { njs_str("var buf1 = Buffer.from('ABCD');"
+              "var buf2 = Buffer.alloc(10, 0);"
+              "buf1.copy(buf2, -1)"),
+      njs_str("RangeError: invalid index") },
 
-    { njs_str("try {} catch (e) {let e}"),
-      njs_str("SyntaxError: \"e\" has already been declared in 1") },
+    { njs_str("var buf1 = Buffer.from('ABCD');"
+              "var buf2 = Buffer.alloc(10, 0);"
+              "buf1.copy(buf2, 0, -1)"),
+      njs_str("RangeError: invalid index") },
 
-    { njs_str("let arr = [], x = 2;"
-              "switch(true) {default: let x = 1; arr.push(x)}"
-              "arr.push(x); arr"),
-      njs_str("1,2") },
+    { njs_str("var buf1 = Buffer.from('ABCD');"
+              "var buf2 = Buffer.alloc(10, 0);"
+              "buf1.copy(buf2, 0, 5)"),
+      njs_str("RangeError: \"sourceStart\" is out of range: 5") },
 
-    { njs_str("switch(true) {case false: let x = 1; default: x = 2}"),
-      njs_str("ReferenceError: cannot access variable before initialization") },
+    { njs_str("var arr = new Uint8Array(4);"
+              "arr[0] = 0x41; arr[1] = 0x42; arr[2] = 0x43; arr[3] = 0x44;"
+              "arr = arr.subarray(1, 4);"
+              "var buf1 = Buffer.from(arr);"
+              "var buf2 = Buffer.alloc(10, 0);"
+              "var length = buf1.copy(buf2, 1, 1, 2); [length, njs.dump(buf2)]"),
+      njs_str("1,Buffer [0,67,0,0,0,0,0,0,0,0]") },
 
-    { njs_str("let res;"
-              "switch(true) {case true: let x = 1; default: x = 2; res = x} res"),
-      njs_str("2") },
+    { njs_str("var arr = new Uint8Array(4);"
+              "arr[0] = 0x41; arr[1] = 0x42; arr[2] = 0x43; arr[3] = 0x44;"
+              "arr = arr.subarray(1, 4);"
+              "var buf1 = Buffer.from(arr);"
+              "var buf2 = Buffer.alloc(10, 0);"
+              "var length = buf1.copy(buf2, 1, 1, 2); [length, njs.dump(buf2)]"),
+      njs_str("1,Buffer [0,67,0,0,0,0,0,0,0,0]") },
 
-    { njs_str("let null"),
-      njs_str("SyntaxError: Unexpected token \"null\" in 1") },
+    { njs_str("["
+              " ['ABC', 'ABCD', false],"
+              " ['ABCD', 'ABC', false],"
+              " ['ABC', 'ACB', false],"
+              " ['ACB', 'ABC', false],"
+              " ['ABC', 'ABC', true],"
+              " ['', 'ABC', false],"
+              " ['', '', true],"
+              "].every(args => {"
+              "   if (Buffer.from(args[0]).equals(Buffer.from(args[1])) != args[2]) {"
+              "       throw new TypeError("
+              "            `Buffer.from(${args[0]}).compare(Buffer.from(${args[1]})) != ${args[2]}`);"
+              "   }"
+              "   return true;"
+              "})"),
+      njs_str("true") },
 
-    { njs_str("let continue"),
-      njs_str("SyntaxError: Unexpected token \"continue\" in 1") },
+    { njs_str("Buffer.from([1,2]).equals(new ArrayBuffer(1))"),
+      njs_str("TypeError: \"target\" argument must be an instance of Buffer or Uint8Array") },
 
-    { njs_str("let undefined"),
-      njs_str("SyntaxError: \"undefined\" has already been declared in 1") },
+    { njs_str("Buffer.from([1,2]).equals(1)"),
+      njs_str("TypeError: \"target\" argument must be an instance of Buffer or Uint8Array") },
 
-    { njs_str("let a = 1; globalThis.a"),
-      njs_str("undefined") },
+    { njs_str("var buf = Buffer.alloc(4);"
+              "buf.fill('ZXZpbA==', 'base64')"),
+      njs_str("evil") },
 
-    { njs_str("if (false) {x = 2} else {x = 1} let x;"),
-      njs_str("ReferenceError: cannot access variable before initialization") },
+    { njs_str("var buf = Buffer.alloc(4);"
+              "buf.fill('6576696c', 'hex')"),
+      njs_str("evil") },
 
-    { njs_str("let let"),
-      njs_str("SyntaxError: Unexpected token \"let\" in 1") },
+    { njs_str("var buf = Buffer.alloc(4);"
+              "buf.fill('ZXZpbA==', '')"),
+      njs_str("TypeError: \"\" encoding is not supported") },
 
-    { njs_str("let null"),
-      njs_str("SyntaxError: Unexpected token \"null\" in 1") },
+    { njs_str("var buf = Buffer.alloc(8);"
+              "buf.fill('6576696c', 'hex')"),
+      njs_str("evilevil") },
 
-    { njs_str("function let() {}"),
-      njs_str("SyntaxError: Unexpected token \"let\" in 1") },
+    { njs_str("var buf = Buffer.alloc(10);"
+              "buf.fill('evil')"),
+      njs_str("evilevilev") },
 
-    { njs_str("function static() {}"),
-      njs_str("SyntaxError: Unexpected token \"static\" in 1") },
+    { njs_str("var buf = Buffer.allocUnsafe(5);"
+              "buf[3] = 1;"
+              "buf.fill(''); njs.dump(buf)"),
+      njs_str("Buffer [0,0,0,0,0]") },
 
-    /* const */
+    { njs_str("var arr = new Uint8Array(4);"
+              "arr[0] = 0x41; arr[1] = 0x42; arr[2] = 0x43; arr[3] = 0x44;"
+              "arr = arr.subarray(1, 4);"
+              "var buf = Buffer.allocUnsafe(6);"
+              "buf.fill(arr); njs.dump(buf)"),
+      njs_str("Buffer [66,67,68,66,67,68]") },
 
-    { njs_str("const x"),
-      njs_str("SyntaxError: missing initializer in const declaration") },
+    { njs_str("var buf = Buffer.alloc(6, 'ABCDEF');"
+              "buf.fill(buf, 2, 6)"),
+      njs_str("ABABCD") },
 
-    { njs_str("const x = 1; x"),
-      njs_str("1") },
+    { njs_str("Buffer.alloc(6).fill(0x41)"),
+      njs_str("AAAAAA") },
 
-    { njs_str("const x = 1; x = 1"),
-      njs_str("TypeError: assignment to constant variable") },
+    { njs_str("Buffer.alloc(6).fill({valueOf(){return 0x42}})"),
+      njs_str("BBBBBB") },
 
-    { njs_str("function abc() {const x}"),
-      njs_str("SyntaxError: missing initializer in const declaration") },
+    { njs_str("njs.dump(Buffer.alloc(3).fill(-1))"),
+      njs_str("Buffer [255,255,255]") },
 
-    { njs_str("const x = [123]; x"),
-      njs_str("123") },
+    { njs_str("[NaN, Infinity, -Infinity, undefined, null, {}]"
+              ".every(v => njs.dump(Buffer.alloc(3).fill(v)) == 'Buffer [0,0,0]')"),
+      njs_str("true") },
 
-    { njs_str("const x = () => x; x()"),
-      njs_str("[object Function]") },
+    { njs_str("njs.dump(Buffer.alloc(6).fill({valueOf(){throw 'Oops'}}, 4,3))"),
+      njs_str("Buffer [0,0,0,0,0,0]") },
 
-    { njs_str("const x = (() => x)()"),
-      njs_str("ReferenceError: cannot access variable before initialization") },
+    { njs_str("njs.dump(Buffer.alloc(6).fill({valueOf(){throw 'Oops'}}, 3,3))"),
+      njs_str("Buffer [0,0,0,0,0,0]") },
 
-    { njs_str("x; const x = 123"),
-      njs_str("ReferenceError: cannot access variable before initialization") },
+    { njs_str("njs.dump(Buffer.alloc(6).fill({valueOf(){throw 'Oops'}}, 2,3))"),
+      njs_str("Oops") },
 
-    { njs_str("const x = x + 123"),
-      njs_str("ReferenceError: cannot access variable before initialization") },
+    { njs_str("njs.dump(Buffer.alloc(5).fill('α'))"),
+      njs_str("Buffer [206,177,206,177,206]") },
 
-    { njs_str("const x; var x"),
-      njs_str("SyntaxError: \"x\" has already been declared in 1") },
+    { njs_str("Buffer.alloc(4).fill('ABCD', -1)"),
+      njs_str("RangeError: invalid index") },
 
-    { njs_str("const x; let x"),
-      njs_str("SyntaxError: \"x\" has already been declared in 1") },
+    { njs_str("Buffer.alloc(4).fill('ABCD', 5)"),
+      njs_str("RangeError: \"offset\" is out of range") },
 
-    { njs_str("let x; const x"),
-      njs_str("SyntaxError: \"x\" has already been declared in 1") },
+    { njs_str("Buffer.alloc(4).fill('ABCD', 0, -1)"),
+      njs_str("RangeError: invalid index") },
 
-    { njs_str("const x = 1; function x() {}"),
-      njs_str("SyntaxError: \"x\" has already been declared in 1") },
+    { njs_str("Buffer.alloc(4).fill('ABCD', 0, 5)"),
+      njs_str("RangeError: \"end\" is out of range") },
 
-    { njs_str("function x() {} const x = 1"),
-      njs_str("SyntaxError: \"x\" has already been declared in 1") },
+    { njs_str("Buffer.alloc(513).fill('A'.repeat(512)).length"),
+      njs_str("513") },
 
-    { njs_str("function x() {const x; var x}"),
-      njs_str("SyntaxError: \"x\" has already been declared in 1") },
+    { njs_str("njs.dump(Buffer.alloc(4).fill((new Uint8Array(5)).fill(1)))"),
+      njs_str("Buffer [1,1,1,1]") },
 
-    { njs_str("function x() {var x; const x}"),
-      njs_str("SyntaxError: \"x\" has already been declared in 1") },
+    { njs_str("var src = new Uint8Array(10).fill(255);"
+              "var u8 = new Uint8Array(src.buffer, 1, 8);"
+              "u8.set([1,2,3,4,5,6,7,8]);"
+              "njs.dump(Buffer.alloc(9).fill(u8))"),
+      njs_str("Buffer [1,2,3,4,5,6,7,8,1]") },
 
-    { njs_str("const x = function f() {const f = 1}"),
-      njs_str("undefined") },
+    { njs_str("Buffer.alloc(513).fill((new Uint8Array(512)).fill(1)).length"),
+      njs_str("513") },
 
-    { njs_str("let res; const x = 1;"
-              "{const x = 2; res = x}"
-              "[x, res]"),
-      njs_str("1,2") },
+    { njs_str("Buffer.alloc(4).fill('ABCD', undefined, undefined, 'utf-128')"),
+      njs_str("TypeError: \"utf-128\" encoding is not supported") },
 
-    { njs_str("let res; const x = 1;"
-              "if (true) {const x = 2; res = x}"
-              "[x, res]"),
-      njs_str("1,2") },
+    { njs_str("var buf1 = Buffer.from('ABCD').subarray(1, 3);"
+              "buf1.fill('B', 1, 2); njs.dump(buf1)"),
+      njs_str("Buffer [66,66]") },
 
-    { njs_str("function func() {return x}"
-              "const x = 123;"
-              "func()"),
-      njs_str("123") },
+    { njs_str("var buf1 = Buffer.from('ABCD').subarray(1, 3);"
+              "buf1.fill(0x42, 1, 2); njs.dump(buf1)"),
+      njs_str("Buffer [66,66]") },
 
-    { njs_str("function func() {return x}"
-              "func();"
-              "const x = 123"),
-      njs_str("ReferenceError: cannot access variable before initialization") },
+    { njs_str("var buf1 = Buffer.from('ABCD').subarray(1, 2);"
+              "var buf2 = Buffer.from('ABCD').subarray(1, 3);"
+              "buf2.fill(buf1, 1, 2); njs.dump(buf2)"),
+      njs_str("Buffer [66,66]") },
 
-    { njs_str("function func() {return () => x}"
-              "const x = 123;"
-              "func()()"),
-      njs_str("123") },
+    { njs_str("var buf = Buffer.from('ABCD');"
+              "['BC', 'CB', 'ABCD', 'ABCDE', ''].map(v=>buf.indexOf(v))"),
+      njs_str("1,-1,0,-1,0") },
 
-    { njs_str("function func() {return () => x++}"
-              "const x = 123;"
-              "func()()"),
-      njs_str("TypeError: assignment to constant variable") },
+    { njs_str("var buf = Buffer.from('ABCD');"
+              "[0,5,-2,-1].map(v=>buf.indexOf('C', v))"),
+      njs_str("2,-1,2,-1") },
 
-    { njs_str("for (const i = 0; i < 1; i++) {}"),
-      njs_str("TypeError: assignment to constant variable") },
+    { njs_str("var buf = Buffer.from('evil');"
+              "buf.indexOf('ZXZpbA==', undefined, 'base64')"),
+      njs_str("0") },
 
-    { njs_str("let res = [];"
-              "for (const n in [1,2,3]) {res.push(n)}"
-              "res"),
-      njs_str("0,1,2") },
+    { njs_str("var buf = Buffer.from('evil');"
+              "buf.indexOf('6576696c', undefined, 'hex')"),
+      njs_str("0") },
 
-    { njs_str("let arr = [], res = [];"
-              ""
-              "for (const n in [1,2,3]) {"
-              "    arr.push(() => n);"
-              "}"
-              ""
-              "for (let n in arr) {"
-              "    res.push(arr[n]());"
-              "}"
-              "res"),
-      njs_str("0,1,2") },
+    { njs_str("var buf = Buffer.from('ABCD');"
+              "buf.indexOf('C', undefined, 'utf-128')"),
+      njs_str("TypeError: \"utf-128\" encoding is not supported") },
 
-    { njs_str("let arr = [];"
-              ""
-              "for (const n in [1,2,3]) {"
-              "    let n = 1;"
-              "    arr.push(n);"
-              "}"
-              "arr"),
-      njs_str("1,1,1") },
+    { njs_str("var buf = Buffer.from('ABCDABC');"
+              "['BC', 'CB', 'ABCD', 'ABCDE', '', 'C', 'ABCDABCD'].map(v=>buf.indexOf(Buffer.from(v)))"),
+      njs_str("1,-1,0,-1,0,2,-1") },
 
-    { njs_str("for (const n in [1,2,3]) {"
-              "    let n = n + 1;"
-              "}"),
-      njs_str("ReferenceError: cannot access variable before initialization") },
+    { njs_str("var buf = Buffer.from('ABCDABC');"
+              "['BC', 'CB', 'ABCD', 'ABCDE', '', 'C', 'ABCDABCD'].map(v=>buf.includes(Buffer.from(v)))"),
+      njs_str("true,false,true,false,true,true,false") },
 
-    { njs_str("for (const n in [1,2,3]) {}"
-              "n"),
-      njs_str("ReferenceError: \"n\" is not defined") },
+    { njs_str("var buf = Buffer.from('ZABCDABC').subarray(1);"
+              "['BC', 'CB', 'ABCD', 'ABCDE', '', 'C', 'ABCDABCD'].map(v=>buf.indexOf(Buffer.from(v)))"),
+      njs_str("1,-1,0,-1,0,2,-1") },
 
-    { njs_str("for (const n in [1,n,3]) {}"),
-      njs_str("ReferenceError: cannot access variable before initialization") },
+    { njs_str("var buf = Buffer.from('ABCD');"
+              "buf.indexOf(0x43)"),
+      njs_str("2") },
 
-    { njs_str("(function() {"
-              "function f() {return x + 1}"
-              "function abc() {f()};"
-              "abc();"
-              "const x = 1;"
-              "}())"),
-      njs_str("ReferenceError: cannot access variable before initialization") },
+    { njs_str("var buf = Buffer.from('ABCD');"
+              "buf.indexOf(0x43, -2)"),
+      njs_str("2") },
 
-    { njs_str("if (false) const x = 1"),
-      njs_str("SyntaxError: const declaration cannot appear in a single-statement context in 1") },
+    { njs_str("var buf = Buffer.from('ABCD');"
+              "buf.indexOf(0x43, -1)"),
+      njs_str("-1") },
 
-    { njs_str("while (false) const x = 1"),
-      njs_str("SyntaxError: const declaration cannot appear in a single-statement context in 1") },
+    { njs_str("var buf1 = Buffer.from('ABCD');"
+              "var buf2 = Buffer.from('XXCX').subarray(2, 3);"
+              "buf1.indexOf(buf2)"),
+      njs_str("2") },
 
-    { njs_str("for (;;) const x = 1"),
-      njs_str("SyntaxError: const declaration cannot appear in a single-statement context in 1") },
+    { njs_str("var buf1 = Buffer.from('ABCD').subarray(1, 4);"
+              "buf1.indexOf(0x43)"),
+      njs_str("1") },
 
-    { njs_str("try {} catch (e) {const e = 1}"),
-      njs_str("SyntaxError: \"e\" has already been declared in 1") },
+    { njs_str("var buf1 = Buffer.from('ABCD').subarray(1, 4);"
+              "buf1.indexOf('C')"),
+      njs_str("1") },
 
-    { njs_str("let arr = []; const x = 2;"
-              "switch(true) {default: const x = 1; arr.push(x)}"
-              "arr.push(x); arr"),
-      njs_str("1,2") },
+    { njs_str("var buf = Buffer.from('ABCDABC');"
+              "['BC', 'CB', 'ABCD', 'ABCDE', '', 'C', 'ABCDABCD'].map(v=>buf.lastIndexOf(v))"),
+      njs_str("5,-1,0,-1,7,6,-1") },
 
-    { njs_str("let res;"
-              "switch(true) {case true: const x = 1; default: x = 2; res = x} res"),
-      njs_str("TypeError: assignment to constant variable") },
+    { njs_str("var buf = Buffer.from('ABCDABC');"
+              "['BC', 'CB', 'ABCD', 'ABCDE', '', 'C', 'ABCDABCD'].map(v=>buf.lastIndexOf(Buffer.from(v)))"),
+      njs_str("5,-1,0,-1,7,6,-1") },
 
-    { njs_str("const null"),
-      njs_str("SyntaxError: Unexpected token \"null\" in 1") },
+    { njs_str("var buf = Buffer.from('ZABCDABC').subarray(1);"
+              "['BC', 'CB', 'ABCD', 'ABCDE', '', 'C', 'ABCDABCD'].map(v=>buf.lastIndexOf(v))"),
+      njs_str("5,-1,0,-1,7,6,-1") },
 
-    { njs_str("const continue"),
-      njs_str("SyntaxError: Unexpected token \"continue\" in 1") },
+    { njs_str("var buf = Buffer.from('ZABCDABC').subarray(1);"
+              "['BC', 'CB', 'ABCD', 'ABCDE', '', 'C', 'ABCDABCD'].map(v=>buf.lastIndexOf(Buffer.from(v)))"),
+      njs_str("5,-1,0,-1,7,6,-1") },
 
-    { njs_str("const undefined"),
-      njs_str("SyntaxError: \"undefined\" has already been declared in 1") },
+    { njs_str("var buf = Buffer.from('CABCD');"
+              "[2,-2,1,-10,10,-5,-4,0].map(v=>buf.lastIndexOf('C', v))"),
+      njs_str("0,3,0,-1,3,0,0,0") },
 
-    { njs_str("const a = 1; globalThis.a"),
-      njs_str("undefined") },
+    { njs_str("var buf = Buffer.from('CABCD');"
+              "[2,-2,1,-10,10,-5,-4,0].map(v=>buf.lastIndexOf(Buffer.from('CZ').subarray(0,1), v))"),
+      njs_str("0,3,0,-1,3,0,0,0") },
 
-    { njs_str("if (false) {x = 2} else {x = 1} const x = 0"),
-      njs_str("ReferenceError: cannot access variable before initialization") },
+    { njs_str("var buf = Buffer.from('CABCD');"
+              "buf.lastIndexOf(0x43)"),
+      njs_str("3") },
 
-    { njs_str("const const"),
-      njs_str("SyntaxError: Unexpected token \"const\" in 1") },
+    { njs_str("var buf = Buffer.from('CABCD');"
+              "[2,1,0,4,5,-1,-5].map(v=>buf.lastIndexOf(0x43, v))"),
+      njs_str("0,0,0,3,3,3,0") },
 
-    /* Async/Await */
+    { njs_str("var buf1 = Buffer.from('ACBCD').subarray(1, 4);"
+              "var buf2 = Buffer.from('C');"
+              "buf1.lastIndexOf(buf2)"),
+      njs_str("2") },
 
-    { njs_str("async function f() {}; f.prototype"),
-      njs_str("undefined") },
+    { njs_str("var buf1 = Buffer.from('XXCXX').subarray(2,3);"
+              "buf1.lastIndexOf(Buffer.from('X'))"),
+      njs_str("-1") },
 
-    { njs_str("async function f() {await 1}"),
-      njs_str("undefined") },
+    { njs_str("var buf = Buffer.from('ACBCD').subarray(1, 4);"
+              "buf.lastIndexOf(0x43)"),
+      njs_str("2") },
 
-    { njs_str("function f() {await 1}"),
-      njs_str("SyntaxError: await is only valid in async functions in 1") },
+    { njs_str("var buf = Buffer.from('ACBCD').subarray(1, 4);"
+              "buf.lastIndexOf('C')"),
+      njs_str("2") },
 
-    { njs_str("async function f() {function a() {await 1}}"),
-      njs_str("SyntaxError: await is only valid in async functions in 1") },
+    { njs_str("['swap16', 'swap32', 'swap64'].every(method => {"
+              "    var buf = Buffer.from([]);"
+              "    buf[method]();"
+              "    return njs.dump(buf) === 'Buffer []';"
+              "})"),
+      njs_str("true") },
 
-    { njs_str("async function f() {() => {await 1}}"),
-      njs_str("SyntaxError: await is only valid in async functions in 1") },
+    { njs_str("['swap16', 'swap32', 'swap64'].every(method => {"
+              "    var buf = Buffer.from([1,2,3]);"
+              "    try { buf[method]() } "
+              "    catch(e) {return e.message === `Buffer size must be a multiple of ${method.substr(4)}-bits`};"
+              "})"),
+      njs_str("true") },
 
-    { njs_str("function f() {async () => {await 1}}"),
-      njs_str("undefined") },
+    { njs_str("['swap16', 'swap32', 'swap64'].map(method => {"
+              "    var buf = Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]);"
+              "    buf[method]();"
+              "    return njs.dump(buf);"
+              "})"),
+      njs_str("Buffer [2,1,4,3,6,5,8,7],"
+              "Buffer [4,3,2,1,8,7,6,5],"
+              "Buffer [8,7,6,5,4,3,2,1]") },
 
-    { njs_str("let f = async () => {await 1}"),
-      njs_str("undefined") },
+    { njs_str("['swap16', 'swap32', 'swap64'].map(method => {"
+              "    var u8 = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8]);"
+              "    var buf = Buffer.from(u8.buffer, 1);"
+              "    buf[method]();"
+              "    return njs.dump(buf);"
+              "})"),
+      njs_str("Buffer [2,1,4,3,6,5,8,7],"
+              "Buffer [4,3,2,1,8,7,6,5],"
+              "Buffer [8,7,6,5,4,3,2,1]") },
 
-    { njs_str("let f = () => {await 1}"),
-      njs_str("SyntaxError: await is only valid in async functions in 1") },
+    { njs_str("njs.dump(Buffer.from('αααα').toJSON())"),
+      njs_str("{type:'Buffer',data:[206,177,206,177,206,177,206,177]}") },
 
-    { njs_str("(async function() {await 1})"),
-      njs_str("[object AsyncFunction]") },
+    { njs_str("njs.dump(Buffer.from('').toJSON())"),
+      njs_str("{type:'Buffer',data:[]}") },
 
-    { njs_str("(function() {await 1})"),
-      njs_str("SyntaxError: await is only valid in async functions in 1") },
+    { njs_str("["
+              " [['base64'], 'ZXZpbA=='],"
+              " [['base64url'], 'ZXZpbA'],"
+              " [['hex'], '6576696c'],"
+              " [[undefined,1,3], 'vi'],"
+              " [[undefined,5], ''],"
+              " [[undefined,undefined,5], 'evil'],"
+              " [[undefined,undefined,undefined], 'evil'],"
+              "].every(args => {"
+              "   var buf = Buffer.from('evil');"
+              "   var as = args[0];"
+              "   if (buf.toString(as[0], as[1], as[2]) != args[1]) {"
+              "       throw new TypeError("
+              "            `buf.toString(${as[0]}, ${as[1]}, ${as[2]}) != ${args[1]}`);"
+              "   }"
+              "   return true;"
+              "})"),
+      njs_str("true") },
 
-    { njs_str("let ctor = Object.getPrototypeOf(async function(){}).constructor;"
-              "ctor"),
-      njs_str("[object Function]") },
+    { njs_str("Buffer.from('evil').toString('utf-128')"),
+      njs_str("TypeError: \"utf-128\" encoding is not supported") },
 
-    { njs_str("let ctor = Object.getPrototypeOf(async function(){}).constructor;"
-              "ctor()"),
-      njs_str("[object AsyncFunction]") },
+    { njs_str("var buf = Buffer.allocUnsafe(4);"
+              "var len = buf.write('ZXZpbA==', 'base64'); [len, buf]"),
+      njs_str("4,evil") },
 
-    { njs_str("let ctor = Object.getPrototypeOf(async function(){}).constructor;"
-              "new ctor();"),
-      njs_str("[object AsyncFunction]") },
+    { njs_str("var buf = Buffer.allocUnsafe(4);"
+              "var len = buf.write('ZXZpbA==', undefined, 'base64'); [len, buf]"),
+      njs_str("4,evil") },
 
-    { njs_str("let f = new Function('x', 'await 1; return x'); f(1)"),
-      njs_str("SyntaxError: await is only valid in async functions in runtime:1") },
+    { njs_str("var buf = Buffer.allocUnsafe(4);"
+              "var len = buf.write('ZXZpbA==', undefined, undefined, 'base64'); [len, buf]"),
+      njs_str("4,evil") },
 
-    { njs_str("new AsyncFunction()"),
-      njs_str("ReferenceError: \"AsyncFunction\" is not defined") },
+    { njs_str("Buffer.allocUnsafe(4).write()"),
+      njs_str("TypeError: first argument must be a string") },
 
-    { njs_str("(async function() {console.log(await 111)})"),
-      njs_str("SyntaxError: await in arguments not supported in 1") },
+    { njs_str("Buffer.allocUnsafe(4).write({a: 1})"),
+      njs_str("TypeError: first argument must be a string") },
 
-    { njs_str("(async function() {console.log('Number: ' + await 111)})"),
-      njs_str("SyntaxError: await in arguments not supported in 1") },
+    { njs_str("Buffer.alloc(4).write('evil', 4, 1);"),
+      njs_str("RangeError: \"offset\" is out of range") },
 
-    { njs_str("function f(a) {}"
-              "(async function() {f(await 111)})"),
-      njs_str("SyntaxError: await in arguments not supported in 1") },
+    { njs_str("Buffer.alloc(4).write('evil', -1);"),
+      njs_str("RangeError: invalid index") },
 
-    { njs_str("async () => [await x(1)(),]; async () => [await x(1)()]"),
-      njs_str("[object AsyncFunction]") },
+    { njs_str("var buf = Buffer.alloc(4);"
+              "var len = buf.write('evil', 3, 1); [len, njs.dump(buf)]"),
+      njs_str("1,Buffer [0,0,0,101]") },
 
-    { njs_str("function f(a, b, c) {}"
-              "(async function() {f(1, 'a', await 111)})"),
-      njs_str("SyntaxError: await in arguments not supported in 1") },
+    { njs_str("var buf = Buffer.alloc(4);"
+              "var len = buf.write('evil', 0, 5); [len, buf]"),
+      njs_str("4,evil") },
 
-    { njs_str("function f(a) {}"
-              "(async function() {f('Number: ' + await 111)})"),
-      njs_str("SyntaxError: await in arguments not supported in 1") },
+    { njs_str("Buffer.alloc(4).write('evil', undefined, -1);"),
+      njs_str("RangeError: invalid index") },
 
-    { njs_str("async function af() {await encrypt({},}"),
-      njs_str("SyntaxError: Unexpected token \"}\" in 1") },
+    { njs_str("var buf = Buffer.from([0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0xF9, 0xf8]);"
+              "[1,2,3,4,5,6].map(byte => [buf.readUIntLE(0, byte), buf.readUIntLE(1, byte)])"),
+      njs_str("250,251,"
+              "64506,64763,"
+              "16579578,16645371,"
+              "4261215226,4278058235,"
+              "1095182908410,1099494718715,"
+              "281470647991290,274877890034939") },
 
-    { njs_str("let x = {async af() {await Promise.resolve(1)}}; x.af"),
-      njs_str("[object AsyncFunction]") },
+    { njs_str("var buf = Buffer.from([0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0xF9, 0xf8]);"
+              "[1,2,3,4,5,6].map(byte => [buf.readIntLE(0, byte), buf.readIntLE(1, byte)])"),
+      njs_str("-6,-5,"
+              "-1030,-773,"
+              "-197638,-131845,"
+              "-33752070,-16909061,"
+              "-4328719366,-16909061,"
+              "-4328719366,-6597086675717") },
 
-    { njs_str("let name = 'af', x = {async [name]() {await Promise.resolve(1)}}; x.af"),
-      njs_str("[object AsyncFunction]") },
-};
+    { njs_str("var buf = Buffer.from([0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0xF9, 0xf8]);"
+              "[1,2,3,4,5,6].map(byte => [buf.readUIntBE(0, byte), buf.readUIntBE(1, byte)])"),
+      njs_str("250,251,"
+              "64251,64508,"
+              "16448508,16514301,"
+              "4210818301,4227661310,"
+              "1077969485310,1082281295615,"
+              "275960188239615,277064011677689") },
 
+    { njs_str("var buf = Buffer.from([0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0xF9, 0xf8]);"
+              "[1,2,3,4,5,6].map(byte => [buf.readIntBE(0, byte), buf.readIntBE(1, byte)])"),
+      njs_str("-6,-5,"
+              "-1285,-1028,"
+              "-328708,-262915,"
+              "-84148995,-67305986,"
+              "-21542142466,-17230332161,"
+              "-5514788471041,-4410965032967") },
 
-static njs_unit_test_t  njs_safe_test[] =
-{
-    { njs_str("(new Function('return this'))() === globalThis"),
+    { njs_str("var buf = Buffer.from([0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0xF9, 0xf8]);"
+              "function t(sign, endianness, offset) { "
+              "    return [1,2,4].every(size => {"
+              "        var method = `read${sign}Int${size * 8}`;"
+              "        if (size > 1) { method += endianness};"
+              "        var gmethod = `read${sign}Int${endianness}`;"
+              "        var gv = buf[gmethod](offset, size);"
+              "        var sv = buf[method](offset);"
+              "        if (gv != sv) {throw Error(`${gmethod}(${offset},${size}):${gv} != ${method}(${offset}):${sv}`)}"
+              "        return true;"
+              "   });"
+              "}; "
+              "t('U', 'LE', 0) && t('U', 'LE', 1)"
+              "&& t('', 'LE', 0) && t('', 'LE', 1)"
+              "&& t('U', 'BE', 0) && t('U', 'BE', 1)"
+              "&& t('', 'BE', 0) && t('', 'BE', 1)"),
       njs_str("true") },
 
-    { njs_str("(new Function('return this;'))() === globalThis"),
+    { njs_str("var buf = Buffer.alloc(9);"
+              "function t(sign, endianness, offset) { "
+              "    return [1,2,4].every(size => {"
+              "        var rgmethod = `read${sign}Int${endianness}`;"
+              "        var wgmethod = `write${sign}Int${endianness}`;"
+              "        var rmethod = `read${sign}Int${size * 8}`;"
+              "        var wmethod = `write${sign}Int${size * 8}`;"
+              "        if (size > 1) { rmethod += endianness; wmethod += endianness; };"
+              "        var v = 0x7abbccddeeff & (size * 8 - 1);"
+              ""
+              "        var ret = buf[wgmethod](v, offset, size);"
+              "        if(ret !== offset + size) {"
+              "            throw Error(`${wgmethod} returned ${ret}, need ${offset + size}`);"
+              "        }"
+              ""
+              "        var gv = buf[rgmethod](offset, size);"
+              ""
+              "        buf.fill(0);"
+              "        buf[wmethod](v, offset);"
+              "        var sv = buf[rmethod](offset);"
+              "        if (gv != sv) {throw Error(`${wmethod}(${v}, ${offset}):${sv} != ${wgmethod}(${v},${offset}):${gv}`)}"
+              "        return true;"
+              "   });"
+              "}; "
+              "t('U', 'LE', 0) && t('U', 'LE', 1)"
+              "&& t('', 'LE', 0) && t('', 'LE', 1)"
+              "&& t('U', 'BE', 0) && t('U', 'BE', 1)"
+              "&& t('', 'BE', 0) && t('', 'BE', 1)"),
       njs_str("true") },
 
-    { njs_str("(new Function('return    this  '))() === globalThis"),
-      njs_str("true") },
+    { njs_str(njs_buffer_byte_map("writeUIntLE", "+", 1)),
+      njs_str("Buffer [128,0,0,0,0,0],"
+              "Buffer [0,64,0,0,0,0],"
+              "Buffer [0,0,32,0,0,0],"
+              "Buffer [0,0,0,16,0,0],"
+              "Buffer [0,0,0,0,8,0],"
+              "Buffer [0,0,0,0,0,4]") },
 
-    { njs_str("(new Function('return thi'))()"),
-      njs_str("TypeError: function constructor is disabled in \"safe\" mode") },
+    { njs_str(njs_buffer_byte_map("writeUIntBE", "+", 1)),
+      njs_str("Buffer [128,0,0,0,0,0],"
+              "Buffer [64,0,0,0,0,0],"
+              "Buffer [32,0,0,0,0,0],"
+              "Buffer [16,0,0,0,0,0],"
+              "Buffer [8,0,0,0,0,0],"
+              "Buffer [4,0,0,0,0,0]") },
 
-    { njs_str("(new Function('){return 1337})//', 'return this'))()"),
-      njs_str("TypeError: function constructor is disabled in \"safe\" mode") },
-};
+    { njs_str(njs_buffer_byte_map("writeIntLE", "-", 2)),
+      njs_str("Buffer [192,0,0,0,0,0],"
+              "Buffer [0,224,0,0,0,0],"
+              "Buffer [0,0,240,0,0,0],"
+              "Buffer [0,0,0,248,0,0],"
+              "Buffer [0,0,0,0,252,0],"
+              "Buffer [0,0,0,0,0,254]") },
 
+    { njs_str(njs_buffer_byte_map("writeIntBE", "-", 2)),
+      njs_str("Buffer [192,0,0,0,0,0],"
+              "Buffer [224,0,0,0,0,0],"
+              "Buffer [240,0,0,0,0,0],"
+              "Buffer [248,0,0,0,0,0],"
+              "Buffer [252,0,0,0,0,0],"
+              "Buffer [254,0,0,0,0,0]") },
 
-static njs_unit_test_t  njs_denormals_test[] =
-{
-    { njs_str("2.2250738585072014e-308"),
-      njs_str("2.2250738585072014e-308") },
+    { njs_str("Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]).readDoubleBE()"),
+      njs_str("8.20788039913184e-304") },
 
-#ifndef NJS_SUNC
-    { njs_str("2.2250738585072014E-308.toString(2) == ('0.' + '0'.repeat(1021) + '1')"),
-      njs_str("true") },
+    { njs_str("Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]).readDoubleLE()"),
+      njs_str("5.447603722011605e-270") },
 
-    { njs_str("Number('2.2250738585072014E-323')"),
-      njs_str("2.5e-323") },
+    { njs_str("Buffer.from([1, 2, 3, 4]).readFloatBE()"),
+      njs_str("2.387939260590663e-38") },
 
-    { njs_str("Number('2.2250738585072014E-323') + 0"),
-      njs_str("2.5e-323") },
+    { njs_str("Buffer.from([1, 2, 3, 4]).readFloatLE()"),
+      njs_str("1.539989614439558e-36") },
 
-    /* Smallest positive double (next_double(0)). */
-    { njs_str("5E-324.toString(36) === '0.' + '0'.repeat(207) + '3'"),
-      njs_str("true") },
+    { njs_str("Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]).readDoubleBE(1)"),
+      njs_str("RangeError: index 1 is outside the bound of the buffer") },
 
-    /* Maximum fraction length. */
-    { njs_str("2.2250738585072014E-323.toString(2) == ('0.' + '0'.repeat(1071) + '101')"),
-      njs_str("true") },
+    { njs_str("Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]).readDoubleLE(1)"),
+      njs_str("RangeError: index 1 is outside the bound of the buffer") },
 
-    /* Denormals. */
-    { njs_str("var zeros = count => '0'.repeat(count);"
-              "["
-              "  [1.8858070859709815e-308, `0.${zeros(1022)}1101100011110111011100000100011001111101110001010111`],"
-              // FIXME: "  [Number.MIN_VALUE, `0.${zeros(1073)}1`]"
-              "  [-5.06631661953108e-309, `-0.${zeros(1024)}11101001001010000001101111010101011111111011010111`],"
-              "  [6.22574126804e-313, `0.${zeros(1037)}11101010101101100111000110100111001`],"
-              "  [-4e-323, `-0.${zeros(1070)}1`],"
-              "].every(t=>t[0].toString(2) === t[1])"),
-      njs_str("true") },
+    { njs_str("Buffer.from([1, 2, 3, 4]).readFloatBE(1)"),
+      njs_str("RangeError: index 1 is outside the bound of the buffer") },
 
-    { njs_str("4.94065645841246544176568792868e-324.toExponential()"),
-      njs_str("5e-324") },
+    { njs_str("Buffer.from([1, 2, 3, 4]).readFloatLE(1)"),
+      njs_str("RangeError: index 1 is outside the bound of the buffer") },
 
-    { njs_str("4.94065645841246544176568792868e-324.toExponential(10)"),
-      njs_str("4.9406564584e-324") },
-#endif
+    { njs_str("var buf = Buffer.allocUnsafe(8);"
+              "buf.writeDoubleBE(123.456); njs.dump(buf)"),
+      njs_str("Buffer [64,94,221,47,26,159,190,119]") },
 
-};
+    { njs_str("var buf = Buffer.allocUnsafe(8);"
+              "buf.writeDoubleLE(123.456); njs.dump(buf)"),
+      njs_str("Buffer [119,190,159,26,47,221,94,64]") },
 
+    { njs_str("var buf = Buffer.allocUnsafe(4);"
+              "buf.writeFloatBE(123.456); njs.dump(buf)"),
+      njs_str("Buffer [66,246,233,121]") },
 
-static njs_unit_test_t  njs_disabled_denormals_test[] =
-{
-    { njs_str("Number('2.2250738585072014E-323')"),
-      njs_str("0") },
+    { njs_str("var buf = Buffer.allocUnsafe(4);"
+              "buf.writeFloatLE(123.456); njs.dump(buf)"),
+      njs_str("Buffer [121,233,246,66]") },
 
-    { njs_str("Number('2.2250738585072014E-323') + 0"),
-      njs_str("0") },
+    { njs_str("var buf = Buffer.allocUnsafe(8).writeDoubleBE(123.456, 1)"),
+      njs_str("RangeError: index 1 is outside the bound of the buffer") },
 
-    /* Smallest positive double (next_double(0)). */
-    { njs_str("5E-324.toString(36)"),
-      njs_str("0") },
+    { njs_str("var buf = Buffer.allocUnsafe(8).writeDoubleLE(123.456, 1)"),
+      njs_str("RangeError: index 1 is outside the bound of the buffer") },
 
-    { njs_str("2.2250738585072014E-323.toString(2)"),
-      njs_str("0") },
+    { njs_str("var buf = Buffer.allocUnsafe(4).writeFloatBE(123.456, 1)"),
+      njs_str("RangeError: index 1 is outside the bound of the buffer") },
 
-    /* Smallest normal double. */
+    { njs_str("var buf = Buffer.allocUnsafe(4).writeFloatLE(123.456, 1)"),
+      njs_str("RangeError: index 1 is outside the bound of the buffer") },
 
-    { njs_str("2.2250738585072014e-308"),
-      njs_str("2.2250738585072014e-308") },
+    { njs_str("var buffer = require('buffer');"
+              "buffer.Buffer.alloc(5).fill('ABC')"),
+      njs_str("ABCAB") },
 
-    { njs_str("2.2250738585072014e-308/2"),
-      njs_str("0") },
+    { njs_str("var buffer = require('buffer');"
+              "typeof buffer.kMaxLength === 'number' "),
+      njs_str("true") },
 
-    /* Denormals. */
-    { njs_str("["
-              "1.8858070859709815e-308,"
-              "-5.06631661953108e-309,"
-              "6.22574126804e-313,"
-              "-4e-323,"
-              "].map(v=>v.toString(2))"),
-      njs_str("0,0,0,0") },
+    { njs_str("var buffer = require('buffer');"
+              "typeof buffer.constants.MAX_LENGTH === 'number' "),
+      njs_str("true") },
+
+    { njs_str("var buffer = require('buffer');"
+              "typeof buffer.constants.MAX_STRING_LENGTH === 'number' "),
+      njs_str("true") },
 };
 
 
@@ -23374,6 +23379,30 @@ static njs_test_suite_t  njs_suites[] =
       njs_nitems(njs_module_test),
       njs_unit_test },
 
+    { njs_str("fs module"),
+      { .repeat = 1, .unsafe = 1 },
+      njs_fs_module_test,
+      njs_nitems(njs_fs_module_test),
+      njs_unit_test },
+
+    { njs_str("crypto module"),
+      { .repeat = 1, .unsafe = 1 },
+      njs_crypto_module_test,
+      njs_nitems(njs_crypto_module_test),
+      njs_unit_test },
+
+    { njs_str("querystring module"),
+      { .repeat = 1, .unsafe = 1 },
+      njs_querystring_module_test,
+      njs_nitems(njs_querystring_module_test),
+      njs_unit_test },
+
+    { njs_str("buffer module"),
+      { .repeat = 1, .unsafe = 1 },
+      njs_buffer_module_test,
+      njs_nitems(njs_buffer_module_test),
+      njs_unit_test },
+
     { njs_str("externals"),
       { .externals = 1, .repeat = 1, .unsafe = 1 },
       njs_externals_test,