<commit_before>(function() {
    var wheel = require('../utils/base.js').wheel;
    var $;

    wheel(
        'compiler.Compiler',
        wheel.Class(function() {
            this.init = function(opts) {
                $ = wheel.compiler.command;

                this._compilerData   = new wheel.compiler.CompilerData({compiler: this});
                this._output         = new wheel.compiler.CompilerOutput({compiler: this});
                this._mainIndex      = -1;
                this._filename       = '';
                this._includes       = null;
                this._procStartIndex = -1;
                this._activeStruct   = null;

                var compilerOpts = {
                        compiler:     this,
                        compilerData: this._compilerData
                    };
                var constructors = [
                        'NumberDeclaration',
                        'NumberInc',
                        'NumberDec',
                        'NumberOperator',
                        'StringDeclaration',
                        'ProcedureDeclaration',
                        'Set',
                        'Call',
                        'CallFunction',
                        'CallReturn',
                        'Ret',
                        'Label',
                        'ArrayR',
                        'ArrayW',
                        'Addr',
                        'JmpC'
                    ];
                var compilers = {};

                for (var i = 0; i < constructors.length; i++) {
                    compilers[constructors[i]] = new wheel.compiler.commands[constructors[i]](compilerOpts); // Needs namespace!
                }
                this._compilers = compilers;

                compilers.CallFunction.setCallCompiler(compilers.Call);
                compilers.CallFunction.setSetCompiler(compilers.Set);
                compilers.CallFunction.setNumberOperatorCompiler(compilers.NumberOperator);

                compilers.CallReturn.setSetCompiler(compilers.Set);
                compilers.CallReturn.setRetCompiler(compilers.Ret);

                this._compilerByCommand = {
                    je:         compilers.JmpC,
                    jne:        compilers.JmpC,
                    jl:         compilers.JmpC,
                    jle:        compilers.JmpC,
                    jg:         compilers.JmpC,
                    jge:        compilers.JmpC,
                    set:        compilers.Set,
                    addr:       compilers.Addr,
                    arrayr:     compilers.ArrayR,
                    arrayw:     compilers.ArrayW,
                    number:     compilers.NumberDeclaration,
                    inc:        compilers.NumberInc,
                    dec:        compilers.NumberDec,
                    add:        compilers.NumberOperator,
                    sub:        compilers.NumberOperator,
                    mul:        compilers.NumberOperator,
                    div:        compilers.NumberOperator,
                    and:        compilers.NumberOperator,
                    or:         compilers.NumberOperator,
                    xor:        compilers.NumberOperator,
                    cmp:        compilers.NumberOperator,
                    mod:        compilers.NumberOperator,
                    string:     compilers.StringDeclaration,
                    proc:       compilers.ProcedureDeclaration,
                    ret:        compilers.Ret,
                    'return':   compilers.CallReturn
                };
            };

            this.createError = function(errorNumber, message, location) {
                location || (location = this._location || {});

                var error    = new Error('#' + errorNumber + ' ' + message);
                var includes = this._includes;
                var filename = location.filename;
                var line     = '';

                for (var i = 0; i < includes.length; i++) {
                    var include = includes[i];
                    if (include.filename === filename) {
                        line = include.lines[location.lineNumber] || '';
                        break;
                    }
                }

                error.location = {
                    filename:   location.filename,
                    lineNumber: location.lineNumber,
                    line:       line
                };
                return error;
            };

            this.createCommand = function(command, params) {
                var args = wheel.compiler.command[command].args;
                var code = wheel.compiler.command[command].code;

                if (params.length) {
                    for (var i = 0; i < params.length; i++) {
                        var param = params[i];
                        var found = false;

                        for (var j = 0; j < args.length; j++) {
                            var argsMetaType = args[j].metaType || false;
                            var matchType    = false;

                            // Check the primitive types...
                            if (param.type === args[j].type) {
                                if (argsMetaType) {
                                    if (param.metaType === argsMetaType) {
                                        matchType = true;
                                    } else if (param.vr && (param.vr.metaType === argsMetaType)) {
                                        matchType = true;
                                    }
                                } else {
                                    matchType = true;
                                }
                            // Check the var types...
                            } else if (param.vr && param.vr.field && (param.vr.field.type === args[j].type)) {
                                matchType = true;
                            }

                            if (matchType) {
                                args  = ('args' in args[j]) ? args[j].args : args[j];
                                found = true;
                                break;
                            }
                        }
                        if (!found) {
                            console.log(command, params);
                            throw this.createError(wheel.compiler.error.TYPE_MISMATCH, 'Type mismatch "' + param.param + '".');
                        }
                    }
                    return {
                        code:   code,
                        params: params,
                        location: {
                            filename:   this._location.filename,
                            lineNumber: this._location.lineNumber
                        }
                    };
                }
            };

            this.validateCommand = function(command, params) {
                if (!(command in wheel.compiler.command)) {
                    return false;
                }

                for (var i = 0; i < params.length; i++) {
                    params[i] = this._compilerData.paramInfo(params[i]);
                }
                return this.createCommand(command, params);
            };

            this.compileLine = function(line, location) {
                var compilerByCommand = this._compilerByCommand;
                var compilerData      = this._compilerData;
                var output            = this._output;

                if ((line.indexOf('proc ') === -1) && (line.indexOf('(') !== -1)) {
                    var spacePos = line.indexOf(' ');
                    var command  = line.substr(0, spacePos).trim();
                    if (['set', 'add', 'sub', 'mul', 'div', 'mod', 'cmp'].indexOf(command) === -1) {
                        this._compilers.Call.compile(line);
                    } else {
                        this._compilers.CallFunction.compile(line);
                    }
                } else if (this._compilers.Label.hasLabel(line)) {
                    compilerData.findLabel(line.substr(0, line.length - 1)).index = output.getLength() - 1;
                } else {
                    var commandAndParams = this.getCommandAndParams(line);
                    var splitParams      = wheel.compiler.compilerHelper.splitParams(commandAndParams.params);
                    var validatedCommand = this.validateCommand(commandAndParams.command, splitParams);
                    validatedCommand && (validatedCommand.command = commandAndParams.command);
                    switch (commandAndParams.command) {
                        case 'endp':
                            if (this._activeStruct !== null) {
                                throw this.createError(wheel.compiler.error.INVALID_BLOCK_CLOSE, 'Invalid command "endp".');
                            }
                            this._compilers.Ret.compile(null);

                            output.getBuffer()[this._procStartIndex].localCount = compilerData.getLocalOffset();
                            this._procStartIndex = -1;
                            compilerData.resetLocal();
                            compilerData.removeLocalStructs();
                            break;

                        case 'struct':
                            this._activeStruct = compilerData.declareStruct(commandAndParams.params, commandAndParams.command, location);
                            break;

                        case 'ends':
                            this._activeStruct = null;
                            break;

                        default:
                            if (commandAndParams.command in compilerByCommand) {
                                compilerByCommand[commandAndParams.command].compile(validatedCommand, splitParams, commandAndParams.params, location);
                            } else if (validatedCommand === false) {
                                var struct = compilerData.findStruct(commandAndParams.command);
                                if (struct === null) {
                                    throw this.createError(wheel.compiler.error.UNKNOWN_COMMAND, 'Unknown command "' + commandAndParams.command + '".');
                                } else if (this._activeStruct !== null) {
                                    for (var j = 0; j < splitParams.length; j++) {
                                        compilerData.declareStructField(splitParams[j], $.T_STRUCT_G, $.T_STRUCT_G_ARRAY, struct.size, struct);
                                    }
                                } else if (this.getInProc()) {
                                    for (var j = 0; j < splitParams.length; j++) {
                                        compilerData.declareLocal(splitParams[j], $.T_STRUCT_L, $.T_STRUCT_L_ARRAY, struct);
                                    }
                                } else {
                                    for (var j = 0; j < splitParams.length; j++) {
                                        compilerData.declareGlobal(splitParams[j], $.T_STRUCT_G, $.T_STRUCT_G_ARRAY, struct, location);
                                    }
                                }
                            } else {
                                this.getOutput().add(validatedCommand);
                            }
                            break;
                    }
                }
            };

            this.compileTypeof = function(line) {
                var i = line.indexOf('@typeof(');
                if (i === -1) {
                    return line;
                }
                var j            = line.indexOf(')');
                var vr           = line.substr(i + 8, j - 8 - i).trim();
                var compilerData = this._compilerData;

                var local = compilerData.findLocal(vr);
                if (local === null) {
                    var global = compilerData.findLocal(vr);
                    if (global === null) {
                        throw this.createError(wheel.compiler.error.UNDEFINED_IDENTIFIER_IN_TYPEOF, 'Undefined identifier "' + vr + '".');
                    } else if (global.type === $.T_NUM_G_ARRAY) {
                        line = 'number ' + line.substr(j + 1 - line.length).trim();
                    } else if (global.struct) {
                        line = global.struct.name + ' ' + line.substr(j + 1 - line.length).trim();
                    }
                } else if (local.type === $.T_NUM_L_ARRAY) {
                    line = 'number ' + line.substr(j + 1 - line.length).trim();
                } else if (local.struct) {
                    line = local.struct.name + ' ' + line.substr(j + 1 - line.length).trim();
                }

                return line;
            };

            this.compileLines = function(lines) {
                var sourceMap = lines.sourceMap;
                var output    = this._output;

                this._procStartIndex = -1;
                this._activeStruct   = null;
                for (var i = 0; i < lines.output.length; i++) {
                    var line = lines.output[i].trim();
                    if (line === '') {
                        continue;
                    }

                    this._location = sourceMap[i];

                    this.compileLine(this.compileTypeof(line));
                }

                return output.getBuffer();
            };

            this.compile = function(includes) {
                var compilerData = this._compilerData;
                var output       = this._output;

                compilerData.reset();
                output.reset();
                this._mainIndex = -1;
                this._includes  = includes;

                var scriptCompiler = new wheel.compiler.script.ScriptCompiler({});
                var i              = includes.length;
                while (i) {
                    i--;
                    var filename = includes[i].filename;
                    var lines    = scriptCompiler.compile(filename, includes[i].lines);
                    this._filename = filename;

                    this._compilers.Label.compile(lines);
                    this.compileLines(lines);
                    this._compilers.Label.updateLabels();
                }

                if (this._mainIndex === -1) {
                    throw this.createError(wheel.compiler.error.NO_MAIN_PROCEDURE, 'No main procedure found.');
                }

                output.optimizeTypes();
                output.setGlobalOffset(compilerData.getGlobalOffset());
                output.setMainIndex(this._mainIndex);
                output.getLines();

                return output;
            };

            this.getIncludes = function() {
                return this._includes;
            };

            this.getOutput = function() {
                return this._output;
            };

            this.getCompilerData = function() {
                return this._compilerData;
            };

            this.getProcStartIndex = function() {
                return this._procStartIndex;
            };

            this.setProcStartIndex = function(procStartIndex) {
                this._procStartIndex = procStartIndex;
            };

            this.getActiveStruct = function() {
                return this._activeStruct;
            };

            this.setMainIndex = function(mainIndex) {
                this._mainIndex = mainIndex;
            };

            this.getInProc = function() {
                return (this._procStartIndex !== -1);
            };

            this.getCommandAndParams = function(line) {
                var command = line;
                var params  = '';
                var i       = line.indexOf(' ');

                if (i !== -1) {
                    command = line.substr(0, i),
                    params  = line.substr(i - line.length + 1).trim();
                }
                return {
                    command: command,
                    params:  params
                };
            };
        })
    );
})();<commit_msg>Removed log.<commit_after>(function() {
    var wheel = require('../utils/base.js').wheel;
    var $;

    wheel(
        'compiler.Compiler',
        wheel.Class(function() {
            this.init = function(opts) {
                $ = wheel.compiler.command;

                this._compilerData   = new wheel.compiler.CompilerData({compiler: this});
                this._output         = new wheel.compiler.CompilerOutput({compiler: this});
                this._mainIndex      = -1;
                this._filename       = '';
                this._includes       = null;
                this._procStartIndex = -1;
                this._activeStruct   = null;

                var compilerOpts = {
                        compiler:     this,
                        compilerData: this._compilerData
                    };
                var constructors = [
                        'NumberDeclaration',
                        'NumberInc',
                        'NumberDec',
                        'NumberOperator',
                        'StringDeclaration',
                        'ProcedureDeclaration',
                        'Set',
                        'Call',
                        'CallFunction',
                        'CallReturn',
                        'Ret',
                        'Label',
                        'ArrayR',
                        'ArrayW',
                        'Addr',
                        'JmpC'
                    ];
                var compilers = {};

                for (var i = 0; i < constructors.length; i++) {
                    compilers[constructors[i]] = new wheel.compiler.commands[constructors[i]](compilerOpts); // Needs namespace!
                }
                this._compilers = compilers;

                compilers.CallFunction.setCallCompiler(compilers.Call);
                compilers.CallFunction.setSetCompiler(compilers.Set);
                compilers.CallFunction.setNumberOperatorCompiler(compilers.NumberOperator);

                compilers.CallReturn.setSetCompiler(compilers.Set);
                compilers.CallReturn.setRetCompiler(compilers.Ret);

                this._compilerByCommand = {
                    je:         compilers.JmpC,
                    jne:        compilers.JmpC,
                    jl:         compilers.JmpC,
                    jle:        compilers.JmpC,
                    jg:         compilers.JmpC,
                    jge:        compilers.JmpC,
                    set:        compilers.Set,
                    addr:       compilers.Addr,
                    arrayr:     compilers.ArrayR,
                    arrayw:     compilers.ArrayW,
                    number:     compilers.NumberDeclaration,
                    inc:        compilers.NumberInc,
                    dec:        compilers.NumberDec,
                    add:        compilers.NumberOperator,
                    sub:        compilers.NumberOperator,
                    mul:        compilers.NumberOperator,
                    div:        compilers.NumberOperator,
                    and:        compilers.NumberOperator,
                    or:         compilers.NumberOperator,
                    xor:        compilers.NumberOperator,
                    cmp:        compilers.NumberOperator,
                    mod:        compilers.NumberOperator,
                    string:     compilers.StringDeclaration,
                    proc:       compilers.ProcedureDeclaration,
                    ret:        compilers.Ret,
                    'return':   compilers.CallReturn
                };
            };

            this.createError = function(errorNumber, message, location) {
                location || (location = this._location || {});

                var error    = new Error('#' + errorNumber + ' ' + message);
                var includes = this._includes;
                var filename = location.filename;
                var line     = '';

                for (var i = 0; i < includes.length; i++) {
                    var include = includes[i];
                    if (include.filename === filename) {
                        line = include.lines[location.lineNumber] || '';
                        break;
                    }
                }

                error.location = {
                    filename:   location.filename,
                    lineNumber: location.lineNumber,
                    line:       line
                };
                return error;
            };

            this.createCommand = function(command, params) {
                var args = wheel.compiler.command[command].args;
                var code = wheel.compiler.command[command].code;

                if (params.length) {
                    for (var i = 0; i < params.length; i++) {
                        var param = params[i];
                        var found = false;

                        for (var j = 0; j < args.length; j++) {
                            var argsMetaType = args[j].metaType || false;
                            var matchType    = false;

                            // Check the primitive types...
                            if (param.type === args[j].type) {
                                if (argsMetaType) {
                                    if (param.metaType === argsMetaType) {
                                        matchType = true;
                                    } else if (param.vr && (param.vr.metaType === argsMetaType)) {
                                        matchType = true;
                                    }
                                } else {
                                    matchType = true;
                                }
                            // Check the var types...
                            } else if (param.vr && param.vr.field && (param.vr.field.type === args[j].type)) {
                                matchType = true;
                            }

                            if (matchType) {
                                args  = ('args' in args[j]) ? args[j].args : args[j];
                                found = true;
                                break;
                            }
                        }
                        if (!found) {
                            throw this.createError(wheel.compiler.error.TYPE_MISMATCH, 'Type mismatch "' + param.param + '".');
                        }
                    }
                    return {
                        code:   code,
                        params: params,
                        location: {
                            filename:   this._location.filename,
                            lineNumber: this._location.lineNumber
                        }
                    };
                }
            };

            this.validateCommand = function(command, params) {
                if (!(command in wheel.compiler.command)) {
                    return false;
                }

                for (var i = 0; i < params.length; i++) {
                    params[i] = this._compilerData.paramInfo(params[i]);
                }
                return this.createCommand(command, params);
            };

            this.compileLine = function(line, location) {
                var compilerByCommand = this._compilerByCommand;
                var compilerData      = this._compilerData;
                var output            = this._output;

                if ((line.indexOf('proc ') === -1) && (line.indexOf('(') !== -1)) {
                    var spacePos = line.indexOf(' ');
                    var command  = line.substr(0, spacePos).trim();
                    if (['set', 'add', 'sub', 'mul', 'div', 'mod', 'cmp'].indexOf(command) === -1) {
                        this._compilers.Call.compile(line);
                    } else {
                        this._compilers.CallFunction.compile(line);
                    }
                } else if (this._compilers.Label.hasLabel(line)) {
                    compilerData.findLabel(line.substr(0, line.length - 1)).index = output.getLength() - 1;
                } else {
                    var commandAndParams = this.getCommandAndParams(line);
                    var splitParams      = wheel.compiler.compilerHelper.splitParams(commandAndParams.params);
                    var validatedCommand = this.validateCommand(commandAndParams.command, splitParams);
                    validatedCommand && (validatedCommand.command = commandAndParams.command);
                    switch (commandAndParams.command) {
                        case 'endp':
                            if (this._activeStruct !== null) {
                                throw this.createError(wheel.compiler.error.INVALID_BLOCK_CLOSE, 'Invalid command "endp".');
                            }
                            this._compilers.Ret.compile(null);

                            output.getBuffer()[this._procStartIndex].localCount = compilerData.getLocalOffset();
                            this._procStartIndex = -1;
                            compilerData.resetLocal();
                            compilerData.removeLocalStructs();
                            break;

                        case 'struct':
                            this._activeStruct = compilerData.declareStruct(commandAndParams.params, commandAndParams.command, location);
                            break;

                        case 'ends':
                            this._activeStruct = null;
                            break;

                        default:
                            if (commandAndParams.command in compilerByCommand) {
                                compilerByCommand[commandAndParams.command].compile(validatedCommand, splitParams, commandAndParams.params, location);
                            } else if (validatedCommand === false) {
                                var struct = compilerData.findStruct(commandAndParams.command);
                                if (struct === null) {
                                    throw this.createError(wheel.compiler.error.UNKNOWN_COMMAND, 'Unknown command "' + commandAndParams.command + '".');
                                } else if (this._activeStruct !== null) {
                                    for (var j = 0; j < splitParams.length; j++) {
                                        compilerData.declareStructField(splitParams[j], $.T_STRUCT_G, $.T_STRUCT_G_ARRAY, struct.size, struct);
                                    }
                                } else if (this.getInProc()) {
                                    for (var j = 0; j < splitParams.length; j++) {
                                        compilerData.declareLocal(splitParams[j], $.T_STRUCT_L, $.T_STRUCT_L_ARRAY, struct);
                                    }
                                } else {
                                    for (var j = 0; j < splitParams.length; j++) {
                                        compilerData.declareGlobal(splitParams[j], $.T_STRUCT_G, $.T_STRUCT_G_ARRAY, struct, location);
                                    }
                                }
                            } else {
                                this.getOutput().add(validatedCommand);
                            }
                            break;
                    }
                }
            };

            this.compileTypeof = function(line) {
                var i = line.indexOf('@typeof(');
                if (i === -1) {
                    return line;
                }
                var j            = line.indexOf(')');
                var vr           = line.substr(i + 8, j - 8 - i).trim();
                var compilerData = this._compilerData;

                var local = compilerData.findLocal(vr);
                if (local === null) {
                    var global = compilerData.findLocal(vr);
                    if (global === null) {
                        throw this.createError(wheel.compiler.error.UNDEFINED_IDENTIFIER_IN_TYPEOF, 'Undefined identifier "' + vr + '".');
                    } else if (global.type === $.T_NUM_G_ARRAY) {
                        line = 'number ' + line.substr(j + 1 - line.length).trim();
                    } else if (global.struct) {
                        line = global.struct.name + ' ' + line.substr(j + 1 - line.length).trim();
                    }
                } else if (local.type === $.T_NUM_L_ARRAY) {
                    line = 'number ' + line.substr(j + 1 - line.length).trim();
                } else if (local.struct) {
                    line = local.struct.name + ' ' + line.substr(j + 1 - line.length).trim();
                }

                return line;
            };

            this.compileLines = function(lines) {
                var sourceMap = lines.sourceMap;
                var output    = this._output;

                this._procStartIndex = -1;
                this._activeStruct   = null;
                for (var i = 0; i < lines.output.length; i++) {
                    var line = lines.output[i].trim();
                    if (line === '') {
                        continue;
                    }

                    this._location = sourceMap[i];

                    this.compileLine(this.compileTypeof(line));
                }

                return output.getBuffer();
            };

            this.compile = function(includes) {
                var compilerData = this._compilerData;
                var output       = this._output;

                compilerData.reset();
                output.reset();
                this._mainIndex = -1;
                this._includes  = includes;

                var scriptCompiler = new wheel.compiler.script.ScriptCompiler({});
                var i              = includes.length;
                while (i) {
                    i--;
                    var filename = includes[i].filename;
                    var lines    = scriptCompiler.compile(filename, includes[i].lines);
                    this._filename = filename;

                    this._compilers.Label.compile(lines);
                    this.compileLines(lines);
                    this._compilers.Label.updateLabels();
                }

                if (this._mainIndex === -1) {
                    throw this.createError(wheel.compiler.error.NO_MAIN_PROCEDURE, 'No main procedure found.');
                }

                output.optimizeTypes();
                output.setGlobalOffset(compilerData.getGlobalOffset());
                output.setMainIndex(this._mainIndex);
                output.getLines();

                return output;
            };

            this.getIncludes = function() {
                return this._includes;
            };

            this.getOutput = function() {
                return this._output;
            };

            this.getCompilerData = function() {
                return this._compilerData;
            };

            this.getProcStartIndex = function() {
                return this._procStartIndex;
            };

            this.setProcStartIndex = function(procStartIndex) {
                this._procStartIndex = procStartIndex;
            };

            this.getActiveStruct = function() {
                return this._activeStruct;
            };

            this.setMainIndex = function(mainIndex) {
                this._mainIndex = mainIndex;
            };

            this.getInProc = function() {
                return (this._procStartIndex !== -1);
            };

            this.getCommandAndParams = function(line) {
                var command = line;
                var params  = '';
                var i       = line.indexOf(' ');

                if (i !== -1) {
                    command = line.substr(0, i),
                    params  = line.substr(i - line.length + 1).trim();
                }
                return {
                    command: command,
                    params:  params
                };
            };
        })
    );
})();<|endoftext|>


<commit_before>
var jsdom = require('jsdom').jsdom;

var exposedProperties = ['window', 'navigator', 'document'];

global.document = jsdom('');
global.window = document.defaultView;
Object.keys(document.defaultView).forEach((property) => {
  if (typeof global[property] === 'undefined') {
    exposedProperties.push(property);
    global[property] = document.defaultView[property];
  }
});

global.navigator = {
  userAgent: 'node.js'
};
<commit_msg>Link to original setup.js resource.<commit_after>// From https://github.com/airbnb/enzyme/blob/master/docs/guides/jsdom.md

var jsdom = require('jsdom').jsdom;

var exposedProperties = ['window', 'navigator', 'document'];

global.document = jsdom('');
global.window = document.defaultView;
Object.keys(document.defaultView).forEach((property) => {
  if (typeof global[property] === 'undefined') {
    exposedProperties.push(property);
    global[property] = document.defaultView[property];
  }
});

global.navigator = {
  userAgent: 'node.js'
};
<|endoftext|>


<commit_before>var expect = require('chai').expect
var assert = require('chai').assert
var sinon  = require('sinon')
var Q      = require('q')
var starx  = require('../index')

describe('starx', function() {
  var spy,
      TOKEN = {},
      ERROR = new Error()

  beforeEach(function() {
    spy = sinon.spy()
  })

  it('throws if argument is not a function', function() {
    expect(function() {
      starx()
    }).to.throw(TypeError)
  })

  it('returns an executor when invoked with a generator', function() {
    expect(starx(function*() {})).to.be.a('function')
  })

  describe('executor', function() {
    var niceGuy = function(cb) {
      cb(null, TOKEN)
    }
    var throwGuy = function(cb) {
      cb(ERROR)
    }
    var asyncGuy = function(cb) {
      process.nextTick(function() {
        cb(null, TOKEN)
      })
    }

    it('runs generator when invoked', function() {
      starx(function*() {
        spy()
      })()
      expect(spy.calledOnce).to.be.true
    })

    it('allows generator to be reused', function() {
      var g = function*() {
        spy()
      }
      starx(g)()
      starx(g)()
      expect(spy.calledTwice).to.be.true
    })

    describe('when yieldable is a function(args..., cb)', function() {
      it('invokes the yielded function automatically', function() {
        starx(function*() {
          yield spy
        })()
        expect(spy.calledOnce).to.be.true
      })

      it('sends value of previous call into the generator', function() {
        starx(function*() {
          var res = yield niceGuy
          expect(res).to.equal(TOKEN)
        })()
      })

      it('keeps sending values into the generator', function() {
        starx(function*() {
          for (var i = 0; i < 10; i++) {
            spy(yield niceGuy)
          }
        })()
        expect(spy.alwaysCalledWith(TOKEN)).to.be.true
        expect(spy.callCount).to.equal(10)
      })

      it('throws error into the generator', function() {
        starx(function*() {
          try {
            yield throwGuy
            assert(false, 'should not come here')
          } catch(e) {
            expect(e).to.be.equal(ERROR)
            var res = yield niceGuy
            expect(res).to.equal(TOKEN)
          }
        })()
      })

      it('waits until async call is completed', function(done) {
        var _done = function() {
          _catch(done, function() {
            expect(spy.alwaysCalledWith(TOKEN)).to.be.true
            expect(spy.callCount).to.equal(10)
            done()
          })
        }
        starx(function*() {
          for (var i = 0; i < 10; i++) {
            spy(yield asyncGuy)
            if (i === 9) _done()
          }
        })()
      })
    })

    describe('when yieldable is a promise', function() {
      var ff = Q.fcall(function() {
        return TOKEN
      })
      var rj = Q.fcall(function() {
        throw ERROR
      })

      it('sends fulfilled value into the generator', function(done) {
        var _done = function() {
          _catch(done, function() {
            expect(spy.alwaysCalledWith(TOKEN)).to.be.true
            expect(spy.callCount).to.equal(10)
            done()
          })
        }
        starx(function*() {
          for (var i = 0; i < 10; i++) {
            spy(yield ff)
            if (i === 9) _done()
          }
        })()
      })

      it('sends rejected error into the generator', function(done) {
        var _done = function() {
          _catch(done, function() {
            expect(spy.alwaysCalledWith(ERROR)).to.be.true
            expect(spy.callCount).to.equal(10)
            done()
          })
        }
        starx(function*() {
          for (var i = 0; i < 10; i++) {
            try {
              yield rj
            } catch (e) {
              spy(e)
              if (i === 9) done()
            }
          }
        })()
      })
    })

    describe('when yieldable is an array', function() {
      it('executes all functions in the array', function() {
        starx(function*() {
          spy(yield [niceGuy, niceGuy])
        })()
        expect(spy.withArgs([TOKEN, TOKEN]).calledOnce).to.be.true
      })

      it('supports nested arrays', function() {
        starx(function*() {
          spy(yield [niceGuy, [niceGuy, [niceGuy, niceGuy]]])
        })()
        expect(spy.withArgs([TOKEN, [TOKEN, [TOKEN, TOKEN]]]).calledOnce).to.be.true
      })

      it('supports mixing different yieldables', function() {
        starx(function*() {
          spy(yield [TOKEN, [niceGuy, 1]])
        })()
        expect(spy.withArgs([TOKEN, [TOKEN, 1]]).calledOnce).to.be.true
      })
    })

    describe('when yieldable is an executor', function() {
      it('executes the executor\'s return value as a yieldable', function() {
        var g1 = starx(function*() {
          return niceGuy
        })
        var g2 = starx(function*() {
          return [niceGuy, niceGuy]
        })
        starx(function*() {
          spy(yield [g1, g2])
        })()
        expect(spy.withArgs([TOKEN, [TOKEN, TOKEN]]).calledOnce).to.be.true
      })
    })

    describe('when yieldable is a generator', function() {
      it('dives into the generator', function() {
        var g1 = function*() {
          spy(yield niceGuy)
          spy(yield niceGuy)
        }
        var g2 = starx(function*() {
          yield g1()
        })
        g2()
        expect(spy.withArgs(TOKEN).calledTwice).to.be.true
      })
    })

    describe('when yieldable is a generator', function() {
      it('dives into the generator', function() {
        var g1 = function*() {
          spy(yield niceGuy)
          spy(yield niceGuy)
        }
        var g2 = starx(function*() {
          yield g1
        })
        g2()
        expect(spy.withArgs(TOKEN).calledTwice).to.be.true
      })
    })

    describe('when yieldable is anything thing else', function() {
      it('returns value directly', function() {
        starx(function*() {
          spy(yield TOKEN)
          spy(yield 1)
          var res = yield
          spy(res)
        })()
        expect(spy.firstCall.calledWithExactly(TOKEN)).to.be.true
        expect(spy.secondCall.calledWithExactly(1)).to.be.true
        expect(spy.thirdCall.calledWithExactly(undefined)).to.be.true
      })
    })
  })
})<commit_msg>Add test to show that result of nested generator/iterator are injected back into current generator<commit_after>var expect = require('chai').expect
var assert = require('chai').assert
var sinon  = require('sinon')
var Q      = require('q')
var starx  = require('../index')

describe('starx', function() {
  var spy,
      TOKEN = {},
      ERROR = new Error()

  beforeEach(function() {
    spy = sinon.spy()
  })

  it('throws if argument is not a function', function() {
    expect(function() {
      starx()
    }).to.throw(TypeError)
  })

  it('returns an executor when invoked with a generator', function() {
    expect(starx(function*() {})).to.be.a('function')
  })

  describe('executor', function() {
    var niceGuy = function(cb) {
      cb(null, TOKEN)
    }
    var throwGuy = function(cb) {
      cb(ERROR)
    }
    var asyncGuy = function(cb) {
      process.nextTick(function() {
        cb(null, TOKEN)
      })
    }

    it('runs generator when invoked', function() {
      starx(function*() {
        spy()
      })()
      expect(spy.calledOnce).to.be.true
    })

    it('allows generator to be reused', function() {
      var g = function*() {
        spy()
      }
      starx(g)()
      starx(g)()
      expect(spy.calledTwice).to.be.true
    })

    describe('when yieldable is a function(args..., cb)', function() {
      it('invokes the yielded function automatically', function() {
        starx(function*() {
          yield spy
        })()
        expect(spy.calledOnce).to.be.true
      })

      it('sends value of previous call into the generator', function() {
        starx(function*() {
          var res = yield niceGuy
          expect(res).to.equal(TOKEN)
        })()
      })

      it('keeps sending values into the generator', function() {
        starx(function*() {
          for (var i = 0; i < 10; i++) {
            spy(yield niceGuy)
          }
        })()
        expect(spy.alwaysCalledWith(TOKEN)).to.be.true
        expect(spy.callCount).to.equal(10)
      })

      it('throws error into the generator', function() {
        starx(function*() {
          try {
            yield throwGuy
            assert(false, 'should not come here')
          } catch(e) {
            expect(e).to.be.equal(ERROR)
            var res = yield niceGuy
            expect(res).to.equal(TOKEN)
          }
        })()
      })

      it('waits until async call is completed', function(done) {
        var _done = function() {
          _catch(done, function() {
            expect(spy.alwaysCalledWith(TOKEN)).to.be.true
            expect(spy.callCount).to.equal(10)
            done()
          })
        }
        starx(function*() {
          for (var i = 0; i < 10; i++) {
            spy(yield asyncGuy)
            if (i === 9) _done()
          }
        })()
      })
    })

    describe('when yieldable is a promise', function() {
      var ff = Q.fcall(function() {
        return TOKEN
      })
      var rj = Q.fcall(function() {
        throw ERROR
      })

      it('sends fulfilled value into the generator', function(done) {
        var _done = function() {
          _catch(done, function() {
            expect(spy.alwaysCalledWith(TOKEN)).to.be.true
            expect(spy.callCount).to.equal(10)
            done()
          })
        }
        starx(function*() {
          for (var i = 0; i < 10; i++) {
            spy(yield ff)
            if (i === 9) _done()
          }
        })()
      })

      it('sends rejected error into the generator', function(done) {
        var _done = function() {
          _catch(done, function() {
            expect(spy.alwaysCalledWith(ERROR)).to.be.true
            expect(spy.callCount).to.equal(10)
            done()
          })
        }
        starx(function*() {
          for (var i = 0; i < 10; i++) {
            try {
              yield rj
            } catch (e) {
              spy(e)
              if (i === 9) done()
            }
          }
        })()
      })
    })

    describe('when yieldable is an array', function() {
      it('executes all functions in the array', function() {
        starx(function*() {
          spy(yield [niceGuy, niceGuy])
        })()
        expect(spy.withArgs([TOKEN, TOKEN]).calledOnce).to.be.true
      })

      it('supports nested arrays', function() {
        starx(function*() {
          spy(yield [niceGuy, [niceGuy, [niceGuy, niceGuy]]])
        })()
        expect(spy.withArgs([TOKEN, [TOKEN, [TOKEN, TOKEN]]]).calledOnce).to.be.true
      })

      it('supports mixing different yieldables', function() {
        starx(function*() {
          spy(yield [TOKEN, [niceGuy, 1]])
        })()
        expect(spy.withArgs([TOKEN, [TOKEN, 1]]).calledOnce).to.be.true
      })
    })

    describe('when yieldable is an executor', function() {
      it('executes the executor\'s return value as a yieldable', function() {
        var g1 = starx(function*() {
          return niceGuy
        })
        var g2 = starx(function*() {
          return [niceGuy, niceGuy]
        })
        starx(function*() {
          spy(yield [g1, g2])
        })()
        expect(spy.withArgs([TOKEN, [TOKEN, TOKEN]]).calledOnce).to.be.true
      })
    })

    describe('when yieldable is a generator', function() {
      it('dives into the generator', function() {
        var g1 = function*() {
          spy(yield niceGuy)
          return niceGuy
        }
        var g2 = starx(function*() {
          spy(yield g1)
          spy(yield g1)
        })
        g2()
        expect(spy.withArgs(TOKEN).callCount).equal(4)
      })
    })

    describe('when yieldable is a generator', function() {
      it('dives into the generator', function() {
        var g1 = function*() {
          spy(yield niceGuy)
          return niceGuy
        }
        var g2 = starx(function*() {
          spy(yield g1)
          spy(yield g1)
        })
        g2()
        expect(spy.withArgs(TOKEN).callCount).equal(4)
      })
    })

    describe('when yieldable is anything thing else', function() {
      it('returns value directly', function() {
        starx(function*() {
          spy(yield TOKEN)
          spy(yield 1)
          var res = yield
          spy(res)
        })()
        expect(spy.firstCall.calledWithExactly(TOKEN)).to.be.true
        expect(spy.secondCall.calledWithExactly(1)).to.be.true
        expect(spy.thirdCall.calledWithExactly(undefined)).to.be.true
      })
    })
  })
})<|endoftext|>


<commit_before>"use strict";

var innerSchema = {
    id: "inner",
    type: "int8[]"
};

var schema = {
    id: "main",
    type: "inner[]"
};

var data = [
    [1,2,3,4,5,6,7,8,9],
    [2,3,4,5,6,7,8,9,1],
    [3,4,5,6,7,8,9,1,2],
    [4,5,6,7,8,9,1,2,3],
    [5,6,7,8,9,1,2,3,4],
    [6,7,8,9,1,2,3,4,5],
    [7,8,9,1,2,3,4,5,6],
    [8,9,1,2,3,4,5,6,7],
    [9,1,2,3,4,5,6,7,8],
];

module.exports = {
    schema: schema,
    data: data,
    schemaPool: [innerSchema]
}
<commit_msg>update test<commit_after>"use strict";

var innerSchema = {
    id: "inner",
    type: "int8[]"
};

var schema = {
    id: "main",
    type: "inner[]"
};

var data = [
    [1, 2, 3, 4, 5, 6, 7, 8, 9],
    [2, 3, 4, 5, 6, 7, 8, 9, 1],
    [3, 4, 5, 6, 7, 8, 9, 1, 2],
    [4, 5, 6, 7, 8, 9, 1, 2, 3],
    [5, 6, 7, 8, 9, 1, 2, 3, 4],
    [6, 7, 8, 9, 1, 2, 3, 4, 5],
    [7, 8, 9, 1, 2, 3, 4, 5, 6],
    [8, 9, 1, 2, 3, 4, 5, 6, 7],
    [9, 1, 2, 3, 4, 5, 6, 7, 8],
];

module.exports = {
    schema: schema,
    data: data,
    schemaPool: [innerSchema]
}
<|endoftext|>


<commit_before>module("Tiny Validator");

function fixture(html) {
    return $('#qunit-fixture').html('<form>' + html + '</form>').find('form');
}

function submit() {
    $('form').trigger('submit');
}

function fill() {
    $('#textInput1').val('hjoreteg@gmail.com');
    $('#textInput2').val('(909)555-5555');
    $('#textarea1').val('something');
    $('#password1').val('password');
    $('#password2').val('password');
}

test("check basic required", function () {
	var form = fixture('<input type="text" id="textInput1" />');

	form.isHappy({
	    fields: {
	        '#textInput1': {
	            required: true,
	            message: 'Please enter an email'
	        }
	    },
	    testMode: true
	});

	form.trigger('submit');
	equal($('.unhappy').length, 1);
	equal($('.unhappyMessage').length, 1);

	$('#textInput1').val('test');
	form.trigger('submit');
	equal($('.unhappy').length, 0);
	equal($('.unhappyMessage').length, 0);
});

test("check setting required with 'required' attribute", function () {
	var form = fixture('<input type="text" required id="textInput1" />');

	form.isHappy({
	    fields: {
	        '#textInput1': {
	            message: 'Please enter an email'
	        }
	    },
	    testMode: true
	});

	form.trigger('submit');
	equal($('.unhappy').length, 1);
	equal($('.unhappyMessage').length, 1);

	$('#textInput1').val('test');
	form.trigger('submit');
	equal($('.unhappy').length, 0);
	equal($('.unhappyMessage').length, 0);
});

test("check email", function () {
	var form = fixture('<input type="text" id="textInput1" />');

	form.isHappy({
	    fields: {
	        '#textInput1': {
	            required: true,
	            message: 'Please enter an email',
	            test: happy.email
	        }
	    },
	    testMode: true
	});

	form.trigger('submit');
	equal($('.unhappy').length, 1);
	equal($('.unhappyMessage').length, 1);

	$('#textInput1').val('test');
	form.trigger('submit');
	equal($('.unhappy').length, 1);
	equal($('.unhappyMessage').length, 1);

	$('#textInput1').val('hjoreteg@gmail.com');
	form.trigger('submit');
	equal($('.unhappy').length, 0);
	equal($('.unhappyMessage').length, 0);
});

test("test password match", function () {
    var form = fixture('<input type="password1" id="p1" /><input type="password2" id="p2" />');

    form.isHappy({
        fields: {
            '#p1': {
                required: true,
                message: 'Please enter a new password',
                test: function (val1, val2) {
                    return (val1 === val2);
                },
                arg: function () {
                    return $('#p2').val();
                }
            },
            '#p2': {
                required: true,
                message: 'Please enter your new password again'
            }
        },
        testMode: true
    });

    form.trigger('submit');
    equal($('.unhappy').length, 2);
    equal($('.unhappyMessage').length, 2);

    $('#p1').val('test');
    form.trigger('submit');
    equal($('.unhappy').length, 2);
    equal($('.unhappyMessage').length, 2);

    $('#p2').val('test2');
    form.trigger('submit');
    equal($('.unhappy').length, 1);
    equal($('.unhappyMessage').length, 1);

    $('#p2').val('test');
    form.trigger('submit');
    equal($('.unhappy').length, 0);
    equal($('.unhappyMessage').length, 0);
});

test("test passed in 'clean' method", function () {
	var form = fixture('<input type="text" id="textInput1" />');

	form.isHappy({
	    fields: {
	        '#textInput1': {
	            message: 'Please enter an email',
	            clean: function (val) {
	                return val.replace("a", "b");
	            }
	        }
	    },
	    testMode: true
	});

	$('#textInput1').val('  a  ');
	form.trigger('submit');
	equal($('#textInput1').val(), '  b  ');
});

test("test passing 'sometimes' to required", function () {
	var form = fixture('<input type="text" id="textInput1" />'),
	    testFlag = false;

	form.isHappy({
	    fields: {
	        '#textInput1': {
	            message: 'Please enter an email',
	            required: 'sometimes',
	            test: function (val) {
	                return testFlag;
	            }
	        }
	    },
	    testMode: true
	});

	form.trigger('submit');
	equal($('.unhappy').length, 1);
	testFlag = true;
	form.trigger('submit');
	equal($('.unhappy').length, 0);
});

test("test required fields should only be tested on submit", function () {
    var form = fixture('<input type="text" id="textInput1" />');

    form.isHappy({
        fields: {
            '#textInput1': {
                message: 'test',
                required: true
            }
        },
        testMode: true
    });

    $('#textInput1').trigger('blur');
    equal($('.unhappy').length, 0);
    form.trigger('submit');
    equal($('.unhappy').length, 1);
});

test("test non-required fields still tested on blur", function () {
    var form = fixture('<input type="text" id="textInput1" />');

    form.isHappy({
        fields: {
            '#textInput1': {
                message: 'test',
                test: happy.email
            }
        },
        testMode: true
    });

    $('#textInput1').val('h@h').trigger('blur');
    equal($('.unhappy').length, 1);
    form.trigger('submit');
    equal($('.unhappy').length, 1);
});

test("test unHappy callback", function () {
    var form = fixture('<input type="text" id="textInput1" required />'),
        myFlag = false;

    form.isHappy({
        fields: {
            '#textInput1': {
                message: "not happy dude"
            }
        },
        testMode: true,
        unHappy: function () {
            myFlag = true;
        }
    });

    form.trigger('submit');
    ok(myFlag);
    myFlag = false;
    $('#textInput1').val('test');
    form.trigger('submit');
    equals(myFlag, false);
});

test("test included email validator", function () {
    var happyEmails = [
            'henrik@andyet.net',
            'h.joreteg@gmail.com',
            '23423.24.2.2342@test.test',
            '2.3.2.4.a.a.a.ffasaf.a@aol.com'
        ],
        sadEmails = [
            '.henrik@andyet.net',
            'henrik.@andyet.net',
            'test@test.afcom.com.',
            'h@.h',
            'a@a'
        ],
        i;

    for (i = 0; i < happyEmails.length; i++) {
        ok(happy.email(happyEmails[i]));
    }

    for (i = 0; i < sadEmails.length; i++) {
        ok(!happy.email(sadEmails[i]));
    }
});

test("test included date validator", function () {
    var happyDates = [
            '12/29/1982',
            '11/02/2099'
        ],
        sadDates = [
            '123/24/1999',
            '13/31/2099',
            '12/32/2099',
            '1/31/2999'
        ],
        i;

    for (i = 0; i < happyDates.length; i++) {
        ok(happy.date(happyDates[i]));
    }

    for (i = 0; i < sadDates.length; i++) {
        ok(!happy.date(sadDates[i]));
    }
});

test("test included phone validator", function () {
    var happyPhones = [
            '909-765-3941',
            '(909) 234-2343',
            '9999999999',
            '(909)234-2343',
        ],
        sadPhones = [
            '12-123-22311',
            'asdfasdf',
            '123-123-12344'
        ],
        i;

    for (i = 0; i < happyPhones.length; i++) {
        ok(happy.USPhone(happyPhones[i]));
    }

    for (i = 0; i < sadPhones.length; i++) {
        ok(!happy.USPhone(sadPhones[i]));
    }
});<commit_msg>add test<commit_after>module("Tiny Validator");

function fixture(html) {
    return $('#qunit-fixture').html('<form>' + html + '</form>').find('form');
}

function submit() {
    $('form').trigger('submit');
}

function fill() {
    $('#textInput1').val('hjoreteg@gmail.com');
    $('#textInput2').val('(909)555-5555');
    $('#textarea1').val('something');
    $('#password1').val('password');
    $('#password2').val('password');
}

test("check basic required", function () {
	var form = fixture('<input type="text" id="textInput1" />');

	form.isHappy({
	    fields: {
	        '#textInput1': {
	            required: true,
	            message: 'Please enter an email'
	        }
	    },
	    testMode: true
	});

	form.trigger('submit');
	equal($('.unhappy').length, 1);
	equal($('.unhappyMessage').length, 1);

	$('#textInput1').val('test');
	form.trigger('submit');
	equal($('.unhappy').length, 0);
	equal($('.unhappyMessage').length, 0);
});

test("check setting required with 'required' attribute", function () {
	var form = fixture('<input type="text" required id="textInput1" />');

	form.isHappy({
	    fields: {
	        '#textInput1': {
	            message: 'Please enter an email'
	        }
	    },
	    testMode: true
	});

	form.trigger('submit');
	equal($('.unhappy').length, 1);
	equal($('.unhappyMessage').length, 1);

	$('#textInput1').val('test');
	form.trigger('submit');
	equal($('.unhappy').length, 0);
	equal($('.unhappyMessage').length, 0);
});

test("check email", function () {
	var form = fixture('<input type="text" id="textInput1" />');

	form.isHappy({
	    fields: {
	        '#textInput1': {
	            required: true,
	            message: 'Please enter an email',
	            test: happy.email
	        }
	    },
	    testMode: true
	});

	form.trigger('submit');
	equal($('.unhappy').length, 1);
	equal($('.unhappyMessage').length, 1);

	$('#textInput1').val('test');
	form.trigger('submit');
	equal($('.unhappy').length, 1);
	equal($('.unhappyMessage').length, 1);

	$('#textInput1').val('hjoreteg@gmail.com');
	form.trigger('submit');
	equal($('.unhappy').length, 0);
	equal($('.unhappyMessage').length, 0);
});

test("test password match", function () {
    var form = fixture('<input type="password1" id="p1" /><input type="password2" id="p2" />');

    form.isHappy({
        fields: {
            '#p1': {
                required: true,
                message: 'Please enter a new password',
                test: function (val1, val2) {
                    return (val1 === val2);
                },
                arg: function () {
                    return $('#p2').val();
                }
            },
            '#p2': {
                required: true,
                message: 'Please enter your new password again'
            }
        },
        testMode: true
    });

    form.trigger('submit');
    equal($('.unhappy').length, 2);
    equal($('.unhappyMessage').length, 2);

    $('#p1').val('test');
    form.trigger('submit');
    equal($('.unhappy').length, 2);
    equal($('.unhappyMessage').length, 2);

    $('#p2').val('test2');
    form.trigger('submit');
    equal($('.unhappy').length, 1);
    equal($('.unhappyMessage').length, 1);

    $('#p2').val('test');
    form.trigger('submit');
    equal($('.unhappy').length, 0);
    equal($('.unhappyMessage').length, 0);
});

test("test passed in 'clean' method", function () {
	var form = fixture('<input type="text" id="textInput1" />');

	form.isHappy({
	    fields: {
	        '#textInput1': {
	            message: 'Please enter an email',
	            clean: function (val) {
	                return val.replace("a", "b");
	            }
	        }
	    },
	    testMode: true
	});

	$('#textInput1').val('  a  ');
	form.trigger('submit');
	equal($('#textInput1').val(), '  b  ');
});

test("test passing 'sometimes' to required", function () {
	var form = fixture('<input type="text" id="textInput1" />'),
	    testFlag = false;

	form.isHappy({
	    fields: {
	        '#textInput1': {
	            message: 'Please enter an email',
	            required: 'sometimes',
	            test: function (val) {
	                return testFlag;
	            }
	        }
	    },
	    testMode: true
	});

	form.trigger('submit');
	equal($('.unhappy').length, 1);
	testFlag = true;
	form.trigger('submit');
	equal($('.unhappy').length, 0);
});

test("test required fields should only be tested on submit", function () {
    var form = fixture('<input type="text" id="textInput1" />');

    form.isHappy({
        fields: {
            '#textInput1': {
                message: 'test',
                required: true
            }
        },
        testMode: true
    });

    $('#textInput1').trigger('blur');
    equal($('.unhappy').length, 0);
    form.trigger('submit');
    equal($('.unhappy').length, 1);
});

test("test non-required fields still tested on blur", function () {
    var form = fixture('<input type="text" id="textInput1" />');

    form.isHappy({
        fields: {
            '#textInput1': {
                message: 'test',
                test: happy.email
            }
        },
        testMode: true
    });

    $('#textInput1').val('h@h').trigger('blur');
    equal($('.unhappy').length, 1);
    form.trigger('submit');
    equal($('.unhappy').length, 1);
});

test("test unHappy callback", function () {
    var form = fixture('<input type="text" id="textInput1" required />'),
        myFlag = false;

    form.isHappy({
        fields: {
            '#textInput1': {
                message: "not happy dude"
            }
        },
        testMode: true,
        unHappy: function () {
            myFlag = true;
        }
    });

    form.trigger('submit');
    ok(myFlag);
    myFlag = false;
    $('#textInput1').val('test');
    form.trigger('submit');
    equals(myFlag, false);
});

test("test included email validator", function () {
    var happyEmails = [
            'henrik@andyet.net',
            'h.joreteg@gmail.com',
            '23423.24.2.2342@test.test',
            '2.3.2.4.a.a.a.ffasaf.a@aol.com'
        ],
        sadEmails = [
            '.henrik@andyet.net',
            'henrik.@andyet.net',
            'test@test.afcom.com.',
            'h@.h',
            'a@a'
        ],
        i;

    for (i = 0; i < happyEmails.length; i++) {
        ok(happy.email(happyEmails[i]));
    }

    for (i = 0; i < sadEmails.length; i++) {
        ok(!happy.email(sadEmails[i]));
    }
});

test("test included date validator", function () {
    var happyDates = [
            '12/29/1982',
            '11/02/2099'
        ],
        sadDates = [
            '123/24/1999',
            '13/31/2099',
            '12/32/2099',
            '1/31/2999'
        ],
        i;

    for (i = 0; i < happyDates.length; i++) {
        ok(happy.date(happyDates[i]));
    }

    for (i = 0; i < sadDates.length; i++) {
        ok(!happy.date(sadDates[i]));
    }
});

test("test included phone validator", function () {
    var happyPhones = [
            '909-765-3941',
            '(909) 234-2343',
            '9999999999',
            '(909)234-2343',
        ],
        sadPhones = [
            '12-123-22311',
            'asdfasdf',
            '123-123-12344'
        ],
        i;

    for (i = 0; i < happyPhones.length; i++) {
        ok(happy.USPhone(happyPhones[i]));
    }

    for (i = 0; i < sadPhones.length; i++) {
        ok(!happy.USPhone(sadPhones[i]));
    }
});

test("test message is empty string when not explicitly set", function() {
  var form = fixture('<input type="text" id="textInput1" />');

  form.isHappy({
      fields: {
          '#textInput1': {
              required: true,
          }
      },
      testMode: true
  });

  form.trigger('submit');
  equal($('.unhappyMessage').first().text(), '');
});
<|endoftext|>


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

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

function getModifiedPaths() {
  assert.ok(process.env.TRAVIS_COMMIT_RANGE, 'VALIDATE_MODIFIED_ONLY requires TRAVIS_COMMIT_RANGE to be set to [START_COMMIT_HASH]...[END_COMMIT_HASH]');
  var stdout = execSync('git diff --name-only ' + process.env.TRAVIS_COMMIT_RANGE, {
    encoding: 'utf8'
  });
  var lines = stdout.split('\n');
  var result = {};

  for (var i = 0; i < lines.length; i += 1) {
    result[lines[i]] = lines[i];
  }

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

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

  return object;
}

// Vaidates that the expected file paths exist
function ensureExists(templatePath) {
  assert(fs.existsSync(templatePath), 'The file ' + templatePath + ' is missing.');
}

function validateMetadata(metadataPath) {
  var metadataData = fs.readFileSync(metadataPath, {
    encoding: 'utf-8'
  });
  metadataData = metadataData.trim();

  var metadata = tryParse(metadataPath, metadataData);

  var result = skeemas.validate(metadata, {
    properties: {
      itemDisplayName: {
        type: 'string',
        required: true,
        minLength: 10,
        maxLength: 60
      },
      description: {
        type: 'string',
        required: true,
        minLength: 10,
        maxLength: 1000
      },
      summary: {
        type: 'string',
        required: true,
        minLength: 10,
        maxLength: 200
      },
      githubUsername: {
        type: 'string',
        required: true,
        minLength: 2
      },
      dateUpdated: {
        type: 'string',
        required: true,
        minLength: 10
      },
      icon: {
        type: 'string'
      }
    },
    additionalProperties: false
  });
  var messages = '';
  result.errors.forEach(function (error) {
    messages += (metadataPath + ' - ' + error.context + ':' + error.message + '\n');
  });
  assert(result.valid, messages);

  // validate description has no html
  assert(!/<[a-z][\s\S]*>/i.test(metadata.description), metadataPath + ' - Contains possible HTML elements which are not allowed');
  // validate date
  var date = new Date(metadata.dateUpdated);
  var currentTime = new Date(Date.now());
  assert(!isNaN(date.getTime()), metadataPath + ' - dateUpdated field should be a valid date in the format YYYY-MM-DD');
  // validate date is not in future
  assert(date < currentTime, metadataPath + ' - dateUpdated field should not be in the future');
}

// azure cli apparently does not check for this
function validateTemplateParameters(templatePath, templateObject) {
  assert.ok(templateObject.parameters, 'Expected a \'.parameters\' field within the deployment template');
  for (var k in templateObject.parameters) {
    if (typeof k === 'string') {
      assert.ok(templateObject.parameters[k].metadata,
        templatePath + ' -  Parameter \"' + k + '\" is missing its \"metadata\" property');
      assert.ok(templateObject.parameters[k].metadata.description,
        templatePath + ' - Parameter \"' + k + '\" is missing its \"description\" field within the metadata property');
    }
  }
}

function validateParamtersFile(parametersPath) {
  var parametersData = fs.readFileSync(parametersPath, {
    encoding: 'utf-8'
  });
  var metadataData = parametersData.trim();

  var parametersObject = tryParse(parametersPath, metadataData);

  assert.ok(parametersObject.parameters, parametersPath + ' - Expected a \'.parameters\' field within the parameters file');
  for (var k in parametersObject.parameters) {
    if (typeof k === 'string') {
      assert.ok(parametersObject.parameters[k].value !== null &&
        parametersObject.parameters[k].value !== undefined &&
        parametersObject.parameters[k].value !== '',
        parametersPath + ' -  Parameter \"' + k + '\" is missing its value field');
    }
  }
}

function prepTemplate(templatePath, parametersPath) {
  var templateData = fs.readFileSync(templatePath, {
      encoding: 'utf-8'
    }),
    parameterData = fs.readFileSync(parametersPath, {
      encoding: 'utf-8'
    });

  templateData = templateData.trim();
  parameterData = parameterData.trim();

  var requestBody = {
    template: tryParse(templatePath, templateData),
    parameters: tryParse(templatePath, parameterData)
  };

  return requestBody;
}

// Calls a remote url which will validate the template and parameters
function validateTemplate(templatePath, parametersPath) {
  var requestBody = prepTemplate(templatePath, parametersPath);

  if (process.env.TRAVIS_PULL_REQUEST &&
    process.env.TRAVIS_PULL_REQUEST !== 'false') {
    requestBody.pull_request = process.env.TRAVIS_PULL_REQUEST;
  }

  // validate the template paramters, particularly the description field
  validateTemplateParameters(templatePath, requestBody.template);

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

        return resolve(response.body);
      });
  });
}

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

// Calls a remote url which will deploy the template
function deployTemplate(templatePath, parametersPath) {
  var requestBody = prepTemplate(templatePath, parametersPath);

  if (process.env.TRAVIS_PULL_REQUEST &&
    process.env.TRAVIS_PULL_REQUEST !== 'false') {
    requestBody.pull_request = process.env.TRAVIS_PULL_REQUEST;
  }

  // validate the template paramters, particularly the description field
  validateTemplateParameters(templatePath, requestBody.template);

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

  return new RSVP.Promise(function (resolve, reject) {
    unirest.post(process.env.VALIDATION_HOST + '/deploy')
      .type('json')
      .timeout(3600 * 1000) // template deploy can take some time
      .send(JSON.stringify(requestBody))
      .end(function (response) {
        timedOutput(false, intervalObj);
        debug(response.status);
        debug(response.body);

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

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

function getDirectories(srcpath) {
  return fs.readdirSync(srcpath).filter(function (file) {
    return fs.statSync(path.join(srcpath, file)).isDirectory();
  });
}

// Generates the mocha tests based on directories in
// the existing repo.
function generateTests(modifiedPaths) {
  var tests = [];
  var directories = getDirectories('./');
  debug(modifiedPaths);
  var modifiedDirs = {};

  for (var k in modifiedPaths) {
    if (typeof k === 'string') {
      // don't include the top level dir
      if (path.dirname(k) === '.') {
        continue;
      }
      modifiedDirs[path.dirname(k)] = true;
    }
  }
  debug('modified dirs:');
  debug(modifiedDirs);
  directories.forEach(function (dirName) {
    // exceptions
    if (dirName === '.git' ||
      dirName === 'node_modules') {
      return;
    }

    if (fs.existsSync(path.join(dirName, '.ci_skip'))) {
      return;
    }
    var templatePath = path.join(dirName, 'azuredeploy.json'),
      paramsPath = path.join(dirName, 'azuredeploy.parameters.json'),
      metadataPath = path.join(dirName, 'metadata.json'),
      readmePath = path.join(dirName, 'README.md');

    // if we are only validating modified templates
    // only add test if this directory template has been modified
    if (modifiedPaths && !modifiedDirs[dirName]) {
      return;
    }

    tests.push({
      args: [templatePath, paramsPath, metadataPath, readmePath],
      expected: true
    });
  });

  debug('created tests:');
  debug(tests);

  return tests;
}

// Group tests in chunks defined by an environment variable
// or by the default value
function groupTests(modifiedPaths) {
  // we probably shouldn't deploy a ton of templates at once...
  var tests = generateTests(modifiedPaths),
    testGroups = [],
    groupIndex = 0,
    counter = 0,
    groupSize = process.env.PARALLEL_DEPLOYMENT_NUMBER || 2;

  tests.forEach(function (test) {
    if (!testGroups[groupIndex]) {
      testGroups[groupIndex] = [];
    }

    testGroups[groupIndex].push(test);
    counter += 1;

    if (counter % groupSize === 0) {
      groupIndex += 1;
    }
  });

  return testGroups;
}

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

  var modifiedPaths;

  if (process.env.VALIDATE_MODIFIED_ONLY) {
    var count = 0;
    // we automatically reset to the beginning of the commit range
    // so this includes all file paths that have changed for the CI run
    modifiedPaths = getModifiedPaths();
    debug(modifiedPaths);
    for (var i in modifiedPaths) {
      if (typeof i === 'string') {
        count += 1;
      }
    }

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

  var testGroups = groupTests(modifiedPaths);

  testGroups.forEach(function (tests) {
    parallel('Running ' + tests.length + ' Parallel Template Validation(s)...', function () {
      tests.forEach(function (test) {
        it(test.args[0] + ' & ' + test.args[1] + ' should be valid', function () {
          // validate template files are in correct place
          test.args.forEach(function (path) {
            ensureExists.apply(null, [path]);
          });

          validateMetadata.apply(null, [test.args[2]]);
          validateParamtersFile.apply(null, [test.args[1]]);

          return validateTemplate.apply(null, test.args)
            .then(function () {
              debug('template validation sucessful, deploying template...');
              return deployTemplate.apply(null, test.args);
            })
            .then(function () {
              // success
              return assert(true);
            })
            .catch(function (err) {
              var errorString = 'Template Validiation Failed. Try deploying your template with the commands:\n';
              errorString += 'azure group template validate --resource-group (your_group_name) ';
              errorString += ' --template-file ' + test.args[0] + ' --parameters-file ' + test.args[1] + '\n';
              errorString += 'azure group deployment create --resource-group (your_group_name) ';
              errorString += ' --template-file ' + test.args[0] + ' --parameters-file ' + test.args[1];
              assert(false, errorString + ' \n\nServer Error:' + JSON.stringify(err, null, 4));
            });
        });
      });
    });
  });
});
<commit_msg>Refactor tests.js<commit_after>/*global describe, it*/
var assert = require('assert');
var colors = require('mocha/lib/reporters/base').colors;
var debug = require('debug')('validator');
var childProcess = require('child_process');
var fs = require('fs');
var parallel = require('mocha.parallel');
var path = require('path');
var RSVP = require('rsvp');
var skeemas = require('skeemas');
var unirest = require('unirest');

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

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

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

  return object;
}

function readJSONFile(filePath) {
  var fileContents = fs.readFileSync(filePath, {
    encoding: 'utf-8'
  }).trim();
  return tryParse(filePath, fileContents);
}

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

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

function validateMetadata(metadataFilePath) {
  var metadataObject = readJSONFile(metadataFilePath);
  var metadataSchemaValidationResult = skeemas.validate(metadataObject, {
    properties: {
      itemDisplayName: {
        type: 'string',
        required: true,
        minLength: 10,
        maxLength: 60
      },
      description: {
        type: 'string',
        required: true,
        minLength: 10,
        maxLength: 1000
      },
      summary: {
        type: 'string',
        required: true,
        minLength: 10,
        maxLength: 200
      },
      githubUsername: {
        type: 'string',
        required: true,
        minLength: 2
      },
      dateUpdated: {
        type: 'string',
        required: true,
        minLength: 10
      },
      icon: {
        type: 'string',
        enum: [
          'api',
          'blankTemplate',
          'cdnStorage',
          'cdnWebsite',
          'docker',
          'documentDB',
          'logic',
          'serviceFabric',
          'ubuntu',
          'vmss',
          'windowsVM'
        ]
      }
    },
    additionalProperties: false
  });

  var metadataSchemaValidationErrorMessages = '';
  metadataSchemaValidationResult.errors.forEach(function (error) {
    metadataSchemaValidationErrorMessages += (metadataFilePath + ' - ' + error.context + ':' + error.message + '\n');
  });
  assert(metadataSchemaValidationResult.valid, metadataSchemaValidationErrorMessages);

  // validate description has no html
  assert(!(/<[a-z][\s\S]*>/i).test(metadataObject.description), metadataFilePath + ' - Contains possible HTML elements which are not allowed');
  // validate date
  var date = new Date(metadataObject.dateUpdated);
  var currentTime = new Date(Date.now());
  assert(!isNaN(date.getTime()), metadataFilePath + ' - dateUpdated field should be a valid date in the format YYYY-MM-DD');
  // validate date is not in future
  assert(date < currentTime, metadataFilePath + ' - dateUpdated field should not be in the future');
}

function validateParameters(parametersFilePath, parametersObject) {
  assert(isDefined(parametersObject.$schema), parametersFilePath + ' - Expected a \'.$schema\' field within the parameters file');

  assert(parametersObject.parameters, parametersFilePath + ' - Expected a \'.parameters\' field within the parameters file');
  for (var parameterName in parametersObject.parameters) {
    if (typeof parameterName === 'string') {
      var parameterObject = parametersObject.parameters[parameterName];
      assert(isDefined(parameterObject.value) || isDefined(parameterObject.reference),
        parametersFilePath + ' - Parameter \"' + parameterName + '\" should have a \"value\" or \"reference\" property.');
    }
  }
}

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

    var templateObject = requestBody.template;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            [templateFilePath, parametersFilePath, metadataFilePath, readmeFilePath].forEach(function (filePath) {
              // Vaidates that the expected file paths exist
              assert(fs.existsSync(filePath), 'The file ' + filePath + ' is missing.');
            });

            validateMetadata(metadataFilePath);

            var parametersObject = readJSONFile(parametersFilePath);
            validateParameters(parametersFilePath, parametersObject);

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

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


<commit_before>(function(expect) {
  'use strict';

  describe('numberFormat', function() {
    describe('formatMoney', function() {
      it('should return a string', function() {
        expect(numberFormat.formatMoney(1)).to.be.a('string');
      });

      it('should default to 2 decimal places', function() {
        expect(numberFormat.formatMoney(1.123).substr(3)).to.have.length(2);
      });

      it('should round result if 0 passed for decimal_places', function() {
        var rounded_up = numberFormat.formatMoney(1.5, 0);
        var rounded_down = numberFormat.formatMoney(1.49, 0);

        expect(rounded_up).to.equal('$2');
        expect(rounded_down).to.equal('$1');
      });

      it('should default to "$" currency symbol', function() {
        expect(numberFormat.formatMoney(1)[0]).to.equal('$');
      });

      it('should default to "," thousands separator', function() {
        expect(numberFormat.formatMoney(1000)[2]).to.equal(',');
      });

      it('should default to "." decimal separator', function() {
        expect(numberFormat.formatMoney(1)[2]).to.equal('.');
      });

      it('should group numbers by thousands', function() {
        var formatted = numberFormat.formatMoney(1000000000);

        expect(formatted[2]).to.equal(',');
        expect(formatted[6]).to.equal(',');
        expect(formatted[10]).to.equal(',');
      });

      it('should proccess alternate currency formats', function() {
        var costa_rico = numberFormat.formatMoney(1000000, 2, '₡', '.', ',');
        var ukraine = numberFormat.formatMoney(1000000, 2, '₴', ' ', ',');
        var switzerland = numberFormat.formatMoney(1000000, 2, 'Fr. ', "'", '.');

        expect(costa_rico).to.equal('₡1.000.000,00');
        expect(ukraine).to.equal('₴1 000 000,00');
        expect(switzerland).to.equal("Fr. 1'000'000.00");
      });
    });

    describe('unformatMoney', function() {
      it('should return a number', function() {
        expect(numberFormat.unformatMoney('1')).to.be.a('number');
      });

      it('should return the numeric representation of a string', function() {
        expect(numberFormat.unformatMoney('1')).to.equal(1);
        expect(numberFormat.unformatMoney('100 goats')).to.equal(100);
        expect(numberFormat.unformatMoney('1,000,000')).to.equal(1000000);
        expect(numberFormat.unformatMoney('-1,000.985')).to.equal(-1000.985);
        expect(numberFormat.unformatMoney('$1,000,000.00')).to.equal(1000000);
        expect(numberFormat.unformatMoney('-$2,000.15: OVERDRAWN')).to.equal(-2000.15);
      });

      it('should only use leading minus or hyphen-minus to determine negativity', function() {
        expect(numberFormat.unformatMoney('−1'), 'leading minus')
          .to.equal(-1);
        expect(numberFormat.unformatMoney('  −1'), 'leading minus + spaces')
          .to.equal(-1);
        expect(numberFormat.unformatMoney('1−'), 'trailing minus')
          .to.equal(1);
        expect(numberFormat.unformatMoney('10−1'), 'inner minus')
          .to.equal(101);
        expect(numberFormat.unformatMoney('-1'), 'leading hyphen-minus')
          .to.equal(-1);
        expect(numberFormat.unformatMoney('  -1'), 'leading hyphen-minus + spaces')
          .to.equal(-1);
        expect(numberFormat.unformatMoney('1-'), 'trailing hyphen-minus')
          .to.equal(1);
        expect(numberFormat.unformatMoney('10-1'), 'inner hyphen-minus')
          .to.equal(101);
      });

      it('should remove non-numeric characters except decimal, while respecting leading minus as negative indicator', function() {
        var unformat = numberFormat.unformatMoney;

        expect(unformat('1!2@3#4$5%6a7`89₴01'), 'string includes non-numbers')
          .to.equal(12345678901);
        expect(unformat('1!2@3#4$5%6a7`.89₴01'), 'non-numbers and a decimal')
          .to.equal(1234567.8901);
        expect(unformat('-1!2@3#4$5%6a7`89₴01'), 'non-numbers and a leading minus')
          .to.equal(-12345678901);
        expect(unformat('-1!2@3#4$5%6a7`.89₴01'), 'non-numbers, decimal, and leading minus')
          .to.equal(-1234567.8901);
        expect(unformat('1!2@3#4$5%6a7`8-9₴01'), 'non-numbers plus internal minus')
          .to.equal(12345678901);
        expect(unformat('1!2@3#4$5%6a7`.8-9₴01'), 'non-numbers, decimal, and internal minus')
          .to.equal(1234567.8901);
        expect(unformat('-1!2@3#4$5%6a7`8-9₴01'), 'non-numbers, leading minus, and internal minus')
          .to.equal(-12345678901);
        expect(unformat('-1!2@3#4$5%6a7`.8-9₴01'), 'non-numbers, decimal, leading minus, and internal minus')
          .to.equal(-1234567.8901);
      });

      it('should remove any passed currency_symbol option before processing', function() {
        expect(numberFormat.unformatMoney("Fr. 1'000'000.00", {
          currency_symbol: 'Fr. '
        })).to.equal(1000000);
      });

      it('should respect alternate thousands_separator option when passed', function() {
        expect(numberFormat.unformatMoney('₡1.000.000', {
          thousands_separator: '.'
        })).to.equal(1000000);
      });

      it('should respect alternate decimal_separator option when passed', function() {
        expect(numberFormat.unformatMoney('₴1 000 000,99', {
          decimal_separator: ','
        })).to.equal(1000000.99);
      });
    });
  });
})(chai.expect);<commit_msg>Passing undefined for decimal places arg of formatMoney in alt currency format test, to trigger default.<commit_after>(function(expect) {
  'use strict';

  describe('numberFormat', function() {
    describe('formatMoney', function() {
      it('should return a string', function() {
        expect(numberFormat.formatMoney(1)).to.be.a('string');
      });

      it('should default to 2 decimal places', function() {
        expect(numberFormat.formatMoney(1.123).substr(3)).to.have.length(2);
      });

      it('should round result if 0 passed for decimal_places', function() {
        var rounded_up = numberFormat.formatMoney(1.5, 0);
        var rounded_down = numberFormat.formatMoney(1.49, 0);

        expect(rounded_up).to.equal('$2');
        expect(rounded_down).to.equal('$1');
      });

      it('should default to "$" currency symbol', function() {
        expect(numberFormat.formatMoney(1)[0]).to.equal('$');
      });

      it('should default to "," thousands separator', function() {
        expect(numberFormat.formatMoney(1000)[2]).to.equal(',');
      });

      it('should default to "." decimal separator', function() {
        expect(numberFormat.formatMoney(1)[2]).to.equal('.');
      });

      it('should group numbers by thousands', function() {
        var formatted = numberFormat.formatMoney(1000000000);

        expect(formatted[2]).to.equal(',');
        expect(formatted[6]).to.equal(',');
        expect(formatted[10]).to.equal(',');
      });

      it('should proccess alternate currency formats', function() {
        var costa_rico = numberFormat.formatMoney(1000000, undefined, '₡', '.', ',');
        var ukraine = numberFormat.formatMoney(1000000, undefined, '₴', ' ', ',');
        var switzerland = numberFormat.formatMoney(1000000, undefined, 'Fr. ', "'", '.');

        expect(costa_rico).to.equal('₡1.000.000,00');
        expect(ukraine).to.equal('₴1 000 000,00');
        expect(switzerland).to.equal("Fr. 1'000'000.00");
      });
    });

    describe('unformatMoney', function() {
      it('should return a number', function() {
        expect(numberFormat.unformatMoney('1')).to.be.a('number');
      });

      it('should return the numeric representation of a string', function() {
        expect(numberFormat.unformatMoney('1')).to.equal(1);
        expect(numberFormat.unformatMoney('100 goats')).to.equal(100);
        expect(numberFormat.unformatMoney('1,000,000')).to.equal(1000000);
        expect(numberFormat.unformatMoney('-1,000.985')).to.equal(-1000.985);
        expect(numberFormat.unformatMoney('$1,000,000.00')).to.equal(1000000);
        expect(numberFormat.unformatMoney('-$2,000.15: OVERDRAWN')).to.equal(-2000.15);
      });

      it('should only use leading minus or hyphen-minus to determine negativity', function() {
        expect(numberFormat.unformatMoney('−1'), 'leading minus')
          .to.equal(-1);
        expect(numberFormat.unformatMoney('  −1'), 'leading minus + spaces')
          .to.equal(-1);
        expect(numberFormat.unformatMoney('1−'), 'trailing minus')
          .to.equal(1);
        expect(numberFormat.unformatMoney('10−1'), 'inner minus')
          .to.equal(101);
        expect(numberFormat.unformatMoney('-1'), 'leading hyphen-minus')
          .to.equal(-1);
        expect(numberFormat.unformatMoney('  -1'), 'leading hyphen-minus + spaces')
          .to.equal(-1);
        expect(numberFormat.unformatMoney('1-'), 'trailing hyphen-minus')
          .to.equal(1);
        expect(numberFormat.unformatMoney('10-1'), 'inner hyphen-minus')
          .to.equal(101);
      });

      it('should remove non-numeric characters except decimal, while respecting leading minus as negative indicator', function() {
        var unformat = numberFormat.unformatMoney;

        expect(unformat('1!2@3#4$5%6a7`89₴01'), 'string includes non-numbers')
          .to.equal(12345678901);
        expect(unformat('1!2@3#4$5%6a7`.89₴01'), 'non-numbers and a decimal')
          .to.equal(1234567.8901);
        expect(unformat('-1!2@3#4$5%6a7`89₴01'), 'non-numbers and a leading minus')
          .to.equal(-12345678901);
        expect(unformat('-1!2@3#4$5%6a7`.89₴01'), 'non-numbers, decimal, and leading minus')
          .to.equal(-1234567.8901);
        expect(unformat('1!2@3#4$5%6a7`8-9₴01'), 'non-numbers plus internal minus')
          .to.equal(12345678901);
        expect(unformat('1!2@3#4$5%6a7`.8-9₴01'), 'non-numbers, decimal, and internal minus')
          .to.equal(1234567.8901);
        expect(unformat('-1!2@3#4$5%6a7`8-9₴01'), 'non-numbers, leading minus, and internal minus')
          .to.equal(-12345678901);
        expect(unformat('-1!2@3#4$5%6a7`.8-9₴01'), 'non-numbers, decimal, leading minus, and internal minus')
          .to.equal(-1234567.8901);
      });

      it('should remove any passed currency_symbol option before processing', function() {
        expect(numberFormat.unformatMoney("Fr. 1'000'000.00", {
          currency_symbol: 'Fr. '
        })).to.equal(1000000);
      });

      it('should respect alternate thousands_separator option when passed', function() {
        expect(numberFormat.unformatMoney('₡1.000.000', {
          thousands_separator: '.'
        })).to.equal(1000000);
      });

      it('should respect alternate decimal_separator option when passed', function() {
        expect(numberFormat.unformatMoney('₴1 000 000,99', {
          decimal_separator: ','
        })).to.equal(1000000.99);
      });
    });
  });
})(chai.expect);<|endoftext|>