<commit_before>/**
 * Voicemail Main module unit tests.
 *
 * @module tests-voicemail-main
 * @copyright 2014, Digium, Inc.
 * @license Apache License, Version 2.0
 * @author Samuel Fortier-Galarneau <sgalarneau@digium.com>
 */

'use strict';

/*global describe:false*/
/*global beforeEach:false*/
/*global afterEach:false*/
/*global it:false*/

var assert = require('assert');
var mockery = require('mockery');
var Q = require('q');
var util = require('util');
var Emitter = require('events').EventEmitter;

var mockClient;
// milliseconds to delay async ops for mock requests
var asyncDelay = 100;
var mockeryOpts = {
  warnOnReplace: false,
  warnOnUnregistered: false,
  useCleanCache: true
};
// used to track whether fsm was created after StasisStart event
var fsmCreated = false;

/**
 * Returns a mock client that to allow a single EventEmitter to be
 * used for testing.
 *
 * The mock client is cached so tests can access it to emit events if
 * necessary.
 */
var getMockClient = function() {

  if (mockClient) {
    return mockClient;
  }

  var Client = function() {
    this.start = function() {
      var self = this;

      process.nextTick(function() {
        self.emit('StasisStart');
      });
    };
  };
  util.inherits(Client, Emitter);

  mockClient = new Client();

  return mockClient;
};

/**
 * Mock Voicemail FSM for testing.
 */
var getMockFsm = function() {
  return configure;

  function configure() {
    var fsm = {
      create: function(event, channel) {
        fsmCreated = true;
      }
    };

    return fsm;
  }
};

describe('voicemail-main', function() {

  beforeEach(function(done) {

    mockery.enable(mockeryOpts);

    var clientMock = {
      getClient: function(config, appName) {
        var deferred = Q.defer();

        if (config.url && config.username &&
            config.password && appName) {
          deferred.resolve(getMockClient());
        }

        return deferred.promise;
      }
    };
    var loggingMock = {
      create: function() {
        return {
          trace: function() {},
          debug: function() {},
          info: function() {},
          warn: function() {},
          error: function() {},
          fatal: function() {}
        };
      }
    };

    mockery.registerMock('ari-client-wrapper', clientMock);
    mockery.registerMock('voicemail-logging', loggingMock);
    mockery.registerMock('voicemail-main-fsm', getMockFsm());

    done();
  });

  afterEach(function(done) {
    mockery.disable();
    fsmCreated = false;

    done();
  });

  it('should configure StasisStart handler', function(done) {
    var voicemailMain = require('../lib/voicemail-main.js');

    voicemailMain.create();
    checkSuccess();
    getMockClient().start();

    // call done if fsm was created
    function checkSuccess() {
      setTimeout(function() {
        if (fsmCreated) {
          done();
        } else{
          checkSuccess();
        }
      }, asyncDelay);
    }
  });

});
<commit_msg>Fixed test error due to logging changes.<commit_after>/**
 * Voicemail Main module unit tests.
 *
 * @module tests-voicemail-main
 * @copyright 2014, Digium, Inc.
 * @license Apache License, Version 2.0
 * @author Samuel Fortier-Galarneau <sgalarneau@digium.com>
 */

'use strict';

/*global describe:false*/
/*global beforeEach:false*/
/*global afterEach:false*/
/*global it:false*/

var assert = require('assert');
var mockery = require('mockery');
var Q = require('q');
var util = require('util');
var Emitter = require('events').EventEmitter;

var mockClient;
// milliseconds to delay async ops for mock requests
var asyncDelay = 100;
var mockeryOpts = {
  warnOnReplace: false,
  warnOnUnregistered: false,
  useCleanCache: true
};
// used to track whether fsm was created after StasisStart event
var fsmCreated = false;

/**
 * Returns a mock client that to allow a single EventEmitter to be
 * used for testing.
 *
 * The mock client is cached so tests can access it to emit events if
 * necessary.
 */
var getMockClient = function() {

  if (mockClient) {
    return mockClient;
  }

  var Client = function() {
    this.start = function() {
      var self = this;

      process.nextTick(function() {
        self.emit('StasisStart');
      });
    };
  };
  util.inherits(Client, Emitter);

  mockClient = new Client();

  return mockClient;
};

/**
 * Mock Voicemail FSM for testing.
 */
var getMockFsm = function() {
  return configure;

  function configure() {
    var fsm = {
      create: function(event, channel) {
        fsmCreated = true;
      }
    };

    return fsm;
  }
};

describe('voicemail-main', function() {

  beforeEach(function(done) {

    mockery.enable(mockeryOpts);

    var clientMock = {
      getClient: function(config, appName) {
        var deferred = Q.defer();

        if (config.url && config.username &&
            config.password && appName) {
          deferred.resolve(getMockClient());
        }

        return deferred.promise;
      }
    };
    var loggingMock = {
      create: function() {
        return {
          trace: function() {},
          debug: function() {},
          info: function() {},
          warn: function() {},
          error: function() {},
          fatal: function() {},
          child: function() {
            return this;
          }
        };
      }
    };

    mockery.registerMock('ari-client-wrapper', clientMock);
    mockery.registerMock('voicemail-logging', loggingMock);
    mockery.registerMock('voicemail-main-fsm', getMockFsm());

    done();
  });

  afterEach(function(done) {
    mockery.disable();
    fsmCreated = false;

    done();
  });

  it('should configure StasisStart handler', function(done) {
    var voicemailMain = require('../lib/voicemail-main.js');

    voicemailMain.create();
    checkSuccess();
    getMockClient().start();

    // call done if fsm was created
    function checkSuccess() {
      setTimeout(function() {
        if (fsmCreated) {
          done();
        } else{
          checkSuccess();
        }
      }, asyncDelay);
    }
  });

});
<|endoftext|>


<commit_before>module.exports = function(grunt) {

  // Project configuration.
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    dust: {
      default: {
        files: [{
          expand: true,
          cwd: 'src/templates/dusts/',
          src: ['*.dust'],
          dest: 'dist/templates/dusts/',
          ext: '.js'
        }],
        options: {
          relative: true,
          runtime: false,
          amd: false
        }
      },
    },
    concat: {
      options: {
        // define a string to put between each file in the concatenated output
        separator: ';'
      },
      dist: {
        // the files to concatenate
        src: ['dist/templates/dusts/*.js', 'src/javascript/<%= pkg.name %>.js'],
        // the location of the resulting JS file
        dest: 'dist/js/<%= pkg.name %>.js'
      }
    },
    uglify: {
      options: {
        banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
      },
      dist: {
        files: {
          'public/js/<%= pkg.name %>.min.js': ['<%= concat.dist.dest %>'],
          'public/js/<%= pkg.name %>-data.min.js': ['src/javascript/<%= pkg.name %>-data.js']
        }
      }
    },
    watch: {
      dust: {
        files: ['src/templates/dusts/*.dust'],
        tasks: ['dust', 'concat', 'uglify']
      },
      javascript: {
        files: ['src/javascript/*.js'],
        tasks: ['concat', 'uglify']
      }
    }
  });

  grunt.loadNpmTasks('grunt-dust');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-concat');

  grunt.registerTask('default', ['dust', 'concat', 'uglify']);

};<commit_msg>Removed some unneeded comments<commit_after>module.exports = function(grunt) {

  // Project configuration.
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    dust: {
      default: {
        files: [{
          expand: true,
          cwd: 'src/templates/dusts/',
          src: ['*.dust'],
          dest: 'dist/templates/dusts/',
          ext: '.js'
        }],
        options: {
          relative: true,
          runtime: false,
          amd: false
        }
      },
    },
    concat: {
      options: {
        separator: ';'
      },
      dist: {
        src: ['dist/templates/dusts/*.js', 'src/javascript/<%= pkg.name %>.js'],
        dest: 'dist/js/<%= pkg.name %>.js'
      }
    },
    uglify: {
      options: {
        banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
      },
      dist: {
        files: {
          'public/js/<%= pkg.name %>.min.js': ['<%= concat.dist.dest %>'],
          'public/js/<%= pkg.name %>-data.min.js': ['src/javascript/<%= pkg.name %>-data.js']
        }
      }
    },
    watch: {
      dust: {
        files: ['src/templates/dusts/*.dust'],
        tasks: ['dust', 'concat', 'uglify']
      },
      javascript: {
        files: ['src/javascript/*.js'],
        tasks: ['concat', 'uglify']
      }
    }
  });

  grunt.loadNpmTasks('grunt-dust');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-concat');

  grunt.registerTask('default', ['dust', 'concat', 'uglify']);

};<|endoftext|>


<commit_before>'use strict';

/*global describe, it*/
var assert = require('assert');
var colors = require('mocha/lib/reporters/base').colors;
var debug = require('debug')('validator');
var childProcess = require('child_process');
var fs = require('fs');
var parallel = require('mocha.parallel');
var path = require('path');
var RSVP = require('rsvp');
var skeemas = require('skeemas');
var unirest = require('unirest');

// setup mocha color scheme
// 32 = console code for green
colors.pass = 32;

// Tries to parse a json string and asserts with a friendly
// message if something is wrong
function tryParse(fileName, jsonStringData) {
  var object;

  try {
    object = JSON.parse(jsonStringData);
  } catch (e) {
    assert(false, fileName + ' is not valid JSON. Copy and paste the contents to https://jsonformatter.curiousconcept.com/ and correct the syntax errors. Error: ' + e.toString());
  }

  return object;
}

const filePathExistsMap = {};

function fileExists(filePath) {
  if (!(filePath in filePathExistsMap)) {
    filePathExistsMap[filePath] = fs.existsSync(filePath);
  }
  return filePathExistsMap[filePath];
}

const jsonFileContentsMap = {};

function readJSONFile(filePath) {
  if (!(filePath in jsonFileContentsMap)) {
    if (fileExists(filePath)) {
      const fileContents = fs.readFileSync(filePath, {
        encoding: 'utf-8'
      });
      jsonFileContentsMap[filePath] = tryParse(filePath, fileContents.trim());
    } else {
      jsonFileContentsMap[filePath] = null;
    }
  }
  return jsonFileContentsMap[filePath];
}

function isDefined(value) {
  return value !== null && value !== undefined && value !== '';
}

// this is required to keep travis from timing out
// due to lack of console output
function timedOutput(onOff, intervalObject) {
  if (onOff) {
    return setInterval(function () {
      process.stdout.write('...');
    }, 60 * 1000);
  } else {
    clearTimeout(intervalObject);
  }
}

function getEnvironmentVariableBoolean(variableName, defaultValue) {
  let result = defaultValue;

  if (variableName) {
    const variableValue = process.env[variableName];
    if (variableValue) {
      if (typeof variableValue === 'string') {
        result = (variableValue.toLowerCase() === 'true');
      }
    }
  }

  return result;
}

function validateTemplate(requestBody, templateFilePath) {
  var validatePromise;
  if (getEnvironmentVariableBoolean('VALIDATION_SKIP_VALIDATE')) {
    validatePromise = RSVP.resolve({});
  } else {
    // Calls a remote url which will validate the template and parameters
    if (process.env.TRAVIS_PULL_REQUEST &&
      process.env.TRAVIS_PULL_REQUEST !== 'false') {
      requestBody.pull_request = process.env.TRAVIS_PULL_REQUEST;
    }

    var templateObject = requestBody.template;

    // validate the template paramters, particularly the description field
    assert(templateObject.parameters, 'Expected a \'.parameters\' field within the deployment template');
    for (var parameterName in templateObject.parameters) {
      if (typeof parameterName === 'string') {
        assert(templateObject.parameters[parameterName].metadata,
          templateFilePath + ' - Parameter \"' + parameterName + '\" is missing its \"metadata\" property');
        assert(templateObject.parameters[parameterName].metadata.description,
          templateFilePath + ' - Parameter \"' + parameterName + '\" is missing its \"description\" field within the metadata property');
      }
    }

    validatePromise = new RSVP.Promise(function (resolve, reject) {
      unirest.post(process.env.VALIDATION_HOST + '/validate')
        .type('json')
        .send(JSON.stringify(requestBody))
        .end(function (response) {
          if (response.status !== 200) {
            reject(response);
          } else {
            resolve(response.body);
          }
        });
    });
  }
  return validatePromise;
}

function deployTemplate(requestBody) {
  var deployPromise;
  if (getEnvironmentVariableBoolean('VALIDATION_SKIP_DEPLOY')) {
    deployPromise = RSVP.resolve({});
  } else {
    if (process.env.TRAVIS_PULL_REQUEST &&
      process.env.TRAVIS_PULL_REQUEST !== 'false') {
      requestBody.pull_request = process.env.TRAVIS_PULL_REQUEST;
    }

    var intervalObj = timedOutput(true);
    debug('making deploy request');

    // Calls a remote url which will deploy the template
    deployPromise = new RSVP.Promise(function (resolve, reject) {
      return unirest.post(process.env.VALIDATION_HOST + '/deploy')
        .type('json')
        .timeout(3600 * 1000) // Templates can take a long time to deploy, so set the timeout to 1 hour
        .send(JSON.stringify(requestBody))
        .end(function (response) {
          timedOutput(false, intervalObj);
          debug(response.status);
          debug(response.body);

          // 202 is the long poll response
          // anything else is really bad
          if (response.status !== 202) {
            reject(response.body);
          }

          if (response.body.result === 'Deployment Successful') {
            resolve(response.body);
          } else {
            reject(response.body);
          }
        });
    });
  }
  return deployPromise;
}

function assertFileExists(filePath) {
  assert(fileExists(filePath), filePath + ' should exist.');
}

function itExists(filePath) {
  it('exists', function () {
    assertFileExists(filePath);
  });
}

describe('Template', function () {
  this.timeout(7100 * 1000);

  const validateModifiedOnly = getEnvironmentVariableBoolean('VALIDATE_MODIFIED_ONLY', false);
  const runRemoteValidation = !getEnvironmentVariableBoolean('VALIDATION_SKIP_VALIDATE');
  const runRemoteDeployment = !getEnvironmentVariableBoolean('VALIDATION_SKIP_DEPLOY');

  var modifiedDirectories = {};
  if (validateModifiedOnly) {
    // we automatically reset to the beginning of the commit range
    // so this includes all file paths that have changed for the CI run
    assert(process.env.TRAVIS_COMMIT_RANGE, 'VALIDATE_MODIFIED_ONLY requires TRAVIS_COMMIT_RANGE to be set to [START_COMMIT_HASH]...[END_COMMIT_HASH]');

    const modifiedPaths = childProcess.execSync('git diff --name-only ' + process.env.TRAVIS_COMMIT_RANGE, {
      encoding: 'utf8'
    }).split('\n');
    debug(modifiedPaths);

    assert(modifiedPaths.length !== 0, 'No changes were detected in your commit. Verify you added files and try again.');

    if (modifiedPaths) {
      for (var i = 0; i < modifiedPaths.length; i += 1) {
        var modifiedDirectoryPath = path.dirname(modifiedPaths[i]);
        // don't include the top level dir
        if (modifiedDirectoryPath !== '.') {
          modifiedDirectories[modifiedDirectoryPath] = true;
        }
      }
    }
  }

  // Generates the mocha tests based on directories in the existing repo.
  var srcPath = './';
  var testDirectories = fs.readdirSync(srcPath).filter(function (fileEntry) {
    var fileEntryPath = path.join(srcPath, fileEntry);
    return fs.statSync(fileEntryPath).isDirectory() &&
      fileEntry !== '.git' &&
      fileEntry !== 'node_modules' &&
      !fileExists(path.join(fileEntryPath, '.ci_skip')) &&
      // if we are only validating modified templates
      // only add test if this directory template has been modified
      (!validateModifiedOnly || modifiedDirectories[fileEntry]);
  });

  describe('Local Validation', function () {
    testDirectories.forEach(function (testDirectory) {
      describe(testDirectory, function () {
        describe('README.md', function () {
          itExists(path.join(testDirectory, 'README.md'));
        });

        describe('metadata.json', function () {
          const metadataFilePath = path.join(testDirectory, 'metadata.json');

          itExists(metadataFilePath);

          it('matches schema', function () {
            const schemaFilePath = path.join(__dirname, 'metadata.schema.json');
            assertFileExists(schemaFilePath, 'The provided JSON schema file path "' + schemaFilePath + '" doesn\'t exist.');

            const jsonSchemaObject = readJSONFile(schemaFilePath);
            var schemaValidationResult = skeemas.validate(readJSONFile(metadataFilePath), jsonSchemaObject);

            if (!schemaValidationResult.valid) {
              var schemaValidationErrorMessages = '';
              schemaValidationResult.errors.forEach(function (error) {
                schemaValidationErrorMessages += (error.context + ':' + error.message + '\n');
              });
              assert(false, schemaValidationErrorMessages);
            }
          });

          it('No HTML in description', function () {
            const metadataObject = readJSONFile(metadataFilePath);
            const description = metadataObject.description;
            const htmlDetectionRegex = /<[a-z][\s\S]*>/i;
            assert(!(htmlDetectionRegex).test(description), metadataFilePath + ' - Contains possible HTML elements which are not allowed');
          });

          it('dateUpdated not in the future', function () {
            const metadataObject = readJSONFile(metadataFilePath);
            const date = new Date(metadataObject.dateUpdated);
            const currentTime = new Date(Date.now());
            assert(date < currentTime, metadataFilePath + ' - dateUpdated field should not be in the future');
          });
        });

        describe('Validate azuredeploy.parameters.json', function () {
          const parametersFilePath = path.join(testDirectory, 'azuredeploy.parameters.json');

          itExists(parametersFilePath);

          it('has a value or reference property for each parameter', function () {
            const parametersObject = readJSONFile(parametersFilePath);
            assert(parametersObject, 'Parameters file doesn\'t exist or isn\'t a valid JSON value.');
            assert(parametersObject.parameters, parametersFilePath + ' - Expected a \'.parameters\' field within the parameters file');
            for (var parameterName in parametersObject.parameters) {
              if (typeof parameterName === 'string') {
                var parameterObject = parametersObject.parameters[parameterName];
                assert(isDefined(parameterObject.value) || isDefined(parameterObject.reference),
                  parametersFilePath + ' - Parameter \"' + parameterName + '\" should have a \"value\" or \"reference\" property.');
              }
            }
          });
        });

        describe('azuredeploy.json', function () {
          const templateFilePath = path.join(testDirectory, 'azuredeploy.json');

          itExists(templateFilePath);
        });
      });
    });
  });

  if (runRemoteValidation || runRemoteDeployment) {
    // Group tests in chunks defined by an environment variable or by the default value.
    // we probably shouldn't deploy a ton of templates at once...
    var groupSizeMaximum = isDefined(process.env.PARALLEL_DEPLOYMENT_NUMBER) ? parseInt(process.env.PARALLEL_DEPLOYMENT_NUMBER) : 2;
    var testIndex = 0;

    var testDirectoryGroup = [];
    testDirectories.forEach(function (testDirectory) {
      testDirectoryGroup.push(testDirectory);
      testIndex += 1;

      if (testIndex === testDirectories.length || testDirectoryGroup.length === groupSizeMaximum) {
        parallel('Running ' + testDirectoryGroup.length + ' Parallel Template Validation(s)...', function () {
          testDirectoryGroup.forEach(function (testDirectory) {
            it(testDirectory, function () {
              var templateFilePath = path.join(testDirectory, 'azuredeploy.json');
              var parametersFilePath = path.join(testDirectory, 'azuredeploy.parameters.json');

              var requestBody = {
                template: readJSONFile(templateFilePath),
                parameters: readJSONFile(parametersFilePath)
              };

              return validateTemplate(requestBody, templateFilePath)
                .then(function () {
                  return deployTemplate(requestBody, templateFilePath);
                })
                .catch(function (err) {
                  var errorString = 'Template Validiation Failed. Try deploying your template with the commands:\n';
                  errorString += 'azure group template validate --resource-group (your_group_name) ';
                  errorString += ' --template-file ' + templateFilePath + ' --parameters-file ' + parametersFilePath + '\n';
                  errorString += 'azure group deployment create --resource-group (your_group_name) ';
                  errorString += ' --template-file ' + templateFilePath + ' --parameters-file ' + parametersFilePath;
                  assert(false, errorString + ' \n\nServer Error:' + JSON.stringify(err, null, 4));
                });
            });
          });
        });

        testDirectoryGroup.length = 0;
      }
    });
  }
});
<commit_msg>Change 'const' to 'var'<commit_after>'use strict';

/*global describe, it*/
var assert = require('assert');
var colors = require('mocha/lib/reporters/base').colors;
var debug = require('debug')('validator');
var childProcess = require('child_process');
var fs = require('fs');
var parallel = require('mocha.parallel');
var path = require('path');
var RSVP = require('rsvp');
var skeemas = require('skeemas');
var unirest = require('unirest');

// setup mocha color scheme
// 32 = console code for green
colors.pass = 32;

// Tries to parse a json string and asserts with a friendly
// message if something is wrong
function tryParse(fileName, jsonStringData) {
  var object;

  try {
    object = JSON.parse(jsonStringData);
  } catch (e) {
    assert(false, fileName + ' is not valid JSON. Copy and paste the contents to https://jsonformatter.curiousconcept.com/ and correct the syntax errors. Error: ' + e.toString());
  }

  return object;
}

var filePathExistsMap = {};

function fileExists(filePath) {
  if (!(filePath in filePathExistsMap)) {
    filePathExistsMap[filePath] = fs.existsSync(filePath);
  }
  return filePathExistsMap[filePath];
}

var jsonFileContentsMap = {};

function readJSONFile(filePath) {
  if (!(filePath in jsonFileContentsMap)) {
    if (fileExists(filePath)) {
      var fileContents = fs.readFileSync(filePath, {
        encoding: 'utf-8'
      });
      jsonFileContentsMap[filePath] = tryParse(filePath, fileContents.trim());
    } else {
      jsonFileContentsMap[filePath] = null;
    }
  }
  return jsonFileContentsMap[filePath];
}

function isDefined(value) {
  return value !== null && value !== undefined && value !== '';
}

// this is required to keep travis from timing out
// due to lack of console output
function timedOutput(onOff, intervalObject) {
  if (onOff) {
    return setInterval(function () {
      process.stdout.write('...');
    }, 60 * 1000);
  } else {
    clearTimeout(intervalObject);
  }
}

function getEnvironmentVariableBoolean(variableName, defaultValue) {
  let result = defaultValue;

  if (variableName) {
    var variableValue = process.env[variableName];
    if (variableValue) {
      if (typeof variableValue === 'string') {
        result = (variableValue.toLowerCase() === 'true');
      }
    }
  }

  return result;
}

function validateTemplate(requestBody, templateFilePath) {
  var validatePromise;
  if (getEnvironmentVariableBoolean('VALIDATION_SKIP_VALIDATE')) {
    validatePromise = RSVP.resolve({});
  } else {
    // Calls a remote url which will validate the template and parameters
    if (process.env.TRAVIS_PULL_REQUEST &&
      process.env.TRAVIS_PULL_REQUEST !== 'false') {
      requestBody.pull_request = process.env.TRAVIS_PULL_REQUEST;
    }

    var templateObject = requestBody.template;

    // validate the template paramters, particularly the description field
    assert(templateObject.parameters, 'Expected a \'.parameters\' field within the deployment template');
    for (var parameterName in templateObject.parameters) {
      if (typeof parameterName === 'string') {
        assert(templateObject.parameters[parameterName].metadata,
          templateFilePath + ' - Parameter \"' + parameterName + '\" is missing its \"metadata\" property');
        assert(templateObject.parameters[parameterName].metadata.description,
          templateFilePath + ' - Parameter \"' + parameterName + '\" is missing its \"description\" field within the metadata property');
      }
    }

    validatePromise = new RSVP.Promise(function (resolve, reject) {
      unirest.post(process.env.VALIDATION_HOST + '/validate')
        .type('json')
        .send(JSON.stringify(requestBody))
        .end(function (response) {
          if (response.status !== 200) {
            reject(response);
          } else {
            resolve(response.body);
          }
        });
    });
  }
  return validatePromise;
}

function deployTemplate(requestBody) {
  var deployPromise;
  if (getEnvironmentVariableBoolean('VALIDATION_SKIP_DEPLOY')) {
    deployPromise = RSVP.resolve({});
  } else {
    if (process.env.TRAVIS_PULL_REQUEST &&
      process.env.TRAVIS_PULL_REQUEST !== 'false') {
      requestBody.pull_request = process.env.TRAVIS_PULL_REQUEST;
    }

    var intervalObj = timedOutput(true);
    debug('making deploy request');

    // Calls a remote url which will deploy the template
    deployPromise = new RSVP.Promise(function (resolve, reject) {
      return unirest.post(process.env.VALIDATION_HOST + '/deploy')
        .type('json')
        .timeout(3600 * 1000) // Templates can take a long time to deploy, so set the timeout to 1 hour
        .send(JSON.stringify(requestBody))
        .end(function (response) {
          timedOutput(false, intervalObj);
          debug(response.status);
          debug(response.body);

          // 202 is the long poll response
          // anything else is really bad
          if (response.status !== 202) {
            reject(response.body);
          }

          if (response.body.result === 'Deployment Successful') {
            resolve(response.body);
          } else {
            reject(response.body);
          }
        });
    });
  }
  return deployPromise;
}

function assertFileExists(filePath) {
  assert(fileExists(filePath), filePath + ' should exist.');
}

function itExists(filePath) {
  it('exists', function () {
    assertFileExists(filePath);
  });
}

describe('Template', function () {
  this.timeout(7100 * 1000);

  var validateModifiedOnly = getEnvironmentVariableBoolean('VALIDATE_MODIFIED_ONLY', false);
  var runRemoteValidation = !getEnvironmentVariableBoolean('VALIDATION_SKIP_VALIDATE');
  var runRemoteDeployment = !getEnvironmentVariableBoolean('VALIDATION_SKIP_DEPLOY');

  var modifiedDirectories = {};
  if (validateModifiedOnly) {
    // we automatically reset to the beginning of the commit range
    // so this includes all file paths that have changed for the CI run
    assert(process.env.TRAVIS_COMMIT_RANGE, 'VALIDATE_MODIFIED_ONLY requires TRAVIS_COMMIT_RANGE to be set to [START_COMMIT_HASH]...[END_COMMIT_HASH]');

    var modifiedPaths = childProcess.execSync('git diff --name-only ' + process.env.TRAVIS_COMMIT_RANGE, {
      encoding: 'utf8'
    }).split('\n');
    debug(modifiedPaths);

    assert(modifiedPaths.length !== 0, 'No changes were detected in your commit. Verify you added files and try again.');

    if (modifiedPaths) {
      for (var i = 0; i < modifiedPaths.length; i += 1) {
        var modifiedDirectoryPath = path.dirname(modifiedPaths[i]);
        // don't include the top level dir
        if (modifiedDirectoryPath !== '.') {
          modifiedDirectories[modifiedDirectoryPath] = true;
        }
      }
    }
  }

  // Generates the mocha tests based on directories in the existing repo.
  var srcPath = './';
  var testDirectories = fs.readdirSync(srcPath).filter(function (fileEntry) {
    var fileEntryPath = path.join(srcPath, fileEntry);
    return fs.statSync(fileEntryPath).isDirectory() &&
      fileEntry !== '.git' &&
      fileEntry !== 'node_modules' &&
      !fileExists(path.join(fileEntryPath, '.ci_skip')) &&
      // if we are only validating modified templates
      // only add test if this directory template has been modified
      (!validateModifiedOnly || modifiedDirectories[fileEntry]);
  });

  describe('Local Validation', function () {
    testDirectories.forEach(function (testDirectory) {
      describe(testDirectory, function () {
        describe('README.md', function () {
          itExists(path.join(testDirectory, 'README.md'));
        });

        describe('metadata.json', function () {
          var metadataFilePath = path.join(testDirectory, 'metadata.json');

          itExists(metadataFilePath);

          it('matches schema', function () {
            var schemaFilePath = path.join(__dirname, 'metadata.schema.json');
            assertFileExists(schemaFilePath, 'The provided JSON schema file path "' + schemaFilePath + '" doesn\'t exist.');

            var jsonSchemaObject = readJSONFile(schemaFilePath);
            var schemaValidationResult = skeemas.validate(readJSONFile(metadataFilePath), jsonSchemaObject);

            if (!schemaValidationResult.valid) {
              var schemaValidationErrorMessages = '';
              schemaValidationResult.errors.forEach(function (error) {
                schemaValidationErrorMessages += (error.context + ':' + error.message + '\n');
              });
              assert(false, schemaValidationErrorMessages);
            }
          });

          it('No HTML in description', function () {
            var metadataObject = readJSONFile(metadataFilePath);
            var description = metadataObject.description;
            var htmlDetectionRegex = /<[a-z][\s\S]*>/i;
            assert(!(htmlDetectionRegex).test(description), metadataFilePath + ' - Contains possible HTML elements which are not allowed');
          });

          it('dateUpdated not in the future', function () {
            var metadataObject = readJSONFile(metadataFilePath);
            var date = new Date(metadataObject.dateUpdated);
            var currentTime = new Date(Date.now());
            assert(date < currentTime, metadataFilePath + ' - dateUpdated field should not be in the future');
          });
        });

        describe('Validate azuredeploy.parameters.json', function () {
          var parametersFilePath = path.join(testDirectory, 'azuredeploy.parameters.json');

          itExists(parametersFilePath);

          it('has a value or reference property for each parameter', function () {
            var parametersObject = readJSONFile(parametersFilePath);
            assert(parametersObject, 'Parameters file doesn\'t exist or isn\'t a valid JSON value.');
            assert(parametersObject.parameters, parametersFilePath + ' - Expected a \'.parameters\' field within the parameters file');
            for (var parameterName in parametersObject.parameters) {
              if (typeof parameterName === 'string') {
                var parameterObject = parametersObject.parameters[parameterName];
                assert(isDefined(parameterObject.value) || isDefined(parameterObject.reference),
                  parametersFilePath + ' - Parameter \"' + parameterName + '\" should have a \"value\" or \"reference\" property.');
              }
            }
          });
        });

        describe('azuredeploy.json', function () {
          var templateFilePath = path.join(testDirectory, 'azuredeploy.json');

          itExists(templateFilePath);
        });
      });
    });
  });

  if (runRemoteValidation || runRemoteDeployment) {
    // Group tests in chunks defined by an environment variable or by the default value.
    // we probably shouldn't deploy a ton of templates at once...
    var groupSizeMaximum = isDefined(process.env.PARALLEL_DEPLOYMENT_NUMBER) ? parseInt(process.env.PARALLEL_DEPLOYMENT_NUMBER) : 2;
    var testIndex = 0;

    var testDirectoryGroup = [];
    testDirectories.forEach(function (testDirectory) {
      testDirectoryGroup.push(testDirectory);
      testIndex += 1;

      if (testIndex === testDirectories.length || testDirectoryGroup.length === groupSizeMaximum) {
        parallel('Running ' + testDirectoryGroup.length + ' Parallel Template Validation(s)...', function () {
          testDirectoryGroup.forEach(function (testDirectory) {
            it(testDirectory, function () {
              var templateFilePath = path.join(testDirectory, 'azuredeploy.json');
              var parametersFilePath = path.join(testDirectory, 'azuredeploy.parameters.json');

              var requestBody = {
                template: readJSONFile(templateFilePath),
                parameters: readJSONFile(parametersFilePath)
              };

              return validateTemplate(requestBody, templateFilePath)
                .then(function () {
                  return deployTemplate(requestBody, templateFilePath);
                })
                .catch(function (err) {
                  var errorString = 'Template Validiation Failed. Try deploying your template with the commands:\n';
                  errorString += 'azure group template validate --resource-group (your_group_name) ';
                  errorString += ' --template-file ' + templateFilePath + ' --parameters-file ' + parametersFilePath + '\n';
                  errorString += 'azure group deployment create --resource-group (your_group_name) ';
                  errorString += ' --template-file ' + templateFilePath + ' --parameters-file ' + parametersFilePath;
                  assert(false, errorString + ' \n\nServer Error:' + JSON.stringify(err, null, 4));
                });
            });
          });
        });

        testDirectoryGroup.length = 0;
      }
    });
  }
});
<|endoftext|>


<commit_before>/*
Copyright 2012 Adobe Systems Inc.;
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/*global module:false, require:false, process:false*/

var path = require('path'),
    os = require('os'),
    chromiumSrc = process.env.CHROMIUM_SRC || "";

module.exports = function(grunt) {
    'use strict';

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),

        stylus: {
            options: {
                paths: grunt.file.expand(__dirname + '/node_modules/topcoat-*/src/')
                        /*
                         * FIXME: We need to refactor all components to
                         * remove mixins directory *See button & button-base
                         */
                         .concat(grunt.file.expand('node_modules/topcoat-*/src/mixins')),
            },

            mobilelight: {
                options: {
                    import: ['theme-topcoat-mobile-light', 'nib'],
                    compress: false
                },

                files: [{
                    src: 'node_modules/topcoat-*/src/**/*.styl',
                    dest: 'css/topcoat-mobile-light.css'
                }]
            },

            mobiledark: {
                options: {
                    import: ['theme-topcoat-mobile-dark', 'nib'],
                    compress: false
                },

                files: [{
                    src: 'node_modules/topcoat-*/src/**/*.styl',
                    dest: 'css/topcoat-mobile-dark.css'
                }]
            },

            desktoplight: {
                options: {
                    import: ['theme-topcoat-desktop-light', 'nib'],
                    compress: false
                },
                files: [{
                    src: 'node_modules/topcoat-*/src/**/*.styl',
                    dest: 'css/topcoat-desktop-light.css'
                }]
            },

            desktopdark: {
                options: {
                    import: ['theme-topcoat-desktop-dark', 'nib'],
                    compress: false
                },

                files: [{
                    src: 'node_modules/topcoat-*/src/**/*.styl',
                    dest: 'css/topcoat-desktop-dark.css'
                }]
            }
        },

        topdoc: {
            usageguides: {
                options: {
                    source: 'css',
                    destination: './',
                    template: '<%= pkg.topdoc.template %>',
                    templateData: '<%= pkg.topdoc.templateData %>'
                }
            }
        },

        cssmin: {
            minify: {
                expand: true,
                cwd: 'css',
                src: ['*.css', '!*.min.css'],
                dest: 'css',
                ext: '.min.css'
            }
        },

        htmlmin: {
            telemetry: {
                options: {
                    removeComments: true,
                    collapseWhitespace: true
                },
                files: [{
                    expand: true,
                    src: ['dev/test/**/topcoat/*.html'],
                    dest: '',
                    ext: '.test.html',
                }],
            },
        },

        clean: {
            release: ['css']
        },

        copy: {
            release: {
                files: [{
                    expand: true,
                    flatten: true,
                    src: 'node_modules/topcoat-theme/font/**',
                    dest: 'font'
                }, {
                    expand: true,
                    flatten: true,
                    src: 'node_modules/topcoat-theme/img/*',
                    dest: 'img'
                }]
            },
            telemetry: {
                files: [{
                    expand: true,
                    cwd: 'dev/test/perf/telemetry/perf/',
                    src: ['**'],
                    dest: path.join(chromiumSrc, 'tools/perf/')
                }, {
                    src: ['css/**'],
                    dest: path.join(chromiumSrc, 'tools/perf/page_sets/topcoat/release/')
                }]
            }
        },

        jshint: {
            options: {
                curly: true,
                eqeqeq: true,
                immed: true,
                latedef: true,
                newcap: true,
                noarg: true,
                sub: true,
                undef: true,
                unused: true,
                boss: true,
                eqnull: true,
                browser: true,
                globals: {
                    jQuery: true
                }
            },
            gruntfile: {
                src: 'Gruntfile.js'
            },
            lib_test: {
                src: ['dev/lib/**/*.js', 'dev/test/**/*.js']
            }
        },

        watch: {
            files: ['src/**/*.styl'],
            tasks: ['compile']
        }

    });

    // These plugins provide necessary tasks.
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-contrib-jade');
    grunt.loadNpmTasks('grunt-contrib-stylus');
    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-exec');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-topdoc');
    grunt.loadNpmTasks('grunt-contrib-cssmin');
    grunt.loadNpmTasks('grunt-contrib-htmlmin');

    //Load local tasks
    grunt.loadTasks('dev/tasks');

    // Default task.
    grunt.registerTask('default', ['clean', 'stylus', 'cssmin', 'topdoc', 'copy:release']);
    grunt.registerTask('release', ['default', 'clean:src']);
    grunt.registerTask('compile', ['topcoat:compile', 'topdoc', 'copy:release']);

    grunt.registerTask('telemetry', '', function(platform, theme) {
        if (chromiumSrc === "") grunt.fail.warn("Set CHROMIUM_SRC to point to the correct location\n");
        grunt.task.run('check_chromium_src', 'perf:'.concat(platform || 'mobile').concat(':').concat(theme || 'light'), 'htmlmin:telemetry', 'copy:telemetry');
    });
};
<commit_msg>fixed copy task for Grunt telemetry<commit_after>/*
Copyright 2012 Adobe Systems Inc.;
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/*global module:false, require:false, process:false*/

var path = require('path'),
    os = require('os'),
    chromiumSrc = process.env.CHROMIUM_SRC || "";

module.exports = function(grunt) {
    'use strict';

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),

        stylus: {
            options: {
                paths: grunt.file.expand(__dirname + '/node_modules/topcoat-*/src/')
                        /*
                         * FIXME: We need to refactor all components to
                         * remove mixins directory *See button & button-base
                         */
                         .concat(grunt.file.expand('node_modules/topcoat-*/src/mixins')),
            },

            mobilelight: {
                options: {
                    import: ['theme-topcoat-mobile-light', 'nib'],
                    compress: false
                },

                files: [{
                    src: 'node_modules/topcoat-*/src/**/*.styl',
                    dest: 'css/topcoat-mobile-light.css'
                }]
            },

            mobiledark: {
                options: {
                    import: ['theme-topcoat-mobile-dark', 'nib'],
                    compress: false
                },

                files: [{
                    src: 'node_modules/topcoat-*/src/**/*.styl',
                    dest: 'css/topcoat-mobile-dark.css'
                }]
            },

            desktoplight: {
                options: {
                    import: ['theme-topcoat-desktop-light', 'nib'],
                    compress: false
                },
                files: [{
                    src: 'node_modules/topcoat-*/src/**/*.styl',
                    dest: 'css/topcoat-desktop-light.css'
                }]
            },

            desktopdark: {
                options: {
                    import: ['theme-topcoat-desktop-dark', 'nib'],
                    compress: false
                },

                files: [{
                    src: 'node_modules/topcoat-*/src/**/*.styl',
                    dest: 'css/topcoat-desktop-dark.css'
                }]
            }
        },

        topdoc: {
            usageguides: {
                options: {
                    source: 'css',
                    destination: './',
                    template: '<%= pkg.topdoc.template %>',
                    templateData: '<%= pkg.topdoc.templateData %>'
                }
            }
        },

        cssmin: {
            minify: {
                expand: true,
                cwd: 'css',
                src: ['*.css', '!*.min.css'],
                dest: 'css',
                ext: '.min.css'
            }
        },

        htmlmin: {
            telemetry: {
                options: {
                    removeComments: true,
                    collapseWhitespace: true
                },
                files: [{
                    expand: true,
                    src: ['dev/test/**/topcoat/*.html'],
                    dest: '',
                    ext: '.test.html',
                }],
            },
        },

        clean: {
            release: ['css']
        },

        copy: {
            release: {
                files: [{
                    expand: true,
                    flatten: true,
                    src: 'node_modules/topcoat-theme/font/**',
                    dest: 'font'
                }, {
                    expand: true,
                    flatten: true,
                    src: 'node_modules/topcoat-theme/img/*',
                    dest: 'img'
                }]
            },
            telemetry: {
                files: [{
                    expand: true,
                    cwd: 'dev/test/perf/telemetry/perf/',
                    src: ['**'],
                    dest: path.join(chromiumSrc, 'tools/perf/')
                }, {
                    expand: true,
                    flatten: true,
                    src: 'node_modules/topcoat-theme/font/**',
                    dest: path.join(chromiumSrc, 'tools/perf/page_sets/topcoat/font')
                }, {
                    expand: true,
                    flatten: true,
                    src: 'node_modules/topcoat-theme/img/*',
                    dest: path.join(chromiumSrc, 'tools/perf/page_sets/topcoat/img')
                }, {
                    src: ['css/**'],
                    dest: path.join(chromiumSrc, 'tools/perf/page_sets/topcoat/release/')
                }]
            }
        },

        jshint: {
            options: {
                curly: true,
                eqeqeq: true,
                immed: true,
                latedef: true,
                newcap: true,
                noarg: true,
                sub: true,
                undef: true,
                unused: true,
                boss: true,
                eqnull: true,
                browser: true,
                globals: {
                    jQuery: true
                }
            },
            gruntfile: {
                src: 'Gruntfile.js'
            },
            lib_test: {
                src: ['dev/lib/**/*.js', 'dev/test/**/*.js']
            }
        },

        watch: {
            files: ['src/**/*.styl'],
            tasks: ['compile']
        }

    });

    // These plugins provide necessary tasks.
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-contrib-jade');
    grunt.loadNpmTasks('grunt-contrib-stylus');
    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-exec');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-topdoc');
    grunt.loadNpmTasks('grunt-contrib-cssmin');
    grunt.loadNpmTasks('grunt-contrib-htmlmin');

    //Load local tasks
    grunt.loadTasks('dev/tasks');

    // Default task.
    grunt.registerTask('default', ['clean', 'stylus', 'cssmin', 'topdoc', 'copy:release']);
    grunt.registerTask('release', ['default', 'clean:src']);
    grunt.registerTask('compile', ['topcoat:compile', 'topdoc', 'copy:release']);

    grunt.registerTask('telemetry', '', function(platform, theme) {
        if (chromiumSrc === "") grunt.fail.warn("Set CHROMIUM_SRC to point to the correct location\n");
        grunt.task.run('check_chromium_src', 'perf:'.concat(platform || 'mobile').concat(':').concat(theme || 'light'), 'htmlmin:telemetry', 'copy:telemetry');
    });
};
<|endoftext|>


<commit_before>module.exports = function(grunt) {
  // Do grunt-related things in here

  grunt.loadNpmTasks('grunt-saucelabs');

  // Project configuration.
  grunt.initConfig({
    'saucelabs-custom': {
      all: {
        options: {
          "max-duration": 300,
          urls: [
            //'http://localhost:8080/saucerunner.html'
            'http://localhost:8080/saucerun'

            //'http://localhost:8080/smoke/bitmapbutton.html', //no asserts
            //'http://localhost:8080/smoke/misc.html', //no asserts
//            'http://localhost:8080/smoke/replicatorbug.html', //no asserts (assert doesn't run)

//            'http://localhost:8080/smoke/ace.html', //passing
//            'http://localhost:8080/smoke/animator.html', //passing
//            'http://localhost:8080/smoke/animator_js.html', //passing
//            'http://localhost:8080/smoke/animgroup.html', //passing
//            'http://localhost:8080/smoke/art.html', //passing
//            'http://localhost:8080/smoke/attributes.html', //passing
//            'http://localhost:8080/smoke/bitmap.html', //passing
//            'http://localhost:8080/smoke/button.html', //passing
//            'http://localhost:8080/smoke/circularevent.html', //passing
//            'http://localhost:8080/smoke/class.html', //passing
//            'http://localhost:8080/smoke/dre.html', //passing
//            'http://localhost:8080/smoke/events.html', //passing
//            'http://localhost:8080/smoke/handlers.html', //passing
//            'http://localhost:8080/smoke/idle.html', //passing
//            'http://localhost:8080/smoke/initialization.html', //passing
//            'http://localhost:8080/smoke/inputtext.html'//, //passing
//            'http://localhost:8080/smoke/labelbutton.html', //passing
//            'http://localhost:8080/smoke/layout_align.html', //passing
//            'http://localhost:8080/smoke/layout_constant.html', //passing
//            'http://localhost:8080/smoke/layout_resize.html', //passing
//            'http://localhost:8080/smoke/layout_spaced.html', //passing
//            'http://localhost:8080/smoke/layout_variable.html', //passing
//            'http://localhost:8080/smoke/layout_wrapping.html', //passing
//            'http://localhost:8080/smoke/node.html', //passing
//            'http://localhost:8080/smoke/replication.html', //passing
//            'http://localhost:8080/smoke/scrollable.html', //passing
//            'http://localhost:8080/smoke/setter.html', //passing
//            'http://localhost:8080/smoke/sizetodom.html', //passing
//            'http://localhost:8080/smoke/statebutton.html', //passing
//            'http://localhost:8080/smoke/states.html', //passing
//            'http://localhost:8080/smoke/super.html', //passing
//            'http://localhost:8080/smoke/text.html'//, //failing
//            'http://localhost:8080/smoke/twojs.html', //passing
//            'http://localhost:8080/smoke/video.html', //passing
//            'http://localhost:8080/smoke/view.html', //passing
//            'http://localhost:8080/smoke/view_border_padding.html', //passing
//            'http://localhost:8080/smoke/view_bounds_transforms.html', //passing
//            'http://localhost:8080/smoke/view_position.html', //passing
//            'http://localhost:8080/smoke/view_size.html', //passing
//            'http://localhost:8080/smoke/z.html' //passing
          ],
          testname: 'DREEM smoke test',

          browsers: [
            {
              platform: 'OS X 10.10',
              browserName: 'chrome',
              version: '39'
            },
            {
              platform: 'OS X 10.10',
              browserName: 'firefox',
              version: '34'
            },
            {
              platform: 'Windows 8.1',
              browserName: 'chrome',
              version: '39'
            },
            {
              platform: 'Windows 8.1',
              browserName: 'firefox',
              version: '34'
            },
            {
              platform: 'Linux',
              browserName: 'chrome',
              version: '39'
            },
            {
              platform: 'Linux',
              browserName: 'firefox',
              version: '34'
            },
            {
              browserName: 'android',
              version: '4.4',
              platform: 'Linux',
              deviceName: 'Android Emulator',
              'device-orientation': 'portrait'
            },
            {
              browserName: 'iphone',
              version: '8.1',
              platform: 'OS X 10.9',
              deviceName: 'iPhone Simulator',
              'device-orientation': 'portrait'
            }//,
//            {
//              browserName: 'iphone',
//              version: '6.1',
//              platform: 'OS X 10.9',
//              deviceName: 'iPhone Simulator',
//              'device-orientation': 'portrait'
//            },
//            {
//              browserName: 'iphone',
//              version: '7.1',
//              platform: 'OS X 10.9',
//              deviceName: 'iPhone Simulator',
//              'device-orientation': 'portrait'
//            }//,
//            {
//              browserName: 'ipad',
//              version: '8.1',
//              platform: 'OS X 10.9',
//              deviceName: 'iPad Simulator',
//              'device-orientation': 'portrait'
//            }//,

//            {
//              browserName: 'android',
//              version: '4.3',
//              platform: 'Linux',
//              deviceName: 'Android Emulator',
//              'device-orientation': 'portrait'
//            },
//            {
//              browserName: 'android',
//              version: '4.2',
//              platform: 'Linux',
//              deviceName: 'Android Emulator',
//              'device-orientation': 'portrait'
//            },
//            {
//              browserName: 'android',
//              version: '4.1',
//              platform: 'Linux',
//              deviceName: 'Android Emulator',
//              'device-orientation': 'portrait'
//            },
//            {
//              browserName: 'android',
//              version: '4.0',
//              platform: 'Linux',
//              deviceName: 'Android Emulator',
//              'device-orientation': 'portrait'
//            },
//            {
//              browserName: 'android',
//              version: '4.4',
//              platform: 'Linux',
//              deviceName: 'Google Nexus 7 HD Emulator',
//              'device-orientation': 'portrait'
//            },
//            {
//              browserName: 'android',
//              version: '4.4',
//              platform: 'Linux',
//              deviceName: 'Google Nexus 7C Emulator',
//              'device-orientation': 'portrait'
//            },
//            {
//              browserName: 'android',
//              version: '4.0',
//              platform: 'Linux',
//              deviceName: 'HTC Evo 3D Emulator',
//              'device-orientation': 'portrait'
//            },
//            {
//              browserName: 'android',
//              version: '4.1',
//              platform: 'Linux',
//              deviceName: 'HTC One X Emulator',
//              'device-orientation': 'portrait'
//            },
//            {
//              browserName: 'android',
//              version: '4.4',
//              platform: 'Linux',
//              deviceName: 'LG Nexus 4 Emulator',
//              'device-orientation': 'portrait'
//            }
          ]
          // optionally, he `browsers` param can be a flattened array:
          // [["XP", "firefox", 19], ["XP", "chrome", 31]]
        }
      }
    }
  });

  grunt.registerTask('default', ['saucelabs-custom']);

};
<commit_msg>[#86461900] [#86856048] modification to the grunt task config to queue up tests locally rather than on sauce<commit_after>module.exports = function(grunt) {
  // Do grunt-related things in here

  grunt.loadNpmTasks('grunt-saucelabs');

  // Project configuration.
  grunt.initConfig({
    'saucelabs-custom': {
      all: {
        options: {
          "max-duration": 600,
          "throttled": 3,
          urls: [
            //'http://localhost:8080/saucerunner.html'
            'http://localhost:8080/saucerun'

            //'http://localhost:8080/smoke/bitmapbutton.html', //no asserts
            //'http://localhost:8080/smoke/misc.html', //no asserts
//            'http://localhost:8080/smoke/replicatorbug.html', //no asserts (assert doesn't run)

//            'http://localhost:8080/smoke/ace.html', //passing
//            'http://localhost:8080/smoke/animator.html', //passing
//            'http://localhost:8080/smoke/animator_js.html', //passing
//            'http://localhost:8080/smoke/animgroup.html', //passing
//            'http://localhost:8080/smoke/art.html', //passing
//            'http://localhost:8080/smoke/attributes.html', //passing
//            'http://localhost:8080/smoke/bitmap.html', //passing
//            'http://localhost:8080/smoke/button.html', //passing
//            'http://localhost:8080/smoke/circularevent.html', //passing
//            'http://localhost:8080/smoke/class.html', //passing
//            'http://localhost:8080/smoke/dre.html', //passing
//            'http://localhost:8080/smoke/events.html', //passing
//            'http://localhost:8080/smoke/handlers.html', //passing
//            'http://localhost:8080/smoke/idle.html', //passing
//            'http://localhost:8080/smoke/initialization.html', //passing
//            'http://localhost:8080/smoke/inputtext.html'//, //passing
//            'http://localhost:8080/smoke/labelbutton.html', //passing
//            'http://localhost:8080/smoke/layout_align.html', //passing
//            'http://localhost:8080/smoke/layout_constant.html', //passing
//            'http://localhost:8080/smoke/layout_resize.html', //passing
//            'http://localhost:8080/smoke/layout_spaced.html', //passing
//            'http://localhost:8080/smoke/layout_variable.html', //passing
//            'http://localhost:8080/smoke/layout_wrapping.html', //passing
//            'http://localhost:8080/smoke/node.html', //passing
//            'http://localhost:8080/smoke/replication.html', //passing
//            'http://localhost:8080/smoke/scrollable.html', //passing
//            'http://localhost:8080/smoke/setter.html', //passing
//            'http://localhost:8080/smoke/sizetodom.html', //passing
//            'http://localhost:8080/smoke/statebutton.html', //passing
//            'http://localhost:8080/smoke/states.html', //passing
//            'http://localhost:8080/smoke/super.html', //passing
//            'http://localhost:8080/smoke/text.html'//, //failing
//            'http://localhost:8080/smoke/twojs.html', //passing
//            'http://localhost:8080/smoke/video.html', //passing
//            'http://localhost:8080/smoke/view.html', //passing
//            'http://localhost:8080/smoke/view_border_padding.html', //passing
//            'http://localhost:8080/smoke/view_bounds_transforms.html', //passing
//            'http://localhost:8080/smoke/view_position.html', //passing
//            'http://localhost:8080/smoke/view_size.html', //passing
//            'http://localhost:8080/smoke/z.html' //passing
          ],
          testname: 'DREEM smoke test',

          browsers: [
            {
              platform: 'OS X 10.10',
              browserName: 'chrome',
              version: '39'
            },
            {
              platform: 'OS X 10.10',
              browserName: 'firefox',
              version: '34'
            },
            {
              platform: 'Windows 8.1',
              browserName: 'chrome',
              version: '39'
            },
            {
              platform: 'Windows 8.1',
              browserName: 'firefox',
              version: '34'
            },
            {
              platform: 'Linux',
              browserName: 'chrome',
              version: '39'
            },
            {
              platform: 'Linux',
              browserName: 'firefox',
              version: '34'
            },
            {
              browserName: 'android',
              version: '4.4',
              platform: 'Linux',
              deviceName: 'Android Emulator',
              'device-orientation': 'portrait'
            },
            {
              browserName: 'iphone',
              version: '8.1',
              platform: 'OS X 10.9',
              deviceName: 'iPhone Simulator',
              'device-orientation': 'portrait'
            }//,
//            {
//              browserName: 'iphone',
//              version: '6.1',
//              platform: 'OS X 10.9',
//              deviceName: 'iPhone Simulator',
//              'device-orientation': 'portrait'
//            },
//            {
//              browserName: 'iphone',
//              version: '7.1',
//              platform: 'OS X 10.9',
//              deviceName: 'iPhone Simulator',
//              'device-orientation': 'portrait'
//            }//,
//            {
//              browserName: 'ipad',
//              version: '8.1',
//              platform: 'OS X 10.9',
//              deviceName: 'iPad Simulator',
//              'device-orientation': 'portrait'
//            }//,

//            {
//              browserName: 'android',
//              version: '4.3',
//              platform: 'Linux',
//              deviceName: 'Android Emulator',
//              'device-orientation': 'portrait'
//            },
//            {
//              browserName: 'android',
//              version: '4.2',
//              platform: 'Linux',
//              deviceName: 'Android Emulator',
//              'device-orientation': 'portrait'
//            },
//            {
//              browserName: 'android',
//              version: '4.1',
//              platform: 'Linux',
//              deviceName: 'Android Emulator',
//              'device-orientation': 'portrait'
//            },
//            {
//              browserName: 'android',
//              version: '4.0',
//              platform: 'Linux',
//              deviceName: 'Android Emulator',
//              'device-orientation': 'portrait'
//            },
//            {
//              browserName: 'android',
//              version: '4.4',
//              platform: 'Linux',
//              deviceName: 'Google Nexus 7 HD Emulator',
//              'device-orientation': 'portrait'
//            },
//            {
//              browserName: 'android',
//              version: '4.4',
//              platform: 'Linux',
//              deviceName: 'Google Nexus 7C Emulator',
//              'device-orientation': 'portrait'
//            },
//            {
//              browserName: 'android',
//              version: '4.0',
//              platform: 'Linux',
//              deviceName: 'HTC Evo 3D Emulator',
//              'device-orientation': 'portrait'
//            },
//            {
//              browserName: 'android',
//              version: '4.1',
//              platform: 'Linux',
//              deviceName: 'HTC One X Emulator',
//              'device-orientation': 'portrait'
//            },
//            {
//              browserName: 'android',
//              version: '4.4',
//              platform: 'Linux',
//              deviceName: 'LG Nexus 4 Emulator',
//              'device-orientation': 'portrait'
//            }
          ]
          // optionally, he `browsers` param can be a flattened array:
          // [["XP", "firefox", 19], ["XP", "chrome", 31]]
        }
      }
    }
  });

  grunt.registerTask('default', ['saucelabs-custom']);

};
<|endoftext|>


<commit_before>const chai = require('chai');
const assert = chai.assert;
const SV = require('../src/index.js');
const schema = require('../src/schema.js');

const verbose = process.argv[3] === '-v'; // npm test -- -v

const log = verbose ? function() {
  console.log.apply(console, arguments);
} : () => {};

const throws = (f, name, valueString) => {
  let value = null;
  try {
    value = f();
  } catch (e) {
    if (!(e instanceof schema.SchemaValidatorError)) {
      throw new Error('unknown error was thrown: ' + e);
    }
    if (name && !e.message.startsWith(name)) {
      throw new Error(`name "${name}" is not included in message: ` + e.message);
    }
    if (valueString && !e.message.endsWith(valueString)) {
      throw new Error(`value "${valueString}" is not included in message: ` + e.message);
    }
    log('    ' + e.message);
    return;
  }
  throw new Error('unexpectedly succeeded: ' + JSON.stringify(value, null, 2));
}

const sv = SV({
  isHello() {
    return this.then(value => (value === 'hello') ? value : this.reject('should be "hello"'));
  }
});

describe('schema-validator', function() {
  afterEach(function() {
    log();
  });
  it('should validate number', function() {
    assert.equal(0, sv.number().validate(0));
    assert.equal(1, sv.number().validate(1));
    assert.equal(Infinity, sv.number().validate(Infinity));
    throws(() => sv.number().validate(null));
    throws(() => sv.number().validate({}));
    throws(() => sv.number().validate(''));
    throws(() => sv.number().validate(() => {}));
  });
  it('should validate min and max', function() {
    assert.equal(1, sv.number().min(1).validate(1));
    throws(() => sv.number().min(1).validate(0));
    assert.equal(1, sv.number().max(1).validate(1));
    throws(() => sv.number().max(1).validate(2));
    throws(() => sv.number().min(0).max(1).validate(-1));
  });
  it('should validate string', function() {
    assert.equal('', sv.string().validate(''));
    assert.equal('hello', sv.string().validate('hello'));
    assert.equal('hello', sv.string().minLength(5).validate('hello'));
    assert.equal('hello', sv.string().maxLength(5).validate('hello'));
    throws(() => sv.string().minLength(6).validate('hello'));
    throws(() => sv.string().maxLength(4).validate('hello'));
  });
  it('should validate array', function() {
    assert.deepEqual([], sv.array().items(sv.number()).validate([]));
    assert.deepEqual([], sv.array().validate([]));
    assert.deepEqual([0], sv.array().items(sv.number()).validate([0]));
    assert.deepEqual([0], sv.array().items(sv.number().max(1)).validate([0]));
    assert.deepEqual([''], sv.array().items(sv.string()).validate(['']));
    assert.deepEqual([1], sv.array().validate([1]));
    assert.deepEqual(['', 1], sv.array().validate(['', 1]));

    throws(() => sv.array().items(sv.number()).validate(['1']));
    throws(() => sv.array().items(sv.number()).validate(['1', 2]));
    throws(() => sv.array().items(sv.number().min(3)).validate([5, 2, 4]));
  });
  it('should validate field', function() {
    const schema = sv.object().field('a', sv.number());
    assert.deepEqual({
      a: 1
    }, schema.validate({
      a: 1
    }));
    throws(() => schema.validate());
    throws(() => schema.validate(null));
    throws(() => schema.validate({}));
    throws(() => schema.validate({
      a: ''
    }));
    throws(() => schema.validate({
      a: '1'
    }));
  });
  it('should validate optional field', function() {
    const schema = sv.object()
      .field('a', sv.number())
      .field('b', sv.number(), sv.key('a').equal(1));
    assert.deepEqual({
      a: 1,
      b: 10
    }, schema.validate({
      a: 1,
      b: 10
    }));
    assert.deepEqual({
      a: 0,
      b: 'a'
    }, schema.validate({
      a: 0,
      b: 'a'
    }));
    throws(() => schema.validate({
      a: 1,
    }));
    throws(() => schema.validate({
      a: 1,
      b: 'a'
    }));
  });
  it('should validate object', function() {
    const schema = sv.object().name('options')
      .field('a', sv.number().then(v => v * 2))
      .field('b', sv.string().then(v => v.toUpperCase()))
      .field('c', sv.array().items(sv.number()))
      .field('d', sv.object(), sv.key('c').minLength(3))
      .field('e', sv.boolean().default_(true))
      .when(sv.key('e').truthy(),
        sv.field('f', sv.number())
        .field('g', sv.number().default_(100))
      )

    assert.deepEqual({
      a: 2,
      b: 'FOO',
      c: [10, 20, 30],
      d: {},
      e: true,
      f: 10,
      g: 100
    }, schema.validate({
      a: 1,
      b: 'foo',
      c: [10, 20, 30],
      d: {},
      f: 10
    }));
  });
  it('should validate when', function() {
    assert.equal(1, sv.when(sv.number(), sv.min(1)).validate(1));
    throws(() => sv.when(sv.number(), sv.min(1)).validate(0));
    assert.equal(1, sv.when(sv.string(), sv.min(1)).validate(1));
    throws(() => sv.when(sv.number(), sv.min(1)).string().validate(1));
  });
  it('should validate required', function() {
    assert.equal(0, sv.number().validate(0));
    throws(() => sv.number().validate());
    assert.equal(0, sv.number().required().validate(0));
    assert.equal(0, sv.required().number().validate(0));
    throws(() => sv.number().required().validate());
    throws(() => sv.number().required().validate('a'));
    throws(() => sv.required().number().validate());
  });
  it('should validate default', function() {
    assert.equal(0, sv.default_(1).number().validate(0));
    assert.equal(0, sv.number().default_(1).validate(0));
    assert.equal(1, sv.default_(1).number().validate());
    assert.equal(1, sv.number().default_(1).validate());
  });
  it('should validate complex case', function() {
    const retrySchema = sv.try_(sv.number().then(value => ({
        count: value
      })))
      .field('count', sv.integer().min(1))
      .field('interval', sv.number().default_(0));
    const schema = sv.object().name('options')
      .field('retry', retrySchema);
    assert.deepEqual({
      retry: {
        count: 2,
        interval: 0
      }
    }, schema.validate({
      retry: 2
    }));
    assert.deepEqual({
      retry: {
        count: 2,
        interval: 5
      }
    }, schema.validate({
      retry: {
        count: 2,
        interval: 5
      }
    }));
  });
  it('should read custom plugin', function() {
    assert.equal('hello', sv.isHello().validate('hello'));
    throws(() => sv.isHello().validate('bye'));
  });
  it('should throw correct error', function() {
    throws(() => sv.number().name('foo').validate(), 'foo');
    throws(() => sv.number().name('foo').required().validate(), 'foo');
    throws(() => sv.number().required().name('foo').validate(), 'foo');
    throws(() => sv.when(sv.string(), sv.number()).name('foo').validate(''), 'foo');
    throws(() => sv.array().minLength(1).name('foo').validate([]), 'foo.length', '[]');
    throws(() => sv.array().items(sv.string()).name('foo').validate([1]), 'foo[0]', '1');
    throws(() => sv.array().items(sv.string().minLength(1)).name('foo').validate(['1', '']), 'foo[1].length', '""');
    throws(() => sv.object().check(sv.key('a').string()).name('foo').validate({
      a: 1
    }), 'foo.a');
    throws(() => sv.object().field('a', sv.string()).name('foo').validate({
      a: 1
    }), 'foo.a');
  });
});
<commit_msg>make test more strictly check error messages<commit_after>const chai = require('chai');
const assert = chai.assert;
const SV = require('../src/index.js');
const schema = require('../src/schema.js');

const verbose = process.argv[3] === '-v'; // npm test -- -v

const log = verbose ? function() {
  console.log.apply(console, arguments);
} : () => {};

const throws = (f, name, valueString) => {
  let value = null;
  try {
    value = f();
  } catch (e) {
    if (!(e instanceof schema.SchemaValidatorError)) {
      throw new Error('unknown error was thrown: ' + e);
    }
    if (name && !e.message.startsWith(name)) {
      throw new Error(`error message does not start with "${name}": ` + e.message);
    }
    if (valueString && !e.message.endsWith(valueString)) {
      throw new Error(`error message does not end with "${valueString}": ` + e.message);
    }
    log('    ' + e.message);
    return;
  }
  throw new Error('unexpectedly succeeded: ' + JSON.stringify(value, null, 2));
}

const sv = SV({
  isHello() {
    return this.then(value => (value === 'hello') ? value : this.reject('should be "hello"'));
  }
});

describe('schema-validator', function() {
  afterEach(function() {
    log();
  });
  it('should validate number', function() {
    assert.equal(0, sv.number().validate(0));
    assert.equal(1, sv.number().validate(1));
    assert.equal(Infinity, sv.number().validate(Infinity));
    throws(() => sv.number().validate(null));
    throws(() => sv.number().validate({}));
    throws(() => sv.number().validate(''));
    throws(() => sv.number().validate(() => {}));
  });
  it('should validate min and max', function() {
    assert.equal(1, sv.number().min(1).validate(1));
    throws(() => sv.number().min(1).validate(0));
    assert.equal(1, sv.number().max(1).validate(1));
    throws(() => sv.number().max(1).validate(2));
    throws(() => sv.number().min(0).max(1).validate(-1));
  });
  it('should validate string', function() {
    assert.equal('', sv.string().validate(''));
    assert.equal('hello', sv.string().validate('hello'));
    assert.equal('hello', sv.string().minLength(5).validate('hello'));
    assert.equal('hello', sv.string().maxLength(5).validate('hello'));
    throws(() => sv.string().minLength(6).validate('hello'));
    throws(() => sv.string().maxLength(4).validate('hello'));
  });
  it('should validate array', function() {
    assert.deepEqual([], sv.array().items(sv.number()).validate([]));
    assert.deepEqual([], sv.array().validate([]));
    assert.deepEqual([0], sv.array().items(sv.number()).validate([0]));
    assert.deepEqual([0], sv.array().items(sv.number().max(1)).validate([0]));
    assert.deepEqual([''], sv.array().items(sv.string()).validate(['']));
    assert.deepEqual([1], sv.array().validate([1]));
    assert.deepEqual(['', 1], sv.array().validate(['', 1]));

    throws(() => sv.array().items(sv.number()).validate(['1']));
    throws(() => sv.array().items(sv.number()).validate(['1', 2]));
    throws(() => sv.array().items(sv.number().min(3)).validate([5, 2, 4]));
  });
  it('should validate field', function() {
    const schema = sv.object().field('a', sv.number());
    assert.deepEqual({
      a: 1
    }, schema.validate({
      a: 1
    }));
    throws(() => schema.validate());
    throws(() => schema.validate(null));
    throws(() => schema.validate({}));
    throws(() => schema.validate({
      a: ''
    }));
    throws(() => schema.validate({
      a: '1'
    }));
  });
  it('should validate optional field', function() {
    const schema = sv.object()
      .field('a', sv.number())
      .field('b', sv.number(), sv.key('a').equal(1));
    assert.deepEqual({
      a: 1,
      b: 10
    }, schema.validate({
      a: 1,
      b: 10
    }));
    assert.deepEqual({
      a: 0,
      b: 'a'
    }, schema.validate({
      a: 0,
      b: 'a'
    }));
    throws(() => schema.validate({
      a: 1,
    }));
    throws(() => schema.validate({
      a: 1,
      b: 'a'
    }));
  });
  it('should validate object', function() {
    const schema = sv.object().name('options')
      .field('a', sv.number().then(v => v * 2))
      .field('b', sv.string().then(v => v.toUpperCase()))
      .field('c', sv.array().items(sv.number()))
      .field('d', sv.object(), sv.key('c').minLength(3))
      .field('e', sv.boolean().default_(true))
      .when(sv.key('e').truthy(),
        sv.field('f', sv.number())
        .field('g', sv.number().default_(100))
      )

    assert.deepEqual({
      a: 2,
      b: 'FOO',
      c: [10, 20, 30],
      d: {},
      e: true,
      f: 10,
      g: 100
    }, schema.validate({
      a: 1,
      b: 'foo',
      c: [10, 20, 30],
      d: {},
      f: 10
    }));
  });
  it('should validate when', function() {
    assert.equal(1, sv.when(sv.number(), sv.min(1)).validate(1));
    throws(() => sv.when(sv.number(), sv.min(1)).validate(0));
    assert.equal(1, sv.when(sv.string(), sv.min(1)).validate(1));
    throws(() => sv.when(sv.number(), sv.min(1)).string().validate(1));
  });
  it('should validate required', function() {
    assert.equal(0, sv.number().validate(0));
    throws(() => sv.number().validate());
    assert.equal(0, sv.number().required().validate(0));
    assert.equal(0, sv.required().number().validate(0));
    throws(() => sv.number().required().validate());
    throws(() => sv.number().required().validate('a'));
    throws(() => sv.required().number().validate());
  });
  it('should validate default', function() {
    assert.equal(0, sv.default_(1).number().validate(0));
    assert.equal(0, sv.number().default_(1).validate(0));
    assert.equal(1, sv.default_(1).number().validate());
    assert.equal(1, sv.number().default_(1).validate());
  });
  it('should validate complex case', function() {
    const retrySchema = sv.try_(sv.number().then(value => ({
        count: value
      })))
      .field('count', sv.integer().min(1))
      .field('interval', sv.number().default_(0));
    const schema = sv.object().name('options')
      .field('retry', retrySchema);
    assert.deepEqual({
      retry: {
        count: 2,
        interval: 0
      }
    }, schema.validate({
      retry: 2
    }));
    assert.deepEqual({
      retry: {
        count: 2,
        interval: 5
      }
    }, schema.validate({
      retry: {
        count: 2,
        interval: 5
      }
    }));
  });
  it('should read custom plugin', function() {
    assert.equal('hello', sv.isHello().validate('hello'));
    throws(() => sv.isHello().validate('bye'));
  });
  it('should throw correct error', function() {
    throws(() => sv.number().name('foo').validate(), 'foo', 'undefined');
    throws(() => sv.number().name('foo').required().validate(), 'foo', 'undefined');
    throws(() => sv.number().required().name('foo').validate(), 'foo', 'undefined');
    throws(() => sv.when(sv.string(), sv.number()).name('foo').validate(''), 'foo', '""');
    throws(() => sv.array().minLength(1).name('foo').validate([]), 'foo.length', '[]');
    throws(() => sv.array().items(sv.string()).name('foo').validate([1]), 'foo[0]', '1');
    throws(() => sv.array().items(sv.string().minLength(1)).name('foo').validate(['1', '']), 'foo[1].length', '""');
    throws(() => sv.object().check(sv.key('a').string()).name('foo').validate({
      a: 1
    }), 'foo.a', '1');
    throws(() => sv.object().field('a', sv.string()).name('foo').validate({
      a: 1
    }), 'foo.a', '1');
  });
});
<|endoftext|>


<commit_before>/*global module:false*/
module.exports = function(grunt) {
    grunt.loadNpmTasks('grunt-contrib-copy');
	grunt.loadNpmTasks('grunt-contrib-jshint');
	grunt.loadNpmTasks('grunt-contrib-qunit');
    grunt.loadNpmTasks('grunt-contrib-uglify');

	grunt.initConfig({
		jshint: {
			all: ['Gruntfile.js', 'src/cubiq.js']
		},
		qunit: {
			all: ['test/qunit.html']
		},
        uglify: {
            main: {
                files: {
                    'dist/cubiq.min.js': ['src/cubiq.js']
                }
            }
        },
        copy: {
            main: {
                files: [
                    {src: 'src/cubiq.js', dest: 'dist/', expand: true, flatten: true}
                ]
            }
        }
	});

	grunt.registerTask('test', ['jshint', 'qunit']);
	grunt.registerTask('default', ['test', 'publish']);
    grunt.registerTask('publish', ['uglify', 'copy']);
};
<commit_msg>Run test spec through jshint<commit_after>/*global module:false*/
module.exports = function(grunt) {
    grunt.loadNpmTasks('grunt-contrib-copy');
	grunt.loadNpmTasks('grunt-contrib-jshint');
	grunt.loadNpmTasks('grunt-contrib-qunit');
    grunt.loadNpmTasks('grunt-contrib-uglify');

	grunt.initConfig({
		jshint: {
			all: ['Gruntfile.js', 'src/cubiq.js', 'test/spec.js']
		},
		qunit: {
			all: ['test/qunit.html']
		},
        uglify: {
            main: {
                files: {
                    'dist/cubiq.min.js': ['src/cubiq.js']
                }
            }
        },
        copy: {
            main: {
                files: [
                    {src: 'src/cubiq.js', dest: 'dist/', expand: true, flatten: true}
                ]
            }
        }
	});

	grunt.registerTask('test', ['jshint', 'qunit']);
	grunt.registerTask('default', ['test', 'publish']);
    grunt.registerTask('publish', ['uglify', 'copy']);
};
<|endoftext|>


<commit_before>var env = process.env.NODE_ENV || 'development';
var config = require('./config/config')[env];
var templates = require('./app/modules/templates');

// Connect to database
require('./app/modules/database')(config);
var db = require('./app/modules/database');
var Games = require('./app/controller/games');
var GamesIndex = db.collection('games');
var Indexer = require('./app/modules/index');
var SteamURL = require('./app/modules/steam');
var timer = '';

/**
 * Fetches a game and starts a new 2 seconds timer if specified
 * @param games {{}}
 * @param current number
 * @param callback function
 **/
function getGame(games,current,callback){
    var game = games[current];
    console.log('Updating game ID: ' + game.steam_appid + ' - ' + current + ' of ' + games.length);
    Games.fetchParseGame(game.steam_appid, function(){return null;},game._id);
    current++;
    if(typeof games[current] !== 'undefined'){
        setTimeout(function(){
            getGame(games,current,callback);
        },2000);
    } else {
        console.timeEnd(timer);
        callback();
    }
}

module.exports = function(grunt) {

	// Project configuration.
	grunt.initConfig({
		pkg: grunt.file.readJSON('package.json'),
		sass: {
			dist: {
				files: {
					'public/css/structure.css': 'scss/structure.scss'
				},
				options: {
					compass: true,
					style: 'compressed'
				}
			},
			dev: {
				files: {
					'public/css/structure.css': 'scss/structure.scss'
				},
                options: {
					quiet: true,
					compass: true,
					style: 'expanded',
					lineNumbers: true
				}
			}
		},
        uglify: {
            files: [
                {
                    expand: true,
                    cwd: 'src/js',
                    src: '**/*.js',
                    dest: 'dest/js'
                }
            ]
        },
		watch: {
			templates: {
				files: [
					'app/views/templates/**'
				],
				tasks: [
					'build_templates'
				],
				options: {
					nospawn: true
				}
            },
            css: {
                files: [
					'scss/**'
				],
				tasks: [
					'sass:dev'
				],
				options: {
					nospawn: true
				}
            }
		}
	});

	grunt.loadNpmTasks('grunt-contrib-watch');
	grunt.loadNpmTasks('grunt-contrib-sass');

	// Default task
	grunt.registerTask('default', [
		'sass:dev',
		'build_templates',
        'watch'
	]);

	// Add the JADE includes
	grunt.registerTask('build_templates', 'Generates the JADE template includes', function(){
		templates();
		return true;
	});

    grunt.registerTask('update_games', 'Updates all the games in the DB by fetching from Steam', function(){
        var done = this.async();
        GamesIndex.find(function(err, games){
            timer = 'Done, updated ' + games.length + ' games in';
            console.time(timer);
            getGame(games,0,done);
        });
    });
};<commit_msg>No more 0 index in Grunt output<commit_after>var env = process.env.NODE_ENV || 'development';
var config = require('./config/config')[env];
var templates = require('./app/modules/templates');

// Connect to database
require('./app/modules/database')(config);
var db = require('./app/modules/database');
var Games = require('./app/controller/games');
var GamesIndex = db.collection('games');
var Indexer = require('./app/modules/index');
var SteamURL = require('./app/modules/steam');
var timer = '';

/**
 * Fetches a game and starts a new 2 seconds timer if specified
 * @param games {{}}
 * @param current number
 * @param callback function
 **/
function getGame(games,current,callback){
    var game = games[current];
    current++;
    console.log('Updating game ID: ' + game.steam_appid + ' - ' + current + ' of ' + games.length);
    Games.fetchParseGame(game.steam_appid, function(){return null;},game._id);
    if(typeof games[current] !== 'undefined'){
        setTimeout(function(){
            getGame(games,current,callback);
        },2000);
    } else {
        console.timeEnd(timer);
        callback();
    }
}

module.exports = function(grunt) {

	// Project configuration.
	grunt.initConfig({
		pkg: grunt.file.readJSON('package.json'),
		sass: {
			dist: {
				files: {
					'public/css/structure.css': 'scss/structure.scss'
				},
				options: {
					compass: true,
					style: 'compressed'
				}
			},
			dev: {
				files: {
					'public/css/structure.css': 'scss/structure.scss'
				},
                options: {
					quiet: true,
					compass: true,
					style: 'expanded',
					lineNumbers: true
				}
			}
		},
        uglify: {
            files: [
                {
                    expand: true,
                    cwd: 'src/js',
                    src: '**/*.js',
                    dest: 'dest/js'
                }
            ]
        },
		watch: {
			templates: {
				files: [
					'app/views/templates/**'
				],
				tasks: [
					'build_templates'
				],
				options: {
					nospawn: true
				}
            },
            css: {
                files: [
					'scss/**'
				],
				tasks: [
					'sass:dev'
				],
				options: {
					nospawn: true
				}
            }
		}
	});

	grunt.loadNpmTasks('grunt-contrib-watch');
	grunt.loadNpmTasks('grunt-contrib-sass');

	// Default task
	grunt.registerTask('default', [
		'sass:dev',
		'build_templates',
        'watch'
	]);

	// Add the JADE includes
	grunt.registerTask('build_templates', 'Generates the JADE template includes', function(){
		templates();
		return true;
	});

    grunt.registerTask('update_games', 'Updates all the games in the DB by fetching from Steam', function(){
        var done = this.async();
        GamesIndex.find(function(err, games){
            timer = 'Done, updated ' + games.length + ' games in';
            console.time(timer);
            getGame(games,0,done);
        });
    });
};<|endoftext|>


<commit_before>'use strict';

var npmDest = 'dist';
var buildDest = 'dist';
var entryJS = 'src/js/app.js';
var devDir = 'dev/';
var tmpDir = '.tmp/';
var jsBundle = 'fittable.js';
var cssBundle = 'fittable.css';

module.exports = function (grunt) {
  // Project configuration
  grunt.initConfig({

    pkg: grunt.file.readJSON('package.json'),

    concurrent: {
      options: {
        logConcurrentOutput: true
      },
      dev: {
        tasks: [
          'compass:dev',              // start compass watch
          'browserify:dev',           // start watchify
          'copy:dev',                 // copy HTML files
          'watch:copyDev',            // watch src files
          'watch:autoprefixerDev',    // watch for CSS generated by Compass
          'livereactload',            // start monitoring bundle changes
          'browserSync',              // start static files server
        ],
        options: {
          logConcurrentOutput: true,
          limit: Infinity
        },
      },
      dist: {
        tasks: [
          'css:dist',
          'browserify:dist',
          'browserify:min',
          'copy:dist',
        ]
      },
      npm: {
        tasks: [
          'babel:npm',
          'copy:npm'
        ]
      }
    },

    // Empties folders to start fresh
    clean: {
      dist: {
        files: [{
          dot: true,
          src: [
            tmpDir,
            'dist/*',
            '!dist/.git*'
          ]
        }]
      },
      dev: {
        files: [{
          dot: true,
          src: [
            devDir,
            tmpDir
          ]
        }]
      }
    },

    // Compiles Sass to CSS and generates necessary files if requested
    // autoprefixer is invoked from compass, see config.rb
    compass: {
      dev: {
        options: {
          sassDir: 'src/scss',
          cssDir: tmpDir,
          noLineComments: true,
          sourcemap: true,
          watch: true,
          force: true
        }
      },
      dist: {
        options: {
          sassDir: 'src/scss',
          cssDir: buildDest,
          environment: 'production'
        }
      }
    },

    // Watches files for changes and runs tasks based on the changed files
    watch: {
      'copyDev': {
        files: ['src/*.html'],
        tasks: ['copy:dev']
      },
      'autoprefixerDev': {
        files: [tmpDir + '**/*.css'],
        tasks: ['autoprefixer:dev'],
        options: {
          verbose: true
        },
      }
    },

    autoprefixer: {
      dev: {
        options: {
          map: true
        },
        files: [{
          src: [tmpDir + cssBundle],
          dest: devDir + cssBundle
        }]
      },
      dist: {
        files: [{
          src: 'dist/*.css'
        }]
      }
    },

    // Copies remaining files to places other tasks can use
    copy: {
      dist: {
        files: [{
          expand: true,
          cwd: 'src/',
          dest: buildDest,
          flatten: false,
          src: [
            'index.html',
            'landing.html',
            'img/**',
          ]
        }]
      },
      npm: {
        files: [{
          expand: true,
          dest: npmDest,
          cwd: './src',
          src: [
            'lang/*'
          ]
        }]
      },
      dev: {
        files: [{
          expand: true,
          cwd: 'src/',
          dest: devDir,
          flatten: false,
          src: [
            'index.html',
            'landing.html',
            'img/**',
          ]
        }]
      },
    },

    // Browserify
    browserify: {
      options: {
        transform: [ 'babelify' ],
        browserifyOptions: {
          debug: true,
          standalone: 'fittable'
        }
      },
      dev: {
        src: entryJS,
        dest: devDir + jsBundle,
        options: {
          watch: true,
          keepAlive: true,
          transform: [[{}, 'babelify'], [{global: true, preventCache: false}, 'livereactload']],
          browserifyOptions: {
            debug: true,
            standalone: 'fittable'
          }
        }
      },
      dist: {
        files: {
          'dist/fittable.js': entryJS
        }
      },
      min: {
        options: {
          transform: [ 'babelify' ],
          plugin: [ 'minifyify' ]
        },
        files: {
          'dist/fittable.min.js': entryJS
        }
      }
    },

    // Babel: Used for npm prepublishing, otherwise see browserify
    babel: {
      options: {
        sourceMap: true
      },
      npm: {
        files: [{
            expand: true,
            cwd: 'src/js',
            src: ['**/*.js'],
            dest: npmDest + '/js'
        }]
      }
    },

    // browserSync: Provides static server and assets reloading
    browserSync: {
      bsFiles: {
          src: [
            devDir + '*.css',
            devDir + '*.html'
          ]
      },
      options: {
        server: {
          baseDir: devDir
        }
      }
    },

  });

  // Load grunt tasks automatically
  require('load-grunt-tasks')(grunt);

  grunt.registerTask('livereactload', 'Runs LiveReactload monitor.', function() {
    var lrld = require('livereactload');
    // var done = this.async();
    this.async();

    // grunt.log.writeln('Running LiveReactload monitor server...');
    lrld.monitor(devDir + jsBundle);
  });

  grunt.registerTask('touchCSS', 'Creates an empty CSS file for watching', function() {
    grunt.file.write(tmpDir + cssBundle);
  });

  grunt.registerTask('dev', [
    'touchCSS',
    'concurrent:dev',
  ]);

  grunt.registerTask('css:dist', [
    'compass:dist',
    'autoprefixer:dist'
  ]);

  grunt.registerTask('build', [
    'clean:dist',
    'concurrent:dist',
  ]);

  grunt.registerTask('build:npm', [
    'build',
    'concurrent:npm'
  ]);

  grunt.registerTask('default', ['dev']);
};
<commit_msg>browserSync: Don't open browser on start<commit_after>'use strict';

var npmDest = 'dist';
var buildDest = 'dist';
var entryJS = 'src/js/app.js';
var devDir = 'dev/';
var tmpDir = '.tmp/';
var jsBundle = 'fittable.js';
var cssBundle = 'fittable.css';

module.exports = function (grunt) {
  // Project configuration
  grunt.initConfig({

    pkg: grunt.file.readJSON('package.json'),

    concurrent: {
      options: {
        logConcurrentOutput: true
      },
      dev: {
        tasks: [
          'compass:dev',              // start compass watch
          'browserify:dev',           // start watchify
          'copy:dev',                 // copy HTML files
          'watch:copyDev',            // watch src files
          'watch:autoprefixerDev',    // watch for CSS generated by Compass
          'livereactload',            // start monitoring bundle changes
          'browserSync',              // start static files server
        ],
        options: {
          logConcurrentOutput: true,
          limit: Infinity
        },
      },
      dist: {
        tasks: [
          'css:dist',
          'browserify:dist',
          'browserify:min',
          'copy:dist',
        ]
      },
      npm: {
        tasks: [
          'babel:npm',
          'copy:npm'
        ]
      }
    },

    // Empties folders to start fresh
    clean: {
      dist: {
        files: [{
          dot: true,
          src: [
            tmpDir,
            'dist/*',
            '!dist/.git*'
          ]
        }]
      },
      dev: {
        files: [{
          dot: true,
          src: [
            devDir,
            tmpDir
          ]
        }]
      }
    },

    // Compiles Sass to CSS and generates necessary files if requested
    // autoprefixer is invoked from compass, see config.rb
    compass: {
      dev: {
        options: {
          sassDir: 'src/scss',
          cssDir: tmpDir,
          noLineComments: true,
          sourcemap: true,
          watch: true,
          force: true
        }
      },
      dist: {
        options: {
          sassDir: 'src/scss',
          cssDir: buildDest,
          environment: 'production'
        }
      }
    },

    // Watches files for changes and runs tasks based on the changed files
    watch: {
      'copyDev': {
        files: ['src/*.html'],
        tasks: ['copy:dev']
      },
      'autoprefixerDev': {
        files: [tmpDir + '**/*.css'],
        tasks: ['autoprefixer:dev'],
        options: {
          verbose: true
        },
      }
    },

    autoprefixer: {
      dev: {
        options: {
          map: true
        },
        files: [{
          src: [tmpDir + cssBundle],
          dest: devDir + cssBundle
        }]
      },
      dist: {
        files: [{
          src: 'dist/*.css'
        }]
      }
    },

    // Copies remaining files to places other tasks can use
    copy: {
      dist: {
        files: [{
          expand: true,
          cwd: 'src/',
          dest: buildDest,
          flatten: false,
          src: [
            'index.html',
            'landing.html',
            'img/**',
          ]
        }]
      },
      npm: {
        files: [{
          expand: true,
          dest: npmDest,
          cwd: './src',
          src: [
            'lang/*'
          ]
        }]
      },
      dev: {
        files: [{
          expand: true,
          cwd: 'src/',
          dest: devDir,
          flatten: false,
          src: [
            'index.html',
            'landing.html',
            'img/**',
          ]
        }]
      },
    },

    // Browserify
    browserify: {
      options: {
        transform: [ 'babelify' ],
        browserifyOptions: {
          debug: true,
          standalone: 'fittable'
        }
      },
      dev: {
        src: entryJS,
        dest: devDir + jsBundle,
        options: {
          watch: true,
          keepAlive: true,
          transform: [[{}, 'babelify'], [{global: true, preventCache: false}, 'livereactload']],
          browserifyOptions: {
            debug: true,
            standalone: 'fittable'
          }
        }
      },
      dist: {
        files: {
          'dist/fittable.js': entryJS
        }
      },
      min: {
        options: {
          transform: [ 'babelify' ],
          plugin: [ 'minifyify' ]
        },
        files: {
          'dist/fittable.min.js': entryJS
        }
      }
    },

    // Babel: Used for npm prepublishing, otherwise see browserify
    babel: {
      options: {
        sourceMap: true
      },
      npm: {
        files: [{
            expand: true,
            cwd: 'src/js',
            src: ['**/*.js'],
            dest: npmDest + '/js'
        }]
      }
    },

    // browserSync: Provides static server and assets reloading
    browserSync: {
      bsFiles: {
          src: [
            devDir + '*.css',
            devDir + '*.html'
          ]
      },
      options: {
        server: {
          baseDir: devDir
        },
        open: false
      }
    },

  });

  // Load grunt tasks automatically
  require('load-grunt-tasks')(grunt);

  grunt.registerTask('livereactload', 'Runs LiveReactload monitor.', function() {
    var lrld = require('livereactload');
    // var done = this.async();
    this.async();

    // grunt.log.writeln('Running LiveReactload monitor server...');
    lrld.monitor(devDir + jsBundle);
  });

  grunt.registerTask('touchCSS', 'Creates an empty CSS file for watching', function() {
    grunt.file.write(tmpDir + cssBundle);
  });

  grunt.registerTask('dev', [
    'touchCSS',
    'concurrent:dev',
  ]);

  grunt.registerTask('css:dist', [
    'compass:dist',
    'autoprefixer:dist'
  ]);

  grunt.registerTask('build', [
    'clean:dist',
    'concurrent:dist',
  ]);

  grunt.registerTask('build:npm', [
    'build',
    'concurrent:npm'
  ]);

  grunt.registerTask('default', ['dev']);
};
<|endoftext|>