Permalink
Browse files

[wip] Tests

  • Loading branch information...
filipediasf committed Jan 3, 2013
2 parents c003792 + 5e578fc commit 6f6276c08d6550f77476cfeddb6ff09038322972
Showing with 575 additions and 85 deletions.
  1. +2 −4 .gitignore
  2. +56 −1 .npmignore
  3. +49 −29 README.md
  4. +25 −12 index.js
  5. +394 −27 test/core.js
  6. +2 −2 test/helpers/tasks/callback.js
  7. +1 −1 test/tasks/cp.js
  8. +39 −2 test/tasks/init.js
  9. +5 −5 test/tasks/mkdir.js
  10. +2 −2 test/tasks/run.js
View
@@ -41,7 +41,7 @@ Session.vim
# Sublime TextEditor #
######################
-/*.sublime-project
+*.sublime-project
# Eclipse #
######################
@@ -55,6 +55,4 @@ npm-debug.*
# Project specific #
######################
-components
-vendor
-test/tmp
+/test/tmp
View
@@ -1,3 +1,58 @@
+# Compiled source #
+###################
+*.com
+*.class
+*.dll
+*.exe
+*.o
+*.so
+
+# OS generated files #
+######################
+.DS_Store*
+ehthumbs.db
+Icon?
+Thumbs.db
+Desktop.ini
+.Spotlight-V100
+.Trashes
+._*
+
+# NetBeans #
+############
+nbsettings/
+nbproject/
+nbbuild/
+nbdist/
+nbactions.xml
+nb-configuration.xml
+
+# Textmate #
+############
+*.tmproj
+*.tmproject
+tmtags
+
+# VIM #
+#######
+.*.sw[a-z]
+*.un~
+Session.vim
+
+# Sublime TextEditor #
+######################
+*.sublime-project
+
+# Eclipse #
+######################
+/.project
+/.settings
+
+# Node #
+######################
+node_modules
+npm-debug.*
+
# Project specific #
######################
-test
+/test
View
@@ -27,22 +27,23 @@ An automaton task is a simple object, describing what the task will do.
For illustration purposes, here's a simple `autofile` that just creates a folder and copies a file into it:
-```javascript
+```js
var myTask = {
tasks: [
{
task: 'mkdir',
- description: 'create the project root folder',
+ description: 'Create the project root folder',
options: {
- dir: 'some_dir'
+ dirs: ['some_dir']
}
},
{
task: 'cp',
- description: 'copy some file',
+ description: 'Copy some file',
options: {
- src: 'some_file',
- dst: 'some_dir/dest_file'
+ files: {
+ 'some_file': 'some_dir/dest_file'
+ }
}
}
]
@@ -53,31 +54,37 @@ module.exports = myTask;
To illustrate most of the capabilities of Automaton, here's a complete `autofile` with comments along the file:
-```javascript
+```js
var task = {
// This id is not mandatory but,
// if you want to use this task in other tasks,
- // must be provided and unique
+ // must be provided and should be unique.
id: 'example_task',
// A user friendly name,
- // just for reference, not mandatory
+ // just for reference, not mandatory.
name: 'Example task',
- // also not mandatory
+ // Also not mandatory
author: 'Indigo United',
+ // Description is not mandatory,
+ // but can be used to give a base description for the task.
+ // Can be a string or a function that receives the passed options
+ // and returns a string.
+ description: 'My example task',
+
// Filter is not mandatory,
// but can be used to perform some operation
- // on the options before running the subtasks
+ // on the options before running the subtasks.
filter: function (options, next) {
- // You can change existing options
+ // You can change existing options.
options.dir2 = options.dir2 + '_indigo';
// and even define additional options.
// In this case we're defining
// a `dir3` option,
- // which will be used by one of the subtasks
+ // which will be used by one of the subtasks.
options.dir3 = 'united';
next();
@@ -86,7 +93,8 @@ var task = {
// This is also optional,
// but useful if you want the automaton
// to automatically check for required options,
- // and some additional features, check below
+ // and some additional features
+ // Check below for more info.
options: {
dir1: {
// Option description is not mandatory
@@ -108,16 +116,16 @@ var task = {
},
// A list of subtasks that will run
- // when the example_task runs
+ // when the example_task runs.
tasks: [
{
task: 'mkdir',
- description: 'create the root and second folder',
+ description: 'Create the root and second folder',
options: {
// the option below
// will have its placeholders replaced by
- // the value that it receives
- dir: '{{dir1}}/{{dir2}}'
+ // the value that it receives.
+ dirs: ['{{dir1}}/{{dir2}}']
}
},
{
@@ -128,32 +136,37 @@ var task = {
// In this case, we even used a placeholder,
// allowing us to skip this subtask depending
// on the run_all option. Of course, you have
- // just setted it to something like `false`
+ // just setted it to something like `false`.
on: '{{run_all}}',
// Description messages can be generated according to the options
- // by using a function instead of a static description
+ // by using a function instead of a static description.
description: function (opt) {
return 'Creating ' + opt.dir1 + '/' + opt.dir2 + '/' + opt.dir3
},
options: {
- dir: '{{dir1}}/{{dir2}}/{{dir3}}'
+ dirs: ['{{dir1}}/{{dir2}}/{{dir3}}']
}
},
{
- // if you find yourself looking
+ // If you find yourself looking
// for something a bit more custom,
- // you can just provide a function as the task
+ // you can just provide a function as the task.
task : function (opt, next) {
// opt is a list of the options
- // provided to the task
+ // provided to the task.
console.log('I can do whatever I want', opt);
- // when the task is done,
+ // When the task is done,
// you just call next(),
// not like the MTV show, though…
// (- -')
next();
+ },
+ // The 'on' attribute can also be a function
+ // for more complex cases.
+ on: function (opt) {
+ return !!opt.run_all;
}
}
]
@@ -175,6 +188,7 @@ Please note that placeholders can be escaped with backslashes:
- **chmod:** Change mode of files
- **cp:** Copy files and directories
+- **mv:** Move files and directories
- **mkdir:** Make directories recursively
- **rm:** Remove several files or directories
- **symlink:** Create symlink
@@ -213,18 +227,24 @@ In order to run an `autofile`, you simply run `automaton`. This will look for `a
### Node.js
-Automaton can also be used as a node module. Here's a quick example of its usage:
+Automaton can also be used programatically as a node module. Here's a quick example of its usage:
```javascript
-var automaton = require('automaton');
+var automaton = require('automaton').create();
// Since autofiles are node modules themselves,
// you can just require them
// Note that you could have instead declared
-// the module inline, in JSON
+// the module inline, in JSON.
var myTask = require('my_autofile');
-automaton.run(myTask, { 'some_option': 'that is handy' });
+automaton.run(myTask, { 'some_option': 'that is handy' }, function (err) {
+ if (err) {
+ console.log('Something went wrong: ' + err.message);
+ } else {
+ console.log('All done!');
+ }
+});
```
## Acknowledgements
View
@@ -142,6 +142,10 @@ var Automaton = d.Class.declare({
// function to handle the completion of the task
handle = function (err) {
+ if (utils.lang.isString(err)) {
+ err = new Error(err);
+ }
+
if (err) {
this._logger.errorln(err.message);
}
@@ -160,7 +164,8 @@ var Automaton = d.Class.declare({
try {
batch = this._batchTask({
task: task,
- options: $options
+ options: $options,
+ depth: 1
});
} catch (e) {
return handle(e);
@@ -192,12 +197,13 @@ var Automaton = d.Class.declare({
if (utils.lang.isString(def.task)) {
this._assertTaskLoaded(def.task, true);
def.task = this._tasks[def.task];
+ } else if (def.depth === 1) {
+ this._validateTask(def.task);
}
def.options = def.options || {};
def.parentOptions = def.parentOptions || {};
def.description = def.description || def.task.description;
- def.depth = def.depth || 1;
// fill in the options with default values where the option was not provided
for (option in def.task.options) {
@@ -246,10 +252,8 @@ var Automaton = d.Class.declare({
this._reportNextTask(this._createTaskDefinition(currentSubtask, def));
currentSubtask.task.call(this._context, def.options, next);
}.$bind(this));
- // it's not a function, then it must be another task, check if it is loaded, and batch it
- } else if (utils.lang.isString(currentSubtask.task)) {
- this._assertTaskLoaded(currentSubtask.task);
-
+ // it's not a function, then it must be another task
+ } else {
subtaskBatch = this._batchTask(this._createTaskDefinition(currentSubtask, def));
batch.push(function (subtask, subtaskBatch, next) {
// skip task if disabled
@@ -376,17 +380,22 @@ var Automaton = d.Class.declare({
* @param {Object} task The task
*/
_validateTask: function (task) {
- var taskId = task.id || 'unknown',
+ var taskId,
x,
- curr;
+ curr,
+ length;
this._assertIsObject(task, 'Expected task to be an object', true);
if (task.id !== undefined) {
this._assertIsString(task.id, 'Expected id to be a string', true);
if (!task.id) {
this._throwError('Task id cannot be empty.', true);
}
+ taskId = task.id;
+ } else {
+ taskId = 'unknown';
}
+
if (task.name !== undefined) {
this._assertIsString(task.name, 'Expected name to be a string in \'' + taskId + '\' task', true);
}
@@ -404,24 +413,28 @@ var Automaton = d.Class.declare({
for (x in task.options) {
curr = task.options[x];
this._assertIsObject(curr, 'Expected options definition to be an object in \'' + taskId + '\' task', true);
+ if (curr.description !== undefined) {
+ this._assertIsString(curr.description, 'Expected \'' + x + '\' option description to be a string in \'' + taskId + '\' task', true);
+ }
}
} else {
task.options = {};
}
this._assertIsArray(task.tasks, 'Expected subtasks to be an array in \'' + taskId + '\' task', true);
- for (x = 0; x < task.tasks; ++x) {
+ length = task.tasks.length;
+ for (x = 0; x < length; ++x) {
curr = task.tasks[x];
- this._assertIsObject('Expected subtask at index \'' + x + '\' to be an object', true);
+ this._assertIsObject(curr, 'Expected subtask at index \'' + x + '\' to be an object', true);
if (utils.lang.isObject(curr.task)) {
- this._assertIsValidTask(curr.task);
+ this._validateTask(curr.task);
} else {
if (!utils.lang.isString(curr.task) && !utils.lang.isFunction(curr.task)) {
this._throwError('Expected subtask at index \'' + x + '\' to be a string, a function or a task object in \'' + taskId + '\' task', true);
}
- if (curr.description !== undefined && !utils.lang.isString(task.description) && !utils.lang.isFunction(task.description)) {
+ if (curr.description !== undefined && !utils.lang.isString(curr.description) && !utils.lang.isFunction(curr.description)) {
this._throwError('Expected subtask description at index \'' + x + '\' to be a string or a function in \'' + taskId + '\' task', true);
}
if (curr.options !== undefined) {
Oops, something went wrong.

0 comments on commit 6f6276c

Please sign in to comment.