OLD | NEW |
| (Empty) |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 library mixin_test; | |
6 | |
7 import 'package:unittest/unittest.dart'; | |
8 import 'testing.dart'; | |
9 | |
10 final options = ['--warnings_as_errors', '--no-colors', 'memory']; | |
11 | |
12 compileAndValidate(String input, String generated) { | |
13 var errors = []; | |
14 var stylesheet = compileCss(input, errors: errors, opts: options); | |
15 expect(stylesheet != null, true); | |
16 expect(errors.isEmpty, true, reason: errors.toString()); | |
17 expect(prettyPrint(stylesheet), generated); | |
18 } | |
19 | |
20 compilePolyfillAndValidate(String input, String generated) { | |
21 var errors = []; | |
22 var stylesheet = polyFillCompileCss(input, errors: errors, opts: options); | |
23 expect(stylesheet != null, true); | |
24 expect(errors.isEmpty, true, reason: errors.toString()); | |
25 expect(prettyPrint(stylesheet), generated); | |
26 } | |
27 | |
28 void topLevelMixin() { | |
29 compileAndValidate(r''' | |
30 @mixin silly-links { | |
31 a { | |
32 color: blue; | |
33 background-color: red; | |
34 } | |
35 } | |
36 | |
37 @include silly-links; | |
38 ''', r'''a { | |
39 color: #00f; | |
40 background-color: #f00; | |
41 }'''); | |
42 } | |
43 | |
44 void topLevelMixinTwoIncludes() { | |
45 compileAndValidate(r''' | |
46 @mixin a { | |
47 a { | |
48 color: blue; | |
49 background-color: red; | |
50 } | |
51 } | |
52 @mixin b { | |
53 span { | |
54 color: black; | |
55 background-color: orange; | |
56 } | |
57 } | |
58 @include a; | |
59 @include b; | |
60 ''', r'''a { | |
61 color: #00f; | |
62 background-color: #f00; | |
63 } | |
64 span { | |
65 color: #000; | |
66 background-color: #ffa500; | |
67 }'''); | |
68 } | |
69 | |
70 /** Tests top-level mixins that includes another mixin. */ | |
71 void topLevelMixinMultiRulesets() { | |
72 compileAndValidate(r''' | |
73 @mixin a { | |
74 a { | |
75 color: blue; | |
76 background-color: red; | |
77 } | |
78 } | |
79 @mixin b { | |
80 #foo-id { | |
81 border-top: 1px solid red; | |
82 border-bottom: 2px solid green; | |
83 } | |
84 } | |
85 @mixin c { | |
86 span { | |
87 color: black; | |
88 background-color: orange; | |
89 } | |
90 @include b; | |
91 } | |
92 @include a; | |
93 @include c; | |
94 ''', r'''a { | |
95 color: #00f; | |
96 background-color: #f00; | |
97 } | |
98 span { | |
99 color: #000; | |
100 background-color: #ffa500; | |
101 } | |
102 #foo-id { | |
103 border-top: 1px solid #f00; | |
104 border-bottom: 2px solid #008000; | |
105 }'''); | |
106 } | |
107 | |
108 void topLevelMixinDeeplyNestedRulesets() { | |
109 compileAndValidate(r''' | |
110 @mixin a { | |
111 a { | |
112 color: blue; | |
113 background-color: red; | |
114 } | |
115 } | |
116 @mixin b { | |
117 #foo-id { | |
118 border-top: 1px solid red; | |
119 border-bottom: 2px solid green; | |
120 } | |
121 } | |
122 @mixin f { | |
123 #split-bar div { | |
124 border: 1px solid lightgray; | |
125 } | |
126 } | |
127 @mixin e { | |
128 #split-bar:visited { | |
129 color: gray; | |
130 } | |
131 @include f; | |
132 } | |
133 @mixin d { | |
134 a:hover { | |
135 cursor: arrow; | |
136 } | |
137 @include e | |
138 } | |
139 @mixin c { | |
140 @include a; | |
141 span { | |
142 color: black; | |
143 background-color: orange; | |
144 } | |
145 @include b; | |
146 @include d; | |
147 } | |
148 @include c; | |
149 ''', r'''a { | |
150 color: #00f; | |
151 background-color: #f00; | |
152 } | |
153 span { | |
154 color: #000; | |
155 background-color: #ffa500; | |
156 } | |
157 #foo-id { | |
158 border-top: 1px solid #f00; | |
159 border-bottom: 2px solid #008000; | |
160 } | |
161 a:hover { | |
162 cursor: arrow; | |
163 } | |
164 #split-bar:visited { | |
165 color: #808080; | |
166 } | |
167 #split-bar div { | |
168 border: 1px solid #d3d3d3; | |
169 }'''); | |
170 } | |
171 | |
172 /** Tests selector groups and other combinators. */ | |
173 void topLevelMixinSelectors() { | |
174 compileAndValidate(r''' | |
175 @mixin a { | |
176 a, b { | |
177 color: blue; | |
178 background-color: red; | |
179 } | |
180 div > span { | |
181 color: black; | |
182 background-color: orange; | |
183 } | |
184 } | |
185 | |
186 @include a; | |
187 ''', r'''a, b { | |
188 color: #00f; | |
189 background-color: #f00; | |
190 } | |
191 div > span { | |
192 color: #000; | |
193 background-color: #ffa500; | |
194 }'''); | |
195 } | |
196 | |
197 void declSimpleMixin() { | |
198 compileAndValidate(r''' | |
199 @mixin div-border { | |
200 border: 2px dashed red; | |
201 } | |
202 div { | |
203 @include div-border; | |
204 } | |
205 ''', r'''div { | |
206 border: 2px dashed #f00; | |
207 }'''); | |
208 } | |
209 | |
210 void declMixinTwoIncludes() { | |
211 compileAndValidate(r''' | |
212 @mixin div-border { | |
213 border: 2px dashed red; | |
214 } | |
215 @mixin div-color { | |
216 color: blue; | |
217 } | |
218 div { | |
219 @include div-border; | |
220 @include div-color; | |
221 } | |
222 ''', r'''div { | |
223 border: 2px dashed #f00; | |
224 color: #00f; | |
225 }'''); | |
226 } | |
227 | |
228 void declMixinNestedIncludes() { | |
229 compileAndValidate(r''' | |
230 @mixin div-border { | |
231 border: 2px dashed red; | |
232 } | |
233 @mixin div-padding { | |
234 padding: .5em; | |
235 } | |
236 @mixin div-margin { | |
237 margin: 5px; | |
238 } | |
239 @mixin div-color { | |
240 @include div-padding; | |
241 color: blue; | |
242 @include div-margin; | |
243 } | |
244 div { | |
245 @include div-border; | |
246 @include div-color; | |
247 } | |
248 ''', r'''div { | |
249 border: 2px dashed #f00; | |
250 padding: .5em; | |
251 color: #00f; | |
252 margin: 5px; | |
253 }'''); | |
254 } | |
255 | |
256 void declMixinDeeperNestedIncludes() { | |
257 compileAndValidate(r''' | |
258 @mixin div-border { | |
259 border: 2px dashed red; | |
260 } | |
261 @mixin div-padding { | |
262 padding: .5em; | |
263 } | |
264 @mixin div-margin { | |
265 margin: 5px; | |
266 } | |
267 @mixin div-color { | |
268 @include div-padding; | |
269 @include div-margin; | |
270 } | |
271 div { | |
272 @include div-border; | |
273 @include div-color; | |
274 } | |
275 ''', r'''div { | |
276 border: 2px dashed #f00; | |
277 padding: .5em; | |
278 margin: 5px; | |
279 }'''); | |
280 } | |
281 | |
282 void mixinArg() { | |
283 compileAndValidate(r''' | |
284 @mixin div-border-1 { | |
285 border: 2px dashed red; | |
286 } | |
287 @mixin div-border-2() { | |
288 border: 22px solid blue; | |
289 } | |
290 @mixin div-left(@dist) { | |
291 margin-left: @dist; | |
292 } | |
293 @mixin div-right(var-margin) { | |
294 margin-right: var(margin); | |
295 } | |
296 div-1 { | |
297 @include div-left(10px); | |
298 @include div-right(100px); | |
299 @include div-border-1; | |
300 } | |
301 div-2 { | |
302 @include div-left(20em); | |
303 @include div-right(5in); | |
304 @include div-border-2(); | |
305 } | |
306 div-3 { | |
307 @include div-border-1(); | |
308 } | |
309 div-4 { | |
310 @include div-border-2; | |
311 } | |
312 ''', r'''div-1 { | |
313 margin-left: 10px; | |
314 margin-right: 100px; | |
315 border: 2px dashed #f00; | |
316 } | |
317 div-2 { | |
318 margin-left: 20em; | |
319 margin-right: 5in; | |
320 border: 22px solid #00f; | |
321 } | |
322 div-3 { | |
323 border: 2px dashed #f00; | |
324 } | |
325 div-4 { | |
326 border: 22px solid #00f; | |
327 }'''); | |
328 } | |
329 | |
330 void mixinArgs() { | |
331 compileAndValidate(r''' | |
332 @mixin box-shadow(@shadows...) { | |
333 -moz-box-shadow: @shadows; | |
334 -webkit-box-shadow: @shadows; | |
335 box-shadow: var(shadows); | |
336 } | |
337 | |
338 .shadows { | |
339 @include box-shadow(0px 4px 5px #666, 2px 6px 10px #999); | |
340 }''', r''' | |
341 .shadowed { | |
342 -moz-box-shadow: 0px 4px 5px #666, 2px 6px 10px #999; | |
343 -webkit-box-shadow: 0px 4px 5px #666, 2px 6px 10px #999; | |
344 box-shadow: 0px 4px 5px #666, 2px 6px 10px #999; | |
345 } | |
346 '''); | |
347 } | |
348 | |
349 void mixinManyArgs() { | |
350 compileAndValidate(r''' | |
351 @mixin border(@border-values) { | |
352 border: @border-values | |
353 } | |
354 | |
355 .primary { | |
356 @include border(3px solid green); | |
357 } | |
358 ''', r''' | |
359 .primary { | |
360 border: 3px solid #008000; | |
361 }'''); | |
362 | |
363 compileAndValidate(r''' | |
364 @mixin setup(@border-color, @border-style, @border-size, @color) { | |
365 border: @border-size @border-style @border-color; | |
366 color: @color; | |
367 } | |
368 | |
369 .primary { | |
370 @include setup(red, solid, 5px, blue); | |
371 } | |
372 ''', r''' | |
373 .primary { | |
374 border: 5px solid #f00; | |
375 color: #00f; | |
376 }'''); | |
377 | |
378 // Test passing a declaration that is multiple parameters. | |
379 compileAndValidate(r''' | |
380 @mixin colors(@text, @background, @border) { | |
381 color: @text; | |
382 background-color: @background; | |
383 border-color: @border; | |
384 } | |
385 | |
386 @values: #ff0000, #00ff00, #0000ff; | |
387 .primary { | |
388 @include colors(@values); | |
389 } | |
390 ''', r'''var-values: #f00, #0f0, #00f; | |
391 | |
392 .primary { | |
393 color: #f00; | |
394 background-color: #0f0; | |
395 border-color: #00f; | |
396 }'''); | |
397 | |
398 compilePolyfillAndValidate(r''' | |
399 @mixin colors(@text, @background, @border) { | |
400 color: @text; | |
401 background-color: @background; | |
402 border-color: @border; | |
403 } | |
404 | |
405 @values: #ff0000, #00ff00, #0000ff; | |
406 .primary { | |
407 @include colors(@values); | |
408 } | |
409 ''', r'''.primary { | |
410 color: #f00; | |
411 background-color: #0f0; | |
412 border-color: #00f; | |
413 }'''); | |
414 } | |
415 | |
416 void badDeclarationInclude() { | |
417 final errors = []; | |
418 final input = r''' | |
419 @mixin a { | |
420 #foo-id { | |
421 color: red; | |
422 } | |
423 } | |
424 @mixin b { | |
425 span { | |
426 border: 2px dashed red; | |
427 @include a; | |
428 } | |
429 } | |
430 @include b; | |
431 '''; | |
432 | |
433 var stylesheet = compileCss(input, errors: errors, opts: options); | |
434 | |
435 expect(stylesheet != null, true); | |
436 expect(errors.isNotEmpty, true); | |
437 expect(errors.length, 1, reason: errors.toString()); | |
438 var error = errors[0]; | |
439 expect(error.message, 'Using top-level mixin a as a declaration'); | |
440 expect(error.span.start.line, 8); | |
441 expect(error.span.end.offset, 105); | |
442 } | |
443 | |
444 void badTopInclude() { | |
445 final errors = []; | |
446 final input = r''' | |
447 @mixin b { | |
448 color: red; | |
449 } | |
450 | |
451 @mixin a { | |
452 span { | |
453 border: 2px dashed red; | |
454 } | |
455 @include b; | |
456 } | |
457 | |
458 @include a; | |
459 '''; | |
460 | |
461 var generated = r'''span { | |
462 border: 2px dashed #f00; | |
463 }'''; | |
464 | |
465 var stylesheet = compileCss(input, errors: errors, opts: options); | |
466 expect(stylesheet != null, true); | |
467 expect(errors.length, 1, reason: errors.toString()); | |
468 var error = errors[0]; | |
469 expect(error.message, 'Using declaration mixin b as top-level mixin'); | |
470 expect(error.span.start.line, 8); | |
471 expect(error.span.end.offset, 90); | |
472 } | |
473 | |
474 void emptyMixin() { | |
475 final errors = []; | |
476 final input = r''' | |
477 @mixin a { | |
478 } | |
479 @mixin b { | |
480 border: 2px dashed red; | |
481 @include a; | |
482 } | |
483 div { | |
484 @include b; | |
485 } | |
486 '''; | |
487 | |
488 var generated = r'''div { | |
489 border: 2px dashed #f00; | |
490 }'''; | |
491 | |
492 var stylesheet = compileCss(input, errors: errors, opts: options); | |
493 | |
494 expect(stylesheet != null, true); | |
495 expect(errors.isEmpty, true, reason: errors.toString()); | |
496 expect(prettyPrint(stylesheet), generated); | |
497 } | |
498 | |
499 | |
500 void undefinedTopLevel() { | |
501 final errors = []; | |
502 final input = r''' | |
503 @mixin a { | |
504 @include b; | |
505 } | |
506 @mixin b { | |
507 span { | |
508 border: 2px dashed red; | |
509 } | |
510 @include a; | |
511 } | |
512 | |
513 @include b; | |
514 | |
515 '''; | |
516 | |
517 var stylesheet = compileCss(input, errors: errors, opts: options); | |
518 | |
519 expect(stylesheet != null, true); | |
520 expect(errors.isNotEmpty, true); | |
521 expect(errors.length, 1, reason: errors.toString()); | |
522 var error = errors[0]; | |
523 expect(error.message, 'Undefined mixin b'); | |
524 expect(error.span.start.line, 1); | |
525 expect(error.span.start.offset, 14); | |
526 } | |
527 | |
528 void undefinedDeclaration() { | |
529 final errors = []; | |
530 final input = r''' | |
531 @mixin a { | |
532 @include b; | |
533 } | |
534 @mixin b { | |
535 border: 2px dashed red; | |
536 @include a; | |
537 } | |
538 div { | |
539 @include b; | |
540 } | |
541 '''; | |
542 | |
543 var stylesheet = compileCss(input, errors: errors, opts: options); | |
544 | |
545 expect(stylesheet != null, true); | |
546 expect(errors.isNotEmpty, true); | |
547 expect(errors.length, 1, reason: errors.toString()); | |
548 var error = errors[0]; | |
549 expect(error.message, 'Undefined mixin b'); | |
550 expect(error.span.start.line, 1); | |
551 expect(error.span.start.offset, 14); | |
552 } | |
553 | |
554 void includeGrammar() { | |
555 compileAndValidate(r''' | |
556 @mixin a { | |
557 foo { color: red } | |
558 } | |
559 | |
560 @mixin b { | |
561 @include a; | |
562 @include a; | |
563 } | |
564 | |
565 @include b; | |
566 ''', r'''foo { | |
567 color: #f00; | |
568 } | |
569 foo { | |
570 color: #f00; | |
571 }'''); | |
572 | |
573 compileAndValidate(r''' | |
574 @mixin a { | |
575 color: red | |
576 } | |
577 | |
578 foo { | |
579 @include a; | |
580 @include a | |
581 } | |
582 ''', r'''foo { | |
583 color: #f00; | |
584 color: #f00; | |
585 }'''); | |
586 | |
587 var errors = []; | |
588 var input = r''' | |
589 @mixin a { | |
590 foo { color: red } | |
591 } | |
592 | |
593 @mixin b { | |
594 @include a | |
595 @include a | |
596 } | |
597 | |
598 @include b | |
599 '''; | |
600 | |
601 var stylesheet = compileCss(input, errors: errors, opts: options); | |
602 | |
603 expect(stylesheet != null, true); | |
604 | |
605 expect(errors.isNotEmpty, true); | |
606 expect(errors.length, 6, reason: errors.toString()); | |
607 var error = errors[0]; | |
608 expect(error.message, 'parsing error expected ;'); | |
609 expect(error.span.start.line, 6); | |
610 expect(error.span.end.offset, 69); | |
611 error = errors[1]; | |
612 expect(error.message, 'expected :, but found }'); | |
613 expect(error.span.start.line, 7); | |
614 expect(error.span.end.offset, 73); | |
615 error = errors[2]; | |
616 expect(error.message, 'parsing error expected }'); | |
617 expect(error.span.start.line, 9); | |
618 expect(error.span.end.offset, 83); | |
619 error = errors[3]; | |
620 expect(error.message, 'expected {, but found end of file()'); | |
621 expect(error.span.start.line, 9); | |
622 expect(error.span.end.offset, 86); | |
623 error = errors[4]; | |
624 expect(error.message, 'expected }, but found end of file()'); | |
625 expect(error.span.start.line, 10); | |
626 expect(error.span.end.offset, 86); | |
627 error = errors[5]; | |
628 expect(error.message, 'Using top-level mixin a as a declaration'); | |
629 expect(error.span.start.line, 5); | |
630 expect(error.span.end.offset, 56); | |
631 } | |
632 | |
633 main() { | |
634 group('Basic mixin', () { | |
635 test('include grammar', includeGrammar); | |
636 test('empty mixin content', emptyMixin); | |
637 }); | |
638 | |
639 group('Top-level mixin', () { | |
640 test('simple mixin', topLevelMixin); | |
641 test('mixin with two @includes', topLevelMixinTwoIncludes); | |
642 test('multi rulesets', topLevelMixinMultiRulesets); | |
643 test('multi rulesets and nesting', topLevelMixinDeeplyNestedRulesets); | |
644 test('selector groups', topLevelMixinSelectors); | |
645 }); | |
646 | |
647 group('Declaration mixin', () { | |
648 test('simple', declSimpleMixin); | |
649 test('with two @includes', declMixinTwoIncludes); | |
650 test('with includes', declMixinNestedIncludes); | |
651 test('with deeper nesting', declMixinDeeperNestedIncludes); | |
652 }); | |
653 | |
654 group('Mixin arguments', () { | |
655 test('simple arg', mixinArg); | |
656 test('multiple args and var decls as args', mixinManyArgs); | |
657 }); | |
658 | |
659 group('Mixin warnings', () { | |
660 test('undefined top-level', undefinedTopLevel); | |
661 test('undefined declaration', undefinedDeclaration); | |
662 test('detect bad top-level as declaration', badDeclarationInclude); | |
663 test('detect bad declaration as top-level', badTopInclude); | |
664 }); | |
665 } | |
OLD | NEW |