/*
 * Jake JavaScript build tool
 * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/

var path = require('path')
  , fs = require('fs')
  , exec = require('child_process').exec
  , currDir = process.cwd();

/**
  @name jake
  @namespace jake
*/
/**
  @name jake.TestTask
  @constructor
  @description Instantiating a TestTask creates a number of Jake
  Tasks that make running tests for your software easy.

  @param {String} name The name of the project
  @param {Function} definition Defines the list of files containing the tests,
  and the name of the namespace/task for running them. Will be executed on the
  instantiated TestTask (i.e., 'this', will be the TestTask instance), to set
  the various instance-propertiess.

  @example
  var t = new jake.TestTask('bij-js', function () {
    this.testName = 'testSpecial';
    this.testFiles.include('test/**');
  });

 */
var TestTask = function (name, definition) {
  var self = this;

  /**
    @name jake.TestTask#testNam
    @public
    @type {String}
    @description The name of the namespace to place the tests in, and
    the top-level task for running tests. Defaults to "test"
   */
  this.testName = 'test';

  /**
    @name jake.TestTask#testFiles
    @public
    @type {jake.FileList}
    @description The list of files containing tests to load
   */
  this.testFiles = new jake.FileList();

  /**
    @name jake.TestTask#showDescription
    @public
    @type {Boolean}
    @description Show the created task when doing Jake -T
   */
  this.showDescription = true;

  if (typeof definition == 'function') {
    definition.call(this);
  }

  if (this.showDescription) {
    desc('Run the tests for ' + name);
  }
  task(this.testName, function () {
    var t = jake.Task[self.testName + ':run'];
    t.invoke.apply(t, arguments);
  }, {async: true});

  namespace(self.testName, function () {

    task('run', function (pat) {
      var p = pat || '.*'
        , re
        , testFiles;

      // Don't nest; make a top-level namespace. Don't want
      // re-calling from inside to nest infinitely
     jake.currentNamespace = jake.defaultNamespace;

      re = new RegExp(pat);
      testFiles = self.testFiles.toArray().filter(function (f) {
        return (re).test(f);
      });

      // Create a namespace for all the testing tasks to live in
      namespace(self.testName + 'Exec', function () {
        // Each test will be a prereq for the dummy top-level task
        var prereqs = []
        // Continuation to pass to the async tests, wrapping `continune`
          , next = function () {
              complete();
            }
        // Create the task for this test-function
          , createTask = function (name, action) {
              // If the test-function is defined with a continuation
              // param, flag the task as async
              var isAsync = !!action.length;

              // Define the actual namespaced task with the name, the
              // wrapped action, and the correc async-flag
              task(name, createAction(name, action), {
                async: isAsync
              });
            }
        // Used as the action for the defined task for each test.
          , createAction = function (n, a) {
              // A wrapped function that passes in the `next` function
              // for any tasks that run asynchronously
              return function () {
                var cb
                  , msg;
                if (a.length) {
                  cb = next;
                }
                if (!(n == 'before' || n == 'after' ||
                    /_beforeEach$/.test(n) || /_afterEach$/.test(n))) {
                  if (n.toLowerCase().indexOf('test') === 0) {
                    msg = n;
                  }
                  else {
                    msg = 'test ' + n;
                  }
                  jake.logger.log(n);
                }
                // 'this' will be the task when action is run
                return a.call(this, cb);
              };
            }
          // Dummy top-level task for everything to be prereqs for
          , topLevel;

        // Pull in each test-file, and iterate over any exported
        // test-functions. Register each test-function as a prereq task
        testFiles.forEach(function (file) {
          var exp = require(path.join(currDir, file))
            , name
            , action
            , isAsync;

          // Create a namespace for each filename, so test-name collisions
          // won't be a problem
          namespace(file, function () {
            var testPrefix = self.testName + 'Exec:' + file + ':'
              , testName;
            // Dummy task for displaying file banner
            testName = '*** Running ' + file + ' ***';
            prereqs.push(testPrefix + testName);
            createTask(testName, function () {});

            // 'before' setup
            if (typeof exp.before == 'function') {
              prereqs.push(testPrefix + 'before');
              // Create the task
              createTask('before', exp.before);
            }

            // Walk each exported function, and create a task for each
            for (var p in exp) {
              if (p == 'before' || p == 'after' ||
                  p == 'beforeEach' || p == 'afterEach') {
                continue;
              }

              if (typeof exp.beforeEach == 'function') {
                prereqs.push(testPrefix + p + '_beforeEach');
                // Create the task
                createTask(p + '_beforeEach', exp.beforeEach);
              }

              // Add the namespace:name of this test to the list of prereqs
              // for the dummy top-level task
              prereqs.push(testPrefix + p);
              // Create the task
              createTask(p, exp[p]);

              if (typeof exp.afterEach == 'function') {
                prereqs.push(testPrefix + p + '_afterEach');
                // Create the task
                createTask(p + '_afterEach', exp.afterEach);
              }
            }

            // 'after' teardown
            if (typeof exp.after == 'function') {
              prereqs.push(testPrefix + 'after');
              // Create the task
              createTask('after', exp.after);
            }

          });
        });

        // Create the dummy top-level task. When calling a task internally
        // with `invoke` that is async (or has async prereqs), have to listen
        // for the 'complete' event to know when it's done
        topLevel = task('__top__', prereqs);
        topLevel.addListener('complete', function () {
          jake.logger.log('All tests ran successfully');
          complete();
        });

        topLevel.invoke(); // Do the thing!
      });


    }, {async: true});
  });


};

jake.TestTask = TestTask;
exports.TestTask = TestTask;


@@ -2267,120 +2267,47 @@
 me, 
-function () %7B%0A    var t = jake.Task%5Bself.testName + ':run'%5D;%0A    t.invoke.apply(t, arguments);%0A  %7D, %7Basync: true
+%5Bself.testName + ':run'%5D, function () %7B
 %7D);%0A
@@ -2349,16 +2349,16 @@
 n () %7B%0A%0A
-
     task
@@ -2364,16 +2364,31 @@
 k('run',
+ %7Basync: true%7D,
  functio
@@ -7286,28 +7286,12 @@
 );%0A%0A
-%0A
     
-%7D, %7Basync: true
 %7D);%0A

Fix async bug with completing TestTask