css_dryer 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,826 @@
1
+ require 'test/unit'
2
+ require File.dirname(__FILE__) + '/../lib/css_dryer/processor'
3
+
4
+ class TestCssDryer < Test::Unit::TestCase
5
+ include CssDryer::Processor
6
+
7
+ def test_should_build_structure_without_nesting
8
+ css = <<END
9
+ /* comment 0 */
10
+ s0 {
11
+ k00: v00;
12
+ k01: v01;
13
+ }
14
+ /* comment 1 */
15
+ s1 { k10: v10; }
16
+ s2 {
17
+ k20: v20;
18
+ /* comment 2 */
19
+ k21: v21;
20
+ }
21
+ END
22
+ output = nested_css_to_structure(css)
23
+ assert_equal 5, output.length
24
+
25
+ assert_equal '/* comment 0 */', output.shift
26
+
27
+ hsh = output.shift
28
+ assert_equal 1, hsh.length
29
+ assert hsh.multiline
30
+ assert_equal 's0', hsh.keys.first
31
+ ary = hsh.values.first
32
+ assert_equal 2, ary.length
33
+ assert_equal ' k00: v00;', ary.first
34
+ assert_equal ' k01: v01;', ary.last
35
+
36
+ assert_equal '/* comment 1 */', output.shift
37
+
38
+ hsh = output.shift
39
+ assert_equal 1, hsh.length
40
+ assert ! hsh.multiline
41
+ assert_equal 's1', hsh.keys.first
42
+ ary = hsh.values.first
43
+ assert_equal 1, ary.length
44
+ assert_equal ' k10: v10; ', ary.first
45
+
46
+ hsh = output.shift
47
+ assert_equal 1, hsh.length
48
+ assert hsh.multiline
49
+ assert_equal 's2', hsh.keys.first
50
+ ary = hsh.values.first
51
+ assert_equal 3, ary.length
52
+ assert_equal ' k20: v20;', ary.shift
53
+ assert_equal ' /* comment 2 */', ary.shift
54
+ assert_equal ' k21: v21;', ary.shift
55
+ end
56
+
57
+ def test_should_build_structure_with_nesting
58
+ css = <<END
59
+ /* comment 0 */
60
+ s0 {
61
+ k00: v00;
62
+ k01: v01;
63
+ }
64
+ s1 {
65
+ k10: v10;
66
+ /* comment 1 */
67
+ s2 {
68
+ k20: v20;
69
+ k21: v21;
70
+ }
71
+ k11: v11;
72
+ s3 { k30: v30; }
73
+ }
74
+ END
75
+
76
+ # [
77
+ # '/* comment 0 */',
78
+ # { 's0' => [ ' k00: v00;', ' k01: v01;' ] },
79
+ # { 's1' => [ ' k10: v10;',
80
+ # ' /* comment 1 */',
81
+ # { 's2' => [ 'k20: v20;', 'k21: v21;'] },
82
+ # ' k11: v11;',
83
+ # { 's3' => [ ' k30: v30; ' ] } } ]
84
+ # ]
85
+ output = nested_css_to_structure(css)
86
+ assert_equal 3, output.length
87
+
88
+ assert_equal '/* comment 0 */', output.shift
89
+
90
+ hsh = output.shift
91
+ assert_equal 1, hsh.length
92
+ assert hsh.multiline
93
+ assert_equal 's0', hsh.keys.first
94
+ ary = hsh.values.first
95
+ assert_equal 2, ary.length
96
+ assert_equal ' k00: v00;', ary.shift
97
+ assert_equal ' k01: v01;', ary.shift
98
+
99
+ hsh = output.shift
100
+ assert_equal 1, hsh.length
101
+ assert hsh.multiline
102
+ assert_equal 's1', hsh.keys.first
103
+ ary = hsh.values.first
104
+ assert_equal 5, ary.length
105
+
106
+ assert_equal ' k10: v10;', ary.shift
107
+ assert_equal ' /* comment 1 */', ary.shift
108
+ s2_hsh = ary.shift
109
+ assert_equal 1, s2_hsh.length
110
+ assert s2_hsh.multiline
111
+ assert_equal 's2', s2_hsh.keys.first
112
+ s2_ary = s2_hsh.values.first
113
+ assert_equal 2, s2_ary.length
114
+ assert_equal 'k20: v20;', s2_ary.shift
115
+ assert_equal 'k21: v21;', s2_ary.shift
116
+ assert_equal ' k11: v11;', ary.shift
117
+ s3_hsh = ary.shift
118
+ assert_equal 1, s3_hsh.length
119
+ assert ! s3_hsh.multiline
120
+ assert_equal 's3', s3_hsh.keys.first
121
+ s3_ary = s3_hsh.values.first
122
+ assert_equal 1, s3_ary.length
123
+ assert_equal ' k30: v30; ', s3_ary.shift
124
+ end
125
+
126
+ def test_should_build_structure_with_triple_nesting
127
+ css = <<END
128
+ /* comment 0 */
129
+ s0 {
130
+ k00: v00;
131
+ k01: v01;
132
+ }
133
+ s1 {
134
+ k10: v10;
135
+ /* comment 1 */
136
+ s2 {
137
+ k20: v20;
138
+ k21: v21;
139
+ s3 {k30: v30;}
140
+ }
141
+ k11: v11;
142
+ }
143
+ END
144
+
145
+ # [
146
+ # '/* comment 0 */',
147
+ # { 's0' => [ ' k00: v00;', ' k01: v01;' ] },
148
+ # { 's1' => [ ' k10: v10;',
149
+ # ' /* comment 1 */',
150
+ # { 's2' => [ 'k20: v20;',
151
+ # 'k21: v21;',
152
+ # { 's3' => [ 'k30: v30;' ] } ] },
153
+ # ' k11: v11;' ]
154
+ # ]
155
+ output = nested_css_to_structure(css)
156
+ assert_equal 3, output.length
157
+
158
+ assert_equal '/* comment 0 */', output.shift
159
+
160
+ hsh = output.shift
161
+ assert_equal 1, hsh.length
162
+ assert hsh.multiline
163
+ assert_equal 's0', hsh.keys.first
164
+ ary = hsh.values.first
165
+ assert_equal 2, ary.length
166
+ assert_equal ' k00: v00;', ary.shift
167
+ assert_equal ' k01: v01;', ary.shift
168
+
169
+ hsh = output.shift
170
+ assert_equal 1, hsh.length
171
+ assert hsh.multiline
172
+ assert_equal 's1', hsh.keys.first
173
+ ary = hsh.values.first
174
+ assert_equal 4, ary.length
175
+ assert_equal ' k10: v10;', ary.shift
176
+ assert_equal ' /* comment 1 */', ary.shift
177
+ hsh = ary.shift
178
+ assert_equal 1, hsh.length
179
+ assert hsh.multiline
180
+ assert_equal 's2', hsh.keys.first
181
+ ary_prime = hsh.values.first
182
+ assert_equal 3, ary_prime.length
183
+ assert_equal 'k20: v20;', ary_prime.shift
184
+ assert_equal 'k21: v21;', ary_prime.shift
185
+ hsh = ary_prime.shift
186
+ assert_equal 1, hsh.length
187
+ assert ! hsh.multiline
188
+ assert_equal 's3', hsh.keys.first
189
+ assert_equal 'k30: v30;', hsh.values.first.shift
190
+ assert_equal ' k11: v11;', ary.shift
191
+ end
192
+
193
+ def test_should_convert_type_selectors_aka_no_nesting_structure_to_css
194
+ structure = []
195
+ structure << '/* comment 0 */'
196
+ hsh = StyleHash['s0' => [ ' k00: v00;', ' k01: v01;' ] ]
197
+ hsh.multiline = true
198
+ structure << hsh
199
+ structure << '/* comment 1 */'
200
+ structure << StyleHash['s1' => [ ' k10: v10; ' ] ]
201
+ hsh = StyleHash['s2' => [ ' k20: v20;', ' /* comment 2 */', ' k21: v21;' ] ]
202
+ hsh.multiline = true
203
+ structure << hsh
204
+
205
+ assert_equal <<END, structure_to_css(structure)
206
+ /* comment 0 */
207
+ s0 {
208
+ k00: v00;
209
+ k01: v01;
210
+ }
211
+ /* comment 1 */
212
+ s1 { k10: v10; }
213
+ s2 {
214
+ k20: v20;
215
+ /* comment 2 */
216
+ k21: v21;
217
+ }
218
+ END
219
+ end
220
+
221
+ def test_should_convert_descendant_selectors_structure_to_css
222
+ structure = []
223
+ structure << '/* comment 0 */'
224
+
225
+ hsh_s0 = StyleHash['s0' => [ ' k00: v00;', ' k01: v01;' ] ]
226
+ hsh_s0.multiline = true
227
+ structure << hsh_s0
228
+
229
+ hsh_s3 = StyleHash['s3' => [ ' k30: v30; ' ] ]
230
+ hsh_s2 = StyleHash['s2' => [ 'k20: v20;', 'k21: v21;', hsh_s3 ] ]
231
+ hsh_s2.multiline = true
232
+
233
+ hsh_s1 = StyleHash['s1' => [ ' k10: v10;', ' /* comment 1 */', hsh_s2, ' k11: v11;' ] ]
234
+ hsh_s1.multiline = true
235
+ structure << hsh_s1
236
+
237
+ assert_equal <<END, structure_to_css(structure)
238
+ /* comment 0 */
239
+ s0 {
240
+ k00: v00;
241
+ k01: v01;
242
+ }
243
+ s1 {
244
+ k10: v10;
245
+ /* comment 1 */
246
+ k11: v11;
247
+ }
248
+ s1 s2 {
249
+ k20: v20;
250
+ k21: v21;
251
+ }
252
+ s1 s2 s3 { k30: v30; }
253
+ END
254
+ end
255
+
256
+ def test_should_handle_rails_tip_example_of_descendant_selectors
257
+ input = <<END
258
+ div#content {
259
+ /* some styles which apply only to div#content ... */
260
+ h2 { /* some styles which apply only to div#content h2 ... */ }
261
+ a {
262
+ /* some styles which apply only to div#content a ... */
263
+ }
264
+ }
265
+ END
266
+
267
+ output = <<END
268
+ div#content {
269
+ /* some styles which apply only to div#content ... */
270
+ }
271
+ div#content h2 { /* some styles which apply only to div#content h2 ... */ }
272
+ div#content a {
273
+ /* some styles which apply only to div#content a ... */
274
+ }
275
+ END
276
+
277
+ assert_equal output, process(input)
278
+ end
279
+
280
+ def test_should_handle_one_descendant_selector
281
+ input = <<END
282
+ div p {
283
+ color: blue;
284
+ }
285
+ END
286
+ assert_equal input, process(input)
287
+ end
288
+
289
+ def test_should_handle_media_block
290
+ input = <<END
291
+ @media screen, projection {
292
+ div {font-size:100%;}
293
+ }
294
+ END
295
+
296
+ output = <<END
297
+ @media screen, projection {
298
+ div {font-size:100%;}
299
+ }
300
+ END
301
+
302
+ assert_equal output, process(input)
303
+ end
304
+
305
+ def test_should_handle_inline_media_block
306
+ input = <<END
307
+ @media screen, projection { div {font-size:100%;} }
308
+ END
309
+
310
+ output = <<END
311
+ @media screen, projection { div {font-size:100%;} }
312
+ END
313
+
314
+ assert_equal output, process(input)
315
+ end
316
+
317
+ def test_should_not_output_empty_selectors
318
+ input = <<END
319
+ div#content {
320
+ h2 { /* some styles which apply only to div#content h2 ... */ }
321
+ a {
322
+ /* some styles which apply only to div#content a ... */
323
+ }
324
+ }
325
+ END
326
+
327
+ output = <<END
328
+ div#content h2 { /* some styles which apply only to div#content h2 ... */ }
329
+ div#content a {
330
+ /* some styles which apply only to div#content a ... */
331
+ }
332
+ END
333
+
334
+ assert_equal output, process(input)
335
+ end
336
+
337
+ def test_should_not_output_blank_lines
338
+ input = <<END
339
+ div {
340
+ color: red;
341
+
342
+ span { color: blue; }
343
+
344
+ a {
345
+ .hover { text-decoration: none; }
346
+ .visited { text-decoration: none; }
347
+ }
348
+
349
+ }
350
+ END
351
+ assert_equal <<END, process(input)
352
+ div {
353
+ color: red;
354
+ }
355
+ div span { color: blue; }
356
+ div a.hover { text-decoration: none; }
357
+ div a.visited { text-decoration: none; }
358
+ END
359
+ end
360
+
361
+ def test_style_hash_has_non_hash_children
362
+ hsh = StyleHash[ 'key' => %w( foo ) ]
363
+ assert hsh.has_non_style_hash_children
364
+ hsh.value.pop
365
+ hsh.value << StyleHash.new
366
+ assert ! hsh.has_non_style_hash_children
367
+ end
368
+
369
+ def test_should_handle_class_selectors
370
+ input = <<END
371
+ td {
372
+ font-family: verdana;
373
+ .even { background: blue; }
374
+ .odd {
375
+ background: green;
376
+ .odder-still { background: infra-red; }
377
+ }
378
+ }
379
+ END
380
+
381
+ output = <<END
382
+ td {
383
+ font-family: verdana;
384
+ }
385
+ td.even { background: blue; }
386
+ td.odd {
387
+ background: green;
388
+ }
389
+ td.odd.odder-still { background: infra-red; }
390
+ END
391
+
392
+ assert_equal output, process(input)
393
+ end
394
+
395
+ def test_should_handle_pseudo_class_selectors
396
+ input = <<END
397
+ a {
398
+ text-decoration: underline; padding: 1px;
399
+ :link { color: #03c; }
400
+ :visited { color: #03c; }
401
+ :hover { color: #fff; background-color: #30c; text-decoration: none; }
402
+ .image:link {
403
+ background: none;
404
+ padding: 0;
405
+ }
406
+ }
407
+ END
408
+
409
+ output = <<END
410
+ a {
411
+ text-decoration: underline; padding: 1px;
412
+ }
413
+ a:link { color: #03c; }
414
+ a:visited { color: #03c; }
415
+ a:hover { color: #fff; background-color: #30c; text-decoration: none; }
416
+ a.image:link {
417
+ background: none;
418
+ padding: 0;
419
+ }
420
+ END
421
+
422
+ assert_equal output, process(input)
423
+ end
424
+
425
+ def test_should_handle_id_selectors
426
+ input = <<END
427
+ div {
428
+ color: blue;
429
+ border: 1px solid green;
430
+ #flash {
431
+ background: yellow;
432
+ font-size: x-large;
433
+ }
434
+ }
435
+ END
436
+
437
+ output = <<END
438
+ div {
439
+ color: blue;
440
+ border: 1px solid green;
441
+ }
442
+ div#flash {
443
+ background: yellow;
444
+ font-size: x-large;
445
+ }
446
+ END
447
+
448
+ assert_equal output, process(input)
449
+ end
450
+
451
+ def test_should_handle_child_selectors
452
+ input = <<END
453
+ div {
454
+ color: blue;
455
+ border: 1px solid green;
456
+ > p {
457
+ color: yellow;
458
+ > b { font-variant: small-caps; }
459
+ }
460
+ }
461
+ END
462
+
463
+ output = <<END
464
+ div {
465
+ color: blue;
466
+ border: 1px solid green;
467
+ }
468
+ div > p {
469
+ color: yellow;
470
+ }
471
+ div > p > b { font-variant: small-caps; }
472
+ END
473
+
474
+ assert_equal output, process(input)
475
+ end
476
+
477
+ def test_should_handle_adjacent_selectors
478
+ input = <<END
479
+ div {
480
+ color: blue;
481
+ border: 1px solid green;
482
+ + p {
483
+ color: yellow;
484
+ + b { font-variant: small-caps; }
485
+ }
486
+ }
487
+ END
488
+
489
+ output = <<END
490
+ div {
491
+ color: blue;
492
+ border: 1px solid green;
493
+ }
494
+ div + p {
495
+ color: yellow;
496
+ }
497
+ div + p + b { font-variant: small-caps; }
498
+ END
499
+ assert_equal output, process(input)
500
+ end
501
+
502
+ def test_should_handle_attribute_selectors
503
+ input = <<END
504
+ div {
505
+ color: blue;
506
+ border: 1px solid green;
507
+ [foo] { color: yellow; }
508
+ [foo~="warning"] { color: blue; }
509
+ }
510
+ END
511
+
512
+ output = <<END
513
+ div {
514
+ color: blue;
515
+ border: 1px solid green;
516
+ }
517
+ div[foo] { color: yellow; }
518
+ div[foo~="warning"] { color: blue; }
519
+ END
520
+
521
+ assert_equal output, process(input)
522
+ end
523
+
524
+ def test_should_handle_comma_separated_selectors_without_nesting
525
+ input = <<END
526
+ h1, h2, h3 {
527
+ margin-top: 5px;
528
+ color: red;
529
+ }
530
+ END
531
+ assert_equal <<END, process(input)
532
+ h1 {
533
+ margin-top: 5px;
534
+ color: red;
535
+ }
536
+ h2 {
537
+ margin-top: 5px;
538
+ color: red;
539
+ }
540
+ h3 {
541
+ margin-top: 5px;
542
+ color: red;
543
+ }
544
+ END
545
+ end
546
+
547
+ def test_should_handle_comma_separated_selectors_with_outer_nesting
548
+ input = <<END
549
+ h1, h2, h3 {
550
+ margin-top: 5px;
551
+ color: red;
552
+ p { padding: 3px; }
553
+ }
554
+ END
555
+ assert_equal <<END, process(input)
556
+ h1 {
557
+ margin-top: 5px;
558
+ color: red;
559
+ }
560
+ h1 p { padding: 3px; }
561
+ h2 {
562
+ margin-top: 5px;
563
+ color: red;
564
+ }
565
+ h2 p { padding: 3px; }
566
+ h3 {
567
+ margin-top: 5px;
568
+ color: red;
569
+ }
570
+ h3 p { padding: 3px; }
571
+ END
572
+ end
573
+
574
+ def test_should_handle_comma_separated_selectors_with_inner_nesting
575
+ input = <<END
576
+ h1 {
577
+ color: red;
578
+ p, span { padding: 3px; }
579
+ }
580
+ END
581
+ assert_equal <<END, process(input)
582
+ h1 {
583
+ color: red;
584
+ }
585
+ h1 p {
586
+ padding: 3px;
587
+ }
588
+ h1 span {
589
+ padding: 3px;
590
+ }
591
+ END
592
+ end
593
+
594
+ def test_should_handle_comma_separated_selectors_with_deep_nesting
595
+ input = <<END
596
+ div {
597
+ color: red;
598
+ h1 {
599
+ color: blue;
600
+ p, span {
601
+ font-weight: strong;
602
+ }
603
+ }
604
+ }
605
+ END
606
+ assert_equal <<END, process(input)
607
+ div {
608
+ color: red;
609
+ }
610
+ div h1 {
611
+ color: blue;
612
+ }
613
+ div h1 p {
614
+ font-weight: strong;
615
+ }
616
+ div h1 span {
617
+ font-weight: strong;
618
+ }
619
+ END
620
+ end
621
+
622
+ def test_should_handle_comma_separated_selectors_with_inner_and_outer_nesting
623
+ input = <<END
624
+ div, span {
625
+ color: red;
626
+ h1, h2 {
627
+ font-weight: strong;
628
+ }
629
+ }
630
+ END
631
+ assert_equal <<END, process(input)
632
+ div {
633
+ color: red;
634
+ }
635
+ div h1 {
636
+ font-weight: strong;
637
+ }
638
+ div h2 {
639
+ font-weight: strong;
640
+ }
641
+ span {
642
+ color: red;
643
+ }
644
+ span h1 {
645
+ font-weight: strong;
646
+ }
647
+ span h2 {
648
+ font-weight: strong;
649
+ }
650
+ END
651
+ end
652
+
653
+ def test_should_handle_comma_separated_selectors_on_subsequent_lines_inline_styles
654
+ input = <<END
655
+ div#some,
656
+ div#another,
657
+ div#third { color: red; }
658
+ END
659
+ assert_equal <<END, process(input)
660
+ div#some {
661
+ color: red;
662
+ }
663
+ div#another {
664
+ color: red;
665
+ }
666
+ div#third {
667
+ color: red;
668
+ }
669
+ END
670
+ end
671
+
672
+ def test_should_handle_comma_separated_selectors_on_subsequent_lines_multiline_styles
673
+ input = <<END
674
+ div#some,
675
+ div#another,
676
+ div#third {
677
+ color: red;
678
+ }
679
+ END
680
+ assert_equal <<END, process(input)
681
+ div#some {
682
+ color: red;
683
+ }
684
+ div#another {
685
+ color: red;
686
+ }
687
+ div#third {
688
+ color: red;
689
+ }
690
+ END
691
+ end
692
+
693
+ def test_should_handle_comma_separated_fonts
694
+ input = <<END
695
+ html, body {
696
+ font-family: "Lucida Grande", Verdana, sans-serif;
697
+ }
698
+ END
699
+ assert_equal <<END, process(input)
700
+ html {
701
+ font-family: "Lucida Grande", Verdana, sans-serif;
702
+ }
703
+ body {
704
+ font-family: "Lucida Grande", Verdana, sans-serif;
705
+ }
706
+ END
707
+ end
708
+
709
+ def test_should_handle_multiline_comments
710
+ input = <<END
711
+ /*
712
+ * Multilined comment outside a selector.
713
+ */
714
+ html {
715
+ /*
716
+ * Multilined comment inside a selector.
717
+ */
718
+ p {
719
+ /*
720
+ * And another one.
721
+ */
722
+ color: blue;
723
+ }
724
+ }
725
+ END
726
+ assert_equal <<END, process(input)
727
+ /*
728
+ * Multilined comment outside a selector.
729
+ */
730
+ html {
731
+ /*
732
+ * Multilined comment inside a selector.
733
+ */
734
+ }
735
+ html p {
736
+ /*
737
+ * And another one.
738
+ */
739
+ color: blue;
740
+ }
741
+ END
742
+ end
743
+
744
+ def test_should_handle_comments_with_blank_lines
745
+ input = <<END
746
+ /*
747
+ * This is a multiline comment.
748
+
749
+ */
750
+ html {
751
+ color: blue;
752
+ /*
753
+ * This is a multiline comment.
754
+
755
+ */
756
+ p {
757
+ color: red;
758
+ }
759
+ }
760
+ END
761
+ assert_equal <<END, process(input)
762
+ /*
763
+ * This is a multiline comment.
764
+
765
+ */
766
+ html {
767
+ color: blue;
768
+ /*
769
+ * This is a multiline comment.
770
+ */
771
+ }
772
+ html p {
773
+ color: red;
774
+ }
775
+ END
776
+ end
777
+
778
+ def test_should_handle_comments_with_commas
779
+ input = <<END
780
+ /*********************************************************
781
+ Structural styling, sizing and positioning of elements
782
+ ********************************************************/
783
+
784
+ * {
785
+ margin: 0;
786
+ padding: 0;
787
+ }
788
+
789
+ body {
790
+ z-index: 2;
791
+ }
792
+ END
793
+ assert_equal <<END, process(input)
794
+ /*********************************************************
795
+ Structural styling sizing and positioning of elements
796
+ ********************************************************/
797
+
798
+ * {
799
+ margin: 0;
800
+ padding: 0;
801
+ }
802
+
803
+ body {
804
+ z-index: 2;
805
+ }
806
+ END
807
+ end
808
+
809
+ def test_should_fail_on_missing_closing_brace
810
+ input = <<END
811
+ * html {
812
+ body {
813
+ padding: 4px;
814
+ }
815
+ END
816
+ # TODO: decide what css_dryer should do with invalid input.
817
+ # Currently it doesn't test for CSS or nested CSS validity,
818
+ # and here it (accidentally) automagically replaces missing
819
+ # brace. Handy, but a recipe for disaster.
820
+ assert_not_equal <<END, process(input)
821
+ * html body {
822
+ padding: 4px;
823
+ }
824
+ END
825
+ end
826
+ end