<commit_before>!function () {
    'use strict';
    var Class = require('ee-class')
        , ORM = require('related')
        , EventEmitter = require('ee-event-emitter')
        , fs = require('fs')
        , path = require('path')
        , semver = require('semver')
        , Promise = require('promise')
        , sqlFiles = []
        , schemaDirs = []
        , filesLength
        , sqlStatments
        , ormObject
        , error;

    module.exports = new Class({
        inherits: EventEmitter
        , config: {}
        , init: function (options) {
            this.config = options;
        }

        /**
         *@param {String} file
         */
        , _getSchemaDirectories: function _getSchemaDirectories(file) {
            return new Promise(function (resolve, reject) {
                fs.stat(file, function (err, stats) {
                    if (err) {
                        reject(err);
                    } else {
                        if (stats && stats.isDirectory() && path.basename(file)[0] !== '.') {
                            if (semver.valid(file)) {
                                schemaDirs.push(file);
                            }
                        }
                        if (!--filesLength) {
                            resolve(schemaDirs);
                        }
                    }
                });
            });
        }

        /**
         *@param {String} file
         */
        , _getSqlFiles: function _getSqlFiles(file) {
            return new Promise(function (resolve, reject) {
                fs.stat(file, function (err, stats) {
                    if (err) {
                        reject(err);
                    } else {
                        if (stats && !stats.isDirectory() && path.extname(file) === '.sql') {
                            sqlFiles.push(file);
                        }
                        if (!--filesLength) {
                            resolve(sqlFiles);
                        }
                    }
                });
            });
        }

        /**
         * Return all schema version directories
         * @param {String} migrationPath
         * @param {Function} callback
         */
        , _readSchemaDir: function _readSchemaDir(migrationPath, callback) {
            var _this = this;
            fs.readdir(migrationPath, function (err, files) {
                if (err) {
                    callback(err);
                } else {
                    filesLength = files.length;
                    if (!filesLength) {
                        callback(null, schemaDirs);
                    } else {
                        Promise.all(files.map(_this._getSchemaDirectories).map(function (file) {
                            return path.resolve(migrationPath, file);
                        })).done(function (response) {
                            callback(null, response);
                        }, function (err) {
                            callback(err);
                        });
                    }
                }
            });
        }

        /**
         * Return all sql files
         * @param {String} versionPath
         * @param {Function} callback
         */
        , _readSqlFiles: function _readSqlFiles(versionPath, callback) {
            var _this = this;
            fs.readdir(versionPath, function (err, files) {
                if (err) {
                    callback(err);
                } else {
                    filesLength = files.length;
                    if (!filesLength) {
                        callback(null, sqlFiles);
                    } else {
                        Promise.all(files.map(_this._getSqlFiles).map(function (file) {
                            return file = path.resolve(versionPath, file);
                        })).done(function (response) {
                            callback(null, response);
                        }, function (err) {
                            callback(err);
                        });
                        ;
                    }
                }
            });
        }

        /**
         * Migrate all sql files of schema version
         * @param {Function} callback
         */
        , migrate: function migration(callback) {
            var options = this.config
                , _this = this
                , ormDatabase;
            ormObject = new ORM(options.user
                , options.password
                , options.host
                , options.schema
                , options.database
                , options.type);

            ormObject.load(function (err) {
                if (err) {
                    callback(err);
                } else {
                    ormDatabase = ormObject[options.schema];
                    if (!ormDatabase) {
                        error = new Error('Database doesn\'t exists');
                        error.name = 'errorNotFound';
                        callback(error);
                    } else if (!ormDatabase.schemaVersion) {
                        error = new Error('Table schemaVersion doesn\'t exists');
                        error.name = 'errorNotFound';
                        callback(error);
                    } else if (!fs.existsSync(options.migrationPath)) {
                        error = new Error('Migration path doesn\'t exists');
                        error.name = 'InvalidPath';
                        callback(error);
                    } else {
                        _this._readSchemaDir(options.migrationPath, function (err, dirs) {
                            if (err) {
                                callback(err);
                            } else {
                                if (!dirs.length) {
                                    error = new Error('No migration found!');
                                    error.name = 'errorEmptyPath';
                                    callback(error);
                                } else {
                                    dirs.forEach(function (dir) {
                                        _this._readSqlFiles(dir, function (err, files) {
                                            if (err) {
                                                callback(err);
                                            } else {
                                                if (!files.length) {
                                                    error = new Error('No migration sql found!');
                                                    error.name = 'errorEmptyPath';
                                                    callback(error);
                                                } else {

                                                    files.forEach(function (file) {
                                                        sqlStatments = fs.readFileSync(file).toString().split(';').map(function (input) {
                                                            return input.trim().replace(/\n/gi, ' ').replace(/\s{2,}/g, ' ');
                                                        }).filter(function (item) {
                                                            return item.length;
                                                        });

                                                    });
                                                }
                                            }
                                        });
                                    });
                                }
                            }
                        });

                    }

                }
            });

        }
    });
}();<commit_msg>refactored code to demontrate the use fo the bind function<commit_after>!function () {
    'use strict';
    var Class = require('ee-class')
        , ORM = require('related')
        , EventEmitter = require('ee-event-emitter')
        , fs = require('fs')
        , path = require('path')
        , semver = require('semver')
        , Promise = require('promise')
        , sqlFiles = []
        , schemaDirs = []
        , filesLength
        , sqlStatments
        , ormObject
        , error;

    module.exports = new Class({
        inherits: EventEmitter
        , config: {}
        , init: function (options) {
            this.config = options;
        }

        /**
         *@param {String} file
         */
        , _getSchemaDirectories: function _getSchemaDirectories(file) {
            return new Promise(function (resolve, reject) {
                fs.stat(file, function (err, stats) {
                    if (err) {
                        reject(err);
                    } else {
                        if (stats && stats.isDirectory() && path.basename(file)[0] !== '.') {
                            if (semver.valid(file)) {
                                schemaDirs.push(file);
                            }
                        }
                        if (!--filesLength) {
                            resolve(schemaDirs);
                        }
                    }
                });
            });
        }

        /**
         *@param {String} file
         */
        , _getSqlFiles: function _getSqlFiles(file) {
            return new Promise(function (resolve, reject) {
                fs.stat(file, function (err, stats) {
                    if (err) {
                        reject(err);
                    } else {
                        if (stats && !stats.isDirectory() && path.extname(file) === '.sql') {
                            sqlFiles.push(file);
                        }
                        if (!--filesLength) {
                            resolve(sqlFiles);
                        }
                    }
                });
            });
        }

        /**
         * Return all schema version directories
         *
         * @param {String} migrationPath
         * @param {Function} callback
         */
        , _readSchemaDir: function(migrationPath, callback) {

            fs.readdir(migrationPath, function(err, files) {
                if (err) callback(err);
                else {

                    if (!files.length) callback(null, schemaDirs);
                    else {
                        Promise.all(files.map(this._getSchemaDirectories.bind(this)).map(function(file) {
                            return path.resolve(migrationPath, file);
                        })).done(function(response) {
                            callback(null, response);
                        }, function(err) {
                            callback(err);
                        });
                    }
                }
            }.bind(this));
        }

        /**
         * Return all sql files
         * @param {String} versionPath
         * @param {Function} callback
         */
        , _readSqlFiles: function _readSqlFiles(versionPath, callback) {
            var _this = this;
            fs.readdir(versionPath, function (err, files) {
                if (err) {
                    callback(err);
                } else {
                    filesLength = files.length;
                    if (!filesLength) {
                        callback(null, sqlFiles);
                    } else {
                        Promise.all(files.map(_this._getSqlFiles).map(function (file) {
                            return file = path.resolve(versionPath, file);
                        })).done(function (response) {
                            callback(null, response);
                        }, function (err) {
                            callback(err);
                        });
                        ;
                    }
                }
            });
        }

        /**
         * Migrate all sql files of schema version
         * @param {Function} callback
         */
        , migrate: function migration(callback) {
            var options = this.config
                , _this = this
                , ormDatabase;
            ormObject = new ORM(options.user
                , options.password
                , options.host
                , options.schema
                , options.database
                , options.type);

            ormObject.load(function (err) {
                if (err) {
                    callback(err);
                } else {
                    ormDatabase = ormObject[options.schema];
                    if (!ormDatabase) {
                        error = new Error('Database doesn\'t exists');
                        error.name = 'errorNotFound';
                        callback(error);
                    } else if (!ormDatabase.schemaVersion) {
                        error = new Error('Table schemaVersion doesn\'t exists');
                        error.name = 'errorNotFound';
                        callback(error);
                    } else if (!fs.existsSync(options.migrationPath)) {
                        error = new Error('Migration path doesn\'t exists');
                        error.name = 'InvalidPath';
                        callback(error);
                    } else {
                        _this._readSchemaDir(options.migrationPath, function (err, dirs) {
                            if (err) {
                                callback(err);
                            } else {
                                if (!dirs.length) {
                                    error = new Error('No migration found!');
                                    error.name = 'errorEmptyPath';
                                    callback(error);
                                } else {
                                    dirs.forEach(function (dir) {
                                        _this._readSqlFiles(dir, function (err, files) {
                                            if (err) {
                                                callback(err);
                                            } else {
                                                if (!files.length) {
                                                    error = new Error('No migration sql found!');
                                                    error.name = 'errorEmptyPath';
                                                    callback(error);
                                                } else {

                                                    files.forEach(function (file) {
                                                        sqlStatments = fs.readFileSync(file).toString().split(';').map(function (input) {
                                                            return input.trim().replace(/\n/gi, ' ').replace(/\s{2,}/g, ' ');
                                                        }).filter(function (item) {
                                                            return item.length;
                                                        });

                                                    });
                                                }
                                            }
                                        });
                                    });
                                }
                            }
                        });

                    }

                }
            });

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


<commit_before>var gulp = require('gulp');
var durandal = require('gulp-durandal');
var paths = require('../paths');

gulp.task('durandal', function(){
    return durandal({
            baseDir: paths.root,
            main: 'main.js',
            output: 'main.js',
            almond: true,
            minify: true
        })
        .pipe(gulp.dest(paths.output + paths.root));
});
<commit_msg>Extend durandal config<commit_after>var gulp = require('gulp');
var durandal = require('gulp-durandal');
var paths = require('../paths');

gulp.task('durandal', function(){
    return durandal({
            baseDir: paths.root,
            main: 'main.js',
            output: 'main.js',
            almond: true,
            minify: true,
            rjsConfigAdapter: function(cfg) {
            	cfg.generateSourceMaps = false;
	            cfg.uglify2 = {
					output: {
						beautify: true
					},
					compress: {
						sequences: false,
						global_defs: {
							DEBUG: false
						},
						drop_console: true
					},
					warnings: true,
					mangle: false
				};

            	return cfg;
            }
        })
        .pipe(gulp.dest(paths.output + paths.root));
});
<|endoftext|>


<commit_before>/* @flow weak */

import RemoteCozy from './cozy'
import Watcher from './watcher'

export default class Remote {
  watcher: Watcher

  constructor (config, prep, pouch) {
    const deviceName = config.getDefaultDeviceName()
    const device = config.getDevice(deviceName)
    const remoteCozy = new RemoteCozy(device.url)

    this.watcher = new Watcher(pouch, prep, remoteCozy)
  }

  start (callback) {
    this.watcher.start()
    callback()
  }

  stop (callback) {
    this.watcher.stop()
    callback()
  }
}
<commit_msg>remote/index: Add remoteCozy property<commit_after>/* @flow weak */

import RemoteCozy from './cozy'
import Watcher from './watcher'

export default class Remote {
  watcher: Watcher
  remoteCozy: RemoteCozy

  constructor (config, prep, pouch) {
    const deviceName = config.getDefaultDeviceName()
    const device = config.getDevice(deviceName)

    this.remoteCozy = new RemoteCozy(device.url)
    this.watcher = new Watcher(pouch, prep, this.remoteCozy)
  }

  start (callback) {
    this.watcher.start()
    callback()
  }

  stop (callback) {
    this.watcher.stop()
    callback()
  }
}
<|endoftext|>


<commit_before>define( [
            'dojo/_base/declare',
            'dojo/_base/array',
            'dojo/aspect',
            'dojo/on',
            'JBrowse/has',
            'dojo/window',
            'dojo/dom-construct',
            'JBrowse/Util',
            'dijit/form/Button',
            'dijit/form/RadioButton',
            'dijit/Dialog',
            'FileSaver/FileSaver'
        ],
        function(
            declare,
            array,
            aspect,
            on,
            has,
            dojoWindow,
            dom,
            Util,
            dijitButton,
            dijitRadioButton,
            dijitDialog,
            saveAs
        ) {
/**
 * Mixin for a track that can export its data.
 * @lends JBrowse.View.Track.ExportMixin
 */
return declare( null, {

    _canExport: function() {
        if( this.config.noExport )
            return false;

        var visibleRegion = this.browser.view.visibleRegion();
        var wholeRefSeqRegion = { ref: this.refSeq.name, start: this.refSeq.start, end: this.refSeq.end };
        var canExportVisibleRegion = this._canExportRegion( visibleRegion );
        var canExportWholeRef = this._canExportRegion( wholeRefSeqRegion );
        return canExportVisibleRegion || canExportWholeRef;
    },

    _possibleExportRegions: function() {
        return [
            // the visible region
            (function() {
                 var r = dojo.clone( this.browser.view.visibleRegion() );
                 r.description = 'Visible region';
                 r.name = 'visible';
                 return r;
             }.call(this)),
            // whole reference sequence
            { ref: this.refSeq.name, start: this.refSeq.start, end: this.refSeq.end, description: 'Whole reference sequence', name: 'wholeref' }
        ];
    },

    _exportDialogContent: function() {
        // note that the `this` for this content function is not the track, it's the menu-rendering context
        var possibleRegions = this.track._possibleExportRegions();

        // for each region, calculate its length and determine whether we can export it
        array.forEach( possibleRegions, function( region ) {
            region.length = Math.round( region.end - region.start + 1 );
            region.canExport = this._canExportRegion( region );
        },this.track);

        var setFilenameValue = dojo.hitch(this.track, function() {
            var region = this._readRadio(form.elements.region);
            var format = nameToExtension[this._readRadio(form.elements.format)];
            form.elements.filename.value = ((this.key || this.label) + "-" + region).replace(/[^ .a-zA-Z0-9_-]/g,'-') + "." + format;
        });

        var form = dom.create('form', { onSubmit: function() { return false; } });
        var regionFieldset = dom.create('fieldset', {class: "region"});
        var regionLegend = dom.create('legend', {innerHTML: "Region to save"});
        regionFieldset.appendChild(regionLegend);
        form.appendChild(regionFieldset);

        var checked = 0;
        array.forEach( possibleRegions, function(r) {
                var locstring = Util.assembleLocString(r);
                var regionButton = new dijitRadioButton({ name: "region", id: "region_"+r.name, value: locstring,
                    checked: r.canExport && checked++ ? "checked" : ""});
                regionFieldset.appendChild(regionButton.domNode);
                var regionButtonLabel = dom.create("label", {for: regionButton.id, innerHTML: r.description+' - '
                                   +         locstring+' ('+Util.humanReadableNumber(r.length)+(r.canExport ? 'b' : 'b, too large')+')'}, regionFieldset);
                if(!r.canExport) {
                    regionButton.domNode.disabled = "disabled";
                    regionButtonLabel.class = "ghosted";
                }

                on(regionButton, "click", setFilenameValue);

               regionFieldset.appendChild(dom.create("br"));
        });

        var formatFieldset = dom.create("fieldset", {class: "format"});
        var formatLegend = dom.create("legend", {innerHTML: "Format"});
        formatFieldset.appendChild(formatLegend);
        form.appendChild(formatFieldset);

        checked = 0;
        var nameToExtension = {};
        array.forEach( this.track._exportFormats(), function(fmt) {
            if( ! fmt.name ) {
                fmt = { name: fmt, label: fmt };
            }
            if( ! fmt.fileExt) {
                fmt.fileExt = fmt.name || fmt;
            }
            nameToExtension[fmt.name] = fmt.fileExt;
            var formatButton = new dijitRadioButton({ name: "format", id: "format"+fmt.name, value: fmt.name, checked: checked++?"":"checked"});
            formatFieldset.appendChild(formatButton.domNode);
            var formatButtonLabel = dom.create("label", {for: formatButton.id, innerHTML: fmt.label}, formatFieldset);

            on(formatButton, "click", setFilenameValue);
            formatFieldset.appendChild(dom.create("br"));
        });

        var filenameFieldset = dom.create("fieldset", {class: "filename"});
        var filenameLegend = dom.create("legend", {innerHTML: "Filename"});
        filenameFieldset.appendChild(filenameLegend);
        form.appendChild(filenameFieldset);
        dom.create("input", {type: "text", name: "filename", style: {width: "100%"}}, filenameFieldset);

        setFilenameValue();

        var actionBar = dom.create( 'div', {
            className: 'dijitDialogPaneActionBar'
        });

        // note that the `this` for this content function is not the track, it's the menu-rendering context
        var dialog = this.dialog;

        new dijitButton({ iconClass: 'dijitIconDelete', onClick: dojo.hitch(dialog,'hide'), label: 'Cancel' })
            .placeAt( actionBar );
        var viewButton = new dijitButton({ iconClass: 'dijitIconTask',
                          label: 'View',
                          disabled: ! array.some(possibleRegions,function(r) { return r.canExport; }),
                          onClick: dojo.hitch( this.track, function() {
                            var track = this;
                            viewButton.set('disabled',true);
                            viewButton.set('iconClass','jbrowseIconBusy');

                            var region = this._readRadio( form.elements.region );
                            var format = this._readRadio( form.elements.format );
                            var filename = form.elements.filename.value.replace(/[^ .a-zA-Z0-9_-]/g,'-');
                            this.exportRegion( region, format, function(output) {
                                dialog.hide();
                                var text = dom.create('textarea', {
                                                           rows: Math.round( dojoWindow.getBox().h / 12 * 0.5 ),
                                                           wrap: 'off',
                                                           cols: 80,
                                                           style: "maxWidth: 90em; overflow: scroll; overflow-y: scroll; overflow-x: scroll; overflow:-moz-scrollbars-vertical;",
                                                           readonly: true
                                                       });
                                text.value = output;
                                var actionBar = dom.create( 'div', {
                                    className: 'dijitDialogPaneActionBar'
                                });
                                var exportView = new dijitDialog({
                                    className: 'export-view-dialog',
                                    title: format + ' export - '+ region+' ('+Util.humanReadableNumber(output.length)+'b)',
                                    content: [ text, actionBar ]
                                });
                                new dijitButton({ iconClass: 'dijitIconDelete',
                                                  label: 'Close', onClick: dojo.hitch( exportView, 'hide' )
                                                })
                                     .placeAt(actionBar);

                                // data URL download doesn't work on IE < 10
                                if( ! (has('ie') < 10) ) {
                                    var filenameDiv = dom.create("div", {class: "filename", style: {display: "inline-block", "margin-left": "50px"}});
                                    var filenameSpan = dom.create("span", {innerHTML: "Filename:  "});
                                    filenameDiv.appendChild(filenameSpan);
                                    actionBar.appendChild(filenameDiv)
                                    var filenameText = dom.create("input", {type: "text", name: "filename", style: {width: "250px"},value: filename}, filenameDiv);

                                    new dijitButton(
                                        {
                                            iconClass: 'dijitIconSave',
                                            label: 'Save',
                                            onClick: function() {
                                                var filename = filenameText.value.replace(/[^ .a-zA-Z0-9_-]/g,'-');
                                                exportView.hide();
                                                track._fileDownload({ format: format, data: output, filename: filename });
                                            }
                                        }).placeAt(actionBar);
                                }

                                aspect.after( exportView, 'hide', function() {
                                    // manually unhook and free the (possibly huge) text area
                                    text.parentNode.removeChild( text );
                                    text = null;
                                    setTimeout( function() {
                                        exportView.destroyRecursive();
                                    }, 500 );
                                });
                                exportView.show();
                            });
                          })})
            .placeAt( actionBar );

        // don't show a download button if the user is using IE older
        // than 10, cause it won't work.
        if( ! (has('ie') < 10) ) {
            var dlButton = new dijitButton({ iconClass: 'dijitIconSave',
                              label: 'Save',
                              disabled: ! array.some(possibleRegions,function(r) { return r.canExport; }),
                              onClick: dojo.hitch( this.track, function() {
                                var format = this._readRadio( form.elements.format );
                                var region = this._readRadio( form.elements.region );
                                var filename = form.elements.filename.value.replace(/[^ .a-zA-Z0-9_-]/g,'-');
                                dlButton.set('disabled',true);
                                dlButton.set('iconClass','jbrowseIconBusy');
                                this.exportRegion( region, format, dojo.hitch( this, function( output ) {
                                    dialog.hide();
                                    this._fileDownload({ format: format, data: output, filename: filename });
                                }));
                              })})
                .placeAt( actionBar );
        }

        return [ form, actionBar ];
    },

    _fileDownload: function( args ) {
        saveAs(new Blob([args.data], {type: args.format ? 'application/x-'+args.format.toLowerCase() : 'text/plain'}), args.filename);
        // We will need to check whether this breaks the WebApollo plugin.
    },

    // cross-platform function for (portably) reading the value of a radio control. sigh. *rolls eyes*
    _readRadio: function( r ) {
        if( r.length ) {
            for( var i = 0; i<r.length; i++ ) {
                if( r[i].checked )
                    return r[i].value;
            }
        }
        return r.value;
    },

    exportRegion: function( region, format, callback ) {
        // parse the locstring if necessary
        if( typeof region == 'string' )
            region = Util.parseLocString( region );

        // we can only export from the currently-visible reference
        // sequence right now
        if( region.ref != this.refSeq.name ) {
            console.error("cannot export data for ref seq "+region.ref+", "
                          + "exporting is currently only supported for the "
                          + "currently-visible reference sequence" );
            return;
        }

        require( ['JBrowse/View/Export/'+format], dojo.hitch(this,function( exportDriver ) {
            new exportDriver({
                refSeq: this.refSeq,
                track: this,
                store: this.store
            }).exportRegion( region, callback );
        }));
    },

    _trackMenuOptions: function() {
        var opts = this.inherited(arguments);

        if( ! this.config.noExport )
            // add a "Save track data as" option to the track menu
            opts.push({ label: 'Save track data',
                        iconClass: 'dijitIconSave',
                        disabled: ! this._canExport(),
                        action: 'bareDialog',
                        content: this._exportDialogContent,
                        dialog: { id: 'exportDialog', className: 'export-dialog' }
                      });

        return opts;
    },

    _canExportRegion: function( l ) {
        //console.log('can generic export?');
        if( ! l ) return false;

        // if we have a maxExportSpan configured for this track, use it.
        if( typeof this.config.maxExportSpan == 'number' || typeof this.config.maxExportSpan == 'string' ) {
            return l.end - l.start + 1 <= this.config.maxExportSpan;
        }
        else {
            // if we know the store's feature density, then use that with
            // a limit of maxExportFeatures or 5,000 features
            var thisB = this;
            var storeStats = {};
            // will return immediately if the stats are available
            this.store.getGlobalStats( function( s ) {
                storeStats = s;
            });
            if( storeStats.featureDensity ) {
                return storeStats.featureDensity*(l.end - l.start) <= ( thisB.config.maxExportFeatures || 5000 );
            }
        }

        // otherwise, i guess we can export
        return true;
    }

});
});
<commit_msg>remove unnecessary use of appendChild, fix some whitespace and reserved word errors<commit_after>define( [
            'dojo/_base/declare',
            'dojo/_base/array',
            'dojo/aspect',
            'dojo/on',
            'JBrowse/has',
            'dojo/window',
            'dojo/dom-construct',
            'JBrowse/Util',
            'dijit/form/Button',
            'dijit/form/RadioButton',
            'dijit/Dialog',
            'FileSaver/FileSaver'
        ],
        function(
            declare,
            array,
            aspect,
            on,
            has,
            dojoWindow,
            dom,
            Util,
            dijitButton,
            dijitRadioButton,
            dijitDialog,
            saveAs
        ) {
/**
 * Mixin for a track that can export its data.
 * @lends JBrowse.View.Track.ExportMixin
 */
return declare( null, {

    _canExport: function() {
        if( this.config.noExport )
            return false;

        var visibleRegion = this.browser.view.visibleRegion();
        var wholeRefSeqRegion = { ref: this.refSeq.name, start: this.refSeq.start, end: this.refSeq.end };
        var canExportVisibleRegion = this._canExportRegion( visibleRegion );
        var canExportWholeRef = this._canExportRegion( wholeRefSeqRegion );
        return canExportVisibleRegion || canExportWholeRef;
    },

    _possibleExportRegions: function() {
        return [
            // the visible region
            (function() {
                 var r = dojo.clone( this.browser.view.visibleRegion() );
                 r.description = 'Visible region';
                 r.name = 'visible';
                 return r;
             }.call(this)),
            // whole reference sequence
            { ref: this.refSeq.name, start: this.refSeq.start, end: this.refSeq.end, description: 'Whole reference sequence', name: 'wholeref' }
        ];
    },

    _exportDialogContent: function() {
        // note that the `this` for this content function is not the track, it's the menu-rendering context
        var possibleRegions = this.track._possibleExportRegions();

        // for each region, calculate its length and determine whether we can export it
        array.forEach( possibleRegions, function( region ) {
            region.length = Math.round( region.end - region.start + 1 );
            region.canExport = this._canExportRegion( region );
        },this.track);

        var setFilenameValue = dojo.hitch(this.track, function() {
            var region = this._readRadio(form.elements.region);
            var format = nameToExtension[this._readRadio(form.elements.format)];
            form.elements.filename.value = ((this.key || this.label) + "-" + region).replace(/[^ .a-zA-Z0-9_-]/g,'-') + "." + format;
        });

        var form = dom.create('form', { onSubmit: function() { return false; } });
        var regionFieldset = dom.create('fieldset', {className: "region"}, form );
        dom.create('legend', {innerHTML: "Region to save"}, regionFieldset);

        var checked = 0;
        array.forEach( possibleRegions, function(r) {
                var locstring = Util.assembleLocString(r);
                var regionButton = new dijitRadioButton({ name: "region", id: "region_"+r.name, value: locstring,
                    checked: r.canExport && checked++ ? "checked" : ""});
                regionFieldset.appendChild(regionButton.domNode);
                var regionButtonLabel = dom.create("label", {for: regionButton.id, innerHTML: r.description+' - '
                                   +         locstring+' ('+Util.humanReadableNumber(r.length)+(r.canExport ? 'b' : 'b, too large')+')'}, regionFieldset);
                if(!r.canExport) {
                    regionButton.domNode.disabled = "disabled";
                    regionButtonLabel.className = "ghosted";
                }

                on(regionButton, "click", setFilenameValue);

                dom.create('br',{},regionFieldset);
        });

        var formatFieldset = dom.create("fieldset", {className: "format"}, form);
        dom.create("legend", {innerHTML: "Format"}, formatFieldset);

        checked = 0;
        var nameToExtension = {};
        array.forEach( this.track._exportFormats(), function(fmt) {
            if( ! fmt.name ) {
                fmt = { name: fmt, label: fmt };
            }
            if( ! fmt.fileExt) {
                fmt.fileExt = fmt.name || fmt;
            }
            nameToExtension[fmt.name] = fmt.fileExt;
            var formatButton = new dijitRadioButton({ name: "format", id: "format"+fmt.name, value: fmt.name, checked: checked++?"":"checked"});
            formatFieldset.appendChild(formatButton.domNode);
            var formatButtonLabel = dom.create("label", {for: formatButton.id, innerHTML: fmt.label}, formatFieldset);

            on(formatButton, "click", setFilenameValue);
            dom.create( "br", {}, formatFieldset );
        },this);

        var filenameFieldset = dom.create("fieldset", {className: "filename"}, form);
        dom.create("legend", {innerHTML: "Filename"}, filenameFieldset);
        dom.create("input", {type: "text", name: "filename", style: {width: "100%"}}, filenameFieldset);

        setFilenameValue();

        var actionBar = dom.create( 'div', {
            className: 'dijitDialogPaneActionBar'
        });

        // note that the `this` for this content function is not the track, it's the menu-rendering context
        var dialog = this.dialog;

        new dijitButton({ iconClass: 'dijitIconDelete', onClick: dojo.hitch(dialog,'hide'), label: 'Cancel' })
            .placeAt( actionBar );
        var viewButton = new dijitButton({ iconClass: 'dijitIconTask',
                          label: 'View',
                          disabled: ! array.some(possibleRegions,function(r) { return r.canExport; }),
                          onClick: dojo.hitch( this.track, function() {
                            var track = this;
                            viewButton.set('disabled',true);
                            viewButton.set('iconClass','jbrowseIconBusy');

                            var region = this._readRadio( form.elements.region );
                            var format = this._readRadio( form.elements.format );
                            var filename = form.elements.filename.value.replace(/[^ .a-zA-Z0-9_-]/g,'-');
                            this.exportRegion( region, format, function(output) {
                                dialog.hide();
                                var text = dom.create('textarea', {
                                                           rows: Math.round( dojoWindow.getBox().h / 12 * 0.5 ),
                                                           wrap: 'off',
                                                           cols: 80,
                                                           style: "maxWidth: 90em; overflow: scroll; overflow-y: scroll; overflow-x: scroll; overflow:-moz-scrollbars-vertical;",
                                                           readonly: true
                                                       });
                                text.value = output;
                                var actionBar = dom.create( 'div', {
                                    className: 'dijitDialogPaneActionBar'
                                });
                                var exportView = new dijitDialog({
                                    className: 'export-view-dialog',
                                    title: format + ' export - '+ region+' ('+Util.humanReadableNumber(output.length)+'b)',
                                    content: [ text, actionBar ]
                                });
                                new dijitButton({ iconClass: 'dijitIconDelete',
                                                  label: 'Close', onClick: dojo.hitch( exportView, 'hide' )
                                                })
                                     .placeAt(actionBar);

                                // data URL download doesn't work on IE < 10
                                if( ! (has('ie') < 10) ) {
                                    var filenameDiv = dom.create("div", {className: "filename", style: {display: "inline-block", "margin-left": "50px"}}, actionBar);
                                    var filenameSpan = dom.create("span", {innerHTML: "Filename:  "}, filenameDiv);
                                    var filenameText = dom.create("input", {type: "text", name: "filename", style: {width: "250px"},value: filename}, filenameDiv);

                                    new dijitButton(
                                        {
                                            iconClass: 'dijitIconSave',
                                            label: 'Save',
                                            onClick: function() {
                                                var filename = filenameText.value.replace(/[^ .a-zA-Z0-9_-]/g,'-');
                                                exportView.hide();
                                                track._fileDownload({ format: format, data: output, filename: filename });
                                            }
                                        }).placeAt(actionBar);
                                }

                                aspect.after( exportView, 'hide', function() {
                                    // manually unhook and free the (possibly huge) text area
                                    text.parentNode.removeChild( text );
                                    text = null;
                                    setTimeout( function() {
                                        exportView.destroyRecursive();
                                    }, 500 );
                                });
                                exportView.show();
                            });
                          })})
            .placeAt( actionBar );

        // don't show a download button if the user is using IE older
        // than 10, cause it won't work.
        if( ! (has('ie') < 10) ) {
            var dlButton = new dijitButton({ iconClass: 'dijitIconSave',
                              label: 'Save',
                              disabled: ! array.some(possibleRegions,function(r) { return r.canExport; }),
                              onClick: dojo.hitch( this.track, function() {
                                var format = this._readRadio( form.elements.format );
                                var region = this._readRadio( form.elements.region );
                                var filename = form.elements.filename.value.replace(/[^ .a-zA-Z0-9_-]/g,'-');
                                dlButton.set('disabled',true);
                                dlButton.set('iconClass','jbrowseIconBusy');
                                this.exportRegion( region, format, dojo.hitch( this, function( output ) {
                                    dialog.hide();
                                    this._fileDownload({ format: format, data: output, filename: filename });
                                }));
                              })})
                .placeAt( actionBar );
        }

        return [ form, actionBar ];
    },

    _fileDownload: function( args ) {
        saveAs(new Blob([args.data], {type: args.format ? 'application/x-'+args.format.toLowerCase() : 'text/plain'}), args.filename);
        // We will need to check whether this breaks the WebApollo plugin.
    },

    // cross-platform function for (portably) reading the value of a radio control. sigh. *rolls eyes*
    _readRadio: function( r ) {
        if( r.length ) {
            for( var i = 0; i<r.length; i++ ) {
                if( r[i].checked )
                    return r[i].value;
            }
        }
        return r.value;
    },

    exportRegion: function( region, format, callback ) {
        // parse the locstring if necessary
        if( typeof region == 'string' )
            region = Util.parseLocString( region );

        // we can only export from the currently-visible reference
        // sequence right now
        if( region.ref != this.refSeq.name ) {
            console.error("cannot export data for ref seq "+region.ref+", "
                          + "exporting is currently only supported for the "
                          + "currently-visible reference sequence" );
            return;
        }

        require( ['JBrowse/View/Export/'+format], dojo.hitch(this,function( exportDriver ) {
            new exportDriver({
                refSeq: this.refSeq,
                track: this,
                store: this.store
            }).exportRegion( region, callback );
        }));
    },

    _trackMenuOptions: function() {
        var opts = this.inherited(arguments);

        if( ! this.config.noExport )
            // add a "Save track data as" option to the track menu
            opts.push({ label: 'Save track data',
                        iconClass: 'dijitIconSave',
                        disabled: ! this._canExport(),
                        action: 'bareDialog',
                        content: this._exportDialogContent,
                        dialog: { id: 'exportDialog', className: 'export-dialog' }
                      });

        return opts;
    },

    _canExportRegion: function( l ) {
        //console.log('can generic export?');
        if( ! l ) return false;

        // if we have a maxExportSpan configured for this track, use it.
        if( typeof this.config.maxExportSpan == 'number' || typeof this.config.maxExportSpan == 'string' ) {
            return l.end - l.start + 1 <= this.config.maxExportSpan;
        }
        else {
            // if we know the store's feature density, then use that with
            // a limit of maxExportFeatures or 5,000 features
            var thisB = this;
            var storeStats = {};
            // will return immediately if the stats are available
            this.store.getGlobalStats( function( s ) {
                storeStats = s;
            });
            if( storeStats.featureDensity ) {
                return storeStats.featureDensity*(l.end - l.start) <= ( thisB.config.maxExportFeatures || 5000 );
            }
        }

        // otherwise, i guess we can export
        return true;
    }

});
});
<|endoftext|>


<commit_before>QUnit.module('templateParser - error', {
  before: function() {
    this.parse = function() {
      this.result = this.parser.parse(this.source);
    };
  },
  beforeEach: function() {
    this.parser = smodules.templateParser();
    this.source = '';
    this.result = null;
  },
});

QUnit.test('normal block - error - 1', function(assert) {
  this.source = '
{left} is ok, only { is forbidden.
';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('normal block - error - 2', function(assert) {
  this.source = '
 } is forbidden.
';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('literal block - error - only open tag', function(assert) {
  this.source = '
{literal}
';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('literal block - error - only close tag', function(assert) {
  this.source = '
{/literal}
';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('holder block - no filters - error - space between $ and property name', function(assert) {
  this.source = '{ $ foo } has space between $ and property name.';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('holder block - no filters - error - dot between $ and property name', function(assert) {
  this.source = '{ $.foo }';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('holder block - no filters - error - dot after property name', function(assert) {
  this.source = '{ $foo. }';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('holder block - no filters - error - continuous dots', function(assert) {
  this.source = '{ $foo..bar }';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('holder block - filter - error - filter name has space', function(assert) {
  this.source = '{ $foo | invalid filter name }';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('holder block - filter - error - filter name has symbol', function(assert) {
  this.source = '{ $foo | filter! }';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('holder block - filter - error - no pipe', function(assert) {
  this.source = '{ $foo pipeNotFound }';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('holder block - filter - error - no filter args after colon', function(assert) {
  this.source = '{ $foo | filter : }';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('holder block - filter with args - error - NULL', function(assert) {
  this.source = '{ $foo | filter : NULL }';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('holder block - filter with args - error - TRUE', function(assert) {
  this.source = '{ $foo | filter : TRUE }';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('holder block - filter with args - error - FALSE', function(assert) {
  this.source = '{ $foo | filter : FALSE }';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('holder block - filter with args - string - error - quote 1', function(assert) {
  this.source = '{ $foo | filter : \'test }';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('holder block - filter with args - string - error - quote 2', function(assert) {
  this.source = '{ $foo | filter : test\' }';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('holder block - filter with args - string - error - quote char 1', function(assert) {
  this.source = '{ $foo | filter : "test\' }';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('holder block - filter with args - string - error - quote char 2', function(assert) {
  this.source = '{ $foo | filter : \'test" }';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - if elseif else - error 1', function(assert) {
  this.source = '{if $foo}
hoge
';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - if elseif else - error 2', function(assert) {
  this.source = '{elseif $foo}
hoge
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - if elseif else - error 3', function(assert) {
  this.source = '{else}
hoge
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - if elseif else - error 4', function(assert) {
  this.source = '{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});
QUnit.test('if block - if elseif else - error 5', function(assert) {
  this.source = '{if $foo}
foo
{if $bar}
bar
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - no space', function(assert) {
  this.source = '{if$foo }
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - round bracket balance', function(assert) {
  this.source = '{if ($foo) and $bar) }
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - lack of endRoundBracket', function(assert) {
  this.source = '{if ( $foo }
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - lack of roundBracket', function(assert) {
  this.source = '{if ( $foo ) ) }
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - roundBracket -> endRoundBracket', function(assert) {
  this.source = '{if () }
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - roundBracket -> comp', function(assert) {
  this.source = '{if ( === $foo )}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - roundBracket -> andor', function(assert) {
  this.source = '{if ( and $foo )}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - endRoundBracket -> roundBracket', function(assert) {
  this.source = '{if ( $foo ) ( $bar )}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - endRoundBracket -> value', function(assert) {
  this.source = '{if ( $foo ) 10 === $bar}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - endRoundBracket -> var', function(assert) {
  this.source = '{if ( $foo ) $bar gte 10}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - endRoundBracket -> comp', function(assert) {
  this.source = '{if ( $foo ) === $bar}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - value -> roundBracket', function(assert) {
  this.source = '{if 10 ( $foo === 1 )}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - value -> value', function(assert) {
  this.source = '{if 10 20}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - value -> var', function(assert) {
  this.source = '{if 10 $foo}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - var -> roundBracket', function(assert) {
  this.source = '{if $foo ( $bar === 1 )}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - var -> value', function(assert) {
  this.source = '{if $foo 10}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - var -> var', function(assert) {
  this.source = '{if $foo $bar}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - comp -> roundBracket', function(assert) {
  this.source = '{if $foo lte ( $bar ) }
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - comp -> endRoundBracket', function(assert) {
  this.source = '{if ( $foo gte ) $bar}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - comp -> comp', function(assert) {
  this.source = '{if $foo === === $bar}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - comp -> andor', function(assert) {
  this.source = '{if $foo !== or $bar}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - comp -> value -> comp', function(assert) {
  this.source = '{if 10 === 10 === 10}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - comp -> var -> comp', function(assert) {
  this.source = '{if $foo gt $bar gt $baz}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - andor -> endRoundBracket', function(assert) {
  this.source = '{if ( $foo or ) $bar}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - andor -> comp', function(assert) {
  this.source = '{if $foo or === $bar}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - andor -> andor', function(assert) {
  this.source = '{if $foo or or $bar}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('for block - error - lack of index argument', function(assert) {
  this.source = '{for , $item in $items}
{$item}
{/for}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('for block - error - lack of comma', function(assert) {
  this.source = '{for $idx $item in $items}
{$item}
{/for}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('for block - error - lack of value argument', function(assert) {
  this.source = '{for $idx , in $items}
{$idx}
{/for}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('for block - error - lack of in', function(assert) {
  this.source = '{for $idx , $item $items}
{$item}
{/for}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('for block - error - lack of haystack', function(assert) {
  this.source = '{for $idx , $item in}
{$item}
{/for}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('for block - error - too many elements 1', function(assert) {
  this.source = '{for $idx , $item , $foo in $items}
{$item}
{/for}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('for block - error - too many elements 2', function(assert) {

  this.source = '{for $idx , $item in $items1 , $items2}
{$item}
{/for}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('for block - error - too many elements 3', function(assert) {

  this.source = '{for $idx , $item in $items1 $items2}
{$item}
{/for}';

  assert.throws(function() {
    this.parse();
  }, Error);
});
<commit_msg>[QUnit] add tests for if block error<commit_after>QUnit.module('templateParser - error', {
  before: function() {
    this.parse = function() {
      this.result = this.parser.parse(this.source);
    };
  },
  beforeEach: function() {
    this.parser = smodules.templateParser();
    this.source = '';
    this.result = null;
  },
});

QUnit.test('normal block - error - 1', function(assert) {
  this.source = '
{left} is ok, only { is forbidden.
';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('normal block - error - 2', function(assert) {
  this.source = '
 } is forbidden.
';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('literal block - error - only open tag', function(assert) {
  this.source = '
{literal}
';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('literal block - error - only close tag', function(assert) {
  this.source = '
{/literal}
';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('holder block - no filters - error - space between $ and property name', function(assert) {
  this.source = '{ $ foo } has space between $ and property name.';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('holder block - no filters - error - dot between $ and property name', function(assert) {
  this.source = '{ $.foo }';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('holder block - no filters - error - dot after property name', function(assert) {
  this.source = '{ $foo. }';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('holder block - no filters - error - continuous dots', function(assert) {
  this.source = '{ $foo..bar }';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('holder block - filter - error - filter name has space', function(assert) {
  this.source = '{ $foo | invalid filter name }';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('holder block - filter - error - filter name has symbol', function(assert) {
  this.source = '{ $foo | filter! }';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('holder block - filter - error - no pipe', function(assert) {
  this.source = '{ $foo pipeNotFound }';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('holder block - filter - error - no filter args after colon', function(assert) {
  this.source = '{ $foo | filter : }';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('holder block - filter with args - error - NULL', function(assert) {
  this.source = '{ $foo | filter : NULL }';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('holder block - filter with args - error - TRUE', function(assert) {
  this.source = '{ $foo | filter : TRUE }';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('holder block - filter with args - error - FALSE', function(assert) {
  this.source = '{ $foo | filter : FALSE }';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('holder block - filter with args - string - error - quote 1', function(assert) {
  this.source = '{ $foo | filter : \'test }';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('holder block - filter with args - string - error - quote 2', function(assert) {
  this.source = '{ $foo | filter : test\' }';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('holder block - filter with args - string - error - quote char 1', function(assert) {
  this.source = '{ $foo | filter : "test\' }';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('holder block - filter with args - string - error - quote char 2', function(assert) {
  this.source = '{ $foo | filter : \'test" }';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - if elseif else - error 1', function(assert) {
  this.source = '{if $foo}
hoge
';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - if elseif else - error 2', function(assert) {
  this.source = '{elseif $foo}
hoge
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - if elseif else - error 3', function(assert) {
  this.source = '{else}
hoge
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - if elseif else - error 4', function(assert) {
  this.source = '{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});
QUnit.test('if block - if elseif else - error 5', function(assert) {
  this.source = '{if $foo}
foo
{if $bar}
bar
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - no space 1', function(assert) {
  this.source = '{if$foo }
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - no space 2', function(assert) {
  this.source = '{if $foo }
foo
{elseif$bar}
bar
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - round bracket balance', function(assert) {
  this.source = '{if ($foo) and $bar) }
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - lack of endRoundBracket', function(assert) {
  this.source = '{if ( $foo }
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - lack of roundBracket', function(assert) {
  this.source = '{if ( $foo ) ) }
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - roundBracket -> endRoundBracket', function(assert) {
  this.source = '{if () }
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - roundBracket -> comp', function(assert) {
  this.source = '{if ( === $foo )}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - roundBracket -> andor', function(assert) {
  this.source = '{if ( and $foo )}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - endRoundBracket -> roundBracket', function(assert) {
  this.source = '{if ( $foo ) ( $bar )}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - endRoundBracket -> value', function(assert) {
  this.source = '{if ( $foo ) 10 === $bar}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - endRoundBracket -> var', function(assert) {
  this.source = '{if ( $foo ) $bar gte 10}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - endRoundBracket -> comp', function(assert) {
  this.source = '{if ( $foo ) === $bar}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - value -> roundBracket', function(assert) {
  this.source = '{if 10 ( $foo === 1 )}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - value -> value', function(assert) {
  this.source = '{if 10 20}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - value -> var', function(assert) {
  this.source = '{if 10 $foo}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - var -> roundBracket', function(assert) {
  this.source = '{if $foo ( $bar === 1 )}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - var -> value', function(assert) {
  this.source = '{if $foo 10}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - var -> var', function(assert) {
  this.source = '{if $foo $bar}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - comp -> roundBracket', function(assert) {
  this.source = '{if $foo lte ( $bar ) }
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - comp -> endRoundBracket', function(assert) {
  this.source = '{if ( $foo gte ) $bar}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - comp -> comp', function(assert) {
  this.source = '{if $foo === === $bar}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - comp -> andor', function(assert) {
  this.source = '{if $foo !== or $bar}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - comp -> value -> comp', function(assert) {
  this.source = '{if 10 === 10 === 10}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - comp -> var -> comp', function(assert) {
  this.source = '{if $foo gt $bar gt $baz}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - andor -> endRoundBracket', function(assert) {
  this.source = '{if ( $foo or ) $bar}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - andor -> comp', function(assert) {
  this.source = '{if $foo or === $bar}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('if block - conditions - error - andor -> andor', function(assert) {
  this.source = '{if $foo or or $bar}
ok
{/if}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('for block - error - lack of index argument', function(assert) {
  this.source = '{for , $item in $items}
{$item}
{/for}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('for block - error - lack of comma', function(assert) {
  this.source = '{for $idx $item in $items}
{$item}
{/for}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('for block - error - lack of value argument', function(assert) {
  this.source = '{for $idx , in $items}
{$idx}
{/for}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('for block - error - lack of in', function(assert) {
  this.source = '{for $idx , $item $items}
{$item}
{/for}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('for block - error - lack of haystack', function(assert) {
  this.source = '{for $idx , $item in}
{$item}
{/for}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('for block - error - too many elements 1', function(assert) {
  this.source = '{for $idx , $item , $foo in $items}
{$item}
{/for}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('for block - error - too many elements 2', function(assert) {

  this.source = '{for $idx , $item in $items1 , $items2}
{$item}
{/for}';

  assert.throws(function() {
    this.parse();
  }, Error);
});

QUnit.test('for block - error - too many elements 3', function(assert) {

  this.source = '{for $idx , $item in $items1 $items2}
{$item}
{/for}';

  assert.throws(function() {
    this.parse();
  }, Error);
});
<|endoftext|>


<commit_before>/*jslint forin:true sub:true anon:true, sloppy:true, stupid:true nomen:true, node:true continue:true*/

/*
 * Copyright (c) 2012, Yahoo! Inc. All rights reserved.
 * Copyrights licensed under the New BSD License.
 * See the accompanying LICENSE file for terms.
 */
var log4js = require("log4js");
var SessionFactory = require("./sessionfactory");
var ReportManager = require("../util/reportmanager");
var FileUtil = require("../util/fileutil");
var WdSession = require("../session/wdsession");
var TestSession = require("../session/testsession");
var ProxyManager = require("../proxy/proxymanager");
var clone = require('clone');
var path = require("path");
var os = require("os");
var fs = require("fs");
var async = require("async");

var sf;
var testExecutor;
var curSessionCount;
var totalSessionCount;
var wdSessions;
var parallelCount;
var tests;
var testQueues;

function TestExecutor(sessionFactory) {

    sf = sessionFactory;

    this.logger = log4js.getLogger("TestExecutor");
    testExecutor = this;
    tests = [];
    wdSessions = [];
    testQueues = [];
    curSessionCount = 0;
    totalSessionCount = 0;
    parallelCount = 0;

}

TestExecutor.prototype.writeReportForDescriptor = function(testSession, callback) {

    var descriptor,
        testSessionsArr,
        currTime,
        reportObj,
        reportManager;

    for (descriptor in sf.descriptorObj) {

        if (descriptor === testSession.descriptorPath) {
            // Store testSessions array for each descriptor in testSessionMap
            if (sf.testSessionMap[descriptor]) {
                testSessionsArr = sf.testSessionMap[descriptor];
            } else {
                testSessionsArr = [];
            }
            testSessionsArr.push(testSession);

            sf.testSessionMap[descriptor] = testSessionsArr;

            sf.descriptorObj[descriptor].testSessionCount -= 1;
            if (sf.descriptorObj[descriptor].testSessionCount === 0) {

                sf.timeReportObj[testSession.descriptorPath].endTime = Date.now(); // TODO Is endTime required ???
                sf.timeReportObj[testSession.descriptorPath].timeTaken =
                    ((sf.timeReportObj[testSession.descriptorPath].endTime - sf.timeReportObj[testSession.descriptorPath].startTime) / 1000).toFixed(2);

                testExecutor.logger.info('Time taken to run descriptor-' + testSession.descriptorPath + ' = ' + sf.timeReportObj[testSession.descriptorPath].timeTaken);

                testExecutor.logger.info('All tests over for descriptor:' + testSession.descriptorPath);
                reportObj = {
                    "reportFolder" : global.reportFolder,
                    "arrTestSessions" : sf.testSessionMap[descriptor],
                    "descriptor" : testSession.descriptorPath,
                    "reuseSession" : sf.reuseSession,
                    "testSuiteName" : sf.descriptorObj[descriptor].testSuiteName,
                    "driver" : sf.driver,
                    "browser" : sf.browser,
                    "group" : sf.args.group,
                    "testName" : sf.args.testName

                };
                reportManager = new ReportManager(reportObj);
                reportManager.totalTimeTaken = sf.timeReportObj[testSession.descriptorPath].timeTaken;
                reportManager.writeReports();

            }

        }
    }
    callback();
};

TestExecutor.prototype.startProxy = function(proxyConfigPath, callback) {

    //TODO - move this to index.js
    if (os.type() === "Darwin") {
        global.hostname = "localhost";
    } else {
        global.hostname = os.hostname();
    }

    testExecutor.logger.info('Starting proxy server : ' + proxyConfigPath);

    var proxyManager = new ProxyManager(path.resolve(global.workingDirectory, proxyConfigPath),sf.config);

    proxyManager.runRouterProxy(sf.config.minPort, sf.config.maxPort, global.hostname, function(proxyHost) {

        if (proxyHost) {
            if (proxyHost.indexOf("Error") === -1) {
                testExecutor.logger.info("Running Proxy Server at " + proxyHost + ' for :::' + proxyConfigPath);
                global.routerMap[proxyConfigPath] = proxyHost;
            } else {
                testExecutor.logger.info("Unable to Start Proxy, " + proxyHost);
                testExecutor.logger.info("Running Tests Without Proxy! ");
            }
        } else {
            testExecutor.logger.info("Some error while starting proxy");
            //TODO - What message to show here??
        }

    });

    setTimeout(callback, 500);

};

TestExecutor.prototype.runNextTest = function(testQueue) {

    var testSession,
        testSessionTimeArr = [];

    if (testQueue.curIndex === testQueue.sessions.length) {
        return; // all done with this queue
    }
    testSession = testQueue.sessions[testQueue.curIndex];

    var thisSession = testQueue.sessions[testQueue.curIndex];

    testQueue.curIndex += 1;
    // If first test session is starting for the descriptor, note start time
    if (!sf.timeReportObj[testSession.descriptorPath]) {
        sf.timeReportObj[testSession.descriptorPath] = [];
        sf.timeReportObj[testSession.descriptorPath].startTime = Date.now();
    }

    testSession.runTest(function (error) {

        if (error) {
            var obj = {};
            obj.error = error;
            thisSession.driver.reports.addReport(obj);
            testExecutor.logger.debug("Error : " + error);
        }

        testExecutor.logger.trace("Run Test :" + curSessionCount + "==" + totalSessionCount);
        thisSession.endTime = Date.now();

        // Write report per descriptor ( if all testsessions for the descriptor ( to which the current test session belongs ) are run )

        if (sf.timeReportObj[thisSession.descriptorPath].testSessionTimeArr) {
            testSessionTimeArr = sf.timeReportObj[thisSession.descriptorPath].testSessionTimeArr;
        } else {
            testSessionTimeArr = {};
        }

        testSessionTimeArr[thisSession.args.testName] = {};

        testSessionTimeArr[thisSession.args.testName].timeTaken = ((thisSession.endTime - thisSession.startTime) / 1000).toFixed(2);
        sf.timeReportObj[thisSession.descriptorPath].testSessionTimeArr = testSessionTimeArr;

        testExecutor.logger.info('Time taken to run - ' + thisSession.descriptorPath + '-' + thisSession.args.testName + ' is::' +
            testSessionTimeArr[thisSession.args.testName].timeTaken);

        testExecutor.writeReportForDescriptor(thisSession, function() {
            curSessionCount += 1;
            if (curSessionCount === totalSessionCount) {
                testExecutor.logger.trace("Done with all the sessions");
                sf.tearDown(testQueue, wdSessions);
            } else {
                testExecutor.logger.trace("Calling Next Test : " + curSessionCount);
                testExecutor.runNextTest(testQueue);
            }
        });

    });
};

TestExecutor.prototype.runTests = function(testQueues, parallelCount) {
    var i, j;
    for (i = 0; i < testQueues.length; i += 1) {
        // start running as many sessions as we can in parallel as specified
        for (j = 0; j < parallelCount; j += 1) {
            testExecutor.runNextTest(testQueues[i]);
        }
    }

};

TestExecutor.prototype.setupTestQueues = function(callback) {

    var test,
        browsers,
        i,
        j;
    function incrementTestSessionCount(test) {
        if (test.descriptorPath) {
            if (sf.descriptorObj[test.descriptorPath]) {
                sf.descriptorObj[test.descriptorPath].testSessionCount += 1;
            } else {
                sf.descriptorObj[test.descriptorPath].testSessionCount = 1;
            }

        }
    }

    // there may be more than one independent queue that can always run in parallel
    if (wdSessions.length > 0) {

        parallelCount = 1; // when reusing sessions, items in a single queue cannot run in parallel
        // every wd session gets its own queue
        for (i = 0; i < wdSessions.length; i += 1) {
            testQueues[i] = {curIndex: 0, sessions: []};
            for (j = 0; j < tests.length; j += 1) {
                test = clone(tests[j]);

                // If proxy set to true or reuseSession set to false , ignore reuseSession
                if (test.startProxyServer === true || test.reuseSession === false) {
                    testQueues[i].sessions.push(new TestSession(sf.config, test));
                } else {
                    testQueues[i].sessions.push(new TestSession(sf.config, test, wdSessions[i]));
                }
                incrementTestSessionCount(test);

            }
            totalSessionCount += tests.length;
        }
    } else {
        // when not reusing sessions, a single queue contains all the items
        // parallelism is controlled by the "parallel" argument passed by the user
        testQueues[0] = {curIndex: 0, sessions: []};

        for (i = 0; i < tests.length; i += 1) {
            browsers = sf.getBrowsers(tests[i]);
            for (j = 0; j < browsers.length; j += 1) {
                test = clone(tests[i]);
                test.browser = browsers[j];
                testQueues[0].sessions.push(new TestSession(sf.config, test));
                incrementTestSessionCount(test);
            }
            totalSessionCount += browsers.length;

        }

    }
    testExecutor.logger.info("Total test sessions: " + totalSessionCount);
    callback();

};

TestExecutor.prototype.getTests = function(callback) {

    var testParams,
        test,
        i;

    if (sf.arrDescriptor) {

        tests = sf.getFactoryTests();
        if (tests.length === 0) {
            sf.tearDown({}, null);
        }
    } else if (sf.tests) {
        for (i = 0; i < sf.tests.length; i += 1) {
            testParams = clone(sf.args);
            testParams.test = sf.tests[i];
            // convert the cmd line test to look like a descriptor test
            test = {
                config : {},
                params : testParams,
                testName : "Default",
                driver : sf.args.driver,
                controller : sf.args.controller,
                browser : sf.browser
            };
            tests.push(test);
        }
    } else {
        // convert the cmd line test to look like a descriptor test
        test = {
            config: {},
            params : sf.args,
            testName : "Default",
            driver : sf.args.driver,
            controller : sf.args.controller,
            browser : sf.browser
        };
        test.params.lib = sf.args.lib;
        tests.push(test);
    }

    callback();

};

TestExecutor.prototype.populateProxyConfigList = function(callback) {

    var i,
        proxyConfig;

    // Get how many unique proxy servers we need to start
    for (i = 0; i < tests.length; i += 1) {

        proxyConfig = undefined;

        if (tests[i].startProxyServer === false) {
            continue;
        }

        // If test has routerProxyConfig
        if (tests[i].proxyConfig) {

            proxyConfig = tests[i].proxyConfig;

            if (tests[i].relativePath) {
                proxyConfig = path.resolve(global.workingDirectory, tests[i].relativePath, proxyConfig);
            } else {
                proxyConfig = path.resolve(global.workingDirectory, proxyConfig);
            }

        } else if (sf.args.routerProxyConfig) { // If proxyConfig is passed as an argument
            proxyConfig = path.resolve(global.workingDirectory, sf.args.routerProxyConfig);
        }

        if (proxyConfig) {

            tests[i].resolvedProxyConfigPath = proxyConfig;
            // Add routerConfig to the list ,if not already added
            if (sf.proxyConfigList.indexOf(proxyConfig) === -1) {
                sf.proxyConfigList.push(proxyConfig);
            }
        }
    }
    callback();

};

TestExecutor.prototype.setupProxy = function(callback) {

    // If set from command line
    if (sf.args.startProxyServer === true || sf.args.startProxyServer === undefined) {

        testExecutor.populateProxyConfigList(function () {

            if (sf.proxyConfigList && sf.proxyConfigList.length > 0) {

                testExecutor.logger.info('Number of Proxy servers needed to start:' + sf.proxyConfigList.length);

                async.eachSeries(sf.proxyConfigList, testExecutor.startProxy, function(err) {

                    if (err) {
                        testExecutor.logger.info('ERROR !! Failed to start proxy servers..');
                    } else {
                        testExecutor.logger.info('Started all proxy servers..Now running tests\n\n');
                    }
                    callback();

                });

            } else {
                callback();
            }
        });

    } else {
        callback();
    }

};

TestExecutor.prototype.startTest = function() {
    testExecutor.getTests(function() {
        parallelCount = parseInt(sf.parallel, 10);
        if (isNaN(parallelCount) || (parallelCount <= 0)) {
            parallelCount = 1;
        }
        testExecutor.setupProxy(function() {
            testExecutor.setupTestQueues(function() {
                testExecutor.runTests(testQueues, parallelCount);
            });
        });

    });

};

TestExecutor.prototype.executeTests = function () {
    var hub;

    // get all wd sessions if applicable (based on reuseSession flag)
    if (sf.reuseSession) {
        hub = new WdSession(sf.config);
        hub.getSessions(sf, function (error, sf, arrSessions) {
            if (error) {
                // logger.error('No sessions found..'); TODO  search for this msg
                process.exit(1);
            }
            wdSessions = arrSessions;
            testExecutor.startTest();
        });
    } else {
        testExecutor.startTest();
    }

};

module.exports = TestExecutor;<commit_msg>Fixing callback in test executor<commit_after>/*jslint forin:true sub:true anon:true, sloppy:true, stupid:true nomen:true, node:true continue:true*/

/*
 * Copyright (c) 2012, Yahoo! Inc. All rights reserved.
 * Copyrights licensed under the New BSD License.
 * See the accompanying LICENSE file for terms.
 */
var log4js = require("log4js");
var SessionFactory = require("./sessionfactory");
var ReportManager = require("../util/reportmanager");
var FileUtil = require("../util/fileutil");
var WdSession = require("../session/wdsession");
var TestSession = require("../session/testsession");
var ProxyManager = require("../proxy/proxymanager");
var clone = require('clone');
var path = require("path");
var os = require("os");
var fs = require("fs");
var async = require("async");

var sf;
var testExecutor;
var curSessionCount;
var totalSessionCount;
var wdSessions;
var parallelCount;
var tests;
var testQueues;

function TestExecutor(sessionFactory) {

    sf = sessionFactory;

    this.logger = log4js.getLogger("TestExecutor");
    testExecutor = this;
    tests = [];
    wdSessions = [];
    testQueues = [];
    curSessionCount = 0;
    totalSessionCount = 0;
    parallelCount = 0;

}

TestExecutor.prototype.writeReportForDescriptor = function(testSession, callback) {

    var descriptor,
        testSessionsArr,
        currTime,
        reportObj,
        reportManager;

    for (descriptor in sf.descriptorObj) {

        if (descriptor === testSession.descriptorPath) {
            // Store testSessions array for each descriptor in testSessionMap
            if (sf.testSessionMap[descriptor]) {
                testSessionsArr = sf.testSessionMap[descriptor];
            } else {
                testSessionsArr = [];
            }
            testSessionsArr.push(testSession);

            sf.testSessionMap[descriptor] = testSessionsArr;

            sf.descriptorObj[descriptor].testSessionCount -= 1;
            if (sf.descriptorObj[descriptor].testSessionCount === 0) {

                sf.timeReportObj[testSession.descriptorPath].endTime = Date.now(); // TODO Is endTime required ???
                sf.timeReportObj[testSession.descriptorPath].timeTaken =
                    ((sf.timeReportObj[testSession.descriptorPath].endTime - sf.timeReportObj[testSession.descriptorPath].startTime) / 1000).toFixed(2);

                testExecutor.logger.info('Time taken to run descriptor-' + testSession.descriptorPath + ' = ' + sf.timeReportObj[testSession.descriptorPath].timeTaken);

                testExecutor.logger.info('All tests over for descriptor:' + testSession.descriptorPath);
                reportObj = {
                    "reportFolder" : global.reportFolder,
                    "arrTestSessions" : sf.testSessionMap[descriptor],
                    "descriptor" : testSession.descriptorPath,
                    "reuseSession" : sf.reuseSession,
                    "testSuiteName" : sf.descriptorObj[descriptor].testSuiteName,
                    "driver" : sf.driver,
                    "browser" : sf.browser,
                    "group" : sf.args.group,
                    "testName" : sf.args.testName

                };
                reportManager = new ReportManager(reportObj);
                reportManager.totalTimeTaken = sf.timeReportObj[testSession.descriptorPath].timeTaken;
                reportManager.writeReports();

            }

        }
    }
    callback();
};

TestExecutor.prototype.startProxy = function(proxyConfigPath, callback) {

    //TODO - move this to index.js
    if (os.type() === "Darwin") {
        global.hostname = "localhost";
    } else {
        global.hostname = os.hostname();
    }

    testExecutor.logger.info('Starting proxy server : ' + proxyConfigPath);

    var proxyManager = new ProxyManager(path.resolve(global.workingDirectory, proxyConfigPath),sf.config);

    proxyManager.runRouterProxy(sf.config.minPort, sf.config.maxPort, global.hostname, function(proxyHost) {

        if (proxyHost) {
            if (proxyHost.indexOf("Error") === -1) {
                testExecutor.logger.info("Running Proxy Server at " + proxyHost + ' for :::' + proxyConfigPath);
                global.routerMap[proxyConfigPath] = proxyHost;
            } else {
                testExecutor.logger.info("Unable to Start Proxy, " + proxyHost);
                testExecutor.logger.info("Running Tests Without Proxy! ");
            }
        } else {
            testExecutor.logger.info("Some error while starting proxy");
            //TODO - What message to show here??
        }

    });

    setTimeout(callback, 500);

};

TestExecutor.prototype.runNextTest = function(testQueue) {

    var testSession,
        testSessionTimeArr = [];

    if (testQueue.curIndex === testQueue.sessions.length) {
        return; // all done with this queue
    }
    testSession = testQueue.sessions[testQueue.curIndex];

    var thisSession = testQueue.sessions[testQueue.curIndex];

    testQueue.curIndex += 1;
    // If first test session is starting for the descriptor, note start time
    if (!sf.timeReportObj[testSession.descriptorPath]) {
        sf.timeReportObj[testSession.descriptorPath] = [];
        sf.timeReportObj[testSession.descriptorPath].startTime = Date.now();
    }

    testSession.runTest(function (error) {

        if (error) {
            var obj = {};
            obj.error = error;
            thisSession.driver.reports.addReport(obj);
            testExecutor.logger.debug("Error : " + error);
        }

        testExecutor.logger.trace("Run Test :" + curSessionCount + "==" + totalSessionCount);
        thisSession.endTime = Date.now();

        // Write report per descriptor ( if all testsessions for the descriptor ( to which the current test session belongs ) are run )

        if (sf.timeReportObj[thisSession.descriptorPath].testSessionTimeArr) {
            testSessionTimeArr = sf.timeReportObj[thisSession.descriptorPath].testSessionTimeArr;
        } else {
            testSessionTimeArr = {};
        }

        testSessionTimeArr[thisSession.args.testName] = {};

        testSessionTimeArr[thisSession.args.testName].timeTaken = ((thisSession.endTime - thisSession.startTime) / 1000).toFixed(2);
        sf.timeReportObj[thisSession.descriptorPath].testSessionTimeArr = testSessionTimeArr;

        testExecutor.logger.info('Time taken to run - ' + thisSession.descriptorPath + '-' + thisSession.args.testName + ' is::' +
            testSessionTimeArr[thisSession.args.testName].timeTaken);

        testExecutor.writeReportForDescriptor(thisSession, function() {
            curSessionCount += 1;
            if (curSessionCount === totalSessionCount) {
                testExecutor.logger.trace("Done with all the sessions");
                sf.tearDown(testQueue, wdSessions);
            } else {
                testExecutor.logger.trace("Calling Next Test : " + curSessionCount);
                testExecutor.runNextTest(testQueue);
            }
        });

    });
};

TestExecutor.prototype.runTests = function(testQueues, parallelCount) {
    var i, j;
    for (i = 0; i < testQueues.length; i += 1) {
        // start running as many sessions as we can in parallel as specified
        for (j = 0; j < parallelCount; j += 1) {
            testExecutor.runNextTest(testQueues[i]);
        }
    }

};

TestExecutor.prototype.setupTestQueues = function(callback) {

    var test,
        browsers,
        i,
        j;
    function incrementTestSessionCount(test) {
        if (test.descriptorPath) {
            if (sf.descriptorObj[test.descriptorPath]) {
                sf.descriptorObj[test.descriptorPath].testSessionCount += 1;
            } else {
                sf.descriptorObj[test.descriptorPath].testSessionCount = 1;
            }

        }
    }

    // there may be more than one independent queue that can always run in parallel
    if (wdSessions.length > 0) {

        parallelCount = 1; // when reusing sessions, items in a single queue cannot run in parallel
        // every wd session gets its own queue
        for (i = 0; i < wdSessions.length; i += 1) {
            testQueues[i] = {curIndex: 0, sessions: []};
            for (j = 0; j < tests.length; j += 1) {
                test = clone(tests[j]);

                // If proxy set to true or reuseSession set to false , ignore reuseSession
                if (test.startProxyServer === true || test.reuseSession === false) {
                    testQueues[i].sessions.push(new TestSession(sf.config, test));
                } else {
                    testQueues[i].sessions.push(new TestSession(sf.config, test, wdSessions[i]));
                }
                incrementTestSessionCount(test);

            }
            totalSessionCount += tests.length;
        }
    } else {
        // when not reusing sessions, a single queue contains all the items
        // parallelism is controlled by the "parallel" argument passed by the user
        testQueues[0] = {curIndex: 0, sessions: []};

        for (i = 0; i < tests.length; i += 1) {
            browsers = sf.getBrowsers(tests[i]);
            for (j = 0; j < browsers.length; j += 1) {
                test = clone(tests[i]);
                test.browser = browsers[j];
                testQueues[0].sessions.push(new TestSession(sf.config, test));
                incrementTestSessionCount(test);
            }
            totalSessionCount += browsers.length;

        }

    }
    testExecutor.logger.info("Total test sessions: " + totalSessionCount);
    callback();

};

TestExecutor.prototype.getTests = function(callback) {

    var testParams,
        test,
        i;

    if (sf.arrDescriptor) {

        tests = sf.getFactoryTests();
        if (tests.length === 0) {
            sf.tearDown({}, null);
        }
    } else if (sf.tests) {
        for (i = 0; i < sf.tests.length; i += 1) {
            testParams = clone(sf.args);
            testParams.test = sf.tests[i];
            // convert the cmd line test to look like a descriptor test
            test = {
                config : {},
                params : testParams,
                testName : "Default",
                driver : sf.args.driver,
                controller : sf.args.controller,
                browser : sf.browser
            };
            tests.push(test);
        }
    } else {
        // convert the cmd line test to look like a descriptor test
        test = {
            config: {},
            params : sf.args,
            testName : "Default",
            driver : sf.args.driver,
            controller : sf.args.controller,
            browser : sf.browser
        };
        test.params.lib = sf.args.lib;
        tests.push(test);
    }

    callback();

};

TestExecutor.prototype.populateProxyConfigList = function(callback) {

    var i,
        proxyConfig;

    // Get how many unique proxy servers we need to start
    for (i = 0; i < tests.length; i += 1) {

        proxyConfig = undefined;

        if (tests[i].startProxyServer === false) {
            continue;
        }

        // If test has routerProxyConfig
        if (tests[i].proxyConfig) {

            proxyConfig = tests[i].proxyConfig;

            if (tests[i].relativePath) {
                proxyConfig = path.resolve(global.workingDirectory, tests[i].relativePath, proxyConfig);
            } else {
                proxyConfig = path.resolve(global.workingDirectory, proxyConfig);
            }

        } else if (sf.args.routerProxyConfig) { // If proxyConfig is passed as an argument
            proxyConfig = path.resolve(global.workingDirectory, sf.args.routerProxyConfig);
        }

        if (proxyConfig) {

            tests[i].resolvedProxyConfigPath = proxyConfig;
            // Add routerConfig to the list ,if not already added
            if (sf.proxyConfigList.indexOf(proxyConfig) === -1) {
                sf.proxyConfigList.push(proxyConfig);
            }
        }
    }
    callback();

};

TestExecutor.prototype.setupProxy = function(callback) {

    // If set from command line
    if (sf.args.startProxyServer === true || sf.args.startProxyServer === undefined) {

        testExecutor.populateProxyConfigList(function () {

            if (sf.proxyConfigList && sf.proxyConfigList.length > 0) {

                testExecutor.logger.info('Number of Proxy servers needed to start:' + sf.proxyConfigList.length);

                async.eachSeries(sf.proxyConfigList, testExecutor.startProxy, function(err) {

                    if (err) {
                        testExecutor.logger.info('ERROR !! Failed to start proxy servers..');
                    } else {
                        testExecutor.logger.info('Started all proxy servers..Now running tests\n\n');
                    }
                    callback();

                });

            } else {
                callback();
            }
        });

    } else {
        callback();
    }

};

TestExecutor.prototype.startTest = function() {
    testExecutor.getTests(function() {
        parallelCount = parseInt(sf.parallel, 10);
        if (isNaN(parallelCount) || (parallelCount <= 0)) {
            parallelCount = 1;
        }
        testExecutor.setupProxy(function() {
            testExecutor.setupTestQueues(function() {
                testExecutor.runTests(testQueues, parallelCount);
            });
        });

    });

};

TestExecutor.prototype.executeTests = function () {
    var hub;

    // get all wd sessions if applicable (based on reuseSession flag)
    if (sf.reuseSession) {
        hub = new WdSession(sf.config);
        hub.getSessions(function (error, arrSessions) {
            if (error) {
                // logger.error('No sessions found..'); TODO  search for this msg
                process.exit(1);
            }
            wdSessions = arrSessions;
            testExecutor.startTest();
        });
    } else {
        testExecutor.startTest();
    }

};

module.exports = TestExecutor;<|endoftext|>