<commit_before>describe('window.angulartics', function() {
  beforeEach(function() {
    jasmine.Clock.useMock();
  });
  afterEach(function() {
    delete window.angularticsTestVendor;
  });

  it('should manage vendor wait count', function() {
    spy = jasmine.createSpy('vendorCallback');
    spyWhenLoaded = jasmine.createSpy('vendorCallbackWhenLoaded');
    angulartics.waitForVendorApi('angularticsTestVendor', 1, 'loaded', spy);
    angulartics.waitForVendorApi('angularticsTestVendor', 1, spyWhenLoaded);
    expect(window.angulartics.waitForVendorCount).toEqual(2);

    jasmine.Clock.tick(1);
    expect(window.angulartics.waitForVendorCount).toEqual(2);

    window.angularticsTestVendor = {};
    jasmine.Clock.tick(1);
    expect(angulartics.waitForVendorCount).toEqual(1);

    window.angularticsTestVendor.loaded = true;
    jasmine.Clock.tick(1);
    expect(window.angulartics.waitForVendorCount).toEqual(0);
    expect(spyWhenLoaded).toHaveBeenCalledWith(window.angularticsTestVendor);
  });

});

describe('Module: angulartics', function() {
  'use strict';

  beforeEach(module('angulartics'));

  describe('Configuration', function() {
    it('should configure virtualPageviews', function() {
      module(function(_$analyticsProvider_) {
        _$analyticsProvider_.virtualPageviews(false);
      });
      inject(function(_$analytics_) {
        expect(_$analytics_.settings.pageTracking.autoTrackVirtualPages).toBe(false);
      });
    });

    it('should be configured to use the <base> element', function() {
      var baseUrl = 'http://my/path';

      module(function($provide, _$analyticsProvider_) {
        var baseEl = document.createElement('base');
        baseEl.setAttribute('href', baseUrl);
        document.getElementsByTagName('body')[0].appendChild(baseEl);
        _$analyticsProvider_.withBase(true);
      });
      inject(function(_$analytics_) {
        expect(_$analytics_.settings.pageTracking.basePath).toBe(baseUrl);
      });

    });

  });

  describe('Provider: analytics', function() {

    describe('initialize', function() {
      it('should track pages by default', function() {
        inject(function(_$analytics_) {
          expect(_$analytics_.settings.pageTracking.autoTrackVirtualPages).toBe(true);
        });
      });
    });

    describe('ngRoute support', function() {
      var analytics,
          rootScope,
          location;
      beforeEach(module('ngRoute'));
      beforeEach(inject(function(_$analytics_, _$rootScope_, _$location_) {
        analytics = _$analytics_;
        location = _$location_;
        rootScope = _$rootScope_;

        spyOn(analytics, 'pageTrack');
      }));

      it('should track pages on route change', function() {
        location.path('/abc');
        rootScope.$emit('$routeChangeSuccess');
        expect(analytics.pageTrack).toHaveBeenCalledWith('/abc', location);
      });
    });

    describe('ui-router support', function() {
      var analytics,
          rootScope,
          location;
      beforeEach(module('ui.router'));
      beforeEach(inject(function(_$analytics_, _$rootScope_, _$location_) {
        analytics = _$analytics_;
        location = _$location_;
        rootScope = _$rootScope_;

        spyOn(analytics, 'pageTrack');
      }));

      it('should track pages on route change', function() {
        location.path('/abc');
        rootScope.$emit('$stateChangeSuccess');
        expect(analytics.pageTrack).toHaveBeenCalledWith('/abc', location);
      });
    });

  });

  describe('$analyticsProvider', function() {

    describe('registration', function() {
      var expectedHandler = [
        'pageTrack',
        'eventTrack',
        'setUsername',
        'setUserProperties',
        'setUserPropertiesOnce',
        'setSuperProperties',
        'setSuperPropertiesOnce'
      ];
      var capitalize = function(input) {
        return input.replace(/^./, function(match) {
          return match.toUpperCase();
        });
      };

      var $analytics, $analyticsProvider;
      beforeEach(function() {
        module(function(_$analyticsProvider_) {
          $analyticsProvider = _$analyticsProvider_;
        });
        inject(function(_$analytics_) {
          $analytics = _$analytics_;
        });
      });
      angular.forEach(expectedHandler, function(handlerName) {
        it('should install a register function for "' + handlerName + '" on $analyticsProvider', function() {
          var fn = $analyticsProvider['register' + capitalize(handlerName)];
          expect(fn).toBeDefined();
          expect(typeof fn).toEqual('function');
        });
        it('should expose a handler "' + handlerName + '" on $analytics', function() {
          var fn = $analytics[handlerName];
          expect(fn).toBeDefined();
          expect(typeof fn).toEqual('function');
        });
      });
    });
  });

  describe('$analytics', function() {
    describe('buffering', function() {
      var $analytics, $analyticsProvider, eventTrackSpy;
      beforeEach(function() {
        module(function(_$analyticsProvider_) {
          $analyticsProvider = _$analyticsProvider_;
          $analyticsProvider.settings.bufferFlushDelay = 0;
        });
        inject(function(_$analytics_) {
          $analytics = _$analytics_;
        });
      });

      beforeEach(function() {
        eventTrackSpy = jasmine.createSpy('eventTrackSpy');
      });

      it('should buffer events if waiting on a vendor', function() {
        angulartics.waitForVendorCount++; // Mock that we're waiting for a vendor api
        $analytics.eventTrack('foo'); // These events should be buffered
        $analytics.eventTrack('bar'); // This event should be buffered

        $analyticsProvider.registerEventTrack(eventTrackSpy); // This should immediately flush
        expect(eventTrackSpy.calls.length).toEqual(2);
        expect(eventTrackSpy.calls[0].args).toEqual(['foo']);
        expect(eventTrackSpy.calls[1].args).toEqual(['bar']);
      });

      it('should not buffer events if not waiting on any vendors', function() {
        angulartics.waitForVendorCount = 0; // Mock that we're waiting for a vendor api
        $analytics.eventTrack('foo'); // These events should be buffered
        $analyticsProvider.registerEventTrack(eventTrackSpy); // This should immediately flush
        expect(eventTrackSpy).not.toHaveBeenCalled();
      });

      it('should continue to buffer events until all vendors are resolved', function() {
        angulartics.waitForVendorCount = 2; // Mock that we're waiting for a vendor api
        $analytics.eventTrack('foo'); // These events should be buffered

        $analyticsProvider.registerEventTrack(eventTrackSpy); // This should immediately flush
        expect(eventTrackSpy).toHaveBeenCalledWith('foo');

        $analytics.eventTrack('bar');
        expect(eventTrackSpy.calls.length).toEqual(2);
        expect(eventTrackSpy.calls[1].args).toEqual(['bar']);

        var secondVendor = jasmine.createSpy('secondVendor');
        $analyticsProvider.registerEventTrack(secondVendor); // This should immediately flush
        expect(secondVendor.calls.length).toEqual(2);
        expect(secondVendor.calls[0].args).toEqual(['foo']);
        expect(secondVendor.calls[1].args).toEqual(['bar']);

      });
    });
  });

  describe('Directive: analyticsOn', function() {
    var analytics,
        elem,
        scope;

    function compileElem() {
      inject(function($compile) {
        $compile(elem)(scope);
      });
      scope.$digest();
    }

    beforeEach(inject(function(_$analytics_, _$rootScope_) {
      analytics = _$analytics_;
      scope = _$rootScope_.$new();
    }));

    it('should not send on and event fields to the eventTrack function', function() {
      elem = angular.element('<div>').attr({
        'analytics-on': 'click',
        'analytics-event': 'InitiateSearch',
        'analytics-category': 'Search'
      });
      spyOn(analytics, 'eventTrack');
      expect(analytics.eventTrack).not.toHaveBeenCalled();

      compileElem();
      elem.triggerHandler('click');
      expect(analytics.eventTrack).toHaveBeenCalledWith('InitiateSearch', {category: 'Search', eventType: 'click'});
    });
  });

});
<commit_msg>Updated test case<commit_after>describe('window.angulartics', function() {
  beforeEach(function() {
    jasmine.Clock.useMock();
  });
  afterEach(function() {
    delete window.angularticsTestVendor;
  });

  it('should manage vendor wait count', function() {
    spy = jasmine.createSpy('vendorCallback');
    spyWhenLoaded = jasmine.createSpy('vendorCallbackWhenLoaded');
    angulartics.waitForVendorApi('angularticsTestVendor', 1, 'loaded', spy);
    angulartics.waitForVendorApi('angularticsTestVendor', 1, spyWhenLoaded);
    expect(window.angulartics.waitForVendorCount).toEqual(2);

    jasmine.Clock.tick(1);
    expect(window.angulartics.waitForVendorCount).toEqual(2);

    window.angularticsTestVendor = {};
    jasmine.Clock.tick(1);
    expect(angulartics.waitForVendorCount).toEqual(1);

    window.angularticsTestVendor.loaded = true;
    jasmine.Clock.tick(1);
    expect(window.angulartics.waitForVendorCount).toEqual(0);
    expect(spyWhenLoaded).toHaveBeenCalledWith(window.angularticsTestVendor);
  });

});

describe('Module: angulartics', function() {
  'use strict';

  beforeEach(module('angulartics'));

  describe('Configuration', function() {
    it('should configure virtualPageviews', function() {
      module(function(_$analyticsProvider_) {
        _$analyticsProvider_.virtualPageviews(false);
      });
      inject(function(_$analytics_) {
        expect(_$analytics_.settings.pageTracking.autoTrackVirtualPages).toBe(false);
      });
    });

    it('should be configured to use the <base> element', function() {
      var baseUrl = 'http://my/path';

      module(function($provide, _$analyticsProvider_) {
        var baseEl = document.createElement('base');
        baseEl.setAttribute('href', baseUrl);
        document.getElementsByTagName('body')[0].appendChild(baseEl);
        _$analyticsProvider_.withBase(true);
      });
      inject(function(_$analytics_) {
        expect(_$analytics_.settings.pageTracking.basePath).toBe(baseUrl);
      });

    });

  });

  describe('Provider: analytics', function() {

    describe('initialize', function() {
      it('should track pages by default', function() {
        inject(function(_$analytics_) {
          expect(_$analytics_.settings.pageTracking.autoTrackVirtualPages).toBe(true);
        });
      });
    });

    describe('ngRoute support', function() {
      var analytics,
          rootScope,
          location;
      beforeEach(module('ngRoute'));
      beforeEach(inject(function(_$analytics_, _$rootScope_, _$location_) {
        analytics = _$analytics_;
        location = _$location_;
        rootScope = _$rootScope_;

        spyOn(analytics, 'pageTrack');
      }));

      it('should track pages on route change', function() {
        location.path('/abc');
        rootScope.$emit('$routeChangeSuccess');
        expect(analytics.pageTrack).toHaveBeenCalledWith('/abc', location);
      });
    });

    describe('ui-router support', function() {
      var analytics,
          rootScope,
          location;
      beforeEach(module('ui.router'));
      beforeEach(inject(function(_$analytics_, _$rootScope_, _$location_) {
        analytics = _$analytics_;
        location = _$location_;
        rootScope = _$rootScope_;

        spyOn(analytics, 'pageTrack');
      }));

      it('should track pages on route change', function() {
        location.path('/abc');
        rootScope.$emit('$stateChangeSuccess');
        expect(analytics.pageTrack).toHaveBeenCalledWith('/abc', location);
      });
    });

  });

  describe('$analyticsProvider', function() {

    describe('registration', function() {
      var expectedHandler = [
        'pageTrack',
        'eventTrack',
        'setUsername',
        'setUserProperties',
        'setUserPropertiesOnce',
        'setSuperProperties',
        'setSuperPropertiesOnce',
        'userTimings'
      ];
      var capitalize = function(input) {
        return input.replace(/^./, function(match) {
          return match.toUpperCase();
        });
      };

      var $analytics, $analyticsProvider;
      beforeEach(function() {
        module(function(_$analyticsProvider_) {
          $analyticsProvider = _$analyticsProvider_;
        });
        inject(function(_$analytics_) {
          $analytics = _$analytics_;
        });
      });
      angular.forEach(expectedHandler, function(handlerName) {
        it('should install a register function for "' + handlerName + '" on $analyticsProvider', function() {
          var fn = $analyticsProvider['register' + capitalize(handlerName)];
          expect(fn).toBeDefined();
          expect(typeof fn).toEqual('function');
        });
        it('should expose a handler "' + handlerName + '" on $analytics', function() {
          var fn = $analytics[handlerName];
          expect(fn).toBeDefined();
          expect(typeof fn).toEqual('function');
        });
      });
    });
  });

  describe('$analytics', function() {
    describe('buffering', function() {
      var $analytics, $analyticsProvider, eventTrackSpy;
      beforeEach(function() {
        module(function(_$analyticsProvider_) {
          $analyticsProvider = _$analyticsProvider_;
          $analyticsProvider.settings.bufferFlushDelay = 0;
        });
        inject(function(_$analytics_) {
          $analytics = _$analytics_;
        });
      });

      beforeEach(function() {
        eventTrackSpy = jasmine.createSpy('eventTrackSpy');
      });

      it('should buffer events if waiting on a vendor', function() {
        angulartics.waitForVendorCount++; // Mock that we're waiting for a vendor api
        $analytics.eventTrack('foo'); // These events should be buffered
        $analytics.eventTrack('bar'); // This event should be buffered

        $analyticsProvider.registerEventTrack(eventTrackSpy); // This should immediately flush
        expect(eventTrackSpy.calls.length).toEqual(2);
        expect(eventTrackSpy.calls[0].args).toEqual(['foo']);
        expect(eventTrackSpy.calls[1].args).toEqual(['bar']);
      });

      it('should not buffer events if not waiting on any vendors', function() {
        angulartics.waitForVendorCount = 0; // Mock that we're waiting for a vendor api
        $analytics.eventTrack('foo'); // These events should be buffered
        $analyticsProvider.registerEventTrack(eventTrackSpy); // This should immediately flush
        expect(eventTrackSpy).not.toHaveBeenCalled();
      });

      it('should continue to buffer events until all vendors are resolved', function() {
        angulartics.waitForVendorCount = 2; // Mock that we're waiting for a vendor api
        $analytics.eventTrack('foo'); // These events should be buffered

        $analyticsProvider.registerEventTrack(eventTrackSpy); // This should immediately flush
        expect(eventTrackSpy).toHaveBeenCalledWith('foo');

        $analytics.eventTrack('bar');
        expect(eventTrackSpy.calls.length).toEqual(2);
        expect(eventTrackSpy.calls[1].args).toEqual(['bar']);

        var secondVendor = jasmine.createSpy('secondVendor');
        $analyticsProvider.registerEventTrack(secondVendor); // This should immediately flush
        expect(secondVendor.calls.length).toEqual(2);
        expect(secondVendor.calls[0].args).toEqual(['foo']);
        expect(secondVendor.calls[1].args).toEqual(['bar']);

      });
    });
  });

  describe('Directive: analyticsOn', function() {
    var analytics,
        elem,
        scope;

    function compileElem() {
      inject(function($compile) {
        $compile(elem)(scope);
      });
      scope.$digest();
    }

    beforeEach(inject(function(_$analytics_, _$rootScope_) {
      analytics = _$analytics_;
      scope = _$rootScope_.$new();
    }));

    it('should not send on and event fields to the eventTrack function', function() {
      elem = angular.element('<div>').attr({
        'analytics-on': 'click',
        'analytics-event': 'InitiateSearch',
        'analytics-category': 'Search'
      });
      spyOn(analytics, 'eventTrack');
      expect(analytics.eventTrack).not.toHaveBeenCalled();

      compileElem();
      elem.triggerHandler('click');
      expect(analytics.eventTrack).toHaveBeenCalledWith('InitiateSearch', {category: 'Search', eventType: 'click'});
    });
  });

});
<|endoftext|>


<commit_before>var Class = require('../../utils/Class');
var BaseSoundManager = require('../BaseSoundManager');
var HTML5AudioSound = require('./HTML5AudioSound');
/*!
 * @author Pavle Goloskokovic <pgoloskokovic@gmail.com> (http://prunegames.com)
 */
var HTML5AudioSoundManager = new Class({
    Extends: BaseSoundManager,
    /**
     * HTML5 Audio implementation of the sound manager.
     *
     * @class Phaser.Sound.HTML5AudioSoundManager
     * @constructor
     * @param {Phaser.Game} game - Reference to the current game instance.
     */
    initialize: function HTML5AudioSoundManager(game) {
        /**
         * Flag indicating whether if there are no idle instances of HTML5 Audio tag,
         * for any particular sound, if one of the used tags should be hijacked and used
         * for succeeding playback or if succeeding Phaser.Sound.HTML5AudioSound#play
         * call should be ignored.
         *
         * @property {boolean} override
         * @default true
         */
        this.override = true;
        /**
         * Value representing time difference, in seconds, between calling
         * play method on an audio tag and when it actually starts playing.
         * It is used to achieve more accurate delayed sound playback.
         *
         * You might need to tweak this value to get the desired results
         * since audio play delay varies depending on the browser/platform.
         *
         * @property {number} audioPlayDelay
         * @default 0.1
         */
        this.audioPlayDelay = 0.1;
        /**
         * A value by which we should offset the loop end marker of the
         * looping sound to compensate for lag, caused by changing audio
         * tag playback position, in order to achieve gapless looping.
         *
         * You might need to tweak this value to get the desired results
         * since loop lag varies depending on the browser/platform.
         *
         * @property {number} loopEndOffset
         * @default 0.05
         */
        this.loopEndOffset = 0.05;
        /**
         * An array for keeping track of all the sounds
         * that were paused when game lost focus.
         *
         * @private
         * @property {Phaser.Sound.HTML5AudioSound[]} onBlurPausedSounds
         * @default []
         */
        this.onBlurPausedSounds = [];
        this.locked = 'ontouchstart' in window;
        /**
         * A queue of all actions performed on sound objects while audio was locked.
         * Once the audio gets unlocked, after an explicit user interaction,
         * all actions will be performed in chronological order.
         *
         * @private
         * @property {{ sound: Phaser.Sound.HTML5AudioSound, name: string, value?: * }[]} lockedActionsQueue
         */
        this.lockedActionsQueue = this.locked ? [] : null;
        /**
         * Property that actually holds the value of global mute
         * for HTML5 Audio sound manager implementation.
         *
         * @private
         * @property {boolean} _mute
         * @default false
         */
        this._mute = false;
        /**
         * Property that actually holds the value of global volume
         * for HTML5 Audio sound manager implementation.
         *
         * @private
         * @property {boolean} _volume
         * @default 1
         */
        this._volume = 1;
        BaseSoundManager.call(this, game);
    },
    /**
     * Adds a new sound into the sound manager.
     *
     * @method Phaser.Sound.HTML5AudioSoundManager#add
     * @param {string} key - Asset key for the sound.
     * @param {ISoundConfig} [config] - An optional config object containing default sound settings.
     * @returns {Phaser.Sound.HTML5AudioSound} The new sound instance.
     */
    add: function (key, config) {
        var sound = new HTML5AudioSound(this, key, config);
        this.sounds.push(sound);
        return sound;
    },
    /**
     * Unlocks HTML5 Audio loading and playback on mobile
     * devices on the initial explicit user interaction.
     *
     * @private
     * @method Phaser.Sound.HTML5AudioSoundManager#unlock
     */
    unlock: function () {
        var _this = this;
        var moved = false;
        var detectMove = function () {
            moved = true;
        };
        var unlock = function () {
            if (moved) {
                moved = false;
                return;
            }
            document.body.removeEventListener('touchmove', detectMove);
            document.body.removeEventListener('touchend', unlock);
            var allTags = [];
            _this.game.cache.audio.entries.each(function (key, tags) {
                for (var i = 0; i < tags.length; i++) {
                    allTags.push(tags[i]);
                }
                return true;
            });
            var lastTag = allTags[allTags.length - 1];
            lastTag.oncanplaythrough = function () {
                lastTag.oncanplaythrough = null;
                _this.unlocked = true;
            };
            allTags.forEach(function (tag) {
                tag.load();
            });
        };
        this.once('unlocked', function () {
            _this.forEachActiveSound(function (sound) {
                sound.duration = sound.tags[0].duration;
                sound.totalDuration = sound.tags[0].duration;
            });
            _this.lockedActionsQueue.forEach(function (lockedAction) {
                if (lockedAction.sound[lockedAction.prop].apply) {
                    lockedAction.sound[lockedAction.prop].apply(lockedAction.sound, lockedAction.value || []);
                }
                else {
                    lockedAction.sound[lockedAction.prop] = lockedAction.value;
                }
            });
            _this.lockedActionsQueue.length = 0;
            _this.lockedActionsQueue = null;
        });
        document.body.addEventListener('touchmove', detectMove, false);
        document.body.addEventListener('touchend', unlock, false);
    },
    /**
     * Method used internally for pausing sound manager if
     * Phaser.Sound.HTML5AudioSoundManager#pauseOnBlur is set to true.
     *
     * @protected
     * @method Phaser.Sound.HTML5AudioSoundManager#onBlur
     */
    onBlur: function () {
        this.forEachActiveSound(function (sound) {
            if (sound.isPlaying) {
                this.onBlurPausedSounds.push(sound);
                sound.onBlur();
            }
        });
    },
    /**
     * Method used internally for resuming sound manager if
     * Phaser.Sound.HTML5AudioSoundManager#pauseOnBlur is set to true.
     *
     * @protected
     * @method Phaser.Sound.HTML5AudioSoundManager#onFocus
     */
    onFocus: function () {
        this.onBlurPausedSounds.forEach(function (sound) {
            sound.onFocus();
        });
        this.onBlurPausedSounds.length = 0;
    },
    destroy: function () {
        BaseSoundManager.prototype.destroy.call(this);
        this.onBlurPausedSounds.length = 0;
        this.onBlurPausedSounds = null;
    },
    isLocked: function (sound, prop, value) {
        if (this.locked) {
            this.lockedActionsQueue.push({
                sound: sound,
                prop: prop,
                value: value
            });
            return true;
        }
        return false;
    }
});
/**
 * Global mute setting.
 *
 * @name Phaser.Sound.HTML5AudioSoundManager#mute
 * @property {boolean} mute
 */
Object.defineProperty(HTML5AudioSoundManager.prototype, 'mute', {
    get: function () {
        return this._mute;
    },
    set: function (value) {
        this._mute = value;
        this.forEachActiveSound(function (sound) {
            sound.setMute();
        });
        this.emit('mute', this, value);
    }
});
/**
 * Global volume setting.
 *
 * @name Phaser.Sound.HTML5AudioSoundManager#volume
 * @property {number} volume
 */
Object.defineProperty(HTML5AudioSoundManager.prototype, 'volume', {
    get: function () {
        return this._volume;
    },
    set: function (value) {
        this._volume = value;
        this.forEachActiveSound(function (sound) {
            sound.setVolume();
        });
        this.emit('volume', this, value);
    }
});
module.exports = HTML5AudioSoundManager;
<commit_msg>Added destroy method docs<commit_after>var Class = require('../../utils/Class');
var BaseSoundManager = require('../BaseSoundManager');
var HTML5AudioSound = require('./HTML5AudioSound');
/*!
 * @author Pavle Goloskokovic <pgoloskokovic@gmail.com> (http://prunegames.com)
 */
var HTML5AudioSoundManager = new Class({
    Extends: BaseSoundManager,
    /**
     * HTML5 Audio implementation of the sound manager.
     *
     * @class Phaser.Sound.HTML5AudioSoundManager
     * @constructor
     * @param {Phaser.Game} game - Reference to the current game instance.
     */
    initialize: function HTML5AudioSoundManager(game) {
        /**
         * Flag indicating whether if there are no idle instances of HTML5 Audio tag,
         * for any particular sound, if one of the used tags should be hijacked and used
         * for succeeding playback or if succeeding Phaser.Sound.HTML5AudioSound#play
         * call should be ignored.
         *
         * @property {boolean} override
         * @default true
         */
        this.override = true;
        /**
         * Value representing time difference, in seconds, between calling
         * play method on an audio tag and when it actually starts playing.
         * It is used to achieve more accurate delayed sound playback.
         *
         * You might need to tweak this value to get the desired results
         * since audio play delay varies depending on the browser/platform.
         *
         * @property {number} audioPlayDelay
         * @default 0.1
         */
        this.audioPlayDelay = 0.1;
        /**
         * A value by which we should offset the loop end marker of the
         * looping sound to compensate for lag, caused by changing audio
         * tag playback position, in order to achieve gapless looping.
         *
         * You might need to tweak this value to get the desired results
         * since loop lag varies depending on the browser/platform.
         *
         * @property {number} loopEndOffset
         * @default 0.05
         */
        this.loopEndOffset = 0.05;
        /**
         * An array for keeping track of all the sounds
         * that were paused when game lost focus.
         *
         * @private
         * @property {Phaser.Sound.HTML5AudioSound[]} onBlurPausedSounds
         * @default []
         */
        this.onBlurPausedSounds = [];
        this.locked = 'ontouchstart' in window;
        /**
         * A queue of all actions performed on sound objects while audio was locked.
         * Once the audio gets unlocked, after an explicit user interaction,
         * all actions will be performed in chronological order.
         *
         * @private
         * @property {{ sound: Phaser.Sound.HTML5AudioSound, name: string, value?: * }[]} lockedActionsQueue
         */
        this.lockedActionsQueue = this.locked ? [] : null;
        /**
         * Property that actually holds the value of global mute
         * for HTML5 Audio sound manager implementation.
         *
         * @private
         * @property {boolean} _mute
         * @default false
         */
        this._mute = false;
        /**
         * Property that actually holds the value of global volume
         * for HTML5 Audio sound manager implementation.
         *
         * @private
         * @property {boolean} _volume
         * @default 1
         */
        this._volume = 1;
        BaseSoundManager.call(this, game);
    },
    /**
     * Adds a new sound into the sound manager.
     *
     * @method Phaser.Sound.HTML5AudioSoundManager#add
     * @param {string} key - Asset key for the sound.
     * @param {ISoundConfig} [config] - An optional config object containing default sound settings.
     * @returns {Phaser.Sound.HTML5AudioSound} The new sound instance.
     */
    add: function (key, config) {
        var sound = new HTML5AudioSound(this, key, config);
        this.sounds.push(sound);
        return sound;
    },
    /**
     * Unlocks HTML5 Audio loading and playback on mobile
     * devices on the initial explicit user interaction.
     *
     * @private
     * @method Phaser.Sound.HTML5AudioSoundManager#unlock
     */
    unlock: function () {
        var _this = this;
        var moved = false;
        var detectMove = function () {
            moved = true;
        };
        var unlock = function () {
            if (moved) {
                moved = false;
                return;
            }
            document.body.removeEventListener('touchmove', detectMove);
            document.body.removeEventListener('touchend', unlock);
            var allTags = [];
            _this.game.cache.audio.entries.each(function (key, tags) {
                for (var i = 0; i < tags.length; i++) {
                    allTags.push(tags[i]);
                }
                return true;
            });
            var lastTag = allTags[allTags.length - 1];
            lastTag.oncanplaythrough = function () {
                lastTag.oncanplaythrough = null;
                _this.unlocked = true;
            };
            allTags.forEach(function (tag) {
                tag.load();
            });
        };
        this.once('unlocked', function () {
            _this.forEachActiveSound(function (sound) {
                sound.duration = sound.tags[0].duration;
                sound.totalDuration = sound.tags[0].duration;
            });
            _this.lockedActionsQueue.forEach(function (lockedAction) {
                if (lockedAction.sound[lockedAction.prop].apply) {
                    lockedAction.sound[lockedAction.prop].apply(lockedAction.sound, lockedAction.value || []);
                }
                else {
                    lockedAction.sound[lockedAction.prop] = lockedAction.value;
                }
            });
            _this.lockedActionsQueue.length = 0;
            _this.lockedActionsQueue = null;
        });
        document.body.addEventListener('touchmove', detectMove, false);
        document.body.addEventListener('touchend', unlock, false);
    },
    /**
     * Method used internally for pausing sound manager if
     * Phaser.Sound.HTML5AudioSoundManager#pauseOnBlur is set to true.
     *
     * @protected
     * @method Phaser.Sound.HTML5AudioSoundManager#onBlur
     */
    onBlur: function () {
        this.forEachActiveSound(function (sound) {
            if (sound.isPlaying) {
                this.onBlurPausedSounds.push(sound);
                sound.onBlur();
            }
        });
    },
    /**
     * Method used internally for resuming sound manager if
     * Phaser.Sound.HTML5AudioSoundManager#pauseOnBlur is set to true.
     *
     * @protected
     * @method Phaser.Sound.HTML5AudioSoundManager#onFocus
     */
    onFocus: function () {
        this.onBlurPausedSounds.forEach(function (sound) {
            sound.onFocus();
        });
        this.onBlurPausedSounds.length = 0;
    },
    /**
     * Calls Phaser.Sound.BaseSoundManager#destroy method
     * and cleans up all HTML5 Audio related stuff.
     *
     * @method Phaser.Sound.HTML5AudioSoundManager#destroy
     */
    destroy: function () {
        BaseSoundManager.prototype.destroy.call(this);
        this.onBlurPausedSounds.length = 0;
        this.onBlurPausedSounds = null;
    },
    isLocked: function (sound, prop, value) {
        if (this.locked) {
            this.lockedActionsQueue.push({
                sound: sound,
                prop: prop,
                value: value
            });
            return true;
        }
        return false;
    }
});
/**
 * Global mute setting.
 *
 * @name Phaser.Sound.HTML5AudioSoundManager#mute
 * @property {boolean} mute
 */
Object.defineProperty(HTML5AudioSoundManager.prototype, 'mute', {
    get: function () {
        return this._mute;
    },
    set: function (value) {
        this._mute = value;
        this.forEachActiveSound(function (sound) {
            sound.setMute();
        });
        this.emit('mute', this, value);
    }
});
/**
 * Global volume setting.
 *
 * @name Phaser.Sound.HTML5AudioSoundManager#volume
 * @property {number} volume
 */
Object.defineProperty(HTML5AudioSoundManager.prototype, 'volume', {
    get: function () {
        return this._volume;
    },
    set: function (value) {
        this._volume = value;
        this.forEachActiveSound(function (sound) {
            sound.setVolume();
        });
        this.emit('volume', this, value);
    }
});
module.exports = HTML5AudioSoundManager;
<|endoftext|>


<commit_before>var path = require('path')
var execspawn = require('execspawn')

var boot = function (cmd, opts) {
  return execspawn(boot.command(cmd, opts), opts)
}

boot.command = function (cmd, opts) {
  if (typeof cmd !== 'string') throw new Error('Command must be a string')
  if (!opts) opts = {}

  var dir = opts.cwd || process.cwd()
  var volumes = opts.volumes || {}
  var cmds = []
  var cleanup = []

  var procPath = JSON.stringify(path.resolve(path.join(dir, 'proc')))
  var sysPath = JSON.stringify(path.resolve(path.join(dir, 'sys')))
  var devPath = JSON.stringify(path.resolve(path.join(dir, 'dev')))

  cmds.push('mount -t proc proc ' + procPath)
  cmds.push('mount -t sysfs sys ' + sysPath)
  cmds.push('mount -t bind /dev ' + devPath)

  cleanup.push('umount ' + procPath)
  cleanup.push('umount ' + sysPath)
  cleanup.push('umount ' + devPath)

  Object.keys(volumes).forEach(function (host) {
    var childPath = JSON.stringify(path.join(dir, volumes[host]))
    var hostPath = JSON.stringify(path.resolve(host))
    cmds.push('mkdir -p ' + childPath)
    cmds.push('mount --bind ' + hostPath + ' ' + childPath)
  })

  return '/bin/sh -c \'' + cmds.join('; ') + '\' >/dev/null 2>&1; chroot . ' + cmd + '; ' + cleanup.join('; ')
}

module.exports = boot
<commit_msg>do not mount /dev and do silence errors<commit_after>var path = require('path')
var execspawn = require('execspawn')

var boot = function (cmd, opts) {
  return execspawn(boot.command(cmd, opts), opts)
}

boot.command = function (cmd, opts) {
  if (typeof cmd !== 'string') throw new Error('Command must be a string')
  if (!opts) opts = {}

  var dir = opts.cwd || process.cwd()
  var volumes = opts.volumes || {}
  var cmds = []
  var cleanup = []

  var procPath = JSON.stringify(path.resolve(path.join(dir, 'proc')))
  var sysPath = JSON.stringify(path.resolve(path.join(dir, 'sys')))
  var devPath = JSON.stringify(path.resolve(path.join(dir, 'dev')))

  cmds.push('mount -t proc proc ' + procPath)
  cmds.push('mount -t sysfs sys ' + sysPath)

  cleanup.push('umount ' + procPath)
  cleanup.push('umount ' + sysPath)

  Object.keys(volumes).forEach(function (host) {
    var childPath = JSON.stringify(path.join(dir, volumes[host]))
    var hostPath = JSON.stringify(path.resolve(host))
    cmds.push('mkdir -p ' + childPath)
    cmds.push('mount --bind ' + hostPath + ' ' + childPath)
  })

  return '/bin/sh -c \'' + cmds.join('; ') + '\'; chroot . ' + cmd + '; ' + cleanup.join('; ')
}

module.exports = boot
<|endoftext|>


<commit_before>"use strict";

var env = require("./env"),
    uuidGenerator = require('node-uuid');

var spinTitle = function (expTitle, browser, _timeout) {
  var timeout = typeof _timeout === 'undefined' ? 90 : _timeout;
  timeout.should.be.above(0);
  return browser
    .title()
    .then(function (pageTitle) {
      if (pageTitle.indexOf(expTitle) < 0) {
        return browser
          .sleep(500)
          .then(function () { return spinTitle(expTitle, browser, timeout - 1); });
      }
    });
};

var loadWebView = function (app, browser, urlToLoad, titleToSpin) {
  var uuid = uuidGenerator.v1();
  if (typeof urlToLoad === "undefined") {
    if (app === "chrome" || app === "chromium") {
      urlToLoad = env.CHROME_GUINEA_TEST_END_POINT + '?' + uuid;
    } else {
      urlToLoad = env.GUINEA_TEST_END_POINT + '?' + uuid;
    }
  }
  if (typeof titleToSpin === "undefined") {
    titleToSpin = uuid;
  }
  if (app === "safari" || app === "iwebview") {
    return browser
      .get(urlToLoad)
      .then(function () { return spinTitle(titleToSpin, browser); });
  } else {
    return browser
      .contexts()
      .then(function (ctxs) {
        ctxs.length.should.be.above(0);
        return browser
          .context(ctxs[1])
          .url();
      })
      .then(function (url) {
        if (url !== urlToLoad) {
          return browser
            .get(urlToLoad)
            .then(function () { return spinTitle(titleToSpin, browser); });
        } else {
          return spinTitle(titleToSpin, browser);
        }
      });
  }
};

module.exports = {
  spinTitle: spinTitle,
  loadWebView: loadWebView
};
<commit_msg>make chrome tests skip context check<commit_after>"use strict";

var env = require("./env")
  , _ = require('underscore')
  , uuidGenerator = require('node-uuid');

var spinTitle = function (expTitle, browser, _timeout) {
  var timeout = typeof _timeout === 'undefined' ? 90 : _timeout;
  timeout.should.be.above(0);
  return browser
    .title()
    .then(function (pageTitle) {
      if (pageTitle.indexOf(expTitle) < 0) {
        return browser
          .sleep(500)
          .then(function () { return spinTitle(expTitle, browser, timeout - 1); });
      }
    });
};

var loadWebView = function (app, browser, urlToLoad, titleToSpin) {
  var uuid = uuidGenerator.v1();
  if (typeof urlToLoad === "undefined") {
    if (app === "chrome" || app === "chromium") {
      urlToLoad = env.CHROME_GUINEA_TEST_END_POINT + '?' + uuid;
    } else {
      urlToLoad = env.GUINEA_TEST_END_POINT + '?' + uuid;
    }
  }
  if (typeof titleToSpin === "undefined") {
    titleToSpin = uuid;
  }
  if (_.contains(["safari", "iwebview", "chrome", "chromium"], app)) {
    return browser
      .get(urlToLoad)
      .then(function () { return spinTitle(titleToSpin, browser); });
  } else {
    return browser
      .contexts()
      .then(function (ctxs) {
        ctxs.length.should.be.above(0);
        return browser
          .context(ctxs[1])
          .url();
      })
      .then(function (url) {
        if (url !== urlToLoad) {
          return browser
            .get(urlToLoad)
            .then(function () { return spinTitle(titleToSpin, browser); });
        } else {
          return spinTitle(titleToSpin, browser);
        }
      });
  }
};

module.exports = {
  spinTitle: spinTitle,
  loadWebView: loadWebView
};
<|endoftext|>


<commit_before>
'use strict';

const request = require('supertest');
const Koa = require('../..');

describe('app.use(fn)', function(){
  it('should compose middleware', function(done){
    const app = new Koa();
    const calls = [];

    app.use(function *(ctx, next){
      calls.push(1);
      yield next();
      calls.push(6);
    });

    app.use(function *(ctx, next){
      calls.push(2);
      yield next();
      calls.push(5);
    });

    app.use(function *(ctx, next){
      calls.push(3);
      yield next();
      calls.push(4);
    });

    const server = app.listen();

    request(server)
    .get('/')
    .expect(404)
    .end(function(err){
      if (err) return done(err);
      calls.should.eql([1, 2, 3, 4, 5, 6]);
      done();
    });
  });

  // https://github.com/koajs/koa/pull/530#issuecomment-148138051
  it('should catch thrown errors in non-async functions', function(done){
    const app = new Koa();

    app.use(ctx => {
      ctx.throw('Not Found', 404);
    });

    request(app.listen())
    .get('/')
    .expect(404)
    .end(done);
  });
});
<commit_msg>Update test: application -> use() should throw if not a function<commit_after>
'use strict';

const request = require('supertest');
const Koa = require('../..');

describe('app.use(fn)', function(){
  it('should compose middleware', function(done){
    const app = new Koa();
    const calls = [];

    app.use(function *(ctx, next){
      calls.push(1);
      yield next();
      calls.push(6);
    });

    app.use(function *(ctx, next){
      calls.push(2);
      yield next();
      calls.push(5);
    });

    app.use(function *(ctx, next){
      calls.push(3);
      yield next();
      calls.push(4);
    });

    const server = app.listen();

    request(server)
    .get('/')
    .expect(404)
    .end(function(err){
      if (err) return done(err);
      calls.should.eql([1, 2, 3, 4, 5, 6]);
      done();
    });
  });

  // https://github.com/koajs/koa/pull/530#issuecomment-148138051
  it('should catch thrown errors in non-async functions', function(done){
    const app = new Koa();

    app.use(ctx => {
      ctx.throw('Not Found', 404);
    });

    request(app.listen())
    .get('/')
    .expect(404)
    .end(done);
  });

  it('should throw error for non function', function(done){
    const app = new Koa();

    (() => app.use('not a function')).should.throw('middleware must be a function!');
    done();
  });
});
<|endoftext|>


<commit_before>var path          = require('path');
var should        = require('chai').should();
var expect        = require('chai').expect;
var avisynth      = require('../main');
var Script        = require('../code/script');
var loader        = require('../code/loader');
var pluginSystem  = require('../code/plugins');
var AvisynthError = require('../code/errors').AvisynthError;

describe('avisynth.Script', function() {
    var baseRefs = loader.references;
    var fakePluginsDir = path.resolve(__dirname, 'plugins');
    var scriptPath = path.resolve(fakePluginsDir, 'colors_rgb.avsi');
    var pluginPath = path.resolve(fakePluginsDir, 'DeDup.dll');
    var textFile   = path.resolve(fakePluginsDir, 'colors_rgb.txt');
    var missing    = path.resolve(fakePluginsDir, 'non-existent.dll');
    var rand = Math.random(); // Guess what, initializing it takes ~260ms for me on Win7.

    it('should be a Script construtor', function() {
        avisynth.Script.should.be.a('function');
        (new avisynth.Script).should.be.instanceof(Script);
    });

    it('should accept omitting the "new" operator', function() {
        avisynth.Script().should.be.instanceof(Script);
    });

    describe('instances', function() {
        it('should accept a code parameter, and include it as a property', function() {
            var code = '\nVersion()\n\nSubtitle("' + rand + '")';
            avisynth.Script(code).rawCode.should.equal(code);
        });

        it('should have empty code if no code was provided', function() {
            avisynth.Script().rawCode.should.equal('');
        });

        it('should integrate with the plugins by prototypal inheritance', function() {
            var script = new avisynth.Script();
            Object.getPrototypeOf(script).should.equal(pluginSystem.pluginPrototype);
        });

        describe('.load', function() {
            it('should load scripts and plugins from given paths', function() {
                var script = avisynth.Script();
                script.load(scriptPath);
                script.load(pluginPath);
                script.references[scriptPath].should.equal('script');
                script.references[pluginPath].should.equal('plugin');
            });

            it('should throw an error for an invalid path', function() {
                var script = avisynth.Script();
                var directory = fakePluginsDir;
                script.load.bind(script,  textFile).should.throw(AvisynthError);
                script.load.bind(script,   missing).should.throw(AvisynthError);
                script.load.bind(script, directory).should.throw(AvisynthError);
            });

            it('should not throw errors if told to ignore them', function() {
                var script = avisynth.Script();
                var directory = fakePluginsDir;
                script.load.bind(script,  textFile, true).should.not.throw();
                script.load.bind(script,   missing, true).should.not.throw();
                script.load.bind(script, directory, true).should.not.throw();
            });

            it('should throw error if the path contains an invalid character', function() {
                var script = avisynth.Script();
                var invalid = path.resolve(__dirname, 'zettai-ryōiki/invalid-path.avs');
                script.load.bind(avisynth, invalid).should.throw(AvisynthError);
            });
        });

        describe('.autoload', function() {
            it('should load plugins and scripts from a given directory', function() {
                var script = avisynth.Script();
                script.autoload(fakePluginsDir);
                script.references[scriptPath].should.equal('script');
                script.references[pluginPath].should.equal('plugin');
            });

            it('should throw an error if the directory does not exist', function() {
                var script = avisynth.Script();
                var invalid = path.resolve(__dirname, 'non-existant');
                script.autoload.bind(script, invalid).should.throw(AvisynthError);
            });

            it('should throw error if the path contains an invalid character', function() {
                var script = avisynth.Script();
                var invalid = path.resolve(__dirname, 'zettai-ryōiki');
                script.autoload.bind(avisynth, invalid).should.throw(AvisynthError);
            });
        });

        describe('.allReferences', function() {
            it('should initially return the global references', function() {
                avisynth.Script().allReferences().should.deep.equal(baseRefs);
            });

            it('should be updated when loading or autoloading', function() {
                var script = avisynth.Script();
                expect(script.allReferences()[scriptPath]).to.be.undefined;
                script.load(scriptPath);
                script.allReferences()[scriptPath].should.equal('script');
                expect(script.allReferences()[pluginPath]).to.be.undefined;
                script.load(pluginPath);
                script.allReferences()[pluginPath].should.equal('plugin');
                script = new avisynth.Script;
                expect(script.allReferences()[scriptPath]).to.be.undefined;
                expect(script.allReferences()[pluginPath]).to.be.undefined;
                script.autoload(fakePluginsDir);
                avisynth.Script().allReferences().should.deep.equal(baseRefs);
                script.allReferences()[scriptPath].should.equal('script');
                script.allReferences()[pluginPath].should.equal('plugin');
            });
        });

        describe('.fullCode', function() {
            it('should be a function that returns a string', function() {
                avisynth.Script().fullCode.should.be.a('function');
                avisynth.Script().fullCode().should.be.a('string');
            });

            it('should embed code to load all initial plugins/scripts', function() {
                var expected = '';
                Object.keys(baseRefs).forEach(function(v) {
                    expected += 'LoadPlugin("' + v + '")\n';
                });
                avisynth.Script().fullCode().should.equal(expected);
            });

            it('should also embed code to load further plugins/scripts', function() {
                var script = avisynth.Script();
                script.load(scriptPath);
                script.load(pluginPath);
                var expected = '';
                Object.keys(baseRefs).forEach(function(v) {
                    expected += 'LoadPlugin("' + v + '")\n';
                });
                expected += 'Import("' + scriptPath + '")\n';
                expected += 'LoadPlugin("' + pluginPath + '")\n';
                script.fullCode().should.equal(expected);
            });

            it('should moreover include any code passed to the construtor', function() {
                var code = 'Version()\nSubtitle("' + rand + '")';
                var script = avisynth.Script(code);
                script.load(scriptPath);
                script.load(pluginPath);
                var expected = '';
                Object.keys(baseRefs).forEach(function(v) {
                    expected += 'LoadPlugin("' + v + '")\n';
                });
                expected += 'Import("' + scriptPath + '")\n';
                expected += 'LoadPlugin("' + pluginPath + '")\n';
                expected += code + '\n';
                script.fullCode().should.equal(expected);
            });
        });

        describe('.code', function() {
            it('should be a function that allows adding code', function() {
                var code = '\nVersion()\n\nSubtitle("'+rand+'")\nSharpen(1)';
                var lines = code.split('\n');
                var script = new avisynth.Script(code);
                lines.forEach(function(line) {
                    script.code(line);
                });
                script.code(code);
                script.rawCode.should.equal(code + '\n' + code + '\n' + code + '\n');
                script.rawCode.should.equal([code, code, code, ''].join('\n'));
            });
        });
    });
});
<commit_msg>Breaking it on purpose again. Testing stuff.<commit_after>var path          = require('path');
var should        = require('chai').should();
var expect        = require('chai').expect;
var avisynth      = require('../main');
var Script        = require('../code/script');
var loader        = require('../code/loader');
var pluginSystem  = require('../code/plugins');
var AvisynthError = require('../code/errors').AvisynthError;

describe('avisynth.Script', function() {
    var baseRefs = loader.references;
    var fakePluginsDir = path.resolve(__dirname, 'plugins');
    var scriptPath = path.resolve(fakePluginsDir, 'colors_rgb.avsi');
    var pluginPath = path.resolve(fakePluginsDir, 'DeDup.dll');
    var textFile   = path.resolve(fakePluginsDir, 'colors_rgb.txt');
    var missing    = path.resolve(fakePluginsDir, 'non-existent.dll');
    var rand = Math.random(); // Guess what, initializing it takes ~260ms for me on Win7.

    it('should be a Script construtor', function() {
        avisynth.Script.should.be.a('function');
        (new avisynth.Script).should.be.instanceof(Script);
    });

    it('should accept omitting the "new" operator', function() {
        avisynth.Script().should.be.instanceof(Script);
    });

    describe('instances', function() {
        it('should accept a code parameter, and include it as a property', function() {
            var code = '\nVersion()\n\nSubtitle("' + rand + '")';
            avisynth.Script(code).rawCode.should.equal(code);
        });

        it('should have empty code if no code was provided', function() {
            avisynth.Script().rawCode.should.equal('');
        });

        it('should integrate with the plugins by prototypal inheritance', function() {
            var script = new avisynth.Script();
            Object.getPrototypeOf(script).should.equal(pluginSystem.pluginPrototype);
        });

        describe('.load', function() {
            it('should load scripts and plugins from given paths', function() {
                var script = avisynth.Script();
                script.load(scriptPath);
                script.load(pluginPath);
                script.references[scriptPath].should.equal('script');
                script.references[pluginPath].should.equal('plugin');
            });

            it('should throw an error for an invalid path', function() {
                var script = avisynth.Script();
                var directory = fakePluginsDir;
                script.load.bind(script,  textFile).should.throw(AvisynthError);
                script.load.bind(script,   missing).should.throw(AvisynthError);
                script.load.bind(script, directory).should.throw(AvisynthError);
            });

            it('should not throw errors if told to ignore them', function() {
                var script = avisynth.Script();
                var directory = fakePluginsDir;
                script.load.bind(script,  textFile, true).should.not.throw();
                script.load.bind(script,   missing, true).should.not.throw();
                script.load.bind(script, directory, true).should.not.throw();
            });

            it('should throw error if the path contains an invalid character', function() {
                var script = avisynth.Script();
                var invalid = path.resolve(__dirname, 'zettai-ryōiki/invalid-path.avs');
                script.load.bind(avisynth, invalid).should.throw(AvisynthError);
            });
        });

        describe('.autoload', function() {
            it('should load plugins and scripts from a given directory', function() {
                var script = avisynth.Script();
                script.autoload(fakePluginsDir);
                script.references[scriptPath].should.equal('script');
                script.references[pluginPath].should.equal('plugin');
            });

            it('should throw an error if the directory does not exist', function() {
                var script = avisynth.Script();
                var invalid = path.resolve(__dirname, 'non-existant');
                script.autoload.bind(script, invalid).should.throw(AvisynthError);
            });

            it('should throw error if the path contains an invalid character', function() {
                var script = avisynth.Script();
                var invalid = path.resolve(__dirname, 'zettai-ryōiki');
                script.autoload.bind(avisynth, invalid).should.throw(AvisynthError);
            });
        });

        describe('.allReferences', function() {
            it('should initially return the global references', function() {
                avisynth.Script().allReferences().should.deep.equal(baseRefs);
            });

            it('should be updated when loading or autoloading', function() {
                var script = avisynth.Script();
                expect(script.allReferences()[scriptPath]).to.be.undefined;
                script.load(scriptPath);
                script.allReferences()[scriptPath].should.equal('script');
                expect(script.allReferences()[pluginPath]).to.be.undefined;
                script.load(pluginPath);
                script.allReferences()[pluginPath].should.equal('plugin');
                script = new avisynth.Script;
                expect(script.allReferences()[scriptPath]).to.be.undefined;
                expect(script.allReferences()[pluginPath]).to.be.undefined;
                script.autoload(fakePluginsDir);
                avisynth.Script().allReferences().should.deep.equal(baseRefs);
                script.allReferences()[scriptPath].should.equal('script');
                script.allReferences()[pluginPath].should.equal('plugin');
            });
        });

        describe('.fullCode', function() {
            it('should be a function that returns a string', function() {
                avisynth.Script().fullCode.should.be.a('function');
                avisynth.Script().fullCode().should.be.a('string');
            });

            it('should embed code to load all initial plugins/scripts', function() {
                var expected = '';
                Object.keys(baseRefs).forEach(function(v) {
                    expected += 'LoadPlugin("' + v + '")\n';
                });
                avisynth.Script().fullCode().should.equal(expected);
            });

            it('should also embed code to load further plugins/scripts', function() {
                var script = avisynth.Script();
                script.load(scriptPath);
                script.load(pluginPath);
                var expected = '';
                Object.keys(baseRefs).forEach(function(v) {
                    expected += 'LoadPlugin("' + v + '")\n';
                });
                expected += 'Import("' + scriptPath + '")\n';
                expected += 'LoadPlugin("' + pluginPath + '")\n';
                script.fullCode().should.equal(expected);
            });

            it('should moreover include any code passed to the construtor', function() {
                var code = 'Version()\nSubtitle("' + rand + '")';
                var script = avisynth.Script(code);
                script.load(scriptPath);
                script.load(pluginPath);
                var expected = '';
                Object.keys(baseRefs).forEach(function(v) {
                    expected += 'LoadPlugin("' + v + '")\n';
                });
                expected += 'Import("' + scriptPath + '")\n';
                expected += 'LoadPlugin("' + pluginPath + '")\n';
                expected += code + '\n';
                script.fullCode().should.equal(expected);
            });
        });

        //describe('.code', function() {
        //    it('should be a function that allows adding code', function() {
        //        var code = '\nVersion()\n\nSubtitle("'+rand+'")\nSharpen(1)';
        //        var lines = code.split('\n');
        //        var script = new avisynth.Script(code);
        //        lines.forEach(function(line) {
        //            script.code(line);
        //        });
        //        script.code(code);
        //        script.rawCode.should.equal(code + '\n' + code + '\n' + code + '\n');
        //        script.rawCode.should.equal([code, code, code, ''].join('\n'));
        //    });
        //});
    });
});
<|endoftext|>


<commit_before>suite('group-player', function() {
  setup(function() {
    document.timeline.players = [];
    this.elements = [];

    var animationMargin = function(target) {
      return new Animation(
          target,
          [
           {marginLeft: '0px'},
           {marginLeft: '100px'}
          ],
          500);
    };
    var animationColor = function(target) {
      return new Animation(
          target,
          [
           {backgroundColor: 'black'},
           {backgroundColor: 'white'}
          ],
          500);
    };

    var sequenceEmpty = function() {
      return new AnimationSequence();
    };
    var groupEmpty = function() {
      return new AnimationGroup();
    };
    var sequenceWithEffects = function(target) {
      return new AnimationSequence(
          [
           animationMargin(target),
           animationColor(target)
          ]);
    };
    var groupWithEffects = function(target) {
      return new AnimationGroup(
          [
           animationMargin(target),
           animationColor(target)
          ]);
    };

    var seqEmpty_source = sequenceEmpty();

    var seqSimple_target = document.createElement('div');
    var seqSimple_source = sequenceWithEffects(seqSimple_target);

    var seqWithSeq_target = document.createElement('div');
    this.elements.push(seqWithSeq_target);
    var seqWithSeq_source = new AnimationSequence(
        [
         animationMargin(seqWithSeq_target),
         animationColor(seqWithSeq_target),
         sequenceWithEffects(seqWithSeq_target)
        ]);

    var seqWithGroup_target = document.createElement('div');
    this.elements.push(seqWithGroup_target);
    var seqWithGroup_source = new AnimationSequence(
        [
         animationMargin(seqWithGroup_target),
         animationColor(seqWithGroup_target),
         groupWithEffects(seqWithGroup_target)
        ]);

    var seqWithEmptyGroup_source = new AnimationSequence([groupEmpty()]);
    var seqWithEmptySeq_source = new AnimationSequence([sequenceEmpty()]);

    var groupEmpty_source = groupEmpty();

    var groupSimple_target = document.createElement('div');
    var groupSimple_source = groupWithEffects(groupSimple_target);

    var groupWithSeq_target = document.createElement('div');
    this.elements.push(groupWithSeq_target);
    var groupWithSeq_source = new AnimationGroup(
        [
         animationMargin(groupWithSeq_target),
         animationColor(groupWithSeq_target),
         sequenceWithEffects(groupWithSeq_target)
        ]);

    var groupWithGroup_target = document.createElement('div');
    this.elements.push(groupWithGroup_target);
    var groupWithGroup_source = new AnimationGroup(
        [
         animationMargin(groupWithGroup_target),
         animationColor(groupWithGroup_target),
         groupWithEffects(groupWithGroup_target)
        ]);

    var groupWithEmptyGroup_source = new AnimationGroup([groupEmpty()]);
    var groupWithEmptySeq_source = new AnimationGroup([sequenceEmpty()]);

    this.seqEmpty_source = seqEmpty_source;
    this.seqSimple_source = seqSimple_source;
    this.seqWithSeq_source = seqWithSeq_source;
    this.seqWithGroup_source = seqWithGroup_source;
    this.seqWithEmptyGroup_source = seqWithEmptyGroup_source;
    this.seqWithEmptySeq_source = seqWithEmptySeq_source;

    this.groupEmpty_source = groupEmpty_source;
    this.groupSimple_source = groupSimple_source;
    this.groupWithSeq_source = groupWithSeq_source;
    this.groupWithGroup_source = groupWithGroup_source;
    this.groupWithEmptyGroup_source = groupWithEmptyGroup_source;
    this.groupWithEmptySeq_source = groupWithEmptySeq_source;

    var staticAnimation = function(target, value, duration) {
      return new Animation(target, [{marginLeft: value}, {marginLeft: value}], duration);
    };
    // The following animation structure looks like:
    // 44444
    // 11
    //   33
    //   2
    // 0
    this.complexTarget = document.createElement('div');
    this.elements.push(this.complexTarget);
    this.complexSource = new AnimationGroup([
      staticAnimation(this.complexTarget, '4px', 5),
      new AnimationSequence([
        staticAnimation(this.complexTarget, '1px', 2),
        new AnimationGroup([
          staticAnimation(this.complexTarget, '3px', 2),
          staticAnimation(this.complexTarget, '2px', 1),
        ]),
      ]),
      staticAnimation(this.complexTarget, '0px', 1),
    ]);

    for (var i = 0; i < this.elements.length; i++)
      document.documentElement.appendChild(this.elements[i]);
  });

  teardown(function() {
    for (var i = 0; i < this.elements.length; i++)
      this.elements[i].remove();
  });

  function simpleAnimationGroup() {
    return new AnimationGroup([new Animation(document.body, [], 2000), new Animation(document.body, [], 1000), new Animation(document.body, [], 3000)]);
  }

  function simpleAnimationSequence() {
    return new AnimationSequence([new Animation(document.body, [], 2000), new Animation(document.body, [], 1000), new Animation(document.body, [], 3000)]);
  }

  // topTimes and restOfTimes contain duplets (startTime, currentTime)
  // and triplets (startTime, currentTime, startOffset)
  function checkTimes(player, topTimes, restOfTimes, description) {
    description = description ? (description + ' ') : '';
    _checkTimes(player, topTimes, 0, description + 'toplevel');
    _checkTimes(player, restOfTimes, 0, description + 'internals');
  }

  function _checkTimes(player, timingList, index, trace) {
    if (timingList.length == 0) {
      return;
    }
    if (timingList[0] == null || typeof timingList[0] == 'number') {
      assert.equal(player._startTime, timingList[0], trace + ' startTime');
      assert.equal(player.currentTime, timingList[1], trace + ' currentTime');
      if (timingList.length == 3)
        assert.equal(player._startOffset, timingList[2], trace + ' startOffset');
    } else {
      _checkTimes(player.childPlayers[index], timingList[0], 0, trace + ' ' + index);
      _checkTimes(player, timingList.slice(1), index + 1, trace);
    }
  }

  test('playing an animationGroup works as expected', function() {
    tick(100);
    var p = document.timeline.play(simpleAnimationGroup());
    checkTimes(p, [100, 0], [[100, 0, 0], [100, 0, 0], [100, 0, 0]]);
    tick(300);
    checkTimes(p, [100, 200], [[100, 200], [100, 200], [100, 200]]);
    tick(1200);
    checkTimes(p, [100, 1100], [[100, 1100], [100, 1000], [100, 1100]]);
    tick(2200);
    checkTimes(p, [100, 2100], [[100, 2000], [100, 1000], [100, 2100]]);
    tick(3200);
    // TODO Limit toplevel currentTime
    checkTimes(p, [100, 3100], [[100, 2000], [100, 1000], [100, 3000]]);
  });

  test('playing an animationSequence works as expected', function() {
    tick(110);
    var p = document.timeline.play(simpleAnimationSequence());
    checkTimes(p, [110, 0], [[110, 0], [2110, -2000, 2000], [3110, -3000, 3000]]);
    tick(210);
    checkTimes(p, [110, 100], [[110, 100], [2110, -1900, 2000], [3110, -2900, 3000]]);
  });

  test('complex animation tree timing while playing', function() {
    tick(100);
    var player = document.timeline.play(this.complexSource);
    checkTimes(player, [100, 0], [
      [100, 0, 0], [ // 4
        [100, 0, 0], [ // 1
          [102, -2, 0], // 3
          [102, -2, 0]]], // 2
      [100, 0, 0], // 0
    ], 't = 100');
    tick(101);
    checkTimes(player, [100, 1], [
      [100, 1, 0], [ // 4
        [100, 1, 0], [ // 1
          [102, -1, 0], // 3
          [102, -1, 0]]], // 2
      [100, 1, 0], // 0
    ], 't = 101');
    tick(102);
    checkTimes(player, [100, 2], [
      [100, 2, 0], [ // 4
        [100, 2, 0], [ // 1
          [102, 0, 0], // 3
          [102, 0, 0]]], // 2
      [100, 1, 0], // 0
    ], 't = 102');
  });

  test('effects apply in the correct order', function() {
    tick(0);
    var player = document.timeline.play(this.complexSource);
    player.currentTime = 0;
    assert.equal(getComputedStyle(this.complexTarget).marginLeft, '0px');
    player.currentTime = 1;
    checkTimes(player, [-1, 1], [[-1, 1, 0], [[-1, 1, 0], [[1, -1, 0], [1, -1, 0]]], [-1, 1, 0]]);
    assert.equal(getComputedStyle(this.complexTarget).marginLeft, '1px');
    player.currentTime = 2;
    checkTimes(player, [-2, 2], [[-2, 2, 0], [[-2, 2, 0], [[0, 0, 0], [0, 0, 0]]], [-2, 1, 0]]);
    assert.equal(getComputedStyle(this.complexTarget).marginLeft, '2px');
    player.currentTime = 3;
    assert.equal(getComputedStyle(this.complexTarget).marginLeft, '3px');
    player.currentTime = 4;
    assert.equal(getComputedStyle(this.complexTarget).marginLeft, '4px');
    player.currentTime = 5;
    assert.equal(getComputedStyle(this.complexTarget).marginLeft, '0px');
  });

  test('cancelling group players', function() {
    tick(0);
    var player = document.timeline.play(this.complexSource);
    tick(3);
    assert.equal(getComputedStyle(this.complexTarget).marginLeft, '3px');
    player.cancel();
    assert.equal(player.currentTime, 0);
    assert.equal(getComputedStyle(this.complexTarget).marginLeft, '0px');
  });

  // FIXME: This test can be removed when this suite is finished.
  test('sources are working for basic operations', function() {
    var player_a = document.timeline.play(this.seqEmpty_source);
    var player_b = document.timeline.play(this.seqSimple_source);
    var player_c = document.timeline.play(this.seqWithSeq_source);
    var player_d = document.timeline.play(this.seqWithGroup_source);
    var player_e = document.timeline.play(this.seqWithEmptyGroup_source);
    var player_f = document.timeline.play(this.seqWithEmptySeq_source);

    var player_g = document.timeline.play(this.groupEmpty_source);
    var player_h = document.timeline.play(this.groupSimple_source);
    var player_i = document.timeline.play(this.groupWithSeq_source);
    var player_j = document.timeline.play(this.groupWithGroup_source);
    var player_k = document.timeline.play(this.groupWithEmptyGroup_source);
    var player_l = document.timeline.play(this.groupWithEmptySeq_source);

    tick(200);
    player_a.pause();
    player_b.pause();
    player_c.pause();
    player_d.pause();
    player_e.pause();
    player_f.pause();
    player_g.pause();
    player_h.pause();
    player_i.pause();
    player_j.pause();
    player_k.pause();
    player_l.pause();

    player_a.play();
    player_b.play();
    player_c.play();
    player_d.play();
    player_e.play();
    player_f.play();
    player_g.play();
    player_h.play();
    player_i.play();
    player_j.play();
    player_k.play();
    player_l.play();
    tick(300);

    player_a.currentTime += 1;
    player_b.currentTime += 1;
    player_c.currentTime += 1;
    player_d.currentTime += 1;
    player_e.currentTime += 1;
    player_f.currentTime += 1;
    player_g.currentTime += 1;
    player_h.currentTime += 1;
    player_i.currentTime += 1;
    player_j.currentTime += 1;
    player_k.currentTime += 1;
    player_l.currentTime += 1;
  });

});
<commit_msg>Clean up the test that tests the sources<commit_after>suite('group-player', function() {
  setup(function() {
    document.timeline.players = [];
    this.elements = [];

    var animationMargin = function(target) {
      return new Animation(
          target,
          [
           {marginLeft: '0px'},
           {marginLeft: '100px'}
          ],
          500);
    };
    var animationColor = function(target) {
      return new Animation(
          target,
          [
           {backgroundColor: 'black'},
           {backgroundColor: 'white'}
          ],
          500);
    };

    var sequenceEmpty = function() {
      return new AnimationSequence();
    };
    var groupEmpty = function() {
      return new AnimationGroup();
    };
    var sequenceWithEffects = function(target) {
      return new AnimationSequence(
          [
           animationMargin(target),
           animationColor(target)
          ]);
    };
    var groupWithEffects = function(target) {
      return new AnimationGroup(
          [
           animationMargin(target),
           animationColor(target)
          ]);
    };

    var seqEmpty_source = sequenceEmpty();

    var seqSimple_target = document.createElement('div');
    var seqSimple_source = sequenceWithEffects(seqSimple_target);

    var seqWithSeq_target = document.createElement('div');
    this.elements.push(seqWithSeq_target);
    var seqWithSeq_source = new AnimationSequence(
        [
         animationMargin(seqWithSeq_target),
         animationColor(seqWithSeq_target),
         sequenceWithEffects(seqWithSeq_target)
        ]);

    var seqWithGroup_target = document.createElement('div');
    this.elements.push(seqWithGroup_target);
    var seqWithGroup_source = new AnimationSequence(
        [
         animationMargin(seqWithGroup_target),
         animationColor(seqWithGroup_target),
         groupWithEffects(seqWithGroup_target)
        ]);

    var seqWithEmptyGroup_source = new AnimationSequence([groupEmpty()]);
    var seqWithEmptySeq_source = new AnimationSequence([sequenceEmpty()]);

    var groupEmpty_source = groupEmpty();

    var groupSimple_target = document.createElement('div');
    var groupSimple_source = groupWithEffects(groupSimple_target);

    var groupWithSeq_target = document.createElement('div');
    this.elements.push(groupWithSeq_target);
    var groupWithSeq_source = new AnimationGroup(
        [
         animationMargin(groupWithSeq_target),
         animationColor(groupWithSeq_target),
         sequenceWithEffects(groupWithSeq_target)
        ]);

    var groupWithGroup_target = document.createElement('div');
    this.elements.push(groupWithGroup_target);
    var groupWithGroup_source = new AnimationGroup(
        [
         animationMargin(groupWithGroup_target),
         animationColor(groupWithGroup_target),
         groupWithEffects(groupWithGroup_target)
        ]);

    var groupWithEmptyGroup_source = new AnimationGroup([groupEmpty()]);
    var groupWithEmptySeq_source = new AnimationGroup([sequenceEmpty()]);

    this.seqEmpty_source = seqEmpty_source;
    this.seqSimple_source = seqSimple_source;
    this.seqWithSeq_source = seqWithSeq_source;
    this.seqWithGroup_source = seqWithGroup_source;
    this.seqWithEmptyGroup_source = seqWithEmptyGroup_source;
    this.seqWithEmptySeq_source = seqWithEmptySeq_source;

    this.groupEmpty_source = groupEmpty_source;
    this.groupSimple_source = groupSimple_source;
    this.groupWithSeq_source = groupWithSeq_source;
    this.groupWithGroup_source = groupWithGroup_source;
    this.groupWithEmptyGroup_source = groupWithEmptyGroup_source;
    this.groupWithEmptySeq_source = groupWithEmptySeq_source;

    var staticAnimation = function(target, value, duration) {
      return new Animation(target, [{marginLeft: value}, {marginLeft: value}], duration);
    };
    // The following animation structure looks like:
    // 44444
    // 11
    //   33
    //   2
    // 0
    this.complexTarget = document.createElement('div');
    this.elements.push(this.complexTarget);
    this.complexSource = new AnimationGroup([
      staticAnimation(this.complexTarget, '4px', 5),
      new AnimationSequence([
        staticAnimation(this.complexTarget, '1px', 2),
        new AnimationGroup([
          staticAnimation(this.complexTarget, '3px', 2),
          staticAnimation(this.complexTarget, '2px', 1),
        ]),
      ]),
      staticAnimation(this.complexTarget, '0px', 1),
    ]);

    for (var i = 0; i < this.elements.length; i++)
      document.documentElement.appendChild(this.elements[i]);
  });

  teardown(function() {
    for (var i = 0; i < this.elements.length; i++)
      this.elements[i].remove();
  });

  function simpleAnimationGroup() {
    return new AnimationGroup([new Animation(document.body, [], 2000), new Animation(document.body, [], 1000), new Animation(document.body, [], 3000)]);
  }

  function simpleAnimationSequence() {
    return new AnimationSequence([new Animation(document.body, [], 2000), new Animation(document.body, [], 1000), new Animation(document.body, [], 3000)]);
  }

  // topTimes and restOfTimes contain duplets (startTime, currentTime)
  // and triplets (startTime, currentTime, startOffset)
  function checkTimes(player, topTimes, restOfTimes, description) {
    description = description ? (description + ' ') : '';
    _checkTimes(player, topTimes, 0, description + 'toplevel');
    _checkTimes(player, restOfTimes, 0, description + 'internals');
  }

  function _checkTimes(player, timingList, index, trace) {
    if (timingList.length == 0) {
      return;
    }
    if (timingList[0] == null || typeof timingList[0] == 'number') {
      assert.equal(player._startTime, timingList[0], trace + ' startTime');
      assert.equal(player.currentTime, timingList[1], trace + ' currentTime');
      if (timingList.length == 3)
        assert.equal(player._startOffset, timingList[2], trace + ' startOffset');
    } else {
      _checkTimes(player.childPlayers[index], timingList[0], 0, trace + ' ' + index);
      _checkTimes(player, timingList.slice(1), index + 1, trace);
    }
  }

  test('playing an animationGroup works as expected', function() {
    tick(100);
    var p = document.timeline.play(simpleAnimationGroup());
    checkTimes(p, [100, 0], [[100, 0, 0], [100, 0, 0], [100, 0, 0]]);
    tick(300);
    checkTimes(p, [100, 200], [[100, 200], [100, 200], [100, 200]]);
    tick(1200);
    checkTimes(p, [100, 1100], [[100, 1100], [100, 1000], [100, 1100]]);
    tick(2200);
    checkTimes(p, [100, 2100], [[100, 2000], [100, 1000], [100, 2100]]);
    tick(3200);
    // TODO Limit toplevel currentTime
    checkTimes(p, [100, 3100], [[100, 2000], [100, 1000], [100, 3000]]);
  });

  test('playing an animationSequence works as expected', function() {
    tick(110);
    var p = document.timeline.play(simpleAnimationSequence());
    checkTimes(p, [110, 0], [[110, 0], [2110, -2000, 2000], [3110, -3000, 3000]]);
    tick(210);
    checkTimes(p, [110, 100], [[110, 100], [2110, -1900, 2000], [3110, -2900, 3000]]);
  });

  test('complex animation tree timing while playing', function() {
    tick(100);
    var player = document.timeline.play(this.complexSource);
    checkTimes(player, [100, 0], [
      [100, 0, 0], [ // 4
        [100, 0, 0], [ // 1
          [102, -2, 0], // 3
          [102, -2, 0]]], // 2
      [100, 0, 0], // 0
    ], 't = 100');
    tick(101);
    checkTimes(player, [100, 1], [
      [100, 1, 0], [ // 4
        [100, 1, 0], [ // 1
          [102, -1, 0], // 3
          [102, -1, 0]]], // 2
      [100, 1, 0], // 0
    ], 't = 101');
    tick(102);
    checkTimes(player, [100, 2], [
      [100, 2, 0], [ // 4
        [100, 2, 0], [ // 1
          [102, 0, 0], // 3
          [102, 0, 0]]], // 2
      [100, 1, 0], // 0
    ], 't = 102');
  });

  test('effects apply in the correct order', function() {
    tick(0);
    var player = document.timeline.play(this.complexSource);
    player.currentTime = 0;
    assert.equal(getComputedStyle(this.complexTarget).marginLeft, '0px');
    player.currentTime = 1;
    checkTimes(player, [-1, 1], [[-1, 1, 0], [[-1, 1, 0], [[1, -1, 0], [1, -1, 0]]], [-1, 1, 0]]);
    assert.equal(getComputedStyle(this.complexTarget).marginLeft, '1px');
    player.currentTime = 2;
    checkTimes(player, [-2, 2], [[-2, 2, 0], [[-2, 2, 0], [[0, 0, 0], [0, 0, 0]]], [-2, 1, 0]]);
    assert.equal(getComputedStyle(this.complexTarget).marginLeft, '2px');
    player.currentTime = 3;
    assert.equal(getComputedStyle(this.complexTarget).marginLeft, '3px');
    player.currentTime = 4;
    assert.equal(getComputedStyle(this.complexTarget).marginLeft, '4px');
    player.currentTime = 5;
    assert.equal(getComputedStyle(this.complexTarget).marginLeft, '0px');
  });

  test('cancelling group players', function() {
    tick(0);
    var player = document.timeline.play(this.complexSource);
    tick(3);
    assert.equal(getComputedStyle(this.complexTarget).marginLeft, '3px');
    player.cancel();
    assert.equal(player.currentTime, 0);
    assert.equal(getComputedStyle(this.complexTarget).marginLeft, '0px');
  });

  // FIXME: This test can be removed when this suite is finished.
  test('sources are working for basic operations', function() {
    var players = [];
    players.push(document.timeline.play(this.seqEmpty_source));
    players.push(document.timeline.play(this.seqSimple_source));
    players.push(document.timeline.play(this.seqWithSeq_source));
    players.push(document.timeline.play(this.seqWithGroup_source));
    players.push(document.timeline.play(this.seqWithEmptyGroup_source));
    players.push(document.timeline.play(this.seqWithEmptySeq_source));

    players.push(document.timeline.play(this.groupEmpty_source));
    players.push(document.timeline.play(this.groupSimple_source));
    players.push(document.timeline.play(this.groupWithSeq_source));
    players.push(document.timeline.play(this.groupWithGroup_source));
    players.push(document.timeline.play(this.groupWithEmptyGroup_source));
    players.push(document.timeline.play(this.groupWithEmptySeq_source));

    var length = players.length;

    tick(100);
    for (var i = 0; i < length; i++)
      players[i].pause();

    tick(200);
    for (var i = 0; i < length; i++)
      players[i].pause();

    tick(300);
    for (var i = 0; i < length; i++)
      players[i].currentTime += 1;

    tick(400);
    for (var i = 0; i < length; i++)
      players[i].startTime += 1;
  });

});
<|endoftext|>