<commit_before>const assert = require('assert');

const Parser = require('../src/parser');
const Evaluator = require('../src/evaluator');

function interpret(input) {
  const parser = new Parser(input);
  const ast = parser.parse();
  const evaluator = new Evaluator(ast);
  const output = evaluator.evaluate();
  return output.value;
}

describe('interpret()', function () {
  const positiveTests = [
    {input: '1', expected: 1},
    {input: '-1', expected: -1},
    {input: '0.1', expected: 0.1},
    {input: '-0.1', expected: -0.1},
    {input: '(add 1 2)', expected: 3},
    {input: '(sub 3 2)', expected: 1},
    {input: '(mul 2 3)', expected: 6},
    {input: '(div 6 3)', expected: 2},
    {input: '(mod 9 6)', expected: 3},
    {input: '(pow 2 3)', expected: 8},
    {input: '(add (add 1 2) 3)', expected: 6},
    {input: 'foo', expected: 'foo'},
    {input: 'foo-bar', expected: 'foo-bar'},
    {input: 'fooBar', expected: 'fooBar'},
  ];

  positiveTests.forEach(function (test) {
    it(`correctly evaluates ${test.input}`, function () {
      const actual = interpret(test.input);
      assert.equal(actual, test.expected);
    });
  });

  const negativeTests = [
    {input: '(', reason: 'unmatched parenthesis'},
    {input: ')', reason: 'unmatched parenthesis'},
    {input: '()', reason: 'empty symbolic expression'},
    {input: '(1)', reason: 'symbolic expression must begin with a symbol'},
    {input: '(foo)', reason: 'undefined symbol'},
    {input: 'foo bar', reason: 'must be single expression'},
    {input: '(add 1 2) foo', reason: 'must be single expression'},
    {input: 'foo (add 1 2)', reason: 'must be single expression'},
    {input: '-foo', reason: 'symbol cannot begin with a hyphen'},
    {input: 'foo-', reason: 'symbol cannot end with a hyphen'},
    {input: '.1', reason: 'number cannot begin with a decimal point'},
    {input: '1.', reason: 'number cannot end with a decimal point'},
  ];

  negativeTests.forEach(function (test) {
    it(`throws an error evaluating ${test.input} (${test.reason})`, function () {
      assert.throws(() => {
        interpret(test.input);
      });
    })
  });
});
<commit_msg>Add tests for quoting expressions with the single quote character<commit_after>const assert = require('assert');
const {describe, it} = require('mocha');

const Parser = require('../src/parser');
const Evaluator = require('../src/evaluator');

function interpret(input) {
  const parser = new Parser(input);
  const ast = parser.parse();
  const evaluator = new Evaluator(ast);
  return evaluator.evaluate();
}

describe('interpret()', function () {
  const positiveTests = [
    {input: '1', expected: {type: 'number', value: 1}},
    {input: '-1', expected: {type: 'number', value: -1}},
    {input: '0.1', expected: {type: 'number', value: 0.1}},
    {input: '-0.1', expected: {type: 'number', value: -0.1}},
    {input: '(add 1 2)', expected: {type: 'number', value: 3}},
    {input: '(sub 3 2)', expected: {type: 'number', value: 1}},
    {input: '(mul 2 3)', expected: {type: 'number', value: 6}},
    {input: '(div 6 3)', expected: {type: 'number', value: 2}},
    {input: '(mod 9 6)', expected: {type: 'number', value: 3}},
    {input: '(pow 2 3)', expected: {type: 'number', value: 8}},
    {input: '(add (add 1 2) 3)', expected: {type: 'number', value: 6}},
    {input: 'foo', expected: {type: 'symbol', value: 'foo'}},
    {input: 'foo-bar', expected: {type: 'symbol', value: 'foo-bar'}},
    {input: 'fooBar', expected: {type: 'symbol', value: 'fooBar'}},
    {input: "'1", expected: {type: 'quoted-expression', value: {type: 'number', value: 1}}},
    {input: "'-1", expected: {type: 'quoted-expression', value: {type: 'number', value: -1}}},
    {input: "'0.1", expected: {type: 'quoted-expression', value: {type: 'number', value: 0.1}}},
    {input: "'-0.1", expected: {type: 'quoted-expression', value: {type: 'number', value: -0.1}}},
    {input: "'foo", expected: {type: 'quoted-expression', value: {type: 'symbol', value: 'foo'}}},
    {input: "'foo-bar", expected: {type: 'quoted-expression', value: {type: 'symbol', value: 'foo-bar'}}},
    {input: "'fooBar", expected: {type: 'quoted-expression', value: {type: 'symbol', value: 'fooBar'}}},
    {
      input: "'(add 1 2)",
      expected: {
        type: 'quoted-expression',
        value: {
          type: 'symbolic-expression',
          operator: {type: 'symbol', value: 'add'},
          operands: [
            {type: 'number', value: 1},
            {type: 'number', value: 2}
          ]
        }
      }
    },
    {
      input: "'(add (add 1 2) 3)",
      expected: {
        type: 'quoted-expression',
        value: {
          type: 'symbolic-expression',
          operator: {type: 'symbol', value: 'add'},
          operands: [
            {
              type: 'symbolic-expression',
              operator: {type: 'symbol', value: 'add'},
              operands: [
                {type: 'number', value: 1},
                {type: 'number', value: 2}
              ]
            },
            {type: 'number', value: 3}
          ]
        }
      }
    },
  ];

  positiveTests.forEach(function (test) {
    it(`correctly evaluates ${test.input}`, function () {
      const actual = interpret(test.input);
      assert.deepStrictEqual(actual, test.expected);
    });
  });

  const negativeTests = [
    {input: '(', reason: 'unmatched parenthesis'},
    {input: ')', reason: 'unmatched parenthesis'},
    {input: '()', reason: 'empty symbolic expression'},
    {input: '(1)', reason: 'symbolic expression must begin with a symbol'},
    {input: '(foo)', reason: 'undefined symbol'},
    {input: 'foo bar', reason: 'must be single expression'},
    {input: '(add 1 2) foo', reason: 'must be single expression'},
    {input: 'foo (add 1 2)', reason: 'must be single expression'},
    {input: '-foo', reason: 'symbol cannot begin with a hyphen'},
    {input: 'foo-', reason: 'symbol cannot end with a hyphen'},
    {input: '.1', reason: 'number cannot begin with a decimal point'},
    {input: '1.', reason: 'number cannot end with a decimal point'},
  ];

  negativeTests.forEach(function (test) {
    it(`throws an error evaluating ${test.input} (${test.reason})`, function () {
      assert.throws(() => {
        interpret(test.input);
      });
    })
  });
});
<|endoftext|>


<commit_before>define(["Tone/core/Tone", "Tone/source/Source", "Tone/source/Oscillator",
	"Tone/source/PulseOscillator", "Tone/source/PWMOscillator"],
function(Tone){

	"use strict";

	/**
	 *  @class Tone.OmniOscillator aggregates Tone.Oscillator, Tone.PulseOscillator,
	 *         and Tone.PWMOscillator into one class, allowing it to have the
	 *         types: sine, square, triangle, sawtooth, pulse or pwm. Additionally,
	 *         OmniOscillator is capable of setting the first x number of partials
	 *         of the oscillator. For example: "sine4" would set be the first 4
	 *         partials of the sine wave and "triangle8" would set the first
	 *         8 partials of the triangle wave.
	 *
	 *  @extends {Tone.Oscillator}
	 *  @constructor
	 *  @param {Frequency} frequency The initial frequency of the oscillator.
	 *  @param {string} type The type of the oscillator.
	 *  @example
	 *  var omniOsc = new Tone.OmniOscillator("C#4", "pwm");
	 */
	Tone.OmniOscillator = function(){
		var options = this.optionsObject(arguments, ["frequency", "type"], Tone.OmniOscillator.defaults);
		Tone.Source.call(this, options);

		/**
		 *  The frequency control.
		 *  @type {Frequency}
		 *  @signal
		 */
		this.frequency = new Tone.Signal(options.frequency, Tone.Type.Frequency);

		/**
		 *  The detune control
		 *  @type {Cents}
		 *  @signal
		 */
		this.detune = new Tone.Signal(options.detune, Tone.Type.Cents);

		/**
		 *  the type of the oscillator source
		 *  @type {string}
		 *  @private
		 */
		this._sourceType = undefined;

		/**
		 *  the oscillator
		 *  @type {Tone.Oscillator|Tone.PWMOscillator|Tone.PulseOscillator}
		 *  @private
		 */
		this._oscillator = null;

		//set the oscillator
		this.type = options.type;
		this._readOnly(["frequency", "detune"]);
	};

	Tone.extend(Tone.OmniOscillator, Tone.Oscillator);

	/**
	 *  default values
	 *  @static
	 *  @type {Object}
	 *  @const
	 */
	Tone.OmniOscillator.defaults = {
		"frequency" : 440,
		"detune" : 0,
		"type" : "sine",
		"width" : 0.4, //only applies if the oscillator is set to "pulse",
		"modulationFrequency" : 0.4, //only applies if the oscillator is set to "pwm",
	};

	/**
	 *  @enum {string}
	 *  @private
	 */
	var OmniOscType = {
		PulseOscillator : "PulseOscillator",
		PWMOscillator : "PWMOscillator",
		Oscillator : "Oscillator"
	};

	/**
	 *  start the oscillator
	 *  @param {Time} [time=now] the time to start the oscillator
	 *  @private
	 */
	Tone.OmniOscillator.prototype._start = function(time){
		this._oscillator.start(time);
	};

	/**
	 *  start the oscillator
	 *  @param {Time} [time=now] the time to start the oscillator
	 *  @private
	 */
	Tone.OmniOscillator.prototype._stop = function(time){
		this._oscillator.stop(time);
	};

	/**
	 * The type of the oscillator. sine, square, triangle, sawtooth, pwm, or pulse.
	 * @memberOf Tone.OmniOscillator#
	 * @type {string}
	 * @name type
	 */
	Object.defineProperty(Tone.OmniOscillator.prototype, "type", {
		get : function(){
			return this._oscillator.type;
		},
		set : function(type){
			if (type.indexOf("sine") === 0 || type.indexOf("square") === 0 ||
				type.indexOf("triangle") === 0 || type.indexOf("sawtooth") === 0){
				if (this._sourceType !== OmniOscType.Oscillator){
					this._sourceType = OmniOscType.Oscillator;
					this._createNewOscillator(Tone.Oscillator);
				}
				this._oscillator.type = type;
			} else if (type === "pwm"){
				if (this._sourceType !== OmniOscType.PWMOscillator){
					this._sourceType = OmniOscType.PWMOscillator;
					this._createNewOscillator(Tone.PWMOscillator);
				}
			} else if (type === "pulse"){
				if (this._sourceType !== OmniOscType.PulseOscillator){
					this._sourceType = OmniOscType.PulseOscillator;
					this._createNewOscillator(Tone.PulseOscillator);
				}
			} else {
				throw new TypeError("Tone.OmniOscillator does not support type "+type);
			}
		}
	});

	/**
	 *  connect the oscillator to the frequency and detune signals
	 *  @private
	 */
	Tone.OmniOscillator.prototype._createNewOscillator = function(OscillatorConstructor){
		//short delay to avoid clicks on the change
		var now = this.now() + this.blockTime;
		if (this._oscillator !== null){
			var oldOsc = this._oscillator;
			oldOsc.stop(now);
			oldOsc.onended = function(){
				oldOsc.dispose();
				oldOsc = null;
			};
		}
		this._oscillator = new OscillatorConstructor();
		this.frequency.connect(this._oscillator.frequency);
		this.detune.connect(this._oscillator.detune);
		this._oscillator.connect(this.output);
		if (this.state === Tone.State.Started){
			this._oscillator.start(now);
		}
	};

	/**
	 * The phase of the oscillator in degrees.
	 * @memberOf Tone.OmniOscillator#
	 * @type {Degrees}
	 * @name phase
	 */
	Object.defineProperty(Tone.OmniOscillator.prototype, "phase", {
		get : function(){
			return this._oscillator.phase;
		},
		set : function(phase){
			this._oscillator.phase = phase;
		}
	});

	/**
	 * The width of the oscillator (only if the oscillator is set to pulse)
	 * @memberOf Tone.OmniOscillator#
	 * @type {NormalRange}
	 * @signal
	 * @name width
	 * @example
	 * var omniOsc = new Tone.OmniOscillator(440, "pulse");
	 * //can access the width attribute only if type === "pulse"
	 * omniOsc.width.value = 0.2;
	 */
	Object.defineProperty(Tone.OmniOscillator.prototype, "width", {
		get : function(){
			if (this._sourceType === OmniOscType.PulseOscillator){
				return this._oscillator.width;
			}
		}
	});

	/**
	 * The modulationFrequency Signal of the oscillator
	 * (only if the oscillator type is set to pwm).
	 * @memberOf Tone.OmniOscillator#
	 * @type {Frequency}
	 * @signal
	 * @name modulationFrequency
	 * @example
	 * var omniOsc = new Tone.OmniOscillator(440, "pwm");
	 * //can access the modulationFrequency attribute only if type === "pwm"
	 * omniOsc.modulationFrequency.value = 0.2;
	 */
	Object.defineProperty(Tone.OmniOscillator.prototype, "modulationFrequency", {
		get : function(){
			if (this._sourceType === OmniOscType.PWMOscillator){
				return this._oscillator.modulationFrequency;
			}
		}
	});

	/**
	 *  Clean up.
	 *  @return {Tone.OmniOscillator} this
	 */
	Tone.OmniOscillator.prototype.dispose = function(){
		Tone.Source.prototype.dispose.call(this);
		this._writable(["frequency", "detune"]);
		this.detune.dispose();
		this.detune = null;
		this.frequency.dispose();
		this.frequency = null;
		this._oscillator.dispose();
		this._oscillator = null;
		this._sourceType = null;
		return this;
	};

	return Tone.OmniOscillator;
});<commit_msg>using Error instead of TypeError<commit_after>define(["Tone/core/Tone", "Tone/source/Source", "Tone/source/Oscillator",
	"Tone/source/PulseOscillator", "Tone/source/PWMOscillator"],
function(Tone){

	"use strict";

	/**
	 *  @class Tone.OmniOscillator aggregates Tone.Oscillator, Tone.PulseOscillator,
	 *         and Tone.PWMOscillator into one class, allowing it to have the
	 *         types: sine, square, triangle, sawtooth, pulse or pwm. Additionally,
	 *         OmniOscillator is capable of setting the first x number of partials
	 *         of the oscillator. For example: "sine4" would set be the first 4
	 *         partials of the sine wave and "triangle8" would set the first
	 *         8 partials of the triangle wave.
	 *
	 *  @extends {Tone.Oscillator}
	 *  @constructor
	 *  @param {Frequency} frequency The initial frequency of the oscillator.
	 *  @param {string} type The type of the oscillator.
	 *  @example
	 *  var omniOsc = new Tone.OmniOscillator("C#4", "pwm");
	 */
	Tone.OmniOscillator = function(){
		var options = this.optionsObject(arguments, ["frequency", "type"], Tone.OmniOscillator.defaults);
		Tone.Source.call(this, options);

		/**
		 *  The frequency control.
		 *  @type {Frequency}
		 *  @signal
		 */
		this.frequency = new Tone.Signal(options.frequency, Tone.Type.Frequency);

		/**
		 *  The detune control
		 *  @type {Cents}
		 *  @signal
		 */
		this.detune = new Tone.Signal(options.detune, Tone.Type.Cents);

		/**
		 *  the type of the oscillator source
		 *  @type {string}
		 *  @private
		 */
		this._sourceType = undefined;

		/**
		 *  the oscillator
		 *  @type {Tone.Oscillator|Tone.PWMOscillator|Tone.PulseOscillator}
		 *  @private
		 */
		this._oscillator = null;

		//set the oscillator
		this.type = options.type;
		this._readOnly(["frequency", "detune"]);
	};

	Tone.extend(Tone.OmniOscillator, Tone.Oscillator);

	/**
	 *  default values
	 *  @static
	 *  @type {Object}
	 *  @const
	 */
	Tone.OmniOscillator.defaults = {
		"frequency" : 440,
		"detune" : 0,
		"type" : "sine",
		"width" : 0.4, //only applies if the oscillator is set to "pulse",
		"modulationFrequency" : 0.4, //only applies if the oscillator is set to "pwm",
	};

	/**
	 *  @enum {string}
	 *  @private
	 */
	var OmniOscType = {
		PulseOscillator : "PulseOscillator",
		PWMOscillator : "PWMOscillator",
		Oscillator : "Oscillator"
	};

	/**
	 *  start the oscillator
	 *  @param {Time} [time=now] the time to start the oscillator
	 *  @private
	 */
	Tone.OmniOscillator.prototype._start = function(time){
		this._oscillator.start(time);
	};

	/**
	 *  start the oscillator
	 *  @param {Time} [time=now] the time to start the oscillator
	 *  @private
	 */
	Tone.OmniOscillator.prototype._stop = function(time){
		this._oscillator.stop(time);
	};

	/**
	 * The type of the oscillator. sine, square, triangle, sawtooth, pwm, or pulse.
	 * @memberOf Tone.OmniOscillator#
	 * @type {string}
	 * @name type
	 */
	Object.defineProperty(Tone.OmniOscillator.prototype, "type", {
		get : function(){
			return this._oscillator.type;
		},
		set : function(type){
			if (type.indexOf("sine") === 0 || type.indexOf("square") === 0 ||
				type.indexOf("triangle") === 0 || type.indexOf("sawtooth") === 0){
				if (this._sourceType !== OmniOscType.Oscillator){
					this._sourceType = OmniOscType.Oscillator;
					this._createNewOscillator(Tone.Oscillator);
				}
				this._oscillator.type = type;
			} else if (type === "pwm"){
				if (this._sourceType !== OmniOscType.PWMOscillator){
					this._sourceType = OmniOscType.PWMOscillator;
					this._createNewOscillator(Tone.PWMOscillator);
				}
			} else if (type === "pulse"){
				if (this._sourceType !== OmniOscType.PulseOscillator){
					this._sourceType = OmniOscType.PulseOscillator;
					this._createNewOscillator(Tone.PulseOscillator);
				}
			} else {
				throw new Error("Tone.OmniOscillator does not support type "+type);
			}
		}
	});

	/**
	 *  connect the oscillator to the frequency and detune signals
	 *  @private
	 */
	Tone.OmniOscillator.prototype._createNewOscillator = function(OscillatorConstructor){
		//short delay to avoid clicks on the change
		var now = this.now() + this.blockTime;
		if (this._oscillator !== null){
			var oldOsc = this._oscillator;
			oldOsc.stop(now);
			//dispose the old one
			setTimeout(function(){
				oldOsc.dispose();
				oldOsc = null;
			}, this.blockTime * 1000);
		}
		this._oscillator = new OscillatorConstructor();
		this.frequency.connect(this._oscillator.frequency);
		this.detune.connect(this._oscillator.detune);
		this._oscillator.connect(this.output);
		if (this.state === Tone.State.Started){
			this._oscillator.start(now);
		}
	};

	/**
	 * The phase of the oscillator in degrees.
	 * @memberOf Tone.OmniOscillator#
	 * @type {Degrees}
	 * @name phase
	 */
	Object.defineProperty(Tone.OmniOscillator.prototype, "phase", {
		get : function(){
			return this._oscillator.phase;
		},
		set : function(phase){
			this._oscillator.phase = phase;
		}
	});

	/**
	 * The width of the oscillator (only if the oscillator is set to pulse)
	 * @memberOf Tone.OmniOscillator#
	 * @type {NormalRange}
	 * @signal
	 * @name width
	 * @example
	 * var omniOsc = new Tone.OmniOscillator(440, "pulse");
	 * //can access the width attribute only if type === "pulse"
	 * omniOsc.width.value = 0.2;
	 */
	Object.defineProperty(Tone.OmniOscillator.prototype, "width", {
		get : function(){
			if (this._sourceType === OmniOscType.PulseOscillator){
				return this._oscillator.width;
			}
		}
	});

	/**
	 * The modulationFrequency Signal of the oscillator
	 * (only if the oscillator type is set to pwm).
	 * @memberOf Tone.OmniOscillator#
	 * @type {Frequency}
	 * @signal
	 * @name modulationFrequency
	 * @example
	 * var omniOsc = new Tone.OmniOscillator(440, "pwm");
	 * //can access the modulationFrequency attribute only if type === "pwm"
	 * omniOsc.modulationFrequency.value = 0.2;
	 */
	Object.defineProperty(Tone.OmniOscillator.prototype, "modulationFrequency", {
		get : function(){
			if (this._sourceType === OmniOscType.PWMOscillator){
				return this._oscillator.modulationFrequency;
			}
		}
	});

	/**
	 *  Clean up.
	 *  @return {Tone.OmniOscillator} this
	 */
	Tone.OmniOscillator.prototype.dispose = function(){
		Tone.Source.prototype.dispose.call(this);
		this._writable(["frequency", "detune"]);
		this.detune.dispose();
		this.detune = null;
		this.frequency.dispose();
		this.frequency = null;
		this._oscillator.dispose();
		this._oscillator = null;
		this._sourceType = null;
		return this;
	};

	return Tone.OmniOscillator;
});<|endoftext|>


<commit_before><commit_msg>save config file with indentation<commit_after><|endoftext|>


<commit_before>exports.name = 'task.pushover';
exports.version = '1.0.0';

exports.register = function(plugin, options, next) {
  var app     = plugin.app;
  var request = app.service.request;
  var url     = 'https://api.pushover.net/1/messages.json';

  function run(job, done) {

    var params = {
      method: 'POST',
      url: url,
      json: true,
      form: {
        token: app.config.get('/env/PUSHOVER_TOKEN'),
        user: app.config.get('/env/PUSHOVER_USER'),
        title: 'Doorbell - Side Gate',
        message: 'Ring! Ring! Ring!',
        priority: 1
      }
    };

    request(params, function(err, res, body) {
      if(err) return done(err);
      return done();
    });
  }

  app.task.define('Notify Pushover', options || {}, run);

  next();
};
<commit_msg>Set pushover sound<commit_after>exports.name = 'task.pushover';
exports.version = '1.0.0';

exports.register = function(plugin, options, next) {
  var app     = plugin.app;
  var request = app.service.request;
  var url     = 'https://api.pushover.net/1/messages.json';

  function run(job, done) {

    var params = {
      method: 'POST',
      url: url,
      json: true,
      form: {
        token: app.config.get('/env/PUSHOVER_TOKEN'),
        user: app.config.get('/env/PUSHOVER_USER'),
        title: 'Doorbell - Side Gate',
        message: 'Ring! Ring! Ring!',
        priority: 1,
        sound: 'persistent'
      }
    };

    request(params, function(err, res, body) {
      if(err) return done(err);
      return done();
    });
  }

  app.task.define('Notify Pushover', options || {}, run);

  next();
};
<|endoftext|>


<commit_before>/***
|''Requires''|TiddlySpaceConfig|
***/
//{{{
(function($) {
config.options.chkBackstage = true;
config.backstageTasks = [];

config.tasks.login = {
	text: "login",
	tooltip: "TiddlySpace login",
	content: "<<tiddler BackstageLogin>>"
};
config.backstageTasks.push("login");

config.tasks.user = {
	text: "user: ",
	tooltip: "user control panel",
	content: "<<tiddler BackstageUser>>"
};
config.backstageTasks.push("user");

config.tasks.space = {
	text: "space: "+config.extensions.tiddlyspace.currentSpace.name,
	tooltip: "space control panel",
	content: "<<tiddler BackstageSpace>>",
	className: "right"
};
config.backstageTasks.push("space");

config.messages.backstage.prompt = "";
// initialize state
var _show = backstage.show;
backstage.show = function() {
	// selectively hide backstage tasks based on user status
	var tasks = $("#backstageToolbar .backstageTask").show();
	config.extensions.tiddlyweb.getUserInfo(function(user) {
		if(user.anon) {
			tasks.slice(1, 2).hide();
		} else {
			tasks.eq(0).hide();
		}
	});
	// display backstage
	return _show.apply(this, arguments);
};

var _init = backstage.init;
backstage.init = function(){
	var result = _init.apply(this, arguments);

	//update usernames
	var userButton = $(".backstageTask[task=user]").
	html(config.tasks.user.text+ ""+ glyph("downTriangle"));
	config.macros.option.handler($(".txtUserName",userButton)[0],null,["txtUserName"]);

	//make the backstage become visible when you mouseover it
	var _revealBackstageArea;
	$("#backstageButton").mouseover(function(e){ //when mouseover the button set a timeout to show backstage
		if(!backstage.isVisible()){
			_revealBackstageArea = window.setTimeout(function(){
				if(!backstage.isVisible())backstage.show();
			},"600");}
		}
	).
	mouseout(function(e){ //on a mouseout we prevent showing of the backstage.
		if(_revealBackstageArea){
			window.clearTimeout(_revealBackstageArea);
		}
	});

	//override show button with an svg image
	var showButton = $("#backstageShow")[0];
	$(showButton).html("");
	wikify("<<image backstage.svg 60 60>>",showButton);

	//override hide button
	var hideButton =$("#backstageHide")[0];
	jQuery(hideButton).html("");
	wikify("<<image close.svg 25 25>>",hideButton);

	var backstageToolbar = $("#backstageToolbar")[0];
	$("

").prependTo(backstageToolbar);
	wikify("<<image tiddlyspace.svg 16 16>> ''{{privateLightText{tiddly}}}{{publicLightText{space}}}''",$("#backstageLogo",backstageToolbar)[0]);

	var siteIcon =store.getTiddler("SiteIcon")
	if(siteIcon){
		wikify(siteIcon.text,jQuery("[task=space]","#backstageArea")[0]);
	}

	var host = config.defaultCustomFields['server.host'];
	var subdomainStart = host.indexOf(".");
	var addressStart = host.indexOf("/") + 2;
	var tsHost = host.substr(0,addressStart)+ host.substr(subdomainStart+1);

	//show avatar in the users public bag
	jQuery("[task=user]","#backstageArea").append('
');
	//show default avatar for the login button
	jQuery("[task=login]","#backstageArea").append('
');

}

})(jQuery);
//}}}
<commit_msg>code cleanup, fallback for ie<commit_after>/***
|''Requires''|TiddlySpaceConfig|
***/
//{{{
(function($) {
config.options.chkBackstage = true;
config.backstageTasks = [];

config.tasks.login = {
	text: "login",
	tooltip: "TiddlySpace login",
	content: "<<tiddler BackstageLogin>>"
};
config.backstageTasks.push("login");

config.tasks.user = {
	text: "user: ",
	tooltip: "user control panel",
	content: "<<tiddler BackstageUser>>"
};
config.backstageTasks.push("user");

config.tasks.space = {
	text: "space: "+config.extensions.tiddlyspace.currentSpace.name,
	tooltip: "space control panel",
	content: "<<tiddler BackstageSpace>>",
	className: "right"
};
config.backstageTasks.push("space");

config.messages.backstage.prompt = "";
// initialize state
var _show = backstage.show;
backstage.show = function() {
	// selectively hide backstage tasks based on user status
	var tasks = $("#backstageToolbar .backstageTask").show();
	config.extensions.tiddlyweb.getUserInfo(function(user) {
		if(user.anon) {
			tasks.slice(1, 2).hide();
		} else {
			tasks.eq(0).hide();
		}
	});
	// display backstage
	return _show.apply(this, arguments);
};

var _init = backstage.init;
backstage.init = function(){
	var result = _init.apply(this, arguments);

	//update usernames
	var userButton = $(".backstageTask[task=user]").
	html(config.tasks.user.text+ ""+ glyph("downTriangle"));
	config.macros.option.handler($(".txtUserName",userButton)[0],null,["txtUserName"]);

	//make the backstage become visible when you mouseover it
	var _revealBackstageArea;
	$("#backstageButton").mouseover(function(e){ //when mouseover the button set a timeout to show backstage
		if(!backstage.isVisible()){
			_revealBackstageArea = window.setTimeout(function(){
				if(!backstage.isVisible())backstage.show();
			},"600");}
		}
	).
	mouseout(function(e){ //on a mouseout we prevent showing of the backstage.
		if(_revealBackstageArea){
			window.clearTimeout(_revealBackstageArea);
		}
	});

	//override show button with an svg image
	var showButton = $("#backstageShow")[0];
	var altText = $(showButton).text();
	$(showButton).empty();
	wikify("<<image backstage.svg 60 60 alt:\""+altText+"\">>",showButton);

	//override hide button
	var hideButton =$("#backstageHide")[0];
	var altText = $(hideButton).text();
	$(hideButton).empty();
	wikify("<<image close.svg 25 25 alt:\""+altText+"\">>",hideButton);

	var backstageToolbar = $("#backstageToolbar")[0];
	$("

").prependTo(backstageToolbar);
	wikify("<<image tiddlyspace.svg 16 16>> ''{{privateLightText{tiddly}}}{{publicLightText{space}}}''",$("#backstageLogo",backstageToolbar)[0]);

	var siteIcon =store.getTiddler("SiteIcon")
	if(siteIcon){
		wikify(siteIcon.text,$("[task=space]","#backstageArea")[0]);
	}

	var host = config.defaultCustomFields['server.host'];
	var subdomainStart = host.indexOf(".");
	var addressStart = host.indexOf("/") + 2;
	var tsHost = host.substr(0,addressStart)+ host.substr(subdomainStart+1);

	//show avatar in the users public bag
	$("[task=user]","#backstageArea").append('
');
	//show default avatar for the login button
	$("[task=login]","#backstageArea").append('
');

}

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


<commit_before>
describe('Logagent parse JSON', function() {
  it('should return corect message with timestamp', function(done) {
    var Logagent = require('../lib/index.js')
    var la = new Logagent()
    la.parseLine (JSON.stringify({
      message: 'hello world',
      counter: 1
    }), 'json', function (err, data) {
      if (err) {
        done(err)
      } else {
        if(data.message === 'hello world' && data.counter === 1 && data['@timestamp']) {
          done()
        } else {
          done (new Error('message is wrong: ' + data.message))
        }
      }
    })
  })
})

describe('Logagent parse web server Log', function() {
  it('should return client_ip and status_code', function(done) {
    var Logagent = require('../lib/index.js')
    var la = new Logagent()
    la.parseLine ('190.160.248.117 - - [03/Apr/2016:06:25:38 +0000] "GET /about/ HTTP/1.1" 200 14243 "https://sematext.com/consulting/elasticsearch/" "Mozilla/5.0 (iPhone; CPU iPhone OS 8_1_1 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Mobile/12B436 Twitter for iPhone"',
      'nginx', function (err, data) {
      if (err) {
        done(err)
      } else {
        if(data.message === 'GET /about/ HTTP/1.1' && data.client_ip === '190.160.248.117' && data.status_code === 200 && data['@timestamp']) {
          done()
        } else {
          done (new Error('message is wrong: ' + JSON.stringify(data)))
        }
      }
    })
  })
})<commit_msg>add simple tests<commit_after>
describe('Logagent parse JSON', function() {
  it('should return corect message with timestamp', function(done) {
    this.timeout(150000)
    var Logagent = require('../lib/index.js')
    var la = new Logagent()
    la.parseLine (JSON.stringify({
      message: 'hello world',
      counter: 1
    }), 'json', function (err, data) {
      if (err) {
        done(err)
      } else {
        if(data.message === 'hello world' && data.counter === 1 && data['@timestamp']) {
          done()
        } else {
          done (new Error('message is wrong: ' + data.message))
        }
      }
    })
  })
})

describe('Logagent parse web server Log', function() {
  it('should return client_ip and status_code', function(done) {
    this.timeout(150000)
    var Logagent = require('../lib/index.js')
    var la = new Logagent()
    la.parseLine ('190.160.248.117 - - [03/Apr/2016:06:25:38 +0000] "GET /about/ HTTP/1.1" 200 14243 "https://sematext.com/consulting/elasticsearch/" "Mozilla/5.0 (iPhone; CPU iPhone OS 8_1_1 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Mobile/12B436 Twitter for iPhone"',
      'nginx', function (err, data) {
      if (err) {
        done(err)
      } else {
        if(data.message === 'GET /about/ HTTP/1.1' && data.client_ip === '190.160.248.117' && data.status_code === 200 && data['@timestamp']) {
          done()
        } else {
          done (new Error('message is wrong: ' + JSON.stringify(data)))
        }
      }
    })
  })
})

<|endoftext|>


<commit_before>define(["Tone/core/Tone", "Tone/source/Source", "Tone/source/Oscillator",
	"Tone/source/PulseOscillator", "Tone/source/PWMOscillator"],
function(Tone){

	"use strict";

	/**
	 *  @class Tone.OmniOscillator aggregates Tone.Oscillator, Tone.PulseOscillator,
	 *         and Tone.PWMOscillator into one class, allowing it to have the
	 *         types: sine, square, triangle, sawtooth, pulse or pwm. Additionally,
	 *         OmniOscillator is capable of setting the first x number of partials
	 *         of the oscillator. For example: "sine4" would set be the first 4
	 *         partials of the sine wave and "triangle8" would set the first
	 *         8 partials of the triangle wave.
	 *
	 *  @extends {Tone.Oscillator}
	 *  @constructor
	 *  @param {Frequency} frequency The initial frequency of the oscillator.
	 *  @param {string} type The type of the oscillator.
	 *  @example
	 *  var omniOsc = new Tone.OmniOscillator("C#4", "pwm");
	 */
	Tone.OmniOscillator = function(){
		var options = this.optionsObject(arguments, ["frequency", "type"], Tone.OmniOscillator.defaults);
		Tone.Source.call(this, options);

		/**
		 *  The frequency control.
		 *  @type {Frequency}
		 *  @signal
		 */
		this.frequency = new Tone.Signal(options.frequency, Tone.Type.Frequency);

		/**
		 *  The detune control
		 *  @type {Cents}
		 *  @signal
		 */
		this.detune = new Tone.Signal(options.detune, Tone.Type.Cents);

		/**
		 *  the type of the oscillator source
		 *  @type {string}
		 *  @private
		 */
		this._sourceType = undefined;

		/**
		 *  the oscillator
		 *  @type {Tone.Oscillator|Tone.PWMOscillator|Tone.PulseOscillator}
		 *  @private
		 */
		this._oscillator = null;

		//set the oscillator
		this.type = options.type;
		this.phase = options.phase;
		this._readOnly(["frequency", "detune"]);
	};

	Tone.extend(Tone.OmniOscillator, Tone.Oscillator);

	/**
	 *  default values
	 *  @static
	 *  @type {Object}
	 *  @const
	 */
	Tone.OmniOscillator.defaults = {
		"frequency" : 440,
		"detune" : 0,
		"type" : "sine",
		"phase" : 0,
		"width" : 0.4, //only applies if the oscillator is set to "pulse",
		"modulationFrequency" : 0.4, //only applies if the oscillator is set to "pwm",
	};

	/**
	 *  @enum {string}
	 *  @private
	 */
	var OmniOscType = {
		PulseOscillator : "PulseOscillator",
		PWMOscillator : "PWMOscillator",
		Oscillator : "Oscillator"
	};

	/**
	 *  start the oscillator
	 *  @param {Time} [time=now] the time to start the oscillator
	 *  @private
	 */
	Tone.OmniOscillator.prototype._start = function(time){
		this._oscillator.start(time);
	};

	/**
	 *  start the oscillator
	 *  @param {Time} [time=now] the time to start the oscillator
	 *  @private
	 */
	Tone.OmniOscillator.prototype._stop = function(time){
		this._oscillator.stop(time);
	};

	/**
	 * The type of the oscillator. sine, square, triangle, sawtooth, pwm, or pulse.
	 * @memberOf Tone.OmniOscillator#
	 * @type {string}
	 * @name type
	 */
	Object.defineProperty(Tone.OmniOscillator.prototype, "type", {
		get : function(){
			return this._oscillator.type;
		},
		set : function(type){
			if (type.indexOf("sine") === 0 || type.indexOf("square") === 0 ||
				type.indexOf("triangle") === 0 || type.indexOf("sawtooth") === 0 || type === Tone.Oscillator.Type.Custom){
				if (this._sourceType !== OmniOscType.Oscillator){
					this._sourceType = OmniOscType.Oscillator;
					this._createNewOscillator(Tone.Oscillator);
				}
				this._oscillator.type = type;
			} else if (type === "pwm"){
				if (this._sourceType !== OmniOscType.PWMOscillator){
					this._sourceType = OmniOscType.PWMOscillator;
					this._createNewOscillator(Tone.PWMOscillator);
				}
			} else if (type === "pulse"){
				if (this._sourceType !== OmniOscType.PulseOscillator){
					this._sourceType = OmniOscType.PulseOscillator;
					this._createNewOscillator(Tone.PulseOscillator);
				}
			} else {
				throw new Error("Tone.OmniOscillator does not support type "+type);
			}
		}
	});

	/**
	 * The partials of the waveform. A partial represents
	 * the amplitude at a harmonic. The first harmonic is the
	 * fundamental frequency, the second is the octave and so on
	 * following the harmonic series.
	 * Setting this value will automatically set the type to "custom".
	 * The value is an empty array when the type is not "custom".
	 * @memberOf Tone.OmniOscillator#
	 * @type {Array}
	 * @name partials
	 * @example
	 * osc.partials = [1, 0.2, 0.01];
	 */
	Object.defineProperty(Tone.OmniOscillator.prototype, "partials", {
		get : function(){
			return this._oscillator.partials;
		},
		set : function(partials){
			if (this._sourceType !== OmniOscType.Oscillator){
				this.type = Tone.Oscillator.Type.Custom;
			}
			this._oscillator.partials = partials;
		}
	});

	/**
	 *  connect the oscillator to the frequency and detune signals
	 *  @private
	 */
	Tone.OmniOscillator.prototype._createNewOscillator = function(OscillatorConstructor){
		//short delay to avoid clicks on the change
		var now = this.now() + this.blockTime;
		if (this._oscillator !== null){
			var oldOsc = this._oscillator;
			oldOsc.stop(now);
			//dispose the old one
			setTimeout(function(){
				oldOsc.dispose();
				oldOsc = null;
			}, this.blockTime * 1000);
		}
		this._oscillator = new OscillatorConstructor();
		this.frequency.connect(this._oscillator.frequency);
		this.detune.connect(this._oscillator.detune);
		this._oscillator.connect(this.output);
		if (this.state === Tone.State.Started){
			this._oscillator.start(now);
		}
	};

	/**
	 * The phase of the oscillator in degrees.
	 * @memberOf Tone.OmniOscillator#
	 * @type {Degrees}
	 * @name phase
	 */
	Object.defineProperty(Tone.OmniOscillator.prototype, "phase", {
		get : function(){
			return this._oscillator.phase;
		},
		set : function(phase){
			this._oscillator.phase = phase;
		}
	});

	/**
	 * The width of the oscillator (only if the oscillator is set to pulse)
	 * @memberOf Tone.OmniOscillator#
	 * @type {NormalRange}
	 * @signal
	 * @name width
	 * @example
	 * var omniOsc = new Tone.OmniOscillator(440, "pulse");
	 * //can access the width attribute only if type === "pulse"
	 * omniOsc.width.value = 0.2;
	 */
	Object.defineProperty(Tone.OmniOscillator.prototype, "width", {
		get : function(){
			if (this._sourceType === OmniOscType.PulseOscillator){
				return this._oscillator.width;
			}
		}
	});

	/**
	 * The modulationFrequency Signal of the oscillator
	 * (only if the oscillator type is set to pwm).
	 * @memberOf Tone.OmniOscillator#
	 * @type {Frequency}
	 * @signal
	 * @name modulationFrequency
	 * @example
	 * var omniOsc = new Tone.OmniOscillator(440, "pwm");
	 * //can access the modulationFrequency attribute only if type === "pwm"
	 * omniOsc.modulationFrequency.value = 0.2;
	 */
	Object.defineProperty(Tone.OmniOscillator.prototype, "modulationFrequency", {
		get : function(){
			if (this._sourceType === OmniOscType.PWMOscillator){
				return this._oscillator.modulationFrequency;
			}
		}
	});

	/**
	 *  Clean up.
	 *  @return {Tone.OmniOscillator} this
	 */
	Tone.OmniOscillator.prototype.dispose = function(){
		Tone.Source.prototype.dispose.call(this);
		this._writable(["frequency", "detune"]);
		this.detune.dispose();
		this.detune = null;
		this.frequency.dispose();
		this.frequency = null;
		this._oscillator.dispose();
		this._oscillator = null;
		this._sourceType = null;
		return this;
	};

	return Tone.OmniOscillator;
});<commit_msg>can set partials in constructor<commit_after>define(["Tone/core/Tone", "Tone/source/Source", "Tone/source/Oscillator",
	"Tone/source/PulseOscillator", "Tone/source/PWMOscillator"],
function(Tone){

	"use strict";

	/**
	 *  @class Tone.OmniOscillator aggregates Tone.Oscillator, Tone.PulseOscillator,
	 *         and Tone.PWMOscillator into one class, allowing it to have the
	 *         types: sine, square, triangle, sawtooth, pulse or pwm. Additionally,
	 *         OmniOscillator is capable of setting the first x number of partials
	 *         of the oscillator. For example: "sine4" would set be the first 4
	 *         partials of the sine wave and "triangle8" would set the first
	 *         8 partials of the triangle wave.
	 *
	 *  @extends {Tone.Oscillator}
	 *  @constructor
	 *  @param {Frequency} frequency The initial frequency of the oscillator.
	 *  @param {string} type The type of the oscillator.
	 *  @example
	 *  var omniOsc = new Tone.OmniOscillator("C#4", "pwm");
	 */
	Tone.OmniOscillator = function(){
		var options = this.optionsObject(arguments, ["frequency", "type"], Tone.OmniOscillator.defaults);
		Tone.Source.call(this, options);

		/**
		 *  The frequency control.
		 *  @type {Frequency}
		 *  @signal
		 */
		this.frequency = new Tone.Signal(options.frequency, Tone.Type.Frequency);

		/**
		 *  The detune control
		 *  @type {Cents}
		 *  @signal
		 */
		this.detune = new Tone.Signal(options.detune, Tone.Type.Cents);

		/**
		 *  the type of the oscillator source
		 *  @type {string}
		 *  @private
		 */
		this._sourceType = undefined;

		/**
		 *  the oscillator
		 *  @type {Tone.Oscillator|Tone.PWMOscillator|Tone.PulseOscillator}
		 *  @private
		 */
		this._oscillator = null;

		//set the oscillator
		this.type = options.type;
		this.phase = options.phase;
		this._readOnly(["frequency", "detune"]);
		if (this.isArray(options.partials)){
			this.partials = options.partials;
		}
	};

	Tone.extend(Tone.OmniOscillator, Tone.Oscillator);

	/**
	 *  default values
	 *  @static
	 *  @type {Object}
	 *  @const
	 */
	Tone.OmniOscillator.defaults = {
		"frequency" : 440,
		"detune" : 0,
		"type" : "sine",
		"phase" : 0,
		"width" : 0.4, //only applies if the oscillator is set to "pulse",
		"modulationFrequency" : 0.4, //only applies if the oscillator is set to "pwm",
	};

	/**
	 *  @enum {string}
	 *  @private
	 */
	var OmniOscType = {
		PulseOscillator : "PulseOscillator",
		PWMOscillator : "PWMOscillator",
		Oscillator : "Oscillator"
	};

	/**
	 *  start the oscillator
	 *  @param {Time} [time=now] the time to start the oscillator
	 *  @private
	 */
	Tone.OmniOscillator.prototype._start = function(time){
		this._oscillator.start(time);
	};

	/**
	 *  start the oscillator
	 *  @param {Time} [time=now] the time to start the oscillator
	 *  @private
	 */
	Tone.OmniOscillator.prototype._stop = function(time){
		this._oscillator.stop(time);
	};

	/**
	 * The type of the oscillator. sine, square, triangle, sawtooth, pwm, or pulse.
	 * @memberOf Tone.OmniOscillator#
	 * @type {string}
	 * @name type
	 */
	Object.defineProperty(Tone.OmniOscillator.prototype, "type", {
		get : function(){
			return this._oscillator.type;
		},
		set : function(type){
			if (type.indexOf("sine") === 0 || type.indexOf("square") === 0 ||
				type.indexOf("triangle") === 0 || type.indexOf("sawtooth") === 0 || type === Tone.Oscillator.Type.Custom){
				if (this._sourceType !== OmniOscType.Oscillator){
					this._sourceType = OmniOscType.Oscillator;
					this._createNewOscillator(Tone.Oscillator);
				}
				this._oscillator.type = type;
			} else if (type === "pwm"){
				if (this._sourceType !== OmniOscType.PWMOscillator){
					this._sourceType = OmniOscType.PWMOscillator;
					this._createNewOscillator(Tone.PWMOscillator);
				}
			} else if (type === "pulse"){
				if (this._sourceType !== OmniOscType.PulseOscillator){
					this._sourceType = OmniOscType.PulseOscillator;
					this._createNewOscillator(Tone.PulseOscillator);
				}
			} else {
				throw new Error("Tone.OmniOscillator does not support type "+type);
			}
		}
	});

	/**
	 * The partials of the waveform. A partial represents
	 * the amplitude at a harmonic. The first harmonic is the
	 * fundamental frequency, the second is the octave and so on
	 * following the harmonic series.
	 * Setting this value will automatically set the type to "custom".
	 * The value is an empty array when the type is not "custom".
	 * @memberOf Tone.OmniOscillator#
	 * @type {Array}
	 * @name partials
	 * @example
	 * osc.partials = [1, 0.2, 0.01];
	 */
	Object.defineProperty(Tone.OmniOscillator.prototype, "partials", {
		get : function(){
			return this._oscillator.partials;
		},
		set : function(partials){
			if (this._sourceType !== OmniOscType.Oscillator){
				this.type = Tone.Oscillator.Type.Custom;
			}
			this._oscillator.partials = partials;
		}
	});

	/**
	 *  connect the oscillator to the frequency and detune signals
	 *  @private
	 */
	Tone.OmniOscillator.prototype._createNewOscillator = function(OscillatorConstructor){
		//short delay to avoid clicks on the change
		var now = this.now() + this.blockTime;
		if (this._oscillator !== null){
			var oldOsc = this._oscillator;
			oldOsc.stop(now);
			//dispose the old one
			setTimeout(function(){
				oldOsc.dispose();
				oldOsc = null;
			}, this.blockTime * 1000);
		}
		this._oscillator = new OscillatorConstructor();
		this.frequency.connect(this._oscillator.frequency);
		this.detune.connect(this._oscillator.detune);
		this._oscillator.connect(this.output);
		if (this.state === Tone.State.Started){
			this._oscillator.start(now);
		}
	};

	/**
	 * The phase of the oscillator in degrees.
	 * @memberOf Tone.OmniOscillator#
	 * @type {Degrees}
	 * @name phase
	 */
	Object.defineProperty(Tone.OmniOscillator.prototype, "phase", {
		get : function(){
			return this._oscillator.phase;
		},
		set : function(phase){
			this._oscillator.phase = phase;
		}
	});

	/**
	 * The width of the oscillator (only if the oscillator is set to pulse)
	 * @memberOf Tone.OmniOscillator#
	 * @type {NormalRange}
	 * @signal
	 * @name width
	 * @example
	 * var omniOsc = new Tone.OmniOscillator(440, "pulse");
	 * //can access the width attribute only if type === "pulse"
	 * omniOsc.width.value = 0.2;
	 */
	Object.defineProperty(Tone.OmniOscillator.prototype, "width", {
		get : function(){
			if (this._sourceType === OmniOscType.PulseOscillator){
				return this._oscillator.width;
			}
		}
	});

	/**
	 * The modulationFrequency Signal of the oscillator
	 * (only if the oscillator type is set to pwm).
	 * @memberOf Tone.OmniOscillator#
	 * @type {Frequency}
	 * @signal
	 * @name modulationFrequency
	 * @example
	 * var omniOsc = new Tone.OmniOscillator(440, "pwm");
	 * //can access the modulationFrequency attribute only if type === "pwm"
	 * omniOsc.modulationFrequency.value = 0.2;
	 */
	Object.defineProperty(Tone.OmniOscillator.prototype, "modulationFrequency", {
		get : function(){
			if (this._sourceType === OmniOscType.PWMOscillator){
				return this._oscillator.modulationFrequency;
			}
		}
	});

	/**
	 *  Clean up.
	 *  @return {Tone.OmniOscillator} this
	 */
	Tone.OmniOscillator.prototype.dispose = function(){
		Tone.Source.prototype.dispose.call(this);
		this._writable(["frequency", "detune"]);
		this.detune.dispose();
		this.detune = null;
		this.frequency.dispose();
		this.frequency = null;
		this._oscillator.dispose();
		this._oscillator = null;
		this._sourceType = null;
		return this;
	};

	return Tone.OmniOscillator;
});<|endoftext|>


<commit_before>// http://docs.couchdb.org/en/stable/api/index.html
// https://github.com/substack/tape#methods
'use strict'
const http = require('http')
const util = require('util')
//
const test = require('tape')
const db = require('../index')

const baseUrl = process.env.DB_URL || 'http://localhost:5984'
const prefix = 'testdb_' + Date.now() + '_'

function getName () {
  return prefix + Math.random().toString(36).slice(2, 8)
}

function checkResponse (t, response, status) {
  t.test(t.name, function (ts) {
    // this will only fire when t finishes
    ts.plan(6)
    ts.equal(Object.prototype.toString.call(response), '[object Object]', 'response is real object')
    ts.equal(typeof response.data, 'object', 'type of response.data is \'object\'')
    ts.equal(typeof response.message, 'string', 'type of response.message is \'string\'')
    ts.true(response.message, 'response.message is not empty')
    ts.equal(response.status, status, 'response.status is ' + status)
    ts.pass(response.message)
  })
  return response
}

test('url does not belong to a couchdb server', function (t) {
  t.plan(1)
  db.listDatabases('http://www.google.com')
  .catch(response => checkResponse(t, response, 500))
})

test('url with invalid protocol', function (t) {
  t.plan(1)
  db.listDatabases('ftp://www.google.com')
  .catch(response => checkResponse(t, response, 400))
})

test('getInfo()', function (t) {
  t.plan(1)
  db.getInfo(baseUrl)
  .then(response => checkResponse(t, response, 200))
  .catch(response => console.error(util.inspect(response)))
})

test('getUuids()', function (t) {
  t.plan(4)
  db.getUuids(baseUrl, 10)
  .then(response => checkResponse(t, response, 200))
  .then(response => {
    t.equal(Object.prototype.toString.call(response.data.uuids), '[object Array]', 'object is Array')
    t.equal(response.data.uuids.length, 10, 'array contains 10 elements')
    t.true(response.data.uuids[0].match(/^[a-z0-9]+$/), 'first element looks like a UUID')
  })
  .catch(response => console.error(util.inspect(response)))
})

test('listDatabases()', function (t) {
  t.plan(1)
  db.listDatabases(baseUrl)
  .then(response => checkResponse(t, response, 200))
  .catch(response => console.error(util.inspect(response)))
})

test('createDatabase()', function (t) {
  t.plan(1)
  const dbName = getName()
  db.createDatabase(baseUrl, dbName)
  .then(response => checkResponse(t, response, 201))
  .then(response => db.deleteDatabase(baseUrl, dbName))
  .catch(response => console.error(util.inspect(response)))
})

test('createDatabase() with special name', function (t) {
  t.plan(1)
  const dbName = getName() + '_$()+-/'
  db.createDatabase(baseUrl, dbName)
  .then(response => checkResponse(t, response, 201))
  .then(response => db.deleteDatabase(baseUrl, dbName))
  .catch(response => console.error(util.inspect(response)))
})

test('createDatabase() with error', function (t) {
  t.plan(2)
  const dbName = getName()
  db.createDatabase(baseUrl, dbName)
  .then(response => db.createDatabase(baseUrl, '%123'))   // invalid dbName
  .catch(response => checkResponse(t, response, 400))
  .then(response => db.createDatabase(baseUrl, dbName))   // db alredy exists
  .catch(response => checkResponse(t, response, 412))
  .then(response => db.deleteDatabase(baseUrl, dbName))
  .catch(response => console.error(util.inspect(response)))
})

test('deleteDatabase()', function (t) {
  t.plan(1)
  const dbName = getName()
  db.createDatabase(baseUrl, dbName)
  .then(response => db.deleteDatabase(baseUrl, dbName))
  .then(response => checkResponse(t, response, 200))
  .catch(response => console.error(util.inspect(response)))
})

test('deleteDatabase() with error', function (t) {
  t.plan(1)
  const dbName = getName()
  db.deleteDatabase(baseUrl, dbName)
  .catch(response => checkResponse(t, response, 404))   // not found
})

test('createDocument() without docId', function (t) {
  t.plan(1)
  const dbName = getName()
  const doc = {foo: 'bar'}
  db.createDatabase(baseUrl, dbName)
  .then(response => db.createDocument(baseUrl, dbName, doc))
  .then(response => checkResponse(t, response, 201))
  .then(response => db.deleteDatabase(baseUrl, dbName))
  .catch(response => console.error(util.inspect(response)))
})

test('createDocument() with docId', function (t) {
  t.plan(1)
  const dbName = getName()
  const doc = {foo: 'bar'}
  db.createDatabase(baseUrl, dbName)
  .then(response => db.createDocument(baseUrl, dbName, doc, 'doc'))
  .then(response => checkResponse(t, response, 201))
  .then(response => db.deleteDatabase(baseUrl, dbName))
  .catch(response => console.error(util.inspect(response)))
})

test('createDocument() with docId special name', function (t) {
  t.plan(1)
  const dbName = getName()
  const doc = {foo: 'bar'}
  db.createDatabase(baseUrl, dbName)
  .then(response => db.createDocument(baseUrl, dbName, doc, 'a_$() : + -/'))
  .then(response => checkResponse(t, response, 201))
  .then(response => db.deleteDatabase(baseUrl, dbName))
  .catch(response => console.error(util.inspect(response)))
})

test('createDocument() with docId with error', function (t) {
  t.plan(2)
  const dbName = getName()
  const doc = {foo: 'bar'}
  db.createDatabase(baseUrl, dbName)
  .then(response => db.createDocument(baseUrl, dbName, doc, 'doc'))
  .then(response => checkResponse(t, response, 201))
  .then(response => db.createDocument(baseUrl, dbName, doc, 'doc')) // conflict
  .catch(response => checkResponse(t, response, 409))
  .then(response => db.deleteDatabase(baseUrl, dbName))
  .catch(response => console.error(util.inspect(response)))
})

test('createDocument() update', function (t) {
  t.plan(2)
  const dbName = getName()
  const doc = {foo: 'bar'}
  db.createDatabase(baseUrl, dbName)
  .then(response => db.createDocument(baseUrl, dbName, doc, 'doc'))
  .then(response => db.getDocument(baseUrl, dbName, 'doc'))
  .then(response => checkResponse(t, response, 200))
  .then(response => {
    let doc = response.data
    doc.baz = 42
    return db.createDocument(baseUrl, dbName, doc, 'doc')
  })
  .then(response => checkResponse(t, response, 201))
  .then(response => db.deleteDatabase(baseUrl, dbName))
  .catch(response => console.error(util.inspect(response)))
})

test('deleteDocument()', function (t) {
  t.plan(2)
  const dbName = getName()
  const doc = {foo: 'bar'}
  db.createDatabase(baseUrl, dbName)
  .then(response => db.createDocument(baseUrl, dbName, doc, 'doc'))
  .then(response => db.getDocument(baseUrl, dbName, 'doc'))
  .then(response => checkResponse(t, response, 200))
  .then(response => db.deleteDocument(baseUrl, dbName, 'doc', response.data._rev))
  .then(response => checkResponse(t, response, 200))
  .then(response => db.deleteDatabase(baseUrl, dbName))
  .catch(response => console.error(util.inspect(response)))
})

test('getAllDocs()', function (t) {
  t.plan(3)
  const dbName = getName()
  db.createDatabase(baseUrl, dbName)
  .then(response => db.createDocument(baseUrl, dbName, {foo: 1}, 'doc1'))
  .then(response => db.createDocument(baseUrl, dbName, {bar: 2}, 'doc2'))
  .then(() => db.getAllDocs(baseUrl, dbName, {
    include_docs: true,
    descending: true
  }))
  .then(response => checkResponse(t, response, 200))
  .then(response => {
    t.true(response.data.total_rows === 2, 'total_rows is ok')
    t.equal(response.data.rows[0].id, 'doc2', 'query paramter decending ok')
  })
  .then(response => db.deleteDatabase(baseUrl, dbName))
  .catch(response => console.error(util.inspect(response)))
})

test('getDocument()', function (t) {
  t.plan(4)
  const dbName = getName()
  const doc = {foo: 'bar'}
  db.createDatabase(baseUrl, dbName)
  .then(response => db.createDocument(baseUrl, dbName, doc, 'doc'))
  .then(response => db.getDocument(baseUrl, dbName, 'doc'))
  .then(response => checkResponse(t, response, 200))
  .then(response => {
    let doc = response.data
    doc.baz = 42
    return db.createDocument(baseUrl, dbName, doc, 'doc')
  })
  .then(response => checkResponse(t, response, 201))
  .then(response => db.getDocument(baseUrl, dbName, 'doc', {rev: response.data.rev}))
  .then(response => checkResponse(t, response, 200))
  .then(response => t.equal(response.data.baz, 42), 'doc constains new property')
  .then(response => db.deleteDatabase(baseUrl, dbName))
  .catch(response => console.error(util.inspect(response)))
})

test('[create|delete|get]DesignDocument(), getDesignDocumentInfo(), getView()', function (t) {
  t.plan(6)
  const dbName = getName()
  const docId = 'doc1'
  const ddoc = {
    language: 'javascript',
    views: { all: { map: 'function (doc) {emit(null, doc.foo)}' } }
  }
  db.createDatabase(baseUrl, dbName)
  .then(response => db.createDocument(baseUrl, dbName, {foo: 'bar'}, 'doc1'))
  .then(response => db.createDocument(baseUrl, dbName, {foo: 'baz'}, 'doc2'))
  .then(response => db.createDesignDocument(baseUrl, dbName, ddoc, docId))
  .then(response => checkResponse(t, response, 201))
  .then(response => db.getView(baseUrl, dbName, docId, 'all', {descending: true}))
  .then(response => checkResponse(t, response, 200))
  .then(response => {
    t.true(response.data.total_rows, 2, 'number of rows returned')
    t.equal(response.data.rows[0].value, 'baz', 'row order')
    return response
  })
  .then(response => db.getDesignDocumentInfo(baseUrl, dbName, docId))
  .then(response => checkResponse(t, response, 200))
  .then(response => db.getDesignDocument(baseUrl, dbName, docId))
  .then(response => checkResponse(t, response, 200))
  .then(response => db.deleteDesignDocument(baseUrl, dbName, docId, response.data._rev))
  .then(response => checkResponse(t, response, 200))
  .then(response => db.deleteDatabase(baseUrl, dbName))
  .catch(response => console.error(util.inspect(response)))
})

test('setTimeout()', function (t) {
  const timeout = 1000
  const eps = 100
  const port = 47474
  const server = http.createServer().listen(port)
  t.plan(2)
  t.timeoutAfter(timeout + 2 * eps)
  db.setTimeout(timeout)
  const t0 = Date.now()
  db.getInfo('http://localhost:' + port)
  .catch(response => checkResponse(t, response, 500))
  .then(() => t.true(Date.now() - t0 < timeout + eps, 'time difference is ok'))
  .then(() => {
    server.close()
    db.setTimeout(10000)
  })
})

test('db server is clean', function (t) {
  t.plan(1)
  const re = new RegExp('^' + prefix)
  db.listDatabases(baseUrl)
  .then(response => response.data.find(e => re.test(e)) ? Promise.reject() : Promise.resolve())
  .catch(() => new Promise(function (resolve, reject) {
    // sleep 1 sec and try again
    setTimeout(() => resolve(), 1000)
  }))
  .then(() => db.listDatabases(baseUrl))
  .then(response => t.false(response.data.find(e => re.test(e)), 'all tempdb deleted'))
})
<commit_msg>fix number of tests<commit_after>// http://docs.couchdb.org/en/stable/api/index.html
// https://github.com/substack/tape#methods
'use strict'
const http = require('http')
const util = require('util')
//
const test = require('tape')
const db = require('../index')

const baseUrl = process.env.DB_URL || 'http://localhost:5984'
const prefix = 'testdb_' + Date.now() + '_'

function getName () {
  return prefix + Math.random().toString(36).slice(2, 8)
}

function checkResponse (t, response, status) {
  t.test(t.name, function (ts) {
    // this will only fire when t finishes
    ts.plan(6)
    ts.equal(Object.prototype.toString.call(response), '[object Object]', 'response is real object')
    ts.equal(typeof response.data, 'object', 'type of response.data is \'object\'')
    ts.equal(typeof response.message, 'string', 'type of response.message is \'string\'')
    ts.true(response.message, 'response.message is not empty')
    ts.equal(response.status, status, 'response.status is ' + status)
    ts.pass(response.message)
  })
  return response
}

test('url does not belong to a couchdb server', function (t) {
  t.plan(1)
  db.listDatabases('http://www.google.com')
  .catch(response => checkResponse(t, response, 500))
})

test('url with invalid protocol', function (t) {
  t.plan(1)
  db.listDatabases('ftp://www.google.com')
  .catch(response => checkResponse(t, response, 400))
})

test('getInfo()', function (t) {
  t.plan(1)
  db.getInfo(baseUrl)
  .then(response => checkResponse(t, response, 200))
  .catch(response => console.error(util.inspect(response)))
})

test('getUuids()', function (t) {
  t.plan(4)
  db.getUuids(baseUrl, 10)
  .then(response => checkResponse(t, response, 200))
  .then(response => {
    t.equal(Object.prototype.toString.call(response.data.uuids), '[object Array]', 'object is Array')
    t.equal(response.data.uuids.length, 10, 'array contains 10 elements')
    t.true(response.data.uuids[0].match(/^[a-z0-9]+$/), 'first element looks like a UUID')
  })
  .catch(response => console.error(util.inspect(response)))
})

test('listDatabases()', function (t) {
  t.plan(1)
  db.listDatabases(baseUrl)
  .then(response => checkResponse(t, response, 200))
  .catch(response => console.error(util.inspect(response)))
})

test('createDatabase()', function (t) {
  t.plan(1)
  const dbName = getName()
  db.createDatabase(baseUrl, dbName)
  .then(response => checkResponse(t, response, 201))
  .then(response => db.deleteDatabase(baseUrl, dbName))
  .catch(response => console.error(util.inspect(response)))
})

test('createDatabase() with special name', function (t) {
  t.plan(1)
  const dbName = getName() + '_$()+-/'
  db.createDatabase(baseUrl, dbName)
  .then(response => checkResponse(t, response, 201))
  .then(response => db.deleteDatabase(baseUrl, dbName))
  .catch(response => console.error(util.inspect(response)))
})

test('createDatabase() with error', function (t) {
  t.plan(2)
  const dbName = getName()
  db.createDatabase(baseUrl, dbName)
  .then(response => db.createDatabase(baseUrl, '%123'))   // invalid dbName
  .catch(response => checkResponse(t, response, 400))
  .then(response => db.createDatabase(baseUrl, dbName))   // db alredy exists
  .catch(response => checkResponse(t, response, 412))
  .then(response => db.deleteDatabase(baseUrl, dbName))
  .catch(response => console.error(util.inspect(response)))
})

test('deleteDatabase()', function (t) {
  t.plan(1)
  const dbName = getName()
  db.createDatabase(baseUrl, dbName)
  .then(response => db.deleteDatabase(baseUrl, dbName))
  .then(response => checkResponse(t, response, 200))
  .catch(response => console.error(util.inspect(response)))
})

test('deleteDatabase() with error', function (t) {
  t.plan(1)
  const dbName = getName()
  db.deleteDatabase(baseUrl, dbName)
  .catch(response => checkResponse(t, response, 404))   // not found
})

test('createDocument() without docId', function (t) {
  t.plan(1)
  const dbName = getName()
  const doc = {foo: 'bar'}
  db.createDatabase(baseUrl, dbName)
  .then(response => db.createDocument(baseUrl, dbName, doc))
  .then(response => checkResponse(t, response, 201))
  .then(response => db.deleteDatabase(baseUrl, dbName))
  .catch(response => console.error(util.inspect(response)))
})

test('createDocument() with docId', function (t) {
  t.plan(1)
  const dbName = getName()
  const doc = {foo: 'bar'}
  db.createDatabase(baseUrl, dbName)
  .then(response => db.createDocument(baseUrl, dbName, doc, 'doc'))
  .then(response => checkResponse(t, response, 201))
  .then(response => db.deleteDatabase(baseUrl, dbName))
  .catch(response => console.error(util.inspect(response)))
})

test('createDocument() with docId special name', function (t) {
  t.plan(1)
  const dbName = getName()
  const doc = {foo: 'bar'}
  db.createDatabase(baseUrl, dbName)
  .then(response => db.createDocument(baseUrl, dbName, doc, 'a_$() : + -/'))
  .then(response => checkResponse(t, response, 201))
  .then(response => db.deleteDatabase(baseUrl, dbName))
  .catch(response => console.error(util.inspect(response)))
})

test('createDocument() with docId with error', function (t) {
  t.plan(2)
  const dbName = getName()
  const doc = {foo: 'bar'}
  db.createDatabase(baseUrl, dbName)
  .then(response => db.createDocument(baseUrl, dbName, doc, 'doc'))
  .then(response => checkResponse(t, response, 201))
  .then(response => db.createDocument(baseUrl, dbName, doc, 'doc')) // conflict
  .catch(response => checkResponse(t, response, 409))
  .then(response => db.deleteDatabase(baseUrl, dbName))
  .catch(response => console.error(util.inspect(response)))
})

test('createDocument() update', function (t) {
  t.plan(2)
  const dbName = getName()
  const doc = {foo: 'bar'}
  db.createDatabase(baseUrl, dbName)
  .then(response => db.createDocument(baseUrl, dbName, doc, 'doc'))
  .then(response => db.getDocument(baseUrl, dbName, 'doc'))
  .then(response => checkResponse(t, response, 200))
  .then(response => {
    let doc = response.data
    doc.baz = 42
    return db.createDocument(baseUrl, dbName, doc, 'doc')
  })
  .then(response => checkResponse(t, response, 201))
  .then(response => db.deleteDatabase(baseUrl, dbName))
  .catch(response => console.error(util.inspect(response)))
})

test('deleteDocument()', function (t) {
  t.plan(2)
  const dbName = getName()
  const doc = {foo: 'bar'}
  db.createDatabase(baseUrl, dbName)
  .then(response => db.createDocument(baseUrl, dbName, doc, 'doc'))
  .then(response => db.getDocument(baseUrl, dbName, 'doc'))
  .then(response => checkResponse(t, response, 200))
  .then(response => db.deleteDocument(baseUrl, dbName, 'doc', response.data._rev))
  .then(response => checkResponse(t, response, 200))
  .then(response => db.deleteDatabase(baseUrl, dbName))
  .catch(response => console.error(util.inspect(response)))
})

test('getAllDocs()', function (t) {
  t.plan(3)
  const dbName = getName()
  db.createDatabase(baseUrl, dbName)
  .then(response => db.createDocument(baseUrl, dbName, {foo: 1}, 'doc1'))
  .then(response => db.createDocument(baseUrl, dbName, {bar: 2}, 'doc2'))
  .then(() => db.getAllDocs(baseUrl, dbName, {
    include_docs: true,
    descending: true
  }))
  .then(response => checkResponse(t, response, 200))
  .then(response => {
    t.true(response.data.total_rows === 2, 'total_rows is ok')
    t.equal(response.data.rows[0].id, 'doc2', 'query paramter decending ok')
  })
  .then(response => db.deleteDatabase(baseUrl, dbName))
  .catch(response => console.error(util.inspect(response)))
})

test('getDocument()', function (t) {
  t.plan(4)
  const dbName = getName()
  const doc = {foo: 'bar'}
  db.createDatabase(baseUrl, dbName)
  .then(response => db.createDocument(baseUrl, dbName, doc, 'doc'))
  .then(response => db.getDocument(baseUrl, dbName, 'doc'))
  .then(response => checkResponse(t, response, 200))
  .then(response => {
    let doc = response.data
    doc.baz = 42
    return db.createDocument(baseUrl, dbName, doc, 'doc')
  })
  .then(response => checkResponse(t, response, 201))
  .then(response => db.getDocument(baseUrl, dbName, 'doc', {rev: response.data.rev}))
  .then(response => checkResponse(t, response, 200))
  .then(response => t.equal(response.data.baz, 42), 'doc constains new property')
  .then(response => db.deleteDatabase(baseUrl, dbName))
  .catch(response => console.error(util.inspect(response)))
})

test('[create|delete|get]DesignDocument(), getDesignDocumentInfo(), getView()', function (t) {
  t.plan(7)
  const dbName = getName()
  const docId = 'doc1'
  const ddoc = {
    language: 'javascript',
    views: { all: { map: 'function (doc) {emit(null, doc.foo)}' } }
  }
  db.createDatabase(baseUrl, dbName)
  .then(response => db.createDocument(baseUrl, dbName, {foo: 'bar'}, 'doc1'))
  .then(response => db.createDocument(baseUrl, dbName, {foo: 'baz'}, 'doc2'))
  .then(response => db.createDesignDocument(baseUrl, dbName, ddoc, docId))
  .then(response => checkResponse(t, response, 201))
  .then(response => db.getView(baseUrl, dbName, docId, 'all', {descending: true}))
  .then(response => checkResponse(t, response, 200))
  .then(response => {
    t.true(response.data.total_rows, 2, 'number of rows returned')
    t.equal(response.data.rows[0].value, 'baz', 'row order')
    return response
  })
  .then(response => db.getDesignDocumentInfo(baseUrl, dbName, docId))
  .then(response => checkResponse(t, response, 200))
  .then(response => db.getDesignDocument(baseUrl, dbName, docId))
  .then(response => checkResponse(t, response, 200))
  .then(response => db.deleteDesignDocument(baseUrl, dbName, docId, response.data._rev))
  .then(response => checkResponse(t, response, 200))
  .then(response => db.deleteDatabase(baseUrl, dbName))
  .catch(response => console.error(util.inspect(response)))
})

test('setTimeout()', function (t) {
  const timeout = 1000
  const eps = 100
  const port = 47474
  const server = http.createServer().listen(port)
  t.plan(2)
  t.timeoutAfter(timeout + 2 * eps)
  db.setTimeout(timeout)
  const t0 = Date.now()
  db.getInfo('http://localhost:' + port)
  .catch(response => checkResponse(t, response, 500))
  .then(() => t.true(Date.now() - t0 < timeout + eps, 'time difference is ok'))
  .then(() => {
    server.close()
    db.setTimeout(10000)
  })
})

test('db server is clean', function (t) {
  t.plan(1)
  const re = new RegExp('^' + prefix)
  db.listDatabases(baseUrl)
  .then(response => response.data.find(e => re.test(e)) ? Promise.reject() : Promise.resolve())
  .catch(() => new Promise(function (resolve, reject) {
    // sleep 1 sec and try again
    setTimeout(() => resolve(), 1000)
  }))
  .then(() => db.listDatabases(baseUrl))
  .then(response => t.false(response.data.find(e => re.test(e)), 'all tempdb deleted'))
})
<|endoftext|>


<commit_before>require(["react", "util", "models", "apiclient", "storage", "downloads", "cache", "minify", "notifications", "status"],
        function(React, Util, models, APIClient, Storage, Downloads, Cache, Minify, Notifications, Status) {

    // Languages in which topic trees should be tested for
    var languages = ["en", "fr", "es", "pt"];
    QUnit.asyncTest("testUtil", function(assert) {
        assert.strictEqual(Util.numberWithCommas("1234567890"),"1,234,567,890");
        var oneAdder = Util.partial(function(x, y) { return x + y; }, 1);
        assert.strictEqual(oneAdder(5), 6);
        assert.strictEqual(window.x, undefined);
        assert.strictEqual(Util.appendQueryParam("http://test.com?a=b", "x", "y"), "http://test.com?a=b&x=y");
        assert.strictEqual(Util.appendQueryParam("http://test.com", "x", "y"), "http://test.com?x=y");
        assert.strictEqual(Util.getParameterByName("a", "?a=b"), "b");
        assert.strictEqual(Util.getParameterByName("a", "?a=b&c=d"), "b");
        assert.strictEqual(Util.getParameterByName("c", "?a=b&c=d"), "d");
        var old = navigator.connection;
        if (!navigator.connection) {
            navigator.connection = { metered: false, bandwidth: Infinity };
            assert.strictEqual(Util.isMeteredConnection(), false);
            assert.strictEqual(Util.isBandwidthCapped(), false);
            navigator.connection = { metered: true, bandwidth: 33};
            assert.strictEqual(Util.isMeteredConnection(), true);
            assert.strictEqual(Util.isBandwidthCapped(), true);
            navigator.connection = { metered: false, bandwidth: 33};
            assert.strictEqual(Util.isMeteredConnection(), false);
            assert.strictEqual(Util.isBandwidthCapped(), true);
        }
        navigator.connection = old;
        Util.loadScript("/test/_test1.js").done(function() {
            assert.strictEqual(window.x, 3);
            QUnit.start();
        });
    });

    QUnit.test("testLocalization", function(assert) {
        document.webL10n.setAsyncLoading(false);
        document.webL10n.setExactLangOnly(true);
        var enDict = document.webL10n.getData();
        var otherLanguages = languages.slice(1);

        // Make sure each localization file has an associated string
        otherLanguages.forEach(function(lang) {
            document.webL10n.setLanguage(lang);
            for (var s in enDict) {
                if (enDict.hasOwnProperty(s)) {

                    var translated = document.webL10n.get(s);
                    if (!translated) {
                        console.error("Not localized! lang: %s, prop: %s, en-associated: %o",
                            lang, s, enDict[s], lang);
                    }
                    assert.ok(translated.length);
                }
            }
        });
    });

    QUnit.asyncTest("APIClient.init", function(assert) {
        expect(5);
        APIClient.init().done(function() {
            // Consumer key and secret should be available after init
            assert.ok(APIClient.oauth.consumerKey);
            assert.ok(APIClient.oauth.consumerSecret);
            APIClient.getTopicTree().done(function() {
                assert.ok(true);
                return APIClient.getVideoTranscript();
            }).then(function() {
                assert.ok(true);
                return APIClient.getVideoTranscript();
            }).done(function() {
                assert.ok(true);
                QUnit.start();
            });
        });
    });

    QUnit.asyncTest("models.TopicTree.init", function(assert) {

        // Helper method for validating a valid topic
        var assertValidTopic = (t) => {
            assert.ok(t.isTopic());
            assert.ok(!t.isVideoList());
            assert.ok(!t.isVideo());
            assert.ok(!t.isArticleList());
            assert.ok(!t.isArticle());
            assert.ok(!t.isContent());
            assert.ok(!t.isContentList());
            assert.strictEqual(t.getKind(), "Topic");
        };

        // Helper method for validating a validcontent item
        var assertValidContent = (c) => {
            assert.ok(!c.isTopic());
            assert.ok(!c.isVideoList());
            assert.ok(c.isVideo() ^ c.isArticle());
            assert.ok(!c.isArticleList());
            assert.ok(c.isContent());
            assert.ok(!c.isContentList());
            assert.ok(c.getParentDomain());
            assert.ok(!c.isRoot());
            assert.ok(!c.isRootChild());
            if (c.isVideo()) {
                assert.strictEqual(c.getKind(), "Video");
            } else if (c.isArticle()) {
                assert.strictEqual(c.getKind(), "Article");
            }
        };

        var promise = $.Deferred().resolve().promise();
        languages.forEach((lang) => {

            promise = promise.then(function() {
                var stub = sinon.stub(Util, "getLang", function() {
                    if (lang === "en") {
                        return null;
                    }
                    return lang;
                });
                var p = models.TopicTree.init();
                Util.getLang.restore();
                return p;
            }).then(function() {

                var root = models.TopicTree.root;
                assert.ok(root);
                assert.strictEqual(root.getTitle(), "Khan Academy");
                assert.ok(!root.getParentDomain());
                assert.ok(root.isRoot());
                assert.ok(!root.getParent());
                assertValidTopic(root);

                // Topics are at root
                assert.ok(models.TopicTree.root.get("topics").models.length > 0);
                _(models.TopicTree.root.get("topics").models).each((m) => {
                    assert.ok(m.getParentDomain());
                    assert.ok(!m.isRoot());
                    assert.ok(m.getParent());
                    assertValidTopic(m);
                });

                assert.ok(models.TopicTree.allContentItems.length > 0);
                _(models.TopicTree.allContentItems).each((c) => {
                    assertValidContent(c);
                });

                // But there are no content items at root
                assert.ok(models.TopicTree.root.get("contentItems").models.length === 0);
                assert.strictEqual(models.TopicTree.root.findContentItems("math", 1).length, 1);
                var results = models.TopicTree.root.findContentItems("math", 2);
                assert.strictEqual(results.length, 2);
                assert.notStrictEqual(results[0], results[1]);

            });
        });
        promise.done(() => {
            QUnit.start();
        });
    });
    QUnit.asyncTest("models.CurrentUser.init", function(assert) {
        expect(1);
        models.CurrentUser.init().done(function() {
            assert.ok(models.CurrentUser.initialized);
            QUnit.start();
        });
    });
    QUnit.asyncTest("models.AppOptions.fetch", function(assert) {
        expect(1);
        models.AppOptions.fetch().done(function() {
            assert.ok(models.AppOptions.get("showDownloadsOnly") === false);
            QUnit.start();
        });
    });
    QUnit.asyncTest("Storage.init", function(assert) {
        expect(1);
        Storage.init().then(function() {
            if (!Util.isFirefoxOS()) {
                assert.ok(true);
                QUnit.start();
                return;
            }
            return Storage.writeText("test-file", "test");
        }).then(function() {
            return Storage.readText("test-file");
        }).done(function(result) {
            console.log('did the test!!!');
            assert.strictEqual(result, "test");
            QUnit.start();
        });
    });
    QUnit.asyncTest("Downloads.init", function(assert) {
        expect(1);
        Downloads.init().done(function() {
            assert.ok(true);
            QUnit.start();
        });
    });
    QUnit.asyncTest("Status.start, stop, update", function(assert) {
        expect(6);
        assert.ok(!models.TempAppState.get("showingStatus"));
        Status.start();
        assert.strictEqual(models.TempAppState.get("showingStatus"), true);
        var message = "hello world!";
        Status.update(message);
        assert.strictEqual(models.TempAppState.get("status"), message);
        message = "changed message!";
        Status.update(message);
        assert.strictEqual(models.TempAppState.get("status"), message);
        Status.stop();
        setTimeout(function() {
            assert.strictEqual(models.TempAppState.get("status"), "");
            assert.strictEqual(models.TempAppState.get("showingStatus"), false);
            QUnit.start();
        });
    });
    QUnit.asyncTest("Cache.init", function(assert) {
        expect(2);
        Cache.heartbeatInterval = 100;
        var count = 0;
        sinon.stub(Cache, "heartbeat", function() {
            ++count;
            if (count >= 3) {
                assert.ok(true);
                window.clearInterval(Cache.timer);
                Cache.heartbeat.restore();
                QUnit.start();
            }
        });
        Cache.init().done(function() {
            assert.ok(Cache.timer);
        });
    });
    QUnit.test("Notifications.info", function(assert) {
        var notificationPropExists = !!window.Notification;
        window.Notification = window.Notification || function() {};
        var title = "title";
        var message = "message";
        sinon.stub(window, "Notification", function(t, m) {
            assert.strictEqual(t, title);
            assert.strictEqual(m.body, message);
        });
        Notifications.info(title, message);
        if (notificationPropExists) {
            window.Notification.restore();
        } else {
            delete window.Notification;
        }
    });
});
<commit_msg>Add tests for APIClient methods<commit_after>require(["react", "util", "models", "apiclient", "storage", "downloads", "cache", "minify", "notifications", "status"],
        function(React, Util, models, APIClient, Storage, Downloads, Cache, Minify, Notifications, Status) {

    QUnit.asyncTest("test APIClient calls the right things", function(assert) {

        APIClient.init().done(function() {
            sinon.stub(APIClient, "_basicAPICall", function(url, extraParams, method, dataType) {
                console.log('basic api called here: ' + url);
                return  $.Deferred().resolve({
                    url: url,
                    extraParams: extraParams ? JSON.stringify(extraParams) : "",
                    method: method || "GET",
                    dataType: dataType}).promise();
            });
            APIClient.getUserProgress().then(function(result) {
                assert.strictEqual("https://www.khanacademy.org/api/v1/user/progress_summary", result.url);
                assert.strictEqual(result.method, "GET");
                assert.strictEqual(result.extraParams, "{\"kind\":\"Video,Article\"}");
                return APIClient.getUserInfo();
            }).then(function(result) {
                assert.strictEqual("https://www.khanacademy.org/api/v1/user", result.url);
                assert.strictEqual(result.method, "GET");
                assert.strictEqual(result.extraParams, "");
                return APIClient.getInstalledTopicTree(false);
            }).then(function(result) {
                assert.strictEqual("/data/topic-tree.min.json", result.url);
                assert.strictEqual(result.method, "GET");
                assert.strictEqual(result.extraParams, "");
                return APIClient.getInstalledTopicTree(true);
            }).then(function(result) {
                assert.strictEqual("/data/topic-tree.min.js", result.url);
                assert.strictEqual(result.extraParams, "");
                return APIClient.getTopicTree();
            }).then(function(result) {
                assert.strictEqual("https://www.khanacademy.org/api/v1/fxos/topictree", result.url);
                assert.strictEqual(result.method, "GET");
                assert.strictEqual(result.extraParams, "");
                return APIClient.getVideoTranscript('abcd');
            }).then(function(result) {
                assert.strictEqual("https://www.khanacademy.org/api/v1/videos/abcd/transcript", result.url);
                assert.strictEqual(result.method, "GET");
                assert.strictEqual(result.extraParams, "");
                return APIClient.getArticle(54);
            }).then(function(result) {
                assert.strictEqual("https://www.khanacademy.org/api/v1/articles/54", result.url);
                assert.strictEqual(result.method, "GET");
                assert.strictEqual(result.extraParams, "");
                return APIClient.reportArticleRead(54);
            }).then(function(result) {
                assert.strictEqual("https://www.khanacademy.org/api/v1/user/article/54/log", result.url);
                assert.strictEqual(result.method, "POST");
                assert.strictEqual(result.extraParams, "");
                return APIClient.getUserVideos();
            }).then(function(result) {
                assert.strictEqual("https://www.khanacademy.org/api/v1/user/videos", result.url);
                assert.strictEqual(result.method, "GET");
                assert.strictEqual(result.extraParams, "");
                return APIClient.getUserVideos();
            }).then(function(result) {
                assert.strictEqual("https://www.khanacademy.org/api/v1/user/videos", result.url);
                assert.strictEqual(result.method, "GET");
                assert.strictEqual(result.extraParams, "");
                return APIClient.reportVideoProgress(1,2,3,4,5);
            }).done(function(result) {
                assert.strictEqual("https://www.khanacademy.org/api/v1/user/videos/2/log", result.url);
                assert.strictEqual(result.method, "POST");
                assert.strictEqual(result.extraParams, "{\"seconds_watched\":\"4\",\"last_second_watched\":\"5\"}");
                APIClient._basicAPICall.restore();
                QUnit.start();
            });
        });
    });

    // Languages in which topic trees should be tested for
    var languages = ["en", "fr", "es", "pt"];
    QUnit.asyncTest("testUtil", function(assert) {
        assert.strictEqual(Util.numberWithCommas("1234567890"),"1,234,567,890");
        var oneAdder = Util.partial(function(x, y) { return x + y; }, 1);
        assert.strictEqual(oneAdder(5), 6);
        assert.strictEqual(window.x, undefined);
        assert.strictEqual(Util.appendQueryParam("http://test.com?a=b", "x", "y"), "http://test.com?a=b&x=y");
        assert.strictEqual(Util.appendQueryParam("http://test.com", "x", "y"), "http://test.com?x=y");
        assert.strictEqual(Util.getParameterByName("a", "?a=b"), "b");
        assert.strictEqual(Util.getParameterByName("a", "?a=b&c=d"), "b");
        assert.strictEqual(Util.getParameterByName("c", "?a=b&c=d"), "d");
        var old = navigator.connection;
        if (!navigator.connection) {
            navigator.connection = { metered: false, bandwidth: Infinity };
            assert.strictEqual(Util.isMeteredConnection(), false);
            assert.strictEqual(Util.isBandwidthCapped(), false);
            navigator.connection = { metered: true, bandwidth: 33};
            assert.strictEqual(Util.isMeteredConnection(), true);
            assert.strictEqual(Util.isBandwidthCapped(), true);
            navigator.connection = { metered: false, bandwidth: 33};
            assert.strictEqual(Util.isMeteredConnection(), false);
            assert.strictEqual(Util.isBandwidthCapped(), true);
        }
        navigator.connection = old;
        Util.loadScript("/test/_test1.js").done(function() {
            assert.strictEqual(window.x, 3);
            QUnit.start();
        });
    });

    QUnit.test("testLocalization", function(assert) {
        document.webL10n.setAsyncLoading(false);
        document.webL10n.setExactLangOnly(true);
        var enDict = document.webL10n.getData();
        var otherLanguages = languages.slice(1);

        // Make sure each localization file has an associated string
        otherLanguages.forEach(function(lang) {
            document.webL10n.setLanguage(lang);
            for (var s in enDict) {
                if (enDict.hasOwnProperty(s)) {

                    var translated = document.webL10n.get(s);
                    if (!translated) {
                        console.error("Not localized! lang: %s, prop: %s, en-associated: %o",
                            lang, s, enDict[s], lang);
                    }
                    assert.ok(translated.length);
                }
            }
        });
    });

    QUnit.asyncTest("APIClient.init", function(assert) {
        expect(5);
        APIClient.init().done(function() {
            // Consumer key and secret should be available after init
            assert.ok(APIClient.oauth.consumerKey);
            assert.ok(APIClient.oauth.consumerSecret);
            APIClient.getTopicTree().done(function() {
                assert.ok(true);
                return APIClient.getVideoTranscript();
            }).then(function() {
                assert.ok(true);
                return APIClient.getVideoTranscript();
            }).done(function() {
                assert.ok(true);
                QUnit.start();
            });
        });
    });

    QUnit.asyncTest("models.TopicTree.init", function(assert) {

        // Helper method for validating a valid topic
        var assertValidTopic = (t) => {
            assert.ok(t.isTopic());
            assert.ok(!t.isVideoList());
            assert.ok(!t.isVideo());
            assert.ok(!t.isArticleList());
            assert.ok(!t.isArticle());
            assert.ok(!t.isContent());
            assert.ok(!t.isContentList());
            assert.strictEqual(t.getKind(), "Topic");
        };

        // Helper method for validating a validcontent item
        var assertValidContent = (c) => {
            assert.ok(!c.isTopic());
            assert.ok(!c.isVideoList());
            assert.ok(c.isVideo() ^ c.isArticle());
            assert.ok(!c.isArticleList());
            assert.ok(c.isContent());
            assert.ok(!c.isContentList());
            assert.ok(c.getParentDomain());
            assert.ok(!c.isRoot());
            assert.ok(!c.isRootChild());
            if (c.isVideo()) {
                assert.strictEqual(c.getKind(), "Video");
            } else if (c.isArticle()) {
                assert.strictEqual(c.getKind(), "Article");
            }
        };

        var promise = $.Deferred().resolve().promise();
        languages.forEach((lang) => {

            promise = promise.then(function() {
                var stub = sinon.stub(Util, "getLang", function() {
                    if (lang === "en") {
                        return null;
                    }
                    return lang;
                });
                var p = models.TopicTree.init();
                Util.getLang.restore();
                return p;
            }).then(function() {

                var root = models.TopicTree.root;
                assert.ok(root);
                assert.strictEqual(root.getTitle(), "Khan Academy");
                assert.ok(!root.getParentDomain());
                assert.ok(root.isRoot());
                assert.ok(!root.getParent());
                assertValidTopic(root);

                // Topics are at root
                assert.ok(models.TopicTree.root.get("topics").models.length > 0);
                _(models.TopicTree.root.get("topics").models).each((m) => {
                    assert.ok(m.getParentDomain());
                    assert.ok(!m.isRoot());
                    assert.ok(m.getParent());
                    assertValidTopic(m);
                });

                assert.ok(models.TopicTree.allContentItems.length > 0);
                _(models.TopicTree.allContentItems).each((c) => {
                    assertValidContent(c);
                });

                // But there are no content items at root
                assert.ok(models.TopicTree.root.get("contentItems").models.length === 0);
                assert.strictEqual(models.TopicTree.root.findContentItems("math", 1).length, 1);
                var results = models.TopicTree.root.findContentItems("math", 2);
                assert.strictEqual(results.length, 2);
                assert.notStrictEqual(results[0], results[1]);

            });
        });
        promise.done(() => {
            QUnit.start();
        });
    });
    QUnit.asyncTest("models.CurrentUser.init", function(assert) {
        expect(1);
        models.CurrentUser.init().done(function() {
            assert.ok(models.CurrentUser.initialized);
            QUnit.start();
        });
    });
    QUnit.asyncTest("models.AppOptions.fetch", function(assert) {
        expect(1);
        models.AppOptions.fetch().done(function() {
            assert.ok(models.AppOptions.get("showDownloadsOnly") === false);
            QUnit.start();
        });
    });
    QUnit.asyncTest("Storage.init", function(assert) {
        expect(1);
        Storage.init().then(function() {
            if (!Util.isFirefoxOS()) {
                assert.ok(true);
                QUnit.start();
                return;
            }
            return Storage.writeText("test-file", "test");
        }).then(function() {
            return Storage.readText("test-file");
        }).done(function(result) {
            console.log('did the test!!!');
            assert.strictEqual(result, "test");
            QUnit.start();
        });
    });
    QUnit.asyncTest("Downloads.init", function(assert) {
        expect(1);
        Downloads.init().done(function() {
            assert.ok(true);
            QUnit.start();
        });
    });
    QUnit.asyncTest("Status.start, stop, update", function(assert) {
        expect(6);
        assert.ok(!models.TempAppState.get("showingStatus"));
        Status.start();
        assert.strictEqual(models.TempAppState.get("showingStatus"), true);
        var message = "hello world!";
        Status.update(message);
        assert.strictEqual(models.TempAppState.get("status"), message);
        message = "changed message!";
        Status.update(message);
        assert.strictEqual(models.TempAppState.get("status"), message);
        Status.stop();
        setTimeout(function() {
            assert.strictEqual(models.TempAppState.get("status"), "");
            assert.strictEqual(models.TempAppState.get("showingStatus"), false);
            QUnit.start();
        });
    });
    QUnit.asyncTest("Cache.init", function(assert) {
        expect(2);
        Cache.heartbeatInterval = 100;
        var count = 0;
        sinon.stub(Cache, "heartbeat", function() {
            ++count;
            if (count >= 3) {
                assert.ok(true);
                window.clearInterval(Cache.timer);
                Cache.heartbeat.restore();
                QUnit.start();
            }
        });
        Cache.init().done(function() {
            assert.ok(Cache.timer);
        });
    });
    QUnit.test("Notifications.info", function(assert) {
        var notificationPropExists = !!window.Notification;
        window.Notification = window.Notification || function() {};
        var title = "title";
        var message = "message";
        sinon.stub(window, "Notification", function(t, m) {
            assert.strictEqual(t, title);
            assert.strictEqual(m.body, message);
        });
        Notifications.info(title, message);
        if (notificationPropExists) {
            window.Notification.restore();
        } else {
            delete window.Notification;
        }
    });
});
<|endoftext|>