exit_test.js
  1  'use strict';
  2  
  3  /*
  4    ======== A Handy Little Nodeunit Reference ========
  5    https://github.com/caolan/nodeunit
  6  
  7    Test methods:
  8      test.expect(numAssertions)
  9      test.done()
 10    Test assertions:
 11      test.ok(value, [message])
 12      test.equal(actual, expected, [message])
 13      test.notEqual(actual, expected, [message])
 14      test.deepEqual(actual, expected, [message])
 15      test.notDeepEqual(actual, expected, [message])
 16      test.strictEqual(actual, expected, [message])
 17      test.notStrictEqual(actual, expected, [message])
 18      test.throws(block, [error], [message])
 19      test.doesNotThrow(block, [error], [message])
 20      test.ifError(value)
 21  */
 22  
 23  var fs = require('fs');
 24  var exec = require('child_process').exec;
 25  
 26  var _which = require('which').sync;
 27  function which(command) {
 28    try {
 29      _which(command);
 30      return command;
 31    } catch (err) {
 32      return false;
 33    }
 34  }
 35  
 36  // Look for grep first (any OS). If not found (but on Windows) look for find,
 37  // which is Windows' horribly crippled grep alternative.
 38  var grep = which('grep') || process.platform === 'win32' && which('find');
 39  
 40  exports['exit'] = {
 41    setUp: function(done) {
 42      this.origCwd = process.cwd();
 43      process.chdir('test/fixtures');
 44      done();
 45    },
 46    tearDown: function(done) {
 47      process.chdir(this.origCwd);
 48      done();
 49    },
 50    'grep': function(test) {
 51      test.expect(1);
 52      // Many unit tests depend on this.
 53      test.ok(grep, 'A suitable "grep" or "find" program was not found in the PATH.');
 54      test.done();
 55    },
 56    // The rest of the tests are built dynamically, to keep things sane.
 57  };
 58  
 59  // A few helper functions.
 60  function normalizeLineEndings(s) {
 61    return s.replace(/\r?\n/g, '\n');
 62  }
 63  
 64  // Capture command output, normalizing captured stdout to unix file endings.
 65  function run(command, callback) {
 66    exec(command, function(error, stdout) {
 67      callback(error ? error.code : 0, normalizeLineEndings(stdout));
 68    });
 69  }
 70  
 71  // Read a fixture file, normalizing file contents to unix file endings.
 72  function fixture(filename) {
 73    return normalizeLineEndings(String(fs.readFileSync(filename)));
 74  }
 75  
 76  function buildTests() {
 77    // Build individual unit tests for command output.
 78    var counts = [10, 100, 1000];
 79    var outputs = [' stdout stderr', ' stdout', ' stderr'];
 80    var pipes = ['', ' | ' + grep + ' "std"'];
 81    counts.forEach(function(count) {
 82      outputs.forEach(function(output) {
 83        pipes.forEach(function(pipe) {
 84          var command = 'node log.js 0 ' + count + output + ' 2>&1' + pipe;
 85          exports['exit']['output (' + command + ')'] = function(test) {
 86            test.expect(2);
 87            run(command, function(code, actual) {
 88              var expected = fixture(count + output.replace(/ /g, '-') + '.txt');
 89              // Sometimes, the actual file lines are out of order on Windows.
 90              // But since the point of this lib is to drain the buffer and not
 91              // guarantee output order, we only test the length.
 92              test.equal(actual.length, expected.length, 'should be the same length.');
 93              // The "fail" lines in log.js should NOT be output!
 94              test.ok(actual.indexOf('fail') === -1, 'should not output after exit is called.');
 95              test.done();
 96            });
 97          };
 98        });
 99      });
100    });
101  
102    // Build individual unit tests for exit codes.
103    var codes = [0, 1, 123];
104    codes.forEach(function(code) {
105      var command = 'node log.js ' + code + ' 10 stdout stderr';
106      exports['exit']['exit code (' + command + ')'] = function(test) {
107        test.expect(1);
108        run(command, function(actual) {
109          // The specified exit code should be passed through.
110          test.equal(actual, code, 'should exit with ' + code + ' error code.');
111          test.done();
112        });
113      };
114    });
115  }
116  
117  // Don't bother building tests if grep wasn't found, otherwise everything will
118  // fail and the error will get lost.
119  if (grep) {
120    buildTests();
121  }