| /* eslint-disable max-len, strict */ |
| var common = require('../common'); |
| var assert = require('assert'); |
| |
| common.globalCheck = false; |
| |
| var net = require('net'), |
| repl = require('repl'), |
| message = 'Read, Eval, Print Loop', |
| prompt_unix = 'node via Unix socket> ', |
| prompt_tcp = 'node via TCP socket> ', |
| prompt_multiline = '... ', |
| prompt_npm = 'npm should be run outside of the ' + |
| 'node repl, in your normal shell.\n' + |
| '(Press Control-D to exit.)\n', |
| expect_npm = prompt_npm + prompt_unix, |
| server_tcp, server_unix, client_tcp, client_unix, timer; |
| |
| |
| // absolute path to test/fixtures/a.js |
| var moduleFilename = require('path').join(common.fixturesDir, 'a'); |
| |
| console.error('repl test'); |
| |
| // function for REPL to run |
| invoke_me = function(arg) { |
| return 'invoked ' + arg; |
| }; |
| |
| function send_expect(list) { |
| if (list.length > 0) { |
| var cur = list.shift(); |
| |
| console.error('sending ' + JSON.stringify(cur.send)); |
| |
| cur.client.expect = cur.expect; |
| cur.client.list = list; |
| if (cur.send.length > 0) { |
| cur.client.write(cur.send + '\n'); |
| } |
| } |
| } |
| |
| function clean_up() { |
| client_tcp.end(); |
| client_unix.end(); |
| clearTimeout(timer); |
| } |
| |
| function error_test() { |
| // The other stuff is done so reuse unix socket |
| var read_buffer = ''; |
| client_unix.removeAllListeners('data'); |
| |
| client_unix.on('data', function(data) { |
| read_buffer += data.toString('ascii', 0, data.length); |
| console.error('Unix data: ' + JSON.stringify(read_buffer) + ', expecting ' + |
| (client_unix.expect.exec ? |
| client_unix.expect : |
| JSON.stringify(client_unix.expect))); |
| |
| if (read_buffer.indexOf(prompt_unix) !== -1) { |
| // if it's an exact match, then don't do the regexp |
| if (read_buffer !== client_unix.expect) { |
| var expect = client_unix.expect; |
| if (expect === prompt_multiline) |
| expect = /[\.]{3} /; |
| assert.ok(read_buffer.match(expect)); |
| console.error('match'); |
| } |
| read_buffer = ''; |
| if (client_unix.list && client_unix.list.length > 0) { |
| send_expect(client_unix.list); |
| } else { |
| console.error('End of Error test, running TCP test.'); |
| tcp_test(); |
| } |
| |
| } else if (read_buffer.indexOf(prompt_multiline) !== -1) { |
| // Check that you meant to send a multiline test |
| assert.strictEqual(prompt_multiline, client_unix.expect); |
| read_buffer = ''; |
| if (client_unix.list && client_unix.list.length > 0) { |
| send_expect(client_unix.list); |
| } else { |
| console.error('End of Error test, running TCP test.\n'); |
| tcp_test(); |
| } |
| |
| } else { |
| console.error('didn\'t see prompt yet, buffering.'); |
| } |
| }); |
| |
| send_expect([ |
| // Uncaught error throws and prints out |
| { client: client_unix, send: 'throw new Error(\'test error\');', |
| expect: /^Error: test error/ }, |
| // Common syntax error is treated as multiline command |
| { client: client_unix, send: 'function test_func() {', |
| expect: prompt_multiline }, |
| // You can recover with the .break command |
| { client: client_unix, send: '.break', |
| expect: prompt_unix }, |
| // But passing the same string to eval() should throw |
| { client: client_unix, send: 'eval("function test_func() {")', |
| expect: /^SyntaxError: Unexpected end of input/ }, |
| // Can handle multiline template literals |
| { client: client_unix, send: '`io.js', |
| expect: prompt_multiline }, |
| // Special REPL commands still available |
| { client: client_unix, send: '.break', |
| expect: prompt_unix }, |
| // Template expressions can cross lines |
| { client: client_unix, send: '`io.js ${"1.0"', |
| expect: prompt_multiline }, |
| { client: client_unix, send: '+ ".2"}`', |
| expect: `'io.js 1.0.2'\n${prompt_unix}` }, |
| // Floating point numbers are not interpreted as REPL commands. |
| { client: client_unix, send: '.1234', |
| expect: '0.1234' }, |
| // Floating point expressions are not interpreted as REPL commands |
| { client: client_unix, send: '.1+.1', |
| expect: '0.2' }, |
| // Can parse valid JSON |
| { client: client_unix, send: 'JSON.parse(\'{"valid": "json"}\');', |
| expect: '{ valid: \'json\' }'}, |
| // invalid input to JSON.parse error is special case of syntax error, |
| // should throw |
| { client: client_unix, send: 'JSON.parse(\'{invalid: \\\'json\\\'}\');', |
| expect: /^SyntaxError: Unexpected token i/ }, |
| // end of input to JSON.parse error is special case of syntax error, |
| // should throw |
| { client: client_unix, send: 'JSON.parse(\'066\');', |
| expect: /^SyntaxError: Unexpected number/ }, |
| // should throw |
| { client: client_unix, send: 'JSON.parse(\'{\');', |
| expect: /^SyntaxError: Unexpected end of input/ }, |
| // invalid RegExps are a special case of syntax error, |
| // should throw |
| { client: client_unix, send: '/(/;', |
| expect: /^SyntaxError: Invalid regular expression\:/ }, |
| // invalid RegExp modifiers are a special case of syntax error, |
| // should throw (GH-4012) |
| { client: client_unix, send: 'new RegExp("foo", "wrong modifier");', |
| expect: /^SyntaxError: Invalid flags supplied to RegExp constructor/ }, |
| // strict mode syntax errors should be caught (GH-5178) |
| { client: client_unix, send: '(function() { "use strict"; return 0755; })()', |
| expect: /^SyntaxError: Octal literals are not allowed in strict mode/ }, |
| { client: client_unix, send: '(function(a, a, b) { "use strict"; return a + b + c; })()', |
| expect: /^SyntaxError: Strict mode function may not have duplicate parameter names/ }, |
| { client: client_unix, send: '(function() { "use strict"; with (this) {} })()', |
| expect: /^SyntaxError: Strict mode code may not include a with statement/ }, |
| { client: client_unix, send: '(function() { "use strict"; var x; delete x; })()', |
| expect: /^SyntaxError: Delete of an unqualified identifier in strict mode/ }, |
| { client: client_unix, send: '(function() { "use strict"; eval = 17; })()', |
| expect: /^SyntaxError: Unexpected eval or arguments in strict mode/ }, |
| { client: client_unix, send: '(function() { "use strict"; if (true) function f() { } })()', |
| expect: /^SyntaxError: In strict mode code, functions can only be declared at top level or immediately within another function/ }, |
| // Named functions can be used: |
| { client: client_unix, send: 'function blah() { return 1; }', |
| expect: prompt_unix }, |
| { client: client_unix, send: 'blah()', |
| expect: '1\n' + prompt_unix }, |
| // Functions should not evaluate twice (#2773) |
| { client: client_unix, send: 'var I = [1,2,3,function() {}]; I.pop()', |
| expect: '[Function]' }, |
| // Multiline object |
| { client: client_unix, send: '{ a: ', |
| expect: prompt_multiline }, |
| { client: client_unix, send: '1 }', |
| expect: '{ a: 1 }' }, |
| // Multiline anonymous function with comment |
| { client: client_unix, send: '(function() {', |
| expect: prompt_multiline }, |
| { client: client_unix, send: '// blah', |
| expect: prompt_multiline }, |
| { client: client_unix, send: 'return 1;', |
| expect: prompt_multiline }, |
| { client: client_unix, send: '})()', |
| expect: '1' }, |
| // npm prompt error message |
| { client: client_unix, send: 'npm install foobar', |
| expect: expect_npm }, |
| { client: client_unix, send: '(function() {\n\nreturn 1;\n})()', |
| expect: '1' }, |
| { client: client_unix, send: '{\n\na: 1\n}', |
| expect: '{ a: 1 }' }, |
| { client: client_unix, send: 'url.format("http://google.com")', |
| expect: 'http://google.com/' }, |
| { client: client_unix, send: 'var path = 42; path', |
| expect: '42' }, |
| // this makes sure that we don't print `undefined` when we actually print |
| // the error message |
| { client: client_unix, send: '.invalid_repl_command', |
| expect: 'Invalid REPL keyword\n' + prompt_unix }, |
| // this makes sure that we don't crash when we use an inherited property as |
| // a REPL command |
| { client: client_unix, send: '.toString', |
| expect: 'Invalid REPL keyword\n' + prompt_unix }, |
| // fail when we are not inside a String and a line continuation is used |
| { client: client_unix, send: '[] \\', |
| expect: /^SyntaxError: Unexpected token ILLEGAL/ }, |
| // do not fail when a String is created with line continuation |
| { client: client_unix, send: '\'the\\\nfourth\\\neye\'', |
| expect: prompt_multiline + prompt_multiline + |
| '\'thefourtheye\'\n' + prompt_unix }, |
| // Don't fail when a partial String is created and line continuation is used |
| // with whitespace characters at the end of the string. We are to ignore it. |
| // This test is to make sure that we properly remove the whitespace |
| // characters at the end of line, unlike the buggy `trimWhitespace` function |
| { client: client_unix, send: ' \t .break \t ', |
| expect: prompt_unix }, |
| // multiline strings preserve whitespace characters in them |
| { client: client_unix, send: '\'the \\\n fourth\t\t\\\n eye \'', |
| expect: prompt_multiline + prompt_multiline + |
| '\'the fourth\\t\\t eye \'\n' + prompt_unix }, |
| // more than one multiline strings also should preserve whitespace chars |
| { client: client_unix, send: '\'the \\\n fourth\' + \'\t\t\\\n eye \'', |
| expect: prompt_multiline + prompt_multiline + |
| '\'the fourth\\t\\t eye \'\n' + prompt_unix }, |
| // using REPL commands within a string literal should still work |
| { client: client_unix, send: '\'\\\n.break', |
| expect: prompt_unix }, |
| // using REPL command "help" within a string literal should still work |
| { client: client_unix, send: '\'thefourth\\\n.help\neye\'', |
| expect: /'thefourtheye'/ }, |
| // empty lines in the REPL should be allowed |
| { client: client_unix, send: '\n\r\n\r\n', |
| expect: prompt_unix + prompt_unix + prompt_unix }, |
| // empty lines in the string literals should not affect the string |
| { client: client_unix, send: '\'the\\\n\\\nfourtheye\'\n', |
| expect: prompt_multiline + prompt_multiline + |
| '\'thefourtheye\'\n' + prompt_unix }, |
| // Regression test for https://github.com/nodejs/node/issues/597 |
| { client: client_unix, |
| send: '/(.)(.)(.)(.)(.)(.)(.)(.)(.)/.test(\'123456789\')\n', |
| expect: `true\n${prompt_unix}` }, |
| // the following test's result depends on the RegEx's match from the above |
| { client: client_unix, |
| send: 'RegExp.$1\nRegExp.$2\nRegExp.$3\nRegExp.$4\nRegExp.$5\n' + |
| 'RegExp.$6\nRegExp.$7\nRegExp.$8\nRegExp.$9\n', |
| expect: ['\'1\'\n', '\'2\'\n', '\'3\'\n', '\'4\'\n', '\'5\'\n', '\'6\'\n', |
| '\'7\'\n', '\'8\'\n', '\'9\'\n'].join(`${prompt_unix}`) }, |
| ]); |
| } |
| |
| function tcp_test() { |
| server_tcp = net.createServer(function(socket) { |
| assert.strictEqual(server_tcp, socket.server); |
| |
| socket.on('end', function() { |
| socket.end(); |
| }); |
| |
| repl.start(prompt_tcp, socket); |
| }); |
| |
| server_tcp.listen(common.PORT, function() { |
| var read_buffer = ''; |
| |
| client_tcp = net.createConnection(common.PORT); |
| |
| client_tcp.on('connect', function() { |
| assert.equal(true, client_tcp.readable); |
| assert.equal(true, client_tcp.writable); |
| |
| send_expect([ |
| { client: client_tcp, send: '', |
| expect: prompt_tcp }, |
| { client: client_tcp, send: 'invoke_me(333)', |
| expect: ('\'' + 'invoked 333' + '\'\n' + prompt_tcp) }, |
| { client: client_tcp, send: 'a += 1', |
| expect: ('12346' + '\n' + prompt_tcp) }, |
| { client: client_tcp, |
| send: 'require(' + JSON.stringify(moduleFilename) + ').number', |
| expect: ('42' + '\n' + prompt_tcp) } |
| ]); |
| }); |
| |
| client_tcp.on('data', function(data) { |
| read_buffer += data.toString('ascii', 0, data.length); |
| console.error('TCP data: ' + JSON.stringify(read_buffer) + |
| ', expecting ' + JSON.stringify(client_tcp.expect)); |
| if (read_buffer.indexOf(prompt_tcp) !== -1) { |
| assert.strictEqual(client_tcp.expect, read_buffer); |
| console.error('match'); |
| read_buffer = ''; |
| if (client_tcp.list && client_tcp.list.length > 0) { |
| send_expect(client_tcp.list); |
| } else { |
| console.error('End of TCP test.\n'); |
| clean_up(); |
| } |
| } else { |
| console.error('didn\'t see prompt yet, buffering'); |
| } |
| }); |
| |
| client_tcp.on('error', function(e) { |
| throw e; |
| }); |
| |
| client_tcp.on('close', function() { |
| server_tcp.close(); |
| }); |
| }); |
| |
| } |
| |
| function unix_test() { |
| server_unix = net.createServer(function(socket) { |
| assert.strictEqual(server_unix, socket.server); |
| |
| socket.on('end', function() { |
| socket.end(); |
| }); |
| |
| repl.start({ |
| prompt: prompt_unix, |
| input: socket, |
| output: socket, |
| useGlobal: true |
| }).context.message = message; |
| }); |
| |
| server_unix.on('listening', function() { |
| var read_buffer = ''; |
| |
| client_unix = net.createConnection(common.PIPE); |
| |
| client_unix.on('connect', function() { |
| assert.equal(true, client_unix.readable); |
| assert.equal(true, client_unix.writable); |
| |
| send_expect([ |
| { client: client_unix, send: '', |
| expect: prompt_unix }, |
| { client: client_unix, send: 'message', |
| expect: ('\'' + message + '\'\n' + prompt_unix) }, |
| { client: client_unix, send: 'invoke_me(987)', |
| expect: ('\'' + 'invoked 987' + '\'\n' + prompt_unix) }, |
| { client: client_unix, send: 'a = 12345', |
| expect: ('12345' + '\n' + prompt_unix) }, |
| { client: client_unix, send: '{a:1}', |
| expect: ('{ a: 1 }' + '\n' + prompt_unix) } |
| ]); |
| }); |
| |
| client_unix.on('data', function(data) { |
| read_buffer += data.toString('ascii', 0, data.length); |
| console.error('Unix data: ' + JSON.stringify(read_buffer) + |
| ', expecting ' + JSON.stringify(client_unix.expect)); |
| if (read_buffer.indexOf(prompt_unix) !== -1) { |
| assert.strictEqual(client_unix.expect, read_buffer); |
| console.error('match'); |
| read_buffer = ''; |
| if (client_unix.list && client_unix.list.length > 0) { |
| send_expect(client_unix.list); |
| } else { |
| console.error('End of Unix test, running Error test.\n'); |
| process.nextTick(error_test); |
| } |
| } else { |
| console.error('didn\'t see prompt yet, buffering.'); |
| } |
| }); |
| |
| client_unix.on('error', function(e) { |
| throw e; |
| }); |
| |
| client_unix.on('close', function() { |
| server_unix.close(); |
| }); |
| }); |
| |
| server_unix.listen(common.PIPE); |
| } |
| |
| unix_test(); |
| |
| timer = setTimeout(function() { |
| assert.fail('Timeout'); |
| }, 5000); |