michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: 'use strict'; michael@0: michael@0: const ERR_CONFLICT = 'Remaining conflicting property: ', michael@0: ERR_REQUIRED = 'Missing required property: '; michael@0: michael@0: function assertSametrait(assert, trait1, trait2) { michael@0: let names1 = Object.getOwnPropertyNames(trait1), michael@0: names2 = Object.getOwnPropertyNames(trait2); michael@0: michael@0: assert.equal( michael@0: names1.length, michael@0: names2.length, michael@0: 'equal traits must have same amount of properties' michael@0: ); michael@0: michael@0: for (let i = 0; i < names1.length; i++) { michael@0: let name = names1[i]; michael@0: assert.notEqual( michael@0: -1, michael@0: names2.indexOf(name), michael@0: 'equal traits must contain same named properties: ' + name michael@0: ); michael@0: assertSameDescriptor(assert, name, trait1[name], trait2[name]); michael@0: } michael@0: } michael@0: michael@0: function assertSameDescriptor(assert, name, desc1, desc2) { michael@0: if (desc1.conflict || desc2.conflict) { michael@0: assert.equal( michael@0: desc1.conflict, michael@0: desc2.conflict, michael@0: 'if one of same descriptors has `conflict` another must have it: ' michael@0: + name michael@0: ); michael@0: } michael@0: else if (desc1.required || desc2.required) { michael@0: assert.equal( michael@0: desc1.required, michael@0: desc2.required, michael@0: 'if one of same descriptors is has `required` another must have it: ' michael@0: + name michael@0: ); michael@0: } michael@0: else { michael@0: assert.equal( michael@0: desc1.get, michael@0: desc2.get, michael@0: 'get must be the same on both descriptors: ' + name michael@0: ); michael@0: assert.equal( michael@0: desc1.set, michael@0: desc2.set, michael@0: 'set must be the same on both descriptors: ' + name michael@0: ); michael@0: assert.equal( michael@0: desc1.value, michael@0: desc2.value, michael@0: 'value must be the same on both descriptors: ' + name michael@0: ); michael@0: assert.equal( michael@0: desc1.enumerable, michael@0: desc2.enumerable, michael@0: 'enumerable must be the same on both descriptors: ' + name michael@0: ); michael@0: assert.equal( michael@0: desc1.required, michael@0: desc2.required, michael@0: 'value must be the same on both descriptors: ' + name michael@0: ); michael@0: } michael@0: } michael@0: michael@0: function Data(value, enumerable, confligurable, writable) { michael@0: return { michael@0: value: value, michael@0: enumerable: false !== enumerable, michael@0: confligurable: false !== confligurable, michael@0: writable: false !== writable michael@0: }; michael@0: } michael@0: michael@0: function Method(method, enumerable, confligurable, writable) { michael@0: return { michael@0: value: method, michael@0: enumerable: false !== enumerable, michael@0: confligurable: false !== confligurable, michael@0: writable: false !== writable michael@0: }; michael@0: } michael@0: michael@0: function Accessor(get, set, enumerable, confligurable) { michael@0: return { michael@0: get: get, michael@0: set: set, michael@0: enumerable: false !== enumerable, michael@0: confligurable: false !== confligurable, michael@0: }; michael@0: } michael@0: michael@0: function Required(name) { michael@0: function required() { throw new Error(ERR_REQUIRED + name) } michael@0: return { michael@0: get: required, michael@0: set: required, michael@0: required: true michael@0: }; michael@0: } michael@0: michael@0: function Conflict(name) { michael@0: function conflict() { throw new Error(ERR_CONFLICT + name) } michael@0: return { michael@0: get: conflict, michael@0: set: conflict, michael@0: conflict: true michael@0: }; michael@0: } michael@0: michael@0: function testMethod() {}; michael@0: michael@0: const { trait, compose, resolve, required, override, create } = michael@0: require('sdk/deprecated/traits/core'); michael@0: michael@0: michael@0: exports['test:empty trait'] = function(assert) { michael@0: assertSametrait( michael@0: assert, michael@0: trait({}), michael@0: {} michael@0: ); michael@0: }; michael@0: michael@0: exports['test:simple trait'] = function(assert) { michael@0: assertSametrait( michael@0: assert, michael@0: trait({ michael@0: a: 0, michael@0: b: testMethod michael@0: }), michael@0: { michael@0: a: Data(0, true, true, true), michael@0: b: Method(testMethod, true, true, true) michael@0: } michael@0: ); michael@0: }; michael@0: michael@0: exports['test:simple trait with required prop'] = function(assert) { michael@0: assertSametrait( michael@0: assert, michael@0: trait({ michael@0: a: required, michael@0: b: 1 michael@0: }), michael@0: { michael@0: a: Required('a'), michael@0: b: Data(1) michael@0: } michael@0: ); michael@0: }; michael@0: michael@0: exports['test:ordering of trait properties is irrelevant'] = function(assert) { michael@0: assertSametrait( michael@0: assert, michael@0: trait({ a: 0, b: 1, c: required }), michael@0: trait({ b: 1, c: required, a: 0 }) michael@0: ); michael@0: }; michael@0: michael@0: exports['test:trait with accessor property'] = function(assert) { michael@0: let record = { get a() {}, set a(v) {} }; michael@0: let get = Object.getOwnPropertyDescriptor(record,'a').get; michael@0: let set = Object.getOwnPropertyDescriptor(record,'a').set; michael@0: assertSametrait(assert, michael@0: trait(record), michael@0: { a: Accessor(get, set ) } michael@0: ); michael@0: }; michael@0: michael@0: exports['test:simple composition'] = function(assert) { michael@0: assertSametrait( michael@0: assert, michael@0: compose( michael@0: trait({ a: 0, b: 1 }), michael@0: trait({ c: 2, d: testMethod }) michael@0: ), michael@0: { michael@0: a: Data(0), michael@0: b: Data(1), michael@0: c: Data(2), michael@0: d: Method(testMethod) michael@0: } michael@0: ); michael@0: }; michael@0: michael@0: exports['test:composition with conflict'] = function(assert) { michael@0: assertSametrait( michael@0: assert, michael@0: compose( michael@0: trait({ a: 0, b: 1 }), michael@0: trait({ a: 2, c: testMethod }) michael@0: ), michael@0: { michael@0: a: Conflict('a'), michael@0: b: Data(1), michael@0: c: Method(testMethod) michael@0: } michael@0: ); michael@0: }; michael@0: michael@0: exports['test:composition of identical props does not cause conflict'] = michael@0: function(assert) { michael@0: assertSametrait(assert, michael@0: compose( michael@0: trait({ a: 0, b: 1 }), michael@0: trait({ a: 0, c: testMethod }) michael@0: ), michael@0: { michael@0: a: Data(0), michael@0: b: Data(1), michael@0: c: Method(testMethod) } michael@0: ) michael@0: }; michael@0: michael@0: exports['test:composition with identical required props'] = michael@0: function(assert) { michael@0: assertSametrait(assert, michael@0: compose( michael@0: trait({ a: required, b: 1 }), michael@0: trait({ a: required, c: testMethod }) michael@0: ), michael@0: { michael@0: a: Required(), michael@0: b: Data(1), michael@0: c: Method(testMethod) michael@0: } michael@0: ); michael@0: }; michael@0: michael@0: exports['test:composition satisfying a required prop'] = function (assert) { michael@0: assertSametrait(assert, michael@0: compose( michael@0: trait({ a: required, b: 1 }), michael@0: trait({ a: testMethod }) michael@0: ), michael@0: { michael@0: a: Method(testMethod), michael@0: b: Data(1) michael@0: } michael@0: ); michael@0: }; michael@0: michael@0: exports['test:compose is neutral wrt conflicts'] = function (assert) { michael@0: assertSametrait(assert, michael@0: compose( michael@0: compose( michael@0: trait({ a: 1 }), michael@0: trait({ a: 2 }) michael@0: ), michael@0: trait({ b: 0 }) michael@0: ), michael@0: { michael@0: a: Conflict('a'), michael@0: b: Data(0) michael@0: } michael@0: ); michael@0: }; michael@0: michael@0: exports['test:conflicting prop overrides required prop'] = function (assert) { michael@0: assertSametrait(assert, michael@0: compose( michael@0: compose( michael@0: trait({ a: 1 }), michael@0: trait({ a: 2 }) michael@0: ), michael@0: trait({ a: required }) michael@0: ), michael@0: { michael@0: a: Conflict('a') michael@0: } michael@0: ); michael@0: }; michael@0: michael@0: exports['test:compose is commutative'] = function (assert) { michael@0: assertSametrait(assert, michael@0: compose( michael@0: trait({ a: 0, b: 1 }), michael@0: trait({ c: 2, d: testMethod }) michael@0: ), michael@0: compose( michael@0: trait({ c: 2, d: testMethod }), michael@0: trait({ a: 0, b: 1 }) michael@0: ) michael@0: ); michael@0: }; michael@0: michael@0: exports['test:compose is commutative, also for required/conflicting props'] = michael@0: function (assert) { michael@0: assertSametrait(assert, michael@0: compose( michael@0: trait({ a: 0, b: 1, c: 3, e: required }), michael@0: trait({ c: 2, d: testMethod }) michael@0: ), michael@0: compose( michael@0: trait({ c: 2, d: testMethod }), michael@0: trait({ a: 0, b: 1, c: 3, e: required }) michael@0: ) michael@0: ); michael@0: }; michael@0: exports['test:compose is associative'] = function (assert) { michael@0: assertSametrait(assert, michael@0: compose( michael@0: trait({ a: 0, b: 1, c: 3, d: required }), michael@0: compose( michael@0: trait({ c: 3, d: required }), michael@0: trait({ c: 2, d: testMethod, e: 'foo' }) michael@0: ) michael@0: ), michael@0: compose( michael@0: compose( michael@0: trait({ a: 0, b: 1, c: 3, d: required }), michael@0: trait({ c: 3, d: required }) michael@0: ), michael@0: trait({ c: 2, d: testMethod, e: 'foo' }) michael@0: ) michael@0: ); michael@0: }; michael@0: michael@0: exports['test:diamond import of same prop does not generate conflict'] = michael@0: function (assert) { michael@0: assertSametrait(assert, michael@0: compose( michael@0: compose( michael@0: trait({ b: 2 }), michael@0: trait({ a: 1 }) michael@0: ), michael@0: compose( michael@0: trait({ c: 3 }), michael@0: trait({ a: 1 }) michael@0: ), michael@0: trait({ d: 4 }) michael@0: ), michael@0: { michael@0: a: Data(1), michael@0: b: Data(2), michael@0: c: Data(3), michael@0: d: Data(4) michael@0: } michael@0: ); michael@0: }; michael@0: michael@0: exports['test:resolve with empty resolutions has no effect'] = michael@0: function (assert) { michael@0: assertSametrait(assert, resolve({}, trait({ michael@0: a: 1, michael@0: b: required, michael@0: c: testMethod michael@0: })), { michael@0: a: Data(1), michael@0: b: Required(), michael@0: c: Method(testMethod) michael@0: }); michael@0: }; michael@0: michael@0: exports['test:resolve: renaming'] = function (assert) { michael@0: assertSametrait(assert, michael@0: resolve( michael@0: { a: 'A', c: 'C' }, michael@0: trait({ a: 1, b: required, c: testMethod }) michael@0: ), michael@0: { michael@0: A: Data(1), michael@0: b: Required(), michael@0: C: Method(testMethod), michael@0: a: Required(), michael@0: c: Required() michael@0: } michael@0: ); michael@0: }; michael@0: michael@0: exports['test:resolve: renaming to conflicting name causes conflict, order 1'] michael@0: = function (assert) { michael@0: assertSametrait(assert, michael@0: resolve( michael@0: { a: 'b'}, michael@0: trait({ a: 1, b: 2 }) michael@0: ), michael@0: { michael@0: b: Conflict('b'), michael@0: a: Required() michael@0: } michael@0: ); michael@0: }; michael@0: michael@0: exports['test:resolve: renaming to conflicting name causes conflict, order 2'] michael@0: = function (assert) { michael@0: assertSametrait(assert, michael@0: resolve( michael@0: { a: 'b' }, michael@0: trait({ b: 2, a: 1 }) michael@0: ), michael@0: { michael@0: b: Conflict('b'), michael@0: a: Required() michael@0: } michael@0: ); michael@0: }; michael@0: michael@0: exports['test:resolve: simple exclusion'] = function (assert) { michael@0: assertSametrait(assert, michael@0: resolve( michael@0: { a: undefined }, michael@0: trait({ a: 1, b: 2 }) michael@0: ), michael@0: { michael@0: a: Required(), michael@0: b: Data(2) michael@0: } michael@0: ); michael@0: }; michael@0: michael@0: exports['test:resolve: exclusion to "empty" trait'] = function (assert) { michael@0: assertSametrait(assert, michael@0: resolve( michael@0: { a: undefined, b: undefined }, michael@0: trait({ a: 1, b: 2 }) michael@0: ), michael@0: { michael@0: a: Required(), michael@0: b: Required() michael@0: } michael@0: ); michael@0: }; michael@0: michael@0: exports['test:resolve: exclusion and renaming of disjoint props'] = michael@0: function (assert) { michael@0: assertSametrait(assert, michael@0: resolve( michael@0: { a: undefined, b: 'c' }, michael@0: trait({ a: 1, b: 2 }) michael@0: ), michael@0: { michael@0: a: Required(), michael@0: c: Data(2), michael@0: b: Required() michael@0: } michael@0: ); michael@0: }; michael@0: michael@0: exports['test:resolve: exclusion and renaming of overlapping props'] = michael@0: function (assert) { michael@0: assertSametrait(assert, michael@0: resolve( michael@0: { a: undefined, b: 'a' }, michael@0: trait({ a: 1, b: 2 }) michael@0: ), michael@0: { michael@0: a: Data(2), michael@0: b: Required() michael@0: } michael@0: ); michael@0: }; michael@0: michael@0: exports['test:resolve: renaming to a common alias causes conflict'] = michael@0: function (assert) { michael@0: assertSametrait(assert, michael@0: resolve( michael@0: { a: 'c', b: 'c' }, michael@0: trait({ a: 1, b: 2 }) michael@0: ), michael@0: { michael@0: c: Conflict('c'), michael@0: a: Required(), michael@0: b: Required() michael@0: } michael@0: ); michael@0: }; michael@0: michael@0: exports['test:resolve: renaming overrides required target'] = michael@0: function (assert) { michael@0: assertSametrait(assert, michael@0: resolve( michael@0: { b: 'a' }, michael@0: trait({ a: required, b: 2 }) michael@0: ), michael@0: { michael@0: a: Data(2), michael@0: b: Required() michael@0: } michael@0: ); michael@0: }; michael@0: michael@0: exports['test:resolve: renaming required properties has no effect'] = michael@0: function (assert) { michael@0: assertSametrait(assert, michael@0: resolve( michael@0: { b: 'a' }, michael@0: trait({ a: 2, b: required }) michael@0: ), michael@0: { michael@0: a: Data(2), michael@0: b: Required() michael@0: } michael@0: ); michael@0: }; michael@0: michael@0: exports['test:resolve: renaming of non-existent props has no effect'] = michael@0: function (assert) { michael@0: assertSametrait(assert, michael@0: resolve( michael@0: { a: 'c', d: 'c' }, michael@0: trait({ a: 1, b: 2 }) michael@0: ), michael@0: { michael@0: c: Data(1), michael@0: b: Data(2), michael@0: a: Required() michael@0: } michael@0: ); michael@0: }; michael@0: michael@0: exports['test:resolve: exclusion of non-existent props has no effect'] = michael@0: function (assert) { michael@0: assertSametrait(assert, michael@0: resolve( michael@0: { b: undefined }, michael@0: trait({ a: 1 }) michael@0: ), michael@0: { michael@0: a: Data(1) michael@0: } michael@0: ); michael@0: }; michael@0: michael@0: exports['test:resolve is neutral w.r.t. required properties'] = michael@0: function (assert) { michael@0: assertSametrait(assert, michael@0: resolve( michael@0: { a: 'c', b: undefined }, michael@0: trait({ a: required, b: required, c: 'foo', d: 1 }) michael@0: ), michael@0: { michael@0: a: Required(), michael@0: b: Required(), michael@0: c: Data('foo'), michael@0: d: Data(1) michael@0: } michael@0: ); michael@0: }; michael@0: michael@0: exports['test:resolve supports swapping of property names, ordering 1'] = michael@0: function (assert) { michael@0: assertSametrait(assert, michael@0: resolve( michael@0: { a: 'b', b: 'a' }, michael@0: trait({ a: 1, b: 2 }) michael@0: ), michael@0: { michael@0: a: Data(2), michael@0: b: Data(1) michael@0: } michael@0: ); michael@0: }; michael@0: michael@0: exports['test:resolve supports swapping of property names, ordering 2'] = michael@0: function (assert) { michael@0: assertSametrait(assert, michael@0: resolve( michael@0: { b: 'a', a: 'b' }, michael@0: trait({ a: 1, b: 2 }) michael@0: ), michael@0: { michael@0: a: Data(2), michael@0: b: Data(1) michael@0: } michael@0: ); michael@0: }; michael@0: michael@0: exports['test:resolve supports swapping of property names, ordering 3'] = michael@0: function (assert) { michael@0: assertSametrait(assert, michael@0: resolve( michael@0: { b: 'a', a: 'b' }, michael@0: trait({ b: 2, a: 1 }) michael@0: ), michael@0: { michael@0: a: Data(2), michael@0: b: Data(1) michael@0: } michael@0: ); michael@0: }; michael@0: michael@0: exports['test:resolve supports swapping of property names, ordering 4'] = michael@0: function (assert) { michael@0: assertSametrait(assert, michael@0: resolve( michael@0: { a: 'b', b: 'a' }, michael@0: trait({ b: 2, a: 1 }) michael@0: ), michael@0: { michael@0: a: Data(2), michael@0: b: Data(1) michael@0: } michael@0: ); michael@0: }; michael@0: michael@0: exports['test:override of mutually exclusive traits'] = function (assert) { michael@0: assertSametrait(assert, michael@0: override( michael@0: trait({ a: 1, b: 2 }), michael@0: trait({ c: 3, d: testMethod }) michael@0: ), michael@0: { michael@0: a: Data(1), michael@0: b: Data(2), michael@0: c: Data(3), michael@0: d: Method(testMethod) michael@0: } michael@0: ); michael@0: }; michael@0: michael@0: exports['test:override of mutually exclusive traits is compose'] = michael@0: function (assert) { michael@0: assertSametrait(assert, michael@0: override( michael@0: trait({ a: 1, b: 2 }), michael@0: trait({ c: 3, d: testMethod }) michael@0: ), michael@0: compose( michael@0: trait({ d: testMethod, c: 3 }), michael@0: trait({ b: 2, a: 1 }) michael@0: ) michael@0: ); michael@0: }; michael@0: michael@0: exports['test:override of overlapping traits'] = function (assert) { michael@0: assertSametrait(assert, michael@0: override( michael@0: trait({ a: 1, b: 2 }), michael@0: trait({ a: 3, c: testMethod }) michael@0: ), michael@0: { michael@0: a: Data(1), michael@0: b: Data(2), michael@0: c: Method(testMethod) michael@0: } michael@0: ); michael@0: }; michael@0: michael@0: exports['test:three-way override of overlapping traits'] = function (assert) { michael@0: assertSametrait(assert, michael@0: override( michael@0: trait({ a: 1, b: 2 }), michael@0: trait({ b: 4, c: 3 }), michael@0: trait({ a: 3, c: testMethod, d: 5 }) michael@0: ), michael@0: { michael@0: a: Data(1), michael@0: b: Data(2), michael@0: c: Data(3), michael@0: d: Data(5) michael@0: } michael@0: ); michael@0: }; michael@0: michael@0: exports['test:override replaces required properties'] = function (assert) { michael@0: assertSametrait(assert, michael@0: override( michael@0: trait({ a: required, b: 2 }), michael@0: trait({ a: 1, c: testMethod }) michael@0: ), michael@0: { michael@0: a: Data(1), michael@0: b: Data(2), michael@0: c: Method(testMethod) michael@0: } michael@0: ); michael@0: }; michael@0: michael@0: exports['test:override is not commutative'] = function (assert) { michael@0: assertSametrait(assert, michael@0: override( michael@0: trait({ a: 1, b: 2 }), michael@0: trait({ a: 3, c: 4 }) michael@0: ), michael@0: { michael@0: a: Data(1), michael@0: b: Data(2), michael@0: c: Data(4) michael@0: } michael@0: ); michael@0: michael@0: assertSametrait(assert, michael@0: override( michael@0: trait({ a: 3, c: 4 }), michael@0: trait({ a: 1, b: 2 }) michael@0: ), michael@0: { michael@0: a: Data(3), michael@0: b: Data(2), michael@0: c: Data(4) michael@0: } michael@0: ); michael@0: }; michael@0: michael@0: exports['test:override is associative'] = function (assert) { michael@0: assertSametrait(assert, michael@0: override( michael@0: override( michael@0: trait({ a: 1, b: 2 }), michael@0: trait({ a: 3, c: 4, d: 5 }) michael@0: ), michael@0: trait({ a: 6, c: 7, e: 8 }) michael@0: ), michael@0: override( michael@0: trait({ a: 1, b: 2 }), michael@0: override( michael@0: trait({ a: 3, c: 4, d: 5 }), michael@0: trait({ a: 6, c: 7, e: 8 }) michael@0: ) michael@0: ) michael@0: ); michael@0: }; michael@0: michael@0: exports['test:create simple'] = function(assert) { michael@0: let o1 = create( michael@0: Object.prototype, michael@0: trait({ a: 1, b: function() { return this.a; } }) michael@0: ); michael@0: michael@0: assert.equal( michael@0: Object.prototype, michael@0: Object.getPrototypeOf(o1), michael@0: 'o1 prototype' michael@0: ); michael@0: assert.equal(1, o1.a, 'o1.a'); michael@0: assert.equal(1, o1.b(), 'o1.b()'); michael@0: assert.equal( michael@0: 2, michael@0: Object.getOwnPropertyNames(o1).length, michael@0: 'Object.keys(o1).length === 2' michael@0: ); michael@0: }; michael@0: michael@0: exports['test:create with Array.prototype'] = function(assert) { michael@0: let o2 = create(Array.prototype, trait({})); michael@0: assert.equal( michael@0: Array.prototype, michael@0: Object.getPrototypeOf(o2), michael@0: "o2 prototype" michael@0: ); michael@0: }; michael@0: michael@0: exports['test:exception for incomplete required properties'] = michael@0: function(assert) { michael@0: try { michael@0: create(Object.prototype, trait({ foo: required })); michael@0: assert.fail('expected create to complain about missing required props'); michael@0: } michael@0: catch(e) { michael@0: assert.equal( michael@0: 'Error: Missing required property: foo', michael@0: e.toString(), michael@0: 'required prop error' michael@0: ); michael@0: } michael@0: }; michael@0: michael@0: exports['test:exception for unresolved conflicts'] = function(assert) { michael@0: try { michael@0: create({}, compose(trait({ a: 0 }), trait({ a: 1 }))); michael@0: assert.fail('expected create to complain about unresolved conflicts'); michael@0: } michael@0: catch(e) { michael@0: assert.equal( michael@0: 'Error: Remaining conflicting property: a', michael@0: e.toString(), michael@0: 'conflicting prop error' michael@0: ); michael@0: } michael@0: }; michael@0: michael@0: exports['test:verify that required properties are present but undefined'] = michael@0: function(assert) { michael@0: try { michael@0: let o4 = Object.create(Object.prototype, trait({ foo: required })); michael@0: assert.equal(true, 'foo' in o4, 'required property present'); michael@0: try { michael@0: let foo = o4.foo; michael@0: assert.fail('access to required property must throw'); michael@0: } michael@0: catch(e) { michael@0: assert.equal( michael@0: 'Error: Missing required property: foo', michael@0: e.toString(), michael@0: 'required prop error' michael@0: ) michael@0: } michael@0: } michael@0: catch(e) { michael@0: assert.fail('did not expect create to complain about required props'); michael@0: } michael@0: }; michael@0: michael@0: exports['test:verify that conflicting properties are present'] = michael@0: function(assert) { michael@0: try { michael@0: let o5 = Object.create( michael@0: Object.prototype, michael@0: compose(trait({ a: 0 }), trait({ a: 1 })) michael@0: ); michael@0: assert.equal(true, 'a' in o5, 'conflicting property present'); michael@0: try { michael@0: let a = o5.a; // accessors or data prop michael@0: assert.fail('expected conflicting prop to cause exception'); michael@0: } michael@0: catch (e) { michael@0: assert.equal( michael@0: 'Error: Remaining conflicting property: a', michael@0: e.toString(), michael@0: 'conflicting prop access error' michael@0: ); michael@0: } michael@0: } michael@0: catch(e) { michael@0: assert.fail('did not expect create to complain about conflicting props'); michael@0: } michael@0: }; michael@0: michael@0: exports['test diamond with conflicts'] = function(assert) { michael@0: function makeT1(x) trait({ m: function() { return x; } }) michael@0: function makeT2(x) compose(trait({ t2: 'foo' }), makeT1(x)) michael@0: function makeT3(x) compose(trait({ t3: 'bar' }), makeT1(x)) michael@0: michael@0: let T4 = compose(makeT2(5), makeT3(5)); michael@0: try { michael@0: let o = create(Object.prototype, T4); michael@0: assert.fail('expected diamond prop to cause exception'); michael@0: } michael@0: catch(e) { michael@0: assert.equal( michael@0: 'Error: Remaining conflicting property: m', michael@0: e.toString(), michael@0: 'diamond prop conflict' michael@0: ); michael@0: } michael@0: }; michael@0: michael@0: require('sdk/test').run(exports);