2014-03-11 06:26:19 +08:00
|
|
|
"use strict";
|
|
|
|
|
|
|
|
var utils = source("utils");
|
2014-02-28 06:52:25 +08:00
|
|
|
|
|
|
|
describe("Utils", function() {
|
2014-03-11 06:26:19 +08:00
|
|
|
describe("Monkey-patches", function() {
|
|
|
|
describe("Number", function() {
|
|
|
|
describe("#seconds", function() {
|
|
|
|
it("allows for expressing time in seconds", function() {
|
|
|
|
expect((5).seconds()).to.be.eql(5000);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe("#second", function() {
|
|
|
|
it("allows for expressing time in seconds", function() {
|
|
|
|
expect((1).second()).to.be.eql(1000);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe("#fromScale", function() {
|
|
|
|
it("converts a value from one scale to 0-1 scale", function() {
|
|
|
|
expect((5).fromScale(0, 10)).to.be.eql(0.5);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("converts floats", function() {
|
|
|
|
expect(2.5.fromScale(0, 10)).to.be.eql(0.25);
|
|
|
|
});
|
2014-06-12 05:32:40 +08:00
|
|
|
|
|
|
|
it("should return 1 if the number goes above the top of the scale", function() {
|
|
|
|
expect((15).fromScale(0, 10)).to.be.eql(1);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("should return 0 if the number goes below the bottom of the scale", function() {
|
|
|
|
expect((5).fromScale(10, 20)).to.be.eql(0);
|
|
|
|
});
|
2014-03-11 06:26:19 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
describe("#toScale", function() {
|
|
|
|
it("converts a value from 0-1 scale to another", function() {
|
|
|
|
expect((0.5).toScale(0, 10)).to.be.eql(5);
|
|
|
|
});
|
|
|
|
|
2014-06-12 05:32:40 +08:00
|
|
|
it("bottom of scale should be returned when value goes below it", function() {
|
|
|
|
expect((-5).toScale(0, 10)).to.be.eql(0);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("top of scale should be returned when value goes above it", function() {
|
|
|
|
expect((15).toScale(0, 10)).to.be.eql(10);
|
|
|
|
});
|
|
|
|
|
2014-03-11 06:26:19 +08:00
|
|
|
it("converts to floats", function() {
|
|
|
|
expect(0.25.toScale(0, 10)).to.be.eql(2.5);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("can be chained with #fromScale", function() {
|
|
|
|
var num = (5).fromScale(0, 20).toScale(0, 10);
|
|
|
|
expect(num).to.be.eql(2.5);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2014-09-05 05:51:44 +08:00
|
|
|
describe("#makeUnique", function() {
|
|
|
|
it("returns the original name if it's not a conflict", function() {
|
|
|
|
var res = utils.makeUnique("hello", ["world"]);
|
|
|
|
expect(res).to.be.eql("hello");
|
|
|
|
});
|
|
|
|
|
|
|
|
it("generates a unique name if it does collide", function() {
|
|
|
|
var res = utils.makeUnique("hello", ["hello"]);
|
|
|
|
expect(res).to.be.eql("hello-1");
|
|
|
|
});
|
|
|
|
|
|
|
|
it("will ignore existing duplicates", function() {
|
|
|
|
var res = utils.makeUnique("hello", ["hello", "hello-1", "hello-2"]);
|
|
|
|
expect(res).to.be.eql("hello-3");
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2014-03-11 06:26:19 +08:00
|
|
|
describe("#every", function() {
|
2014-07-05 00:49:29 +08:00
|
|
|
beforeEach(function() {
|
2014-03-11 06:26:19 +08:00
|
|
|
this.clock = sinon.useFakeTimers();
|
|
|
|
});
|
|
|
|
|
2014-07-05 00:49:29 +08:00
|
|
|
afterEach(function() {
|
2014-03-11 06:26:19 +08:00
|
|
|
this.clock.restore();
|
2014-02-28 06:52:25 +08:00
|
|
|
});
|
|
|
|
|
2014-03-11 06:26:19 +08:00
|
|
|
it("sets a function to be called every time an interval passes", function() {
|
|
|
|
var func = spy();
|
|
|
|
utils.every(10, func);
|
|
|
|
this.clock.tick(25);
|
|
|
|
expect(func).to.be.calledTwice;
|
2014-02-28 06:52:25 +08:00
|
|
|
});
|
2014-03-11 06:26:19 +08:00
|
|
|
});
|
2014-02-28 06:52:25 +08:00
|
|
|
|
2014-03-11 06:26:19 +08:00
|
|
|
describe("#after", function() {
|
2014-07-05 00:49:29 +08:00
|
|
|
beforeEach(function() {
|
2014-03-11 06:26:19 +08:00
|
|
|
this.clock = sinon.useFakeTimers();
|
2014-02-28 06:52:25 +08:00
|
|
|
});
|
|
|
|
|
2014-07-05 00:49:29 +08:00
|
|
|
afterEach(function() {
|
2014-03-11 06:26:19 +08:00
|
|
|
this.clock.restore();
|
2013-10-25 05:25:42 +08:00
|
|
|
});
|
2014-02-28 06:52:25 +08:00
|
|
|
|
2014-03-11 06:26:19 +08:00
|
|
|
it("sets a function to be called after time an interval passes", function() {
|
|
|
|
var func = spy();
|
|
|
|
utils.after(10, func);
|
|
|
|
this.clock.tick(15);
|
|
|
|
expect(func).to.be.called;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe("constantly", function() {
|
2014-07-05 00:49:29 +08:00
|
|
|
beforeEach(function() {
|
2014-03-11 06:26:19 +08:00
|
|
|
stub(global, 'every').returns(0);
|
2013-10-29 03:07:56 +08:00
|
|
|
});
|
2014-02-28 06:52:25 +08:00
|
|
|
|
2014-07-05 00:49:29 +08:00
|
|
|
afterEach(function() {
|
2014-03-11 06:26:19 +08:00
|
|
|
global.every.restore();
|
|
|
|
});
|
|
|
|
|
|
|
|
it("schedules a task to run continuously with #every", function() {
|
|
|
|
var func = function() {};
|
|
|
|
utils.constantly(func);
|
|
|
|
|
|
|
|
expect(global.every).to.be.calledWith(0, func);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe("#subclass", function() {
|
|
|
|
var BaseClass = (function() {
|
|
|
|
function BaseClass(opts) {
|
|
|
|
this.greeting = opts.greeting;
|
|
|
|
};
|
|
|
|
|
|
|
|
BaseClass.prototype.sayHi = function() {
|
|
|
|
return "Hi!";
|
|
|
|
};
|
|
|
|
|
|
|
|
return BaseClass
|
|
|
|
})();
|
|
|
|
|
|
|
|
var SubClass = (function(klass) {
|
2014-06-06 03:11:37 +08:00
|
|
|
utils.subclass(SubClass, klass);
|
2014-03-11 06:26:19 +08:00
|
|
|
|
|
|
|
function SubClass(opts) {
|
|
|
|
SubClass.__super__.constructor.apply(this, arguments);
|
|
|
|
};
|
|
|
|
|
|
|
|
return SubClass;
|
|
|
|
})(BaseClass);
|
|
|
|
|
|
|
|
it("adds inheritance to Javascript classes", function() {
|
|
|
|
var sub = new SubClass({greeting: "Hello World"});
|
|
|
|
expect(sub.greeting).to.be.eql("Hello World");
|
|
|
|
expect(sub.sayHi()).to.be.eql("Hi!");
|
2014-02-20 07:52:47 +08:00
|
|
|
});
|
2013-10-25 05:25:42 +08:00
|
|
|
});
|
|
|
|
|
2014-02-28 06:52:25 +08:00
|
|
|
describe("#proxyFunctionsToObject", function() {
|
2014-03-11 06:26:19 +08:00
|
|
|
var methods = ['asString', 'toString', 'returnString'];
|
2014-02-28 09:39:02 +08:00
|
|
|
|
2014-03-11 06:26:19 +08:00
|
|
|
var ProxyClass = (function() {
|
2014-02-28 06:52:25 +08:00
|
|
|
function ProxyClass() {}
|
|
|
|
|
|
|
|
ProxyClass.prototype.asString = function() {
|
|
|
|
return "[object ProxyClass]";
|
|
|
|
};
|
|
|
|
|
|
|
|
ProxyClass.prototype.toString = function() {
|
|
|
|
return "[object ProxyClass]";
|
|
|
|
};
|
|
|
|
|
|
|
|
ProxyClass.prototype.returnString = function(string) {
|
|
|
|
return string;
|
|
|
|
};
|
|
|
|
|
|
|
|
return ProxyClass;
|
|
|
|
})();
|
|
|
|
|
2014-03-11 06:26:19 +08:00
|
|
|
var TestClass = (function() {
|
2014-02-28 06:52:25 +08:00
|
|
|
function TestClass() {
|
|
|
|
this.testInstance = new ProxyClass;
|
2014-07-04 00:35:24 +08:00
|
|
|
utils.proxyFunctionsToObject(methods, this.testInstance, this, true);
|
2014-02-28 06:52:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return TestClass;
|
|
|
|
})();
|
|
|
|
|
2014-03-11 06:26:19 +08:00
|
|
|
var testclass = new TestClass();
|
|
|
|
|
2014-02-28 06:52:25 +08:00
|
|
|
it('can alias methods', function() {
|
2014-03-11 06:26:19 +08:00
|
|
|
expect(testclass.asString()).to.be.eql("[object ProxyClass]");
|
2014-02-28 06:52:25 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
it('can alias existing methods if forced to', function() {
|
2014-03-11 06:26:19 +08:00
|
|
|
expect(testclass.toString()).to.be.eql("[object ProxyClass]");
|
2014-02-28 06:52:25 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
it('can alias methods with arguments', function() {
|
2014-03-11 06:26:19 +08:00
|
|
|
expect(testclass.returnString).to.be.a('function');
|
2014-02-28 06:52:25 +08:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2014-06-18 07:00:36 +08:00
|
|
|
describe("#fetch", function() {
|
|
|
|
var fetch = utils.fetch,
|
|
|
|
obj = { property: 'hello world', 'false': false, 'null': null };
|
|
|
|
|
|
|
|
context("if the property exists on the object", function() {
|
|
|
|
it("returns the value", function() {
|
|
|
|
expect(fetch(obj, 'property')).to.be.eql('hello world');
|
|
|
|
expect(fetch(obj, 'false')).to.be.eql(false);
|
|
|
|
expect(fetch(obj, 'null')).to.be.eql(null);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
context("if the property doesn't exist on the object", function() {
|
|
|
|
context("and no fallback value has been provided", function() {
|
|
|
|
it("throws an Error", function() {
|
|
|
|
var fn = function() { return fetch(obj, "notaproperty"); };
|
|
|
|
expect(fn).to.throw(Error, 'key not found: "notaproperty"');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
context("and a fallback value has been provided", function() {
|
|
|
|
it('returns the fallback value', function() {
|
|
|
|
expect(fetch(obj, 'notakey', 'fallback')).to.be.eql('fallback');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
context("and a fallback function has been provided", function() {
|
|
|
|
context("if the function has no return value", function() {
|
|
|
|
it("throws an Error", function() {
|
|
|
|
var fn = function() { fetch(obj, 'notakey', function() {}); },
|
|
|
|
str = 'no return value from provided fallback function';
|
|
|
|
|
|
|
|
expect(fn).to.throw(Error, str);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
context("if the function returns a value", function() {
|
|
|
|
it("returns the value returned by the fallback function", function() {
|
|
|
|
var fn = function(key) { return "Couldn't find " + key },
|
|
|
|
value = "Couldn't find notakey";
|
|
|
|
|
|
|
|
expect(fetch(obj, 'notakey', fn)).to.be.eql(value);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2014-02-28 06:52:25 +08:00
|
|
|
});
|