diff options
Diffstat (limited to 'tools/addon-sdk-1.3/packages/api-utils/tests/traits')
5 files changed, 894 insertions, 0 deletions
diff --git a/tools/addon-sdk-1.3/packages/api-utils/tests/traits/assert.js b/tools/addon-sdk-1.3/packages/api-utils/tests/traits/assert.js new file mode 100644 index 0000000..dd662a4 --- /dev/null +++ b/tools/addon-sdk-1.3/packages/api-utils/tests/traits/assert.js @@ -0,0 +1,94 @@ +"use strict"; + +var BaseAssert = require("test/assert").Assert; + +/** + * Whether or not given property descriptors are equivalent. They are + * equivalent either if both are marked as "conflict" or "required" property + * or if all the properties of descriptors are equal. + * @param {Object} actual + * @param {Object} expected + */ +function equivalentDescriptors(actual, expected) { + return (actual.conflict && expected.conflict) || + (actual.required && expected.required) || + equalDescriptors(actual, expected); +} + +function equalDescriptors(actual, expected) { + return actual.get === expected.get && + actual.set === expected.set && + actual.value === expected.value && + !!actual.enumerable === !!expected.enumerable && + !!actual.configurable === !!expected.configurable && + !!actual.writable === !!expected.writable; +} + +/** + * Whether or not given `target` array contains all the element + * from a given `source` array. + */ +function containsSet(source, target) { + return source.some(function(element) { + return 0 > target.indexOf(element); + }); +} + +/** + * Whether or not given two arrays contain all elements from another. + */ +function equivalentSets(source, target) { + return containsSet(source, target) && containsSet(target, source); +} + +/** + * Finds name of the property from `source` property descriptor map, that + * is not equivalent of the name named property in the `target` property + * descriptor map. If not found `null` is returned instead. + */ +function findNonEquivalentPropertyName(source, target) { + var value = null; + Object.getOwnPropertyNames(source).some(function(key) { + var areEquivalent = false; + if (!equivalentDescriptors(source[key], target[key])) { + value = key; + areEquivalent = true; + } + return areEquivalent; + }); + return value; +} + +var AssertDescriptor = { + equalTraits: { + value: function equivalentTraits(actual, expected, message) { + var difference; + var actualKeys = Object.getOwnPropertyNames(actual); + var expectedKeys = Object.getOwnPropertyNames(expected); + + if (equivalentSets(actualKeys, expectedKeys)) { + this.fail({ + operator: "equalTraits", + message: "Traits define different properties", + actual: actualKeys.sort().join(","), + expected: expectedKeys.sort().join(","), + }); + } + else if ((difference = findNonEquivalentPropertyName(actual, expected))) { + this.fail({ + operator: "equalTraits", + message: "Traits define non-equivalent property `" + difference + "`", + actual: actual[difference], + expected: expected[difference] + }); + } + else { + this.pass(message || "Traits are equivalent."); + } + } + } +}; + +exports.Assert = function Assert() { + return Object.create(BaseAssert.apply(null, arguments), AssertDescriptor); +}; diff --git a/tools/addon-sdk-1.3/packages/api-utils/tests/traits/descriptor-tests.js b/tools/addon-sdk-1.3/packages/api-utils/tests/traits/descriptor-tests.js new file mode 100644 index 0000000..7c27ac4 --- /dev/null +++ b/tools/addon-sdk-1.3/packages/api-utils/tests/traits/descriptor-tests.js @@ -0,0 +1,331 @@ +"use strict"; + +var Trait = require("light-traits").Trait; +var utils = require("./utils"); +var Data = utils.Data; +var Method = utils.Method; +var Accessor = utils.Accessor; +var Required = utils.Required; +var Conflict = utils.Conflict; + +function method() {} + +exports.Assert = require("./assert").Assert +exports["test simple composition"] = function(assert) { + var actual = Trait.compose( + Trait({ a: 0, b: 1 }), + { c: { value: 2 }, d: { value: method, enumerable: true } } + ); + + var expected = { + a: Data(0), + b: Data(1), + c: Data(2, false, false, false), + d: Method(method, true, false, false) + }; + + assert.equalTraits(actual, expected); +}; + +exports["test composition with conflict"] = function(assert) { + var actual = Trait.compose( + Trait({ a: 0, b: 1 }), + { + a: { + value: 2, + writable: true, + configurable: true, + enumerable: true + }, + c: { + value: method, + configurable: true + } + } + ); + + var expected = { + a: Conflict("a"), + b: Data(1), + c: Method(method, false, true, false) + }; + + assert.equalTraits(actual, expected); +}; + +exports["test identical props does not cause conflict"] = function(assert) { + var actual = Trait.compose( + { + a: { + value: 0, + writable: true, + configurable: true, + enumerable: true + }, + b: { + value: 1 + } + }, + Trait({ + a: 0, + c: method + }) + ); + + var expected = { + a: Data(0), + b: Data(1, false, false, false), + c: Method(method) + } + + assert.equalTraits(actual, expected); +}; + +exports["test composition with identical required props"] = function(assert) { + var actual = Trait.compose( + Trait({ a: Trait.required, b: 1 }), + { a: { required: true }, c: { value: method } } + ); + + var expected = { + a: Required(), + b: Data(1), + c: Method(method, false, false, false) + }; + + assert.equalTraits(actual, expected); +}; + +exports["test composition satisfying a required prop"] = function(assert) { + var actual = Trait.compose( + Trait({ a: Trait.required, b: 1 }), + { a: { value: method, enumerable: true } } + ); + + var expected = { + a: Method(method, true, false, false), + b: Data(1) + }; + + assert.equalTraits(actual, expected); +}; + +exports["test compose is neutral wrt conflicts"] = function(assert) { + var actual = Trait.compose( + Trait({ a: { value: 1 } }, Trait({ a: 2 })), + { b: { value: 0, writable: true, configurable: true, enumerable: false } } + ); + + var expected = { a: Conflict("a"), b: Data(0, false) }; + + assert.equalTraits(actual, expected); +}; + +exports["test conflicting prop overrides Trait.required"] = function(assert) { + var actual = Trait.compose( + Trait.compose( + Trait({ a: 1 }), + { a: { value: 2 } } + ), + { a: { value: Trait.required } } + ); + + var expected = { a: Conflict("a") }; + + assert.equalTraits(actual, expected); +}; + +exports["test compose is commutative"] = function(assert) { + var actual = Trait.compose( + Trait({ a: 0, b: 1 }), + { c: { value: 2 }, d: { value: method } } + ); + + var expected = Trait.compose( + { c: { value: 2 }, d: { value: method } }, + Trait({ a: 0, b: 1 }) + ); + + assert.equalTraits(actual, expected); +} + +exports["test compose is commutative, also for required/conflicting props"] = function(assert) { + var actual = Trait.compose( + { + a: { value: 0 }, + b: { value: 1 }, + c: { value: 3 }, + e: { value: Trait.required } + }, + { + c: { value: 2 }, + d: { get: method } + } + ); + + var expected = Trait.compose( + Trait({ c: 3 }), + { + c: { value: 2 }, + d: { get: method }, + a: { value: 0 }, + b: { value: 1 }, + e: { value: Trait.required }, + } + ); + + assert.equalTraits(actual, expected); +}; + +exports["test compose is associative"] = function(assert) { + var actual = Trait.compose( + { + a: { value: 0 }, + b: { value: 1 }, + c: { value: 3 }, + d: { value: Trait.required } + }, + Trait.compose( + { c: { value: 3 }, d: { value: Trait.required } }, + { c: { value: 2 }, d: { value: method }, e: { value: "foo" } } + ) + ); + + var expected = Trait.compose( + Trait.compose( + { + a: { value: 0 }, + b: { value: 1 }, + c: { value: 3 }, + d: { value: Trait.required } + }, + { + c: { value: 3 }, + d: { value: Trait.required } + } + ), + { + c: { value: 2 }, + d: { value: method }, + e: { value: "foo" } + } + ); + + assert.equalTraits(actual, expected); +}; + +exports["test diamond import of same prop do not conflict"] = function(assert) { + var actual = Trait.compose( + Trait.compose( + { b: { value: 2 } }, + { a: { value: 1, enumerable: true, configurable: true, writable: true } } + ), + Trait.compose( + { c: { value: 3 } }, + Trait({ a: 1 }) + ), + Trait({ d: 4 }) + ); + + var expected = { + a: Data(1), + b: Data(2, false, false, false), + c: Data(3, false, false, false), + d: Data(4) + }; + + assert.equalTraits(actual, expected); +}; + +exports["test create simple"] = function(assert) { + var o1 = Trait.compose( + Trait({ a: 1 }), + { + b: { + value: function() { + return this.a; + } + } + } + ).create(Object.prototype); + + assert.equal(Object.getPrototypeOf(o1), Object.prototype, "o1 prototype"); + assert.equal(1, o1.a, "o1.a"); + assert.equal(1, o1.b(), "o1.b()"); + assert.equal(Object.keys(o1).length, 1, "Object.keys(o1).length === 2"); +}; + +exports["test create with Array.prototype"] = function(assert) { + var o2 = Trait.compose({}, {}).create(Array.prototype); + assert.equal(Object.getPrototypeOf(o2), Array.prototype, "o2 prototype"); +}; + +exports["test exception for incomplete required properties"] = function(assert) { + assert.throws(function() { + Trait({ foo: Trait.required }).create(Object.prototype) + }, /Missing required property: `foo`/, "required prop error"); +} + +exports["test exception for unresolved conflicts"] = function(assert) { + assert.throws(function() { + Trait(Trait({ a: 0 }), Trait({ a: 1 })).create({}) + }, /Remaining conflicting property: `a`/, "conflicting prop error"); +} + +exports["test conflicting properties are present"] = function(assert) { + var o5 = Object.create(Object.prototype, Trait.compose( + { a: { value: 0 } }, + { a: { value: 1 } } + )); + + assert.ok("a" in o5, "conflicting property present"); + assert.throws(function() { + o5.a + }, /Remaining conflicting property: `a`/, "conflicting prop access error"); +}; + +exports["test diamond with conflicts"] = function(assert) { + function makeT1(x) { + return { + m: { + value: function() { + return x + } + } + }; + }; + + function makeT2(x) { + return Trait.compose( + Trait({ t2: "foo" }), + makeT1(x) + ); + }; + + function makeT3(x) { + return Trait.compose( + { + t3: { value: "bar" } + }, + makeT1(x) + ); + }; + + var T4 = Trait.compose(makeT2(5), makeT3(5)); + + assert.throws(function() { + T4.create(Object.prototype); + }, /Remaining conflicting property: `m`/, "diamond prop conflict"); +}; + +exports["test providing requirements through proto"] = function(assert) { + var t = Trait.compose( + {}, + { required: { required: true } } + ).create({ required: "test" }); + + assert.equal(t.required, "test", "property from proto is inherited"); +}; + +if (module == require.main) + require("test").run(exports); diff --git a/tools/addon-sdk-1.3/packages/api-utils/tests/traits/inheritance-tests.js b/tools/addon-sdk-1.3/packages/api-utils/tests/traits/inheritance-tests.js new file mode 100644 index 0000000..73a23b7 --- /dev/null +++ b/tools/addon-sdk-1.3/packages/api-utils/tests/traits/inheritance-tests.js @@ -0,0 +1,100 @@ +"use strict"; + +var Trait = require("light-traits").Trait; + +exports["test custom constructor and inherited toString"] = function(assert) { + function Type() { + return Object.create(Type.prototype); + } + Type.prototype = Trait({ + method: function method() { + return 2; + } + }).create(Object.freeze(Type.prototype)); + + var fixture = Type(); + + assert.equal(fixture.constructor, Type, "must override constructor"); + assert.equal(fixture.toString(), "[object Type]", "must inherit toString"); +}; + +exports["test custom toString and inherited constructor"] = function(assert) { + function Type() { + return Object.create(Type.prototype); + } + Type.prototype = Trait({ + toString: function toString() { + return "<toString>"; + } + }).create(); + + var fixture = Type(); + + assert.equal(fixture.constructor, Trait, "must inherit constructor Trait"); + assert.equal(fixture.toString(), "<toString>", "Must override toString"); +}; + +exports["test custom toString and constructor"] = function(assert) { + function Type() { + return TypeTrait.create(Type.prototype); + } + Object.freeze(Type.prototype); + var TypeTrait = Trait({ + toString: function toString() { + return "<toString>"; + } + }); + + var fixture = Type(); + + assert.equal(fixture.constructor, Type, "constructor is provided to create"); + assert.equal(fixture.toString(), "<toString>", "toString was overridden"); +}; + +exports["test resolve constructor"] = function (assert) { + function Type() {} + var T1 = Trait({ constructor: Type }).resolve({ constructor: '_foo' }); + var f1 = T1.create(); + + assert.equal(f1._foo, Type, "constructor was resolved"); + assert.equal(f1.constructor, Trait, "constructor of prototype is inherited"); + assert.equal(f1.toString(), "[object Trait]", "toString is inherited"); +}; + +exports["test compose read-only"] = function (assert) { + function Type() {} + Type.prototype = Trait.compose(Trait({}), { + constructor: { value: Type }, + a: { value: "b", enumerable: true } + }).resolve({ a: "b" }).create({ a: "a" }); + + var f1 = new Type(); + + assert.equal(Object.getPrototypeOf(f1), Type.prototype, "inherits correctly"); + assert.equal(f1.constructor, Type, "constructor was overridden"); + assert.equal(f1.toString(), "[object Type]", "toString was inherited"); + assert.equal(f1.a, "a", "property a was resolved"); + assert.equal(f1.b, "b", "property a was renamed to b"); + assert.ok(!Object.getOwnPropertyDescriptor(Type.prototype, "a"), + "a is not on the prototype of the instance"); + + var proto = Object.getPrototypeOf(Type.prototype); + var dc = Object.getOwnPropertyDescriptor(Type.prototype, "constructor"); + var db = Object.getOwnPropertyDescriptor(Type.prototype, "b"); + var da = Object.getOwnPropertyDescriptor(proto, "a"); + + assert.ok(!dc.writable, "constructor is not writable"); + assert.ok(!dc.enumerable, "constructor is not enumerable"); + assert.ok(dc.configurable, "constructor inherits configurability"); + + assert.ok(!db.writable, "a -> b is not writable"); + assert.ok(db.enumerable, "a -> b is enumerable"); + assert.ok(!db.configurable, "a -> b is not configurable"); + + assert.ok(da.writable, "a is writable"); + assert.ok(da.enumerable, "a is enumerable"); + assert.ok(da.configurable, "a is configurable"); +}; + +if (require.main == module) + require("test").run(exports); diff --git a/tools/addon-sdk-1.3/packages/api-utils/tests/traits/object-tests.js b/tools/addon-sdk-1.3/packages/api-utils/tests/traits/object-tests.js new file mode 100644 index 0000000..afea3ce --- /dev/null +++ b/tools/addon-sdk-1.3/packages/api-utils/tests/traits/object-tests.js @@ -0,0 +1,317 @@ +"use strict"; + +var Trait = require("light-traits").Trait; +var utils = require("./utils"); +var Data = utils.Data; +var Method = utils.Method; +var Accessor = utils.Accessor; +var Required = utils.Required; +var Conflict = utils.Conflict; + +function method() {} + +exports.Assert = require("./assert").Assert; + +exports["test empty trait"] = function (assert) { + assert.equalTraits(Trait({}), {}); +}; + +exports["test simple trait"] = function (assert) { + var expected = { + a: Data(0, true, true, true), + b: Method(method, true, true, true) + }; + + assert.equalTraits(Trait({ a: 0, b: method }), expected); +}; + +exports["test simple trait with Trait.required property"] = function (assert) { + var actual = Trait({ a: Trait.required, b: 1 }); + var expected = { a: Required("a"), b: Data(1) }; + + assert.equalTraits(actual, expected); +}; + +exports["test ordering of trait properties is irrelevant"] = function (assert) { + var actual = Trait({ a: 0, b: 1, c: Trait.required }); + var expected = Trait({ b: 1, c: Trait.required, a: 0 }); + + assert.equalTraits(actual, expected); +}; + +exports["test trait with accessor property"] = function (assert) { + var record = { get a() {}, set a(v) {} }; + var get = Object.getOwnPropertyDescriptor(record, "a").get; + var set = Object.getOwnPropertyDescriptor(record, "a").set; + + assert.equalTraits(Trait(record), { a: Accessor(get, set) }); +}; + +exports["test simple composition"] = function (assert) { + var actual = Trait.compose(Trait({ a: 0, b: 1 }), Trait({ c: 2, d: method })); + var expected = { a: Data(0), b: Data(1), c: Data(2), d: Method(method) }; + + assert.equalTraits(actual, expected); +}; + +exports["test composition with conflict"] = function (assert) { + var actual = Trait.compose(Trait({ a: 0, b: 1 }), Trait({ a: 2, c: method })); + var expected = { a: Conflict("a"), b: Data(1), c: Method(method) }; + + assert.equalTraits(actual, expected); +}; + +exports["test composition of identical props does not cause conflict"] = function (assert) { + var actual = Trait.compose(Trait({ a: 0, b: 1 }), Trait({ a: 0, c: method })); + + assert.equalTraits(actual, { a: Data(0), b: Data(1), c: Method(method) }); +}; + +exports["test composition with identical Trait.required props"] = function (assert) { + var actual = Trait.compose(Trait({ a: Trait.required, b: 1 }), + Trait({ a: Trait.required, c: method })); + + assert.equalTraits(actual, { a: Required(), b: Data(1), c: Method(method) }); +}; + +exports["test composition satisfying a Trait.required prop"] = function (assert) { + var actual = Trait.compose(Trait({ a: Trait.required, b: 1 }), + Trait({ a: method })); + + assert.equalTraits(actual, { a: Method(method), b: Data(1) }); +}; + +exports["test compose is neutral wrt conflicts"] = function (assert) { + var actual = Trait.compose(Trait.compose(Trait({ a: 1 }), Trait({ a: 2 })), + Trait({ b: 0 })); + + assert.equalTraits(actual, { a: Conflict("a"), b: Data(0) }); +}; + +exports["test conflicting prop overrides Trait.required prop"] = function (assert) { + var actual = Trait.compose(Trait.compose(Trait({ a: 1 }), + Trait({ a: 2 })), + Trait({ a: Trait.required })); + + assert.equalTraits(actual, { a: Conflict("a") }); +}; + +exports["test compose is commutative"] = function (assert) { + var actual = Trait.compose(Trait({ a: 0, b: 1 }), Trait({ c: 2, d: method })); + var expected = Trait.compose(Trait({ c: 2, d: method }), + Trait({ a: 0, b: 1 })); + + assert.equalTraits(actual, expected); +}; + +exports["test compose is commutative, also for Trait.required/conflicting props"] = function (assert) { + var actual = Trait.compose(Trait({ a: 0, b: 1, c: 3, e: Trait.required }), + Trait({ c: 2, d: method })); + + var expected = Trait.compose(Trait({ c: 2, d: method }), + Trait({ a: 0, b: 1, c: 3, e: Trait.required })); + + assert.equalTraits(actual, expected); +}; + +exports["test compose is associative"] = function (assert) { + var actual = Trait.compose(Trait({ a: 0, b: 1, c: 3, d: Trait.required }), + Trait.compose(Trait({ c: 3, d: Trait.required }), + Trait({ c: 2, d: method, + e: "foo" }))); + + var expected = Trait.compose( + Trait.compose(Trait({ a: 0, b: 1, c: 3, d: Trait.required }), + Trait({ c: 3, d: Trait.required })), + Trait({ c: 2, d: method, e: "foo" })); + + assert.equalTraits(actual, expected); +}; + +exports["test diamond import of same prop does not generate conflict"] = function (assert) { + var actual = Trait.compose(Trait.compose(Trait({ b: 2 }), Trait({ a: 1 })), + Trait.compose(Trait({ c: 3 }), Trait({ a: 1 })), + Trait({ d: 4 })); + var expected = { a: Data(1), b: Data(2), c: Data(3), d: Data(4) }; + + assert.equalTraits(actual, expected); +}; + +exports["test resolve with empty resolutions has no effect"] = function (assert) { + assert.equalTraits(Trait({ a: 1, b: Trait.required, c: method }).resolve({}), + { a: Data(1), b: Required(), c: Method(method) }); +}; + +exports["test resolve: renaming"] = function (assert) { + var actual = Trait({ a: 1, b: Trait.required, c: method }); + + assert.equalTraits(actual.resolve({ a: "A", c: "C" }), + { A: Data(1), b: Required(), C: Method(method), + a: Required(), c: Required() }); +}; + +exports["test resolve: renaming to conflicting name causes conflict, order 1"] = function (assert) { + assert.equalTraits(Trait({ a: 1, b: 2 }).resolve({ a: "b" }), + { b: Conflict("b"), a: Required() }); +}; + +exports["test resolve: renaming to conflicting name causes conflict, order 2"] = function (assert) { + assert.equalTraits(Trait({ b: 2, a: 1 }).resolve({ a: "b" }), + { b: Conflict("b"), a: Required() }); +}; + +exports["test resolve: simple exclusion"] = function (assert) { + assert.equalTraits(Trait({ a: 1, b: 2 }).resolve({ a: undefined }), + { a: Required(), b: Data(2) }); +}; + +exports["test resolve: exclusion to empty trait"] = function (assert) { + assert.equalTraits(Trait({ a: 1, b: 2 }).resolve({ a: null, b: undefined }), + { a: Required(), b: Required() }); +}; + +exports["test resolve: exclusion and renaming of disjoint props"] = function (assert) { + assert.equalTraits(Trait({ a: 1, b: 2 }).resolve({ a: undefined, b: "c" }), + { a: Required(), c: Data(2), b: Required() }); +}; + +exports["test resolve: exclusion and renaming of overlapping props"] = function (assert) { + assert.equalTraits(Trait({ a: 1, b: 2 }).resolve({ a: undefined, b: "a" }), + { a: Data(2), b: Required() }); +}; + +exports["test resolve: renaming to a common alias causes conflict"] = function (assert) { + assert.equalTraits(Trait({ a: 1, b: 2 }).resolve({ a: "c", b: "c" }), + { c: Conflict("c"), a: Required(), b: Required() }); +}; + +exports["test resolve: renaming overrides Trait.required target"] = function (assert) { + assert.equalTraits(Trait({ a: Trait.required, b: 2 }).resolve({ b: "a" }), + { a: Data(2), b: Required() }); +}; + +exports["test resolve: renaming Trait.required properties has no effect"] = function (assert) { + assert.equalTraits(Trait({ a: 2, b: Trait.required }).resolve({ b: "a" }), + { a: Data(2), b: Required() }); +}; + +exports["test resolve: renaming of non-existent props has no effect"] = function (assert) { + assert.equalTraits(Trait({ a: 1, b: 2 }).resolve({ a: "c", d: "c" }), + { c: Data(1), b: Data(2), a: Required() }); +}; + +exports["test resolve: exclusion of non-existent props has no effect"] = function (assert) { + assert.equalTraits(Trait({ a: 1 }).resolve({ b: undefined }), { a: Data(1) }); +}; + +exports["test resolve is neutral w.r.t. Trait.required properties"] = function (assert) { + var actual = Trait({ a: Trait.required, b: Trait.required, c: "foo", d: 1 }); + var expected = { a: Required(), b: Required(), c: Data("foo"), d: Data(1) }; + assert.equalTraits(actual.resolve({ a: "c", b: undefined }), expected); +}; + +exports["test resolve supports swapping of property names, ordering 1"] = function (assert) { + assert.equalTraits(Trait({ a: 1, b: 2 }).resolve({ a: "b", b: "a" }), + { a: Data(2), b: Data(1) }); +}; + +exports["test resolve supports swapping of property names, ordering 2"] = function (assert) { + assert.equalTraits(Trait({ a: 1, b: 2 }).resolve({ b: "a", a: "b" }), + { a: Data(2), b: Data(1) }); +}; + +exports["test resolve supports swapping of property names, ordering 3"] = function (assert) { + assert.equalTraits(Trait({ b: 2, a: 1 }).resolve({ b: "a", a: "b" }), + { a: Data(2), b: Data(1) }); +}; + +exports["test resolve supports swapping of property names, ordering 4"] = function (assert) { + assert.equalTraits(Trait({ b: 2, a: 1 }).resolve({ a: "b", b: "a" }), + { a: Data(2), b: Data(1) }); +}; + +exports["test create simple"] = function (assert) { + var o1 = Trait({ + a: 1, + b: function () { + return this.a; + } + }).create(Object.prototype); + + assert.equal(Object.getPrototypeOf(o1), Object.prototype, "o1 prototype"); + assert.equal(1, o1.a, "o1.a"); + assert.equal(1, o1.b(), "o1.b()"); + assert.equal(Object.keys(o1).length, 2, "Object.keys(o1).length === 2"); +}; + +exports["test create with Array.prototype"] = function (assert) { + var o2 = Trait({}).create(Array.prototype); + assert.equal(Object.getPrototypeOf(o2), Array.prototype, "o2 prototype"); +}; + +exports["test exception for incomplete required properties"] = function (assert) { + assert.throws(function () { + Trait({ foo: Trait.required }).create(Object.prototype); + }, /Missing required property: `foo`/, "required prop error"); +}; + +exports["test exception for unresolved conflicts"] = function (assert) { + assert.throws(function () { + Trait.compose(Trait({ a: 0 }), Trait({ a: 1 })).create({}); + }, /Remaining conflicting property: `a`/, "conflicting prop error"); +}; + +exports["test verify that required properties are present but undefined"] = function (assert) { + var o4 = Object.create(Object.prototype, Trait({ foo: Trait.required })); + + assert.ok("foo" in o4, "required property present"); + assert.throws(function () { + o4.foo; + }, /Missing required property: `foo`/, "required prop error"); +}; + +exports["test verify that conflicting properties are present"] = function (assert) { + var o5 = Object.create(Object.prototype, Trait.compose(Trait({ a: 0 }), + Trait({ a: 1 }))); + + assert.ok("a" in o5, "conflicting property present"); + assert.throws(function () { + o5.a; + }, /Remaining conflicting property: `a`/, "conflicting prop access error"); +}; + +exports["test diamond with conflicts"] = function (assert) { + function makeT1(x) { + return Trait({ + m: function () { + return x + } + }) + }; + + function makeT2(x) { + return Trait.compose(Trait({ + t2: "foo" + }), makeT1(x)); + }; + + function makeT3(x) { + return Trait.compose(Trait({ + t3: "bar" + }), makeT1(x)); + }; + + var T4 = Trait.compose(makeT2(5), makeT3(5)); + + assert.throws(function () { + T4.create(Object.prototype); + }, /Remaining conflicting property: `m`/, "diamond prop conflict"); +}; + +exports["test providing requirements through proto"] = function (assert) { + var t = Trait({ required: Trait.required }).create({ required: "test" }); + assert.equal(t.required, "test", "property from proto is inherited"); +}; + +if (module == require.main) + require("test").run(exports); diff --git a/tools/addon-sdk-1.3/packages/api-utils/tests/traits/utils.js b/tools/addon-sdk-1.3/packages/api-utils/tests/traits/utils.js new file mode 100644 index 0000000..5647fb9 --- /dev/null +++ b/tools/addon-sdk-1.3/packages/api-utils/tests/traits/utils.js @@ -0,0 +1,52 @@ +"use strict"; + +var ERR_CONFLICT = "Remaining conflicting property: "; +var ERR_REQUIRED = "Missing required property: "; + +exports.Data = function Data(value, enumerable, configurable, writable) { + return ({ + value: value, + enumerable: enumerable !== false, + configurable: configurable !== false, + writable: writable !== false + }); +}; + +exports.Method = function Method(method, enumerable, configurable, writable) { + return ({ + value: method, + enumerable: enumerable !== false, + configurable: configurable !== false, + writable: writable !== false + }); +}; + +exports.Accessor = function Accessor(get, set, enumerable, configurable) { + return ({ + get: get, + set: set, + enumerable: enumerable !== false, + configurable: configurable !== false + }); +}; + +exports.Required = function Required(name) { + function required() { throw new Error(ERR_REQUIRED + name) } + + return ({ + get: required, + set: required, + required: true + }); +}; + +exports.Conflict = function Conflict(name) { + function conflict() { throw new Error(ERR_CONFLICT + name) } + + return ({ + get: conflict, + set: conflict, + conflict: true + }); +}; + |