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