From c00a488cb27550cee2d8679b72d4eca9204c5a35 Mon Sep 17 00:00:00 2001 From: Kirill Fomichev Date: Fri, 25 Mar 2016 10:22:19 +0300 Subject: [PATCH 1/6] Apply standard code style --- lib/suppose-process.js | 57 ++++++++--------------- lib/suppose-stream.js | 56 +++++++++-------------- lib/suppose.js | 11 ++--- package.json | 26 +++++++---- test/suppose-process.test.js | 89 +++++++++++++++--------------------- test/suppose-stream.test.js | 35 +++++--------- 6 files changed, 108 insertions(+), 166 deletions(-) diff --git a/lib/suppose-process.js b/lib/suppose-process.js index 08d2d3e..044b3d2 100644 --- a/lib/suppose-process.js +++ b/lib/suppose-process.js @@ -1,22 +1,18 @@ var EventEmitter = require('events') -var S = require('string') -var spawn = require('child_process').spawn -var util = require('util') +var S = require('string') +var spawn = require('child_process').spawn +var util = require('util') var SupposeStream = require('./suppose-stream') - -function SupposeProcess(command, args, options) -{ - if(!(this instanceof SupposeProcess)) +function SupposeProcess (command, args, options) { + if (!(this instanceof SupposeProcess)) { return new SupposeProcess(command, args, options) - + } var self = this - - if(args && !(args instanceof Array)) - { + if (args && !(args instanceof Array)) { options = args args = undefined } @@ -26,53 +22,42 @@ function SupposeProcess(command, args, options) options = options || {} var debug = options.debug - if(debug === true) debug = process.stderr + if (debug === true) debug = process.stderr var supposeStream = SupposeStream(debug) var exe supposeStream.on('error', this.emit.bind(this, 'error')) - Object.defineProperty(this, 'expects', - { - get: function(){return supposeStream.expects} + Object.defineProperty(this, 'expects', { + get: function () { return supposeStream.expects } }) - - this.when = function(expect, response) - { + this.when = function (expect, response) { supposeStream.when(expect) - - if(response) this.respond(response) - + if (response) this.respond(response) return this } - this.respond = function(response) - { - if(response instanceof Function) - supposeStream.respond(function() - { + this.respond = function (response) { + if (response instanceof Function) { + supposeStream.respond(function () { var argv = Array.prototype.slice.call(arguments) argv.unshift(exe) - response.apply(self, argv) }) - else + } else { supposeStream.respond(response) + } return this } - - this.end = function(callback) - { + this.end = function (callback) { exe = spawn(command, args, options) - if(debug) - { + if (debug) { var cmdString = util.format('%s %s', command, args.join(' ')) + '\n' - debug.write(cmdString, 'utf8') debug.write(S('-').times(cmdString.length) + '\n') } @@ -83,8 +68,7 @@ function SupposeProcess(command, args, options) exe.stdout.pipe(supposeStream).pipe(exe.stdin) - exe.stderr.on('data', function(data) - { + exe.stderr.on('data', function (data) { self.emit('error', new Error(data.toString())) }) @@ -95,5 +79,4 @@ function SupposeProcess(command, args, options) } util.inherits(SupposeProcess, EventEmitter) - module.exports = SupposeProcess diff --git a/lib/suppose-stream.js b/lib/suppose-stream.js index e6dd03f..995fec6 100644 --- a/lib/suppose-stream.js +++ b/lib/suppose-stream.js @@ -1,15 +1,13 @@ var forceArray = require('force-array') -var S = require('string') -var Transform = require('stream').Transform -var util = require('util') +var S = require('string') +var Transform = require('stream').Transform +var util = require('util') - -function SupposeStream(debug) { - if(!(this instanceof SupposeStream)) return new SupposeStream(debug) +function SupposeStream (debug) { + if (!(this instanceof SupposeStream)) return new SupposeStream(debug) SupposeStream.super_.call(this) - this.expects = [] var readBuffer = '' @@ -19,20 +17,17 @@ function SupposeStream(debug) { var condition var responses - this._transform = function(chunk, encoding, callback) - { - if(debug) debug.write(chunk) + this._transform = function (chunk, encoding, callback) { + if (debug) debug.write(chunk) readBuffer += chunk.toString() - if(needNew) - { + if (needNew) { var expect = this.expects.shift() condition = expect && expect.condition responses = expect && expect.responses - if(!expect && !sentEof) - { + if (!expect && !sentEof) { // this.expects was always empty this.push(null) sentEof = true @@ -42,37 +37,31 @@ function SupposeStream(debug) { } var match - switch(typeof condition) - { + switch (typeof condition) { case 'string': match = S(readBuffer).endsWith(condition) - break + break case 'object': match = readBuffer.match(condition) } - if(match) - { + if (match) { match = (match instanceof Array) ? match.slice(1) : [] readBuffer = '' needNew = true - responses.forEach(function(response) - { - if(response instanceof Function) + responses.forEach(function (response) { + if (response instanceof Function) { response.apply(this, match) - else - { + } else { this.push(response) - - if(debug) debug.write(response, 'utf8') + if (debug) debug.write(response, 'utf8') } }, this) - if(!this.expects.length) - { + if (!this.expects.length) { this.push(null) sentEof = true } @@ -83,10 +72,8 @@ function SupposeStream(debug) { } util.inherits(SupposeStream, Transform) - -SupposeStream.prototype.when = function(condition, response) { - var expect = - { +SupposeStream.prototype.when = function (condition, response) { + var expect = { condition: condition, responses: forceArray(response) } @@ -96,14 +83,13 @@ SupposeStream.prototype.when = function(condition, response) { return this } -SupposeStream.prototype.respond = function(response) { +SupposeStream.prototype.respond = function (response) { var expects = this.expects - var expect = expects[expects.length-1] + var expect = expects[expects.length - 1] expect.responses = expect.responses.concat(response) return this } - module.exports = SupposeStream diff --git a/lib/suppose.js b/lib/suppose.js index 20fdbfc..63bae3e 100644 --- a/lib/suppose.js +++ b/lib/suppose.js @@ -1,17 +1,12 @@ var sp = require('./suppose-process') var ss = require('./suppose-stream') - -function suppose() -{ - if(typeof arguments[0] === 'string') - return sp.apply(null, arguments) - +function suppose () { + if (typeof arguments[0] === 'string') return sp.apply(null, arguments) return ss.apply(null, arguments) } - suppose.process = sp -suppose.stream = ss +suppose.stream = ss module.exports = suppose diff --git a/package.json b/package.json index e052724..c3ebc62 100644 --- a/package.json +++ b/package.json @@ -2,11 +2,6 @@ "name": "suppose", "version": "0.5.2", "description": "Automate command line programs. Like UNIX expect.", - "homepage": "https://github.com/jprichardson/node-suppose", - "repository": { - "type": "git", - "url": "https://github.com/jprichardson/node-suppose" - }, "keywords": [ "test", "testing", @@ -14,11 +9,25 @@ "expect", "unix" ], + "homepage": "https://github.com/jprichardson/node-suppose", + "license": "MIT", "author": "JP Richardson ", "contributors": [ "Kevin Locke " ], - "license": "MIT", + "files": [ + "lib" + ], + "main": "./lib/suppose", + "repository": { + "type": "git", + "url": "https://github.com/jprichardson/node-suppose" + }, + "scripts": { + "lint": "standard", + "test": "npm run lint && npm run unit", + "unit": "tape test/*.js" + }, "dependencies": { "force-array": "^3.1.0", "string": "~3.3.1" @@ -27,10 +36,7 @@ "autoresolve": "0.0.x", "fs-extra": "~0.26.5", "mocha": "^2.4.5", + "standard": "^6.0.8", "testutil": "~0.7.0" - }, - "main": "./lib/suppose", - "scripts": { - "test": "mocha" } } diff --git a/test/suppose-process.test.js b/test/suppose-process.test.js index bcc4bd3..b5f5bc0 100644 --- a/test/suppose-process.test.js +++ b/test/suppose-process.test.js @@ -1,46 +1,40 @@ -var assert = require('assert') -var join = require('path').join -var os = require('os') -var readline = require('readline') - - -var fs = require('fs-extra') -var P = require('autoresolve') -var S = require('string') +/* global beforeEach, describe, it */ +var assert = require('assert') +var join = require('path').join +var os = require('os') + +var fs = require('fs-extra') +var P = require('autoresolve') +var S = require('string') var testutil = require('testutil') var suppose = require('../lib/suppose') - -beforeEach(function(done) -{ +beforeEach(function (done) { this.TEST_DIR = testutil.createTestDir('suppose') fs.writeFile(join(this.TEST_DIR, 'README.md'), 'READ IT', done) }) -describe('process', function() -{ - it('should automate the command: npm init', function(done) - { +describe('process', function () { + it('should automate the command: npm init', function (done) { var self = this process.chdir(this.TEST_DIR) suppose('npm', ['init']) - .when(/name\: \((\w|\-)+\)\s*/).respond("awesome_package\n") - //.when('name: (test-suppose) ').respond('awesome_package\n') + .when(/name\: \((\w|\-)+\)\s*/).respond('awesome_package\n') + // .when('name: (test-suppose) ').respond('awesome_package\n') .when('version: (1.0.0) ').respond('0.0.1\n') - .when('description: ').respond("It's an awesome package man!\n") - .when('entry point: (index.js) ').respond("\n") + .when('description: ').respond('It\'s an awesome package man!\n') + .when('entry point: (index.js) ').respond('\n') .when('test command: ').respond('npm test\n') - .when('git repository: ').respond("\n") + .when('git repository: ').respond('\n') .when('keywords: ').respond('awesome, cool\n') .when('author: ').respond('JP Richardson\n') .when('license: (ISC) ').respond('MIT\n') - .when('ok? (yes) ' ).respond('yes\n') + .when('ok? (yes) ').respond('yes\n') .on('error', done) - .end(function(code) - { + .end(function (code) { assert.strictEqual(code, 0) var packageObj = require(join(self.TEST_DIR, 'package.json')) @@ -59,27 +53,25 @@ describe('process', function() }) }) - it('should automate the command: npm init and output stdio', function(done) - { + it('should automate the command: npm init and output stdio', function (done) { var self = this var debugFile = join(this.TEST_DIR, 'debug.txt') process.chdir(this.TEST_DIR) suppose('npm', ['init'], {debug: fs.createWriteStream(debugFile)}) - .when(/name\: \([\w|\-]+\)[\s]*/).respond("awesome_package\n") - //.when('name: (test-suppose) ').respond('awesome_package\n') + .when(/name\: \([\w|\-]+\)[\s]*/).respond('awesome_package\n') + // .when('name: (test-suppose) ').respond('awesome_package\n') .when('version: (1.0.0) ').respond('0.0.1\n') .when('description: ').respond("It's an awesome package man!\n") - .when('entry point: (index.js) ').respond("\n") + .when('entry point: (index.js) ').respond('\n') .when('test command: ').respond('npm test\n') - .when('git repository: ').respond("\n") + .when('git repository: ').respond('\n') .when('keywords: ').respond('awesome, cool\n') .when('author: ').respond('JP Richardson\n') .when('license: (ISC) ').respond('MIT\n') - .when('ok? (yes) ' ).respond('yes\n') - .end(function(code, signal) - { + .when('ok? (yes) ').respond('yes\n') + .end(function (code, signal) { assert.strictEqual(code, 0) var packageObj = require(join(self.TEST_DIR, 'package.json')) @@ -95,12 +87,13 @@ describe('process', function() assert.strictEqual(packageObj.license, 'MIT') var debugResFile = '' - if (os.platform() === 'darwin') + if (os.platform() === 'darwin') { debugResFile = P('test/resources/debug-darwin.txt') - else + } else { debugResFile = P('test/resources/debug-linux.txt') + } - //check debug file + // check debug file var debugString = fs.readFileSync(debugFile).toString() var checkString = fs.readFileSync(debugResFile).toString() @@ -110,49 +103,41 @@ describe('process', function() }) }) - it('should emit the error event if there is an error', function(done) - { + it('should emit the error event if there is an error', function (done) { process.chdir(this.TEST_DIR) suppose('node', ['this_script_does_not_exist.js']) - .on('error',function(err) - { + .on('error', function (err) { assert.notStrictEqual(err, undefined) assert.ok(S(err.message).contains('Error: Cannot find module')) }) - .end(function(code) - { + .end(function (code) { assert.notStrictEqual(code, 0) done() }) }) - it('should call a method as response', function(done) - { + it('should call a method as response', function (done) { process.chdir(this.TEST_DIR) suppose('ls', ['-l']) - .when(/total (\d+)\s*/).respond(function(exe, num) - { + .when(/total (\d+)\s*/).respond(function (exe, num) { assert.notStrictEqual(exe, undefined) assert.notStrictEqual(exe.pid, undefined) assert.ok(!isNaN(num)) }) - .end(function(code) - { + .end(function (code) { assert.strictEqual(code, 0) done() }) }) - it('should end if no expectations and no output', function(done) - { + it('should end if no expectations and no output', function (done) { suppose('cat') - .end(function(code) - { + .end(function (code) { assert.strictEqual(code, 0) done() diff --git a/test/suppose-stream.test.js b/test/suppose-stream.test.js index 9d53851..f2c51be 100644 --- a/test/suppose-stream.test.js +++ b/test/suppose-stream.test.js @@ -1,34 +1,23 @@ +/* global describe, it */ var assert = require('assert') -var net = require('net') -var path = require('path') var PassThrough = require('stream').PassThrough -var util = require('util') - -var fs = require('fs-extra') -var P = require('autoresolve') -var S = require('string') var SupposeStream = require('../lib/suppose-stream') - -describe('stream', function() -{ - it('should respond to a stream', function(done) - { - var input = new PassThrough() +describe('stream', function () { + it('should respond to a stream', function (done) { + var input = new PassThrough() var output = new PassThrough() input.pipe(SupposeStream()) .when('Hi').respond('Bye') - .pipe(output) + .pipe(output) - output.once('data', function(chunk, encoding, next) - { + output.once('data', function (chunk, encoding, next) { assert.strictEqual(chunk.toString(), 'Bye') - output.once('data', function(chunk, encoding, next) - { - throw new Error('Unexpected output: ' + chunk); + output.once('data', function (chunk, encoding, next) { + throw new Error('Unexpected output: ' + chunk) }) }) output.once('error', done) @@ -38,13 +27,11 @@ describe('stream', function() input.push('Unexpected') }) - it('should end if no expectations', function(done) - { + it('should end if no expectations', function (done) { var suppose = new SupposeStream() - suppose.once('data', function(chunk, encoding, next) - { - throw new Error('Unexpected output: ' + chunk); + suppose.once('data', function (chunk, encoding, next) { + throw new Error('Unexpected output: ' + chunk) }) suppose.once('error', done) suppose.once('end', done) From 051e59f73a9842e5f922ac215e68a9c027ca5b3c Mon Sep 17 00:00:00 2001 From: Kirill Fomichev Date: Fri, 25 Mar 2016 11:27:15 +0300 Subject: [PATCH 2/6] Tests: tape instead mocha --- package.json | 2 +- test/mocha.opts | 3 - test/suppose-process.js | 136 ++++++++++++++++++++++++++++++++ test/suppose-process.test.js | 146 ----------------------------------- test/suppose-stream.js | 40 ++++++++++ test/suppose-stream.test.js | 42 ---------- 6 files changed, 177 insertions(+), 192 deletions(-) delete mode 100644 test/mocha.opts create mode 100644 test/suppose-process.js delete mode 100644 test/suppose-process.test.js create mode 100644 test/suppose-stream.js delete mode 100644 test/suppose-stream.test.js diff --git a/package.json b/package.json index c3ebc62..6be328b 100644 --- a/package.json +++ b/package.json @@ -35,8 +35,8 @@ "devDependencies": { "autoresolve": "0.0.x", "fs-extra": "~0.26.5", - "mocha": "^2.4.5", "standard": "^6.0.8", + "tape": "^4.5.1", "testutil": "~0.7.0" } } diff --git a/test/mocha.opts b/test/mocha.opts deleted file mode 100644 index fec68ab..0000000 --- a/test/mocha.opts +++ /dev/null @@ -1,3 +0,0 @@ ---reporter spec ---ui bdd ---timeout 5000 \ No newline at end of file diff --git a/test/suppose-process.js b/test/suppose-process.js new file mode 100644 index 0000000..6103dd6 --- /dev/null +++ b/test/suppose-process.js @@ -0,0 +1,136 @@ +var test = require('tape').test +var join = require('path').join +var os = require('os') + +var fs = require('fs-extra') +var P = require('autoresolve') +var S = require('string') +var testutil = require('testutil') + +var suppose = require('../lib/suppose') + +function before (next) { + return function (t) { + t.context = { TEST_DIR: testutil.createTestDir('suppose') } + fs.writeFile(join(t.context.TEST_DIR, 'README.md'), 'READ IT', function (err) { + t.ifError(err) + next(t) + }) + } +} + +test('should automate the command: npm init', before(function (t) { + process.chdir(t.context.TEST_DIR) + + suppose('npm', ['init']) + .when(/name\: \((\w|\-)+\)\s*/).respond('awesome_package\n') + // .when('name: (test-suppose) ').respond('awesome_package\n') + .when('version: (1.0.0) ').respond('0.0.1\n') + .when('description: ').respond('It\'s an awesome package man!\n') + .when('entry point: (index.js) ').respond('\n') + .when('test command: ').respond('npm test\n') + .when('git repository: ').respond('\n') + .when('keywords: ').respond('awesome, cool\n') + .when('author: ').respond('JP Richardson\n') + .when('license: (ISC) ').respond('MIT\n') + .when('ok? (yes) ').respond('yes\n') + .on('error', function (err) { t.fail(err) }) + .end(function (code) { + t.same(code, 0) + + var packageObj = require(join(t.context.TEST_DIR, 'package.json')) + t.same(packageObj.name, 'awesome_package') + t.same(packageObj.version, '0.0.1') + t.same(packageObj.description, 'It\'s an awesome package man!') + t.same(packageObj.main, 'index.js') + t.same(packageObj.scripts.test, 'npm test') + t.same(packageObj.keywords[0], 'awesome') + t.same(packageObj.keywords[1], 'cool') + t.same(packageObj.author, 'JP Richardson') + t.same(packageObj.license, 'MIT') + + t.end() + }) +})) + +test('should automate the command: npm init and output stdio', before(function (t) { + var debugFile = join(t.context.TEST_DIR, 'debug.txt') + process.chdir(t.context.TEST_DIR) + + suppose('npm', ['init'], { debug: fs.createWriteStream(debugFile) }) + .when(/name\: \([\w|\-]+\)[\s]*/).respond('awesome_package\n') + // .when('name: (test-suppose) ').respond('awesome_package\n') + .when('version: (1.0.0) ').respond('0.0.1\n') + .when('description: ').respond("It's an awesome package man!\n") + .when('entry point: (index.js) ').respond('\n') + .when('test command: ').respond('npm test\n') + .when('git repository: ').respond('\n') + .when('keywords: ').respond('awesome, cool\n') + .when('author: ').respond('JP Richardson\n') + .when('license: (ISC) ').respond('MIT\n') + .when('ok? (yes) ').respond('yes\n') + .on('error', function (err) { t.fail(err) }) + .end(function (code, signal) { + t.same(code, 0) + + var packageObj = require(join(t.context.TEST_DIR, 'package.json')) + t.same(packageObj.name, 'awesome_package') + t.same(packageObj.version, '0.0.1') + t.same(packageObj.description, "It's an awesome package man!") + t.same(packageObj.main, 'index.js') + t.same(packageObj.scripts.test, 'npm test') + t.same(packageObj.keywords[0], 'awesome') + t.same(packageObj.keywords[1], 'cool') + t.same(packageObj.author, 'JP Richardson') + t.same(packageObj.license, 'MIT') + + var debugResFile = os.platform() === 'darwin' + ? P('test/resources/debug-darwin.txt') + : P('test/resources/debug-linux.txt') + + // check debug file + var debugString = fs.readFileSync(debugFile).toString() + var checkString = fs.readFileSync(debugResFile).toString() + + t.same(debugString, checkString) + + t.end() + }) +})) + +test('should emit the error event if there is an error', before(function (t) { + process.chdir(t.context.TEST_DIR) + + suppose('node', [ 'this_script_does_not_exist.js' ]) + .on('error', function (err) { + t.notSame(err, undefined) + t.ok(S(err.message).contains('Error: Cannot find module')) + }) + .end(function (code) { + t.notSame(code, 0) + t.end() + }) +})) + +test('should call a method as response', before(function (t) { + process.chdir(t.context.TEST_DIR) + + suppose('ls', ['-l']) + .when(/total (\d+)\s*/).respond(function (exe, num) { + t.notSame(exe, undefined) + t.notSame(exe.pid, undefined) + t.notOk(isNaN(num)) + }) + .end(function (code) { + t.same(code, 0) + t.end() + }) +})) + +test('should end if no expectations and no output', before(function (t) { + suppose('cat') + .end(function (code) { + t.same(code, 0) + t.end() + }) +})) diff --git a/test/suppose-process.test.js b/test/suppose-process.test.js deleted file mode 100644 index b5f5bc0..0000000 --- a/test/suppose-process.test.js +++ /dev/null @@ -1,146 +0,0 @@ -/* global beforeEach, describe, it */ -var assert = require('assert') -var join = require('path').join -var os = require('os') - -var fs = require('fs-extra') -var P = require('autoresolve') -var S = require('string') -var testutil = require('testutil') - -var suppose = require('../lib/suppose') - -beforeEach(function (done) { - this.TEST_DIR = testutil.createTestDir('suppose') - fs.writeFile(join(this.TEST_DIR, 'README.md'), 'READ IT', done) -}) - -describe('process', function () { - it('should automate the command: npm init', function (done) { - var self = this - - process.chdir(this.TEST_DIR) - - suppose('npm', ['init']) - .when(/name\: \((\w|\-)+\)\s*/).respond('awesome_package\n') - // .when('name: (test-suppose) ').respond('awesome_package\n') - .when('version: (1.0.0) ').respond('0.0.1\n') - .when('description: ').respond('It\'s an awesome package man!\n') - .when('entry point: (index.js) ').respond('\n') - .when('test command: ').respond('npm test\n') - .when('git repository: ').respond('\n') - .when('keywords: ').respond('awesome, cool\n') - .when('author: ').respond('JP Richardson\n') - .when('license: (ISC) ').respond('MIT\n') - .when('ok? (yes) ').respond('yes\n') - .on('error', done) - .end(function (code) { - assert.strictEqual(code, 0) - - var packageObj = require(join(self.TEST_DIR, 'package.json')) - - assert.strictEqual(packageObj.name, 'awesome_package') - assert.strictEqual(packageObj.version, '0.0.1') - assert.strictEqual(packageObj.description, "It's an awesome package man!") - assert.strictEqual(packageObj.main, 'index.js') - assert.strictEqual(packageObj.scripts.test, 'npm test') - assert.strictEqual(packageObj.keywords[0], 'awesome') - assert.strictEqual(packageObj.keywords[1], 'cool') - assert.strictEqual(packageObj.author, 'JP Richardson') - assert.strictEqual(packageObj.license, 'MIT') - - done() - }) - }) - - it('should automate the command: npm init and output stdio', function (done) { - var self = this - - var debugFile = join(this.TEST_DIR, 'debug.txt') - process.chdir(this.TEST_DIR) - - suppose('npm', ['init'], {debug: fs.createWriteStream(debugFile)}) - .when(/name\: \([\w|\-]+\)[\s]*/).respond('awesome_package\n') - // .when('name: (test-suppose) ').respond('awesome_package\n') - .when('version: (1.0.0) ').respond('0.0.1\n') - .when('description: ').respond("It's an awesome package man!\n") - .when('entry point: (index.js) ').respond('\n') - .when('test command: ').respond('npm test\n') - .when('git repository: ').respond('\n') - .when('keywords: ').respond('awesome, cool\n') - .when('author: ').respond('JP Richardson\n') - .when('license: (ISC) ').respond('MIT\n') - .when('ok? (yes) ').respond('yes\n') - .end(function (code, signal) { - assert.strictEqual(code, 0) - - var packageObj = require(join(self.TEST_DIR, 'package.json')) - - assert.strictEqual(packageObj.name, 'awesome_package') - assert.strictEqual(packageObj.version, '0.0.1') - assert.strictEqual(packageObj.description, "It's an awesome package man!") - assert.strictEqual(packageObj.main, 'index.js') - assert.strictEqual(packageObj.scripts.test, 'npm test') - assert.strictEqual(packageObj.keywords[0], 'awesome') - assert.strictEqual(packageObj.keywords[1], 'cool') - assert.strictEqual(packageObj.author, 'JP Richardson') - assert.strictEqual(packageObj.license, 'MIT') - - var debugResFile = '' - if (os.platform() === 'darwin') { - debugResFile = P('test/resources/debug-darwin.txt') - } else { - debugResFile = P('test/resources/debug-linux.txt') - } - - // check debug file - var debugString = fs.readFileSync(debugFile).toString() - var checkString = fs.readFileSync(debugResFile).toString() - - assert.strictEqual(debugString, checkString) - - done() - }) - }) - - it('should emit the error event if there is an error', function (done) { - process.chdir(this.TEST_DIR) - - suppose('node', ['this_script_does_not_exist.js']) - .on('error', function (err) { - assert.notStrictEqual(err, undefined) - assert.ok(S(err.message).contains('Error: Cannot find module')) - }) - .end(function (code) { - assert.notStrictEqual(code, 0) - - done() - }) - }) - - it('should call a method as response', function (done) { - process.chdir(this.TEST_DIR) - - suppose('ls', ['-l']) - .when(/total (\d+)\s*/).respond(function (exe, num) { - assert.notStrictEqual(exe, undefined) - assert.notStrictEqual(exe.pid, undefined) - - assert.ok(!isNaN(num)) - }) - .end(function (code) { - assert.strictEqual(code, 0) - - done() - }) - }) - - it('should end if no expectations and no output', function (done) { - suppose('cat') - .end(function (code) { - assert.strictEqual(code, 0) - - done() - }) - }) -}) diff --git a/test/suppose-stream.js b/test/suppose-stream.js new file mode 100644 index 0000000..e560138 --- /dev/null +++ b/test/suppose-stream.js @@ -0,0 +1,40 @@ +var test = require('tape').test +var PassThrough = require('stream').PassThrough + +var SupposeStream = require('../lib/suppose-stream') + +function unexpectedOutput (chunk) { + throw new Error('Unexpected output: ' + chunk) +} + +test('should respond to a stream', function (t) { + var input = new PassThrough() + var output = new PassThrough() + + input.pipe(SupposeStream()) + .when('Hi').respond('Bye') + .pipe(output) + + t.plan(1) + output.once('data', function (chunk, encoding, next) { + t.same(chunk.toString(), 'Bye') + output.once('data', unexpectedOutput) + }) + output.once('error', function (err) { t.fail(err) }) + output.once('end', t.end.bind(t)) + + input.push('Hi') + input.push('Unexpected') +}) + +test('should end if no expectations', function (t) { + var suppose = new SupposeStream() + + t.plan(0) + suppose.once('data', unexpectedOutput) + suppose.once('error', function (err) { t.fail(err) }) + suppose.once('end', t.end.bind(t)) + + suppose.write('Hi') + // stream should end without end of input +}) diff --git a/test/suppose-stream.test.js b/test/suppose-stream.test.js deleted file mode 100644 index f2c51be..0000000 --- a/test/suppose-stream.test.js +++ /dev/null @@ -1,42 +0,0 @@ -/* global describe, it */ -var assert = require('assert') -var PassThrough = require('stream').PassThrough - -var SupposeStream = require('../lib/suppose-stream') - -describe('stream', function () { - it('should respond to a stream', function (done) { - var input = new PassThrough() - var output = new PassThrough() - - input.pipe(SupposeStream()) - .when('Hi').respond('Bye') - .pipe(output) - - output.once('data', function (chunk, encoding, next) { - assert.strictEqual(chunk.toString(), 'Bye') - - output.once('data', function (chunk, encoding, next) { - throw new Error('Unexpected output: ' + chunk) - }) - }) - output.once('error', done) - output.once('end', done) - - input.push('Hi') - input.push('Unexpected') - }) - - it('should end if no expectations', function (done) { - var suppose = new SupposeStream() - - suppose.once('data', function (chunk, encoding, next) { - throw new Error('Unexpected output: ' + chunk) - }) - suppose.once('error', done) - suppose.once('end', done) - - suppose.write('Hi') - // stream should end without end of input - }) -}) From c97e45bd073198d786820097a690456e28637d03 Mon Sep 17 00:00:00 2001 From: Kirill Fomichev Date: Fri, 25 Mar 2016 11:28:26 +0300 Subject: [PATCH 3/6] Update travis config --- .travis.yml | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4ce8af0..d814cee 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,17 @@ +sudo: false +os: linux language: node_js node_js: - - 0.10 - - 0.8 \ No newline at end of file + - "0.10" + - "0.11" + - "0.12" + - "4" + - "5" +env: + matrix: + - TEST_SUITE=unit +matrix: + include: + - node_js: 4 + env: TEST_SUITE=lint +script: npm run $TEST_SUITE From 38eaec0c1afa7cd67a35f4f16c4f4ad89aa23443 Mon Sep 17 00:00:00 2001 From: Kirill Fomichev Date: Fri, 25 Mar 2016 11:29:18 +0300 Subject: [PATCH 4/6] Add coverage script --- .gitignore | 4 +++- package.json | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 1ca9571..e4df30e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ -node_modules/ +.nyc_output +node_modules + npm-debug.log diff --git a/package.json b/package.json index 6be328b..fc6e5b0 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "url": "https://github.com/jprichardson/node-suppose" }, "scripts": { + "coverage": "nyc npm run unit", "lint": "standard", "test": "npm run lint && npm run unit", "unit": "tape test/*.js" @@ -35,6 +36,7 @@ "devDependencies": { "autoresolve": "0.0.x", "fs-extra": "~0.26.5", + "nyc": "^6.1.1", "standard": "^6.0.8", "tape": "^4.5.1", "testutil": "~0.7.0" From 7a8677d5bb2042569ee56eb60c051e77d2961924 Mon Sep 17 00:00:00 2001 From: Kirill Fomichev Date: Fri, 25 Mar 2016 11:46:13 +0300 Subject: [PATCH 5/6] Update README.md --- README.md | 87 ++++++++++++++++++++++--------------------------------- 1 file changed, 34 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index 40f8b4c..b8aea45 100644 --- a/README.md +++ b/README.md @@ -1,90 +1,71 @@ +# suppose -Node.js - suppose -================= +[![NPM Package](https://img.shields.io/npm/v/suppose.svg?style=flat-square)](https://www.npmjs.org/package/suppose) +[![Build Status](https://img.shields.io/travis/jprichardson/node-suppose.svg?branch=master&style=flat-square)](https://travis-ci.org/jprichardson/node-suppose) +[![Dependency status](https://img.shields.io/david/jprichardson/node-suppose.svg?style=flat-square)](https://david-dm.org/jprichardson/node-suppose#info=dependencies) - +[![js-standard-style](https://cdn.rawgit.com/feross/standard/master/badge.svg)](https://github.com/feross/standard) -Have you ever heard of the command line program [expect][1]? Basically, `expect` allows you to automate command line programs. `suppose` is a programmable Node.js module that allows the same behavior. +Have you ever heard of the command line program [expect][1]? Basically, `expect` allows you to automate command line programs. `suppose` is a programmable [Node.js][2] module that allows the same behavior. (*not exactly same, just based on ideas from expect*) +## Why? +From the [expect wikipedia][1] page, you can see many examples of `expect` scripts automating tasks such as `telnet` or `ftp` sessions. Now you can easily write [Node.js][2] scripts to do the same. This may be most beneficial during testing. -Why? ----- - -From the [expect wikipedia][1] page, you can see many examples of `expect` scripts automating tasks such as `telnet` or `ftp` sessions. Now you can easily write Node.js scripts to do the same. This may be most beneficial during testing. - - - -Installation ------------- - - npm install suppose - +## Installation +```shell +npm install suppose +``` -Example ------- +## Example Automate the command `npm init`, which initializes a new npm module. -```javascript +```js var suppose = require('suppose') - , fs = require('fs') - , assert = require('assert') +var fs = require('fs') +var assert = require('assert') -process.chdir('/tmp/awesome'); +process.chdir('/tmp/awesome') fs.writeFileSync('/tmp/awesome/README.md', 'READ IT') // debug is an optional writeable output stream -suppose('npm', ['init'], {debug: fs.createWriteStream('/tmp/debug.txt')}) +suppose('npm', [ 'init' ], { debug: fs.createWriteStream('/tmp/debug.txt') }) .when(/name\: \([\w|\-]+\)[\s]*/).respond('awesome_package\n') .when('version: (1.0.0) ').respond('0.0.1\n') // response can also be the second argument to .when - .when('description: ', "It's an awesome package man!\n") - .when('entry point: (index.js) ').respond("\n") + .when('description: ', 'It\'s an awesome package man!\n') + .when('entry point: (index.js) ').respond('\n') .when('test command: ').respond('npm test\n') - .when('git repository: ').respond("\n") + .when('git repository: ').respond('\n') .when('keywords: ').respond('awesome, cool\n') .when('author: ').respond('JP Richardson\n') .when('license: (ISC) ').respond('MIT\n') - .when('ok? (yes) ' ).respond('yes\n') -.on('error', function(err){ - console.log(err.message); + .when('ok? (yes) ').respond('yes\n') +.on('error', function (err) { + console.log(err) }) -.end(function(code){ - var packageFile = '/tmp/awesome/package.json'; - fs.readFile(packageFile, function(err, data){ - var packageObj = JSON.parse(data.toString()); - console.log(packageObj.name); //'awesome_package' - }) +.end(function (code) { + var packageFile = '/tmp/awesome/package.json' + var packageObj = JSON.parse(fs.readFileSync(packageFile)) + console.log(packageObj.name) // 'awesome_package' }) ``` -`.respond()` may be called any number of times after `.when()`. Each response -will be sent in the order defined when the condition matches. Once all +`.respond()` may be called any number of times after `.when()`. Each response will be sent in the order defined when the condition matches. Once all conditions and responses are defined, call `.end()` to begin execution. +## Contributors -Contributors ------------- -- [*] [Philipp Staender](https://github.com/pstaender) - - -License -------- - -(MIT License) - -Copyright 2012-2013, JP Richardson + - [Philipp Staender](https://github.com/pstaender) +## License +MIT [1]: http://en.wikipedia.org/wiki/Expect - - +[2]: http://nodejs.org/ [aboutjp]: http://about.me/jprichardson [twitter]: http://twitter.com/jprichardson [procbits]: http://procbits.com [gitpilot]: http://gitpilot.com - From 5d54d16b499d64d8593e47412d097469cddf7887 Mon Sep 17 00:00:00 2001 From: Kirill Fomichev Date: Fri, 25 Mar 2016 14:18:40 +0300 Subject: [PATCH 6/6] Remove dependencies, move functions from constructors --- browser.js | 2 + index.js | 3 + lib/process.js | 76 ++++++++++++++++++++ lib/stream.js | 80 +++++++++++++++++++++ lib/suppose-process.js | 82 --------------------- lib/suppose-stream.js | 95 ------------------------- lib/suppose.js | 12 ---- package.json | 12 ++-- test/{suppose-process.js => process.js} | 22 +++--- test/{suppose-stream.js => stream.js} | 4 +- 10 files changed, 179 insertions(+), 209 deletions(-) create mode 100644 browser.js create mode 100644 index.js create mode 100644 lib/process.js create mode 100644 lib/stream.js delete mode 100644 lib/suppose-process.js delete mode 100644 lib/suppose-stream.js delete mode 100644 lib/suppose.js rename test/{suppose-process.js => process.js} (88%) rename test/{suppose-stream.js => stream.js} (91%) diff --git a/browser.js b/browser.js new file mode 100644 index 0000000..fcfd314 --- /dev/null +++ b/browser.js @@ -0,0 +1,2 @@ +'use strict' +module.exports.Stream = require('./lib/stream') diff --git a/index.js b/index.js new file mode 100644 index 0000000..4fd9b0f --- /dev/null +++ b/index.js @@ -0,0 +1,3 @@ +'use strict' +module.exports.Process = require('./lib/process') +module.exports.Stream = require('./lib/stream') diff --git a/lib/process.js b/lib/process.js new file mode 100644 index 0000000..14d8fb9 --- /dev/null +++ b/lib/process.js @@ -0,0 +1,76 @@ +var EventEmitter = require('events') +var spawn = require('child_process').spawn +var inherits = require('inherits') + +var SupposeStream = require('./stream') + +function SupposeProcess (command, args, options) { + EventEmitter.call(this) + + if (!Array.isArray(args)) { + options = args + args = undefined + } + + this._command = command + this._args = args || [] + this._options = options || {} + + this._debug = this._options.debug + if (this._debug === true) this._debug = process.stderr + + this._supposeStream = new SupposeStream(this._debug) + this._supposeStream.on('error', this.emit.bind(this, 'error')) + + this._exe = null +} + +inherits(SupposeProcess, EventEmitter) + +SupposeProcess.prototype.when = function (expect, response) { + this._supposeStream.when(expect, response) + return this +} + +SupposeProcess.prototype.respond = function (response) { + if (typeof response === 'function') { + var self = this + var _response = response + response = function () { + var args = [].slice.call(arguments) + args.unshift(self._exe) + _response.apply(self, args) + } + } + + this._supposeStream.respond(response) + return this +} + +SupposeProcess.prototype.end = function (callback) { + this._exe = spawn(this._command, this._args, this._options) + + if (this._debug) { + var cmdString = this._command + ' ' + this._args.join(' ') + '\n' + this._debug.write(cmdString, 'utf8') + for (var i = 0; i < cmdString.length; ++i) this._debug.write('-') + this._debug.write('\n') + } + + // Empty write signals SupposeStream that input has started and .when() + // will not be called again so it can end output early where possible. + this._supposeStream.write('') + + this._exe.stdout.pipe(this._supposeStream).pipe(this._exe.stdin) + + var self = this + this._exe.stderr.on('data', function (data) { + self.emit('error', new Error(data.toString())) + }) + + this._exe.on('exit', callback.bind(this)) + + return this._exe +} + +module.exports = SupposeProcess diff --git a/lib/stream.js b/lib/stream.js new file mode 100644 index 0000000..f521030 --- /dev/null +++ b/lib/stream.js @@ -0,0 +1,80 @@ +var Transform = require('stream').Transform +var inherits = require('inherits') + +function SupposeStream (debug) { + Transform.call(this) + + this._debug = debug + + this._expects = [] + this._condition = null + this._responses = null + this._text = '' + this._needNew = true + this._sentEOF = false +} + +inherits(SupposeStream, Transform) + +SupposeStream.prototype._transform = function (chunk, encoding, callback) { + if (this._debug) this._debug.write(chunk) + + this._text += chunk.toString() + if (this._needNew) { + var expect = this._expects.shift() + this._condition = expect && expect.condition + this._responses = expect && expect.responses + + if (!expect && !this._sentEOF) { + // this.expects was always empty + this.push(null) + this._sentEOF = true + } + + this._needNew = false + } + + var match + if (typeof this._condition === 'string') { + match = this._text.slice(-this._condition.length) === this._condition + } else if (this._condition instanceof RegExp) { + match = this._text.match(this._condition) + } + + if (match) { + match = Array.isArray(match) ? match.slice(1) : [] + + this._text = '' + this._needNew = true + + this._responses.forEach(function (response) { + if (typeof response === 'function') { + response.apply(this, match) + } else { + this.push(response) + if (this._debug) this._debug.write(response, 'utf8') + } + }, this) + + if (this._expects.length === 0) { + this.push(null) + this._sentEOF = true + } + } + + callback() +} + +SupposeStream.prototype.when = function (condition, response) { + this._expects.push({ condition: condition, responses: [] }) + if (response) this.respond(response) + return this +} + +SupposeStream.prototype.respond = function (responses) { + var expect = this._expects[this._expects.length - 1] + expect.responses = expect.responses.concat(responses) + return this +} + +module.exports = SupposeStream diff --git a/lib/suppose-process.js b/lib/suppose-process.js deleted file mode 100644 index 044b3d2..0000000 --- a/lib/suppose-process.js +++ /dev/null @@ -1,82 +0,0 @@ -var EventEmitter = require('events') -var S = require('string') -var spawn = require('child_process').spawn -var util = require('util') - -var SupposeStream = require('./suppose-stream') - -function SupposeProcess (command, args, options) { - if (!(this instanceof SupposeProcess)) { - return new SupposeProcess(command, args, options) - } - - var self = this - - if (args && !(args instanceof Array)) { - options = args - args = undefined - } - - args = args || [] - - options = options || {} - var debug = options.debug - - if (debug === true) debug = process.stderr - - var supposeStream = SupposeStream(debug) - var exe - - supposeStream.on('error', this.emit.bind(this, 'error')) - - Object.defineProperty(this, 'expects', { - get: function () { return supposeStream.expects } - }) - - this.when = function (expect, response) { - supposeStream.when(expect) - if (response) this.respond(response) - return this - } - - this.respond = function (response) { - if (response instanceof Function) { - supposeStream.respond(function () { - var argv = Array.prototype.slice.call(arguments) - argv.unshift(exe) - response.apply(self, argv) - }) - } else { - supposeStream.respond(response) - } - - return this - } - - this.end = function (callback) { - exe = spawn(command, args, options) - - if (debug) { - var cmdString = util.format('%s %s', command, args.join(' ')) + '\n' - debug.write(cmdString, 'utf8') - debug.write(S('-').times(cmdString.length) + '\n') - } - - // Empty write signals SupposeStream that input has started and .when() - // will not be called again so it can end output early where possible. - supposeStream.write('') - - exe.stdout.pipe(supposeStream).pipe(exe.stdin) - - exe.stderr.on('data', function (data) { - self.emit('error', new Error(data.toString())) - }) - - exe.on('exit', callback.bind(this)) - - return exe - } -} -util.inherits(SupposeProcess, EventEmitter) - -module.exports = SupposeProcess diff --git a/lib/suppose-stream.js b/lib/suppose-stream.js deleted file mode 100644 index 995fec6..0000000 --- a/lib/suppose-stream.js +++ /dev/null @@ -1,95 +0,0 @@ -var forceArray = require('force-array') -var S = require('string') -var Transform = require('stream').Transform -var util = require('util') - -function SupposeStream (debug) { - if (!(this instanceof SupposeStream)) return new SupposeStream(debug) - - SupposeStream.super_.call(this) - - this.expects = [] - - var readBuffer = '' - var needNew = true - var sentEof = false - - var condition - var responses - - this._transform = function (chunk, encoding, callback) { - if (debug) debug.write(chunk) - - readBuffer += chunk.toString() - if (needNew) { - var expect = this.expects.shift() - - condition = expect && expect.condition - responses = expect && expect.responses - - if (!expect && !sentEof) { - // this.expects was always empty - this.push(null) - sentEof = true - } - - needNew = false - } - - var match - switch (typeof condition) { - case 'string': - match = S(readBuffer).endsWith(condition) - break - - case 'object': - match = readBuffer.match(condition) - } - - if (match) { - match = (match instanceof Array) ? match.slice(1) : [] - - readBuffer = '' - needNew = true - - responses.forEach(function (response) { - if (response instanceof Function) { - response.apply(this, match) - } else { - this.push(response) - if (debug) debug.write(response, 'utf8') - } - }, this) - - if (!this.expects.length) { - this.push(null) - sentEof = true - } - } - - callback() - } -} -util.inherits(SupposeStream, Transform) - -SupposeStream.prototype.when = function (condition, response) { - var expect = { - condition: condition, - responses: forceArray(response) - } - - this.expects.push(expect) - - return this -} - -SupposeStream.prototype.respond = function (response) { - var expects = this.expects - var expect = expects[expects.length - 1] - - expect.responses = expect.responses.concat(response) - - return this -} - -module.exports = SupposeStream diff --git a/lib/suppose.js b/lib/suppose.js deleted file mode 100644 index 63bae3e..0000000 --- a/lib/suppose.js +++ /dev/null @@ -1,12 +0,0 @@ -var sp = require('./suppose-process') -var ss = require('./suppose-stream') - -function suppose () { - if (typeof arguments[0] === 'string') return sp.apply(null, arguments) - return ss.apply(null, arguments) -} - -suppose.process = sp -suppose.stream = ss - -module.exports = suppose diff --git a/package.json b/package.json index fc6e5b0..6073da6 100644 --- a/package.json +++ b/package.json @@ -16,9 +16,11 @@ "Kevin Locke " ], "files": [ - "lib" + "lib", + "browser.js", + "index.js" ], - "main": "./lib/suppose", + "main": "./index.js", "repository": { "type": "git", "url": "https://github.com/jprichardson/node-suppose" @@ -30,8 +32,7 @@ "unit": "tape test/*.js" }, "dependencies": { - "force-array": "^3.1.0", - "string": "~3.3.1" + "inherits": "^2.0.1" }, "devDependencies": { "autoresolve": "0.0.x", @@ -40,5 +41,6 @@ "standard": "^6.0.8", "tape": "^4.5.1", "testutil": "~0.7.0" - } + }, + "browser": "./browser.js" } diff --git a/test/suppose-process.js b/test/process.js similarity index 88% rename from test/suppose-process.js rename to test/process.js index 6103dd6..8518425 100644 --- a/test/suppose-process.js +++ b/test/process.js @@ -4,10 +4,9 @@ var os = require('os') var fs = require('fs-extra') var P = require('autoresolve') -var S = require('string') var testutil = require('testutil') -var suppose = require('../lib/suppose') +var SupposeProcess = require('../').Process function before (next) { return function (t) { @@ -22,9 +21,8 @@ function before (next) { test('should automate the command: npm init', before(function (t) { process.chdir(t.context.TEST_DIR) - suppose('npm', ['init']) + new SupposeProcess('npm', ['init']) .when(/name\: \((\w|\-)+\)\s*/).respond('awesome_package\n') - // .when('name: (test-suppose) ').respond('awesome_package\n') .when('version: (1.0.0) ').respond('0.0.1\n') .when('description: ').respond('It\'s an awesome package man!\n') .when('entry point: (index.js) ').respond('\n') @@ -57,9 +55,8 @@ test('should automate the command: npm init and output stdio', before(function ( var debugFile = join(t.context.TEST_DIR, 'debug.txt') process.chdir(t.context.TEST_DIR) - suppose('npm', ['init'], { debug: fs.createWriteStream(debugFile) }) + new SupposeProcess('npm', ['init'], { debug: fs.createWriteStream(debugFile) }) .when(/name\: \([\w|\-]+\)[\s]*/).respond('awesome_package\n') - // .when('name: (test-suppose) ').respond('awesome_package\n') .when('version: (1.0.0) ').respond('0.0.1\n') .when('description: ').respond("It's an awesome package man!\n") .when('entry point: (index.js) ').respond('\n') @@ -101,21 +98,21 @@ test('should automate the command: npm init and output stdio', before(function ( test('should emit the error event if there is an error', before(function (t) { process.chdir(t.context.TEST_DIR) - suppose('node', [ 'this_script_does_not_exist.js' ]) + t.plan(3) + new SupposeProcess('node', [ 'this_script_does_not_exist.js' ]) .on('error', function (err) { - t.notSame(err, undefined) - t.ok(S(err.message).contains('Error: Cannot find module')) + t.ok(err.toString().match(/Error: Cannot find module/)) }) .end(function (code) { t.notSame(code, 0) - t.end() }) })) test('should call a method as response', before(function (t) { process.chdir(t.context.TEST_DIR) - suppose('ls', ['-l']) + t.plan(5) + new SupposeProcess('ls', [ '-l' ]) .when(/total (\d+)\s*/).respond(function (exe, num) { t.notSame(exe, undefined) t.notSame(exe.pid, undefined) @@ -123,12 +120,11 @@ test('should call a method as response', before(function (t) { }) .end(function (code) { t.same(code, 0) - t.end() }) })) test('should end if no expectations and no output', before(function (t) { - suppose('cat') + new SupposeProcess('cat') .end(function (code) { t.same(code, 0) t.end() diff --git a/test/suppose-stream.js b/test/stream.js similarity index 91% rename from test/suppose-stream.js rename to test/stream.js index e560138..9597594 100644 --- a/test/suppose-stream.js +++ b/test/stream.js @@ -1,7 +1,7 @@ var test = require('tape').test var PassThrough = require('stream').PassThrough -var SupposeStream = require('../lib/suppose-stream') +var SupposeStream = require('../').Stream function unexpectedOutput (chunk) { throw new Error('Unexpected output: ' + chunk) @@ -11,7 +11,7 @@ test('should respond to a stream', function (t) { var input = new PassThrough() var output = new PassThrough() - input.pipe(SupposeStream()) + input.pipe(new SupposeStream()) .when('Hi').respond('Bye') .pipe(output)