<commit_before>/* Copyright (c) Royal Holloway, University of London | Contact Blake Loring (blake@parsed.uk), Duncan Mitchell (Duncan.Mitchell.2015@rhul.ac.uk), or Johannes Kinder (johannes.kinder@rhul.ac.uk) for details or support | LICENSE.md for license details */

"use strict";

class Coverage {

    constructor() {
        this._current = {};
    }

	_getFile(file) {
		if (!this._current[file]) {
			this._current[file] = {
				smap: [],
				branches: [],
				lines: {
                  all: new Set(),
                  touched: new Set()
                }
			};
		}
		return this._current[file];
	}

	_addSMap(f, smap) {
		f.smap = smap;
	}

	_mergeBranches(f, branches) {
		for (let i in branches) {
			f.branches[i] = 1;
		}
	}

    _mergeLineNumbers(set, lineNumbers) {
        lineNumbers.forEach(lineNumber => {
            set.add(lineNumber);
        });
    }

    /**
     * Merges new coverage data from a path with existing data
       */
    add(coverage) {
        for (let i in coverage) {
            let file = this._getFile(i);
            this._addSMap(file, coverage[i].smap);
            this._mergeBranches(file, coverage[i].branches);
            this._mergeLineNumbers(file.lines.all, coverage[i].lines.all);
            this._mergeLineNumbers(file.lines.touched, coverage[i].lines.touched);
        }
    }

	_termResults(file) {
		let found = 0;
		let total = 0;

		for (let i in file.smap) {
			total++;
			found = file.branches[i] ? found + 1 : found;
		}

		return {
			found: found,
			total: total,
			coverage: found / total
		}
	}

    _locResults(file) {
        let touchedLines = Array.from(file.lines.touched).sort((a, b) => a - b);
        let allLines = Array.from(file.lines.all).sort((a, b) => a - b);
        return {
            touched: touchedLines,
            all: allLines,
            found: touchedLines.length,
            total: allLines.length,
            coverage: touchedLines.length / allLines.length
        }
    }

    final() {
        let results = [];

        for (let fileName in this._current) {
            let file = this._getFile(fileName);
            results.push({
                file: fileName,
                terms: this._termResults(file),
                loc: this._locResults(file)
            });
        }

        return results;
    }

    /**
     * Final without terms or lines
     * TODO: Doesn't really need to exist
     */
    current() {
        let results = this.final();

        results.forEach(item => {
            delete item.lines.touched;
            delete results.lines.all;
        });

        return results;
    }

    lines() {
        return this.final().reduce((prev, next) => {
            prev[next.file] = {
                all: next.loc.all,
                touched: next.loc.touched
            };
            return prev;
        }, {});
    }
}

export default Coverage;
<commit_msg>item is not lines<commit_after>/* Copyright (c) Royal Holloway, University of London | Contact Blake Loring (blake@parsed.uk), Duncan Mitchell (Duncan.Mitchell.2015@rhul.ac.uk), or Johannes Kinder (johannes.kinder@rhul.ac.uk) for details or support | LICENSE.md for license details */

"use strict";

class Coverage {

    constructor() {
        this._current = {};
    }

	_getFile(file) {
		if (!this._current[file]) {
			this._current[file] = {
				smap: [],
				branches: [],
				lines: {
                  all: new Set(),
                  touched: new Set()
                }
			};
		}
		return this._current[file];
	}

	_addSMap(f, smap) {
		f.smap = smap;
	}

	_mergeBranches(f, branches) {
		for (let i in branches) {
			f.branches[i] = 1;
		}
	}

    _mergeLineNumbers(set, lineNumbers) {
        lineNumbers.forEach(lineNumber => {
            set.add(lineNumber);
        });
    }

    /**
     * Merges new coverage data from a path with existing data
       */
    add(coverage) {
        for (let i in coverage) {
            let file = this._getFile(i);
            this._addSMap(file, coverage[i].smap);
            this._mergeBranches(file, coverage[i].branches);
            this._mergeLineNumbers(file.lines.all, coverage[i].lines.all);
            this._mergeLineNumbers(file.lines.touched, coverage[i].lines.touched);
        }
    }

	_termResults(file) {
		let found = 0;
		let total = 0;

		for (let i in file.smap) {
			total++;
			found = file.branches[i] ? found + 1 : found;
		}

		return {
			found: found,
			total: total,
			coverage: found / total
		}
	}

    _locResults(file) {
        let touchedLines = Array.from(file.lines.touched).sort((a, b) => a - b);
        let allLines = Array.from(file.lines.all).sort((a, b) => a - b);
        return {
            touched: touchedLines,
            all: allLines,
            found: touchedLines.length,
            total: allLines.length,
            coverage: touchedLines.length / allLines.length
        }
    }

    final() {
        let results = [];

        for (let fileName in this._current) {
            let file = this._getFile(fileName);
            results.push({
                file: fileName,
                terms: this._termResults(file),
                loc: this._locResults(file)
            });
        }

        return results;
    }

    /**
     * Final without terms or lines
     * TODO: Doesn't really need to exist
     */
    current() {
        let results = this.final();

        results.forEach(item => {
            delete item.lines.touched;
            delete item.lines.all;
        });

        return results;
    }

    lines() {
        return this.final().reduce((prev, next) => {
            prev[next.file] = {
                all: next.loc.all,
                touched: next.loc.touched
            };
            return prev;
        }, {});
    }
}

export default Coverage;
<|endoftext|>


<commit_before>/**
 * Adds a new notification to the database and enqueues it for delivery via configured channels.
 */

var boom = require('boom');
var hapi = require('hapi');
var logger = require('log4js').getLogger('server');
var models = require('../../db/models');
var notificationUtils = require('./utils');
var routeUtils = require('../utils');

var addNotification = function(request, reply) {

  var notification = notificationUtils.notificationFromPayload(request.payload);

  var success = function(notification) {
    var locationURL = routeUtils.makePrefixedPath('/notifications/' + notification.notificationId);

    var externalNotification = notification.externalize();
    notificationUtils.sendNotification(
      externalNotification, request.server.methods.dispatchPushNotification);

    reply(externalNotification)
      .code(201)
      .header('Location', locationURL);
  };

  models.Notifications
    .build(notification)
    .save()
    .then(success, function(err) {
      logger.error('unable to add notification %s, error: %s', notification, err);
      reply(boom.badImplementation('unable to add the notification', err));
    });
};

module.exports = addNotification;
<commit_msg>return promise<commit_after>/**
 * Adds a new notification to the database and enqueues it for delivery via configured channels.
 */

var boom = require('boom');
var hapi = require('hapi');
var logger = require('log4js').getLogger('server');
var models = require('../../db/models');
var notificationUtils = require('./utils');
var routeUtils = require('../utils');

var addNotification = function(request, reply) {

  var notification = notificationUtils.notificationFromPayload(request.payload);

  var success = function(notification) {
    var locationURL = routeUtils.makePrefixedPath('/notifications/' + notification.notificationId);

    var externalNotification = notification.externalize();
    notificationUtils.sendNotification(
      externalNotification, request.server.methods.dispatchPushNotification);

    return reply(externalNotification)
      .code(201)
      .header('Location', locationURL);
  };

  models.Notifications
    .build(notification)
    .save()
    .then(success, function(err) {
      logger.error('unable to add notification %s, error: %s', notification, err);
      reply(boom.badImplementation('unable to add the notification', err));
    });
};

module.exports = addNotification;
<|endoftext|>


<commit_before>var add = require('../.');
describe('small fractions', function () {
	describe('in positive range', function () {
		it('works with numbers', function (done) {
			add(0.1, 0.2, function (err, result) {
				expect(err).toEqual(null, 'small fractions are valid');
				expect(result).toEqual('0.3', '0.1+0.2 should be "0.3"');
				done();
			});
		});
		it('works with strings', function (done) {
			add('0.1', '0.2', function (err, result) {
				expect(err).toEqual(null, 'small fractions are valid');
				expect(result).toEqual('0.3', '0.1+0.2 should be "0.3"');
				done();
			});
		});
		it('works with carry', function (done) {
			add('0.05', '0.05', function (err, result) {
				expect(err).toEqual(null, 'small fractions are valid');
				expect(result).toEqual('0.1', '0.05+0.05 should be "0.1"');
				done();
			});
		});
		it('works with carry over', function (done) {
			add('0.55', '0.55', function (err, result) {
				expect(err).toEqual(null, 'small fractions are valid');
				expect(result).toEqual('1.1', '0.55+0.55 should be "1.1"');
				done();
			});
		});

	});
});
<commit_msg>fractions<commit_after>var add = require('../.');
describe('small fractions', function () {
	describe('in positive range', function () {
		it('works with numbers', function (done) {
			add(0.1, 0.2, function (err, result) {
				expect(err).toEqual(null, 'small fractions are valid');
				expect(result).toEqual('0.3', '0.1+0.2 should be "0.3"');
				done();
			});
		});
		it('works with strings', function (done) {
			add('0.1', '0.2', function (err, result) {
				expect(err).toEqual(null, 'small fractions are valid');
				expect(result).toEqual('0.3', '0.1+0.2 should be "0.3"');
				done();
			});
		});
		it('works with carry', function (done) {
			add('0.05', '0.05', function (err, result) {
				expect(err).toEqual(null, 'small fractions are valid');
				expect(result).toEqual('0.1', '0.05+0.05 should be "0.1"');
				done();
			});
		});
		it('works with carry over', function (done) {
			add('0.55', '0.55', function (err, result) {
				expect(err).toEqual(null, 'small fractions are valid');
				expect(result).toEqual('1.1', '0.55+0.55 should be "1.1"');
				done();
			});
		});
		it('works with different length of numbers', function (done) {
			add('0.5', '0.05', function (err, result) {
				expect(err).toEqual(null, 'small fractions are valid');
				expect(result).toEqual('0.55', '0.5+0.05 should be "0.55"');
				done();
			});
		});

	});
});
<|endoftext|>


<commit_before>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

var fs = require('fs');
var https = require('https');
var program = require('commander');
var git = require('simple-git')();
var child_process = require('child_process');
var path = require('path');

var tempFolder = `test_data`;
var testRepoUrl = 'https://github.com/Microsoft/vscode-smoketest-express';
var testRepoLocalDir = path.join(process.cwd(), `${tempFolder}/vscode-smoketest-express`);
var keybindingsUrl = 'https://raw.githubusercontent.com/Microsoft/vscode-docs/master/scripts/keybindings';

program
	.option('-l, --latest <file path>', 'path to the latest VS Code to test')
	.option('-s, --stable [file path]', 'path to the stable VS Code to be used in data migration tests');

program.on('--help', () => {
	console.log('  Examples:');
	console.log('');
	console.log('    $ npm test -- --latest path/to/binary');
	console.log('    $ npm test -- -l path/to/binary');
	console.log('');
	console.log('    $ npm test -- --latest path/to/latest/binary --stable path/to/stable/binary');
	console.log('    $ npm test -- -l path/to/latest/binary -s path/to/stable/binary');
	console.log('');
});
program.parse(process.argv);

if (!program.latest) {
	console.error('You must specify the binary to run the smoke test against');
	process.exit(1);
}
if (!binaryExists(program.latest) || (program.stable && !binaryExists(program.stable))) {
	console.error('The file path to electron binary does not exist or permissions do not allow to execute it. Please check the path provided.');
	process.exit(1);
}

// Setting up environment variables
process.env['VSCODE_LATEST_PATH'] = program.latest;
if (program.stable) process.env['VSCODE_STABLE_PATH'] = program.stable;
process.env['SMOKETEST_REPO'] = testRepoLocalDir;
if (program.stable && program.stable.toLowerCase().startsWith('insiders')) process.env['VSCODE_EDITION'] = 'insiders';

// Setting up 'vscode-smoketest-express' project
var os = process.platform;
if (os === 'darwin') os = 'osx';
else if (os === 'win32') os = 'win';
var promises = [];

try {
	promises.push(getKeybindings(`${keybindingsUrl}/doc.keybindings.${os}.json`, `${tempFolder}/keybindings.json`));
	promises.push(cleanOrClone(testRepoUrl, testRepoLocalDir));

	Promise.all(promises).then(() => { execute('npm install', testRepoLocalDir).then(() => runTests()); });
} catch (e) {
	throw new Error('Error caught running the smoke test: ' + e);
}

function runTests() {
	console.log('Running tests...')
	const spawn = require('child_process').spawn;
	var proc = spawn(process.execPath, [
		'src/mocha-runner.js'
	]);
	proc.stdout.on('data', data => {
		console.log(data.toString());
	});
	proc.stderr.on('data', data => {
		var date = new Date().toLocaleString();
		fs.appendFile(`${tempFolder}/errors.log`, `${date}: ${data.toString()}`, (err) => {
			if (err) throw new Error(`Could not write stderr to errors.log with the following error: ${err}`);
		});
	});
}

function cleanOrClone(repo, dir) {
	console.log('Cleaning or cloning test project repository...');
	return new Promise((res, rej) => {
		if (!folderExists(dir)) {
			git.clone(repo, dir, () => {
				console.log('Test repository successfully cloned.');
				res();
			});
		} else {
			git.cwd(dir);
			git.fetch((err) => {
				if (err) rej(err);
				resetAndClean();
			});
		}

		var resetAndClean = () => {
			git.reset(['FETCH_HEAD', '--hard'], (err) => {
				if (err) rej(err);

				git.clean('f', ['-d'], (err) => {
					if (err) rej(err);
					console.log('Test project was successfully reset to initial state.');
					res();
				});
			});
		}
	});
}

function execute(cmd, dir) {
	return new Promise((res, rej) => {
		console.log(`Running ${cmd}...`);
		var output = child_process.exec(cmd, { cwd: dir, stdio: [0, 1, 2] }, (error, stdout, stderr) => {
			if (error) rej(error);
			if (stderr) console.error(stderr);
			console.log(stdout);
			res();
		});
	});
}

function getKeybindings(url, location) {
	console.log(`Fetching keybindings from ${url}...`);
	return new Promise((resolve, reject) => {
		https.get(url, (res) => {
			if (res.statusCode != 200) {
				reject(`Failed to obtain key bindings with response code: ${res.statusCode}`);
			}

			var buffer = [];
			res.on('data', (chunk) => buffer.push(chunk));
			res.on('end', () => {
				fs.writeFile(location, Buffer.concat(buffer), 'utf8', () => {
					console.log('Keybindings were successfully fetched.');
					resolve();
				});
			});
		}).on('error', (e) => {
			reject(`Failed to obtain key bindings with an error: ${e}`);
		});
	});
}

function folderExists(folder) {
	try {
		fs.accessSync(folder, 'rw');
		return true;
	} catch (e) {
		return false;
	}
}

function binaryExists(filePath) {
	try {
		fs.accessSync(filePath, 'x');
		return true;
	} catch (e) {
		return false;
	}
}<commit_msg>Code sanity.<commit_after>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

var fs = require('fs');
var https = require('https');
var program = require('commander');
var git = require('simple-git')();
var child_process = require('child_process');
var path = require('path');

var tempFolder = 'test_data';
var testRepoUrl = 'https://github.com/Microsoft/vscode-smoketest-express';
var testRepoLocalDir = path.join(process.cwd(), `${tempFolder}/vscode-smoketest-express`);
var keybindingsUrl = 'https://raw.githubusercontent.com/Microsoft/vscode-docs/master/scripts/keybindings';

program
	.option('-l, --latest <file path>', 'path to the latest VS Code to test')
	.option('-s, --stable [file path]', 'path to the stable VS Code to be used in data migration tests');

program.on('--help', () => {
	console.log('  Examples:');
	console.log('');
	console.log('    $ npm test -- --latest path/to/binary');
	console.log('    $ npm test -- -l path/to/binary');
	console.log('');
	console.log('    $ npm test -- --latest path/to/latest/binary --stable path/to/stable/binary');
	console.log('    $ npm test -- -l path/to/latest/binary -s path/to/stable/binary');
	console.log('');
});
program.parse(process.argv);

if (!program.latest) {
	console.error('You must specify the binary to run the smoke test against');
	process.exit(1);
}
if (!binaryExists(program.latest) || (program.stable && !binaryExists(program.stable))) {
	console.error('The file path to electron binary does not exist or permissions do not allow to execute it. Please check the path provided.');
	process.exit(1);
}

// Setting up environment variables
process.env.VSCODE_LATEST_PATH = program.latest;
if (program.stable) process.env.VSCODE_STABLE_PATH = program.stable;
process.env.SMOKETEST_REPO = testRepoLocalDir;
if (program.stable && program.stable.toLowerCase().startsWith('insiders')) process.env.VSCODE_EDITION = 'insiders';

// Setting up 'vscode-smoketest-express' project
var os = process.platform;
if (os === 'darwin') os = 'osx';
else if (os === 'win32') os = 'win';
var promises = [];

try {
	promises.push(getKeybindings(`${keybindingsUrl}/doc.keybindings.${os}.json`, `${tempFolder}/keybindings.json`));
	promises.push(cleanOrClone(testRepoUrl, testRepoLocalDir));

	Promise.all(promises).then(() => { execute('npm install', testRepoLocalDir).then(() => runTests()); });
} catch (e) {
	throw new Error('Error caught running the smoke test: ' + e);
}

function runTests() {
	console.log('Running tests...')
	const spawn = require('child_process').spawn;
	var proc = spawn(process.execPath, [
		'src/mocha-runner.js'
	]);
	proc.stdout.on('data', data => {
		console.log(data.toString());
	});
	proc.stderr.on('data', data => {
		var date = new Date().toLocaleString();
		fs.appendFile(`${tempFolder}/errors.log`, `${date}: ${data.toString()}`, (err) => {
			if (err) throw new Error(`Could not write stderr to errors.log with the following error: ${err}`);
		});
	});
}

function cleanOrClone(repo, dir) {
	console.log('Cleaning or cloning test project repository...');
	return new Promise((res, rej) => {
		if (!folderExists(dir)) {
			git.clone(repo, dir, () => {
				console.log('Test repository successfully cloned.');
				res();
			});
		} else {
			git.cwd(dir);
			git.fetch((err) => {
				if (err) rej(err);
				resetAndClean();
			});
		}

		var resetAndClean = () => {
			git.reset(['FETCH_HEAD', '--hard'], (err) => {
				if (err) rej(err);

				git.clean('f', ['-d'], (err) => {
					if (err) rej(err);
					console.log('Test project was successfully reset to initial state.');
					res();
				});
			});
		}
	});
}

function execute(cmd, dir) {
	return new Promise((res, rej) => {
		console.log(`Running ${cmd}...`);
		child_process.exec(cmd, { cwd: dir, stdio: [0, 1, 2] }, (error, stdout, stderr) => {
			if (error) rej(error);
			if (stderr) console.error(stderr);
			console.log(stdout);
			res();
		});
	});
}

function getKeybindings(url, location) {
	console.log(`Fetching keybindings from ${url}...`);
	return new Promise((resolve, reject) => {
		https.get(url, (res) => {
			if (res.statusCode != 200) {
				reject(`Failed to obtain key bindings with response code: ${res.statusCode}`);
			}

			var buffer = [];
			res.on('data', (chunk) => buffer.push(chunk));
			res.on('end', () => {
				fs.writeFile(location, Buffer.concat(buffer), 'utf8', () => {
					console.log('Keybindings were successfully fetched.');
					resolve();
				});
			});
		}).on('error', (e) => {
			reject(`Failed to obtain key bindings with an error: ${e}`);
		});
	});
}

function folderExists(folder) {
	try {
		fs.accessSync(folder, 'rw');
		return true;
	} catch (e) {
		return false;
	}
}

function binaryExists(filePath) {
	try {
		fs.accessSync(filePath, 'x');
		return true;
	} catch (e) {
		return false;
	}
}<|endoftext|>


<commit_before>"use strict";

describe("luga", function(){

	it("Requires jQuery in order to work", function(){
		expect(jQuery).toBeDefined();
	});

	it("Lives inside its own namespace", function(){
		expect(luga).toBeDefined();
	});

	describe(".namespace()", function(){

		it("Creates namespaces to be used for scoping variables and classes", function(){
			luga.namespace("myspace");
			expect(myspace).toBeDefined();
		});

		it("Does not override existing namespaces", function(){
			var testRoot = {};
			testRoot.child = {};
			testRoot.child.grandChild = {};
			luga.namespace("child", testRoot);
			expect(testRoot.child.grandChild).toBeDefined();
		});

		it("By default uses window as root object", function(){
			luga.namespace("ciccio");
			expect(window.ciccio).toBeDefined();
		});

		it("Accept a second argument to be used as root object", function(){
			var testRoot = {};
			luga.namespace("child", testRoot);
			expect(testRoot.child).toBeDefined();
		});

	});

	describe(".extend()", function(){

		it("Offers a simple solution for inheritance among classes", function(){

			/* Class Person. */
			function Person(gender){
				this.gender = gender;
				this.getGender = function(){
					return this.gender;
				};
			}

			/* Class Superstar */
			function Superstar(gender, name){
				luga.extend(Person, this, arguments);
				this.gender = gender;
				this.name = name;
				this.getName = function(){
					return this.name;
				};
			}

			var nicole = new Superstar("female", "Nicole Kidman");

			expect(nicole.getGender()).toEqual("female");
			expect(nicole.getName()).toEqual("Nicole Kidman")
		});

	});

	describe(".lookup(). Given the name of a function as a string", function(){

		it("Returns the relevant function if it finds it inside the window/global scope", function(){
			window.myFunc = function(){
			};
			var result = luga.lookup("myFunc");
			expect(result).not.toBeNull();
			expect(jQuery.isFunction(result)).toBeTruthy();
		});

		it("Or any given namespace", function(){
			var mySpace = {};
			mySpace.myFunction = function(){
			};
			var result = luga.lookup("luga.namespace");
			expect(result).not.toBeNull();
			expect(jQuery.isFunction(result)).toBeTruthy();
		});

		it("Returns null if the function does not exist", function(){
			expect(luga.lookup("missing")).toBeNull();
		});

		it("Or if the variable exists, but it's not a function", function(){
			window.str = "ciao";
			expect(luga.lookup("str")).toBeNull();
		});

	});

	describe(".merge()", function(){

		it("Merges the contents of two objects together into the first object", function(){
			var config = {letter: "a", number: 1};
			var params = {number: 2, symbol: "@"};
			luga.merge(config, params);
			expect(config).toEqual({letter: "a", number: 2, symbol: "@"});
		});

	});

	describe(".Notifier", function(){
		var notifierObj, observerObj, uselessObj;

		beforeEach(function(){

			var NotifierClass = function(){
				luga.extend(luga.Notifier, this);
			};
			var ObserverClass = function(){
				this.completeFlag = false;
				this.onCompleteHandler = function(data){
					this.completeFlag = data.flag;
				};
				this.onSomethingHandler = function(){
				};
			};
			var UselessObserverClass = function(){
			};
			notifierObj = new NotifierClass();
			observerObj = new ObserverClass();
			uselessObj = new UselessObserverClass();
		});

		it("Is an interface class that cannot be instantiated directly, it can only be used as a base class", function(){
			expect(jQuery.isFunction(luga.Notifier)).toBeTruthy();

			expect(function(){
				new luga.Notifier();
			}).toThrow();
		});

		it("Observers are stored as an array inside the .observers property", function(){
			expect(jQuery.isArray(notifierObj.observers)).toBeTruthy();
			expect(notifierObj.observers.length).toEqual(0);
		});

		describe(".addObserver()", function(){

			it("Adds an observer object to the list of observers", function(){
				notifierObj.addObserver(observerObj);
				expect(notifierObj.observers.length).toEqual(1);
				notifierObj.addObserver(uselessObj);
				expect(notifierObj.observers.length).toEqual(2);
			});

			it("Ensures that only objects are register as observers", function(){
				expect(function(){
					notifierObj.addObserver("test");
				}).toThrow();
			});

		});

		describe(".notifyObserver()", function(){

			it("Is used to send a notification to all registered observers", function(){
				notifierObj.addObserver(observerObj);
				spyOn(observerObj, "onCompleteHandler").and.callFake(function(){
				});

				notifierObj.notifyObservers("complete", {});
				expect(observerObj.onCompleteHandler).toHaveBeenCalled();
			});

			it("Requires two parameters: eventName and data. Both are required", function(){
				expect(function(){
					notifierObj.notifyObservers("complete");
				}).toThrow();
			});

			it("The data parameter must be an object", function(){
				expect(function(){
					notifierObj.notifyObservers("complete", "ciao");
				}).toThrow();
			});

			it("Observers must follow a naming convention. For an event named 'complete' they must implement a method named: 'onCompleteHandler'", function(){
				notifierObj.addObserver(observerObj);
				spyOn(observerObj, "onCompleteHandler").and.callFake(function(){
				});
				spyOn(observerObj, "onSomethingHandler").and.callFake(function(){
				});

				notifierObj.notifyObservers("complete", {});
				expect(observerObj.onCompleteHandler).toHaveBeenCalled();
				expect(observerObj.onSomethingHandler).not.toHaveBeenCalled();
			});

			it("The data parameter provides a means for passing data from the point of notification to all interested observers", function(){
				notifierObj.addObserver(observerObj);
				expect(observerObj.completeFlag).toEqual(false);

				notifierObj.notifyObservers("complete", {flag: true});
				expect(observerObj.completeFlag).toEqual(true);
			});

		});

		describe('.removeObserver()', function(){

			it('Removes the given observer object.', function(){
				notifierObj.addObserver(observerObj);
				expect(notifierObj.observers.length).toEqual(1);
				notifierObj.removeObserver(observerObj);
				expect(notifierObj.observers.length).toEqual(0);
			});

		});

	});

});<commit_msg>Added missing semicolon<commit_after>"use strict";

describe("luga", function(){

	it("Requires jQuery in order to work", function(){
		expect(jQuery).toBeDefined();
	});

	it("Lives inside its own namespace", function(){
		expect(luga).toBeDefined();
	});

	describe(".namespace()", function(){

		it("Creates namespaces to be used for scoping variables and classes", function(){
			luga.namespace("myspace");
			expect(myspace).toBeDefined();
		});

		it("Does not override existing namespaces", function(){
			var testRoot = {};
			testRoot.child = {};
			testRoot.child.grandChild = {};
			luga.namespace("child", testRoot);
			expect(testRoot.child.grandChild).toBeDefined();
		});

		it("By default uses window as root object", function(){
			luga.namespace("ciccio");
			expect(window.ciccio).toBeDefined();
		});

		it("Accept a second argument to be used as root object", function(){
			var testRoot = {};
			luga.namespace("child", testRoot);
			expect(testRoot.child).toBeDefined();
		});

	});

	describe(".extend()", function(){

		it("Offers a simple solution for inheritance among classes", function(){

			/* Class Person. */
			function Person(gender){
				this.gender = gender;
				this.getGender = function(){
					return this.gender;
				};
			}

			/* Class Superstar */
			function Superstar(gender, name){
				luga.extend(Person, this, arguments);
				this.gender = gender;
				this.name = name;
				this.getName = function(){
					return this.name;
				};
			}

			var nicole = new Superstar("female", "Nicole Kidman");

			expect(nicole.getGender()).toEqual("female");
			expect(nicole.getName()).toEqual("Nicole Kidman");
		});

	});

	describe(".lookup(). Given the name of a function as a string", function(){

		it("Returns the relevant function if it finds it inside the window/global scope", function(){
			window.myFunc = function(){
			};
			var result = luga.lookup("myFunc");
			expect(result).not.toBeNull();
			expect(jQuery.isFunction(result)).toBeTruthy();
		});

		it("Or any given namespace", function(){
			var mySpace = {};
			mySpace.myFunction = function(){
			};
			var result = luga.lookup("luga.namespace");
			expect(result).not.toBeNull();
			expect(jQuery.isFunction(result)).toBeTruthy();
		});

		it("Returns null if the function does not exist", function(){
			expect(luga.lookup("missing")).toBeNull();
		});

		it("Or if the variable exists, but it's not a function", function(){
			window.str = "ciao";
			expect(luga.lookup("str")).toBeNull();
		});

	});

	describe(".merge()", function(){

		it("Merges the contents of two objects together into the first object", function(){
			var config = {letter: "a", number: 1};
			var params = {number: 2, symbol: "@"};
			luga.merge(config, params);
			expect(config).toEqual({letter: "a", number: 2, symbol: "@"});
		});

	});

	describe(".Notifier", function(){
		var notifierObj, observerObj, uselessObj;

		beforeEach(function(){

			var NotifierClass = function(){
				luga.extend(luga.Notifier, this);
			};
			var ObserverClass = function(){
				this.completeFlag = false;
				this.onCompleteHandler = function(data){
					this.completeFlag = data.flag;
				};
				this.onSomethingHandler = function(){
				};
			};
			var UselessObserverClass = function(){
			};
			notifierObj = new NotifierClass();
			observerObj = new ObserverClass();
			uselessObj = new UselessObserverClass();
		});

		it("Is an interface class that cannot be instantiated directly, it can only be used as a base class", function(){
			expect(jQuery.isFunction(luga.Notifier)).toBeTruthy();

			expect(function(){
				new luga.Notifier();
			}).toThrow();
		});

		it("Observers are stored as an array inside the .observers property", function(){
			expect(jQuery.isArray(notifierObj.observers)).toBeTruthy();
			expect(notifierObj.observers.length).toEqual(0);
		});

		describe(".addObserver()", function(){

			it("Adds an observer object to the list of observers", function(){
				notifierObj.addObserver(observerObj);
				expect(notifierObj.observers.length).toEqual(1);
				notifierObj.addObserver(uselessObj);
				expect(notifierObj.observers.length).toEqual(2);
			});

			it("Ensures that only objects are register as observers", function(){
				expect(function(){
					notifierObj.addObserver("test");
				}).toThrow();
			});

		});

		describe(".notifyObserver()", function(){

			it("Is used to send a notification to all registered observers", function(){
				notifierObj.addObserver(observerObj);
				spyOn(observerObj, "onCompleteHandler").and.callFake(function(){
				});

				notifierObj.notifyObservers("complete", {});
				expect(observerObj.onCompleteHandler).toHaveBeenCalled();
			});

			it("Requires two parameters: eventName and data. Both are required", function(){
				expect(function(){
					notifierObj.notifyObservers("complete");
				}).toThrow();
			});

			it("The data parameter must be an object", function(){
				expect(function(){
					notifierObj.notifyObservers("complete", "ciao");
				}).toThrow();
			});

			it("Observers must follow a naming convention. For an event named 'complete' they must implement a method named: 'onCompleteHandler'", function(){
				notifierObj.addObserver(observerObj);
				spyOn(observerObj, "onCompleteHandler").and.callFake(function(){
				});
				spyOn(observerObj, "onSomethingHandler").and.callFake(function(){
				});

				notifierObj.notifyObservers("complete", {});
				expect(observerObj.onCompleteHandler).toHaveBeenCalled();
				expect(observerObj.onSomethingHandler).not.toHaveBeenCalled();
			});

			it("The data parameter provides a means for passing data from the point of notification to all interested observers", function(){
				notifierObj.addObserver(observerObj);
				expect(observerObj.completeFlag).toEqual(false);

				notifierObj.notifyObservers("complete", {flag: true});
				expect(observerObj.completeFlag).toEqual(true);
			});

		});

		describe('.removeObserver()', function(){

			it('Removes the given observer object.', function(){
				notifierObj.addObserver(observerObj);
				expect(notifierObj.observers.length).toEqual(1);
				notifierObj.removeObserver(observerObj);
				expect(notifierObj.observers.length).toEqual(0);
			});

		});

	});

});<|endoftext|>


<commit_before>function runSpecs(title, file, options) {
  const json = require(file);
  let longestName = 0;
  let maxSpecs = 0;
  const specs = json.reduce((obj, spec) => {
    if (!obj[spec.section]) {
      longestName = Math.max(spec.section.length, longestName);
      obj[spec.section] = {
        specs: [],
        pass: 0,
        total: 0
      };
    }
    obj[spec.section].total++;
    maxSpecs = Math.max(obj[spec.section].total, maxSpecs);
    if (!spec.shouldFail) {
      obj[spec.section].pass++;
    }
    obj[spec.section].specs.push(spec);
    return obj;
  }, {});

  describe(title, () => {
    const maxSpecsLen = ('' + maxSpecs).length;
    const spaces = maxSpecsLen * 2 + longestName + 11;
    console.log('-'.padEnd(spaces + 4, '-'));
    console.log(`| ${title.padStart(Math.ceil((spaces + title.length) / 2)).padEnd(spaces)} |`);
    console.log(`| ${' '.padEnd(spaces)} |`);
    Object.keys(specs).forEach(section => {
      console.log(`| ${section.padEnd(longestName)} ${('' + specs[section].pass).padStart(maxSpecsLen)} of ${('' + specs[section].total).padStart(maxSpecsLen)} ${(100 * specs[section].pass / specs[section].total).toFixed().padStart(4)}% |`);
      describe(section, () => {
        specs[section].specs.forEach((spec) => {
          if (options) {
            spec.options = Object.assign({}, options, (spec.options || {}));
          }
          (spec.only ? fit : it)('should ' + (spec.shouldFail ? 'fail' : 'pass') + ' example ' + spec.example, () => {
            if (spec.shouldFail) {
              expect(spec).not.toRender(spec.html);
            } else {
              expect(spec).toRender(spec.html);
            }
          });
        });
      });
    });
    console.log('-'.padEnd(spaces + 4, '-'));
    console.log();
  });
};

runSpecs('GFM 0.29', './gfm/gfm.0.29.json', {gfm: true});
runSpecs('CommonMark 0.29', './commonmark/commonmark.0.29.json', {headerIds: false});
<commit_msg>update run-spec for node 4<commit_after>'use strict';

function node4Polyfills() {
  // https://github.com/uxitten/polyfill/blob/master/string.polyfill.js
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padEnd
  if (!String.prototype.padEnd) {
    // eslint-disable-next-line no-extend-native
    String.prototype.padEnd = function padEnd(targetLength, padString) {
      targetLength = targetLength >> 0; // floor if number or convert non-number to 0;
      padString = String((typeof padString !== 'undefined' ? padString : ' '));
      if (this.length > targetLength) {
        return String(this);
      } else {
        targetLength = targetLength - this.length;
        if (targetLength > padString.length) {
          padString += padString.repeat(targetLength / padString.length); // append to original to ensure we are longer than needed
        }
        return String(this) + padString.slice(0, targetLength);
      }
    };
  }

  // https://github.com/uxitten/polyfill/blob/master/string.polyfill.js
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padStart
  if (!String.prototype.padStart) {
    // eslint-disable-next-line no-extend-native
    String.prototype.padStart = function padStart(targetLength, padString) {
      targetLength = targetLength >> 0; // truncate if number, or convert non-number to 0;
      padString = String(typeof padString !== 'undefined' ? padString : ' ');
      if (this.length >= targetLength) {
        return String(this);
      } else {
        targetLength = targetLength - this.length;
        if (targetLength > padString.length) {
          padString += padString.repeat(targetLength / padString.length); // append to original to ensure we are longer than needed
        }
        return padString.slice(0, targetLength) + String(this);
      }
    };
  }
}

function outputCompletionTable(title, specs, longestName, maxSpecs) {
  const maxSpecsLen = ('' + maxSpecs).length;
  const spaces = maxSpecsLen * 2 + longestName + 11;
  console.log('-'.padEnd(spaces + 4, '-'));
  console.log(`| ${title.padStart(Math.ceil((spaces + title.length) / 2)).padEnd(spaces)} |`);
  console.log(`| ${' '.padEnd(spaces)} |`);
  for (const section in specs) {
    console.log(`| ${section.padEnd(longestName)} ${('' + specs[section].pass).padStart(maxSpecsLen)} of ${('' + specs[section].total).padStart(maxSpecsLen)} ${(100 * specs[section].pass / specs[section].total).toFixed().padStart(4)}% |`);
  }
  console.log('-'.padEnd(spaces + 4, '-'));
  console.log();
}

function runSpecs(title, file, options) {
  options = options || {};
  const json = require(file);
  let longestName = 0;
  let maxSpecs = 0;
  const specs = json.reduce((obj, spec) => {
    if (!obj[spec.section]) {
      longestName = Math.max(spec.section.length, longestName);
      obj[spec.section] = {
        specs: [],
        pass: 0,
        total: 0
      };
    }
    obj[spec.section].total++;
    maxSpecs = Math.max(obj[spec.section].total, maxSpecs);
    if (!spec.shouldFail) {
      obj[spec.section].pass++;
    }
    obj[spec.section].specs.push(spec);
    return obj;
  }, {});

  outputCompletionTable(title, specs, longestName, maxSpecs);

  describe(title, () => {
    Object.keys(specs).forEach(section => {
      describe(section, () => {
        specs[section].specs.forEach((spec) => {
          spec.options = Object.assign({}, options, (spec.options || {}));
          (spec.only ? fit : it)('should ' + (spec.shouldFail ? 'fail' : 'pass') + ' example ' + spec.example, () => {
            if (spec.shouldFail) {
              expect(spec).not.toRender(spec.html);
            } else {
              expect(spec).toRender(spec.html);
            }
          });
        });
      });
    });
  });
};

node4Polyfills();

runSpecs('GFM 0.29', './gfm/gfm.0.29.json', {gfm: true});
runSpecs('CommonMark 0.29', './commonmark/commonmark.0.29.json', {headerIds: false});
<|endoftext|>


<commit_before>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow strict
 * @format
 */
'use strict';

// TODO: type these properly.
type Node = {};
type NodeSet = Array<Node>;
type NodeProps = {};
type InstanceHandle = {};
type Spec = {|
  +createNode: (
    reactTag: number,
    viewName: string,
    rootTag: number,
    props: NodeProps,
    instanceHandle: InstanceHandle,
  ) => Node,
  +cloneNode: (node: Node) => Node,
  +cloneNodeWithNewChildren: (node: Node) => Node,
  +cloneNodeWithNewProps: (node: Node, newProps: NodeProps) => Node,
  +cloneNodeWithNewChildrenAndProps: (node: Node, newProps: NodeProps) => Node,
  +createChildSet: (rootTag: number) => NodeSet,
  +appendChild: (parentNode: Node, child: Node) => Node,
  +appendChildToSet: (childSet: NodeSet, child: Node) => void,
  +completeRoot: (rootTag: number, childSet: NodeSet) => void,
|};

const FabricUIManager: ?Spec = global.nativeFabricUIManager;

module.exports = FabricUIManager;
<commit_msg>Add setNativeProps type to FabricUIManager.js<commit_after>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow strict
 * @format
 */
'use strict';

// TODO: type these properly.
type Node = {};
type NodeSet = Array<Node>;
type NodeProps = {};
type InstanceHandle = {};
type Spec = {|
  +createNode: (
    reactTag: number,
    viewName: string,
    rootTag: number,
    props: NodeProps,
    instanceHandle: InstanceHandle,
  ) => Node,
  +cloneNode: (node: Node) => Node,
  +cloneNodeWithNewChildren: (node: Node) => Node,
  +cloneNodeWithNewProps: (node: Node, newProps: NodeProps) => Node,
  +cloneNodeWithNewChildrenAndProps: (node: Node, newProps: NodeProps) => Node,
  +createChildSet: (rootTag: number) => NodeSet,
  +appendChild: (parentNode: Node, child: Node) => Node,
  +appendChildToSet: (childSet: NodeSet, child: Node) => void,
  +completeRoot: (rootTag: number, childSet: NodeSet) => void,
  +setNativeProps: (node: Node, nativeProps: NodeProps) => void,
|};

const FabricUIManager: ?Spec = global.nativeFabricUIManager;

module.exports = FabricUIManager;
<|endoftext|>


<commit_before>import { assert }    from 'chai';
import TyphonEvents  from '../../src/TyphonEvents';

/* eslint-disable no-undef */

describe('Events', () =>
{
   let callbacks, eventbus;

   beforeEach(() => { callbacks = {}; eventbus = new TyphonEvents(); });

   it('set / get name', () =>
   {
      eventbus.setEventbusName('testname');
      assert.strictEqual(eventbus.getEventbusName(), 'testname');

      eventbus = new TyphonEvents('testname2');
      assert.strictEqual(eventbus.getEventbusName(), 'testname2');
   });

   it('forEachEvent', () =>
   {
      const callback1 = () => {};
      const callback2 = () => {};
      const callback3 = () => {};
      const callback3A = () => {};

      const context1 = {};
      const context2 = {};
      const context3 = {};
      const context3A = {};

      const allCallbacks = [callback1, callback2, callback3, callback3A];
      const allContexts = [context1, context2, context3, context3A];
      const allNames = ['test:trigger', 'test:trigger2', 'test:trigger3', 'test:trigger3'];

      eventbus.on('test:trigger', callback1, context1);
      eventbus.on('test:trigger2', callback2, context2);
      eventbus.on('test:trigger3', callback3, context3);
      eventbus.on('test:trigger3', callback3A, context3A);

      let cntr = 0;

      eventbus.forEachEvent((name, callback, context) =>
      {
         assert.strictEqual(name, allNames[cntr]);
         assert.strictEqual(callback, allCallbacks[cntr]);
         assert.strictEqual(context, allContexts[cntr]);
         cntr++;
      });
   });

   it('getEventNames', () =>
   {
      eventbus.on('test:trigger', () => {});
      eventbus.on('test:trigger2', () => {});
      eventbus.on('test:trigger3', () => {});
      eventbus.on('test:trigger3', () => {});

      const eventNames = eventbus.getEventNames();

      assert.strictEqual(JSON.stringify(eventNames), '["test:trigger","test:trigger2","test:trigger3"]');
   });

   it('trigger', () =>
   {
      eventbus.on('test:trigger', () => { callbacks.testTrigger = true; });
      eventbus.trigger('test:trigger');

      assert.strictEqual(eventbus.eventCount, 1);

      assert.isTrue(callbacks.testTrigger);
   });

   it('trigger (on / off)', () =>
   {
      callbacks.testTrigger = 0;
      eventbus.on('test:trigger', () => { callbacks.testTrigger++; });
      eventbus.trigger('test:trigger');

      assert.strictEqual(eventbus.eventCount, 1);

      assert.strictEqual(callbacks.testTrigger, 1);

      eventbus.off();

      assert.strictEqual(eventbus.eventCount, 0);

      eventbus.trigger('test:trigger');
      eventbus.trigger('test:trigger');

      assert.strictEqual(callbacks.testTrigger, 1);
   });

   it('trigger (once)', () =>
   {
      callbacks.testTriggerOnce = 0;
      eventbus.once('test:trigger:once', () => { callbacks.testTriggerOnce++; });

      assert.strictEqual(eventbus.eventCount, 1);

      eventbus.trigger('test:trigger:once');

      assert.strictEqual(eventbus.eventCount, 0);

      eventbus.trigger('test:trigger:once');

      assert.strictEqual(eventbus.eventCount, 0);

      assert.strictEqual(callbacks.testTriggerOnce, 1);
   });

   it('trigger (listenTo)', () =>
   {
      const test = new TyphonEvents();

      callbacks.testTriggerCount = 0;

      test.listenTo(eventbus, 'test:trigger', () => { callbacks.testTriggerCount++; });

      eventbus.trigger('test:trigger');

      assert.strictEqual(eventbus.eventCount, 1);

      assert.strictEqual(callbacks.testTriggerCount, 1);

      // Test stop listening such that `test:trigger` is no longer registered.
      test.stopListening(eventbus, 'test:trigger');

      eventbus.trigger('test:trigger');

      assert.strictEqual(eventbus.eventCount, 0);

      assert.strictEqual(callbacks.testTriggerCount, 1);
   });

   it('trigger (listenToOnce)', () =>
   {
      const test = new TyphonEvents();

      callbacks.testTriggerOnce = 0;

      test.listenToOnce(eventbus, 'test:trigger', () => { callbacks.testTriggerOnce++; });

      assert.strictEqual(eventbus.eventCount, 1);

      eventbus.trigger('test:trigger');

      assert.strictEqual(eventbus.eventCount, 0);

      assert.strictEqual(callbacks.testTriggerOnce, 1);

      eventbus.trigger('test:trigger');

      assert.strictEqual(eventbus.eventCount, 0);

      assert.strictEqual(callbacks.testTriggerOnce, 1);
   });

   it('triggerDefer', (done) =>
   {
      eventbus.on('test:trigger:defer', () =>
      {
         assert.strictEqual(eventbus.eventCount, 1);

         done();
      });

      assert.strictEqual(eventbus.eventCount, 1);

      eventbus.triggerDefer('test:trigger:defer');
   });

   it('triggerDefer (once)', (done) =>
   {
      callbacks.testTriggerOnce = 0;

      eventbus.once('test:trigger:once', () => { callbacks.testTriggerOnce++; });

      assert.strictEqual(eventbus.eventCount, 1);

      eventbus.on('test:trigger:verify', () =>
      {
         assert.strictEqual(callbacks.testTriggerOnce, 1);

         assert.strictEqual(eventbus.eventCount, 1);

         done();
      });

      assert.strictEqual(eventbus.eventCount, 2);

      eventbus.triggerDefer('test:trigger:once');

      assert.strictEqual(eventbus.eventCount, 2); // Trigger is deferred so 2 events still exist.

      eventbus.triggerDefer('test:trigger:once');

      assert.strictEqual(eventbus.eventCount, 2); // Trigger is deferred so 2 events still exist.

      eventbus.triggerDefer('test:trigger:verify');
   });

   it('triggerDefer (listenTo)', (done) =>
   {
      const test = new TyphonEvents();

      callbacks.testTriggerCount = 0;

      test.listenTo(eventbus, 'test:trigger', () => { callbacks.testTriggerCount++; });

      assert.strictEqual(eventbus.eventCount, 1);

      eventbus.on('test:trigger:verify', () =>
      {
         assert.strictEqual(callbacks.testTriggerCount, 1);

         // Test stop listening such that `test:trigger` is no longer registered.
         test.stopListening(eventbus, 'test:trigger');

         assert.strictEqual(eventbus.eventCount, 2);
      });

      assert.strictEqual(eventbus.eventCount, 2);

      eventbus.on('test:trigger:verify:done', () =>
      {
         assert.strictEqual(callbacks.testTriggerCount, 1);

         assert.strictEqual(eventbus.eventCount, 2);

         done();
      });

      assert.strictEqual(eventbus.eventCount, 3);

      eventbus.triggerDefer('test:trigger');

      eventbus.triggerDefer('test:trigger:verify');

      eventbus.triggerDefer('test:trigger');

      eventbus.triggerDefer('test:trigger:verify:done');

      assert.strictEqual(eventbus.eventCount, 3);
   });

   it('triggerDefer (listenToOnce)', (done) =>
   {
      const test = new TyphonEvents();

      callbacks.testTriggerOnce = 0;

      test.listenToOnce(eventbus, 'test:trigger', () =>
      {
         callbacks.testTriggerOnce++;

         assert.strictEqual(eventbus.eventCount, 1);
      });

      assert.strictEqual(eventbus.eventCount, 1);

      eventbus.on('test:trigger:verify', () =>
      {
         assert.strictEqual(callbacks.testTriggerOnce, 1);

         assert.strictEqual(eventbus.eventCount, 1);

         done();
      });

      assert.strictEqual(eventbus.eventCount, 2);

      eventbus.triggerDefer('test:trigger');
      eventbus.triggerDefer('test:trigger');
      eventbus.triggerDefer('test:trigger:verify');

      assert.strictEqual(eventbus.eventCount, 2);
   });

   it('triggerSync-0', () =>
   {
      const result = eventbus.triggerSync('test:trigger:sync0');

      assert.strictEqual(eventbus.eventCount, 0);

      assert.isNotArray(result);
      assert.isUndefined(result);
   });

   it('triggerSync-1', () =>
   {
      eventbus.on('test:trigger:sync1', () => { callbacks.testTriggerSync1 = true; return 'foo'; });

      assert.strictEqual(eventbus.eventCount, 1);

      const result = eventbus.triggerSync('test:trigger:sync1');

      assert.isTrue(callbacks.testTriggerSync1);
      assert.isNotArray(result);
      assert.strictEqual(result, 'foo');
   });

   it('triggerSync-2', () =>
   {
      eventbus.on('test:trigger:sync2', () => { callbacks.testTriggerSync2A = true; return 'foo'; });
      eventbus.on('test:trigger:sync2', () => { callbacks.testTriggerSync2B = true; return 'bar'; });

      assert.strictEqual(eventbus.eventCount, 2);

      const results = eventbus.triggerSync('test:trigger:sync2');

      assert.isTrue(callbacks.testTriggerSync2A);
      assert.isTrue(callbacks.testTriggerSync2B);
      assert.isArray(results);
      assert.strictEqual(results.length, 2);
      assert.strictEqual(results[0], 'foo');
      assert.strictEqual(results[1], 'bar');
   });

   it('triggerSync (on / off)', () =>
   {
      assert.strictEqual(eventbus.eventCount, 0);

      eventbus.on('test:trigger:sync:off', () => { callbacks.testTriggerSyncOff = true; return true; });

      assert.strictEqual(eventbus.eventCount, 1);

      eventbus.off('test:trigger:sync:off');

      assert.strictEqual(eventbus.eventCount, 0);

      assert.isUndefined(eventbus.triggerSync('test:trigger:sync:off'));
      assert.isUndefined(callbacks.testTriggerSyncOff);
   });

   it('triggerSync-1 (once)', () =>
   {
      callbacks.testTriggerOnce = 0;

      eventbus.once('test:trigger:once', () => { callbacks.testTriggerOnce++; return 'foo'; });

      assert.strictEqual(eventbus.eventCount, 1);

      let result = eventbus.triggerSync('test:trigger:once');

      assert.strictEqual(eventbus.eventCount, 0);

      assert.strictEqual(callbacks.testTriggerOnce, 1);
      assert.isNotArray(result);
      assert.strictEqual(result, 'foo');

      result = eventbus.triggerSync('test:trigger:once');

      assert.strictEqual(callbacks.testTriggerOnce, 1);
      assert.isUndefined(result);
   });

   it('triggerSync-1 (listenTo)', () =>
   {
      const test = new TyphonEvents();

      callbacks.testTriggerCount = 0;

      test.listenTo(eventbus, 'test:trigger:sync', () => { callbacks.testTriggerCount++; return 'foo'; });

      assert.strictEqual(eventbus.eventCount, 1);

      let result = eventbus.triggerSync('test:trigger:sync');

      assert.strictEqual(callbacks.testTriggerCount, 1);
      assert.isNotArray(result);
      assert.strictEqual(result, 'foo');

      assert.strictEqual(eventbus.eventCount, 1);

      test.stopListening(eventbus, 'test:trigger:sync');

      assert.strictEqual(eventbus.eventCount, 0);

      result = eventbus.triggerSync('test:trigger:sync');

      assert.strictEqual(callbacks.testTriggerCount, 1);
      assert.isUndefined(result);
   });

   it('triggerSync-1 (listenToOnce)', () =>
   {
      const test = new TyphonEvents();

      callbacks.testTriggerOnce = 0;

      test.listenToOnce(eventbus, 'test:trigger:once', () => { callbacks.testTriggerOnce++; return 'foo'; });

      assert.strictEqual(eventbus.eventCount, 1);

      let result = eventbus.triggerSync('test:trigger:once');

      assert.strictEqual(eventbus.eventCount, 0);

      assert.strictEqual(callbacks.testTriggerOnce, 1);
      assert.isNotArray(result);
      assert.strictEqual(result, 'foo');

      result = eventbus.triggerSync('test:trigger:once');

      assert.strictEqual(callbacks.testTriggerOnce, 1);
      assert.isUndefined(result);
   });

   it('triggerSync (Promise)', (done) =>
   {
      eventbus.on('test:trigger:sync:then', () =>
      {
         callbacks.testTriggerSyncThen = true;

         return Promise.resolve('foobar');
      });

      assert.strictEqual(eventbus.eventCount, 1);

      const promise = eventbus.triggerSync('test:trigger:sync:then');

      assert(promise instanceof Promise);

      promise.then((result) =>
      {
         assert.isTrue(callbacks.testTriggerSyncThen);
         assert.strictEqual(result, 'foobar');
         done();
      });
   });

   it('triggerAsync', (done) =>
   {
      eventbus.on('test:trigger:async', () => { callbacks.testTriggerAsync = true; return 'foo'; });
      eventbus.on('test:trigger:async', () => { callbacks.testTriggerAsync2 = true; return 'bar'; });

      assert.strictEqual(eventbus.eventCount, 2);

      const promise = eventbus.triggerAsync('test:trigger:async');

      assert(promise instanceof Promise);

      // triggerAsync resolves all Promises by Promise.all() so result is an array.
      promise.then((result) =>
      {
         assert.isTrue(callbacks.testTriggerAsync);
         assert.isTrue(callbacks.testTriggerAsync2);
         assert.strictEqual(result[0], 'foo');
         assert.strictEqual(result[1], 'bar');
         done();
      });
   });

   it('triggerAsync (once)', (done) =>
   {
      callbacks.testTriggerOnce = 0;

      assert.strictEqual(eventbus.eventCount, 0);

      eventbus.once('test:trigger:once', () => { callbacks.testTriggerOnce++; return 'foo'; });

      assert.strictEqual(eventbus.eventCount, 1);

      const promise = eventbus.triggerAsync('test:trigger:once');

      assert.strictEqual(eventbus.eventCount, 0);

      assert.strictEqual(callbacks.testTriggerOnce, 1);
      assert(promise instanceof Promise);

      const promise2 = eventbus.triggerAsync('test:trigger:once');

      assert.strictEqual(callbacks.testTriggerOnce, 1);
      assert(promise2 instanceof Promise);

      // triggerAsync resolves all Promises by Promise.all() or Promise.resolve() so result is a string.
      promise.then((result) =>
      {
         assert.strictEqual(callbacks.testTriggerOnce, 1);
         assert.strictEqual(result, 'foo');
         done();
      });
   });

   it('triggerAsync (listenTo)', (done) =>
   {
      const test = new TyphonEvents();

      callbacks.testTriggerCount = 0;

      test.listenTo(eventbus, 'test:trigger:async', () => { callbacks.testTriggerCount++; return 'foo'; });

      assert.strictEqual(eventbus.eventCount, 1);

      let promise = eventbus.triggerAsync('test:trigger:async');

      assert(promise instanceof Promise);

      promise.then((result) =>
      {
         assert.strictEqual(callbacks.testTriggerCount, 1);
         assert.strictEqual(result, 'foo');
      });

      test.stopListening(eventbus, 'test:trigger:async');

      assert.strictEqual(eventbus.eventCount, 0);

      promise = eventbus.triggerAsync('test:trigger:async');

      promise.then((result) =>
      {
         assert.isUndefined(result);
         assert.strictEqual(callbacks.testTriggerCount, 1);
         done();
      });
   });

   it('triggerAsync (listenToOnce)', (done) =>
   {
      const test = new TyphonEvents();

      callbacks.testTriggerOnce = 0;

      assert.strictEqual(eventbus.eventCount, 0);

      test.listenToOnce(eventbus, 'test:trigger:once', () => { callbacks.testTriggerOnce++; return 'foo'; });

      assert.strictEqual(eventbus.eventCount, 1);

      const promise = eventbus.triggerAsync('test:trigger:once');

      assert.strictEqual(eventbus.eventCount, 0);

      assert.strictEqual(callbacks.testTriggerOnce, 1);
      assert(promise instanceof Promise);

      const promise2 = eventbus.triggerAsync('test:trigger:once');

      assert.strictEqual(callbacks.testTriggerOnce, 1);
      assert(promise2 instanceof Promise);

      // triggerAsync resolves all Promises by Promise.all() or Promise.resolve() so result is a string.
      promise.then((result) =>
      {
         assert.strictEqual(callbacks.testTriggerOnce, 1);
         assert.strictEqual(result, 'foo');
         done();
      });
   });
});<commit_msg>added object composition test<commit_after>import { assert }    from 'chai';
import TyphonEvents  from '../../src/TyphonEvents';

/* eslint-disable no-undef */

describe('Events', () =>
{
   let callbacks, eventbus;

   beforeEach(() => { callbacks = {}; eventbus = new TyphonEvents(); });

   it('set / get name', () =>
   {
      eventbus.setEventbusName('testname');
      assert.strictEqual(eventbus.getEventbusName(), 'testname');

      eventbus = new TyphonEvents('testname2');
      assert.strictEqual(eventbus.getEventbusName(), 'testname2');
   });

   it('forEachEvent', () =>
   {
      const callback1 = () => {};
      const callback2 = () => {};
      const callback3 = () => {};
      const callback3A = () => {};

      const context1 = {};
      const context2 = {};
      const context3 = {};
      const context3A = {};

      const allCallbacks = [callback1, callback2, callback3, callback3A];
      const allContexts = [context1, context2, context3, context3A];
      const allNames = ['test:trigger', 'test:trigger2', 'test:trigger3', 'test:trigger3'];

      eventbus.on('test:trigger', callback1, context1);
      eventbus.on('test:trigger2', callback2, context2);
      eventbus.on('test:trigger3', callback3, context3);
      eventbus.on('test:trigger3', callback3A, context3A);

      let cntr = 0;

      eventbus.forEachEvent((name, callback, context) =>
      {
         assert.strictEqual(name, allNames[cntr]);
         assert.strictEqual(callback, allCallbacks[cntr]);
         assert.strictEqual(context, allContexts[cntr]);
         cntr++;
      });
   });

   it('getEventNames', () =>
   {
      eventbus.on('test:trigger', () => {});
      eventbus.on('test:trigger2', () => {});
      eventbus.on('test:trigger3', () => {});
      eventbus.on('test:trigger3', () => {});

      const eventNames = eventbus.getEventNames();

      assert.strictEqual(JSON.stringify(eventNames), '["test:trigger","test:trigger2","test:trigger3"]');
   });

   it('trigger', () =>
   {
      eventbus.on('test:trigger', () => { callbacks.testTrigger = true; });
      eventbus.trigger('test:trigger');

      assert.strictEqual(eventbus.eventCount, 1);

      assert.isTrue(callbacks.testTrigger);
   });

   it('object composition - trigger (on / off)', () =>
   {
      const anObject = {
         events: new TyphonEvents(),
         register: function() { this.events.on('test:trigger', this.handler, this); },
         testTrigger: 0,
         triggerTest: function() { this.events.trigger('test:trigger'); },
         handler: function() { this.testTrigger++; }
      };

      anObject.register();
      anObject.triggerTest();

      assert.strictEqual(anObject.events.eventCount, 1);

      assert.strictEqual(anObject.testTrigger, 1);

      anObject.events.off();

      assert.strictEqual(anObject.events.eventCount, 0);

      anObject.triggerTest();
      anObject.triggerTest();

      assert.strictEqual(anObject.testTrigger, 1);
   });

   it('trigger (on / off)', () =>
   {
      callbacks.testTrigger = 0;
      eventbus.on('test:trigger', () => { callbacks.testTrigger++; });
      eventbus.trigger('test:trigger');

      assert.strictEqual(eventbus.eventCount, 1);

      assert.strictEqual(callbacks.testTrigger, 1);

      eventbus.off();

      assert.strictEqual(eventbus.eventCount, 0);

      eventbus.trigger('test:trigger');
      eventbus.trigger('test:trigger');

      assert.strictEqual(callbacks.testTrigger, 1);
   });

   it('trigger (once)', () =>
   {
      callbacks.testTriggerOnce = 0;
      eventbus.once('test:trigger:once', () => { callbacks.testTriggerOnce++; });

      assert.strictEqual(eventbus.eventCount, 1);

      eventbus.trigger('test:trigger:once');

      assert.strictEqual(eventbus.eventCount, 0);

      eventbus.trigger('test:trigger:once');

      assert.strictEqual(eventbus.eventCount, 0);

      assert.strictEqual(callbacks.testTriggerOnce, 1);
   });

   it('trigger (listenTo)', () =>
   {
      const test = new TyphonEvents();

      callbacks.testTriggerCount = 0;

      test.listenTo(eventbus, 'test:trigger', () => { callbacks.testTriggerCount++; });

      eventbus.trigger('test:trigger');

      assert.strictEqual(eventbus.eventCount, 1);

      assert.strictEqual(callbacks.testTriggerCount, 1);

      // Test stop listening such that `test:trigger` is no longer registered.
      test.stopListening(eventbus, 'test:trigger');

      eventbus.trigger('test:trigger');

      assert.strictEqual(eventbus.eventCount, 0);

      assert.strictEqual(callbacks.testTriggerCount, 1);
   });

   it('trigger (listenToOnce)', () =>
   {
      const test = new TyphonEvents();

      callbacks.testTriggerOnce = 0;

      test.listenToOnce(eventbus, 'test:trigger', () => { callbacks.testTriggerOnce++; });

      assert.strictEqual(eventbus.eventCount, 1);

      eventbus.trigger('test:trigger');

      assert.strictEqual(eventbus.eventCount, 0);

      assert.strictEqual(callbacks.testTriggerOnce, 1);

      eventbus.trigger('test:trigger');

      assert.strictEqual(eventbus.eventCount, 0);

      assert.strictEqual(callbacks.testTriggerOnce, 1);
   });

   it('triggerDefer', (done) =>
   {
      eventbus.on('test:trigger:defer', () =>
      {
         assert.strictEqual(eventbus.eventCount, 1);

         done();
      });

      assert.strictEqual(eventbus.eventCount, 1);

      eventbus.triggerDefer('test:trigger:defer');
   });

   it('triggerDefer (once)', (done) =>
   {
      callbacks.testTriggerOnce = 0;

      eventbus.once('test:trigger:once', () => { callbacks.testTriggerOnce++; });

      assert.strictEqual(eventbus.eventCount, 1);

      eventbus.on('test:trigger:verify', () =>
      {
         assert.strictEqual(callbacks.testTriggerOnce, 1);

         assert.strictEqual(eventbus.eventCount, 1);

         done();
      });

      assert.strictEqual(eventbus.eventCount, 2);

      eventbus.triggerDefer('test:trigger:once');

      assert.strictEqual(eventbus.eventCount, 2); // Trigger is deferred so 2 events still exist.

      eventbus.triggerDefer('test:trigger:once');

      assert.strictEqual(eventbus.eventCount, 2); // Trigger is deferred so 2 events still exist.

      eventbus.triggerDefer('test:trigger:verify');
   });

   it('triggerDefer (listenTo)', (done) =>
   {
      const test = new TyphonEvents();

      callbacks.testTriggerCount = 0;

      test.listenTo(eventbus, 'test:trigger', () => { callbacks.testTriggerCount++; });

      assert.strictEqual(eventbus.eventCount, 1);

      eventbus.on('test:trigger:verify', () =>
      {
         assert.strictEqual(callbacks.testTriggerCount, 1);

         // Test stop listening such that `test:trigger` is no longer registered.
         test.stopListening(eventbus, 'test:trigger');

         assert.strictEqual(eventbus.eventCount, 2);
      });

      assert.strictEqual(eventbus.eventCount, 2);

      eventbus.on('test:trigger:verify:done', () =>
      {
         assert.strictEqual(callbacks.testTriggerCount, 1);

         assert.strictEqual(eventbus.eventCount, 2);

         done();
      });

      assert.strictEqual(eventbus.eventCount, 3);

      eventbus.triggerDefer('test:trigger');

      eventbus.triggerDefer('test:trigger:verify');

      eventbus.triggerDefer('test:trigger');

      eventbus.triggerDefer('test:trigger:verify:done');

      assert.strictEqual(eventbus.eventCount, 3);
   });

   it('triggerDefer (listenToOnce)', (done) =>
   {
      const test = new TyphonEvents();

      callbacks.testTriggerOnce = 0;

      test.listenToOnce(eventbus, 'test:trigger', () =>
      {
         callbacks.testTriggerOnce++;

         assert.strictEqual(eventbus.eventCount, 1);
      });

      assert.strictEqual(eventbus.eventCount, 1);

      eventbus.on('test:trigger:verify', () =>
      {
         assert.strictEqual(callbacks.testTriggerOnce, 1);

         assert.strictEqual(eventbus.eventCount, 1);

         done();
      });

      assert.strictEqual(eventbus.eventCount, 2);

      eventbus.triggerDefer('test:trigger');
      eventbus.triggerDefer('test:trigger');
      eventbus.triggerDefer('test:trigger:verify');

      assert.strictEqual(eventbus.eventCount, 2);
   });

   it('triggerSync-0', () =>
   {
      const result = eventbus.triggerSync('test:trigger:sync0');

      assert.strictEqual(eventbus.eventCount, 0);

      assert.isNotArray(result);
      assert.isUndefined(result);
   });

   it('triggerSync-1', () =>
   {
      eventbus.on('test:trigger:sync1', () => { callbacks.testTriggerSync1 = true; return 'foo'; });

      assert.strictEqual(eventbus.eventCount, 1);

      const result = eventbus.triggerSync('test:trigger:sync1');

      assert.isTrue(callbacks.testTriggerSync1);
      assert.isNotArray(result);
      assert.strictEqual(result, 'foo');
   });

   it('triggerSync-2', () =>
   {
      eventbus.on('test:trigger:sync2', () => { callbacks.testTriggerSync2A = true; return 'foo'; });
      eventbus.on('test:trigger:sync2', () => { callbacks.testTriggerSync2B = true; return 'bar'; });

      assert.strictEqual(eventbus.eventCount, 2);

      const results = eventbus.triggerSync('test:trigger:sync2');

      assert.isTrue(callbacks.testTriggerSync2A);
      assert.isTrue(callbacks.testTriggerSync2B);
      assert.isArray(results);
      assert.strictEqual(results.length, 2);
      assert.strictEqual(results[0], 'foo');
      assert.strictEqual(results[1], 'bar');
   });

   it('triggerSync (on / off)', () =>
   {
      assert.strictEqual(eventbus.eventCount, 0);

      eventbus.on('test:trigger:sync:off', () => { callbacks.testTriggerSyncOff = true; return true; });

      assert.strictEqual(eventbus.eventCount, 1);

      eventbus.off('test:trigger:sync:off');

      assert.strictEqual(eventbus.eventCount, 0);

      assert.isUndefined(eventbus.triggerSync('test:trigger:sync:off'));
      assert.isUndefined(callbacks.testTriggerSyncOff);
   });

   it('triggerSync-1 (once)', () =>
   {
      callbacks.testTriggerOnce = 0;

      eventbus.once('test:trigger:once', () => { callbacks.testTriggerOnce++; return 'foo'; });

      assert.strictEqual(eventbus.eventCount, 1);

      let result = eventbus.triggerSync('test:trigger:once');

      assert.strictEqual(eventbus.eventCount, 0);

      assert.strictEqual(callbacks.testTriggerOnce, 1);
      assert.isNotArray(result);
      assert.strictEqual(result, 'foo');

      result = eventbus.triggerSync('test:trigger:once');

      assert.strictEqual(callbacks.testTriggerOnce, 1);
      assert.isUndefined(result);
   });

   it('triggerSync-1 (listenTo)', () =>
   {
      const test = new TyphonEvents();

      callbacks.testTriggerCount = 0;

      test.listenTo(eventbus, 'test:trigger:sync', () => { callbacks.testTriggerCount++; return 'foo'; });

      assert.strictEqual(eventbus.eventCount, 1);

      let result = eventbus.triggerSync('test:trigger:sync');

      assert.strictEqual(callbacks.testTriggerCount, 1);
      assert.isNotArray(result);
      assert.strictEqual(result, 'foo');

      assert.strictEqual(eventbus.eventCount, 1);

      test.stopListening(eventbus, 'test:trigger:sync');

      assert.strictEqual(eventbus.eventCount, 0);

      result = eventbus.triggerSync('test:trigger:sync');

      assert.strictEqual(callbacks.testTriggerCount, 1);
      assert.isUndefined(result);
   });

   it('triggerSync-1 (listenToOnce)', () =>
   {
      const test = new TyphonEvents();

      callbacks.testTriggerOnce = 0;

      test.listenToOnce(eventbus, 'test:trigger:once', () => { callbacks.testTriggerOnce++; return 'foo'; });

      assert.strictEqual(eventbus.eventCount, 1);

      let result = eventbus.triggerSync('test:trigger:once');

      assert.strictEqual(eventbus.eventCount, 0);

      assert.strictEqual(callbacks.testTriggerOnce, 1);
      assert.isNotArray(result);
      assert.strictEqual(result, 'foo');

      result = eventbus.triggerSync('test:trigger:once');

      assert.strictEqual(callbacks.testTriggerOnce, 1);
      assert.isUndefined(result);
   });

   it('triggerSync (Promise)', (done) =>
   {
      eventbus.on('test:trigger:sync:then', () =>
      {
         callbacks.testTriggerSyncThen = true;

         return Promise.resolve('foobar');
      });

      assert.strictEqual(eventbus.eventCount, 1);

      const promise = eventbus.triggerSync('test:trigger:sync:then');

      assert(promise instanceof Promise);

      promise.then((result) =>
      {
         assert.isTrue(callbacks.testTriggerSyncThen);
         assert.strictEqual(result, 'foobar');
         done();
      });
   });

   it('triggerAsync', (done) =>
   {
      eventbus.on('test:trigger:async', () => { callbacks.testTriggerAsync = true; return 'foo'; });
      eventbus.on('test:trigger:async', () => { callbacks.testTriggerAsync2 = true; return 'bar'; });

      assert.strictEqual(eventbus.eventCount, 2);

      const promise = eventbus.triggerAsync('test:trigger:async');

      assert(promise instanceof Promise);

      // triggerAsync resolves all Promises by Promise.all() so result is an array.
      promise.then((result) =>
      {
         assert.isTrue(callbacks.testTriggerAsync);
         assert.isTrue(callbacks.testTriggerAsync2);
         assert.strictEqual(result[0], 'foo');
         assert.strictEqual(result[1], 'bar');
         done();
      });
   });

   it('triggerAsync (once)', (done) =>
   {
      callbacks.testTriggerOnce = 0;

      assert.strictEqual(eventbus.eventCount, 0);

      eventbus.once('test:trigger:once', () => { callbacks.testTriggerOnce++; return 'foo'; });

      assert.strictEqual(eventbus.eventCount, 1);

      const promise = eventbus.triggerAsync('test:trigger:once');

      assert.strictEqual(eventbus.eventCount, 0);

      assert.strictEqual(callbacks.testTriggerOnce, 1);
      assert(promise instanceof Promise);

      const promise2 = eventbus.triggerAsync('test:trigger:once');

      assert.strictEqual(callbacks.testTriggerOnce, 1);
      assert(promise2 instanceof Promise);

      // triggerAsync resolves all Promises by Promise.all() or Promise.resolve() so result is a string.
      promise.then((result) =>
      {
         assert.strictEqual(callbacks.testTriggerOnce, 1);
         assert.strictEqual(result, 'foo');
         done();
      });
   });

   it('triggerAsync (listenTo)', (done) =>
   {
      const test = new TyphonEvents();

      callbacks.testTriggerCount = 0;

      test.listenTo(eventbus, 'test:trigger:async', () => { callbacks.testTriggerCount++; return 'foo'; });

      assert.strictEqual(eventbus.eventCount, 1);

      let promise = eventbus.triggerAsync('test:trigger:async');

      assert(promise instanceof Promise);

      promise.then((result) =>
      {
         assert.strictEqual(callbacks.testTriggerCount, 1);
         assert.strictEqual(result, 'foo');
      });

      test.stopListening(eventbus, 'test:trigger:async');

      assert.strictEqual(eventbus.eventCount, 0);

      promise = eventbus.triggerAsync('test:trigger:async');

      promise.then((result) =>
      {
         assert.isUndefined(result);
         assert.strictEqual(callbacks.testTriggerCount, 1);
         done();
      });
   });

   it('triggerAsync (listenToOnce)', (done) =>
   {
      const test = new TyphonEvents();

      callbacks.testTriggerOnce = 0;

      assert.strictEqual(eventbus.eventCount, 0);

      test.listenToOnce(eventbus, 'test:trigger:once', () => { callbacks.testTriggerOnce++; return 'foo'; });

      assert.strictEqual(eventbus.eventCount, 1);

      const promise = eventbus.triggerAsync('test:trigger:once');

      assert.strictEqual(eventbus.eventCount, 0);

      assert.strictEqual(callbacks.testTriggerOnce, 1);
      assert(promise instanceof Promise);

      const promise2 = eventbus.triggerAsync('test:trigger:once');

      assert.strictEqual(callbacks.testTriggerOnce, 1);
      assert(promise2 instanceof Promise);

      // triggerAsync resolves all Promises by Promise.all() or Promise.resolve() so result is a string.
      promise.then((result) =>
      {
         assert.strictEqual(callbacks.testTriggerOnce, 1);
         assert.strictEqual(result, 'foo');
         done();
      });
   });
});<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 * @format
 */
'use strict';

const Systrace = require('Systrace');

const infoLog = require('infoLog');
const performanceNow =
  /* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an
   * error found when Flow v0.54 was deployed. To see the error delete this
   * comment and run Flow. */
  global.nativePerformanceNow || require('fbjs/lib/performanceNow');

type Timespan = {
  description?: string,
  totalTime?: number,
  startTime?: number,
  endTime?: number,
};

let timespans: {[key: string]: Timespan} = {};
let extras: {[key: string]: any} = {};
const cookies: {[key: string]: number} = {};

const PRINT_TO_CONSOLE = false;

/**
 * This is meant to collect and log performance data in production, which means
 * it needs to have minimal overhead.
 */
const PerformanceLogger = {
  addTimespan(key: string, lengthInMs: number, description?: string) {
    if (timespans[key]) {
      if (__DEV__) {
        infoLog(
          'PerformanceLogger: Attempting to add a timespan that already exists ',
          key,
        );
      }
      return;
    }

    timespans[key] = {
      description: description,
      totalTime: lengthInMs,
    };
  },

  startTimespan(key: string, description?: string) {
    if (timespans[key]) {
      if (__DEV__) {
        infoLog(
          'PerformanceLogger: Attempting to start a timespan that already exists ',
          key,
        );
      }
      return;
    }

    timespans[key] = {
      description: description,
      startTime: performanceNow(),
    };
    cookies[key] = Systrace.beginAsyncEvent(key);
    if (__DEV__ && PRINT_TO_CONSOLE) {
      infoLog('PerformanceLogger.js', 'start: ' + key);
    }
  },

  stopTimespan(key: string) {
    const timespan = timespans[key];
    if (!timespan || !timespan.startTime) {
      if (__DEV__) {
        infoLog(
          'PerformanceLogger: Attempting to end a timespan that has not started ',
          key,
        );
      }
      return;
    }
    if (timespan.endTime) {
      if (__DEV__) {
        infoLog(
          'PerformanceLogger: Attempting to end a timespan that has already ended ',
          key,
        );
      }
      return;
    }

    timespan.endTime = performanceNow();
    timespan.totalTime = timespan.endTime - (timespan.startTime || 0);
    if (__DEV__ && PRINT_TO_CONSOLE) {
      infoLog('PerformanceLogger.js', 'end: ' + key);
    }

    Systrace.endAsyncEvent(key, cookies[key]);
    delete cookies[key];
  },

  clear() {
    timespans = {};
    extras = {};
    if (__DEV__ && PRINT_TO_CONSOLE) {
      infoLog('PerformanceLogger.js', 'clear');
    }
  },

  clearCompleted() {
    for (const key in timespans) {
      if (timespans[key].totalTime) {
        delete timespans[key];
      }
    }
    extras = {};
    if (__DEV__ && PRINT_TO_CONSOLE) {
      infoLog('PerformanceLogger.js', 'clearCompleted');
    }
  },

  clearExceptTimespans(keys: Array<string>) {
    timespans = Object.keys(timespans).reduce(function(previous, key) {
      if (keys.indexOf(key) !== -1) {
        previous[key] = timespans[key];
      }
      return previous;
    }, {});
    extras = {};
  },

  currentTimestamp() {
    return performanceNow();
  },

  getTimespans() {
    return timespans;
  },

  hasTimespan(key: string) {
    return !!timespans[key];
  },

  logTimespans() {
    for (const key in timespans) {
      if (timespans[key].totalTime) {
        infoLog(key + ': ' + timespans[key].totalTime + 'ms');
      }
    }
  },

  addTimespans(newTimespans: Array<number>, labels: Array<string>) {
    for (let ii = 0, l = newTimespans.length; ii < l; ii += 2) {
      const label = labels[ii / 2];
      PerformanceLogger.addTimespan(
        label,
        newTimespans[ii + 1] - newTimespans[ii],
        label,
      );
    }
  },

  setExtra(key: string, value: any) {
    if (extras[key]) {
      if (__DEV__) {
        infoLog(
          'PerformanceLogger: Attempting to set an extra that already exists ',
          {key, currentValue: extras[key], attemptedValue: value},
        );
      }
      return;
    }
    extras[key] = value;
  },

  getExtras() {
    return extras;
  },
};

module.exports = PerformanceLogger;
<commit_msg>improve console logging<commit_after>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 * @format
 */
'use strict';

const Systrace = require('Systrace');

const infoLog = require('infoLog');
const performanceNow =
  /* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an
   * error found when Flow v0.54 was deployed. To see the error delete this
   * comment and run Flow. */
  global.nativePerformanceNow || require('fbjs/lib/performanceNow');

type Timespan = {
  description?: string,
  totalTime?: number,
  startTime?: number,
  endTime?: number,
};

let timespans: {[key: string]: Timespan} = {};
let extras: {[key: string]: any} = {};
const cookies: {[key: string]: number} = {};

const PRINT_TO_CONSOLE: false = false; // Type as false to prevent accidentally committing `true`;

/**
 * This is meant to collect and log performance data in production, which means
 * it needs to have minimal overhead.
 */
const PerformanceLogger = {
  addTimespan(key: string, lengthInMs: number, description?: string) {
    if (timespans[key]) {
      if (__DEV__) {
        infoLog(
          'PerformanceLogger: Attempting to add a timespan that already exists ',
          key,
        );
      }
      return;
    }

    timespans[key] = {
      description: description,
      totalTime: lengthInMs,
    };
  },

  startTimespan(key: string, description?: string) {
    if (timespans[key]) {
      if (__DEV__) {
        infoLog(
          'PerformanceLogger: Attempting to start a timespan that already exists ',
          key,
        );
      }
      return;
    }

    timespans[key] = {
      description: description,
      startTime: performanceNow(),
    };
    cookies[key] = Systrace.beginAsyncEvent(key);
    if (PRINT_TO_CONSOLE) {
      infoLog('PerformanceLogger.js', 'start: ' + key);
    }
  },

  stopTimespan(key: string) {
    const timespan = timespans[key];
    if (!timespan || !timespan.startTime) {
      if (__DEV__) {
        infoLog(
          'PerformanceLogger: Attempting to end a timespan that has not started ',
          key,
        );
      }
      return;
    }
    if (timespan.endTime) {
      if (__DEV__) {
        infoLog(
          'PerformanceLogger: Attempting to end a timespan that has already ended ',
          key,
        );
      }
      return;
    }

    timespan.endTime = performanceNow();
    timespan.totalTime = timespan.endTime - (timespan.startTime || 0);
    if (PRINT_TO_CONSOLE) {
      infoLog('PerformanceLogger.js', 'end: ' + key);
    }

    Systrace.endAsyncEvent(key, cookies[key]);
    delete cookies[key];
  },

  clear() {
    timespans = {};
    extras = {};
    if (PRINT_TO_CONSOLE) {
      infoLog('PerformanceLogger.js', 'clear');
    }
  },

  clearCompleted() {
    for (const key in timespans) {
      if (timespans[key].totalTime) {
        delete timespans[key];
      }
    }
    extras = {};
    if (PRINT_TO_CONSOLE) {
      infoLog('PerformanceLogger.js', 'clearCompleted');
    }
  },

  clearExceptTimespans(keys: Array<string>) {
    timespans = Object.keys(timespans).reduce(function(previous, key) {
      if (keys.indexOf(key) !== -1) {
        previous[key] = timespans[key];
      }
      return previous;
    }, {});
    extras = {};
    if (PRINT_TO_CONSOLE) {
      infoLog('PerformanceLogger.js', 'clearExceptTimespans', keys);
    }
  },

  currentTimestamp() {
    return performanceNow();
  },

  getTimespans() {
    return timespans;
  },

  hasTimespan(key: string) {
    return !!timespans[key];
  },

  logTimespans() {
    for (const key in timespans) {
      if (timespans[key].totalTime) {
        infoLog(key + ': ' + timespans[key].totalTime + 'ms');
      }
    }
  },

  addTimespans(newTimespans: Array<number>, labels: Array<string>) {
    for (let ii = 0, l = newTimespans.length; ii < l; ii += 2) {
      const label = labels[ii / 2];
      PerformanceLogger.addTimespan(
        label,
        newTimespans[ii + 1] - newTimespans[ii],
        label,
      );
    }
  },

  setExtra(key: string, value: any) {
    if (extras[key]) {
      if (__DEV__) {
        infoLog(
          'PerformanceLogger: Attempting to set an extra that already exists ',
          {key, currentValue: extras[key], attemptedValue: value},
        );
      }
      return;
    }
    extras[key] = value;
  },

  getExtras() {
    return extras;
  },
};

module.exports = PerformanceLogger;
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var createTestProperties = function createTestProperties() {
  if ( ! foam.lookup('test.PropTypeTester', true) ) {
    foam.CLASS({
      name: 'PropTypeTester',
      package: 'test',

      properties: [
        {
          class: 'Date',
          name: 'date',
        },
        {
          class: 'DateTime',
          name: 'dateTime',
        },
        {
          class: 'Long',
          name: 'long',
        },
        {
          class: 'Float',
          name: 'float',
        },
        {
          class: 'Function',
          name: 'func',
        },
        {
          class: 'Blob',
          name: 'blob',
        },
        {
          class: 'StringArray',
          name: 'stringArray',
        },
        {
          class: 'Class',
          name: 'class',
        }
        // TODO: other types, as they gain testable functionality
      ]
    });
  }

  return test.PropTypeTester.create(undefined, foam.__context__);
}
var createDateTestProperties = function createDateTestProperties() {
  if ( ! foam.lookup('test.DateTypeTester', true) ) {
    foam.CLASS({
      name: 'DateTypeTester',
      package: 'test',

      properties: [
        {
          class: 'Date',
          name: 'date',
        },
        {
          class: 'DateTime',
          name: 'dateTime',
        },
      ]
    });
  }
  return test.DateTypeTester.create(undefined, foam.__context__);
}

describe('Date', function() {
  var p;
  var p2;

  beforeEach(function() {
    p = createDateTestProperties();
    p2 = createDateTestProperties();
  });
  afterEach(function() {
    p = null;
    p2 = null;
  });

  it('accepts dates', function() {
    var d = new Date();
    p.date = d;
    expect(p.date).toBe(d);
  });
  it('accepts numbers', function() {
    p.date = 3434;
    expect(p.date).toEqual(new Date(3434));
  });
  it('accepts valid date strings', function() {
    dateStr = "Wed Dec 31 1987 19:00:03 GMT-0500 (EST)";
    p.date = dateStr;
    expect(p.date).toEqual(new Date(dateStr));
  });
  it('accepts invalid date strings, retains invalidity', function() {
    dateStr = "d ";
    p.date = dateStr;
    expect(p.date.toUTCString()).toEqual((new Date(dateStr)).toUTCString());
  });
  it('compares', function() {
    p.date = 55555;
    p2.date = 88888;

    expect(p.compareTo(p2)).toEqual(-1);
    expect(p2.compareTo(p)).toEqual(1);
  });
  it('compares when undefined', function() {
    p2.date = 88888;

    expect(p.compareTo(p2)).toEqual(-1);
    expect(p2.compareTo(p)).toEqual(1);
  });
  it('compares when undefined2', function() {
    p.date = 55555;

    expect(p.compareTo(p2)).toEqual(1);
    expect(p2.compareTo(p)).toEqual(-1);
  });
  it('compares when equal', function() {
    expect(p.compareTo(p2)).toEqual(0);
    expect(p2.compareTo(p)).toEqual(0);

    p.date =  55555;
    p2.date = 55555;
    expect(p.compareTo(p2)).toEqual(0);
    expect(p2.compareTo(p)).toEqual(0);
    expect(p.equals(p2)).toEqual(true);

  });
});

describe('Float', function() {
  var p;

  beforeEach(function() {
    p = createTestProperties();
  });
  afterEach(function() {
    p = null;
  });

  it('accepts ints', function() {
    p.float = 5;
    expect(p.float).toEqual(5);
  });
  it('accepts floats', function() {
    p.float = 456.456332;
    expect(p.float).toEqual(456.456332);
  });
  it('accepts negative floats', function() {
    p.float = -3.948474;
    expect(p.float).toEqual(-3.948474);
  });
  it('accepts string floats', function() {
    p.float = "-3.948474";
    expect(p.float).toEqual(-3.948474);
  });
  it('defaults to 0 if falsey', function() {
    p.float = null;
    expect(p.float).toEqual(0);
    p.float = '';
    expect(p.float).toEqual(0);
    p.float = undefined;
    expect(p.float).toEqual(0);
  });
});

describe('Function', function() {
  var p;

  beforeEach(function() {
    p = createTestProperties();
  });
  afterEach(function() {
    p = null;
  });

  it('defaults to a function', function() {
    expect(typeof p.func).toEqual('function');
    p.func();
  });
  it('accepts functions', function() {
    p.func = function() { return 55; }
    expect(p.func()).toEqual(55);
  });
  it('rejects non functions', function() {
    expect(function() {
      p.func = 'asdlfkjalskdjf';
    }).toThrow();
  });
});

describe('StringArray', function() {
  var p;

  beforeEach(function() {
    p = createTestProperties();
  });
  afterEach(function() {
    p = null;
  });

  it('setting an array to a number throws an exception', function() {
    expect(function() { p.stringArray = 42; }).toThrow();
  });
  it('setting an array to null throws an exception', function() {
    expect(function() { p.stringArray = null; }).toThrow();
  });
  it('setting an array to an object throws an exception', function() {
    expect(function() { p.stringArray = {}; }).toThrow();
  });
  it('is empty array by default', function() {
    expect(p.stringArray).toEqual([]);
  });
  it('accepts string in an array', function() {
    p.stringArray = [ "Hello", "I see", "Well" ];
    expect(p.stringArray).toEqual([ "Hello", "I see", "Well" ]);
  });
  it('converts elements to strings', function() {
    var d = new Date();
    var golden = '' + d;

    p.stringArray = [
      { a: 1 },
      2,
      true,
      d,
      'hello'
    ];

    expect(p.stringArray).toEqual([
      '[object Object]',
      '2',
      'true',
      golden,
      'hello'
    ]);
  });
});

describe('Class property', function() {
  var p;

  beforeEach(function() {
    p = createTestProperties();
    createDateTestProperties();
  });
  afterEach(function() {
    p = null;
  });

  it('is undefined by default', function() {
    expect(p.class).toBeUndefined();
  });

  it('stores a given model instance', function() {
    p.class = test.DateTypeTester;
    expect(p.class).toBe(test.DateTypeTester);
  });
  it('looks up a model from a string name', function() {
    p.class = 'test.DateTypeTester';
    expect(p.class).toBe(test.DateTypeTester);
  });
  it('accepts undefined', function() {
    p.class = 'test.DateTypeTester';
    expect(p.class).toBe(test.DateTypeTester);

    p.class = undefined;
    expect(p.class).toBeUndefined();
  });

});
<commit_msg>Add float hashing test<commit_after>/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var createTestProperties = function createTestProperties() {
  if ( ! foam.lookup('test.PropTypeTester', true) ) {
    foam.CLASS({
      name: 'PropTypeTester',
      package: 'test',

      properties: [
        {
          class: 'Date',
          name: 'date',
        },
        {
          class: 'DateTime',
          name: 'dateTime',
        },
        {
          class: 'Long',
          name: 'long',
        },
        {
          class: 'Float',
          name: 'float',
        },
        {
          class: 'Function',
          name: 'func',
        },
        {
          class: 'Blob',
          name: 'blob',
        },
        {
          class: 'StringArray',
          name: 'stringArray',
        },
        {
          class: 'Class',
          name: 'class',
        }
        // TODO: other types, as they gain testable functionality
      ]
    });
  }

  return test.PropTypeTester.create(undefined, foam.__context__);
}
var createDateTestProperties = function createDateTestProperties() {
  if ( ! foam.lookup('test.DateTypeTester', true) ) {
    foam.CLASS({
      name: 'DateTypeTester',
      package: 'test',

      properties: [
        {
          class: 'Date',
          name: 'date',
        },
        {
          class: 'DateTime',
          name: 'dateTime',
        },
      ]
    });
  }
  return test.DateTypeTester.create(undefined, foam.__context__);
}

describe('Date', function() {
  var p;
  var p2;

  beforeEach(function() {
    p = createDateTestProperties();
    p2 = createDateTestProperties();
  });
  afterEach(function() {
    p = null;
    p2 = null;
  });

  it('accepts dates', function() {
    var d = new Date();
    p.date = d;
    expect(p.date).toBe(d);
  });
  it('accepts numbers', function() {
    p.date = 3434;
    expect(p.date).toEqual(new Date(3434));
  });
  it('accepts valid date strings', function() {
    dateStr = "Wed Dec 31 1987 19:00:03 GMT-0500 (EST)";
    p.date = dateStr;
    expect(p.date).toEqual(new Date(dateStr));
  });
  it('accepts invalid date strings, retains invalidity', function() {
    dateStr = "d ";
    p.date = dateStr;
    expect(p.date.toUTCString()).toEqual((new Date(dateStr)).toUTCString());
  });
  it('compares', function() {
    p.date = 55555;
    p2.date = 88888;

    expect(p.compareTo(p2)).toEqual(-1);
    expect(p2.compareTo(p)).toEqual(1);
  });
  it('compares when undefined', function() {
    p2.date = 88888;

    expect(p.compareTo(p2)).toEqual(-1);
    expect(p2.compareTo(p)).toEqual(1);
  });
  it('compares when undefined2', function() {
    p.date = 55555;

    expect(p.compareTo(p2)).toEqual(1);
    expect(p2.compareTo(p)).toEqual(-1);
  });
  it('compares when equal', function() {
    expect(p.compareTo(p2)).toEqual(0);
    expect(p2.compareTo(p)).toEqual(0);

    p.date =  55555;
    p2.date = 55555;
    expect(p.compareTo(p2)).toEqual(0);
    expect(p2.compareTo(p)).toEqual(0);
    expect(p.equals(p2)).toEqual(true);

  });
});

describe('Float', function() {
  var p;

  beforeEach(function() {
    p = createTestProperties();
  });
  afterEach(function() {
    p = null;
  });

  it('accepts ints', function() {
    p.float = 5;
    expect(p.float).toEqual(5);
  });
  it('accepts floats', function() {
    p.float = 456.456332;
    expect(p.float).toEqual(456.456332);
  });
  it('accepts negative floats', function() {
    p.float = -3.948474;
    expect(p.float).toEqual(-3.948474);
  });
  it('accepts string floats', function() {
    p.float = "-3.948474";
    expect(p.float).toEqual(-3.948474);
  });
  it('defaults to 0 if falsey', function() {
    p.float = null;
    expect(p.float).toEqual(0);
    p.float = '';
    expect(p.float).toEqual(0);
    p.float = undefined;
    expect(p.float).toEqual(0);
  });

  it('has different hashes for f1 != f2, round(f1) == round(f2)', function() {
    // Hash code should be deterministic.
    expect(foam.util.hashCode(p)).toBe(foam.util.hashCode(p));
    p.float = 0.01;
    var hashPsFloat0_01 = foam.util.hashCode(p);
    p.float = 0.001;
    var hashPsFloat0_001 = foam.util.hashCode(p);
    expect(hashPsFloat0_01).not.toEqual(hashPsFloat0_001);
  });
});

describe('Function', function() {
  var p;

  beforeEach(function() {
    p = createTestProperties();
  });
  afterEach(function() {
    p = null;
  });

  it('defaults to a function', function() {
    expect(typeof p.func).toEqual('function');
    p.func();
  });
  it('accepts functions', function() {
    p.func = function() { return 55; }
    expect(p.func()).toEqual(55);
  });
  it('rejects non functions', function() {
    expect(function() {
      p.func = 'asdlfkjalskdjf';
    }).toThrow();
  });
});

describe('StringArray', function() {
  var p;

  beforeEach(function() {
    p = createTestProperties();
  });
  afterEach(function() {
    p = null;
  });

  it('setting an array to a number throws an exception', function() {
    expect(function() { p.stringArray = 42; }).toThrow();
  });
  it('setting an array to null throws an exception', function() {
    expect(function() { p.stringArray = null; }).toThrow();
  });
  it('setting an array to an object throws an exception', function() {
    expect(function() { p.stringArray = {}; }).toThrow();
  });
  it('is empty array by default', function() {
    expect(p.stringArray).toEqual([]);
  });
  it('accepts string in an array', function() {
    p.stringArray = [ "Hello", "I see", "Well" ];
    expect(p.stringArray).toEqual([ "Hello", "I see", "Well" ]);
  });
  it('converts elements to strings', function() {
    var d = new Date();
    var golden = '' + d;

    p.stringArray = [
      { a: 1 },
      2,
      true,
      d,
      'hello'
    ];

    expect(p.stringArray).toEqual([
      '[object Object]',
      '2',
      'true',
      golden,
      'hello'
    ]);
  });
});

describe('Class property', function() {
  var p;

  beforeEach(function() {
    p = createTestProperties();
    createDateTestProperties();
  });
  afterEach(function() {
    p = null;
  });

  it('is undefined by default', function() {
    expect(p.class).toBeUndefined();
  });

  it('stores a given model instance', function() {
    p.class = test.DateTypeTester;
    expect(p.class).toBe(test.DateTypeTester);
  });
  it('looks up a model from a string name', function() {
    p.class = 'test.DateTypeTester';
    expect(p.class).toBe(test.DateTypeTester);
  });
  it('accepts undefined', function() {
    p.class = 'test.DateTypeTester';
    expect(p.class).toBe(test.DateTypeTester);

    p.class = undefined;
    expect(p.class).toBeUndefined();
  });

});
<|endoftext|>