test: add tests for persistent repl history
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>
This commit is contained in:
parent
1721968b22
commit
ceee8d2807
@ -10,6 +10,8 @@ ecmaFeatures:
|
||||
generators: true
|
||||
forOf: true
|
||||
objectLiteralShorthandProperties: true
|
||||
objectLiteralShorthandMethods: true
|
||||
classes: true
|
||||
|
||||
rules:
|
||||
# Possible Errors
|
||||
|
@ -17,8 +17,12 @@ function replStart() {
|
||||
return REPL.start.apply(REPL, arguments);
|
||||
}
|
||||
|
||||
function createRepl(env, cb) {
|
||||
const opts = {
|
||||
function createRepl(env, opts, cb) {
|
||||
if (typeof opts === 'function') {
|
||||
cb = opts;
|
||||
opts = null;
|
||||
}
|
||||
opts = opts || {
|
||||
ignoreUndefined: false,
|
||||
terminal: process.stdout.isTTY,
|
||||
useGlobal: true
|
||||
|
2
test/fixtures/.node_repl_history
vendored
Normal file
2
test/fixtures/.node_repl_history
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
'you look fabulous today'
|
||||
'Stay Fresh~'
|
4
test/fixtures/old-repl-history-file.json
vendored
Normal file
4
test/fixtures/old-repl-history-file.json
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
[
|
||||
"'=^.^='",
|
||||
"'hello world'"
|
||||
]
|
193
test/sequential/test-repl-persistent-history.js
Normal file
193
test/sequential/test-repl-persistent-history.js
Normal file
@ -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…
x
Reference in New Issue
Block a user