mirror of https://github.com/lukechilds/node.git
Browse Source
PR-URL: https://github.com/nodejs/io.js/pull/2224 Reviewed-By: Michaël Zasso <mic.besace@gmail.com> Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com> Reviewed-By: Roman Reiss <me@silverwind.io>v4.0.0-rc
committed by
Rod Vagg
5 changed files with 207 additions and 2 deletions
@ -0,0 +1,2 @@ |
|||||
|
'you look fabulous today' |
||||
|
'Stay Fresh~' |
@ -0,0 +1,4 @@ |
|||||
|
[ |
||||
|
"'=^.^='", |
||||
|
"'hello world'" |
||||
|
] |
@ -0,0 +1,193 @@ |
|||||
|
'use strict'; |
||||
|
|
||||
|
// Flags: --expose-internals
|
||||
|
|
||||
|
const common = require('../common'); |
||||
|
const stream = require('stream'); |
||||
|
const REPL = require('internal/repl'); |
||||
|
const assert = require('assert'); |
||||
|
const fs = require('fs'); |
||||
|
const util = require('util'); |
||||
|
const path = require('path'); |
||||
|
const os = require('os'); |
||||
|
|
||||
|
common.refreshTmpDir(); |
||||
|
|
||||
|
// Mock os.homedir()
|
||||
|
os.homedir = function() { |
||||
|
return common.tmpDir; |
||||
|
}; |
||||
|
|
||||
|
// Create an input stream specialized for testing an array of actions
|
||||
|
class ActionStream extends stream.Stream { |
||||
|
run(data) { |
||||
|
const _iter = data[Symbol.iterator](); |
||||
|
const self = this; |
||||
|
|
||||
|
function doAction() { |
||||
|
const next = _iter.next(); |
||||
|
if (next.done) { |
||||
|
// Close the repl. Note that it must have a clean prompt to do so.
|
||||
|
setImmediate(function() { |
||||
|
self.emit('keypress', '', { ctrl: true, name: 'd' }); |
||||
|
}); |
||||
|
return; |
||||
|
} |
||||
|
const action = next.value; |
||||
|
|
||||
|
if (typeof action === 'object') { |
||||
|
self.emit('keypress', '', action); |
||||
|
} else { |
||||
|
self.emit('data', action + '\n'); |
||||
|
} |
||||
|
setImmediate(doAction); |
||||
|
} |
||||
|
setImmediate(doAction); |
||||
|
} |
||||
|
resume() {} |
||||
|
pause() {} |
||||
|
} |
||||
|
ActionStream.prototype.readable = true; |
||||
|
|
||||
|
|
||||
|
// Mock keys
|
||||
|
const UP = { name: 'up' }; |
||||
|
const ENTER = { name: 'enter' }; |
||||
|
const CLEAR = { ctrl: true, name: 'u' }; |
||||
|
// Common message bits
|
||||
|
const prompt = '> '; |
||||
|
const replDisabled = '\nPersistent history support disabled. Set the ' + |
||||
|
'NODE_REPL_HISTORY environment\nvariable to a valid, ' + |
||||
|
'user-writable path to enable.\n'; |
||||
|
const convertMsg = '\nConverting old JSON repl history to line-separated ' + |
||||
|
'history.\nThe new repl history file can be found at ' + |
||||
|
path.join(common.tmpDir, '.node_repl_history') + '.\n'; |
||||
|
const homedirErr = '\nError: Could not get the home directory.\n' + |
||||
|
'REPL session history will not be persisted.\n'; |
||||
|
// File paths
|
||||
|
const fixtures = path.join(common.testDir, 'fixtures'); |
||||
|
const historyFixturePath = path.join(fixtures, '.node_repl_history'); |
||||
|
const historyPath = path.join(common.tmpDir, '.fixture_copy_repl_history'); |
||||
|
const oldHistoryPath = path.join(fixtures, 'old-repl-history-file.json'); |
||||
|
|
||||
|
|
||||
|
const tests = [{ |
||||
|
env: { NODE_REPL_HISTORY: '' }, |
||||
|
test: [UP], |
||||
|
expected: [prompt, replDisabled, prompt] |
||||
|
}, |
||||
|
{ |
||||
|
env: { NODE_REPL_HISTORY: '', |
||||
|
NODE_REPL_HISTORY_FILE: oldHistoryPath }, |
||||
|
test: [UP], |
||||
|
expected: [prompt, replDisabled, prompt] |
||||
|
}, |
||||
|
{ |
||||
|
env: { NODE_REPL_HISTORY: historyPath }, |
||||
|
test: [UP, CLEAR], |
||||
|
expected: [prompt, prompt + '\'you look fabulous today\'', prompt] |
||||
|
}, |
||||
|
{ |
||||
|
env: { NODE_REPL_HISTORY: historyPath, |
||||
|
NODE_REPL_HISTORY_FILE: oldHistoryPath }, |
||||
|
test: [UP, CLEAR], |
||||
|
expected: [prompt, prompt + '\'you look fabulous today\'', prompt] |
||||
|
}, |
||||
|
{ |
||||
|
env: { NODE_REPL_HISTORY: historyPath, |
||||
|
NODE_REPL_HISTORY_FILE: '' }, |
||||
|
test: [UP, CLEAR], |
||||
|
expected: [prompt, prompt + '\'you look fabulous today\'', prompt] |
||||
|
}, |
||||
|
{ |
||||
|
env: {}, |
||||
|
test: [UP], |
||||
|
expected: [prompt] |
||||
|
}, |
||||
|
{ |
||||
|
env: { NODE_REPL_HISTORY_FILE: oldHistoryPath }, |
||||
|
test: [UP, CLEAR, '\'42\'', ENTER/*, function(cb) { |
||||
|
// XXX(Fishrock123) Allow the REPL to save to disk.
|
||||
|
// There isn't a way to do this programmatically right now.
|
||||
|
setTimeout(cb, 50); |
||||
|
}*/], |
||||
|
expected: [prompt, convertMsg, prompt, prompt + '\'=^.^=\'', prompt, '\'', |
||||
|
'4', '2', '\'', '\'42\'\n', prompt, prompt], |
||||
|
after: function ensureHistoryFixture() { |
||||
|
// XXX(Fishrock123) Make sure nothing weird happened to our fixture
|
||||
|
// or it's temporary copy.
|
||||
|
// Sometimes this test used to erase the fixture and I'm not sure why.
|
||||
|
const history = fs.readFileSync(historyFixturePath, 'utf8'); |
||||
|
assert.strictEqual(history, |
||||
|
'\'you look fabulous today\'\n\'Stay Fresh~\'\n'); |
||||
|
const historyCopy = fs.readFileSync(historyPath, 'utf8'); |
||||
|
assert.strictEqual(historyCopy, '\'you look fabulous today\'' + os.EOL + |
||||
|
'\'Stay Fresh~\'' + os.EOL); |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
env: {}, |
||||
|
test: [UP, UP, ENTER], |
||||
|
expected: [prompt, prompt + '\'42\'', prompt + '\'=^.^=\'', '\'=^.^=\'\n', |
||||
|
prompt] |
||||
|
}, |
||||
|
{ // Make sure this is always the last test, since we change os.homedir()
|
||||
|
before: function mockHomedirFailure() { |
||||
|
// Mock os.homedir() failure
|
||||
|
os.homedir = function() { |
||||
|
throw new Error('os.homedir() failure'); |
||||
|
}; |
||||
|
}, |
||||
|
env: {}, |
||||
|
test: [UP], |
||||
|
expected: [prompt, homedirErr, prompt, replDisabled, prompt] |
||||
|
}]; |
||||
|
|
||||
|
|
||||
|
// Copy our fixture to the tmp directory
|
||||
|
fs.createReadStream(historyFixturePath) |
||||
|
.pipe(fs.createWriteStream(historyPath)).on('unpipe', runTest); |
||||
|
|
||||
|
function runTest() { |
||||
|
const opts = tests.shift(); |
||||
|
if (!opts) return; // All done
|
||||
|
|
||||
|
const env = opts.env; |
||||
|
const test = opts.test; |
||||
|
const expected = opts.expected; |
||||
|
const after = opts.after; |
||||
|
const before = opts.before; |
||||
|
|
||||
|
if (before) before(); |
||||
|
|
||||
|
REPL.createInternalRepl(env, { |
||||
|
input: new ActionStream(), |
||||
|
output: new stream.Writable({ |
||||
|
write(chunk, _, next) { |
||||
|
const output = chunk.toString(); |
||||
|
|
||||
|
// Ignore escapes and blank lines
|
||||
|
if (output.charCodeAt(0) === 27 || /^[\r\n]+$/.test(output)) |
||||
|
return next(); |
||||
|
|
||||
|
assert.strictEqual(output, expected.shift()); |
||||
|
next(); |
||||
|
} |
||||
|
}), |
||||
|
prompt: prompt, |
||||
|
useColors: false, |
||||
|
terminal: true |
||||
|
}, function(err, repl) { |
||||
|
if (err) throw err; |
||||
|
|
||||
|
if (after) repl.on('close', after); |
||||
|
|
||||
|
repl.on('close', function() { |
||||
|
// Ensure everything that we expected was output
|
||||
|
assert.strictEqual(expected.length, 0); |
||||
|
setImmediate(runTest); |
||||
|
}); |
||||
|
|
||||
|
repl.inputStream.run(test); |
||||
|
}); |
||||
|
} |
Loading…
Reference in new issue