michael@0: "use strict"; michael@0: michael@0: var Method = require("../core") michael@0: michael@0: function type(value) { michael@0: return Object.prototype.toString.call(value). michael@0: split(" "). michael@0: pop(). michael@0: split("]"). michael@0: shift(). michael@0: toLowerCase() michael@0: } michael@0: michael@0: var values = [ michael@0: null, // 0 michael@0: undefined, // 1 michael@0: Infinity, // 2 michael@0: NaN, // 3 michael@0: 5, // 4 michael@0: {}, // 5 michael@0: Object.create({}), // 6 michael@0: Object.create(null), // 7 michael@0: [], // 8 michael@0: /foo/, // 9 michael@0: new Date(), // 10 michael@0: Function, // 11 michael@0: function() {}, // 12 michael@0: true, // 13 michael@0: false, // 14 michael@0: "string" // 15 michael@0: ] michael@0: michael@0: function True() { return true } michael@0: function False() { return false } michael@0: michael@0: var trues = values.map(True) michael@0: var falses = values.map(False) michael@0: michael@0: exports["test throws if not implemented"] = function(assert) { michael@0: var method = Method("nope") michael@0: michael@0: assert.throws(function() { michael@0: method({}) michael@0: }, /not implement/i, "method throws if not implemented") michael@0: michael@0: assert.throws(function() { michael@0: method(null) michael@0: }, /not implement/i, "method throws on null") michael@0: } michael@0: michael@0: exports["test all types inherit from default"] = function(assert) { michael@0: var isImplemented = Method("isImplemented") michael@0: isImplemented.define(function() { return true }) michael@0: michael@0: values.forEach(function(value) { michael@0: assert.ok(isImplemented(value), michael@0: type(value) + " inherits deafult implementation") michael@0: }) michael@0: } michael@0: michael@0: exports["test default can be implemented later"] = function(assert) { michael@0: var isImplemented = Method("isImplemented") michael@0: isImplemented.define(function() { michael@0: return true michael@0: }) michael@0: michael@0: values.forEach(function(value) { michael@0: assert.ok(isImplemented(value), michael@0: type(value) + " inherits deafult implementation") michael@0: }) michael@0: } michael@0: michael@0: exports["test dispatch not-implemented"] = function(assert) { michael@0: var isDefault = Method("isDefault") michael@0: values.forEach(function(value) { michael@0: assert.throws(function() { michael@0: isDefault(value) michael@0: }, /not implement/, type(value) + " throws if not implemented") michael@0: }) michael@0: } michael@0: michael@0: exports["test dispatch default"] = function(assert) { michael@0: var isDefault = Method("isDefault") michael@0: michael@0: // Implement default michael@0: isDefault.define(True) michael@0: assert.deepEqual(values.map(isDefault), trues, michael@0: "all implementation inherit from default") michael@0: michael@0: } michael@0: michael@0: exports["test dispatch null"] = function(assert) { michael@0: var isNull = Method("isNull") michael@0: michael@0: // Implement default michael@0: isNull.define(False) michael@0: isNull.define(null, True) michael@0: assert.deepEqual(values.map(isNull), michael@0: [ true ]. michael@0: concat(falses.slice(1)), michael@0: "only null gets methods defined for null") michael@0: } michael@0: michael@0: exports["test dispatch undefined"] = function(assert) { michael@0: var isUndefined = Method("isUndefined") michael@0: michael@0: // Implement default michael@0: isUndefined.define(False) michael@0: isUndefined.define(undefined, True) michael@0: assert.deepEqual(values.map(isUndefined), michael@0: [ false, true ]. michael@0: concat(falses.slice(2)), michael@0: "only undefined gets methods defined for undefined") michael@0: } michael@0: michael@0: exports["test dispatch object"] = function(assert) { michael@0: var isObject = Method("isObject") michael@0: michael@0: // Implement default michael@0: isObject.define(False) michael@0: isObject.define(Object, True) michael@0: assert.deepEqual(values.map(isObject), michael@0: [ false, false, false, false, false ]. michael@0: concat(trues.slice(5, 13)). michael@0: concat([false, false, false]), michael@0: "all values except primitives inherit Object methods") michael@0: michael@0: } michael@0: michael@0: exports["test dispatch number"] = function(assert) { michael@0: var isNumber = Method("isNumber") michael@0: isNumber.define(False) michael@0: isNumber.define(Number, True) michael@0: michael@0: assert.deepEqual(values.map(isNumber), michael@0: falses.slice(0, 2). michael@0: concat(true, true, true). michael@0: concat(falses.slice(5)), michael@0: "all numbers inherit from Number method") michael@0: } michael@0: michael@0: exports["test dispatch string"] = function(assert) { michael@0: var isString = Method("isString") michael@0: isString.define(False) michael@0: isString.define(String, True) michael@0: michael@0: assert.deepEqual(values.map(isString), michael@0: falses.slice(0, 15). michael@0: concat(true), michael@0: "all strings inherit from String method") michael@0: } michael@0: michael@0: exports["test dispatch function"] = function(assert) { michael@0: var isFunction = Method("isFunction") michael@0: isFunction.define(False) michael@0: isFunction.define(Function, True) michael@0: michael@0: assert.deepEqual(values.map(isFunction), michael@0: falses.slice(0, 11). michael@0: concat(true, true). michael@0: concat(falses.slice(13)), michael@0: "all functions inherit from Function method") michael@0: } michael@0: michael@0: exports["test dispatch date"] = function(assert) { michael@0: var isDate = Method("isDate") michael@0: isDate.define(False) michael@0: isDate.define(Date, True) michael@0: michael@0: assert.deepEqual(values.map(isDate), michael@0: falses.slice(0, 10). michael@0: concat(true). michael@0: concat(falses.slice(11)), michael@0: "all dates inherit from Date method") michael@0: } michael@0: michael@0: exports["test dispatch RegExp"] = function(assert) { michael@0: var isRegExp = Method("isRegExp") michael@0: isRegExp.define(False) michael@0: isRegExp.define(RegExp, True) michael@0: michael@0: assert.deepEqual(values.map(isRegExp), michael@0: falses.slice(0, 9). michael@0: concat(true). michael@0: concat(falses.slice(10)), michael@0: "all regexps inherit from RegExp method") michael@0: } michael@0: michael@0: exports["test redefine for descendant"] = function(assert) { michael@0: var isFoo = Method("isFoo") michael@0: var ancestor = {} michael@0: isFoo.implement(ancestor, function() { return true }) michael@0: var descendant = Object.create(ancestor) michael@0: isFoo.implement(descendant, function() { return false }) michael@0: michael@0: assert.ok(isFoo(ancestor), "defined on ancestor") michael@0: assert.ok(!isFoo(descendant), "overrided for descendant") michael@0: } michael@0: michael@0: exports["test on custom types"] = function(assert) { michael@0: function Bar() {} michael@0: var isBar = Method("isBar") michael@0: michael@0: isBar.define(function() { return false }) michael@0: isBar.define(Bar, function() { return true }) michael@0: michael@0: assert.ok(!isBar({}), "object is get's default implementation") michael@0: assert.ok(isBar(new Bar()), "Foo type objects get own implementation") michael@0: michael@0: var isObject = Method("isObject") michael@0: isObject.define(function() { return false }) michael@0: isObject.define(Object, function() { return true }) michael@0: michael@0: assert.ok(isObject(new Bar()), "foo inherits implementation from object") michael@0: michael@0: michael@0: isObject.define(Bar, function() { return false }) michael@0: michael@0: assert.ok(!isObject(new Bar()), michael@0: "implementation inherited form object can be overrided") michael@0: } michael@0: michael@0: michael@0: exports["test error types"] = function(assert) { michael@0: var isError = Method("isError") michael@0: isError.define(function() { return false }) michael@0: isError.define(Error, function() { return true }) michael@0: michael@0: assert.ok(isError(Error("boom")), "error is error") michael@0: assert.ok(isError(TypeError("boom")), "type error is an error") michael@0: assert.ok(isError(EvalError("boom")), "eval error is an error") michael@0: assert.ok(isError(RangeError("boom")), "range error is an error") michael@0: assert.ok(isError(ReferenceError("boom")), "reference error is an error") michael@0: assert.ok(isError(SyntaxError("boom")), "syntax error is an error") michael@0: assert.ok(isError(URIError("boom")), "URI error is an error") michael@0: } michael@0: michael@0: exports["test override define polymorphic method"] = function(assert) { michael@0: var define = Method.define michael@0: var implement = Method.implement michael@0: michael@0: var fn = Method("fn") michael@0: var methods = {} michael@0: implement(define, fn, function(method, label, implementation) { michael@0: methods[label] = implementation michael@0: }) michael@0: michael@0: function foo() {} michael@0: michael@0: define(fn, "foo-case", foo) michael@0: michael@0: assert.equal(methods["foo-case"], foo, "define set property") michael@0: } michael@0: michael@0: exports["test override define via method API"] = function(assert) { michael@0: var define = Method.define michael@0: var implement = Method.implement michael@0: michael@0: var fn = Method("fn") michael@0: var methods = {} michael@0: define.implement(fn, function(method, label, implementation) { michael@0: methods[label] = implementation michael@0: }) michael@0: michael@0: function foo() {} michael@0: michael@0: define(fn, "foo-case", foo) michael@0: michael@0: assert.equal(methods["foo-case"], foo, "define set property") michael@0: } michael@0: michael@0: require("test").run(exports)