addon-sdk/source/test/test-traits-core.js

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4 'use strict';
michael@0 5
michael@0 6 const ERR_CONFLICT = 'Remaining conflicting property: ',
michael@0 7 ERR_REQUIRED = 'Missing required property: ';
michael@0 8
michael@0 9 function assertSametrait(assert, trait1, trait2) {
michael@0 10 let names1 = Object.getOwnPropertyNames(trait1),
michael@0 11 names2 = Object.getOwnPropertyNames(trait2);
michael@0 12
michael@0 13 assert.equal(
michael@0 14 names1.length,
michael@0 15 names2.length,
michael@0 16 'equal traits must have same amount of properties'
michael@0 17 );
michael@0 18
michael@0 19 for (let i = 0; i < names1.length; i++) {
michael@0 20 let name = names1[i];
michael@0 21 assert.notEqual(
michael@0 22 -1,
michael@0 23 names2.indexOf(name),
michael@0 24 'equal traits must contain same named properties: ' + name
michael@0 25 );
michael@0 26 assertSameDescriptor(assert, name, trait1[name], trait2[name]);
michael@0 27 }
michael@0 28 }
michael@0 29
michael@0 30 function assertSameDescriptor(assert, name, desc1, desc2) {
michael@0 31 if (desc1.conflict || desc2.conflict) {
michael@0 32 assert.equal(
michael@0 33 desc1.conflict,
michael@0 34 desc2.conflict,
michael@0 35 'if one of same descriptors has `conflict` another must have it: '
michael@0 36 + name
michael@0 37 );
michael@0 38 }
michael@0 39 else if (desc1.required || desc2.required) {
michael@0 40 assert.equal(
michael@0 41 desc1.required,
michael@0 42 desc2.required,
michael@0 43 'if one of same descriptors is has `required` another must have it: '
michael@0 44 + name
michael@0 45 );
michael@0 46 }
michael@0 47 else {
michael@0 48 assert.equal(
michael@0 49 desc1.get,
michael@0 50 desc2.get,
michael@0 51 'get must be the same on both descriptors: ' + name
michael@0 52 );
michael@0 53 assert.equal(
michael@0 54 desc1.set,
michael@0 55 desc2.set,
michael@0 56 'set must be the same on both descriptors: ' + name
michael@0 57 );
michael@0 58 assert.equal(
michael@0 59 desc1.value,
michael@0 60 desc2.value,
michael@0 61 'value must be the same on both descriptors: ' + name
michael@0 62 );
michael@0 63 assert.equal(
michael@0 64 desc1.enumerable,
michael@0 65 desc2.enumerable,
michael@0 66 'enumerable must be the same on both descriptors: ' + name
michael@0 67 );
michael@0 68 assert.equal(
michael@0 69 desc1.required,
michael@0 70 desc2.required,
michael@0 71 'value must be the same on both descriptors: ' + name
michael@0 72 );
michael@0 73 }
michael@0 74 }
michael@0 75
michael@0 76 function Data(value, enumerable, confligurable, writable) {
michael@0 77 return {
michael@0 78 value: value,
michael@0 79 enumerable: false !== enumerable,
michael@0 80 confligurable: false !== confligurable,
michael@0 81 writable: false !== writable
michael@0 82 };
michael@0 83 }
michael@0 84
michael@0 85 function Method(method, enumerable, confligurable, writable) {
michael@0 86 return {
michael@0 87 value: method,
michael@0 88 enumerable: false !== enumerable,
michael@0 89 confligurable: false !== confligurable,
michael@0 90 writable: false !== writable
michael@0 91 };
michael@0 92 }
michael@0 93
michael@0 94 function Accessor(get, set, enumerable, confligurable) {
michael@0 95 return {
michael@0 96 get: get,
michael@0 97 set: set,
michael@0 98 enumerable: false !== enumerable,
michael@0 99 confligurable: false !== confligurable,
michael@0 100 };
michael@0 101 }
michael@0 102
michael@0 103 function Required(name) {
michael@0 104 function required() { throw new Error(ERR_REQUIRED + name) }
michael@0 105 return {
michael@0 106 get: required,
michael@0 107 set: required,
michael@0 108 required: true
michael@0 109 };
michael@0 110 }
michael@0 111
michael@0 112 function Conflict(name) {
michael@0 113 function conflict() { throw new Error(ERR_CONFLICT + name) }
michael@0 114 return {
michael@0 115 get: conflict,
michael@0 116 set: conflict,
michael@0 117 conflict: true
michael@0 118 };
michael@0 119 }
michael@0 120
michael@0 121 function testMethod() {};
michael@0 122
michael@0 123 const { trait, compose, resolve, required, override, create } =
michael@0 124 require('sdk/deprecated/traits/core');
michael@0 125
michael@0 126
michael@0 127 exports['test:empty trait'] = function(assert) {
michael@0 128 assertSametrait(
michael@0 129 assert,
michael@0 130 trait({}),
michael@0 131 {}
michael@0 132 );
michael@0 133 };
michael@0 134
michael@0 135 exports['test:simple trait'] = function(assert) {
michael@0 136 assertSametrait(
michael@0 137 assert,
michael@0 138 trait({
michael@0 139 a: 0,
michael@0 140 b: testMethod
michael@0 141 }),
michael@0 142 {
michael@0 143 a: Data(0, true, true, true),
michael@0 144 b: Method(testMethod, true, true, true)
michael@0 145 }
michael@0 146 );
michael@0 147 };
michael@0 148
michael@0 149 exports['test:simple trait with required prop'] = function(assert) {
michael@0 150 assertSametrait(
michael@0 151 assert,
michael@0 152 trait({
michael@0 153 a: required,
michael@0 154 b: 1
michael@0 155 }),
michael@0 156 {
michael@0 157 a: Required('a'),
michael@0 158 b: Data(1)
michael@0 159 }
michael@0 160 );
michael@0 161 };
michael@0 162
michael@0 163 exports['test:ordering of trait properties is irrelevant'] = function(assert) {
michael@0 164 assertSametrait(
michael@0 165 assert,
michael@0 166 trait({ a: 0, b: 1, c: required }),
michael@0 167 trait({ b: 1, c: required, a: 0 })
michael@0 168 );
michael@0 169 };
michael@0 170
michael@0 171 exports['test:trait with accessor property'] = function(assert) {
michael@0 172 let record = { get a() {}, set a(v) {} };
michael@0 173 let get = Object.getOwnPropertyDescriptor(record,'a').get;
michael@0 174 let set = Object.getOwnPropertyDescriptor(record,'a').set;
michael@0 175 assertSametrait(assert,
michael@0 176 trait(record),
michael@0 177 { a: Accessor(get, set ) }
michael@0 178 );
michael@0 179 };
michael@0 180
michael@0 181 exports['test:simple composition'] = function(assert) {
michael@0 182 assertSametrait(
michael@0 183 assert,
michael@0 184 compose(
michael@0 185 trait({ a: 0, b: 1 }),
michael@0 186 trait({ c: 2, d: testMethod })
michael@0 187 ),
michael@0 188 {
michael@0 189 a: Data(0),
michael@0 190 b: Data(1),
michael@0 191 c: Data(2),
michael@0 192 d: Method(testMethod)
michael@0 193 }
michael@0 194 );
michael@0 195 };
michael@0 196
michael@0 197 exports['test:composition with conflict'] = function(assert) {
michael@0 198 assertSametrait(
michael@0 199 assert,
michael@0 200 compose(
michael@0 201 trait({ a: 0, b: 1 }),
michael@0 202 trait({ a: 2, c: testMethod })
michael@0 203 ),
michael@0 204 {
michael@0 205 a: Conflict('a'),
michael@0 206 b: Data(1),
michael@0 207 c: Method(testMethod)
michael@0 208 }
michael@0 209 );
michael@0 210 };
michael@0 211
michael@0 212 exports['test:composition of identical props does not cause conflict'] =
michael@0 213 function(assert) {
michael@0 214 assertSametrait(assert,
michael@0 215 compose(
michael@0 216 trait({ a: 0, b: 1 }),
michael@0 217 trait({ a: 0, c: testMethod })
michael@0 218 ),
michael@0 219 {
michael@0 220 a: Data(0),
michael@0 221 b: Data(1),
michael@0 222 c: Method(testMethod) }
michael@0 223 )
michael@0 224 };
michael@0 225
michael@0 226 exports['test:composition with identical required props'] =
michael@0 227 function(assert) {
michael@0 228 assertSametrait(assert,
michael@0 229 compose(
michael@0 230 trait({ a: required, b: 1 }),
michael@0 231 trait({ a: required, c: testMethod })
michael@0 232 ),
michael@0 233 {
michael@0 234 a: Required(),
michael@0 235 b: Data(1),
michael@0 236 c: Method(testMethod)
michael@0 237 }
michael@0 238 );
michael@0 239 };
michael@0 240
michael@0 241 exports['test:composition satisfying a required prop'] = function (assert) {
michael@0 242 assertSametrait(assert,
michael@0 243 compose(
michael@0 244 trait({ a: required, b: 1 }),
michael@0 245 trait({ a: testMethod })
michael@0 246 ),
michael@0 247 {
michael@0 248 a: Method(testMethod),
michael@0 249 b: Data(1)
michael@0 250 }
michael@0 251 );
michael@0 252 };
michael@0 253
michael@0 254 exports['test:compose is neutral wrt conflicts'] = function (assert) {
michael@0 255 assertSametrait(assert,
michael@0 256 compose(
michael@0 257 compose(
michael@0 258 trait({ a: 1 }),
michael@0 259 trait({ a: 2 })
michael@0 260 ),
michael@0 261 trait({ b: 0 })
michael@0 262 ),
michael@0 263 {
michael@0 264 a: Conflict('a'),
michael@0 265 b: Data(0)
michael@0 266 }
michael@0 267 );
michael@0 268 };
michael@0 269
michael@0 270 exports['test:conflicting prop overrides required prop'] = function (assert) {
michael@0 271 assertSametrait(assert,
michael@0 272 compose(
michael@0 273 compose(
michael@0 274 trait({ a: 1 }),
michael@0 275 trait({ a: 2 })
michael@0 276 ),
michael@0 277 trait({ a: required })
michael@0 278 ),
michael@0 279 {
michael@0 280 a: Conflict('a')
michael@0 281 }
michael@0 282 );
michael@0 283 };
michael@0 284
michael@0 285 exports['test:compose is commutative'] = function (assert) {
michael@0 286 assertSametrait(assert,
michael@0 287 compose(
michael@0 288 trait({ a: 0, b: 1 }),
michael@0 289 trait({ c: 2, d: testMethod })
michael@0 290 ),
michael@0 291 compose(
michael@0 292 trait({ c: 2, d: testMethod }),
michael@0 293 trait({ a: 0, b: 1 })
michael@0 294 )
michael@0 295 );
michael@0 296 };
michael@0 297
michael@0 298 exports['test:compose is commutative, also for required/conflicting props'] =
michael@0 299 function (assert) {
michael@0 300 assertSametrait(assert,
michael@0 301 compose(
michael@0 302 trait({ a: 0, b: 1, c: 3, e: required }),
michael@0 303 trait({ c: 2, d: testMethod })
michael@0 304 ),
michael@0 305 compose(
michael@0 306 trait({ c: 2, d: testMethod }),
michael@0 307 trait({ a: 0, b: 1, c: 3, e: required })
michael@0 308 )
michael@0 309 );
michael@0 310 };
michael@0 311 exports['test:compose is associative'] = function (assert) {
michael@0 312 assertSametrait(assert,
michael@0 313 compose(
michael@0 314 trait({ a: 0, b: 1, c: 3, d: required }),
michael@0 315 compose(
michael@0 316 trait({ c: 3, d: required }),
michael@0 317 trait({ c: 2, d: testMethod, e: 'foo' })
michael@0 318 )
michael@0 319 ),
michael@0 320 compose(
michael@0 321 compose(
michael@0 322 trait({ a: 0, b: 1, c: 3, d: required }),
michael@0 323 trait({ c: 3, d: required })
michael@0 324 ),
michael@0 325 trait({ c: 2, d: testMethod, e: 'foo' })
michael@0 326 )
michael@0 327 );
michael@0 328 };
michael@0 329
michael@0 330 exports['test:diamond import of same prop does not generate conflict'] =
michael@0 331 function (assert) {
michael@0 332 assertSametrait(assert,
michael@0 333 compose(
michael@0 334 compose(
michael@0 335 trait({ b: 2 }),
michael@0 336 trait({ a: 1 })
michael@0 337 ),
michael@0 338 compose(
michael@0 339 trait({ c: 3 }),
michael@0 340 trait({ a: 1 })
michael@0 341 ),
michael@0 342 trait({ d: 4 })
michael@0 343 ),
michael@0 344 {
michael@0 345 a: Data(1),
michael@0 346 b: Data(2),
michael@0 347 c: Data(3),
michael@0 348 d: Data(4)
michael@0 349 }
michael@0 350 );
michael@0 351 };
michael@0 352
michael@0 353 exports['test:resolve with empty resolutions has no effect'] =
michael@0 354 function (assert) {
michael@0 355 assertSametrait(assert, resolve({}, trait({
michael@0 356 a: 1,
michael@0 357 b: required,
michael@0 358 c: testMethod
michael@0 359 })), {
michael@0 360 a: Data(1),
michael@0 361 b: Required(),
michael@0 362 c: Method(testMethod)
michael@0 363 });
michael@0 364 };
michael@0 365
michael@0 366 exports['test:resolve: renaming'] = function (assert) {
michael@0 367 assertSametrait(assert,
michael@0 368 resolve(
michael@0 369 { a: 'A', c: 'C' },
michael@0 370 trait({ a: 1, b: required, c: testMethod })
michael@0 371 ),
michael@0 372 {
michael@0 373 A: Data(1),
michael@0 374 b: Required(),
michael@0 375 C: Method(testMethod),
michael@0 376 a: Required(),
michael@0 377 c: Required()
michael@0 378 }
michael@0 379 );
michael@0 380 };
michael@0 381
michael@0 382 exports['test:resolve: renaming to conflicting name causes conflict, order 1']
michael@0 383 = function (assert) {
michael@0 384 assertSametrait(assert,
michael@0 385 resolve(
michael@0 386 { a: 'b'},
michael@0 387 trait({ a: 1, b: 2 })
michael@0 388 ),
michael@0 389 {
michael@0 390 b: Conflict('b'),
michael@0 391 a: Required()
michael@0 392 }
michael@0 393 );
michael@0 394 };
michael@0 395
michael@0 396 exports['test:resolve: renaming to conflicting name causes conflict, order 2']
michael@0 397 = function (assert) {
michael@0 398 assertSametrait(assert,
michael@0 399 resolve(
michael@0 400 { a: 'b' },
michael@0 401 trait({ b: 2, a: 1 })
michael@0 402 ),
michael@0 403 {
michael@0 404 b: Conflict('b'),
michael@0 405 a: Required()
michael@0 406 }
michael@0 407 );
michael@0 408 };
michael@0 409
michael@0 410 exports['test:resolve: simple exclusion'] = function (assert) {
michael@0 411 assertSametrait(assert,
michael@0 412 resolve(
michael@0 413 { a: undefined },
michael@0 414 trait({ a: 1, b: 2 })
michael@0 415 ),
michael@0 416 {
michael@0 417 a: Required(),
michael@0 418 b: Data(2)
michael@0 419 }
michael@0 420 );
michael@0 421 };
michael@0 422
michael@0 423 exports['test:resolve: exclusion to "empty" trait'] = function (assert) {
michael@0 424 assertSametrait(assert,
michael@0 425 resolve(
michael@0 426 { a: undefined, b: undefined },
michael@0 427 trait({ a: 1, b: 2 })
michael@0 428 ),
michael@0 429 {
michael@0 430 a: Required(),
michael@0 431 b: Required()
michael@0 432 }
michael@0 433 );
michael@0 434 };
michael@0 435
michael@0 436 exports['test:resolve: exclusion and renaming of disjoint props'] =
michael@0 437 function (assert) {
michael@0 438 assertSametrait(assert,
michael@0 439 resolve(
michael@0 440 { a: undefined, b: 'c' },
michael@0 441 trait({ a: 1, b: 2 })
michael@0 442 ),
michael@0 443 {
michael@0 444 a: Required(),
michael@0 445 c: Data(2),
michael@0 446 b: Required()
michael@0 447 }
michael@0 448 );
michael@0 449 };
michael@0 450
michael@0 451 exports['test:resolve: exclusion and renaming of overlapping props'] =
michael@0 452 function (assert) {
michael@0 453 assertSametrait(assert,
michael@0 454 resolve(
michael@0 455 { a: undefined, b: 'a' },
michael@0 456 trait({ a: 1, b: 2 })
michael@0 457 ),
michael@0 458 {
michael@0 459 a: Data(2),
michael@0 460 b: Required()
michael@0 461 }
michael@0 462 );
michael@0 463 };
michael@0 464
michael@0 465 exports['test:resolve: renaming to a common alias causes conflict'] =
michael@0 466 function (assert) {
michael@0 467 assertSametrait(assert,
michael@0 468 resolve(
michael@0 469 { a: 'c', b: 'c' },
michael@0 470 trait({ a: 1, b: 2 })
michael@0 471 ),
michael@0 472 {
michael@0 473 c: Conflict('c'),
michael@0 474 a: Required(),
michael@0 475 b: Required()
michael@0 476 }
michael@0 477 );
michael@0 478 };
michael@0 479
michael@0 480 exports['test:resolve: renaming overrides required target'] =
michael@0 481 function (assert) {
michael@0 482 assertSametrait(assert,
michael@0 483 resolve(
michael@0 484 { b: 'a' },
michael@0 485 trait({ a: required, b: 2 })
michael@0 486 ),
michael@0 487 {
michael@0 488 a: Data(2),
michael@0 489 b: Required()
michael@0 490 }
michael@0 491 );
michael@0 492 };
michael@0 493
michael@0 494 exports['test:resolve: renaming required properties has no effect'] =
michael@0 495 function (assert) {
michael@0 496 assertSametrait(assert,
michael@0 497 resolve(
michael@0 498 { b: 'a' },
michael@0 499 trait({ a: 2, b: required })
michael@0 500 ),
michael@0 501 {
michael@0 502 a: Data(2),
michael@0 503 b: Required()
michael@0 504 }
michael@0 505 );
michael@0 506 };
michael@0 507
michael@0 508 exports['test:resolve: renaming of non-existent props has no effect'] =
michael@0 509 function (assert) {
michael@0 510 assertSametrait(assert,
michael@0 511 resolve(
michael@0 512 { a: 'c', d: 'c' },
michael@0 513 trait({ a: 1, b: 2 })
michael@0 514 ),
michael@0 515 {
michael@0 516 c: Data(1),
michael@0 517 b: Data(2),
michael@0 518 a: Required()
michael@0 519 }
michael@0 520 );
michael@0 521 };
michael@0 522
michael@0 523 exports['test:resolve: exclusion of non-existent props has no effect'] =
michael@0 524 function (assert) {
michael@0 525 assertSametrait(assert,
michael@0 526 resolve(
michael@0 527 { b: undefined },
michael@0 528 trait({ a: 1 })
michael@0 529 ),
michael@0 530 {
michael@0 531 a: Data(1)
michael@0 532 }
michael@0 533 );
michael@0 534 };
michael@0 535
michael@0 536 exports['test:resolve is neutral w.r.t. required properties'] =
michael@0 537 function (assert) {
michael@0 538 assertSametrait(assert,
michael@0 539 resolve(
michael@0 540 { a: 'c', b: undefined },
michael@0 541 trait({ a: required, b: required, c: 'foo', d: 1 })
michael@0 542 ),
michael@0 543 {
michael@0 544 a: Required(),
michael@0 545 b: Required(),
michael@0 546 c: Data('foo'),
michael@0 547 d: Data(1)
michael@0 548 }
michael@0 549 );
michael@0 550 };
michael@0 551
michael@0 552 exports['test:resolve supports swapping of property names, ordering 1'] =
michael@0 553 function (assert) {
michael@0 554 assertSametrait(assert,
michael@0 555 resolve(
michael@0 556 { a: 'b', b: 'a' },
michael@0 557 trait({ a: 1, b: 2 })
michael@0 558 ),
michael@0 559 {
michael@0 560 a: Data(2),
michael@0 561 b: Data(1)
michael@0 562 }
michael@0 563 );
michael@0 564 };
michael@0 565
michael@0 566 exports['test:resolve supports swapping of property names, ordering 2'] =
michael@0 567 function (assert) {
michael@0 568 assertSametrait(assert,
michael@0 569 resolve(
michael@0 570 { b: 'a', a: 'b' },
michael@0 571 trait({ a: 1, b: 2 })
michael@0 572 ),
michael@0 573 {
michael@0 574 a: Data(2),
michael@0 575 b: Data(1)
michael@0 576 }
michael@0 577 );
michael@0 578 };
michael@0 579
michael@0 580 exports['test:resolve supports swapping of property names, ordering 3'] =
michael@0 581 function (assert) {
michael@0 582 assertSametrait(assert,
michael@0 583 resolve(
michael@0 584 { b: 'a', a: 'b' },
michael@0 585 trait({ b: 2, a: 1 })
michael@0 586 ),
michael@0 587 {
michael@0 588 a: Data(2),
michael@0 589 b: Data(1)
michael@0 590 }
michael@0 591 );
michael@0 592 };
michael@0 593
michael@0 594 exports['test:resolve supports swapping of property names, ordering 4'] =
michael@0 595 function (assert) {
michael@0 596 assertSametrait(assert,
michael@0 597 resolve(
michael@0 598 { a: 'b', b: 'a' },
michael@0 599 trait({ b: 2, a: 1 })
michael@0 600 ),
michael@0 601 {
michael@0 602 a: Data(2),
michael@0 603 b: Data(1)
michael@0 604 }
michael@0 605 );
michael@0 606 };
michael@0 607
michael@0 608 exports['test:override of mutually exclusive traits'] = function (assert) {
michael@0 609 assertSametrait(assert,
michael@0 610 override(
michael@0 611 trait({ a: 1, b: 2 }),
michael@0 612 trait({ c: 3, d: testMethod })
michael@0 613 ),
michael@0 614 {
michael@0 615 a: Data(1),
michael@0 616 b: Data(2),
michael@0 617 c: Data(3),
michael@0 618 d: Method(testMethod)
michael@0 619 }
michael@0 620 );
michael@0 621 };
michael@0 622
michael@0 623 exports['test:override of mutually exclusive traits is compose'] =
michael@0 624 function (assert) {
michael@0 625 assertSametrait(assert,
michael@0 626 override(
michael@0 627 trait({ a: 1, b: 2 }),
michael@0 628 trait({ c: 3, d: testMethod })
michael@0 629 ),
michael@0 630 compose(
michael@0 631 trait({ d: testMethod, c: 3 }),
michael@0 632 trait({ b: 2, a: 1 })
michael@0 633 )
michael@0 634 );
michael@0 635 };
michael@0 636
michael@0 637 exports['test:override of overlapping traits'] = function (assert) {
michael@0 638 assertSametrait(assert,
michael@0 639 override(
michael@0 640 trait({ a: 1, b: 2 }),
michael@0 641 trait({ a: 3, c: testMethod })
michael@0 642 ),
michael@0 643 {
michael@0 644 a: Data(1),
michael@0 645 b: Data(2),
michael@0 646 c: Method(testMethod)
michael@0 647 }
michael@0 648 );
michael@0 649 };
michael@0 650
michael@0 651 exports['test:three-way override of overlapping traits'] = function (assert) {
michael@0 652 assertSametrait(assert,
michael@0 653 override(
michael@0 654 trait({ a: 1, b: 2 }),
michael@0 655 trait({ b: 4, c: 3 }),
michael@0 656 trait({ a: 3, c: testMethod, d: 5 })
michael@0 657 ),
michael@0 658 {
michael@0 659 a: Data(1),
michael@0 660 b: Data(2),
michael@0 661 c: Data(3),
michael@0 662 d: Data(5)
michael@0 663 }
michael@0 664 );
michael@0 665 };
michael@0 666
michael@0 667 exports['test:override replaces required properties'] = function (assert) {
michael@0 668 assertSametrait(assert,
michael@0 669 override(
michael@0 670 trait({ a: required, b: 2 }),
michael@0 671 trait({ a: 1, c: testMethod })
michael@0 672 ),
michael@0 673 {
michael@0 674 a: Data(1),
michael@0 675 b: Data(2),
michael@0 676 c: Method(testMethod)
michael@0 677 }
michael@0 678 );
michael@0 679 };
michael@0 680
michael@0 681 exports['test:override is not commutative'] = function (assert) {
michael@0 682 assertSametrait(assert,
michael@0 683 override(
michael@0 684 trait({ a: 1, b: 2 }),
michael@0 685 trait({ a: 3, c: 4 })
michael@0 686 ),
michael@0 687 {
michael@0 688 a: Data(1),
michael@0 689 b: Data(2),
michael@0 690 c: Data(4)
michael@0 691 }
michael@0 692 );
michael@0 693
michael@0 694 assertSametrait(assert,
michael@0 695 override(
michael@0 696 trait({ a: 3, c: 4 }),
michael@0 697 trait({ a: 1, b: 2 })
michael@0 698 ),
michael@0 699 {
michael@0 700 a: Data(3),
michael@0 701 b: Data(2),
michael@0 702 c: Data(4)
michael@0 703 }
michael@0 704 );
michael@0 705 };
michael@0 706
michael@0 707 exports['test:override is associative'] = function (assert) {
michael@0 708 assertSametrait(assert,
michael@0 709 override(
michael@0 710 override(
michael@0 711 trait({ a: 1, b: 2 }),
michael@0 712 trait({ a: 3, c: 4, d: 5 })
michael@0 713 ),
michael@0 714 trait({ a: 6, c: 7, e: 8 })
michael@0 715 ),
michael@0 716 override(
michael@0 717 trait({ a: 1, b: 2 }),
michael@0 718 override(
michael@0 719 trait({ a: 3, c: 4, d: 5 }),
michael@0 720 trait({ a: 6, c: 7, e: 8 })
michael@0 721 )
michael@0 722 )
michael@0 723 );
michael@0 724 };
michael@0 725
michael@0 726 exports['test:create simple'] = function(assert) {
michael@0 727 let o1 = create(
michael@0 728 Object.prototype,
michael@0 729 trait({ a: 1, b: function() { return this.a; } })
michael@0 730 );
michael@0 731
michael@0 732 assert.equal(
michael@0 733 Object.prototype,
michael@0 734 Object.getPrototypeOf(o1),
michael@0 735 'o1 prototype'
michael@0 736 );
michael@0 737 assert.equal(1, o1.a, 'o1.a');
michael@0 738 assert.equal(1, o1.b(), 'o1.b()');
michael@0 739 assert.equal(
michael@0 740 2,
michael@0 741 Object.getOwnPropertyNames(o1).length,
michael@0 742 'Object.keys(o1).length === 2'
michael@0 743 );
michael@0 744 };
michael@0 745
michael@0 746 exports['test:create with Array.prototype'] = function(assert) {
michael@0 747 let o2 = create(Array.prototype, trait({}));
michael@0 748 assert.equal(
michael@0 749 Array.prototype,
michael@0 750 Object.getPrototypeOf(o2),
michael@0 751 "o2 prototype"
michael@0 752 );
michael@0 753 };
michael@0 754
michael@0 755 exports['test:exception for incomplete required properties'] =
michael@0 756 function(assert) {
michael@0 757 try {
michael@0 758 create(Object.prototype, trait({ foo: required }));
michael@0 759 assert.fail('expected create to complain about missing required props');
michael@0 760 }
michael@0 761 catch(e) {
michael@0 762 assert.equal(
michael@0 763 'Error: Missing required property: foo',
michael@0 764 e.toString(),
michael@0 765 'required prop error'
michael@0 766 );
michael@0 767 }
michael@0 768 };
michael@0 769
michael@0 770 exports['test:exception for unresolved conflicts'] = function(assert) {
michael@0 771 try {
michael@0 772 create({}, compose(trait({ a: 0 }), trait({ a: 1 })));
michael@0 773 assert.fail('expected create to complain about unresolved conflicts');
michael@0 774 }
michael@0 775 catch(e) {
michael@0 776 assert.equal(
michael@0 777 'Error: Remaining conflicting property: a',
michael@0 778 e.toString(),
michael@0 779 'conflicting prop error'
michael@0 780 );
michael@0 781 }
michael@0 782 };
michael@0 783
michael@0 784 exports['test:verify that required properties are present but undefined'] =
michael@0 785 function(assert) {
michael@0 786 try {
michael@0 787 let o4 = Object.create(Object.prototype, trait({ foo: required }));
michael@0 788 assert.equal(true, 'foo' in o4, 'required property present');
michael@0 789 try {
michael@0 790 let foo = o4.foo;
michael@0 791 assert.fail('access to required property must throw');
michael@0 792 }
michael@0 793 catch(e) {
michael@0 794 assert.equal(
michael@0 795 'Error: Missing required property: foo',
michael@0 796 e.toString(),
michael@0 797 'required prop error'
michael@0 798 )
michael@0 799 }
michael@0 800 }
michael@0 801 catch(e) {
michael@0 802 assert.fail('did not expect create to complain about required props');
michael@0 803 }
michael@0 804 };
michael@0 805
michael@0 806 exports['test:verify that conflicting properties are present'] =
michael@0 807 function(assert) {
michael@0 808 try {
michael@0 809 let o5 = Object.create(
michael@0 810 Object.prototype,
michael@0 811 compose(trait({ a: 0 }), trait({ a: 1 }))
michael@0 812 );
michael@0 813 assert.equal(true, 'a' in o5, 'conflicting property present');
michael@0 814 try {
michael@0 815 let a = o5.a; // accessors or data prop
michael@0 816 assert.fail('expected conflicting prop to cause exception');
michael@0 817 }
michael@0 818 catch (e) {
michael@0 819 assert.equal(
michael@0 820 'Error: Remaining conflicting property: a',
michael@0 821 e.toString(),
michael@0 822 'conflicting prop access error'
michael@0 823 );
michael@0 824 }
michael@0 825 }
michael@0 826 catch(e) {
michael@0 827 assert.fail('did not expect create to complain about conflicting props');
michael@0 828 }
michael@0 829 };
michael@0 830
michael@0 831 exports['test diamond with conflicts'] = function(assert) {
michael@0 832 function makeT1(x) trait({ m: function() { return x; } })
michael@0 833 function makeT2(x) compose(trait({ t2: 'foo' }), makeT1(x))
michael@0 834 function makeT3(x) compose(trait({ t3: 'bar' }), makeT1(x))
michael@0 835
michael@0 836 let T4 = compose(makeT2(5), makeT3(5));
michael@0 837 try {
michael@0 838 let o = create(Object.prototype, T4);
michael@0 839 assert.fail('expected diamond prop to cause exception');
michael@0 840 }
michael@0 841 catch(e) {
michael@0 842 assert.equal(
michael@0 843 'Error: Remaining conflicting property: m',
michael@0 844 e.toString(),
michael@0 845 'diamond prop conflict'
michael@0 846 );
michael@0 847 }
michael@0 848 };
michael@0 849
michael@0 850 require('sdk/test').run(exports);

mercurial