blob: 5c5ed2da9656cf740d8e778ab54fca291743d6ec [file] [log] [blame]
#
# Copyright (C) Dmitry Volyntsev
# Copyright (C) NGINX, Inc.
#
proc njs_test {body {opts ""}} {
if {$opts eq ""} {
spawn -nottycopy njs
} else {
eval spawn -nottycopy njs $opts
}
# TODO:
# SIGINT handling race condition
# deb9-amd64-generic-njs-try
# ub1404-armv7-generic-njs-try
# ub1804-arm64-generic-njs-try
# UTF8 terminal support issue
# sol11-amd64-sunpro-njs-try
# ub1604-arm64-generic-njs-try
# set timeout 30
# expect_before timeout { exit 1 }
expect -re "interactive njs \\d+\.\\d+\.\\d+\r\n\r"
expect "v.<Tab> -> the properties and prototype methods of v.\r
\r
>> "
set len [llength $body]
for {set i 0} {$i < $len} {incr i} {
set pair [lindex $body $i]
send [lindex $pair 0]
expect [lindex $pair 1]
}
# Ctrl-C
send \x03
expect eof
}
proc njs_run {opts expected_re} {
catch {exec njs {*}$opts} out
if {[regexp $expected_re $out match] == 0} {
return -code error "njs_run: unexpected output '$out' vs '$expected_re'"
}
}
njs_test {
{"njs.version\r\n"
"njs.version\r\n\*\.\*\.\*"}
}
# simple multi line interaction
njs_test {
{"var a = 1\r\n"
"var a = 1\r\nundefined\r\n>> "}
{"a *= 2\r\n"
"a *= 2\r\n2\r\n>> "}
}
# Global completions, no
njs_test {
{"\t\tn"
"\a\r\nDisplay all*possibilities? (y or n)*>> "}
}
# Global completions, yes
njs_test {
{"\t\ty"
"\a\r\nDisplay all*possibilities? (y or n)*Array"}
}
# Global completions, single partial match
# \a* is WORKAROUND for libedit-20170329.3.1-r3
# which inserts '\rESC[6G' after '\a'.
njs_test {
{"O\t"
"O\a*bject"}
}
njs_test {
{"Ma\t"
"Ma\a*th"}
}
# FIXME: completions for external objects
# are not supported
# njs_test {
# {"conso\t"
# "conso\a*le"}
# }
# Global completions, multiple partial match
njs_test {
{"cons\t\t"
"console*const"}
}
njs_test {
{"O\t"
"O\a*bject"}
{"\t\t"
"Object.create*Object.isSealed"}
}
njs_test {
{"Object.\t\t"
"Object.create*Object.isSealed"}
}
njs_test {
{"Object.g\t"
"Object.g\a*et"}
{"\t\t"
"Object.getOwnPropertyDescriptor*Object.getPrototypeOf"}
}
njs_test {
{"JS\t"
"JS\a*ON"}
{"\t\t"
"JSON.parse*JSON.stringify"}
}
# Global completions, no matches
njs_test {
{"1.\t\t"
"1."}
}
njs_test {
{"1..\t\t"
"1.."}
}
njs_test {
{"'abc'.\t\t"
"'abc'."}
}
# Global completions, global vars
njs_test {
{"var a = 1; var aa = 2\r\n"
"var a = 1; var aa = 2\r\nundefined\r\n>> "}
{"a\t\t"
"a*aa*arguments*await"}
}
# z*z is WORKAROUND for libedit-20170329.3.1-r3
# which inserts bogus '\a' between 'z'
njs_test {
{"var zz = 1\r\n"
"var zz = 1\r\nundefined\r\n>> "}
{"1 + z\t\r\n"
"1 + z*z*\r\n2"}
}
njs_test {
{"unknown_var\t\t"
"unknown_var"}
}
njs_test {
{"unknown_var.\t\t"
"unknown_var."}
}
# An object's level completions
njs_test {
{"var o = {zz:1, zb:2}\r\n"
"var o = {zz:1, zb:2}\r\nundefined\r\n>> "}
{"o.z\t\t"
"o.zb*o.zz"}
}
njs_test {
{"var d = new Date()\r\n"
"var d = new Date()\r\nundefined\r\n>> "}
{"d.to\t\t"
"d.toDateString*d.toLocaleDateString*d.toString"}
}
njs_test {
{"var o = {a:new Date()}\r\n"
"var o = {a:new Date()}\r\nundefined\r\n>> "}
{"o.a.to\t\t"
"o.a.toDateString*o.a.toLocaleDateString*o.a.toString"}
}
njs_test {
{"var o = {a:1,b:2,333:'t'}\r\n"
"var o = {a:1,b:2,333:'t'}\r\nundefined\r\n>> "}
{"o.3\t\t"
"o.3"}
}
njs_test {
{"var a = Array(5000000); a.aab = 1; a.aac = 2\r\n"
"var a = Array(5000000); a.aab = 1; a.aac = 2\r\n2\r\n>> "}
{"a.\t\t"
"a.aab*"}
}
njs_test {
{"var a = new Uint8Array([5,6,7,8,8]); a.aab = 1; a.aac = 2\r\n"
"var a = new Uint8Array(\\\[5,6,7,8,8]); a.aab = 1; a.aac = 2\r\n2\r\n>> "}
{"a.\t\t"
"a.aab*"}
}
# function declarations in interactive mode
njs_test {
{"function a() { return 1; }\r\n"
"undefined\r\n>> "}
{"a();\r\n"
"1\r\n>> "}
{"function a() { return 2; }\r\n"
"undefined\r\n>> "}
{"a();\r\n"
"2\r\n>> "}
}
# console object
njs_test {
{"console[Symbol.toStringTag]\r\n"
"console\\\[Symbol.toStringTag]\r\n'Console'\r\n>> "}
{"Object.prototype.toString.call(console)\r\n"
"Object.prototype.toString.call(console)\r\n'\\\[object Console]'\r\n>> "}
{"console.toString()\r\n"
"console.toString()\r\n'\\\[object Console]'\r\n>> "}
{"console\r\n"
"console\r\nConsole *>> "}
{"delete console.log\r\n"
"delete console.log\r\ntrue\r\n>>"}
{"console\r\n"
"console\r\nConsole *>> "}
}
# console log functions
njs_test {
{"console[Symbol.toStringTag]\r\n"
"console\\\[Symbol.toStringTag]\r\n'Console'\r\n>> "}
{"console\r\n"
"console\r\nConsole *>> "}
{"console.log()\r\n"
"console.log()\r\nundefined\r\n>> "}
{"console.log('')\r\n"
"console.log('')\r\n\r\nundefined\r\n>> "}
{"console.log(1)\r\n"
"console.log(1)\r\n1\r\nundefined\r\n>> "}
{"console.log(1, 'a')\r\n"
"console.log(1, 'a')\r\n1 a\r\nundefined\r\n>> "}
{"print(1, 'a')\r\n"
"print(1, 'a')\r\n1 a\r\nundefined\r\n>> "}
{"console.log('\\tабв\\nгд')\r\n"
"console.log('\\\\tабв\\\\nгд')\r\n\tабв\r\nгд\r\nundefined\r\n>> "}
{"console.dump()\r\n"
"console.dump()\r\nundefined\r\n>> "}
{"console.dump(1)\r\n"
"console.dump(1)\r\n1\r\nundefined\r\n>> "}
{"console.dump(1, 'a')\r\n"
"console.dump(1, 'a')\r\n1 a\r\nundefined\r\n>> "}
}
# console.time* functions
njs_test {
{"console.time()\r\n"
"console.time()\r\nundefined\r\n>> "}
{"console.timeEnd()\r\n"
"console.timeEnd()\r\ndefault: *.*ms\r\nundefined\r\n>> "}
{"console.time(undefined)\r\n"
"console.time(undefined)\r\nundefined\r\n>> "}
{"console.timeEnd(undefined)\r\n"
"console.timeEnd(undefined)\r\ndefault: *.*ms\r\nundefined\r\n>> "}
{"console.time('abc')\r\n"
"console.time('abc')\r\nundefined\r\n>> "}
{"console.time('abc')\r\n"
"console.time('abc')\r\nTimer \"abc\" already exists.\r\nundefined\r\n>> "}
{"console.timeEnd('abc')\r\n"
"console.timeEnd('abc')\r\nabc: *.*ms\r\nundefined\r\n>> "}
{"console.time(true)\r\n"
"console.time(true)\r\nundefined\r\n>> "}
{"console.timeEnd(true)\r\n"
"console.timeEnd(true)\r\ntrue: *.*ms\r\nundefined\r\n>> "}
{"console.time(42)\r\n"
"console.time(42)\r\nundefined\r\n>> "}
{"console.timeEnd(42)\r\n"
"console.timeEnd(42)\r\n42: *.*ms\r\nundefined\r\n>> "}
{"console.timeEnd()\r\n"
"console.timeEnd()\r\nTimer \"default\" doesn’t exist."}
{"console.timeEnd('abc')\r\n"
"console.timeEnd('abc')\r\nTimer \"abc\" doesn’t exist."}
}
njs_test {
{"console.ll()\r\n"
"console.ll()\r\nThrown:\r\nTypeError: (intermediate value)\\\[\"ll\"] is not a function"}
}
njs_test {
{"console.log.length\r\n"
"console.log.length\r\n0"}
}
njs_test {
{"var print = console.log.bind(console); print(1, 'a', [1, 2])\r\n"
"1 a \\\[1,2]\r\nundefined\r\n>> "}
{"var print = console.dump.bind(console); print(1, 'a', [1, 2])\r\n"
"1 a \\\[\r\n 1,\r\n 2\r\n]\r\nundefined\r\n>> "}
{"var print = console.log.bind(console); print(console.a.a)\r\n"
"TypeError: cannot get property \"a\" of undefined*at console.log"}
{"print(console.a.a)\r\n"
"TypeError: cannot get property \"a\" of undefined*at console.log"}
}
# Backtraces for external objects
njs_test {
{"console.log(console.a.a)\r\n"
"console.log(console.a.a)\r\nThrown:\r\nTypeError:*at console.log (native)"}
}
# dumper
njs_test {
{"var o = {toString: function(){}, log: console.log}\r\n"
"undefined\r\n>> "}
{"o\r\n"
"o\r\n{\r\n toString: \\\[Function],\r\n log: \\\[Function: log]\r\n}"}
}
njs_test {
{"[1, new Number(2), 'a', new String('αβZγ'), true, new Boolean(false)]\r\n"
"\\\[\r\n 1,\r\n \\\[Number: 2],\r\n 'a',\r\n \\\[String: 'αβZγ'],\r\n true,\r\n \\\[Boolean: false]\r\n]"}
}
njs_test {
{"[undefined,,null]\r\n"
"\\\[\r\n undefined,\r\n <empty>,\r\n null\r\n]"}
}
njs_test {
{"[InternalError(),TypeError('msg'), new RegExp(), /^undef$/m, new Date(0)]\r\n"
"\\\[\r\n InternalError,\r\n TypeError: msg,\r\n /(?:)/,\r\n /^undef$/m,\r\n 1970-01-01T00:00:00.000Z\r\n]"}
}
# dumper excapes special characters as JSON.stringify()
# except '\"'
njs_test {
{"\"\\r\\0\\\"\"\r\n"
"\\\\r\\\\u0000\""}
}
njs_test {
{"[{a:1}]\r\n"
"\r\n\\\[\r\n {\r\n a: 1\r\n }\r\n]"}
}
# Backtraces are reset between invocations
njs_test {
{"JSON.parse(Error())\r\n"
"JSON.parse(Error())\r\nThrown:\r\nSyntaxError: Unexpected token at position 0*at JSON.parse (native)"}
{"JSON.parse(Error()\r\n"
"JSON.parse(Error()\r\nThrown:\r\nSyntaxError: Unexpected end of input in shell:1"}
}
njs_test {
{"try { console.log({ toString: function() { throw 'test'; } }) } catch (e) {}\r\n"
"undefined"}
{"function f() { throw 't' }; try { console.log({ toString: function() { return f() } }) } catch (e) {}\r\n"
"undefined"}
}
njs_test {
{"(function() { throw 'test' })()\r\n"
"Thrown:\r\ntest"}
}
njs_test {
{"function f() { return ({}.a.a); }\r\n"
"undefined"}
{"var e; try {f()} catch (ee) {e = ee}\r\n"
"undefined"}
{"Object.keys(null)\r\n"
"Thrown:\r\nTypeError: cannot convert null argument to object"}
{"e\r\n"
"TypeError: cannot get property \"a\" of undefined*at f (shell:1)"}
}
# Non-ASCII characters
njs_test {
{"'絵文字'\r\n"
"'絵文字'"}
{"var v = 'абвгдеёжзийкл';v[10]\r\n"
"'й'"}
}
# Immediate events
njs_test {
{"var t = setImmediate(console.log, 'a', 'aa')\r\n"
"undefined\r\na aa"}
}
njs_test {
{"var a = 1 + 1; setTimeout(function (x) {a = x}, 0, 'a'); a\r\n"
"2"}
{"a\r\n"
"a\r\n'a'"}
}
njs_test {
{"setTimeout(function () {}, 1, 'a')\r\n"
"njs_console_set_timer(): async timers unsupported"}
}
njs_test {
{"var a = 1 + 1; setTimeout(function (x) { setTimeout(function (y) {a = y}, 0, x)}, 0, 'a'); a\r\n"
"2"}
{"a\r\n"
"a\r\n'a'"}
}
njs_test {
{"var a = 1 + 1; setImmediate(function (x) { setImmediate(function (y) {a = y}, x)}, 'a'); a\r\n"
"2"}
{"a\r\n"
"a\r\n'a'"}
}
njs_test {
{"var i = 0; (function x() { if (i < 10) setImmediate(x); i++; })()\r\n"
"undefined"}
{"i\r\n"
"i\r\n11"}
}
njs_test {
{"var a = 0, t = setImmediate(function() {a = 1}); clearTimeout(t)\r\n"
"undefined"}
{"a\r\n"
"a\r\n0"}
}
njs_test {
{"var i = 0; (function x() { if (i < 3) setImmediate(x); i++; throw 'Oops';})()\r\n"
"Oops"}
{"i\r\n"
"i\r\n4"}
}
njs_test {
{"var i = 0, queue = []; (function x() { if (i < 5) setImmediate(x); queue.push(i++); })()\r\n"
"undefined"}
{"queue.toString()\r\n"
"queue.toString()\r\n'0,1,2,3,4,5'"}
}
# require('fs').readFile()
njs_run {"./test/js/fs_readFile.js" "test/fs/utf8"} "αβZγ Buffer 7"
njs_run {"./test/js/fs_readFile.js" "test/fs/utf8" "utf8"} "αβZγ string 4"
njs_run {"./test/js/fs_readFile.js" "test/fs/utf8" "utf8" "r+"} "αβZγ string 4"
njs_run {"./test/js/fs_readFile.js" "test/fs/nonexistent"} \
"{\"errno\":2,\"code\":\"ENOENT\",\"path\":\"test/fs/nonexistent\",\"syscall\":\"open\"}"
njs_run {"./test/js/fs_readFile.js" "test/fs/non_utf8" "utf8"} "�� string 2"
njs_run {"./test/js/fs_readFile.js" "test/fs/non_utf8" "hex"} "8080 string 4"
njs_run {"./test/js/fs_readFile.js" "test/fs/non_utf8" "base64"} "gIA= string 4"
njs_test {
{"var fs = require('fs')\r\n"
"undefined\r\n>> "}
{"fs.readFile('test/fs/ascii', 'utf8', function (e, data) {console.log(data[599], data[600])})\r\n"
"undefined\r\nx undefined\r\n>> "}
{"fs.readFile('test/fs/ascii', {encoding:'utf8',flag:'r+'}, function (e, data) {console.log(data[599], data[600])})\r\n"
"undefined\r\nx undefined\r\n>> "}
{"fs.readFile(Buffer.from([0x80,0x80]), function(e) {console.log(e.path.codePointAt())})\r\n"
"undefined\r\n65533"}
}
njs_test {
{"var fs = require('fs')\r\n"
"undefined\r\n>> "}
{"fs.readFile('/proc/version', (e, data) => {console.log(e || data.slice(0,5) == 'Linux')})\r\n"
"undefined\r\ntrue\r\n>> "}
{"fs.readFile('/proc/cpuinfo', (e, data) => {console.log(e || data.slice(0,9) == 'processor')})\r\n"
"undefined\r\ntrue\r\n>> "}
}
# require('fs').readFileSync()
njs_run {"./test/js/fs_readFileSync.js" "test/fs/utf8"} "αβZγ Buffer 7"
njs_run {"./test/js/fs_readFileSync.js" "test/fs/utf8" "utf8"} "αβZγ string 4"
njs_run {"./test/js/fs_readFileSync.js" "test/fs/utf8" "utf8" "r+"} "αβZγ string 4"
njs_run {"./test/js/fs_readFileSync.js" "test/fs/nonexistent"} \
"{\"errno\":2,\"code\":\"ENOENT\",\"path\":\"test/fs/nonexistent\",\"syscall\":\"open\"}"
njs_run {"./test/js/fs_readFileSync.js" "test/fs/non_utf8" "utf8"} "�� string 2"
njs_run {"./test/js/fs_readFileSync.js" "test/fs/non_utf8" "hex"} "8080 string 4"
njs_run {"./test/js/fs_readFileSync.js" "test/fs/non_utf8" "base64"} "gIA= string 4"
njs_test {
{"var fs = require('fs')\r\n"
"undefined\r\n>> "}
{"fs.readFileSync('test/fs/non_utf8', 'utf8').charCodeAt(1)\r\n"
"65533"}
{"fs.readFile('x'.repeat(8192))\r\n"
"TypeError: \"path\" is too long >= 4096"}
}
njs_test {
{"var fs = require('fs'), file\r\n"
"undefined\r\n>> "}
{"try { file = fs.readFileSync('/proc/version')} catch (e) {}\r\n"
"undefined"}
{"(!file || file.slice(0,5) == 'Linux')\r\n"
"true"}
{"try { file = fs.readFileSync('/proc/cpuinfo')} catch (e) {}\r\n"
"undefined"}
{"(!file || file.slice(0,9) == 'processor')\r\n"
"true"}
}
# require('fs').writeFile()
njs_run {"./test/js/fs_writeFile.js" "ABCD" "Buffer" "1"} "BCD"
njs_run {"./test/js/fs_writeFile.js" "ABC" "DataView"} "ABC"
njs_run {"./test/js/fs_writeFile.js" "414243" "Object" "hex"} "ABC"
njs_run {"./test/js/fs_writeFile.js" "ABC" "String"} "ABC"
njs_run {"./test/js/fs_writeFile.js" "ABC" "Symbol"} "TypeError: Cannot convert a Symbol value to a string*"
njs_run {"./test/js/fs_writeFile.js" "ABC" "Uint8Array"} "ABC"
njs_run {"./test/js/fs_writeFile.js" "ABC" "String" "utf8"} "ABC"
njs_run {"./test/js/fs_writeFile.js" "ABC" "String" "utf8" "0o666"} "ABC"
njs_run {"./test/js/fs_writeFile.js" "ABC" "String" "utf8" "0o222"} "Error: Permission denied*"
njs_run {"./test/js/fs_writeFile.js" "414243" "String" "hex"} "ABC"
njs_run {"./test/js/fs_writeFile.js" "QUJD" "String" "base64"} "ABC"
njs_run {"./test/js/fs_writeFile.js" "QUJD" "String" "base64url"} "ABC"
njs_test {
{"var fs = require('fs')\r\n"
"undefined\r\n>> "}
{"fs.writeFile('/invalid_path', 'ABC', function (e) { console.log(JSON.stringify(e))})\r\n"
"undefined\r\n{\"errno\":13,\"code\":\"EACCES\",\"path\":\"/invalid_path\",\"syscall\":\"open\"}\r\n>> "}
{"fs.writeFile(Buffer.from('/invalid_path'), 'ABC', function (e) { console.log(typeof e.path)})\r\n"
"undefined\r\nstring\r\n>> "}
}
# require('fs').writeFileSync()
njs_run {"./test/js/fs_writeFileSync.js" "ABCD" "Buffer" "1"} "BCD"
njs_run {"./test/js/fs_writeFileSync.js" "ABC" "DataView"} "ABC"
njs_run {"./test/js/fs_writeFileSync.js" "414243" "Object" "hex"} "ABC"
njs_run {"./test/js/fs_writeFileSync.js" "ABC" "String"} "ABC"
njs_run {"./test/js/fs_writeFileSync.js" "ABC" "Symbol"} "TypeError: Cannot convert a Symbol value to a string*"
njs_run {"./test/js/fs_writeFileSync.js" "ABC" "Uint8Array"} "ABC"
njs_run {"./test/js/fs_writeFileSync.js" "ABC" "String" "utf8"} "ABC"
njs_run {"./test/js/fs_writeFileSync.js" "ABC" "String" "utf8" "0o666"} "ABC"
njs_run {"./test/js/fs_writeFileSync.js" "ABC" "String" "utf8" "0o222"} "Error: Permission denied*"
njs_run {"./test/js/fs_writeFileSync.js" "78797a" "String" "hex"} "xyz"
njs_run {"./test/js/fs_writeFileSync.js" "eHl6" "String" "base64"} "xyz"
njs_run {"./test/js/fs_writeFileSync.js" "eHl6" "String" "base64url"} "xyz"
njs_test {
{"var fs = require('fs'), fn = './build/test/file2';\r\n"
"undefined\r\n>> "}
{"fs.writeFileSync(fn, 'ABC')\r\n"
"undefined\r\n>> "}
{"fs.writeFileSync(fn, 'ABC')\r\n"
"undefined\r\n>> "}
{"fs.readFileSync(fn, 'utf8')\r\n"
"'ABC'\r\n>> "}
}
# require('fs').appendFile()
njs_run {"./test/js/fs_appendFile.js" "ABCD" "Buffer" "1"} "BCDBCD"
njs_run {"./test/js/fs_appendFile.js" "ABC" "DataView"} "ABCABC"
njs_run {"./test/js/fs_appendFile.js" "414243" "Object" "hex"} "ABCABC"
njs_run {"./test/js/fs_appendFile.js" "ABC" "String"} "ABCABC"
njs_run {"./test/js/fs_appendFile.js" "ABC" "Symbol"} "TypeError: Cannot convert a Symbol value to a string*"
njs_run {"./test/js/fs_appendFile.js" "ABC" "Uint8Array"} "ABCABC"
njs_run {"./test/js/fs_appendFile.js" "ABC" "String" "utf8"} "ABC"
njs_run {"./test/js/fs_appendFile.js" "ABC" "String" "utf8" "0o666"} "ABC"
njs_run {"./test/js/fs_appendFile.js" "ABC" "String" "utf8" "0o222"} "Error: Permission denied*"
njs_run {"./test/js/fs_appendFile.js" "414243" "String" "hex"} "ABC"
njs_run {"./test/js/fs_appendFile.js" "QUJD" "String" "base64"} "ABC"
njs_run {"./test/js/fs_appendFile.js" "QUJD" "String" "base64url"} "ABC"
# require('fs').appendFileSync()
njs_run {"./test/js/fs_appendFileSync.js" "ABCD" "Buffer" "1"} "BCDBCD"
njs_run {"./test/js/fs_appendFileSync.js" "ABC" "DataView"} "ABCABC"
njs_run {"./test/js/fs_appendFileSync.js" "414243" "Object" "hex"} "ABCABC"
njs_run {"./test/js/fs_appendFileSync.js" "ABC" "String"} "ABCABC"
njs_run {"./test/js/fs_appendFileSync.js" "ABC" "Symbol"} "TypeError: Cannot convert a Symbol value to a string*"
njs_run {"./test/js/fs_appendFileSync.js" "ABC" "Uint8Array"} "ABCABC"
njs_run {"./test/js/fs_appendFileSync.js" "ABC" "String" "utf8"} "ABC"
njs_run {"./test/js/fs_appendFileSync.js" "ABC" "String" "utf8" "0o666"} "ABC"
njs_run {"./test/js/fs_appendFileSync.js" "ABC" "String" "utf8" "0o222"} "Error: Permission denied*"
njs_run {"./test/js/fs_appendFileSync.js" "414243" "String" "hex"} "ABC"
njs_run {"./test/js/fs_appendFileSync.js" "QUJD" "String" "base64"} "ABC"
njs_run {"./test/js/fs_appendFileSync.js" "QUJD" "String" "base64url"} "ABC"
# require('fs').renameSync()
njs_test {
{"var fs = require('fs'), mktemp = ()=> `/tmp/njs_${Math.round(Math.random() * 1000000)}`\r\n"
"undefined\r\n>> "}
{"var fn1 = mktemp(), fn2 = mktemp();\r\n"
"undefined\r\n>> "}
{"fs.writeFileSync(fn1, 'ABC')\r\n"
"undefined\r\n>> "}
{"fs.renameSync(fn1, fn2)\r\n"
"undefined\r\n>> "}
{"String(fs.readFileSync(fn2))\r\n"
"'ABC'\r\n>> "}
}
njs_test {
{"var fs = require('fs'), fn = './build/test/file2'\r\n"
"undefined\r\n>> "}
{"fs.writeFileSync(fn, 'ABC')\r\n"
"undefined\r\n>> "}
{"fs.renameSync(fn, 'test/fs/')\r\n"
"Error: Not a directory*"}
}
# require('fs').realpathSync()
njs_test {
{"var fs = require('fs')\r\n"
"undefined\r\n>> "}
{"fs.realpathSync('./build/test/..').endsWith('build')\r\n"
"true\r\n>> "}
{"fs.realpathSync('./build/test/..', {encoding:'buffer'}) instanceof Buffer\r\n"
"true\r\n>> "}
}
njs_run {"-c" "setTimeout(() => {console.log('A'.repeat(1024))}, 0); ref"} \
"^Thrown:
ReferenceError: \"ref\" is not defined
at main \\\(string:1\\\)\n$"
njs_run {"-c" "setTimeout(() => {ref}, 0); setTimeout(() => {console.log('A'.repeat(1024))}, 0)"} \
"^Thrown:
ReferenceError: \"ref\" is not defined
at anonymous \\\(string:1\\\)
at main \\\(string:1\\\)\n$"
# Modules
njs_run {"-p" "test/module/libs" "./test/module/normal.js"} \
"passed!"
njs_run {"-p" "test/module/libs/" "./test/module/normal.js"} \
"passed!"
njs_run {"-p" "test/module" "-p" "test/module/libs" "./test/module/normal.js"} \
"passed!"
njs_run {"./test/module/normal.js"} \
"SyntaxError: Cannot find module \"hash.js\" in lib1.js:13"
njs_run {"-p" "test/module/libs" "./test/module/exception.js"} \
"at error \\(sub1.js:6\\)"
njs_run {"-p" "test/module" "./test/module/recursive.js"} \
"SyntaxError: Cannot import itself \"./test/module/recursive.js\" in recursive.js:1"
# CLI OPTIONS
# help
njs_run {"-h"} "Options"
# ast
njs_run {"-a" "-c" "console.log(1*2)"} "{\"name\": \"END\""
# command
njs_run {"-c" "console.log(\"a b c\")"} "a b c"
njs_run {"-c" "console.log("} "SyntaxError: Unexpected end of input in string:1"
# process
njs_run {"-c" "console.log(typeof process.argv)"} "object"
njs_run {"-c" "console.log(process.argv.slice(2))" "AAA"} "AAA"
njs_run {"-c" "console.log(typeof process.env)"} "object"
njs_run {"-c" "console.log(process.env.HOME != undefined)"} "true"
njs_run {"-c" "console.log(process.env.___UNDECLARED != undefined)"} "false"
njs_run {"-c" "console.log(process.pid)"} "\\d+"
njs_run {"-c" "console.log(process.ppid)"} "\\d+"
# script args
njs_run {"test/script_args.js" "A" "B"} "AB"
# disassemble
njs_test {
{"1+1\r\n"
" 1 | 00000 ADD*\r\n*2"}
{"__unknown\r\n"
" 1 | 00000 GLOBAL GET*\r\n*REFERENCE ERROR*"}
{"for (var n in [1]) {try {break} finally{}}\r\n"
" 1 | 00000 ARRAY*\r\n*TRY BREAK*PROP NEXT*-*\r\n\r\nundefined"}
{"(function() {try {return} finally{}})()\r\n"
" 1 | 00000 TRY START*\r\n*TRY RETURN*\r\n\r\nundefined"}
} "-d"
# modules
# FIXME:
# During import, the variable is declared regardless of the result of the import.
# Because of this, in the console mode, checking the variable after the import
# error may give an incorrect result.
#
# For example:
# {"import ref from 'ref_exception.js'\r\n"
# "ReferenceError: \"undeclared\" is not defined"}
# {"ref\r\n"
# "ReferenceError: \"ref\" is not defined\r\n"}
njs_test {
{"import lib1 from 'lib1.js'; import lib2 from 'lib1.js'\r\n"
"undefined\r\n"}
{"lib2.inc()\r\n"
"undefined\r\n"}
{"lib1.get()\r\n"
"1\r\n"}
{"import m from 'return.js'\r\n"
"Illegal return statement in return.js:1\r\n"}
{"import m from 'empty.js'\r\n"
"export statement is required in empty.js:1\r\n"}
{"import m from 'export.js'\r\n"
"Identifier \"default\" has already been declared in export.js:5\r\n"}
{"import m from 'export_non_default.js'\r\n"
"Non-default export is not supported in export_non_default.js:3\r\n"}
{"import m from 'export_non_assignment.js'\r\n"
"Unexpected token \",\" in export_non_assignment.js:1\r\n"}
{"import ref from 'ref_exception.js'\r\n"
"ReferenceError: \"undeclared\" is not defined"}
{"var ref\r\n"
"undefined\r\n"}
{"import ref from 'ref_exception.js'\r\n"
"ReferenceError: \"undeclared\" is not defined"}
{"import m from 'declaration_exception.js'\r\n"
"SyntaxError: \"f\" has already been declared in declaration_exception.js:6"}
{"import m from 'loading_exception.js'\r\n"
"Error: loading exception\r\n at module \\(loading_exception.js:1\\)"}
{"import lib3 from 'lib1.js'\r\n"
"undefined\r\n"}
} "-p test/module/ -p test/module/libs/"
njs_test {
{"import m from 'export_name.js'\r\n"
"undefined\r\n"}
{"m.prod(3,4)\r\n"
"12\r\n"}
{"import m from 'export_expression.js'\r\n"
"undefined\r\n"}
{"m.sum(3,4)\r\n"
"7\r\n"}
{"import m from 'export_expression2.js'\r\n"
"undefined\r\n"}
{"m.prod(3,4)\r\n"
"12\r\n"}
} "-p test/module/"
njs_run {"-q" "./test/module/normal.js"} \
"SyntaxError: Cannot find module \"hash.js\" in 13"
njs_run {"-p" "test/module/libs/" "-d" "./test/module/normal.js"} \
"passed!"
# sandboxing
njs_test {
{"var fs = require('fs')\r\n"
"Error: Cannot find module \"fs\"\r\n"}
} "-s"
njs_test {
{"var crypto = require('crypto')\r\n"
"undefined\r\n"}
} "-s"
# safe mode
njs_test {
{"new Function()\r\n"
"TypeError: function constructor is disabled in \"safe\" mode\r\n"}
{"(new Function('return this'))() === globalThis\r\n"
"true\r\n"}
{"new Function('return this;')\r\n"
"[Function]"}
{"new Function('return thi')\r\n"
"TypeError: function constructor is disabled in \"safe\" mode\r\n"}
} "-u"
# source type
njs_test {
{"this\r\n"
"this\r\nundefined"}
{"(() => this)()\r\n"
"(() => this)()\r\nundefined"}
} "-t module"
njs_test {
{"this.NaN\r\n"
"this.NaN\r\nNaN"}
} "-t script"
# version
njs_run {"-v"} "\\d+\.\\d+\.\\d+"
# Promise
njs_run {"./test/js/promise_set_timeout.js"} \
"One,Two,Three
One,Two,Three,Four,Five,Six,Seven,Eight"
njs_run {"./test/js/promise_s1.js"} \
"One
Two
Three
123
Four
Five
Six
Seven
Eight"
njs_run {"./test/js/promise_s2.js"} \
"One
Two
Three"
njs_run {"./test/js/promise_s3.js"} \
"One
Two
Three
Rejected: Error: Blah"
njs_run {"./test/js/promise_s4.js"} \
"Error: Oh my"
njs_run {"./test/js/promise_s5.js"} \
"Success"
njs_run {"./test/js/promise_s6.js"} \
"1"
njs_run {"./test/js/promise_s7.js"} \
"true
fulfilled!"
njs_run {"./test/js/promise_s8.js"} \
"Ok"
njs_run {"./test/js/promise_s9.js"} \
"S
true"
njs_run {"./test/js/promise_s10.js"} \
"One
Two
Three
Oh no"
njs_run {"./test/js/promise_s11.js"} \
"end
S: all
R: all"
njs_run {"./test/js/promise_s12.js"} \
"Done"
njs_run {"./test/js/promise_s13.js"} \
"Done"
njs_run {"./test/js/promise_s14.js"} \
"TypeError: oops
at anonymous \\\(promise_s14.js:5\\\)
at native \\\(native\\\)
at main \\\(promise_s14.js:9\\\)
Done"
njs_run {"./test/js/promise_s15.js"} \
"Done"
njs_run {"./test/js/promise_s16.js"} \
"Done"
njs_run {"./test/js/promise_s17.js"} \
"Done"
njs_run {"./test/js/promise_s18.js"} \
"State 1
State 2
State 3
State 4
State 5
Done"
njs_run {"./test/js/promise_s19.js"} \
"Throw!
undefined
Reject!
Done"
njs_run {"./test/js/promise_s20.js"} \
"true
Done"
njs_run {"./test/js/promise_s21.js"} \
"Done"
njs_run {"./test/js/promise_s22.js"} \
"true
Done"
njs_run {"./test/js/promise_s23.js"} \
"true
Done"
njs_run {"./test/js/promise_s24.js"} \
"true"
njs_run {"./test/js/promise_s25.js"} \
"Done"
njs_run {"./test/js/promise_s26.js"} \
"BoxedPromise.constructor
BoxedPromise.prototype.then
BoxedPromise resolve OK
BoxedPromise.constructor
BoxedPromise.prototype.then
BoxedPromise reject OK
BoxedPromise.constructor
BoxedPromise.prototype.then
BoxedPromise.prototype.then
BoxedPromise chain OK
BoxedPromise.prototype.then
BoxedPromise finally OK
BoxedPromise sync done
BoxedPromise.prototype.then
BoxedPromise.prototype.then
resolved BoxedPromise
rejected BoxedPromise
then BoxedPromise
then BoxedPromise
finally BoxedPromise
BoxedPromise.constructor
BoxedPromise.prototype.then
BoxedPromise.prototype.then
BoxedPromise async done
PatchedPromise.constructor
PatchedPromise.constructor
PatchedPromise resolve OK
PatchedPromise.constructor
PatchedPromise.constructor
PatchedPromise reject OK
PatchedPromise.constructor
PatchedPromise.constructor
PatchedPromise.constructor
PatchedPromise chain OK
PatchedPromise.constructor
PatchedPromise finally OK
PatchedPromise sync done
PatchedPromise.constructor
PatchedPromise.constructor
resolved PatchedPromise
rejected PatchedPromise
then PatchedPromise
then PatchedPromise
finally PatchedPromise
PatchedPromise.constructor
PatchedPromise.constructor
PatchedPromise.constructor
PatchedPromise async done"
njs_run {"./test/js/fs_promises_001.js"} \
"init ok true
short circut ok true
chain ok true
error 1 ok true
error 2 ok true
errors ok"
njs_run {"./test/js/fs_promises_002.js"} \
"testSync ok true
testCallback ok true
testPromise ok true"
njs_run {"./test/js/fs_promises_003.js"} \
"test fs.unlinkSync
test fs.unlink
test fsp.unlink"
njs_run {"./test/js/fs_promises_004.js"} \
"test fs.symlinkSync
test fs.symlink
test fsp.symlink"
njs_run {"./test/js/fs_promises_005.js"} \
"test fs.mkdirSync
test fs.mkdir
test fsp.mkdir"
njs_run {"./test/js/fs_promises_006.js"} \
"test fs.renameSync
test fs.rename
test fsp.rename"
njs_run {"./test/js/fs_promises_007.js"} \
"test fs.readdirSync
test fs.readdir
test fsp.readdir"
njs_run {"./test/js/fs_promises_008.js"} \
"test recursive fs.mkdirSync"
njs_run {"./test/js/fs_promises_009.js"} \
"test recursive fs.rmdirSync"
njs_run {"./test/js/promise_then_throw_finally_catch.js"} \
"Done"
njs_run {"./test/js/promise_catch_throw.js"} \
"Error: unhandled promise rejection: ReferenceError: \"nonExsistingInCatch\" is not defined"
njs_run {"./test/js/promise_then_throw.js"} \
"Error: unhandled promise rejection: ReferenceError: \"nonExsisting\" is not defined"
njs_run {"./test/js/promise_then_throw_catch.js"} \
"Done"
njs_run {"./test/js/promise_catch_then_throw_catch.js"} \
"Done"
njs_run {"./test/js/promise_finally.js"} \
"here
Thrown:
Error: unhandled promise rejection: nope"
njs_run {"./test/js/promise_finally_throw.js"} \
"Error: unhandled promise rejection: ReferenceError: \"nonExsistingInFinally\" is not defined"
njs_run {"./test/js/promise_finally_throw_catch.js"} \
"Done"
njs_run {"./test/js/promise_two_then_throw.js"} \
"Error: unhandled promise rejection: ReferenceError: \"nonExsistingOne\" is not defined"
njs_run {"./test/js/promise_two_first_then_throw.js"} \
"Error: unhandled promise rejection: ReferenceError: \"nonExsistingOne\" is not defined"
njs_run {"./test/js/promise_reject_catch.js"} \
"rejected test"
njs_run {"./test/js/promise_reject_post_catch.js"} \
"Error: unhandled promise rejection: undefined"
njs_run {"./test/js/promise_all.js"} \
"resolved:\\\[\\\['one','two'],\\\['three','four']]"
njs_run {"./test/js/promise_all_throw.js"} \
"rejected:foo"
njs_run {"./test/js/promise_allSettled.js"} \
"resolved:resolved:F:0,3,42,here|R:finally,finally after rejected,foo,here too,yes"
njs_run {"./test/js/promise_allSettled_string.js"} \
"resolved:F:a,b,c|R:"
njs_run {"./test/js/promise_any.js"} \
"resolved:4"
njs_run {"./test/js/promise_any_all_rejected.js"} \
"reject:AggregateError: All promises were rejected"
njs_run {"./test/js/promise_race.js"} \
"resolved:one"
njs_run {"./test/js/promise_race_throw.js"} \
"rejected:one"