text: /*!
   * Nodeunit
   * Copyright (c) 2010 Caolan McMahon
   * MIT Licensed
   */
  
  /**
   * Module dependencies
   */
  
  var nodeunit = require('../nodeunit'),
      utils = require('../utils'),
      fs = require('fs'),
      path = require('path'),
      async = require('../../deps/async'),
      AssertionError = require('../assert').AssertionError,
      child_process = require('child_process'),
      ejs = require('ejs');
  
  
  /**
   * Reporter info string
   */
  
  exports.info = "jUnit XML test reports";
  
  
  /**
   * Ensures a directory exists using mkdir -p.
   *
   * @param {String} path
   * @param {Function} callback
   * @api private
   */
  
  var ensureDir = function (path, callback) {
      var mkdir = child_process.spawn('mkdir', ['-p', path]);
      mkdir.on('error', function (err) {
          callback(err);
          callback = function(){};
      });
      mkdir.on('exit', function (code) {
          if (code === 0) callback();
          else callback(new Error('mkdir exited with code: ' + code));
      });
  };
  
  
  /**
   * Returns absolute version of a path. Relative paths are interpreted
   * relative to process.cwd() or the cwd parameter. Paths that are already
   * absolute are returned unaltered.
   *
   * @param {String} p
   * @param {String} cwd
   * @return {String}
   * @api public
   */
  
  var abspath = function (p, /*optional*/cwd) {
      if (p[0] === '/') return p;
      cwd = cwd || process.cwd();
      return path.normalize(path.resolve(p));
  };
  
  
  /**
   * Run all tests within each module, reporting the results to the command-line,
   * then writes out junit-compatible xml documents.
   *
   * @param {Array} files
   * @api public
   */
  
  exports.run = function (files, opts, callback) {
      if (!opts.output) {
          console.error(
              'Error: No output directory defined.\n' +
              '\tEither add an "output" property to your nodeunit.json config ' +
              'file, or\n\tuse the --output command line option.'
          );
          return;
      }
      opts.output = abspath(opts.output);
      var error = function (str) {
          return opts.error_prefix + str + opts.error_suffix;
      };
      var ok    = function (str) {
          return opts.ok_prefix + str + opts.ok_suffix;
      };
      var bold  = function (str) {
          return opts.bold_prefix + str + opts.bold_suffix;
      };
  
      var start = new Date().getTime();
      var paths = files.map(function (p) {
          return path.resolve(p);
      });
  
      var modules = {}
      var curModule;
  
      nodeunit.runFiles(paths, {
          testspec: opts.testspec,
          testFullSpec: opts.testFullSpec,
          moduleStart: function (name) {
              curModule = {
                  errorCount: 0,
                  failureCount: 0,
                  tests: 0,
                  testcases: [],
                  name: name
              };
              modules[name] = curModule;
          },
          testDone: function (name, assertions) {
              var testcase = {name: name};
              for (var i=0; i<assertions.length; i++) {
                  var a = assertions[i];
                  if (a.failed()) {
                      a = utils.betterErrors(a);
                      testcase.failure = {
                          message: a.message,
                          backtrace: a.error.stack
                      };
  
                      if (a.error instanceof AssertionError) {
                          curModule.failureCount++;
                      }
                      else {
                          curModule.errorCount++;
                      }
                      break;
                  }
              }
              curModule.tests++;
              curModule.testcases.push(testcase);
          },
          done: function (assertions) {
              var end = new Date().getTime();
              var duration = end - start;
  
              ensureDir(opts.output, function (err) {
                  var tmpl = __dirname + "/../../share/junit.xml.ejs";
                  fs.readFile(tmpl, function (err, data) {
                      if (err) throw err;
                      var tmpl = data.toString();
                      for(var k in modules) {
                          var module = modules[k];
                          var rendered = ejs.render(tmpl, {
                              locals: {suites: [module]}
                          });
                          var filename = path.resolve(
                              opts.output,
                              module.name + '.xml'
                          );
                          console.log('Writing ' + filename);
                          fs.writeFileSync(filename, rendered, 'utf8');
                      }
                      if (assertions.failures()) {
                          console.log(
                              '\n' + bold(error('FAILURES: ')) +
                              assertions.failures() + '/' +
                              assertions.length + ' assertions failed (' +
                              assertions.duration + 'ms)'
                      	);
                      }
                      else {
                          console.log(
                              '\n' + bold(ok('OK: ')) + assertions.length +
                              ' assertions (' + assertions.duration + 'ms)'
                          );
                      }
                      
                      if (callback) callback(assertions.failures() ? new Error('We have got test failures.') : undefined);
                  });
              });
          }
      });
  }
  