<commit_before>import * as utils from './utils';
import baseLogger from './logger';

class Interpolator {
  constructor(options = {}) {
    this.logger = baseLogger.create('interpolator');

    this.init(options, true);
  }

  /* eslint no-param-reassign: 0 */
  init(options = {}, reset) {
    if (reset) {
      this.options = options;
      this.format = (options.interpolation && options.interpolation.format) || (value => value);
      this.escape = (options.interpolation && options.interpolation.escape) || utils.escape;
    }
    if (!options.interpolation) options.interpolation = { escapeValue: true };

    const iOpts = options.interpolation;

    this.escapeValue = iOpts.escapeValue !== undefined ? iOpts.escapeValue : true;

    this.prefix = iOpts.prefix ? utils.regexEscape(iOpts.prefix) : iOpts.prefixEscaped || '{{';
    this.suffix = iOpts.suffix ? utils.regexEscape(iOpts.suffix) : iOpts.suffixEscaped || '}}';

    this.formatSeparator = iOpts.formatSeparator ? iOpts.formatSeparator : iOpts.formatSeparator || ',';

    this.unescapePrefix = iOpts.unescapeSuffix ? '' : iOpts.unescapePrefix || '-';
    this.unescapeSuffix = this.unescapePrefix ? '' : iOpts.unescapeSuffix || '';

    this.nestingPrefix = iOpts.nestingPrefix ? utils.regexEscape(iOpts.nestingPrefix) : iOpts.nestingPrefixEscaped || utils.regexEscape('$t(');
    this.nestingSuffix = iOpts.nestingSuffix ? utils.regexEscape(iOpts.nestingSuffix) : iOpts.nestingSuffixEscaped || utils.regexEscape(')');

    this.maxReplaces = iOpts.maxReplaces ? iOpts.maxReplaces : 1000;

    // the regexp
    this.resetRegExp();
  }

  reset() {
    if (this.options) this.init(this.options);
  }

  resetRegExp() {
    // the regexp
    const regexpStr = `${this.prefix}(.+?)${this.suffix}`;
    this.regexp = new RegExp(regexpStr, 'g');

    const regexpUnescapeStr = `${this.prefix}${this.unescapePrefix}(.+?)${this.unescapeSuffix}${this.suffix}`;
    this.regexpUnescape = new RegExp(regexpUnescapeStr, 'g');

    const nestingRegexpStr = `${this.nestingPrefix}(.+?)${this.nestingSuffix}`;
    this.nestingRegexp = new RegExp(nestingRegexpStr, 'g');
  }

  interpolate(str, data, lng) {
    let match;
    let value;
    let replaces;

    function regexSafe(val) {
      return val.replace(/\$/g, '$$$$');
    }

    const handleFormat = (key) => {
      if (key.indexOf(this.formatSeparator) < 0) return utils.getPath(data, key);

      const p = key.split(this.formatSeparator);
      const k = p.shift().trim();
      const f = p.join(this.formatSeparator).trim();

      return this.format(utils.getPath(data, k), f, lng);
    };

    this.resetRegExp();

    replaces = 0;
    // unescape if has unescapePrefix/Suffix
    /* eslint no-cond-assign: 0 */
    while (match = this.regexpUnescape.exec(str)) {
      value = handleFormat(match[1].trim());
      str = str.replace(match[0], value);
      this.regexpUnescape.lastIndex = 0;
      replaces++;
      if(replaces >= this.maxReplaces) {
        break;
      }
    }

    replaces = 0;
    // regular escape on demand
    while (match = this.regexp.exec(str)) {
      value = handleFormat(match[1].trim());
      if (typeof value !== 'string') value = utils.makeString(value);
      if (!value) {
        this.logger.warn(`missed to pass in variable ${match[1]} for interpolating ${str}`);
        value = '';
      }
      value = this.escapeValue ? regexSafe(this.escape(value)) : regexSafe(value);
      str = str.replace(match[0], value);
      this.regexp.lastIndex = 0;
      replaces++;
      if(replaces >= this.maxReplaces) {
        break;
      }
    }
    return str;
  }

  nest(str, fc, options = {}) {
    let match;
    let value;

    let clonedOptions = { ...options };
    clonedOptions.applyPostProcessor = false; // avoid post processing on nested lookup

    // if value is something like "myKey": "lorem $(anotherKey, { "count": {{aValueInOptions}} })"
    function handleHasOptions(key) {
      if (key.indexOf(',') < 0) return key;

      const p = key.split(',');
      key = p.shift();
      let optionsString = p.join(',');
      optionsString = this.interpolate(optionsString, clonedOptions);
      optionsString = optionsString.replace(/'/g, '"');

      try {
        clonedOptions = JSON.parse(optionsString);
      } catch (e) {
        this.logger.error(`failed parsing options string in nesting for key ${key}`, e);
      }

      return key;
    }

    // regular escape on demand
    while (match = this.nestingRegexp.exec(str)) {
      value = fc(handleHasOptions.call(this, match[1].trim()), clonedOptions);

      // is only the nesting key (key1 = '$(key2)') return the value without stringify
      if (value && match[0] === str && typeof value !== 'string') return value;

      // no string to include or empty
      if (typeof value !== 'string') value = utils.makeString(value);
      if (!value) {
        this.logger.warn(`missed to resolve ${match[1]} for nesting ${str}`);
        value = '';
      }
      // Nested keys should not be escaped by default #854
      // value = this.escapeValue ? regexSafe(utils.escape(value)) : regexSafe(value);
      str = str.replace(match[0], value);
      this.regexp.lastIndex = 0;
    }
    return str;
  }
}

export default Interpolator;
<commit_msg>style fixes<commit_after>import * as utils from './utils';
import baseLogger from './logger';

class Interpolator {
  constructor(options = {}) {
    this.logger = baseLogger.create('interpolator');

    this.init(options, true);
  }

  /* eslint no-param-reassign: 0 */
  init(options = {}, reset) {
    if (reset) {
      this.options = options;
      this.format = (options.interpolation && options.interpolation.format) || (value => value);
      this.escape = (options.interpolation && options.interpolation.escape) || utils.escape;
    }
    if (!options.interpolation) options.interpolation = { escapeValue: true };

    const iOpts = options.interpolation;

    this.escapeValue = iOpts.escapeValue !== undefined ? iOpts.escapeValue : true;

    this.prefix = iOpts.prefix ? utils.regexEscape(iOpts.prefix) : iOpts.prefixEscaped || '{{';
    this.suffix = iOpts.suffix ? utils.regexEscape(iOpts.suffix) : iOpts.suffixEscaped || '}}';

    this.formatSeparator = iOpts.formatSeparator ? iOpts.formatSeparator : iOpts.formatSeparator || ',';

    this.unescapePrefix = iOpts.unescapeSuffix ? '' : iOpts.unescapePrefix || '-';
    this.unescapeSuffix = this.unescapePrefix ? '' : iOpts.unescapeSuffix || '';

    this.nestingPrefix = iOpts.nestingPrefix ? utils.regexEscape(iOpts.nestingPrefix) : iOpts.nestingPrefixEscaped || utils.regexEscape('$t(');
    this.nestingSuffix = iOpts.nestingSuffix ? utils.regexEscape(iOpts.nestingSuffix) : iOpts.nestingSuffixEscaped || utils.regexEscape(')');

    this.maxReplaces = iOpts.maxReplaces ? iOpts.maxReplaces : 1000;
    // the regexp
    this.resetRegExp();
  }

  reset() {
    if (this.options) this.init(this.options);
  }

  resetRegExp() {
    // the regexp
    const regexpStr = `${this.prefix}(.+?)${this.suffix}`;
    this.regexp = new RegExp(regexpStr, 'g');

    const regexpUnescapeStr = `${this.prefix}${this.unescapePrefix}(.+?)${this.unescapeSuffix}${this.suffix}`;
    this.regexpUnescape = new RegExp(regexpUnescapeStr, 'g');

    const nestingRegexpStr = `${this.nestingPrefix}(.+?)${this.nestingSuffix}`;
    this.nestingRegexp = new RegExp(nestingRegexpStr, 'g');
  }

  interpolate(str, data, lng) {
    let match;
    let value;
    let replaces;

    function regexSafe(val) {
      return val.replace(/\$/g, '$$$$');
    }

    const handleFormat = (key) => {
      if (key.indexOf(this.formatSeparator) < 0) return utils.getPath(data, key);

      const p = key.split(this.formatSeparator);
      const k = p.shift().trim();
      const f = p.join(this.formatSeparator).trim();

      return this.format(utils.getPath(data, k), f, lng);
    };

    this.resetRegExp();

    replaces = 0;
    // unescape if has unescapePrefix/Suffix
    /* eslint no-cond-assign: 0 */
    while (match = this.regexpUnescape.exec(str)) {
      value = handleFormat(match[1].trim());
      str = str.replace(match[0], value);
      this.regexpUnescape.lastIndex = 0;
      replaces++;
      if (replaces >= this.maxReplaces) {
        break;
      }
    }

    replaces = 0;
    // regular escape on demand
    while (match = this.regexp.exec(str)) {
      value = handleFormat(match[1].trim());
      if (typeof value !== 'string') value = utils.makeString(value);
      if (!value) {
        this.logger.warn(`missed to pass in variable ${match[1]} for interpolating ${str}`);
        value = '';
      }
      value = this.escapeValue ? regexSafe(this.escape(value)) : regexSafe(value);
      str = str.replace(match[0], value);
      this.regexp.lastIndex = 0;
      replaces++;
      if (replaces >= this.maxReplaces) {
        break;
      }
    }
    return str;
  }

  nest(str, fc, options = {}) {
    let match;
    let value;

    let clonedOptions = { ...options };
    clonedOptions.applyPostProcessor = false; // avoid post processing on nested lookup

    // if value is something like "myKey": "lorem $(anotherKey, { "count": {{aValueInOptions}} })"
    function handleHasOptions(key) {
      if (key.indexOf(',') < 0) return key;

      const p = key.split(',');
      key = p.shift();
      let optionsString = p.join(',');
      optionsString = this.interpolate(optionsString, clonedOptions);
      optionsString = optionsString.replace(/'/g, '"');

      try {
        clonedOptions = JSON.parse(optionsString);
      } catch (e) {
        this.logger.error(`failed parsing options string in nesting for key ${key}`, e);
      }

      return key;
    }

    // regular escape on demand
    while (match = this.nestingRegexp.exec(str)) {
      value = fc(handleHasOptions.call(this, match[1].trim()), clonedOptions);

      // is only the nesting key (key1 = '$(key2)') return the value without stringify
      if (value && match[0] === str && typeof value !== 'string') return value;

      // no string to include or empty
      if (typeof value !== 'string') value = utils.makeString(value);
      if (!value) {
        this.logger.warn(`missed to resolve ${match[1]} for nesting ${str}`);
        value = '';
      }
      // Nested keys should not be escaped by default #854
      // value = this.escapeValue ? regexSafe(utils.escape(value)) : regexSafe(value);
      str = str.replace(match[0], value);
      this.regexp.lastIndex = 0;
    }
    return str;
  }
}

export default Interpolator;
<|endoftext|>


<commit_before>const chai = require('chai');
const chaiHttp = require('chai-http');
chai.use(chaiHttp);
const assert = chai.assert;
const mongoose = require('mongoose');
const app = require('../lib/app');
const request = chai.request(app);

describe('list api', () => {
    before(() => {
        mongoose.connection.dropDatabase();
    });

    let listOne = {
        name: 'List One',
        item: []
    };

    function saveResource(resource, route) {
        return request.post(route)
            .send(resource)
            .then(res => res.body);
    }

    describe('list POST routes', () => {
        it('create a new list', () => {
            return saveResource(listOne, '/lists')
                .then(savedList => {
                    assert.isOk(savedList._id);
                    listOne._id = savedList._id;
                    listOne.__v = 0;
                    assert.deepEqual(savedList, listOne);
                });
        });
    });

    describe('list GET routes', () => {
        it('GET all lists', () => {
            return request.get('/lists')
                .then(req => req.body)
                .then(res => {
                    assert.isArray(res);
                });
        });

        it('GET list by id', () => {
            return request.get(`/lists/${listOne._id}`)
                .then(res => {
                    assert.deepEqual(res.body, listOne);
                });
        });
    });

});<commit_msg>deleted drop database from file (action performed in _before)<commit_after>const chai = require('chai');
const chaiHttp = require('chai-http');
chai.use(chaiHttp);
const assert = chai.assert;
const app = require('../lib/app');
const request = chai.request(app);

describe('list api', () => {

    let listOne = {
        name: 'List One',
        item: []
    };

    function saveResource(resource, route) {
        return request.post(route)
            .send(resource)
            .then(res => res.body);
    }

    describe('list POST routes', () => {
        it('create a new list', () => {
            return saveResource(listOne, '/lists')
                .then(savedList => {
                    assert.isOk(savedList._id);
                    listOne._id = savedList._id;
                    listOne.__v = 0;
                    assert.deepEqual(savedList, listOne);
                });
        });
    });

    describe('list GET routes', () => {
        it('GET all lists', () => {
            return request.get('/lists')
                .then(req => req.body)
                .then(res => {
                    assert.isArray(res);
                });
        });

        it('GET list by id', () => {
            return request.get(`/lists/${listOne._id}`)
                .then(res => {
                    assert.deepEqual(res.body, listOne);
                });
        });
    });

});<|endoftext|>


<commit_before><commit_msg>update log<commit_after><|endoftext|>


<commit_before>import * as utils from './utils';
import baseLogger from './logger';

class Interpolator {
  constructor(options = {}) {
    this.logger = baseLogger.create('interpolator');

    this.init(options, true);
  }

  init(options = {}, reset) {
    if (reset) this.options = options;
    if (!options.interpolation) options.interpolation = { escapeValue: true };

    let iOpts = options.interpolation;

    this.escapeValue = iOpts.escapeValue;

    this.prefix = iOpts.prefix ? utils.regexEscape(iOpts.prefix) : iOpts.prefixEscaped || '{{';
    this.suffix = iOpts.suffix ? utils.regexEscape(iOpts.suffix) : iOpts.suffixEscaped || '}}';

    this.unescapePrefix = iOpts.unescapeSuffix ? '' : iOpts.unescapePrefix || '-';
    this.unescapeSuffix = this.unescapePrefix ? '' : iOpts.unescapeSuffix || '';

    this.nestingPrefix = iOpts.nestingPrefix ? utils.regexEscape(iOpts.nestingPrefix) : iOpts.nestingPrefixEscaped || utils.regexEscape('$t(');
    this.nestingSuffix = iOpts.nestingSuffix ? utils.regexEscape(iOpts.nestingSuffix) : iOpts.nestingSuffixEscaped || utils.regexEscape(')');

    // the regexp
    let regexpStr = this.prefix + '(.+?)' + this.suffix;
    this.regexp = new RegExp(regexpStr, 'g');

    let regexpUnescapeStr = this.prefix + this.unescapePrefix + '(.+?)' + this.unescapeSuffix + this.suffix;
    this.regexpUnescape = new RegExp(regexpUnescapeStr, 'g');

    let nestingRegexpStr = this.nestingPrefix + '(.+?)' + this.nestingSuffix;
    this.nestingRegexp = new RegExp(nestingRegexpStr, 'g');
  }

  reset() {
    if (this.options) this.init(this.options);
  }

  interpolate(str, data) {
    let match, value;

    function regexSafe(val) {
      return val.replace(/\$/g, '$$$$');
    }

    // unescape if has unescapePrefix/Suffix
    var unescapedReplacements = str;
    while(match = this.regexpUnescape.exec(str)) {
      let value = utils.getPath(data, match[1].trim());
      unescapedReplacements = unescapedReplacements.replace(match[0], value);
    }
    str = unescapedReplacements;

    // regular escape on demand
    var escapedRelacements = str;
    while(match = this.regexp.exec(str)) {
      value = utils.getPath(data, match[1].trim());
      if (typeof value !== 'string') value = utils.makeString(value);
      if (!value) {
        this.logger.warn(`missed to pass in variable ${match[1]} for interpolating ${str}`);
        value = '';
      }
      value = this.escapeValue ? regexSafe(utils.escape(value)) : regexSafe(value);
      escapedRelacements = escapedRelacements.replace(match[0], value);
    }
    str = escapedRelacements ;
    return str;
  }

  nest(str, fc, options = {}) {
    let match, value;

    let clonedOptions = JSON.parse(JSON.stringify(options));
    clonedOptions.applyPostProcessor = false; // avoid post processing on nested lookup

    function regexSafe(val) {
      return val.replace(/\$/g, '$$$$');
    }

    // if value is something like "myKey": "lorem $(anotherKey, { "count": {{aValueInOptions}} })"
    function handleHasOptions(key) {
      if (key.indexOf(',') < 0) return key;

      let p = key.split(',');
      key = p.shift();
      let optionsString = p.join(',');
      optionsString = this.interpolate(optionsString, clonedOptions);

      try {
        clonedOptions = JSON.parse(optionsString);
      } catch (e) {
        this.logger.error(`failed parsing options string in nesting for key ${key}`, e);
      }

      return key;
    }

    // regular escape on demand
    while(match = this.nestingRegexp.exec(str)) {
      value = fc(handleHasOptions.call(this, match[1].trim()), clonedOptions);
      if (typeof value !== 'string') value = utils.makeString(value);
      if (!value) {
        this.logger.warn(`missed to pass in variable ${match[1]} for interpolating ${str}`);
        value = '';
      }
      value = this.escapeValue ? regexSafe(utils.escape(value)) : regexSafe(value);
      str = str.replace(match[0], value);
      this.regexp.lastIndex = 0;
    }
    return str;
  }
}

export default Interpolator;
<commit_msg>resorted to lastIndex=0 behaviour for backwards compatibility<commit_after>import * as utils from './utils';
import baseLogger from './logger';

class Interpolator {
  constructor(options = {}) {
    this.logger = baseLogger.create('interpolator');

    this.init(options, true);
  }

  init(options = {}, reset) {
    if (reset) this.options = options;
    if (!options.interpolation) options.interpolation = { escapeValue: true };

    let iOpts = options.interpolation;

    this.escapeValue = iOpts.escapeValue;

    this.prefix = iOpts.prefix ? utils.regexEscape(iOpts.prefix) : iOpts.prefixEscaped || '{{';
    this.suffix = iOpts.suffix ? utils.regexEscape(iOpts.suffix) : iOpts.suffixEscaped || '}}';

    this.unescapePrefix = iOpts.unescapeSuffix ? '' : iOpts.unescapePrefix || '-';
    this.unescapeSuffix = this.unescapePrefix ? '' : iOpts.unescapeSuffix || '';

    this.nestingPrefix = iOpts.nestingPrefix ? utils.regexEscape(iOpts.nestingPrefix) : iOpts.nestingPrefixEscaped || utils.regexEscape('$t(');
    this.nestingSuffix = iOpts.nestingSuffix ? utils.regexEscape(iOpts.nestingSuffix) : iOpts.nestingSuffixEscaped || utils.regexEscape(')');

    // the regexp
    let regexpStr = this.prefix + '(.+?)' + this.suffix;
    this.regexp = new RegExp(regexpStr, 'g');

    let regexpUnescapeStr = this.prefix + this.unescapePrefix + '(.+?)' + this.unescapeSuffix + this.suffix;
    this.regexpUnescape = new RegExp(regexpUnescapeStr, 'g');

    let nestingRegexpStr = this.nestingPrefix + '(.+?)' + this.nestingSuffix;
    this.nestingRegexp = new RegExp(nestingRegexpStr, 'g');
  }

  reset() {
    if (this.options) this.init(this.options);
  }

  interpolate(str, data) {
    let match, value;

    function regexSafe(val) {
      return val.replace(/\$/g, '$$$$');
    }

    // unescape if has unescapePrefix/Suffix
    while(match = this.regexpUnescape.exec(str)) {
      let value = utils.getPath(data, match[1].trim());
      str = str.replace(match[0], value);
      this.regexpUnescape.lastIndex = 0;
    }

    // regular escape on demand
    while(match = this.regexp.exec(str)) {
      value = utils.getPath(data, match[1].trim());
      if (typeof value !== 'string') value = utils.makeString(value);
      if (!value) {
        this.logger.warn(`missed to pass in variable ${match[1]} for interpolating ${str}`);
        value = '';
      }
      value = this.escapeValue ? regexSafe(utils.escape(value)) : regexSafe(value);
      str = str.replace(match[0], value);
      this.regexp.lastIndex = 0;
    }
    return str;
  }

  nest(str, fc, options = {}) {
    let match, value;

    let clonedOptions = JSON.parse(JSON.stringify(options));
    clonedOptions.applyPostProcessor = false; // avoid post processing on nested lookup

    function regexSafe(val) {
      return val.replace(/\$/g, '$$$$');
    }

    // if value is something like "myKey": "lorem $(anotherKey, { "count": {{aValueInOptions}} })"
    function handleHasOptions(key) {
      if (key.indexOf(',') < 0) return key;

      let p = key.split(',');
      key = p.shift();
      let optionsString = p.join(',');
      optionsString = this.interpolate(optionsString, clonedOptions);

      try {
        clonedOptions = JSON.parse(optionsString);
      } catch (e) {
        this.logger.error(`failed parsing options string in nesting for key ${key}`, e);
      }

      return key;
    }

    // regular escape on demand
    while(match = this.nestingRegexp.exec(str)) {
      value = fc(handleHasOptions.call(this, match[1].trim()), clonedOptions);
      if (typeof value !== 'string') value = utils.makeString(value);
      if (!value) {
        this.logger.warn(`missed to pass in variable ${match[1]} for interpolating ${str}`);
        value = '';
      }
      value = this.escapeValue ? regexSafe(utils.escape(value)) : regexSafe(value);
      str = str.replace(match[0], value);
      this.regexp.lastIndex = 0;
    }
    return str;
  }
}

export default Interpolator;
<|endoftext|>


<commit_before>var mockexpect = require('../lib/mockexpect');
var assert = require('assert');

describe('mockexpect', function () {
  var DummyObject, mockDummyObject, CustomMatcher;

  beforeEach(function () {
    DummyObject = function () {};
    DummyObject.prototype.testFunction = function () {};
    DummyObject.prototype.secondTestFunction = function () {};

    CustomMatcher = function (expectedObject) {
      this.expectedObject_ = expectedObject;
    };
    CustomMatcher.prototype = new mockexpect.Matcher();
    CustomMatcher.prototype.matches = function (actualObject) {
      return this.expectedObject_.id === actualObject.id;
    };

    mockDummyObject = mockexpect.mock(DummyObject);
  });

  it('asserts that a function was called', function () {
    mockDummyObject.testFunction.expect.toHaveBeenCalled();

    mockDummyObject.testFunction();

    mockDummyObject.assertExpectations();
  });

  it('asserts that a function was called an exact number of times', function () {
    mockDummyObject.testFunction.expect.toHaveBeenCalled(3);

    mockDummyObject.testFunction();
    mockDummyObject.testFunction();
    mockDummyObject.testFunction();

    mockDummyObject.assertExpectations();
  });

  it('all functions are spied on', function () {
    mockDummyObject.secondTestFunction.expect.toHaveBeenCalled();

    mockDummyObject.secondTestFunction();

    mockDummyObject.assertExpectations();
  });

  it('asserts that a function was not called', function () {
    mockDummyObject.testFunction.expect.not.toHaveBeenCalled();

    mockDummyObject.assertExpectations();
  });

  it('asserts that a function was called with a string', function () {
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith('someString');

    mockDummyObject.testFunction('someString');

    mockDummyObject.assertExpectations();
  });

  it('asserts that a function was called with multiple arguments', function () {
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith('someString', 'anotherString', 3);

    mockDummyObject.testFunction('someString', 'anotherString', 3);

    mockDummyObject.assertExpectations();
  });

  it('asserts that a function was called with an object', function () {
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith({ 'a': 'b', 'c': 1 });

    mockDummyObject.testFunction({ 'a': 'b', 'c': 1 });

    mockDummyObject.assertExpectations();
  });

  it('asserts that a function was called with a given type', function () {
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith(new mockexpect.Matcher(Function));

    mockDummyObject.testFunction(function () { return 'something happened'; });

    mockDummyObject.assertExpectations();
  });

  it('fails the assertion when types do not match', function () {
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith(new mockexpect.Matcher(DummyObject));

    mockDummyObject.testFunction(function () { return 'something happened'; });

    assert.throws(
      mockDummyObject.assertExpectations.bind(mockDummyObject),
      function (err) {
        return err.message === 'testFunction() was not called with [Matcher(function () {})], but was called with [function () { return \'something happened\'; }]';
      },
      'exception message did not contain call arguments'
    );
  });

  it('asserts that a function was called with a mix of specific and non-specific arguments', function () {
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith(new mockexpect.Matcher(Function), 'string', { 'a': 'b' });

    mockDummyObject.testFunction(function () { return 'something happened'; }, 'string', { 'a': 'b' });

    mockDummyObject.assertExpectations();
  });

  it('asserts that a function was not called with a string', function () {
    mockDummyObject.testFunction.expect.not.toHaveBeenCalledWith('different string');
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith('someString');

    mockDummyObject.testFunction('someString');

    mockDummyObject.assertExpectations();
  });

  it('asserts that a function was not called with multiple arguments', function () {
    mockDummyObject.testFunction.expect.not.toHaveBeenCalledWith('someString', 1, 'anotherString');
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith('someString', 5, 'anotherString');
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith('someString');

    mockDummyObject.testFunction('someString');
    mockDummyObject.testFunction('someString', 5, 'anotherString');

    mockDummyObject.assertExpectations();
  });

  it('asserts that strict equality is enforced', function () {
    mockDummyObject.testFunction.expect.not.toHaveBeenCalledWith(1);
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith('1');

    mockDummyObject.testFunction('1');

    mockDummyObject.assertExpectations();
  });

  it('asserts that a function was not called with an object', function () {
    mockDummyObject.testFunction.expect.not.toHaveBeenCalledWith({ 'a': 'b', 'c': 2 });
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith({ 'a': 'b', 'c': 1, 'd': 2 });

    mockDummyObject.testFunction({ 'a': 'b', 'c': 1, 'd': 2 });

    mockDummyObject.assertExpectations();
  });

  it('asserts that a function was not called with a given type', function () {
    mockDummyObject.testFunction.expect.not.toHaveBeenCalledWith(new mockexpect.Matcher(DummyObject));
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith(new mockexpect.Matcher(Function));

    mockDummyObject.testFunction(function () { return 'something happened'; });

    mockDummyObject.assertExpectations();
  });

  it('return the specified value', function () {
    mockDummyObject.testFunction.expect.toHaveBeenCalled().andReturn(5);

    assert.strictEqual(mockDummyObject.testFunction(), 5);
  });

  it('fails when a function is called without an expectation being set', function () {
    assert.throws(
      mockDummyObject.secondTestFunction.bind(mockDummyObject),
      function (err) {
        return err.message === 'secondTestFunction() was called without an expectation being set.';
      },
      'exception was not thrown'
    );
  });

  it('shows the actual calls for a function when an expectation is not met', function () {
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith('this string', 5, 'another string');
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith('weird string');
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith('that string', 5, 'another string');

    mockDummyObject.testFunction('that string', 5, 'another string');
    mockDummyObject.testFunction('weird string');

    assert.throws(
      mockDummyObject.assertExpectations.bind(mockDummyObject),
      function (err) {
        return err.message === 'testFunction() was not called with [this string, 5, another string], but was called with [that string, 5, another string], [weird string]';
      },
      'exception message did not contain call arguments'
    );
  });

  it('shows the actual and expected call count in failure message when there are no calls', function () {
    mockDummyObject.testFunction.expect.toHaveBeenCalled();

    assert.throws(
      mockDummyObject.assertExpectations.bind(mockDummyObject),
      function (err) {
        return err.message === 'expected testFunction() to have been called 1 time but it was never called.';
      },
      'call count exception message is not correct'
    );
  });

  it('shows the actual and expected call count in failure message when there is one call', function () {
    mockDummyObject.testFunction.expect.toHaveBeenCalled(2);

    mockDummyObject.testFunction();

    assert.throws(
      mockDummyObject.assertExpectations.bind(mockDummyObject),
      function (err) {
        return err.message === 'expected testFunction() to have been called 2 times but it was called 1 time.';
      },
      'call count exception message is not correct'
    );
  });

  it('shows the actual and expected call count in failure message when there are multiple calls', function () {
    mockDummyObject.testFunction.expect.toHaveBeenCalled(3);

    mockDummyObject.testFunction();
    mockDummyObject.testFunction();

    assert.throws(
      mockDummyObject.assertExpectations.bind(mockDummyObject),
      function (err) {
        return err.message === 'expected testFunction() to have been called 3 times but it was called 2 times.';
      },
      'call count exception message is not correct'
    );
  });

  it('shows the fields of an object in a failure message', function () {
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith({'a': 'something', 'b': new mockexpect.Matcher(Function)});
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith({3: new mockexpect.Matcher(Function), 'z': 'something else'});

    mockDummyObject.testFunction({3: function () {}, 'z': 'something else'});
    mockDummyObject.testFunction({'a': 'different thing', 'b': function () {}});

    assert.throws(
      mockDummyObject.assertExpectations.bind(mockDummyObject),
      function (err) {
        return err.message === 'testFunction() was not called with [{ a: something, b: Matcher(function Function() { [native code] }) }], but was called with [{ 3: function () {}, z: something else }], [{ a: different thing, b: function () {} }]';
      },
      'exception message did not contain call arguments'
    );
  });

  it('deep equality on object matching', function () {
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith({'a': 'something', 'b': 'something else'});

    mockDummyObject.testFunction({'a': 'something', 'b': 'something else', 'c': 'another thing'});

    assert.throws(
      mockDummyObject.assertExpectations.bind(mockDummyObject),
      function (err) {
        return err.message === 'testFunction() was not called with [{ a: something, b: something else }], but was called with [{ a: something, b: something else, c: another thing }]';
      },
      'exception message did not contain call arguments'
    );
  });

  it('works with custom matchers', function () {
    var expected, actualObject;

    expected = { id: 3, field: 'a' };
    actualObject = { id: 3, field: 'b' };
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith(new CustomMatcher(expected));

    mockDummyObject.testFunction(actualObject);

    mockDummyObject.assertExpectations();
  });

  it('spies on a static function', function () {
    var ObjectWithStaticFunction;

    ObjectWithStaticFunction = {};
    ObjectWithStaticFunction.someFunction = function () {};

    mockexpect.spyOn(ObjectWithStaticFunction, 'someFunction');

    ObjectWithStaticFunction.someFunction.expect.toHaveBeenCalled();

    ObjectWithStaticFunction.someFunction();

    ObjectWithStaticFunction.assertExpectations();
  });

  it('invokes the specified function', function () {
    var functionCalled;

    functionCalled = false;

    mockDummyObject.testFunction.expect.toHaveBeenCalled().andCall(function () {
      functionCalled = true;
    });

    mockDummyObject.testFunction();

    assert.ok(functionCalled, 'function was not called');
  });
});
<commit_msg>test failing test<commit_after>var mockexpect = require('../lib/mockexpect');
var assert = require('assert');

describe('mockexpect', function () {
  var DummyObject, mockDummyObject, CustomMatcher;

  beforeEach(function () {
    DummyObject = function () {};
    DummyObject.prototype.testFunction = function () {};
    DummyObject.prototype.secondTestFunction = function () {};

    CustomMatcher = function (expectedObject) {
      this.expectedObject_ = expectedObject;
    };
    CustomMatcher.prototype = new mockexpect.Matcher();
    CustomMatcher.prototype.matches = function (actualObject) {
      return this.expectedObject_.id === actualObject.id;
    };

    mockDummyObject = mockexpect.mock(DummyObject);
  });

  it('asserts that a function was called', function () {
    mockDummyObject.testFunction.expect.toHaveBeenCalled();

    mockDummyObject.testFunction();

    mockDummyObject.assertExpectations();
  });

  it('asserts that a function was called an exact number of times', function () {
    mockDummyObject.testFunction.expect.toHaveBeenCalled(3);

    mockDummyObject.testFunction();
    mockDummyObject.testFunction();
    // mockDummyObject.testFunction();

    mockDummyObject.assertExpectations();
  });

  it('all functions are spied on', function () {
    mockDummyObject.secondTestFunction.expect.toHaveBeenCalled();

    mockDummyObject.secondTestFunction();

    mockDummyObject.assertExpectations();
  });

  it('asserts that a function was not called', function () {
    mockDummyObject.testFunction.expect.not.toHaveBeenCalled();

    mockDummyObject.assertExpectations();
  });

  it('asserts that a function was called with a string', function () {
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith('someString');

    mockDummyObject.testFunction('someString');

    mockDummyObject.assertExpectations();
  });

  it('asserts that a function was called with multiple arguments', function () {
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith('someString', 'anotherString', 3);

    mockDummyObject.testFunction('someString', 'anotherString', 3);

    mockDummyObject.assertExpectations();
  });

  it('asserts that a function was called with an object', function () {
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith({ 'a': 'b', 'c': 1 });

    mockDummyObject.testFunction({ 'a': 'b', 'c': 1 });

    mockDummyObject.assertExpectations();
  });

  it('asserts that a function was called with a given type', function () {
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith(new mockexpect.Matcher(Function));

    mockDummyObject.testFunction(function () { return 'something happened'; });

    mockDummyObject.assertExpectations();
  });

  it('fails the assertion when types do not match', function () {
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith(new mockexpect.Matcher(DummyObject));

    mockDummyObject.testFunction(function () { return 'something happened'; });

    assert.throws(
      mockDummyObject.assertExpectations.bind(mockDummyObject),
      function (err) {
        return err.message === 'testFunction() was not called with [Matcher(function () {})], but was called with [function () { return \'something happened\'; }]';
      },
      'exception message did not contain call arguments'
    );
  });

  it('asserts that a function was called with a mix of specific and non-specific arguments', function () {
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith(new mockexpect.Matcher(Function), 'string', { 'a': 'b' });

    mockDummyObject.testFunction(function () { return 'something happened'; }, 'string', { 'a': 'b' });

    mockDummyObject.assertExpectations();
  });

  it('asserts that a function was not called with a string', function () {
    mockDummyObject.testFunction.expect.not.toHaveBeenCalledWith('different string');
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith('someString');

    mockDummyObject.testFunction('someString');

    mockDummyObject.assertExpectations();
  });

  it('asserts that a function was not called with multiple arguments', function () {
    mockDummyObject.testFunction.expect.not.toHaveBeenCalledWith('someString', 1, 'anotherString');
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith('someString', 5, 'anotherString');
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith('someString');

    mockDummyObject.testFunction('someString');
    mockDummyObject.testFunction('someString', 5, 'anotherString');

    mockDummyObject.assertExpectations();
  });

  it('asserts that strict equality is enforced', function () {
    mockDummyObject.testFunction.expect.not.toHaveBeenCalledWith(1);
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith('1');

    mockDummyObject.testFunction('1');

    mockDummyObject.assertExpectations();
  });

  it('asserts that a function was not called with an object', function () {
    mockDummyObject.testFunction.expect.not.toHaveBeenCalledWith({ 'a': 'b', 'c': 2 });
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith({ 'a': 'b', 'c': 1, 'd': 2 });

    mockDummyObject.testFunction({ 'a': 'b', 'c': 1, 'd': 2 });

    mockDummyObject.assertExpectations();
  });

  it('asserts that a function was not called with a given type', function () {
    mockDummyObject.testFunction.expect.not.toHaveBeenCalledWith(new mockexpect.Matcher(DummyObject));
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith(new mockexpect.Matcher(Function));

    mockDummyObject.testFunction(function () { return 'something happened'; });

    mockDummyObject.assertExpectations();
  });

  it('return the specified value', function () {
    mockDummyObject.testFunction.expect.toHaveBeenCalled().andReturn(5);

    assert.strictEqual(mockDummyObject.testFunction(), 5);
  });

  it('fails when a function is called without an expectation being set', function () {
    assert.throws(
      mockDummyObject.secondTestFunction.bind(mockDummyObject),
      function (err) {
        return err.message === 'secondTestFunction() was called without an expectation being set.';
      },
      'exception was not thrown'
    );
  });

  it('shows the actual calls for a function when an expectation is not met', function () {
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith('this string', 5, 'another string');
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith('weird string');
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith('that string', 5, 'another string');

    mockDummyObject.testFunction('that string', 5, 'another string');
    mockDummyObject.testFunction('weird string');

    assert.throws(
      mockDummyObject.assertExpectations.bind(mockDummyObject),
      function (err) {
        return err.message === 'testFunction() was not called with [this string, 5, another string], but was called with [that string, 5, another string], [weird string]';
      },
      'exception message did not contain call arguments'
    );
  });

  it('shows the actual and expected call count in failure message when there are no calls', function () {
    mockDummyObject.testFunction.expect.toHaveBeenCalled();

    assert.throws(
      mockDummyObject.assertExpectations.bind(mockDummyObject),
      function (err) {
        return err.message === 'expected testFunction() to have been called 1 time but it was never called.';
      },
      'call count exception message is not correct'
    );
  });

  it('shows the actual and expected call count in failure message when there is one call', function () {
    mockDummyObject.testFunction.expect.toHaveBeenCalled(2);

    mockDummyObject.testFunction();

    assert.throws(
      mockDummyObject.assertExpectations.bind(mockDummyObject),
      function (err) {
        return err.message === 'expected testFunction() to have been called 2 times but it was called 1 time.';
      },
      'call count exception message is not correct'
    );
  });

  it('shows the actual and expected call count in failure message when there are multiple calls', function () {
    mockDummyObject.testFunction.expect.toHaveBeenCalled(3);

    mockDummyObject.testFunction();
    mockDummyObject.testFunction();

    assert.throws(
      mockDummyObject.assertExpectations.bind(mockDummyObject),
      function (err) {
        return err.message === 'expected testFunction() to have been called 3 times but it was called 2 times.';
      },
      'call count exception message is not correct'
    );
  });

  it('shows the fields of an object in a failure message', function () {
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith({'a': 'something', 'b': new mockexpect.Matcher(Function)});
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith({3: new mockexpect.Matcher(Function), 'z': 'something else'});

    mockDummyObject.testFunction({3: function () {}, 'z': 'something else'});
    mockDummyObject.testFunction({'a': 'different thing', 'b': function () {}});

    assert.throws(
      mockDummyObject.assertExpectations.bind(mockDummyObject),
      function (err) {
        return err.message === 'testFunction() was not called with [{ a: something, b: Matcher(function Function() { [native code] }) }], but was called with [{ 3: function () {}, z: something else }], [{ a: different thing, b: function () {} }]';
      },
      'exception message did not contain call arguments'
    );
  });

  it('deep equality on object matching', function () {
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith({'a': 'something', 'b': 'something else'});

    mockDummyObject.testFunction({'a': 'something', 'b': 'something else', 'c': 'another thing'});

    assert.throws(
      mockDummyObject.assertExpectations.bind(mockDummyObject),
      function (err) {
        return err.message === 'testFunction() was not called with [{ a: something, b: something else }], but was called with [{ a: something, b: something else, c: another thing }]';
      },
      'exception message did not contain call arguments'
    );
  });

  it('works with custom matchers', function () {
    var expected, actualObject;

    expected = { id: 3, field: 'a' };
    actualObject = { id: 3, field: 'b' };
    mockDummyObject.testFunction.expect.toHaveBeenCalledWith(new CustomMatcher(expected));

    mockDummyObject.testFunction(actualObject);

    mockDummyObject.assertExpectations();
  });

  it('spies on a static function', function () {
    var ObjectWithStaticFunction;

    ObjectWithStaticFunction = {};
    ObjectWithStaticFunction.someFunction = function () {};

    mockexpect.spyOn(ObjectWithStaticFunction, 'someFunction');

    ObjectWithStaticFunction.someFunction.expect.toHaveBeenCalled();

    ObjectWithStaticFunction.someFunction();

    ObjectWithStaticFunction.assertExpectations();
  });

  it('invokes the specified function', function () {
    var functionCalled;

    functionCalled = false;

    mockDummyObject.testFunction.expect.toHaveBeenCalled().andCall(function () {
      functionCalled = true;
    });

    mockDummyObject.testFunction();

    assert.ok(functionCalled, 'function was not called');
  });
});
<|endoftext|>


<commit_before>var tests = {
  boardValid: boardValid,
  cellsValid: cellsValid
}

// Checks the board to make sure:
// 1. it is a JavaScript object
// 2. it has a cells property (which is an array)
// 3. that the cells array is not empty
// 4. that the cells array is not too large
// 5. that the number of cells can form a square
function boardValid () {
  if (typeof board !== 'object') {
    displayMessage('Remember to define your board object!')
    return false
  }
  if (!board.hasOwnProperty('cells')) {
    displayMessage('Your board object needs a property named cells.')
    return false
  }
  if (!isArray(board.cells)) {
    displayMessage('board.cells should be an array.')
    return false
  }
  if (board.cells.length === 0) {
    displayMessage("This board doesn\'t seem to have any cells in it...")
    return false
  }
  if (board.cells.length > 36) {
    displayMessage('The game can only cope with total number of cells up to 36! Try again with fewer cells.')
    return false
  }
  if (!isSquare(board.cells.length)) {
    displayMessage('The number of cells in your object must be able to form a square: same number on each side!')
    return false
  }
  return true
}

// Check all the cells to make sure they have the correct properties
function cellsValid () {
  var invalidCells = board.cells.filter(isInvalidCell)
  return invalidCells.length === 0
}

// Checks each cell to make sure:
// 1. it has a row property
// 2. it has a col property
// 3. that the coordinates are valid
// 4. it has an isMine property
// 5. it has a hidden property
function isInvalidCell (cell) {
  if (typeof cell !== 'object') {
    displayMessage('At least one of those cells is not an object! { }')
    return true
  }
  if (!cell.hasOwnProperty('row')) {
    displayMessage('I found a cell without a row property!')
    return true
  }
  if (!cell.hasOwnProperty('col')) {
    displayMessage('I found a cell without a col property!')
    return true
  }
  if (!coordinatesValid(cell)) {
    return true
  }
  if (!cell.hasOwnProperty('isMine')) {
    displayMessage("I found a cell that doesn't know if it's a mine or not (each cell needs an isMine property)!")
    return true
  }
  if (!cell.hasOwnProperty('hidden')) {
    displayMessage("I found a cell that doesn't know if it's hidden or not (each cell needs a hidden property)!")
    return true
  }
  return false
}

// Checks each set of coordinates to ensure:
// 1. they are numbers
// 2. they refer to a place inside the board
// 3. there is only one copy of each
function coordinatesValid (cell) {
  if (typeof cell.row !== 'number' || typeof cell.col !== 'number') {
    displayMessage('Both row and col must be numbers (not strings or anything else).')
    return false
  }
  var duplicates = board.cells.filter(function (c) {
    return cell.row === c.row && cell.col === c.col
  })
  if (duplicates.length > 1) {
    displayMessage('There seems to be more than one cell with row: ' + cell.row +
      ' and col: ' + cell.col + '.')
    return false
  }
  var sideLength = Math.sqrt(board.cells.length)
  if (cell.row >= sideLength || cell.col >= sideLength) {
    displayMessage('I found a cell with row or col outside the board boundaries.')
    return false
  }
  return true
}

function isSquare (numberOfCells) {
  if (numberOfCells === 1) {
    return false
  }

  // Check for whole numbers per http://stackoverflow.com/a/2304062/122643
  return Math.sqrt(numberOfCells) %1 === 0
}

function isArray(a) {
  return Object.prototype.toString.call(a) === '[object Array]'
}
<commit_msg>Add a hint<commit_after>var tests = {
  boardValid: boardValid,
  cellsValid: cellsValid
}

// Checks the board to make sure:
// 1. it is a JavaScript object
// 2. it has a cells property (which is an array)
// 3. that the cells array is not empty
// 4. that the cells array is not too large
// 5. that the number of cells can form a square
function boardValid () {
  if (typeof board !== 'object') {
    displayMessage('Remember to define your board object!')
    return false
  }
  if (!board.hasOwnProperty('cells')) {
    displayMessage('Your board object needs a property named cells.')
    return false
  }
  if (!isArray(board.cells)) {
    displayMessage('board.cells should be an array.')
    return false
  }
  if (board.cells.length === 0) {
    displayMessage("This board doesn\'t seem to have any cells in it... try adding some elements to your array.")
    return false
  }
  if (board.cells.length > 36) {
    displayMessage('The game can only cope with total number of cells up to 36! Try again with fewer cells.')
    return false
  }
  if (!isSquare(board.cells.length)) {
    displayMessage('The number of cells in your object must be able to form a square: same number on each side!')
    return false
  }
  return true
}

// Check all the cells to make sure they have the correct properties
function cellsValid () {
  var invalidCells = board.cells.filter(isInvalidCell)
  return invalidCells.length === 0
}

// Checks each cell to make sure:
// 1. it has a row property
// 2. it has a col property
// 3. that the coordinates are valid
// 4. it has an isMine property
// 5. it has a hidden property
function isInvalidCell (cell) {
  if (typeof cell !== 'object') {
    displayMessage('At least one of those cells is not an object! { }')
    return true
  }
  if (!cell.hasOwnProperty('row')) {
    displayMessage('I found a cell without a row property!')
    return true
  }
  if (!cell.hasOwnProperty('col')) {
    displayMessage('I found a cell without a col property!')
    return true
  }
  if (!coordinatesValid(cell)) {
    return true
  }
  if (!cell.hasOwnProperty('isMine')) {
    displayMessage("I found a cell that doesn't know if it's a mine or not (each cell needs an isMine property)!")
    return true
  }
  if (!cell.hasOwnProperty('hidden')) {
    displayMessage("I found a cell that doesn't know if it's hidden or not (each cell needs a hidden property)!")
    return true
  }
  return false
}

// Checks each set of coordinates to ensure:
// 1. they are numbers
// 2. they refer to a place inside the board
// 3. there is only one copy of each
function coordinatesValid (cell) {
  if (typeof cell.row !== 'number' || typeof cell.col !== 'number') {
    displayMessage('Both row and col must be numbers (not strings or anything else).')
    return false
  }
  var duplicates = board.cells.filter(function (c) {
    return cell.row === c.row && cell.col === c.col
  })
  if (duplicates.length > 1) {
    displayMessage('There seems to be more than one cell with row: ' + cell.row +
      ' and col: ' + cell.col + '.')
    return false
  }
  var sideLength = Math.sqrt(board.cells.length)
  if (cell.row >= sideLength || cell.col >= sideLength) {
    displayMessage('I found a cell with row or col outside the board boundaries.')
    return false
  }
  return true
}

function isSquare (numberOfCells) {
  if (numberOfCells === 1) {
    return false
  }

  // Check for whole numbers per http://stackoverflow.com/a/2304062/122643
  return Math.sqrt(numberOfCells) %1 === 0
}

function isArray(a) {
  return Object.prototype.toString.call(a) === '[object Array]'
}
<|endoftext|>


<commit_before>module.exports = thunk

function thunk(fn, args) {
  if (!isFn(fn)) {
    args = [fn]
    fn = identity
  } else if (arguments.length > 2) {
    args = slice(arguments, 1)
  } else if (arguments.length > 1) {
    args = [args]
  } else {
    args = []
  }

  if (args.length > 1) {
    return function thunk() {
      return fn.apply(this, args)
    }
  } else if (args.length) {
    return function thunk() {
      return fn.call(this, args[0])
    }
  } else {
    return function thunk() {
      return fn.call(this)
    }
  }
}

const identity = require('./identity')
    , slice    = require('./slice')
    , isFn     = require('./isFn')<commit_msg>Changed `thunk` to use `variadic`<commit_after>const identity = require('./identity')
    , variadic = require('./variadic')
    , slice    = require('./slice')
    , isFn     = require('./isFn')

module.exports = variadic(thunk)

function thunk(fn, rest) {
  if (!isFn(fn)) {
    rest = [fn]
    fn = identity
  }

  if (rest.length > 1) {
    return function thunk() {
      return fn.apply(this, rest)
    }
  } else if (rest.length) {
    return function thunk() {
      return fn.call(this, rest[0])
    }
  } else {
    return function thunk() {
      return fn.call(this)
    }
  }
}<|endoftext|>


<commit_before>
/**
 * Module dependencies.
 */

var util = require('./util');
var Track = require('./schemas').metadata['spotify.metadata.proto.Track'];
var PassThrough = require('stream').PassThrough;
var debug = require('debug')('spotify-web:track');

// node v0.8.x compat
if (!PassThrough) PassThrough = require('readable-stream/passthrough');

/**
 * Module exports.
 */

exports = module.exports = Track;

/**
 * Track URI getter.
 */

Object.defineProperty(Track.prototype, 'uri', {
  get: function () {
    return util.gid2uri('track', this.gid);
  },
  enumerable: true,
  configurable: true
});

/**
 * Loads all the metadata for this Track instance. Useful for when you get an only
 * partially filled Track instance from an Album instance for example.
 *
 * @param {Function} fn callback function
 * @api public
 */

Track.prototype.get =
Track.prototype.metadata = function (fn) {
  if (this._loaded) {
    // already been loaded...
    debug('track already loaded');
    return process.nextTick(fn.bind(null, null, this));
  }
  var spotify = this._spotify;
  var self = this;
  spotify.get(this.uri, function (err, track) {
    if (err) return fn(err);
    // extend this Track instance with the new one's properties
    Object.keys(track).forEach(function (key) {
      if (!self.hasOwnProperty(key)) {
        self[key] = track[key];
      }
    });
    fn(null, self);
  });
};

/**
 * Begins playing this track, returns a Readable stream that outputs MP3 data.
 *
 * @api public
 */

Track.prototype.play = function () {
  // TODO: add formatting options once we figure that out
  var spotify = this._spotify;
  var stream = new PassThrough();

  // if a song was playing before this, the "track_end" command needs to be sent
  var track = spotify.currentTrack;
  if (track) {
    spotify.sendTrackEnd(track._playSession.lid, track.uri, track.duration);
    track._playSession = null;
  }

  // set this Track instance as the "currentTrack"
  spotify.currentTrack = track = this;

  // initiate a "play session" for this Track
  spotify.trackUri(track, function (err, res) {
    if (err) return stream.emit('error', err);
    if (!res.uri) return stream.emit('error', new Error('response contained no "uri"'));
    debug('GET %s', res.uri);
    track._playSession = res;
    var req = spotify.agent.get(res.uri).end().request();
    req.on('response', response);
  });

  function response (res) {
    debug('HTTP/%s %s', res.httpVersion, res.statusCode);
    res.pipe(stream);
  }

  // return stream immediately so it can be .pipe()'d
  return stream;
};
<commit_msg>track: don't send "track_end" event when no playSession<commit_after>
/**
 * Module dependencies.
 */

var util = require('./util');
var Track = require('./schemas').metadata['spotify.metadata.proto.Track'];
var PassThrough = require('stream').PassThrough;
var debug = require('debug')('spotify-web:track');

// node v0.8.x compat
if (!PassThrough) PassThrough = require('readable-stream/passthrough');

/**
 * Module exports.
 */

exports = module.exports = Track;

/**
 * Track URI getter.
 */

Object.defineProperty(Track.prototype, 'uri', {
  get: function () {
    return util.gid2uri('track', this.gid);
  },
  enumerable: true,
  configurable: true
});

/**
 * Loads all the metadata for this Track instance. Useful for when you get an only
 * partially filled Track instance from an Album instance for example.
 *
 * @param {Function} fn callback function
 * @api public
 */

Track.prototype.get =
Track.prototype.metadata = function (fn) {
  if (this._loaded) {
    // already been loaded...
    debug('track already loaded');
    return process.nextTick(fn.bind(null, null, this));
  }
  var spotify = this._spotify;
  var self = this;
  spotify.get(this.uri, function (err, track) {
    if (err) return fn(err);
    // extend this Track instance with the new one's properties
    Object.keys(track).forEach(function (key) {
      if (!self.hasOwnProperty(key)) {
        self[key] = track[key];
      }
    });
    fn(null, self);
  });
};

/**
 * Begins playing this track, returns a Readable stream that outputs MP3 data.
 *
 * @api public
 */

Track.prototype.play = function () {
  // TODO: add formatting options once we figure that out
  var spotify = this._spotify;
  var stream = new PassThrough();

  // if a song was playing before this, the "track_end" command needs to be sent
  var track = spotify.currentTrack;
  if (track && track._playSession) {
    spotify.sendTrackEnd(track._playSession.lid, track.uri, track.duration);
    track._playSession = null;
  }

  // set this Track instance as the "currentTrack"
  spotify.currentTrack = track = this;

  // initiate a "play session" for this Track
  spotify.trackUri(track, function (err, res) {
    if (err) return stream.emit('error', err);
    if (!res.uri) return stream.emit('error', new Error('response contained no "uri"'));
    debug('GET %s', res.uri);
    track._playSession = res;
    var req = spotify.agent.get(res.uri).end().request();
    req.on('response', response);
  });

  function response (res) {
    debug('HTTP/%s %s', res.httpVersion, res.statusCode);
    res.pipe(stream);
  }

  // return stream immediately so it can be .pipe()'d
  return stream;
};
<|endoftext|>


<commit_before><commit_msg>Add verbose option<commit_after><|endoftext|>


<commit_before><commit_msg>Copyboard: Fix JavaScript syntax and add semicolons<commit_after><|endoftext|>


<commit_before>/**
 *
 * You can check the live example on here http://jsfiddle.net/gianlucaguarini/ftoLgfg3/
 *
 */

var
	jsdom = require('jsdom')
	riot = require('../../dist/riot/riot')
	myComponent = 'my-component'
	myComponentHTML = [
		'
{ opts.title }
',
		'
{ opts.description }
',
		'<my-list-item each="{ opts.items }">'
	].join('')
	myListItem = 'my-list-item'
	myListItemHTML = [
		'<input type="checkbox" onchange="{ onChange }">',
		'I am active',
	].join('')

/**
 * Check the memory usage analizing the heap
 * @param  { function } fun
 * @return { array } memory used + duration
 */

function measure(fun) {
	startTime = Date.now()
	duration = null
	fun()
	duration = Date.now() - startTime
	return [process.memoryUsage().heapUsed, duration]
}

/**
 *
 * Adding the custom tags to the riot internal cache
 *
 */
function setTags() {
	riot.tag(myComponent, myComponentHTML,function (opts) {
		var self = this
    function loop () {
        opts.items = generateItems(1000,{
            isActive:false
        })
        result = measure(self.update.bind(self))
				console.log(
					(result[0] / 1024 / 1024).toFixed(2) + ' MiB',
					result[1] + ' ms'
				)
        setTimeout(loop,1000)
    }
    loop()
	})
	riot.tag(myListItem, myListItemHTML, function () {
		this.onChange = function () {
			opts.isActive = e.target.checked
		}
	})
}

/**
 *
 * Mount the custom tags passing some fake values
 *
 */

function mount() {
	riot.mount(myComponent, {
		title: 'hello world',
		description: 'mad world',
		items: generateItems(1000,{
			isActive: false
		})
	})
}

/**
 * Helper function to generate custom array
 * @param  { int } amount amount of entries in the array
 * @param  { * } data
 * @return array
 */
function generateItems(amount, data) {
	var items = []
	while (--amount) {
		items.push(data)
	}
	return items
}

/**
 *
 * Start the tests
 *
 */

function test () {
	global.gc()
	mount()
}

/**
 * Pepare the DOM and mount the riot components
 */
jsdom.env({
	html: '<!doctype html><' + myComponent + ' />',
	done: function (errors, window) {
		global.document = window.document
		setTags()
		test()
	}
});

<commit_msg>indentation fixes on the memory test file<commit_after>/**
 *
 * You can check the live example on here http://jsfiddle.net/gianlucaguarini/ftoLgfg3/
 *
 */

var jsdom = require('jsdom')
  riot = require('../../dist/riot/riot')
  myComponent = 'my-component'
  myComponentHTML = [
    '
{ opts.title }
',
    '
{ opts.description }
',
    '<my-list-item each="{ opts.items }">'
  ].join('')
  myListItem = 'my-list-item'
  myListItemHTML = [
    '<input type="checkbox" onchange="{ onChange }">',
    'I am active',
  ].join('')

/**
 * Check the memory usage analizing the heap
 * @param  { function } fun
 * @return { array } memory used + duration
 */

function measure(fun) {
  var startTime = Date.now()
  fun()
  return [process.memoryUsage().heapUsed, Date.now() - startTime]
}

/**
 *
 * Adding the custom tags to the riot internal cache
 *
 */

function setTags() {
  riot.tag(myComponent, myComponentHTML,function (opts) {
    var self = this
    function loop () {
      opts.items = generateItems(1000,{
          isActive:false
      })
      result = measure(self.update.bind(self))
      console.log(
        (result[0] / 1024 / 1024).toFixed(2) + ' MiB',
        result[1] + ' ms'
      )
      setTimeout(loop,1000)
    }
    loop()
  })
  riot.tag(myListItem, myListItemHTML, function () {
    this.onChange = function () {
      opts.isActive = e.target.checked
    }
  })
}

/**
 *
 * Mount the custom tags passing some fake values
 *
 */

function mount() {
  riot.mount(myComponent, {
    title: 'hello world',
    description: 'mad world',
    items: generateItems(1000,{
      isActive: false
    })
  })
}

/**
 * Helper function to generate custom array
 * @param  { int } amount amount of entries in the array
 * @param  { * } data
 * @return array
 */

function generateItems(amount, data) {
  var items = []
  while (--amount) {
    items.push(data)
  }
  return items
}

/**
 *
 * Start the tests
 *
 */

function test () {
  global.gc()
  mount()
}

/**
 * Pepare the DOM and mount the riot components
 */

jsdom.env({
  html: '<!doctype html><' + myComponent + ' />',
  done: function (errors, window) {
    global.document = window.document
    setTags()
    test()
  }
})

<|endoftext|>


<commit_before>'use strict';

exports.config = (function() {

    var profile = process.env.PROTRACTOR_PROFILE;
    console.log('protractor profile: ' + profile);

    var extra;
    switch (profile) {
        case undefined:
            extra = {
                capabilities: {
                    'browserName': 'chrome'
                },
                chromeOnly: true
            };
            break;
        case 'phantomjs':
            extra = {
                capabilities: {
                   'browserName': 'phantomjs',
                   'phantomjs.binary.path': './node_modules/karma-phantomjs-launcher/node_modules/phantomjs/bin/phantomjs'
                }
            };
            break;
        default:
            throw 'invalid protractor profile: ' + profile;
    }

    var config = {
      allScriptsTimeout: 11000,

      specs: [
        'e2e/*.js'
      ],

      baseUrl: 'http://localhost:9000/',

      framework: 'jasmine',

      jasmineNodeOpts: {
        defaultTimeoutInterval: 30000
      }
    };

    for (var key in extra) {
        config[key] = extra[key];
    }

    return config;
}());
<commit_msg>Add Travis protractor profiles.<commit_after>'use strict';

exports.config = (function() {

    var profile = process.env.PROTRACTOR_PROFILE;
    console.log('protractor profile: ' + profile);

    var extra;
    switch (profile) {
        case undefined:
            extra = {
                capabilities: {
                    'browserName': 'chrome'
                },
                chromeOnly: true
            };
            break;
        case 'phantomjs':
            extra = {
                capabilities: {
                   'browserName': 'phantomjs',
                   'phantomjs.binary.path': './node_modules/karma-phantomjs-launcher/node_modules/phantomjs/bin/phantomjs'
                }
            };
            break;
        case 'travis':
            // Travis has Firefox installed.  The GUI emulator xvfb
            // (X Virtual Framebuffer) needs to be started prior to running
            // Protractor.
            extra = {
                capabilities: {
                    'browserName': 'firefox'
                }
            };
            break;
        case 'travis-phantom':
            // Travis has phantomjs on the PATH.
            extra = {
                capabilities: {
                    'browserName': 'firefox'
                }
            };
            break;
        default:
            throw 'invalid protractor profile: ' + profile;
    }

    var config = {
      allScriptsTimeout: 11000,

      specs: [
        'e2e/*.js'
      ],

      baseUrl: 'http://localhost:9000/',

      framework: 'jasmine',

      jasmineNodeOpts: {
        defaultTimeoutInterval: 30000
      }
    };

    for (var key in extra) {
        config[key] = extra[key];
    }

    return config;
}());
<|endoftext|>


<commit_before>/**
 * Tests public phantomas API
 */
var vows = require('vows'),
	assert = require('assert'),
	mockery = require('mockery'),
	phantomas = require('../core/phantomas');

// mock PhantomJS-specific modules and globals
GLOBAL.phantom = {
	version: {}
};
mockery.registerMock('fs', {
	list: function() {}
});
mockery.registerMock('system', {
	os: {}
});
mockery.registerMock('webpage', {
	create: function() {
		return {
			evaluate: function() {},
			injectJs: function() {},
			render: function() {}
		};
	},
});
mockery.enable({
	warnOnUnregistered: false
});

// helper
function getPhantomasAPI(params) {
	var instance = new phantomas(params || {});
	return instance.getPublicWrapper();
}

// run the test
vows.describe('phantomas public API').addBatch({
	'exposes values and methods': {
		topic: function() {
			return getPhantomasAPI({
				url: 'http://example.com'
			});
		},
		'url field is set correctly': function(api) {
			assert.equal(api.url, 'http://example.com');
		},
		'methods are accessible': function(api) {
			var methods = [
				'getParam',
				'on',
				'once',
				'emit',
				'setMetric',
				'setMetricEvaluate',
				'setMetricFromScope',
				'getFromScope',
				'incrMetric',
				'getMetric',
				'addNotice',
				'log',
				'echo',
				'evaluate',
				'injectJs',
				'require',
				'median'
			];

			methods.forEach(function(method) {
				assert.equal(typeof api[method], 'function');
			});
		}
	},
	'events are processed': {
		topic: getPhantomasAPI,
		'event is triggered': function(api) {
			var triggered;

			api.on('foo', function() {
				triggered = true;
			});
			api.emit('foo');

			assert.isTrue(triggered);
		},
		'params are passed': function(api) {
			var a, b;

			api.on('foo', function(valA, valB) {
				a = valA;
				b = valB;
			});
			api.emit('foo', 123, 456);

			assert.equal(a, 123);
			assert.equal(b, 456);
		}
	},
	'metrics': {
		topic: getPhantomasAPI,
		'have default value': function(api) {
			assert.equal(typeof api.getMetric('undef'), 'undefined');
		},
		'are set': function(api) {
			api.setMetric('foo', 123);
			assert.equal(api.getMetric('foo'), 123);
		},
		'are properly incremented': function(api) {
			api.incrMetric('bar');
			assert.equal(api.getMetric('bar'), 1);

			api.incrMetric('bar', 3);
			assert.equal(api.getMetric('bar'), 4);
		}
	},
	'parameters': {
		topic: function() {
			return getPhantomasAPI({
				foo: 123,
				bar: 'abc'
			});
		},
		'params are accessible': function(api) {
			assert.equal(api.getParam('foo'), 123);
			assert.equal(api.getParam('bar'), 'abc');
		},
	}
}).export(module);
<commit_msg>Test default metric value<commit_after>/**
 * Tests public phantomas API
 */
var vows = require('vows'),
	assert = require('assert'),
	mockery = require('mockery'),
	phantomas = require('../core/phantomas');

// mock PhantomJS-specific modules and globals
GLOBAL.phantom = {
	version: {}
};
mockery.registerMock('fs', {
	list: function() {}
});
mockery.registerMock('system', {
	os: {}
});
mockery.registerMock('webpage', {
	create: function() {
		return {
			evaluate: function() {},
			injectJs: function() {},
			render: function() {}
		};
	},
});
mockery.enable({
	warnOnUnregistered: false
});

// helper
function getPhantomasAPI(params) {
	var instance = new phantomas(params || {});
	return instance.getPublicWrapper();
}

// run the test
vows.describe('phantomas public API').addBatch({
	'exposes values and methods': {
		topic: function() {
			return getPhantomasAPI({
				url: 'http://example.com'
			});
		},
		'url field is set correctly': function(api) {
			assert.equal(api.url, 'http://example.com');
		},
		'methods are accessible': function(api) {
			var methods = [
				'getParam',
				'on',
				'once',
				'emit',
				'setMetric',
				'setMetricEvaluate',
				'setMetricFromScope',
				'getFromScope',
				'incrMetric',
				'getMetric',
				'addNotice',
				'log',
				'echo',
				'evaluate',
				'injectJs',
				'require',
				'median'
			];

			methods.forEach(function(method) {
				assert.equal(typeof api[method], 'function');
			});
		}
	},
	'events are processed': {
		topic: getPhantomasAPI,
		'event is triggered': function(api) {
			var triggered;

			api.on('foo', function() {
				triggered = true;
			});
			api.emit('foo');

			assert.isTrue(triggered);
		},
		'params are passed': function(api) {
			var a, b;

			api.on('foo', function(valA, valB) {
				a = valA;
				b = valB;
			});
			api.emit('foo', 123, 456);

			assert.equal(a, 123);
			assert.equal(b, 456);
		}
	},
	'metrics': {
		topic: getPhantomasAPI,
		'have default value': function(api) {
			assert.equal(typeof api.getMetric('undef'), 'undefined');
		},
		'are set': function(api) {
			api.setMetric('foo', 123);
			assert.equal(api.getMetric('foo'), 123);
		},
		'are set with default value': function(api) {
			api.setMetric('foo');
			assert.equal(api.getMetric('foo'), 0);
		},
		'are properly incremented': function(api) {
			api.incrMetric('bar');
			assert.equal(api.getMetric('bar'), 1);

			api.incrMetric('bar', 3);
			assert.equal(api.getMetric('bar'), 4);
		}
	},
	'parameters': {
		topic: function() {
			return getPhantomasAPI({
				foo: 123,
				bar: 'abc'
			});
		},
		'params are accessible': function(api) {
			assert.equal(api.getParam('foo'), 123);
			assert.equal(api.getParam('bar'), 'abc');
		},
	}
}).export(module);
<|endoftext|>


<commit_before>import expect from 'expect';

import {relateReducer, relateReducerInit, actionTypes} from '../../lib';

describe('Reducer', () => {
  it('Does not alter state if not a Relate action', () => {
    const state = {something: 1};
    const newState = relateReducer(state, {type: 'not'});
    expect(newState).toBe(state);
    expect(newState).toEqual(state);
  });

  it('Reducer init returns with merged settings', () => {
    const reducer = relateReducerInit({endpoint: '/test'});
    const newState = reducer();
    expect(newState).toEqual({
      headers: {
        'Content-Type': 'application/json',
        Accept: 'application/json'
      },
      endpoint: '/test'
    });
    const reducer1 = relateReducerInit({headers: {test: 1}});
    const newState1 = reducer1();
    expect(newState1).toEqual({
      headers: {
        test: 1
      },
      endpoint: '/test'
    });

    // revert
    const reducer2 = relateReducerInit({
      headers: {
        'Content-Type': 'application/json',
        Accept: 'application/json'
      },
      endpoint: '/graphql'
    });
    const newState2 = reducer2();
    expect(newState2).toEqual({
      headers: {
        'Content-Type': 'application/json',
        Accept: 'application/json'
      },
      endpoint: '/graphql'
    });
  });

  it('Does not alter state if query action does not have data or fragments', () => {
    const state = {something: 1};
    const newState = relateReducer(state, {type: actionTypes.query});
    const newState1 = relateReducer(state, {type: actionTypes.query, data: {}});
    expect(newState).toBe(state);
    expect(newState).toEqual(state);
    expect(newState1).toBe(state);
    expect(newState1).toEqual(state);
  });

  it('State returns connectors data from what was requested', () => {
    const state = {};
    const newState = relateReducer(state, {
      type: actionTypes.query,
      data: {
        pages: [{_id: 'a', title: 'some'}, {_id: 'b', title: 'another'}],
        page: {_id: 'c', title: 'other'}
      },
      fragments: {
        pages: {
          _id: 1,
          title: 1
        },
        page: {
          _id: 1,
          title: 1
        }
      },
      connectors: {
        connector1: {
          fragments: {
            pages: {
              _id: 1,
              title: 1
            }
          }
        },
        connector2: {
          fragments: {
            pages: {
              _id: 1,
              title: 1
            },
            page: {
              _id: 1,
              title: 1
            }
          }
        }
      }
    });
    expect(newState).toNotBe(state);
    expect(newState).toEqual({
      connector1: {
        pages: [
          {
            _id: 'a',
            title: 'some'
          },
          {
            _id: 'b',
            title: 'another'
          }
        ]
      },
      connector2: {
        pages: [
          {
            _id: 'a',
            title: 'some'
          },
          {
            _id: 'b',
            title: 'another'
          }
        ],
        page: {_id: 'c', title: 'other'}
      }
    });
  });
});
<commit_msg>improved testing for deep data structures<commit_after>import expect from 'expect';

import {relateReducer, relateReducerInit, actionTypes} from '../../lib';

describe('Reducer', () => {
  it('Does not alter state if not a Relate action', () => {
    const state = {something: 1};
    const newState = relateReducer(state, {type: 'not'});
    expect(newState).toBe(state);
    expect(newState).toEqual(state);
  });

  it('Reducer init returns with merged settings', () => {
    const reducer = relateReducerInit({endpoint: '/test'});
    const newState = reducer();
    expect(newState).toEqual({
      headers: {
        'Content-Type': 'application/json',
        Accept: 'application/json'
      },
      endpoint: '/test'
    });
    const reducer1 = relateReducerInit({headers: {test: 1}});
    const newState1 = reducer1();
    expect(newState1).toEqual({
      headers: {
        test: 1
      },
      endpoint: '/test'
    });

    // revert
    const reducer2 = relateReducerInit({
      headers: {
        'Content-Type': 'application/json',
        Accept: 'application/json'
      },
      endpoint: '/graphql'
    });
    const newState2 = reducer2();
    expect(newState2).toEqual({
      headers: {
        'Content-Type': 'application/json',
        Accept: 'application/json'
      },
      endpoint: '/graphql'
    });
  });

  it('Does not alter state if query action does not have data or fragments', () => {
    const state = {something: 1};
    const newState = relateReducer(state, {type: actionTypes.query});
    const newState1 = relateReducer(state, {type: actionTypes.query, data: {}});
    expect(newState).toBe(state);
    expect(newState).toEqual(state);
    expect(newState1).toBe(state);
    expect(newState1).toEqual(state);
  });

  it('State returns connectors data from what was requested', () => {
    const state = {};
    const newState = relateReducer(state, {
      type: actionTypes.query,
      data: {
        pages: [{_id: 'a', title: 'some'}, {_id: 'b', title: 'another'}],
        page: {_id: 'c', title: 'other'},
        root: {
          list: [{_id: 'd', title: 'd entry'}, {_id: 'e', title: 'e entry'}]
        }
      },
      fragments: {
        pages: {
          _id: 1,
          title: 1
        },
        page: {
          _id: 1,
          title: 1
        },
        root: {
          list: {
            _id: 1,
            title: 1
          }
        }
      },
      connectors: {
        connector1: {
          fragments: {
            pages: {
              _id: 1,
              title: 1
            }
          }
        },
        connector2: {
          fragments: {
            pages: {
              _id: 1,
              title: 1
            },
            page: {
              _id: 1,
              title: 1
            }
          }
        },
        connector3: {
          fragments: {
            root: {
              list: {
                _id: 1,
                title: 1
              }
            }
          }
        }
      }
    });
    expect(newState).toNotBe(state);
    expect(newState).toEqual({
      connector1: {
        pages: [
          {
            _id: 'a',
            title: 'some'
          },
          {
            _id: 'b',
            title: 'another'
          }
        ]
      },
      connector2: {
        pages: [
          {
            _id: 'a',
            title: 'some'
          },
          {
            _id: 'b',
            title: 'another'
          }
        ],
        page: {_id: 'c', title: 'other'}
      },
      connector3: {
        root: {
          list: [
            {
              _id: 'd',
              title: 'd entry'
            },
            {
              _id: 'e',
              title: 'e entry'
            }
          ]
        }
      }
    });
  });
});
<|endoftext|>


<commit_before><commit_msg>Fixed bugs: butterfly holes & ghost segments on drawn holes.<commit_after><|endoftext|>


<commit_before>"use strict";

/**
 * Users
 * @module users
 */
module.exports = api => {
  return {
    /**
     * Retrieve a user object.
     * @param {string|Number} userId - A user id
     * @param {Object} [params] - Additional URI parameters
     * @returns {Promise}
     */
    user(userId, params = {}) {
      return api.request(`/users/${userId}`, { params: params });
    },

    /**
     * Retrieve a users avatar image.
     * @param {string|Number} userId - A user id
     * @param {boolean} [true] - Should the return value be prebuffered via the fetch API?
     * @returns {Promise}
     */
    avatar(userId, buffered = true) {
      let options = buffered
        ? {
            resultAs: "buffer"
          }
        : {
            resultAs: "response"
          };
      return api.request(`/users/${userId}/avatar`, options);
    },

    /**
     * Upload a new avatar image
     * @param {object} form - A valid DOM node of a form with a file field named "avatar"
     * @returns {Promise}
     */
    uploadAvatar(form) {
      return api.request(`/users/me/avatar`, {
        httpMethod: "POST",
        dataAs: "dom-node",
        data: form
      });
    },

    /**
     * Upload a new cover image
     * @param {object} form - A valid DOM node of a form with a file field named "cover"
     * @returns {Promise}
     */
    uploadCover(form) {
      return api.request(`/users/me/cover`, {
        httpMethod: "POST",
        dataAs: "dom-node",
        data: form
      });
    },

    /**
     * Retrieve a users cover image.
     * @param {string|Number} userId - A user id
     * @param {boolean} [true] - Should the return value be prebuffered via the fetch API?
     * @returns {Promise}
     */
    cover(userId, buffered = true) {
      let options = buffered
        ? {
            resultAs: "buffer"
          }
        : {
            resultAs: "response"
          };
      return api.request(`/users/${userId}/cover`, options);
    },

    /**
     * Retrieve a list of specified user objects. Only retrieves the first 200 found.
     * @param {...string|Number} userIds - 1 or more user ids
     * @returns {Promise}
     */
    users(...userIds) {
      return api.request(`/users`, { params: { ids: userIds } });
    },

    /**
     * Retrieve posts mentioning the specified user.
     * @param {string|Number} userid - A user id
     * @param {Object} [params] - Additional URI parameters
     * @returns {Promise}
     */
    mentions(userId, params = {}) {
      return api.request(`/users/${userId}/mentions`, { params: params });
    },

    /**
     * Retrieve posts created by a specific user.
     * @param {string|Number} userId - A user id
     * @param {Object} [params] - Additional URI parameters
     * @returns {Promise}
     */
    postsFrom(userId, params = {}) {
      return api.request(`/users/${userId}/posts`, { params: params });
    },

    /**
     * Replaces the authenticated user's profile. Anything not included is removed.
     * @param {Object} profile - Object with the required API parameters
     * @returns {Promise}
     */
    replaceProfile(profile = {}) {
      return api.request("/users/me", {
        httpMethod: "PUT",
        data: profile
      });
    },

    /**
     * Updates only specified parts of the authenticated user's profile.
     * @param {Object} profile - Object with the require API parameters
     * @returns {Promise}
     */
    updateProfile(profile = {}) {
      return api.request("/users/me", {
        httpMethod: "PATCH",
        data: profile
      });
    },

    /**
     * Retrieve a list of user objects that the specified user is following.
     * @param {string|Number} userId - A user id
     * @param {Object} [params] - Additional URI parameters
     * @returns {Promise}
     */
    following(userId, params = {}) {
      return api.request(`/users/${userId}/following`, { params: params });
    },

    /**
     * Retrieve a list of user objects that are following the specified user.
     * @param {string|Number} userId - A user id
     * @param {Object} [params] - Additional URI parameters
     * @returns {Promise}
     */
    followers(userId, params = {}) {
      return api.request(`/users/${userId}/followers`, { params: params });
    },

    /**
     * Follow a user.
     * @param {string|Number} userId - id of user to follow
     * @returns {Promise}
     */
    follow(userId) {
      return api.request(`/users/${userId}/follow`, {
        httpMethod: "PUT"
      });
    },

    /**
     * Unfollow a user.
     * @param {string|Number} userId - id of the user to unfollow
     * @returns {Promise}
     */
    unfollow(userId) {
      return api.request(`/users/${userId}/follow`, {
        httpMethod: "DELETE"
      });
    },

    /**
     * Retrieve a list of muted users.
     * @param {Object} [params] - Additional URI parameters
     * @returns {Promise}
     */
    muted(params = {}) {
      return api.request(`/users/me/muted`, { params: params });
    },

    /**
     * Mute a user.
     * @param {string|Number} userId - id of the user to mute
     * @returns {Promise}
     */
    mute(userId) {
      return api.request(`/users/${userId}/mute`, {
        httpMethod: "PUT"
      });
    },

    /**
     * Unmute a user.
     * @param {string|Number} userId - id of the user to unmute
     * @returns {Promise}
     */
    unmute(userId) {
      return api.request(`/users/${userId}/mute`, {
        httpMethod: "DELETE"
      });
    },

    /**
     * Retrieve a list of blocked users.
     * @param {Object} [params] - Additional URI parameters
     * @returns {Promise}
     */
    blocked(params = {}) {
      return api.request(
        `/users/me/blocked`,
        {
          httpMethod: "GET"
        },
        { params: params }
      );
    },

    /**
     * Block a user.
     * @param {string|Number} userId - id of the user to block.
     * @returns {Promise}
     */
    block(userId) {
      return api.request(`/users/${userId}/block`, {
        httpMethod: "PUT"
      });
    },

    /**
     * Unblock a user.
     * @param {string} userId - id of the user to unblock.
     * @returns {Promise}
     */
    unblock(userId) {
      return api.request(`/users/${userId}/block`, {
        httpMethod: "DELETE"
      });
    },

    /**
     * Retrieve all users' presence statuses that are not "offline".
     * @param {Object} [params] - Additional URI parameters
     * @returns {Promise}
     */
    presence(params = {}) {
      return api.request("/presence", { params: params });
    },

    /**
     * Retrieve a user's presence.
     * @param {string} userId - A user id
     * @param {Object} [params] - Additional URI parameters
     * @returns {Promise}
     */
    presenceOf(userId, params = {}) {
      return api.request(`/presence/${userId}`, { params: params });
    },

    /**
     * Update a user's presence.
     * @param {string} msg - An optional status message
     * @returns {Promise}
     */
    updatePresence(msg) {
      let params = {
        httpMethod: "PUT"
      };
      if (msg) {
        params.data = {
          presence: msg
        };
      }

      return api.request("/users/me/presence", params);
    },

    /**
     * Retrieve a list of users filtered by the given criteria.
     *
     * @example
     * pnut.searchUsers({
     *  q: "news",
     *  types: "feed"
     * });
     * @param {Object} params
     */
    searchUsers(params = {}) {
      return api.request("/users/search", { params: params });
    }
  };
};
<commit_msg>Add missing JSDoc examples for the users module (#3)<commit_after>"use strict";

/**
 * Users
 * @module users
 */
module.exports = api => {
  return {
    /**
     * Retrieve a user object.
     * @param {string|Number} userId - A user id
     * @param {Object} [params] - Additional URI parameters
     * @returns {Promise}
     */
    user(userId, params = {}) {
      return api.request(`/users/${userId}`, { params: params });
    },

    /**
     * Retrieve a users avatar image.
     * @param {string|Number} userId - A user id
     * @param {boolean} [true] - Should the return value be prebuffered via the fetch API?
     * @returns {Promise}
     */
    avatar(userId, buffered = true) {
      let options = buffered
        ? {
            resultAs: "buffer"
          }
        : {
            resultAs: "response"
          };
      return api.request(`/users/${userId}/avatar`, options);
    },

    /**
     * Upload a new avatar image
     * @param {object} form - A valid DOM node of a form with a file field named "avatar"
     * @returns {Promise}
     */
    uploadAvatar(form) {
      return api.request(`/users/me/avatar`, {
        httpMethod: "POST",
        dataAs: "dom-node",
        data: form
      });
    },

    /**
     * Upload a new cover image
     * @param {object} form - A valid DOM node of a form with a file field named "cover"
     * @returns {Promise}
     */
    uploadCover(form) {
      return api.request(`/users/me/cover`, {
        httpMethod: "POST",
        dataAs: "dom-node",
        data: form
      });
    },

    /**
     * Retrieve a users cover image.
     *
     * @example
     * pnut.cover(1);
     * @param {string|Number} userId - A user id
     * @param {boolean} [true] - Should the return value be prebuffered via the fetch API?
     * @returns {Promise}
     */
    cover(userId, buffered = true) {
      let options = buffered
        ? {
            resultAs: "buffer"
          }
        : {
            resultAs: "response"
          };
      return api.request(`/users/${userId}/cover`, options);
    },

    /**
     * Retrieve a list of specified user objects. Only retrieves the first 200 found.
     *
     * @example
     * pnut.users(1,15,127);
     * @param {...string|Number} userIds - 1 or more user ids
     * @returns {Promise}
     */
    users(...userIds) {
      return api.request(`/users`, { params: { ids: userIds } });
    },

    /**
     * Retrieve posts mentioning the specified user.
     *
     * @example
     * pnut.mentions(1);
     * @param {string|Number} userid - A user id
     * @param {Object} [params] - Additional URI parameters
     * @returns {Promise}
     */
    mentions(userId, params = {}) {
      return api.request(`/users/${userId}/mentions`, { params: params });
    },

    /**
     * Retrieve posts created by a specific user.
     *
     * @example
     * pnut.postsFrom(1);
     * @param {string|Number} userId - A user id
     * @param {Object} [params] - Additional URI parameters
     * @returns {Promise}
     */
    postsFrom(userId, params = {}) {
      return api.request(`/users/${userId}/posts`, { params: params });
    },

    /**
     * Replaces the authenticated user's profile. Anything not included is removed.
     *
     * @example
     * pnut.replaceProfile({
     *   timezone: "Europe/Berlin",
     *   name: "Robert"
     * });
     * @param {Object} profile - Object with the required API parameters
     * @returns {Promise}
     */
    replaceProfile(profile = {}) {
      return api.request("/users/me", {
        httpMethod: "PUT",
        data: profile
      });
    },

    /**
     * Updates only specified parts of the authenticated user's profile.
     *
     * @example
     * pnut.updateProfile({
     *   timezone: "Europe/Berlin",
     *   name: "Robert"
     * });
     * @param {Object} profile - Object with the require API parameters
     * @returns {Promise}
     */
    updateProfile(profile = {}) {
      return api.request("/users/me", {
        httpMethod: "PATCH",
        data: profile
      });
    },

    /**
     * Retrieve a list of user objects that the specified user is following.
     *
     * @example
     * pnut.following(1);
     * @param {string|Number} userId - A user id
     * @param {Object} [params] - Additional URI parameters
     * @returns {Promise}
     */
    following(userId, params = {}) {
      return api.request(`/users/${userId}/following`, { params: params });
    },

    /**
     * Retrieve a list of user objects that are following the specified user.
     *
     * @example
     * pnut.followers(1);
     * @param {string|Number} userId - A user id
     * @param {Object} [params] - Additional URI parameters
     * @returns {Promise}
     */
    followers(userId, params = {}) {
      return api.request(`/users/${userId}/followers`, { params: params });
    },

    /**
     * Follow a user.
     *
     * @example
     * pnut.follow(1);
     * @param {string|Number} userId - id of user to follow
     * @returns {Promise}
     */
    follow(userId) {
      return api.request(`/users/${userId}/follow`, {
        httpMethod: "PUT"
      });
    },

    /**
     * Unfollow a user.
     *
     * @example
     * pnut.unfollow(1);
     * @param {string|Number} userId - id of the user to unfollow
     * @returns {Promise}
     */
    unfollow(userId) {
      return api.request(`/users/${userId}/follow`, {
        httpMethod: "DELETE"
      });
    },

    /**
     * Retrieve a list of muted users.
     *
     * @example
     * pnut.muted();
     * @param {Object} [params] - Additional URI parameters
     * @returns {Promise}
     */
    muted(params = {}) {
      return api.request(`/users/me/muted`, { params: params });
    },

    /**
     * Mute a user.
     *
     * @example
     * pnut.mute(1);
     * @param {string|Number} userId - id of the user to mute
     * @returns {Promise}
     */
    mute(userId) {
      return api.request(`/users/${userId}/mute`, {
        httpMethod: "PUT"
      });
    },

    /**
     * Unmute a user.
     *
     * @example
     * pnut.unmute(1);
     * @param {string|Number} userId - id of the user to unmute
     * @returns {Promise}
     */
    unmute(userId) {
      return api.request(`/users/${userId}/mute`, {
        httpMethod: "DELETE"
      });
    },

    /**
     * Retrieve a list of blocked users.
     *
     * @example
     * pnut.blocked();
     * @param {Object} [params] - Additional URI parameters
     * @returns {Promise}
     */
    blocked(params = {}) {
      return api.request(
        `/users/me/blocked`,
        {
          httpMethod: "GET"
        },
        { params: params }
      );
    },

    /**
     * Block a user.
     *
     * @example
     * pnut.block(1);
     * @param {string|Number} userId - id of the user to block.
     * @returns {Promise}
     */
    block(userId) {
      return api.request(`/users/${userId}/block`, {
        httpMethod: "PUT"
      });
    },

    /**
     * Unblock a user.
     *
     * @example
     * pnut.unblock(1);
     * @param {string} userId - id of the user to unblock.
     * @returns {Promise}
     */
    unblock(userId) {
      return api.request(`/users/${userId}/block`, {
        httpMethod: "DELETE"
      });
    },

    /**
     * Retrieve all users' presence statuses that are not "offline".
     *
     * @example
     * pnut.presence();
     * @param {Object} [params] - Additional URI parameters
     * @returns {Promise}
     */
    presence(params = {}) {
      return api.request("/presence", { params: params });
    },

    /**
     * Retrieve a user's presence.
     * @param {string} userId - A user id
     * @param {Object} [params] - Additional URI parameters
     * @returns {Promise}
     */
    presenceOf(userId, params = {}) {
      return api.request(`/presence/${userId}`, { params: params });
    },

    /**
     * Update a user's presence.
     * @param {string} msg - An optional status message
     * @returns {Promise}
     */
    updatePresence(msg) {
      let params = {
        httpMethod: "PUT"
      };
      if (msg) {
        params.data = {
          presence: msg
        };
      }

      return api.request("/users/me/presence", params);
    },

    /**
     * Retrieve a list of users filtered by the given criteria.
     *
     * @example
     * pnut.searchUsers({
     *  q: "news",
     *  types: "feed"
     * });
     * @param {Object} params
     */
    searchUsers(params = {}) {
      return api.request("/users/search", { params: params });
    }
  };
};
<|endoftext|>


<commit_before>var expect = require('chai').expect
  , types = require('../../..')
  , ArgumentTypeError = types.ArgumentTypeError
  , define = require('cli-define')
  , Option = define.Option;

describe('cli-types:', function() {
  var d = '2014-02-01';
  var dt = new Date(d);
  it('should coerce single value to date', function(done) {
    var value = d;
    var opt = new Option(
      '-d, --date <d>', 'a date argument');
    var res = types.date(value, opt);
    expect(res).to.eql(dt);
    done();
  });
  it('should error on invalid date', function(done) {
    var value = 'xyz' + d;
    var opt = new Option(
      '-d, --date <d>', 'a date argument');
    function func() {
      types.date(value, opt);
    }
    expect(func).to.throw(ArgumentTypeError);
    done();
  });
  //it('should coerce multiple values to array of dates', function(done) {
    //var cli = require('../../..')(pkg);
    //cli.configure({exit:false});
    //var args = ['-d', d, '--date=' + d];
    //cli
      //.option('-d, --date <date...>', 'a date argument', types.date)
      //.parse(args);
    //expect(cli.date).to.eql([dt, dt]);
    //done();
  //});
  //it('should error on invalid date in array', function(done) {
    //var cli = require('../../..')(pkg);
    //cli.configure({exit:false});
    //var args = ['-d', d, '--date=' + d, '--date', d + 'zyx'];
    //cli
      //.once('error',function(e) {
        ////expect(cli).to.eql(this);
        ////expect(code).to.eql(codes.ETYPE);
        ////parameters.unshift(message);
        ////console.error.apply(null, parameters);
        //done();
      //})
      //.option('-d, --date <date...>', 'a date argument', types.date)
    //cli.parse(args);
  //});
})
<commit_msg>Update date tests.<commit_after>var expect = require('chai').expect
  , types = require('../../..')
  , ArgumentTypeError = types.ArgumentTypeError
  , define = require('cli-define')
  , Option = define.Option;

describe('cli-types:', function() {
  var d = '2014-02-01';
  var dt = new Date(d);
  it('should coerce single value to date', function(done) {
    var value = d;
    var opt = new Option(
      '-d, --date <d>', 'a date argument');
    var res = types.date(value, opt);
    expect(res).to.eql(dt);
    done();
  });
  it('should error on invalid date', function(done) {
    var value = 'xyz' + d;
    var opt = new Option(
      '-d, --date <d>', 'a date argument');
    function func() {
      types.date(value, opt);
    }
    expect(func).to.throw(ArgumentTypeError);
    done();
  });
  it('should coerce multiple values to array of dates', function(done) {
    var value = [d, d];
    var opt = new Option(
      '-d, --date <d>', 'a date argument');
    var res = types.date(value, opt);
    expect(res).to.eql([dt, dt]);
    done();
  });
  it('should error on invalid date in array', function(done) {
    var value = [d, d, 'xyz'];
    var opt = new Option(
      '-d, --date <d>', 'a date argument');
    function func() {
      types.date(value, opt);
    }
    expect(func).to.throw(ArgumentTypeError);
    done();
  });
})
<|endoftext|>