<commit_before>/*global describe, beforeEach, it*/
'use strict';

var assert  = require('yeoman-generator').assert;
var path    = require('path');
var helpers = require('yeoman-generator').test;

var basicExpected = [
  '.bowerrc',
  '.gitignore',
  'bower.json',
  'app.js',
  'public/img',
  'public/components',
  'public/js',
  'package.json',
  'routes/index.js',
  'routes/user.js',
  'bin/www'
];

var MVCExpected = [
  '.bowerrc',
  '.gitignore',
  'bower.json',
  'app.js',
  'public/img',
  'public/components',
  'public/js',
  'public/css',
  'package.json',
  'config/config.js',
  'config/express.js',
  'app/controllers',
  'app/controllers/home.js',
  'app/models',
  'app/views'
];

var appFiles = {
  basic: basicExpected,
  mvc: MVCExpected
};

var toCoffeeFileArray = function (fileArray) {
  var newArray = [];
  for (var i in fileArray) {
    if (fileArray[i] === 'app.js') {
      newArray.push(fileArray[i]);
    } else {
      newArray.push(fileArray[i].replace(/(.*?)\.js$/, '$1.coffee'));
    }
  }

  return newArray;
};

var runGenerationTest = function (extraFiles, type, engine, preprocessor, coffee, database, buildTool, callback) {
  var expectedFiles;
  this.app.options[type] = true;
  this.app.options['skip-install'] = true;
  this.app.options.database = database;
  this.app.options.viewEngine = engine;
  this.app.options.cssPreprocessor = preprocessor;
  this.app.options.coffee = coffee;
  this.app.options.buildTool = buildTool;
  expectedFiles = extraFiles.concat(appFiles[type]);
  if (preprocessor === 'sass') {
    expectedFiles.push('public/css/style.scss');
  } else if (preprocessor === 'node-sass') {
    expectedFiles.push('public/css/style.scss');
  } else if (preprocessor === 'less') {
    expectedFiles.push('public/css/style.less');
  } else {
    expectedFiles.push('public/css/style.css');
  }
  if (coffee) {
    expectedFiles = toCoffeeFileArray(expectedFiles);
  }
  expectedFiles.push(buildTool === 'grunt' ? 'Gruntfile.js' : 'gulpfile.js');
  this.app.run({}, function () {
    assert.file(expectedFiles);
    callback();
  });
};

describe('Express generator', function () {
  beforeEach(function (done) {
    helpers.testDirectory(path.join(__dirname, 'temp'), function (err) {
      if (err) {
        return done(err);
      }

      this.app = helpers.createGenerator('express:app', [
        '../../app'
      ]);
      done();
    }.bind(this));
  });

  describe('Basic generator with Jade', function () {
    var expected = [
      'views/index.jade',
      'views/layout.jade',
      'views/error.jade'
    ];

    it('creates expected files', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'jade', 'none', false, 'none', 'grunt', done);
    });

    it('works with coffee', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'jade', 'none', true, 'none', 'grunt', done);
    });

    it('works with gulp', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'jade', 'none', false, 'none', 'gulp', done);
    });

    it('works with coffee and gulp', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'jade', 'none', true, 'none', 'gulp', done);
    });

    it('creates expected files with sass', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'jade', 'sass', false, 'none', 'grunt', done);
    });

    it('works with coffee and sass', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'jade', 'sass', false, 'none', 'grunt', done);
    });

    it('works with gulp and sass', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'jade', 'sass', false, 'none', 'gulp', done);
    });

    it('works with coffee and gulp and sass', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'jade', 'sass', false, 'none', 'gulp', done);
    });

    it('creates expected files with node-sass', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'jade', 'node-sass', false, 'none', 'grunt', done);
    });

    it('works with coffee and node-sass', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'jade', 'node-sass', false, 'none', 'grunt', done);
    });

    it('works with gulp and node-sass', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'jade', 'node-sass', false, 'none', 'gulp', done);
    });

    it('works with coffee and gulp and node-sass', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'jade', 'node-sass', false, 'none', 'gulp', done);
    });

    it('creates expected files with less', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'jade', 'less', false, 'none', 'grunt', done);
    });

    it('works with coffee and less', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'jade', 'less', false, 'none', 'grunt', done);
    });

    it('works with gulp and less', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'jade', 'less', false, 'none', 'gulp', done);
    });

    it('works with coffee and gulp and less', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'jade', 'less', false, 'none', 'gulp', done);
    });
  });

  describe('Basic generator with EJS', function () {
    var expected = [
      'views/index.ejs',
      'views/header.ejs',
      'views/footer.ejs',
      'views/error.ejs',
    ];

    it('creates expected files', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'ejs', 'none', false, 'none', 'grunt', done);
    });

    it('works with coffee', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'ejs', 'none', true, 'none', 'grunt', done);
    });

    it('creates expected files with sass', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'ejs', 'sass', false, 'none', 'grunt', done);
    });

    it('works with coffee and sass', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'ejs', 'sass', false, 'none', 'grunt', done);
    });

    it('creates expected files with node-sass', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'ejs', 'node-sass', false, 'none', 'grunt', done);
    });

    it('works with coffee and node-sass', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'ejs', 'node-sass', false, 'none', 'grunt', done);
    });

    it('creates expected files with less', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'ejs', 'less', false, 'none', 'grunt', done);
    });

    it('works with coffee and less', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'ejs', 'less', false, 'none', 'grunt', done);
    });
  });

  describe('MVC generator with Jade', function () {
    var expected = [
      'app/views/layout.jade',
      'app/views/error.jade',
      'app/views/index.jade'
    ];
    it('creates expected files', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'none', false, 'none', 'grunt', done);
    });

    it('works with coffee', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'none', true, 'none', 'grunt', done);
    });

    it('works with gulp', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'none', false, 'none', 'gulp', done);
    });

    it('works with coffee and gulp', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'none', true, 'none', 'gulp', done);
    });

    it('creates expected files with sass', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'sass', false, 'none', 'grunt', done);
    });

    it('works with coffee and sass', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'sass', false, 'none', 'grunt', done);
    });

    it('works with gulp and sass', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'sass', false, 'none', 'gulp', done);
    });

    it('works with coffee and gulp and sass', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'sass', false, 'none', 'gulp', done);
    });

    it('creates expected files with node-sass', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'node-sass', false, 'none', 'grunt', done);
    });

    it('works with coffee and node-sass', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'node-sass', false, 'none', 'grunt', done);
    });

    it('works with gulp and node-sass', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'node-sass', false, 'none', 'gulp', done);
    });

    it('works with coffee and gulp and node-sass', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'node-sass', false, 'none', 'gulp', done);
    });

    it('creates expected files with less', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'less', false, 'none', 'grunt', done);
    });

    it('works with coffee and less', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'less', false, 'none', 'grunt', done);
    });

    it('works with gulp and less', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'less', false, 'none', 'gulp', done);
    });

    it('works with coffee and gulp and less', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'less', false, 'none', 'gulp', done);
    });
  });

  describe('MVC generator with EJS', function () {
    var expected = [
      'app/views/header.ejs',
      'app/views/footer.ejs',
      'app/views/error.ejs',
      'app/views/index.ejs'
    ];

    it('creates expected files', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'ejs', 'none', false, 'none', 'grunt', done);
    });

    it('works with coffee', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'ejs', 'none', true, 'none', 'grunt', done);
    });

    it('creates expected files with sass', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'ejs', 'sass', false, 'none', 'grunt', done);
    });

    it('works with coffee and sass', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'ejs', 'sass', false, 'none', 'grunt', done);
    });

    it('creates expected files with node-sass', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'ejs', 'node-sass', false, 'none', 'grunt', done);
    });

    it('works with coffee and node-sass', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'ejs', 'node-sass', false, 'none', 'grunt', done);
    });

    it('creates expected files with less', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'ejs', 'less', false, 'none', 'grunt', done);
    });

    it('works with coffee and less', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'ejs', 'less', false, 'none', 'grunt', done);
    });
  });

  describe('MVC generator with MySQL', function () {
    var expected = [
      'app/models/index.js'
    ];

    it('creates expected files', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'none', false, 'mysql', 'grunt', done);
    });

    it('works with coffee', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'none', true, 'mysql', 'grunt', done);
    });

    it('creates expected files with sass', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'sass', false, 'mysql', 'grunt', done);
    });

    it('works with coffee and sass', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'sass', false, 'mysql', 'grunt', done);
    });

    it('creates expected files with node-sass', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'node-sass', false, 'mysql', 'grunt', done);
    });

    it('works with coffee and node-sass', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'node-sass', false, 'mysql', 'grunt', done);
    });

    it('creates expected files with less', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'less', false, 'mysql', 'grunt', done);
    });

    it('works with coffee and less', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'less', false, 'mysql', 'grunt', done);
    });
  });
});
<commit_msg>add comments in the test test-creation run function<commit_after>/*global describe, beforeEach, it*/
'use strict';

var assert  = require('yeoman-generator').assert;
var path    = require('path');
var helpers = require('yeoman-generator').test;

var basicExpected = [
  '.bowerrc',
  '.gitignore',
  'bower.json',
  'app.js',
  'public/img',
  'public/components',
  'public/js',
  'package.json',
  'routes/index.js',
  'routes/user.js',
  'bin/www'
];

var MVCExpected = [
  '.bowerrc',
  '.gitignore',
  'bower.json',
  'app.js',
  'public/img',
  'public/components',
  'public/js',
  'public/css',
  'package.json',
  'config/config.js',
  'config/express.js',
  'app/controllers',
  'app/controllers/home.js',
  'app/models',
  'app/views'
];

var appFiles = {
  basic: basicExpected,
  mvc: MVCExpected
};

var toCoffeeFileArray = function (fileArray) {
  var newArray = [];
  for (var i in fileArray) {
    if (fileArray[i] === 'app.js') {
      newArray.push(fileArray[i]);
    } else {
      newArray.push(fileArray[i].replace(/(.*?)\.js$/, '$1.coffee'));
    }
  }

  return newArray;
};

var runGenerationTest = function (extraFiles, type, engine, preprocessor, coffee, database, buildTool, callback) {
  var expectedFiles;

  // Never install dependencies
  this.app.options['skip-install'] = true;

  // Set generator options
  this.app.options[type] = true;
  this.app.options.database = database;
  this.app.options.viewEngine = engine;
  this.app.options.cssPreprocessor = preprocessor;
  this.app.options.coffee = coffee;
  this.app.options.buildTool = buildTool;

  // Set up initial file list Basic or MVC
  expectedFiles = extraFiles.concat(appFiles[type]);

  // Set optional files, CSS preprocessor
  if (preprocessor === 'sass') {
    expectedFiles.push('public/css/style.scss');
  } else if (preprocessor === 'node-sass') {
    expectedFiles.push('public/css/style.scss');
  } else if (preprocessor === 'less') {
    expectedFiles.push('public/css/style.less');
  } else {
    expectedFiles.push('public/css/style.css');
  }

  // Set optional files, Coffee
  if (coffee) {
    expectedFiles = toCoffeeFileArray(expectedFiles);
  }

  // Set optional files, Build tool
  if (buildTool === 'grunt') {
    expectedFiles.push('Gruntfile.js');
  } else {
    expectedFiles.push('gulpfile.js');
  }

  // Test files generation
  this.app.run({}, function () {
    assert.file(expectedFiles);
    callback();
  });
};

describe('Express generator', function () {
  beforeEach(function (done) {
    helpers.testDirectory(path.join(__dirname, 'temp'), function (err) {
      if (err) {
        return done(err);
      }

      this.app = helpers.createGenerator('express:app', [
        '../../app'
      ]);
      done();
    }.bind(this));
  });

  describe('Basic generator with Jade', function () {
    var expected = [
      'views/index.jade',
      'views/layout.jade',
      'views/error.jade'
    ];

    it('creates expected files', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'jade', 'none', false, 'none', 'grunt', done);
    });

    it('works with coffee', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'jade', 'none', true, 'none', 'grunt', done);
    });

    it('works with gulp', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'jade', 'none', false, 'none', 'gulp', done);
    });

    it('works with coffee and gulp', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'jade', 'none', true, 'none', 'gulp', done);
    });

    it('creates expected files with sass', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'jade', 'sass', false, 'none', 'grunt', done);
    });

    it('works with coffee and sass', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'jade', 'sass', false, 'none', 'grunt', done);
    });

    it('works with gulp and sass', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'jade', 'sass', false, 'none', 'gulp', done);
    });

    it('works with coffee and gulp and sass', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'jade', 'sass', false, 'none', 'gulp', done);
    });

    it('creates expected files with node-sass', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'jade', 'node-sass', false, 'none', 'grunt', done);
    });

    it('works with coffee and node-sass', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'jade', 'node-sass', false, 'none', 'grunt', done);
    });

    it('works with gulp and node-sass', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'jade', 'node-sass', false, 'none', 'gulp', done);
    });

    it('works with coffee and gulp and node-sass', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'jade', 'node-sass', false, 'none', 'gulp', done);
    });

    it('creates expected files with less', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'jade', 'less', false, 'none', 'grunt', done);
    });

    it('works with coffee and less', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'jade', 'less', false, 'none', 'grunt', done);
    });

    it('works with gulp and less', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'jade', 'less', false, 'none', 'gulp', done);
    });

    it('works with coffee and gulp and less', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'jade', 'less', false, 'none', 'gulp', done);
    });
  });

  describe('Basic generator with EJS', function () {
    var expected = [
      'views/index.ejs',
      'views/header.ejs',
      'views/footer.ejs',
      'views/error.ejs',
    ];

    it('creates expected files', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'ejs', 'none', false, 'none', 'grunt', done);
    });

    it('works with coffee', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'ejs', 'none', true, 'none', 'grunt', done);
    });

    it('creates expected files with sass', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'ejs', 'sass', false, 'none', 'grunt', done);
    });

    it('works with coffee and sass', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'ejs', 'sass', false, 'none', 'grunt', done);
    });

    it('creates expected files with node-sass', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'ejs', 'node-sass', false, 'none', 'grunt', done);
    });

    it('works with coffee and node-sass', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'ejs', 'node-sass', false, 'none', 'grunt', done);
    });

    it('creates expected files with less', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'ejs', 'less', false, 'none', 'grunt', done);
    });

    it('works with coffee and less', function (done) {
      runGenerationTest.call(this, expected, 'basic', 'ejs', 'less', false, 'none', 'grunt', done);
    });
  });

  describe('MVC generator with Jade', function () {
    var expected = [
      'app/views/layout.jade',
      'app/views/error.jade',
      'app/views/index.jade'
    ];
    it('creates expected files', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'none', false, 'none', 'grunt', done);
    });

    it('works with coffee', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'none', true, 'none', 'grunt', done);
    });

    it('works with gulp', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'none', false, 'none', 'gulp', done);
    });

    it('works with coffee and gulp', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'none', true, 'none', 'gulp', done);
    });

    it('creates expected files with sass', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'sass', false, 'none', 'grunt', done);
    });

    it('works with coffee and sass', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'sass', false, 'none', 'grunt', done);
    });

    it('works with gulp and sass', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'sass', false, 'none', 'gulp', done);
    });

    it('works with coffee and gulp and sass', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'sass', false, 'none', 'gulp', done);
    });

    it('creates expected files with node-sass', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'node-sass', false, 'none', 'grunt', done);
    });

    it('works with coffee and node-sass', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'node-sass', false, 'none', 'grunt', done);
    });

    it('works with gulp and node-sass', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'node-sass', false, 'none', 'gulp', done);
    });

    it('works with coffee and gulp and node-sass', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'node-sass', false, 'none', 'gulp', done);
    });

    it('creates expected files with less', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'less', false, 'none', 'grunt', done);
    });

    it('works with coffee and less', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'less', false, 'none', 'grunt', done);
    });

    it('works with gulp and less', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'less', false, 'none', 'gulp', done);
    });

    it('works with coffee and gulp and less', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'less', false, 'none', 'gulp', done);
    });
  });

  describe('MVC generator with EJS', function () {
    var expected = [
      'app/views/header.ejs',
      'app/views/footer.ejs',
      'app/views/error.ejs',
      'app/views/index.ejs'
    ];

    it('creates expected files', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'ejs', 'none', false, 'none', 'grunt', done);
    });

    it('works with coffee', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'ejs', 'none', true, 'none', 'grunt', done);
    });

    it('creates expected files with sass', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'ejs', 'sass', false, 'none', 'grunt', done);
    });

    it('works with coffee and sass', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'ejs', 'sass', false, 'none', 'grunt', done);
    });

    it('creates expected files with node-sass', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'ejs', 'node-sass', false, 'none', 'grunt', done);
    });

    it('works with coffee and node-sass', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'ejs', 'node-sass', false, 'none', 'grunt', done);
    });

    it('creates expected files with less', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'ejs', 'less', false, 'none', 'grunt', done);
    });

    it('works with coffee and less', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'ejs', 'less', false, 'none', 'grunt', done);
    });
  });

  describe('MVC generator with MySQL', function () {
    var expected = [
      'app/models/index.js'
    ];

    it('creates expected files', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'none', false, 'mysql', 'grunt', done);
    });

    it('works with coffee', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'none', true, 'mysql', 'grunt', done);
    });

    it('creates expected files with sass', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'sass', false, 'mysql', 'grunt', done);
    });

    it('works with coffee and sass', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'sass', false, 'mysql', 'grunt', done);
    });

    it('creates expected files with node-sass', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'node-sass', false, 'mysql', 'grunt', done);
    });

    it('works with coffee and node-sass', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'node-sass', false, 'mysql', 'grunt', done);
    });

    it('creates expected files with less', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'less', false, 'mysql', 'grunt', done);
    });

    it('works with coffee and less', function (done) {
      runGenerationTest.call(this, expected, 'mvc', 'jade', 'less', false, 'mysql', 'grunt', done);
    });
  });
});
<|endoftext|>


<commit_before>'use strict';
describe("high level REST requests on mongoose", function () {
    this.timeout(2000);
    before(function (done) {
        _.each(require.cache, function (mod, modName) {
            if (~modName.indexOf('formage') || ~modName.indexOf('mongoose') || ~modName.indexOf('jugglingdb'))
                delete require.cache[modName];
        });
        var formage = require('../index');
        var mongoose = module.mongoose = require("mongoose");
        mongoose.connect('mongodb://localhost/formage-test', function () {
            var AppliesTo = mongoose.model('AppliesTo', new mongoose.Schema({
                Title: {type: String, limit: 100, required: true},
                Identifier: {type: String, limit: 100},
                Editable: {type: Number}
            }));
            var tests = require('../example/models/tests');
            var pages = require('../example/models/pages');
            var express = require('express');
            var app = express();
            formage.init(app, express, {pages:pages, AppliesTo: AppliesTo, Tests:tests}, {
                title: 'Formage Example',
                default_section: 'Main',
                admin_users_gui: true
            });
            mock_req_proto.app = module.admin_app = app.admin_app;
            done()
        });
    });

    describe("pages", function () {
        it("Mock test document page", function (done) {
            var mock_req = _.defaults({
                url: "/model/Tests/document/new",
                method: "GET"
            }, mock_req_proto);
            var mock_res = _.defaults({ req: mock_req }, mock_res_proto);

            mock_res.render = function (view, options) {
                view.should.equal("document.jade");
                should.exist(options);
                done()
            };

            module.admin_app.handle(mock_req, mock_res);
        });

        it("test document - post simple", function (done) {
            var mock_req = _.defaults({
                url: "/model/AppliesTo/document/new",
                method: "POST",
                body: {
                    Title: "gaga5",
                    Identifier: "asdf",
                    Editable: "1"
                },
                path: ""
            }, mock_req_proto);
            var mock_res = _.defaults({ req: mock_req }, mock_res_proto);

            mock_res.redirect = function (path) {
                should.not.exist(mock_res._status);
                Number(1).should.equal(arguments.length);
                done();
            };

            module.admin_app.handle(mock_req, mock_res);
        });

        it("test document - post - failing validation", function (done) {
            var mock_req = _.defaults({
                url: "/model/AppliesTo/document/new",
                method: "POST",
                body: {
                    Identifier: "asdf",
                    Editable: "1"
                },
                path: ""
            }, mock_req_proto);
            var mock_res = _.defaults({ req: mock_req }, mock_res_proto);

            mock_res.render = function (view, options) {
                view.should.equal("document.jade");
                should.exist(options.errors.Title);
                Number(422).should.equal(mock_res._status);
                done();
            };

            module.admin_app.handle(mock_req, mock_res);
        });

        it("test document - post progressive", function (done) {
            var mock_req = _.defaults({
                url: "/json/model/Tests/document/new",
                method: "POST",
                body: {
                    string_req: "gaga",
                    num_with_params: "0",
                    enum: "",
                    "object.object.object.nested_string_req" : "gigi"
                },
                path: ""
            }, mock_req_proto);
            var mock_res = _.defaults({ req: mock_req }, mock_res_proto);

            mock_res.json = function (status, data) {
                status.should.equal(205);
                data.label.should.equal(mock_req.body.string_req);
                module._create_id = data.id;
                done();
            };

            module.admin_app.handle(mock_req, mock_res);
        });

        it("test document - delete", function (done) {
            var mock_req = _.defaults({
                url: "/json/model/Tests/document/" + module._create_id,
                method: "DELETE",
                path: ""
            }, mock_req_proto);
            delete module._create_id;

            var mock_res = _.defaults({ req: mock_req }, mock_res_proto);

            mock_res.json = function (status, data) {
                status.should.equal(204);
                data.collection.should.equal("Tests");
                done();
            };

            module.admin_app.handle(mock_req, mock_res);
        });

        it("test document - checkDependencies", function (done) {
            var mock_req = _.defaults({
                url: "/json/model/Tests/document/" + module._create_id+'/dependencies',
                method: "GET",
                path: ""
            }, mock_req_proto);

            var mock_res = _.defaults({ req: mock_req }, mock_res_proto);

            mock_res.json = function (status, data) {
                status.should.equal(200);
                should.exist(data.length);
                done();
            };

            module.admin_app.handle(mock_req, mock_res);
        });

        it("Mock test model page", function (done) {
            var mock_req = _.defaults({
                url: "/model/AppliesTo/",
                method: "GET"
            }, mock_req_proto);
            var mock_res = _.defaults({ req: mock_req }, mock_res_proto);

            mock_res.render = function (view, options) {
                view.should.equal("model.jade");
                should.exist(options);
                this.req.app.render(view, options, function (err, doc) {
                    should.exist(doc);
                    done(err);
                });
            };

            module.admin_app.handle(mock_req, mock_res);
        });

        it("Mock test model page with query params", function (done) {
            var mock_req = _.defaults({
                url: "/model/Tests/",
                query: {start: "0", order_by:"string_req", limit:"20", populates:"ref"},
                method: "GET"
            }, mock_req_proto);
            var mock_res = _.defaults({ req: mock_req }, mock_res_proto);

            mock_res.render = function (view, options) {
                view.should.equal("model.jade");
                should.exist(options);
                this.req.app.render(view, options, function (err, doc) {
                    should.exist(doc);
                    done(err);
                });
            };

            module.admin_app.handle(mock_req, mock_res);
        });

        it("Mock test models page", function (done) {
            var mock_req = _.defaults({
                url: "/",
                method: "GET"
            }, mock_req_proto);
            var mock_res = _.defaults({ req: mock_req }, mock_res_proto);

            mock_res.render = function (view, options) {
                view.should.equal("models.jade");
                should.exist(options);
                this.req.app.render(view, options, function (err, doc) {
                    should.exist(doc);
                    done(err);
                });
            };

            module.admin_app.handle(mock_req, mock_res);
        });

        it("Mock test admin user page post", function (done) {
            this.timeout(2000);
            var mock_req = _.defaults({
                url: "/model/Admin_Users/document/new",
                body: {username: "admin" + Math.random()},
                method: "POST",
                path: ""
            }, mock_req_proto);

            var mock_res = _.defaults({
                req: mock_req
            }, mock_res_proto);

            mock_res.redirect = function (p) {
                mock_res.app.route.should.equal(p);
                should.exist(p);
                done();
            };

            module.admin_app.handle(mock_req, mock_res);
        });
    });

    after(function (done) {
        module.mongoose.disconnect();
        done();
    });
});
<commit_msg>Cover ArrayFields<commit_after>'use strict';
describe("high level REST requests on mongoose", function () {
    this.timeout(2000);
    before(function (done) {
        _.each(require.cache, function (mod, modName) {
            if (~modName.indexOf('formage') || ~modName.indexOf('mongoose') || ~modName.indexOf('jugglingdb'))
                delete require.cache[modName];
        });
        var formage = require('../index');
        var mongoose = module.mongoose = require("mongoose");
        mongoose.connect('mongodb://localhost/formage-test', function () {
            var AppliesTo = mongoose.model('AppliesTo', new mongoose.Schema({
                Title: {type: String, limit: 100, required: true},
                Identifier: {type: String, limit: 100},
                Editable: {type: Number}
            }));
            var tests = require('../example/models/tests');
            var pages = require('../example/models/pages');
            var express = require('express');
            var app = express();
            formage.init(app, express, {pages:pages, AppliesTo: AppliesTo, Tests:tests}, {
                title: 'Formage Example',
                default_section: 'Main',
                admin_users_gui: true
            });
            mock_req_proto.app = module.admin_app = app.admin_app;
            done()
        });
    });

    describe("pages", function () {
        it("Mock test document page", function (done) {
            var mock_req = _.defaults({
                url: "/model/Tests/document/new",
                method: "GET"
            }, mock_req_proto);
            var mock_res = _.defaults({ req: mock_req }, mock_res_proto);

            mock_res.render = function (view, options) {
                view.should.equal("document.jade");
                should.exist(options);
                done()
            };

            module.admin_app.handle(mock_req, mock_res);
        });

        it("test document - post simple", function (done) {
            var mock_req = _.defaults({
                url: "/model/AppliesTo/document/new",
                method: "POST",
                body: {
                    Title: "gaga5",
                    Identifier: "asdf",
                    Editable: "1"
                },
                path: ""
            }, mock_req_proto);
            var mock_res = _.defaults({ req: mock_req }, mock_res_proto);

            mock_res.redirect = function (path) {
                should.not.exist(mock_res._status);
                Number(1).should.equal(arguments.length);
                done();
            };

            module.admin_app.handle(mock_req, mock_res);
        });

        it("test document - post - failing validation", function (done) {
            var mock_req = _.defaults({
                url: "/model/AppliesTo/document/new",
                method: "POST",
                body: {
                    Identifier: "asdf",
                    Editable: "1"
                },
                path: ""
            }, mock_req_proto);
            var mock_res = _.defaults({ req: mock_req }, mock_res_proto);

            mock_res.render = function (view, options) {
                view.should.equal("document.jade");
                should.exist(options.errors.Title);
                Number(422).should.equal(mock_res._status);
                done();
            };

            module.admin_app.handle(mock_req, mock_res);
        });

        it("test document - post progressive", function (done) {
            var mock_req = _.defaults({
                url: "/json/model/Tests/document/new",
                method: "POST",
                body: {
                    string_req: "gaga",
                    num_with_params: "0",
                    enum: "",
                    "object.object.object.nested_string_req" : "gigi",
                    list_o_numbers_li0___self__: "5"
                },
                path: ""
            }, mock_req_proto);
            var mock_res = _.defaults({ req: mock_req }, mock_res_proto);

            mock_res.json = function (status, data) {
                status.should.equal(200);
                data.label.should.equal(mock_req.body.string_req);
                module._create_id = data.id;
                done();
            };

            module.admin_app.handle(mock_req, mock_res);
        });

        it("test document - delete", function (done) {
            var mock_req = _.defaults({
                url: "/json/model/Tests/document/" + module._create_id,
                method: "DELETE",
                path: ""
            }, mock_req_proto);
            delete module._create_id;

            var mock_res = _.defaults({ req: mock_req }, mock_res_proto);

            mock_res.json = function (status, data) {
                status.should.equal(204);
                data.collection.should.equal("Tests");
                done();
            };

            module.admin_app.handle(mock_req, mock_res);
        });

        it("test document - checkDependencies", function (done) {
            var mock_req = _.defaults({
                url: "/json/model/Tests/document/" + module._create_id+'/dependencies',
                method: "GET",
                path: ""
            }, mock_req_proto);

            var mock_res = _.defaults({ req: mock_req }, mock_res_proto);

            mock_res.json = function (status, data) {
                status.should.equal(200);
                should.exist(data.length);
                done();
            };

            module.admin_app.handle(mock_req, mock_res);
        });

        it("Mock test model page", function (done) {
            var mock_req = _.defaults({
                url: "/model/AppliesTo/",
                method: "GET"
            }, mock_req_proto);
            var mock_res = _.defaults({ req: mock_req }, mock_res_proto);

            mock_res.render = function (view, options) {
                view.should.equal("model.jade");
                should.exist(options);
                this.req.app.render(view, options, function (err, doc) {
                    should.exist(doc);
                    done(err);
                });
            };

            module.admin_app.handle(mock_req, mock_res);
        });

        it("Mock test model page with query params", function (done) {
            var mock_req = _.defaults({
                url: "/model/Tests/",
                query: {start: "0", order_by:"string_req", limit:"20", populates:"ref"},
                method: "GET"
            }, mock_req_proto);
            var mock_res = _.defaults({ req: mock_req }, mock_res_proto);

            mock_res.render = function (view, options) {
                view.should.equal("model.jade");
                should.exist(options);
                this.req.app.render(view, options, function (err, doc) {
                    should.exist(doc);
                    done(err);
                });
            };

            module.admin_app.handle(mock_req, mock_res);
        });

        it("Mock test models page", function (done) {
            var mock_req = _.defaults({
                url: "/",
                method: "GET"
            }, mock_req_proto);
            var mock_res = _.defaults({ req: mock_req }, mock_res_proto);

            mock_res.render = function (view, options) {
                view.should.equal("models.jade");
                should.exist(options);
                this.req.app.render(view, options, function (err, doc) {
                    should.exist(doc);
                    done(err);
                });
            };

            module.admin_app.handle(mock_req, mock_res);
        });

        it("Mock test admin user page post", function (done) {
            this.timeout(2000);
            var mock_req = _.defaults({
                url: "/model/Admin_Users/document/new",
                body: {username: "admin" + Math.random()},
                method: "POST",
                path: ""
            }, mock_req_proto);

            var mock_res = _.defaults({
                req: mock_req
            }, mock_res_proto);

            mock_res.redirect = function (p) {
                mock_res.app.route.should.equal(p);
                should.exist(p);
                done();
            };

            module.admin_app.handle(mock_req, mock_res);
        });
    });

    after(function (done) {
        module.mongoose.disconnect();
        done();
    });
});
<|endoftext|>


<commit_before>/*global describe, before, after, beforeEach, afterEach, it, sinon */
var fs = require('fs');
var path = require('path');
var mkdirp = require('mkdirp');
var rimraf = require('rimraf');
var should = require('should');

var pidfiles = require('../lib/cluster/pidfiles');

describe("pidfiles", function () {
    /*jshint expr:true */

    var PIDS_DIR = 'test/fixtures/pids';

    describe("#getMasterPid()", function () {
        beforeEach(function () {
            sinon.stub(fs, "readFile");
        });
        afterEach(function () {
            fs.readFile.restore();
        });

        it("should read master.pid", function (done) {
            fs.readFile.yields(null, 0, PIDS_DIR);

            pidfiles.getMasterPid(PIDS_DIR, function (err, pid, dir) {
                should.not.exist(err);
                pid.should.equal(0);
                dir.should.equal(PIDS_DIR);
                done();
            });
        });

        it("should pass fs error to callback", function (done) {
            fs.readFile.yields("foo");

            pidfiles.getMasterPid(PIDS_DIR, function (err) {
                should.exist(err);
                err.should.equal("foo");
                done();
            });
        });
    });

    describe("#getWorkerPidsSync()", function () {
        beforeEach(function () {
            sinon.stub(fs, "readdirSync");
            sinon.stub(fs, "readFileSync");
        });
        afterEach(function () {
            fs.readdirSync.restore();
            fs.readFileSync.restore();
        });

        it("should return worker pids only", function () {
            fs.readdirSync
                .withArgs(PIDS_DIR)
                .returns(["master.pid", "worker1.pid"]);

            fs.readFileSync
                .withArgs(path.join(PIDS_DIR, "worker1.pid"))
                .returns("1");

            pidfiles.getWorkerPidsSync(PIDS_DIR)
                .should.have.length(1)
                    .and.contain(1);
        });
    });

    describe("#removePidFile()", function () {
        beforeEach(function () {
            sinon.stub(fs, "unlink");
        });
        afterEach(function () {
            fs.unlink.restore();
        });

        it("should remove designated pidfile", function (done) {
            fs.unlink.yields(null);

            pidfiles.removePidFile(PIDS_DIR, "worker1", done);
        });

        it("should not require callback", function () {
            fs.unlink
                .withArgs(path.join(PIDS_DIR, "worker1.pid"))
                .yields(null);

            /*jshint immed:false */
            (function () {
                pidfiles.removePidFile(PIDS_DIR, "worker1");
            }).should.not.throwError();
        });

        it("should pass errors to callback", function () {
            fs.unlink
                .withArgs(path.join(PIDS_DIR, "worker1.pid"), sinon.match.func)
                .yields({ code: "ENOENT" });

            fs.unlink
                .withArgs(path.join(PIDS_DIR, "worker2.pid"), sinon.match.func)
                .yields({ code: "FOO" });

            pidfiles.removePidFile(PIDS_DIR, "worker1", function (err) {
                should.exist(err);
                err.should.have.property("code", "ENOENT");
            });

            pidfiles.removePidFile(PIDS_DIR, "worker2", function (err) {
                should.exist(err);
                err.should.have.property("code", "FOO");
            });
        });

        it("should log ENOENT errors", function () {
            var consoleError = sinon.stub(console, "error");
            fs.unlink.yields({ code: "ENOENT" });

            pidfiles.removePidFile(PIDS_DIR, "worker1");

            consoleError.calledOnce.should.be.ok;
            consoleError.calledWith('Could not find pidfile: %s', "worker1.pid");
            consoleError.restore();
        });

        it("should throw other errors", function () {
            fs.unlink.yields({ code: "FOO" });

            /*jshint immed:false */
            (function () {
                pidfiles.removePidFile(PIDS_DIR, "worker1");
            }).should.throwError();
        });
    });

    describe("#removePidFileSync()", function () {
        beforeEach(function () {
            sinon.stub(fs, "unlinkSync");
        });
        afterEach(function () {
            fs.unlinkSync.restore();
        });

        it("should remove designated pidfile", function () {
            pidfiles.removePidFileSync(PIDS_DIR, "worker1");

            fs.unlinkSync.calledOnce.should.be.ok;
            fs.unlinkSync.calledWith(path.join(PIDS_DIR, "worker1.pid")).should.be.ok;
        });
    });

    describe("#removeWorkerPidFiles()", function () {
        beforeEach(function () {
            sinon.stub(fs, "readdirSync");
        });
        afterEach(function () {
            fs.readdirSync.restore();
        });

        describe("without workers", function () {
            beforeEach(function () {
                fs.readdirSync
                    .withArgs(PIDS_DIR)
                    .returns([
                        "master.pid"
                    ]);
            });

            it("should callback immediately", function (done) {
                pidfiles.removeWorkerPidFiles(PIDS_DIR, done);
            });
        });

        describe("workers present", function () {
            beforeEach(function () {
                sinon.stub(pidfiles, "removePidFile");
                fs.readdirSync
                    .withArgs(PIDS_DIR)
                    .returns([
                        "master.pid",
                        "worker1.pid",
                        "worker2.pid"
                    ]);
            });
            afterEach(function () {
                pidfiles.removePidFile.restore();
            });

            describe("with callback", function () {
                it("should succeed", function (done) {
                    pidfiles.removePidFile.yields(null);
                    pidfiles.removeWorkerPidFiles(PIDS_DIR, done);
                });

                it("should log ENOENT errors", function (done) {
                    var consoleError = sinon.stub(console, "error");

                    pidfiles.removePidFile.yields(null);
                    pidfiles.removePidFile
                        .withArgs(PIDS_DIR, "worker1", sinon.match.func)
                        .yields({ code: "ENOENT" });

                    pidfiles.removeWorkerPidFiles(PIDS_DIR, function (err) {
                        should.not.exist(err);

                        pidfiles.removePidFile.calledTwice.should.be.ok;

                        consoleError.calledOnce.should.be.ok;
                        consoleError.calledWith('Could not find pidfile: %s', "worker1.pid");
                        consoleError.restore();

                        done();
                    });
                });

                it("should pass other errors to callback", function (done) {
                    pidfiles.removePidFile.yields(null);
                    pidfiles.removePidFile
                        .withArgs(PIDS_DIR, "worker1", sinon.match.func)
                        .yields({ code: "FOO" });

                    pidfiles.removeWorkerPidFiles(PIDS_DIR, function (err) {
                        should.exist(err);
                        err.should.have.property("code", "FOO");

                        pidfiles.removePidFile.calledOnce.should.be.ok;

                        done();
                    });
                });
            });

            describe("without callback", function () {
                it("should succeed", function () {
                    pidfiles.removePidFile.yields(null);
                    pidfiles.removeWorkerPidFiles(PIDS_DIR);
                    pidfiles.removePidFile.calledTwice.should.be.ok;
                });

                it("should log ENOENT errors", function () {
                    var consoleError = sinon.stub(console, "error");

                    pidfiles.removePidFile.yields(null);
                    pidfiles.removePidFile
                        .withArgs(PIDS_DIR, "worker1", sinon.match.func)
                        .yields({ code: "ENOENT" });

                    pidfiles.removeWorkerPidFiles(PIDS_DIR);
                    pidfiles.removePidFile.calledTwice.should.be.ok;

                    consoleError.calledOnce.should.be.ok;
                    consoleError.calledWith('Could not find pidfile: %s', "worker1.pid");
                    consoleError.restore();
                });

                it("should swallow other errors", function () {
                    pidfiles.removePidFile.yields(null);
                    pidfiles.removePidFile
                        .withArgs(PIDS_DIR, "worker1", sinon.match.func)
                        .yields({ code: "FOO" });

                    pidfiles.removeWorkerPidFiles(PIDS_DIR);
                    pidfiles.removePidFile.calledTwice.should.be.ok;
                });
            });
        });
    });

    describe("#writePidFileSync()", function () {
        beforeEach(function () {
            sinon.stub(fs, "existsSync");
            sinon.stub(fs, "writeFileSync");
            sinon.stub(mkdirp, "sync");
        });
        afterEach(function () {
            fs.existsSync.restore();
            fs.writeFileSync.restore();
            mkdirp.sync.restore();
        });

        it("should create directory if necessary", function () {
            fs.existsSync.returns(false);
            pidfiles.writePidFileSync(PIDS_DIR, "master", 0);

            mkdirp.sync.calledOnce.should.be.ok;
            mkdirp.sync.calledWith(PIDS_DIR).should.be.ok;

            fs.writeFileSync.calledOnce.should.be.ok;
            fs.writeFileSync.calledWith(path.join(PIDS_DIR, "master.pid"), "0").should.be.ok;
        });

        it("should write pidfile successfully", function () {
            fs.existsSync.returns(true);
            pidfiles.writePidFileSync(PIDS_DIR, "master", 0);

            fs.writeFileSync.calledOnce.should.be.ok;
            fs.writeFileSync.calledWith(path.join(PIDS_DIR, "master.pid"), "0").should.be.ok;
        });

        it("should default 'nameless' pidfile to master.pid", function () {
            fs.existsSync.returns(true);
            pidfiles.writePidFileSync(PIDS_DIR, "", 0);

            fs.writeFileSync.calledOnce.should.be.ok;
            fs.writeFileSync.calledWith(path.join(PIDS_DIR, "master.pid"), "0").should.be.ok;
        });
    });
});
<commit_msg>Add 'cluster' to pidfiles suite name, and clarify pids are distinct from worker indices.<commit_after>/*global describe, before, after, beforeEach, afterEach, it, sinon */
var fs = require('fs');
var path = require('path');
var mkdirp = require('mkdirp');
var rimraf = require('rimraf');
var should = require('should');

var pidfiles = require('../lib/cluster/pidfiles');

describe("cluster pidfiles", function () {
    /*jshint expr:true */

    var PIDS_DIR = 'test/fixtures/pids';

    describe("#getMasterPid()", function () {
        beforeEach(function () {
            sinon.stub(fs, "readFile");
        });
        afterEach(function () {
            fs.readFile.restore();
        });

        it("should read master.pid", function (done) {
            fs.readFile.yields(null, 0, PIDS_DIR);

            pidfiles.getMasterPid(PIDS_DIR, function (err, pid, dir) {
                should.not.exist(err);
                pid.should.equal(0);
                dir.should.equal(PIDS_DIR);
                done();
            });
        });

        it("should pass fs error to callback", function (done) {
            fs.readFile.yields("foo");

            pidfiles.getMasterPid(PIDS_DIR, function (err) {
                should.exist(err);
                err.should.equal("foo");
                done();
            });
        });
    });

    describe("#getWorkerPidsSync()", function () {
        beforeEach(function () {
            sinon.stub(fs, "readdirSync");
            sinon.stub(fs, "readFileSync");
        });
        afterEach(function () {
            fs.readdirSync.restore();
            fs.readFileSync.restore();
        });

        it("should return worker pids only", function () {
            fs.readdirSync
                .withArgs(PIDS_DIR)
                .returns(["master.pid", "worker1.pid"]);

            fs.readFileSync
                .withArgs(path.join(PIDS_DIR, "worker1.pid"))
                .returns("100");

            pidfiles.getWorkerPidsSync(PIDS_DIR)
                .should.have.length(1)
                    .and.contain(100);
        });
    });

    describe("#removePidFile()", function () {
        beforeEach(function () {
            sinon.stub(fs, "unlink");
        });
        afterEach(function () {
            fs.unlink.restore();
        });

        it("should remove designated pidfile", function (done) {
            fs.unlink.yields(null);

            pidfiles.removePidFile(PIDS_DIR, "worker1", done);
        });

        it("should not require callback", function () {
            fs.unlink
                .withArgs(path.join(PIDS_DIR, "worker1.pid"))
                .yields(null);

            /*jshint immed:false */
            (function () {
                pidfiles.removePidFile(PIDS_DIR, "worker1");
            }).should.not.throwError();
        });

        it("should pass errors to callback", function () {
            fs.unlink
                .withArgs(path.join(PIDS_DIR, "worker1.pid"), sinon.match.func)
                .yields({ code: "ENOENT" });

            fs.unlink
                .withArgs(path.join(PIDS_DIR, "worker2.pid"), sinon.match.func)
                .yields({ code: "FOO" });

            pidfiles.removePidFile(PIDS_DIR, "worker1", function (err) {
                should.exist(err);
                err.should.have.property("code", "ENOENT");
            });

            pidfiles.removePidFile(PIDS_DIR, "worker2", function (err) {
                should.exist(err);
                err.should.have.property("code", "FOO");
            });
        });

        it("should log ENOENT errors", function () {
            var consoleError = sinon.stub(console, "error");
            fs.unlink.yields({ code: "ENOENT" });

            pidfiles.removePidFile(PIDS_DIR, "worker1");

            consoleError.calledOnce.should.be.ok;
            consoleError.calledWith('Could not find pidfile: %s', "worker1.pid");
            consoleError.restore();
        });

        it("should throw other errors", function () {
            fs.unlink.yields({ code: "FOO" });

            /*jshint immed:false */
            (function () {
                pidfiles.removePidFile(PIDS_DIR, "worker1");
            }).should.throwError();
        });
    });

    describe("#removePidFileSync()", function () {
        beforeEach(function () {
            sinon.stub(fs, "unlinkSync");
        });
        afterEach(function () {
            fs.unlinkSync.restore();
        });

        it("should remove designated pidfile", function () {
            pidfiles.removePidFileSync(PIDS_DIR, "worker1");

            fs.unlinkSync.calledOnce.should.be.ok;
            fs.unlinkSync.calledWith(path.join(PIDS_DIR, "worker1.pid")).should.be.ok;
        });
    });

    describe("#removeWorkerPidFiles()", function () {
        beforeEach(function () {
            sinon.stub(fs, "readdirSync");
        });
        afterEach(function () {
            fs.readdirSync.restore();
        });

        describe("without workers", function () {
            beforeEach(function () {
                fs.readdirSync
                    .withArgs(PIDS_DIR)
                    .returns([
                        "master.pid"
                    ]);
            });

            it("should callback immediately", function (done) {
                pidfiles.removeWorkerPidFiles(PIDS_DIR, done);
            });
        });

        describe("workers present", function () {
            beforeEach(function () {
                sinon.stub(pidfiles, "removePidFile");
                fs.readdirSync
                    .withArgs(PIDS_DIR)
                    .returns([
                        "master.pid",
                        "worker1.pid",
                        "worker2.pid"
                    ]);
            });
            afterEach(function () {
                pidfiles.removePidFile.restore();
            });

            describe("with callback", function () {
                it("should succeed", function (done) {
                    pidfiles.removePidFile.yields(null);
                    pidfiles.removeWorkerPidFiles(PIDS_DIR, done);
                });

                it("should log ENOENT errors", function (done) {
                    var consoleError = sinon.stub(console, "error");

                    pidfiles.removePidFile.yields(null);
                    pidfiles.removePidFile
                        .withArgs(PIDS_DIR, "worker1", sinon.match.func)
                        .yields({ code: "ENOENT" });

                    pidfiles.removeWorkerPidFiles(PIDS_DIR, function (err) {
                        should.not.exist(err);

                        pidfiles.removePidFile.calledTwice.should.be.ok;

                        consoleError.calledOnce.should.be.ok;
                        consoleError.calledWith('Could not find pidfile: %s', "worker1.pid");
                        consoleError.restore();

                        done();
                    });
                });

                it("should pass other errors to callback", function (done) {
                    pidfiles.removePidFile.yields(null);
                    pidfiles.removePidFile
                        .withArgs(PIDS_DIR, "worker1", sinon.match.func)
                        .yields({ code: "FOO" });

                    pidfiles.removeWorkerPidFiles(PIDS_DIR, function (err) {
                        should.exist(err);
                        err.should.have.property("code", "FOO");

                        pidfiles.removePidFile.calledOnce.should.be.ok;

                        done();
                    });
                });
            });

            describe("without callback", function () {
                it("should succeed", function () {
                    pidfiles.removePidFile.yields(null);
                    pidfiles.removeWorkerPidFiles(PIDS_DIR);
                    pidfiles.removePidFile.calledTwice.should.be.ok;
                });

                it("should log ENOENT errors", function () {
                    var consoleError = sinon.stub(console, "error");

                    pidfiles.removePidFile.yields(null);
                    pidfiles.removePidFile
                        .withArgs(PIDS_DIR, "worker1", sinon.match.func)
                        .yields({ code: "ENOENT" });

                    pidfiles.removeWorkerPidFiles(PIDS_DIR);
                    pidfiles.removePidFile.calledTwice.should.be.ok;

                    consoleError.calledOnce.should.be.ok;
                    consoleError.calledWith('Could not find pidfile: %s', "worker1.pid");
                    consoleError.restore();
                });

                it("should swallow other errors", function () {
                    pidfiles.removePidFile.yields(null);
                    pidfiles.removePidFile
                        .withArgs(PIDS_DIR, "worker1", sinon.match.func)
                        .yields({ code: "FOO" });

                    pidfiles.removeWorkerPidFiles(PIDS_DIR);
                    pidfiles.removePidFile.calledTwice.should.be.ok;
                });
            });
        });
    });

    describe("#writePidFileSync()", function () {
        beforeEach(function () {
            sinon.stub(fs, "existsSync");
            sinon.stub(fs, "writeFileSync");
            sinon.stub(mkdirp, "sync");
        });
        afterEach(function () {
            fs.existsSync.restore();
            fs.writeFileSync.restore();
            mkdirp.sync.restore();
        });

        it("should create directory if necessary", function () {
            fs.existsSync.returns(false);
            pidfiles.writePidFileSync(PIDS_DIR, "master", 0);

            mkdirp.sync.calledOnce.should.be.ok;
            mkdirp.sync.calledWith(PIDS_DIR).should.be.ok;

            fs.writeFileSync.calledOnce.should.be.ok;
            fs.writeFileSync.calledWith(path.join(PIDS_DIR, "master.pid"), "0").should.be.ok;
        });

        it("should write pidfile successfully", function () {
            fs.existsSync.returns(true);
            pidfiles.writePidFileSync(PIDS_DIR, "master", 0);

            fs.writeFileSync.calledOnce.should.be.ok;
            fs.writeFileSync.calledWith(path.join(PIDS_DIR, "master.pid"), "0").should.be.ok;
        });

        it("should default 'nameless' pidfile to master.pid", function () {
            fs.existsSync.returns(true);
            pidfiles.writePidFileSync(PIDS_DIR, "", 0);

            fs.writeFileSync.calledOnce.should.be.ok;
            fs.writeFileSync.calledWith(path.join(PIDS_DIR, "master.pid"), "0").should.be.ok;
        });
    });
});
<|endoftext|>


<commit_before>/* global require, describe, it */
'use strict';

// MODULES //

var chai = require( 'chai' ),
	validate = require( './../lib/validate.js' );

// VARIABLES //

var expect = chai.expect,
	assert = chai.assert;

// TESTS //

describe( 'validate', function tests() {

	it( 'should export a function', function test() {
		expect( validate ).to.be.a( 'function' );
	});

	it( 'should return an error if provided an options argument which is not an object', function test() {
		var values = [
			'5',
			5,
			true,
			undefined,
			null,
			NaN,
			function(){},
			[]
		];

		for ( var i = 0; i < values.length; i++ ) {
			assert.isTrue( validate( {}, values[ i ] ) instanceof TypeError );
		}
	});

	it( 'should return an error if provided a separator option which is not a string or regular expression', function test() {
		var values, err;

		values = [
			5,
			undefined,
			null,
			NaN,
			[],
			{},
			function(){}
		];

		for ( var i = 0; i < values.length; i++ ) {
			err = validate( {}, {
				'sep': values[ i ]
			});
			assert.isTrue( err instanceof TypeError );
		}
	});

	it( 'should return an error if provided an object mode option which is not a boolean primitive', function test() {
		var values, err;

		values = [
			5,
			'5',
			undefined,
			null,
			NaN,
			[],
			{},
			function(){}
		];

		for ( var i = 0; i < values.length; i++ ) {
			err = validate( {}, {
				'objectMode': values[ i ]
			});
			assert.isTrue( err instanceof TypeError );
		}
	});

	it( 'should return an error if provided a `writableObjectMode` option which is not a boolean primitive', function test() {
		var values, err;

		values = [
			5,
			'5',
			undefined,
			null,
			NaN,
			[],
			{},
			function(){}
		];

		for ( var i = 0; i < values.length; i++ ) {
			err = validate( {}, {
				'writableObjectMode': values[ i ]
			});
			assert.isTrue( err instanceof TypeError );
		}
	});

	it( 'should return an error if provided an encoding option which is not a string primitive', function test() {
		var values, err;

		values = [
			5,
			true,
			undefined,
			null,
			NaN,
			[],
			{},
			function(){}
		];

		for ( var i = 0; i < values.length; i++ ) {
			err = validate( {}, {
				'encoding': values[ i ]
			});
			assert.isTrue( err instanceof TypeError );
		}
	});

	it( 'should return an error if provided an `allowHalfOpen` option which is not a boolean primitive', function test() {
		var values, err;

		values = [
			5,
			'5',
			undefined,
			null,
			NaN,
			[],
			{},
			function(){}
		];

		for ( var i = 0; i < values.length; i++ ) {
			err = validate( {}, {
				'allowHalfOpen': values[ i ]
			});
			assert.isTrue( err instanceof TypeError );
		}
	});

	it( 'should return an error if provided a high water mark option which is not a nonnegative number', function test() {
		var values, err;

		values = [
			-5,
			'5',
			undefined,
			null,
			NaN,
			[],
			{},
			function(){}
		];

		for ( var i = 0; i < values.length; i++ ) {
			err = validate( {}, {
				'highWaterMark': values[ i ]
			});
			assert.isTrue( err instanceof TypeError );
		}
	});

	it( 'should return null if all options are valid', function test() {
		var err;

		err = validate( {}, {
			'objectMode': true,
			'writableObjectMode': true,
			'encoding': 'base64',
			'allowHalfOpen': true,
			'highWaterMark': 64
		});

		assert.isNull( err );

		err = validate( {}, {
			'beep': true, // misc options
			'boop': 'bop'
		});

		assert.isNull( err );
	});

});
<commit_msg>[TESTS] update positive validation check.<commit_after>/* global require, describe, it */
'use strict';

// MODULES //

var chai = require( 'chai' ),
	validate = require( './../lib/validate.js' );

// VARIABLES //

var expect = chai.expect,
	assert = chai.assert;

// TESTS //

describe( 'validate', function tests() {

	it( 'should export a function', function test() {
		expect( validate ).to.be.a( 'function' );
	});

	it( 'should return an error if provided an options argument which is not an object', function test() {
		var values = [
			'5',
			5,
			true,
			undefined,
			null,
			NaN,
			function(){},
			[]
		];

		for ( var i = 0; i < values.length; i++ ) {
			assert.isTrue( validate( {}, values[ i ] ) instanceof TypeError );
		}
	});

	it( 'should return an error if provided a separator option which is not a string or regular expression', function test() {
		var values, err;

		values = [
			5,
			undefined,
			null,
			NaN,
			[],
			{},
			function(){}
		];

		for ( var i = 0; i < values.length; i++ ) {
			err = validate( {}, {
				'sep': values[ i ]
			});
			assert.isTrue( err instanceof TypeError );
		}
	});

	it( 'should return an error if provided an object mode option which is not a boolean primitive', function test() {
		var values, err;

		values = [
			5,
			'5',
			undefined,
			null,
			NaN,
			[],
			{},
			function(){}
		];

		for ( var i = 0; i < values.length; i++ ) {
			err = validate( {}, {
				'objectMode': values[ i ]
			});
			assert.isTrue( err instanceof TypeError );
		}
	});

	it( 'should return an error if provided a `writableObjectMode` option which is not a boolean primitive', function test() {
		var values, err;

		values = [
			5,
			'5',
			undefined,
			null,
			NaN,
			[],
			{},
			function(){}
		];

		for ( var i = 0; i < values.length; i++ ) {
			err = validate( {}, {
				'writableObjectMode': values[ i ]
			});
			assert.isTrue( err instanceof TypeError );
		}
	});

	it( 'should return an error if provided an encoding option which is not a string primitive', function test() {
		var values, err;

		values = [
			5,
			true,
			undefined,
			null,
			NaN,
			[],
			{},
			function(){}
		];

		for ( var i = 0; i < values.length; i++ ) {
			err = validate( {}, {
				'encoding': values[ i ]
			});
			assert.isTrue( err instanceof TypeError );
		}
	});

	it( 'should return an error if provided an `allowHalfOpen` option which is not a boolean primitive', function test() {
		var values, err;

		values = [
			5,
			'5',
			undefined,
			null,
			NaN,
			[],
			{},
			function(){}
		];

		for ( var i = 0; i < values.length; i++ ) {
			err = validate( {}, {
				'allowHalfOpen': values[ i ]
			});
			assert.isTrue( err instanceof TypeError );
		}
	});

	it( 'should return an error if provided a high water mark option which is not a nonnegative number', function test() {
		var values, err;

		values = [
			-5,
			'5',
			undefined,
			null,
			NaN,
			[],
			{},
			function(){}
		];

		for ( var i = 0; i < values.length; i++ ) {
			err = validate( {}, {
				'highWaterMark': values[ i ]
			});
			assert.isTrue( err instanceof TypeError );
		}
	});

	it( 'should return null if all options are valid', function test() {
		var err;

		err = validate( {}, {
			'sep': /\t/,
			'objectMode': true,
			'writableObjectMode': true,
			'encoding': 'base64',
			'allowHalfOpen': true,
			'highWaterMark': 64
		});

		assert.isNull( err );

		err = validate( {}, {
			'beep': true, // misc options
			'boop': 'bop'
		});

		assert.isNull( err );
	});

});
<|endoftext|>


<commit_before>/* dendry
 * http://github.com/idmillington/dendry
 *
 * MIT License
 */
/*jshint indent:2 */
(function() {
  "use strict";

  var _ = require('lodash');
  var should = require('should');
  // Disable errors from using the should library.
  /*jshint -W030 */

  var compiler = require('../lib/compiler');

  describe("game compiler", function() {

    it("should compile a simple two-scene game", function(done) {
      var info = {
        title: "My Game",
        author: "Jo Doe"
      };
      var listOfScenes = [
        {id: "root", title:"Back to root", content: "Root content", options: {
          options:[{id:"@foo", title:"Foo link"}]
        }},
        {id: "foo", title:"The Foo", content:"Foo content", options: {
          options:[{id:"@foo", title:"Foo link"}]
        }}
      ];
      compiler.compile(info, listOfScenes, function(err, game) {
        (!!err).should.be.false;
        game.scenes.foo.title.should.equal('The Foo');
        done();
      });
    });

    it("should fail on another scene with the same id", function(done) {
      var info = {
        title: "My Game",
        author: "Jo Doe"
      };
      var listOfScenes = [
        {id: "root", title:"Back to root", content: "Root content", options: {
          options:[{id:"@foo", title:"Foo link"}]
        }},
        {id: "root", title:"The Root", content:"More Root content", options: {
          options:[{id:"@foo", title:"Foo link"}]
        }}
      ];
      compiler.compile(info, listOfScenes, function(err, game) {
        (!!err).should.be.true;
        err.toString().should.equal(
          "Error: Duplicate scenes with id 'root' found.");
        (game === undefined).should.be.true;
        done();
      });
    });

    it("should add sections as scenes", function(done) {
      var info = {
        title: "My Game",
        author: "Jo Doe"
      };
      var listOfScenes = [
        {id: "root", title:"Back to root", content: "Root content",
         tags: ["alpha", "bravo"],
         sections: [
           {id: "root.foo", title:"The Foo", content:"Foo content",
            tags: ["alpha", "charlie"],
            options: {
              options:[{id:"@foo", title:"Foo link"}]}
           }
         ],
         options: {
           options:[{id:"@foo", title:"Foo link"}]
         }},
      ];
      compiler.compile(info, listOfScenes, function(err, game) {
        (!!err).should.be.false;
        game.tagLookup.alpha.should.eql({root: true, "root.foo": true});
        game.tagLookup.bravo.should.eql({root: true});
        game.tagLookup.charlie.should.eql({"root.foo": true});
        done();
      });
    });

    it("should fail with duplicate id", function(done) {
      var info = {
        title: "My Game",
        author: "Jo Doe"
      };
      var listOfScenes = [
        {id: "root", title:"Root", content: "Root."},
        {id: "root", title:"Root Two", content: "Root Two."},
      ];
      compiler.compile(info, listOfScenes, function(err, game) {
        (!!err).should.be.true;
        err.toString().should.equal(
          "Error: Duplicate scenes with id 'root' found.");
        (game === undefined).should.be.true;
        done();
      });
    });

    it("should fail with duplicate section id", function(done) {
      var info = {
        title: "My Game",
        author: "Jo Doe"
      };
      var listOfScenes = [
        {id: "root.foo", title:"Explicit Root Foo", content: "Root Foo."},
        {id: "root", title:"Root", content: "Root.",
         sections: [{id: "foo", title:"Root Foo", content:"Root Foo."}],
        }
      ];
      compiler.compile(info, listOfScenes, function(err, game) {
        (!!err).should.be.true;
        err.toString().should.equal(
          "Error: Duplicate scenes with id 'root.foo' found.");
        (game === undefined).should.be.true;
        done();
      });
    });

    it("should index scene tags", function(done) {
      var info = {
        title: "My Game",
        author: "Jo Doe"
      };
      var listOfScenes = [
        {id: "root", title:"Back to root", content: "Root content",
         tags: ["alpha", "bravo"],
         options: {
          options:[{id:"@foo", title:"Foo link"}]
        }},
        {id: "foo", title:"The Foo", content:"Foo content",
         tags: ["alpha", "charlie"],
         options: {
          options:[{id:"@foo", title:"Foo link"}]
        }}
      ];
      compiler.compile(info, listOfScenes, function(err, game) {
        (!!err).should.be.false;
        game.tagLookup.alpha.should.eql({root: true, foo: true});
        game.tagLookup.bravo.should.eql({root: true});
        game.tagLookup.charlie.should.eql({foo: true});
        done();
      });
    });

    describe("id inheritance", function() {
      it("should set nested id, if not already nested", function(done) {
        var info = {title: "My Game", author: "Jo Doe"};
        var listOfScenes = [
          {id: "root", title:"Root scene", content:"Root content",
           sections: [
             {id: "one", title:"One", content:"One."},
             {id: "two", title:"Two", content:"Two."},
           ]}
        ];
        compiler.compile(info, listOfScenes, function(err, game) {
          (!!err).should.be.false;
          (!!game.scenes.one).should.be.false;
          (!!game.scenes.two).should.be.false;
          (!!game.scenes["root.one"]).should.not.be.false;
          (!!game.scenes["root.two"]).should.not.be.false;
          done();
        });
      });

      it("should inherit parent id in option", function(done) {
        var info = {title: "My Game", author: "Jo Doe"};
        var listOfScenes = [
          {id: "root", title:"Root scene", content:"Root content",
           sections: [
             {id: "root.one", title:"One", content:"One.",
              options:{
                options:[{id:"@two", title:"Two"}]
              }},
             {id: "root.two", title:"Two", content:"Two."},
           ]}
        ];
        compiler.compile(info, listOfScenes, function(err, game) {
          (!!err).should.be.false;
          game.scenes["root.one"].options.options[0].id.
            should.equal("@root.two");
          done();
        });
      });

      it("should ignore tag in option", function(done) {
        var info = {title: "My Game", author: "Jo Doe"};
        var listOfScenes = [
          {id: "root", title:"Root scene", content:"Root content",
           sections: [
             {id: "root.one", title:"One", content:"One.",
              options:{
                options:[{id:"#tag", title:"Two"}]
              }},
             {id: "root.two", title:"Two", content:"Two."},
           ]}
        ];
        compiler.compile(info, listOfScenes, function(err, game) {
          (!!err).should.be.false;
          game.scenes["root.one"].options.options[0].id.should.equal("#tag");
          done();
        });
      });

      it("should use own id as context in option", function(done) {
        var info = {title: "My Game", author: "Jo Doe"};
        var listOfScenes = [
          {id: "root", title:"Root scene", content:"Root content",
           options: {
             options: [{id:"@one", title:"One"}]
           },
           sections: [
             {id: "root.one", title:"One", content:"One."}
           ]}
        ];
        compiler.compile(info, listOfScenes, function(err, game) {
          (!!err).should.be.false;
          game.scenes.root.options.options[0].id.should.equal("@root.one");
          done();
        });
      });

      it("should inherit parent id in goto", function(done) {
        var info = {title: "My Game", author: "Jo Doe"};
        var listOfScenes = [
          {id: "root", title:"Root scene", content:"Root content",
           sections: [
             {id: "root.one", title:"One", content:"One.", goTo:"two"},
             {id: "root.two", title:"Two", content:"Two."}
           ]}
        ];
        compiler.compile(info, listOfScenes, function(err, game) {
          (!!err).should.be.false;
          game.scenes["root.one"].goTo.should.equal("root.two");
          done();
        });
      });

      it("should fail if there's no matching goto id", function(done) {
        var info = {title: "My Game", author: "Jo Doe"};
        var listOfScenes = [
          {id: "root", title:"Root scene", content:"Root content",
           sections: [
             {id: "root.one", title:"One", content:"One.", goTo:"three"},
             {id: "root.two", title:"Two", content:"Two."}
           ]}
        ];
        compiler.compile(info, listOfScenes, function(err, game) {
          (!!err).should.be.true;
          err.toString().should.equal(
            "Error: Couldn't find an id matching 'three' in 'root.one'."
          );
          done();
        });
      });

      it("should fail if there's no matching option id", function(done) {
        var info = {title: "My Game", author: "Jo Doe"};
        var listOfScenes = [
          {id: "root", title:"Root scene", content:"Root content",
           sections: [
             {id: "root.one", title:"One", content:"One.",
              options:{
                options:[{id:"@three"}]
              }},
             {id: "root.two", title:"Two", content:"Two."}
           ]}
        ];
        compiler.compile(info, listOfScenes, function(err, game) {
          (!!err).should.be.true;
          err.toString().should.equal(
            "Error: Couldn't find an id matching 'three' in 'root.one'."
          );
          done();
        });
      });

    }); // end id inheritance

  });
}());
<commit_msg>Remove duplicate test.<commit_after>/* dendry
 * http://github.com/idmillington/dendry
 *
 * MIT License
 */
/*jshint indent:2 */
(function() {
  "use strict";

  var _ = require('lodash');
  var should = require('should');
  // Disable errors from using the should library.
  /*jshint -W030 */

  var compiler = require('../lib/compiler');

  describe("game compiler", function() {

    it("should compile a simple two-scene game", function(done) {
      var info = {
        title: "My Game",
        author: "Jo Doe"
      };
      var listOfScenes = [
        {id: "root", title:"Back to root", content: "Root content", options: {
          options:[{id:"@foo", title:"Foo link"}]
        }},
        {id: "foo", title:"The Foo", content:"Foo content", options: {
          options:[{id:"@foo", title:"Foo link"}]
        }}
      ];
      compiler.compile(info, listOfScenes, function(err, game) {
        (!!err).should.be.false;
        game.scenes.foo.title.should.equal('The Foo');
        done();
      });
    });

    it("should add sections as scenes", function(done) {
      var info = {
        title: "My Game",
        author: "Jo Doe"
      };
      var listOfScenes = [
        {id: "root", title:"Back to root", content: "Root content",
         tags: ["alpha", "bravo"],
         sections: [
           {id: "root.foo", title:"The Foo", content:"Foo content",
            tags: ["alpha", "charlie"],
            options: {
              options:[{id:"@foo", title:"Foo link"}]}
           }
         ],
         options: {
           options:[{id:"@foo", title:"Foo link"}]
         }},
      ];
      compiler.compile(info, listOfScenes, function(err, game) {
        (!!err).should.be.false;
        game.tagLookup.alpha.should.eql({root: true, "root.foo": true});
        game.tagLookup.bravo.should.eql({root: true});
        game.tagLookup.charlie.should.eql({"root.foo": true});
        done();
      });
    });

    it("should fail with duplicate id", function(done) {
      var info = {
        title: "My Game",
        author: "Jo Doe"
      };
      var listOfScenes = [
        {id: "root", title:"Root", content: "Root."},
        {id: "root", title:"Root Two", content: "Root Two."},
      ];
      compiler.compile(info, listOfScenes, function(err, game) {
        (!!err).should.be.true;
        err.toString().should.equal(
          "Error: Duplicate scenes with id 'root' found.");
        (game === undefined).should.be.true;
        done();
      });
    });

    it("should fail with duplicate section id", function(done) {
      var info = {
        title: "My Game",
        author: "Jo Doe"
      };
      var listOfScenes = [
        {id: "root.foo", title:"Explicit Root Foo", content: "Root Foo."},
        {id: "root", title:"Root", content: "Root.",
         sections: [{id: "foo", title:"Root Foo", content:"Root Foo."}],
        }
      ];
      compiler.compile(info, listOfScenes, function(err, game) {
        (!!err).should.be.true;
        err.toString().should.equal(
          "Error: Duplicate scenes with id 'root.foo' found.");
        (game === undefined).should.be.true;
        done();
      });
    });

    it("should index scene tags", function(done) {
      var info = {
        title: "My Game",
        author: "Jo Doe"
      };
      var listOfScenes = [
        {id: "root", title:"Back to root", content: "Root content",
         tags: ["alpha", "bravo"],
         options: {
          options:[{id:"@foo", title:"Foo link"}]
        }},
        {id: "foo", title:"The Foo", content:"Foo content",
         tags: ["alpha", "charlie"],
         options: {
          options:[{id:"@foo", title:"Foo link"}]
        }}
      ];
      compiler.compile(info, listOfScenes, function(err, game) {
        (!!err).should.be.false;
        game.tagLookup.alpha.should.eql({root: true, foo: true});
        game.tagLookup.bravo.should.eql({root: true});
        game.tagLookup.charlie.should.eql({foo: true});
        done();
      });
    });

    describe("id inheritance", function() {
      it("should set nested id, if not already nested", function(done) {
        var info = {title: "My Game", author: "Jo Doe"};
        var listOfScenes = [
          {id: "root", title:"Root scene", content:"Root content",
           sections: [
             {id: "one", title:"One", content:"One."},
             {id: "two", title:"Two", content:"Two."},
           ]}
        ];
        compiler.compile(info, listOfScenes, function(err, game) {
          (!!err).should.be.false;
          (!!game.scenes.one).should.be.false;
          (!!game.scenes.two).should.be.false;
          (!!game.scenes["root.one"]).should.not.be.false;
          (!!game.scenes["root.two"]).should.not.be.false;
          done();
        });
      });

      it("should inherit parent id in option", function(done) {
        var info = {title: "My Game", author: "Jo Doe"};
        var listOfScenes = [
          {id: "root", title:"Root scene", content:"Root content",
           sections: [
             {id: "root.one", title:"One", content:"One.",
              options:{
                options:[{id:"@two", title:"Two"}]
              }},
             {id: "root.two", title:"Two", content:"Two."},
           ]}
        ];
        compiler.compile(info, listOfScenes, function(err, game) {
          (!!err).should.be.false;
          game.scenes["root.one"].options.options[0].id.
            should.equal("@root.two");
          done();
        });
      });

      it("should ignore tag in option", function(done) {
        var info = {title: "My Game", author: "Jo Doe"};
        var listOfScenes = [
          {id: "root", title:"Root scene", content:"Root content",
           sections: [
             {id: "root.one", title:"One", content:"One.",
              options:{
                options:[{id:"#tag", title:"Two"}]
              }},
             {id: "root.two", title:"Two", content:"Two."},
           ]}
        ];
        compiler.compile(info, listOfScenes, function(err, game) {
          (!!err).should.be.false;
          game.scenes["root.one"].options.options[0].id.should.equal("#tag");
          done();
        });
      });

      it("should use own id as context in option", function(done) {
        var info = {title: "My Game", author: "Jo Doe"};
        var listOfScenes = [
          {id: "root", title:"Root scene", content:"Root content",
           options: {
             options: [{id:"@one", title:"One"}]
           },
           sections: [
             {id: "root.one", title:"One", content:"One."}
           ]}
        ];
        compiler.compile(info, listOfScenes, function(err, game) {
          (!!err).should.be.false;
          game.scenes.root.options.options[0].id.should.equal("@root.one");
          done();
        });
      });

      it("should inherit parent id in goto", function(done) {
        var info = {title: "My Game", author: "Jo Doe"};
        var listOfScenes = [
          {id: "root", title:"Root scene", content:"Root content",
           sections: [
             {id: "root.one", title:"One", content:"One.", goTo:"two"},
             {id: "root.two", title:"Two", content:"Two."}
           ]}
        ];
        compiler.compile(info, listOfScenes, function(err, game) {
          (!!err).should.be.false;
          game.scenes["root.one"].goTo.should.equal("root.two");
          done();
        });
      });

      it("should fail if there's no matching goto id", function(done) {
        var info = {title: "My Game", author: "Jo Doe"};
        var listOfScenes = [
          {id: "root", title:"Root scene", content:"Root content",
           sections: [
             {id: "root.one", title:"One", content:"One.", goTo:"three"},
             {id: "root.two", title:"Two", content:"Two."}
           ]}
        ];
        compiler.compile(info, listOfScenes, function(err, game) {
          (!!err).should.be.true;
          err.toString().should.equal(
            "Error: Couldn't find an id matching 'three' in 'root.one'."
          );
          done();
        });
      });

      it("should fail if there's no matching option id", function(done) {
        var info = {title: "My Game", author: "Jo Doe"};
        var listOfScenes = [
          {id: "root", title:"Root scene", content:"Root content",
           sections: [
             {id: "root.one", title:"One", content:"One.",
              options:{
                options:[{id:"@three"}]
              }},
             {id: "root.two", title:"Two", content:"Two."}
           ]}
        ];
        compiler.compile(info, listOfScenes, function(err, game) {
          (!!err).should.be.true;
          err.toString().should.equal(
            "Error: Couldn't find an id matching 'three' in 'root.one'."
          );
          done();
        });
      });

    }); // end id inheritance

  });
}());
<|endoftext|>