Permalink
Browse files

[api test dist] Added functionality: nexpect.wait(), options.stripCol…

…ors, options.ignoreCase, options.verbose
  • Loading branch information...
indexzero committed Aug 10, 2011
1 parent 1a1ebb5 commit 178fd4fb5902e3ac1d82c6ad802d1cacd812499b
Showing with 191 additions and 33 deletions.
  1. +125 −32 lib/nexpect.js
  2. +2 −0 package.json
  3. +7 −0 test/fixtures/log-colors
  4. +5 −0 test/fixtures/multiple-cases
  5. +14 −0 test/fixtures/prompt-and-respond
  6. +38 −1 test/nexpect-test.js
View
@@ -9,73 +9,162 @@ var spawn = require('child_process').spawn;
function chain (context) {
return {
- expect: function (assert) {
- context.queue.push(function (data) {
- return data.indexOf(assert) > -1;
- });
+ expect: function (str) {
+ var _expect = function _expect (data) {
+ return data.indexOf(str) > -1;
+ };
+
+ _expect.shift = true;
+ context.queue.push(_expect);
return chain(context);
},
sendline: function (line) {
- context.queue.push(function () {
+ var _sendline = function _sendline () {
context.process.stdin.write(line + '\n');
- });
+ };
+
+ _sendline.shift = true;
+ context.queue.push(_sendline);
+
+ return chain(context);
+ },
+ wait: function (str) {
+ var _wait = function _wait (data) {
+ return data.indexOf(str) > -1;
+ };
+ _wait.shift = false;
+ context.queue.push(_wait);
return chain(context);
},
run: function (callback) {
- var errState = null;
+ var errState = null,
+ responded = false,
+ stdout = [];
- function onError (err) {
- if (errState) {
+ function onError (err, kill) {
+ if (errState || responded) {
return;
}
errState = err;
+ responded = true;
- try { context.process.kill() }
- catch (ex) { }
-
+ if (kill) {
+ try { context.process.kill() }
+ catch (ex) { }
+ }
+
callback(err);
}
+ function evalContext (data, name) {
+ var currentFn = context.queue[0];
+
+ if (!currentFn || (name === '_expect' && currentFn.name === '_expect')) {
+ //
+ // If there is nothing left on the context or we are trying to
+ // evaluate two consecutive `_expect` functions, return.
+ //
+ return;
+ }
+
+ if (currentFn.shift) {
+ context.queue.shift();
+ }
+
+ if (typeof currentFn !== 'function') {
+ //
+ // If the `currentFn` is not a function, short-circuit with an error.
+ //
+ return onError(new Error('Cannot process non-function on nexpect stack.'), true);
+ }
+ else if (['_expect', '_sendline', '_wait'].indexOf(currentFn.name) === -1) {
+ //
+ // If the `currentFn` is a function, but not those set by `.sendline()` or
+ // `.expect()` then short-circuit with an error.
+ //
+ return onError(new Error('Unexpected context function name: ' + currentFn.name), true);
+ }
+
+ if (currentFn.name === '_expect') {
+ //
+ // If this is an `_expect` function, then evaluate it and attempt
+ // to evaluate the next function (in case it is a `_sendline` function).
+ //
+ return currentFn(data) === true
+ ? evalContext(data, '_expect')
+ : onError(new Error(data + ' was not expected..'), true);
+ }
+ else if (currentFn.name === '_wait') {
+ //
+ // If this is a `_wait` function, then evaluate it and if it returns true,
+ // then evaluate the function (in case it is a `_sendline` function).
+ //
+ if (currentFn(data) === true) {
+ context.queue.shift();
+ evalContext(data, '_expect');
+ }
+ }
+ else if (currentFn.name === '_sendline') {
+ //
+ // If the `currentFn` is a `_sendline` function then evaluate
+ // it and return.
+ //
+ currentFn();
+ }
+ }
+
function onLine (data) {
data = data.toString();
- if (module.exports.debug || module.exports.nspawn.debug) {
+ if (context.verbose) {
process.stdout.write(data);
}
- var expect = context.queue[0];
-
- if (!expect) {
- return;
- }
- else if (typeof expect !== 'function') {
- console.dir(expect);
- return onError('Cannot process non-function on nexpect stack.');
+ if (context.stripColors) {
+ data = data.replace(/\u001b\[\d{0,2}m/g, '');
}
- else if (expect(data) !== true) {
- return onError(data + ' was not expected..');
- }
-
- context.queue.shift();
- var sendline = context.queue.shift();
- if (typeof sendline === 'function') {
- sendline();
+
+ if (context.ignoreCase) {
+ data = data.toLowerCase();
}
+
+ stdout = stdout.concat(data.split('\n').filter(function (line) { line !== '' }));
+ evalContext(data, null);
};
context.process = spawn(context.command, context.params);
context.process.stdout.on('data', onLine);
- context.process.stdout.on('end', function () {
- callback(errState);
+ context.process.on('exit', function (code, signal) {
+ if (code === 127) {
+ //
+ // If the response code is `127` then `context.command` was not found.
+ //
+ return onError(new Error('Command not found: ' + context.command));
+ }
+
+ callback(null, stdout);
});
+
+ return context.process;
}
};
};
-function nspawn (command, params) {
+function nspawn (command, params, options) {
+ if (arguments.length === 2) {
+ if (Array.isArray(arguments[1])) {
+ params = arguments[1];
+ options = {};
+ }
+ else {
+ params = [];
+ options = arguments[1];
+ }
+ }
+
if (Array.isArray(command)) {
params = command;
command = params.shift();
@@ -86,10 +175,14 @@ function nspawn (command, params) {
command = command[0];
}
+ options = options || {};
context = {
command: command,
params: params,
queue: [],
+ verbose: options.verbose,
+ stripColors: options.stripColors,
+ ignoreCase: options.ignoreCase
};
return chain(context);
View
@@ -13,6 +13,8 @@
},
"keywords": ["nexpect", "spawn", "child process", "terminal"],
"devDependencies": {
+ "colors": "0.x.x",
+ "prompt": "0.1.x >=0.1.5",
"vows": "0.5.x"
},
"main": "./lib/nexpect",
View
@@ -0,0 +1,7 @@
+#!/usr/bin/env node
+
+var colors = require('colors');
+
+console.log('first has no colors');
+console.log('second has colors'.green);
+console.log('third has colors'.yellow);
@@ -0,0 +1,5 @@
+#!/usr/bin/env node
+
+console.log('this is all lowercase');
+console.log('ThIs HAS mAny cases');
+console.log('ThIs also HAS mAny cASEs');
@@ -0,0 +1,14 @@
+#!/usr/bin/env node
+
+var prompt = require('prompt');
+
+console.log('Starting prompt');
+
+prompt.start();
+prompt.get(['first'], function (err, result) {
+ console.log(result.first);
+
+ prompt.get(['second'], function (err, result) {
+ console.log(result.second);
+ })
+});
View
@@ -6,6 +6,7 @@
*/
var assert = require('assert'),
+ path = require('path'),
vows = require('vows'),
spawn = require('child_process').spawn,
nexpect = require('../lib/nexpect');
@@ -15,8 +16,21 @@ function assertSpawn (expect) {
topic: function () {
expect.run(this.callback)
},
- "should respond with no error": function (err) {
+ "should respond with no error": function (err, stdout) {
assert.isTrue(!err);
+ assert.isArray(stdout);
+ }
+ }
+}
+
+function assertError (expect) {
+ return {
+ topic: function () {
+ expect.run(this.callback.bind(this, null))
+ },
+ "should respond with no error": function (_, err) {
+ assert.isObject(err);
+ assert.isNotNull(err.message.match(/^Command not found/));
}
}
}
@@ -37,12 +51,35 @@ vows.describe('nexpect').addBatch({
nexpect.spawn("ls -la /tmp/undefined")
.expect("No such file or directory")
),
+ "a command that does not exist": assertError(
+ nexpect.spawn("idontexist")
+ .expect("This will never work")
+ ),
"and using the sendline() method": assertSpawn(
nexpect.spawn("node")
.expect(">")
.sendline("console.log('testing')")
.expect("testing")
.sendline("process.exit()")
+ ),
+ "and using the wait() method": assertSpawn(
+ nexpect.spawn(path.join(__dirname, 'fixtures', 'prompt-and-respond'))
+ .wait('first')
+ .sendline('first-prompt')
+ .expect('first-prompt')
+ .wait('second')
+ .sendline('second-prompt')
+ .expect('second-prompt')
+ ),
+ "when options.stripColors is set": assertSpawn(
+ nexpect.spawn(path.join(__dirname, 'fixtures', 'log-colors'), { stripColors: true })
+ .wait('second has colors')
+ .expect('third has colors')
+ ),
+ "when options.ignoreCase is set": assertSpawn(
+ nexpect.spawn(path.join(__dirname, 'fixtures', 'multiple-cases'), { ignoreCase: true })
+ .wait('this has many cases')
+ .expect('this also has many cases')
)
}
}

0 comments on commit 178fd4f

Please sign in to comment.