<commit_before>/* globals jasmine, describe, beforeEach, afterEach, it, expect, loadFixtures, $ */
'use strict';

var fixture = 'fixture.html';
jasmine.getFixtures().fixturesPath = 'base/test/';
jasmine.getFixtures().preload(fixture);

var malarkey = require('../index.js');

describe('malarkey(elem [, opts])', function() {

  var elem;
  var defaults = {
    loop: false,
    typeSpeed: 50,
    deleteSpeed: 50,
    pauseDelay: 2000,
    postFix: ''
  };

  var clock;

  var expectContents = function(str) {
    expect(elem.innerHTML).toBe(str);
  };

  var expectTyping = function(str, speed) {
    var i = -1;
    var len = str.length;
    while (++i < len) {
      var curr = elem.innerHTML;
      clock.tick(speed);
      expectContents(curr + str[i]);
    }
  };

  var expectDeletion = function(str, speed) {
    var i = str.length;
    while (i-- > 0) {
      var curr = elem.innerHTML;
      expect(curr[curr.length-1]).toBe(str[i]); // character to be deleted
      clock.tick(speed);
      expectContents(curr.substring(0, curr.length-1));
    }
    clock.tick(speed);
  };

  beforeEach(function() {
    loadFixtures(fixture);
    elem = $('.malarkey')[0];
    jasmine.clock().install();
    clock = jasmine.clock();
  });

  afterEach(function() {
    jasmine.clock().uninstall();
  });

  describe('type(str [, speed])', function() {

    it('types `str` at the default speed', function() {
      malarkey(elem)
        .type('foobar');
      expectContents('');
      // type
      expectTyping('foobar', defaults.typeSpeed);
      expectContents('foobar');
    });

    it('does nothing if `str` is an empty string', function() {
      malarkey(elem)
        .type('') // ignored
        .type('foobar');
      expectContents('');
      // type
      expectTyping('foobar', defaults.typeSpeed);
      expectContents('foobar');
    });

    it('types `str` at a custom speed', function() {
      var str = 'foobar';
      var customSpeed = defaults.typeSpeed * 10;
      malarkey(elem)
        .type(str, customSpeed);
      expectContents('');
      // type
      expectTyping(str, customSpeed);
      expectContents(str);
    });

  });

  describe('delete()', function() {

    it('deletes every character in `elem` at the default speed', function() {
      var typeStr = 'foobar';
      malarkey(elem)
        .type(typeStr)
        .delete();
      expectContents('');
      // type
      expectTyping(typeStr, defaults.typeSpeed);
      expectContents(typeStr);
      // delete
      expectDeletion(typeStr, defaults.deleteSpeed);
      expectContents('');
    });

  });

  describe('delete(str [, speed])', function() {

    it('deletes every character in `elem` at a custom speed', function() {
      var typeStr = 'foobar';
      var customSpeed = defaults.deleteSpeed * 10;
      malarkey(elem)
        .type(typeStr)
        .delete(null, customSpeed);
      expectContents('');
      // type
      expectTyping(typeStr, defaults.typeSpeed);
      expectContents(typeStr);
      // delete
      expectDeletion(typeStr, customSpeed);
      expectContents('');
    });

    it('deletes `str` at the default speed', function() {
      var typeStr = 'foobar';
      var str = 'bar';
      malarkey(elem)
        .type(typeStr)
        .delete(str);
      expectContents('');
      // type
      expectTyping(typeStr, defaults.typeSpeed);
      expectContents(typeStr);
      // delete
      expectDeletion(str, defaults.deleteSpeed);
      expectContents('foo');
    });

    it('does nothing if `elem` does not end with `str`', function() {
      var typeStr = 'foobar';
      var str = 'qux';
      malarkey(elem)
        .type(typeStr)
        .delete(str);
      expectContents('');
      // type
      expectTyping(typeStr, defaults.typeSpeed);
      expectContents(typeStr);
      // delete
      clock.tick(defaults.deleteSpeed * str.length);
      expectContents(typeStr);
    });

    it('deletes `str` at a custom speed', function() {
      var typeStr = 'foobar';
      var str = 'bar';
      var customSpeed = defaults.deleteSpeed * 10;
      malarkey(elem)
        .type(typeStr)
        .delete(str, customSpeed);
      expectContents('');
      // type
      expectTyping(typeStr, defaults.typeSpeed);
      expectContents(typeStr);
      // delete
      expectDeletion(str, customSpeed);
      expectContents('foo');
    });

  });

  describe('delete(n [, speed])', function() {

    describe('deletes `n` characters at the default speed', function() {

      it('`n` < 0', function() {
        var typeStr = 'foobar';
        malarkey(elem)
          .type(typeStr)
          .delete(-1);
        expectContents('');
        // type
        expectTyping(typeStr, defaults.typeSpeed);
        expectContents(typeStr);
        // delete
        expectDeletion(typeStr, defaults.deleteSpeed);
        expectContents('');
      });

      it('`n` < number of characters in `elem`', function() {
        var typeStr = 'foobar';
        malarkey(elem)
          .type(typeStr)
          .delete(3);
        expectContents('');
        // type
        expectTyping(typeStr, defaults.typeSpeed);
        expectContents(typeStr);
        // delete
        expectDeletion('bar', defaults.deleteSpeed);
        expectContents('foo');
      });

      it('`n` > number of characters in `elem`', function() {
        var typeStr = 'foobar';
        malarkey(elem)
          .type(typeStr)
          .delete(100);
        expectContents('');
        // type
        expectTyping(typeStr, defaults.typeSpeed);
        expectContents(typeStr);
        // delete
        expectDeletion(typeStr, defaults.deleteSpeed);
        expectContents('');
      });

    });

    it('deletes `n` characters at a custom speed', function() {
      var typeStr = 'foobar';
      var customSpeed = defaults.deleteSpeed * 10;
      malarkey(elem)
        .type(typeStr)
        .delete(3, customSpeed);
      expectContents('');
      // type
      expectTyping(typeStr, defaults.typeSpeed);
      expectContents(typeStr);
      // delete
      expectDeletion('bar', customSpeed);
      expectContents('foo');
    });

  });

  describe('clear()', function() {

    it('clears contents of `elem`', function() {
      var str = 'foobar';
      malarkey(elem)
        .type(str)
        .pause()
        .clear();
      expectContents('');
      // type
      expectTyping(str, defaults.typeSpeed);
      expectContents(str);
      // pause
      clock.tick(defaults.pauseDelay);
      // clear
      expectContents('');
    });

  });

  describe('pause([delay])', function() {

    it('does nothing for the default delay', function() {
      var str = 'foobar';
      malarkey(elem)
        .pause()
        .type(str);
      expectContents('');
      // pause
      clock.tick(defaults.pauseDelay);
      expectContents('');
      // type
      expectTyping(str, defaults.typeSpeed);
      expectContents(str);
    });

    it('does nothing for a custom delay', function() {
      var str = 'foobar';
      var customDelay = defaults.pauseDelay * 10;
      malarkey(elem)
        .pause(customDelay)
        .type(str);
      expectContents('');
      // pause
      clock.tick(customDelay);
      expectContents('');
      // type
      expectTyping(str, defaults.typeSpeed);
      expectContents(str);
    });

  });

  describe('call(fn)', function() {

    it('calls the given `fn`, passing it `elem`', function() {
      var fn = jasmine.createSpy('fn').and.callFake(function() {
        this();
      });
      var str = 'foobar';
      malarkey(elem)
        .pause()
        .call(fn)
        .type(str);
      expectContents('');
      // pause
      expect(fn).not.toHaveBeenCalled();
      clock.tick(defaults.pauseDelay);
      // call
      expect(fn).toHaveBeenCalledWith(elem);
      // type
      expectTyping(str, defaults.typeSpeed);
    });

  });

  it('complex sequence with `opts`', function() {
    var opts = {
      loop: true,
      typeSpeed: 10 * defaults.typeSpeed,
      deleteSpeed: 10 * defaults.deleteSpeed,
      pauseDelay: 10 * defaults.pauseDelay,
      postfix: 'qux'
    };
    var str = 'foobar';
    var customTypeSpeed = 20 * defaults.typeSpeed;
    var customDeleteSpeed = 20 * defaults.deleteSpeed;
    var customPauseDelay = 20 * defaults.pauseDelay;
    var i = 3; // repeat
    malarkey(elem, opts)
      .type(str, customTypeSpeed)
      .delete(str, customDeleteSpeed)
      .pause(customPauseDelay)
      .type(str)
      .delete('bar')
      .pause()
      .clear();
    expectContents('');
    while (i--) {
      // type
      expectTyping(str + opts.postfix, customTypeSpeed);
      expectContents(str + opts.postfix);
      // delete
      expectDeletion(str + opts.postfix, customDeleteSpeed);
      expectContents('');
      // pause
      clock.tick(customPauseDelay);
      expectContents('');
      // type
      expectTyping(str + opts.postfix, opts.typeSpeed);
      expectContents(str + opts.postfix);
      // delete
      expectDeletion('bar' + opts.postfix, opts.deleteSpeed);
      expectContents('foo');
      // pause
      clock.tick(opts.pauseDelay);
      // clear
      expectContents('');
    }
  });

});
<commit_msg>Add test for `getter` and `setter`<commit_after>/* globals jasmine, describe, beforeEach, afterEach, it, expect, loadFixtures, $ */
'use strict';

var fixture = 'fixture.html';
jasmine.getFixtures().fixturesPath = 'base/test/';
jasmine.getFixtures().preload(fixture);

var malarkey = require('../index.js');

describe('malarkey(elem [, opts])', function() {

  var elem;
  var defaults = {
    loop: false,
    typeSpeed: 50,
    deleteSpeed: 50,
    pauseDelay: 2000,
    postfix: '',
    getter: function(elem) {
      return elem.innerHTML;
    },
    setter: function(elem, val) {
      elem.innerHTML = val;
    }
  };

  var clock;

  var expectContents = function(str, getter) {
    getter = getter || defaults.getter;
    expect(getter(elem)).toBe(str);
  };

  var expectTyping = function(str, speed, getter) {
    getter = getter || defaults.getter;
    var i = -1;
    var len = str.length;
    while (++i < len) {
      var curr = getter(elem);
      clock.tick(speed);
      expectContents(curr + str[i], getter);
    }
  };

  var expectDeletion = function(str, speed, getter) {
    getter = getter || defaults.getter;
    var i = str.length;
    while (i-- > 0) {
      var curr = getter(elem);
      expect(curr[curr.length-1]).toBe(str[i]); // character to be deleted
      clock.tick(speed);
      expectContents(curr.substring(0, curr.length-1), getter);
    }
    clock.tick(speed);
  };

  beforeEach(function() {
    loadFixtures(fixture);
    elem = $('.malarkey')[0];
    jasmine.clock().install();
    clock = jasmine.clock();
  });

  afterEach(function() {
    jasmine.clock().uninstall();
  });

  describe('type(str [, speed])', function() {

    it('types `str` at the default speed', function() {
      malarkey(elem)
        .type('foobar');
      expectContents('');
      // type
      expectTyping('foobar', defaults.typeSpeed);
      expectContents('foobar');
    });

    it('does nothing if `str` is an empty string', function() {
      malarkey(elem)
        .type('') // ignored
        .type('foobar');
      expectContents('');
      // type
      expectTyping('foobar', defaults.typeSpeed);
      expectContents('foobar');
    });

    it('types `str` at a custom speed', function() {
      var str = 'foobar';
      var customSpeed = defaults.typeSpeed * 10;
      malarkey(elem)
        .type(str, customSpeed);
      expectContents('');
      // type
      expectTyping(str, customSpeed);
      expectContents(str);
    });

  });

  describe('delete()', function() {

    it('deletes every character in `elem` at the default speed', function() {
      var typeStr = 'foobar';
      malarkey(elem)
        .type(typeStr)
        .delete();
      expectContents('');
      // type
      expectTyping(typeStr, defaults.typeSpeed);
      expectContents(typeStr);
      // delete
      expectDeletion(typeStr, defaults.deleteSpeed);
      expectContents('');
    });

  });

  describe('delete(str [, speed])', function() {

    it('deletes every character in `elem` at a custom speed', function() {
      var typeStr = 'foobar';
      var customSpeed = defaults.deleteSpeed * 10;
      malarkey(elem)
        .type(typeStr)
        .delete(null, customSpeed);
      expectContents('');
      // type
      expectTyping(typeStr, defaults.typeSpeed);
      expectContents(typeStr);
      // delete
      expectDeletion(typeStr, customSpeed);
      expectContents('');
    });

    it('deletes `str` at the default speed', function() {
      var typeStr = 'foobar';
      var str = 'bar';
      malarkey(elem)
        .type(typeStr)
        .delete(str);
      expectContents('');
      // type
      expectTyping(typeStr, defaults.typeSpeed);
      expectContents(typeStr);
      // delete
      expectDeletion(str, defaults.deleteSpeed);
      expectContents('foo');
    });

    it('does nothing if `elem` does not end with `str`', function() {
      var typeStr = 'foobar';
      var str = 'qux';
      malarkey(elem)
        .type(typeStr)
        .delete(str);
      expectContents('');
      // type
      expectTyping(typeStr, defaults.typeSpeed);
      expectContents(typeStr);
      // delete
      clock.tick(defaults.deleteSpeed * str.length);
      expectContents(typeStr);
    });

    it('deletes `str` at a custom speed', function() {
      var typeStr = 'foobar';
      var str = 'bar';
      var customSpeed = defaults.deleteSpeed * 10;
      malarkey(elem)
        .type(typeStr)
        .delete(str, customSpeed);
      expectContents('');
      // type
      expectTyping(typeStr, defaults.typeSpeed);
      expectContents(typeStr);
      // delete
      expectDeletion(str, customSpeed);
      expectContents('foo');
    });

  });

  describe('delete(n [, speed])', function() {

    describe('deletes `n` characters at the default speed', function() {

      it('`n` < 0', function() {
        var typeStr = 'foobar';
        malarkey(elem)
          .type(typeStr)
          .delete(-1);
        expectContents('');
        // type
        expectTyping(typeStr, defaults.typeSpeed);
        expectContents(typeStr);
        // delete
        expectDeletion(typeStr, defaults.deleteSpeed);
        expectContents('');
      });

      it('`n` < number of characters in `elem`', function() {
        var typeStr = 'foobar';
        malarkey(elem)
          .type(typeStr)
          .delete(3);
        expectContents('');
        // type
        expectTyping(typeStr, defaults.typeSpeed);
        expectContents(typeStr);
        // delete
        expectDeletion('bar', defaults.deleteSpeed);
        expectContents('foo');
      });

      it('`n` > number of characters in `elem`', function() {
        var typeStr = 'foobar';
        malarkey(elem)
          .type(typeStr)
          .delete(100);
        expectContents('');
        // type
        expectTyping(typeStr, defaults.typeSpeed);
        expectContents(typeStr);
        // delete
        expectDeletion(typeStr, defaults.deleteSpeed);
        expectContents('');
      });

    });

    it('deletes `n` characters at a custom speed', function() {
      var typeStr = 'foobar';
      var customSpeed = defaults.deleteSpeed * 10;
      malarkey(elem)
        .type(typeStr)
        .delete(3, customSpeed);
      expectContents('');
      // type
      expectTyping(typeStr, defaults.typeSpeed);
      expectContents(typeStr);
      // delete
      expectDeletion('bar', customSpeed);
      expectContents('foo');
    });

  });

  describe('clear()', function() {

    it('clears contents of `elem`', function() {
      var str = 'foobar';
      malarkey(elem)
        .type(str)
        .pause()
        .clear();
      expectContents('');
      // type
      expectTyping(str, defaults.typeSpeed);
      expectContents(str);
      // pause
      clock.tick(defaults.pauseDelay);
      // clear
      expectContents('');
    });

  });

  describe('pause([delay])', function() {

    it('does nothing for the default delay', function() {
      var str = 'foobar';
      malarkey(elem)
        .pause()
        .type(str);
      expectContents('');
      // pause
      clock.tick(defaults.pauseDelay);
      expectContents('');
      // type
      expectTyping(str, defaults.typeSpeed);
      expectContents(str);
    });

    it('does nothing for a custom delay', function() {
      var str = 'foobar';
      var customDelay = defaults.pauseDelay * 10;
      malarkey(elem)
        .pause(customDelay)
        .type(str);
      expectContents('');
      // pause
      clock.tick(customDelay);
      expectContents('');
      // type
      expectTyping(str, defaults.typeSpeed);
      expectContents(str);
    });

  });

  describe('call(fn)', function() {

    it('calls the given `fn`, passing it `elem`', function() {
      var fn = jasmine.createSpy('fn').and.callFake(function() {
        this();
      });
      var str = 'foobar';
      malarkey(elem)
        .pause()
        .call(fn)
        .type(str);
      expectContents('');
      // pause
      expect(fn).not.toHaveBeenCalled();
      clock.tick(defaults.pauseDelay);
      // call
      expect(fn).toHaveBeenCalledWith(elem);
      // type
      expectTyping(str, defaults.typeSpeed);
    });

  });

  it('custom `getter` and `setter`', function() {
    var opts = {
      getter: function(elem) {
        return elem.getAttribute('title') || '';
      },
      setter: function(elem, val) {
        elem.setAttribute('title', val);
      }
    };
    var str = 'foobar';
    malarkey(elem, opts)
      .type(str)
      .delete(str);
    // type
    expectTyping(str, defaults.typeSpeed, opts.getter);
    // delete
    expectDeletion(str, defaults.deleteSpeed, opts.getter);
  });

  it('complex sequence with `opts`', function() {
    var opts = {
      loop: true,
      typeSpeed: 10 * defaults.typeSpeed,
      deleteSpeed: 10 * defaults.deleteSpeed,
      pauseDelay: 10 * defaults.pauseDelay,
      postfix: 'qux'
    };
    var str = 'foobar';
    var customTypeSpeed = 20 * defaults.typeSpeed;
    var customDeleteSpeed = 20 * defaults.deleteSpeed;
    var customPauseDelay = 20 * defaults.pauseDelay;
    var i = 3; // repeat
    malarkey(elem, opts)
      .type(str, customTypeSpeed)
      .delete(str, customDeleteSpeed)
      .pause(customPauseDelay)
      .type(str)
      .delete('bar')
      .pause()
      .clear();
    expectContents('');
    while (i--) {
      // type
      expectTyping(str + opts.postfix, customTypeSpeed);
      expectContents(str + opts.postfix);
      // delete
      expectDeletion(str + opts.postfix, customDeleteSpeed);
      expectContents('');
      // pause
      clock.tick(customPauseDelay);
      expectContents('');
      // type
      expectTyping(str + opts.postfix, opts.typeSpeed);
      expectContents(str + opts.postfix);
      // delete
      expectDeletion('bar' + opts.postfix, opts.deleteSpeed);
      expectContents('foo');
      // pause
      clock.tick(opts.pauseDelay);
      // clear
      expectContents('');
    }
  });

});
<|endoftext|>


<commit_before>require('ember-runtime/mixins/mutable_array');
require('ember-runtime/system/object');

/**
@module ember
@submodule ember-runtime
*/

var OUT_OF_RANGE_EXCEPTION = "Index out of range";
var EMPTY = [];

var get = Ember.get, set = Ember.set;

/**
  An ArrayProxy wraps any other object that implements `Ember.Array` and/or
  `Ember.MutableArray,` forwarding all requests. This makes it very useful for
  a number of binding use cases or other cases where being able to swap
  out the underlying array is useful.

  A simple example of usage:

  ```javascript
  var pets = ['dog', 'cat', 'fish'];
  var ap = Ember.ArrayProxy.create({ content: Ember.A(pets) });

  ap.get('firstObject');                        // 'dog'
  ap.set('content', ['amoeba', 'paramecium']);
  ap.get('firstObject');                        // 'amoeba'
  ```

  This class can also be useful as a layer to transform the contents of
  an array, as they are accessed. This can be done by overriding
  `objectAtContent`:

  ```javascript
  var pets = ['dog', 'cat', 'fish'];
  var ap = Ember.ArrayProxy.create({
      content: Ember.A(pets),
      objectAtContent: function(idx) {
          return this.get('content').objectAt(idx).toUpperCase();
      }
  });

  ap.get('firstObject'); // . 'DOG'
  ```

  @class ArrayProxy
  @namespace Ember
  @extends Ember.Object
  @uses Ember.MutableArray
*/
Ember.ArrayProxy = Ember.Object.extend(Ember.MutableArray, {

  /**
    The content array. Must be an object that implements `Ember.Array` and/or
    `Ember.MutableArray.`

    @property content
    @type Ember.Array
  */
  content: null,

  /**
   The array that the proxy pretends to be. In the default `ArrayProxy`
   implementation, this and `content` are the same. Subclasses of `ArrayProxy`
   can override this property to provide things like sorting and filtering.

   @property arrangedContent
  */
  arrangedContent: Ember.computed.alias('content'),

  /**
    Should actually retrieve the object at the specified index from the
    content. You can override this method in subclasses to transform the
    content item to something new.

    This method will only be called if content is non-`null`.

    @method objectAtContent
    @param {Number} idx The index to retrieve.
    @return {Object} the value or undefined if none found
  */
  objectAtContent: function(idx) {
    return get(this, 'arrangedContent').objectAt(idx);
  },

  /**
    Should actually replace the specified objects on the content array.
    You can override this method in subclasses to transform the content item
    into something new.

    This method will only be called if content is non-`null`.

    @method replaceContent
    @param {Number} idx The starting index
    @param {Number} amt The number of items to remove from the content.
    @param {Array} objects Optional array of objects to insert or null if no
      objects.
    @return {void}
  */
  replaceContent: function(idx, amt, objects) {
    get(this, 'content').replace(idx, amt, objects);
  },

  /**
    Invoked when the content property is about to change. Notifies observers that the
    entire array content will change.

    @private
    @method _contentWillChange
  */
  _contentWillChange: Ember.beforeObserver('content', function() {
    this._teardownContent();
  }),

  _teardownContent: function() {
    var content = get(this, 'content');

    if (content) {
      content.removeArrayObserver(this, {
        willChange: 'contentArrayWillChange',
        didChange: 'contentArrayDidChange'
      });
    }
  },

  contentArrayWillChange: Ember.K,
  contentArrayDidChange: Ember.K,

  /**
    Invoked when the content property changes. Notifies observers that the
    entire array content has changed.

    @private
    @method _contentDidChange
  */
  _contentDidChange: Ember.observer('content', function() {
    var content = get(this, 'content');

    Ember.assert("Can't set ArrayProxy's content to itself", content !== this);

    this._setupContent();
  }),

  _setupContent: function() {
    var content = get(this, 'content');

    if (content) {
      content.addArrayObserver(this, {
        willChange: 'contentArrayWillChange',
        didChange: 'contentArrayDidChange'
      });
    }
  },

  _arrangedContentWillChange: Ember.beforeObserver('arrangedContent', function() {
    var arrangedContent = get(this, 'arrangedContent'),
        len = arrangedContent ? get(arrangedContent, 'length') : 0;

    this.arrangedContentArrayWillChange(this, 0, len, undefined);
    this.arrangedContentWillChange(this);

    this._teardownArrangedContent(arrangedContent);
  }),

  _arrangedContentDidChange: Ember.observer('arrangedContent', function() {
    var arrangedContent = get(this, 'arrangedContent'),
        len = arrangedContent ? get(arrangedContent, 'length') : 0;

    Ember.assert("Can't set ArrayProxy's content to itself", arrangedContent !== this);

    this._setupArrangedContent();

    this.arrangedContentDidChange(this);
    this.arrangedContentArrayDidChange(this, 0, undefined, len);
  }),

  _setupArrangedContent: function() {
    var arrangedContent = get(this, 'arrangedContent');

    if (arrangedContent) {
      arrangedContent.addArrayObserver(this, {
        willChange: 'arrangedContentArrayWillChange',
        didChange: 'arrangedContentArrayDidChange'
      });
    }
  },

  _teardownArrangedContent: function() {
    var arrangedContent = get(this, 'arrangedContent');

    if (arrangedContent) {
      arrangedContent.removeArrayObserver(this, {
        willChange: 'arrangedContentArrayWillChange',
        didChange: 'arrangedContentArrayDidChange'
      });
    }
  },

  arrangedContentWillChange: Ember.K,
  arrangedContentDidChange: Ember.K,

  objectAt: function(idx) {
    return get(this, 'content') && this.objectAtContent(idx);
  },

  length: Ember.computed(function() {
    var arrangedContent = get(this, 'arrangedContent');
    return arrangedContent ? get(arrangedContent, 'length') : 0;
    // No dependencies since Enumerable notifies length of change
  }),

  _replace: function(idx, amt, objects) {
    var content = get(this, 'content');
    Ember.assert('The content property of '+ this.constructor + ' should be set before modifying it', content);
    if (content) this.replaceContent(idx, amt, objects);
    return this;
  },

  replace: function() {
    if (get(this, 'arrangedContent') === get(this, 'content')) {
      this._replace.apply(this, arguments);
    } else {
      throw new Ember.Error("Using replace on an arranged ArrayProxy is not allowed.");
    }
  },

  _insertAt: function(idx, object) {
    if (idx > get(this, 'content.length')) throw new Ember.Error(OUT_OF_RANGE_EXCEPTION);
    this._replace(idx, 0, [object]);
    return this;
  },

  insertAt: function(idx, object) {
    if (get(this, 'arrangedContent') === get(this, 'content')) {
      return this._insertAt(idx, object);
    } else {
      throw new Ember.Error("Using insertAt on an arranged ArrayProxy is not allowed.");
    }
  },

  removeAt: function(start, len) {
    if ('number' === typeof start) {
      var content = get(this, 'content'),
          arrangedContent = get(this, 'arrangedContent'),
          indices = [], i;

      if ((start < 0) || (start >= get(this, 'length'))) {
        throw new Ember.Error(OUT_OF_RANGE_EXCEPTION);
      }

      if (len === undefined) len = 1;

      // Get a list of indices in original content to remove
      for (i=start; i<start+len; i++) {
        // Use arrangedContent here so we avoid confusion with objects transformed by objectAtContent
        indices.push(content.indexOf(arrangedContent.objectAt(i)));
      }

      // Replace in reverse order since indices will change
      indices.sort(function(a,b) { return b - a; });

      Ember.beginPropertyChanges();
      for (i=0; i<indices.length; i++) {
        this._replace(indices[i], 1, EMPTY);
      }
      Ember.endPropertyChanges();
    }

    return this ;
  },

  pushObject: function(obj) {
    this._insertAt(get(this, 'content.length'), obj) ;
    return obj ;
  },

  pushObjects: function(objects) {
    if (!(Ember.Enumerable.detect(objects) || Ember.isArray(objects))) {
      throw new TypeError("Must pass Ember.Enumerable to Ember.MutableArray#pushObjects");
    }
    this._replace(get(this, 'length'), 0, objects);
    return this;
  },

  setObjects: function(objects) {
    if (objects.length === 0) return this.clear();

    var len = get(this, 'length');
    this._replace(0, len, objects);
    return this;
  },

  unshiftObject: function(obj) {
    this._insertAt(0, obj) ;
    return obj ;
  },

  unshiftObjects: function(objects) {
    this._replace(0, 0, objects);
    return this;
  },

  slice: function() {
    var arr = this.toArray();
    return arr.slice.apply(arr, arguments);
  },

  arrangedContentArrayWillChange: function(item, idx, removedCnt, addedCnt) {
    this.arrayContentWillChange(idx, removedCnt, addedCnt);
  },

  arrangedContentArrayDidChange: function(item, idx, removedCnt, addedCnt) {
    this.arrayContentDidChange(idx, removedCnt, addedCnt);
  },

  init: function() {
    this._super();
    this._setupContent();
    this._setupArrangedContent();
  },

  willDestroy: function() {
    this._teardownArrangedContent();
    this._teardownContent();
  }
});
<commit_msg>[BUGFIX beta] Better error for content set on object<commit_after>require('ember-runtime/mixins/mutable_array');
require('ember-runtime/system/object');

/**
@module ember
@submodule ember-runtime
*/

var OUT_OF_RANGE_EXCEPTION = "Index out of range";
var EMPTY = [];

var get = Ember.get, set = Ember.set;

/**
  An ArrayProxy wraps any other object that implements `Ember.Array` and/or
  `Ember.MutableArray,` forwarding all requests. This makes it very useful for
  a number of binding use cases or other cases where being able to swap
  out the underlying array is useful.

  A simple example of usage:

  ```javascript
  var pets = ['dog', 'cat', 'fish'];
  var ap = Ember.ArrayProxy.create({ content: Ember.A(pets) });

  ap.get('firstObject');                        // 'dog'
  ap.set('content', ['amoeba', 'paramecium']);
  ap.get('firstObject');                        // 'amoeba'
  ```

  This class can also be useful as a layer to transform the contents of
  an array, as they are accessed. This can be done by overriding
  `objectAtContent`:

  ```javascript
  var pets = ['dog', 'cat', 'fish'];
  var ap = Ember.ArrayProxy.create({
      content: Ember.A(pets),
      objectAtContent: function(idx) {
          return this.get('content').objectAt(idx).toUpperCase();
      }
  });

  ap.get('firstObject'); // . 'DOG'
  ```

  @class ArrayProxy
  @namespace Ember
  @extends Ember.Object
  @uses Ember.MutableArray
*/
Ember.ArrayProxy = Ember.Object.extend(Ember.MutableArray, {

  /**
    The content array. Must be an object that implements `Ember.Array` and/or
    `Ember.MutableArray.`

    @property content
    @type Ember.Array
  */
  content: null,

  /**
   The array that the proxy pretends to be. In the default `ArrayProxy`
   implementation, this and `content` are the same. Subclasses of `ArrayProxy`
   can override this property to provide things like sorting and filtering.

   @property arrangedContent
  */
  arrangedContent: Ember.computed.alias('content'),

  /**
    Should actually retrieve the object at the specified index from the
    content. You can override this method in subclasses to transform the
    content item to something new.

    This method will only be called if content is non-`null`.

    @method objectAtContent
    @param {Number} idx The index to retrieve.
    @return {Object} the value or undefined if none found
  */
  objectAtContent: function(idx) {
    return get(this, 'arrangedContent').objectAt(idx);
  },

  /**
    Should actually replace the specified objects on the content array.
    You can override this method in subclasses to transform the content item
    into something new.

    This method will only be called if content is non-`null`.

    @method replaceContent
    @param {Number} idx The starting index
    @param {Number} amt The number of items to remove from the content.
    @param {Array} objects Optional array of objects to insert or null if no
      objects.
    @return {void}
  */
  replaceContent: function(idx, amt, objects) {
    get(this, 'content').replace(idx, amt, objects);
  },

  /**
    Invoked when the content property is about to change. Notifies observers that the
    entire array content will change.

    @private
    @method _contentWillChange
  */
  _contentWillChange: Ember.beforeObserver('content', function() {
    this._teardownContent();
  }),

  _teardownContent: function() {
    var content = get(this, 'content');

    if (content) {
      content.removeArrayObserver(this, {
        willChange: 'contentArrayWillChange',
        didChange: 'contentArrayDidChange'
      });
    }
  },

  contentArrayWillChange: Ember.K,
  contentArrayDidChange: Ember.K,

  /**
    Invoked when the content property changes. Notifies observers that the
    entire array content has changed.

    @private
    @method _contentDidChange
  */
  _contentDidChange: Ember.observer('content', function() {
    var content = get(this, 'content');

    Ember.assert("Can't set ArrayProxy's content to itself", content !== this);

    this._setupContent();
  }),

  _setupContent: function() {
    var content = get(this, 'content');

    if (content) {
      Ember.assert(Ember.String.fmt('ArrayProxy expects an Array or ' +
        'Ember.ArrayProxy, but you passed %@', [typeof content]),
        Ember.isArray(content));

      content.addArrayObserver(this, {
        willChange: 'contentArrayWillChange',
        didChange: 'contentArrayDidChange'
      });
    }
  },

  _arrangedContentWillChange: Ember.beforeObserver('arrangedContent', function() {
    var arrangedContent = get(this, 'arrangedContent'),
        len = arrangedContent ? get(arrangedContent, 'length') : 0;

    this.arrangedContentArrayWillChange(this, 0, len, undefined);
    this.arrangedContentWillChange(this);

    this._teardownArrangedContent(arrangedContent);
  }),

  _arrangedContentDidChange: Ember.observer('arrangedContent', function() {
    var arrangedContent = get(this, 'arrangedContent'),
        len = arrangedContent ? get(arrangedContent, 'length') : 0;

    Ember.assert("Can't set ArrayProxy's content to itself", arrangedContent !== this);

    this._setupArrangedContent();

    this.arrangedContentDidChange(this);
    this.arrangedContentArrayDidChange(this, 0, undefined, len);
  }),

  _setupArrangedContent: function() {
    var arrangedContent = get(this, 'arrangedContent');

    if (arrangedContent) {
      Ember.assert(Ember.String.fmt('ArrayProxy expects an Array or ' +
        'Ember.ArrayProxy, but you passed %@', [typeof arrangedContent]),
        Ember.isArray(arrangedContent));

      arrangedContent.addArrayObserver(this, {
        willChange: 'arrangedContentArrayWillChange',
        didChange: 'arrangedContentArrayDidChange'
      });
    }
  },

  _teardownArrangedContent: function() {
    var arrangedContent = get(this, 'arrangedContent');

    if (arrangedContent) {
      arrangedContent.removeArrayObserver(this, {
        willChange: 'arrangedContentArrayWillChange',
        didChange: 'arrangedContentArrayDidChange'
      });
    }
  },

  arrangedContentWillChange: Ember.K,
  arrangedContentDidChange: Ember.K,

  objectAt: function(idx) {
    return get(this, 'content') && this.objectAtContent(idx);
  },

  length: Ember.computed(function() {
    var arrangedContent = get(this, 'arrangedContent');
    return arrangedContent ? get(arrangedContent, 'length') : 0;
    // No dependencies since Enumerable notifies length of change
  }),

  _replace: function(idx, amt, objects) {
    var content = get(this, 'content');
    Ember.assert('The content property of '+ this.constructor + ' should be set before modifying it', content);
    if (content) this.replaceContent(idx, amt, objects);
    return this;
  },

  replace: function() {
    if (get(this, 'arrangedContent') === get(this, 'content')) {
      this._replace.apply(this, arguments);
    } else {
      throw new Ember.Error("Using replace on an arranged ArrayProxy is not allowed.");
    }
  },

  _insertAt: function(idx, object) {
    if (idx > get(this, 'content.length')) throw new Ember.Error(OUT_OF_RANGE_EXCEPTION);
    this._replace(idx, 0, [object]);
    return this;
  },

  insertAt: function(idx, object) {
    if (get(this, 'arrangedContent') === get(this, 'content')) {
      return this._insertAt(idx, object);
    } else {
      throw new Ember.Error("Using insertAt on an arranged ArrayProxy is not allowed.");
    }
  },

  removeAt: function(start, len) {
    if ('number' === typeof start) {
      var content = get(this, 'content'),
          arrangedContent = get(this, 'arrangedContent'),
          indices = [], i;

      if ((start < 0) || (start >= get(this, 'length'))) {
        throw new Ember.Error(OUT_OF_RANGE_EXCEPTION);
      }

      if (len === undefined) len = 1;

      // Get a list of indices in original content to remove
      for (i=start; i<start+len; i++) {
        // Use arrangedContent here so we avoid confusion with objects transformed by objectAtContent
        indices.push(content.indexOf(arrangedContent.objectAt(i)));
      }

      // Replace in reverse order since indices will change
      indices.sort(function(a,b) { return b - a; });

      Ember.beginPropertyChanges();
      for (i=0; i<indices.length; i++) {
        this._replace(indices[i], 1, EMPTY);
      }
      Ember.endPropertyChanges();
    }

    return this ;
  },

  pushObject: function(obj) {
    this._insertAt(get(this, 'content.length'), obj) ;
    return obj ;
  },

  pushObjects: function(objects) {
    if (!(Ember.Enumerable.detect(objects) || Ember.isArray(objects))) {
      throw new TypeError("Must pass Ember.Enumerable to Ember.MutableArray#pushObjects");
    }
    this._replace(get(this, 'length'), 0, objects);
    return this;
  },

  setObjects: function(objects) {
    if (objects.length === 0) return this.clear();

    var len = get(this, 'length');
    this._replace(0, len, objects);
    return this;
  },

  unshiftObject: function(obj) {
    this._insertAt(0, obj) ;
    return obj ;
  },

  unshiftObjects: function(objects) {
    this._replace(0, 0, objects);
    return this;
  },

  slice: function() {
    var arr = this.toArray();
    return arr.slice.apply(arr, arguments);
  },

  arrangedContentArrayWillChange: function(item, idx, removedCnt, addedCnt) {
    this.arrayContentWillChange(idx, removedCnt, addedCnt);
  },

  arrangedContentArrayDidChange: function(item, idx, removedCnt, addedCnt) {
    this.arrayContentDidChange(idx, removedCnt, addedCnt);
  },

  init: function() {
    this._super();
    this._setupContent();
    this._setupArrangedContent();
  },

  willDestroy: function() {
    this._teardownArrangedContent();
    this._teardownContent();
  }
});
<|endoftext|>


<commit_before><commit_msg>ensure that URL (web URI) is preserved<commit_after><|endoftext|>


<commit_before>(function(app) {
  'use strict';

  var dom = app.dom || require('../dom.js');
  var Button = app.Button || require('./button.js');

  var LoadButton = Button.inherits(function(props) {
    this.loader = props.loader;

    this.registerChangeListener();
  });

  LoadButton.prototype.inputElement = function() {
    return dom.child(this.element(), 2);
  };

  LoadButton.prototype.registerChangeListener = function() {
    dom.on(this.inputElement(), 'change', function(event) {
      var target = dom.target(event);
      var file = dom.file(target);

      if (!file) {
        return;
      }

      this.loader(file);

      // reset file input
      dom.value(target, '');
    }.bind(this));
  };

  LoadButton.prototype.ontap = function() {
    dom.click(this.inputElement());
  };

  if (typeof module !== 'undefined' && module.exports) {
    module.exports = LoadButton;
  } else {
    app.LoadButton = LoadButton;
  }
})(this.app || (this.app = {}));
<commit_msg>Remove unnecessary reset for input element of load-button<commit_after>(function(app) {
  'use strict';

  var dom = app.dom || require('../dom.js');
  var Button = app.Button || require('./button.js');

  var LoadButton = Button.inherits(function(props) {
    this.loader = props.loader;

    this.registerChangeListener();
  });

  LoadButton.prototype.inputElement = function() {
    return dom.child(this.element(), 2);
  };

  LoadButton.prototype.registerChangeListener = function() {
    dom.on(this.inputElement(), 'change', function(event) {
      var file = dom.file(dom.target(event));
      if (file) {
        this.loader(file);
      }
    }.bind(this));
  };

  LoadButton.prototype.ontap = function() {
    dom.click(this.inputElement());
  };

  if (typeof module !== 'undefined' && module.exports) {
    module.exports = LoadButton;
  } else {
    app.LoadButton = LoadButton;
  }
})(this.app || (this.app = {}));
<|endoftext|>


<commit_before>var tape = require('tape')
var crypto = require('crypto')
var b = require('../')

tape('simple', function (t) {

  var byte = b.byte
  var double = b.Double

  t.equal(byte.decode(byte.encode(9)), 9)
  t.equal(byte.decode.bytesRead, 1)
  t.equal(byte.encode.bytesWritten, 1)
  var r = Math.random()
  t.equal(double.decode(double.encode(r)), r)
  t.equal(double.decode.bytesRead, 8)
  t.equal(double.encode.bytesWritten, 8)
  t.end()
})

tape('vector', function (t) {
  var double = b.Double

  var vector = b({
    x: double,
    y: double,
    z: double
  })

  var v = {x: 1, y: 2, z: 3}
  var buffer = vector.encode(v)
  t.equal(vector.encode.bytesWritten, 24)
  console.log(buffer)
  t.equal(buffer.length, vector.length)
  t.deepEqual(vector.decode(buffer), v)
  t.equal(vector.decode.bytesRead, 24)
  t.end()
})

tape('buffer', function (t) {

  var sha256 = b.array(32) //a fixed length buffer

  var message = b({
    num : b.byte,
    hash: sha256
  })

  t.equal(message.length, 33)

  var expected = {
    num: 25,
    hash: crypto.createHash('sha256').digest()
  }
  var buffer = message.encode(expected)
  t.equal(message.encode.bytesWritten, 33)
  t.equal(sha256.encode.bytesWritten, 32)
  t.equal(buffer.length, 33)

  t.deepEqual(message.decode(buffer), expected)
  t.equal(sha256.decode.bytesRead, 32)
  t.equal(message.decode.bytesRead, 33)

  t.throws(function () {
    message.decode(buffer.slice(0, 16))
  })
  t.end()

})

tape('varbuf', function (t) {
  var slice = b.varbuf(b.byte)
  var expected = new Buffer([1, 2, 3, 4, 5])
  var buffer = slice.encode(expected)
  t.deepEqual(buffer, new Buffer([5, 1, 2, 3, 4, 5]))
  t.deepEqual(slice.decode(buffer), expected)
  t.end()
})

tape('varbuf + static', function (t) {

  var sha256 = b.array(32)

  var message = b({
    prev: sha256,
    author: sha256,
    sequence: b.UInt32,
    type: sha256,
    message: b.varbuf(b.byte)
  })
  var empty = crypto.createHash('sha256').digest()

  var zeros = new Buffer(32); zeros.fill()

  var expected = {
    prev     : empty, author : empty,
    sequence : 0,     type   : zeros,
    message  : new Buffer('hello there this is the first message', 'utf8')
  }

  var buffer = message.encode(expected)
  var expectedLength = 32 + 32 + 4 + 32 + expected.message.length + 1

  t.equal(message.encode.bytesWritten, expectedLength)

  t.deepEqual(message.decode(buffer), expected)
  t.equal(message.decode.bytesRead, expectedLength)

  t.end()

})

tape('varint buffer', function (t) {

  var buf = b.varbuf(b.varint)

  var buffer = buf.encode(new Buffer('hello'))
  console.log('out', buffer)
  t.deepEqual(new Buffer([0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f]), buffer)

  var expected = new Buffer(
    'hellohellohellohellohellohellohellohellohellohellohellohello\n'
  + 'hellohellohellohellohellohellohellohellohellohellohellohello\n'
  + 'hellohellohellohellohellohellohellohellohellohellohellohello\n'
  + 'hellohellohellohellohellohellohellohellohellohellohellohello\n'
  + 'hellohellohellohellohellohellohellohellohellohellohellohello\n'
  + 'hellohellohellohellohellohellohellohellohellohellohellohello\n'
  + 'hellohellohellohellohellohellohellohellohellohellohellohello\n'
  )

  var buffer = buf.encode(expected)

  console.log(buffer)
  t.equal(buffer.length, expected.length + 2)
  t.equal(buf.encode.bytesWritten, expected.length + 2)
  t.deepEqual(buf.decode(buffer), expected)
  t.equal(buf.decode.bytesRead, expected.length + 2)
  t.end()
})

tape('vararray', function (t) {

  var array = b.vararray(b.byte, b.DoubleBE)
  var expected = [
    Math.random(), Math.random(), Math.random(), Math.random(),
    Math.random(), Math.random(), Math.random(), Math.random(),
    Math.random(), Math.random(), Math.random(), Math.random(),
    Math.random(), Math.random(), Math.random(), Math.random(),
  ]

  var expectedLength = 1 + 8*4*4
  t.equal(array.encodingLength(expected), expectedLength)
  var buffer = array.encode(expected)
  t.equal(array.encode.bytesWritten, expectedLength)
  console.log(buffer)
  t.deepEqual(array.decode(buffer), expected)
  t.equal(array.decode.bytesRead, expectedLength)
  t.end()
})

tape('varstruct inside array', function (t) {
  var struct = b({
    i: b.varint,
    d: b.Double
  })
  var array = b.vararray(b.varint, struct)

  var expected = [          //length of varint
    {i:10, d:0.1},          //1
    {i:142, d:0.1231},      //2
    {i:123456,d:1e23},      //3
    {i:8383838,d:1e23},     //4
    {i:4000000000, d:2e-17} //5
  ]

  var buffer = array.encode(expected)
  var length = 1+2+3+4+5+(5*8)+1
  t.equal(array.encode.bytesWritten, length, 'bytesWritten')
  t.equal(array.encodingLength(expected), length, 'dynamicLength()')
  t.deepEqual(array.decode(buffer), expected)
  t.equal(array.decode.bytesRead, array.encode.bytesWritten)
  t.end()
})

tape('bounded numbers', function (t) {

  var max32 = b.bound(b.byte, 0, 32)
  var buffer = max32.encode(31)
  console.log(buffer)
  t.deepEqual(buffer, new Buffer([31]))
  t.equal(max32.decode(buffer), 31)
  t.throws(function () {
    max32.encode(33)
  })

  t.equal(max32.length, 1)

  var max1024 = b.bound(b.varint, 0, 1024)
  var buffer = max1024.encode(999)

  t.deepEqual(buffer, b.varint.encode(999))
  t.equal(max1024.decode(buffer), 999)
  t.throws(function () {
    max1024.encode(1025)
  })

  t.equal(max1024.encodingLength(999), 2)

  t.end()
})

tape('64bit ints', function (t) {
  var date = Date.now()
  var buffer = b.UInt64.encode(date)
  t.equal(buffer.length, 8)
  t.equal(b.UInt64.encode.bytesWritten, 8)
  t.equal(b.UInt64.decode(buffer), date)
  t.equal(b.UInt64.decode.bytesRead, 8)

  var buffer2 = b.UInt64LE.encode(date)
  t.equal(buffer2.length, 8)
  t.equal(b.UInt64LE.encode.bytesWritten, 8)
  t.equal(b.UInt64LE.decode(buffer2), date)
  t.equal(b.UInt64LE.decode.bytesRead, 8)

  t.notDeepEqual(buffer, buffer2)

  t.end()
})

tape('varbuf: buffer out of range', function (t) {
  var vb = b.varbuf(b.varint)
  var random = crypto.randomBytes(100)
  var buffer = vb.encode(random)
  t.throws(function () {
    vb.decode(buffer.slice(0, 40))
    console.log('expected a throw')
  })
  t.throws(function () {
    vb.decode(buffer.slice(40))
    console.log('expected a throw')
  })
  t.deepEqual(vb.decode(buffer), random)
  t.end()
})
<commit_msg>fix broken test<commit_after>var tape = require('tape')
var crypto = require('crypto')
var b = require('../')

tape('simple', function (t) {

  var byte = b.byte
  var double = b.Double

  t.equal(byte.decode(byte.encode(9)), 9)
  t.equal(byte.decode.bytesRead, 1)
  t.equal(byte.encode.bytesWritten, 1)
  var r = Math.random()
  t.equal(double.decode(double.encode(r)), r)
  t.equal(double.decode.bytesRead, 8)
  t.equal(double.encode.bytesWritten, 8)
  t.end()
})

tape('vector', function (t) {
  var double = b.Double

  var vector = b({
    x: double,
    y: double,
    z: double
  })

  var v = {x: 1, y: 2, z: 3}
  var buffer = vector.encode(v)
  t.equal(vector.encode.bytesWritten, 24)
  console.log(buffer)
  t.equal(buffer.length, vector.length)
  t.deepEqual(vector.decode(buffer), v)
  t.equal(vector.decode.bytesRead, 24)
  t.end()
})

tape('buffer', function (t) {

  var sha256 = b.array(32) //a fixed length buffer

  var message = b({
    num : b.byte,
    hash: sha256
  })

  t.equal(message.length, 33)

  var expected = {
    num: 25,
    hash: crypto.createHash('sha256').digest()
  }
  var buffer = message.encode(expected)
  t.equal(message.encode.bytesWritten, 33)
  t.equal(sha256.encode.bytesWritten, 32)
  t.equal(buffer.length, 33)

  t.deepEqual(message.decode(buffer), expected)
  t.equal(sha256.decode.bytesRead, 32)
  t.equal(message.decode.bytesRead, 33)

  t.throws(function () {
    message.decode(buffer.slice(0, 16))
  })
  t.end()

})

tape('varbuf', function (t) {
  var slice = b.varbuf(b.byte)
  var expected = new Buffer([1, 2, 3, 4, 5])
  var buffer = slice.encode(expected)
  t.deepEqual(buffer, new Buffer([5, 1, 2, 3, 4, 5]))
  t.deepEqual(slice.decode(buffer), expected)
  t.end()
})

tape('varbuf + static', function (t) {

  var sha256 = b.array(32)

  var message = b({
    prev: sha256,
    author: sha256,
    sequence: b.UInt32,
    type: sha256,
    message: b.varbuf(b.byte)
  })
  var empty = crypto.createHash('sha256').digest()

  var zeros = new Buffer(32); zeros.fill()

  var expected = {
    prev     : empty, author : empty,
    sequence : 0,     type   : zeros,
    message  : new Buffer('hello there this is the first message', 'utf8')
  }

  var buffer = message.encode(expected)
  var expectedLength = 32 + 32 + 4 + 32 + expected.message.length + 1

  t.equal(message.encode.bytesWritten, expectedLength)

  t.deepEqual(message.decode(buffer), expected)
  t.equal(message.decode.bytesRead, expectedLength)

  t.end()

})

tape('varint buffer', function (t) {

  var buf = b.varbuf(b.varint)

  var buffer = buf.encode(new Buffer('hello'))
  console.log('out', buffer)
  t.deepEqual(new Buffer([0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f]), buffer)

  var expected = new Buffer(
    'hellohellohellohellohellohellohellohellohellohellohellohello\n'
  + 'hellohellohellohellohellohellohellohellohellohellohellohello\n'
  + 'hellohellohellohellohellohellohellohellohellohellohellohello\n'
  + 'hellohellohellohellohellohellohellohellohellohellohellohello\n'
  + 'hellohellohellohellohellohellohellohellohellohellohellohello\n'
  + 'hellohellohellohellohellohellohellohellohellohellohellohello\n'
  + 'hellohellohellohellohellohellohellohellohellohellohellohello\n'
  )

  var buffer = buf.encode(expected)

  console.log(buffer)
  t.equal(buffer.length, expected.length + 2)
  t.equal(buf.encode.bytesWritten, expected.length + 2)
  t.deepEqual(buf.decode(buffer), expected)
  t.equal(buf.decode.bytesRead, expected.length + 2)
  t.end()
})

tape('vararray', function (t) {

  var array = b.vararray(b.byte, b.DoubleBE)
  var expected = [
    Math.random(), Math.random(), Math.random(), Math.random(),
    Math.random(), Math.random(), Math.random(), Math.random(),
    Math.random(), Math.random(), Math.random(), Math.random(),
    Math.random(), Math.random(), Math.random(), Math.random(),
  ]

  var expectedLength = 1 + 8*4*4
  t.equal(array.encodingLength(expected), expectedLength)
  var buffer = array.encode(expected)
  t.equal(array.encode.bytesWritten, expectedLength)
  console.log(buffer)
  t.deepEqual(array.decode(buffer), expected)
  t.equal(array.decode.bytesRead, expectedLength)
  t.end()
})

tape('varstruct inside array', function (t) {
  var struct = b({
    i: b.varint,
    d: b.Double
  })
  var array = b.vararray(b.varint, struct)

  var expected = [          //length of varint
    {i:10, d:0.1},          //1
    {i:142, d:0.1231},      //2
    {i:123456,d:1e23},      //3
    {i:8383838,d:1e23},     //4
    {i:4000000000, d:2e-17} //5
  ]

  var buffer = array.encode(expected)
  var length = 1+2+3+4+5+(5*8)+1
  t.equal(array.encode.bytesWritten, length, 'bytesWritten')
  t.equal(array.encodingLength(expected), length, 'dynamicLength()')
  t.deepEqual(array.decode(buffer), expected)
  t.equal(array.decode.bytesRead, array.encode.bytesWritten)
  t.end()
})

tape('bounded numbers', function (t) {

  var max32 = b.bound(b.byte, 0, 32)
  var buffer = max32.encode(31)
  console.log(buffer)
  t.deepEqual(buffer, new Buffer([31]))
  t.equal(max32.decode(buffer), 31)
  t.throws(function () {
    max32.encode(33)
  })

  t.equal(max32.length, 1)

  var max1024 = b.bound(b.varint, 0, 1024)
  var buffer = max1024.encode(999)

  t.deepEqual(buffer, b.varint.encode(999))
  t.equal(max1024.decode(buffer), 999)
  t.throws(function () {
    max1024.encode(1025)
  })

  t.equal(max1024.encodingLength(999), 2)

  t.end()
})

tape('64bit ints', function (t) {
  var date = Date.now()
  var buffer = b.UInt64.encode(date)
  t.equal(buffer.length, 8)
  t.equal(b.UInt64.encode.bytesWritten, 8)
  t.equal(b.UInt64.decode(buffer), date)
  t.equal(b.UInt64.decode.bytesRead, 8)

  var buffer2 = b.UInt64LE.encode(date)
  t.equal(buffer2.length, 8)
  t.equal(b.UInt64LE.encode.bytesWritten, 8)
  t.equal(b.UInt64LE.decode(buffer2), date)
  t.equal(b.UInt64LE.decode.bytesRead, 8)

  t.notDeepEqual(buffer, buffer2)

  t.end()
})

tape('varbuf: buffer out of range', function (t) {
  var vb = b.varbuf(b.varint)
  var random = crypto.randomBytes(100)
  var buffer = vb.encode(random)
  t.throws(function () {
    vb.decode(buffer.slice(0, 40))
    console.log('expected a throw')
  })
  var l = buffer.length
  while(l--)
    t.throws(function () {
      vb.decode(buffer.slice(0, l))
      console.log('expected a throw')
    })
//this isn't a good test, because SOMETIMES this produces
//a valid varbuf
//  t.throws(function () {
//    var value = vb.decode(buffer.slice(40))
//    console.log('expected a throw, got:', value, random)
//  })

  t.deepEqual(vb.decode(buffer), random)
  t.end()
})
<|endoftext|>


<commit_before>(function(app) {
  'use strict';

  var dom = app.dom || require('../dom.js');
  var Component = app.Component || require('./component.js');

  var ModulePort = Component.inherits(function(props) {
    this.parentListElement = this.prop(props.parentListElement);
    this.parentOptGroupElement = this.prop(props.parentOptGroupElement);

    this.listItem = new ModulePort.ListItem({
      label: props.label,
      type: props.type,
      plugDisabled: props.plugDisabled,
      socketDisabled: props.socketDisabled,
    });

    this.option = new ModulePort.Option({
      parentElement: props.parentOptGroupElement,
      label: props.label,
      name: props.name,
    });
  });

  ModulePort.prototype.visible = function(value) {
    if (typeof value !== 'undefined') {
      this.markDirty();
      this.listItem.parentElement(value ? this.parentListElement() : null);
      this.option.parentElement(value ? null : this.parentOptGroupElement());
    }
    return (this.listItem.parentElement() !== null);
  };

  ModulePort.prototype.label = function() {
    return this.listItem.label();
  };

  ModulePort.prototype.name = function() {
    return this.option.name();
  };

  ModulePort.prototype.type = function() {
    return this.listItem.type();
  };

  ModulePort.prototype.top = function(value) {
    if (typeof value !== 'undefined') {
      this.markDirty();
    }
    return this.listItem.top(value);
  };

  ModulePort.prototype.highlighted = function(value) {
    if (typeof value !== 'undefined') {
      this.markDirty();
    }
    return this.listItem.highlighted(value);
  };

  ModulePort.prototype.isMoving = function(value) {
    if (typeof value !== 'undefined') {
      this.markDirty();
    }
    return this.listItem.isMoving(value);
  };

  ModulePort.prototype.plugDisabled = function() {
    return this.listItem.plugDisabled();
  };

  ModulePort.prototype.plugHighlighted = function(value) {
    if (!this.visible()) {
      return false;
    }
    if (typeof value !== 'undefined') {
      this.markDirty();
    }
    return this.listItem.plugHighlighted(value);
  };

  ModulePort.prototype.socketDisabled = function() {
    return this.listItem.socketDisabled();
  };

  ModulePort.prototype.socketHighlighted = function(value) {
    if (typeof value !== 'undefined') {
      this.markDirty();
    }
    return this.listItem.socketHighlighted(value);
  };

  ModulePort.prototype.socketConnected = function(value) {
    if (typeof value !== 'undefined') {
      this.markDirty();
    }
    return this.listItem.socketConnected(value);
  };

  ModulePort.prototype.height = function() {
    return this.listItem.height();
  };

  ModulePort.prototype.middle = function() {
    return this.top() + this.height() / 2;
  };

  ModulePort.prototype.bottom = function() {
    return this.top() + this.height();
  };

  ModulePort.prototype.plugOffsetX = function() {
    return this.listItem.plugOffsetX();
  };

  ModulePort.prototype.socketOffsetX = function() {
    return this.listItem.socketOffsetX();
  };

  ModulePort.prototype.elementContains = function(element) {
    var listItemElement = this.listItem.element();
    return (listItemElement ? dom.contains(listItemElement, element) : false);
  };

  ModulePort.prototype.redraw = function() {
    this.listItem.redraw();
    this.option.redraw();
  };

  ModulePort.TYPE_PROP = 'prop';
  ModulePort.TYPE_EVENT = 'event';

  ModulePort.PLUG_WIDTH = 50;
  ModulePort.SOCKET_WIDTH = 50;

  ModulePort.ListItem = (function() {
    var ListItem = Component.inherits(function(props) {
      this.label = this.prop(props.label);
      this.type = this.prop(props.type);
      this.socketDisabled = this.prop(props.socketDisabled);
      this.top = this.prop(0);
      this.highlighted = this.prop(false);
      this.isMoving = this.prop(false);
      this.socketHighlighted = this.prop(false);
      this.socketConnected = this.prop(false);
      this.height = this.prop(44);
      this.plugOffsetX = this.prop(261);
      this.socketOffsetX = this.prop(-25);

      this.plug = new ListItem.Handle({ disabled: props.plugDisabled });
    });

    ListItem.prototype.plugElement = function() {
      return dom.child(this.element(), 0);
    };

    ListItem.prototype.socketElement = function() {
      return dom.child(this.element(), 1);
    };

    ListItem.prototype.socketHandleElement = function() {
      return dom.child(this.element(), 1, 0);
    };

    ListItem.prototype.labelElement = function() {
      return dom.child(this.element(), 2);
    };

    ListItem.prototype.hideButtonElement = function() {
      return dom.child(this.element(), 3);
    };

    ListItem.prototype.hideDisabled = function() {
      // don't hide highlighted port
      return this.highlighted();
    };

    ListItem.prototype.plugDisabled = function(value) {
      return this.plug.disabled(value);
    };

    ListItem.prototype.plugHighlighted = function(value) {
      return this.plug.highlighted(value);
    };

    ListItem.prototype.render = function() {
      return dom.render(ListItem.HTML_TEXT);
    };

    ListItem.prototype.onappend = function() {
      this.plug.element(this.plugElement());
      this.plug.parentElement(this.element());
      this.plug.redraw();
    };

    ListItem.prototype.onredraw = function() {
      this.redrawType();
      this.redrawPosition();
      this.redrawDOMToggleClasses();
      this.redrawSocket();
      this.redrawLabel();
      this.redrawHideButton();
    };

    ListItem.prototype.redrawType = function() {
      this.redrawDOMDataBy('type', 'type');
    };

    ListItem.prototype.redrawPosition = function() {
      this.redrawBy('top', function(top) {
        dom.translateY(this.element(), top);
      });
    };

    ListItem.prototype.redrawDOMToggleClasses = function() {
      this.redrawDOMToggleClassBy('highlighted', 'highlighted');
      this.redrawDOMToggleClassBy('isMoving', 'moving');
    };

    ListItem.prototype.redrawSocket = function() {
      this.redrawBy('socketDisabled', function(socketDisabled) {
        dom.toggleClass(this.socketElement(), 'hide', socketDisabled);
      });

      this.redrawBy('socketHighlighted', function(socketHighlighted) {
        dom.toggleClass(this.socketElement(), 'highlighted', socketHighlighted);
        dom.toggleClass(this.socketHandleElement(), 'highlighted', socketHighlighted);
      });

      this.redrawBy('socketConnected', function(socketConnected) {
        dom.toggleClass(this.socketHandleElement(), 'hide', !socketConnected);
      });
    };

    ListItem.prototype.redrawLabel = function() {
      this.redrawBy('label', function(label) {
        dom.text(this.labelElement(), label);
      });
    };

    ListItem.prototype.redrawHideButton = function() {
      this.redrawBy('hideDisabled', function(hideDisabled) {
        dom.toggleClass(this.hideButtonElement(), 'disabled', hideDisabled);
      });
    };

    ListItem.HTML_TEXT = [
      '
',
        '

',
        '
',
          '

',
        '
',
        '

',
        '',
      '
',
    ].join('');

    ListItem.Handle = (function() {
      var Handle = Component.inherits(function(props) {
        this.disabled = this.prop(props.disabled);
        this.highlighted = this.prop(false);
      });

      Handle.prototype.redraw = function() {
        this.redrawDOMToggleClassBy('disabled', 'hide');
        this.redrawDOMToggleClassBy('highlighted', 'highlighted');
      };

      return Handle;
    })();

    return ListItem;
  })();

  ModulePort.Option = (function() {
    var Option = Component.inherits(function(props) {
      this.label = this.prop(props.label);
      this.name = this.prop(props.name);
    });

    Option.prototype.render = function() {
      return dom.render(Option.HTML_TEXT);
    };

    Option.prototype.onredraw = function() {
      this.redrawDOMTextBy('label');
      this.redrawDOMValueBy('name');
    };

    Option.HTML_TEXT = '<option></option>';

    return Option;
  })();

  if (typeof module !== 'undefined' && module.exports) {
    module.exports = ModulePort;
  } else {
    app.ModulePort = ModulePort;
  }
})(this.app || (this.app = {}));
<commit_msg>Make component for hide-button of module-port list-item<commit_after>(function(app) {
  'use strict';

  var dom = app.dom || require('../dom.js');
  var Component = app.Component || require('./component.js');

  var ModulePort = Component.inherits(function(props) {
    this.parentListElement = this.prop(props.parentListElement);
    this.parentOptGroupElement = this.prop(props.parentOptGroupElement);

    this.listItem = new ModulePort.ListItem({
      label: props.label,
      type: props.type,
      plugDisabled: props.plugDisabled,
      socketDisabled: props.socketDisabled,
    });

    this.option = new ModulePort.Option({
      parentElement: props.parentOptGroupElement,
      label: props.label,
      name: props.name,
    });
  });

  ModulePort.prototype.visible = function(value) {
    if (typeof value !== 'undefined') {
      this.markDirty();
      this.listItem.parentElement(value ? this.parentListElement() : null);
      this.option.parentElement(value ? null : this.parentOptGroupElement());
    }
    return (this.listItem.parentElement() !== null);
  };

  ModulePort.prototype.label = function() {
    return this.listItem.label();
  };

  ModulePort.prototype.name = function() {
    return this.option.name();
  };

  ModulePort.prototype.type = function() {
    return this.listItem.type();
  };

  ModulePort.prototype.top = function(value) {
    if (typeof value !== 'undefined') {
      this.markDirty();
    }
    return this.listItem.top(value);
  };

  ModulePort.prototype.highlighted = function(value) {
    if (typeof value !== 'undefined') {
      this.markDirty();

      // don't hide highlighted port
      this.listItem.hideDisabled(value);
    }
    return this.listItem.highlighted(value);
  };

  ModulePort.prototype.isMoving = function(value) {
    if (typeof value !== 'undefined') {
      this.markDirty();
    }
    return this.listItem.isMoving(value);
  };

  ModulePort.prototype.plugDisabled = function() {
    return this.listItem.plugDisabled();
  };

  ModulePort.prototype.plugHighlighted = function(value) {
    if (!this.visible()) {
      return false;
    }
    if (typeof value !== 'undefined') {
      this.markDirty();
    }
    return this.listItem.plugHighlighted(value);
  };

  ModulePort.prototype.socketDisabled = function() {
    return this.listItem.socketDisabled();
  };

  ModulePort.prototype.socketHighlighted = function(value) {
    if (typeof value !== 'undefined') {
      this.markDirty();
    }
    return this.listItem.socketHighlighted(value);
  };

  ModulePort.prototype.socketConnected = function(value) {
    if (typeof value !== 'undefined') {
      this.markDirty();
    }
    return this.listItem.socketConnected(value);
  };

  ModulePort.prototype.height = function() {
    return this.listItem.height();
  };

  ModulePort.prototype.middle = function() {
    return this.top() + this.height() / 2;
  };

  ModulePort.prototype.bottom = function() {
    return this.top() + this.height();
  };

  ModulePort.prototype.plugOffsetX = function() {
    return this.listItem.plugOffsetX();
  };

  ModulePort.prototype.socketOffsetX = function() {
    return this.listItem.socketOffsetX();
  };

  ModulePort.prototype.elementContains = function(element) {
    var listItemElement = this.listItem.element();
    return (listItemElement ? dom.contains(listItemElement, element) : false);
  };

  ModulePort.prototype.redraw = function() {
    this.listItem.redraw();
    this.option.redraw();
  };

  ModulePort.TYPE_PROP = 'prop';
  ModulePort.TYPE_EVENT = 'event';

  ModulePort.PLUG_WIDTH = 50;
  ModulePort.SOCKET_WIDTH = 50;

  ModulePort.ListItem = (function() {
    var ListItem = Component.inherits(function(props) {
      this.label = this.prop(props.label);
      this.type = this.prop(props.type);
      this.socketDisabled = this.prop(props.socketDisabled);
      this.top = this.prop(0);
      this.highlighted = this.prop(false);
      this.isMoving = this.prop(false);
      this.socketHighlighted = this.prop(false);
      this.socketConnected = this.prop(false);
      this.height = this.prop(44);
      this.plugOffsetX = this.prop(261);
      this.socketOffsetX = this.prop(-25);

      this.plug = new ListItem.Handle({ disabled: props.plugDisabled });
      this.hideButton = new ListItem.HideButton();
    });

    ListItem.prototype.plugElement = function() {
      return dom.child(this.element(), 0);
    };

    ListItem.prototype.socketElement = function() {
      return dom.child(this.element(), 1);
    };

    ListItem.prototype.socketHandleElement = function() {
      return dom.child(this.element(), 1, 0);
    };

    ListItem.prototype.labelElement = function() {
      return dom.child(this.element(), 2);
    };

    ListItem.prototype.hideButtonElement = function() {
      return dom.child(this.element(), 3);
    };

    ListItem.prototype.plugDisabled = function(value) {
      return this.plug.disabled(value);
    };

    ListItem.prototype.plugHighlighted = function(value) {
      return this.plug.highlighted(value);
    };

    ListItem.prototype.hideDisabled = function(value) {
      return this.hideButton.disabled(value);
    };

    ListItem.prototype.render = function() {
      return dom.render(ListItem.HTML_TEXT);
    };

    ListItem.prototype.onappend = function() {
      this.plug.element(this.plugElement());
      this.plug.parentElement(this.element());
      this.plug.redraw();

      this.hideButton.element(this.hideButtonElement());
      this.hideButton.parentElement(this.element());
      this.hideButton.redraw();
    };

    ListItem.prototype.onredraw = function() {
      this.redrawType();
      this.redrawPosition();
      this.redrawDOMToggleClasses();
      this.redrawSocket();
      this.redrawLabel();
    };

    ListItem.prototype.redrawType = function() {
      this.redrawDOMDataBy('type', 'type');
    };

    ListItem.prototype.redrawPosition = function() {
      this.redrawBy('top', function(top) {
        dom.translateY(this.element(), top);
      });
    };

    ListItem.prototype.redrawDOMToggleClasses = function() {
      this.redrawDOMToggleClassBy('highlighted', 'highlighted');
      this.redrawDOMToggleClassBy('isMoving', 'moving');
    };

    ListItem.prototype.redrawSocket = function() {
      this.redrawBy('socketDisabled', function(socketDisabled) {
        dom.toggleClass(this.socketElement(), 'hide', socketDisabled);
      });

      this.redrawBy('socketHighlighted', function(socketHighlighted) {
        dom.toggleClass(this.socketElement(), 'highlighted', socketHighlighted);
        dom.toggleClass(this.socketHandleElement(), 'highlighted', socketHighlighted);
      });

      this.redrawBy('socketConnected', function(socketConnected) {
        dom.toggleClass(this.socketHandleElement(), 'hide', !socketConnected);
      });
    };

    ListItem.prototype.redrawLabel = function() {
      this.redrawBy('label', function(label) {
        dom.text(this.labelElement(), label);
      });
    };

    ListItem.HTML_TEXT = [
      '
',
        '

',
        '
',
          '

',
        '
',
        '

',
        '',
      '
',
    ].join('');

    ListItem.Handle = (function() {
      var Handle = Component.inherits(function(props) {
        this.disabled = this.prop(props.disabled);
        this.highlighted = this.prop(false);
      });

      Handle.prototype.redraw = function() {
        this.redrawDOMToggleClassBy('disabled', 'hide');
        this.redrawDOMToggleClassBy('highlighted', 'highlighted');
      };

      return Handle;
    })();

    ListItem.HideButton = (function() {
      var HideButton = Component.inherits(function() {
        this.disabled = this.prop(false);
      });

      HideButton.prototype.redraw = function() {
        this.redrawDOMToggleClassBy('disabled', 'disabled');
      };

      return HideButton;
    })();

    return ListItem;
  })();

  ModulePort.Option = (function() {
    var Option = Component.inherits(function(props) {
      this.label = this.prop(props.label);
      this.name = this.prop(props.name);
    });

    Option.prototype.render = function() {
      return dom.render(Option.HTML_TEXT);
    };

    Option.prototype.onredraw = function() {
      this.redrawDOMTextBy('label');
      this.redrawDOMValueBy('name');
    };

    Option.HTML_TEXT = '<option></option>';

    return Option;
  })();

  if (typeof module !== 'undefined' && module.exports) {
    module.exports = ModulePort;
  } else {
    app.ModulePort = ModulePort;
  }
})(this.app || (this.app = {}));
<|endoftext|>


<commit_before>var WS = require('pull-ws')
var URL = require('url')

module.exports = function (opts) {

  return {
    name: 'ws',
    server: function (onConnect) {
      var server = WS.createServer(opts, function (stream) {
        onConnect(stream)
      })

      if(!opts.server) server.listen(opts.port)
      return server.close.bind(server)
    },
    client: function (addr, cb) {
      if(!addr.host) {
        addr.hostname = addr.hostname || opts.host || 'localhost'
        addr.slashes = true
        addr = URL.format(addr)
      }

      var stream = WS.connect(addr, {onConnect: function (err) {
        cb(err, stream)
      }})
    },
    stringify: function () {
      return URL.format({
        protocol: 'ws',
        slashes: true,
        hostname: opts.host || 'localhost', //detect ip address
        port: opts.port
      })
    },
    parse: function (str) {
      var addr = URL.parse(str)
      if(!/^wss?\:$/.test(addr.protocol)) return null
      return addr
    }
  }
}

<commit_msg>set default binary type<commit_after>var WS = require('pull-ws')
var URL = require('url')

module.exports = function (opts) {
  opts = opts || {}
  opts.binaryType = opts.binaryType: 'arraybuffer')
  return {
    name: 'ws',
    server: function (onConnect) {
      var server = WS.createServer(opts, function (stream) {
        onConnect(stream)
      })

      if(!opts.server) server.listen(opts.port)
      return server.close.bind(server)
    },
    client: function (addr, cb) {
      if(!addr.host) {
        addr.hostname = addr.hostname || opts.host || 'localhost'
        addr.slashes = true
        addr = URL.format(addr)
      }

      var stream = WS.connect(addr, {
        binaryType: opts.binaryType,
        onConnect: function (err) {
          cb(err, stream)
        }
      })
    },
    stringify: function () {
      return URL.format({
        protocol: 'ws',
        slashes: true,
        hostname: opts.host || 'localhost', //detect ip address
        port: opts.port
      })
    },
    parse: function (str) {
      var addr = URL.parse(str)
      if(!/^wss?\:$/.test(addr.protocol)) return null
      return addr
    }
  }
}

<|endoftext|>


<commit_before>require('../helper');

var _      = require('underscore')
    , redis  = require("redis")
    , MetaData  = require('../../app/models/metadata')
    , assert = require('assert')

    , tests  = module.exports = {};

tests['test can retrieve database name from header and redis'] = function(){
    var req = {headers: {host: 'vizzuality.cartodb.com'}};

    MetaData.getDatabase(req, function(err, data){
        assert.equal(data, 'cartodb_test_user_1_db');
    });
};

tests['test can retrieve id from header and redis'] = function(){
    var req = {headers: {host: 'vizzuality.cartodb.com'}};

    MetaData.getId(req, function(err, data){
        assert.equal(data, '1');
    });
};
<commit_msg>metadata unit test tidy<commit_after>require('../helper');

var _           = require('underscore')
    , redis     = require("redis")
    , MetaData  = require('../../app/models/metadata')
    , assert    = require('assert')
    , tests  = module.exports = {};

tests['test can retrieve database name from header and redis'] = function(){
    var req = {headers: {host: 'vizzuality.cartodb.com'}};

    MetaData.getDatabase(req, function(err, data){
        assert.equal(data, 'cartodb_test_user_1_db');
    });
};

tests['test can retrieve id from header and redis'] = function(){
    var req = {headers: {host: 'vizzuality.cartodb.com'}};

    MetaData.getId(req, function(err, data){
        assert.equal(data, '1');
    });
};
<|endoftext|>


<commit_before>var test = require('tape')
var bashEmulator = require('../src')

test('initialise', function (t) {
  t.plan(1)
  var emulator = bashEmulator()
  t.equal(typeof emulator, 'object', 'emulator is an object')
})

test('initialise with state', function (t) {
  t.plan(1)
  var testState = {
    history: ['ls'],
    user: 'test',
    workingDirectory: '/home/test',
    fileSystem: {
      '/': {
        type: 'dir',
        lastEdited: Date.now()
      },
      '/home': {
        type: 'dir',
        lastEdited: Date.now()
      },
      '/home/test': {
        type: 'dir',
        lastEdited: Date.now()
      }
    }
  }
  var emulator = bashEmulator(testState)
  t.deepEqual(emulator.state, testState, 'emulator uses initial state')
})

test('run missing command', function (t) {
  t.plan(1)
  bashEmulator().run('nonexistend').then(null, function (err) {
    t.equals(err, 'nonexistend: command not found', 'error when running missing comand')
  })
})

test('change working directory', function (t) {
  t.plan(5)
  var emulator = bashEmulator()
  emulator.getDir().then(function (dir) {
    t.equal(dir, '/home/user', 'initial WD matches')
  }).then(function () {
    return emulator.changeDir('..')
  }).then(function () {
    return emulator.getDir()
  }).then(function (dir) {
    t.equal(dir, '/home', 'changes dir with ..')
  }).then(function () {
    return emulator.changeDir('/')
  }).then(function () {
    return emulator.getDir()
  }).then(function (dir) {
    t.equal(dir, '/', 'changes dir with absolute path')
  }).then(function () {
    return emulator.changeDir('home/user')
  }).then(function () {
    return emulator.getDir()
  }).then(function (dir) {
    t.equal(dir, '/home/user', 'changes dir with chained path')
  }).then(function () {
    return emulator.changeDir('nonexistend')
  }).then(null, function (err) {
    t.equal(err, '/home/user/nonexistend: No such file or directory', 'cannot change to non-existend dir')
  })
})

test('update history', function (t) {
  t.plan(2)
  var emulator = bashEmulator()
  emulator.getHistory().then(function (history) {
    t.deepEqual(history, [], 'history is empty')
  }).then(function () {
    return emulator.run('ls /')
  }).then(function () {
    return emulator.getHistory()
  }).then(function (history) {
    t.deepEqual(history, ['ls /'], 'command get appended to history')
  })
})

test('reading files', function (t) {
  t.plan(3)
  var testState = {
    history: [],
    workingDirectory: '/',
    fileSystem: {
      '/': {
        type: 'dir',
        lastEdited: Date.now()
      },
      '/log.txt': {
        type: 'file',
        lastEdited: Date.now(),
        content: 'some log'
      }
    }
  }
  var emulator = bashEmulator(testState)
  emulator.read('/nonexistend').then(null, function (err) {
    t.equal(err, '/nonexistend: No such file or directory', 'cannot read missing file')
  })
  emulator.read('/').then(null, function (err) {
    t.equal(err, '/: Is a directory', 'cannot read content of directory')
  })
  emulator.read('/log.txt').then(function (content) {
    t.equal(content, 'some log', 'read content of a file')
  })
})

test('removing', function (t) {
  t.plan(4)
  var testState = {
    history: [],
    workingDirectory: '/',
    fileSystem: {
      '/': {
        type: 'dir',
        lastEdited: Date.now()
      },
      '/home': {
        type: 'dir',
        lastEdited: Date.now()
      },
      '/home/test': {
        type: 'dir',
        lastEdited: Date.now()
      },
      '/log.txt': {
        type: 'file',
        lastEdited: Date.now(),
        content: 'some log'
      }
    }
  }
  var emulator = bashEmulator(testState)
  emulator.remove('/nonexistend').then(null, function (err) {
    t.equal(err, 'cannot remove ‘/nonexistend’: No such file or directory', 'cannot remove non-existend file')
  })
  emulator.remove('/log.txt').then(function () {
    return emulator.remove('/log.txt')
  }).then(null, function () {
    t.ok(true, 'file is deleted')
  })
  emulator.remove('/home').then(function () {
    emulator.remove('/home').then(null, function () {
      t.ok(true, 'directory is deleted')
    })
    emulator.remove('/home/test').then(null, function () {
      t.ok(true, 'sub-directory is deleted')
    })
  })
})

//
// running sub tests
//
require('./commands/pwd')
require('./commands/cd')
<commit_msg>test cov<commit_after>var test = require('tape')
var bashEmulator = require('../src')

test('initialise', function (t) {
  t.plan(1)
  var emulator = bashEmulator()
  t.equal(typeof emulator, 'object', 'emulator is an object')
})

test('initialise with state', function (t) {
  t.plan(1)
  var testState = {
    history: ['ls'],
    user: 'test',
    workingDirectory: '/home/test',
    fileSystem: {
      '/': {
        type: 'dir',
        lastEdited: Date.now()
      },
      '/home': {
        type: 'dir',
        lastEdited: Date.now()
      },
      '/home/test': {
        type: 'dir',
        lastEdited: Date.now()
      }
    }
  }
  var emulator = bashEmulator(testState)
  t.deepEqual(emulator.state, testState, 'emulator uses initial state')
})

test('run missing command', function (t) {
  t.plan(1)
  bashEmulator().run('nonexistend').then(null, function (err) {
    t.equals(err, 'nonexistend: command not found', 'error when running missing comand')
  })
})

test('change working directory', function (t) {
  t.plan(6)
  var emulator = bashEmulator()
  emulator.getDir().then(function (dir) {
    t.equal(dir, '/home/user', 'initial WD matches')
  }).then(function () {
    return emulator.changeDir('..')
  }).then(function () {
    return emulator.getDir()
  }).then(function (dir) {
    t.equal(dir, '/home', 'changes dir with ..')
  }).then(function () {
    return emulator.changeDir('./user')
  }).then(function () {
    return emulator.getDir()
  }).then(function (dir) {
    t.equal(dir, '/home/user', 'changes dir with relative path')
  }).then(function () {
    return emulator.changeDir('/')
  }).then(function () {
    return emulator.getDir()
  }).then(function (dir) {
    t.equal(dir, '/', 'changes dir with absolute path')
  }).then(function () {
    return emulator.changeDir('home/user')
  }).then(function () {
    return emulator.getDir()
  }).then(function (dir) {
    t.equal(dir, '/home/user', 'changes dir with chained path')
  }).then(function () {
    return emulator.changeDir('nonexistend')
  }).then(null, function (err) {
    t.equal(err, '/home/user/nonexistend: No such file or directory', 'cannot change to non-existend dir')
  })
})

test('update history', function (t) {
  t.plan(2)
  var emulator = bashEmulator()
  emulator.getHistory().then(function (history) {
    t.deepEqual(history, [], 'history is empty')
  }).then(function () {
    return emulator.run('ls /')
  }).then(function () {
    return emulator.getHistory()
  }).then(function (history) {
    t.deepEqual(history, ['ls /'], 'command get appended to history')
  })
})

test('reading files', function (t) {
  t.plan(3)
  var testState = {
    history: [],
    workingDirectory: '/',
    fileSystem: {
      '/': {
        type: 'dir',
        lastEdited: Date.now()
      },
      '/log.txt': {
        type: 'file',
        lastEdited: Date.now(),
        content: 'some log'
      }
    }
  }
  var emulator = bashEmulator(testState)
  emulator.read('/nonexistend').then(null, function (err) {
    t.equal(err, '/nonexistend: No such file or directory', 'cannot read missing file')
  })
  emulator.read('/').then(null, function (err) {
    t.equal(err, '/: Is a directory', 'cannot read content of directory')
  })
  emulator.read('/log.txt').then(function (content) {
    t.equal(content, 'some log', 'read content of a file')
  })
})

// test('reading a directory\'s content', function (t) {
//   t.plan(1)
//   var emulator = bashEmulator()
//   emulator.readDir('/home')
// })

test('removing', function (t) {
  t.plan(4)
  var testState = {
    history: [],
    workingDirectory: '/',
    fileSystem: {
      '/': {
        type: 'dir',
        lastEdited: Date.now()
      },
      '/home': {
        type: 'dir',
        lastEdited: Date.now()
      },
      '/home/test': {
        type: 'dir',
        lastEdited: Date.now()
      },
      '/log.txt': {
        type: 'file',
        lastEdited: Date.now(),
        content: 'some log'
      }
    }
  }
  var emulator = bashEmulator(testState)
  emulator.remove('/nonexistend').then(null, function (err) {
    t.equal(err, 'cannot remove ‘/nonexistend’: No such file or directory', 'cannot remove non-existend file')
  })
  emulator.remove('/log.txt').then(function () {
    return emulator.remove('/log.txt')
  }).then(null, function () {
    t.ok(true, 'file is deleted')
  })
  emulator.remove('/home').then(function () {
    emulator.remove('/home').then(null, function () {
      t.ok(true, 'directory is deleted')
    })
    emulator.remove('/home/test').then(null, function () {
      t.ok(true, 'sub-directory is deleted')
    })
  })
})

//
// running sub tests
//
require('./commands/pwd')
require('./commands/cd')
<|endoftext|>