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

import ReactBubbleChartD3 from './ReactBubbleChartD3';
import React              from 'react';
import ReactDOM           from 'react-dom';

// Description of props!

// data format:
// An array of data objects (defined below) used to populate the bubble chart.
// {
//    _id: string,        // unique id (required)
//    value: number,      // used to determine relative size of bubbles (required)
//    displayText: string,// will use _id if undefined
//    colorValue: number, // used to determine color
//    selected: boolean,  // if true will use selectedColor/selectedTextColor for circle/text
// }
//
// Can also be a nested JSON object if you want a nested bubble chart. That would look like:
// {
//   _id: string,
//   children: [
//     {data object},
//     {data object},
//     {
//       _id: string,
//       children: [...]
//     }
//   ]

// legend (optional)
// boolean. if true, create and show a legend based on the passed on colors

// colorLegend (optional)
// an array of:
// string || {
//   color: string,
//   text: string used in legend,
//   textColor: string (optional) - if specified will use this for the text color when
//              over bubbles with that color
// }
// If this is left undefined everything will render black. But fear not! we add
// the css class `bubble` to all... bubbles and `bubble leaf` if it has no
// children. This way if you want all bubbles to be styled the same way you can do
// so with just css instead of defining a color legend array.

// fixedDomain (optional)
// Used in tandum with the color legend. If defined, the minimum number corresponds
// to the minimum value in the color legend array, and the maximum corresponds to
// the max. The rest of the `colorValue` values will use a quantized domain to find
// their spot.
// If this is undefined we will use the min and max of the `colorValue`s of the
// dataset.
// {
//   min: number,
//   max: number
// }

// tooltip (optional)
// If `true`, will create a `<div>` as a sibling of the main `<svg>` chart, whose
// content will be populated by highlighting over one of the bubbles. The class of
// this element is `tooltip`. For now all of the styling is handled by this module,
// not by CSS.

// tooltipProps (optional)
// This is where you configure what is populated (and from where) in the tooltip.
// This is an array of objects or strings. The objects take three properties -
// `css`, `prop`, and `display` (optional). If you use a string instead of an
// object, that strings values will be used for all three.

// For each object in this array, we create a `<div>` whose class is specified by
// `css`. `prop` specifies what property of the data object to display in the
// tooltip. `display` (if specified) will prepend the string with `Value: `, if
// unspecified, nothing is prepended.

// tooltipFunc (optional)
// A function that is passed the domNode, the d3 data object, and the color of the
// tooltip on hover. Can be used if you want to do fancier dom stuff than just set
// some text values.

// selectedColor
// String hex value.
// If defined, will use this to color the circle corresponding to the data object
// whose `selected` property is true.

// selectedTextColor
// String hex value.
// If defined, will use this to color the text corresponding to the data object
// whose `selected` property is true.

// onClick
// Can pass a function that will be called with the data object when that bubble is
// clicked on.

// smallDiameter
// Can pass a number below which the label div will have the `small` class added.
// defaults to 40

// mediumDiameter
// Can pass a number below which the label div will have the `medium` class added,
// and above which the `large` class will be added. Defaults to 115.

// legendSpacing
// The number of pixels between blocks in the legend

// for more info, see the README

class ReactBubbleChart extends React.Component {
  constructor(props) {
    super(props);
    // define the method this way so that we have a clear reference to it
    // this is necessary so that window.removeEventListener will work properly
    this.handleResize = (e => this._handleResize(e));
  }

  /** Render town */
  render() {
    return

;
  }

  /** When we mount, intialize resize handler and create the bubbleChart */
  componentDidMount() {
    window.addEventListener('resize', this.handleResize);
    this.bubbleChart = new ReactBubbleChartD3(this.getDOMNode(), this.getChartState());
  }

  /** When we update, update our friend, the bubble chart */
  componentDidUpdate() {
    this.bubbleChart.update(this.getDOMNode(), this.getChartState());
  }

  /** Define what props get passed down to the d3 chart */
  getChartState() {
    return {
      data: this.props.data,
      colorLegend: this.props.colorLegend,
      fixedDomain: this.props.fixedDomain,
      selectedColor: this.props.selectedColor,
      selectedTextColor: this.props.selectedTextColor,
      onClick: this.props.onClick || () => {},
      smallDiameter: this.props.smallDiameter,
      mediumDiameter: this.props.mediumDiameter,
      legendSpacing: this.props.legendSpacing,
      legend: this.props.legend,
      tooltip: this.props.tooltip,
      tooltipProps: this.props.tooltipProps,
      tooltipFunc: this.props.tooltipFunc
    }
  }

  /** When we're piecing out, remove the handler and destroy the chart */
  componentWillUnmount() {
    window.removeEventListener('resize', this.handleResize);
    this.bubbleChart.destroy(this.getDOMNode());
  }

  /** Helper method to reference this dom node */
  getDOMNode() {
    return ReactDOM.findDOMNode(this);
  }

  /** On a debounce, adjust the size of our graph area and then update the chart */
  _handleResize(e) {
    this.__resizeTimeout && clearTimeout(this.__resizeTimeout);
    this.__resizeTimeout = setTimeout(() => {
      this.bubbleChart.adjustSize(this.getDOMNode());
      this.bubbleChart.update(this.getDOMNode(), this.getChartState());
      delete this.__resizeTimeout;
    }, 200);
  }
}

export default ReactBubbleChart;
<commit_msg>Add customizable font size and animation controls<commit_after>//------------------------------------------------------------------------------
// Copyright Jonathan Kaufman Corp. 2015
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//------------------------------------------------------------------------------

import ReactBubbleChartD3 from './ReactBubbleChartD3';
import React              from 'react';
import ReactDOM           from 'react-dom';

// Description of props!

// data format:
// An array of data objects (defined below) used to populate the bubble chart.
// {
//    _id: string,        // unique id (required)
//    value: number,      // used to determine relative size of bubbles (required)
//    displayText: string,// will use _id if undefined
//    colorValue: number, // used to determine color
//    selected: boolean,  // if true will use selectedColor/selectedTextColor for circle/text
// }
//
// Can also be a nested JSON object if you want a nested bubble chart. That would look like:
// {
//   _id: string,
//   children: [
//     {data object},
//     {data object},
//     {
//       _id: string,
//       children: [...]
//     }
//   ]

// legend (optional)
// boolean. if true, create and show a legend based on the passed on colors

// colorLegend (optional)
// an array of:
// string || {
//   color: string,
//   text: string used in legend,
//   textColor: string (optional) - if specified will use this for the text color when
//              over bubbles with that color
// }
// If this is left undefined everything will render black. But fear not! we add
// the css class `bubble` to all... bubbles and `bubble leaf` if it has no
// children. This way if you want all bubbles to be styled the same way you can do
// so with just css instead of defining a color legend array.

// fixedDomain (optional)
// Used in tandum with the color legend. If defined, the minimum number corresponds
// to the minimum value in the color legend array, and the maximum corresponds to
// the max. The rest of the `colorValue` values will use a quantized domain to find
// their spot.
// If this is undefined we will use the min and max of the `colorValue`s of the
// dataset.
// {
//   min: number,
//   max: number
// }

// tooltip (optional)
// If `true`, will create a `<div>` as a sibling of the main `<svg>` chart, whose
// content will be populated by highlighting over one of the bubbles. The class of
// this element is `tooltip`. For now all of the styling is handled by this module,
// not by CSS.

// tooltipProps (optional)
// This is where you configure what is populated (and from where) in the tooltip.
// This is an array of objects or strings. The objects take three properties -
// `css`, `prop`, and `display` (optional). If you use a string instead of an
// object, that strings values will be used for all three.

// For each object in this array, we create a `<div>` whose class is specified by
// `css`. `prop` specifies what property of the data object to display in the
// tooltip. `display` (if specified) will prepend the string with `Value: `, if
// unspecified, nothing is prepended.

// tooltipFunc (optional)
// A function that is passed the domNode, the d3 data object, and the color of the
// tooltip on hover. Can be used if you want to do fancier dom stuff than just set
// some text values.

// selectedColor
// String hex value.
// If defined, will use this to color the circle corresponding to the data object
// whose `selected` property is true.

// selectedTextColor
// String hex value.
// If defined, will use this to color the text corresponding to the data object
// whose `selected` property is true.

// onClick
// Can pass a function that will be called with the data object when that bubble is
// clicked on.

// smallDiameter
// Can pass a number below which the label div will have the `small` class added.
// defaults to 40

// mediumDiameter
// Can pass a number below which the label div will have the `medium` class added,
// and above which the `large` class will be added. Defaults to 115.

// legendSpacing
// The number of pixels between blocks in the legend

// for more info, see the README

class ReactBubbleChart extends React.Component {
  constructor(props) {
    super(props);
    // define the method this way so that we have a clear reference to it
    // this is necessary so that window.removeEventListener will work properly
    this.handleResize = (e => this._handleResize(e));
  }

  /** Render town */
  render() {
    return

;
  }

  /** When we mount, intialize resize handler and create the bubbleChart */
  componentDidMount() {
    window.addEventListener('resize', this.handleResize);
    this.bubbleChart = new ReactBubbleChartD3(this.getDOMNode(), this.getChartState());
  }

  /** When we update, update our friend, the bubble chart */
  componentDidUpdate() {
    this.bubbleChart.update(this.getDOMNode(), this.getChartState());
  }

  /** Define what props get passed down to the d3 chart */
  getChartState() {
    return {
      data: this.props.data,
      colorLegend: this.props.colorLegend,
      fixedDomain: this.props.fixedDomain,
      selectedColor: this.props.selectedColor,
      selectedTextColor: this.props.selectedTextColor,
      onClick: this.props.onClick || () => {},
      smallDiameter: this.props.smallDiameter,
      mediumDiameter: this.props.mediumDiameter,
      legendSpacing: this.props.legendSpacing,
      legend: this.props.legend,
      tooltip: this.props.tooltip,
      tooltipProps: this.props.tooltipProps,
      tooltipFunc: this.props.tooltipFunc,
      fontSizeFactor: this.props.fontSizeFactor,
      duration: this.props.duration,
      delay: this.props.delay
    }
  }

  /** When we're piecing out, remove the handler and destroy the chart */
  componentWillUnmount() {
    window.removeEventListener('resize', this.handleResize);
    this.bubbleChart.destroy(this.getDOMNode());
  }

  /** Helper method to reference this dom node */
  getDOMNode() {
    return ReactDOM.findDOMNode(this);
  }

  /** On a debounce, adjust the size of our graph area and then update the chart */
  _handleResize(e) {
    this.__resizeTimeout && clearTimeout(this.__resizeTimeout);
    this.__resizeTimeout = setTimeout(() => {
      this.bubbleChart.adjustSize(this.getDOMNode());
      this.bubbleChart.update(this.getDOMNode(), this.getChartState());
      delete this.__resizeTimeout;
    }, 200);
  }
}

export default ReactBubbleChart;
<|endoftext|>


<commit_before>(function() {
  /*
    ======== A Handy Little QUnit Reference ========
    http://api.qunitjs.com/

    Test methods:
      module(name, {[setup][ ,teardown]})
      test(name, callback)
      expect(numberOfAssertions)
      stop(increment)
      start(decrement)
    Test assertions:
      ok(value, [message])
      equal(actual, expected, [message])
      notEqual(actual, expected, [message])
      deepEqual(actual, expected, [message])
      notDeepEqual(actual, expected, [message])
      strictEqual(actual, expected, [message])
      notStrictEqual(actual, expected, [message])
      throws(block, [expected], [message])
  */

  var _ = Eventi._;
  module('Eventi declare', {
    setup: function() {
      //TODO? move declare test markup out of #qunit-fixture to avoid this?
      Eventi._.init();
    }
  });

  test('data-eventi...', function() {
    var el = document.querySelector('#declare'),
      attr = el.getAttribute('data-eventi'),
      listener = el[_._key];
    equal(attr, 'simple type#rich=alias /global', 'should have right attribute');
    ok(listener, 'should have a listener');
    ok(listener.s.simple, 'should listen for simple');
    ok(listener.s.type, 'should listen for type');
    ok(!listener.s.global, 'should not listen for global');
  });

  test('simple="mapped"', function() {
    expect(4);
    var parent = document.querySelector('#declare'),
      el = parent.querySelector('span');
    Eventi.on(parent, 'mapped', function(mapped, simple) {
      equal(mapped.type, 'mapped');
      equal(mapped.target, el);
      equal(this, parent);
      equal(simple.type, 'simple');
    });
    el.dispatchEvent(new CustomEvent('simple', {bubbles:true}));
    Eventi.off(parent, 'mapped');
  });

  test('type#rich=alias="handler"', function() {
    expect(3);
    var parent = document.getElementById('declare'),
      el = parent.children[0];
    window.handler = function(e) {
      equal(e.type, 'type');
      ok(e.rich);
      equal(this, el);// global handler fn still gets declared context
    };
    el.dispatchEvent(new Eventi('type#rich'));
    delete window.handler;
  });

  test('/global="elementHandle"', function() {
    expect(2);
    var parent = document.getElementById('declare'),
      el = parent.children[0];
    el.elementHandle = function(e) {
      equal(e.type, 'global');
      equal(this, el);// global event gets declared context
    };
    Eventi.fire(document.body, 'global');
    delete el.elementHandle;
  });

  test('click="remove"', function() {
    var parent = document.getElementById('declare'),
      el = parent.querySelector('[click]'),
      button = el.querySelector('button');
    if (!el.remove) {
      el.remove = function() {
        this.parentNode.removeChild(this);
      };
    }
    ok(el.parentNode, 'has parent node before event');
    Eventi.fire(button, 'click');
    ok(!el.parentNode, 'should not have parentNode anymore');
  });

  test('internal api presence', function() {
    ok(_.init, "_.init");
    ok(_.declare, "_.declare");
    ok(_.mapped, "_.mapped");
    ok(_.declarers, "_.declarers");
    ok(_.declared, "_.declared");
    ok(_.check, "_.check");
    ok(_.click, "_.click");
    ok(_.allowDefault, "_.allowDefault");
    ok(_.buttonRE, "_.buttonRE");
  });

  test('_.declarers w/target', function() {
    var mapper = document.getElementById('declare'),
      nodes = _.declarers(mapper, 'simple', mapper.querySelector('span'));
    equal(nodes.length, 2);
    equal(nodes[0], document.querySelector('#declare [simple]'));
    equal(nodes[1], mapper);
  });

  test('_.declarers global', function() {
    var mapper = document.getElementById('declare'),
      nodes = _.declarers(mapper, 'global', false);
    equal(nodes.length, 1);
    equal(nodes[0], document.querySelector('#declare [global]'));
  });

  function declared(type, value, fn) {
    var node = document.createElement('span');
    node.setAttribute(type, value);
    if (fn) {
      node[value] = fn;
    }
    document.getElementById('qunit-fixture').appendChild(node);
    _.declared(node, type, new CustomEvent(type));
  }

  test('_.declared mapped event', function() {
    expect(1);
    Eventi.on('type', function(e, oe) {
      equal(oe.type, 'mapped');
    });
    declared('mapped', 'type');
    Eventi.off('type');
  });

  test('_.declared local fn', function() {
    expect(1);
    declared('local', 'elementFn', function(e) {
      equal(e.type, 'local');
    });
  });

  test('_.declared global fn', function() {
    expect(1);
    window.globalFn = function(e) {
      equal(e.type, 'global');
    };
    declared('global', 'globalFn');
  });

  function click(name, attrs, enter) {
    if (attrs === true){ enter=attrs;attrs=null; }
    var node = document.createElement(name);
    if (attrs) {
      for (var key in attrs) {
        node.setAttribute(key, attrs[key]);
      }
    }
    document.getElementById('qunit-fixture').appendChild(node);
    return _.click(node, enter);
  }
  test('_.click', function() {
    ok(click('a'), 'a should be clickable');
    ok(click('a', {click:false}), '[click=false] should never be clickable');
    ok(!click('textarea'), 'textarea should not be clickable');
    ok(click('textarea', {click:true}), '[click=notfalse] should override other factors');
    ok(!click('div', {contenteditable:true}), '[contenteditable] should not be clickable');
    ok(click('button'), 'button should be clickable');
    ok(!click('select'), 'select should not be clickable');
    ok(!click('input'), 'input should not be clickable');
    ok(click('input', {type:'submit'}), 'input[submit] should be clickable');
    ok(click('input', {type:'button'}), 'input[button] should be clickable');
    ok(click('input', {type:'reset'}), 'input[reset] should be clickable');
  });

  function enter(name, attrs){ return click(name, attrs, true); }
  test('_.click from enter', function() {
    ok(enter('a'), 'a should translate enter to click');
    ok(enter('a', {click:false}), '[click=false] should never translate enter to click');
    ok(!enter('textarea'), 'textarea should not translate enter to click');
    ok(enter('textarea', {click:true}), '[click=notfalse] should override other factors');
    ok(!enter('div', {contenteditable:true}), '[contenteditable] should not be clickable');
    ok(enter('select'), 'select should translate enter to click');
    ok(!enter('button'), 'button should not translate enter to click');
    ok(enter('a'), 'a should translate enter to click when there\'s no href');
    ok(!enter('a', {href:'url'}), 'a[href] should not translate enter to click');
    ok(enter('input'), 'input should translate enter to click');
    ok(!enter('input', {type:'submit'}), 'input[type=submit] should not translate enter to click');
    ok(!enter('input', {type:'button'}), 'input[type=button] should not translate enter to click');
    ok(!enter('input', {type:'reset'}), 'input[type=reset] should not translate enter to click');
  });

}());
<commit_msg>null-safe mini-polyfill of remove()<commit_after>(function() {
  /*
    ======== A Handy Little QUnit Reference ========
    http://api.qunitjs.com/

    Test methods:
      module(name, {[setup][ ,teardown]})
      test(name, callback)
      expect(numberOfAssertions)
      stop(increment)
      start(decrement)
    Test assertions:
      ok(value, [message])
      equal(actual, expected, [message])
      notEqual(actual, expected, [message])
      deepEqual(actual, expected, [message])
      notDeepEqual(actual, expected, [message])
      strictEqual(actual, expected, [message])
      notStrictEqual(actual, expected, [message])
      throws(block, [expected], [message])
  */

  var _ = Eventi._;
  module('Eventi declare', {
    setup: function() {
      //TODO? move declare test markup out of #qunit-fixture to avoid this?
      Eventi._.init();
    }
  });

  test('data-eventi...', function() {
    var el = document.querySelector('#declare'),
      attr = el.getAttribute('data-eventi'),
      listener = el[_._key];
    equal(attr, 'simple type#rich=alias /global', 'should have right attribute');
    ok(listener, 'should have a listener');
    ok(listener.s.simple, 'should listen for simple');
    ok(listener.s.type, 'should listen for type');
    ok(!listener.s.global, 'should not listen for global');
  });

  test('simple="mapped"', function() {
    expect(4);
    var parent = document.querySelector('#declare'),
      el = parent.querySelector('span');
    Eventi.on(parent, 'mapped', function(mapped, simple) {
      equal(mapped.type, 'mapped');
      equal(mapped.target, el);
      equal(this, parent);
      equal(simple.type, 'simple');
    });
    el.dispatchEvent(new CustomEvent('simple', {bubbles:true}));
    Eventi.off(parent, 'mapped');
  });

  test('type#rich=alias="handler"', function() {
    expect(3);
    var parent = document.getElementById('declare'),
      el = parent.children[0];
    window.handler = function(e) {
      equal(e.type, 'type');
      ok(e.rich);
      equal(this, el);// global handler fn still gets declared context
    };
    el.dispatchEvent(new Eventi('type#rich'));
    delete window.handler;
  });

  test('/global="elementHandle"', function() {
    expect(2);
    var parent = document.getElementById('declare'),
      el = parent.children[0];
    el.elementHandle = function(e) {
      equal(e.type, 'global');
      equal(this, el);// global event gets declared context
    };
    Eventi.fire(document.body, 'global');
    delete el.elementHandle;
  });

  test('click="remove"', function() {
    var parent = document.getElementById('declare'),
      el = parent.querySelector('[click]'),
      button = el.querySelector('button');
    if (!el.remove) {
      el.remove = function() {
        if (this.parentNode) {
          this.parentNode.removeChild(this);
        }
      };
    }
    ok(el.parentNode, 'has parent node before event');
    Eventi.fire(button, 'click');
    ok(!el.parentNode, 'should not have parentNode anymore');
  });

  test('internal api presence', function() {
    ok(_.init, "_.init");
    ok(_.declare, "_.declare");
    ok(_.mapped, "_.mapped");
    ok(_.declarers, "_.declarers");
    ok(_.declared, "_.declared");
    ok(_.check, "_.check");
    ok(_.click, "_.click");
    ok(_.allowDefault, "_.allowDefault");
    ok(_.buttonRE, "_.buttonRE");
  });

  test('_.declarers w/target', function() {
    var mapper = document.getElementById('declare'),
      nodes = _.declarers(mapper, 'simple', mapper.querySelector('span'));
    equal(nodes.length, 2);
    equal(nodes[0], document.querySelector('#declare [simple]'));
    equal(nodes[1], mapper);
  });

  test('_.declarers global', function() {
    var mapper = document.getElementById('declare'),
      nodes = _.declarers(mapper, 'global', false);
    equal(nodes.length, 1);
    equal(nodes[0], document.querySelector('#declare [global]'));
  });

  function declared(type, value, fn) {
    var node = document.createElement('span');
    node.setAttribute(type, value);
    if (fn) {
      node[value] = fn;
    }
    document.getElementById('qunit-fixture').appendChild(node);
    _.declared(node, type, new CustomEvent(type));
  }

  test('_.declared mapped event', function() {
    expect(1);
    Eventi.on('type', function(e, oe) {
      equal(oe.type, 'mapped');
    });
    declared('mapped', 'type');
    Eventi.off('type');
  });

  test('_.declared local fn', function() {
    expect(1);
    declared('local', 'elementFn', function(e) {
      equal(e.type, 'local');
    });
  });

  test('_.declared global fn', function() {
    expect(1);
    window.globalFn = function(e) {
      equal(e.type, 'global');
    };
    declared('global', 'globalFn');
  });

  function click(name, attrs, enter) {
    if (attrs === true){ enter=attrs;attrs=null; }
    var node = document.createElement(name);
    if (attrs) {
      for (var key in attrs) {
        node.setAttribute(key, attrs[key]);
      }
    }
    document.getElementById('qunit-fixture').appendChild(node);
    return _.click(node, enter);
  }
  test('_.click', function() {
    ok(click('a'), 'a should be clickable');
    ok(click('a', {click:false}), '[click=false] should never be clickable');
    ok(!click('textarea'), 'textarea should not be clickable');
    ok(click('textarea', {click:true}), '[click=notfalse] should override other factors');
    ok(!click('div', {contenteditable:true}), '[contenteditable] should not be clickable');
    ok(click('button'), 'button should be clickable');
    ok(!click('select'), 'select should not be clickable');
    ok(!click('input'), 'input should not be clickable');
    ok(click('input', {type:'submit'}), 'input[submit] should be clickable');
    ok(click('input', {type:'button'}), 'input[button] should be clickable');
    ok(click('input', {type:'reset'}), 'input[reset] should be clickable');
  });

  function enter(name, attrs){ return click(name, attrs, true); }
  test('_.click from enter', function() {
    ok(enter('a'), 'a should translate enter to click');
    ok(enter('a', {click:false}), '[click=false] should never translate enter to click');
    ok(!enter('textarea'), 'textarea should not translate enter to click');
    ok(enter('textarea', {click:true}), '[click=notfalse] should override other factors');
    ok(!enter('div', {contenteditable:true}), '[contenteditable] should not be clickable');
    ok(enter('select'), 'select should translate enter to click');
    ok(!enter('button'), 'button should not translate enter to click');
    ok(enter('a'), 'a should translate enter to click when there\'s no href');
    ok(!enter('a', {href:'url'}), 'a[href] should not translate enter to click');
    ok(enter('input'), 'input should translate enter to click');
    ok(!enter('input', {type:'submit'}), 'input[type=submit] should not translate enter to click');
    ok(!enter('input', {type:'button'}), 'input[type=button] should not translate enter to click');
    ok(!enter('input', {type:'reset'}), 'input[type=reset] should not translate enter to click');
  });

}());
<|endoftext|>


<commit_before>import template from './appstore-store.html';

const appstoreStore = {
  template,
  controller: AppStoreController,
  controllerAs: 'AppStore',
};

export default appstoreStore;

// @ngInject
function AppStoreController(
  baseControllerAddClass,
  servicesService,
  currentStateService,
  usersService,
  ENV,
  ncUtils,
  $q,
  $injector,
  $state,
  resourcesService,
  joinService,
  ncUtilsFlash,
  projectsService,
  priceEstimationService,
  ncServiceUtils,
  resourceUtils,
  coreUtils,
  CategoriesService,
  AppstoreFieldConfiguration,
  AppstoreResourceLoader,
  AppstoreProvidersService,
  AppStoreUtilsService,
  BreadcrumbsService,
  ResourceProvisionPolicy) {
  let controllerScope = this;
  let Controller = baseControllerAddClass.extend({
    enablePurchaseCostDisplay: ENV.enablePurchaseCostDisplay,

    secondStep: false,
    resourceTypesBlock: false,
    loadingResourceProperties: false,

    successMessage: gettext('Purchase of {vm_name} was successful.'),
    formOptions: {},
    allFormOptions: {},
    selectedService: {},
    serviceType: null,
    selectedCategory: {},
    selectedResourceType: null,
    currentCustomer: {},
    currentProject: {},
    services: {},
    renderStore: false,
    loadingProviders: true,
    categoryServices: {},

    configureStepNumber: 4,
    fields: [],

    init:function() {
      this.service = resourcesService;
      this.controllerScope = controllerScope;
      this._super();
    },
    activate:function() {
      this.loading = true;
      $q.all([
        usersService.getCurrentUser().then(user =>
          this.currentUser = user),
        currentStateService.getCustomer().then(customer =>
          this.currentCustomer = customer),
        servicesService.getServicesList().then(servicesMetadata =>
          this.servicesMetadata = servicesMetadata)
      ])
      .then(() => this.setCurrentProject())
      .then(() => this.refreshBreadcrumbs())
      .finally(() => this.loading = false);
    },
    refreshBreadcrumbs: function() {
      BreadcrumbsService.items = [
        {
          label: gettext('Project workspace'),
          state: 'project.details',
          params: {
            uuid: this.currentProject.uuid
          }
        },
        {
          label: gettext('Service store'),
          action: () => AppStoreUtilsService.openDialog(),
        }
      ];
      if (this.selectedCategory) {
        BreadcrumbsService.activeItem = this.selectedCategory.name;
      }
    },
    setCategory: function(category) {
      if (category === this.selectedCategory) {
        return;
      }

      const { disabled, errorMessage } = ResourceProvisionPolicy.checkResource(
        this.currentUser, this.currentCustomer, this.currentProject, category.key
      );
      if (disabled) {
        this.policyErrorMessage = errorMessage;
        return;
      }

      this.selectedCategory = category;
      this.secondStep = true;
      this.serviceMetadata = {};
      this.serviceType = null;
      this.resourceTypesBlock = false;
      this.selectedResourceType = null;
      this.selectedResourceTypeName = null;
      this.selectedService = null;
      this.fields = [];

      let services = this.getServices();
      this.renderStore = services && services.length > 0;

      if (services && services.length === 1) {
        this.setService(services[0]);
      }

      this.refreshBreadcrumbs();
    },
    getServices: function() {
      if (this.selectedCategory) {
        return this.categoryServices[this.selectedCategory.name];
      }
    },
    setService: function(service) {
      if (!service.enabled) {
        return;
      }
      this.selectedService = service;
      this.serviceType = this.selectedService.type;
      this.serviceMetadata = this.servicesMetadata[this.serviceType];
      this.fields = [];
      this.selectedResourceType = null;

      if (this.serviceMetadata) {
        let types = this.getResourceTypes(this.selectedCategory.key, this.serviceType);
        if (types.length === 1) {
          this.setResourceType(types[0]);
          this.resourceTypesBlock = false;
          this.configureStepNumber = 3;
        } else {
          this.resourceTypesBlock = true;
          this.configureStepNumber = 4;
        }
      }
    },
    getResourceTypes: function(category, serviceType) {
      let types = ENV.resourceCategory;
      let blacklisted = ['OpenStackTenant.Snapshot'];
      return Object.keys(types).filter(function(resource) {
        return types[resource] === category &&
               resource.split('.')[0] === serviceType &&
               blacklisted.indexOf(resource) === -1;
      }).map(function(resource) {
        return resource.split('.')[1];
      });
    },
    resetResourceType: function() {
      let vm = this;
      vm.selectedResourceType = null;
      vm.selectedResourceTypeName = null;
      vm.fields = [];
      vm.instance = null;
      vm.allFormOptions = null;
    },
    setResourceType: function(type) {
      this.selectedResourceType = type;
      this.errors = {};
      this.selectedResourceTypeName = type.split(/(?=[A-Z])/).join(' ');
      this.fields = [];

      this.loadingResourceProperties = true;
      return servicesService.getOption(this.getResourceUrl()).then(response => {
        let key = this.serviceType + '.' + this.selectedResourceType;
        let fields = angular.copy(AppstoreFieldConfiguration[key]);
        if (!fields) {
          fields = {
            order: Object.keys(response.actions.POST).filter(key => key !== 'service_project_link'),
            options: response.actions.POST
          };
        } else {
          fields.order = fields.order.filter(name => {
            const field = fields.options[name];
            return !field || !field.is_visible || field.is_visible(ENV);
          });
        }
        let formOptions = angular.merge({}, response.actions.POST, fields.options);
        delete formOptions.project;
        delete formOptions.service_settings;
        this.fields = fields;

        this.allFormOptions = formOptions;
        return AppstoreResourceLoader
          .loadValidChoices(this.getContext(), formOptions)
          .then(validChoices => angular.forEach(validChoices, (choices, name) => {
            if (this.fields.options.hasOwnProperty(name)) {
              this.fields.options[name].choices = choices;
            }
          }));
      }).finally(() => {
        this.instance = this.getInstance();
        this.loadingResourceProperties = false;
      });
    },
    getInstance: function() {
      return {
        type: this.selectedResourceType,
        customer: this.currentCustomer,
        project: this.currentProject,
        service: this.selectedService,
        service_project_link: this.selectedService.service_project_link_url
      };
    },
    getContext: function() {
      return {
        project: this.currentProject.uuid,
        project_uuid: this.currentProject.uuid,
        service_uuid: this.selectedService.uuid,
        settings_uuid: this.selectedService.settings_uuid,
        service_settings_uuid: this.selectedService.settings_uuid,
      };
    },
    getServiceTypeDisplay: ncServiceUtils.getTypeDisplay,
    formatResourceType: resourceUtils.formatResourceType,
    setCurrentProject: function() {
      let vm = this;
      let categories = CategoriesService.getResourceCategories();
      vm.categories = [];
      vm.selectedCategory = null;
      vm.secondStep = false;
      vm.serviceMetadata = {};
      vm.serviceType = null;
      vm.resourceTypesBlock = false;
      vm.fields = [];
      vm.selectedResourceType = null;
      vm.instance = null;
      vm.renderStore = false;
      vm.loadingProviders = true;

      return currentStateService.getProject().then(function(project) {
        vm.currentProject = project;
        return AppstoreProvidersService.loadServices(project).then(function() {
          for (let j = 0; j < categories.length; j++) {
            let category = categories[j];
            vm.categoryServices[category.name] = [];
            for (let i = 0; i < vm.currentProject.services.length; i++) {
              let service = vm.currentProject.services[i];
              if (category.services && (category.services.indexOf(service.type) + 1)) {
                vm.categoryServices[category.name].push(service);
              }
            }
            if (vm.categoryServices[category.name].length > 0) {
              vm.categories.push(category);
            }
            vm.categoryServices[category.name].sort(function(a, b) {
              return a.enabled < b.enabled;
            });
          }
          vm.setCategoryFromParams();
        });
      }).finally(function() {
        vm.loadingProviders = false;
      });
    },
    setCategoryFromParams: function() {
      let vm = this;
      let key = $state.$current.data.category;
      if (key) {
        for (let i = 0; i < vm.categories.length; i++) {
          let category = vm.categories[i];
          if (category.key === key) {
            vm.setCategory(category);
            return;
          }
        }
      }
    },
    canSave: function() {
      if (!this.instance) {
        return false;
      }
      for (let name in this.allFormOptions) {
        if (this.allFormOptions[name].required && (!this.instance[name] && this.instance[name] !== 0)) {
          return false;
        }
      }
      return true;
    },
    getTooltip: function() {
      if (!this.instance) {
        return gettext('Instance is not configured.');
      }
      let fields = [];
      for (let name in this.allFormOptions) {
        let options = this.allFormOptions[name];
        if (options.required && !this.instance[name]) {
          fields.push(options.label);
        }
      }
      if (fields.length > 0) {
        return coreUtils.templateFormatter(gettext('Please specify {fields}.'), {
          fields: fields.join(', ').toLowerCase()
        });
      }
    },
    getResourceUrl: function() {
      if (this.selectedResourceType === 'Tenant') {
        return ENV.apiEndpoint + 'api/openstack-packages/';
      }
      return this.serviceMetadata.resources[this.selectedResourceType];
    },
    save: function() {
      let callback = this._super.bind(this);

      if (!this.canSave()) {
        return $q.reject();
      } else if (this.fields.hasOwnProperty('saveConfirmation')) {
        return this.fields.saveConfirmation($q, this.instance).then(() => {
          // _super is getting lost in clojures.
          return callback();
        }).catch(()=> {
          return $q.reject();
        });
      }

      return callback();
    },
    saveInstance: function() {
      let resourceUrl = this.getResourceUrl();
      let instance = servicesService.$create(resourceUrl);
      instance.service_project_link = this.selectedService.service_project_link_url;

      for (let name in this.allFormOptions) {
        if (this.instance.hasOwnProperty(name)) {
          let value = this.instance[name];
          let option = this.allFormOptions[name];
          if (value && value.hasOwnProperty('url')) {
            value = value.url;
          }
          if (option.serializer) {
            value = option.serializer(value, option);
          }
          instance[name] = value;
        }
      }
      return instance.$save();
    },
    afterSave: function() {
      this._super();
      projectsService.clearAllCacheForCurrentEndpoint();
      priceEstimationService.clearAllCacheForCurrentEndpoint();
      joinService.clearAllCacheForCurrentEndpoint();
      if (this.fields.onSuccess) {
        this.fields.onSuccess($injector);
      }
    },
    onError: function() {
      let message = '';
      if (angular.isObject(this.errors)) {
        for (let name in this.errors) {
          if (this.allFormOptions[name]) {
            message += this.allFormOptions[name].label + ': ' + this.errors[name] + '
';
          } else {
            message += name + ': ' + this.errors[name] + '
';
          }
        }
      } else {
        message = gettext('Server error occurred.');
      }
      ncUtilsFlash.error(message);
    },
    successRedirect: function(model) {
      if (this.selectedResourceType === 'Tenant') {
        $state.go('resources.details', {
          uuid: ncUtils.getUUID(model.tenant),
          resource_type: 'OpenStack.Tenant'
        });
      } else {
        $state.go('resources.details', {uuid: model.uuid, resource_type: model.resource_type});
      }
    }
  });

  controllerScope.__proto__ = new Controller();
}
<commit_msg>Fix OpenStack creation form: remove type field in AppStore instance.<commit_after>import template from './appstore-store.html';

const appstoreStore = {
  template,
  controller: AppStoreController,
  controllerAs: 'AppStore',
};

export default appstoreStore;

// @ngInject
function AppStoreController(
  baseControllerAddClass,
  servicesService,
  currentStateService,
  usersService,
  ENV,
  ncUtils,
  $q,
  $injector,
  $state,
  resourcesService,
  joinService,
  ncUtilsFlash,
  projectsService,
  priceEstimationService,
  ncServiceUtils,
  resourceUtils,
  coreUtils,
  CategoriesService,
  AppstoreFieldConfiguration,
  AppstoreResourceLoader,
  AppstoreProvidersService,
  AppStoreUtilsService,
  BreadcrumbsService,
  ResourceProvisionPolicy) {
  let controllerScope = this;
  let Controller = baseControllerAddClass.extend({
    enablePurchaseCostDisplay: ENV.enablePurchaseCostDisplay,

    secondStep: false,
    resourceTypesBlock: false,
    loadingResourceProperties: false,

    successMessage: gettext('Purchase of {vm_name} was successful.'),
    formOptions: {},
    allFormOptions: {},
    selectedService: {},
    serviceType: null,
    selectedCategory: {},
    selectedResourceType: null,
    currentCustomer: {},
    currentProject: {},
    services: {},
    renderStore: false,
    loadingProviders: true,
    categoryServices: {},

    configureStepNumber: 4,
    fields: [],

    init:function() {
      this.service = resourcesService;
      this.controllerScope = controllerScope;
      this._super();
    },
    activate:function() {
      this.loading = true;
      $q.all([
        usersService.getCurrentUser().then(user =>
          this.currentUser = user),
        currentStateService.getCustomer().then(customer =>
          this.currentCustomer = customer),
        servicesService.getServicesList().then(servicesMetadata =>
          this.servicesMetadata = servicesMetadata)
      ])
      .then(() => this.setCurrentProject())
      .then(() => this.refreshBreadcrumbs())
      .finally(() => this.loading = false);
    },
    refreshBreadcrumbs: function() {
      BreadcrumbsService.items = [
        {
          label: gettext('Project workspace'),
          state: 'project.details',
          params: {
            uuid: this.currentProject.uuid
          }
        },
        {
          label: gettext('Service store'),
          action: () => AppStoreUtilsService.openDialog(),
        }
      ];
      if (this.selectedCategory) {
        BreadcrumbsService.activeItem = this.selectedCategory.name;
      }
    },
    setCategory: function(category) {
      if (category === this.selectedCategory) {
        return;
      }

      const { disabled, errorMessage } = ResourceProvisionPolicy.checkResource(
        this.currentUser, this.currentCustomer, this.currentProject, category.key
      );
      if (disabled) {
        this.policyErrorMessage = errorMessage;
        return;
      }

      this.selectedCategory = category;
      this.secondStep = true;
      this.serviceMetadata = {};
      this.serviceType = null;
      this.resourceTypesBlock = false;
      this.selectedResourceType = null;
      this.selectedResourceTypeName = null;
      this.selectedService = null;
      this.fields = [];

      let services = this.getServices();
      this.renderStore = services && services.length > 0;

      if (services && services.length === 1) {
        this.setService(services[0]);
      }

      this.refreshBreadcrumbs();
    },
    getServices: function() {
      if (this.selectedCategory) {
        return this.categoryServices[this.selectedCategory.name];
      }
    },
    setService: function(service) {
      if (!service.enabled) {
        return;
      }
      this.selectedService = service;
      this.serviceType = this.selectedService.type;
      this.serviceMetadata = this.servicesMetadata[this.serviceType];
      this.fields = [];
      this.selectedResourceType = null;

      if (this.serviceMetadata) {
        let types = this.getResourceTypes(this.selectedCategory.key, this.serviceType);
        if (types.length === 1) {
          this.setResourceType(types[0]);
          this.resourceTypesBlock = false;
          this.configureStepNumber = 3;
        } else {
          this.resourceTypesBlock = true;
          this.configureStepNumber = 4;
        }
      }
    },
    getResourceTypes: function(category, serviceType) {
      let types = ENV.resourceCategory;
      let blacklisted = ['OpenStackTenant.Snapshot'];
      return Object.keys(types).filter(function(resource) {
        return types[resource] === category &&
               resource.split('.')[0] === serviceType &&
               blacklisted.indexOf(resource) === -1;
      }).map(function(resource) {
        return resource.split('.')[1];
      });
    },
    resetResourceType: function() {
      let vm = this;
      vm.selectedResourceType = null;
      vm.selectedResourceTypeName = null;
      vm.fields = [];
      vm.instance = null;
      vm.allFormOptions = null;
    },
    setResourceType: function(type) {
      this.selectedResourceType = type;
      this.errors = {};
      this.selectedResourceTypeName = type.split(/(?=[A-Z])/).join(' ');
      this.fields = [];

      this.loadingResourceProperties = true;
      return servicesService.getOption(this.getResourceUrl()).then(response => {
        let key = this.serviceType + '.' + this.selectedResourceType;
        let fields = angular.copy(AppstoreFieldConfiguration[key]);
        if (!fields) {
          fields = {
            order: Object.keys(response.actions.POST).filter(key => key !== 'service_project_link'),
            options: response.actions.POST
          };
        } else {
          fields.order = fields.order.filter(name => {
            const field = fields.options[name];
            return !field || !field.is_visible || field.is_visible(ENV);
          });
        }
        let formOptions = angular.merge({}, response.actions.POST, fields.options);
        delete formOptions.project;
        delete formOptions.service_settings;
        this.fields = fields;

        this.allFormOptions = formOptions;
        return AppstoreResourceLoader
          .loadValidChoices(this.getContext(), formOptions)
          .then(validChoices => angular.forEach(validChoices, (choices, name) => {
            if (this.fields.options.hasOwnProperty(name)) {
              this.fields.options[name].choices = choices;
            }
          }));
      }).finally(() => {
        this.instance = this.getInstance();
        this.loadingResourceProperties = false;
      });
    },
    getInstance: function() {
      return {
        customer: this.currentCustomer,
        project: this.currentProject,
        service: this.selectedService,
        service_project_link: this.selectedService.service_project_link_url
      };
    },
    getContext: function() {
      return {
        project: this.currentProject.uuid,
        project_uuid: this.currentProject.uuid,
        service_uuid: this.selectedService.uuid,
        settings_uuid: this.selectedService.settings_uuid,
        service_settings_uuid: this.selectedService.settings_uuid,
      };
    },
    getServiceTypeDisplay: ncServiceUtils.getTypeDisplay,
    formatResourceType: resourceUtils.formatResourceType,
    setCurrentProject: function() {
      let vm = this;
      let categories = CategoriesService.getResourceCategories();
      vm.categories = [];
      vm.selectedCategory = null;
      vm.secondStep = false;
      vm.serviceMetadata = {};
      vm.serviceType = null;
      vm.resourceTypesBlock = false;
      vm.fields = [];
      vm.selectedResourceType = null;
      vm.instance = null;
      vm.renderStore = false;
      vm.loadingProviders = true;

      return currentStateService.getProject().then(function(project) {
        vm.currentProject = project;
        return AppstoreProvidersService.loadServices(project).then(function() {
          for (let j = 0; j < categories.length; j++) {
            let category = categories[j];
            vm.categoryServices[category.name] = [];
            for (let i = 0; i < vm.currentProject.services.length; i++) {
              let service = vm.currentProject.services[i];
              if (category.services && (category.services.indexOf(service.type) + 1)) {
                vm.categoryServices[category.name].push(service);
              }
            }
            if (vm.categoryServices[category.name].length > 0) {
              vm.categories.push(category);
            }
            vm.categoryServices[category.name].sort(function(a, b) {
              return a.enabled < b.enabled;
            });
          }
          vm.setCategoryFromParams();
        });
      }).finally(function() {
        vm.loadingProviders = false;
      });
    },
    setCategoryFromParams: function() {
      let vm = this;
      let key = $state.$current.data.category;
      if (key) {
        for (let i = 0; i < vm.categories.length; i++) {
          let category = vm.categories[i];
          if (category.key === key) {
            vm.setCategory(category);
            return;
          }
        }
      }
    },
    canSave: function() {
      if (!this.instance) {
        return false;
      }
      for (let name in this.allFormOptions) {
        if (this.allFormOptions[name].required && (!this.instance[name] && this.instance[name] !== 0)) {
          return false;
        }
      }
      return true;
    },
    getTooltip: function() {
      if (!this.instance) {
        return gettext('Instance is not configured.');
      }
      let fields = [];
      for (let name in this.allFormOptions) {
        let options = this.allFormOptions[name];
        if (options.required && !this.instance[name]) {
          fields.push(options.label);
        }
      }
      if (fields.length > 0) {
        return coreUtils.templateFormatter(gettext('Please specify {fields}.'), {
          fields: fields.join(', ').toLowerCase()
        });
      }
    },
    getResourceUrl: function() {
      if (this.selectedResourceType === 'Tenant') {
        return ENV.apiEndpoint + 'api/openstack-packages/';
      }
      return this.serviceMetadata.resources[this.selectedResourceType];
    },
    save: function() {
      let callback = this._super.bind(this);

      if (!this.canSave()) {
        return $q.reject();
      } else if (this.fields.hasOwnProperty('saveConfirmation')) {
        return this.fields.saveConfirmation($q, this.instance).then(() => {
          // _super is getting lost in clojures.
          return callback();
        }).catch(()=> {
          return $q.reject();
        });
      }

      return callback();
    },
    saveInstance: function() {
      let resourceUrl = this.getResourceUrl();
      let instance = servicesService.$create(resourceUrl);
      instance.service_project_link = this.selectedService.service_project_link_url;

      for (let name in this.allFormOptions) {
        if (this.instance.hasOwnProperty(name)) {
          let value = this.instance[name];
          let option = this.allFormOptions[name];
          if (value && value.hasOwnProperty('url')) {
            value = value.url;
          }
          if (option.serializer) {
            value = option.serializer(value, option);
          }
          instance[name] = value;
        }
      }
      return instance.$save();
    },
    afterSave: function() {
      this._super();
      projectsService.clearAllCacheForCurrentEndpoint();
      priceEstimationService.clearAllCacheForCurrentEndpoint();
      joinService.clearAllCacheForCurrentEndpoint();
      if (this.fields.onSuccess) {
        this.fields.onSuccess($injector);
      }
    },
    onError: function() {
      let message = '';
      if (angular.isObject(this.errors)) {
        for (let name in this.errors) {
          if (this.allFormOptions[name]) {
            message += this.allFormOptions[name].label + ': ' + this.errors[name] + '
';
          } else {
            message += name + ': ' + this.errors[name] + '
';
          }
        }
      } else {
        message = gettext('Server error occurred.');
      }
      ncUtilsFlash.error(message);
    },
    successRedirect: function(model) {
      if (this.selectedResourceType === 'Tenant') {
        $state.go('resources.details', {
          uuid: ncUtils.getUUID(model.tenant),
          resource_type: 'OpenStack.Tenant'
        });
      } else {
        $state.go('resources.details', {uuid: model.uuid, resource_type: model.resource_type});
      }
    }
  });

  controllerScope.__proto__ = new Controller();
}
<|endoftext|>


<commit_before>
/**
 * Module depedencies.
 */

var assert = require('assert')
var should = require('should')
var time = require('../')

describe('exports', function () {

  it('should be a function', function () {
    time.should.be.a('function')
  })

  it('should return itself when invoked', function () {
    var dummy = function () {}
    time(dummy).should.equal(time)
  })

  it('should add node-time extensions to the passed in function\'s prototype'
  , function () {
    var dummy = function () {}
      , proto = dummy.prototype

    proto.should.not.have.property('setTimezone')
    proto.should.not.have.property('getTimezone')
    proto.should.not.have.property('getTimezoneAbbr')
    time(dummy)
    proto.should.have.property('setTimezone')
    proto.should.have.property('getTimezone')
    proto.should.have.property('getTimezoneAbbr')

  })

  it('should throw if in invalid object is passed into it', function () {
    assert.throws(time)
  })

  it('should have a "currentTimezone" property', function () {
    time.should.have.property('currentTimezone')
    assert(time.currentTimezone)
  })

  describe('localtime()', function () {

    // GH-40
    it('should not segfault on a NaN Date value', function () {
      var invalid = new Date(NaN)
      var local = time.localtime(invalid.getTime())
      assert.deepEqual({ invalid: true }, local)
    })

  })

  describe('Date', function () {

    it('should have a "Date" property', function () {
      time.should.have.property('Date')
    })

    it('should *not* be the global "Date" object', function () {
      time.Date.should.not.equal(Date)
    })

    it('should return a real "Date" instance', function () {
      var d = new time.Date()
      Object.prototype.toString.call(d).should.equal('[object Date]')
    })

    it('should pass `time.Date` instanceof', function () {
      var d = new time.Date()
      assert(d instanceof time.Date)
    })

    it('should not pass global instanceof', function () {
      var d = new time.Date()
      assert.equal(d instanceof Date, false)
    })

    it('should already have the node-time extensions', function () {
      should.exist(time.Date.prototype.setTimezone)
      should.exist(time.Date.prototype.getTimezone)
      should.exist(time.Date.prototype.getTimezoneAbbr)
    })

    it('should have all the regular Date properties', function () {
      time.Date.should.have.property('now')
      time.Date.should.have.property('parse')
      time.Date.should.have.property('UTC')
    })

  })

})
<commit_msg>test: remove "should" usage from exports.js test<commit_after>
/**
 * Module depedencies.
 */

var assert = require('assert')
var time = require('../')

describe('exports', function () {

  it('should be a function', function () {
    assert.equal(typeof time, 'function')
  })

  it('should return itself when invoked', function () {
    var dummy = function () {}
    assert.equal(time(dummy), time)
  })

  it('should add node-time extensions to the passed in function\'s prototype',
  function () {
    var dummy = function () {}
    var proto = dummy.prototype

    assert.notEqual('function', typeof proto.setTimezone);
    assert.notEqual('function', typeof proto.getTimezone);
    assert.notEqual('function', typeof proto.getTimezoneAbbr);
    time(dummy)
    assert.equal('function', typeof proto.setTimezone);
    assert.equal('function', typeof proto.getTimezone);
    assert.equal('function', typeof proto.getTimezoneAbbr);
  })

  it('should throw if in invalid object is passed into it', function () {
    assert.throws(time)
  })

  it('should have a "currentTimezone" property', function () {
    assert.equal('string', typeof time.currentTimezone);
    assert(time.currentTimezone)
  })

  describe('localtime()', function () {

    // GH-40
    it('should not segfault on a NaN Date value', function () {
      var invalid = new Date(NaN)
      var local = time.localtime(invalid.getTime())
      assert.deepEqual({ invalid: true }, local)
    })

  })

  describe('Date', function () {

    it('should have a "Date" property', function () {
      assert.equal('function', typeof time.Date);
    })

    it('should *not* be the global "Date" object', function () {
      assert.notStrictEqual(time.Date, Date);
    })

    it('should return a real "Date" instance', function () {
      var d = new time.Date()
      assert.equal(Object.prototype.toString.call(d), '[object Date]')
    })

    it('should pass `time.Date` instanceof', function () {
      var d = new time.Date()
      assert(d instanceof time.Date)
    })

    it('should not pass global instanceof', function () {
      var d = new time.Date()
      assert.equal(d instanceof Date, false)
    })

    it('should already have the node-time extensions', function () {
      assert.equal('function', typeof time.Date.prototype.setTimezone)
      assert.equal('function', typeof time.Date.prototype.getTimezone)
      assert.equal('function', typeof time.Date.prototype.getTimezoneAbbr)
    })

    it('should have all the regular Date properties', function () {
      assert.equal('function', typeof time.Date.now)
      assert.equal('function', typeof time.Date.parse)
      assert.equal('function', typeof time.Date.UTC)
    })

  })

})
<|endoftext|>


<commit_before>'use strict';

module.exports = function (grunt) {

    grunt.registerMultiTask('componentTest',
        'Starts a web server for running component tests again', function () {

            var options = this.options(this.data);
            var done = this.async();

            require('..')(options, function() {
                done();
            });

        });

};<commit_msg>added phantomjs support<commit_after>'use strict';

module.exports = function (grunt) {

    grunt.registerMultiTask('componentTest',
        'Starts a web server for running component tests again', function () {

            var options = this.options(this.data);
            var done = this.async(),
                page;

            var server = require('..')(options, grunt.log.debug);
            var url = "http://localhost:" + options.port;

            if (options.runOnPhantom === true) {
                var phantom = require('phantom');

                phantom.create(function (ph) {
                    ph.createPage(function (p) {
                        page = p;
                        page.open(url, function (status) {

                            if (status === "success") {
                                getTestResult(function(testResult) {
                                    ph.exit();

                                    if (testResult.failedTests.length === 0 &&
                                        testResult.errorTests.length === 0) {
                                        grunt.log.ok(testResult.passedTests.length + " tests passed.");

                                        server.close(function() {
                                            done();
                                        }) ;

                                    } else {

                                        [
                                            {
                                                message: "failed",
                                                tests: testResult.failedTests
                                            },
                                            {
                                                message: "errored",
                                                tests: testResult.errorTests
                                            }
                                        ]
                                        .forEach(function (obj) {
                                                if (obj.tests.length) {
                                                    grunt.log.error(obj.tests.length + " tests " + obj.message + ":");

                                                    obj.tests.forEach(function(test) {
                                                        grunt.log.error("\t" + test.title +
                                                            (test.err ? ": " + test.err.message || test.err : ""))
                                                    });
                                                }
                                        });

                                        server.close(function () {
                                            done(false);
                                        });

                                    }
                                });

                            } else {
                                server.close(function () {
                                    done(false);
                                });
                            }
                        });
                    });
                });
            } else {
                grunt.log.ok("Open " + url + " to run tests and see the result");
            }

            function getTestResult(callback) {
                checkStatus();

                function checkStatus() {
                    page.evaluate(function () {
                        return window.testsCompleted && window.testResults;
                    }, function(result) {
                        if (result) {
                            callback && callback(result);
                        } else {
                            setTimeout(checkStatus, 1000);
                        }
                    })
                }
            }

        });

};<|endoftext|>


<commit_before>/*
 * grunt-release
 * https://github.com/geddski/grunt-release
 *
 * Copyright (c) 2013 Dave Geddes
 * Licensed under the MIT license.
 */

var shell = require('shelljs');
var semver = require('semver');

module.exports = function(grunt){
  grunt.registerTask('release', 'bump version, git tag, git push, npm publish', function(type){

    //defaults
    var options = this.options({
      bump: true,
      file: grunt.config('pkgFile') || 'package.json',
      add: true,
      commit: true,
      tag: true,
      push: true,
      pushTags: true,
      npm : true
    });

    var config = setup(options.file, type);
    var templateOptions = {
      data: {
        version: config.newVersion
      }
    };
    var tagName = grunt.template.process(grunt.config.getRaw('release.options.tagName') || '<%= version %>', templateOptions);
    var commitMessage = grunt.template.process(grunt.config.getRaw('release.options.commitMessage') || 'release <%= version %>', templateOptions);
    var tagMessage = grunt.template.process(grunt.config.getRaw('release.options.tagMessage') || 'version <%= version %>', templateOptions);
    var nowrite = grunt.option('no-write');
    var task = this;

    if (options.bump) bump(config);
    if (options.add) add(config);
    if (options.commit) commit(config);
    if (options.tag) tag(config);
    if (options.push) push();
    if (options.pushTags) pushTags(config);
    if (options.npm) publish(config);
    if (options.github) githubRelease(config);

    function setup(file, type){
      var pkg = grunt.file.readJSON(file);
      var newVersion = pkg.version;
      if (options.bump) {
        newVersion = semver.inc(pkg.version, type || 'patch');
      }
      return {file: file, pkg: pkg, newVersion: newVersion};
    }

    function add(config){
      run('git add ' + config.file);
    }

    function commit(config){
      run('git commit '+ config.file +' -m "'+ commitMessage +'"', config.file + ' committed');
    }

    function tag(config){
      run('git tag ' + tagName + ' -m "'+ tagMessage +'"', 'New git tag created: ' + tagName);
    }

    function push(){
      run('git push', 'pushed to remote');
    }

    function pushTags(config){
      run('git push --tags', 'pushed new tag '+ config.newVersion +' to remote');
    }

    function publish(config){
      var cmd = 'npm publish';
      var msg = 'published '+ config.newVersion +' to npm';
      var npmtag = getNpmTag();
      if (npmtag){
        cmd += ' --tag ' + npmtag;
        msg += ' with a tag of "' + npmtag + '"';
      }
      if (options.folder){ cmd += ' ' + options.folder }
      run(cmd, msg);
    }

    function getNpmTag(){
      var tag = grunt.option('npmtag') || options.npmtag;
      if(tag === true) { tag = config.newVersion }
      return tag;
    }

    function run(cmd, msg){
      if (nowrite) {
        grunt.verbose.writeln('Not actually running: ' + cmd);
      }
      else {
        grunt.verbose.writeln('Running: ' + cmd);
        shell.exec(cmd, {silent:true});
      }

      if (msg) grunt.log.ok(msg);
    }

    function bump(config){
      config.pkg.version = config.newVersion;
      grunt.file.write(config.file, JSON.stringify(config.pkg, null, '  ') + '\n');
      grunt.log.ok('Version bumped to ' + config.newVersion);
    }

    function githubRelease(){
      var request = require('superagent');
      var done = task.async();

      if (nowrite){
        grunt.verbose.writeln('Not actually creating github release: ' + tagName);
        success();
      }

      request
        .post('https://api.github.com/repos/' + options.github.repo + '/releases')
        .auth(process.env[options.github.usernameVar], process.env[options.github.passwordVar])
        .set('Accept', 'application/vnd.github.manifold-preview')
        .set('User-Agent', 'grunt-release')
        .send({"tag_name": tagName, "name": tagMessage})
        .end(function(res){
          if (res.statusCode === 201){
            success();
          }
          else {
            grunt.fail.warn('Error creating github release. Response: ' + res.text);
          }
        });

        function success(){
          grunt.log.ok('created ' + tagName + ' release on github.');
          done();
        }
    }

  });
};
<commit_msg>significant refactor: use promises, fail loudly, consistent logs<commit_after>/*
 * grunt-release
 * https://github.com/geddski/grunt-release
 *
 * Copyright (c) 2013 Dave Geddes
 * Licensed under the MIT license.
 */

var shell = require('shelljs');
var semver = require('semver');
var request = require('superagent');
var Q = require('q');

module.exports = function(grunt){
  grunt.registerTask('release', 'bump version, git tag, git push, npm publish', function(type){

    //defaults
    var options = this.options({
      bump: true,
      file: grunt.config('pkgFile') || 'package.json',
      add: true,
      commit: true,
      tag: true,
      push: true,
      pushTags: true,
      npm : true
    });

    var config = setup(options.file, type);
    var templateOptions = {
      data: {
        version: config.newVersion
      }
    };
    var tagName = grunt.template.process(grunt.config.getRaw('release.options.tagName') || '<%= version %>', templateOptions);
    var commitMessage = grunt.template.process(grunt.config.getRaw('release.options.commitMessage') || 'release <%= version %>', templateOptions);
    var tagMessage = grunt.template.process(grunt.config.getRaw('release.options.tagMessage') || 'version <%= version %>', templateOptions);
    var nowrite = grunt.option('no-write');
    var task = this;
    var done = this.async();

    if (nowrite){
      grunt.log.ok('-------RELEASE DRY RUN-------');
    }

    Q()
      .then(ifEnabled('bump', bump))
      .then(ifEnabled('add', add))
      .then(ifEnabled('commit', commit))
      .then(ifEnabled('tag', tag))
      .then(ifEnabled('push', push))
      .then(ifEnabled('pushTags', pushTags))
      .then(ifEnabled('npm', publish))
      .then(ifEnabled('github', githubRelease))
      .catch(function(msg){
        grunt.fail.warn(msg || 'release failed')
      })
      .finally(done);

    function setup(file, type){
      var pkg = grunt.file.readJSON(file);
      var newVersion = pkg.version;
      if (options.bump) {
        newVersion = semver.inc(pkg.version, type || 'patch');
      }
      return {file: file, pkg: pkg, newVersion: newVersion};
    }

    function getNpmTag(){
      var tag = grunt.option('npmtag') || options.npmtag;
      if(tag === true) { tag = config.newVersion }
      return tag;
    }

    function ifEnabled(option, fn){
      if (options[option]) return fn;
    }

    function run(cmd, msg){
      var deferred = Q.defer();
      grunt.verbose.writeln('Running: ' + cmd);

      if (nowrite) {
        grunt.log.ok(msg || cmd);
        deferred.resolve();
      }
      else {
        var success = shell.exec(cmd, {silent:true}).code === 0;

        if (success){
          grunt.log.ok(msg || cmd);
          deferred.resolve();
        }
        else{
          // fail and stop execution of further tasks
          deferred.reject('Failed when executing: `' + cmd + '`\n');
        }
      }
      return deferred.promise;
    }

    function add(){
      return run('git add ' + config.file, ' staged ' + config.file);
    }

    function commit(){
      return run('git commit '+ config.file +' -m "'+ commitMessage +'"', 'committed ' + config.file);
    }

    function tag(){
      return run('git tag ' + tagName + ' -m "'+ tagMessage +'"', 'created new git tag: ' + tagName);
    }

    function push(){
      return run('git push', 'pushed to remote git repo');
    }

    function pushTags(){
      return run('git push --tags', 'pushed new tag '+ config.newVersion +' to remote git repo');
    }

    function publish(){
      var cmd = 'npm publish';
      var msg = 'published version '+ config.newVersion +' to npm';
      var npmtag = getNpmTag();
      if (npmtag){
        cmd += ' --tag ' + npmtag;
        msg += ' with a tag of "' + npmtag + '"';
      }
      if (options.folder){ cmd += ' ' + options.folder }
      return run(cmd, msg);
    }

    function bump(){
      return Q.fcall(function () {
        config.pkg.version = config.newVersion;
        grunt.file.write(config.file, JSON.stringify(config.pkg, null, '  ') + '\n');
        grunt.log.ok('bumped version to ' + config.newVersion);
      });
    }

    function githubRelease(){
      var deferred = Q.defer();
      if (nowrite){
        success();
        return;
      }

      request
        .post('https://api.github.com/repos/' + options.github.repo + '/releases')
        .auth(process.env[options.github.usernameVar], process.env[options.github.passwordVar])
        .set('Accept', 'application/vnd.github.manifold-preview')
        .set('User-Agent', 'grunt-release')
        .send({"tag_name": tagName, "name": tagMessage})
        .end(function(res){
          if (res.statusCode === 201){
            success();
          }
          else {
            deferred.reject('Error creating github release. Response: ' + res.text);
          }
        });

      function success(){
        grunt.log.ok('created ' + tagName + ' release on github.');
        deferred.resolve();
      }

      return deferred.promise;
    }

  });
};
<|endoftext|>


<commit_before>/*
 * grunt-html-fragment
 * https://github.com/gexiaowei/grunt-html-fragment
 *
 * Copyright (c) 2015 gandxiaowei@gmail.com
 * Licensed under the MIT license.
 */

'use strict';

var cheerio = require('cheerio');
var path = require('path');

module.exports = function (grunt) {

    // Please see the Grunt documentation for more information regarding task
    // creation: http://gruntjs.com/creating-tasks

    grunt.registerMultiTask('html_fragment', 'The best Grunt plugin ever.', function () {
        // Merge task-specific and/or target-specific options with these defaults.
        var options = this.options({
            fragmentPath: 'fragment',
            needReplacePath: true,
            pathDefined: [],
            absoluteHeads: []
        });

        //定义绝对路径开头
        var absoluteHeads = ['http://', 'https://', '\\\\'].concat(options.absoluteHeads),
            absoluteReg = new RegExp('^(' + absoluteHeads.join('|') + ')');
        //定义需要替换路径的标签信息
        var replacePathTags = [
            {tag: 'img', attr: 'src'},
            {tag: 'script', attr: 'src'},
            {tag: 'link', attr: 'href'},
            {tag: 'a', attr: 'href'}
        ].concat(options.pathDefined);

        /**
         * 获取替换的html碎片内容
         * @param fragment HTML碎片文件
         * @param commandInfo 需要改变的命令
         * @param output 碎片导入的文件路径
         */
        function getReplaceHTML(fragmentPath, commandInfo, output) {
            var fragment = grunt.file.read(fragmentPath);
            var $ = cheerio.load(fragment, {decodeEntities: false});
            if (commandInfo) {
                var commands = commandInfo.split(',');
                commands.forEach(function (command) {
                    var args = command.trim().split('->');
                    if (args.length > 2) {
                        $(args[0])[args[1]](args[2]);
                    }
                });
            }
            if (options.needReplacePath) {
                var i, temp;
                replacePathTags.forEach(function (replacePathTag) {
                    var tags = $(replacePathTag.tag),
                        attr = replacePathTag.attr;
                    for (i = 0; i < tags.length; i++) {
                        temp = $(tags[i]);
                        var sourcePath = temp.attr(attr);
                        if (!isAbsolute(sourcePath)) {
                            temp.attr(attr, path.relative(path.dirname(output), path.join(options.fragmentPath, sourcePath)));
                        }
                    }
                });
            }
            return $.html();
        }

        function isAbsolute(path) {
            return absoluteReg.test(path);
        }

        function createHTML(filepath, output) {
            var contents = grunt.file.read(filepath);
            var match;
            var successCount = 0, failCount = 0;
            grunt.log.writeln('[fragment]start replace file:' + filepath);
            while (match = findInclude(contents)) {
                var pathWithCommand = match.path.split('::'),
                    includePath = pathWithCommand[0],
                    command = pathWithCommand[1];
                var fragmentPath = path.join(options.fragmentPath, includePath);
                if (grunt.file.exists(fragmentPath)) {
                    contents = contents.replace(match.content, getReplaceHTML(fragmentPath, command, output));
                    successCount++;
                } else {
                    contents = contents.replace(match.content, '');
                    failCount++
                }
            }
            grunt.log.writeln('[fragment]end replace with ' + successCount + ' succeed,' + failCount + ' failed.');
            var $ = cheerio.load(contents, {decodeEntities: false});
            var i,
                scripts = $('script'), styles = $('link'),
                scriptArr = [], styleArr = [];
            //除去重复引用的script文件
            for (i = 0; i < scripts.length; i++) {
                var script = $(scripts[i]);
                if (scriptArr.indexOf(script.attr('src')) >= 0) {
                    script.remove();
                } else {
                    scriptArr.push(script.attr('src'));
                }
            }
            //除去重复引用的style文件
            for (i = 0; i < styles.length; i++) {
                var style = $(styles[i]);
                if (styleArr.indexOf(style.attr('href')) >= 0) {
                    style.remove();
                } else {
                    styleArr.push(style.attr('href'));
                    //在head中引用css样式
                    $('head').append(style);
                }
            }
            return $.html();
        }

        function findInclude(string) {
            var regex = /<!--\s*@@include\s*[= ]\s*(\S+)\s*(?:([^-]+)\s*)?-->/;
            var match = string.match(regex);
            return match ? {
                content: match[0],
                path: match[1]
            } : null

        }

        // Iterate over all specified file groups.
        this.files.forEach(function (f) {
            // Concat specified files.
            f.src.filter(function (filepath) {
                // Warn on and remove invalid source files (if nonull was set).
                if (!grunt.file.exists(filepath)) {
                    grunt.log.warn('Source file "' + filepath + '" not found.');
                    return false;
                } else {
                    return true;
                }
            }).map(function (filepath) {
                // Read file source.
                var outPath = path.join(f.dest, path.basename(filepath));
                var content = createHTML(filepath, outPath);
                // Print a success message.
                grunt.log.writeln('File "' + outPath + '" created.');
                return grunt.file.write(outPath, content, {encoding: 'utf-8'});
            });
        });
    });

};
<commit_msg>a problem in using path.join<commit_after>/*
 * grunt-html-fragment
 * https://github.com/gexiaowei/grunt-html-fragment
 *
 * Copyright (c) 2015 gandxiaowei@gmail.com
 * Licensed under the MIT license.
 */

'use strict';

var cheerio = require('cheerio');
var path = require('path');

module.exports = function (grunt) {

    // Please see the Grunt documentation for more information regarding task
    // creation: http://gruntjs.com/creating-tasks

    grunt.registerMultiTask('html_fragment', 'The best Grunt plugin ever.', function () {
        // Merge task-specific and/or target-specific options with these defaults.
        var options = this.options({
            fragmentPath: 'fragment/',
            needReplacePath: true,
            pathDefined: [],
            absoluteHeads: []
        });

        //定义绝对路径开头
        var absoluteHeads = ['http://', 'https://', '\\\\'].concat(options.absoluteHeads),
            absoluteReg = new RegExp('^(' + absoluteHeads.join('|') + ')');
        //定义需要替换路径的标签信息
        var replacePathTags = [
            {tag: 'img', attr: 'src'},
            {tag: 'script', attr: 'src'},
            {tag: 'link', attr: 'href'},
            {tag: 'a', attr: 'href'}
        ].concat(options.pathDefined);

        /**
         * 获取替换的html碎片内容
         * @param fragment HTML碎片文件
         * @param commandInfo 需要改变的命令
         * @param output 碎片导入的文件路径
         */
        function getReplaceHTML(fragmentPath, commandInfo, output) {
            var fragment = grunt.file.read(fragmentPath);
            var $ = cheerio.load(fragment, {decodeEntities: false});
            if (commandInfo) {
                var commands = commandInfo.split(',');
                commands.forEach(function (command) {
                    var args = command.trim().split('->');
                    if (args.length > 2) {
                        $(args[0])[args[1]](args[2]);
                    }
                });
            }
            if (options.needReplacePath) {
                var i, temp;
                replacePathTags.forEach(function (replacePathTag) {
                    var tags = $(replacePathTag.tag),
                        attr = replacePathTag.attr;
                    for (i = 0; i < tags.length; i++) {
                        temp = $(tags[i]);
                        var sourcePath = temp.attr(attr);
                        if (!isAbsolute(sourcePath)) {
                            temp.attr(attr, path.relative(path.dirname(output), path.join(options.fragmentPath, sourcePath)));
                        }
                    }
                });
            }
            return $.html();
        }

        function isAbsolute(path) {
            return absoluteReg.test(path);
        }

        function createHTML(filepath, output) {
            var contents = grunt.file.read(filepath);
            var match;
            var successCount = 0, failCount = 0;
            grunt.log.writeln('[fragment]start replace file:' + filepath);
            while (match = findInclude(contents)) {
                var pathWithCommand = match.path.split('::'),
                    includePath = pathWithCommand[0],
                    command = pathWithCommand[1];
                var fragmentPath = options.fragmentPath + includePath;
                if (grunt.file.exists(fragmentPath)) {
                    contents = contents.replace(match.content, getReplaceHTML(fragmentPath, command, output));
                    successCount++;
                } else {
                    contents = contents.replace(match.content, '');
                    failCount++
                }
            }
            grunt.log.writeln('[fragment]end replace with ' + successCount + ' succeed,' + failCount + ' failed.');
            var $ = cheerio.load(contents, {decodeEntities: false});
            var i,
                scripts = $('script'), styles = $('link'),
                scriptArr = [], styleArr = [];
            //除去重复引用的script文件
            for (i = 0; i < scripts.length; i++) {
                var script = $(scripts[i]);
                if (scriptArr.indexOf(script.attr('src')) >= 0) {
                    script.remove();
                } else {
                    scriptArr.push(script.attr('src'));
                }
            }
            //除去重复引用的style文件
            for (i = 0; i < styles.length; i++) {
                var style = $(styles[i]);
                if (styleArr.indexOf(style.attr('href')) >= 0) {
                    style.remove();
                } else {
                    styleArr.push(style.attr('href'));
                    //在head中引用css样式
                    $('head').append(style);
                }
            }
            return $.html();
        }

        function findInclude(string) {
            var regex = /<!--\s*@@include\s*[= ]\s*(\S+)\s*(?:([^-]+)\s*)?-->/;
            var match = string.match(regex);
            return match ? {
                content: match[0],
                path: match[1]
            } : null

        }

        // Iterate over all specified file groups.
        this.files.forEach(function (f) {
            // Concat specified files.
            f.src.filter(function (filepath) {
                // Warn on and remove invalid source files (if nonull was set).
                if (!grunt.file.exists(filepath)) {
                    grunt.log.warn('Source file "' + filepath + '" not found.');
                    return false;
                } else {
                    return true;
                }
            }).map(function (filepath) {
                // Read file source.
                var outPath = path.join(f.dest, path.basename(filepath));
                var content = createHTML(filepath, outPath);
                // Print a success message.
                grunt.log.writeln('File "' + outPath + '" created.');
                return grunt.file.write(outPath, content, {encoding: 'utf-8'});
            });
        });
    });

};
<|endoftext|>


<commit_before>'use strict';
require("amd-loader");
var assert = require("chai").assert;
var hashstructs = require("../build/lib/salve/hashstructs");

function id(x) { return x; }

describe("HashSet", function () {
    describe("integers with id hash", function () {
	it("creation", function () {
	    var hs = new hashstructs.HashSet(id, [1, 2, 3]);
	    for(var x = 1; x <=3; ++x)
		assert.equal(hs.backing[x], x);
	    assert.equal(hs.size(), 3);
	});
	it("forEach", function () {
	    var hs = new hashstructs.HashSet(id, [1, 2, 3]);
	    var t = {};
	    hs.forEach(function (x) {
		t[x] = x;
	    });
	    for(var x = 1; x <=3; ++x)
		assert.equal(t[x], x);
	    assert.equal(hs.size(), 3);
	});

	it("adding", function () {
	    var hs = new hashstructs.HashSet(id, [1, 2, 3]);
	    hs.add(1);
	    hs.add(2);
	    hs.add(3);
	    for(var x = 1; x <=3; ++x)
		assert.equal(hs.backing[x], x);
	    assert.equal(hs.size(), 3);
	});
	it("union", function () {
	    var hs = new hashstructs.HashSet(id, [1, 2, 3]);
	    var hs2 = new hashstructs.HashSet(id, [1, 2, 3, 4, 5, 6]);
	    hs2.union(hs);
	    for(var x = 1; x <=6; ++x)
		assert.equal(hs2.backing[x], x);
	    assert.equal(hs2.size(), 6);
	});
    });
    describe("strings with id hash", function () {
	var init = ["dog", "cat", "hamster"];
    	it("creation", function () {
    	    var hs = new hashstructs.HashSet(id, init);
    	    for(var x = 0, q; q = init[x]; ++x)
    		assert.equal(hs.backing[q], q);
	    assert.equal(hs.size(), 3);
    	});

    	it("forEach", function () {
    	    var hs = new hashstructs.HashSet(id, init);
    	    var t = {};
    	    hs.forEach(function (x) {
    		t[x] = x;
    	    });
    	    for(var x = 0, q; q = init[x]; ++x)
    		assert.equal(t[q], q);
	    assert.equal(hs.size(), 3);
    	});

    	it("adding", function () {
    	    var hs = new hashstructs.HashSet(id, init);
    	    hs.add("dog");
    	    hs.add("cat");
    	    hs.add("hamster");
    	    for(var x = 0, q; q = init[x]; ++x)
    		assert.equal(hs.backing[q], q);
	    assert.equal(hs.size(), 3);
    	});
    	it("union", function () {
    	    var hs = new hashstructs.HashSet(id, init);
	    var init2 = init.concat(["4", "5", "6"]);
    	    var hs2 = new hashstructs.HashSet(id, init2);
    	    hs2.union(hs);
    	    for(var x = 1, q; q = init2[x]; ++x)
    		assert.equal(hs2.backing[q], q);
	    assert.equal(hs2.size(), 6);
	    hs.union(hs2);
    	    for(var x = 1, q; q = init2[x]; ++x)
    		assert.equal(hs.backing[q], q);
	    assert.equal(hs.size(), 6);
    	});
    });

    function Test(name) {
	this.name = name;
	this.id = this.createID();
    }

    (function () {
	var next_id = 0;
	this.createID = function () {
	    return next_id++;
	}

	this.hash = function () { return this.id }
    }).call(Test.prototype);

    var ah_hash = function (x) { return x.hash() }

    describe("Object with ad-hoc hash", function () {
	var init = [new Test("dog"), new Test("cat"), new Test("hamster")];
    	it("creation", function () {
    	    var hs = new hashstructs.HashSet(ah_hash, init);
    	    var t = {};
	    hs.forEach(function (x) {
 	 	t[x.name] = x.name;
	    });
    	    for(var x = 0, q; q = init[x]; ++x)
    		assert.equal(t[q.name], q.name);
	    assert.equal(hs.size(), 3);
    	});

    	it("forEach", function () {
    	    var hs = new hashstructs.HashSet(ah_hash, init);
    	    var t = {};
    	    hs.forEach(function (x) {
    		t[x.name] = x.name;
    	    });
    	    for(var x = 0, q; q = init[x]; ++x)
    		assert.equal(t[q.name], q.name);
	    assert.equal(hs.size(), 3);
    	});

    	it("adding", function () {
    	    var hs = new hashstructs.HashSet(ah_hash, init);
	    init.forEach(function (x) {
		hs.add(x);
	    });
	    assert.equal(hs.size(), 3);
    	    hs.add(new Test("dog"));
    	    hs.add(new Test("cat"));
    	    hs.add(new Test("hamster"));
	    // Each object is unique due to the hashing function.
	    assert.equal(hs.size(), 6);
    	});

    	it("union", function () {
    	    var hs = new hashstructs.HashSet(ah_hash, init);
	    var init2 = init.concat(
		[new Test("dog"), new Test("cat"), new Test("hamster")]);
    	    var hs2 = new hashstructs.HashSet(ah_hash, init2);
    	    hs2.union(hs);
	    assert.equal(hs2.size(), 6, "hs2");
	    hs.union(hs2);
	    assert.equal(hs.size(), 6, "hs");
    	});

	it("filter", function () {
	    var hs = new hashstructs.HashSet(ah_hash, init);
	    var subset = hs.filter(function (x) {
		return x.name.indexOf("a") >= 0;
	    });
	    // Makesure HashBase used the right type.
	    assert.equal(subset.constructor, hashstructs.HashSet);
	    assert.equal(subset.size(), 2);
	});
    });

});

describe("HashMap", function () {
    function Test(name) {
	this.name = name;
	this.id = this.createID();
    }

    (function () {
	var next_id = 0;
	this.createID = function () {
	    return next_id++;
	}

	this.hash = function () { return this.id }
    }).call(Test.prototype);

    var ah_hash = function (x) { return x.hash() }

    describe("ad-hoc hash",function () {
	var init = [
	    [new Test("Alice"), new Test("dog")],
	    [new Test("Bob"), new Test("cat")],
	    [new Test("Charlie"), new Test("hamster")]
	];
	it("simple", function () {
	    var map = new hashstructs.HashMap(ah_hash);
	    for (var i = 0, e; e = init[i]; ++i) {
		map.add(e[0], e[1]);
	    }
	    for (var i = 0, e; e = init[i]; ++i) {
		assert.equal(map.has(e[0]), e[1]);
	    }
	    assert.equal(map.size(), 3);

	});
	it("filter", function () {
	    var map = new hashstructs.HashMap(ah_hash);
	    for (var i = 0, e; e = init[i]; ++i) {
		map.add(e[0], e[1]);
	    }
	    assert.equal(map.size(), 3);
	    var submap = map.filter(function (a, b) {
		return (a.name.indexOf("o") + b.name.indexOf("o")) > -2;
	    });
	    // Makesure HashBase used the right type.
	    assert.equal(submap.constructor, hashstructs.HashMap);
	    assert.equal(submap.size(), 2);
	});
    });
});
<commit_msg>Fix trailing whitespace.<commit_after>'use strict';
require("amd-loader");
var assert = require("chai").assert;
var hashstructs = require("../build/lib/salve/hashstructs");

function id(x) { return x; }

describe("HashSet", function () {
    describe("integers with id hash", function () {
        it("creation", function () {
            var hs = new hashstructs.HashSet(id, [1, 2, 3]);
            for(var x = 1; x <=3; ++x)
                assert.equal(hs.backing[x], x);
            assert.equal(hs.size(), 3);
        });
        it("forEach", function () {
            var hs = new hashstructs.HashSet(id, [1, 2, 3]);
            var t = {};
            hs.forEach(function (x) {
                t[x] = x;
            });
            for(var x = 1; x <=3; ++x)
                assert.equal(t[x], x);
            assert.equal(hs.size(), 3);
        });

        it("adding", function () {
            var hs = new hashstructs.HashSet(id, [1, 2, 3]);
            hs.add(1);
            hs.add(2);
            hs.add(3);
            for(var x = 1; x <=3; ++x)
                assert.equal(hs.backing[x], x);
            assert.equal(hs.size(), 3);
        });
        it("union", function () {
            var hs = new hashstructs.HashSet(id, [1, 2, 3]);
            var hs2 = new hashstructs.HashSet(id, [1, 2, 3, 4, 5, 6]);
            hs2.union(hs);
            for(var x = 1; x <=6; ++x)
                assert.equal(hs2.backing[x], x);
            assert.equal(hs2.size(), 6);
        });
    });
    describe("strings with id hash", function () {
        var init = ["dog", "cat", "hamster"];
        it("creation", function () {
            var hs = new hashstructs.HashSet(id, init);
            for(var x = 0, q; q = init[x]; ++x)
                assert.equal(hs.backing[q], q);
            assert.equal(hs.size(), 3);
        });

        it("forEach", function () {
            var hs = new hashstructs.HashSet(id, init);
            var t = {};
            hs.forEach(function (x) {
                t[x] = x;
            });
            for(var x = 0, q; q = init[x]; ++x)
                assert.equal(t[q], q);
            assert.equal(hs.size(), 3);
        });

        it("adding", function () {
            var hs = new hashstructs.HashSet(id, init);
            hs.add("dog");
            hs.add("cat");
            hs.add("hamster");
            for(var x = 0, q; q = init[x]; ++x)
                assert.equal(hs.backing[q], q);
            assert.equal(hs.size(), 3);
        });
        it("union", function () {
            var hs = new hashstructs.HashSet(id, init);
            var init2 = init.concat(["4", "5", "6"]);
            var hs2 = new hashstructs.HashSet(id, init2);
            hs2.union(hs);
            for(var x = 1, q; q = init2[x]; ++x)
                assert.equal(hs2.backing[q], q);
            assert.equal(hs2.size(), 6);
            hs.union(hs2);
            for(var x = 1, q; q = init2[x]; ++x)
                assert.equal(hs.backing[q], q);
            assert.equal(hs.size(), 6);
        });
    });

    function Test(name) {
        this.name = name;
        this.id = this.createID();
    }

    (function () {
        var next_id = 0;
        this.createID = function () {
            return next_id++;
        }

        this.hash = function () { return this.id }
    }).call(Test.prototype);

    var ah_hash = function (x) { return x.hash() }

    describe("Object with ad-hoc hash", function () {
        var init = [new Test("dog"), new Test("cat"), new Test("hamster")];
        it("creation", function () {
            var hs = new hashstructs.HashSet(ah_hash, init);
            var t = {};
            hs.forEach(function (x) {
                t[x.name] = x.name;
            });
            for(var x = 0, q; q = init[x]; ++x)
                assert.equal(t[q.name], q.name);
            assert.equal(hs.size(), 3);
        });

        it("forEach", function () {
            var hs = new hashstructs.HashSet(ah_hash, init);
            var t = {};
            hs.forEach(function (x) {
                t[x.name] = x.name;
            });
            for(var x = 0, q; q = init[x]; ++x)
                assert.equal(t[q.name], q.name);
            assert.equal(hs.size(), 3);
        });

        it("adding", function () {
            var hs = new hashstructs.HashSet(ah_hash, init);
            init.forEach(function (x) {
                hs.add(x);
            });
            assert.equal(hs.size(), 3);
            hs.add(new Test("dog"));
            hs.add(new Test("cat"));
            hs.add(new Test("hamster"));
            // Each object is unique due to the hashing function.
            assert.equal(hs.size(), 6);
        });

        it("union", function () {
            var hs = new hashstructs.HashSet(ah_hash, init);
            var init2 = init.concat(
                [new Test("dog"), new Test("cat"), new Test("hamster")]);
            var hs2 = new hashstructs.HashSet(ah_hash, init2);
            hs2.union(hs);
	    assert.equal(hs2.size(), 6, "hs2");
	    hs.union(hs2);
	    assert.equal(hs.size(), 6, "hs");
    	});

	it("filter", function () {
	    var hs = new hashstructs.HashSet(ah_hash, init);
	    var subset = hs.filter(function (x) {
		return x.name.indexOf("a") >= 0;
	    });
	    // Makesure HashBase used the right type.
	    assert.equal(subset.constructor, hashstructs.HashSet);
	    assert.equal(subset.size(), 2);
	});
    });

});

describe("HashMap", function () {
    function Test(name) {
	this.name = name;
	this.id = this.createID();
    }

    (function () {
	var next_id = 0;
	this.createID = function () {
	    return next_id++;
	}

	this.hash = function () { return this.id }
    }).call(Test.prototype);

    var ah_hash = function (x) { return x.hash() }

    describe("ad-hoc hash",function () {
	var init = [
	    [new Test("Alice"), new Test("dog")],
	    [new Test("Bob"), new Test("cat")],
	    [new Test("Charlie"), new Test("hamster")]
	];
	it("simple", function () {
	    var map = new hashstructs.HashMap(ah_hash);
	    for (var i = 0, e; e = init[i]; ++i) {
		map.add(e[0], e[1]);
	    }
	    for (var i = 0, e; e = init[i]; ++i) {
		assert.equal(map.has(e[0]), e[1]);
	    }
	    assert.equal(map.size(), 3);

	});
	it("filter", function () {
	    var map = new hashstructs.HashMap(ah_hash);
	    for (var i = 0, e; e = init[i]; ++i) {
		map.add(e[0], e[1]);
	    }
	    assert.equal(map.size(), 3);
	    var submap = map.filter(function (a, b) {
		return (a.name.indexOf("o") + b.name.indexOf("o")) > -2;
	    });
	    // Makesure HashBase used the right type.
	    assert.equal(submap.constructor, hashstructs.HashMap);
	    assert.equal(submap.size(), 2);
	});
    });
});
<|endoftext|>