css_dryer 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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