goog.provide('ol.test.Object'); describe('ol.Object', function() { var o; beforeEach(function() { o = new ol.Object(); }); describe('get and set', function() { describe('get an unset property', function() { var v; beforeEach(function() { v = o.get('k'); }); it('returns undefined', function() { expect(v).to.be(undefined); }); }); describe('get a set property', function() { var v; beforeEach(function() { o.set('k', 1); v = o.get('k'); }); it('returns expected value', function() { expect(v).to.eql(1); }); }); }); describe('#get()', function() { it('does not return values that are not explicitly set', function() { var o = new ol.Object(); expect(o.get('constructor')).to.be(undefined); expect(o.get('hasOwnProperty')).to.be(undefined); expect(o.get('isPrototypeOf')).to.be(undefined); expect(o.get('propertyIsEnumerable')).to.be(undefined); expect(o.get('toLocaleString')).to.be(undefined); expect(o.get('toString')).to.be(undefined); expect(o.get('valueOf')).to.be(undefined); }); }); describe('#set()', function() { it('can be used with arbitrary names', function() { var o = new ol.Object(); o.set('set', 'sat'); expect(o.get('set')).to.be('sat'); o.set('get', 'got'); expect(o.get('get')).to.be('got'); o.set('toString', 'string'); expect(o.get('toString')).to.be('string'); expect(typeof o.toString).to.be('function'); }); }); describe('#getKeys()', function() { it('returns property names set at construction', function() { var o = new ol.Object({ prop1: 'val1', prop2: 'val2', toString: 'string', get: 'foo' }); var keys = o.getKeys(); expect(keys.length).to.be(4); expect(keys.sort()).to.eql(['get', 'prop1', 'prop2', 'toString']); }); }); describe('setValues', function() { it('sets multiple values at once', function() { o.setValues({ k1: 1, k2: 2 }); expect(o.get('k1')).to.eql(1); expect(o.get('k2')).to.eql(2); var keys = o.getKeys().sort(); expect(keys).to.eql(['k1', 'k2']); }); }); describe('notify', function() { var listener1, listener2, listener3; beforeEach(function() { listener1 = sinon.spy(); goog.events.listen(o, 'change:k', listener1); listener2 = sinon.spy(); goog.events.listen(o, 'change', listener2); var o2 = new ol.Object(); o2.bindTo('k', o); listener3 = sinon.spy(); goog.events.listen(o2, 'change:k', listener3); }); it('dispatches events', function() { o.notify('k'); expect(listener1).to.be.called(); }); it('dispatches generic change events to bound objects', function() { o.notify('k'); expect(listener2.calledOnce).to.be(true); var args = listener2.firstCall.args; expect(args).to.have.length(1); var event = args[0]; expect(event.key).to.be('k'); }); it('dispatches events to bound objects', function() { o.notify('k'); expect(listener3).to.be.called(); }); }); describe('set', function() { var listener1, o2, listener2, listener3; beforeEach(function() { listener1 = sinon.spy(); goog.events.listen(o, 'change:k', listener1); listener2 = sinon.spy(); goog.events.listen(o, 'change', listener2); o2 = new ol.Object(); o2.bindTo('k', o); listener3 = sinon.spy(); goog.events.listen(o2, 'change:k', listener3); }); it('dispatches events to object', function() { o.set('k', 1); expect(listener1).to.be.called(); expect(o.getKeys()).to.eql(['k']); expect(o2.getKeys()).to.eql(['k']); }); it('dispatches generic change events to object', function() { o.set('k', 1); expect(listener2.calledOnce).to.be(true); var args = listener2.firstCall.args; expect(args).to.have.length(1); var event = args[0]; expect(event.key).to.be('k'); }); it('dispatches beforechange events to object', function() { o.set('k', 1); var oldValue; var beforeListener = sinon.spy(function(event) { oldValue = o2.get(event.key); }); o.on('beforechange', beforeListener); o.set('k', 2); expect(beforeListener.calledOnce).to.be(true); expect(oldValue).to.be(1); }); it('dispatches events to bound object', function() { o.set('k', 1); expect(listener3).to.be.called(); }); it('dispatches events to object bound to', function() { o2.set('k', 2); expect(listener1).to.be.called(); expect(o.getKeys()).to.eql(['k']); expect(o2.getKeys()).to.eql(['k']); }); it('dispatches generic change events to object bound to', function() { o2.set('k', 2); expect(listener2.calledOnce).to.be(true); var args = listener2.firstCall.args; expect(args).to.have.length(1); var event = args[0]; expect(event.key).to.be('k'); }); it('dispatches beforechange before changing bound objects', function() { o2.set('k', 1); var oldValue; var beforeListener = sinon.spy(function(event) { oldValue = o2.get(event.key); }); o.on('beforechange', beforeListener); o2.set('k', 2); expect(beforeListener.calledOnce).to.be(true); var args = listener2.firstCall.args; expect(args).to.have.length(1); var event = args[0]; expect(event.key).to.be('k'); expect(oldValue).to.be(1); }); }); describe('bind', function() { var o2; beforeEach(function() { o2 = new ol.Object(); }); describe('bindTo after set', function() { it('gets expected value', function() { o.set('k', 1); o2.bindTo('k', o); expect(o.get('k')).to.eql(1); expect(o2.get('k')).to.eql(1); expect(o.getKeys()).to.eql(['k']); expect(o2.getKeys()).to.eql(['k']); }); }); describe('bindTo before set', function() { it('gets expected value', function() { o2.bindTo('k', o); o.set('k', 1); expect(o.get('k')).to.eql(1); expect(o2.get('k')).to.eql(1); expect(o.getKeys()).to.eql(['k']); expect(o2.getKeys()).to.eql(['k']); }); }); describe('backwards', function() { describe('bindTo after set', function() { it('gets expected value', function() { o2.set('k', 1); o2.bindTo('k', o); expect(o.get('k')).to.be(undefined); expect(o2.get('k')).to.be(undefined); }); }); describe('bindTo before set', function() { it('gets expected value', function() { o2.bindTo('k', o); o2.set('k', 1); expect(o.get('k')).to.eql(1); expect(o2.get('k')).to.eql(1); }); }); }); }); describe('unbind', function() { var o2; beforeEach(function() { o2 = new ol.Object(); o2.bindTo('k', o); o2.set('k', 1); }); it('makes changes to unbound object invisible to other object', function() { // initial state expect(o.get('k')).to.eql(1); expect(o2.get('k')).to.eql(1); o2.unbind('k'); expect(o.get('k')).to.eql(1); expect(o2.get('k')).to.eql(1); o2.set('k', 2); expect(o.get('k')).to.eql(1); expect(o2.get('k')).to.eql(2); }); }); describe('unbindAll', function() { var o2; beforeEach(function() { o2 = new ol.Object(); o2.bindTo('k', o); o2.set('k', 1); }); it('makes changes to unbound object invisible to other object', function() { // initial state expect(o.get('k')).to.eql(1); expect(o2.get('k')).to.eql(1); o2.unbindAll(); expect(o.get('k')).to.eql(1); expect(o2.get('k')).to.eql(1); o2.set('k', 2); expect(o.get('k')).to.eql(1); expect(o2.get('k')).to.eql(2); }); }); describe('bind rename', function() { var listener1, o2, listener2; beforeEach(function() { o2 = new ol.Object(); o2.bindTo('k2', o, 'k1'); listener1 = sinon.spy(); goog.events.listen(o, 'change:k1', listener1); listener2 = sinon.spy(); goog.events.listen(o2, 'change:k2', listener2); }); it('sets the expected properties', function() { o.set('k1', 1); expect(o.get('k1')).to.eql(1); expect(o.get('k2')).to.be(undefined); expect(o2.get('k2')).to.eql(1); expect(o2.get('k1')).to.be(undefined); expect(listener1).to.be.called(); expect(listener2).to.be.called(); expect(o.getKeys()).to.eql(['k1']); expect(o2.getKeys()).to.eql(['k2']); }); }); describe('transitive bind', function() { var o2, o3; beforeEach(function() { o2 = new ol.Object(); o3 = new ol.Object(); o2.bindTo('k2', o, 'k1'); o3.bindTo('k3', o2, 'k2'); }); it('sets the expected properties', function() { o.set('k1', 1); expect(o.get('k1')).to.eql(1); expect(o2.get('k2')).to.eql(1); expect(o3.get('k3')).to.eql(1); expect(o.getKeys()).to.eql(['k1']); expect(o2.getKeys()).to.eql(['k2']); expect(o3.getKeys()).to.eql(['k3']); }); describe('backward', function() { it('sets the expected properties', function() { o3.set('k3', 1); expect(o.get('k1')).to.eql(1); expect(o2.get('k2')).to.eql(1); expect(o3.get('k3')).to.eql(1); expect(o.getKeys()).to.eql(['k1']); expect(o2.getKeys()).to.eql(['k2']); expect(o3.getKeys()).to.eql(['k3']); }); }); }); describe('circular bind', function() { var o2; beforeEach(function() { o2 = new ol.Object(); o.bindTo('k', o2); }); it('throws an error', function() { expect(function() { o2.bindTo('k', o); }).to.throwException(); }); }); describe('priority', function() { var o2; beforeEach(function() { o2 = new ol.Object(); }); it('respects set order', function() { o.set('k', 1); o2.set('k', 2); o.bindTo('k', o2); expect(o.get('k')).to.eql(2); expect(o2.get('k')).to.eql(2); }); it('respects set order (undefined)', function() { o.set('k', 1); o.bindTo('k', o2); expect(o.get('k')).to.be(undefined); expect(o2.get('k')).to.be(undefined); }); }); describe('setter', function() { beforeEach(function() { o.setX = function(x) { this.set('x', x); }; sinon.spy(o, 'setX'); }); describe('without bind', function() { it('does not call the setter', function() { o.set('x', 1); expect(o.get('x')).to.eql(1); expect(o.setX).to.not.be.called(); expect(o.getKeys()).to.eql(['x']); }); }); describe('with bind', function() { it('does call the setter', function() { var o2 = new ol.Object(); o2.bindTo('x', o); o2.set('x', 1); expect(o.setX).to.be.called(); expect(o.get('x')).to.eql(1); expect(o.getKeys()).to.eql(['x']); expect(o2.getKeys()).to.eql(['x']); }); }); }); describe('getter', function() { beforeEach(function() { o.getX = function() { return 1; }; sinon.spy(o, 'getX'); }); describe('without bind', function() { it('does not call the getter', function() { expect(o.get('x')).to.be(undefined); expect(o.getX).to.not.be.called(); }); }); describe('with bind', function() { it('does call the getter', function() { var o2 = new ol.Object(); o2.bindTo('x', o); expect(o2.get('x')).to.eql(1); expect(o.getX).to.be.called(); expect(o.getKeys()).to.eql([]); expect(o2.getKeys()).to.eql(['x']); }); }); }); describe('bind self', function() { it('throws an error', function() { expect(function() { o.bindTo('k', o); }).to.throwException(); }); }); describe('create with options', function() { it('sets the property', function() { var o = new ol.Object({k: 1}); expect(o.get('k')).to.eql(1); expect(o.getKeys()).to.eql(['k']); }); }); describe('case sensitivity', function() { var listener1, listener2; beforeEach(function() { listener1 = sinon.spy(); goog.events.listen(o, 'change:k', listener1); listener2 = sinon.spy(); goog.events.listen(o, 'change:K', listener2); }); it('dispatches the expected event', function() { o.set('K', 1); expect(listener1).to.be.called(); expect(listener2).to.not.be.called(); expect(o.getKeys()).to.eql(['K']); }); }); describe('transforms', function() { describe('with multiple binds to a single property', function() { var original, plusOne, asString; beforeEach(function() { original = new ol.Object(); original.set('x', 1); plusOne = new ol.Object(); plusOne.bindTo('x', original).transform( function(x) { return x - 1; }, function(x) { return x + 1; } ); asString = new ol.Object(); asString.bindTo('x', original).transform( function(x) { return +x; }, function(x) { return x + ''; } ); }); it('returns the expected value', function() { expect(original.get('x')).to.be(1); expect(plusOne.get('x')).to.be(2); expect(asString.get('x')).to.be('1'); }); it('allows the original value to be set correctly', function() { original.set('x', 2); expect(plusOne.get('x')).to.be(3); expect(asString.get('x')).to.be('2'); }); it('allows the transformed values to be set correctly', function() { plusOne.set('x', 3); expect(original.get('x')).to.be(2); expect(asString.get('x')).to.be('2'); asString.set('x', '3'); expect(original.get('x')).to.be(3); expect(plusOne.get('x')).to.be(4); }); }); describe('with transitive binds', function() { var original, plusOne, plusOneAsString; beforeEach(function() { original = new ol.Object(); original.set('x', 1); plusOne = new ol.Object(); plusOne.bindTo('x', original).transform( function(x) { return x - 1; }, function(x) { return x + 1; } ); plusOneAsString = new ol.Object(); plusOneAsString.bindTo('x', plusOne).transform( parseFloat, function(x) { return x + ''; } ); }); it('returns the expected value', function() { expect(original.get('x')).to.be(1); expect(plusOne.get('x')).to.be(2); expect(plusOneAsString.get('x')).to.be('2'); }); it('allows the original value to be set correctly', function() { original.set('x', 2); expect(plusOne.get('x')).to.be(3); expect(plusOneAsString.get('x')).to.be('3'); }); it('allows the transformed values to be set correctly', function() { plusOne.set('x', 3); expect(original.get('x')).to.be(2); expect(plusOneAsString.get('x')).to.be('3'); plusOneAsString.set('x', '4'); expect(original.get('x')).to.be(3); expect(plusOne.get('x')).to.be(4); }); }); }); }); goog.require('goog.events'); goog.require('ol.Object');