1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/addon-sdk/source/test/test-traits-core.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,850 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 +'use strict'; 1.8 + 1.9 +const ERR_CONFLICT = 'Remaining conflicting property: ', 1.10 + ERR_REQUIRED = 'Missing required property: '; 1.11 + 1.12 +function assertSametrait(assert, trait1, trait2) { 1.13 + let names1 = Object.getOwnPropertyNames(trait1), 1.14 + names2 = Object.getOwnPropertyNames(trait2); 1.15 + 1.16 + assert.equal( 1.17 + names1.length, 1.18 + names2.length, 1.19 + 'equal traits must have same amount of properties' 1.20 + ); 1.21 + 1.22 + for (let i = 0; i < names1.length; i++) { 1.23 + let name = names1[i]; 1.24 + assert.notEqual( 1.25 + -1, 1.26 + names2.indexOf(name), 1.27 + 'equal traits must contain same named properties: ' + name 1.28 + ); 1.29 + assertSameDescriptor(assert, name, trait1[name], trait2[name]); 1.30 + } 1.31 +} 1.32 + 1.33 +function assertSameDescriptor(assert, name, desc1, desc2) { 1.34 + if (desc1.conflict || desc2.conflict) { 1.35 + assert.equal( 1.36 + desc1.conflict, 1.37 + desc2.conflict, 1.38 + 'if one of same descriptors has `conflict` another must have it: ' 1.39 + + name 1.40 + ); 1.41 + } 1.42 + else if (desc1.required || desc2.required) { 1.43 + assert.equal( 1.44 + desc1.required, 1.45 + desc2.required, 1.46 + 'if one of same descriptors is has `required` another must have it: ' 1.47 + + name 1.48 + ); 1.49 + } 1.50 + else { 1.51 + assert.equal( 1.52 + desc1.get, 1.53 + desc2.get, 1.54 + 'get must be the same on both descriptors: ' + name 1.55 + ); 1.56 + assert.equal( 1.57 + desc1.set, 1.58 + desc2.set, 1.59 + 'set must be the same on both descriptors: ' + name 1.60 + ); 1.61 + assert.equal( 1.62 + desc1.value, 1.63 + desc2.value, 1.64 + 'value must be the same on both descriptors: ' + name 1.65 + ); 1.66 + assert.equal( 1.67 + desc1.enumerable, 1.68 + desc2.enumerable, 1.69 + 'enumerable must be the same on both descriptors: ' + name 1.70 + ); 1.71 + assert.equal( 1.72 + desc1.required, 1.73 + desc2.required, 1.74 + 'value must be the same on both descriptors: ' + name 1.75 + ); 1.76 + } 1.77 +} 1.78 + 1.79 +function Data(value, enumerable, confligurable, writable) { 1.80 + return { 1.81 + value: value, 1.82 + enumerable: false !== enumerable, 1.83 + confligurable: false !== confligurable, 1.84 + writable: false !== writable 1.85 + }; 1.86 +} 1.87 + 1.88 +function Method(method, enumerable, confligurable, writable) { 1.89 + return { 1.90 + value: method, 1.91 + enumerable: false !== enumerable, 1.92 + confligurable: false !== confligurable, 1.93 + writable: false !== writable 1.94 + }; 1.95 +} 1.96 + 1.97 +function Accessor(get, set, enumerable, confligurable) { 1.98 + return { 1.99 + get: get, 1.100 + set: set, 1.101 + enumerable: false !== enumerable, 1.102 + confligurable: false !== confligurable, 1.103 + }; 1.104 +} 1.105 + 1.106 +function Required(name) { 1.107 + function required() { throw new Error(ERR_REQUIRED + name) } 1.108 + return { 1.109 + get: required, 1.110 + set: required, 1.111 + required: true 1.112 + }; 1.113 +} 1.114 + 1.115 +function Conflict(name) { 1.116 + function conflict() { throw new Error(ERR_CONFLICT + name) } 1.117 + return { 1.118 + get: conflict, 1.119 + set: conflict, 1.120 + conflict: true 1.121 + }; 1.122 +} 1.123 + 1.124 +function testMethod() {}; 1.125 + 1.126 +const { trait, compose, resolve, required, override, create } = 1.127 + require('sdk/deprecated/traits/core'); 1.128 + 1.129 + 1.130 +exports['test:empty trait'] = function(assert) { 1.131 + assertSametrait( 1.132 + assert, 1.133 + trait({}), 1.134 + {} 1.135 + ); 1.136 +}; 1.137 + 1.138 +exports['test:simple trait'] = function(assert) { 1.139 + assertSametrait( 1.140 + assert, 1.141 + trait({ 1.142 + a: 0, 1.143 + b: testMethod 1.144 + }), 1.145 + { 1.146 + a: Data(0, true, true, true), 1.147 + b: Method(testMethod, true, true, true) 1.148 + } 1.149 + ); 1.150 +}; 1.151 + 1.152 +exports['test:simple trait with required prop'] = function(assert) { 1.153 + assertSametrait( 1.154 + assert, 1.155 + trait({ 1.156 + a: required, 1.157 + b: 1 1.158 + }), 1.159 + { 1.160 + a: Required('a'), 1.161 + b: Data(1) 1.162 + } 1.163 + ); 1.164 +}; 1.165 + 1.166 +exports['test:ordering of trait properties is irrelevant'] = function(assert) { 1.167 + assertSametrait( 1.168 + assert, 1.169 + trait({ a: 0, b: 1, c: required }), 1.170 + trait({ b: 1, c: required, a: 0 }) 1.171 + ); 1.172 +}; 1.173 + 1.174 +exports['test:trait with accessor property'] = function(assert) { 1.175 + let record = { get a() {}, set a(v) {} }; 1.176 + let get = Object.getOwnPropertyDescriptor(record,'a').get; 1.177 + let set = Object.getOwnPropertyDescriptor(record,'a').set; 1.178 + assertSametrait(assert, 1.179 + trait(record), 1.180 + { a: Accessor(get, set ) } 1.181 + ); 1.182 +}; 1.183 + 1.184 +exports['test:simple composition'] = function(assert) { 1.185 + assertSametrait( 1.186 + assert, 1.187 + compose( 1.188 + trait({ a: 0, b: 1 }), 1.189 + trait({ c: 2, d: testMethod }) 1.190 + ), 1.191 + { 1.192 + a: Data(0), 1.193 + b: Data(1), 1.194 + c: Data(2), 1.195 + d: Method(testMethod) 1.196 + } 1.197 + ); 1.198 +}; 1.199 + 1.200 +exports['test:composition with conflict'] = function(assert) { 1.201 + assertSametrait( 1.202 + assert, 1.203 + compose( 1.204 + trait({ a: 0, b: 1 }), 1.205 + trait({ a: 2, c: testMethod }) 1.206 + ), 1.207 + { 1.208 + a: Conflict('a'), 1.209 + b: Data(1), 1.210 + c: Method(testMethod) 1.211 + } 1.212 + ); 1.213 +}; 1.214 + 1.215 +exports['test:composition of identical props does not cause conflict'] = 1.216 +function(assert) { 1.217 + assertSametrait(assert, 1.218 + compose( 1.219 + trait({ a: 0, b: 1 }), 1.220 + trait({ a: 0, c: testMethod }) 1.221 + ), 1.222 + { 1.223 + a: Data(0), 1.224 + b: Data(1), 1.225 + c: Method(testMethod) } 1.226 + ) 1.227 +}; 1.228 + 1.229 +exports['test:composition with identical required props'] = 1.230 +function(assert) { 1.231 + assertSametrait(assert, 1.232 + compose( 1.233 + trait({ a: required, b: 1 }), 1.234 + trait({ a: required, c: testMethod }) 1.235 + ), 1.236 + { 1.237 + a: Required(), 1.238 + b: Data(1), 1.239 + c: Method(testMethod) 1.240 + } 1.241 + ); 1.242 +}; 1.243 + 1.244 +exports['test:composition satisfying a required prop'] = function (assert) { 1.245 + assertSametrait(assert, 1.246 + compose( 1.247 + trait({ a: required, b: 1 }), 1.248 + trait({ a: testMethod }) 1.249 + ), 1.250 + { 1.251 + a: Method(testMethod), 1.252 + b: Data(1) 1.253 + } 1.254 + ); 1.255 +}; 1.256 + 1.257 +exports['test:compose is neutral wrt conflicts'] = function (assert) { 1.258 + assertSametrait(assert, 1.259 + compose( 1.260 + compose( 1.261 + trait({ a: 1 }), 1.262 + trait({ a: 2 }) 1.263 + ), 1.264 + trait({ b: 0 }) 1.265 + ), 1.266 + { 1.267 + a: Conflict('a'), 1.268 + b: Data(0) 1.269 + } 1.270 + ); 1.271 +}; 1.272 + 1.273 +exports['test:conflicting prop overrides required prop'] = function (assert) { 1.274 + assertSametrait(assert, 1.275 + compose( 1.276 + compose( 1.277 + trait({ a: 1 }), 1.278 + trait({ a: 2 }) 1.279 + ), 1.280 + trait({ a: required }) 1.281 + ), 1.282 + { 1.283 + a: Conflict('a') 1.284 + } 1.285 + ); 1.286 +}; 1.287 + 1.288 +exports['test:compose is commutative'] = function (assert) { 1.289 + assertSametrait(assert, 1.290 + compose( 1.291 + trait({ a: 0, b: 1 }), 1.292 + trait({ c: 2, d: testMethod }) 1.293 + ), 1.294 + compose( 1.295 + trait({ c: 2, d: testMethod }), 1.296 + trait({ a: 0, b: 1 }) 1.297 + ) 1.298 + ); 1.299 +}; 1.300 + 1.301 +exports['test:compose is commutative, also for required/conflicting props'] = 1.302 +function (assert) { 1.303 + assertSametrait(assert, 1.304 + compose( 1.305 + trait({ a: 0, b: 1, c: 3, e: required }), 1.306 + trait({ c: 2, d: testMethod }) 1.307 + ), 1.308 + compose( 1.309 + trait({ c: 2, d: testMethod }), 1.310 + trait({ a: 0, b: 1, c: 3, e: required }) 1.311 + ) 1.312 + ); 1.313 +}; 1.314 +exports['test:compose is associative'] = function (assert) { 1.315 + assertSametrait(assert, 1.316 + compose( 1.317 + trait({ a: 0, b: 1, c: 3, d: required }), 1.318 + compose( 1.319 + trait({ c: 3, d: required }), 1.320 + trait({ c: 2, d: testMethod, e: 'foo' }) 1.321 + ) 1.322 + ), 1.323 + compose( 1.324 + compose( 1.325 + trait({ a: 0, b: 1, c: 3, d: required }), 1.326 + trait({ c: 3, d: required }) 1.327 + ), 1.328 + trait({ c: 2, d: testMethod, e: 'foo' }) 1.329 + ) 1.330 + ); 1.331 +}; 1.332 + 1.333 +exports['test:diamond import of same prop does not generate conflict'] = 1.334 +function (assert) { 1.335 + assertSametrait(assert, 1.336 + compose( 1.337 + compose( 1.338 + trait({ b: 2 }), 1.339 + trait({ a: 1 }) 1.340 + ), 1.341 + compose( 1.342 + trait({ c: 3 }), 1.343 + trait({ a: 1 }) 1.344 + ), 1.345 + trait({ d: 4 }) 1.346 + ), 1.347 + { 1.348 + a: Data(1), 1.349 + b: Data(2), 1.350 + c: Data(3), 1.351 + d: Data(4) 1.352 + } 1.353 + ); 1.354 +}; 1.355 + 1.356 +exports['test:resolve with empty resolutions has no effect'] = 1.357 +function (assert) { 1.358 + assertSametrait(assert, resolve({}, trait({ 1.359 + a: 1, 1.360 + b: required, 1.361 + c: testMethod 1.362 + })), { 1.363 + a: Data(1), 1.364 + b: Required(), 1.365 + c: Method(testMethod) 1.366 + }); 1.367 +}; 1.368 + 1.369 +exports['test:resolve: renaming'] = function (assert) { 1.370 + assertSametrait(assert, 1.371 + resolve( 1.372 + { a: 'A', c: 'C' }, 1.373 + trait({ a: 1, b: required, c: testMethod }) 1.374 + ), 1.375 + { 1.376 + A: Data(1), 1.377 + b: Required(), 1.378 + C: Method(testMethod), 1.379 + a: Required(), 1.380 + c: Required() 1.381 + } 1.382 + ); 1.383 +}; 1.384 + 1.385 +exports['test:resolve: renaming to conflicting name causes conflict, order 1'] 1.386 += function (assert) { 1.387 + assertSametrait(assert, 1.388 + resolve( 1.389 + { a: 'b'}, 1.390 + trait({ a: 1, b: 2 }) 1.391 + ), 1.392 + { 1.393 + b: Conflict('b'), 1.394 + a: Required() 1.395 + } 1.396 + ); 1.397 +}; 1.398 + 1.399 +exports['test:resolve: renaming to conflicting name causes conflict, order 2'] 1.400 += function (assert) { 1.401 + assertSametrait(assert, 1.402 + resolve( 1.403 + { a: 'b' }, 1.404 + trait({ b: 2, a: 1 }) 1.405 + ), 1.406 + { 1.407 + b: Conflict('b'), 1.408 + a: Required() 1.409 + } 1.410 + ); 1.411 +}; 1.412 + 1.413 +exports['test:resolve: simple exclusion'] = function (assert) { 1.414 + assertSametrait(assert, 1.415 + resolve( 1.416 + { a: undefined }, 1.417 + trait({ a: 1, b: 2 }) 1.418 + ), 1.419 + { 1.420 + a: Required(), 1.421 + b: Data(2) 1.422 + } 1.423 + ); 1.424 +}; 1.425 + 1.426 +exports['test:resolve: exclusion to "empty" trait'] = function (assert) { 1.427 + assertSametrait(assert, 1.428 + resolve( 1.429 + { a: undefined, b: undefined }, 1.430 + trait({ a: 1, b: 2 }) 1.431 + ), 1.432 + { 1.433 + a: Required(), 1.434 + b: Required() 1.435 + } 1.436 + ); 1.437 +}; 1.438 + 1.439 +exports['test:resolve: exclusion and renaming of disjoint props'] = 1.440 +function (assert) { 1.441 + assertSametrait(assert, 1.442 + resolve( 1.443 + { a: undefined, b: 'c' }, 1.444 + trait({ a: 1, b: 2 }) 1.445 + ), 1.446 + { 1.447 + a: Required(), 1.448 + c: Data(2), 1.449 + b: Required() 1.450 + } 1.451 + ); 1.452 +}; 1.453 + 1.454 +exports['test:resolve: exclusion and renaming of overlapping props'] = 1.455 +function (assert) { 1.456 + assertSametrait(assert, 1.457 + resolve( 1.458 + { a: undefined, b: 'a' }, 1.459 + trait({ a: 1, b: 2 }) 1.460 + ), 1.461 + { 1.462 + a: Data(2), 1.463 + b: Required() 1.464 + } 1.465 + ); 1.466 +}; 1.467 + 1.468 +exports['test:resolve: renaming to a common alias causes conflict'] = 1.469 +function (assert) { 1.470 + assertSametrait(assert, 1.471 + resolve( 1.472 + { a: 'c', b: 'c' }, 1.473 + trait({ a: 1, b: 2 }) 1.474 + ), 1.475 + { 1.476 + c: Conflict('c'), 1.477 + a: Required(), 1.478 + b: Required() 1.479 + } 1.480 + ); 1.481 +}; 1.482 + 1.483 +exports['test:resolve: renaming overrides required target'] = 1.484 +function (assert) { 1.485 + assertSametrait(assert, 1.486 + resolve( 1.487 + { b: 'a' }, 1.488 + trait({ a: required, b: 2 }) 1.489 + ), 1.490 + { 1.491 + a: Data(2), 1.492 + b: Required() 1.493 + } 1.494 + ); 1.495 +}; 1.496 + 1.497 +exports['test:resolve: renaming required properties has no effect'] = 1.498 +function (assert) { 1.499 + assertSametrait(assert, 1.500 + resolve( 1.501 + { b: 'a' }, 1.502 + trait({ a: 2, b: required }) 1.503 + ), 1.504 + { 1.505 + a: Data(2), 1.506 + b: Required() 1.507 + } 1.508 + ); 1.509 +}; 1.510 + 1.511 +exports['test:resolve: renaming of non-existent props has no effect'] = 1.512 +function (assert) { 1.513 + assertSametrait(assert, 1.514 + resolve( 1.515 + { a: 'c', d: 'c' }, 1.516 + trait({ a: 1, b: 2 }) 1.517 + ), 1.518 + { 1.519 + c: Data(1), 1.520 + b: Data(2), 1.521 + a: Required() 1.522 + } 1.523 + ); 1.524 +}; 1.525 + 1.526 +exports['test:resolve: exclusion of non-existent props has no effect'] = 1.527 +function (assert) { 1.528 + assertSametrait(assert, 1.529 + resolve( 1.530 + { b: undefined }, 1.531 + trait({ a: 1 }) 1.532 + ), 1.533 + { 1.534 + a: Data(1) 1.535 + } 1.536 + ); 1.537 +}; 1.538 + 1.539 +exports['test:resolve is neutral w.r.t. required properties'] = 1.540 +function (assert) { 1.541 + assertSametrait(assert, 1.542 + resolve( 1.543 + { a: 'c', b: undefined }, 1.544 + trait({ a: required, b: required, c: 'foo', d: 1 }) 1.545 + ), 1.546 + { 1.547 + a: Required(), 1.548 + b: Required(), 1.549 + c: Data('foo'), 1.550 + d: Data(1) 1.551 + } 1.552 + ); 1.553 +}; 1.554 + 1.555 +exports['test:resolve supports swapping of property names, ordering 1'] = 1.556 +function (assert) { 1.557 + assertSametrait(assert, 1.558 + resolve( 1.559 + { a: 'b', b: 'a' }, 1.560 + trait({ a: 1, b: 2 }) 1.561 + ), 1.562 + { 1.563 + a: Data(2), 1.564 + b: Data(1) 1.565 + } 1.566 + ); 1.567 +}; 1.568 + 1.569 +exports['test:resolve supports swapping of property names, ordering 2'] = 1.570 +function (assert) { 1.571 + assertSametrait(assert, 1.572 + resolve( 1.573 + { b: 'a', a: 'b' }, 1.574 + trait({ a: 1, b: 2 }) 1.575 + ), 1.576 + { 1.577 + a: Data(2), 1.578 + b: Data(1) 1.579 + } 1.580 + ); 1.581 +}; 1.582 + 1.583 +exports['test:resolve supports swapping of property names, ordering 3'] = 1.584 +function (assert) { 1.585 + assertSametrait(assert, 1.586 + resolve( 1.587 + { b: 'a', a: 'b' }, 1.588 + trait({ b: 2, a: 1 }) 1.589 + ), 1.590 + { 1.591 + a: Data(2), 1.592 + b: Data(1) 1.593 + } 1.594 + ); 1.595 +}; 1.596 + 1.597 +exports['test:resolve supports swapping of property names, ordering 4'] = 1.598 +function (assert) { 1.599 + assertSametrait(assert, 1.600 + resolve( 1.601 + { a: 'b', b: 'a' }, 1.602 + trait({ b: 2, a: 1 }) 1.603 + ), 1.604 + { 1.605 + a: Data(2), 1.606 + b: Data(1) 1.607 + } 1.608 + ); 1.609 +}; 1.610 + 1.611 +exports['test:override of mutually exclusive traits'] = function (assert) { 1.612 + assertSametrait(assert, 1.613 + override( 1.614 + trait({ a: 1, b: 2 }), 1.615 + trait({ c: 3, d: testMethod }) 1.616 + ), 1.617 + { 1.618 + a: Data(1), 1.619 + b: Data(2), 1.620 + c: Data(3), 1.621 + d: Method(testMethod) 1.622 + } 1.623 + ); 1.624 +}; 1.625 + 1.626 +exports['test:override of mutually exclusive traits is compose'] = 1.627 +function (assert) { 1.628 + assertSametrait(assert, 1.629 + override( 1.630 + trait({ a: 1, b: 2 }), 1.631 + trait({ c: 3, d: testMethod }) 1.632 + ), 1.633 + compose( 1.634 + trait({ d: testMethod, c: 3 }), 1.635 + trait({ b: 2, a: 1 }) 1.636 + ) 1.637 + ); 1.638 +}; 1.639 + 1.640 +exports['test:override of overlapping traits'] = function (assert) { 1.641 + assertSametrait(assert, 1.642 + override( 1.643 + trait({ a: 1, b: 2 }), 1.644 + trait({ a: 3, c: testMethod }) 1.645 + ), 1.646 + { 1.647 + a: Data(1), 1.648 + b: Data(2), 1.649 + c: Method(testMethod) 1.650 + } 1.651 + ); 1.652 +}; 1.653 + 1.654 +exports['test:three-way override of overlapping traits'] = function (assert) { 1.655 + assertSametrait(assert, 1.656 + override( 1.657 + trait({ a: 1, b: 2 }), 1.658 + trait({ b: 4, c: 3 }), 1.659 + trait({ a: 3, c: testMethod, d: 5 }) 1.660 + ), 1.661 + { 1.662 + a: Data(1), 1.663 + b: Data(2), 1.664 + c: Data(3), 1.665 + d: Data(5) 1.666 + } 1.667 + ); 1.668 +}; 1.669 + 1.670 +exports['test:override replaces required properties'] = function (assert) { 1.671 + assertSametrait(assert, 1.672 + override( 1.673 + trait({ a: required, b: 2 }), 1.674 + trait({ a: 1, c: testMethod }) 1.675 + ), 1.676 + { 1.677 + a: Data(1), 1.678 + b: Data(2), 1.679 + c: Method(testMethod) 1.680 + } 1.681 + ); 1.682 +}; 1.683 + 1.684 +exports['test:override is not commutative'] = function (assert) { 1.685 + assertSametrait(assert, 1.686 + override( 1.687 + trait({ a: 1, b: 2 }), 1.688 + trait({ a: 3, c: 4 }) 1.689 + ), 1.690 + { 1.691 + a: Data(1), 1.692 + b: Data(2), 1.693 + c: Data(4) 1.694 + } 1.695 + ); 1.696 + 1.697 + assertSametrait(assert, 1.698 + override( 1.699 + trait({ a: 3, c: 4 }), 1.700 + trait({ a: 1, b: 2 }) 1.701 + ), 1.702 + { 1.703 + a: Data(3), 1.704 + b: Data(2), 1.705 + c: Data(4) 1.706 + } 1.707 + ); 1.708 +}; 1.709 + 1.710 +exports['test:override is associative'] = function (assert) { 1.711 + assertSametrait(assert, 1.712 + override( 1.713 + override( 1.714 + trait({ a: 1, b: 2 }), 1.715 + trait({ a: 3, c: 4, d: 5 }) 1.716 + ), 1.717 + trait({ a: 6, c: 7, e: 8 }) 1.718 + ), 1.719 + override( 1.720 + trait({ a: 1, b: 2 }), 1.721 + override( 1.722 + trait({ a: 3, c: 4, d: 5 }), 1.723 + trait({ a: 6, c: 7, e: 8 }) 1.724 + ) 1.725 + ) 1.726 + ); 1.727 +}; 1.728 + 1.729 +exports['test:create simple'] = function(assert) { 1.730 + let o1 = create( 1.731 + Object.prototype, 1.732 + trait({ a: 1, b: function() { return this.a; } }) 1.733 + ); 1.734 + 1.735 + assert.equal( 1.736 + Object.prototype, 1.737 + Object.getPrototypeOf(o1), 1.738 + 'o1 prototype' 1.739 + ); 1.740 + assert.equal(1, o1.a, 'o1.a'); 1.741 + assert.equal(1, o1.b(), 'o1.b()'); 1.742 + assert.equal( 1.743 + 2, 1.744 + Object.getOwnPropertyNames(o1).length, 1.745 + 'Object.keys(o1).length === 2' 1.746 + ); 1.747 +}; 1.748 + 1.749 +exports['test:create with Array.prototype'] = function(assert) { 1.750 + let o2 = create(Array.prototype, trait({})); 1.751 + assert.equal( 1.752 + Array.prototype, 1.753 + Object.getPrototypeOf(o2), 1.754 + "o2 prototype" 1.755 + ); 1.756 +}; 1.757 + 1.758 +exports['test:exception for incomplete required properties'] = 1.759 +function(assert) { 1.760 + try { 1.761 + create(Object.prototype, trait({ foo: required })); 1.762 + assert.fail('expected create to complain about missing required props'); 1.763 + } 1.764 + catch(e) { 1.765 + assert.equal( 1.766 + 'Error: Missing required property: foo', 1.767 + e.toString(), 1.768 + 'required prop error' 1.769 + ); 1.770 + } 1.771 +}; 1.772 + 1.773 +exports['test:exception for unresolved conflicts'] = function(assert) { 1.774 + try { 1.775 + create({}, compose(trait({ a: 0 }), trait({ a: 1 }))); 1.776 + assert.fail('expected create to complain about unresolved conflicts'); 1.777 + } 1.778 + catch(e) { 1.779 + assert.equal( 1.780 + 'Error: Remaining conflicting property: a', 1.781 + e.toString(), 1.782 + 'conflicting prop error' 1.783 + ); 1.784 + } 1.785 +}; 1.786 + 1.787 +exports['test:verify that required properties are present but undefined'] = 1.788 +function(assert) { 1.789 + try { 1.790 + let o4 = Object.create(Object.prototype, trait({ foo: required })); 1.791 + assert.equal(true, 'foo' in o4, 'required property present'); 1.792 + try { 1.793 + let foo = o4.foo; 1.794 + assert.fail('access to required property must throw'); 1.795 + } 1.796 + catch(e) { 1.797 + assert.equal( 1.798 + 'Error: Missing required property: foo', 1.799 + e.toString(), 1.800 + 'required prop error' 1.801 + ) 1.802 + } 1.803 + } 1.804 + catch(e) { 1.805 + assert.fail('did not expect create to complain about required props'); 1.806 + } 1.807 +}; 1.808 + 1.809 +exports['test:verify that conflicting properties are present'] = 1.810 +function(assert) { 1.811 + try { 1.812 + let o5 = Object.create( 1.813 + Object.prototype, 1.814 + compose(trait({ a: 0 }), trait({ a: 1 })) 1.815 + ); 1.816 + assert.equal(true, 'a' in o5, 'conflicting property present'); 1.817 + try { 1.818 + let a = o5.a; // accessors or data prop 1.819 + assert.fail('expected conflicting prop to cause exception'); 1.820 + } 1.821 + catch (e) { 1.822 + assert.equal( 1.823 + 'Error: Remaining conflicting property: a', 1.824 + e.toString(), 1.825 + 'conflicting prop access error' 1.826 + ); 1.827 + } 1.828 + } 1.829 + catch(e) { 1.830 + assert.fail('did not expect create to complain about conflicting props'); 1.831 + } 1.832 +}; 1.833 + 1.834 +exports['test diamond with conflicts'] = function(assert) { 1.835 + function makeT1(x) trait({ m: function() { return x; } }) 1.836 + function makeT2(x) compose(trait({ t2: 'foo' }), makeT1(x)) 1.837 + function makeT3(x) compose(trait({ t3: 'bar' }), makeT1(x)) 1.838 + 1.839 + let T4 = compose(makeT2(5), makeT3(5)); 1.840 + try { 1.841 + let o = create(Object.prototype, T4); 1.842 + assert.fail('expected diamond prop to cause exception'); 1.843 + } 1.844 + catch(e) { 1.845 + assert.equal( 1.846 + 'Error: Remaining conflicting property: m', 1.847 + e.toString(), 1.848 + 'diamond prop conflict' 1.849 + ); 1.850 + } 1.851 +}; 1.852 + 1.853 +require('sdk/test').run(exports);