<commit_before>"use strict";

var TEMP_DIR = "./.tmp",

    exec = require( "child_process" ).exec,
    expect = require( "chai" ).expect,

    path = require( "path" ),
    fs = require( "fs" ),
    Q = require( "q" ),
    iconv = require( "iconv-lite" );

describe( "grunt-meta-excel", function(){

    before( function( done ){
        prepareTestFiles().then( function(){ done(); } );
    } );

    after( function( done ){
        removeTestFiles().then( function(){ done(); } );
    } );

    describe( "Update meta tags.", function(){
        before( function( done ){
            exec( "grunt meta_excel:test_utf8_update", function(){
                done();
            } );
        } );

        it( "内容が更新される。", function(){
            expect( fs.readFileSync( path.join( TEMP_DIR, "htdocs_utf8_update/sample_dir_1/sample_subdir/sample_2.html" ), "utf8" ) )
                .to.contain( "サンプルページ2 | サンプルサブカテゴリー | サンプルカテゴリー1 | サンプルサイト" );
        } );
    } );

    describe( "Generate html files.", function(){
        before( function( done ){
            exec( "grunt meta_excel:test_utf8_generate:generate", function(){
                done();
            } );
        } );

        it( "HTMLファイルが生成される。", function(){
            expect( fs.existsSync( path.join( TEMP_DIR, "htdocs_utf8_generate/sample_dir_1/sample_subdir/sample_2.html" ) ) )
                .to.be.true;
        } );

        it( "内容がxlsxどおりである。", function(){
            expect( fs.readFileSync( path.join( TEMP_DIR, "htdocs_utf8_generate/sample_dir_1/sample_subdir/sample_2.html" ), "utf8" ) )
                .to.contain( "サンプルページ2 | サンプルサブカテゴリー | サンプルカテゴリー1 | サンプルサイト" );
        } );
    } );

    describe( "options", function(){

        describe( "charset ( e.g. shift_jis )", function(){

            describe( "Update meta tags.", function(){
                before( function( done ){
                    exec( "grunt meta_excel:test_sjis_update", function(){
                        done();
                    } );
                } );

                it( "内容が更新される。", function(){
                    var updatedFileContent =iconv.decode(
                        fs.readFileSync( path.join( TEMP_DIR, "htdocs_sjis_update/sample_dir_1/sample_subdir/sample_2.html" ) ),
                        "shift_jis"
                    );

                    expect( updatedFileContent ).to.contain( "サンプルページ2 | サンプルサブカテゴリー | サンプルカテゴリー1 | サンプルサイト" );
                    expect( updatedFileContent ).to.contain( "
サンプルHTML（Shift_JIS）
" );
                } );
            } );

            describe( "Generate html files.", function(){
                before( function( done ){
                    exec( "grunt meta_excel:test_sjis_generate:generate", function(){
                        done();
                    } );
                } );

                it( "HTMLファイルが生成される。", function(){
                    expect( fs.existsSync( path.join( TEMP_DIR, "htdocs_sjis_generate/sample_dir_1/sample_subdir/sample_2.html" ) ) )
                        .to.be.true;
                } );

                it( "内容がxlsxどおりである。", function(){
                    var updatedFileContent =iconv.decode(
                        fs.readFileSync( path.join( TEMP_DIR, "htdocs_sjis_generate/sample_dir_1/sample_subdir/sample_2.html" ) ),
                        "shift_jis"
                    );

                    expect( updatedFileContent ).to.contain( "サンプルページ2 | サンプルサブカテゴリー | サンプルカテゴリー1 | サンプルサイト" );
                    expect( updatedFileContent ).to.contain( "
サンプルHTML（Shift_JIS）
" );
                } );
            } );
        } );

        describe( "patternsJsonPath", function(){
            before( function( done ){
                prepareTestFiles()
                    .then( function(){
                        exec( "grunt meta_excel:test_pattern_json_file:generate", function(){
                            done();
                        } );
                    } )
            } );

            it( "指定されたパターンにもとづいて内容が適用される。", function(){
                expect( fs.readFileSync( path.join( TEMP_DIR, "htdocs_utf8_generate/sample_dir_1/sample_subdir/sample_2.html" ), "utf8" ) )
                    .to.contain( '<title data-test="test">サンプルページ2 | サンプルサブカテゴリー | サンプルカテゴリー1 | サンプルサイト, test</title>' );
            } );
        } );
    } );
} );

function prepareTestFiles(){
    var deferred = Q.defer(),
        shell = require( "shelljs" );

    removeTestFiles()
        .then( function(){
            fs.mkdir( TEMP_DIR, function( err ){
                if( err ){
                    deferred.reject( err );
                    return;
                }

                shell.cp(
                    "-r",
                    path.resolve( "./sample/htdocs/*" ),
                    path.resolve( TEMP_DIR, "htdocs_utf8_update" )
                );

                shell.cp(
                    "-r",
                    path.resolve( "./sample/htdocs/__boilerplate.html" ),
                    path.resolve( TEMP_DIR, "htdocs_utf8_generate" )
                );

                shell.cp(
                    "-r",
                    path.resolve( "./sample/htdocs_sjis/*" ),
                    path.resolve( TEMP_DIR, "htdocs_sjis_update" )
                );

                shell.cp(
                    "-r",
                    path.resolve( "./sample/htdocs_sjis/__boilerplate.html" ),
                    path.resolve( TEMP_DIR, "htdocs_sjis_generate" )
                );

                deferred.resolve( true );
        } );
    } );

    return deferred.promise;
}

function removeTestFiles(){
    var deferred = Q.defer();

        if( fs.existsSync( TEMP_DIR ) ){
            require( "rimraf" )( TEMP_DIR, function(){
            deferred.resolve( true );
        } );
    }
    else {
        deferred.resolve( true );
    }

    return deferred.promise;
}

<commit_msg>テストコードを整形。<commit_after>"use strict";

var TEMP_DIR = "./.tmp",

    exec = require( "child_process" ).exec,
    expect = require( "chai" ).expect,

    path = require( "path" ),
    fs = require( "fs" ),
    Q = require( "q" ),
    iconv = require( "iconv-lite" );

describe( "grunt-meta-excel", function(){

    before( function( done ){
        prepareTestFiles().then( function(){ done(); } );
    } );

    after( function( done ){
        removeTestFiles().then( function(){ done(); } );
    } );

    describe( "Update meta tags.", function(){
        before( function( done ){
            exec( "grunt meta_excel:test_utf8_update", function(){
                done();
            } );
        } );

        it( "内容が更新される。", function(){
            expect( fs.readFileSync( path.join( TEMP_DIR, "htdocs_utf8_update/sample_dir_1/sample_subdir/sample_2.html" ), "utf8" ) )
                .to.contain( "サンプルページ2 | サンプルサブカテゴリー | サンプルカテゴリー1 | サンプルサイト" );
        } );
    } );

    describe( "Generate html files.", function(){
        before( function( done ){
            exec( "grunt meta_excel:test_utf8_generate:generate", function(){
                done();
            } );
        } );

        it( "HTMLファイルが生成される。", function(){
            expect( fs.existsSync( path.join( TEMP_DIR, "htdocs_utf8_generate/sample_dir_1/sample_subdir/sample_2.html" ) ) )
                .to.be.true;
        } );

        it( "内容がxlsxどおりである。", function(){
            expect( fs.readFileSync( path.join( TEMP_DIR, "htdocs_utf8_generate/sample_dir_1/sample_subdir/sample_2.html" ), "utf8" ) )
                .to.contain( "サンプルページ2 | サンプルサブカテゴリー | サンプルカテゴリー1 | サンプルサイト" );
        } );
    } );

    describe( "options", function(){

        describe( "charset ( e.g. shift_jis )", function(){

            describe( "Update meta tags.", function(){
                before( function( done ){
                    exec( "grunt meta_excel:test_sjis_update", function(){
                        done();
                    } );
                } );

                it( "内容が更新される。", function(){
                    var updatedFileContent =iconv.decode(
                        fs.readFileSync( path.join( TEMP_DIR, "htdocs_sjis_update/sample_dir_1/sample_subdir/sample_2.html" ) ),
                        "shift_jis"
                    );

                    expect( updatedFileContent ).to.contain( "サンプルページ2 | サンプルサブカテゴリー | サンプルカテゴリー1 | サンプルサイト" );
                    expect( updatedFileContent ).to.contain( "
サンプルHTML（Shift_JIS）
" );
                } );
            } );

            describe( "Generate html files.", function(){
                before( function( done ){
                    exec( "grunt meta_excel:test_sjis_generate:generate", function(){
                        done();
                    } );
                } );

                it( "HTMLファイルが生成される。", function(){
                    expect( fs.existsSync( path.join( TEMP_DIR, "htdocs_sjis_generate/sample_dir_1/sample_subdir/sample_2.html" ) ) )
                        .to.be.true;
                } );

                it( "内容がxlsxどおりである。", function(){
                    var updatedFileContent =iconv.decode(
                        fs.readFileSync( path.join( TEMP_DIR, "htdocs_sjis_generate/sample_dir_1/sample_subdir/sample_2.html" ) ),
                        "shift_jis"
                    );

                    expect( updatedFileContent ).to.contain( "サンプルページ2 | サンプルサブカテゴリー | サンプルカテゴリー1 | サンプルサイト" );
                    expect( updatedFileContent ).to.contain( "
サンプルHTML（Shift_JIS）
" );
                } );
            } );
        } );

        describe( "patternsJsonPath", function(){
            before( function( done ){
                prepareTestFiles()
                    .then( function(){
                        exec( "grunt meta_excel:test_pattern_json_file:generate", function(){
                            done();
                        } );
                    } )
            } );

            it( "指定されたパターンにもとづいて内容が適用される。", function(){
                expect( fs.readFileSync( path.join( TEMP_DIR, "htdocs_utf8_generate/sample_dir_1/sample_subdir/sample_2.html" ), "utf8" ) )
                    .to.contain( '<title data-test="test">サンプルページ2 | サンプルサブカテゴリー | サンプルカテゴリー1 | サンプルサイト, test</title>' );
            } );
        } );
    } );
} );

function prepareTestFiles(){
    var deferred = Q.defer(),
        shell = require( "shelljs" );

    removeTestFiles()
        .then( function(){
            fs.mkdir( TEMP_DIR, function( err ){
                if( err ){
                    deferred.reject( err );
                    return;
                }

                shell.cp(
                    "-r",
                    path.resolve( "./sample/htdocs/*" ),
                    path.resolve( TEMP_DIR, "htdocs_utf8_update" )
                );

                shell.cp(
                    "-r",
                    path.resolve( "./sample/htdocs/__boilerplate.html" ),
                    path.resolve( TEMP_DIR, "htdocs_utf8_generate" )
                );

                shell.cp(
                    "-r",
                    path.resolve( "./sample/htdocs_sjis/*" ),
                    path.resolve( TEMP_DIR, "htdocs_sjis_update" )
                );

                shell.cp(
                    "-r",
                    path.resolve( "./sample/htdocs_sjis/__boilerplate.html" ),
                    path.resolve( TEMP_DIR, "htdocs_sjis_generate" )
                );

                deferred.resolve( true );
        } );
    } );

    return deferred.promise;
}

function removeTestFiles(){
    var deferred = Q.defer();

    if( fs.existsSync( TEMP_DIR ) ){
        require( "rimraf" )( TEMP_DIR, function(){
            deferred.resolve( true );
        } );
    }
    else {
        deferred.resolve( true );
    }

    return deferred.promise;
}

<|endoftext|>


<commit_before>var _ = require('lodash');
var defaultValidations = require('./defaultValidations');

module.exports = Validator;

/**
 * Creates a validator object and initiates it
 * @param {Model} model - A scoped model to the location on where to put the validator's data
 * @param {Model|string} [origin] - Either a scoped model to the location where the original data is stored. Or, a path (as string) to the location where to find the original data. If not passed, the fields parameter is mandatory.
 * @param {Collection.<string, Object>} [fields] - A collection of fields to use. If not passed, the origin parameter is mandatory. The key for each object is the field name, and the value is the field object (specified below).
   * @param {*} [fields.<fieldName>.default] - A default value for this specific field.
   * @param {Object[]} [fields.<fieldName>.validations] - A list of validations to apply.
     * @param {String|Function|RegEx} [fields.<fieldName>.validations.<index>.rule] - The rule to use when validating this rule. Either, this can be a string matching the name of a default rule (specified in default checks or passed in as an option), OR a function which will get run with the value to be validated as input, which should return true|false reflecting the validity, OR a RegEx, which will get run similar to if you pass in a function.
     * @param {String} [fields.<fieldName>.validations.<index>.message] - The error message to show if validation fails
 * @param {Object} [options] - An options object
   * @param {Collection.<string, Function|RegEx>} [options.rules] - A collection of default rules to add to this instance. Each key is the name of the rule. The value is the rule, either a function or regular expression similar to field specific functions/regular expressions passed in the fields parameter
 * @returns {Validator} - Instance of Validator
 */
function Validator(model, origin, fields, options) {
  // Parse out arguments

  var args = Array.prototype.slice.call(arguments);

  if(!args.length) throw new Error('You must specify a model!');
  if(!args.length == 1) throw new Error('You must either specify an origin or a fields object');

  this.model = args.shift();
  var arg = args.shift();

  if(typeof (arg || {}).path === 'function') {
    this.origin = arg;

    arg = args.shift();
  } else if(typeof arg === 'string') {
    this.origin = this.model.scope(arg);

    arg = args.shift();
  }

  if(arg) this.fields = arg;

  this.options = _.assign({
    rules: {},
    messages: {}
  }, args.shift());

  // Setup
  this._setup();
};

Validator.prototype.getValues = function () {
  var values = {};
  _.each(this.model.get(), function (field, fieldName) {
    values[fieldName] = field.value;
  });
  return values;
}

Validator.prototype.validate = function (fieldname) {
  this._validateField(fieldname);
};

Validator.prototype.validateAll = function() {
  var self = this;
  _.each(this.model.get(), function (n, key) {
    self._validate(key);
  });
};

Validator.prototype.checkForInvalidFields = function() {
  return _.find(this.model.get(), function (field) {
    if(field.isInvalid) return field;
  });
};

Validator.prototype.setInvalid = function (fieldName, message) {
  this._setInvalid(fieldName);
  this.model.push(fieldName + '.messages', message || defaultValidations['default'].message);
};

/*
 * @public
 * Reset values to origin.
 */
Validator.prototype.resetForm = function () {
  this._setup();
};

/*
 * @public
 * Commit values to model. Call after client- and serverside validation.
 */
Validator.prototype.commit = function () {
  if(!this.origin) return;

  var self = this;

  _.each(this.origin.get(), function (n, key) {
    self.origin.set(key, self.model.get(key + '.value'));
  });
};

Validator.prototype._setup = function () {
  var self = this;

  if (this.fields) {
    _.each(this.fields, function (n, key) {
      self._addFieldProperties(key, n);
    });
  };

  if(this.origin) {
    _.each(this.origin.get(), function (value, fieldName) {
      self.model.set(fieldName + '.value', value);
    });
  };
};

Validator.prototype._addFieldProperties = function (fieldName, field) {
  var self = this;

  this.model.setEach(fieldName, {
    value: field.default,
    validations: this._assignValidations(field.validations),
    isValid: false,
    isInvalid: false,
    validate: function () {
      self._validate(fieldName);
    }
  });
};

Validator.prototype._validate = function (fieldName) {
  this.model.del(fieldName + '.messages');

  var field = this.model.get(fieldName);
  var valid = true;

  for (var i = 0; i < field.validations.length; i++) {
    var validation = field.validations[i];

    if (!this._check(field, validation.rule)) {
      valid = false;

      this.model.push(fieldName + '.messages', validation.message);
    }
  };

  if (valid) {
    this._setValid(fieldName);
  } else {
    this._setInvalid(fieldName);
  }
};

Validator.prototype._assignValidations = function (validations) {
  for (var i = 0; i < validations.length; i++) {
    var validation = validations[i];

    if (!validation.message) validation.message = this._getMessage(validation.rule);

    if (typeof validation.rule === 'string') validation.rule = this._getRule(validation.rule);

    if (typeof validation.rule !== 'function' && !_.isRegExp(validation.rule)) throw new Error('This rule is not (or does not point to) a RegEx or a function.');
  }

  return validations;
};

Validator.prototype._getRule = function (ruleName) {
  if(this.options.rules[ruleName]) return this.options.rules[ruleName];

  if(defaultValidations.hasOwnProperty(ruleName)) return defaultValidations[ruleName].rule;

  throw new Error('Rule: "' + ruleName + '" is not available. You need to add it as an option.');
};

Validator.prototype._getMessage = function (ruleName) {
  return this.options.messages[ruleName] || ((defaultValidations.hasOwnProperty(ruleName)) ? defaultValidations[ruleName].message : defaultValidations['default'].message);
};

Validator.prototype._check = function (field, rule) {
  if(_.isRegExp(rule)) return rule.test(field.value);

  if(typeof rule === 'function') return rule(field.value);
};

Validator.prototype._setInvalid = function (fieldName) {
  this.model.setEach(fieldName, { isValid: false, isInvalid: true });
};

Validator.prototype._setValid = function (fieldName) {
  this.model.setEach(fieldName, { isValid: true, isInvalid: false });
};
<commit_msg>Cleanup and changed checkForInvalidFields() to hasInvalidFields property<commit_after>var _ = require('lodash');
var defaultValidations = require('./defaultValidations');

module.exports = Validator;

/**
 * Creates a validator object and initiates it
 * @param {Model} model - A scoped model to the location on where to put the validator's data
 * @param {Model|string} [origin] - Either a scoped model to the location where the original data is stored. Or, a path (as string) to the location where to find the original data. If not passed, the fields parameter is mandatory.
 * @param {Collection.<string, Object>} [fields] - A collection of fields to use. If not passed, the origin parameter is mandatory. The key for each object is the field name, and the value is the field object (specified below).
   * @param {*} [fields.<fieldName>.default] - A default value for this specific field.
   * @param {Object[]} [fields.<fieldName>.validations] - A list of validations to apply.
     * @param {String|Function|RegEx} [fields.<fieldName>.validations.<index>.rule] - The rule to use when validating this rule. Either, this can be a string matching the name of a default rule (specified in default checks or passed in as an option), OR a function which will get run with the value to be validated as input, which should return true|false reflecting the validity, OR a RegEx, which will get run similar to if you pass in a function.
     * @param {String} [fields.<fieldName>.validations.<index>.message] - The error message to show if validation fails
 * @param {Object} [options] - An options object
   * @param {Collection.<string, Function|RegEx>} [options.rules] - A collection of default rules to add to this instance. Each key is the name of the rule. The value is the rule, either a function or regular expression similar to field specific functions/regular expressions passed in the fields parameter
 * @returns {Validator} - Instance of Validator
 */
function Validator(model, origin, fields, options) {
  // Parse out arguments

  var args = Array.prototype.slice.call(arguments);

  if(!args.length) throw new Error('You must specify a model!');
  if(!args.length == 1) throw new Error('You must either specify an origin or a fields object');

  this.model = args.shift();
  var arg = args.shift();

  if(typeof (arg || {}).path === 'function') {
    this.origin = arg;

    arg = args.shift();
  } else if(typeof arg === 'string') {
    this.origin = this.model.scope(arg);

    arg = args.shift();
  }

  if(arg) this.fields = arg;

  this.options = _.assign({
    rules: {},
    messages: {}
  }, args.shift());

  // Setup
  this._setup();
};

Validator.prototype.getValues = function () {
  var values = {};
  _.each(this.model.get(), function (field, fieldName) {
    values[fieldName] = field.value;
  });
  return values;
}

Validator.prototype.validate = function (fieldname) {
  this._validate(fieldname);
};

Validator.prototype.validateAll = function() {
  var self = this;
  _.each(this.model.get(), function (n, key) {
    self._validate(key);
  });
};

Validator.prototype.setInvalid = function (fieldName, message) {
  this._setInvalid(fieldName, false);
  this.model.push(fieldName + '.messages', message || defaultValidations['default'].message);
};

/*
 * @public
 * Reset values to origin.
 */
Validator.prototype.reset = function () {
  this._setup();
};

/*
 * @public
 * Commit values to model. Call after client- and serverside validation.
 */
Validator.prototype.commit = function () {
  if(!this.origin) return;

  var self = this;

  _.each(this.origin.get(), function (n, key) {
    self.origin.set(key, self.model.get(key + '.value'));
  });
};

Validator.prototype._setup = function () {
  var self = this;

  if (this.fields) {
    _.each(this.fields, function (n, key) {
      self._addFieldProperties(key, n);
    });
  };

  if(this.origin) {
    _.each(this.origin.get(), function (value, fieldName) {
      self.model.set(fieldName + '.value', value);
    });
  };
};

Validator.prototype._addFieldProperties = function (fieldName, field) {
  var self = this;

  this.model.setEach(fieldName, {
    value: field.default,
    validations: this._assignValidations(field.validations),
    isValid: false,
    isInvalid: false,
    validate: function () {
      self._validate(fieldName);
    }
  });
};

Validator.prototype._validate = function (fieldName) {
  this.model.del(fieldName + '.messages');

  var field = this.model.get(fieldName);
  var valid = true;

  for (var i = 0; i < field.validations.length; i++) {
    var validation = field.validations[i];

    if (!this._check(field, validation.rule)) {
      valid = false;

      this.model.push(fieldName + '.messages', validation.message);
    }
  };

  this._setValidity(fieldName, valid);
};

Validator.prototype._assignValidations = function (validations) {
  for (var i = 0; i < validations.length; i++) {
    var validation = validations[i];

    if (!validation.message) validation.message = this._getMessage(validation.rule);

    if (typeof validation.rule === 'string') validation.rule = this._getRule(validation.rule);

    if (typeof validation.rule !== 'function' && !_.isRegExp(validation.rule)) throw new Error('This rule is not (or does not point to) a RegEx or a function.');
  }

  return validations;
};

Validator.prototype._getRule = function (ruleName) {
  if(this.options.rules[ruleName]) return this.options.rules[ruleName];

  if(defaultValidations.hasOwnProperty(ruleName)) return defaultValidations[ruleName].rule;

  throw new Error('Rule: "' + ruleName + '" is not available. You need to add it as an option.');
};

Validator.prototype._getMessage = function (ruleName) {
  return this.options.messages[ruleName] || ((defaultValidations.hasOwnProperty(ruleName)) ? defaultValidations[ruleName].message : defaultValidations['default'].message);
};

Validator.prototype._check = function (field, rule) {
  if(_.isRegExp(rule)) return rule.test(field.value);

  if(typeof rule === 'function') return rule(field.value);
};

Validator.prototype._setValidity = function (fieldName, validity) {
  this.model.setEach(fieldName, { isValid: validity, isInvalid: !validity });
  this._setState();
};

Validator.prototype._setState = function() {
  this.model.set('hasInvalidFields', _.result(_.find(this.model.get(), {'isInvalid': true}), 'isInvalid'));
};
<|endoftext|>


<commit_before>/*! Keyframes-Tool | The MIT License (MIT) | Copyright (c) 2016 GibboK */

const css = require('css');
const R = require('ramda');
const fs = require('fs');
const path = require('path');

let fileIn,
    fileOut;

/**
 * Check software requirements.
 */
let prerequisiteCheck = () => {
    return new Promise((fulfill, reject) => {
        try {
            // check node version
            let getNodeVersion = (strVersion) => {
                let numberPattern = /\d+/g;
                return numVersion = Number(strVersion.match(numberPattern).join(''))
            },
                requiredVersion = getNodeVersion('v6.9.1'),
                currentVersion = getNodeVersion(process.version);
            if (currentVersion >= requiredVersion) {
                fulfill();
            } else {
                throw ('you current version of node.js is not supported, please update to the latest version of node.js');
            }
        } catch (err) {
            reject(err);
        }
    });
};

/**
 * Get arguments passed Node.js using terminal.
 */
let getNodeArguments = () => {
    return new Promise((fulfill, reject) => {
        try {
            // check paths in arguments
            let hasFileInOutArgs = process.argv.length === 4;
            if (!hasFileInOutArgs) {
                throw ('arguments for file-in and file-out must be provided');
            }
            // normalize paths
            fileIn = path.resolve(path.normalize(__dirname + process.argv[2])).toString();
            fileOut = path.resolve(path.normalize(__dirname + process.argv[3])).toString();

            // check paths for extensions
            let isFileInCss = fileIn.endsWith('.css'),
                isFileOutJson = fileOut.endsWith('.json');
            if (!isFileInCss) {
                throw ('argument file-in must have extension .css');
            }
            if (!isFileOutJson) {
                throw ('argument file-out must have extension .json');
            }
            fulfill();
        } catch (err) {
            reject(err);
        }
    });
};

/**
 * Read CSS input file.
 */
let readInputFile = () => {
    // read css file
    return new Promise((fulfill, reject) => {
        fs.readFile(fileIn, (err, data) => {
            if (err) {
                reject(err);
            } else {
                fulfill(data);
            }
        });
    });
}

/**
 * Parse content of CSS input file and creates and AST tree.
 */
let parse = (data) => {
    return new Promise((fulfill, reject) => {
        try {
            let parsedData = css.parse(data.toString(), { silent: false });
            fulfill(parsedData);
        } catch (err) {
            reject(err);
        }
    });
};

/**
 * Validate AST tree content.
 */
let validate = (data) => {
    return new Promise((fulfill, reject) => {
        try {
            let isStylesheet = data.type === 'stylesheet',
                hasNoParsingErrors = 'stylesheet' in data && data.stylesheet.parsingErrors.length === 0,
                hasKeyframes = R.any((rule) => rule.type === 'keyframes', data.stylesheet.rules);
            if (!isStylesheet || !hasNoParsingErrors || !hasKeyframes) {
                if (!isStylesheet) {
                    throw 'ast is not of type stylesheet';
                }
                if (!hasNoParsingErrors) {
                    R.map(err => console.log(new Error(`error: ${err}`)), data.stylesheet.parsingErrors);
                    throw 'file has parse error';
                }
                if (!hasKeyframes) {
                    throw 'no keyframes rules found';
                }
            }
            fulfill(data);
        } catch (err) {
            reject(err);
        }
    });
};

/**
 * Process AST tree content and a new data structure valid for Web Animation API KeyframeEffect.
 * The following code uses Ramda.js for traversing a complex AST tree,
 * an alternative version is visible at http://codepen.io/gibbok/pen/PbRrxp
 */
let processAST = (data) => {
    return new Promise((fulfill, reject) => {
        try {
            let processKeyframe = (vals, declarations) => [
                // map each value
                R.map(R.cond([
                    [R.equals('from'), R.always(0)],
                    [R.equals('to'), R.always(1)],
                    [R.T, offset => parseFloat(offset) / 100] // covert `offset` to decimal point
                ]), vals),
                // collect all property value pairs and merge in one object
                R.reduce(R.merge, {},
                    R.map(R.converge(R.objOf, [
                        R.prop('property'),
                        R.prop('value')
                    ]), declarations))
            ];

            let processAnimation = (offsets, transf) =>
                // process offset property
                R.map(R.pipe(
                    R.objOf('offset'),
                    R.merge(transf)), offsets);

            let getContentOfKeyframes = R.map(R.pipe(
                // process keyframes
                R.converge(processKeyframe, [
                    R.prop('values'),
                    R.prop('declarations')
                ]),
                // process animations
                R.converge(processAnimation, [
                    R.nth(0),
                    R.nth(1)
                ])));

            let transformAST = R.pipe(
                // get `stylesheet.rules` property
                R.path(['stylesheet', 'rules']),
                // get only object whose `type` property is `keyframes`
                R.filter(R.propEq('type', 'keyframes')),
                // map each item in `keyframes` collection
                // to an object {name: keyframe.name, content: [contentOfkeyframes] }
                R.map((keyframe) => ({
                    name: keyframe.name,
                    content: getContentOfKeyframes(keyframe.keyframes)
                })),
                // make a new object using animation `name` as keys
                // and using a flatten content as values
                R.converge(R.zipObj, [
                    R.map(R.prop('name')),
                    R.map(R.pipe(R.prop('content'), R.flatten))
                ]),
                // order by property `offset` ascending
                R.map(R.pipe(R.sortBy(R.prop('offset'))))
            );
            let result = transformAST(data);
            fulfill(result);
        } catch (err) {
            reject(err);
        }
    });
};

/**
 * Write JSON output file.
 */
let writeOutputFile = (data) => {
    return new Promise((fulfill, reject) => {
        data = JSON.stringify(data);
        fs.writeFile(fileOut, data, (err) => {
            if (err) {
                reject(err);
            } else {
                fulfill(data);
            }
        });
    });
};

/**
 * Initiate conversion process.
 */
let init = () => {
    prerequisiteCheck().then(() => {
        return getNodeArguments();
    }).then(() => {
        return readInputFile();
    }).then((data) => {
        return parse(data);
    }).then((data) => {
        return validate(data);
    }).then((data) => {
        return processAST(data);
    }).then((data) => {
        return writeOutputFile(data);
    }).then((data) => {
        console.log('success: file created at: ' + fileOut);
    }).catch(function(err) {
        console.log('error: ' + err);
    });
};

init();<commit_msg>Add refactory ramdajs covnert `offset` to decimal<commit_after>/*! Keyframes-Tool | The MIT License (MIT) | Copyright (c) 2016 GibboK */

const css = require('css');
const R = require('ramda');
const fs = require('fs');
const path = require('path');

let fileIn,
    fileOut;

/**
 * Check software requirements.
 */
let prerequisiteCheck = () => {
    return new Promise((fulfill, reject) => {
        try {
            // check node version
            let getNodeVersion = (strVersion) => {
                let numberPattern = /\d+/g;
                return numVersion = Number(strVersion.match(numberPattern).join(''))
            },
                requiredVersion = getNodeVersion('v6.9.1'),
                currentVersion = getNodeVersion(process.version);
            if (currentVersion >= requiredVersion) {
                fulfill();
            } else {
                throw ('you current version of node.js is not supported, please update to the latest version of node.js');
            }
        } catch (err) {
            reject(err);
        }
    });
};

/**
 * Get arguments passed Node.js using terminal.
 */
let getNodeArguments = () => {
    return new Promise((fulfill, reject) => {
        try {
            // check paths in arguments
            let hasFileInOutArgs = process.argv.length === 4;
            if (!hasFileInOutArgs) {
                throw ('arguments for file-in and file-out must be provided');
            }
            // normalize paths
            fileIn = path.resolve(path.normalize(__dirname + process.argv[2])).toString();
            fileOut = path.resolve(path.normalize(__dirname + process.argv[3])).toString();

            // check paths for extensions
            let isFileInCss = fileIn.endsWith('.css'),
                isFileOutJson = fileOut.endsWith('.json');
            if (!isFileInCss) {
                throw ('argument file-in must have extension .css');
            }
            if (!isFileOutJson) {
                throw ('argument file-out must have extension .json');
            }
            fulfill();
        } catch (err) {
            reject(err);
        }
    });
};

/**
 * Read CSS input file.
 */
let readInputFile = () => {
    // read css file
    return new Promise((fulfill, reject) => {
        fs.readFile(fileIn, (err, data) => {
            if (err) {
                reject(err);
            } else {
                fulfill(data);
            }
        });
    });
}

/**
 * Parse content of CSS input file and creates and AST tree.
 */
let parse = (data) => {
    return new Promise((fulfill, reject) => {
        try {
            let parsedData = css.parse(data.toString(), { silent: false });
            fulfill(parsedData);
        } catch (err) {
            reject(err);
        }
    });
};

/**
 * Validate AST tree content.
 */
let validate = (data) => {
    return new Promise((fulfill, reject) => {
        try {
            let isStylesheet = data.type === 'stylesheet',
                hasNoParsingErrors = 'stylesheet' in data && data.stylesheet.parsingErrors.length === 0,
                hasKeyframes = R.any((rule) => rule.type === 'keyframes', data.stylesheet.rules);
            if (!isStylesheet || !hasNoParsingErrors || !hasKeyframes) {
                if (!isStylesheet) {
                    throw 'ast is not of type stylesheet';
                }
                if (!hasNoParsingErrors) {
                    R.map(err => console.log(new Error(`error: ${err}`)), data.stylesheet.parsingErrors);
                    throw 'file has parse error';
                }
                if (!hasKeyframes) {
                    throw 'no keyframes rules found';
                }
            }
            fulfill(data);
        } catch (err) {
            reject(err);
        }
    });
};

/**
 * Process AST tree content and a new data structure valid for Web Animation API KeyframeEffect.
 * The following code uses Ramda.js for traversing a complex AST tree,
 * an alternative version is visible at http://codepen.io/gibbok/pen/PbRrxp
 */
let processAST = (data) => {
    return new Promise((fulfill, reject) => {
        try {
            let processKeyframe = (vals, declarations) => [
                // map each value
                R.map(R.cond([
                    [R.equals('from'), R.always(0)],
                    [R.equals('to'), R.always(1)],
                    [R.T, R.pipe(parseFloat, R.divide(R.__, 100))] // covert `offset` to decimal point
                ]), vals),
                // collect all property value pairs and merge in one object
                R.reduce(R.merge, {},
                    R.map(R.converge(R.objOf, [
                        R.prop('property'),
                        R.prop('value')
                    ]), declarations))
            ];

            let processAnimation = (offsets, transf) =>
                // process offset property
                R.map(R.pipe(
                    R.objOf('offset'),
                    R.merge(transf)), offsets);

            let getContentOfKeyframes = R.map(R.pipe(
                // process keyframes
                R.converge(processKeyframe, [
                    R.prop('values'),
                    R.prop('declarations')
                ]),
                // process animations
                R.converge(processAnimation, [
                    R.nth(0),
                    R.nth(1)
                ])));

            let transformAST = R.pipe(
                // get `stylesheet.rules` property
                R.path(['stylesheet', 'rules']),
                // get only object whose `type` property is `keyframes`
                R.filter(R.propEq('type', 'keyframes')),
                // map each item in `keyframes` collection
                // to an object {name: keyframe.name, content: [contentOfkeyframes] }
                R.map((keyframe) => ({
                    name: keyframe.name,
                    content: getContentOfKeyframes(keyframe.keyframes)
                })),
                // make a new object using animation `name` as keys
                // and using a flatten content as values
                R.converge(R.zipObj, [
                    R.map(R.prop('name')),
                    R.map(R.pipe(R.prop('content'), R.flatten))
                ]),
                // order by property `offset` ascending
                R.map(R.pipe(R.sortBy(R.prop('offset'))))
            );
            let result = transformAST(data);
            fulfill(result);
        } catch (err) {
            reject(err);
        }
    });
};

/**
 * Write JSON output file.
 */
let writeOutputFile = (data) => {
    return new Promise((fulfill, reject) => {
        data = JSON.stringify(data);
        fs.writeFile(fileOut, data, (err) => {
            if (err) {
                reject(err);
            } else {
                fulfill(data);
            }
        });
    });
};

/**
 * Initiate conversion process.
 */
let init = () => {
    prerequisiteCheck().then(() => {
        return getNodeArguments();
    }).then(() => {
        return readInputFile();
    }).then((data) => {
        return parse(data);
    }).then((data) => {
        return validate(data);
    }).then((data) => {
        return processAST(data);
    }).then((data) => {
        return writeOutputFile(data);
    }).then((data) => {
        console.log('success: file created at: ' + fileOut);
    }).catch(function(err) {
        console.log('error: ' + err);
    });
};

init();<|endoftext|>


<commit_before>import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
import { currentURL, visit, fillIn, click} from '@ember/test-helpers';
import { authenticateSession } from 'ember-simple-auth/test-support';

module('Acceptance | client_admin | client', function(hooks) {
  setupApplicationTest(hooks);

  test('visiting client AWI', async function(assert) {
    await authenticateSession({
      uid: 'tib.awi',
      name: 'Alfred Wegener Institute',
      role_id: 'client_admin',
      provider_id: 'tib',
      client_id: 'tib.awi'
    });
    await visit('/clients/tib.awi');

    assert.equal(currentURL(), '/clients/tib.awi');
    assert.dom('h2.work').hasText('Alfred Wegener Institute');
    assert.dom('a.nav-link.active').hasText('Info');
  });

  test('visiting client AWI settings', async function(assert) {
    await authenticateSession({
      uid: 'tib.awi',
      name: 'Alfred Wegener Institute',
      role_id: 'client_admin',
      provider_id: 'tib',
      client_id: 'tib.awi'
    });
    await visit('/clients/tib.awi/settings');

    assert.equal(currentURL(), '/clients/tib.awi/settings');
    assert.dom('h2.work').hasText('Alfred Wegener Institute');
    assert.dom('a.nav-link.active').hasText('Settings');
    assert.dom('button#edit-client').includesText('Update Account');
    assert.dom('button#delete-client').doesNotExist();
  });

  test('visiting client AWI prefixes', async function(assert) {
    await authenticateSession({
      uid: 'tib.awi',
      name: 'Alfred Wegener Institute',
      role_id: 'client_admin',
      provider_id: 'tib',
      client_id: 'tib.awi'
    });
    await visit('/clients/tib.awi/prefixes');

    assert.equal(currentURL(), '/clients/tib.awi/prefixes');
    assert.dom('h2.work').hasText('Alfred Wegener Institute');
    assert.dom('a.nav-link.active').hasText('Prefixes');
  });

  test('visiting client AWI dois', async function(assert) {
    await authenticateSession({
      uid: 'tib.awi',
      name: 'Alfred Wegener Institute',
      role_id: 'client_admin',
      provider_id: 'tib',
      client_id: 'tib.awi'
    });
    await visit('/clients/tib.awi/dois');

    assert.equal(currentURL(), '/clients/tib.awi/dois');
    assert.dom('h2.work').hasText('Alfred Wegener Institute');
    assert.dom('a.nav-link.active').hasText('DOIs');
    assert.dom('a#new-doi').includesText('Create DOI (Form)');
    assert.dom('a#upload-doi').includesText('Create DOI (File Upload)');
    assert.dom('a#transfer-dois').doesNotExist();
  });

  test('creating a new DOI for client AWI renders', async function(assert) {
    await authenticateSession({
      uid: 'tib.awi',
      name: 'Alfred Wegener Institute',
      role_id: 'client_admin',
      provider_id: 'tib',
      client_id: 'tib.awi'
    });
    await visit('/clients/tib.awi/dois/new');
    //on landing
    assert.equal(currentURL(), '/clients/tib.awi/dois/new');
    assert.dom('h3').hasText('Create DOI (Form)');
    assert.dom('input#url-field').hasNoValue();
    assert.dom('input#publisher-field').hasNoValue();
    assert.dom('input#publication-year-field').hasNoValue();
    assert.dom('input#draft-radio').isChecked();
    assert.dom('input#registered-radio').isNotChecked();
    assert.dom('input#findable-radio').isNotChecked();
    assert.dom('input#suffix-field').hasAnyValue();
  });

  test('creating a new DOI for client AWI', async function(assert) {
    assert.expect(5);
    await authenticateSession({
      uid: 'tib.awi',
      name: 'Alfred Wegener Institute',
      role_id: 'client_admin',
      provider_id: 'tib',
      client_id: 'tib.awi'
    });
    await visit('/clients/tib.awi/dois/new');
    await fillIn('input#url-field', 'http://bbc.co.uk');
    await fillIn('input#publisher-field', 'the BBC');
    await fillIn('input#publication-year-field', 1928);

    assert.dom('input#url-field').hasValue('http://bbc.co.uk');
    assert.dom('input#publisher-field').hasValue('the BBC');
    assert.dom('input#publication-year-field').hasValue("1928");
    assert.dom('input#url-field').hasStyle({color:'rgb(46, 204, 113)'});
    assert.dom('input#publisher-field').hasStyle({color:'rgb(46, 204, 113)'});
  });
});
<commit_msg>test for new form<commit_after>import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
import { currentURL, visit, fillIn, click, pauseTest} from '@ember/test-helpers';
import { authenticateSession } from 'ember-simple-auth/test-support';
import { selectChoose, selectSearch, removeMultipleOption, clearSelected } from 'ember-power-select/test-support';

module('Acceptance | client_admin | client', function(hooks) {
  setupApplicationTest(hooks);

  test('visiting client AWI', async function(assert) {
    await authenticateSession({
      uid: 'tib.awi',
      name: 'Alfred Wegener Institute',
      role_id: 'client_admin',
      provider_id: 'tib',
      client_id: 'tib.awi'
    });
    await visit('/clients/tib.awi');

    assert.equal(currentURL(), '/clients/tib.awi');
    assert.dom('h2.work').hasText('Alfred Wegener Institute');
    assert.dom('a.nav-link.active').hasText('Info');
  });

  test('visiting client AWI settings', async function(assert) {
    await authenticateSession({
      uid: 'tib.awi',
      name: 'Alfred Wegener Institute',
      role_id: 'client_admin',
      provider_id: 'tib',
      client_id: 'tib.awi'
    });
    await visit('/clients/tib.awi/settings');

    assert.equal(currentURL(), '/clients/tib.awi/settings');
    assert.dom('h2.work').hasText('Alfred Wegener Institute');
    assert.dom('a.nav-link.active').hasText('Settings');
    assert.dom('button#edit-client').includesText('Update Account');
    assert.dom('button#delete-client').doesNotExist();
  });

  test('visiting client AWI prefixes', async function(assert) {
    await authenticateSession({
      uid: 'tib.awi',
      name: 'Alfred Wegener Institute',
      role_id: 'client_admin',
      provider_id: 'tib',
      client_id: 'tib.awi'
    });
    await visit('/clients/tib.awi/prefixes');

    assert.equal(currentURL(), '/clients/tib.awi/prefixes');
    assert.dom('h2.work').hasText('Alfred Wegener Institute');
    assert.dom('a.nav-link.active').hasText('Prefixes');
  });

  test('visiting client AWI dois', async function(assert) {
    await authenticateSession({
      uid: 'tib.awi',
      name: 'Alfred Wegener Institute',
      role_id: 'client_admin',
      provider_id: 'tib',
      client_id: 'tib.awi'
    });
    await visit('/clients/tib.awi/dois');

    assert.equal(currentURL(), '/clients/tib.awi/dois');
    assert.dom('h2.work').hasText('Alfred Wegener Institute');
    assert.dom('a.nav-link.active').hasText('DOIs');
    assert.dom('a#new-doi').includesText('Create DOI (Form)');
    assert.dom('a#upload-doi').includesText('Create DOI (File Upload)');
    assert.dom('a#transfer-dois').doesNotExist();
  });

  test('creating a new DOI for client AWI renders', async function(assert) {
    await authenticateSession({
      uid: 'tib.awi',
      name: 'Alfred Wegener Institute',
      role_id: 'client_admin',
      provider_id: 'tib',
      client_id: 'tib.awi'
    });
    await visit('/clients/tib.awi/dois/new');
    //on landing
    assert.equal(currentURL(), '/clients/tib.awi/dois/new');
    assert.dom('h3').hasText('Create DOI (Form)');
    assert.dom('input#url-field').hasNoValue();
    assert.dom('input#publisher-field').hasNoValue();
    assert.dom('input#publication-year-field').hasNoValue();
    assert.dom('input#draft-radio').isChecked();
    assert.dom('input#registered-radio').isNotChecked();
    assert.dom('input#findable-radio').isNotChecked();
    assert.dom('input#suffix-field').hasAnyValue();
  });

  test('adding fields for a new DOI for client AWI', async function(assert) {
    assert.expect(5);
    await authenticateSession({
      uid: 'tib.awi',
      name: 'Alfred Wegener Institute',
      role_id: 'client_admin',
      provider_id: 'tib',
      client_id: 'tib.awi'
    });
    await visit('/clients/tib.awi/dois/new');
    await fillIn('input#url-field', 'http://bbc.co.uk');
    await fillIn('input#publisher-field', 'the BBC');
    await fillIn('input#publication-year-field', 1928);

    assert.dom('input#url-field').hasValue('http://bbc.co.uk');
    assert.dom('input#publisher-field').hasValue('the BBC');
    assert.dom('input#publication-year-field').hasValue("1928");
    assert.dom('input#url-field').hasStyle({color:'rgb(46, 204, 113)'});
    assert.dom('input#publisher-field').hasStyle({color:'rgb(46, 204, 113)'});
  });

  test('creating a new DOI for client AWI', async function(assert) {
    assert.expect(3);
    await authenticateSession({
      uid: 'tib.awi',
      name: 'Alfred Wegener Institute',
      role_id: 'client_admin',
      provider_id: 'tib',
      client_id: 'tib.awi'
    });
    await visit('/clients/tib.awi/dois/new');
    await fillIn('input#suffix-field', '111hwks-de38sssssss');
    await fillIn('input#url-field', 'http://bbc.co.uk');
    await fillIn('input#title-field-1', 'Abhinandan: Crowds gather for Indian pilots release');
    await fillIn('input#publisher-field', 'the BBC');
    await fillIn('input#publication-year-field', 1928);
    await fillIn('textarea#creator-field', 'Alexander Payne');
    // await selectChoose('.ember-power-select-trigger', '.ember-power-select-option', 1);
    await click('button#create');
    await pauseTest();

    assert.equal(currentURL(), '/clients/tib.awi/dois/10.2312/111hwks-de38');
    assert.dom('h2.work').hasValue('10.2312/hwks-de38');
    assert.dom('h3.work').hasValue('Abhinandan: Crowds gather for Indian pilots release');

  });
});
<|endoftext|>


<commit_before>var chai = require('chai');
var expect = chai.expect;
var request = require('supertest');

var app;
var errorMsg = 'Parameter is not an integer.';
var errorMsgOutOfRange = 'Parameter is out of range or not int.';

// There are three ways to pass parameters to express:
// - as part of the URL
// - as GET parameter in the querystring
// - as POST parameter in the body
// These test show that req.checkParams are only interested in req.params values, all other
// parameters will be ignored.

function validation(req, res) {
  req.check({
    'testparam': {
      in: 'params',
      notEmpty: true,
      isInt: {
        errorMessage: errorMsg
      }
    },
    'testquery': {
      in: 'query',
      notEmpty: true,
      isInt: {
        options: [{
          min: 2,
          max: 10
        }],
        errorMessage: errorMsgOutOfRange
      }
    }
  });

  var errors = req.validationErrors();
  if (errors) {
    return res.send(errors);
  }
  res.send({
    testparam: req.params.testparam,
    testquery: req.params.testquery
  });
}

function failParams(body, length) {
  expect(body).to.have.length(length);
  expect(body[0]).to.have.property('msg', errorMsg);
}

function failQuery(body, length) {
  expect(body).to.have.length(length);
  expect(body[0]).to.have.property('msg', errorMsgOutOfRange);
}

function failAll(body, length) {
  expect(body).to.have.length(length);
  expect(body[0]).to.have.property('msg', errorMsg);
  expect(body[1]).to.have.property('msg', errorMsgOutOfRange);
}

function pass(params) {
  expect(params).to.have.property('testparam', '25');
}

function getRoute(path, test, length, done) {
  request(app)
    .get(path)
    .end(function(err, res) {
      test(res.body, length);
      done();
    });
}

// This before() is required in each set of tests in
// order to use a new validation function in each file
before(function() {
  delete require.cache[require.resolve('./helpers/app')];
  app = require('./helpers/app')(validation);
});

describe('Check defining validator location inside schema validators', function() {

  it('should validate against schema with query and params locations', function(done) {
    getRoute('/25?testquery=6', pass, 1, done);
  });

  it('should fail when param is not integer', function(done) {
    getRoute('/ImNot?testquery=6', failParams, 1, done);
  });

  it('should fail when query param is out of range', function(done) {
    getRoute('/25?testquery=20', failQuery, 1, done);
  });

  it('should fail when non of params are valid', function(done) {
    getRoute('/ImNot?testquery=20', failAll, 2, done);
  });

});
<commit_msg>Extended test schema to check if not supported location type force validator to skip.<commit_after>var chai = require('chai');
var expect = chai.expect;
var request = require('supertest');

var app;
var errorMsg = 'Parameter is not an integer.';
var errorMsgOutOfRange = 'Parameter is out of range or not int.';

// There are three ways to pass parameters to express:
// - as part of the URL
// - as GET parameter in the querystring
// - as POST parameter in the body
// These test show that req.checkParams are only interested in req.params values, all other
// parameters will be ignored.

function validation(req, res) {
  req.check({
    'testparam': {
      in: 'params',
      notEmpty: true,
      isInt: {
        errorMessage: errorMsg
      }
    },
    'testquery': {
      in: 'query',
      notEmpty: true,
      isInt: {
        options: [{
          min: 2,
          max: 10
        }],
        errorMessage: errorMsgOutOfRange
      }
    },
    'skipped': {
      // this validator is a fake validator which cannot raise any error, should be always skipped
      in: 'notSupportedOne',
      notEmpty: true,
      isInt: {
        options: [{
          min: 2,
          max: 10
        }],
        errorMessage: errorMsgOutOfRange
      }
    }
  });

  var errors = req.validationErrors();
  if (errors) {
    return res.send(errors);
  }
  res.send({
    testparam: req.params.testparam,
    testquery: req.params.testquery
  });
}

function failParams(body, length) {
  expect(body).to.have.length(length);
  expect(body[0]).to.have.property('msg', errorMsg);
}

function failQuery(body, length) {
  expect(body).to.have.length(length);
  expect(body[0]).to.have.property('msg', errorMsgOutOfRange);
}

function failAll(body, length) {
  expect(body).to.have.length(length);
  expect(body[0]).to.have.property('msg', errorMsg);
  expect(body[1]).to.have.property('msg', errorMsgOutOfRange);
}

function pass(params) {
  expect(params).to.have.property('testparam', '25');
}

function getRoute(path, test, length, done) {
  request(app)
    .get(path)
    .end(function(err, res) {
      test(res.body, length);
      done();
    });
}

// This before() is required in each set of tests in
// order to use a new validation function in each file
before(function() {
  delete require.cache[require.resolve('./helpers/app')];
  app = require('./helpers/app')(validation);
});

describe('Check defining validator location inside schema validators', function() {

  it('should validate against schema with query and params locations', function(done) {
    getRoute('/25?testquery=6', pass, 1, done);
  });

  it('should fail when param is not integer', function(done) {
    getRoute('/ImNot?testquery=6', failParams, 1, done);
  });

  it('should fail when query param is out of range', function(done) {
    getRoute('/25?testquery=20', failQuery, 1, done);
  });

  it('should fail when non of params are valid', function(done) {
    getRoute('/ImNot?testquery=20', failAll, 2, done);
  });

});
<|endoftext|>


<commit_before>const request = require('supertest');
const cheerio = require('cheerio');
const { expect } = require('chai');
const app = require('../app');

describe('Middleware', () => {
  describe('http', () => {
    describe('.pageNotFound', () => {
      let req;

      beforeEach(() => {
        req = request(app).get('/nonexisting');
      });

      it('sets HTTP status to 404', (done) => {
        req.expect(404, done);
      });

      it('renders HTML page', (done) => {
        req.expect('Content-Type', /text\/html/, done);
      });

      it('sets page title', (done) => {
        req
          .expect((res) => {
            const content = res.text;
            const $ = cheerio.load(content);
            expect($('title').text()).to.eq('Slava Pavlutin | Page Not Found');
          })
          .end(done);
      });
    });
  });
});
<commit_msg>Remove 404 middleware test<commit_after><|endoftext|>


<commit_before>import * as matrix from '../../src/utils/matrix'

describe('Matrix Utilities', () => {

	describe('format()', () => {
		/**
		 * matrix(a, b, c, d, tx, ty) is a shorthand for:
		 * matrix3d(a, b, 0, 0, c, d, 0, 0, 0, 0, 1, 0, tx, ty, 0, 1)
		 * Source: https://goo.gl/7mJsfK
		 */
		it('should convert CSS transform matrix to matrix3d', () => {
			const source = [1, 2, 3, 4, 5, 6]
			const answer = [1, 2, 0, 0, 3, 4, 0, 0, 0, 0, 1, 0, 5, 6, 0, 1]
			expect(matrix.format(source)).to.eql(answer)
		})

		it('should return source argument if it is already matrix3d format', () => {
			const source = [1, 2, 0, 0, 3, 4, 0, 0, 0, 0, 1, 0, 5, 6, 0, 1]
			expect(matrix.format(source)).to.equal(source)
		})

		it('should throw a type error when passed a non-array', () => {
			let caught
			try {
				matrix.format({ foo: 'bar' })
			} catch (error) {
				caught = error
			}
			expect(caught).to.exist
			expect(caught).to.be.an.instanceOf(TypeError)
		})

		it('should throw a range error when passed an array of invalid length', () => {
			let caught
			try {
				matrix.format([])
			} catch (error) {
				caught = error
			}
			expect(caught).to.exist
			expect(caught).to.be.an.instanceOf(RangeError)
		})
	})

	describe('identity()', () => {
		it('should return a 4x4 identity matrix in column-major order', () => {
			const result = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
			expect(matrix.identity()).to.eql(result)
		})
	})

	describe('multiply()', () => {

		it('should return a 4x4 matrix equal to the sum of its two 4x4 matrix args', () => {
			const first = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
			const second = [16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
			const answer = [386, 444, 502, 560, 274, 316, 358, 400, 162, 188, 214, 240, 50, 60, 70, 80]
			expect(matrix.multiply(first, second)).to.eql(answer)
		})

		it('should throw a range error when passed an array without 16 values', () => {
			const first = [1, 2, 3, 4, 5, 6]
			const second = matrix.identity()
			let caught
			try {
				matrix.multiply(first, second)
			} catch (error) {
				caught = error
			}
			expect(caught).to.exist
			expect(caught).to.be.an.instanceOf(RangeError)
		})
	})

	describe('Transformation', () => {

		let dummy
		let transformProperty

		before('create dummy object', () => {
			dummy = document.createElement('div')
			document.body.appendChild(dummy)

			const computed = window.getComputedStyle(dummy)

			if (typeof computed['transform'] === 'string')
				return transformProperty = 'transform'
			if (typeof computed['-webkit-transform'] === 'string')
				return transformProperty = '-webkit-transform'
		})

		beforeEach('clean dummy object', () => {
			dummy.removeAttribute('style')
		})

		function getTransformAsArray (node) {
			const computedTransform = window.getComputedStyle(node)[transformProperty]
			const match = computedTransform.match(/\(([^)]+)\)/)[1]
			const values = match.split(', ').map(value => parseFloat(value))
			return matrix.format(values)
		}

		describe('rotateX()', () => {
			it('should generate an equivalent 4x4 matrix to CSS transform rotateX', () => {
				dummy.setAttribute('style', `${transformProperty}: rotateX(45deg)`)
				const result = matrix.rotateX(45)
				const answer = getTransformAsArray(dummy)
				expect(result).to.be.eql(answer)
			})
		})

		describe('rotateY()', () => {
			it('should generate an equivalent 4x4 matrix to CSS transform rotateY', () => {
				dummy.setAttribute('style', `${transformProperty}: rotateY(45deg)`)
				const result = matrix.rotateY(45)
				const answer = getTransformAsArray(dummy)
				expect(result).to.be.eql(answer)
			})
		})

		describe('rotateZ()', () => {
			it('should generate an equivalent 4x4 matrix to CSS transform rotateZ', () => {
				dummy.setAttribute('style', `${transformProperty}: rotateZ(45deg)`)
				const result = matrix.rotateZ(45)
				const answer = getTransformAsArray(dummy)
				expect(result).to.be.eql(answer)
			})
		})

		describe('scale()', () => {
			it('should generate an equivalent 4x4 matrix to CSS transform scale', () => {
				dummy.setAttribute('style', `${transformProperty}: scale(2)`)
				const result = matrix.scale(2)
				const answer = getTransformAsArray(dummy)
				expect(result).to.be.eql(answer)
			})
		})

		describe('translateX', () => {
			it('should generate an equivalent 4x4 matrix to CSS transform translateX', () => {
				dummy.setAttribute('style', `${transformProperty}: translateX(20px)`)
				const result = matrix.translateX(20)
				const answer = getTransformAsArray(dummy)
				expect(result).to.be.eql(answer)
			})
		})

		describe('translateY', () => {
			it('should generate an equivalent 4x4 matrix to CSS transform translateY', () => {
				dummy.setAttribute('style', `${transformProperty}: translateY(20px)`)
				const result = matrix.translateY(20)
				const answer = getTransformAsArray(dummy)
				expect(result).to.be.eql(answer)
			})
		})

		after('remove dummy object', () => {
			document.body.removeChild(dummy)
		})
	})
})
<commit_msg>reword matrix multiplication test description<commit_after>import * as matrix from '../../src/utils/matrix'

describe('Matrix Utilities', () => {

	describe('format()', () => {
		/**
		 * matrix(a, b, c, d, tx, ty) is a shorthand for:
		 * matrix3d(a, b, 0, 0, c, d, 0, 0, 0, 0, 1, 0, tx, ty, 0, 1)
		 * Source: https://goo.gl/7mJsfK
		 */
		it('should convert CSS transform matrix to matrix3d', () => {
			const source = [1, 2, 3, 4, 5, 6]
			const answer = [1, 2, 0, 0, 3, 4, 0, 0, 0, 0, 1, 0, 5, 6, 0, 1]
			expect(matrix.format(source)).to.eql(answer)
		})

		it('should return source argument if it is already matrix3d format', () => {
			const source = [1, 2, 0, 0, 3, 4, 0, 0, 0, 0, 1, 0, 5, 6, 0, 1]
			expect(matrix.format(source)).to.equal(source)
		})

		it('should throw a type error when passed a non-array', () => {
			let caught
			try {
				matrix.format({ foo: 'bar' })
			} catch (error) {
				caught = error
			}
			expect(caught).to.exist
			expect(caught).to.be.an.instanceOf(TypeError)
		})

		it('should throw a range error when passed an array of invalid length', () => {
			let caught
			try {
				matrix.format([])
			} catch (error) {
				caught = error
			}
			expect(caught).to.exist
			expect(caught).to.be.an.instanceOf(RangeError)
		})
	})

	describe('identity()', () => {
		it('should return a 4x4 identity matrix in column-major order', () => {
			const result = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
			expect(matrix.identity()).to.eql(result)
		})
	})

	describe('multiply()', () => {

		it('should return a 4x4 matrix equal to the product of both arguments', () => {
			const first = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
			const second = [16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
			const answer = [386, 444, 502, 560, 274, 316, 358, 400, 162, 188, 214, 240, 50, 60, 70, 80]
			expect(matrix.multiply(first, second)).to.eql(answer)
		})

		it('should throw a range error when passed an array without 16 values', () => {
			const first = [1, 2, 3, 4, 5, 6]
			const second = matrix.identity()
			let caught
			try {
				matrix.multiply(first, second)
			} catch (error) {
				caught = error
			}
			expect(caught).to.exist
			expect(caught).to.be.an.instanceOf(RangeError)
		})
	})

	describe('Transformation', () => {

		let dummy
		let transformProperty

		before('create dummy object', () => {
			dummy = document.createElement('div')
			document.body.appendChild(dummy)

			const computed = window.getComputedStyle(dummy)

			if (typeof computed['transform'] === 'string')
				return transformProperty = 'transform'
			if (typeof computed['-webkit-transform'] === 'string')
				return transformProperty = '-webkit-transform'
		})

		beforeEach('clean dummy object', () => {
			dummy.removeAttribute('style')
		})

		function getTransformAsArray (node) {
			const computedTransform = window.getComputedStyle(node)[transformProperty]
			const match = computedTransform.match(/\(([^)]+)\)/)[1]
			const values = match.split(', ').map(value => parseFloat(value))
			return matrix.format(values)
		}

		describe('rotateX()', () => {
			it('should generate an equivalent 4x4 matrix to CSS transform rotateX', () => {
				dummy.setAttribute('style', `${transformProperty}: rotateX(45deg)`)
				const result = matrix.rotateX(45)
				const answer = getTransformAsArray(dummy)
				expect(result).to.be.eql(answer)
			})
		})

		describe('rotateY()', () => {
			it('should generate an equivalent 4x4 matrix to CSS transform rotateY', () => {
				dummy.setAttribute('style', `${transformProperty}: rotateY(45deg)`)
				const result = matrix.rotateY(45)
				const answer = getTransformAsArray(dummy)
				expect(result).to.be.eql(answer)
			})
		})

		describe('rotateZ()', () => {
			it('should generate an equivalent 4x4 matrix to CSS transform rotateZ', () => {
				dummy.setAttribute('style', `${transformProperty}: rotateZ(45deg)`)
				const result = matrix.rotateZ(45)
				const answer = getTransformAsArray(dummy)
				expect(result).to.be.eql(answer)
			})
		})

		describe('scale()', () => {
			it('should generate an equivalent 4x4 matrix to CSS transform scale', () => {
				dummy.setAttribute('style', `${transformProperty}: scale(2)`)
				const result = matrix.scale(2)
				const answer = getTransformAsArray(dummy)
				expect(result).to.be.eql(answer)
			})
		})

		describe('translateX', () => {
			it('should generate an equivalent 4x4 matrix to CSS transform translateX', () => {
				dummy.setAttribute('style', `${transformProperty}: translateX(20px)`)
				const result = matrix.translateX(20)
				const answer = getTransformAsArray(dummy)
				expect(result).to.be.eql(answer)
			})
		})

		describe('translateY', () => {
			it('should generate an equivalent 4x4 matrix to CSS transform translateY', () => {
				dummy.setAttribute('style', `${transformProperty}: translateY(20px)`)
				const result = matrix.translateY(20)
				const answer = getTransformAsArray(dummy)
				expect(result).to.be.eql(answer)
			})
		})

		after('remove dummy object', () => {
			document.body.removeChild(dummy)
		})
	})
})
<|endoftext|>


<commit_before>module.exports = function init(options, callback) {
	require('./lib/config').extend(options);
	return require('./lib')(callback);
};<commit_msg>fix: net._normalizeConnectArgs<commit_after>var net = require('net');

function isPipeName(s) {
  return typeof s === 'string' && toNumber(s) === false;
}

function toNumber(x) {
  return (x = Number(x)) >= 0 ? x : false;
}

if (!net._normalizeConnectArgs) {
  //Returns an array [options] or [options, cb]
  //It is the same as the argument of Socket.prototype.connect().
  net._normalizeConnectArgs = function (args) {
    var options = {};

    if (args[0] !== null && typeof args[0] === 'object') {
      // connect(options, [cb])
      options = args[0];
    } else if (isPipeName(args[0])) {
      // connect(path, [cb]);
      options.path = args[0];
    } else {
      // connect(port, [host], [cb])
      options.port = args[0];
      if (typeof args[1] === 'string') {
        options.host = args[1];
      }
    }

    var cb = args[args.length - 1];
    return typeof cb === 'function' ? [options, cb] : [options];
  };
}

module.exports = function init(options, callback) {
	require('./lib/config').extend(options);
	return require('./lib')(callback);
};<|endoftext|>


<commit_before>import { expect } from 'chai'

import substyle from '../src'

describe('`className` management', () => {

  it('should derive a BEM compliant className for a passed nested element key', function () {
    const { className } = substyle({ className: 'my-class' }, 'toggle')
    expect(className).to.equal('my-class__toggle')
  })

  it('should derive a BEM compliant className for a passed modifier key', function () {
    const { className } = substyle({ className: 'my-class' }, '&active')
    expect(className).to.equal('my-class my-class--active')
  })

  it('should not return a className when no className has been set in the props', function () {
    const props = substyle({ }, 'toggle')
    expect(props).to.not.have.property('className')
  })

  it('should not generate additional class names for modifiers if selectedKeys contain element keys', function () {
    const { className } = substyle({ className: 'my-class' }, ['btn', '&disabled'])
    expect(className).to.equal('my-class__btn')
  })

  it('should return the original className when selectedKeys is not specified or empty', function () {
    const { className } = substyle({ className: 'my-class' })
    expect(className).to.equal('my-class')

    const { className: sameClassName } = substyle({ className: 'my-class' }, { '@active': false })
    expect(sameClassName).to.equal('my-class')

    const { className: stillTheSameClassName } = substyle({ className: 'my-class' }, undefined)
    expect(stillTheSameClassName).to.equal('my-class')
  })

  it('should correctly merge modifiers with existing classNames', function () {
    const { className } = substyle({ className: 'foo foo--bar' }, '&baz')
    expect(className).to.equal('foo foo--bar foo--baz')
  })

  it('should allow passing a function as second arg which is supposed to return the keys to select', () => {
    const { className } = substyle({ className: 'foo' }, () => 'bar')
    expect(className).to.equal('foo__bar')
  })

})
<commit_msg>fixed up the className specs<commit_after>import { expect } from 'chai'

import createSubstyle from '../src/createSubstyle'

describe('`className` management', () => {

  it('should derive a BEM compliant className for a passed nested element key', function () {
    const substyle = createSubstyle({ className: 'my-class' })
    const { className } = substyle('toggle')
    expect(className).to.equal('my-class__toggle')
  })

  it('should derive a BEM compliant className for a passed modifier key', function () {
    const substyle = createSubstyle({ className: 'my-class' })
    const { className } = substyle('&active')
    expect(className).to.equal('my-class my-class--active')
  })

  it('should not return a className when no className has been set in the props', function () {
    const substyle = createSubstyle({})
    const props = substyle('toggle')
    expect(props).to.not.have.property('className')
  })

  it('should not generate additional class names for modifiers if selectedKeys contain element keys', function () {
    const substyle = createSubstyle({ className: 'my-class' })
    const { className } = substyle(['btn', '&disabled'])
    expect(className).to.equal('my-class__btn')
  })

  it('should return the original className when selectedKeys is not specified or empty', function () {
    const substyle = createSubstyle({ className: 'my-class' })
    const { className } = substyle
    expect(className).to.equal('my-class')

    const { className: sameClassName } = substyle({ '@active': false })
    expect(sameClassName).to.equal('my-class')

    const { className: againTheSameClassName } = substyle([])
    expect(againTheSameClassName).to.equal('my-class')

    const { className: stillTheSameClassName } = substyle()
    expect(stillTheSameClassName).to.equal('my-class')
  })

  it('should correctly merge modifiers with existing classNames', function () {
    const substyle = createSubstyle({ className: 'foo foo--bar' })
    const { className } = substyle('&baz')
    expect(className).to.equal('foo foo--bar foo--baz')
  })

})
<|endoftext|>


<commit_before>var test = require('tape');
var _ = require('underscore');
var os = require('os');
var fs = require('fs');
var path = require('path');
var assert = require('assert');
var tilelive = require('tilelive');
var yaml = require('js-yaml');

var tm = require('../lib/tm');
var middleware = require('../lib/middleware');
var style = require('../lib/style');
var source = require('../lib/source');
var mockOauth = require('../lib/mapbox-mock')(require('express')());
var tmp = os.tmpdir();
var tmppath = tm.join(tmp, 'tm2-middleware-' + (+new Date));

var tmpId = tm.join(tmp, 'tm2-middlewareProject-' + (+new Date));
var sourceId = 'tmsource://' + tm.join(path.resolve(__dirname), 'fixtures-localsource');
var styleId = 'tmstyle://' + tm.join(path.resolve(__dirname), 'fixtures-localsource');
var server;

test('setup: config', function(t) {
    tm.config({
        db: path.join(tmppath, 'app.db'),
        cache: path.join(tmppath, 'cache'),
        fonts: path.join(tmppath, 'fonts'),
        mapboxauth: 'http://localhost:3001'
    }, t.end);
});

test('setup: mockserver', function(t) {
    tm.db.set('oauth', {
        account: 'test',
        accesstoken: 'testaccesstoken'
    });
    tm._config.mapboxtile = 'http://localhost:3001/v4';
    server = mockOauth.listen(3001, t.end);
});

test('history: loads', function(t) {
    var req = {};
    middleware.history(req, {}, function() {
        t.ok(req.history, 'has history');
        t.ok(req.history.source, 'history object includes a source');
        t.ok(req.history.source['mapbox:///mapbox.mapbox-streets-v5'], 'default source is listed');
        t.end();
    });
});

test('history: gets style/source info', function(t) {
    tm.history(sourceId);
    tm.history(styleId);

    var req = {};
    middleware.history(req, {}, function() {
        var sourceInfo = req.history.source[sourceId];
        var styleInfo = req.history.style[styleId];
        t.equal('Test source', sourceInfo.name, 'source info was loaded');
        t.equal('Test style', styleInfo.name, 'style info was loaded');
        t.end();
    });
});

test('history: removes dead source/styles', function(t) {
    tm.history('tmstyle:///foo');
    tm.history('tmsource:///bar');
    var req = {};
    middleware.history(req, {}, function() {
        t.ok(!req.history.source.foo, 'source `foo` was removed');
        if (req.history.style) t.ok(!req.history.style.bar, 'style `bar` was removed');
        t.end();
    });
});

test('writeStyle: makes tmp styles', function(t) {
    var data = {
        id:'tmpstyle://' + tmpId,
        name:'tmp-1234',
        source:'mapbox:///mapbox.mapbox-streets-v2',
        styles:{ 'a.mss': '#water { polygon-fill:#fff }' }
    };
    var req = { body: data };
    middleware.writeStyle(req, {}, function() {
        t.ok(req.style, 'appends style to req');
        t.ok(style.tmpid(req.style.data.id), 'creates a valid tmp id');
        var history = tm.history();
        if (history.style) {
            t.ok(history.style.indexOf(req.style.data.id) === -1, 'does not write to history');
        }
        t.equal(req.style.data.name, data.name, 'has correct info');
        t.end();
    });
});

test('writeStyle: makes persistent styles', function(t) {
    var data = {
        id:'tmstyle://' + tmpId,
        name:'tmp-1234',
        source:'mapbox:///mapbox.mapbox-streets-v2',
        styles:{ 'a.mss': '#water { polygon-fill:#fff }' }
    };
    var req = { body: data };
    middleware.writeStyle(req, {}, function() {
        t.ok(req.style, 'appends style to req');
        t.ok(!style.tmpid(req.style.data.id), 'does not create a tmp id');
        t.ok(tm.history().indexOf(req.style.data.id) !== -1, 'writes to history');
        t.equal(req.style.data.name, data.name, 'has correct info');
        t.ok(/maxzoom: 22/.test(fs.readFileSync(tmpId + '/project.yml', 'utf8')), 'saves project.yml');
        t.equal(data.styles['a.mss'], fs.readFileSync(tmpId + '/a.mss', 'utf8'), 'saves a.mss');
        t.end();
    });
});

test('writeStyle: cleanup', function(t) {
    setTimeout(function() {
        ['project.xml','project.yml','a.mss','.thumb.png'].forEach(function(file) {
            try { fs.unlinkSync(path.join(tmpId,file)) } catch(err) {};
        });
        try { fs.rmdirSync(tmpId) } catch(err) {};
        t.end();
    }, 250);
});

test('loadStyle: loads a tmp style', function(t) {
    var req = { query: { id:'tmpstyle://' + tmpId } };
    middleware.loadStyle(req, {}, function() {
        t.ok(req.style, 'appends style to req');
        t.equal(req.style.data.id, req.query.id, 'has the correct id');
        var history = tm.history();
        if (history.style) {
            t.ok(history.style.indexOf(req.style.data.id) === -1, 'does not write to history');
        }
        t.end();
    });
});

test('newStyle: creates a tmp style with source', function(t) {
    var sourceId = 'tmsource://' + tm.join(path.resolve(__dirname), 'fixtures-localsource');
    var req = { body: {}, query: { source:sourceId } };
    middleware.newStyle(req, {}, function(err) {
        t.ifError(err);
        t.deepEqual({
            'style.mss': 'Map {\n  background-color: #fff;\n}\n\n#solid {\n  line-width: 1;\n  line-color: rgba(153,204,68,0.5);\n}\n\n#box {\n  line-width: 1;\n  line-color: rgba(238,68,187,0.5);\n}\n\n'
        }, req.style.data.styles, 'creates default styles');
        t.equal(sourceId, req.style.data.source, 'sets source from input param');
        t.ok(style.tmpid(req.style.data.id));
        t.end();
    });
});

test('newStyle: creates a tmp style with a raster source', function(t) {
    var sourceId = 'tmsource://' + tm.join(path.resolve(__dirname), 'fixtures-localraster');
    var req = { body: {}, query: { source:sourceId } };
    middleware.newStyle(req, {}, function(err) {
        t.ifError(err);
        t.deepEqual({
            'style.mss': 'Map {\n  background-color: #fff;\n}\n\n#raster_local {\n  raster-opacity: 1;\n}\n\n'
        }, req.style.data.styles, 'creates default styles');
        t.equal(sourceId, req.style.data.source, 'sets source from input param');
        t.ok(style.tmpid(req.style.data.id));
        t.end();
    });
});

test('newStyle: errors a tmp style with bad source', function(t) {
    var sourceId = 'tmsource:///bad/path/to/nonexistent/source';
    var req = { body: {}, query: { source:sourceId } };
    middleware.newStyle(req, {}, function(err) {
        t.ok(err);
        t.equal('ENOENT', err.code);
        t.end();
    });
});

test('loadStyle: loads a persistent style', function(t) {
    var styleId = 'tmstyle://' + tm.join(path.resolve(__dirname), 'fixtures-localsource');
    var styleDoc = require('./fixtures-localsource/project.yml');
    var req = { query: { id: styleId } };
    middleware.loadStyle(req, {}, function() {
        t.ok(req.style, 'appends style to req');
        t.equal(req.style.data.id, styleId, 'has the correct id');
        t.ok(tm.history().indexOf(req.style.data.id) !== -1, 'writes to history');
        t.equal(req.style.data.mtime, styleDoc.mtime, 'style info was loaded');
        t.end();
    });
});

test('newSource: makes tmp sources', function(t) {
    var req = { body: {} };
    middleware.newSource(req, {}, function() {
        t.ok(req.source, 'appends source to req');
        t.ok(source.tmpid(req.source.data.id), 'creates a valid tmp id');
        var history = tm.history();
        if (history.source) {
            t.ok(history.source.indexOf(req.source.data.id) === -1, 'does not write to history');
        }
        t.end();
    });
});

test('writeSource: makes persistent sources', function(t) {
    var data = {
        id: 'tmsource://' + tmpId,
        name: 'Test source',
        attribution: '© John Doe 2013.',
        minzoom: 0,
        maxzoom: 6,
        Layer: [ {
            id: 'box',
            name: 'box',
            description: '',
            srs: '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over',
            properties: {
                'buffer-size': 0,
                minzoom: 0,
                maxzoom: 6
            },
            Datasource: {
                file: __dirname + '/fixtures-localsource/10m-900913-bounding-box.shp',
                type: 'shape'
            }
        } ]
    };
    var req = { body: data };
    middleware.writeSource(req, {}, function() {
        var s = req.source;
        t.ok(s, 'appends source to req');
        t.ok(!source.tmpid(s.data.id), 'does not creates a tmp id');
        var history = tm.history();
        if (history.source) {
            t.ok(history.source.indexOf(s.data.id) !== -1, 'writes to history');
        }
        t.deepEqual(s.data, data, 'has the right data');
        t.end();
    });
});

test('writeSource: cleanup', function(t) {
    setTimeout(function() {
        ['data.xml', 'data.yml'].forEach(function(file) {
            try { fs.unlinkSync(path.join(tmpId,file)) } catch(err) {};
        });
        try { fs.rmdirSync(tmpId) } catch(err) {};
        t.end();
    }, 250);
});

test('loadSource: loads a tmp source', function(t) {
    var writeReq = { body: {} };
    var req = { query: { id: source.tmpid() } };
    middleware.loadSource(req, {}, function() {
        t.ok(req.source, 'appends source to req');
        t.equal(req.source.data.id, source.tmpid(), 'has the correct id');
        var history = tm.history();
        if (history.source) {
            t.ok(history.source.indexOf(req.source.data.id) === -1, 'does not write to history');
        }
        t.end();
    });
});

test('loadSource: loads a persistent source', function(t) {
    var sourceId = 'tmsource://' + tm.join(path.resolve(__dirname), 'fixtures-localsource');
    var sourceDoc = require('./fixtures-localsource/data.yml');
    var req = { query: { id: sourceId } };
    middleware.loadSource(req, {}, function() {
        t.ok(req.source, 'appends source to req');
        t.equal(req.source.data.id, sourceId, 'has the correct id');
        t.ok(tm.history().indexOf(req.source.data.id) !== -1, 'writes to history');
        t.equal(req.source.data.name, sourceDoc.name, 'has the correct name');
        t.equal(req.source.data.attribution, sourceDoc.attribution, 'has the correct attribution');
        t.equal(req.source.data.minzoom, sourceDoc.minzoom, 'has the correct minzoom');
        t.equal(req.source.data.maxzoom, sourceDoc.maxzoom, 'has the correct maxzoom');
        t.deepEqual(req.source.data.Layer[0].Datasource, sourceDoc.Layer[0].Datasource, 'has the correct Layer');
        t.end();
    });
});

test('auth: errors on unauthenticated requests', function(t) {
    tm.db.rm('oauth');
    middleware.auth({}, {}, function(err) {
        t.equal('EOAUTH', err.code);
        t.end();
    });
});

test('auth: passes through authenticated requests', function(t) {
    tm.db.set('oauth', {
        account: 'test',
        accesstoken: '12345678'
    });
    middleware.auth({}, {}, function(err) {
        t.ok(!err);
        t.end();
    });
});

test('exporting: passes through', function(t) {
    middleware.exporting({}, {}, function(err) {
        t.ifError(err);
        t.end();
    });
});
// @TODO test cases where copytask has been started.
// Requires fixes for copytask pause/cancel.

test('userTilesets: fails without oauth', function(t) {
    tm.db.rm('oauth');
    middleware.userTilesets({}, {}, function(err) {
        t.equal('Error: No active OAuth account', err.toString());
        t.equal(err.code, 'EOAUTH');
        t.end();
    });
});

test('userTilesets: requires 200 from Mapbox API', function(t) {
    tm.db.set('oauth', {
        account: 'baduser',
        accesstoken: 'badtoken'
    });
    middleware.userTilesets({}, {}, function(err) {
        t.equal('Error: 403 GET http://localhost:3001/api/Map?account=baduser&_type=tileset&private=true&access_token=badtoken', err.toString());
        t.end();
    });
});

test('userTilesets: adds history entries for tilesets', function(t) {
    tm.db.set('oauth', {
        account: 'test',
        accesstoken: '12345678'
    });
    middleware.userTilesets({}, {}, function(err) {
        t.ifError(err);
        t.ok(tm.history().indexOf('mapbox:///test.vector-source') !== -1);
        t.ok(tm.history().indexOf('mapbox:///test.raster-source') === -1);
        t.end();
    });
});

test('latest: finds latest local project entry', function(t) {
    var req = {};
    middleware.latest(req, {}, function(err) {
        t.ifError(err);
        t.equal(req.latest, sourceId, 'finds latest source');
        t.end();
    });
});

test('cleanup', function(t) {
    tm.db.rm('oauth');
    tm.history(sourceId, true);
    tm.history(styleId, true);
    try { fs.unlinkSync(path.join(tmppath, 'app.db')); } catch(err) {}
    try { fs.rmdirSync(path.join(tmppath, 'cache')); } catch(err) {}
    try { fs.rmdirSync(tmppath); } catch(err) {}
    server.close(function() {
        t.end();
    });
});
<commit_msg>Add err assertions.<commit_after>var test = require('tape');
var _ = require('underscore');
var os = require('os');
var fs = require('fs');
var path = require('path');
var assert = require('assert');
var tilelive = require('tilelive');
var yaml = require('js-yaml');

var tm = require('../lib/tm');
var middleware = require('../lib/middleware');
var style = require('../lib/style');
var source = require('../lib/source');
var mockOauth = require('../lib/mapbox-mock')(require('express')());
var tmp = os.tmpdir();
var tmppath = tm.join(tmp, 'tm2-middleware-' + (+new Date));

var tmpId = tm.join(tmp, 'tm2-middlewareProject-' + (+new Date));
var sourceId = 'tmsource://' + tm.join(path.resolve(__dirname), 'fixtures-localsource');
var styleId = 'tmstyle://' + tm.join(path.resolve(__dirname), 'fixtures-localsource');
var server;

test('setup: config', function(t) {
    tm.config({
        db: path.join(tmppath, 'app.db'),
        cache: path.join(tmppath, 'cache'),
        fonts: path.join(tmppath, 'fonts'),
        mapboxauth: 'http://localhost:3001'
    }, t.end);
});

test('setup: mockserver', function(t) {
    tm.db.set('oauth', {
        account: 'test',
        accesstoken: 'testaccesstoken'
    });
    tm._config.mapboxtile = 'http://localhost:3001/v4';
    server = mockOauth.listen(3001, t.end);
});

test('history: loads', function(t) {
    var req = {};
    middleware.history(req, {}, function() {
        t.ok(req.history, 'has history');
        t.ok(req.history.source, 'history object includes a source');
        t.ok(req.history.source['mapbox:///mapbox.mapbox-streets-v5'], 'default source is listed');
        t.end();
    });
});

test('history: gets style/source info', function(t) {
    tm.history(sourceId);
    tm.history(styleId);

    var req = {};
    middleware.history(req, {}, function() {
        var sourceInfo = req.history.source[sourceId];
        var styleInfo = req.history.style[styleId];
        t.equal('Test source', sourceInfo.name, 'source info was loaded');
        t.equal('Test style', styleInfo.name, 'style info was loaded');
        t.end();
    });
});

test('history: removes dead source/styles', function(t) {
    tm.history('tmstyle:///foo');
    tm.history('tmsource:///bar');
    var req = {};
    middleware.history(req, {}, function() {
        t.ok(!req.history.source.foo, 'source `foo` was removed');
        if (req.history.style) t.ok(!req.history.style.bar, 'style `bar` was removed');
        t.end();
    });
});

test('writeStyle: makes tmp styles', function(t) {
    var data = {
        id:'tmpstyle://' + tmpId,
        name:'tmp-1234',
        source:'mapbox:///mapbox.mapbox-streets-v2',
        styles:{ 'a.mss': '#water { polygon-fill:#fff }' }
    };
    var req = { body: data };
    middleware.writeStyle(req, {}, function(err) {
        t.ifError(err);
        t.ok(req.style, 'appends style to req');
        t.ok(style.tmpid(req.style.data.id), 'creates a valid tmp id');
        var history = tm.history();
        if (history.style) {
            t.ok(history.style.indexOf(req.style.data.id) === -1, 'does not write to history');
        }
        t.equal(req.style.data.name, data.name, 'has correct info');
        t.end();
    });
});

test('writeStyle: makes persistent styles', function(t) {
    var data = {
        id:'tmstyle://' + tmpId,
        name:'tmp-1234',
        source:'mapbox:///mapbox.mapbox-streets-v2',
        styles:{ 'a.mss': '#water { polygon-fill:#fff }' }
    };
    var req = { body: data };
    middleware.writeStyle(req, {}, function(err) {
        t.ifError(err);
        t.ok(req.style, 'appends style to req');
        t.ok(!style.tmpid(req.style.data.id), 'does not create a tmp id');
        t.ok(tm.history().indexOf(req.style.data.id) !== -1, 'writes to history');
        t.equal(req.style.data.name, data.name, 'has correct info');
        t.ok(/maxzoom: 22/.test(fs.readFileSync(tmpId + '/project.yml', 'utf8')), 'saves project.yml');
        t.equal(data.styles['a.mss'], fs.readFileSync(tmpId + '/a.mss', 'utf8'), 'saves a.mss');
        t.end();
    });
});

test('writeStyle: cleanup', function(t) {
    setTimeout(function() {
        ['project.xml','project.yml','a.mss','.thumb.png'].forEach(function(file) {
            try { fs.unlinkSync(path.join(tmpId,file)) } catch(err) {};
        });
        try { fs.rmdirSync(tmpId) } catch(err) {};
        t.end();
    }, 250);
});

test('loadStyle: loads a tmp style', function(t) {
    var req = { query: { id:'tmpstyle://' + tmpId } };
    middleware.loadStyle(req, {}, function() {
        t.ok(req.style, 'appends style to req');
        t.equal(req.style.data.id, req.query.id, 'has the correct id');
        var history = tm.history();
        if (history.style) {
            t.ok(history.style.indexOf(req.style.data.id) === -1, 'does not write to history');
        }
        t.end();
    });
});

test('newStyle: creates a tmp style with source', function(t) {
    var sourceId = 'tmsource://' + tm.join(path.resolve(__dirname), 'fixtures-localsource');
    var req = { body: {}, query: { source:sourceId } };
    middleware.newStyle(req, {}, function(err) {
        t.ifError(err);
        t.deepEqual({
            'style.mss': 'Map {\n  background-color: #fff;\n}\n\n#solid {\n  line-width: 1;\n  line-color: rgba(153,204,68,0.5);\n}\n\n#box {\n  line-width: 1;\n  line-color: rgba(238,68,187,0.5);\n}\n\n'
        }, req.style.data.styles, 'creates default styles');
        t.equal(sourceId, req.style.data.source, 'sets source from input param');
        t.ok(style.tmpid(req.style.data.id));
        t.end();
    });
});

test('newStyle: creates a tmp style with a raster source', function(t) {
    var sourceId = 'tmsource://' + tm.join(path.resolve(__dirname), 'fixtures-localraster');
    var req = { body: {}, query: { source:sourceId } };
    middleware.newStyle(req, {}, function(err) {
        t.ifError(err);
        t.deepEqual({
            'style.mss': 'Map {\n  background-color: #fff;\n}\n\n#raster_local {\n  raster-opacity: 1;\n}\n\n'
        }, req.style.data.styles, 'creates default styles');
        t.equal(sourceId, req.style.data.source, 'sets source from input param');
        t.ok(style.tmpid(req.style.data.id));
        t.end();
    });
});

test('newStyle: errors a tmp style with bad source', function(t) {
    var sourceId = 'tmsource:///bad/path/to/nonexistent/source';
    var req = { body: {}, query: { source:sourceId } };
    middleware.newStyle(req, {}, function(err) {
        t.ok(err);
        t.equal('ENOENT', err.code);
        t.end();
    });
});

test('loadStyle: loads a persistent style', function(t) {
    var styleId = 'tmstyle://' + tm.join(path.resolve(__dirname), 'fixtures-localsource');
    var styleDoc = require('./fixtures-localsource/project.yml');
    var req = { query: { id: styleId } };
    middleware.loadStyle(req, {}, function() {
        t.ok(req.style, 'appends style to req');
        t.equal(req.style.data.id, styleId, 'has the correct id');
        t.ok(tm.history().indexOf(req.style.data.id) !== -1, 'writes to history');
        t.equal(req.style.data.mtime, styleDoc.mtime, 'style info was loaded');
        t.end();
    });
});

test('newSource: makes tmp sources', function(t) {
    var req = { body: {} };
    middleware.newSource(req, {}, function() {
        t.ok(req.source, 'appends source to req');
        t.ok(source.tmpid(req.source.data.id), 'creates a valid tmp id');
        var history = tm.history();
        if (history.source) {
            t.ok(history.source.indexOf(req.source.data.id) === -1, 'does not write to history');
        }
        t.end();
    });
});

test('writeSource: makes persistent sources', function(t) {
    var data = {
        id: 'tmsource://' + tmpId,
        name: 'Test source',
        attribution: '© John Doe 2013.',
        minzoom: 0,
        maxzoom: 6,
        Layer: [ {
            id: 'box',
            name: 'box',
            description: '',
            srs: '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over',
            properties: {
                'buffer-size': 0,
                minzoom: 0,
                maxzoom: 6
            },
            Datasource: {
                file: __dirname + '/fixtures-localsource/10m-900913-bounding-box.shp',
                type: 'shape'
            }
        } ]
    };
    var req = { body: data };
    middleware.writeSource(req, {}, function() {
        var s = req.source;
        t.ok(s, 'appends source to req');
        t.ok(!source.tmpid(s.data.id), 'does not creates a tmp id');
        var history = tm.history();
        if (history.source) {
            t.ok(history.source.indexOf(s.data.id) !== -1, 'writes to history');
        }
        t.deepEqual(s.data, data, 'has the right data');
        t.end();
    });
});

test('writeSource: cleanup', function(t) {
    setTimeout(function() {
        ['data.xml', 'data.yml'].forEach(function(file) {
            try { fs.unlinkSync(path.join(tmpId,file)) } catch(err) {};
        });
        try { fs.rmdirSync(tmpId) } catch(err) {};
        t.end();
    }, 250);
});

test('loadSource: loads a tmp source', function(t) {
    var writeReq = { body: {} };
    var req = { query: { id: source.tmpid() } };
    middleware.loadSource(req, {}, function() {
        t.ok(req.source, 'appends source to req');
        t.equal(req.source.data.id, source.tmpid(), 'has the correct id');
        var history = tm.history();
        if (history.source) {
            t.ok(history.source.indexOf(req.source.data.id) === -1, 'does not write to history');
        }
        t.end();
    });
});

test('loadSource: loads a persistent source', function(t) {
    var sourceId = 'tmsource://' + tm.join(path.resolve(__dirname), 'fixtures-localsource');
    var sourceDoc = require('./fixtures-localsource/data.yml');
    var req = { query: { id: sourceId } };
    middleware.loadSource(req, {}, function() {
        t.ok(req.source, 'appends source to req');
        t.equal(req.source.data.id, sourceId, 'has the correct id');
        t.ok(tm.history().indexOf(req.source.data.id) !== -1, 'writes to history');
        t.equal(req.source.data.name, sourceDoc.name, 'has the correct name');
        t.equal(req.source.data.attribution, sourceDoc.attribution, 'has the correct attribution');
        t.equal(req.source.data.minzoom, sourceDoc.minzoom, 'has the correct minzoom');
        t.equal(req.source.data.maxzoom, sourceDoc.maxzoom, 'has the correct maxzoom');
        t.deepEqual(req.source.data.Layer[0].Datasource, sourceDoc.Layer[0].Datasource, 'has the correct Layer');
        t.end();
    });
});

test('auth: errors on unauthenticated requests', function(t) {
    tm.db.rm('oauth');
    middleware.auth({}, {}, function(err) {
        t.equal('EOAUTH', err.code);
        t.end();
    });
});

test('auth: passes through authenticated requests', function(t) {
    tm.db.set('oauth', {
        account: 'test',
        accesstoken: '12345678'
    });
    middleware.auth({}, {}, function(err) {
        t.ok(!err);
        t.end();
    });
});

test('exporting: passes through', function(t) {
    middleware.exporting({}, {}, function(err) {
        t.ifError(err);
        t.end();
    });
});
// @TODO test cases where copytask has been started.
// Requires fixes for copytask pause/cancel.

test('userTilesets: fails without oauth', function(t) {
    tm.db.rm('oauth');
    middleware.userTilesets({}, {}, function(err) {
        t.equal('Error: No active OAuth account', err.toString());
        t.equal(err.code, 'EOAUTH');
        t.end();
    });
});

test('userTilesets: requires 200 from Mapbox API', function(t) {
    tm.db.set('oauth', {
        account: 'baduser',
        accesstoken: 'badtoken'
    });
    middleware.userTilesets({}, {}, function(err) {
        t.equal('Error: 403 GET http://localhost:3001/api/Map?account=baduser&_type=tileset&private=true&access_token=badtoken', err.toString());
        t.end();
    });
});

test('userTilesets: adds history entries for tilesets', function(t) {
    tm.db.set('oauth', {
        account: 'test',
        accesstoken: '12345678'
    });
    middleware.userTilesets({}, {}, function(err) {
        t.ifError(err);
        t.ok(tm.history().indexOf('mapbox:///test.vector-source') !== -1);
        t.ok(tm.history().indexOf('mapbox:///test.raster-source') === -1);
        t.end();
    });
});

test('latest: finds latest local project entry', function(t) {
    var req = {};
    middleware.latest(req, {}, function(err) {
        t.ifError(err);
        t.equal(req.latest, sourceId, 'finds latest source');
        t.end();
    });
});

test('cleanup', function(t) {
    tm.db.rm('oauth');
    tm.history(sourceId, true);
    tm.history(styleId, true);
    try { fs.unlinkSync(path.join(tmppath, 'app.db')); } catch(err) {}
    try { fs.rmdirSync(path.join(tmppath, 'cache')); } catch(err) {}
    try { fs.rmdirSync(tmppath); } catch(err) {}
    server.close(function() {
        t.end();
    });
});
<|endoftext|>