<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

var assert = require('assert');
var globalTimers = {
    setTimeout: require('timers').setTimeout,
    clearTimeout: require('timers').clearTimeout,
    now: Date.now
};
var globalRandom = Math.random;
var net = require('net');
var format = require('util').format;
var extend = require('xtend');

var inherits = require('util').inherits;
var EventEmitter = require('events').EventEmitter;

var nullLogger = require('./null-logger.js');
var EndpointHandler = require('./endpoint-handler.js');
var TChannelRequest = require('./request');
var TChannelServiceNameHandler = require('./service-name-handler');
var errors = require('./errors');

var TChannelConnection = require('./connection');
var TChannelPeers = require('./peers');

var TracingAgent = require('./trace/agent');

// TODO restore spying
// var Spy = require('./v2/spy');
// var dumpEnabled = /\btchannel_dump\b/.test(process.env.NODE_DEBUG || '');

function TChannel(options) {
    if (!(this instanceof TChannel)) {
        return new TChannel(options);
    }

    var self = this;
    EventEmitter.call(self);

    self.options = extend({
        timeoutCheckInterval: 1000,
        timeoutFuzz: 100,
        // TODO: maybe we should always add pid to user-supplied?
        processName: format('%s[%s]', process.title, process.pid)
    }, options);

    self.requestDefaults = extend({
        timeout: TChannelRequest.defaultTimeout
    }, self.options.requestDefaults);

    self.logger = self.options.logger || nullLogger;
    self.random = self.options.random || globalRandom;
    self.timers = self.options.timers || globalTimers;

    // Filled in by the listen call:
    self.host = null;
    self.requestedPort = null;

    // Filled in by listening event:
    self.hostPort = null;

    // name of the service running over this channel
    self.serviceName = '';
    if (self.options.serviceName) {
        self.serviceName = self.options.serviceName;
        self.requestDefaults.serviceName = self.serviceName;
        delete self.options.serviceName;
    }

    // populated by makeSubChannel
    self.topChannel = null;
    self.subChannels = self.serviceName ? null : {};

    // how to handle incoming requests
    if (!self.options.handler) {
        if (!self.serviceName) {
            self.handler = TChannelServiceNameHandler(self);
        } else {
            self.handler = EndpointHandler(self.serviceName);
        }
    } else {
        self.handler = self.options.handler;
        delete self.options.handler;
    }

    // populated by:
    // - manually api (.peers.add etc)
    // - incoming connections on any listening socket
    self.peers = TChannelPeers(self, self.options);

    // TChannel advances through the following states.
    self.listened = false;
    self.listening = false;
    self.destroyed = false;

    if (self.options.trace) {
        self.tracer = new TracingAgent({
            logger: self.logger,
            forceTrace: self.options.forceTrace,
            serviceName: self.options.tracingServiceName,
            reporter: self.options.traceReporter
        });

        if (self.requestDefaults.trace !== false) {
            self.requestDefaults.trace = true;
        }
    }

    // lazily created by .getServer (usually from .listen)
    self.serverSocket = null;
    self.serverConnections = null;
}
inherits(TChannel, EventEmitter);

TChannel.prototype.getServer = function getServer() {
    var self = this;
    if (self.serverSocket) {
        return self.serverSocket;
    }

    self.serverConnections = Object.create(null);
    self.serverSocket = net.createServer(onServerSocketConnection);
    self.serverSocket.on('listening', onServerSocketListening);
    self.serverSocket.on('error', onServerSocketError);

    return self.serverSocket;

    function onServerSocketConnection(sock) {
        self.onServerSocketConnection(sock);
    }

    function onServerSocketListening() {
        self.onServerSocketListening();
    }

    function onServerSocketError(err) {
        self.onServerSocketError(err);
    }
};

TChannel.prototype.onServerSocketConnection = function onServerSocketConnection(sock) {
    var self = this;

    if (self.destroyed) {
        self.logger.error('got incoming socket whilst destroyed', {
            remoteAddr: sock.remoteAddr,
            remotePort: sock.remotePort,
            hostPort: self.hostPort
        });
        return;
    }

    var remoteAddr = sock.remoteAddress + ':' + sock.remotePort;
    var conn = new TChannelConnection(self, sock, 'in', remoteAddr);

    conn.on('span', function handleSpanFromConn(span) {
        self.tracer.report(span);
    });

    if (self.serverConnections[remoteAddr]) {
        var oldConn = self.serverConnections[remoteAddr];
        oldConn.resetAll(errors.SocketClosedError({
            reason: 'duplicate remoteAddr incoming conn'
        }));
        delete self.serverConnections[remoteAddr];
    }

    sock.on('close', onSocketClose);

    self.serverConnections[remoteAddr] = conn;
    self.emit('connection', conn);

    function onSocketClose() {
        delete self.serverConnections[remoteAddr];
    }
};

TChannel.prototype.onServerSocketListening = function onServerSocketListening() {
    var self = this;

    if (self.destroyed) {
        self.logger.error('got serverSocket listen whilst destroyed', {
            requestHostPort: self.host + ':' + self.requestedPort,
            hostPort: self.host + ':' + self.serverSocket.address().port
        });
        return;
    }

    var address = self.serverSocket.address();
    self.hostPort = self.host + ':' + address.port;
    self.listening = true;

    if (self.subChannels) {
        Object.keys(self.subChannels).forEach(function each(serviceName) {
            var chan = self.subChannels[serviceName];
            if (!chan.hostPort) {
                chan.hostPort = self.hostPort;
            }
        });
    }

    self.emit('listening');
};

TChannel.prototype.onServerSocketError = function onServerSocketError(err) {
    var self = this;

    if (err.code === 'EADDRINUSE') {
        err = errors.TChannelListenError(err, {
            requestedPort: self.requestedPort,
            host: self.host
        });
    }
    self.logger.error('server socket error', {
        err: err,
        requestedPort: self.requestedPort,
        host: self.host,
        hostPort: self.hostPort || null
    });
    self.emit('error', err);
};

TChannel.prototype.makeSubChannel = function makeSubChannel(options) {
    var self = this;
    if (!options) options = {};
    assert(!self.serviceName, 'arbitrary-depth sub channels are unsupported');
    assert(options.serviceName, 'must specify serviceName');
    assert(!self.subChannels[options.serviceName], 'duplicate sub channel creation');
    var opts = extend(self.options);
    var keys = Object.keys(options);
    for (var i = 0; i < keys.length; i++) {
        switch (keys[i]) {
            case 'peers':
                break;
            default:
                opts[keys[i]] = options[keys[i]];
        }
    }
    var chan = TChannel(opts);
    chan.topChannel = self;
    if (options.peers) {
        for (i = 0; i < options.peers.length; i++) {
            if (typeof options.peers[i] === 'string') {
                chan.peers.addPeer(self.peers.add(options.peers[i]));
            } else {
                chan.peers.addPeer(options.peers[i]);
            }
        }
    }
    self.subChannels[chan.serviceName] = chan;

    if (self.hostPort) {
        chan.hostPort = self.hostPort;
    }

    return chan;
};

TChannel.prototype.listen = function listen(port, host, callback) {
    // Note:
    // - 0 is a valid port number, indicating that the system must assign an
    //   available ephemeral port
    // - 127.0.0.1 is a valid host, primarily for testing
    var self = this;
    assert(!self.listened, 'TChannel can only listen once');
    assert(typeof host === 'string', 'TChannel requires host argument');
    assert(typeof port === 'number', 'TChannel must listen with numeric port');
    assert(host !== '0.0.0.0', 'TChannel must listen with externally visible host');
    self.listened = true;
    self.requestedPort = port;
    self.host = host;
    self.getServer().listen(port, host, callback);
};

TChannel.prototype.register = function register(name, handler) {
    var self = this;

    var handlerType = self.handler && self.handler.type;

    switch (handlerType) {
        case 'tchannel.endpoint-handler':
            self.handler.register(name, handler);
            break;

        case 'tchannel.service-name-handler':
            throw errors.TopLevelRegisterError();

        default:
            throw errors.InvalidHandlerForRegister({
                handlerType: handlerType,
                handler: self.handler
            });
    }
};

TChannel.prototype.address = function address() {
    var self = this;
    if (self.serverSocket) {
        return self.serverSocket.address() || null;
    } else if (self.topChannel) {
        return self.topChannel.address();
    } else {
        return null;
    }
};

TChannel.prototype.request = function channelRequest(options) {
    var self = this;
    assert(!self.destroyed, 'cannot request() to destroyed tchannel');

    var prop;
    var opts = {};
    // jshint forin:false
    for (prop in self.requestDefaults) {
        opts[prop] = self.requestDefaults[prop];
    }
    if (options) {
        for (prop in options) {
            opts[prop] = options[prop];
        }
    }
    // jshint forin:true

    if (!opts.service && opts.serviceName) {
        opts.service = opts.serviceName;
    }

    if (!self.serviceName && !opts.host) {
        if (opts.service &&
            self.subChannels &&
            self.subChannels[opts.service]) {
            return self.subChannels[opts.service].request(opts);
        } else {
            throw errors.TopLevelRequestError();
        }
    }

    var req = null;
    if (opts.streamed) {
        req = self.peers.request(null, opts);
    } else {
        req = new TChannelRequest(self, opts);
    }
    self.emit('request', req);
    return req;
};

TChannel.prototype.quit = // to provide backward compatibility.
TChannel.prototype.close = function close(callback) {
    var self = this;
    assert(!self.destroyed, 'TChannel double close');
    self.destroyed = true;

    var counter = 1;

    if (self.serverSocket) {
        ++counter;
        if (self.serverSocket.address()) {
            closeServerSocket();
        } else {
            self.serverSocket.once('listening', closeServerSocket);
        }
    }

    if (self.serverConnections) {
        var incomingConns = Object.keys(self.serverConnections);
        for (var i = 0; i < incomingConns.length; i++) {
            ++counter;
            var incomingConn = self.serverConnections[incomingConns[i]];
            incomingConn.close(onClose);
        }
    }

    if (self.subChannels) {
        var serviceNames = Object.keys(self.subChannels);
        serviceNames.forEach(function each(serviceName) {
            var svcchan = self.subChannels[serviceName];
            if (!svcchan.destroyed) {
                counter++;
                svcchan.close(onClose);
            }
        });
    }

    self.peers.close(onClose);

    function closeServerSocket() {
        self.serverSocket.once('close', onClose);
        self.serverSocket.close();
    }

    function onClose() {
        if (--counter <= 0) {
            if (counter < 0) {
                self.logger.error('closed more channel sockets than expected', {
                    counter: counter
                });
            }
            if (typeof callback === 'function') {
                callback();
            }
        }
    }
};

module.exports = TChannel;
<commit_msg>Short-circuit request federation when direct-host specified<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

var assert = require('assert');
var globalTimers = {
    setTimeout: require('timers').setTimeout,
    clearTimeout: require('timers').clearTimeout,
    now: Date.now
};
var globalRandom = Math.random;
var net = require('net');
var format = require('util').format;
var extend = require('xtend');

var inherits = require('util').inherits;
var EventEmitter = require('events').EventEmitter;

var nullLogger = require('./null-logger.js');
var EndpointHandler = require('./endpoint-handler.js');
var TChannelRequest = require('./request');
var TChannelServiceNameHandler = require('./service-name-handler');
var errors = require('./errors');

var TChannelConnection = require('./connection');
var TChannelPeers = require('./peers');

var TracingAgent = require('./trace/agent');

// TODO restore spying
// var Spy = require('./v2/spy');
// var dumpEnabled = /\btchannel_dump\b/.test(process.env.NODE_DEBUG || '');

function TChannel(options) {
    if (!(this instanceof TChannel)) {
        return new TChannel(options);
    }

    var self = this;
    EventEmitter.call(self);

    self.options = extend({
        timeoutCheckInterval: 1000,
        timeoutFuzz: 100,
        // TODO: maybe we should always add pid to user-supplied?
        processName: format('%s[%s]', process.title, process.pid)
    }, options);

    self.requestDefaults = extend({
        timeout: TChannelRequest.defaultTimeout
    }, self.options.requestDefaults);

    self.logger = self.options.logger || nullLogger;
    self.random = self.options.random || globalRandom;
    self.timers = self.options.timers || globalTimers;

    // Filled in by the listen call:
    self.host = null;
    self.requestedPort = null;

    // Filled in by listening event:
    self.hostPort = null;

    // name of the service running over this channel
    self.serviceName = '';
    if (self.options.serviceName) {
        self.serviceName = self.options.serviceName;
        self.requestDefaults.serviceName = self.serviceName;
        delete self.options.serviceName;
    }

    // populated by makeSubChannel
    self.topChannel = null;
    self.subChannels = self.serviceName ? null : {};

    // how to handle incoming requests
    if (!self.options.handler) {
        if (!self.serviceName) {
            self.handler = TChannelServiceNameHandler(self);
        } else {
            self.handler = EndpointHandler(self.serviceName);
        }
    } else {
        self.handler = self.options.handler;
        delete self.options.handler;
    }

    // populated by:
    // - manually api (.peers.add etc)
    // - incoming connections on any listening socket
    self.peers = TChannelPeers(self, self.options);

    // TChannel advances through the following states.
    self.listened = false;
    self.listening = false;
    self.destroyed = false;

    if (self.options.trace) {
        self.tracer = new TracingAgent({
            logger: self.logger,
            forceTrace: self.options.forceTrace,
            serviceName: self.options.tracingServiceName,
            reporter: self.options.traceReporter
        });

        if (self.requestDefaults.trace !== false) {
            self.requestDefaults.trace = true;
        }
    }

    // lazily created by .getServer (usually from .listen)
    self.serverSocket = null;
    self.serverConnections = null;
}
inherits(TChannel, EventEmitter);

TChannel.prototype.getServer = function getServer() {
    var self = this;
    if (self.serverSocket) {
        return self.serverSocket;
    }

    self.serverConnections = Object.create(null);
    self.serverSocket = net.createServer(onServerSocketConnection);
    self.serverSocket.on('listening', onServerSocketListening);
    self.serverSocket.on('error', onServerSocketError);

    return self.serverSocket;

    function onServerSocketConnection(sock) {
        self.onServerSocketConnection(sock);
    }

    function onServerSocketListening() {
        self.onServerSocketListening();
    }

    function onServerSocketError(err) {
        self.onServerSocketError(err);
    }
};

TChannel.prototype.onServerSocketConnection = function onServerSocketConnection(sock) {
    var self = this;

    if (self.destroyed) {
        self.logger.error('got incoming socket whilst destroyed', {
            remoteAddr: sock.remoteAddr,
            remotePort: sock.remotePort,
            hostPort: self.hostPort
        });
        return;
    }

    var remoteAddr = sock.remoteAddress + ':' + sock.remotePort;
    var conn = new TChannelConnection(self, sock, 'in', remoteAddr);

    conn.on('span', function handleSpanFromConn(span) {
        self.tracer.report(span);
    });

    if (self.serverConnections[remoteAddr]) {
        var oldConn = self.serverConnections[remoteAddr];
        oldConn.resetAll(errors.SocketClosedError({
            reason: 'duplicate remoteAddr incoming conn'
        }));
        delete self.serverConnections[remoteAddr];
    }

    sock.on('close', onSocketClose);

    self.serverConnections[remoteAddr] = conn;
    self.emit('connection', conn);

    function onSocketClose() {
        delete self.serverConnections[remoteAddr];
    }
};

TChannel.prototype.onServerSocketListening = function onServerSocketListening() {
    var self = this;

    if (self.destroyed) {
        self.logger.error('got serverSocket listen whilst destroyed', {
            requestHostPort: self.host + ':' + self.requestedPort,
            hostPort: self.host + ':' + self.serverSocket.address().port
        });
        return;
    }

    var address = self.serverSocket.address();
    self.hostPort = self.host + ':' + address.port;
    self.listening = true;

    if (self.subChannels) {
        Object.keys(self.subChannels).forEach(function each(serviceName) {
            var chan = self.subChannels[serviceName];
            if (!chan.hostPort) {
                chan.hostPort = self.hostPort;
            }
        });
    }

    self.emit('listening');
};

TChannel.prototype.onServerSocketError = function onServerSocketError(err) {
    var self = this;

    if (err.code === 'EADDRINUSE') {
        err = errors.TChannelListenError(err, {
            requestedPort: self.requestedPort,
            host: self.host
        });
    }
    self.logger.error('server socket error', {
        err: err,
        requestedPort: self.requestedPort,
        host: self.host,
        hostPort: self.hostPort || null
    });
    self.emit('error', err);
};

TChannel.prototype.makeSubChannel = function makeSubChannel(options) {
    var self = this;
    if (!options) options = {};
    assert(!self.serviceName, 'arbitrary-depth sub channels are unsupported');
    assert(options.serviceName, 'must specify serviceName');
    assert(!self.subChannels[options.serviceName], 'duplicate sub channel creation');
    var opts = extend(self.options);
    var keys = Object.keys(options);
    for (var i = 0; i < keys.length; i++) {
        switch (keys[i]) {
            case 'peers':
                break;
            default:
                opts[keys[i]] = options[keys[i]];
        }
    }
    var chan = TChannel(opts);
    chan.topChannel = self;
    if (options.peers) {
        for (i = 0; i < options.peers.length; i++) {
            if (typeof options.peers[i] === 'string') {
                chan.peers.addPeer(self.peers.add(options.peers[i]));
            } else {
                chan.peers.addPeer(options.peers[i]);
            }
        }
    }
    self.subChannels[chan.serviceName] = chan;

    if (self.hostPort) {
        chan.hostPort = self.hostPort;
    }

    return chan;
};

TChannel.prototype.listen = function listen(port, host, callback) {
    // Note:
    // - 0 is a valid port number, indicating that the system must assign an
    //   available ephemeral port
    // - 127.0.0.1 is a valid host, primarily for testing
    var self = this;
    assert(!self.listened, 'TChannel can only listen once');
    assert(typeof host === 'string', 'TChannel requires host argument');
    assert(typeof port === 'number', 'TChannel must listen with numeric port');
    assert(host !== '0.0.0.0', 'TChannel must listen with externally visible host');
    self.listened = true;
    self.requestedPort = port;
    self.host = host;
    self.getServer().listen(port, host, callback);
};

TChannel.prototype.register = function register(name, handler) {
    var self = this;

    var handlerType = self.handler && self.handler.type;

    switch (handlerType) {
        case 'tchannel.endpoint-handler':
            self.handler.register(name, handler);
            break;

        case 'tchannel.service-name-handler':
            throw errors.TopLevelRegisterError();

        default:
            throw errors.InvalidHandlerForRegister({
                handlerType: handlerType,
                handler: self.handler
            });
    }
};

TChannel.prototype.address = function address() {
    var self = this;
    if (self.serverSocket) {
        return self.serverSocket.address() || null;
    } else if (self.topChannel) {
        return self.topChannel.address();
    } else {
        return null;
    }
};

TChannel.prototype.request = function channelRequest(options) {
    var self = this;
    assert(!self.destroyed, 'cannot request() to destroyed tchannel');

    var prop;
    var opts = {};
    // jshint forin:false
    for (prop in self.requestDefaults) {
        opts[prop] = self.requestDefaults[prop];
    }
    if (options) {
        for (prop in options) {
            opts[prop] = options[prop];
        }
    }
    // jshint forin:true

    if (!opts.service && opts.serviceName) {
        opts.service = opts.serviceName;
    }

    if (!self.serviceName && !opts.host) {
        if (opts.service &&
            self.subChannels &&
            self.subChannels[opts.service]) {
            return self.subChannels[opts.service].request(opts);
        } else {
            throw errors.TopLevelRequestError();
        }
    }

    var req = null;
    if (opts.host || // retries are only between hosts
        opts.streamed // streaming retries not yet implemented
    ) {
        req = self.peers.request(null, opts);
    } else {
        req = new TChannelRequest(self, opts);
    }
    self.emit('request', req);
    return req;
};

TChannel.prototype.quit = // to provide backward compatibility.
TChannel.prototype.close = function close(callback) {
    var self = this;
    assert(!self.destroyed, 'TChannel double close');
    self.destroyed = true;

    var counter = 1;

    if (self.serverSocket) {
        ++counter;
        if (self.serverSocket.address()) {
            closeServerSocket();
        } else {
            self.serverSocket.once('listening', closeServerSocket);
        }
    }

    if (self.serverConnections) {
        var incomingConns = Object.keys(self.serverConnections);
        for (var i = 0; i < incomingConns.length; i++) {
            ++counter;
            var incomingConn = self.serverConnections[incomingConns[i]];
            incomingConn.close(onClose);
        }
    }

    if (self.subChannels) {
        var serviceNames = Object.keys(self.subChannels);
        serviceNames.forEach(function each(serviceName) {
            var svcchan = self.subChannels[serviceName];
            if (!svcchan.destroyed) {
                counter++;
                svcchan.close(onClose);
            }
        });
    }

    self.peers.close(onClose);

    function closeServerSocket() {
        self.serverSocket.once('close', onClose);
        self.serverSocket.close();
    }

    function onClose() {
        if (--counter <= 0) {
            if (counter < 0) {
                self.logger.error('closed more channel sockets than expected', {
                    counter: counter
                });
            }
            if (typeof callback === 'function') {
                callback();
            }
        }
    }
};

module.exports = TChannel;
<|endoftext|>


<commit_before>import assert from 'assert';
import Arc from '../index';

describe('javascript', () => {
    describe('for block', () => {
        it('evaluates content n times', () => {
            const engine = new Arc();
            return engine.evaluateString('<% for(var i = 0; i != 3; ++i) { %>
<% } %>').then(result => {
                assert.equal(result.content, '

');
            });
        });
    });

    describe('for block with embedded document', () => {
        it('evaluates content n times', () => {
            const engine = new Arc();
            return engine.evaluateString('<% for(var i = 0; i != 3; ++i) { <:
 :> } %>').then(result => {
                assert.equal(result.content, '

 ');
            });
        });

        it('defines local variable usable in expressions', () => {
            const engine = new Arc();
            return engine.evaluateString('<% for(var i = 0; i != 3; ++i) { <:
:> } %>').then(result => {
                assert.equal(result.content, '<div0/><div1/><div2/>');
            });
        });

        it('local variable overwrites builtin locals', () => {
            const engine = new Arc();
            return engine.evaluateString('<% for(var raw = 0; raw != 3; ++raw) { <:
:> } %>').then(result => {
                assert.equal(result.content, '<div0/><div1/><div2/>');
            });
        });

        it('local variable overwrites data', () => {
            const engine = new Arc();
            return engine.evaluateString('<% for(var val = 0; val != 3; ++val) { <:
:> } %>', { val: 13 }).then(result => {
                assert.equal(result.content, '<div0/><div1/><div2/>');
            });
        });
    });

    describe('for-of block', () => {
        it('evaluates content', () => {
            const engine = new Arc();
            return engine.evaluateString('<% for (var e of array) { <:
${e}
 :> } %>', { array: ['a', 'b', 13]}).then(result => {
                assert.equal(result.content, '
a

b

13
 ');
            });
        });
    });

    describe('variable declaration', () => {
        it('is available in later expressions', () => {
            const engine = new Arc();
            return engine.evaluateString('<% var x = 13; %>${x}').then(result => {
                assert.equal(result.content, '13');
            });
        });
    });
});
<commit_msg>Adding a fun unit test to see if it works on old Node with Babel.<commit_after>import assert from 'assert';
import Arc from '../index';

describe('javascript', () => {
    describe('for block', () => {
        it('evaluates content n times', () => {
            const engine = new Arc();
            return engine.evaluateString('<% for(var i = 0; i != 3; ++i) { %>
<% } %>').then(result => {
                assert.equal(result.content, '

');
            });
        });
    });

    describe('for block with embedded document', () => {
        it('evaluates content n times', () => {
            const engine = new Arc();
            return engine.evaluateString('<% for(var i = 0; i != 3; ++i) { <:
 :> } %>').then(result => {
                assert.equal(result.content, '

 ');
            });
        });

        it('defines local variable usable in expressions', () => {
            const engine = new Arc();
            return engine.evaluateString('<% for(var i = 0; i != 3; ++i) { <:
:> } %>').then(result => {
                assert.equal(result.content, '<div0/><div1/><div2/>');
            });
        });

        it('local variable overwrites builtin locals', () => {
            const engine = new Arc();
            return engine.evaluateString('<% for(var raw = 0; raw != 3; ++raw) { <:
:> } %>').then(result => {
                assert.equal(result.content, '<div0/><div1/><div2/>');
            });
        });

        it('local variable overwrites data', () => {
            const engine = new Arc();
            return engine.evaluateString('<% for(var val = 0; val != 3; ++val) { <:
:> } %>', { val: 13 }).then(result => {
                assert.equal(result.content, '<div0/><div1/><div2/>');
            });
        });
    });

    describe('for-of block', () => {
        it('evaluates content', () => {
            const engine = new Arc();
            return engine.evaluateString('<% for (var e of array) { <:
${e}
 :> } %>', { array: ['a', 'b', 13]}).then(result => {
                assert.equal(result.content, '
a

b

13
 ');
            });
        });
    });

    describe('for-let-of block', () => {
        it('evaluates content', () => {
            const engine = new Arc();
            return engine.evaluateString('<% for (let e of array) { <:
${e}
 :> } %>', { array: ['a', 'b', 13]}).then(result => {
                assert.equal(result.content, '
a

b

13
 ');
            });
        });
    });

    describe('variable declaration', () => {
        it('is available in later expressions', () => {
            const engine = new Arc();
            return engine.evaluateString('<% var x = 13; %>${x}').then(result => {
                assert.equal(result.content, '13');
            });
        });
    });
});
<|endoftext|>


<commit_before>var assert = require('chai').assert;
var fs = require('fs');
var glob = require('glob');
var jsontosass = require('../jsontosass.js');

function removeFiles () {
  glob('test/*.s[ac]ss', function (er, files) {
    files.forEach(function (file) {
      fs.unlink(file);
    });
  });
}

describe('jsontosass', function () {
  after(function () {
    // delete generated test sass files
    removeFiles();
  });
  describe('module', function () {
    it('is present', function () {
      assert.isDefined(jsontosass, 'jsontosass is defined');
    });
    it('is an object', function () {
      assert.isObject(jsontosass, 'jsontosass is an object');
    });
  });
  describe('createColon()', function () {
    it('creates configured spaces before colon', function () {
      jsontosass.mergeOptions({
        prettify: true,
        spaceBeforeColon: 4
      });
      assert.equal(jsontosass.createColon(), '    : ');
    });
    it('creates configured spaces after colon', function () {
      jsontosass.mergeOptions({
        prettify: true,
        spaceAfterColon: 4
      });
      assert.equal(jsontosass.createColon(), ':    ');
    });
  });
  describe('convertObject()', function () {
    beforeEach(function () {
      jsontosass.mergeOptions({
        prettify: false
      });
    });
    it('is present', function () {
      assert.isFunction(jsontosass.convertObject);
    });
    it('creates Sass variable named $key on root level', function () {
      assert.equal(jsontosass.convertObject({
        key: 'value'
      }), '$key:value;');
    });
    it('creates Sass variables named by JSON key for multiple entries', function () {
      assert.equal(jsontosass.convertObject({
        key: 'value',
        key2: 'otherValue'
      }), '$key:value;$key2:otherValue;');
    });
    it('creates Sass map for nested object', function () {
      assert.equal(jsontosass.convertObject({
        key: {
          key2: 'value'
        }
      }), '$key:(key2:value);');
    });
    it('creates Sass list for JSON array', function () {
      assert.equal(jsontosass.convertObject({
        key: [1, 2, 3]
      }), '$key:(1,2,3);');
    });
  });
  describe('convertFile()', function () {
    after(function () {
      removeFiles();
    });
    it('is present', function () {
      assert.isFunction(jsontosass.convertFile);
    });
    it('basic file conversion', function (done) {
      var testFile = 'test/basic.scss';
      jsontosass.convertFile('test/basic.json', testFile, { prettify: false }, function () {
        fs.readFile(testFile, 'utf8', function (err, sass) {
          if (err) throw err;
          assert.equal(sass, '$key:value;');
          done();
        });
      });
    });
    it('extended file conversion', function (done) {
      var testFile = 'test/extended.scss';
      jsontosass.convertFile('test/extended.json', testFile, { prettify: false }, function () {
        fs.readFile(testFile, 'utf8', function (err, sass) {
          if (err) throw err;
          assert.equal(sass, "$key:(inner-key:(1,2,3),some-object:(color-black:#000,font-family:'Helvetica, sans-serif'));");
          done();
        });
      });
    });
  });
  describe('convertFileSync()', function () {
    after(function () {
      removeFiles();
    });
    it('is present', function () {
      assert.isFunction(jsontosass.convertFileSync);
    });
    it('basic file conversion', function () {
      var sass;
      jsontosass.convertFileSync('test/basic.json', 'test/basic.scss', { prettify: false });
      sass = fs.readFileSync('test/basic.scss', 'utf8');
      assert.equal(sass, '$key:value;');
    });
    it('extended file conversion', function () {
      var sass;
      jsontosass.convertFileSync('test/extended.json', 'test/extended.scss', { prettify: false });
      sass = fs.readFileSync('test/extended.scss', 'utf8');
      assert.equal(sass, "$key:(inner-key:(1,2,3),some-object:(color-black:#000,font-family:'Helvetica, sans-serif'));");
    });
  });
  describe('convert()', function () {
    it('is present', function () {
      assert.isFunction(jsontosass.convert);
    });
    it('throws an error when invalid JSON is given', function () {
      assert.throws(function () {
        jsontosass.convert('');
      }, Error);
    });
    it('returns a string', function () {
      assert.typeOf(jsontosass.convert('{}'), 'string');
    });
    it('returns Sass variables in own line when prettify is enabled', function () {
      assert.equal(jsontosass.convert('{"key":"value","key2":"otherValue"}', {
        prettify: true
      }), '$key: value;\n$key2: otherValue;');
    });
    it('return newLines for map variables', function () {
      assert.equal(jsontosass.convert('{"key":{"key2":"value"},"key2":"otherValue"}', {
        prettify: true
      }), '$key: (\n    key2: value\n);\n$key2: otherValue;');
    });
    it('respect default indent', function () {
      assert.equal(jsontosass.convert('{"key":{"key2":"value"}}', {
        prettify: true
      }), '$key: (\n    key2: value\n);');
    });
    it('respect indent with tabs', function () {
      var options = {
        indent: 'tabs',
        prettify: true
      };
      assert.equal(jsontosass.convert('{"key":{"key2":"value"}}', options), '$key: (\n\tkey2: value\n);');
      assert.equal(jsontosass.convert('{"key":{"key2":{"key3":"value"}}}', options), '$key: (\n\tkey2: (\n\t\tkey3: value\n\t)\n);');
    });
    it('generate dashed variables instead of maps', function () {
      var options = {
        indent: 'tabs',
        prettify: true,
        useMaps: false
      };
      assert.equal(jsontosass.convert('{"key":{"key2":"value"}}', options), '$key-key2: value;');
      assert.equal(jsontosass.convert('{"key":{"key2":{"key3":"value"}}}', options), '$key-key2-key3: value;');
      assert.equal(jsontosass.convert('{"key":{"key2":{"key3":[1,2,3]}}}', options), '$key-key2-key3: (1,2,3);');
    });
  });
  describe('options', function () {
    it('false syntax option should throw an error', function () {
      assert.throws(function () {
        jsontosass.convert('{"key":"value"}', {
          syntax: 'wrong-syntax'
        });
      }, Error);
    });
    it('right syntax option but with capital letters should not throw an error', function () {
      assert.doesNotThrow(function () {
        jsontosass.convert('{"key":"value"}', {
          syntax: 'SCSS'
        });
      }, Error);
    });
  });
  describe('Sass syntax', function () {
    it('no semicolon in output', function () {
      assert.isNull(jsontosass.convert('{"key":"value"}', {
        syntax: 'sass'
      }).match(/;/g));
    });
    it('setting prettify to false should prettify anyway', function () {
      assert.equal(jsontosass.convert('{"key":{"key2":"value"}}', {
        syntax: 'sass'
      }), '$key: (\n    key2: value\n)');
    });
    it('basic file conversion', function () {
      var sass;
      jsontosass.convertFile('test/basic.json', 'test/basic.sass', {
        syntax: 'sass'
      }, function () {
        sass = fs.readFileSync('test/basic.sass');
        assert.equal(sass, '$key: value');
      });
    });
    it('extended file conversion', function () {
      var sass;
      jsontosass.convertFile('test/extended.json', 'test/extended.sass', {
        indent: 'tabs',
        syntax: 'sass'
      }, function () {
        sass = fs.readFileSync('test/extended.sass');
        assert.equal(sass, "$key: (\n\tinner-key: (\n\t\t1,\n\t\t2,\n\t\t3\n\t),\n\tsome-object: (\n\t\tcolor-black: #000,\n\t\tfont-family: 'Helvetica, sans-serif'\n\t)\n)");
      });
    });
  });
});
<commit_msg>Added test for convertFile without options<commit_after>var assert = require('chai').assert;
var fs = require('fs');
var glob = require('glob');
var jsontosass = require('../jsontosass.js');

function removeFiles () {
  glob('test/*.s[ac]ss', function (er, files) {
    files.forEach(function (file) {
      fs.unlink(file);
    });
  });
}

describe('jsontosass', function () {
  after(function () {
    // delete generated test sass files
    removeFiles();
  });
  describe('module', function () {
    it('is present', function () {
      assert.isDefined(jsontosass, 'jsontosass is defined');
    });
    it('is an object', function () {
      assert.isObject(jsontosass, 'jsontosass is an object');
    });
  });
  describe('createColon()', function () {
    it('creates configured spaces before colon', function () {
      jsontosass.mergeOptions({
        prettify: true,
        spaceBeforeColon: 4
      });
      assert.equal(jsontosass.createColon(), '    : ');
    });
    it('creates configured spaces after colon', function () {
      jsontosass.mergeOptions({
        prettify: true,
        spaceAfterColon: 4
      });
      assert.equal(jsontosass.createColon(), ':    ');
    });
  });
  describe('convertObject()', function () {
    beforeEach(function () {
      jsontosass.mergeOptions({
        prettify: false
      });
    });
    it('is present', function () {
      assert.isFunction(jsontosass.convertObject);
    });
    it('creates Sass variable named $key on root level', function () {
      assert.equal(jsontosass.convertObject({
        key: 'value'
      }), '$key:value;');
    });
    it('creates Sass variables named by JSON key for multiple entries', function () {
      assert.equal(jsontosass.convertObject({
        key: 'value',
        key2: 'otherValue'
      }), '$key:value;$key2:otherValue;');
    });
    it('creates Sass map for nested object', function () {
      assert.equal(jsontosass.convertObject({
        key: {
          key2: 'value'
        }
      }), '$key:(key2:value);');
    });
    it('creates Sass list for JSON array', function () {
      assert.equal(jsontosass.convertObject({
        key: [1, 2, 3]
      }), '$key:(1,2,3);');
    });
  });
  describe('convertFile()', function () {
    after(function () {
      removeFiles();
    });
    it('is present', function () {
      assert.isFunction(jsontosass.convertFile);
    });
    it('should use defaultOptions when no options are given', function (done) {
      var testFile = 'test/basic.scss';
      jsontosass.convertFile('test/basic.json', testFile, function () {
        fs.readFile(testFile, 'utf8', function (err, sass) {
          if (err) throw err;
          assert.equal(sass, '$key: value;');
          done();
        });
      });
    });
    it('basic file conversion', function (done) {
      var testFile = 'test/basic.scss';
      jsontosass.convertFile('test/basic.json', testFile, { prettify: false }, function () {
        fs.readFile(testFile, 'utf8', function (err, sass) {
          if (err) throw err;
          assert.equal(sass, '$key:value;');
          done();
        });
      });
    });
    it('extended file conversion', function (done) {
      var testFile = 'test/extended.scss';
      jsontosass.convertFile('test/extended.json', testFile, { prettify: false }, function () {
        fs.readFile(testFile, 'utf8', function (err, sass) {
          if (err) throw err;
          assert.equal(sass, "$key:(inner-key:(1,2,3),some-object:(color-black:#000,font-family:'Helvetica, sans-serif'));");
          done();
        });
      });
    });
  });
  describe('convertFileSync()', function () {
    after(function () {
      removeFiles();
    });
    it('is present', function () {
      assert.isFunction(jsontosass.convertFileSync);
    });
    it('basic file conversion', function () {
      var sass;
      jsontosass.convertFileSync('test/basic.json', 'test/basic.scss', { prettify: false });
      sass = fs.readFileSync('test/basic.scss', 'utf8');
      assert.equal(sass, '$key:value;');
    });
    it('extended file conversion', function () {
      var sass;
      jsontosass.convertFileSync('test/extended.json', 'test/extended.scss', { prettify: false });
      sass = fs.readFileSync('test/extended.scss', 'utf8');
      assert.equal(sass, "$key:(inner-key:(1,2,3),some-object:(color-black:#000,font-family:'Helvetica, sans-serif'));");
    });
  });
  describe('convert()', function () {
    it('is present', function () {
      assert.isFunction(jsontosass.convert);
    });
    it('throws an error when invalid JSON is given', function () {
      assert.throws(function () {
        jsontosass.convert('');
      }, Error);
    });
    it('returns a string', function () {
      assert.typeOf(jsontosass.convert('{}'), 'string');
    });
    it('returns Sass variables in own line when prettify is enabled', function () {
      assert.equal(jsontosass.convert('{"key":"value","key2":"otherValue"}', {
        prettify: true
      }), '$key: value;\n$key2: otherValue;');
    });
    it('return newLines for map variables', function () {
      assert.equal(jsontosass.convert('{"key":{"key2":"value"},"key2":"otherValue"}', {
        prettify: true
      }), '$key: (\n    key2: value\n);\n$key2: otherValue;');
    });
    it('respect default indent', function () {
      assert.equal(jsontosass.convert('{"key":{"key2":"value"}}', {
        prettify: true
      }), '$key: (\n    key2: value\n);');
    });
    it('respect indent with tabs', function () {
      var options = {
        indent: 'tabs',
        prettify: true
      };
      assert.equal(jsontosass.convert('{"key":{"key2":"value"}}', options), '$key: (\n\tkey2: value\n);');
      assert.equal(jsontosass.convert('{"key":{"key2":{"key3":"value"}}}', options), '$key: (\n\tkey2: (\n\t\tkey3: value\n\t)\n);');
    });
    it('generate dashed variables instead of maps', function () {
      var options = {
        indent: 'tabs',
        prettify: true,
        useMaps: false
      };
      assert.equal(jsontosass.convert('{"key":{"key2":"value"}}', options), '$key-key2: value;');
      assert.equal(jsontosass.convert('{"key":{"key2":{"key3":"value"}}}', options), '$key-key2-key3: value;');
      assert.equal(jsontosass.convert('{"key":{"key2":{"key3":[1,2,3]}}}', options), '$key-key2-key3: (1,2,3);');
    });
  });
  describe('options', function () {
    it('false syntax option should throw an error', function () {
      assert.throws(function () {
        jsontosass.convert('{"key":"value"}', {
          syntax: 'wrong-syntax'
        });
      }, Error);
    });
    it('right syntax option but with capital letters should not throw an error', function () {
      assert.doesNotThrow(function () {
        jsontosass.convert('{"key":"value"}', {
          syntax: 'SCSS'
        });
      }, Error);
    });
  });
  describe('Sass syntax', function () {
    it('no semicolon in output', function () {
      assert.isNull(jsontosass.convert('{"key":"value"}', {
        syntax: 'sass'
      }).match(/;/g));
    });
    it('setting prettify to false should prettify anyway', function () {
      assert.equal(jsontosass.convert('{"key":{"key2":"value"}}', {
        syntax: 'sass'
      }), '$key: (\n    key2: value\n)');
    });
    it('basic file conversion', function () {
      var sass;
      jsontosass.convertFile('test/basic.json', 'test/basic.sass', {
        syntax: 'sass'
      }, function () {
        sass = fs.readFileSync('test/basic.sass');
        assert.equal(sass, '$key: value');
      });
    });
    it('extended file conversion', function () {
      var sass;
      jsontosass.convertFile('test/extended.json', 'test/extended.sass', {
        indent: 'tabs',
        syntax: 'sass'
      }, function () {
        sass = fs.readFileSync('test/extended.sass');
        assert.equal(sass, "$key: (\n\tinner-key: (\n\t\t1,\n\t\t2,\n\t\t3\n\t),\n\tsome-object: (\n\t\tcolor-black: #000,\n\t\tfont-family: 'Helvetica, sans-serif'\n\t)\n)");
      });
    });
  });
});
<|endoftext|>


<commit_before>const bin = require('../bin');
const pkg = bin.common.res('package');
const webpackConfig = bin({ run: 'test' });

/*!
|* This is a karma config file. For more details
|* @see http://karma-runner.github.io/0.13/config/configuration-file.html
|* @see http://karma-runner.github.io/0.13/config/browsers.html
|* @see https://github.com/webpack/karma-webpack
`*/
module.exports = (config) => {
	const customLaunchers = {
		bs_ie9: {
			base: 'BrowserStack',
			os: 'Windows',
			os_version: 'XP',
			browser: 'ie',
			browser_version: '9.0',
		},
		bs_ie10: {
			base: 'BrowserStack',
			os: 'Windows',
			os_version: '8',
			browser: 'ie',
			browser_version: '10.0',
		},
		bs_ie11: {
			base: 'BrowserStack',
			os: 'Windows',
			os_version: '10',
			browser: 'ie',
			browser_version: '11.0',
		},
		bs_mobile_safari_8: {
			base: 'BrowserStack',
			os: 'ios',
			os_version: '8.3',
			browser: 'iphone',
			real_mobile: false,
		},
		bs_mobile_safari_9: {
			base: 'BrowserStack',
			os: 'ios',
			os_version: '9.1',
			browser: 'iphone',
			real_mobile: false,
		},
		bs_safari: {
			base: 'BrowserStack',
			os: 'OS X',
			os_version: 'El Capitan',
			browser: 'safari',
			browser_version: '9.0',
		},
		bs_firefox: {
			base: 'BrowserStack',
			os: 'Windows',
			os_version: '10',
			browser: 'firefox',
			browser_version: '43.0',
		},
		bs_chrome: {
			base: 'BrowserStack',
			os: 'Windows',
			os_version: '10',
			browser: 'chrome',
			browser_version: '47.0',
		},
	};

	config.set({
		customLaunchers,
		basePath: '',
		port: 9876,
		colors: true,
		autoWatch: false,
		singleRun: false,
		concurrency: 2,
		browserDisconnectTimeout: 10000,
		browserDisconnectTolerance: 3,
		browsers: ['PhantomJS'],
		frameworks: ['mocha', 'sinon-chai', 'fixture', 'phantomjs-shim'],
		reporters: ['spec', 'coverage'],
		files: [{
			pattern: './fixtures/**/*.fixture.*',
			watched: true,
		}, {
			pattern: './specs/**/*.spec.js',
			watched: true,
		}, {
			pattern: '../source/**/*.js',
			watched: true,
		}],
		preprocessors: {
			'../source/**/*.js': ['webpack', 'sourcemap'],
			'./specs/**/*.spec.js': ['webpack', 'sourcemap'],
			'./fixtures/**/*.html': ['html2js'],
			'./fixtures/**/*.json': ['json_fixtures'],
		},
		jsonFixturesPreprocessor: {
			variableName: '__json__',
		},
		webpack: webpackConfig,
		webpackServer: {
			noInfo: true,
		},
		browserStack: {
			project: pkg.name,
			username: process.env.BROWSERSTACK_USERNAME,
			accessKey: process.env.BROWSERSTACK_KEY,
		},
		coverageReporter: {
			dir: './coverage',
			reporters: [
				{ type: 'lcov', subdir: '.' },
				{ type: 'text-summary' },
			],
		},
	});

	if (process.env.TRAVIS) {
		config.browserStack.browsers = Object.keys(customLaunchers);
		config.browserStack.build = process.env.TRAVIS_BUILD_NUMBER;
		config.browserStack.name = process.env.TRAVIS_JOB_NUMBER;
	} else if (process.env.APPVEYOR) {
		config.browserStack.browsers = Object.keys(customLaunchers);
		config.browserStack.build = process.env.APPVEYOR_BUILD_NUMBER;
		config.browserStack.name = process.env.APPVEYOR_JOB_NUMBER;
	}
};
<commit_msg>test: capture & inactivity time<commit_after>const bin = require('../bin');
const pkg = bin.common.res('package');
const webpackConfig = bin({ run: 'test' });

/*!
|* This is a karma config file. For more details
|* @see http://karma-runner.github.io/0.13/config/configuration-file.html
|* @see http://karma-runner.github.io/0.13/config/browsers.html
|* @see https://github.com/webpack/karma-webpack
`*/
module.exports = (config) => {
	const customLaunchers = {
		bs_ie9: {
			base: 'BrowserStack',
			os: 'Windows',
			os_version: 'XP',
			browser: 'ie',
			browser_version: '9.0',
		},
		bs_ie10: {
			base: 'BrowserStack',
			os: 'Windows',
			os_version: '8',
			browser: 'ie',
			browser_version: '10.0',
		},
		bs_ie11: {
			base: 'BrowserStack',
			os: 'Windows',
			os_version: '10',
			browser: 'ie',
			browser_version: '11.0',
		},
		bs_mobile_safari_8: {
			base: 'BrowserStack',
			os: 'ios',
			os_version: '8.3',
			browser: 'iphone',
			real_mobile: false,
		},
		bs_mobile_safari_9: {
			base: 'BrowserStack',
			os: 'ios',
			os_version: '9.1',
			browser: 'iphone',
			real_mobile: false,
		},
		bs_safari: {
			base: 'BrowserStack',
			os: 'OS X',
			os_version: 'El Capitan',
			browser: 'safari',
			browser_version: '9.0',
		},
		bs_firefox: {
			base: 'BrowserStack',
			os: 'Windows',
			os_version: '10',
			browser: 'firefox',
			browser_version: '43.0',
		},
		bs_chrome: {
			base: 'BrowserStack',
			os: 'Windows',
			os_version: '10',
			browser: 'chrome',
			browser_version: '47.0',
			flags: ['--no-sandbox'],
		},
	};

	const settings = {
		customLaunchers,
		basePath: '',
		port: 9876,
		colors: true,
		autoWatch: false,
		singleRun: false,
		concurrency: 2,
		captureTimeout: 240000,
		browserNoActivityTimeout: 240000,
		browserDisconnectTimeout: 10000,
		browserDisconnectTolerance: 3,
		browsers: ['PhantomJS'],
		frameworks: ['mocha', 'sinon-chai', 'fixture', 'phantomjs-shim'],
		reporters: ['spec', 'coverage'],
		files: [{
			pattern: './fixtures/**/*.fixture.*',
			watched: true,
		}, {
			pattern: './specs/**/*.spec.js',
			watched: true,
		}, {
			pattern: '../source/**/*.js',
			watched: true,
		}],
		preprocessors: {
			'../source/**/*.js': ['webpack', 'sourcemap'],
			'./specs/**/*.spec.js': ['webpack', 'sourcemap'],
			'./fixtures/**/*.html': ['html2js'],
			'./fixtures/**/*.json': ['json_fixtures'],
		},
		jsonFixturesPreprocessor: {
			variableName: '__json__',
		},
		webpack: webpackConfig,
		webpackServer: {
			noInfo: true,
		},
		browserStack: {
			project: pkg.name,
			username: process.env.BROWSERSTACK_USERNAME,
			accessKey: process.env.BROWSERSTACK_KEY,
		},
		coverageReporter: {
			dir: './coverage',
			reporters: [
				{ type: 'lcov', subdir: '.' },
				{ type: 'text-summary' },
			],
		},
	};

	if (process.env.TRAVIS) {
		settings.browserStack.browsers = Object.keys(customLaunchers);
		settings.browserStack.build = process.env.TRAVIS_BUILD_NUMBER;
		settings.browserStack.name = process.env.TRAVIS_JOB_NUMBER;
	} else if (process.env.APPVEYOR) {
		settings.browserStack.browsers = Object.keys(customLaunchers);
		settings.browserStack.build = process.env.APPVEYOR_BUILD_NUMBER;
		settings.browserStack.name = process.env.APPVEYOR_JOB_NUMBER;
	}

	config.set(settings);
};
<|endoftext|>


<commit_before>const commonjs = require('rollup-plugin-commonjs');
const includePaths = require('rollup-plugin-includepaths');
const rollupConfig = require('../rollup.config.js');

const version = process.env.npm_package_version;

rollupConfig.plugins.push(
  commonjs(),
  includePaths({
    include: {
      'purify': 'dist/purify.js',
      'purify.min': 'dist/purify.min.js'
    }
  })
);

module.exports = function(config) {
  config.set({
    autoWatch: true,
    basePath: '../',
    frameworks: ['qunit'],
    files: [
      'node_modules/jquery/dist/jquery.js',
      'node_modules/qunit-parameterize/qunit-parameterize.js',
      'test/config/setup.js',
      'test/**/*.spec.js'
    ],

    preprocessors: {
      'src/*.js': ['rollup'],
      'test/**/*.spec.js': ['rollup']
    },

    reporters: ['progress'],

    exclude: [],
    port: 9876,

    browserStack: {
      project: 'DOMPurify',
      username: process.env.BS_USERNAME,
      accessKey: process.env.BS_ACCESSKEY
    },

    rollupPreprocessor: rollupConfig,

    customLaunchers: {
      bs_win81_ie_11: {
        base: 'BrowserStack',
        browser: 'ie',
        browser_version: '11.0',
        os: 'Windows',
        os_version: '8.1'
      },
      bs_win8_ie_10: {
        base: 'BrowserStack',
        browser: 'ie',
        browser_version: '10.0',
        os: 'Windows',
        os_version: '8'
      },
      bs_mavericks_chrome_44: {
        base: 'BrowserStack',
        device: null,
        os: 'OS X',
        browser_version: '44.0',
        browser: 'chrome',
        os_version: 'Mavericks'
      },
      bs_yosemite_firefox_40: {
        base: 'BrowserStack',
        device: null,
        os: 'OS X',
        browser_version: '40.0',
        browser: 'firefox',
        os_version: 'Yosemite'
      },
      bs_sierra_safari_10: {
        base: 'BrowserStack',
        device: null,
        os: 'OS X',
        browser_version: '10.0',
        browser: 'safari',
        os_version: 'Sierra'
      },
      bs_yosemite_safari_8: {
        base: 'BrowserStack',
        device: null,
        os: 'OS X',
        browser_version: '8.0',
        browser: 'safari',
        os_version: 'Yosemite'
      },
      bs_win81_opera_31: {
        base: 'BrowserStack',
        device: null,
        os: 'Windows',
        browser_version: '31',
        browser: 'opera',
        os_version: '8.1'
      },
      bs_win7_firefox_20: {
        base: 'BrowserStack',
        device: null,
        os: 'Windows',
        browser_version: '20.0',
        browser: 'firefox',
        os_version: '7'
      },
      bs_win7_firefox_15: {
        base: 'BrowserStack',
        device: null,
        os: 'Windows',
        browser_version: '15.0',
        browser: 'firefox',
        os_version: '7'
      },
      bs_win81_chrome_22: {
        base: 'BrowserStack',
        device: null,
        os: 'Windows',
        browser_version: '22.0',
        browser: 'chrome',
        os_version: '8.1'
      },
      bs_win10_edge_13: {
        base: 'BrowserStack',
        device: null,
        os: 'Windows',
        browser_version: '13.0',
        browser: 'edge',
        os_version: '10'
      },
      bs_win10_edge_14: {
        base: 'BrowserStack',
        device: null,
        os: 'Windows',
        browser_version: '14.0',
        browser: 'edge',
        os_version: '10'
      },
      bs_win10_firefox_46: {
        base: 'BrowserStack',
        device: null,
        os: 'Windows',
        browser_version: '46.0',
        browser: 'firefox',
        os_version: '10'
      },
      bs_win10_firefox_52: {
        base: 'BrowserStack',
        device: null,
        os: 'Windows',
        browser_version: '52.0',
        browser: 'firefox',
        os_version: '10'
      },
      bs_win10_chrome_50: {
        base: 'BrowserStack',
        device: null,
        os: 'Windows',
        browser_version: '50.0',
        browser: 'chrome',
        os_version: '10'
      },
      bs_win10_chrome_57: {
        base: 'BrowserStack',
        device: null,
        os: 'Windows',
        browser_version: '57.0',
        browser: 'chrome',
        os_version: '10'
      }
    },

    browsers: [
      'bs_win81_ie_11',
      'bs_win8_ie_10',
      'bs_mavericks_chrome_44',
      'bs_yosemite_firefox_40',
      'bs_yosemite_safari_8',
      'bs_sierra_safari_10',
      'bs_win81_opera_31',
      'bs_win7_firefox_20',
      'bs_win7_firefox_15',
      'bs_win81_chrome_22',
      'bs_win10_edge_13',
      'bs_win10_edge_14',
      'bs_win10_firefox_46',
      'bs_win10_firefox_52',
      'bs_win10_chrome_50',
      'bs_win10_chrome_57'
    ],

    browserDisconnectTimeout: 10000,
    browserDisconnectTolerance: 1,
    browserNoActivityTimeout: 240000,
    captureTimeout: 240000,

    plugins: [
      'karma-rollup-plugin',
      'karma-chrome-launcher',
      'karma-browserstack-launcher',
      'karma-firefox-launcher',
      'karma-qunit'
    ],

    singleRun: true,
    colors: true,
    logLevel: config.LOG_INFO
  });
};
<commit_msg>See #224<commit_after>const commonjs = require('rollup-plugin-commonjs');
const includePaths = require('rollup-plugin-includepaths');
const rollupConfig = require('../rollup.config.js');

const version = process.env.npm_package_version;

rollupConfig.plugins.push(
  commonjs(),
  includePaths({
    include: {
      'purify': 'dist/purify.js',
      'purify.min': 'dist/purify.min.js'
    }
  })
);

module.exports = function(config) {
  config.set({
    autoWatch: true,
    basePath: '../',
    frameworks: ['qunit'],
    files: [
      'node_modules/jquery/dist/jquery.js',
      'node_modules/qunit-parameterize/qunit-parameterize.js',
      'test/config/setup.js',
      'test/**/*.spec.js'
    ],

    preprocessors: {
      'src/*.js': ['rollup'],
      'test/**/*.spec.js': ['rollup']
    },

    reporters: ['progress'],

    exclude: [],
    port: 9876,

    browserStack: {
      project: 'DOMPurify',
      username: process.env.BS_USERNAME,
      accessKey: process.env.BS_ACCESSKEY
    },

    rollupPreprocessor: rollupConfig,

    customLaunchers: {
      bs_win81_ie_11: {
        base: 'BrowserStack',
        browser: 'ie',
        browser_version: '11.0',
        os: 'Windows',
        os_version: '8.1'
      },
      bs_win8_ie_10: {
        base: 'BrowserStack',
        browser: 'ie',
        browser_version: '10.0',
        os: 'Windows',
        os_version: '8'
      },
      bs_mavericks_chrome_44: {
        base: 'BrowserStack',
        device: null,
        os: 'OS X',
        browser_version: '44.0',
        browser: 'chrome',
        os_version: 'Mavericks'
      },
      bs_yosemite_firefox_40: {
        base: 'BrowserStack',
        device: null,
        os: 'OS X',
        browser_version: '40.0',
        browser: 'firefox',
        os_version: 'Yosemite'
      },
      bs_sierra_safari_10: {
        base: 'BrowserStack',
        device: null,
        os: 'OS X',
        browser_version: '10.0',
        browser: 'safari',
        os_version: 'Sierra'
      },
      bs_yosemite_safari_8: {
        base: 'BrowserStack',
        device: null,
        os: 'OS X',
        browser_version: '8.0',
        browser: 'safari',
        os_version: 'Yosemite'
      },
      bs_win81_opera_31: {
        base: 'BrowserStack',
        device: null,
        os: 'Windows',
        browser_version: '31',
        browser: 'opera',
        os_version: '8.1'
      },
      bs_win7_firefox_20: {
        base: 'BrowserStack',
        device: null,
        os: 'Windows',
        browser_version: '20.0',
        browser: 'firefox',
        os_version: '7'
      },
      bs_win7_firefox_15: {
        base: 'BrowserStack',
        device: null,
        os: 'Windows',
        browser_version: '15.0',
        browser: 'firefox',
        os_version: '7'
      },
      bs_win81_chrome_22: {
        base: 'BrowserStack',
        device: null,
        os: 'Windows',
        browser_version: '22.0',
        browser: 'chrome',
        os_version: '8.1'
      },
      bs_win10_edge_13: {
        base: 'BrowserStack',
        device: null,
        os: 'Windows',
        browser_version: '13.0',
        browser: 'edge',
        os_version: '10'
      },
      bs_win10_edge_14: {
        base: 'BrowserStack',
        device: null,
        os: 'Windows',
        browser_version: '14.0',
        browser: 'edge',
        os_version: '10'
      },
      bs_win10_firefox_46: {
        base: 'BrowserStack',
        device: null,
        os: 'Windows',
        browser_version: '46.0',
        browser: 'firefox',
        os_version: '10'
      },
      bs_win10_firefox_52: {
        base: 'BrowserStack',
        device: null,
        os: 'Windows',
        browser_version: '52.0',
        browser: 'firefox',
        os_version: '10'
      },
      bs_win10_chrome_50: {
        base: 'BrowserStack',
        device: null,
        os: 'Windows',
        browser_version: '50.0',
        browser: 'chrome',
        os_version: '10'
      },
      bs_win10_chrome_57: {
        base: 'BrowserStack',
        device: null,
        os: 'Windows',
        browser_version: '57.0',
        browser: 'chrome',
        os_version: '10'
      },
      bs_win10_chrome_59: {
        base: 'BrowserStack',
        device: null,
        os: 'Windows',
        browser_version: '59.0',
        browser: 'chrome',
        os_version: '10'
      }
    },

    browsers: [
      'bs_win81_ie_11',
      'bs_win8_ie_10',
      'bs_mavericks_chrome_44',
      'bs_yosemite_firefox_40',
      'bs_yosemite_safari_8',
      'bs_sierra_safari_10',
      'bs_win81_opera_31',
      'bs_win7_firefox_20',
      'bs_win7_firefox_15',
      'bs_win81_chrome_22',
      'bs_win10_edge_13',
      'bs_win10_edge_14',
      'bs_win10_firefox_46',
      'bs_win10_firefox_52',
      'bs_win10_chrome_50',
      'bs_win10_chrome_57',
      'bs_win10_chrome_59'
    ],

    browserDisconnectTimeout: 10000,
    browserDisconnectTolerance: 1,
    browserNoActivityTimeout: 240000,
    captureTimeout: 240000,

    plugins: [
      'karma-rollup-plugin',
      'karma-chrome-launcher',
      'karma-browserstack-launcher',
      'karma-firefox-launcher',
      'karma-qunit'
    ],

    singleRun: true,
    colors: true,
    logLevel: config.LOG_INFO
  });
};
<|endoftext|>


<commit_before>const Jaryn = Object.freeze(Object.create({
  "configFile": "jaryn-config.json",

  /**
   * loadConfig loads a config object from the config file and passes the
   * config into the callback.
   *
   * @param function cb Callback function to execute upon init.
   */
  "loadConfig": function(cb) {
    const config = {"averageMood": 5, "moodCount": 0, "averageEmotion": []};

    this.readJSON({
      "fileName": this.configFile,
      "onSuccess": cb,
      "onFailure": (err) => this.saveConfig(config, cb)
    });
  },

  /**
   * saveConfig saves a config object to the config file.
   *
   * @param object config Config object to save.
   * @param function cb Callback to execute when saved.
  */
  "saveConfig": function(config, cb) {
    this.writeJSON({
      "fileName": this.configFile,
      "data": config,
      "onSuccess": cb,
      "onFailure": (err) => console.log(err)
    });
  },

  /**
   * loadHistory reads the current months history file and passes the data
   * into the provided callback function.
   *
   * @param function cb Callback to execute once history has been loaded.
   */
  "loadHistory": function(cb) {
    this.readJSON({
      "fileName": this.getThisMonthsJSON(),
      "onSuccess": cb,
      "onFailure": (err) => cb([])
    });
  },

  /**
   * This function gets the last five days of historical information.
   *
   * @param Date date The date to start the history count from.
   * @param function cb The callback function to execute.
   */
  "getFiveDayHistory": function(date, cb) {
    this.loadHistory((data) => {
      console.log(data.length);
    });
  },

  /**
   * getThisMonthsJSON is a convenience function to get the current data file.
   */
  "getThisMonthsJSON": function() {
    return this.getJSONForDate(new Date());
  },

  /**
   * This function takes a date, parses the month and year from it
   * and reads the JSON from that months <month>-<year>.json file.
   * The supplied callback is then passed the data and executed.
   *
   * @param Date date The date to get the history file for.
   * @param function cb Callback to execute when name generated.
   */
  "getJSONForDate": function(date, cb) {
    const year = date.getFullYear();
    const month = (date.getMonth() + 1 < 10) ? "0" + (date.getMonth() + 1) : date.getMonth() + 1;

    return year + "-" + month + ".json";
  },

  /**
   * getDataFile gets the data file for the given filename and executes the
   * given callback with the data stored in the file passed in as an argument.
   *
   * readJSON does NOT create a file if it doesn't already exist.
   *
   * @param object obj An object containing the file name and success/failure
   * callback functions.
   */
  "readJSON": function(obj) {
    console.log(`Reading: ${obj.fileName}.`);
    chrome.syncFileSystem.requestFileSystem((fs) => {
      fs.root.getFile(obj.fileName,
        { "create": false },
        (fileEntry) => {
          fileEntry.file((file) => {
            const fileReader = new FileReader();
            fileReader.onload = (e) => {
              obj.onSuccess(JSON.parse(fileReader.result));
            };
            fileReader.readAsText(file);
          });
        }, obj.onFailure);
    });
  },

  /**
   * This writes data to the specified file, creating it if it does not exist.
   * Ensure data is a JSON object!
   *
   * @param object obj An object containing the file name, data and success or
   * failure callback functions.
   */
  "writeJSON": function(obj) {
    console.log(`Writing: ${obj.fileName}.`);
    chrome.syncFileSystem.requestFileSystem((fs) => {
      fs.root.getFile(obj.fileName,
      { "create": true },
      (file) => {
        // Zero out the file contents.
        file.createWriter((writer) => writer.truncate(0));
        // Re-write with new data.
        file.createWriter((writer) => {
          const blob = new Blob([JSON.stringify(obj.data)], { "type": "text/plain" });
          writer.write(blob);
          obj.onSuccess(obj.data);
        });
      }, obj.onFailure);
    });
  },

  /**
   * updateDiary takes a single entry and saves it to the current months
   * history file.
   *
   * @param Object day The data for the day.
   * @param function cb the Callback function to execute.
   */
  "updateDiary": function(day, cb) {
    const fn = this.getThisMonthsJSON();
    const writeData = (data) => {
      data[day.id] = day;

      this.writeJSON({
        "fileName": fn,
        "data": data,
        "onSuccess": cb,
        "onFailure": (err) => console.log(err)
      });
    };

    this.readJSON({
      "fileName": fn,
      "onSuccess": (data) => writeData(data),
      "onFailure": () => writeData([])
    });
  }
}));<commit_msg>Added getConfigFile and begun work on the 5 day history.<commit_after>const Jaryn = Object.freeze(Object.create({
  "getConfigFile": function() {
    return "jaryn-config.json";
  },

  /**
   * loadConfig loads a config object from the config file and passes the
   * config into the callback.
   *
   * @param function cb Callback function to execute upon init.
   */
  "loadConfig": function(cb) {
    const config = {"averageMood": 5, "moodCount": 0, "averageEmotion": []};

    this.readJSON({
      "fileName": this.getConfigFile(),
      "onSuccess": cb,
      "onFailure": (err) => this.saveConfig(config, cb)
    });
  },

  /**
   * saveConfig saves a config object to the config file.
   *
   * @param object config Config object to save.
   * @param function cb Callback to execute when saved.
  */
  "saveConfig": function(config, cb) {
    this.writeJSON({
      "fileName": this.getConfigFile(),
      "data": config,
      "onSuccess": cb,
      "onFailure": (err) => console.log(err)
    });
  },

  /**
   * loadHistory reads the current months history file and passes the data
   * into the provided callback function.
   *
   * @param function cb Callback to execute once history has been loaded.
   */
  "loadHistory": function(cb) {
    this.readJSON({
      "fileName": this.getThisMonthsJSON(),
      "onSuccess": cb,
      "onFailure": (err) => cb([])
    });
  },

  /**
   * This function gets the last five days of historical information.
   *
   * @param Date date The date to start the history count from.
   * @param function cb The callback function to execute.
   */
  "getFiveDayHistory": function(cb) {
    // Get all the keys we want to get.
    const months = new Set();
    const dates = Array.of(0, 1, 2, 3, 4).map((num) => {
      const dayOffset = ((1000*60)*60)*24;
      const now = new Date();
      const year = now.getFullYear();
      const month = now.getMonth();
      const date = now.getDate();

      now.setTime(0);
      now.setYear(year);
      now.setMonth(month);
      now.setDate(date);

      now.setTime(now-(dayOffset*num));
      return now.getTime();
    });

    // Builds a set of month files needed to get the last five days.
    dates.forEach(key => {
      const dt = new Date();
      // I hate that I have to put this here, looks so bad... :(
      dt.setTime(key);
      const year = dt.getFullYear();
      const month = (dt.getMonth() + 1 < 10) ?
        "0" + (dt.getMonth() + 1) :
        dt.getMonth() + 1;
      months.add(year + '-' + month + '.json');
    });

    console.log(months);
  },

  /**
   * getThisMonthsJSON is a convenience function to get the current data file.
   */
  "getThisMonthsJSON": function() {
    return this.getJSONForDate(new Date());
  },

  /**
   * This function takes a date, parses the month and year from it
   * and reads the JSON from that months <month>-<year>.json file.
   * The supplied callback is then passed the data and executed.
   *
   * @param Date date The date to get the history file for.
   * @param function cb Callback to execute when name generated.
   */
  "getJSONForDate": function(date, cb) {
    const year = date.getFullYear();
    const month = (date.getMonth() + 1 < 10) ? "0" + (date.getMonth() + 1) : date.getMonth() + 1;

    return year + "-" + month + ".json";
  },

  /**
   * getDataFile gets the data file for the given filename and executes the
   * given callback with the data stored in the file passed in as an argument.
   *
   * readJSON does NOT create a file if it doesn't already exist.
   *
   * @param object obj An object containing the file name and success/failure
   * callback functions.
   */
  "readJSON": function(obj) {
    console.log(`Reading: ${obj.fileName}.`);
    chrome.syncFileSystem.requestFileSystem((fs) => {
      fs.root.getFile(obj.fileName,
        { "create": false },
        (fileEntry) => {
          fileEntry.file((file) => {
            const fileReader = new FileReader();
            fileReader.onload = (e) => {
              obj.onSuccess(JSON.parse(fileReader.result));
            };
            fileReader.readAsText(file);
          });
        }, obj.onFailure);
    });
  },

  /**
   * This writes data to the specified file, creating it if it does not exist.
   * Ensure data is a JSON object!
   *
   * @param object obj An object containing the file name, data and success or
   * failure callback functions.
   */
  "writeJSON": function(obj) {
    console.log(`Writing: ${obj.fileName}.`);
    chrome.syncFileSystem.requestFileSystem((fs) => {
      fs.root.getFile(obj.fileName,
      { "create": true },
      (file) => {
        // Zero out the file contents.
        file.createWriter((writer) => writer.truncate(0));
        // Re-write with new data.
        file.createWriter((writer) => {
          const blob = new Blob([JSON.stringify(obj.data)], { "type": "text/plain" });
          writer.write(blob);
          obj.onSuccess(obj.data);
        });
      }, obj.onFailure);
    });
  },

  /**
   * updateDiary takes a single entry and saves it to the current months
   * history file.
   *
   * @param Object day The data for the day.
   * @param function cb the Callback function to execute.
   */
  "updateDiary": function(day, cb) {
    const fn = this.getThisMonthsJSON();
    const writeData = (data) => {
      data[day.id] = day;

      this.writeJSON({
        "fileName": fn,
        "data": data,
        "onSuccess": cb,
        "onFailure": (err) => console.log(err)
      });
    };

    this.readJSON({
      "fileName": fn,
      "onSuccess": (data) => writeData(data),
      "onFailure": () => writeData([])
    });
  }
}));<|endoftext|>


<commit_before>// Karma configuration
// http://karma-runner.github.io/0.12/config/configuration-file.html
// Generated on 2014-10-13 using
// generator-karma 0.8.3

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

  config.set({
    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,

    // base path, that will be used to resolve files and exclude
    basePath: '../',

    // testing framework to use (jasmine/mocha/qunit/...)
    frameworks: ['jasmine'],

    // list of files / patterns to load in the browser
    files: [
      'bower_components/modernizr/modernizr.js',
      'bower_components/angular/angular.js',
      'bower_components/angular-mocks/angular-mocks.js',
      'bower_components/angular-animate/angular-animate.js',
      'bower_components/angular-cookies/angular-cookies.js',
      'bower_components/angular-resource/angular-resource.js',
      'bower_components/angular-route/angular-route.js',
      'bower_components/angular-sanitize/angular-sanitize.js',
      'bower_components/angular-touch/angular-touch.js',
      'bower_components/angular-translate/angular-translate.js',
      'bower_components/angular-translate-loader-static-files/angular-translate-loader-static-files.js',
      'bower_components/mobile-angular-ui/dist/js/mobile-angular-ui.min.js',
      'bower_components/angular-bootstrap/ui-bootstrap-tpls.js',
      'bower_components/angular-ui-select/dist/select.js',
      'app/scripts/**/*.js',
      'test/mock/**/*.js',
      'test/spec/**/*.js'
    ],

    // list of files / patterns to exclude
    exclude: [],

    // web server port
    port: 8080,

    // Start these browsers, currently available:
    // - Chrome
    // - ChromeCanary
    // - Firefox
    // - Opera
    // - Safari (only Mac)
    // - PhantomJS
    // - IE (only Windows)
    browsers: [
      'PhantomJS'
    ],

    // Which plugins to enable
    plugins: [
      'karma-phantomjs-launcher',
      'karma-jasmine'
    ],

    // Continuous Integration mode
    // if true, it capture browsers, run tests and exit
    singleRun: false,

    colors: true,

    // level of logging
    // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
    logLevel: config.LOG_INFO,

    // Uncomment the following lines if you are using grunt's server to run the tests
    // proxies: {
    //   '/': 'http://localhost:9000/'
    // },
    // URL root prevent conflicts with the site root
    // urlRoot: '_karma_'
  });
};
<commit_msg>added file angular-bindonce to tests<commit_after>// Karma configuration
// http://karma-runner.github.io/0.12/config/configuration-file.html
// Generated on 2014-10-13 using
// generator-karma 0.8.3

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

  config.set({
    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,

    // base path, that will be used to resolve files and exclude
    basePath: '../',

    // testing framework to use (jasmine/mocha/qunit/...)
    frameworks: ['jasmine'],

    // list of files / patterns to load in the browser
    files: [
      'bower_components/modernizr/modernizr.js',
      'bower_components/angular/angular.js',
      'bower_components/angular-mocks/angular-mocks.js',
      'bower_components/angular-animate/angular-animate.js',
      'bower_components/angular-cookies/angular-cookies.js',
      'bower_components/angular-resource/angular-resource.js',
      'bower_components/angular-route/angular-route.js',
      'bower_components/angular-sanitize/angular-sanitize.js',
      'bower_components/angular-touch/angular-touch.js',
      'bower_components/angular-translate/angular-translate.js',
      'bower_components/angular-translate-loader-static-files/angular-translate-loader-static-files.js',
      'bower_components/mobile-angular-ui/dist/js/mobile-angular-ui.min.js',
      'bower_components/angular-bootstrap/ui-bootstrap-tpls.js',
      'bower_components/angular-ui-select/dist/select.js',
      'bower_components/angular-bindonce/bindonce.js',
      'app/scripts/**/*.js',
      'test/mock/**/*.js',
      'test/spec/**/*.js'
    ],

    // list of files / patterns to exclude
    exclude: [],

    // web server port
    port: 8080,

    // Start these browsers, currently available:
    // - Chrome
    // - ChromeCanary
    // - Firefox
    // - Opera
    // - Safari (only Mac)
    // - PhantomJS
    // - IE (only Windows)
    browsers: [
      'PhantomJS'
    ],

    // Which plugins to enable
    plugins: [
      'karma-phantomjs-launcher',
      'karma-jasmine'
    ],

    // Continuous Integration mode
    // if true, it capture browsers, run tests and exit
    singleRun: false,

    colors: true,

    // level of logging
    // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
    logLevel: config.LOG_INFO,

    // Uncomment the following lines if you are using grunt's server to run the tests
    // proxies: {
    //   '/': 'http://localhost:9000/'
    // },
    // URL root prevent conflicts with the site root
    // urlRoot: '_karma_'
  });
};
<|endoftext|>


<commit_before>module.exports = function(config) {
  var log4js = require("../node_modules/karma/node_modules/log4js");
  var layouts = require("../node_modules/karma/node_modules/log4js/lib/layouts");

  config.set({
    sauceLabs: {
      startConnect: true,
      testName: "MacGyver"
    },
    customLaunchers: {
      SL_Chrome: {
        base: "SauceLabs",
        browserName: "chrome"
      },
      SL_Firefox: {
        base: 'SauceLabs',
        browserName: 'firefox',
        version: '26'
      },
      SL_Safari: {
        base: 'SauceLabs',
        browserName: 'safari',
        platform: 'OS X 10.9',
        version: '7'
      },
      SL_IE_9: {
        base: 'SauceLabs',
        browserName: 'internet explorer',
        platform: 'Windows 2008',
        version: '9'
      },
      SL_IE_10: {
        base: 'SauceLabs',
        browserName: 'internet explorer',
        platform: 'Windows 2012',
        version: '10'
      },
      SL_IE_11: {
        base: 'SauceLabs',
        browserName: 'internet explorer',
        platform: 'Windows 8.1',
        version: '11'
      }
    },

    // base path, that will be used to resolve files and exclude
    basePath: "../",
    frameworks: ["jasmine"],

    // list of files / patterns to load in the browser
    files: [
      // 3rd party libraries
      "node_modules/phantomjs-polyfill/bind-polyfill.js",
      "bower_components/underscore.string/lib/underscore.string.js",
      "bower_components/angular/angular.js",

      // Template
      "src/template/*.html",

      // Test Code
      "src/main.js",
      "src/**/*.js",
      "bower_components/angular-mocks/angular-mocks.js",
      "test/vendor/browserTrigger.js",
      "test/unit/**/*.spec.js"
    ],
    reporters: ["dots"],
    logLevel: config.LOG_INFO,
    browsers: ["PhantomJS"],
    preprocessors: {
      "**/*.html": ["ng-html2js"]
    },
    plugins: ["karma-*"]
  });

  if (process.env.TRAVIS) {
    var buildLabel = "TRAVIS #" + process.env.TRAVIS_BUILD_NUMBER + " (" + process.env.TRAVIS_BUILD_ID + ")";
    config.sauceLabs.build = buildLabel;
    config.sauceLabs.startConnect = false;
    config.sauceLabs.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER;
  }

  // Taken from AngularJS karma-shared.conf.js
  // Terrible hack to workaround inflexibility of log4js:
  // - ignore web-server's 404 warnings,
  var originalConfigure = log4js.configure;
  log4js.configure = function(log4jsConfig) {
    var consoleAppender, layout, originalResult;
    consoleAppender = log4jsConfig.appenders.shift();
    originalResult = originalConfigure.call(log4js, log4jsConfig);
    layout = layouts.layout(consoleAppender.layout.type, consoleAppender.layout);
    log4js.addAppender(function(log) {
      var msg = log.data[0];

      // ignore web server's 404s
      if (log.categoryName === "web-server" && log.level.levelStr === config.LOG_WARN) {
        return;
      }
      console.log(layout(log));
    });
    return originalResult;
  };
};
<commit_msg>test(karma): Remove underscore.string.js<commit_after>module.exports = function(config) {
  var log4js = require("../node_modules/karma/node_modules/log4js");
  var layouts = require("../node_modules/karma/node_modules/log4js/lib/layouts");

  config.set({
    sauceLabs: {
      startConnect: true,
      testName: "MacGyver"
    },
    customLaunchers: {
      SL_Chrome: {
        base: "SauceLabs",
        browserName: "chrome"
      },
      SL_Firefox: {
        base: 'SauceLabs',
        browserName: 'firefox',
        version: '26'
      },
      SL_Safari: {
        base: 'SauceLabs',
        browserName: 'safari',
        platform: 'OS X 10.9',
        version: '7'
      },
      SL_IE_9: {
        base: 'SauceLabs',
        browserName: 'internet explorer',
        platform: 'Windows 2008',
        version: '9'
      },
      SL_IE_10: {
        base: 'SauceLabs',
        browserName: 'internet explorer',
        platform: 'Windows 2012',
        version: '10'
      },
      SL_IE_11: {
        base: 'SauceLabs',
        browserName: 'internet explorer',
        platform: 'Windows 8.1',
        version: '11'
      }
    },

    // base path, that will be used to resolve files and exclude
    basePath: "../",
    frameworks: ["jasmine"],

    // list of files / patterns to load in the browser
    files: [
      // 3rd party libraries
      "node_modules/phantomjs-polyfill/bind-polyfill.js",
      "bower_components/angular/angular.js",

      // Template
      "src/template/*.html",

      // Test Code
      "src/main.js",
      "src/**/*.js",
      "bower_components/angular-mocks/angular-mocks.js",
      "test/vendor/browserTrigger.js",
      "test/unit/**/*.spec.js"
    ],
    reporters: ["dots"],
    logLevel: config.LOG_INFO,
    browsers: ["PhantomJS"],
    preprocessors: {
      "**/*.html": ["ng-html2js"]
    },
    plugins: ["karma-*"]
  });

  if (process.env.TRAVIS) {
    var buildLabel = "TRAVIS #" + process.env.TRAVIS_BUILD_NUMBER + " (" + process.env.TRAVIS_BUILD_ID + ")";
    config.sauceLabs.build = buildLabel;
    config.sauceLabs.startConnect = false;
    config.sauceLabs.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER;
  }

  // Taken from AngularJS karma-shared.conf.js
  // Terrible hack to workaround inflexibility of log4js:
  // - ignore web-server's 404 warnings,
  var originalConfigure = log4js.configure;
  log4js.configure = function(log4jsConfig) {
    var consoleAppender, layout, originalResult;
    consoleAppender = log4jsConfig.appenders.shift();
    originalResult = originalConfigure.call(log4js, log4jsConfig);
    layout = layouts.layout(consoleAppender.layout.type, consoleAppender.layout);
    log4js.addAppender(function(log) {
      var msg = log.data[0];

      // ignore web server's 404s
      if (log.categoryName === "web-server" && log.level.levelStr === config.LOG_WARN) {
        return;
      }
      console.log(layout(log));
    });
    return originalResult;
  };
};
<|endoftext|>


<commit_before>import { logDebug, logError } from './helpers.js'
import { INSTALL_SCRIPT } from './config.js'

const $ = window.$;
const cockpit = window.cockpit;

const _ = (m) => m; // TODO: add translation

// Example how jQuery can be used to integrate with the parent cockpit:machines
export function showPluginInstallationDialog () {
  $("body").append(getInstallationDialogHtml());

  var deferred = cockpit.defer();
  $("#ovirt-provider-install-dialog-cancel").on("click", function() {
    deferred.reject();
  });
  $("#ovirt-provider-install-dialog-install-button").on("click", function() {
    var engineUrl = $("#ovirt-provider-install-dialog-engine-url").val()
    cockpit.spawn([INSTALL_SCRIPT, engineUrl], { "superuser": "try" })
      .done(function () {
        // $("#ovirt-provider-install-dialog").modal("hide");
        console.info('oVirt Provider installation script successful, logout required');

        // just reload window.top.location is not sufiecient since cockpit's configuration files were changed. The user is required to re-login
        // window.top.location.reload(true);
        $("#ovirt-provider-install-dialog-body").replaceWith( getLogoutConfirmationHtml() );
        $("#ovirt-provider-install-dialog-footer").replaceWith( getLogoutConfirmationFooterHtml() );
        $("#ovirt-provider-install-dialog-logout-button").on("click", function() {
          // TODO: why is nothing from following not working?
          // $("#go-logout", window.parent.document).trigger('click');
          // $("#navbar-dropdown", window.top.document).trigger('click');
          // cockpit.logout(true);

          // workiaround since auto-logout is not working
          $("body").append( getLogoutRequiredHtml() );
          deferred.resolve();
        });
      })
      .fail(function (ex, data) {
        logError('oVirt Provider installation script failed. Exception="'+JSON.stringify(ex)+'", output="'+JSON.stringify(data)+'"');

        // TODO: improve error messages based on process exit code instead of just forwarding error msgs
        var errMsg = _("oVirt Provider installation script failed with following output: ") + data;
        $("#ovirt-provider-install-dialog-error").html(errMsg);

        deferred.reject();
      });
  });

  $("#ovirt-provider-install-dialog").modal({keyboard: false});
  return deferred.promise;
}

function getInstallationDialogHtml() {
    return '
' +
       '
' +
          '
' +
              '
' +
                  '
'+ _("Finish oVirt External Provider installation") + '
' +
              '
' +
              '
' +
                  '
' + _("The oVirt External provider is installed but not yet configured. Please enter Engine URL.") + '
' +
                  '
' +
                      '
' +
                          'Engine URL: 	' +
                          '<input id="ovirt-provider-install-dialog-engine-url" class="form-control" type="text" placeholder="https://engine.mydomain.com/ovirt-engine/">	' +
                      '
' +
                  '
' +
                  '

'+
              '
' +
              '
' +
                  '<button class="btn btn-default" id="ovirt-provider-install-dialog-cancel" data-dismiss="modal">' + _("Not now") + '</button>' +
                  '<button class="btn btn-primary" id="ovirt-provider-install-dialog-install-button">' + _("Install") + '</button>' +
              '
' +
          '
' +
      '
' +
    '
';
}

function getLogoutConfirmationHtml() {
  return '
' +
      '
' + _("Installation finished successfuly.") + '
' +
      '
' + _("Cockpit's configuration scripts were changed, you need to relogin to take effect.") + '
' +
    '
' ;
}

function getLogoutConfirmationFooterHtml() {
  return '
' +
      '<button class="btn btn-default" id="ovirt-provider-install-dialog-logout-button" data-dismiss="modal">' + _("Ok") + '</button>' + // TODO: change to 'Logout' once cockpit.logout() works
    '
' ;
}

function getLogoutRequiredHtml() {
  return '
' +
    '' +
    '' + _("Installation finished successfuly.") + '' + _(" Please re-login to take effect.")
  '
';
}
<commit_msg>installDialog: check for root-login<commit_after>import { logDebug, logError } from './helpers.js'
import { INSTALL_SCRIPT } from './config.js'

const $ = window.$;
const cockpit = window.cockpit;

const _ = (m) => m; // TODO: add translation

// Example how jQuery can be used to integrate with the parent cockpit:machines
export function showPluginInstallationDialog () {
  $("body").append(getInstallationDialogHtml());
  checkForRootUser();

  var deferred = cockpit.defer();
  $("#ovirt-provider-install-dialog-cancel").on("click", function() {
    deferred.reject();
  });
  $("#ovirt-provider-install-dialog-install-button").on("click", function() {
    var engineUrl = $("#ovirt-provider-install-dialog-engine-url").val()
    cockpit.spawn([INSTALL_SCRIPT, engineUrl], { "superuser": "try" })
      .done(function () {
        // $("#ovirt-provider-install-dialog").modal("hide");
        console.info('oVirt Provider installation script successful, logout required');

        // just reload window.top.location is not sufiecient since cockpit's configuration files were changed. The user is required to re-login
        // window.top.location.reload(true);
        $("#ovirt-provider-install-dialog-body").replaceWith( getLogoutConfirmationHtml() );
        $("#ovirt-provider-install-dialog-footer").replaceWith( getLogoutConfirmationFooterHtml() );
        $("#ovirt-provider-install-dialog-logout-button").on("click", function() {
          // TODO: why is nothing from following working?
          // $("#go-logout", window.parent.document).trigger('click');
          // $("#navbar-dropdown", window.top.document).trigger('click');
          // cockpit.logout(true);

          // workaround since auto-logout is not working
          $("body").append( getLogoutRequiredHtml() );

          deferred.resolve();
        });
      })
      .fail(function (ex, data) {
        logError('oVirt Provider installation script failed. Exception="'+JSON.stringify(ex)+'", output="'+JSON.stringify(data)+'"');

        // TODO: improve error messages based on process exit code instead of just forwarding error msgs
        var errMsg = _("oVirt Provider installation script failed with following output: ") + data;
        $("#ovirt-provider-install-dialog-error").html(errMsg);

        deferred.reject();
      });
  });

  $("#ovirt-provider-install-dialog").modal({keyboard: false});
  return deferred.promise;
}

function getInstallationDialogHtml() {
    return '
' +
       '
' +
          '
' +
              '
' +
                  '
'+ _("Finish oVirt External Provider installation") + '
' +
              '
' +
              '
' +
                  '
' + _("The oVirt External provider is installed but not yet configured. Please enter Engine URL.") + '
' +
                  '

' +
                  '
' +
                      '
' +
                          'Engine URL: 	' +
                          '<input id="ovirt-provider-install-dialog-engine-url" class="form-control" type="text" placeholder="https://engine.mydomain.com/ovirt-engine/">	' +
                      '
' +
                  '
' +
                  '

'+
              '
' +
              '
' +
                  '<button class="btn btn-default" id="ovirt-provider-install-dialog-cancel" data-dismiss="modal">' + _("Not now") + '</button>' +
                  '<button class="btn btn-primary" id="ovirt-provider-install-dialog-install-button">' + _("Install") + '</button>' +
              '
' +
          '
' +
      '
' +
    '
';
}

function checkForRootUser() {
  cockpit.user().done(user => {
    if (user.name !== 'root') {
      $("#ovirt-provider-install-dialog-body-rootCheck")
        .replaceWith(`<p>You are logged as <b>${user.name}</b>. Please note, following operation might fail, since <b>root</b> login might be required to access Cockpit's configuration files.</p>`);
    }
  });
}

function getLogoutConfirmationHtml() {
  return '
' +
      '
' + _("Installation finished successfuly.") + '
' +
      '
' + _("Cockpit's configuration scripts were changed, you need to relogin to take effect.") + '
' +
    '
' ;
}

function getLogoutConfirmationFooterHtml() {
  return '
' +
      '<button class="btn btn-default" id="ovirt-provider-install-dialog-logout-button" data-dismiss="modal">' + _("Ok") + '</button>' + // TODO: change to 'Logout' once cockpit.logout() works
    '
' ;
}

function getLogoutRequiredHtml() {
  return '
' +
    '' +
    '' + _("Installation finished successfuly.") + '' + _(" Please re-login to take effect.")
  '
';
}
<|endoftext|>


<commit_before>var fs = require('fs')
var path = require('path')
var testutil = require('testutil')
var terst = require('terst')
var fse = require('../')

var TEST_DIR = ''

describe('fs-extra', function() {
  beforeEach(function() {
    TEST_DIR = testutil.createTestDir('fs-extra')
  })

  afterEach(function(done) {
    fse.remove(TEST_DIR, done)
  })

  describe('+ mkdirs()', function() {
    it('should make the directory', function(done) {
      var dir = path.join(TEST_DIR, 'tmp-' + Date.now() + Math.random())

      F (fs.existsSync(dir))

      fse.mkdirs(dir, function(err) {
        T (err === null)
        T (fs.existsSync(dir))

        done()
      })
    })

    it('should make the entire directory path', function(done) {
      var dir = path.join(TEST_DIR, 'tmp-' + Date.now() + Math.random())
      var newDir = path.join(TEST_DIR, 'dfdf', 'ffff', 'aaa')

      F (fs.existsSync(dir))

      fse.mkdirs(newDir, function(err) {
        T (err === null)
        T (fs.existsSync(newDir))

        done()
      })
    })
  })

  describe('+ mkdirsSync()', function() {
    it('should make the directory', function(done) {
      var dir = path.join(TEST_DIR, 'tmp-' + Date.now() + Math.random())

      F (fs.existsSync(dir))
      fse.mkdirsSync(dir)
      T (fs.existsSync(dir))

      done()
    })

    it('should make the entire directory path', function(done) {
      var dir = path.join(TEST_DIR, 'tmp-' + Date.now() + Math.random())
      var newDir = path.join(dir, 'dfdf', 'ffff', 'aaa')

      F (fs.existsSync(dir))
      fse.mkdirsSync(dir)
      T (fs.existsSync(dir))

      done()
    })
  })

})

<commit_msg>test/mkdir.test: dropped terst for assert<commit_after>var assert = require('assert')
var fs = require('fs')
var path = require('path')
var testutil = require('testutil')
var fse = require('../')

var TEST_DIR = ''

describe('fs-extra', function() {
  beforeEach(function() {
    TEST_DIR = testutil.createTestDir('fs-extra')
  })

  afterEach(function(done) {
    fse.remove(TEST_DIR, done)
  })

  describe('+ mkdirs()', function() {
    it('should make the directory', function(done) {
      var dir = path.join(TEST_DIR, 'tmp-' + Date.now() + Math.random())

      assert(!fs.existsSync(dir))

      fse.mkdirs(dir, function(err) {
        assert.ifError(err)
        assert(fs.existsSync(dir))
        done()
      })
    })

    it('should make the entire directory path', function(done) {
      var dir = path.join(TEST_DIR, 'tmp-' + Date.now() + Math.random())
      var newDir = path.join(TEST_DIR, 'dfdf', 'ffff', 'aaa')

      assert(!fs.existsSync(dir))

      fse.mkdirs(newDir, function(err) {
        assert.ifError(err)
        assert(fs.existsSync(newDir))
        done()
      })
    })
  })

  describe('+ mkdirsSync()', function() {
    it('should make the directory', function(done) {
      var dir = path.join(TEST_DIR, 'tmp-' + Date.now() + Math.random())

      assert(!fs.existsSync(dir))
      fse.mkdirsSync(dir)
      assert(fs.existsSync(dir))

      done()
    })

    it('should make the entire directory path', function(done) {
      var dir = path.join(TEST_DIR, 'tmp-' + Date.now() + Math.random())
      var newDir = path.join(dir, 'dfdf', 'ffff', 'aaa')

      assert(!fs.existsSync(dir))
      fse.mkdirsSync(dir)
      assert(fs.existsSync(dir))

      done()
    })
  })
})

<|endoftext|>