| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554 | 'use strict';var util = require('../');var fs = require('fs');var path = require('path');var Tempfile = require('temporary/lib/file');exports['util.callbackify'] = {  'return': function(test) {    test.expect(1);    // This function returns a value.    function add(a, b) {      return a + b;    }    util.callbackify(add)(1, 2, function(result) {      test.equal(result, 3, 'should be the correct result.');      test.done();    });  },  'callback (sync)': function(test) {    test.expect(1);    // This function accepts a callback which it calls synchronously.    function add(a, b, done) {      done(a + b);    }    util.callbackify(add)(1, 2, function(result) {      test.equal(result, 3, 'should be the correct result.');      test.done();    });  },  'callback (async)': function(test) {    test.expect(1);    // This function accepts a callback which it calls asynchronously.    function add(a, b, done) {      setTimeout(done.bind(null, a + b), 0);    }    util.callbackify(add)(1, 2, function(result) {      test.equal(result, 3, 'should be the correct result.');      test.done();    });  }};exports['util'] = {  'error': function(test) {    test.expect(9);    var origError = new Error('Original error.');    var err = util.error('Test message.');    test.ok(err instanceof Error, 'Should be an Error.');    test.equal(err.name, 'Error', 'Should be an Error.');    test.equal(err.message, 'Test message.', 'Should have the correct message.');    err = util.error('Test message.', origError);    test.ok(err instanceof Error, 'Should be an Error.');    test.equal(err.name, 'Error', 'Should be an Error.');    test.equal(err.message, 'Test message.', 'Should have the correct message.');    test.equal(err.origError, origError, 'Should reflect the original error.');    var newError = new Error('Test message.');    err = util.error(newError, origError);    test.equal(err, newError, 'Should be the passed-in Error.');    test.equal(err.origError, origError, 'Should reflect the original error.');    test.done();  },  'linefeed': function(test) {    test.expect(1);    if (process.platform === 'win32') {      test.equal(util.linefeed, '\r\n', 'linefeed should be operating-system appropriate.');    } else {      test.equal(util.linefeed, '\n', 'linefeed should be operating-system appropriate.');    }    test.done();  },  'normalizelf': function(test) {    test.expect(1);    if (process.platform === 'win32') {      test.equal(util.normalizelf('foo\nbar\r\nbaz\r\n\r\nqux\n\nquux'), 'foo\r\nbar\r\nbaz\r\n\r\nqux\r\n\r\nquux', 'linefeeds should be normalized');    } else {      test.equal(util.normalizelf('foo\nbar\r\nbaz\r\n\r\nqux\n\nquux'), 'foo\nbar\nbaz\n\nqux\n\nquux', 'linefeeds should be normalized');    }    test.done();  }};exports['util.spawn'] = {  setUp: function(done) {    this.script = path.resolve('test/fixtures/spawn.js');    done();  },  'exit code 0': function(test) {    test.expect(6);    util.spawn({      cmd: process.execPath,      args: [ this.script, 0 ],    }, function(err, result, code) {      test.equals(err, null);      test.equals(code, 0);      test.equals(result.stdout, 'stdout');      test.equals(result.stderr, 'stderr');      test.equals(result.code, 0);      test.equals(String(result), 'stdout');      test.done();    });  },  'exit code 0, fallback': function(test) {    test.expect(6);    util.spawn({      cmd: process.execPath,      args: [ this.script, 0 ],      fallback: 'ignored if exit code is 0'    }, function(err, result, code) {      test.equals(err, null);      test.equals(code, 0);      test.equals(result.stdout, 'stdout');      test.equals(result.stderr, 'stderr');      test.equals(result.code, 0);      test.equals(String(result), 'stdout');      test.done();    });  },  'non-zero exit code': function(test) {    test.expect(7);    util.spawn({      cmd: process.execPath,      args: [ this.script, 123 ],    }, function(err, result, code) {      test.ok(err instanceof Error);      test.equals(err.message, 'stderr');      test.equals(code, 123);      test.equals(result.stdout, 'stdout');      test.equals(result.stderr, 'stderr');      test.equals(result.code, 123);      test.equals(String(result), 'stderr');      test.done();    });  },  'non-zero exit code, fallback': function(test) {    test.expect(6);    util.spawn({      cmd: process.execPath,      args: [ this.script, 123 ],      fallback: 'custom fallback'    }, function(err, result, code) {      test.equals(err, null);      test.equals(code, 123);      test.equals(result.stdout, 'stdout');      test.equals(result.stderr, 'stderr');      test.equals(result.code, 123);      test.equals(String(result), 'custom fallback');      test.done();    });  },  'cmd not found': function(test) {    test.expect(3);    util.spawn({      cmd: 'nodewtfmisspelled',    }, function(err, result, code) {      test.ok(err instanceof Error);      test.equals(code, 127);      test.equals(result.code, 127);      test.done();    });  },  'cmd not found, fallback': function(test) {    test.expect(4);    util.spawn({      cmd: 'nodewtfmisspelled',      fallback: 'use a fallback or good luck'    }, function(err, result, code) {      test.equals(err, null);      test.equals(code, 127);      test.equals(result.code, 127);      test.equals(String(result), 'use a fallback or good luck');      test.done();    });  },  'cmd not in path': function(test) {    test.expect(6);    var win32 = process.platform === 'win32';    util.spawn({      cmd: 'test\\fixtures\\exec' + (win32 ? '.cmd' : '.sh'),    }, function(err, result, code) {      test.equals(err, null);      test.equals(code, 0);      test.equals(result.stdout, 'done');      test.equals(result.stderr, '');      test.equals(result.code, 0);      test.equals(String(result), 'done');      test.done();    });  },  'cmd not in path (with cwd)': function(test) {    test.expect(6);    var win32 = process.platform === 'win32';    util.spawn({      cmd: './exec' + (win32 ? '.cmd' : '.sh'),      opts: {cwd: 'test/fixtures'},    }, function(err, result, code) {      test.equals(err, null);      test.equals(code, 0);      test.equals(result.stdout, 'done');      test.equals(result.stderr, '');      test.equals(result.code, 0);      test.equals(String(result), 'done');      test.done();    });  },  'grunt': function(test) {    test.expect(3);    util.spawn({      grunt: true,      args: [ '--gruntfile', 'test/fixtures/Gruntfile-print-text.js', 'print:foo' ],    }, function(err, result, code) {      test.equals(err, null);      test.equals(code, 0);      test.ok(/^OUTPUT: foo/m.test(result.stdout), 'stdout should contain output indicating the grunt task was run.');      test.done();    });  },  'grunt (with cwd)': function(test) {    test.expect(3);    util.spawn({      grunt: true,      args: [ '--gruntfile', 'Gruntfile-print-text.js', 'print:foo' ],      opts: {cwd: 'test/fixtures'},    }, function(err, result, code) {      test.equals(err, null);      test.equals(code, 0);      test.ok(/^OUTPUT: foo/m.test(result.stdout), 'stdout should contain output indicating the grunt task was run.');      test.done();    });  },  'grunt passes execArgv': function(test) {    test.expect(3);    util.spawn({      cmd: process.execPath,      args: [ '--harmony', process.argv[1], '--gruntfile', 'test/fixtures/Gruntfile-execArgv.js'],    }, function(err, result, code) {      test.equals(err, null);      test.equals(code, 0);      test.ok(/^OUTPUT: --harmony/m.test(result.stdout), 'stdout should contain passed-through process.execArgv.');      test.done();    });  },  'grunt result.toString() with error': function(test) {    // grunt.log.error uses standard out, to be fixed in 0.5.    test.expect(4);    util.spawn({      grunt: true,      args: [ 'nonexistentTask' ]    }, function(err, result, code) {      test.ok(err instanceof Error, 'Should be an Error.');      test.equal(err.name, 'Error', 'Should be an Error.');      test.equals(code, 3);      test.ok(/Warning: Task "nonexistentTask" not found./m.test(result.toString()), 'stdout should contain output indicating the grunt task was (attempted to be) run.');      test.done();    });  },  'custom stdio stream(s)': function(test) {    test.expect(6);    var stdoutFile = new Tempfile();    var stderrFile = new Tempfile();    var stdout = fs.openSync(stdoutFile.path, 'a');    var stderr = fs.openSync(stderrFile.path, 'a');    var child = util.spawn({      cmd: process.execPath,      args: [ this.script, 0 ],      opts: {stdio: [null, stdout, stderr]},    }, function(err, result, code) {      test.equals(code, 0);      test.equals(String(fs.readFileSync(stdoutFile.path)), 'stdout\n', 'Child process stdout should have been captured via custom stream.');      test.equals(String(fs.readFileSync(stderrFile.path)), 'stderr\n', 'Child process stderr should have been captured via custom stream.');      stdoutFile.unlinkSync();      stderrFile.unlinkSync();      test.equals(result.stdout, '', 'Nothing will be passed to the stdout string when spawn stdio is a custom stream.');      test.done();    });    test.ok(!child.stdout, 'child should not have a stdout property.');    test.ok(!child.stderr, 'child should not have a stderr property.');  },};exports['util.spawn.multibyte'] = {  setUp: function(done) {    this.script = path.resolve('test/fixtures/spawn-multibyte.js');    done();  },  'partial stdout': function(test) {    test.expect(4);    util.spawn({      cmd: process.execPath,      args: [ this.script ],    }, function(err, result, code) {      test.equals(err, null);      test.equals(code, 0);      test.equals(result.stdout, 'こんにちは');      test.equals(result.stderr, 'こんにちは');      test.done();    });  }};exports['util.underscore.string'] = function(test) {  test.expect(4);  test.equals(util._.trim('    foo     '), 'foo', 'Should have trimmed the string.');  test.equals(util._.capitalize('foo'), 'Foo', 'Should have capitalized the first letter.');  test.equals(util._.words('one two three').length, 3, 'Should have counted three words.');  test.ok(util._.isBlank(' '), 'Should be blank.');  test.done();};function getType(val) {  if (Buffer.isBuffer(val)) { return 'buffer'; }  return Object.prototype.toString.call(val).slice(8, -1).toLowerCase();}exports['util.recurse'] = {  setUp: function(done) {    this.typeValue = function(value) {      return {        value: value,        type: getType(value),      };    };    done();  },  'primitives': function(test) {    test.expect(1);    var actual = util.recurse({      bool: true,      num: 1,      str: 'foo',      nul: null,      undef: undefined,    }, this.typeValue);    var expected = {      bool: {type: 'boolean', value: true},      num: {type: 'number', value: 1},      str: {type: 'string', value: 'foo'},      nul: {type: 'null', value: null},      undef: {type: 'undefined', value: undefined},    };    test.deepEqual(actual, expected, 'Should process primitive values.');    test.done();  },  'array': function(test) {    test.expect(1);    var actual = util.recurse({      arr: [        true,        1,        'foo',        null,        undefined,        [          true,          1,          'foo',          null,          undefined,        ],      ],    }, this.typeValue);    var expected = {      arr: [        {type: 'boolean', value: true},        {type: 'number', value: 1},        {type: 'string', value: 'foo'},        {type: 'null', value: null},        {type: 'undefined', value: undefined},        [          {type: 'boolean', value: true},          {type: 'number', value: 1},          {type: 'string', value: 'foo'},          {type: 'null', value: null},          {type: 'undefined', value: undefined},        ],      ],    };    test.deepEqual(actual, expected, 'Should recurse over arrays.');    test.done();  },  'object': function(test) {    test.expect(1);    var actual = util.recurse({      obj: {        bool: true,        num: 1,        str: 'foo',        nul: null,        undef: undefined,        obj: {          bool: true,          num: 1,          str: 'foo',          nul: null,          undef: undefined,        },      },    }, this.typeValue);    var expected = {      obj: {        bool: {type: 'boolean', value: true},        num: {type: 'number', value: 1},        str: {type: 'string', value: 'foo'},        nul: {type: 'null', value: null},        undef: {type: 'undefined', value: undefined},        obj: {          bool: {type: 'boolean', value: true},          num: {type: 'number', value: 1},          str: {type: 'string', value: 'foo'},          nul: {type: 'null', value: null},          undef: {type: 'undefined', value: undefined},        },      },    };    test.deepEqual(actual, expected, 'Should recurse over objects.');    test.done();  },  'array in object': function(test) {    test.expect(1);    var actual = util.recurse({      obj: {        arr: [          true,          1,          'foo',          null,          undefined,        ],      },    }, this.typeValue);    var expected = {      obj: {        arr: [          {type: 'boolean', value: true},          {type: 'number', value: 1},          {type: 'string', value: 'foo'},          {type: 'null', value: null},          {type: 'undefined', value: undefined},        ],      },    };    test.deepEqual(actual, expected, 'Should recurse over arrays in objects.');    test.done();  },  'object in array': function(test) {    test.expect(1);    var actual = util.recurse({      arr: [        true,        {          num: 1,          str: 'foo',        },        null,        undefined,      ],    }, this.typeValue);    var expected = {      arr: [        {type: 'boolean', value: true},        {          num: {type: 'number', value: 1},          str: {type: 'string', value: 'foo'},        },        {type: 'null', value: null},        {type: 'undefined', value: undefined},      ],    };    test.deepEqual(actual, expected, 'Should recurse over objects in arrays.');    test.done();  },  'buffer': function(test) {    test.expect(1);    var actual = util.recurse({      buf: new Buffer('buf'),    }, this.typeValue);    var expected = {      buf: {type: 'buffer', value: new Buffer('buf')},    };    test.deepEqual(actual, expected, 'Should not mangle Buffer instances.');    test.done();  },  'inherited properties': function(test) {    test.expect(1);    var actual = util.recurse({      obj: Object.create({num: 1}, {        str: {value: 'foo', enumerable: true},        ignored: {value: 'ignored', enumerable: false},      }),    }, this.typeValue);    var expected = {      obj: {        num: {type: 'number', value: 1},        str: {type: 'string', value: 'foo'},      }    };    test.deepEqual(actual, expected, 'Should enumerate inherited object properties.');    test.done();  },  'circular references': function(test) {    test.expect(6);    function assertErrorWithPath(expectedPath) {      return function(actual) {        return actual.path === expectedPath &&          actual.message === 'Circular reference detected (' + expectedPath + ')';      };    }    test.doesNotThrow(function() {      var obj = {        // wat        a:[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]],        // does        b:[[[[],[[[],[[[[],[[[],[[[],[[[],[[[],[[[[],[[]]]]]]]]]]]]]]]]]]]]],        // it        c:{d:{e:{f:{g:{h:{i:{j:{k:{l:{m:{n:{o:{p:{q:{r:{s:{}}}}}}}}}}}}}}}}},        // mean        t:[{u:[{v:[[[[],[[[],[[[{w:[{x:[[[],[[[{y:[[1]]}]]]]]}]}]]]]]]]]}]}],      };      util.recurse(obj, function(v) { return v; });    }, 'Should not throw when no circular reference is detected.');    test.throws(function() {      var obj = {a: 1, b: 2};      obj.obj = obj;      util.recurse(obj, function(v) { return v; });    }, assertErrorWithPath('.obj'), 'Should throw when a circular reference is detected.');    test.throws(function() {      var obj = {a:{'b b':{'c-c':{d_d:{e:{f:{g:{h:{i:{j:{k:{l:{}}}}}}}}}}}}};      obj.a['b b']['c-c'].d_d.e.f.g.h.i.j.k.l.obj = obj;      util.recurse(obj, function(v) { return v; });    }, assertErrorWithPath('.a["b b"]["c-c"].d_d.e.f.g.h.i.j.k.l.obj'), 'Should throw when a circular reference is detected.');    test.throws(function() {      var obj = {a: 1, b: 2};      obj.arr = [1, 2, obj, 3, 4];      util.recurse(obj, function(v) { return v; });    }, assertErrorWithPath('.arr[2]'), 'Should throw when a circular reference is detected.');    test.throws(function() {      var obj = {a: 1, b: 2};      obj.arr = [{a:[1,{b:[2,{c:[3,obj,4]},5]},6]},7];      util.recurse(obj, function(v) { return v; });    }, assertErrorWithPath('.arr[0].a[1].b[1].c[1]'), 'Should throw when a circular reference is detected.');    test.throws(function() {      var obj = {a: 1, b: 2};      obj.arr = [];      obj.arr.push(0,{a:[1,{b:[2,{c:[3,obj.arr,4]},5]},6]},7);      util.recurse(obj, function(v) { return v; });    }, assertErrorWithPath('.arr[1].a[1].b[1].c[1]'), 'Should throw when a circular reference is detected.');    test.done();  },};
 |