css_parser 0.9.0

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,71 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ # Test cases for the handling of media types
4
+ class CssParserMediaTypesTests < Test::Unit::TestCase
5
+ include CssParser
6
+
7
+ def setup
8
+ @cp = Parser.new
9
+ end
10
+
11
+ def test_finding_by_media_type
12
+ # from http://www.w3.org/TR/CSS21/media.html#at-media-rule
13
+ css = <<-EOT
14
+ @media print {
15
+ body { font-size: 10pt }
16
+ }
17
+ @media screen {
18
+ body { font-size: 13px }
19
+ }
20
+ @media screen, print {
21
+ body { line-height: 1.2 }
22
+ }
23
+ EOT
24
+
25
+ @cp.add_block!(css)
26
+
27
+ assert_equal 'font-size: 10pt; line-height: 1.2;', @cp.find_by_selector('body', :print).join(' ')
28
+ assert_equal 'font-size: 13px; line-height: 1.2;', @cp.find_by_selector('body', :screen).join(' ')
29
+ end
30
+
31
+ def atest_finding_by_multiple_media_types
32
+ css = <<-EOT
33
+ @media print {
34
+ body { font-size: 10pt }
35
+ }
36
+ @media handheld {
37
+ body { font-size: 13px }
38
+ }
39
+ @media screen, print {
40
+ body { line-height: 1.2 }
41
+ }
42
+ EOT
43
+ @cp.add_block!(css)
44
+
45
+ assert_equal 'font-size: 13px; line-height: 1.2;', @cp.find_by_selector('body', [:screen,:handheld]).join(' ')
46
+ end
47
+
48
+ def test_adding_block_with_media_types
49
+ css = <<-EOT
50
+ body { font-size: 10pt }
51
+ EOT
52
+
53
+ @cp.add_block!(css, :media_types => [:screen])
54
+
55
+ assert_equal 'font-size: 10pt;', @cp.find_by_selector('body', :screen).join(' ')
56
+ assert @cp.find_by_selector('body', :handheld).empty?
57
+ end
58
+
59
+ def atest_adding_rule_set_with_media_type
60
+ @cp.add_rule!('body', 'color: black;', [:handheld,:tty])
61
+ @cp.add_rule!('body', 'color: blue;', :screen)
62
+ assert_equal 'color: black;', @cp.find_by_selector('body', :handheld).join(' ')
63
+ end
64
+
65
+ def atest_selecting_with_all_meda_type
66
+ @cp.add_rule!('body', 'color: black;', [:handheld,:tty])
67
+ assert_equal 'color: black;', @cp.find_by_selector('body', :all).join(' ')
68
+ end
69
+
70
+
71
+ end
@@ -0,0 +1,143 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ # Test cases for the CssParser.
4
+ class CssParserTests < Test::Unit::TestCase
5
+ include CssParser
6
+
7
+ def setup
8
+ @cp = Parser.new
9
+ end
10
+
11
+ def test_at_page_rule
12
+ # from http://www.w3.org/TR/CSS21/page.html#page-selectors
13
+ css = <<-EOT
14
+ @page { margin: 2cm }
15
+
16
+ @page :first {
17
+ margin-top: 10cm
18
+ }
19
+ EOT
20
+
21
+ @cp.add_block!(css)
22
+
23
+ assert_equal 'margin: 2cm;', @cp.find_by_selector('@page').join(' ')
24
+ assert_equal 'margin-top: 10cm;', @cp.find_by_selector('@page :first').join(' ')
25
+ end
26
+
27
+ def test_should_ignore_comments
28
+ # see http://www.w3.org/Style/CSS/Test/CSS2.1/current/html4/t040109-c17-comments-00-b.htm
29
+ css =<<-EOT
30
+ /* This is a CSS comment. */
31
+ .one {color: green;} /* Another comment */
32
+ /* The following should not be used:
33
+ .one {color: red;} */
34
+ .two {color: green; /* color: yellow; */}
35
+ /**
36
+ .three {color: red;} */
37
+ .three {color: green;}
38
+ /**/
39
+ .four {color: green;}
40
+ /*********/
41
+ .five {color: green;}
42
+ /* a comment **/
43
+ .six {color: green;}
44
+ EOT
45
+
46
+ @cp.add_block!(css)
47
+ @cp.each_selector do |sel, decs, spec|
48
+ assert_equal 'color: green;', decs
49
+ end
50
+ end
51
+
52
+ def test_parsing_blocks
53
+ # dervived from http://www.w3.org/TR/CSS21/syndata.html#rule-sets
54
+ css = <<-EOT
55
+ div[name='test'] {
56
+
57
+ color:
58
+
59
+ red;
60
+
61
+ }div:hover{coloR:red;
62
+ }div:first-letter{color:red;/*color:blue;}"commented out"*/}
63
+
64
+ p[example="public class foo\
65
+ {\
66
+ private string x;\
67
+ \
68
+ foo(int x) {\
69
+ this.x = 'test';\
70
+ this.x = \"test\";\
71
+ }\
72
+ \
73
+ }"] { color: red }
74
+
75
+ p { color:red}
76
+ EOT
77
+
78
+ @cp.add_block!(css)
79
+
80
+ @cp.each_selector do |sel, decs, spec|
81
+ assert_equal 'color: red;', decs
82
+ end
83
+ end
84
+
85
+ def test_ignoring_malformed_declarations
86
+ flunk
87
+ # dervived from http://www.w3.org/TR/CSS21/syndata.html#parsing-errors
88
+ css = <<-EOT
89
+ p { color:green }
90
+ p { color:green; color } /* malformed declaration missing ':', value */
91
+ p { color:red; color; color:green } /* same with expected recovery */
92
+ p { color:green; color: } /* malformed declaration missing value */
93
+ p { color:red; color:; color:green } /* same with expected recovery */
94
+ p { color:green; color{;color:maroon} } /* unexpected tokens { } */
95
+ p { color:red; color{;color:maroon}; color:green } /* same with recovery */
96
+ EOT
97
+
98
+ @cp.add_block!(css)
99
+
100
+ @cp.each_selector do |sel, decs, spec|
101
+ assert_equal 'color: green;', decs
102
+ end
103
+ end
104
+
105
+ def test_calculating_specificity
106
+ # from http://www.w3.org/TR/CSS21/cascade.html#specificity
107
+ assert_equal 0, CssParser.calculate_specificity('*')
108
+ assert_equal 1, CssParser.calculate_specificity('li')
109
+ assert_equal 2, CssParser.calculate_specificity('li:first-line')
110
+ assert_equal 2, CssParser.calculate_specificity('ul li')
111
+ assert_equal 3, CssParser.calculate_specificity('ul ol+li')
112
+ assert_equal 11, CssParser.calculate_specificity('h1 + *[rel=up]')
113
+ assert_equal 13, CssParser.calculate_specificity('ul ol li.red')
114
+ assert_equal 21, CssParser.calculate_specificity('li.red.level')
115
+ assert_equal 100, CssParser.calculate_specificity('#x34y')
116
+
117
+ # from http://www.hixie.ch/tests/adhoc/css/cascade/specificity/003.html
118
+ assert_equal CssParser.calculate_specificity('div *'), CssParser.calculate_specificity('p')
119
+ assert CssParser.calculate_specificity('body div *') > CssParser.calculate_specificity('div *')
120
+
121
+ # other tests
122
+ assert_equal 11, CssParser.calculate_specificity('h1[id|=123]')
123
+ end
124
+
125
+ def test_converting_uris
126
+ base_uri = 'http://www.example.org/style/basic.css'
127
+ ["body { background: url(yellow) };", "body { background: url('yellow') };",
128
+ "body { background: url('/style/yellow') };",
129
+ "body { background: url(\"../style/yellow\") };",
130
+ "body { background: url(\"lib/../../style/yellow\") };"].each do |css|
131
+ converted_css = CssParser.convert_uris(css, base_uri)
132
+ assert_equal "body { background: url('http://www.example.org/style/yellow') };", converted_css
133
+ end
134
+
135
+ converted_css = CssParser.convert_uris("body { background: url(../style/yellow-dot_symbol$.png?abc=123&amp;def=456&ghi=789#1011) };", base_uri)
136
+ assert_equal "body { background: url('http://www.example.org/style/yellow-dot_symbol$.png?abc=123&amp;def=456&ghi=789#1011') };", converted_css
137
+
138
+ # taken from error log: 2007-10-23 04:37:41#2399
139
+ converted_css = CssParser.convert_uris('.specs {font-family:Helvetica;font-weight:bold;font-style:italic;color:#008CA8;font-size:1.4em;list-style-image:url("images/bullet.gif");}', 'http://www.example.org/directory/file.html')
140
+ assert_equal ".specs {font-family:Helvetica;font-weight:bold;font-style:italic;color:#008CA8;font-size:1.4em;list-style-image:url('http://www.example.org/directory/images/bullet.gif');}", converted_css
141
+ end
142
+
143
+ end
@@ -0,0 +1,68 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ # Test cases for CSS regular expressions
4
+ #
5
+ # see http://www.w3.org/TR/CSS21/syndata.html and
6
+ # http://www.w3.org/TR/CSS21/grammar.html
7
+ class CssParserRegexpTests < Test::Unit::TestCase
8
+ def test_strings
9
+ # complete matches
10
+ ['"abcd"', '" A sd s�drcv \'dsf\' asd rfg asd"', '"A\ d??ef 123!"',
11
+ "\"this is\\\n a test\"", '"back\67round"', '"r\000065 ed"',
12
+ "'abcd'", "' A sd sedrcv \"dsf\" asd rf�&23$%#%$g asd'", "'A\\\n def 123!'",
13
+ "'this is\\\n a test'", "'back\\67round'", "'r\\000065 ed'"
14
+ ].each do |str|
15
+ assert_equal str, str.match(CssParser::RE_STRING).to_s
16
+ end
17
+
18
+ test_string = "p { background: red url(\"url\\.'p'ng\"); }"
19
+ assert_equal "\"url\\.'p'ng\"", test_string.match(CssParser::RE_STRING).to_s
20
+
21
+ end
22
+
23
+ def test_unicode
24
+ ['back\67round', 'r\000065 ed', '\00006C'].each do |str|
25
+ assert_match(Regexp.new(CssParser::RE_UNICODE), str)
26
+ end
27
+ end
28
+
29
+ def test_colour
30
+ ['color: #fff', 'color:#f0a09c;', 'color: #04A', 'color: #04a9CE',
31
+ 'color: rgb(100, -10%, 300);', 'color: rgb(10,10,10)', 'color:rgb(12.7253%, -12%,0)',
32
+ 'color: black', 'color:Red;', 'color: AqUa;', 'color: blue ', 'color: transparent'
33
+ ].each do |colour|
34
+ assert_match(CssParser::RE_COLOUR, colour)
35
+ end
36
+
37
+ ['color: #fa', 'color:#f009c;', 'color: #04G', 'color: #04a9Cq',
38
+ 'color: rgb 100, -10%, 300;', 'color: rgb 10,10,10', 'color:rgb(12px, -12%,0)',
39
+ 'color:fuscia;', 'color: thick'
40
+ ].each do |colour|
41
+ assert_no_match(CssParser::RE_COLOUR, colour)
42
+ end
43
+ end
44
+
45
+ def test_uris
46
+ crazy_uri = 'http://www.example.com:80/~/redb%20all.png?test=test&test;test+test#test!'
47
+
48
+ assert_equal "url('#{crazy_uri}')",
49
+ "li { list-style: url('#{crazy_uri}') disc }".match(CssParser::RE_URI).to_s
50
+
51
+ assert_equal "url(#{crazy_uri})",
52
+ "li { list-style: url(#{crazy_uri}) disc }".match(CssParser::RE_URI).to_s
53
+
54
+ assert_equal "url(\"#{crazy_uri}\")",
55
+ "li { list-style: url(\"#{crazy_uri}\") disc }".match(CssParser::RE_URI).to_s
56
+ end
57
+
58
+
59
+ protected
60
+ def load_test_file(filename)
61
+ fh = File.new("fixtures/#{filename}", 'r')
62
+ test_file = fh.read
63
+ fh.close
64
+
65
+ return test_file
66
+ end
67
+
68
+ end
@@ -0,0 +1,8 @@
1
+ $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__), '../'))
2
+ $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__), '../lib/'))
3
+ require 'rubygems'
4
+ require 'test/unit'
5
+ require 'css_parser'
6
+ require 'net/http'
7
+ require 'open-uri'
8
+ require 'WEBrick'
@@ -0,0 +1,88 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class MergingTests < Test::Unit::TestCase
4
+ include CssParser
5
+
6
+ def setup
7
+ @cp = CssParser::Parser.new
8
+ end
9
+
10
+ def test_simple_merge
11
+ rs1 = RuleSet.new(nil, 'color: black;')
12
+ rs2 = RuleSet.new(nil, 'margin: 0px;')
13
+ merged = CssParser.merge(rs1, rs2)
14
+ assert_equal '0px;', merged['margin']
15
+ assert_equal 'black;', merged['color']
16
+ end
17
+
18
+ def test_merging_array
19
+ rs1 = RuleSet.new(nil, 'color: black;')
20
+ rs2 = RuleSet.new(nil, 'margin: 0px;')
21
+ merged = CssParser.merge([rs1, rs2])
22
+ assert_equal '0px;', merged['margin']
23
+ assert_equal 'black;', merged['color']
24
+ end
25
+
26
+
27
+ def test_merging_multiple
28
+ rs1 = RuleSet.new(nil, 'color: black;')
29
+ rs2 = RuleSet.new(nil, 'margin: 0px;')
30
+ rs3 = RuleSet.new(nil, 'margin: 5px;')
31
+ merged = CssParser.merge(rs1, rs2, rs3)
32
+ assert_equal '5px;', merged['margin']
33
+ end
34
+
35
+ def test_multiple_selectors_should_have_zero_specificity
36
+ rs1 = RuleSet.new('p, a[rel="external"]', 'color: black;')
37
+ rs2 = RuleSet.new('a', 'color: blue;')
38
+ merged = CssParser.merge(rs1, rs2)
39
+ assert_equal 'blue;', merged['color']
40
+ end
41
+
42
+ def test_setting_specificity
43
+ rs1 = RuleSet.new(nil, 'color: red;', 20)
44
+ rs2 = RuleSet.new(nil, 'color: blue;', 10)
45
+ merged = CssParser.merge(rs1, rs2)
46
+ assert_equal 'red;', merged['color']
47
+ end
48
+
49
+ def test_properties_should_be_case_insensitive
50
+ rs1 = RuleSet.new(nil, ' CoLor : red ;', 20)
51
+ rs2 = RuleSet.new(nil, 'color: blue;', 10)
52
+ merged = CssParser.merge(rs1, rs2)
53
+ assert_equal 'red;', merged['color']
54
+ end
55
+
56
+ def test_merging_backgrounds
57
+ rs1 = RuleSet.new(nil, 'background-color: black;')
58
+ rs2 = RuleSet.new(nil, 'background-image: none;')
59
+ merged = CssParser.merge(rs1, rs2)
60
+ assert_equal 'black none;', merged['background']
61
+ end
62
+
63
+ def test_merging_dimensions
64
+ rs1 = RuleSet.new(nil, 'margin: 3em;')
65
+ rs2 = RuleSet.new(nil, 'margin-left: 1em;')
66
+ merged = CssParser.merge(rs1, rs2)
67
+ assert_equal '3em 3em 3em 1em;', merged['margin']
68
+ end
69
+
70
+ def test_merging_fonts
71
+ rs1 = RuleSet.new(nil, 'font: 11px Arial;')
72
+ rs2 = RuleSet.new(nil, 'font-weight: bold;')
73
+ merged = CssParser.merge(rs1, rs2)
74
+ assert_equal 'bold 11px Arial;', merged['font']
75
+ end
76
+
77
+ def test_raising_error_on_bad_type
78
+ assert_raise ArgumentError do
79
+ CssParser.merge([1,2,3])
80
+ end
81
+ end
82
+
83
+ def test_returning_early_with_only_one_params
84
+ rs = RuleSet.new(nil, 'font-weight: bold;')
85
+ merged = CssParser.merge(rs)
86
+ assert_equal rs.object_id, merged.object_id
87
+ end
88
+ end
@@ -0,0 +1,74 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ # Test cases for parsing CSS blocks
4
+ class RuleSetTests < Test::Unit::TestCase
5
+ include CssParser
6
+
7
+ def setup
8
+ @cp = Parser.new
9
+ end
10
+
11
+ def test_setting_property_values
12
+ rs = RuleSet.new(nil, nil)
13
+
14
+ rs['background-color'] = 'red'
15
+ assert_equal('red;', rs['background-color'])
16
+
17
+ rs['background-color'] = 'blue !important;'
18
+ assert_equal('blue !important;', rs['background-color'])
19
+ end
20
+
21
+ def test_getting_property_values
22
+ rs = RuleSet.new('#content p, a', 'color: #fff;')
23
+ assert_equal('#fff;', rs['color'])
24
+ end
25
+
26
+ def test_getting_property_value_ignoring_case
27
+ rs = RuleSet.new('#content p, a', 'color: #fff;')
28
+ assert_equal('#fff;', rs[' ColoR '])
29
+ end
30
+
31
+ def test_each_selector
32
+ expected = [
33
+ {:selector => "#content p", :declarations => "color: #fff;", :specificity => 101},
34
+ {:selector => "a", :declarations => "color: #fff;", :specificity => 1}
35
+ ]
36
+
37
+ actual = []
38
+ rs = RuleSet.new('#content p, a', 'color: #fff;')
39
+ rs.each_selector do |sel, decs, spec|
40
+ actual << {:selector => sel, :declarations => decs, :specificity => spec}
41
+ end
42
+
43
+ assert_equal(expected, actual)
44
+ end
45
+
46
+ def test_each_declaration
47
+ expected = [
48
+ {:property => 'margin', :value => '1px -0.25em', :is_important => false},
49
+ {:property => 'background', :value => 'white none no-repeat', :is_important => true},
50
+ {:property => 'color', :value => '#fff', :is_important => false}
51
+ ]
52
+
53
+ actual = []
54
+ rs = RuleSet.new(nil, 'color: #fff; Background: white none no-repeat !important; margin: 1px -0.25em;')
55
+ rs.each_declaration do |prop, val, imp|
56
+ actual << {:property => prop, :value => val, :is_important => imp}
57
+ end
58
+
59
+ assert_equal(expected, actual)
60
+ end
61
+
62
+ def test_declarations_to_s
63
+ declarations = 'color: #fff; font-weight: bold;'
64
+ rs = RuleSet.new('#content p, a', declarations)
65
+ assert_equal(declarations.split(' ').sort, rs.declarations_to_s.split(' ').sort)
66
+ end
67
+
68
+ def test_overriding_specificity
69
+ rs = RuleSet.new('#content p, a', 'color: white', 1000)
70
+ rs.each_selector do |sel, decs, spec|
71
+ assert_equal 1000, spec
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,90 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ # Test cases for reading and generating CSS shorthand properties
4
+ class RuleSetCreatingShorthandTests < Test::Unit::TestCase
5
+ include CssParser
6
+
7
+ def setup
8
+ @cp = CssParser::Parser.new
9
+ end
10
+
11
+ # ==== Dimensions shorthand
12
+ def test_combining_dimensions_into_shorthand
13
+ properties = {'margin-right' => 'auto', 'margin-bottom' => '0px', 'margin-left' => 'auto', 'margin-top' => '0px',
14
+ 'padding-right' => '1.25em', 'padding-bottom' => '11%', 'padding-left' => '3pc', 'padding-top' => '11.25ex'}
15
+
16
+ combined = create_shorthand(properties)
17
+
18
+ assert_equal('0px auto;', combined['margin'])
19
+ assert_equal('11.25ex 1.25em 11% 3pc;', combined['padding'])
20
+
21
+ # after creating shorthand, all long-hand properties should be deleted
22
+ assert_properties_are_deleted(combined, properties)
23
+
24
+ # should not combine if any properties are missing
25
+ properties.delete('margin-right')
26
+ properties.delete('padding-right')
27
+
28
+ combined = create_shorthand(properties)
29
+
30
+ assert_equal '', combined['margin']
31
+ assert_equal '', combined['padding']
32
+ end
33
+
34
+ # ==== Font shorthand
35
+ def test_combining_font_into_shorthand
36
+ # should combine if all font properties are present
37
+ properties = {"font-weight" => "300", "font-size" => "12pt",
38
+ "font-family" => "sans-serif", "line-height" => "18px",
39
+ "font-style" => "oblique", "font-variant" => "small-caps"}
40
+
41
+ combined = create_shorthand(properties)
42
+ assert_equal('oblique small-caps 300 12pt/18px sans-serif;', combined['font'])
43
+
44
+ # after creating shorthand, all long-hand properties should be deleted
45
+ assert_properties_are_deleted(combined, properties)
46
+
47
+ # should not combine if any properties are missing
48
+ properties.delete('font-weight')
49
+ combined = create_shorthand(properties)
50
+ assert_equal '', combined['font']
51
+ end
52
+
53
+ # ==== Background shorthand
54
+ def test_combining_background_into_shorthand
55
+ properties = {'background-image' => 'url(\'chess.png\')', 'background-color' => 'gray',
56
+ 'background-position' => 'center -10.2%', 'background-attachment' => 'fixed',
57
+ 'background-repeat' => 'no-repeat'}
58
+
59
+ combined = create_shorthand(properties)
60
+
61
+ assert_equal('gray url(\'chess.png\') no-repeat center -10.2% fixed;', combined['background'])
62
+
63
+ # after creating shorthand, all long-hand properties should be deleted
64
+ assert_properties_are_deleted(combined, properties)
65
+ end
66
+
67
+ def test_property_values_in_url
68
+ rs = RuleSet.new('#header', "background:url(http://example.com/1528/www/top-logo.jpg) no-repeat top right; padding: 79px 0 10px 0; text-align:left;")
69
+ rs.expand_shorthand!
70
+ assert_equal('top right;', rs['background-position'])
71
+ rs.create_shorthand!
72
+ assert_equal('url(http://example.com/1528/www/top-logo.jpg) no-repeat top right;', rs['background'])
73
+ end
74
+
75
+ protected
76
+ def assert_properties_are_deleted(ruleset, properties)
77
+ properties.each do |property, value|
78
+ assert_equal '', ruleset[property]
79
+ end
80
+ end
81
+
82
+ def create_shorthand(properties)
83
+ ruleset = RuleSet.new(nil, nil)
84
+ properties.each do |property, value|
85
+ ruleset[property] = value
86
+ end
87
+ ruleset.create_shorthand!
88
+ ruleset
89
+ end
90
+ end