Tilemap collision working but needs speeding up

This commit is contained in:
Richard Davey
2013-04-25 20:05:56 +01:00
parent b8ab13fec8
commit b2e1434f5e
1336 changed files with 277759 additions and 6786 deletions
+1
View File
@@ -0,0 +1 @@
foo
+8
View File
@@ -0,0 +1,8 @@
module.exports = function(grunt) {
grunt.registerTask('print', 'Print the specified text.', function(text) {
console.log('OUTPUT: ' + text);
// console.log(process.cwd());
});
};
+1
View File
@@ -0,0 +1 @@
var a = 1;
+1
View File
@@ -0,0 +1 @@
var b = 2;
+11
View File
@@ -0,0 +1,11 @@
/* THIS
* IS
* A
* SAMPLE
* BANNER!
*/
// Comment
/* Comment */
+7
View File
@@ -0,0 +1,7 @@
/*! SAMPLE
* BANNER */
// Comment
/* Comment */
+10
View File
@@ -0,0 +1,10 @@
// This is
// A sample
// Banner
// But this is not
/* And neither
* is this
*/
Generated Vendored Executable
+1
View File
@@ -0,0 +1 @@
@echo done
Generated Vendored Executable
+2
View File
@@ -0,0 +1,2 @@
#!/bin/bash
echo "done"
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
+4
View File
@@ -0,0 +1,4 @@
{
"foo": "Ação é isso aí",
"bar": ["ømg", "pønies"]
}
+1
View File
@@ -0,0 +1 @@
Ação é isso aí
+4
View File
@@ -0,0 +1,4 @@
foo: Ação é isso aí
bar:
- ømg
- pønies
BIN
View File
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
foo
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

+17
View File
@@ -0,0 +1,17 @@
// This is a test fixture for a case where spawn receives incomplete
// multibyte strings in separate data events.
// A multibyte buffer containing all our output. We will slice it later.
// In this case we are using a Japanese word for hello / good day, where each
// character takes three bytes.
var fullOutput = new Buffer('こんにちは');
// Output one full character and one third of a character
process.stdout.write(fullOutput.slice(0, 4));
// Output the rest of the string
process.stdout.write(fullOutput.slice(4));
// Do the same for stderr
process.stderr.write(fullOutput.slice(0, 4));
process.stderr.write(fullOutput.slice(4));
+9
View File
@@ -0,0 +1,9 @@
var code = Number(process.argv[2]);
process.stdout.write('stdout\n');
process.stderr.write('stderr\n');
// Use instead of process.exit to ensure stdout/stderr are flushed
// before exiting in Windows (Tested in Node.js v0.8.7)
require('../../lib/util/exit').exit(code);
+1
View File
@@ -0,0 +1 @@
Version: <%= grunt.version %>, today: <%= grunt.template.today("yyyy-mm-dd") %>.
+4
View File
@@ -0,0 +1,4 @@
{
"foo": "bar",
"baz": [1, 2, 3]
}
+4
View File
@@ -0,0 +1,4 @@
{
"foo": "Ação é isso aí",
"bar": ["ømg", "pønies"]
}
+1
View File
@@ -0,0 +1 @@
Ação é isso aí
+4
View File
@@ -0,0 +1,4 @@
foo: Ação é isso aí
bar:
- ømg
- pønies
+110
View File
@@ -0,0 +1,110 @@
'use strict';
var grunt = require('../../lib/grunt');
exports['config'] = {
setUp: function(done) {
this.origData = grunt.config.data;
grunt.config.init({
meta: grunt.file.readJSON('test/fixtures/test.json'),
foo: '<%= meta.foo %>',
foo2: '<%= foo %>',
obj: {
foo: '<%= meta.foo %>',
foo2: '<%= obj.foo %>',
Arr: ['foo', '<%= obj.foo2 %>'],
arr2: ['<%= arr %>', '<%= obj.Arr %>'],
},
bar: 'bar',
arr: ['foo', '<%= obj.foo2 %>'],
arr2: ['<%= arr %>', '<%= obj.Arr %>'],
});
done();
},
tearDown: function(done) {
grunt.config.data = this.origData;
done();
},
'config.escape': function(test) {
test.expect(2);
test.equal(grunt.config.escape('foo'), 'foo', 'Should do nothing if no . chars.');
test.equal(grunt.config.escape('foo.bar.baz'), 'foo\\.bar\\.baz', 'Should escape all . chars.');
test.done();
},
'config.getPropString': function(test) {
test.expect(4);
test.equal(grunt.config.getPropString('foo'), 'foo', 'Should do nothing if already a string.');
test.equal(grunt.config.getPropString('foo.bar.baz'), 'foo.bar.baz', 'Should do nothing if already a string.');
test.equal(grunt.config.getPropString(['foo', 'bar']), 'foo.bar', 'Should join parts into a dot-delimited string.');
test.equal(grunt.config.getPropString(['foo.bar', 'baz.qux.zip']), 'foo\\.bar.baz\\.qux\\.zip', 'Should join parts into a dot-delimited string, escaping . chars in parts.');
test.done();
},
'config.getRaw': function(test) {
test.expect(4);
test.equal(grunt.config.getRaw('foo'), '<%= meta.foo %>', 'Should not process templates.');
test.equal(grunt.config.getRaw('obj.foo2'), '<%= obj.foo %>', 'Should not process templates.');
test.equal(grunt.config.getRaw(['obj', 'foo2']), '<%= obj.foo %>', 'Should not process templates.');
test.deepEqual(grunt.config.getRaw('arr'), ['foo', '<%= obj.foo2 %>'], 'Should not process templates.');
test.done();
},
'config.process': function(test) {
test.expect(5);
test.equal(grunt.config.process('<%= meta.foo %>'), 'bar', 'Should process templates.');
test.equal(grunt.config.process('<%= foo %>'), 'bar', 'Should process templates recursively.');
test.equal(grunt.config.process('<%= obj.foo %>'), 'bar', 'Should process deeply nested templates recursively.');
test.deepEqual(grunt.config.process(['foo', '<%= obj.foo2 %>']), ['foo', 'bar'], 'Should process templates in arrays.');
test.deepEqual(grunt.config.process(['<%= arr %>', '<%= obj.Arr %>']), [['foo', 'bar'], ['foo', 'bar']], 'Should expand <%= arr %> and <%= obj.Arr %> values as objects if possible.');
test.done();
},
'config.get': function(test) {
test.expect(8);
test.equal(grunt.config.get('foo'), 'bar', 'Should process templates.');
test.equal(grunt.config.get('foo2'), 'bar', 'Should process templates recursively.');
test.equal(grunt.config.get('obj.foo2'), 'bar', 'Should process deeply nested templates recursively.');
test.equal(grunt.config.get(['obj', 'foo2']), 'bar', 'Should process deeply nested templates recursively.');
test.deepEqual(grunt.config.get('arr'), ['foo', 'bar'], 'Should process templates in arrays.');
test.deepEqual(grunt.config.get('obj.Arr'), ['foo', 'bar'], 'Should process templates in arrays.');
test.deepEqual(grunt.config.get('arr2'), [['foo', 'bar'], ['foo', 'bar']], 'Should expand <%= arr %> and <%= obj.Arr %> values as objects if possible.');
test.deepEqual(grunt.config.get(['obj', 'arr2']), [['foo', 'bar'], ['foo', 'bar']], 'Should expand <%= arr %> and <%= obj.Arr %> values as objects if possible.');
test.done();
},
'config.set': function(test) {
test.expect(6);
test.equal(grunt.config.set('foo3', '<%= foo2 %>'), '<%= foo2 %>', 'Should set values.');
test.equal(grunt.config.getRaw('foo3'), '<%= foo2 %>', 'Should have set the value.');
test.equal(grunt.config.data.foo3, '<%= foo2 %>', 'Should have set the value.');
test.equal(grunt.config.set('a.b.c', '<%= foo2 %>'), '<%= foo2 %>', 'Should create interim objects.');
test.equal(grunt.config.getRaw('a.b.c'), '<%= foo2 %>', 'Should have set the value.');
test.equal(grunt.config.data.a.b.c, '<%= foo2 %>', 'Should have set the value.');
test.done();
},
'config': function(test) {
test.expect(10);
test.equal(grunt.config('foo'), 'bar', 'Should retrieve processed data.');
test.equal(grunt.config('obj.foo2'), 'bar', 'Should retrieve processed data.');
test.equal(grunt.config(['obj', 'foo2']), 'bar', 'Should retrieve processed data.');
test.deepEqual(grunt.config('arr'), ['foo', 'bar'], 'Should process templates in arrays.');
test.equal(grunt.config('foo3', '<%= foo2 %>'), '<%= foo2 %>', 'Should set values.');
test.equal(grunt.config.getRaw('foo3'), '<%= foo2 %>', 'Should have set the value.');
test.equal(grunt.config.data.foo3, '<%= foo2 %>', 'Should have set the value.');
test.equal(grunt.config('a.b.c', '<%= foo2 %>'), '<%= foo2 %>', 'Should create interim objects.');
test.equal(grunt.config.getRaw('a.b.c'), '<%= foo2 %>', 'Should have set the value.');
test.equal(grunt.config.data.a.b.c, '<%= foo2 %>', 'Should have set the value.');
test.done();
},
'config.requires': function(test) {
test.expect(8);
grunt.log.muted = true;
test.doesNotThrow(function() { grunt.config.requires('foo'); }, 'This property exists.');
test.doesNotThrow(function() { grunt.config.requires('obj.foo'); }, 'This property exists.');
test.doesNotThrow(function() { grunt.config.requires('foo', 'obj.foo', 'obj.foo2'); }, 'These properties exist.');
test.doesNotThrow(function() { grunt.config.requires('foo', ['obj', 'foo'], ['obj', 'foo2']); }, 'These properties exist.');
test.throws(function() { grunt.config.requires('xyz'); }, 'This property does not exist.');
test.throws(function() { grunt.config.requires('obj.xyz'); }, 'This property does not exist.');
test.throws(function() { grunt.config.requires('foo', 'obj.foo', 'obj.xyz'); }, 'One property does not exist.');
test.throws(function() { grunt.config.requires('foo', ['obj', 'foo'], ['obj', 'xyz']); }, 'One property does not exist.');
grunt.log.muted = false;
test.done();
},
};
+18
View File
@@ -0,0 +1,18 @@
'use strict';
var grunt = require('../../lib/grunt');
exports['event'] = function(test) {
test.expect(3);
grunt.event.on('test.foo', function(a, b, c) {
// This should get executed once (emit test.foo).
test.equals(a + b + c, '123', 'Should have received the correct arguments.');
});
grunt.event.on('test.*', function(a, b, c) {
// This should get executed twice (emit test.foo and test.bar).
test.equals(a + b + c, '123', 'Should have received the correct arguments.');
});
grunt.event.emit('test.foo', '1', '2', '3');
grunt.event.emit('test.bar', '1', '2', '3');
test.done();
};
+764
View File
@@ -0,0 +1,764 @@
'use strict';
var grunt = require('../../lib/grunt');
var fs = require('fs');
var path = require('path');
var Tempfile = require('temporary/lib/file');
var Tempdir = require('temporary/lib/dir');
var tmpdir = new Tempdir();
fs.symlinkSync(path.resolve('test/fixtures/octocat.png'), path.join(tmpdir.path, 'octocat.png'), 'file');
fs.symlinkSync(path.resolve('test/fixtures/expand'), path.join(tmpdir.path, 'expand'), 'dir');
exports['file.match'] = {
'empty set': function(test) {
test.expect(12);
// Should return empty set if a required argument is missing or an empty set.
test.deepEqual(grunt.file.match(null, null), [], 'should return empty set.');
test.deepEqual(grunt.file.match({}, null, null), [], 'should return empty set.');
test.deepEqual(grunt.file.match(null, 'foo.js'), [], 'should return empty set.');
test.deepEqual(grunt.file.match('*.js', null), [], 'should return empty set.');
test.deepEqual(grunt.file.match({}, null, 'foo.js'), [], 'should return empty set.');
test.deepEqual(grunt.file.match({}, '*.js', null), [], 'should return empty set.');
test.deepEqual(grunt.file.match({}, [], 'foo.js'), [], 'should return empty set.');
test.deepEqual(grunt.file.match({}, '*.js', []), [], 'should return empty set.');
test.deepEqual(grunt.file.match(null, ['foo.js']), [], 'should return empty set.');
test.deepEqual(grunt.file.match(['*.js'], null), [], 'should return empty set.');
test.deepEqual(grunt.file.match({}, null, ['foo.js']), [], 'should return empty set.');
test.deepEqual(grunt.file.match({}, ['*.js'], null), [], 'should return empty set.');
test.done();
},
'basic matching': function(test) {
test.expect(6);
test.deepEqual(grunt.file.match('*.js', 'foo.js'), ['foo.js'], 'should match correctly.');
test.deepEqual(grunt.file.match('*.js', ['foo.js']), ['foo.js'], 'should match correctly.');
test.deepEqual(grunt.file.match('*.js', ['foo.js', 'bar.css']), ['foo.js'], 'should match correctly.');
test.deepEqual(grunt.file.match(['*.js', '*.css'], 'foo.js'), ['foo.js'], 'should match correctly.');
test.deepEqual(grunt.file.match(['*.js', '*.css'], ['foo.js']), ['foo.js'], 'should match correctly.');
test.deepEqual(grunt.file.match(['*.js', '*.css'], ['foo.js', 'bar.css']), ['foo.js', 'bar.css'], 'should match correctly.');
test.done();
},
'no matches': function(test) {
test.expect(2);
test.deepEqual(grunt.file.match('*.js', 'foo.css'), [], 'should fail to match.');
test.deepEqual(grunt.file.match('*.js', ['foo.css', 'bar.css']), [], 'should fail to match.');
test.done();
},
'unique': function(test) {
test.expect(2);
test.deepEqual(grunt.file.match('*.js', ['foo.js', 'foo.js']), ['foo.js'], 'should return a uniqued set.');
test.deepEqual(grunt.file.match(['*.js', '*.*'], ['foo.js', 'foo.js']), ['foo.js'], 'should return a uniqued set.');
test.done();
},
'flatten': function(test) {
test.expect(1);
test.deepEqual(grunt.file.match([['*.js', '*.css'], ['*.*', '*.js']], ['foo.js', 'bar.css']), ['foo.js', 'bar.css'], 'should process nested pattern arrays correctly.');
test.done();
},
'exclusion': function(test) {
test.expect(5);
test.deepEqual(grunt.file.match(['!*.js'], ['foo.js', 'bar.js']), [], 'solitary exclusion should match nothing');
test.deepEqual(grunt.file.match(['*.js', '!*.js'], ['foo.js', 'bar.js']), [], 'exclusion should cancel match');
test.deepEqual(grunt.file.match(['*.js', '!f*.js'], ['foo.js', 'bar.js', 'baz.js']), ['bar.js', 'baz.js'], 'partial exclusion should partially cancel match');
test.deepEqual(grunt.file.match(['*.js', '!*.js', 'b*.js'], ['foo.js', 'bar.js', 'baz.js']), ['bar.js', 'baz.js'], 'inclusion / exclusion order matters');
test.deepEqual(grunt.file.match(['*.js', '!f*.js', '*.js'], ['foo.js', 'bar.js', 'baz.js']), ['bar.js', 'baz.js', 'foo.js'], 'inclusion / exclusion order matters');
test.done();
},
'options.matchBase': function(test) {
test.expect(2);
test.deepEqual(grunt.file.match({matchBase: true}, '*.js', ['foo.js', 'bar', 'baz/xyz.js']), ['foo.js', 'baz/xyz.js'], 'should matchBase (minimatch) when specified.');
test.deepEqual(grunt.file.match('*.js', ['foo.js', 'bar', 'baz/xyz.js']), ['foo.js'], 'should not matchBase (minimatch) by default.');
test.done();
}
};
exports['file.isMatch'] = {
'basic matching': function(test) {
test.expect(6);
test.ok(grunt.file.isMatch('*.js', 'foo.js'), 'should match correctly.');
test.ok(grunt.file.isMatch('*.js', ['foo.js']), 'should match correctly.');
test.ok(grunt.file.isMatch('*.js', ['foo.js', 'bar.css']), 'should match correctly.');
test.ok(grunt.file.isMatch(['*.js', '*.css'], 'foo.js'), 'should match correctly.');
test.ok(grunt.file.isMatch(['*.js', '*.css'], ['foo.js']), 'should match correctly.');
test.ok(grunt.file.isMatch(['*.js', '*.css'], ['foo.js', 'bar.css']), 'should match correctly.');
test.done();
},
'no matches': function(test) {
test.expect(6);
test.equal(grunt.file.isMatch('*.js', 'foo.css'), false, 'should fail to match.');
test.equal(grunt.file.isMatch('*.js', ['foo.css', 'bar.css']), false, 'should fail to match.');
test.equal(grunt.file.isMatch(null, 'foo.css'), false, 'should fail to match.');
test.equal(grunt.file.isMatch('*.js', null), false, 'should fail to match.');
test.equal(grunt.file.isMatch([], 'foo.css'), false, 'should fail to match.');
test.equal(grunt.file.isMatch('*.js', []), false, 'should fail to match.');
test.done();
},
'options.matchBase': function(test) {
test.expect(2);
test.ok(grunt.file.isMatch({matchBase: true}, '*.js', ['baz/xyz.js']), 'should matchBase (minimatch) when specified.');
test.equal(grunt.file.isMatch('*.js', ['baz/xyz.js']), false, 'should not matchBase (minimatch) by default.');
test.done();
}
};
exports['file.expand*'] = {
setUp: function(done) {
this.cwd = process.cwd();
process.chdir('test/fixtures/expand');
done();
},
tearDown: function(done) {
process.chdir(this.cwd);
done();
},
'basic matching': function(test) {
test.expect(8);
test.deepEqual(grunt.file.expand('**/*.js'), ['js/bar.js', 'js/foo.js'], 'should match.');
test.deepEqual(grunt.file.expand('**/*.js', '**/*.css'), ['js/bar.js', 'js/foo.js', 'css/baz.css', 'css/qux.css'], 'should match.');
test.deepEqual(grunt.file.expand(['**/*.js', '**/*.css']), ['js/bar.js', 'js/foo.js', 'css/baz.css', 'css/qux.css'], 'should match.');
test.deepEqual(grunt.file.expand('**d*/**'), [
'deep',
'deep/deep.txt',
'deep/deeper',
'deep/deeper/deeper.txt',
'deep/deeper/deepest',
'deep/deeper/deepest/deepest.txt'], 'should match files and directories.');
test.deepEqual(grunt.file.expand({mark: true}, '**d*/**'), [
'deep/',
'deep/deep.txt',
'deep/deeper/',
'deep/deeper/deeper.txt',
'deep/deeper/deepest/',
'deep/deeper/deepest/deepest.txt'], 'the minimatch "mark" option ensures directories end in /.');
test.deepEqual(grunt.file.expand('**d*/**/'), [
'deep/',
'deep/deeper/',
'deep/deeper/deepest/'], 'should match directories, arbitrary / at the end appears in matches.');
test.deepEqual(grunt.file.expand({mark: true}, '**d*/**/'), [
'deep/',
'deep/deeper/',
'deep/deeper/deepest/'], 'should match directories, arbitrary / at the end appears in matches.');
test.deepEqual(grunt.file.expand('*.xyz'), [], 'should fail to match.');
test.done();
},
'filter': function(test) {
test.expect(5);
test.deepEqual(grunt.file.expand({filter: 'isFile'}, '**d*/**'), [
'deep/deep.txt',
'deep/deeper/deeper.txt',
'deep/deeper/deepest/deepest.txt'
], 'should match files only.');
test.deepEqual(grunt.file.expand({filter: 'isDirectory'}, '**d*/**'), [
'deep',
'deep/deeper',
'deep/deeper/deepest'
], 'should match directories only.');
test.deepEqual(grunt.file.expand({filter: function(filepath) { return (/deepest/).test(filepath); }}, '**'), [
'deep/deeper/deepest',
'deep/deeper/deepest/deepest.txt',
], 'should filter arbitrarily.');
test.deepEqual(grunt.file.expand({filter: 'isFile'}, 'js', 'css'), [], 'should fail to match.');
test.deepEqual(grunt.file.expand({filter: 'isDirectory'}, '**/*.js'), [], 'should fail to match.');
test.done();
},
'unique': function(test) {
test.expect(4);
test.deepEqual(grunt.file.expand('**/*.js', 'js/*.js'), ['js/bar.js', 'js/foo.js'], 'file list should be uniqed.');
test.deepEqual(grunt.file.expand('**/*.js', '**/*.css', 'js/*.js'), ['js/bar.js', 'js/foo.js', 'css/baz.css', 'css/qux.css'], 'file list should be uniqed.');
test.deepEqual(grunt.file.expand('js', 'js/'), ['js', 'js/'], 'mixed non-ending-/ and ending-/ dirs will not be uniqed by default.');
test.deepEqual(grunt.file.expand({mark: true}, 'js', 'js/'), ['js/'], 'mixed non-ending-/ and ending-/ dirs will be uniqed when "mark" is specified.');
test.done();
},
'file order': function(test) {
test.expect(4);
var actual = grunt.file.expand('**/*.{js,css}');
var expected = ['css/baz.css', 'css/qux.css', 'js/bar.js', 'js/foo.js'];
test.deepEqual(actual, expected, 'should select 4 files in this order, by default.');
actual = grunt.file.expand('js/foo.js', 'js/bar.js', '**/*.{js,css}');
expected = ['js/foo.js', 'js/bar.js', 'css/baz.css', 'css/qux.css'];
test.deepEqual(actual, expected, 'specifically-specified-up-front file order should be maintained.');
actual = grunt.file.expand('js/bar.js', 'js/foo.js', '**/*.{js,css}');
expected = ['js/bar.js', 'js/foo.js', 'css/baz.css', 'css/qux.css'];
test.deepEqual(actual, expected, 'specifically-specified-up-front file order should be maintained.');
actual = grunt.file.expand('js/foo.js', '**/*.{js,css}', '!js/bar.js', 'js/bar.js');
expected = ['js/foo.js', 'css/baz.css', 'css/qux.css', 'js/bar.js'];
test.deepEqual(actual, expected, 'if a file is excluded and then re-added, it should be added at the end.');
test.done();
},
'flatten': function(test) {
test.expect(1);
test.deepEqual(grunt.file.expand([['**/*.js'], ['**/*.css', 'js/*.js']]), ['js/bar.js', 'js/foo.js', 'css/baz.css', 'css/qux.css'], 'should match.');
test.done();
},
'exclusion': function(test) {
test.expect(8);
test.deepEqual(grunt.file.expand(['!js/*.js']), [], 'solitary exclusion should match nothing');
test.deepEqual(grunt.file.expand(['js/bar.js','!js/bar.js']), [], 'exclusion should cancel match');
test.deepEqual(grunt.file.expand(['**/*.js', '!js/foo.js']), ['js/bar.js'], 'should omit single file from matched set');
test.deepEqual(grunt.file.expand(['!js/foo.js', '**/*.js']), ['js/bar.js', 'js/foo.js'], 'inclusion / exclusion order matters');
test.deepEqual(grunt.file.expand(['**/*.js', '**/*.css', '!js/bar.js', '!css/baz.css']), ['js/foo.js','css/qux.css'], 'multiple exclusions should be removed from the set');
test.deepEqual(grunt.file.expand(['**/*.js', '**/*.css', '!**/*.css']), ['js/bar.js', 'js/foo.js'], 'excluded wildcards should be removed from the matched set');
test.deepEqual(grunt.file.expand(['js/bar.js', 'js/foo.js', 'css/baz.css', 'css/qux.css', '!**/b*.*']), ['js/foo.js', 'css/qux.css'], 'different pattern for exclusion should still work');
test.deepEqual(grunt.file.expand(['js/bar.js', '!**/b*.*', 'js/foo.js', 'css/baz.css', 'css/qux.css']), ['js/foo.js', 'css/baz.css', 'css/qux.css'], 'inclusion / exclusion order matters');
test.done();
},
'options.matchBase': function(test) {
test.expect(4);
var opts = {matchBase: true};
test.deepEqual(grunt.file.expand('*.js'), [], 'should not matchBase (minimatch) by default.');
test.deepEqual(grunt.file.expand(opts, '*.js'), ['js/bar.js', 'js/foo.js'], 'options should be passed through to minimatch.');
test.deepEqual(grunt.file.expand(opts, '*.js', '*.css'), ['js/bar.js', 'js/foo.js', 'css/baz.css', 'css/qux.css'], 'should match.');
test.deepEqual(grunt.file.expand(opts, ['*.js', '*.css']), ['js/bar.js', 'js/foo.js', 'css/baz.css', 'css/qux.css'], 'should match.');
test.done();
},
'options.cwd': function(test) {
test.expect(4);
var cwd = path.resolve(process.cwd(), '..');
test.deepEqual(grunt.file.expand({cwd: cwd}, ['expand/js', 'expand/js/*']), ['expand/js', 'expand/js/bar.js', 'expand/js/foo.js'], 'should match.');
test.deepEqual(grunt.file.expand({cwd: cwd, filter: 'isFile'}, ['expand/js', 'expand/js/*']), ['expand/js/bar.js', 'expand/js/foo.js'], 'should match.');
test.deepEqual(grunt.file.expand({cwd: cwd, filter: 'isDirectory'}, ['expand/js', 'expand/js/*']), ['expand/js'], 'should match.');
test.deepEqual(grunt.file.expand({cwd: cwd, filter: 'isFile'}, ['expand/js', 'expand/js/*', '!**/b*.js']), ['expand/js/foo.js'], 'should negate properly.');
test.done();
},
'options.nonull': function(test) {
test.expect(2);
var opts = {nonull: true};
test.deepEqual(grunt.file.expand(opts, ['js/a*', 'js/b*', 'js/c*']), ['js/a*', 'js/bar.js', 'js/c*'], 'non-matching patterns should be returned in result set.');
test.deepEqual(grunt.file.expand(opts, ['js/foo.js', 'js/bar.js', 'js/baz.js']), ['js/foo.js', 'js/bar.js', 'js/baz.js'], 'non-matching filenames should be returned in result set.');
test.done();
},
};
exports['file.expandMapping'] = {
setUp: function(done) {
this.cwd = process.cwd();
process.chdir('test/fixtures');
done();
},
tearDown: function(done) {
process.chdir(this.cwd);
done();
},
'basic matching': function(test) {
test.expect(2);
var actual = grunt.file.expandMapping(['expand/**/*.txt'], 'dest');
var expected = [
{dest: 'dest/expand/deep/deep.txt', src: ['expand/deep/deep.txt']},
{dest: 'dest/expand/deep/deeper/deeper.txt', src: ['expand/deep/deeper/deeper.txt']},
{dest: 'dest/expand/deep/deeper/deepest/deepest.txt', src: ['expand/deep/deeper/deepest/deepest.txt']},
];
test.deepEqual(actual, expected, 'basic src-dest options');
actual = grunt.file.expandMapping(['expand/**/*.txt'], 'dest/');
test.deepEqual(actual, expected, 'destBase should behave the same both with or without trailing slash');
test.done();
},
'flatten': function(test) {
test.expect(1);
var actual = grunt.file.expandMapping(['expand/**/*.txt'], 'dest', {flatten: true});
var expected = [
{dest: 'dest/deep.txt', src: ['expand/deep/deep.txt']},
{dest: 'dest/deeper.txt', src: ['expand/deep/deeper/deeper.txt']},
{dest: 'dest/deepest.txt', src: ['expand/deep/deeper/deepest/deepest.txt']},
];
test.deepEqual(actual, expected, 'dest paths should be flattened pre-destBase+destPath join');
test.done();
},
'ext': function(test) {
test.expect(2);
var actual, expected;
actual = grunt.file.expandMapping(['expand/**/*.txt'], 'dest', {ext: '.foo'});
expected = [
{dest: 'dest/expand/deep/deep.foo', src: ['expand/deep/deep.txt']},
{dest: 'dest/expand/deep/deeper/deeper.foo', src: ['expand/deep/deeper/deeper.txt']},
{dest: 'dest/expand/deep/deeper/deepest/deepest.foo', src: ['expand/deep/deeper/deepest/deepest.txt']},
];
test.deepEqual(actual, expected, 'specified extension should be added');
actual = grunt.file.expandMapping(['expand-mapping-ext/**/file*'], 'dest', {ext: '.foo'});
expected = [
{dest: 'dest/expand-mapping-ext/dir.ectory/file-no-extension.foo', src: ['expand-mapping-ext/dir.ectory/file-no-extension']},
{dest: 'dest/expand-mapping-ext/dir.ectory/sub.dir.ectory/file.foo', src: ['expand-mapping-ext/dir.ectory/sub.dir.ectory/file.ext.ension']},
{dest: 'dest/expand-mapping-ext/file.foo', src: ['expand-mapping-ext/file.ext.ension']},
];
test.deepEqual(actual, expected, 'specified extension should be added');
test.done();
},
'cwd': function(test) {
test.expect(1);
var actual = grunt.file.expandMapping(['**/*.txt'], 'dest', {cwd: 'expand'});
var expected = [
{dest: 'dest/deep/deep.txt', src: ['expand/deep/deep.txt']},
{dest: 'dest/deep/deeper/deeper.txt', src: ['expand/deep/deeper/deeper.txt']},
{dest: 'dest/deep/deeper/deepest/deepest.txt', src: ['expand/deep/deeper/deepest/deepest.txt']},
];
test.deepEqual(actual, expected, 'cwd should be stripped from front of destPath, pre-destBase+destPath join');
test.done();
},
'rename': function(test) {
test.expect(1);
var actual = grunt.file.expandMapping(['**/*.txt'], 'dest', {
cwd: 'expand',
flatten: true,
rename: function(destBase, destPath, options) {
return path.join(destBase, options.cwd, 'o-m-g', destPath);
}
});
var expected = [
{dest: 'dest/expand/o-m-g/deep.txt', src: ['expand/deep/deep.txt']},
{dest: 'dest/expand/o-m-g/deeper.txt', src: ['expand/deep/deeper/deeper.txt']},
{dest: 'dest/expand/o-m-g/deepest.txt', src: ['expand/deep/deeper/deepest/deepest.txt']},
];
test.deepEqual(actual, expected, 'custom rename function should be used to build dest, post-flatten');
test.done();
},
'rename to same dest': function(test) {
test.expect(1);
var actual = grunt.file.expandMapping(['**/*'], 'dest', {
filter: 'isFile',
cwd: 'expand',
flatten: true,
rename: function(destBase, destPath) {
return path.join(destBase, 'all' + path.extname(destPath));
}
});
var expected = [
{dest: 'dest/all.md', src: ['expand/README.md']},
{dest: 'dest/all.css', src: ['expand/css/baz.css', 'expand/css/qux.css']},
{dest: 'dest/all.txt', src: ['expand/deep/deep.txt', 'expand/deep/deeper/deeper.txt', 'expand/deep/deeper/deepest/deepest.txt']},
{dest: 'dest/all.js', src: ['expand/js/bar.js', 'expand/js/foo.js']},
];
test.deepEqual(actual, expected, 'if dest is same for multiple src, create an array of src');
test.done();
},
};
// Compare two buffers. Returns true if they are equivalent.
var compareBuffers = function(buf1, buf2) {
if (!Buffer.isBuffer(buf1) || !Buffer.isBuffer(buf2)) { return false; }
if (buf1.length !== buf2.length) { return false; }
for (var i = 0; i < buf2.length; i++) {
if (buf1[i] !== buf2[i]) { return false; }
}
return true;
};
// Compare two files. Returns true if they are equivalent.
var compareFiles = function(filepath1, filepath2) {
return compareBuffers(fs.readFileSync(filepath1), fs.readFileSync(filepath2));
};
exports['file'] = {
setUp: function(done) {
this.defaultEncoding = grunt.file.defaultEncoding;
grunt.file.defaultEncoding = 'utf8';
this.string = 'Ação é isso aí\n';
this.object = {foo: 'Ação é isso aí', bar: ['ømg', 'pønies']};
this.writeOption = grunt.option('write');
done();
},
tearDown: function(done) {
grunt.file.defaultEncoding = this.defaultEncoding;
grunt.option('write', this.writeOption);
done();
},
'read': function(test) {
test.expect(5);
test.strictEqual(grunt.file.read('test/fixtures/utf8.txt'), this.string, 'file should be read as utf8 by default.');
test.strictEqual(grunt.file.read('test/fixtures/iso-8859-1.txt', {encoding: 'iso-8859-1'}), this.string, 'file should be read using the specified encoding.');
test.ok(compareBuffers(grunt.file.read('test/fixtures/octocat.png', {encoding: null}), fs.readFileSync('test/fixtures/octocat.png')), 'file should be read as a buffer if encoding is specified as null.');
test.strictEqual(grunt.file.read('test/fixtures/BOM.txt'), 'foo', 'file should have BOM stripped.');
grunt.file.defaultEncoding = 'iso-8859-1';
test.strictEqual(grunt.file.read('test/fixtures/iso-8859-1.txt'), this.string, 'changing the default encoding should work.');
test.done();
},
'readJSON': function(test) {
test.expect(3);
var obj;
obj = grunt.file.readJSON('test/fixtures/utf8.json');
test.deepEqual(obj, this.object, 'file should be read as utf8 by default and parsed correctly.');
obj = grunt.file.readJSON('test/fixtures/iso-8859-1.json', {encoding: 'iso-8859-1'});
test.deepEqual(obj, this.object, 'file should be read using the specified encoding.');
grunt.file.defaultEncoding = 'iso-8859-1';
obj = grunt.file.readJSON('test/fixtures/iso-8859-1.json');
test.deepEqual(obj, this.object, 'changing the default encoding should work.');
test.done();
},
'readYAML': function(test) {
test.expect(3);
var obj;
obj = grunt.file.readYAML('test/fixtures/utf8.yaml');
test.deepEqual(obj, this.object, 'file should be read as utf8 by default and parsed correctly.');
obj = grunt.file.readYAML('test/fixtures/iso-8859-1.yaml', {encoding: 'iso-8859-1'});
test.deepEqual(obj, this.object, 'file should be read using the specified encoding.');
grunt.file.defaultEncoding = 'iso-8859-1';
obj = grunt.file.readYAML('test/fixtures/iso-8859-1.yaml');
test.deepEqual(obj, this.object, 'changing the default encoding should work.');
test.done();
},
'write': function(test) {
test.expect(5);
var tmpfile;
tmpfile = new Tempfile();
grunt.file.write(tmpfile.path, this.string);
test.strictEqual(fs.readFileSync(tmpfile.path, 'utf8'), this.string, 'file should be written as utf8 by default.');
tmpfile.unlinkSync();
tmpfile = new Tempfile();
grunt.file.write(tmpfile.path, this.string, {encoding: 'iso-8859-1'});
test.strictEqual(grunt.file.read(tmpfile.path, {encoding: 'iso-8859-1'}), this.string, 'file should be written using the specified encoding.');
tmpfile.unlinkSync();
grunt.file.defaultEncoding = 'iso-8859-1';
tmpfile = new Tempfile();
grunt.file.write(tmpfile.path, this.string);
grunt.file.defaultEncoding = 'utf8';
test.strictEqual(grunt.file.read(tmpfile.path, {encoding: 'iso-8859-1'}), this.string, 'changing the default encoding should work.');
tmpfile.unlinkSync();
tmpfile = new Tempfile();
var octocat = fs.readFileSync('test/fixtures/octocat.png');
grunt.file.write(tmpfile.path, octocat);
test.ok(compareBuffers(fs.readFileSync(tmpfile.path), octocat), 'buffers should always be written as-specified, with no attempt at re-encoding.');
tmpfile.unlinkSync();
grunt.option('write', false);
var filepath = path.join(tmpdir.path, 'should-not-exist.txt');
grunt.file.write(filepath, 'test');
test.equal(grunt.file.exists(filepath), false, 'file should NOT be created if --no-write was specified.');
test.done();
},
'copy': function(test) {
test.expect(4);
var tmpfile;
tmpfile = new Tempfile();
grunt.file.copy('test/fixtures/utf8.txt', tmpfile.path);
test.ok(compareFiles(tmpfile.path, 'test/fixtures/utf8.txt'), 'files should just be copied as encoding-agnostic by default.');
tmpfile.unlinkSync();
tmpfile = new Tempfile();
grunt.file.copy('test/fixtures/iso-8859-1.txt', tmpfile.path);
test.ok(compareFiles(tmpfile.path, 'test/fixtures/iso-8859-1.txt'), 'files should just be copied as encoding-agnostic by default.');
tmpfile.unlinkSync();
tmpfile = new Tempfile();
grunt.file.copy('test/fixtures/octocat.png', tmpfile.path);
test.ok(compareFiles(tmpfile.path, 'test/fixtures/octocat.png'), 'files should just be copied as encoding-agnostic by default.');
tmpfile.unlinkSync();
grunt.option('write', false);
var filepath = path.join(tmpdir.path, 'should-not-exist.txt');
grunt.file.copy('test/fixtures/utf8.txt', filepath);
test.equal(grunt.file.exists(filepath), false, 'file should NOT be created if --no-write was specified.');
test.done();
},
'copy and process': function(test) {
test.expect(13);
var tmpfile;
tmpfile = new Tempfile();
grunt.file.copy('test/fixtures/utf8.txt', tmpfile.path, {
process: function(src, filepath) {
test.equal(filepath, 'test/fixtures/utf8.txt', 'filepath should be passed in, as-specified.');
test.equal(Buffer.isBuffer(src), false, 'when no encoding is specified, use default encoding and process src as a string');
test.equal(typeof src, 'string', 'when no encoding is specified, use default encoding and process src as a string');
return 'føø' + src + 'bår';
}
});
test.equal(grunt.file.read(tmpfile.path), 'føø' + this.string + 'bår', 'file should be saved as properly encoded processed string.');
tmpfile.unlinkSync();
tmpfile = new Tempfile();
grunt.file.copy('test/fixtures/iso-8859-1.txt', tmpfile.path, {
encoding: 'iso-8859-1',
process: function(src) {
test.equal(Buffer.isBuffer(src), false, 'use specified encoding and process src as a string');
test.equal(typeof src, 'string', 'use specified encoding and process src as a string');
return 'føø' + src + 'bår';
}
});
test.equal(grunt.file.read(tmpfile.path, {encoding: 'iso-8859-1'}), 'føø' + this.string + 'bår', 'file should be saved as properly encoded processed string.');
tmpfile.unlinkSync();
tmpfile = new Tempfile();
grunt.file.copy('test/fixtures/utf8.txt', tmpfile.path, {
encoding: null,
process: function(src) {
test.ok(Buffer.isBuffer(src), 'when encoding is specified as null, process src as a buffer');
return new Buffer('føø' + src.toString() + 'bår');
}
});
test.equal(grunt.file.read(tmpfile.path), 'føø' + this.string + 'bår', 'file should be saved as the buffer returned by process.');
tmpfile.unlinkSync();
grunt.file.defaultEncoding = 'iso-8859-1';
tmpfile = new Tempfile();
grunt.file.copy('test/fixtures/iso-8859-1.txt', tmpfile.path, {
process: function(src) {
test.equal(Buffer.isBuffer(src), false, 'use non-utf8 default encoding and process src as a string');
test.equal(typeof src, 'string', 'use non-utf8 default encoding and process src as a string');
return 'føø' + src + 'bår';
}
});
test.equal(grunt.file.read(tmpfile.path), 'føø' + this.string + 'bår', 'file should be saved as properly encoded processed string.');
tmpfile.unlinkSync();
var filepath = path.join(tmpdir.path, 'should-not-exist.txt');
grunt.file.copy('test/fixtures/iso-8859-1.txt', filepath, {
process: function() {
return false;
}
});
test.equal(grunt.file.exists(filepath), false, 'file should NOT be created if process returns false.');
test.done();
},
'copy and process, noprocess': function(test) {
test.expect(4);
var tmpfile;
tmpfile = new Tempfile();
grunt.file.copy('test/fixtures/utf8.txt', tmpfile.path, {
noProcess: true,
process: function(src) {
return 'føø' + src + 'bår';
}
});
test.equal(grunt.file.read(tmpfile.path), this.string, 'file should not have been processed.');
tmpfile.unlinkSync();
['process', 'noprocess', 'othernoprocess'].forEach(function(filename) {
var filepath = path.join(tmpdir.path, filename);
grunt.file.copy('test/fixtures/utf8.txt', filepath);
var tmpfile = new Tempfile();
grunt.file.copy(filepath, tmpfile.path, {
noProcess: ['**/*no*'],
process: function(src) {
return 'føø' + src + 'bår';
}
});
if (filename === 'process') {
test.equal(grunt.file.read(tmpfile.path), 'føø' + this.string + 'bår', 'file should have been processed.');
} else {
test.equal(grunt.file.read(tmpfile.path), this.string, 'file should not have been processed.');
}
tmpfile.unlinkSync();
}, this);
test.done();
},
'delete': function(test) {
test.expect(2);
var oldBase = process.cwd();
var cwd = path.resolve(tmpdir.path, 'delete', 'folder');
grunt.file.mkdir(cwd);
grunt.file.setBase(tmpdir.path);
grunt.file.write(path.join(cwd, 'test.js'), 'var test;');
test.ok(grunt.file.delete(cwd), 'should return true after deleting file.');
test.equal(grunt.file.exists(cwd), false, 'file should have been deleted.');
grunt.file.setBase(oldBase);
test.done();
},
'delete nonexistent file': function(test) {
test.expect(1);
test.ok(!grunt.file.delete('nonexistent'), 'should return false if file does not exist.');
test.done();
},
'delete outside working directory': function(test) {
test.expect(3);
var oldBase = process.cwd();
var oldWarn = grunt.fail.warn;
grunt.fail.warn = function() {};
var cwd = path.resolve(tmpdir.path, 'delete', 'folder');
var outsidecwd = path.resolve(tmpdir.path, 'delete', 'outsidecwd');
grunt.file.mkdir(cwd);
grunt.file.mkdir(outsidecwd);
grunt.file.setBase(cwd);
grunt.file.write(path.join(outsidecwd, 'test.js'), 'var test;');
test.equal(grunt.file.delete(path.join(outsidecwd, 'test.js')), false, 'should not delete anything outside the cwd.');
test.ok(grunt.file.delete(path.join(outsidecwd), {force:true}), 'should delete outside cwd when using the --force.');
test.equal(grunt.file.exists(outsidecwd), false, 'file outside cwd should have been deleted when using the --force.');
grunt.file.setBase(oldBase);
grunt.fail.warn = oldWarn;
test.done();
},
'dont delete current working directory': function(test) {
test.expect(2);
var oldBase = process.cwd();
var oldWarn = grunt.fail.warn;
grunt.fail.warn = function() {};
var cwd = path.resolve(tmpdir.path, 'dontdelete', 'folder');
grunt.file.mkdir(cwd);
grunt.file.setBase(cwd);
test.equal(grunt.file.delete(cwd), false, 'should not delete the cwd.');
test.ok(grunt.file.exists(cwd), 'the cwd should exist.');
grunt.file.setBase(oldBase);
grunt.fail.warn = oldWarn;
test.done();
},
'dont actually delete with no-write option on': function(test) {
test.expect(2);
grunt.option('write', false);
var oldBase = process.cwd();
var cwd = path.resolve(tmpdir.path, 'dontdelete', 'folder');
grunt.file.mkdir(cwd);
grunt.file.setBase(tmpdir.path);
grunt.file.write(path.join(cwd, 'test.js'), 'var test;');
test.ok(grunt.file.delete(cwd), 'should return true after not actually deleting file.');
test.equal(grunt.file.exists(cwd), true, 'file should NOT be deleted if --no-write was specified.');
grunt.file.setBase(oldBase);
test.done();
},
'mkdir': function(test) {
test.expect(5);
test.doesNotThrow(function() {
grunt.file.mkdir(tmpdir.path);
}, 'Should not explode if the directory already exists.');
test.ok(fs.existsSync(tmpdir.path), 'path should still exist.');
test.doesNotThrow(function() {
grunt.file.mkdir(path.join(tmpdir.path, 'aa/bb/cc'));
}, 'Should also not explode, otherwise.');
test.ok(path.join(tmpdir.path, 'aa/bb/cc'), 'path should have been created.');
fs.writeFileSync(path.join(tmpdir.path, 'aa/bb/xx'), 'test');
test.throws(function() {
grunt.file.mkdir(path.join(tmpdir.path, 'aa/bb/xx/yy'));
}, 'Should throw if a path cannot be created (ENOTDIR).');
test.done();
},
'recurse': function(test) {
test.expect(1);
var rootdir = 'test/fixtures/expand';
var expected = {};
expected[rootdir + '/css/baz.css'] = [rootdir, 'css', 'baz.css'];
expected[rootdir + '/css/qux.css'] = [rootdir, 'css', 'qux.css'];
expected[rootdir + '/deep/deep.txt'] = [rootdir, 'deep', 'deep.txt'];
expected[rootdir + '/deep/deeper/deeper.txt'] = [rootdir, 'deep/deeper', 'deeper.txt'];
expected[rootdir + '/deep/deeper/deepest/deepest.txt'] = [rootdir, 'deep/deeper/deepest', 'deepest.txt'];
expected[rootdir + '/js/bar.js'] = [rootdir, 'js', 'bar.js'];
expected[rootdir + '/js/foo.js'] = [rootdir, 'js', 'foo.js'];
expected[rootdir + '/README.md'] = [rootdir, undefined, 'README.md'];
var actual = {};
grunt.file.recurse(rootdir, function(abspath, rootdir, subdir, filename) {
actual[abspath] = [rootdir, subdir, filename];
});
test.deepEqual(actual, expected, 'paths and arguments should match.');
test.done();
},
'exists': function(test) {
test.expect(6);
test.ok(grunt.file.exists('test/fixtures/octocat.png'), 'files exist.');
test.ok(grunt.file.exists('test', 'fixtures', 'octocat.png'), 'should work for paths in parts.');
test.ok(grunt.file.exists('test/fixtures'), 'directories exist.');
test.ok(grunt.file.exists(path.join(tmpdir.path, 'octocat.png')), 'file links exist.');
test.ok(grunt.file.exists(path.join(tmpdir.path, 'expand')), 'directory links exist.');
test.equal(grunt.file.exists('test/fixtures/does/not/exist'), false, 'nonexistent files do not exist.');
test.done();
},
'isLink': function(test) {
test.expect(6);
test.equals(grunt.file.isLink('test/fixtures/octocat.png'), false, 'files are not links.');
test.equals(grunt.file.isLink('test/fixtures'), false, 'directories are not links.');
test.ok(grunt.file.isLink(path.join(tmpdir.path, 'octocat.png')), 'file links are links.');
test.ok(grunt.file.isLink(path.join(tmpdir.path, 'expand')), 'directory links are links.');
test.ok(grunt.file.isLink(tmpdir.path, 'octocat.png'), 'should work for paths in parts.');
test.equals(grunt.file.isLink('test/fixtures/does/not/exist'), false, 'nonexistent files are not links.');
test.done();
},
'isDir': function(test) {
test.expect(6);
test.equals(grunt.file.isDir('test/fixtures/octocat.png'), false, 'files are not directories.');
test.ok(grunt.file.isDir('test/fixtures'), 'directories are directories.');
test.ok(grunt.file.isDir('test', 'fixtures'), 'should work for paths in parts.');
test.equals(grunt.file.isDir(path.join(tmpdir.path, 'octocat.png')), false, 'file links are not directories.');
test.ok(grunt.file.isDir(path.join(tmpdir.path, 'expand')), 'directory links are directories.');
test.equals(grunt.file.isDir('test/fixtures/does/not/exist'), false, 'nonexistent files are not directories.');
test.done();
},
'isFile': function(test) {
test.expect(6);
test.ok(grunt.file.isFile('test/fixtures/octocat.png'), 'files are files.');
test.ok(grunt.file.isFile('test', 'fixtures', 'octocat.png'), 'should work for paths in parts.');
test.equals(grunt.file.isFile('test/fixtures'), false, 'directories are not files.');
test.ok(grunt.file.isFile(path.join(tmpdir.path, 'octocat.png')), 'file links are files.');
test.equals(grunt.file.isFile(path.join(tmpdir.path, 'expand')), false, 'directory links are not files.');
test.equals(grunt.file.isFile('test/fixtures/does/not/exist'), false, 'nonexistent files are not files.');
test.done();
},
'isPathAbsolute': function(test) {
test.expect(5);
test.ok(grunt.file.isPathAbsolute(path.resolve('/foo')), 'should return true');
test.ok(grunt.file.isPathAbsolute(path.resolve('/foo') + path.sep), 'should return true');
test.equal(grunt.file.isPathAbsolute('foo'), false, 'should return false');
test.ok(grunt.file.isPathAbsolute(path.resolve('test/fixtures/a.js')), 'should return true');
test.equal(grunt.file.isPathAbsolute('test/fixtures/a.js'), false, 'should return false');
test.done();
},
'arePathsEquivalent': function(test) {
test.expect(5);
test.ok(grunt.file.arePathsEquivalent('/foo'), 'should return true');
test.ok(grunt.file.arePathsEquivalent('/foo', '/foo/', '/foo/../foo/'), 'should return true');
test.ok(grunt.file.arePathsEquivalent(process.cwd(), '.', './', 'test/..'), 'should return true');
test.equal(grunt.file.arePathsEquivalent(process.cwd(), '..'), false, 'should return false');
test.equal(grunt.file.arePathsEquivalent('.', '..'), false, 'should return false');
test.done();
},
'doesPathContain': function(test) {
test.expect(6);
test.ok(grunt.file.doesPathContain('/foo', '/foo/bar'), 'should return true');
test.ok(grunt.file.doesPathContain('/foo/', '/foo/bar/baz', '/foo/bar', '/foo/whatever'), 'should return true');
test.equal(grunt.file.doesPathContain('/foo', '/foo'), false, 'should return false');
test.equal(grunt.file.doesPathContain('/foo/xyz', '/foo/xyz/123', '/foo/bar/baz'), false, 'should return false');
test.equal(grunt.file.doesPathContain('/foo/xyz', '/foo'), false, 'should return false');
test.ok(grunt.file.doesPathContain(process.cwd(), 'test', 'test/fixtures', 'lib'), 'should return true');
test.done();
},
'isPathCwd': function(test) {
test.expect(8);
test.ok(grunt.file.isPathCwd(process.cwd()), 'cwd is cwd');
test.ok(grunt.file.isPathCwd('.'), 'cwd is cwd');
test.equal(grunt.file.isPathCwd('test'), false, 'subdirectory is not cwd');
test.equal(grunt.file.isPathCwd(path.resolve('test')), false, 'subdirectory is not cwd');
test.equal(grunt.file.isPathCwd('..'), false, 'parent is not cwd');
test.equal(grunt.file.isPathCwd(path.resolve('..')), false, 'parent is not cwd');
test.equal(grunt.file.isPathCwd('/'), false, 'root is not cwd (I hope)');
test.equal(grunt.file.isPathCwd('nonexistent'), false, 'nonexistent path is not cwd');
test.done();
},
'isPathInCwd': function(test) {
test.expect(8);
test.equal(grunt.file.isPathInCwd(process.cwd()), false, 'cwd is not IN cwd');
test.equal(grunt.file.isPathInCwd('.'), false, 'cwd is not IN cwd');
test.ok(grunt.file.isPathInCwd('test'), 'subdirectory is in cwd');
test.ok(grunt.file.isPathInCwd(path.resolve('test')), 'subdirectory is in cwd');
test.equal(grunt.file.isPathInCwd('..'), false, 'parent is not in cwd');
test.equal(grunt.file.isPathInCwd(path.resolve('..')), false, 'parent is not in cwd');
test.equal(grunt.file.isPathInCwd('/'), false, 'root is not in cwd (I hope)');
test.equal(grunt.file.isPathInCwd('nonexistent'), false, 'nonexistent path is not in cwd');
test.done();
},
};
+224
View File
@@ -0,0 +1,224 @@
'use strict';
var grunt = require('../../lib/grunt');
var log = grunt.log;
var fooBuffer = new Buffer('foo');
// Helper for testing stdout
var hooker = grunt.util.hooker;
var stdoutEqual = function(test, callback, expected) {
var actual = '';
// Hook process.stdout.write
hooker.hook(process.stdout, 'write', {
// This gets executed before the original process.stdout.write.
pre: function(result) {
// Concatenate uncolored result onto actual.
actual += log.uncolor(result);
// Prevent the original process.stdout.write from executing.
return hooker.preempt();
}
});
// Execute the logging code to be tested.
callback();
// Restore process.stdout.write to its original value.
hooker.unhook(process.stdout, 'write');
// Actually test the actually-logged stdout string to the expected value.
test.equal(actual, expected);
};
exports['log'] = {
'setUp': function(done) {
log.muted = false;
grunt.fail.errorcount = 0;
done();
},
'write': function(test) {
test.expect(4);
stdoutEqual(test, function() { log.write(''); }, '');
stdoutEqual(test, function() { log.write('foo'); }, 'foo');
stdoutEqual(test, function() { log.write('%s', 'foo'); }, 'foo');
stdoutEqual(test, function() { log.write(fooBuffer); }, 'foo');
test.done();
},
'writeln': function(test) {
test.expect(4);
stdoutEqual(test, function() { log.writeln(); }, '\n');
stdoutEqual(test, function() { log.writeln('foo'); }, 'foo\n');
stdoutEqual(test, function() { log.writeln('%s', 'foo'); }, 'foo\n');
stdoutEqual(test, function() { log.writeln(fooBuffer); }, 'foo\n');
test.done();
},
'warn': function(test) {
test.expect(5);
stdoutEqual(test, function() { log.warn(); }, 'ERROR\n');
stdoutEqual(test, function() { log.warn('foo'); }, '>> foo\n');
stdoutEqual(test, function() { log.warn('%s', 'foo'); }, '>> foo\n');
stdoutEqual(test, function() { log.warn(fooBuffer); }, '>> foo\n');
test.equal(grunt.fail.errorcount, 0);
test.done();
},
'error': function(test) {
test.expect(5);
stdoutEqual(test, function() { log.error(); }, 'ERROR\n');
stdoutEqual(test, function() { log.error('foo'); }, '>> foo\n');
stdoutEqual(test, function() { log.error('%s', 'foo'); }, '>> foo\n');
stdoutEqual(test, function() { log.error(fooBuffer); }, '>> foo\n');
test.equal(grunt.fail.errorcount, 4);
test.done();
},
'ok': function(test) {
test.expect(4);
stdoutEqual(test, function() { log.ok(); }, 'OK\n');
stdoutEqual(test, function() { log.ok('foo'); }, '>> foo\n');
stdoutEqual(test, function() { log.ok('%s', 'foo'); }, '>> foo\n');
stdoutEqual(test, function() { log.ok(fooBuffer); }, '>> foo\n');
test.done();
},
'errorlns': function(test) {
test.expect(2);
stdoutEqual(test, function() {
log.errorlns(grunt.util._.repeat('foo', 30, ' '));
}, '>> ' + grunt.util._.repeat('foo', 19, ' ') + '\n' +
'>> ' + grunt.util._.repeat('foo', 11, ' ') + '\n');
test.equal(grunt.fail.errorcount, 1);
test.done();
},
'oklns': function(test) {
test.expect(1);
stdoutEqual(test, function() {
log.oklns(grunt.util._.repeat('foo', 30, ' '));
}, '>> ' + grunt.util._.repeat('foo', 19, ' ') + '\n' +
'>> ' + grunt.util._.repeat('foo', 11, ' ') + '\n');
test.done();
},
'success': function(test) {
test.expect(4);
stdoutEqual(test, function() { log.success(); }, '\n');
stdoutEqual(test, function() { log.success('foo'); }, 'foo\n');
stdoutEqual(test, function() { log.success('%s', 'foo'); }, 'foo\n');
stdoutEqual(test, function() { log.success(fooBuffer); }, 'foo\n');
test.done();
},
'fail': function(test) {
test.expect(4);
stdoutEqual(test, function() { log.fail(); }, '\n');
stdoutEqual(test, function() { log.fail('foo'); }, 'foo\n');
stdoutEqual(test, function() { log.fail('%s', 'foo'); }, 'foo\n');
stdoutEqual(test, function() { log.fail(fooBuffer); }, 'foo\n');
test.done();
},
'header': function(test) {
test.expect(4);
stdoutEqual(test, function() { log.header(); }, '\n\n');
stdoutEqual(test, function() { log.header('foo'); }, '\nfoo\n');
stdoutEqual(test, function() { log.header('%s', 'foo'); }, '\nfoo\n');
stdoutEqual(test, function() { log.header(fooBuffer); }, '\nfoo\n');
test.done();
},
'subhead': function(test) {
test.expect(4);
stdoutEqual(test, function() { log.subhead(); }, '\n\n');
stdoutEqual(test, function() { log.subhead('foo'); }, '\nfoo\n');
stdoutEqual(test, function() { log.subhead('%s', 'foo'); }, '\nfoo\n');
stdoutEqual(test, function() { log.subhead(fooBuffer); }, '\nfoo\n');
test.done();
},
'debug': function(test) {
test.expect(5);
var debug = grunt.option('debug');
grunt.option('debug', true);
stdoutEqual(test, function() { log.debug(); }, '[D] \n');
stdoutEqual(test, function() { log.debug('foo'); }, '[D] foo\n');
stdoutEqual(test, function() { log.debug('%s', 'foo'); }, '[D] foo\n');
stdoutEqual(test, function() { log.debug(fooBuffer); }, '[D] foo\n');
grunt.option('debug', false);
stdoutEqual(test, function() { log.debug('foo'); }, '');
grunt.option('debug', debug);
test.done();
},
'writetableln': function(test) {
test.expect(1);
stdoutEqual(test, function() {
log.writetableln([10], [grunt.util._.repeat('foo', 10)]);
}, 'foofoofoof\noofoofoofo\nofoofoofoo\n');
test.done();
},
'writelns': function(test) {
test.expect(1);
stdoutEqual(test, function() {
log.writelns(grunt.util._.repeat('foo', 30, ' '));
}, grunt.util._.repeat('foo', 20, ' ') + '\n' +
grunt.util._.repeat('foo', 10, ' ') + '\n');
test.done();
},
'writeflags': function(test) {
test.expect(1);
stdoutEqual(test, function() {
log.writeflags(['foo', 'bar'], 'test');
}, 'test: foo, bar\n');
test.done();
},
'verbose': function(test) {
test.expect(1);
log.muted = true;
// Test a chain to make sure it's always returning the verbose object.
var obj;
['write','writeln','warn','error','ok'].forEach(function(key) {
obj = obj ? obj[key]('foo') : log.verbose[key]('foo');
});
test.strictEqual(obj, log.verbose);
test.done();
},
'notverbose': function(test) {
test.expect(1);
hooker.hook(process.stdout, 'write', {
pre: function() { return hooker.preempt(); }
});
// Test a chain to make sure it's always returning the notverbose object.
var obj;
['write','writeln','warn','error','ok'].forEach(function(key) {
obj = obj ? obj[key]('foo') : log.notverbose[key]('foo');
});
test.strictEqual(obj, log.notverbose);
hooker.unhook(process.stdout, 'write');
test.done();
}
};
+41
View File
@@ -0,0 +1,41 @@
'use strict';
var grunt = require('../../lib/grunt');
exports['option'] = {
setUp: function(done) {
grunt.option.init();
done();
},
tearDown: function(done) {
grunt.option.init();
done();
},
'option.init': function(test) {
test.expect(1);
var expected = {foo:'bar',bool:true,'bar':{foo:'bar'}};
test.deepEqual(grunt.option.init(expected), expected);
test.done();
},
'option': function(test) {
test.expect(4);
test.equal(grunt.option('foo', 'bar'), grunt.option('foo'));
grunt.option('foo', {foo:'bar'});
test.deepEqual(grunt.option('foo'), {foo:'bar'});
test.equal(grunt.option('no-there'), false);
grunt.option('there', false);
test.equal(grunt.option('no-there'), true);
test.done();
},
'option.flags': function(test) {
test.expect(1);
grunt.option.init({
foo: 'bar',
there: true,
obj: {foo: 'bar'},
arr: []
});
test.deepEqual(grunt.option.flags(), ['--foo=bar', '--there', '--obj=[object Object]']);
test.done();
},
};
+259
View File
@@ -0,0 +1,259 @@
'use strict';
var grunt = require('../../lib/grunt');
exports['task.normalizeMultiTaskFiles'] = {
setUp: function(done) {
this.cwd = process.cwd();
process.chdir('test/fixtures/files');
done();
},
tearDown: function(done) {
process.chdir(this.cwd);
done();
},
'normalize': function(test) {
test.expect(7);
var actual, expected, key, value;
var flatten = grunt.util._.flatten;
key = 'dist/built.js';
value = 'src/*1.js';
actual = grunt.task.normalizeMultiTaskFiles(value, key);
expected = [
{
dest: 'dist/built.js',
src: ['src/file1.js'],
orig: {dest: key, src: [value]},
},
];
test.deepEqual(actual, expected, 'should normalize destTarget: srcString.');
key = 'dist/built.js';
value = [['src/*1.js'], ['src/*2.js']];
actual = grunt.task.normalizeMultiTaskFiles(value, key);
expected = [
{
dest: 'dist/built.js',
src: ['src/file1.js', 'src/file2.js'],
orig: {dest: key, src: flatten(value)},
},
];
test.deepEqual(actual, expected, 'should normalize destTarget: srcArray.');
value = {
src: ['src/*1.js', 'src/*2.js'],
dest: 'dist/built.js'
};
actual = grunt.task.normalizeMultiTaskFiles(value, 'ignored');
expected = [
{
dest: 'dist/built.js',
src: ['src/file1.js', 'src/file2.js'],
orig: value,
},
];
test.deepEqual(actual, expected, 'should normalize target: {src: srcStuff, dest: destStuff}.');
value = {
files: {
'dist/built-a.js': 'src/*1.js',
'dist/built-b.js': ['src/*1.js', [['src/*2.js']]]
}
};
actual = grunt.task.normalizeMultiTaskFiles(value, 'ignored');
expected = [
{
dest: 'dist/built-a.js',
src: ['src/file1.js'],
orig: {dest: 'dist/built-a.js', src: [value.files['dist/built-a.js']]},
},
{
dest: 'dist/built-b.js',
src: ['src/file1.js', 'src/file2.js'],
orig: {dest: 'dist/built-b.js', src: flatten(value.files['dist/built-b.js'])},
},
];
test.deepEqual(actual, expected, 'should normalize target: {files: {destTarget: srcStuff, ...}}.');
value = {
files: [
{'dist/built-a.js': 'src/*.whoops'},
{'dist/built-b.js': [[['src/*1.js'], 'src/*2.js']]}
]
};
actual = grunt.task.normalizeMultiTaskFiles(value, 'ignored');
expected = [
{
dest: 'dist/built-a.js',
src: [],
orig: {dest: Object.keys(value.files[0])[0], src: [value.files[0]['dist/built-a.js']]},
},
{
dest: 'dist/built-b.js',
src: ['src/file1.js', 'src/file2.js'],
orig: {dest: Object.keys(value.files[1])[0], src: flatten(value.files[1]['dist/built-b.js'])},
},
];
test.deepEqual(actual, expected, 'should normalize target: {files: [{destTarget: srcStuff}, ...]}.');
value = {
files: [
{dest: 'dist/built-a.js', src: ['src/*2.js']},
{dest: 'dist/built-b.js', src: ['src/*1.js', 'src/*2.js']}
]
};
actual = grunt.task.normalizeMultiTaskFiles(value, 'ignored');
expected = [
{
dest: 'dist/built-a.js',
src: ['src/file2.js'],
orig: value.files[0],
},
{
dest: 'dist/built-b.js',
src: ['src/file1.js', 'src/file2.js'],
orig: value.files[1],
},
];
test.deepEqual(actual, expected, 'should normalize target: {files: [{src: srcStuff, dest: destStuff}, ...]}.');
value = {
files: [
{dest: 'dist/built-a.js', src: ['src/*2.js'], foo: 123, bar: true},
{dest: 'dist/built-b.js', src: ['src/*1.js', 'src/*2.js'], foo: 456, bar: null}
]
};
actual = grunt.task.normalizeMultiTaskFiles(value, 'ignored');
expected = [
{
dest: 'dist/built-a.js',
src: ['src/file2.js'],
foo: 123,
bar: true,
orig: value.files[0],
},
{
dest: 'dist/built-b.js',
src: ['src/file1.js', 'src/file2.js'],
foo: 456,
bar: null,
orig: value.files[1],
},
];
test.deepEqual(actual, expected, 'should propagate extra properties.');
test.done();
},
'nonull': function(test) {
test.expect(2);
var actual, expected, value;
value = {
src: ['src/xxx*.js', 'src/yyy*.js'],
dest: 'dist/built.js',
};
actual = grunt.task.normalizeMultiTaskFiles(value, 'ignored');
expected = [
{
dest: value.dest,
src: [],
orig: value,
},
];
test.deepEqual(actual, expected, 'if nonull is not set, should not include non-matching patterns.');
value = {
src: ['src/xxx*.js', 'src/yyy*.js'],
dest: 'dist/built.js',
nonull: true,
};
actual = grunt.task.normalizeMultiTaskFiles(value, 'ignored');
expected = [
{
dest: value.dest,
src: value.src,
nonull: true,
orig: value,
},
];
test.deepEqual(actual, expected, 'if nonull is set, should include non-matching patterns.');
test.done();
},
'expandMapping': function(test) {
test.expect(3);
var actual, expected, value;
value = {
files: [
{dest: 'dist/', src: ['src/file?.js'], expand: true},
{dest: 'dist/', src: ['file?.js'], expand: true, cwd: 'src'},
]
};
actual = grunt.task.normalizeMultiTaskFiles(value, 'ignored');
expected = [
{
dest: 'dist/src/file1.js', src: ['src/file1.js'],
orig: value.files[0],
},
{
dest: 'dist/src/file2.js', src: ['src/file2.js'],
orig: value.files[0],
},
{
dest: 'dist/file1.js', src: ['src/file1.js'],
orig: value.files[1],
},
{
dest: 'dist/file2.js', src: ['src/file2.js'],
orig: value.files[1],
},
];
test.deepEqual(actual, expected, 'expand to file mapping, removing cwd from destination paths.');
value = {
files: [
{dest: 'dist/', src: ['src/file?.js'], expand: true, flatten: true},
]
};
actual = grunt.task.normalizeMultiTaskFiles(value, 'ignored');
expected = [
{
dest: 'dist/file1.js', src: ['src/file1.js'],
orig: value.files[0],
},
{
dest: 'dist/file2.js', src: ['src/file2.js'],
orig: value.files[0],
},
];
test.deepEqual(actual, expected, 'expand to file mapping, flattening destination paths.');
value = {
files: [
{
dest: 'dist/',
src: ['src/file?.js'],
expand: true,
rename: function(destBase, destPath) {
return destBase + 'min/' + destPath.replace(/(\.js)$/, '.min$1');
},
},
]
};
actual = grunt.task.normalizeMultiTaskFiles(value, 'ignored');
expected = [
{
dest: 'dist/min/src/file1.min.js', src: ['src/file1.js'],
orig: value.files[0],
},
{
dest: 'dist/min/src/file2.min.js', src: ['src/file2.js'],
orig: value.files[0],
},
];
test.deepEqual(actual, expected, 'expand to file mapping, renaming files.');
test.done();
},
};
+47
View File
@@ -0,0 +1,47 @@
'use strict';
var grunt = require('../../lib/grunt');
exports['template'] = {
'process': function(test) {
test.expect(4);
var obj = {
foo: 'c',
bar: 'b<%= foo %>d',
baz: 'a<%= bar %>e'
};
test.equal(grunt.template.process('<%= foo %>', {data: obj}), 'c', 'should retrieve value.');
test.equal(grunt.template.process('<%= bar %>', {data: obj}), 'bcd', 'should recurse.');
test.equal(grunt.template.process('<%= baz %>', {data: obj}), 'abcde', 'should recurse.');
obj.foo = '<% oops %';
test.equal(grunt.template.process('<%= baz %>', {data: obj}), 'ab<% oops %de', 'should not explode.');
test.done();
},
'custom delimiters': function(test) {
test.expect(6);
var obj = {
foo: 'c',
bar: 'b{%= foo %}d',
baz: 'a{%= bar %}e'
};
test.equal(grunt.template.process('{%= foo %}', {data: obj, delimiters: 'custom'}), '{%= foo %}', 'custom delimiters have yet to be defined.');
// Define custom delimiters.
grunt.template.addDelimiters('custom', '{%', '%}');
test.equal(grunt.template.process('{%= foo %}', {data: obj, delimiters: 'custom'}), 'c', 'should retrieve value.');
test.equal(grunt.template.process('{%= bar %}', {data: obj, delimiters: 'custom'}), 'bcd', 'should recurse.');
test.equal(grunt.template.process('{%= baz %}', {data: obj, delimiters: 'custom'}), 'abcde', 'should recurse.');
test.equal(grunt.template.process('{%= foo %}<%= foo %>', {data: obj, delimiters: 'custom'}), 'c<%= foo %>', 'should ignore default delimiters');
obj.foo = '{% oops %';
test.equal(grunt.template.process('{%= baz %}', {data: obj, delimiters: 'custom'}), 'ab{% oops %de', 'should not explode.');
test.done();
},
};
+301
View File
@@ -0,0 +1,301 @@
'use strict';
var grunt = require('../../lib/grunt');
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;
}
grunt.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);
}
grunt.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);
}
grunt.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 = grunt.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 = grunt.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 = grunt.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(grunt.util.linefeed, '\r\n', 'linefeed should be operating-system appropriate.');
} else {
test.equal(grunt.util.linefeed, '\n', 'linefeed should be operating-system appropriate.');
}
test.done();
},
'normalizelf': function(test) {
test.expect(1);
if (process.platform === 'win32') {
test.equal(grunt.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(grunt.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);
grunt.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);
grunt.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);
grunt.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);
grunt.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);
grunt.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);
grunt.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';
grunt.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';
grunt.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);
grunt.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);
grunt.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 result.toString() with error': function(test) {
// grunt.log.error uses standard out, to be fixed in 0.5.
test.expect(4);
grunt.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 = grunt.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);
grunt.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(grunt.util._.trim(' foo '), 'foo', 'Should have trimmed the string.');
test.equals(grunt.util._.capitalize('foo'), 'Foo', 'Should have capitalized the first letter.');
test.equals(grunt.util._.words('one two three').length, 3, 'Should have counted three words.');
test.ok(grunt.util._.isBlank(' '), 'Should be blank.');
test.done();
};
+361
View File
@@ -0,0 +1,361 @@
/*
* grunt
* http://gruntjs.com/
*
* Copyright (c) 2013 "Cowboy" Ben Alman
* Licensed under the MIT license.
* https://github.com/gruntjs/grunt/blob/master/LICENSE-MIT
*/
// For now, run this "test suite" with:
// grunt --gruntfile ./test/gruntfile/multi-task-files.js
'use strict';
module.exports = function(grunt) {
grunt.file.setBase('../fixtures/files');
grunt.initConfig({
build: '123',
mappings: {
cwd: 'src/',
dest: 'foo/',
ext: '.bar',
rename: function(destBase, destPath) {
return destBase + 'baz/' + destPath.replace(/\.js$/, '<%= mappings.ext %>');
},
},
run: {
options: {a: 1, b: 11},
// This is the "compact" format, where the target name is actually the
// dest filename. Doesn't support per-target options, templated dest, or
// >1 srcs-dest grouping.
'dist/built.js': 'src/*1.js',
'dist/built1.js': ['src/*1.js', 'src/*2.js'],
// This is the "medium" format. The target name is arbitrary and can be
// used like "grunt run:built". Supports per-target options, templated
// dest, and arbitrary "extra" paramters. Doesn't support >1 srcs-dest
// grouping.
built: {
options: {a: 2, c: 22},
src: ['src/*1.js', 'src/*2.js'],
dest: 'dist/built-<%= build %>.js',
extra: 123,
},
// This is the "full" format. The target name is arbitrary and can be
// used like "grunt run:long1". Supports per-target options, templated
// dest and >1 srcs-dest grouping.
long1: {
options: {a: 3, c: 33},
files: {
'dist/built-<%= build %>-a.js': ['src/*1.js'],
'dist/built-<%= build %>-b.js': ['src/*1.js', 'src/*2.js'],
}
},
long2: {
options: {a: 4, c: 44},
files: [
{'dist/built-<%= build %>-a.js': ['src/*.whoops']},
{'dist/built-<%= build %>-b.js': ['src/*1.js', 'src/*2.js']},
]
},
// This "full" variant supports per srcs-dest arbitrary "extra" paramters.
long3: {
options: {a: 5, c: 55},
files: [
{dest: 'dist/built-<%= build %>-a.js', src: ['src/*2.js'], extra: 456},
{dest: 'dist/built-<%= build %>-b.js', src: ['src/*1.js', 'src/*2.js'], extra: 789},
]
},
// File mapping options can be specified in these 2 formats.
built_mapping: {
options: {a: 6, c: 66},
expand: true,
cwd: '<%= mappings.cwd %>',
src: ['*1.js', '*2.js'],
dest: '<%= mappings.dest %>',
rename: '<%= mappings.rename %>',
extra: 123
},
long3_mapping: {
options: {a: 7, c: 77},
files: [
{
expand: true,
cwd: '<%= mappings.cwd %>',
src: ['*1.js', '*2.js'],
dest: '<%= mappings.dest %>',
rename: '<%= mappings.rename %>',
extra: 123
}
]
},
// Need to ensure the task function is run if no files or options were
// specified!
no_files_or_options: {},
},
});
var results = {};
var counters = [];
var counter = -1;
grunt.registerMultiTask('run', 'Store stuff for later testing.', function() {
var key = this.nameArgs;
results[key] = {
options: this.options({d: 9}),
files: this.files,
};
// Test asynchronous-ness.
var done;
if (counter++ % 2 === 0) {
done = this.async();
setTimeout(function() {
counters.push(counter);
done();
}, 10);
} else {
counters.push(counter);
}
});
var expecteds = {
'run:no_files_or_options': {
options: {a: 1, b: 11, d: 9},
files: [],
},
'run:dist/built.js': {
options: {a: 1, b: 11, d: 9},
files: [
{
dest: 'dist/built.js',
src: ['src/file1.js'],
orig: {
dest: 'dist/built.js',
src: ['src/*1.js'],
},
},
]
},
'run:dist/built1.js': {
options: {a: 1, b: 11, d: 9},
files: [
{
dest: 'dist/built1.js',
src: ['src/file1.js', 'src/file2.js'],
orig: {
dest: 'dist/built1.js',
src: ['src/*1.js', 'src/*2.js'],
},
},
]
},
'run:built': {
options: {a: 2, b: 11, c: 22, d: 9},
files: [
{
dest: 'dist/built-123.js',
src: ['src/file1.js', 'src/file2.js'],
extra: 123,
orig: {
dest: 'dist/built-123.js',
src: ['src/*1.js', 'src/*2.js'],
extra: 123,
},
},
],
},
'run:long1': {
options: {a: 3, b: 11, c: 33, d: 9},
files: [
{
dest: 'dist/built-123-a.js',
src: ['src/file1.js'],
orig: {
dest: 'dist/built-123-a.js',
src: ['src/*1.js'],
},
},
{
dest: 'dist/built-123-b.js',
src: ['src/file1.js', 'src/file2.js'],
orig: {
dest: 'dist/built-123-b.js',
src: ['src/*1.js', 'src/*2.js'],
},
},
],
},
'run:long2': {
options: {a: 4, b: 11, c: 44, d: 9},
files: [
{
dest: 'dist/built-123-a.js',
src: [],
orig: {
dest: 'dist/built-123-a.js',
src: ['src/*.whoops'],
},
},
{
dest: 'dist/built-123-b.js',
src: ['src/file1.js', 'src/file2.js'],
orig: {
dest: 'dist/built-123-b.js',
src: ['src/*1.js', 'src/*2.js'],
},
},
],
},
'run:long3': {
options: {a: 5, b: 11, c: 55, d: 9},
files: [
{
dest: 'dist/built-123-a.js',
src: ['src/file2.js'],
extra: 456,
orig: {
dest: 'dist/built-123-a.js',
src: ['src/*2.js'],
extra: 456,
},
},
{
dest: 'dist/built-123-b.js',
src: ['src/file1.js', 'src/file2.js'],
extra: 789,
orig: {
src: ['src/*1.js', 'src/*2.js'],
dest: 'dist/built-123-b.js',
extra: 789,
},
},
],
},
'run:built_mapping': {
options: {a: 6, b: 11, c: 66, d: 9},
files: [
{
dest: 'foo/baz/file1.bar',
src: ['src/file1.js'],
extra: 123,
orig: {
expand: true,
cwd: grunt.config.get('mappings.cwd'),
src: ['*1.js', '*2.js'],
dest: grunt.config.get('mappings.dest'),
rename: grunt.config.get('run.built_mapping.rename'),
extra: 123,
},
},
{
dest: 'foo/baz/file2.bar',
src: ['src/file2.js'],
extra: 123,
orig: {
expand: true,
cwd: grunt.config.get('run.built_mapping.cwd'),
src: ['*1.js', '*2.js'],
dest: grunt.config.get('run.built_mapping.dest'),
rename: grunt.config.get('run.built_mapping.rename'),
extra: 123,
},
},
],
},
'run:long3_mapping': {
options: {a: 7, b: 11, c: 77, d: 9},
files: [
{
dest: 'foo/baz/file1.bar',
src: ['src/file1.js'],
extra: 123,
orig: {
expand: true,
cwd: grunt.config.get('mappings.cwd'),
src: ['*1.js', '*2.js'],
dest: grunt.config.get('mappings.dest'),
rename: grunt.config.get('mappings.rename'),
extra: 123,
},
},
{
dest: 'foo/baz/file2.bar',
src: ['src/file2.js'],
extra: 123,
orig: {
expand: true,
cwd: grunt.config.get('mappings.cwd'),
src: ['*1.js', '*2.js'],
dest: grunt.config.get('mappings.dest'),
rename: grunt.config.get('run.built_mapping.rename'),
extra: 123,
},
},
],
},
};
var assert = require('assert');
var difflet = require('difflet')({indent: 2, comment: true});
var test = function(name, fn) {
try {
fn();
} catch (err) {
grunt.log.subhead('Assertion Failure in ' + name);
console.log(difflet.compare(err.expected, err.actual));
throw new Error(err.message);
}
};
grunt.registerTask('test', 'Test file and option objects.', function() {
var key = 'run:' + this.nameArgs.replace(/^.*?:/, '');
var all = key === 'run:all';
var actual = all ? results : results[key];
var expected = all ? expecteds : expecteds[key];
test(this.name, function() {
assert.deepEqual(actual, expected, 'Actual should match expected.');
});
if (all) {
results = {};
} else {
delete results[key];
}
});
grunt.registerTask('test:counters', 'Test function execution order.', function() {
test(this.name, function() {
assert.equal(counters.length, counter + 1, 'Task functions should have run the correct number of times.');
var expected = [];
for (var i = 0; i < counters.length; i++) { expected.push(i); }
assert.deepEqual(counters, expected, 'Task functions should have actually executed in-order.');
});
});
grunt.registerTask('default', [
'run:no_files_or_options',
'test:no_files_or_options',
'run:dist/built.js',
'test:dist/built.js',
'run:dist/built1.js',
'test:dist/built1.js',
'run:built',
'test:built',
'run:long1',
'test:long1',
'run:long2',
'test:long2',
'run:long3',
'test:long3',
'run:built_mapping',
'test:built_mapping',
'run:long3_mapping',
'test:long3_mapping',
'run',
'test:all',
'test:counters',
]);
};
+51
View File
@@ -0,0 +1,51 @@
'use strict';
var namespace = require('../../lib/util/namespace.js');
exports.get = {
'no create': function(test) {
var obj = {a: {b: {c: 1, d: '', e: null, f: undefined, 'g.h.i': 2}}};
test.strictEqual(namespace.get(obj, 'a'), obj.a, 'should get immediate properties.');
test.strictEqual(namespace.get(obj, 'a.b'), obj.a.b, 'should get nested properties.');
test.strictEqual(namespace.get(obj, 'a.x'), undefined, 'should return undefined for nonexistent properties.');
test.strictEqual(namespace.get(obj, 'a.b.c'), 1, 'should return values.');
test.strictEqual(namespace.get(obj, 'a.b.d'), '', 'should return values.');
test.strictEqual(namespace.get(obj, 'a.b.e'), null, 'should return values.');
test.strictEqual(namespace.get(obj, 'a.b.f'), undefined, 'should return values.');
test.strictEqual(namespace.get(obj, 'a.b.g\\.h\\.i'), 2, 'literal backslash should escape period in property name.');
test.done();
},
'create': function(test) {
var obj = {a: 1};
test.strictEqual(namespace.get(obj, 'a', true), obj.a, 'should just return existing properties.');
test.strictEqual(namespace.get(obj, 'b', true), obj.b, 'should create immediate properties.');
test.strictEqual(namespace.get(obj, 'c.d.e', true), obj.c.d.e, 'should create nested properties.');
test.done();
}
};
exports.set = function(test) {
var obj = {};
test.strictEqual(namespace.set(obj, 'a', 1), 1, 'should return immediate property value.');
test.strictEqual(obj.a, 1, 'should set property value.');
test.strictEqual(namespace.set(obj, 'b.c.d', 1), 1, 'should return nested property value.');
test.strictEqual(obj.b.c.d, 1, 'should set property value.');
test.strictEqual(namespace.set(obj, 'e\\.f\\.g', 1), 1, 'literal backslash should escape period in property name.');
test.strictEqual(obj['e.f.g'], 1, 'should set property value.');
test.done();
};
exports.exists = function(test) {
var obj = {a: {b: {c: 1, d: '', e: null, f: undefined, 'g.h.i': 2}}};
test.ok(namespace.exists(obj, 'a'), 'immediate property should exist.');
test.ok(namespace.exists(obj, 'a.b'), 'nested property should exist.');
test.ok(namespace.exists(obj, 'a.b.c'), 'nested property should exist.');
test.ok(namespace.exists(obj, 'a.b.d'), 'nested property should exist.');
test.ok(namespace.exists(obj, 'a.b.e'), 'nested property should exist.');
test.ok(namespace.exists(obj, 'a.b.f'), 'nested property should exist.');
test.ok(namespace.exists(obj, 'a.b.g\\.h\\.i'), 'literal backslash should escape period in property name.');
test.equal(namespace.exists(obj, 'x'), false, 'nonexistent property should not exist.');
test.equal(namespace.exists(obj, 'a.x'), false, 'nonexistent property should not exist.');
test.equal(namespace.exists(obj, 'a.b.x'), false, 'nonexistent property should not exist.');
test.done();
};
+464
View File
@@ -0,0 +1,464 @@
'use strict';
// Test helpers.
function delay(fn) { setTimeout(fn, 10); }
var result = (function() {
var arr;
var push = function() { [].push.apply(arr, arguments); };
return {
reset: function() { arr = []; },
push: push,
pushTaskname: function() { push(this.name); },
get: function() { return arr; },
getJoined: function() { return arr.join(''); }
};
}());
var requireTask = require.bind(exports, '../../lib/util/task.js');
exports['new Task'] = {
'create': function(test) {
test.expect(1);
var tasklib = requireTask();
test.ok(tasklib.create() instanceof tasklib.Task, 'It should return a Task instance.');
test.done();
}
};
exports['Tasks'] = {
setUp: function(done) {
result.reset();
this.task = requireTask().create();
var task = this.task;
task.registerTask('nothing', 'Do nothing.', function() {});
done();
},
'Task#registerTask': function(test) {
test.expect(1);
var task = this.task;
test.ok('nothing' in task._tasks, 'It should register the passed task.');
test.done();
},
'Task#registerTask (alias)': function(test) {
test.expect(1);
var task = this.task;
task.registerTask('a', 'Push task name onto result.', result.pushTaskname);
task.registerTask('b', 'Push task name onto result.', result.pushTaskname);
task.registerTask('c d', 'Push task name onto result.', result.pushTaskname);
task.registerTask('y', ['a', 'b', 'c d']);
task.registerTask('z', ['a', 'b', 'nonexistent', 'c d']);
task.options({
error: function() {
result.push('!' + this.name);
},
done: function() {
test.strictEqual(result.getJoined(), 'abc d!z', 'The specified tasks should have run, in-order.');
test.done();
}
});
task.run('y', 'z').start();
},
'Task#isTaskAlias': function(test) {
test.expect(2);
var task = this.task;
task.registerTask('a', 'nothing', function() {});
task.registerTask('b', ['a']);
test.strictEqual(task.isTaskAlias('a'), false, 'It should not be an alias.');
test.strictEqual(task.isTaskAlias('b'), true, 'It should be an alias.');
test.done();
},
'Task#renameTask': function(test) {
test.expect(4);
var task = this.task;
task.renameTask('nothing', 'newnothing');
test.ok('newnothing' in task._tasks, 'It should rename the specified task.');
test.equal('nothing' in task._tasks, false, 'It should remove the previous task.');
test.doesNotThrow(function() { task.run('newnothing'); }, 'It should be accessible by its new name.');
test.throws(function() { task.run('nothing'); }, 'It should not be accessible by its previous name and throw an exception.');
test.done();
},
'Task#run (exception handling)': function(test) {
test.expect(4);
var task = this.task;
test.doesNotThrow(function() { task.run('nothing'); }, 'Registered tasks should be runnable.');
test.throws(function() { task.run('nonexistent'); }, 'Attempting to run unregistered tasks should throw an exception.');
task.options({
error: result.pushTaskname
});
test.doesNotThrow(function() { task.run('nonexistent'); }, 'It should not throw an exception because an error handler is defined.');
test.deepEqual(result.get(), [null], 'Non-nested tasks have a null name.');
test.done();
},
'Task#run (async failing)': function(test) {
test.expect(1);
var task = this.task;
var results = [];
task.registerTask('sync1', 'sync, gonna succeed', function() {});
task.registerTask('sync2', 'sync, gonna fail', function() {
return false;
});
task.registerTask('sync3', 'sync, gonna fail', function() {
return new Error('sync3: Error');
});
task.registerTask('sync4', 'sync, gonna fail', function() {
return new TypeError('sync4: TypeError');
});
task.registerTask('sync5', 'sync, gonna fail', function() {
throw new Error('sync5: Error');
});
task.registerTask('sync6', 'sync, gonna fail', function() {
throw new TypeError('sync6: TypeError');
});
task.registerTask('syncs', ['sync1', 'sync2', 'sync3', 'sync4', 'sync5', 'sync6']);
task.registerTask('async1', 'async, gonna succeed', function() {
var done = this.async();
setTimeout(function() {
done();
}, 1);
});
task.registerTask('async2', 'async, gonna fail', function() {
var done = this.async();
setTimeout(function() {
done(false);
}, 1);
});
task.registerTask('async3', 'async, gonna fail', function() {
var done = this.async();
setTimeout(function() {
done(new Error('async3: Error'));
}, 1);
});
task.registerTask('async4', 'async, gonna fail', function() {
var done = this.async();
setTimeout(function() {
done(new TypeError('async4: TypeError'));
}, 1);
});
task.registerTask('asyncs', ['async1', 'async2', 'async3', 'async4']);
task.options({
error: function(e) {
results.push({name: e.name, message: e.message});
},
done: function() {
test.deepEqual(results, [
{name: 'Error', message: 'Task "sync2" failed.'},
{name: 'Error', message: 'sync3: Error'},
{name: 'TypeError', message: 'sync4: TypeError'},
{name: 'Error', message: 'sync5: Error'},
{name: 'TypeError', message: 'sync6: TypeError'},
{name: 'Error', message: 'Task "async2" failed.'},
{name: 'Error', message: 'async3: Error'},
{name: 'TypeError', message: 'async4: TypeError'}
], 'The specified tasks should have run, in-order.');
test.done();
}
});
task.run('syncs', 'asyncs').start();
},
'Task#run (nested, exception handling)': function(test) {
test.expect(2);
var task = this.task;
task.registerTask('yay', 'Run a registered task.', function() {
test.doesNotThrow(function() { task.run('nothing'); }, 'Registered tasks should be runnable.');
});
task.registerTask('nay', 'Attempt to run an unregistered task.', function() {
test.throws(function() { task.run('nonexistent'); }, 'Attempting to run unregistered tasks should throw an exception.');
});
task.options({
done: test.done
});
task.run('yay', 'nay').start();
},
'Task#run (signatures, queue order)': function(test) {
test.expect(1);
var task = this.task;
task.registerTask('a', 'Push task name onto result.', result.pushTaskname);
task.registerTask('b', 'Push task name onto result.', result.pushTaskname);
task.registerTask('c', 'Push task name onto result.', result.pushTaskname);
task.registerTask('d', 'Push task name onto result.', result.pushTaskname);
task.registerTask('e', 'Push task name onto result.', result.pushTaskname);
task.registerTask('f g', 'Push task name onto result.', result.pushTaskname);
task.options({
done: function() {
test.strictEqual(result.getJoined(), 'abcdef g', 'The specified tasks should have run, in-order.');
test.done();
}
});
task.run('a').run('b', 'c').run(['d', 'e']).run('f g').start();
},
'Task#run (colon separated arguments)': function(test) {
test.expect(1);
var task = this.task;
task.registerTask('a', 'Push task name and args onto result.', function(x, y) { result.push([this.nameArgs, 1, this.name, x, y]); });
task.registerTask('a:b', 'Push task name and args onto result.', function(x, y) { result.push([this.nameArgs, 2, this.name, x, y]); });
task.registerTask('a:b:c', 'Push task name and args onto result.', function(x, y) { result.push([this.nameArgs, 3, this.name, x, y]); });
task.options({
done: function() {
test.deepEqual(result.get(), [
['a', 1, 'a', undefined, undefined],
['a:x', 1, 'a', 'x', undefined],
['a:x:c', 1, 'a', 'x', 'c'],
['a:b ', 1, 'a', 'b ', undefined],
['a: b:c', 1, 'a', ' b', 'c'],
['a:x\\:y:\\:z\\:', 1, 'a', 'x:y', ':z:'],
['a:b', 2, 'a:b', undefined, undefined],
['a:b:x', 2, 'a:b', 'x', undefined],
['a:b:x:y', 2, 'a:b', 'x', 'y'],
['a:b:c ', 2, 'a:b', 'c ', undefined],
['a:b:x\\:y:\\:z\\:', 2, 'a:b', 'x:y', ':z:'],
['a:b:c', 3, 'a:b:c', undefined, undefined],
['a:b:c: d', 3, 'a:b:c', ' d', undefined],
], 'Named tasks should be called as-specified if possible, and arguments should be passed properly.');
test.done();
}
});
task.run(
'a', 'a:x', 'a:x:c', 'a:b ', 'a: b:c', 'a:x\\:y:\\:z\\:',
'a:b', 'a:b:x', 'a:b:x:y', 'a:b:c ', 'a:b:x\\:y:\\:z\\:',
'a:b:c', 'a:b:c: d'
).start();
},
'Task#run (nested tasks, queue order)': function(test) {
test.expect(1);
var task = this.task;
task.registerTask('a', 'Push task name onto result and run other tasks.', function() { result.push(this.name); task.run('b', 'e'); });
task.registerTask('b', 'Push task name onto result and run other tasks.', function() { result.push(this.name); task.run('c', 'd d'); });
task.registerTask('c', 'Push task name onto result.', result.pushTaskname);
task.registerTask('d d', 'Push task name onto result.', result.pushTaskname);
task.registerTask('e', 'Push task name onto result and run other tasks.', function() { result.push(this.name); task.run('f f'); });
task.registerTask('f f', 'Push task name onto result.', result.pushTaskname);
task.registerTask('g', 'Push task name onto result.', result.pushTaskname);
task.options({
done: function() {
test.strictEqual(result.getJoined(), 'abcd def fg', 'The specified tasks should have run, in-order.');
test.done();
}
});
task.run('a', 'g').start();
},
'Task#run (async, nested tasks, queue order)': function(test) {
test.expect(1);
var task = this.task;
task.registerTask('a', 'Push task name onto result and run other tasks.', function() { result.push(this.name); task.run('b', 'e'); delay(this.async()); });
task.registerTask('b', 'Push task name onto result and run other tasks.', function() { result.push(this.name); delay(this.async()); task.run('c', 'd d'); });
task.registerTask('c', 'Push task name onto result.', result.pushTaskname);
task.registerTask('d d', 'Push task name onto result.', result.pushTaskname);
task.registerTask('e', 'Push task name onto result and run other tasks.', function() { delay(this.async()); result.push(this.name); task.run('f f'); });
task.registerTask('f f', 'Push task name onto result and run other tasks.', function() { this.async()(); result.push(this.name); task.run('g'); });
task.registerTask('g', 'Push task name onto result.', result.pushTaskname);
task.registerTask('h', 'Push task name onto result.', result.pushTaskname);
task.options({
done: function() {
test.strictEqual(result.getJoined(), 'abcd def fgh', 'The specified tasks should have run, in-order.');
test.done();
}
});
task.run('a', 'h').start();
},
'Task#current': function(test) {
test.expect(8);
var task = this.task;
test.deepEqual(task.current, {}, 'Should start empty.');
task.registerTask('a', 'Sample task.', function() {
test.equal(task.current, this, 'This and task.current should be the same object.');
test.equal(task.current.nameArgs, 'a:b:c', 'Should be task name + args, as-specified.');
test.equal(task.current.name, 'a', 'Should be just the task name, no args.');
test.equal(typeof task.current.async, 'function', 'Should be a function.');
test.deepEqual(task.current.args, ['b', 'c'], 'Should be an array of args.');
test.deepEqual(task.current.flags, {b: true, c: true}, 'Should be a map of flags.');
});
task.options({
done: function() {
test.deepEqual(task.current, {}, 'Should be empty again once tasks are done.');
test.done();
}
});
task.run('a:b:c').start();
},
'Task#clearQueue': function(test) {
test.expect(1);
var task = this.task;
task.registerTask('a', 'Push task name onto result.', result.pushTaskname);
task.registerTask('b', 'Push task name onto result.', result.pushTaskname);
task.registerTask('c', 'Clear the queue.', function() {
result.push(this.name);
task.clearQueue().run('f');
});
task.registerTask('d', 'Push task name onto result.', result.pushTaskname);
task.registerTask('e', 'Push task name onto result.', result.pushTaskname);
task.registerTask('f', 'Push task name onto result.', result.pushTaskname);
task.options({
done: function() {
test.strictEqual(result.getJoined(), 'abcf', 'The specified tasks should have run, in-order.');
test.done();
}
});
task.run('a', 'b', 'c', 'd', 'e').start();
},
'Task#mark': function(test) {
test.expect(1);
var task = this.task;
task.registerTask('a', 'Explode.', function() {
throw task.taskError('whoops.');
});
task.registerTask('b', 'This task should never run.', result.pushTaskname);
task.registerTask('c', 'This task should never run.', result.pushTaskname);
task.registerTask('d', 'Push task name onto result.', result.pushTaskname);
task.registerTask('e', 'Explode.', function() {
throw task.taskError('whoops.');
});
task.registerTask('f', 'This task should never run.', result.pushTaskname);
task.registerTask('g', 'Push task name onto result.', result.pushTaskname);
task.registerTask('h', 'Push task name onto result.', result.pushTaskname);
task.registerTask('i', 'Explode.', function() {
throw task.taskError('whoops.');
});
task.registerTask('j', 'Run a task and push task name onto result.', function() {
task.run('k');
result.push(this.name);
});
task.registerTask('k', 'Explode.', function() {
throw task.taskError('whoops.');
});
task.registerTask('l', 'This task should never run.', result.pushTaskname);
task.registerTask('m', 'Push task name onto result.', result.pushTaskname);
task.registerTask('n', 'Run a task and push task name onto result.', function() {
task.run('o');
result.push(this.name);
});
task.registerTask('o', 'Explode.', function() {
throw task.taskError('whoops.');
});
task.registerTask('p', 'Push task name onto result.', result.pushTaskname);
task.options({
error: function() {
result.push('!' + this.name);
task.clearQueue({untilMarker: true});
},
done: function() {
test.strictEqual(result.getJoined(), '!ad!egh!ij!kmn!op', 'The specified tasks should have run, in-order.');
test.done();
}
});
task.run('a', 'b', 'c').mark().run('d', 'e', 'f').mark().run('g', 'h', 'i').mark().run('j', 'l').mark().run('m', 'n').mark().run('p').mark().start();
},
'Task#requires': function(test) {
test.expect(1);
var task = this.task;
task.registerTask('notrun', 'This task is never run.', function() {});
task.registerTask('a a', 'Push task name onto result, but fail.', function() {
result.push(this.name);
return false;
});
task.registerTask('b', 'Push task name onto result, but fail.', function() {
var done = this.async();
delay(function() { done(false); });
result.push(this.name);
});
task.registerTask('c', 'Succeed.', result.pushTaskname);
task.registerTask('d', 'Succeed.', result.pushTaskname);
task.registerTask('e', 'Succeed because all required tasks ran and succeeded.', function() {
task.requires('c', 'd');
result.push(this.name);
});
task.registerTask('x', 'Fail because a required task never ran.', function() {
task.requires('c', 'notrun', 'd');
result.push(this.name);
});
task.registerTask('y', 'Fail because a synchronous required task has failed.', function() {
task.requires('a a', 'c', 'd');
result.push(this.name);
});
task.registerTask('z', 'Fail because an asynchronous required task has failed.', function() {
task.requires('b', 'c', 'd');
result.push(this.name);
});
task.options({
error: function() {
result.push('!' + this.name);
},
done: function() {
test.strictEqual(result.getJoined(), 'a a!a ab!bcde!x!y!z', 'Tasks whose requirements have failed or are missing should not run.');
test.done();
}
});
task.run('a a', 'b', 'c', 'd', 'e', 'x', 'y', 'z').start();
}
};
exports['Task#parseArgs'] = {
setUp: function(done) {
var task = requireTask().create();
this.parseTest = function() {
return task.parseArgs(arguments);
};
done();
},
'arguments': function(test) {
test.expect(4);
test.deepEqual(this.parseTest('foo bar'), ['foo bar'], 'single argument should be converted to array.');
test.deepEqual(this.parseTest('foo bar: aa : bb '), ['foo bar: aa : bb '], 'single argument should be converted to array.');
test.deepEqual(this.parseTest('foo bar', 'baz', 'test 1 2 3'), ['foo bar', 'baz', 'test 1 2 3'], 'arguments should be converted to array.');
test.deepEqual(this.parseTest('foo bar', 'baz:x y z', 'test 1 2 3: 4 : 5'), ['foo bar', 'baz:x y z', 'test 1 2 3: 4 : 5'], 'arguments should be converted to array.');
test.done();
},
'array': function(test) {
test.expect(1);
test.deepEqual(this.parseTest(['foo bar', 'baz:x y z', 'test 1 2 3: 4 : 5']), ['foo bar', 'baz:x y z', 'test 1 2 3: 4 : 5'], 'passed array should be used.');
test.done();
},
'object': function(test) {
test.expect(1);
var obj = {};
test.deepEqual(this.parseTest(obj), [obj], 'single object should be returned as array.');
test.done();
},
'nothing': function(test) {
test.expect(1);
test.deepEqual(this.parseTest(), [], 'should return an empty array if nothing passed.');
test.done();
}
};
exports['Task#splitArgs'] = {
setUp: function(done) {
this.task = requireTask().create();
done();
},
'arguments': function(test) {
test.expect(9);
var task = this.task;
test.deepEqual(task.splitArgs(), [], 'missing items = empty array.');
test.deepEqual(task.splitArgs(''), [], 'missing items = empty array.');
test.deepEqual(task.splitArgs('a'), ['a'], 'single item should be parsed.');
test.deepEqual(task.splitArgs('a:b:c'), ['a', 'b', 'c'], 'mutliple items should be parsed.');
test.deepEqual(task.splitArgs('a::c'), ['a', '', 'c'], 'missing items should be parsed.');
test.deepEqual(task.splitArgs('::'), ['', '', ''], 'missing items should be parsed.');
test.deepEqual(task.splitArgs('\\:a:\\:b\\::c\\:'), [':a', ':b:', 'c:'], 'escaped colons should be unescaped.');
test.deepEqual(task.splitArgs('a\\\\:b\\\\:c'), ['a\\', 'b\\', 'c'], 'escaped backslashes should not be parsed.');
test.deepEqual(task.splitArgs('\\:a\\\\:\\\\\\:b\\:\\\\:c\\\\\\:\\\\'), [':a\\', '\\:b:\\', 'c\\:\\'], 'please avoid doing this, ok?');
test.done();
}
};