<commit_before>/*
 *	Run this test with mocha:
 *	http://visionmedia.github.io/mocha/
 */

var assert = require('assert');
var https = require('https');
var http = require('http');
var path = require('path');
var net = require('net');
var tls = require('tls');

describe('Proxy', function(){
	'use strict';

	var self = this;

	before(function(done){
		self.options = {
			port: 8000,
			host: '127.0.0.1',
			testServerPort: 8080
		};

		self.Proxy = require(path.join(path.dirname(module.filename), '..', 'lib', 'Proxy.js'));
		done();
	});

	after(function(done){
		self.proxy.stop(done);
	});

	it('should exist', function(){
		assert.ok(self.Proxy);
	});

	it('should initialize', function(){
		self.proxy = new self.Proxy(self.options);
		assert.ok(self.proxy);
	});

	it('should start', function(done){
		self.proxy.start(done);
	});

	it('should stop', function(done){
		self.proxy.stop(done);
	});

	it('should start again', function(done){
		self.proxy.start(done);
	});

	it('should stop again', function(done){
		self.proxy.stop(done);
	});

	describe('HTTP', function(){
		before(function(done){
			var init = self.proxy.whenAllDone.bind(self, {todo: 2}, done);
			self.proxy.start(init);

			self.content = "HELLO WORLD!\n";
			self.server = false;
			self.server = http.createServer(function(request, response){
				response.writeHead(200, {
					'Content-Type': 'text/plain',
					'Content-Length': self.content.length
				});
				response.write(self.content);
				response.end();
			});
			self.server.listen(self.options.testServerPort, self.options.host, 511, function(){
				init();
			});
		});

		after(function(done){
			var cleanup = self.proxy.whenAllDone.bind(self, {todo: 2}, done);

			self.server.close(cleanup);
			self.proxy.stop(cleanup);
		});

		it('should get correct answer from server', function(done){
			this.timeout(2000);
			self.target = {
				hostname: self.options.host,
				port: self.options.httpPort,
				path: '/hello',
				headers: {
					'Host': self.options.host+':'+self.options.testServerPort,
					'Content-Type': 'text/plain; charset=utf8'
				},
				agent: false
			};
			var request = http.request(self.target, function(response){
				var downloaded = '';
				response.on('data', function(data){
					downloaded += data;
				});
				response.on('end', function(){
					assert.strictEqual(downloaded, self.content);
					done();
				});
			});
			request.end();
		});
	});

	describe('HTTPS', function(){
		before(function(done){
			var init = self.proxy.whenAllDone.bind(self, {todo: 2}, done);
			self.proxy.start(init);

			self.content = "HELLO WORLD!\n";
			self.server = false;
			self.server = https.createServer(self.options, function(request, response){
				response.writeHead(200, {
					'Content-Type': 'text/plain',
					'Content-Length': self.content.length
				});
				response.write(self.content);
				response.end();
			});
			self.server.listen(self.options.testServerPort, self.options.host, 511, init);
		});

		after(function(done){
			var cleanup = self.proxy.whenAllDone.bind(self, {todo: 2}, done);

			self.server.close(cleanup);
			self.proxy.stop(cleanup);
		});

		it('should get correct answer from server through HTTPS proxy', function(done){
			this.timeout(2000);

			self.target = {
				hostname: self.options.host,
				port: self.options.httpsPort,
				path: '/hello',
				headers: {
					'Host': self.options.host+':'+self.options.testServerPort,
					'Content-Type': 'text/plain; charset=utf8'
				},
				agent: false
			};
			var request = https.request(self.target, function(response){
				var downloaded = '';
				response.on('data', function(data){
					downloaded += data;
				});
				response.on('end', function(){
					assert.strictEqual(downloaded, self.content);
					done();
				});
			});
			request.end();
		});

		it('should get correct answer from server through HTTPS tunnel on HTTP proxy', function(done){
			this.timeout(2000);

			// Based on: https://github.com/joyent/node/issues/2474#issuecomment-3481078
			var tunnel = http.request({ // establishing a tunnel
				host: self.options.host,
				port: self.options.httpPort,
				method: 'CONNECT',
				agent: false,
				path: self.options.host+':'+self.options.testServerPort
			}).on('connect', function(res, socket, head) {
				self.target = {
					hostname: self.options.host,
					socket: socket,
					path: '/hello',
					headers: {
						'Host': self.options.host+':'+self.options.testServerPort,
						'Content-Type': 'text/plain; charset=utf8'
					},
					agent: false
				};
				https.request(self.target, function(response){
					var downloaded = '';
					response.on('data', function(data){
						downloaded += data;
					});
					response.on('end', function(){
						assert.strictEqual(downloaded, self.content);
						done();
					});
				}).end();
			}).end();
		});
	});

	describe('HTTP through another proxy', function(){
		var proxy2;
		var options2 = {
			port: 8005,
			host: '127.0.0.1'
		};

		before(function(done){
			var init = self.proxy.whenAllDone.bind(self, {todo: 3}, done);
			self.proxy.start(init);

			proxy2 = new self.Proxy(options2);
			proxy2.start(init);

			self.content = "HELLO WORLD!\n";
			self.server = false;
			self.server = http.createServer(function(request, response){
				response.writeHead(200, {
					'Content-Type': 'text/plain',
					'Content-Length': self.content.length
				});
				response.write(self.content);
				response.end();
			});
			self.server.listen(self.options.testServerPort, self.options.host, 511, function(){
				init();
			});
		});

		after(function(done){
			var cleanup = self.proxy.whenAllDone.bind(self, {todo: 3}, done);

			proxy2.stop(cleanup);
			self.proxy.stop(cleanup);
			self.server.close(cleanup);
		});

		it('should get correct answer from server', function(done){
			this.timeout(2000);

			options2.proxy = {
				hostname: self.options.host,
				port: self.options.port
			};

			self.target = {
				hostname: options2.host,
				port: options2.httpPort,
				path: 'http://' + self.options.host + ':' + self.options.testServerPort + '/hello',
				headers: {
					'Host': self.options.host+':'+self.options.testServerPort,
					'Content-Type': 'text/plain; charset=utf8'
				},
				agent: false
			};
			var request = http.request(self.target, function(response){
				var downloaded = '';
				response.on('data', function(data){
					downloaded += data;
				});
				response.on('end', function(){
					assert.strictEqual(downloaded, self.content);
					done();
				});
			}).end();
		});
	});

	describe('HTTPS through another proxy', function(){
		var proxy2;
		var options2 = {
			port: 8005,
			host: '127.0.0.1'
		};

		before(function(done){
			var init = self.proxy.whenAllDone.bind(self, {todo: 3}, done);
			self.proxy.start(init);

			proxy2 = new self.Proxy(options2);
			proxy2.start(init);

			self.content = "HELLO WORLD!\n";
			self.server = false;
			self.server = https.createServer(self.options, function(request, response){
				response.writeHead(200, {
					'Content-Type': 'text/plain',
					'Content-Length': self.content.length
				});
				response.write(self.content);
				response.end();
			});
			self.server.listen(self.options.testServerPort, self.options.host, 511, init);
		});

		after(function(done){
			var cleanup = self.proxy.whenAllDone.bind(self, {todo: 3}, done);

			proxy2.stop(cleanup);
			self.server.close(cleanup);
			self.proxy.stop(cleanup);
		});

		it('should get correct answer from server', function(done){
			this.timeout(2000);

			options2.proxy = {
				hostname: self.options.host,
				port: self.options.httpPort
			};

			// Based on: https://github.com/joyent/node/issues/2474#issuecomment-3481078
			var tunnel = http.request({ // establishing a tunnel
				host: options2.host,
				port: options2.httpPort,
				method: 'CONNECT',
				agent: false,
				path: self.options.host+':'+self.options.testServerPort,
			}).on('connect', function(res, socket, head) {
				self.target = {
					hostname: self.options.host,
					socket: socket,
					path: '/hello',
					headers: {
						'Host': self.options.host+':'+self.options.testServerPort,
						'Content-Type': 'text/plain; charset=utf8'
					},
					agent: false
				};
				https.request(self.target, function(response){
					var downloaded = '';
					response.on('data', function(data){
						downloaded += data;
					});
					response.on('end', function(){
						assert.strictEqual(downloaded, self.content);
						done();
					});
				}).end();
			}).end();
		});
	});

	describe('Certificates', function(){
		before(function(done){
			self.options.useSNI = true;
			// changing SNI option requires rebuilding server :(
			self.proxy = new self.Proxy(self.options);

			var init = self.proxy.whenAllDone.bind(self, {todo: 2}, done);
			self.proxy.start(init);

			self.content = "HELLO WORLD!\n";
			self.server = false;
			self.server = https.createServer(self.options, function(request, response){
				response.writeHead(200, {
					'Content-Type': 'text/plain',
					'Content-Length': self.content.length
				});
				response.write(self.content);
				response.end();
			});
			self.server.listen(self.options.testServerPort, self.options.host, 511, init);
		});

		after(function(done){
			var cleanup = self.proxy.whenAllDone.bind(self, {todo: 2}, done);

			self.server.close(cleanup);
			self.proxy.stop(cleanup);

			self.options.useSNI = false;
		});

		it('should get correct certificate from HTTPS server', function(done){
			this.timeout(3000);

			// We are connecting twice, because current version of node does not have asynchronous SNICallback.
			// TODO: simplify this to a single connection, without setTimout, when node v0.12 shows up.
			var ssocket = tls.connect(self.options.httpsPort, self.options.host, {servername: 'example.com'}, function(){
				ssocket.end();
			});
			ssocket.on('data', function(data){});
			ssocket.on('end', function(){
				setTimeout(function(){
					var ssocket = tls.connect(self.options.httpsPort, self.options.host, {servername: 'example.com'}, function(){
						ssocket.end();

						var cert = ssocket.getPeerCertificate();
						assert.strictEqual(cert.subject.O, 'hyperProxy');
						assert.strictEqual(cert.subject.CN, 'example.com');

						done();
					});
				}, 1000); // give it time to create certificates
			});
		});

		it('should get correct certificate from HTTPS-over-HTTP proxy', function(done){
			this.timeout(2000);

			// Based on: https://github.com/joyent/node/issues/2474#issuecomment-3481078
			var tunnel = http.request({ // establishing a tunnel
				host: self.options.host,
				port: self.options.httpPort,
				headers: {
					'Host': 'example.com'
				},
				method: 'CONNECT',
				agent: false,
				path: self.options.host+':'+self.options.testServerPort
			}).on('connect', function(res, socket, head) {
				var ssocket = tls.connect(0, {socket: socket, servername: 'example.com'}, function(){
					ssocket.write('GET / HTTP/1.1\r\n' +
						'Host: '+self.options.host+':'+self.options.testServerPort+'\r\n' +
						'Connection: close\r\n' +
						'\r\n');
					var cert = ssocket.getPeerCertificate();
					assert.strictEqual(cert.subject.O, 'hyperProxy');
					assert.strictEqual(cert.subject.CN, 'example.com');
				});
				ssocket.on('data', function(data){});
				ssocket.on('end', done);
			}).end();
		});

		it('should get correct certificate from HTTPS proxy', function(done){
			this.timeout(2000);

			https.request({hostname: self.options.host, port: self.options.httpsPort, headers: {host: 'example.com'}, path: 'https://'+self.options.host+':'+self.options.testServerPort+'/hello'}, function(res){
				res.on('data', function(data){});
				res.on('end', function(){
					var cert = res.connection.getPeerCertificate();
					assert.strictEqual(cert.subject.O, 'hyperProxy');
					assert.strictEqual(cert.subject.CN, 'example.com');
					done();
				});

			}).end();
		});
	});
});<commit_msg>Fixed test-proxy.js to use changed organization name (hyperProxy uses `hyperProxy target` now, instead of `hyperProxy`).<commit_after>/*
 *	Run this test with mocha:
 *	http://visionmedia.github.io/mocha/
 */

var assert = require('assert');
var https = require('https');
var http = require('http');
var path = require('path');
var net = require('net');
var tls = require('tls');

describe('Proxy', function(){
	'use strict';

	var self = this;

	before(function(done){
		self.options = {
			port: 8000,
			host: '127.0.0.1',
			testServerPort: 8080
		};

		self.Proxy = require(path.join(path.dirname(module.filename), '..', 'lib', 'Proxy.js'));
		done();
	});

	after(function(done){
		self.proxy.stop(done);
	});

	it('should exist', function(){
		assert.ok(self.Proxy);
	});

	it('should initialize', function(){
		self.proxy = new self.Proxy(self.options);
		assert.ok(self.proxy);
	});

	it('should start', function(done){
		self.proxy.start(done);
	});

	it('should stop', function(done){
		self.proxy.stop(done);
	});

	it('should start again', function(done){
		self.proxy.start(done);
	});

	it('should stop again', function(done){
		self.proxy.stop(done);
	});

	describe('HTTP', function(){
		before(function(done){
			var init = self.proxy.whenAllDone.bind(self, {todo: 2}, done);
			self.proxy.start(init);

			self.content = "HELLO WORLD!\n";
			self.server = false;
			self.server = http.createServer(function(request, response){
				response.writeHead(200, {
					'Content-Type': 'text/plain',
					'Content-Length': self.content.length
				});
				response.write(self.content);
				response.end();
			});
			self.server.listen(self.options.testServerPort, self.options.host, 511, function(){
				init();
			});
		});

		after(function(done){
			var cleanup = self.proxy.whenAllDone.bind(self, {todo: 2}, done);

			self.server.close(cleanup);
			self.proxy.stop(cleanup);
		});

		it('should get correct answer from server', function(done){
			this.timeout(2000);
			self.target = {
				hostname: self.options.host,
				port: self.options.httpPort,
				path: '/hello',
				headers: {
					'Host': self.options.host+':'+self.options.testServerPort,
					'Content-Type': 'text/plain; charset=utf8'
				},
				agent: false
			};
			var request = http.request(self.target, function(response){
				var downloaded = '';
				response.on('data', function(data){
					downloaded += data;
				});
				response.on('end', function(){
					assert.strictEqual(downloaded, self.content);
					done();
				});
			});
			request.end();
		});
	});

	describe('HTTPS', function(){
		before(function(done){
			var init = self.proxy.whenAllDone.bind(self, {todo: 2}, done);
			self.proxy.start(init);

			self.content = "HELLO WORLD!\n";
			self.server = false;
			self.server = https.createServer(self.options, function(request, response){
				response.writeHead(200, {
					'Content-Type': 'text/plain',
					'Content-Length': self.content.length
				});
				response.write(self.content);
				response.end();
			});
			self.server.listen(self.options.testServerPort, self.options.host, 511, init);
		});

		after(function(done){
			var cleanup = self.proxy.whenAllDone.bind(self, {todo: 2}, done);

			self.server.close(cleanup);
			self.proxy.stop(cleanup);
		});

		it('should get correct answer from server through HTTPS proxy', function(done){
			this.timeout(2000);

			self.target = {
				hostname: self.options.host,
				port: self.options.httpsPort,
				path: '/hello',
				headers: {
					'Host': self.options.host+':'+self.options.testServerPort,
					'Content-Type': 'text/plain; charset=utf8'
				},
				agent: false
			};
			var request = https.request(self.target, function(response){
				var downloaded = '';
				response.on('data', function(data){
					downloaded += data;
				});
				response.on('end', function(){
					assert.strictEqual(downloaded, self.content);
					done();
				});
			});
			request.end();
		});

		it('should get correct answer from server through HTTPS tunnel on HTTP proxy', function(done){
			this.timeout(2000);

			// Based on: https://github.com/joyent/node/issues/2474#issuecomment-3481078
			var tunnel = http.request({ // establishing a tunnel
				host: self.options.host,
				port: self.options.httpPort,
				method: 'CONNECT',
				agent: false,
				path: self.options.host+':'+self.options.testServerPort
			}).on('connect', function(res, socket, head) {
				self.target = {
					hostname: self.options.host,
					socket: socket,
					path: '/hello',
					headers: {
						'Host': self.options.host+':'+self.options.testServerPort,
						'Content-Type': 'text/plain; charset=utf8'
					},
					agent: false
				};
				https.request(self.target, function(response){
					var downloaded = '';
					response.on('data', function(data){
						downloaded += data;
					});
					response.on('end', function(){
						assert.strictEqual(downloaded, self.content);
						done();
					});
				}).end();
			}).end();
		});
	});

	describe('HTTP through another proxy', function(){
		var proxy2;
		var options2 = {
			port: 8005,
			host: '127.0.0.1'
		};

		before(function(done){
			var init = self.proxy.whenAllDone.bind(self, {todo: 3}, done);
			self.proxy.start(init);

			proxy2 = new self.Proxy(options2);
			proxy2.start(init);

			self.content = "HELLO WORLD!\n";
			self.server = false;
			self.server = http.createServer(function(request, response){
				response.writeHead(200, {
					'Content-Type': 'text/plain',
					'Content-Length': self.content.length
				});
				response.write(self.content);
				response.end();
			});
			self.server.listen(self.options.testServerPort, self.options.host, 511, function(){
				init();
			});
		});

		after(function(done){
			var cleanup = self.proxy.whenAllDone.bind(self, {todo: 3}, done);

			proxy2.stop(cleanup);
			self.proxy.stop(cleanup);
			self.server.close(cleanup);
		});

		it('should get correct answer from server', function(done){
			this.timeout(2000);

			options2.proxy = {
				hostname: self.options.host,
				port: self.options.port
			};

			self.target = {
				hostname: options2.host,
				port: options2.httpPort,
				path: 'http://' + self.options.host + ':' + self.options.testServerPort + '/hello',
				headers: {
					'Host': self.options.host+':'+self.options.testServerPort,
					'Content-Type': 'text/plain; charset=utf8'
				},
				agent: false
			};
			var request = http.request(self.target, function(response){
				var downloaded = '';
				response.on('data', function(data){
					downloaded += data;
				});
				response.on('end', function(){
					assert.strictEqual(downloaded, self.content);
					done();
				});
			}).end();
		});
	});

	describe('HTTPS through another proxy', function(){
		var proxy2;
		var options2 = {
			port: 8005,
			host: '127.0.0.1'
		};

		before(function(done){
			var init = self.proxy.whenAllDone.bind(self, {todo: 3}, done);
			self.proxy.start(init);

			proxy2 = new self.Proxy(options2);
			proxy2.start(init);

			self.content = "HELLO WORLD!\n";
			self.server = false;
			self.server = https.createServer(self.options, function(request, response){
				response.writeHead(200, {
					'Content-Type': 'text/plain',
					'Content-Length': self.content.length
				});
				response.write(self.content);
				response.end();
			});
			self.server.listen(self.options.testServerPort, self.options.host, 511, init);
		});

		after(function(done){
			var cleanup = self.proxy.whenAllDone.bind(self, {todo: 3}, done);

			proxy2.stop(cleanup);
			self.server.close(cleanup);
			self.proxy.stop(cleanup);
		});

		it('should get correct answer from server', function(done){
			this.timeout(2000);

			options2.proxy = {
				hostname: self.options.host,
				port: self.options.httpPort
			};

			// Based on: https://github.com/joyent/node/issues/2474#issuecomment-3481078
			var tunnel = http.request({ // establishing a tunnel
				host: options2.host,
				port: options2.httpPort,
				method: 'CONNECT',
				agent: false,
				path: self.options.host+':'+self.options.testServerPort,
			}).on('connect', function(res, socket, head) {
				self.target = {
					hostname: self.options.host,
					socket: socket,
					path: '/hello',
					headers: {
						'Host': self.options.host+':'+self.options.testServerPort,
						'Content-Type': 'text/plain; charset=utf8'
					},
					agent: false
				};
				https.request(self.target, function(response){
					var downloaded = '';
					response.on('data', function(data){
						downloaded += data;
					});
					response.on('end', function(){
						assert.strictEqual(downloaded, self.content);
						done();
					});
				}).end();
			}).end();
		});
	});

	describe('Certificates', function(){
		before(function(done){
			self.options.useSNI = true;
			// changing SNI option requires rebuilding server :(
			self.proxy = new self.Proxy(self.options);

			var init = self.proxy.whenAllDone.bind(self, {todo: 2}, done);
			self.proxy.start(init);

			self.content = "HELLO WORLD!\n";
			self.server = false;
			self.server = https.createServer(self.options, function(request, response){
				response.writeHead(200, {
					'Content-Type': 'text/plain',
					'Content-Length': self.content.length
				});
				response.write(self.content);
				response.end();
			});
			self.server.listen(self.options.testServerPort, self.options.host, 511, init);
		});

		after(function(done){
			var cleanup = self.proxy.whenAllDone.bind(self, {todo: 2}, done);

			self.server.close(cleanup);
			self.proxy.stop(cleanup);

			self.options.useSNI = false;
		});

		it('should get correct certificate from HTTPS server', function(done){
			this.timeout(3000);

			// We are connecting twice, because current version of node does not have asynchronous SNICallback.
			// TODO: simplify this to a single connection, without setTimout, when node v0.12 shows up.
			var ssocket = tls.connect(self.options.httpsPort, self.options.host, {servername: 'example.com'}, function(){
				ssocket.end();
			});
			ssocket.on('data', function(data){});
			ssocket.on('end', function(){
				setTimeout(function(){
					var ssocket = tls.connect(self.options.httpsPort, self.options.host, {servername: 'example.com'}, function(){
						ssocket.end();

						var cert = ssocket.getPeerCertificate();
						assert.strictEqual(cert.subject.O, 'hyperProxy target');
						assert.strictEqual(cert.subject.CN, 'example.com');

						done();
					});
				}, 1000); // give it time to create certificates
			});
		});

		it('should get correct certificate from HTTPS-over-HTTP proxy', function(done){
			this.timeout(2000);

			// Based on: https://github.com/joyent/node/issues/2474#issuecomment-3481078
			var tunnel = http.request({ // establishing a tunnel
				host: self.options.host,
				port: self.options.httpPort,
				headers: {
					'Host': 'example.com'
				},
				method: 'CONNECT',
				agent: false,
				path: self.options.host+':'+self.options.testServerPort
			}).on('connect', function(res, socket, head) {
				var ssocket = tls.connect(0, {socket: socket, servername: 'example.com'}, function(){
					ssocket.write('GET / HTTP/1.1\r\n' +
						'Host: '+self.options.host+':'+self.options.testServerPort+'\r\n' +
						'Connection: close\r\n' +
						'\r\n');
					var cert = ssocket.getPeerCertificate();
					assert.strictEqual(cert.subject.O, 'hyperProxy target');
					assert.strictEqual(cert.subject.CN, 'example.com');
				});
				ssocket.on('data', function(data){});
				ssocket.on('end', done);
			}).end();
		});

		it('should get correct certificate from HTTPS proxy', function(done){
			this.timeout(2000);

			https.request({hostname: self.options.host, port: self.options.httpsPort, headers: {host: 'example.com'}, path: 'https://'+self.options.host+':'+self.options.testServerPort+'/hello'}, function(res){
				res.on('data', function(data){});
				res.on('end', function(){
					var cert = res.connection.getPeerCertificate();
					assert.strictEqual(cert.subject.O, 'hyperProxy target');
					assert.strictEqual(cert.subject.CN, 'example.com');
					done();
				});

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


<commit_before>var fs = require('fs');
var path = require('path');
var mkdirp = require('mkdirp');
var croongaServer = require(__dirname + '/../lib/server');
var http = require('http');
var Deferred = require('jsdeferred').Deferred;
var nroonga = require('nroonga');
var Database = require(__dirname + '/../lib/database').Database;

var temporaryDirectory = exports.temporaryDirectory = path.join(__dirname, 'tmp');

var testHost = 'localhost';
var testPort = 3333;
exports.testHost = testHost;
exports.testPort = testPort;

function setupServer(database) {
  var server = croongaServer.createServer({database: database});
  server.listen(testPort);
  return server;
}
exports.setupServer = setupServer;

function get(path) {
  var deferred = new Deferred();

  var options = {
        host: testHost,
        port: testPort,
        path: path
      };
  http.get(options, function(response) {
    var body = '';
    response.on('data', function(data) {
      body += data;
    });
    response.on('end', function() {
      deferred.call({
        statusCode: response.statusCode,
        body: body
      });
    });
  }).on('error', function(error) {
    deferred.fail(error);
  });

  return deferred;
}
exports.get = get;

function post(path, body, headers) {
  var deferred = new Deferred();

  var options = {
        host: testHost,
        port: testPort,
        path: path,
        method: 'POST',
        headers: {}
      };

  if (headers) {
    for (var header in headers) {
      if (headers.hasOwnProperty(header))
        options.headers[header] = headers[header];
    }
  }

  Deferred.next(function() {
    var request = http.request(options, function(response) {
          var body = '';
          response.on('data', function(data) {
            body += data;
          });
          response.on('end', function() {
            deferred.call({
              statusCode: response.statusCode,
              body: body
            });
          });
        });
    request.on('error', function(error) {
      deferred.fail(error);
    });

    if (body) request.write(body);
    request.end();
  });

  return deferred;
}
exports.post = post;

var databaseCount = 0;

exports.createTemporaryDatabase = function() {
  var databaseName = 'database-' + ++databaseCount;
  var databaseDirectory = path.join(temporaryDirectory, databaseName);
  var databasePath = path.join(databaseDirectory, 'database');
  rmRSync(databaseDirectory);
  mkdirp.sync(databaseDirectory);
  return {
    path: databasePath,
    get: function() {
      return this._database ||
             (this._database = new nroonga.Database(databasePath));
    },
    clear: function() {
      var database = this._database;
      var tables = database.commandSync('table_list');
      Database.formatResults(tables).forEach(function(table) {
        database.commandSync('table_remove', { name: table.name });
      });
    },
    teardown: function() {
      rmRSync(databaseDirectory);
      this._database = undefined;
    }
  };
};

exports.loadDumpFile = function(database, path) {
  var dump = fs.readFileSync(path, 'UTF-8');
  dump.split('\n').forEach(function(line) {
    database.commandSyncString(line);
  });
}

function isDirectory(path) {
  return fs.statSync(path).isDirectory();
}
exports.isDirectory = isDirectory;

function rmRSync(directoryPath) {
  if (!path.existsSync(directoryPath)) return;

  var files = fs.readdirSync(directoryPath);
  var file, filePath;
  for (var i = 0, maxi = files.length; i < maxi; i++) {
    file = files[i];
    filePath = path.join(directoryPath, file);
    if (isDirectory(filePath))
      rmRSync(filePath);
    else
      fs.unlinkSync(filePath);
  }
  fs.rmdirSync(directoryPath);
}
exports.rmRSync = rmRSync;
<commit_msg>Rename croonga to gcs<commit_after>var fs = require('fs');
var path = require('path');
var mkdirp = require('mkdirp');
var gcsServer = require(__dirname + '/../lib/server');
var http = require('http');
var Deferred = require('jsdeferred').Deferred;
var nroonga = require('nroonga');
var Database = require(__dirname + '/../lib/database').Database;

var temporaryDirectory = exports.temporaryDirectory = path.join(__dirname, 'tmp');

var testHost = 'localhost';
var testPort = 3333;
exports.testHost = testHost;
exports.testPort = testPort;

function setupServer(database) {
  var server = gcsServer.createServer({database: database});
  server.listen(testPort);
  return server;
}
exports.setupServer = setupServer;

function get(path) {
  var deferred = new Deferred();

  var options = {
        host: testHost,
        port: testPort,
        path: path
      };
  http.get(options, function(response) {
    var body = '';
    response.on('data', function(data) {
      body += data;
    });
    response.on('end', function() {
      deferred.call({
        statusCode: response.statusCode,
        body: body
      });
    });
  }).on('error', function(error) {
    deferred.fail(error);
  });

  return deferred;
}
exports.get = get;

function post(path, body, headers) {
  var deferred = new Deferred();

  var options = {
        host: testHost,
        port: testPort,
        path: path,
        method: 'POST',
        headers: {}
      };

  if (headers) {
    for (var header in headers) {
      if (headers.hasOwnProperty(header))
        options.headers[header] = headers[header];
    }
  }

  Deferred.next(function() {
    var request = http.request(options, function(response) {
          var body = '';
          response.on('data', function(data) {
            body += data;
          });
          response.on('end', function() {
            deferred.call({
              statusCode: response.statusCode,
              body: body
            });
          });
        });
    request.on('error', function(error) {
      deferred.fail(error);
    });

    if (body) request.write(body);
    request.end();
  });

  return deferred;
}
exports.post = post;

var databaseCount = 0;

exports.createTemporaryDatabase = function() {
  var databaseName = 'database-' + ++databaseCount;
  var databaseDirectory = path.join(temporaryDirectory, databaseName);
  var databasePath = path.join(databaseDirectory, 'database');
  rmRSync(databaseDirectory);
  mkdirp.sync(databaseDirectory);
  return {
    path: databasePath,
    get: function() {
      return this._database ||
             (this._database = new nroonga.Database(databasePath));
    },
    clear: function() {
      var database = this._database;
      var tables = database.commandSync('table_list');
      Database.formatResults(tables).forEach(function(table) {
        database.commandSync('table_remove', { name: table.name });
      });
    },
    teardown: function() {
      rmRSync(databaseDirectory);
      this._database = undefined;
    }
  };
};

exports.loadDumpFile = function(database, path) {
  var dump = fs.readFileSync(path, 'UTF-8');
  dump.split('\n').forEach(function(line) {
    database.commandSyncString(line);
  });
}

function isDirectory(path) {
  return fs.statSync(path).isDirectory();
}
exports.isDirectory = isDirectory;

function rmRSync(directoryPath) {
  if (!path.existsSync(directoryPath)) return;

  var files = fs.readdirSync(directoryPath);
  var file, filePath;
  for (var i = 0, maxi = files.length; i < maxi; i++) {
    file = files[i];
    filePath = path.join(directoryPath, file);
    if (isDirectory(filePath))
      rmRSync(filePath);
    else
      fs.unlinkSync(filePath);
  }
  fs.rmdirSync(directoryPath);
}
exports.rmRSync = rmRSync;
<|endoftext|>


<commit_before>'use strict'

import test from 'tape'
import Immutable from 'immutable'
import {JSONLDValue} from '../ImmutableJSONLD'

test('test JSONLDValue construction via factory method', t => {
  const value = JSONLDValue()
  t.plan(9)
  t.ok(value instanceof JSONLDValue,
    'is a JSONLDValue')
  t.ok(value instanceof Immutable.Map,
    'is an Immutable.Map')
  t.ok(value instanceof Immutable.Collection.Keyed,
    'is an Immutable.Collection.Keyed')
  t.ok(value instanceof Immutable.Collection,
    'is an Immutable.Collection')
  t.ok(value instanceof Immutable.Iterable,
    'is an Immutable.Iterable')
  t.ok(JSONLDValue.isJSONLDValue(value), 'isJSONLDValue()')
  t.ok(Immutable.Map.isMap(value), 'isMap()')
  t.ok(Immutable.Iterable.isIterable(value), 'isIterable()')
  t.ok(Immutable.Iterable.isKeyed(value), 'isKeyed()')
})

test('test JSONLDValue @value is always set', t => {
  const empty = JSONLDValue()
      , string = JSONLDValue('hello')
      , number = JSONLDValue(69)
      , truth = JSONLDValue(true)
      , falsity = JSONLDValue(false)
      , nullity = JSONLDValue(null)
  t.plan(9)
  t.equal(empty.get('@value'), '')
  t.equal(string.get('@value'), 'hello')
  t.equal(number.get('@value'), 69)
  t.equal(truth.get('@value'), true)
  t.equal(falsity.get('@value'), false)
  t.equal(nullity, empty)
  try {JSONLDValue({})} catch (e) {
    t.ok(e, 'obj without @value throws exception')
  }
  try {JSONLDValue([])} catch (e) {
    t.ok(e, 'array throws exception')
  }
  try {JSONLDValue(x => x)} catch (e) {
    t.ok(e, 'function throws exception')
  }
})

test('test JSONLDValue.toString()', t => {
  const empty = JSONLDValue()
      , value = JSONLDValue({"@value": "Moby Dick"})
  t.plan(2)
  t.equals(empty.toString(), 'JSONLDValue { "@value": "" }',
    'works for empty value')
  t.equals(value.toString(), 'JSONLDValue { "@value": "Moby Dick" }',
    'works for non-empty value')
})

test('test JSONLDValue.language', t => {
  const val1 = JSONLDValue({'@value': 'Moby Dick'})
      , val2 = JSONLDValue({'@value': 'Moby Dick', '@language': 'en'})
  t.plan(6)
  t.equals(val1.language, undefined)
  t.equals(val2.language, 'en')
  t.equals(val1.set('@language', 'ja').language, 'ja')
  t.equals(val2.set('@language', 'ja').language, 'ja')
  try { val1.language = 'en'} catch (e) {
    t.ok(e instanceof TypeError, 'set throws TypeError')
    t.ok(/^Cannot set property language/.test(e.message), 'with message')
  }
})

test('test JSONLDValue.type', t => {
  const val1 = JSONLDValue({'@value': 'Moby Dick'})
      , val2 = JSONLDValue(
          { '@value': 'Moby Dick'
          , '@type': 'http://www.w3.org/2001/XMLSchema#string'})
  t.plan(6)
  t.equals(val1.type, undefined)
  t.equals(val2.type, 'http://www.w3.org/2001/XMLSchema#string')
  t.equals(val1.set('@type', 'http://schema.org/Text').type,
    'http://schema.org/Text')
  t.equals(val2.set('@type', 'http://schema.org/Text').type,
    'http://schema.org/Text')
  try { val1.type = 'http://schema.org/Text'} catch (e) {
    t.ok(e instanceof TypeError, 'set throws TypeError')
    t.ok(/^Cannot set property type/.test(e.message), 'with message')
  }
})

test('test JSONLDValue.value', t => {
  const val1 = JSONLDValue({'@value': 'Moby Dick'})
  t.plan(4)
  t.equals(val1.value, 'Moby Dick')
  t.equals(val1.set('@value', 'foo').value, 'foo')
  try { val1.value = ''} catch (e) {
    t.ok(e instanceof TypeError, 'set throws TypeError')
    t.ok(/^Cannot set property value/.test(e.message), 'with message')
  }
})
<commit_msg>Whitespace fix.<commit_after>'use strict'

import test from 'tape'
import Immutable from 'immutable'
import {JSONLDValue} from '../ImmutableJSONLD'

test('test JSONLDValue construction via factory method', t => {
  const value = JSONLDValue()
  t.plan(9)
  t.ok(value instanceof JSONLDValue,
    'is a JSONLDValue')
  t.ok(value instanceof Immutable.Map,
    'is an Immutable.Map')
  t.ok(value instanceof Immutable.Collection.Keyed,
    'is an Immutable.Collection.Keyed')
  t.ok(value instanceof Immutable.Collection,
    'is an Immutable.Collection')
  t.ok(value instanceof Immutable.Iterable,
    'is an Immutable.Iterable')
  t.ok(JSONLDValue.isJSONLDValue(value), 'isJSONLDValue()')
  t.ok(Immutable.Map.isMap(value), 'isMap()')
  t.ok(Immutable.Iterable.isIterable(value), 'isIterable()')
  t.ok(Immutable.Iterable.isKeyed(value), 'isKeyed()')
})

test('test JSONLDValue @value is always set', t => {
  const empty = JSONLDValue()
      , string = JSONLDValue('hello')
      , number = JSONLDValue(69)
      , truth = JSONLDValue(true)
      , falsity = JSONLDValue(false)
      , nullity = JSONLDValue(null)
  t.plan(9)
  t.equal(empty.get('@value'), '')
  t.equal(string.get('@value'), 'hello')
  t.equal(number.get('@value'), 69)
  t.equal(truth.get('@value'), true)
  t.equal(falsity.get('@value'), false)
  t.equal(nullity, empty)
  try {JSONLDValue({})} catch (e) {
    t.ok(e, 'obj without @value throws exception')
  }
  try {JSONLDValue([])} catch (e) {
    t.ok(e, 'array throws exception')
  }
  try {JSONLDValue(x => x)} catch (e) {
    t.ok(e, 'function throws exception')
  }
})

test('test JSONLDValue.toString()', t => {
  const empty = JSONLDValue()
      , value = JSONLDValue({"@value": "Moby Dick"})
  t.plan(2)
  t.equals(empty.toString(), 'JSONLDValue { "@value": "" }',
    'works for empty value')
  t.equals(value.toString(), 'JSONLDValue { "@value": "Moby Dick" }',
    'works for non-empty value')
})

test('test JSONLDValue.language', t => {
  const val1 = JSONLDValue({'@value': 'Moby Dick'})
      , val2 = JSONLDValue({'@value': 'Moby Dick', '@language': 'en'})
  t.plan(6)
  t.equals(val1.language, undefined)
  t.equals(val2.language, 'en')
  t.equals(val1.set('@language', 'ja').language, 'ja')
  t.equals(val2.set('@language', 'ja').language, 'ja')
  try {val1.language = 'en'} catch (e) {
    t.ok(e instanceof TypeError, 'set throws TypeError')
    t.ok(/^Cannot set property language/.test(e.message), 'with message')
  }
})

test('test JSONLDValue.type', t => {
  const val1 = JSONLDValue({'@value': 'Moby Dick'})
      , val2 = JSONLDValue(
          { '@value': 'Moby Dick'
          , '@type': 'http://www.w3.org/2001/XMLSchema#string'})
  t.plan(6)
  t.equals(val1.type, undefined)
  t.equals(val2.type, 'http://www.w3.org/2001/XMLSchema#string')
  t.equals(val1.set('@type', 'http://schema.org/Text').type,
    'http://schema.org/Text')
  t.equals(val2.set('@type', 'http://schema.org/Text').type,
    'http://schema.org/Text')
  try {val1.type = 'http://schema.org/Text'} catch (e) {
    t.ok(e instanceof TypeError, 'set throws TypeError')
    t.ok(/^Cannot set property type/.test(e.message), 'with message')
  }
})

test('test JSONLDValue.value', t => {
  const val1 = JSONLDValue({'@value': 'Moby Dick'})
  t.plan(4)
  t.equals(val1.value, 'Moby Dick')
  t.equals(val1.set('@value', 'foo').value, 'foo')
  try {val1.value = ''} catch (e) {
    t.ok(e instanceof TypeError, 'set throws TypeError')
    t.ok(/^Cannot set property value/.test(e.message), 'with message')
  }
})
<|endoftext|>


<commit_before>import EventEmitter from 'events';

import algoliasearch from 'algoliasearch/lite';
import autocomplete from 'autocomplete.js';

import './navigatorLanguage.js';

import createAutocompleteDataset from './createAutocompleteDataset.js';

import clearIcon from './icons/clear.svg';
import pinIcon from './icons/address.svg';

import css from './places.scss';
import insertCss from 'insert-css';
insertCss(css, {prepend: true});

const errors = {
  multiContainers:
`Algolia Places: 'container' must point to a single <input> element.
Example: instantiate the library twice if you want to bind two <inputs>.

See https://community.algolia.com/places/documentation.html#api-options-container`,
  badContainer:
`Algolia Places: 'container' must point to an <input> element.

See https://community.algolia.com/places/documentation.html#api-options-container`
};

export default function places(options) {
  const {
    container,
    style,
    autocompleteOptions: userAutocompleteOptions = {}
  } = options;

  // multiple DOM elements targeted
  if (container instanceof NodeList) {
    if (container.length > 1) {
      throw new Error(errors.multiContainers);
    }

    // if single node NodeList received, resolve to the first one
    return places({container: container[0], ...options});
  }

  // container sent as a string, resolve it for multiple DOM elements issue
  if (typeof container === 'string') {
    const resolvedContainer = document.querySelectorAll(container);
    return places({container: resolvedContainer, ...options});
  }

  // if not an <input>, error
  if (!(container instanceof HTMLInputElement)) {
    throw new Error(errors.badContainer);
  }

  const placesInstance = new EventEmitter();
  const prefix = 'ap' + (style === false ? '-nostyle' : '');

  const autocompleteOptions = {
    autoselect: true,
    hint: false,
    cssClasses: {
      root: 'algolia-places' + (style === false ? '-nostyle' : ''),
      prefix
    },
    debug: process.env.NODE_ENV === 'development' ? true : false,
    ...userAutocompleteOptions
  };

  const autocompleteDataset = createAutocompleteDataset({
    ...options,
    algoliasearch,
    onHits: ({hits, rawAnswer, query}) => placesInstance.emit('suggestions', {
      rawAnswer,
      query,
      suggestions: hits
    }),
    onError: e => placesInstance.emit('error', e),
    onRateLimitReached: () => {
      const listeners = placesInstance.listenerCount('limit');
      if (listeners === 0) {
        console.log(
`Algolia Places: Current rate limit reached.

Sign up for a free 100,000 queries/month account at
https://www.algolia.com/users/sign_up/places.

Or upgrade your 100,000 queries/month plan by contacting us at
https://community.algolia.com/places/contact.html.`
);
        return;
      }

      placesInstance.emit('limit');
    }
  });
  const autocompleteInstance = autocomplete(container, autocompleteOptions, autocompleteDataset);
  const autocompleteContainer = container.parentNode;

  const autocompleteChangeEvents = ['selected', 'autocompleted'];

  autocompleteChangeEvents.forEach(eventName => {
    autocompleteInstance.on(`autocomplete:${eventName}`, (_, suggestion) => {
      placesInstance.emit('change', {
        rawAnswer: suggestion.rawAnswer,
        query: suggestion.query,
        suggestion,
        suggestionIndex: suggestion.hitIndex
      });
    });
  });
  autocompleteInstance.on('autocomplete:cursorchanged', (_, suggestion) => {
    placesInstance.emit('cursorchanged', {
      rawAnswer: suggestion.rawAnswer,
      query: suggestion.query,
      suggestion,
      suggestionIndex: suggestion.hitIndex
    });
  });

  const clear = document.createElement('button');
  clear.setAttribute('type', 'button');
  clear.classList.add(`${prefix}-input-icon`);
  clear.classList.add(`${prefix}-icon-clear`);
  clear.innerHTML = clearIcon;
  autocompleteContainer.appendChild(clear);
  clear.style.display = 'none';

  const pin = document.createElement('button');
  pin.setAttribute('type', 'button');
  pin.classList.add(`${prefix}-input-icon`);
  pin.classList.add(`${prefix}-input-icon-pin`);
  pin.innerHTML = pinIcon;
  autocompleteContainer.appendChild(pin);

  pin.addEventListener('click', () => autocompleteInstance.focus());
  clear.addEventListener('click', () => {
    autocompleteInstance.autocomplete.setVal('');
    autocompleteInstance.focus();
    clear.style.display = 'none';
    pin.style.display = '';
    placesInstance.emit('clear');
  });

  let previousQuery = '';

  const inputListener = () => {
    const query = autocompleteInstance.val();
    if (query === '') {
      pin.style.display = '';
      clear.style.display = 'none';
      if (previousQuery !== query) {
        placesInstance.emit('clear');
      }
    } else {
      clear.style.display = '';
      pin.style.display = 'none';
    }
    previousQuery = query;
  };

  autocompleteContainer.querySelector(`.${prefix}-input`).addEventListener('input', inputListener);

  placesInstance.destroy = () => {
    // this is the only event we need to manually remove because the input will still be here
    autocompleteContainer.querySelector(`.${prefix}-input`).removeEventListener('input', inputListener);
    autocompleteInstance.autocomplete.destroy();
  };

  return placesInstance;
}
<commit_msg>chore(lint): fix lint<commit_after>import EventEmitter from 'events';

import algoliasearch from 'algoliasearch/lite';
import autocomplete from 'autocomplete.js';

import './navigatorLanguage.js';

import createAutocompleteDataset from './createAutocompleteDataset.js';

import clearIcon from './icons/clear.svg';
import pinIcon from './icons/address.svg';

import css from './places.scss';
import insertCss from 'insert-css';
insertCss(css, {prepend: true});

const errors = {
  multiContainers:
`Algolia Places: 'container' must point to a single <input> element.
Example: instantiate the library twice if you want to bind two <inputs>.

See https://community.algolia.com/places/documentation.html#api-options-container`,
  badContainer:
`Algolia Places: 'container' must point to an <input> element.

See https://community.algolia.com/places/documentation.html#api-options-container`
};

export default function places(options) {
  const {
    container,
    style,
    autocompleteOptions: userAutocompleteOptions = {}
  } = options;

  // multiple DOM elements targeted
  if (container instanceof NodeList) {
    if (container.length > 1) {
      throw new Error(errors.multiContainers);
    }

    // if single node NodeList received, resolve to the first one
    return places({container: container[0], ...options});
  }

  // container sent as a string, resolve it for multiple DOM elements issue
  if (typeof container === 'string') {
    const resolvedContainer = document.querySelectorAll(container);
    return places({container: resolvedContainer, ...options});
  }

  // if not an <input>, error
  if (!(container instanceof HTMLInputElement)) {
    throw new Error(errors.badContainer);
  }

  const placesInstance = new EventEmitter();
  const prefix = 'ap' + (style === false ? '-nostyle' : '');

  const autocompleteOptions = {
    autoselect: true,
    hint: false,
    cssClasses: {
      root: 'algolia-places' + (style === false ? '-nostyle' : ''),
      prefix
    },
    debug: process.env.NODE_ENV === 'development' ? true : false,
    ...userAutocompleteOptions
  };

  const autocompleteDataset = createAutocompleteDataset({
    ...options,
    algoliasearch,
    onHits: ({hits, rawAnswer, query}) => placesInstance.emit('suggestions', {
      rawAnswer,
      query,
      suggestions: hits
    }),
    onError: e => placesInstance.emit('error', e),
    onRateLimitReached: () => {
      const listeners = placesInstance.listenerCount('limit');
      if (listeners === 0) {
        console.log( // eslint-disable-line
`Algolia Places: Current rate limit reached.

Sign up for a free 100,000 queries/month account at
https://www.algolia.com/users/sign_up/places.

Or upgrade your 100,000 queries/month plan by contacting us at
https://community.algolia.com/places/contact.html.`
);
        return;
      }

      placesInstance.emit('limit');
    }
  });
  const autocompleteInstance = autocomplete(container, autocompleteOptions, autocompleteDataset);
  const autocompleteContainer = container.parentNode;

  const autocompleteChangeEvents = ['selected', 'autocompleted'];

  autocompleteChangeEvents.forEach(eventName => {
    autocompleteInstance.on(`autocomplete:${eventName}`, (_, suggestion) => {
      placesInstance.emit('change', {
        rawAnswer: suggestion.rawAnswer,
        query: suggestion.query,
        suggestion,
        suggestionIndex: suggestion.hitIndex
      });
    });
  });
  autocompleteInstance.on('autocomplete:cursorchanged', (_, suggestion) => {
    placesInstance.emit('cursorchanged', {
      rawAnswer: suggestion.rawAnswer,
      query: suggestion.query,
      suggestion,
      suggestionIndex: suggestion.hitIndex
    });
  });

  const clear = document.createElement('button');
  clear.setAttribute('type', 'button');
  clear.classList.add(`${prefix}-input-icon`);
  clear.classList.add(`${prefix}-icon-clear`);
  clear.innerHTML = clearIcon;
  autocompleteContainer.appendChild(clear);
  clear.style.display = 'none';

  const pin = document.createElement('button');
  pin.setAttribute('type', 'button');
  pin.classList.add(`${prefix}-input-icon`);
  pin.classList.add(`${prefix}-input-icon-pin`);
  pin.innerHTML = pinIcon;
  autocompleteContainer.appendChild(pin);

  pin.addEventListener('click', () => autocompleteInstance.focus());
  clear.addEventListener('click', () => {
    autocompleteInstance.autocomplete.setVal('');
    autocompleteInstance.focus();
    clear.style.display = 'none';
    pin.style.display = '';
    placesInstance.emit('clear');
  });

  let previousQuery = '';

  const inputListener = () => {
    const query = autocompleteInstance.val();
    if (query === '') {
      pin.style.display = '';
      clear.style.display = 'none';
      if (previousQuery !== query) {
        placesInstance.emit('clear');
      }
    } else {
      clear.style.display = '';
      pin.style.display = 'none';
    }
    previousQuery = query;
  };

  autocompleteContainer.querySelector(`.${prefix}-input`).addEventListener('input', inputListener);

  placesInstance.destroy = () => {
    // this is the only event we need to manually remove because the input will still be here
    autocompleteContainer.querySelector(`.${prefix}-input`).removeEventListener('input', inputListener);
    autocompleteInstance.autocomplete.destroy();
  };

  return placesInstance;
}
<|endoftext|>


<commit_before>/*global require, module*/
/*jslint vars:true*/
var JTLT;
var testBasic;
(function () {'use strict';

var json = {
    "store": {
        "book": { "category": "reference",
            "author": "Nigel Rees",
            "title": "Sayings of the Century",
            "price": [8.95, 8.94, 8.93]
        },
        "books": [
            { "category": "reference",
                "author": "Nigel Rees",
                "title": "Sayings of the Century",
                "price": [8.95, 8.94, 8.93]
            }
        ]
    }
};

var test, expected;

function runTest (templates, replace) {
    var config = {
        ajaxData: 'data/jsonpath-sample.json',
        outputType: 'string', // string is default
        templates: [
            { // We could instead try a root template which applied on the author path
                name: 'scalars',
                path: '$..*@scalar()',
                template: function () {}
            }
        ],
        success: function (result) {
            test.deepEqual(expected, result);
            test.done();
        }
    };
    if (replace) {
        config.templates[0] = templates.shift();
    }
    templates.forEach(function (template) {
        config.templates.push(template);
    });
    try {
        JTLT(config);
    }
    catch (e) {
        alert(e);
    }
}

testBasic = {
    'should support the simple array-based template format': function (t) {
        // test.expect(1);
        test = t;

        expected = 'Nigel ReesEvelyn WaughHerman MelvilleJ. R. R. Tolkien';
        runTest([
            ['$.store.book[*].author', function (author) {
                return '' + author + '';
            }]
        ]);
        // Could just do runTest(['$.store.book[*].author', author => '' + author + '']); but may want to use `this`
    },
    'should be able to use valueOf to get current context': function (t) {
        test = t;

        expected = 'Nigel ReesEvelyn WaughHerman MelvilleJ. R. R. Tolkien';
        runTest([{
            name: 'author', // For use with calling templates
            path: '$.store.book[*].author',
            template: function () {
                this.string('');
                this.valueOf({select: '.'});
                this.string('');
            }
        }]);
    },
    'should be able to utilize argument to template': function (t) {
        test = t;

        expected = 'Nigel ReesEvelyn WaughHerman MelvilleJ. R. R. Tolkien';
        runTest([{
            name: 'author', // For use with calling templates
            path: '$.store.book[*].author',
            template: function (author) {
                this.string('' + author + '');
            }
        }]);
    },
    'should be able to provide return value from template': function (t) {
        test = t;

        expected = 'Nigel ReesEvelyn WaughHerman MelvilleJ. R. R. Tolkien';
        runTest([{
            name: 'author', // For use with calling templates
            path: '$.store.book[*].author',
            template: function (author) {
                return '' + author + '';
            }
        }]);
    },
    'should be able to use a root template calling applyTemplates with a select path': function (t) {
        test = t;
        expected = 'Nigel ReesEvelyn WaughHerman MelvilleJ. R. R. Tolkien';
        runTest([
            ['$', function (value, cfg) {
              this.applyTemplates('$.store.book[*].author', cfg.mode);
            }], ['$.store.book[*].author', function (author) {
              return '' + author + '';
            }]
        ], true);
    },
    'should support multiple child templates': function (t) {
        test = t;

        expected = 'Nigel Rees8.95Evelyn Waugh12.99Herman Melville8.99J. R. R. Tolkien22.99';
        runTest([{
            name: 'author', // For use with calling templates
            path: '$.store.book[*].author',
            template: function (author) {
                return '' + author + '';
            }
        }, {
            name: 'price', // For use with calling templates
            path: '$.store.book[*].price',
            template: function (price) {
                return '' + price + '';
            }
        }]);
    },
    'should support nested templates': function (t) {
        test = t;

        expected = 'Nigel Rees8.95Evelyn Waugh12.99Herman Melville8.99J. R. R. Tolkien22.99';
        runTest([{
            name: 'book', // For use with calling templates
            path: '$.store.book[*]',
            template: function (book) {
                this.string('');
                this.applyTemplates();
                this.string('');
            }
        }, {
            name: 'author', // For use with calling templates
            path: '$.store.book[*].author',
            template: function (author) {
                return '' + author + '';
            }
        }, {
            name: 'price', // For use with calling templates
            path: '$.store.book[*].price',
            template: function (price) {
                return '' + price + '';
            }
        }]);
    }
};

if (typeof exports !== 'undefined') {
    JTLT = require('../src/index');
    module.exports = testBasic;
}

}());
<commit_msg>rmv unused json<commit_after>/*global require, module*/
/*jslint vars:true*/
var JTLT;
var testBasic;
(function () {'use strict';

var test, expected;

function runTest (templates, replace) {
    var config = {
        ajaxData: 'data/jsonpath-sample.json',
        outputType: 'string', // string is default
        templates: [
            { // We could instead try a root template which applied on the author path
                name: 'scalars',
                path: '$..*@scalar()',
                template: function () {}
            }
        ],
        success: function (result) {
            test.deepEqual(expected, result);
            test.done();
        }
    };
    if (replace) {
        config.templates[0] = templates.shift();
    }
    templates.forEach(function (template) {
        config.templates.push(template);
    });
    try {
        JTLT(config);
    }
    catch (e) {
        alert(e);
    }
}

testBasic = {
    'should support the simple array-based template format': function (t) {
        // test.expect(1);
        test = t;

        expected = 'Nigel ReesEvelyn WaughHerman MelvilleJ. R. R. Tolkien';
        runTest([
            ['$.store.book[*].author', function (author) {
                return '' + author + '';
            }]
        ]);
        // Could just do runTest(['$.store.book[*].author', author => '' + author + '']); but may want to use `this`
    },
    'should be able to use valueOf to get current context': function (t) {
        test = t;

        expected = 'Nigel ReesEvelyn WaughHerman MelvilleJ. R. R. Tolkien';
        runTest([{
            name: 'author', // For use with calling templates
            path: '$.store.book[*].author',
            template: function () {
                this.string('');
                this.valueOf({select: '.'});
                this.string('');
            }
        }]);
    },
    'should be able to utilize argument to template': function (t) {
        test = t;

        expected = 'Nigel ReesEvelyn WaughHerman MelvilleJ. R. R. Tolkien';
        runTest([{
            name: 'author', // For use with calling templates
            path: '$.store.book[*].author',
            template: function (author) {
                this.string('' + author + '');
            }
        }]);
    },
    'should be able to provide return value from template': function (t) {
        test = t;

        expected = 'Nigel ReesEvelyn WaughHerman MelvilleJ. R. R. Tolkien';
        runTest([{
            name: 'author', // For use with calling templates
            path: '$.store.book[*].author',
            template: function (author) {
                return '' + author + '';
            }
        }]);
    },
    'should be able to use a root template calling applyTemplates with a select path': function (t) {
        test = t;
        expected = 'Nigel ReesEvelyn WaughHerman MelvilleJ. R. R. Tolkien';
        runTest([
            ['$', function (value, cfg) {
              this.applyTemplates('$.store.book[*].author', cfg.mode);
            }], ['$.store.book[*].author', function (author) {
              return '' + author + '';
            }]
        ], true);
    },
    'should support multiple child templates': function (t) {
        test = t;

        expected = 'Nigel Rees8.95Evelyn Waugh12.99Herman Melville8.99J. R. R. Tolkien22.99';
        runTest([{
            name: 'author', // For use with calling templates
            path: '$.store.book[*].author',
            template: function (author) {
                return '' + author + '';
            }
        }, {
            name: 'price', // For use with calling templates
            path: '$.store.book[*].price',
            template: function (price) {
                return '' + price + '';
            }
        }]);
    },
    'should support nested templates': function (t) {
        test = t;

        expected = 'Nigel Rees8.95Evelyn Waugh12.99Herman Melville8.99J. R. R. Tolkien22.99';
        runTest([{
            name: 'book', // For use with calling templates
            path: '$.store.book[*]',
            template: function (book) {
                this.string('');
                this.applyTemplates();
                this.string('');
            }
        }, {
            name: 'author', // For use with calling templates
            path: '$.store.book[*].author',
            template: function (author) {
                return '' + author + '';
            }
        }, {
            name: 'price', // For use with calling templates
            path: '$.store.book[*].price',
            template: function (price) {
                return '' + price + '';
            }
        }]);
    }
};

if (typeof exports !== 'undefined') {
    JTLT = require('../src/index');
    module.exports = testBasic;
}

}());
<|endoftext|>


<commit_before>import observable from "riot-observable"
import { MIDIController } from "./midi-constants"

const INTERVAL = 1 / 15 * 1000  // low fps

// helper

Array.prototype.deleteArray = function(arr) {
  for (var i = this.length - 1; i >= 0; i--) {
    if (arr.indexOf(this[i]) >= 0) {
      this.splice(i, 1)
    }
  }
}

Array.range = function(a, b) {
  const arr = []
  for (var i = a; i <= b; i++) {
    arr.push(i)
  }
  return arr
}

Array.prototype.flatten = function() {
  return Array.prototype.concat.apply([], this)
}

// timebase: 1/4拍子ごとのtick数
function secToTick(sec, bpm, timebase) {
  return sec *  bpm / 60 * timebase
}

function tickToMillisec(tick, bpm, timebase) {
  return tick / (timebase / 60) / bpm * 1000
}

const EVENT_CODES = {
  "noteOff": 0x8,
  "noteOn": 0x9,
  "noteAftertouch": 0xa,
  "controller": 0xb,
  "programChange": 0xc,
  "channelAftertouch": 0xd,
  "pitchBend": 0xe
}

function firstByte(eventType, channel) {
  return (EVENT_CODES[eventType] << 4) + channel
}

function eventToMidiMessages(e) {
  function eventType(e) {
    return firstByte(e.subtype, e.channel)
  }
  function createMessage(e, data) {
    return [{
      event: e,
      tick: e.tick,
      msg: [eventType(e)].concat(data)
    }]
  }
  switch (e.type) {
    case "meta":
      break
    case "channel":
      switch (e.subtype) {
        case "note":
          return [
            {
              event: e,
              msg: [firstByte("noteOn", e.channel), e.noteNumber, e.velocity],
              tick: e.tick
            },
            {
              event: e,
              msg: [firstByte("noteOff", e.channel), e.noteNumber, 0x40],
              tick: e.tick + e.duration - 1 // prevent overlapping next note on
            }
          ]
        case "noteAftertouch":
          return createMessage(e, [e.noteNumber, e.amount])
        case "controller":
          return createMessage(e, [e.controllerType, e.value])
        case "programChange":
          return createMessage(e, [e.value])
        case "channelAftertouch":
          return createMessage(e, [e.amount])
        case "pitchBend":
          return createMessage(e, [e.value & 0x7f, e.value >> 7])
      }
      break
  }
  return [{
    event: e,
    tick: e.tick
  }]
}

export default class Player {
  constructor(timebase) {
    this._timebase = timebase
    this._playing = false
    this._currentTempo = 120
    this._currentTick = 0
    this._allEvents = []
    this._channelMutes = {}

    observable(this)

    navigator.requestMIDIAccess().then(midiAccess => {
      this._midiOutput = midiAccess.outputs.values().next().value
    }, null)
  }

  prepare(song) {
    this._allEvents = song.getTracks()
      .map(t => t.getEvents())
      .flatten()
      .map(eventToMidiMessages)
      .filter(e => e != null)
      .flatten()
  }

  _updateEvents() {
    this._events = this._allEvents.filter(e => e.tick >= this._currentTick)
  }

  // you must call prepare() before play(), playAt()
  play(tick) {
    if (tick) {
      this._currentTick = Math.max(0, tick)
      this.emitChangePosition()
    }
    this._updateEvents()
    this.resume()
  }

  seek(tick) {
    this._currentTick = Math.max(0, tick)
    this.emitChangePosition()
    this._updateEvents()
  }

  set position(tick) {
    this.seek(tick)
  }

  get position() {
    return this._currentTick
  }

  get isPlaying() {
    return this._playing
  }

  get timebase() {
    return this._timebase
  }

  get channelMutes() {
    return this._channelMutes
  }

  resume() {
    this._playing = true
    clearInterval(this._intervalID)
    this._intervalID = setInterval(this._onTimer.bind(this), INTERVAL)
  }

  stop() {
    clearInterval(this._intervalID)
    this._playing = false

    // all sound off
    for (const ch of Array.range(0, 0xf)) {
      this._midiOutput.send([0xb0 + ch, MIDIController.ALL_SOUNDS_OFF, 0], window.performance.now())
    }
  }

  reset() {
    const time = window.performance.now()
    for (const ch of Array.range(0, 0xf)) {
      // reset controllers
      this._midiOutput.send([firstByte("controller", ch), MIDIController.RESET_CONTROLLERS, 0x7f], time)

      // reset pitch bend
      this._midiOutput.send([firstByte("pitchBend", ch), 0x00, 0x40], time)
    }
    this.stop()
    this.position = 0
  }

  get currentTempo() {
    return this._currentTempo
  }

  muteChannel(channel, mute) {
    this._channelMutes[channel] = mute
    this.trigger("change-mute", channel)
  }

  isChannelMuted(channel) {
    return this._channelMutes[channel]
  }

  /**
   preview note
   duration in milliseconds
   */
  playNote(n) {
    const timestamp = window.performance.now()
    this._midiOutput.send([firstByte("noteOn", n.channel), n.noteNumber, n.velocity], timestamp)
    this._midiOutput.send([firstByte("noteOff", n.channel), n.noteNumber, 0], timestamp + n.duration)
  }

  _onTimer() {
    const deltaTick = Math.ceil(secToTick(INTERVAL / 1000, this._currentTempo, this._timebase))
    const endTick = this._currentTick + deltaTick
    const eventsToPlay = this._events.filter(e => e.tick <= endTick)
    this._events.deleteArray(eventsToPlay)

    const timestamp = window.performance.now()
    eventsToPlay.forEach(e => {
      if (e.msg != null) {
        if (e.event.channel >= 0 && this._channelMutes[e.event.channel]) {
          return
        }
        const waitTick = e.tick - this._currentTick
        this._midiOutput.send(e.msg, timestamp + tickToMillisec(waitTick, this._currentTempo, this._timebase))
      } else {
        // MIDI 以外のイベントを実行
        switch (e.event.subtype) {
          case "setTempo":
            this._currentTempo = 60000000 / e.event.microsecondsPerBeat
            this.trigger("change-tempo", this._currentTempo)
            break
          case "endOfTrack":
            this.stop()
            break
        }
      }
    })

    this._currentTick = endTick
    this.emitChangePosition()
  }

  emitChangePosition() {
    this.trigger("change-position", this._currentTick)
  }
}
<commit_msg>use lodash<commit_after>import _ from "lodash"
import observable from "riot-observable"
import { MIDIController } from "./midi-constants"

const INTERVAL = 1 / 15 * 1000  // low fps

// timebase: 1/4拍子ごとのtick数
function secToTick(sec, bpm, timebase) {
  return sec *  bpm / 60 * timebase
}

function tickToMillisec(tick, bpm, timebase) {
  return tick / (timebase / 60) / bpm * 1000
}

const EVENT_CODES = {
  "noteOff": 0x8,
  "noteOn": 0x9,
  "noteAftertouch": 0xa,
  "controller": 0xb,
  "programChange": 0xc,
  "channelAftertouch": 0xd,
  "pitchBend": 0xe
}

function firstByte(eventType, channel) {
  return (EVENT_CODES[eventType] << 4) + channel
}

function eventToMidiMessages(e) {
  function eventType(e) {
    return firstByte(e.subtype, e.channel)
  }
  function createMessage(e, data) {
    return [{
      event: e,
      tick: e.tick,
      msg: [eventType(e)].concat(data)
    }]
  }
  switch (e.type) {
    case "meta":
      break
    case "channel":
      switch (e.subtype) {
        case "note":
          return [
            {
              event: e,
              msg: [firstByte("noteOn", e.channel), e.noteNumber, e.velocity],
              tick: e.tick
            },
            {
              event: e,
              msg: [firstByte("noteOff", e.channel), e.noteNumber, 0x40],
              tick: e.tick + e.duration - 1 // prevent overlapping next note on
            }
          ]
        case "noteAftertouch":
          return createMessage(e, [e.noteNumber, e.amount])
        case "controller":
          return createMessage(e, [e.controllerType, e.value])
        case "programChange":
          return createMessage(e, [e.value])
        case "channelAftertouch":
          return createMessage(e, [e.amount])
        case "pitchBend":
          return createMessage(e, [e.value & 0x7f, e.value >> 7])
      }
      break
  }
  return [{
    event: e,
    tick: e.tick
  }]
}

export default class Player {
  constructor(timebase) {
    this._timebase = timebase
    this._playing = false
    this._currentTempo = 120
    this._currentTick = 0
    this._allEvents = []
    this._channelMutes = {}

    observable(this)

    navigator.requestMIDIAccess().then(midiAccess => {
      this._midiOutput = midiAccess.outputs.values().next().value
    }, null)
  }

  prepare(song) {
    this._allEvents = _(song.getTracks())
      .map(t => t.getEvents())
      .flatten()
      .map(eventToMidiMessages)
      .filter(e => e != null)
      .flatten()
  }

  _updateEvents() {
    this._events = this._allEvents.filter(e => e.tick >= this._currentTick)
  }

  // you must call prepare() before play(), playAt()
  play(tick) {
    if (tick) {
      this._currentTick = Math.max(0, tick)
      this.emitChangePosition()
    }
    this._updateEvents()
    this.resume()
  }

  seek(tick) {
    this._currentTick = Math.max(0, tick)
    this.emitChangePosition()
    this._updateEvents()
  }

  set position(tick) {
    this.seek(tick)
  }

  get position() {
    return this._currentTick
  }

  get isPlaying() {
    return this._playing
  }

  get timebase() {
    return this._timebase
  }

  get channelMutes() {
    return this._channelMutes
  }

  resume() {
    this._playing = true
    clearInterval(this._intervalID)
    this._intervalID = setInterval(this._onTimer.bind(this), INTERVAL)
  }

  stop() {
    clearInterval(this._intervalID)
    this._playing = false

    // all sound off
      this._midiOutput.send([0xb0 + ch, MIDIController.ALL_SOUNDS_OFF, 0], window.performance.now())
    for (const ch of _.range(0, 0xf)) {
    }
  }

  reset() {
    const time = window.performance.now()
    for (const ch of _.range(0, 0xf)) {
      // reset controllers
      this._midiOutput.send([firstByte("controller", ch), MIDIController.RESET_CONTROLLERS, 0x7f], time)

      // reset pitch bend
      this._midiOutput.send([firstByte("pitchBend", ch), 0x00, 0x40], time)
    }
    this.stop()
    this.position = 0
  }

  get currentTempo() {
    return this._currentTempo
  }

  muteChannel(channel, mute) {
    this._channelMutes[channel] = mute
    this.trigger("change-mute", channel)
  }

  isChannelMuted(channel) {
    return this._channelMutes[channel]
  }

  /**
   preview note
   duration in milliseconds
   */
  playNote(n) {
    const timestamp = window.performance.now()
    this._midiOutput.send([firstByte("noteOn", n.channel), n.noteNumber, n.velocity], timestamp)
    this._midiOutput.send([firstByte("noteOff", n.channel), n.noteNumber, 0], timestamp + n.duration)
  }

  _onTimer() {
    const deltaTick = Math.ceil(secToTick(INTERVAL / 1000, this._currentTempo, this._timebase))
    const endTick = this._currentTick + deltaTick
    const eventsToPlay = this._events.filter(e => e.tick <= endTick)
    _.pullAll(this._events, eventsToPlay)

    const timestamp = window.performance.now()
    eventsToPlay.forEach(e => {
      if (e.msg != null) {
        if (e.event.channel >= 0 && this._channelMutes[e.event.channel]) {
          return
        }
        const waitTick = e.tick - this._currentTick
        this._midiOutput.send(e.msg, timestamp + tickToMillisec(waitTick, this._currentTempo, this._timebase))
      } else {
        // MIDI 以外のイベントを実行
        switch (e.event.subtype) {
          case "setTempo":
            this._currentTempo = 60000000 / e.event.microsecondsPerBeat
            this.trigger("change-tempo", this._currentTempo)
            break
          case "endOfTrack":
            this.stop()
            break
        }
      }
    })

    this._currentTick = endTick
    this.emitChangePosition()
  }

  emitChangePosition() {
    this.trigger("change-position", this._currentTick)
  }
}
<|endoftext|>


<commit_before>var assert = require('assert');
var fs = require('fs');
var fse = require('fs-extra');
var path = require('path');
var temp = require('temp').track();
var ghPages = require('gh-pages');
var deploy = require('../lib/deploy');

describe('Deploy', function() {
  var oldWD = process.cwd();
  var origGHPublish = ghPages.publish;

  afterEach(function() {
    process.chdir(oldWD);
    ghPages.publish = origGHPublish;
    delete process.env['GH_TOKEN'];
  });

  it('should create a gh-pages branch in the origin repo and publish files to it', function(done) {
    var dir = temp.mkdirSync('oghliner');

    var simpleGit = require('simple-git')(dir);

    simpleGit.init(function() {
      fs.writeFileSync(path.join(dir, 'file'), 'data');

      return simpleGit.add('file')
                      .commit('Initial commit')
                      .addRemote('origin', dir, function() {
        process.chdir(dir);

        return deploy({
          cloneDir: '.gh-pages-cache',
        }).then(function() {
          process.chdir(oldWD);

          return simpleGit.checkout('gh-pages').log(function(err, log) {
            try {
              assert.equal(log.total, 1, '1 commit');
              assert.equal(fs.readFileSync(path.join(dir, 'file'), 'utf8'), 'data');
              done();
            } catch (e) {
              done(e);
            }
          });
        }, function() {
          assert(false, 'Deploy\'s promise should be resolved');
        }).catch(done);
      });
    });
  });

  it('should create a gh-pages branch in the origin repo and publish only the specified files to it', function(done) {
    var dir = temp.mkdirSync('oghliner');

    var simpleGit = require('simple-git')(dir);

    simpleGit.init(function() {
      fs.writeFileSync(path.join(dir, 'file1'), 'data');
      fs.writeFileSync(path.join(dir, 'file2'), 'data');

      return simpleGit.add('file1')
                      .add('file2')
                      .commit('Initial commit')
                      .addRemote('origin', dir, function() {
        process.chdir(dir);

        return deploy({
          cloneDir: '.gh-pages-cache',
          fileGlobs: ['file1'],
        }).then(function() {
          process.chdir(oldWD);

          return simpleGit.checkout('gh-pages').log(function(err, log) {
            try {
              assert.equal(log.total, 1, '1 commit');
              assert.equal(fs.readFileSync(path.join(dir, 'file1'), 'utf8'), 'data');
              assert.throws(fs.statSync.bind(fs, path.join(dir, 'file2')), 'file2 isn\'t deployed');
              done();
            } catch (e) {
              done(e);
            }
          });
        }, function(e) {
          console.log(e);
          assert(false, 'Deploy\'s promise should be resolved');
        }).catch(done);
      });
    });
  });

  it('should update the gh-pages branch in the origin repo and publish files to it', function(done) {
    var dir = temp.mkdirSync('oghliner');

    var simpleGit = require('simple-git')(dir);

    simpleGit.init(function() {
      fs.writeFileSync(path.join(dir, 'file1'), 'data1');
      fs.writeFileSync(path.join(dir, 'file2'), 'data2');

      return simpleGit.add('file1')
                      .commit('Initial commit')
                      .addRemote('origin', dir)
                      .checkoutLocalBranch('gh-pages')
                      .add('file2')
                      .commit('Commit in gh-pages')
                      .checkout('master', function() {
        process.chdir(dir);

        return deploy({
          cloneDir: '.gh-pages-cache',
        }).then(function() {
          process.chdir(oldWD);

          return simpleGit.checkout('gh-pages').log(function(err, log) {
            try {
              assert.equal(log.total, 3, '3 commits');
              assert.equal(fs.readFileSync(path.join(dir, 'file1'), 'utf8'), 'data1');
              assert.throws(fs.accessSync.bind(fs, path.join(dir, 'file2')), 'Old files are removed when deploying');
              done();
            } catch (e) {
              done(e);
            }
          });
        }, function() {
          assert(false, 'Deploy\'s promise should be resolved');
        }).catch(done);
      });
    });
  });

  function deployDifferentRepoURL(done, repoURL) {
    ghPages.publish = function(dir, config, callback) {
      assert.equal(config.repo, 'https://oghliner@github.com/mozilla/oghliner.git');
      callback();
    };
    process.env.GH_TOKEN = 'oghliner';

    var dir = temp.mkdirSync('oghliner');

    var simpleGit = require('simple-git')(dir);

    simpleGit.init(function() {
      fs.writeFileSync(path.join(dir, 'file'), 'data');

      return simpleGit.add('file')
                      .commit('Initial commit')
                      .addRemote('origin', repoURL, function() {
        process.chdir(dir);

        return deploy({
          cloneDir: '.gh-pages-cache',
        }).then(function() {
          assert(true, 'Deploy\'s promise should be resolved');
          done();
        }, function() {
          assert(false, 'Deploy\'s promise should be resolved');
        }).catch(done);
      });
    });
  }

  it('should try to publish with a different repo URL (HTTPS)', function(done) {
    deployDifferentRepoURL(done, 'https://github.com/mozilla/oghliner.git');
  });

  it('should try to publish with a different repo URL (SSH)', function(done) {
    deployDifferentRepoURL(done, 'git@github.com:mozilla/oghliner.git');
  });

  function deployNoOriginRemote(done) {
    var dir = temp.mkdirSync('oghliner');

    var simpleGit = require('simple-git')(dir);

    simpleGit.init(function() {
      fs.writeFileSync(path.join(dir, 'file'), 'data');

      return simpleGit.add('file')
                      .commit('Initial commit', function() {
        process.chdir(dir);

        return deploy({
          cloneDir: '.gh-pages-cache',
        }).then(function() {
          assert(false, 'Deploy\'s promise should be rejected');
        }, function() {
          assert(true, 'Deploy\'s promise should be rejected');
        }).then(done, done);
      });
    });
  }

  it('should fail if there is no origin remote', deployNoOriginRemote);

  it('should fail if there is no origin remote', function(done) {
    process.env.GH_TOKEN = 'oghliner';
    deployNoOriginRemote(done);
  });

  function deployOutsideRepo(message) {
    var dir = temp.mkdirSync('oghliner');

    process.chdir(dir);

    return deploy({
      cloneDir: '.gh-pages-cache',
      message: message,
    }).then(function() {
      assert(false, 'Deploy\'s promise should be rejected');
    }, function() {
      assert(true, 'Deploy\'s promise should be rejected');
    });
  }

  it('should fail if called outside of a git repository with no commit message', function() {
    return deployOutsideRepo();
  });
  it('should fail if called outside of a git repository with commit message', function() {
    return deployOutsideRepo('message');
  });

  it('should fail if called outside of a git repository (on Travis) with no commit message', function() {
    process.env.GH_TOKEN = 'oghliner';
    return deployOutsideRepo();
  });
  it('should fail if called outside of a git repository (on Travis) with commit message', function() {
    process.env.GH_TOKEN = 'oghliner';
    return deployOutsideRepo('message');
  });

  it('should succeed if there\'s a node_modules directory in the rootDir', function(done) {
    var dir = temp.mkdirSync('oghliner');

    var simpleGit = require('simple-git')(dir);

    simpleGit.init(function() {
      fs.writeFileSync(path.join(dir, 'file'), 'data');
      fs.mkdirSync(path.join(dir, 'node_modules'));

      return simpleGit.add('file')
                      .commit('Initial commit')
                      .addRemote('origin', dir, function() {
        process.chdir(dir);

        return deploy({
          cloneDir: '.gh-pages-cache',
        }).then(function() {
          assert(true, 'Deploy\'s promise should be resolved');
          done();
        }, function() {
          assert(false, 'Deploy\'s promise should be resolved');
        }).catch(done);
      });
    });
  });
});
<commit_msg>Test deploying to the 'upstream' remote<commit_after>var assert = require('assert');
var fs = require('fs');
var fse = require('fs-extra');
var path = require('path');
var temp = require('temp').track();
var ghPages = require('gh-pages');
var deploy = require('../lib/deploy');

describe('Deploy', function() {
  var oldWD = process.cwd();
  var origGHPublish = ghPages.publish;

  afterEach(function() {
    process.chdir(oldWD);
    ghPages.publish = origGHPublish;
    delete process.env['GH_TOKEN'];
  });

  it('should create a gh-pages branch in the origin repo and publish files to it', function(done) {
    var dir = temp.mkdirSync('oghliner');

    var simpleGit = require('simple-git')(dir);

    simpleGit.init(function() {
      fs.writeFileSync(path.join(dir, 'file'), 'data');

      return simpleGit.add('file')
                      .commit('Initial commit')
                      .addRemote('origin', dir, function() {
        process.chdir(dir);

        return deploy({
          cloneDir: '.gh-pages-cache',
        }).then(function() {
          process.chdir(oldWD);

          return simpleGit.checkout('gh-pages').log(function(err, log) {
            try {
              assert.equal(log.total, 1, '1 commit');
              assert.equal(fs.readFileSync(path.join(dir, 'file'), 'utf8'), 'data');
              done();
            } catch (e) {
              done(e);
            }
          });
        }, function() {
          assert(false, 'Deploy\'s promise should be resolved');
        }).catch(done);
      });
    });
  });

  it('should create a gh-pages branch in the upstream repo and publish files to it', function(done) {
    var dir = temp.mkdirSync('oghliner');

    var simpleGit = require('simple-git')(dir);

    simpleGit.init(function() {
      fs.writeFileSync(path.join(dir, 'file'), 'data');

      return simpleGit.add('file')
                      .commit('Initial commit')
                      .addRemote('upstream', dir, function() {
        process.chdir(dir);

        return deploy({
          cloneDir: '.gh-pages-cache',
          remote: 'upstream',
        }).then(function() {
          process.chdir(oldWD);

          return simpleGit.checkout('gh-pages').log(function(err, log) {
            try {
              assert.equal(log.total, 1, '1 commit');
              assert.equal(fs.readFileSync(path.join(dir, 'file'), 'utf8'), 'data');
              done();
            } catch (e) {
              done(e);
            }
          });
        }, function() {
          assert(false, 'Deploy\'s promise should be resolved');
        }).catch(done);
      });
    });
  });

  it('should create a gh-pages branch in the origin repo and publish only the specified files to it', function(done) {
    var dir = temp.mkdirSync('oghliner');

    var simpleGit = require('simple-git')(dir);

    simpleGit.init(function() {
      fs.writeFileSync(path.join(dir, 'file1'), 'data');
      fs.writeFileSync(path.join(dir, 'file2'), 'data');

      return simpleGit.add('file1')
                      .add('file2')
                      .commit('Initial commit')
                      .addRemote('origin', dir, function() {
        process.chdir(dir);

        return deploy({
          cloneDir: '.gh-pages-cache',
          fileGlobs: ['file1'],
        }).then(function() {
          process.chdir(oldWD);

          return simpleGit.checkout('gh-pages').log(function(err, log) {
            try {
              assert.equal(log.total, 1, '1 commit');
              assert.equal(fs.readFileSync(path.join(dir, 'file1'), 'utf8'), 'data');
              assert.throws(fs.statSync.bind(fs, path.join(dir, 'file2')), 'file2 isn\'t deployed');
              done();
            } catch (e) {
              done(e);
            }
          });
        }, function(e) {
          console.log(e);
          assert(false, 'Deploy\'s promise should be resolved');
        }).catch(done);
      });
    });
  });

  it('should update the gh-pages branch in the origin repo and publish files to it', function(done) {
    var dir = temp.mkdirSync('oghliner');

    var simpleGit = require('simple-git')(dir);

    simpleGit.init(function() {
      fs.writeFileSync(path.join(dir, 'file1'), 'data1');
      fs.writeFileSync(path.join(dir, 'file2'), 'data2');

      return simpleGit.add('file1')
                      .commit('Initial commit')
                      .addRemote('origin', dir)
                      .checkoutLocalBranch('gh-pages')
                      .add('file2')
                      .commit('Commit in gh-pages')
                      .checkout('master', function() {
        process.chdir(dir);

        return deploy({
          cloneDir: '.gh-pages-cache',
        }).then(function() {
          process.chdir(oldWD);

          return simpleGit.checkout('gh-pages').log(function(err, log) {
            try {
              assert.equal(log.total, 3, '3 commits');
              assert.equal(fs.readFileSync(path.join(dir, 'file1'), 'utf8'), 'data1');
              assert.throws(fs.accessSync.bind(fs, path.join(dir, 'file2')), 'Old files are removed when deploying');
              done();
            } catch (e) {
              done(e);
            }
          });
        }, function() {
          assert(false, 'Deploy\'s promise should be resolved');
        }).catch(done);
      });
    });
  });

  function deployDifferentRepoURL(done, repoURL) {
    ghPages.publish = function(dir, config, callback) {
      assert.equal(config.repo, 'https://oghliner@github.com/mozilla/oghliner.git');
      callback();
    };
    process.env.GH_TOKEN = 'oghliner';

    var dir = temp.mkdirSync('oghliner');

    var simpleGit = require('simple-git')(dir);

    simpleGit.init(function() {
      fs.writeFileSync(path.join(dir, 'file'), 'data');

      return simpleGit.add('file')
                      .commit('Initial commit')
                      .addRemote('origin', repoURL, function() {
        process.chdir(dir);

        return deploy({
          cloneDir: '.gh-pages-cache',
        }).then(function() {
          assert(true, 'Deploy\'s promise should be resolved');
          done();
        }, function() {
          assert(false, 'Deploy\'s promise should be resolved');
        }).catch(done);
      });
    });
  }

  it('should try to publish with a different repo URL (HTTPS)', function(done) {
    deployDifferentRepoURL(done, 'https://github.com/mozilla/oghliner.git');
  });

  it('should try to publish with a different repo URL (SSH)', function(done) {
    deployDifferentRepoURL(done, 'git@github.com:mozilla/oghliner.git');
  });

  function deployNoOriginRemote(done) {
    var dir = temp.mkdirSync('oghliner');

    var simpleGit = require('simple-git')(dir);

    simpleGit.init(function() {
      fs.writeFileSync(path.join(dir, 'file'), 'data');

      return simpleGit.add('file')
                      .commit('Initial commit', function() {
        process.chdir(dir);

        return deploy({
          cloneDir: '.gh-pages-cache',
        }).then(function() {
          assert(false, 'Deploy\'s promise should be rejected');
        }, function() {
          assert(true, 'Deploy\'s promise should be rejected');
        }).then(done, done);
      });
    });
  }

  it('should fail if there is no origin remote', deployNoOriginRemote);

  it('should fail if there is no origin remote', function(done) {
    process.env.GH_TOKEN = 'oghliner';
    deployNoOriginRemote(done);
  });

  function deployOutsideRepo(message) {
    var dir = temp.mkdirSync('oghliner');

    process.chdir(dir);

    return deploy({
      cloneDir: '.gh-pages-cache',
      message: message,
    }).then(function() {
      assert(false, 'Deploy\'s promise should be rejected');
    }, function() {
      assert(true, 'Deploy\'s promise should be rejected');
    });
  }

  it('should fail if called outside of a git repository with no commit message', function() {
    return deployOutsideRepo();
  });
  it('should fail if called outside of a git repository with commit message', function() {
    return deployOutsideRepo('message');
  });

  it('should fail if called outside of a git repository (on Travis) with no commit message', function() {
    process.env.GH_TOKEN = 'oghliner';
    return deployOutsideRepo();
  });
  it('should fail if called outside of a git repository (on Travis) with commit message', function() {
    process.env.GH_TOKEN = 'oghliner';
    return deployOutsideRepo('message');
  });

  it('should succeed if there\'s a node_modules directory in the rootDir', function(done) {
    var dir = temp.mkdirSync('oghliner');

    var simpleGit = require('simple-git')(dir);

    simpleGit.init(function() {
      fs.writeFileSync(path.join(dir, 'file'), 'data');
      fs.mkdirSync(path.join(dir, 'node_modules'));

      return simpleGit.add('file')
                      .commit('Initial commit')
                      .addRemote('origin', dir, function() {
        process.chdir(dir);

        return deploy({
          cloneDir: '.gh-pages-cache',
        }).then(function() {
          assert(true, 'Deploy\'s promise should be resolved');
          done();
        }, function() {
          assert(false, 'Deploy\'s promise should be resolved');
        }).catch(done);
      });
    });
  });
});
<|endoftext|>


<commit_before>// Copyright 2014 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.

(function(scope, testing) {

  function AnimationPlayerEvent(target, currentTime, timelineTime) {
    this.target = target;
    this.currentTime = currentTime;
    this.timelineTime = timelineTime;

    this.type = 'finish';
    this.bubbles = false;
    this.cancelable = false;
    this.currentTarget = target;
    this.defaultPrevented = false;
    this.eventPhase = Event.AT_TARGET;
    this.timeStamp = Date.now();
  };
  AnimationPlayerEvent.prototype = window.Event.prototype;

  var sequenceNumber = 0;

  scope.Player = function(source) {
    this.__currentTime = 0;
    this._startTime = null;
    this._source = source;
    this.paused = false;
    this._playbackRate = 1;
    this._sequenceNumber = sequenceNumber++;
    this._inTimeline = true;
    this._finishedFlag = false;
    this.onfinish = null;
    this._finishHandlers = [];
    source(0);
  };

  scope.Player.prototype = {
    get currentTime() { return this.__currentTime; },
    set _currentTime(newTime) {
      if (newTime != this.__currentTime) {
        this.__currentTime = newTime;
        if (this.finished)
          this.__currentTime = this._playbackRate > 0 ? this._source.totalDuration : 0;
        this._inEffect = this._source(this.__currentTime);
        if (!this._inTimeline && this._inEffect) {
          this._inTimeline = true;
          timeline.players.push(this);
        }
        this._source(this.__currentTime);
      }
    },
    get playbackRate() { return this._playbackRate; },
    set currentTime(newTime) {
      this._currentTime = newTime;
      if (!this.paused) {
        this._startTime = this._timeline.currentTime - this.__currentTime / this._playbackRate;
      }
    },
    get finished() {
      return this._playbackRate > 0 && this.__currentTime >= this._source.totalDuration ||
             this._playbackRate < 0 && this.__currentTime <= 0;
    },
    get startTime() { return this._startTime; },
    set startTime(newTime) {
      if (this.paused) {
        return;
      }
      this._startTime = newTime;
      this._currentTime = this._timeline.currentTime - newTime;
    },
    pause: function() {
      this.paused = true;
      this._startTime = null;
    },
    play: function() {
      this.paused = false;
      if (this.finished)
        this.__currentTime = this._playbackRate > 0 ? 0 : this._source.totalDuration;
      this._startTime = this._timeline.currentTime - this.__currentTime / this._playbackRate;
      this._finishedFlag = false;
    },
    reverse: function() {
      this._playbackRate *= -1;
      this._startTime = this._timeline.currentTime - this.__currentTime / this._playbackRate;
      if (!this._inTimeline) {
        this._inTimeline = true;
        timeline.players.push(this);
      }
      this._finishedFlag = false;
    },
    finish: function() {
      this.currentTime = this._playbackRate > 0 ? this._source.totalDuration : 0;
    },
    cancel: function() {
      this._source = function() { };
      this._source.totalDuration = 0;
      this.currentTime = 0;
    },
    addEventListener: function(type, handler) {
      if (typeof handler !== 'function' || type != 'finish')
        return;
      this._finishHandlers.push(handler);
    },
    removeEventListener: function(type, handler) {
      if (typeof handler !== 'function' || type != 'finish')
        return;
      var index = this._finishHandlers.indexOf(handler);
      if (index >= 0)
        this._finishHandlers.splice(index, 1);
    },
    _fireEvents: function() {
      var finished = this.finished;
      if (finished && !this._finishedFlag) {
        var event = new AnimationPlayerEvent(this, this.currentTime, document.timeline.currentTime);
        var handlers = this._finishHandlers.concat(this.onfinish ? [this.onfinish] : []);
        setTimeout(function() {
          handlers.forEach(function(handler) {
            handler.call(event.target, event);
          });
        }, 0);
      }
      this._finishedFlag = finished;
    },
  };

})(minifill, testing);
<commit_msg>Shave off some characters<commit_after>// Copyright 2014 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.

(function(scope, testing) {

  function AnimationPlayerEvent(target, currentTime, timelineTime) {
    this.target = target;
    this.currentTime = currentTime;
    this.timelineTime = timelineTime;

    this.type = 'finish';
    this.bubbles = false;
    this.cancelable = false;
    this.currentTarget = target;
    this.defaultPrevented = false;
    this.eventPhase = Event.AT_TARGET;
    this.timeStamp = Date.now();
  };
  AnimationPlayerEvent.prototype = window.Event.prototype;

  var sequenceNumber = 0;

  scope.Player = function(source) {
    this.__currentTime = 0;
    this._startTime = null;
    this._source = source;
    this.paused = false;
    this._playbackRate = 1;
    this._sequenceNumber = sequenceNumber++;
    this._inTimeline = true;
    this._finishedFlag = false;
    this.onfinish = null;
    this._finishHandlers = [];
    source(0);
  };

  scope.Player.prototype = {
    get currentTime() { return this.__currentTime; },
    set _currentTime(newTime) {
      if (newTime != this.__currentTime) {
        this.__currentTime = newTime;
        if (this.finished)
          this.__currentTime = this._playbackRate > 0 ? this._source.totalDuration : 0;
        this._inEffect = this._source(this.__currentTime);
        if (!this._inTimeline && this._inEffect) {
          this._inTimeline = true;
          timeline.players.push(this);
        }
        this._source(this.__currentTime);
      }
    },
    get playbackRate() { return this._playbackRate; },
    set currentTime(newTime) {
      this._currentTime = newTime;
      if (!this.paused) {
        this._startTime = this._timeline.currentTime - this.__currentTime / this._playbackRate;
      }
    },
    get finished() {
      return this._playbackRate > 0 && this.__currentTime >= this._source.totalDuration ||
             this._playbackRate < 0 && this.__currentTime <= 0;
    },
    get startTime() { return this._startTime; },
    set startTime(newTime) {
      if (this.paused) {
        return;
      }
      this._startTime = newTime;
      this._currentTime = this._timeline.currentTime - newTime;
    },
    pause: function() {
      this.paused = true;
      this._startTime = null;
    },
    play: function() {
      this.paused = false;
      if (this.finished)
        this.__currentTime = this._playbackRate > 0 ? 0 : this._source.totalDuration;
      this._startTime = this._timeline.currentTime - this.__currentTime / this._playbackRate;
      this._finishedFlag = false;
    },
    reverse: function() {
      this._playbackRate *= -1;
      this._startTime = this._timeline.currentTime - this.__currentTime / this._playbackRate;
      if (!this._inTimeline) {
        this._inTimeline = true;
        timeline.players.push(this);
      }
      this._finishedFlag = false;
    },
    finish: function() {
      this.currentTime = this._playbackRate > 0 ? this._source.totalDuration : 0;
    },
    cancel: function() {
      this._source = function() { };
      this._source.totalDuration = 0;
      this.currentTime = 0;
    },
    addEventListener: function(type, handler) {
      if (typeof handler == 'function' && type == 'finish')
        this._finishHandlers.push(handler);
    },
    removeEventListener: function(type, handler) {
      if (type != 'finish')
        return;
      var index = this._finishHandlers.indexOf(handler);
      if (index >= 0)
        this._finishHandlers.splice(index, 1);
    },
    _fireEvents: function() {
      var finished = this.finished;
      if (finished && !this._finishedFlag) {
        var event = new AnimationPlayerEvent(this, this.currentTime, document.timeline.currentTime);
        var handlers = this._finishHandlers.concat(this.onfinish ? [this.onfinish] : []);
        setTimeout(function() {
          handlers.forEach(function(handler) {
            handler.call(event.target, event);
          });
        }, 0);
      }
      this._finishedFlag = finished;
    },
  };

})(minifill, testing);
<|endoftext|>