nokogiri 1.3.0-x86-mswin32

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of nokogiri might be problematic. Click here for more details.

Files changed (256) hide show
  1. data/.autotest +27 -0
  2. data/CHANGELOG.ja.rdoc +233 -0
  3. data/CHANGELOG.rdoc +222 -0
  4. data/Manifest.txt +247 -0
  5. data/README.ja.rdoc +103 -0
  6. data/README.rdoc +117 -0
  7. data/Rakefile +205 -0
  8. data/bin/nokogiri +47 -0
  9. data/ext/nokogiri/extconf.rb +89 -0
  10. data/ext/nokogiri/html_document.c +183 -0
  11. data/ext/nokogiri/html_document.h +10 -0
  12. data/ext/nokogiri/html_element_description.c +272 -0
  13. data/ext/nokogiri/html_element_description.h +10 -0
  14. data/ext/nokogiri/html_entity_lookup.c +30 -0
  15. data/ext/nokogiri/html_entity_lookup.h +8 -0
  16. data/ext/nokogiri/html_sax_parser.c +57 -0
  17. data/ext/nokogiri/html_sax_parser.h +11 -0
  18. data/ext/nokogiri/iconv.dll +0 -0
  19. data/ext/nokogiri/libexslt.dll +0 -0
  20. data/ext/nokogiri/libxml2.dll +0 -0
  21. data/ext/nokogiri/libxslt.dll +0 -0
  22. data/ext/nokogiri/nokogiri.c +81 -0
  23. data/ext/nokogiri/nokogiri.h +149 -0
  24. data/ext/nokogiri/xml_attr.c +92 -0
  25. data/ext/nokogiri/xml_attr.h +9 -0
  26. data/ext/nokogiri/xml_cdata.c +53 -0
  27. data/ext/nokogiri/xml_cdata.h +9 -0
  28. data/ext/nokogiri/xml_comment.c +51 -0
  29. data/ext/nokogiri/xml_comment.h +9 -0
  30. data/ext/nokogiri/xml_document.c +308 -0
  31. data/ext/nokogiri/xml_document.h +21 -0
  32. data/ext/nokogiri/xml_document_fragment.c +48 -0
  33. data/ext/nokogiri/xml_document_fragment.h +10 -0
  34. data/ext/nokogiri/xml_dtd.c +102 -0
  35. data/ext/nokogiri/xml_dtd.h +8 -0
  36. data/ext/nokogiri/xml_entity_reference.c +50 -0
  37. data/ext/nokogiri/xml_entity_reference.h +9 -0
  38. data/ext/nokogiri/xml_io.c +24 -0
  39. data/ext/nokogiri/xml_io.h +10 -0
  40. data/ext/nokogiri/xml_namespace.c +69 -0
  41. data/ext/nokogiri/xml_namespace.h +12 -0
  42. data/ext/nokogiri/xml_node.c +928 -0
  43. data/ext/nokogiri/xml_node.h +14 -0
  44. data/ext/nokogiri/xml_node_set.c +386 -0
  45. data/ext/nokogiri/xml_node_set.h +9 -0
  46. data/ext/nokogiri/xml_processing_instruction.c +54 -0
  47. data/ext/nokogiri/xml_processing_instruction.h +9 -0
  48. data/ext/nokogiri/xml_reader.c +572 -0
  49. data/ext/nokogiri/xml_reader.h +10 -0
  50. data/ext/nokogiri/xml_relax_ng.c +106 -0
  51. data/ext/nokogiri/xml_relax_ng.h +9 -0
  52. data/ext/nokogiri/xml_sax_parser.c +336 -0
  53. data/ext/nokogiri/xml_sax_parser.h +10 -0
  54. data/ext/nokogiri/xml_sax_push_parser.c +86 -0
  55. data/ext/nokogiri/xml_sax_push_parser.h +9 -0
  56. data/ext/nokogiri/xml_schema.c +107 -0
  57. data/ext/nokogiri/xml_schema.h +9 -0
  58. data/ext/nokogiri/xml_syntax_error.c +203 -0
  59. data/ext/nokogiri/xml_syntax_error.h +12 -0
  60. data/ext/nokogiri/xml_text.c +47 -0
  61. data/ext/nokogiri/xml_text.h +9 -0
  62. data/ext/nokogiri/xml_xpath.c +53 -0
  63. data/ext/nokogiri/xml_xpath.h +11 -0
  64. data/ext/nokogiri/xml_xpath_context.c +252 -0
  65. data/ext/nokogiri/xml_xpath_context.h +9 -0
  66. data/ext/nokogiri/xslt_stylesheet.c +131 -0
  67. data/ext/nokogiri/xslt_stylesheet.h +9 -0
  68. data/ext/nokogiri/zlib1.dll +0 -0
  69. data/lib/action-nokogiri.rb +36 -0
  70. data/lib/nokogiri.rb +110 -0
  71. data/lib/nokogiri/1.8/nokogiri.so +0 -0
  72. data/lib/nokogiri/1.9/nokogiri.so +0 -0
  73. data/lib/nokogiri/css.rb +25 -0
  74. data/lib/nokogiri/css/generated_parser.rb +748 -0
  75. data/lib/nokogiri/css/generated_tokenizer.rb +144 -0
  76. data/lib/nokogiri/css/node.rb +107 -0
  77. data/lib/nokogiri/css/parser.rb +82 -0
  78. data/lib/nokogiri/css/parser.y +227 -0
  79. data/lib/nokogiri/css/syntax_error.rb +7 -0
  80. data/lib/nokogiri/css/tokenizer.rb +11 -0
  81. data/lib/nokogiri/css/tokenizer.rex +54 -0
  82. data/lib/nokogiri/css/xpath_visitor.rb +172 -0
  83. data/lib/nokogiri/decorators.rb +2 -0
  84. data/lib/nokogiri/decorators/hpricot.rb +3 -0
  85. data/lib/nokogiri/decorators/hpricot/node.rb +56 -0
  86. data/lib/nokogiri/decorators/hpricot/node_set.rb +54 -0
  87. data/lib/nokogiri/decorators/hpricot/xpath_visitor.rb +30 -0
  88. data/lib/nokogiri/decorators/slop.rb +33 -0
  89. data/lib/nokogiri/ffi/html/document.rb +37 -0
  90. data/lib/nokogiri/ffi/html/element_description.rb +85 -0
  91. data/lib/nokogiri/ffi/html/entity_lookup.rb +16 -0
  92. data/lib/nokogiri/ffi/html/sax/parser.rb +21 -0
  93. data/lib/nokogiri/ffi/io_callbacks.rb +32 -0
  94. data/lib/nokogiri/ffi/libxml.rb +314 -0
  95. data/lib/nokogiri/ffi/structs/common_node.rb +26 -0
  96. data/lib/nokogiri/ffi/structs/html_elem_desc.rb +24 -0
  97. data/lib/nokogiri/ffi/structs/html_entity_desc.rb +13 -0
  98. data/lib/nokogiri/ffi/structs/xml_alloc.rb +16 -0
  99. data/lib/nokogiri/ffi/structs/xml_attr.rb +19 -0
  100. data/lib/nokogiri/ffi/structs/xml_buffer.rb +16 -0
  101. data/lib/nokogiri/ffi/structs/xml_document.rb +108 -0
  102. data/lib/nokogiri/ffi/structs/xml_dtd.rb +26 -0
  103. data/lib/nokogiri/ffi/structs/xml_node.rb +28 -0
  104. data/lib/nokogiri/ffi/structs/xml_node_set.rb +53 -0
  105. data/lib/nokogiri/ffi/structs/xml_notation.rb +11 -0
  106. data/lib/nokogiri/ffi/structs/xml_ns.rb +15 -0
  107. data/lib/nokogiri/ffi/structs/xml_relax_ng.rb +14 -0
  108. data/lib/nokogiri/ffi/structs/xml_sax_handler.rb +51 -0
  109. data/lib/nokogiri/ffi/structs/xml_sax_push_parser_context.rb +14 -0
  110. data/lib/nokogiri/ffi/structs/xml_schema.rb +13 -0
  111. data/lib/nokogiri/ffi/structs/xml_syntax_error.rb +31 -0
  112. data/lib/nokogiri/ffi/structs/xml_text_reader.rb +12 -0
  113. data/lib/nokogiri/ffi/structs/xml_xpath_context.rb +37 -0
  114. data/lib/nokogiri/ffi/structs/xml_xpath_object.rb +35 -0
  115. data/lib/nokogiri/ffi/structs/xml_xpath_parser_context.rb +20 -0
  116. data/lib/nokogiri/ffi/structs/xslt_stylesheet.rb +13 -0
  117. data/lib/nokogiri/ffi/xml/attr.rb +41 -0
  118. data/lib/nokogiri/ffi/xml/cdata.rb +19 -0
  119. data/lib/nokogiri/ffi/xml/comment.rb +18 -0
  120. data/lib/nokogiri/ffi/xml/document.rb +107 -0
  121. data/lib/nokogiri/ffi/xml/document_fragment.rb +26 -0
  122. data/lib/nokogiri/ffi/xml/dtd.rb +42 -0
  123. data/lib/nokogiri/ffi/xml/entity_reference.rb +19 -0
  124. data/lib/nokogiri/ffi/xml/namespace.rb +38 -0
  125. data/lib/nokogiri/ffi/xml/node.rb +380 -0
  126. data/lib/nokogiri/ffi/xml/node_set.rb +130 -0
  127. data/lib/nokogiri/ffi/xml/processing_instruction.rb +20 -0
  128. data/lib/nokogiri/ffi/xml/reader.rb +217 -0
  129. data/lib/nokogiri/ffi/xml/relax_ng.rb +51 -0
  130. data/lib/nokogiri/ffi/xml/sax/parser.rb +148 -0
  131. data/lib/nokogiri/ffi/xml/sax/push_parser.rb +38 -0
  132. data/lib/nokogiri/ffi/xml/schema.rb +55 -0
  133. data/lib/nokogiri/ffi/xml/syntax_error.rb +76 -0
  134. data/lib/nokogiri/ffi/xml/text.rb +18 -0
  135. data/lib/nokogiri/ffi/xml/xpath.rb +19 -0
  136. data/lib/nokogiri/ffi/xml/xpath_context.rb +135 -0
  137. data/lib/nokogiri/ffi/xslt/stylesheet.rb +47 -0
  138. data/lib/nokogiri/hpricot.rb +62 -0
  139. data/lib/nokogiri/html.rb +34 -0
  140. data/lib/nokogiri/html/builder.rb +35 -0
  141. data/lib/nokogiri/html/document.rb +71 -0
  142. data/lib/nokogiri/html/document_fragment.rb +15 -0
  143. data/lib/nokogiri/html/element_description.rb +23 -0
  144. data/lib/nokogiri/html/entity_lookup.rb +13 -0
  145. data/lib/nokogiri/html/sax/parser.rb +47 -0
  146. data/lib/nokogiri/nokogiri.rb +1 -0
  147. data/lib/nokogiri/syntax_error.rb +4 -0
  148. data/lib/nokogiri/version.rb +29 -0
  149. data/lib/nokogiri/version_warning.rb +11 -0
  150. data/lib/nokogiri/xml.rb +62 -0
  151. data/lib/nokogiri/xml/attr.rb +9 -0
  152. data/lib/nokogiri/xml/builder.rb +254 -0
  153. data/lib/nokogiri/xml/cdata.rb +11 -0
  154. data/lib/nokogiri/xml/document.rb +100 -0
  155. data/lib/nokogiri/xml/document_fragment.rb +49 -0
  156. data/lib/nokogiri/xml/dtd.rb +11 -0
  157. data/lib/nokogiri/xml/entity_declaration.rb +11 -0
  158. data/lib/nokogiri/xml/fragment_handler.rb +55 -0
  159. data/lib/nokogiri/xml/namespace.rb +7 -0
  160. data/lib/nokogiri/xml/node.rb +745 -0
  161. data/lib/nokogiri/xml/node/save_options.rb +42 -0
  162. data/lib/nokogiri/xml/node_set.rb +238 -0
  163. data/lib/nokogiri/xml/notation.rb +6 -0
  164. data/lib/nokogiri/xml/parse_options.rb +80 -0
  165. data/lib/nokogiri/xml/processing_instruction.rb +8 -0
  166. data/lib/nokogiri/xml/reader.rb +66 -0
  167. data/lib/nokogiri/xml/relax_ng.rb +32 -0
  168. data/lib/nokogiri/xml/sax.rb +3 -0
  169. data/lib/nokogiri/xml/sax/document.rb +143 -0
  170. data/lib/nokogiri/xml/sax/parser.rb +101 -0
  171. data/lib/nokogiri/xml/sax/push_parser.rb +60 -0
  172. data/lib/nokogiri/xml/schema.rb +65 -0
  173. data/lib/nokogiri/xml/syntax_error.rb +34 -0
  174. data/lib/nokogiri/xml/xpath.rb +10 -0
  175. data/lib/nokogiri/xml/xpath/syntax_error.rb +8 -0
  176. data/lib/nokogiri/xml/xpath_context.rb +16 -0
  177. data/lib/nokogiri/xslt.rb +48 -0
  178. data/lib/nokogiri/xslt/stylesheet.rb +25 -0
  179. data/lib/xsd/xmlparser/nokogiri.rb +64 -0
  180. data/tasks/test.rb +161 -0
  181. data/test/css/test_nthiness.rb +160 -0
  182. data/test/css/test_parser.rb +277 -0
  183. data/test/css/test_tokenizer.rb +176 -0
  184. data/test/css/test_xpath_visitor.rb +76 -0
  185. data/test/ffi/test_document.rb +35 -0
  186. data/test/files/address_book.rlx +12 -0
  187. data/test/files/address_book.xml +10 -0
  188. data/test/files/dont_hurt_em_why.xml +422 -0
  189. data/test/files/exslt.xml +8 -0
  190. data/test/files/exslt.xslt +35 -0
  191. data/test/files/po.xml +32 -0
  192. data/test/files/po.xsd +66 -0
  193. data/test/files/staff.xml +59 -0
  194. data/test/files/staff.xslt +32 -0
  195. data/test/files/tlm.html +850 -0
  196. data/test/helper.rb +123 -0
  197. data/test/hpricot/files/basic.xhtml +17 -0
  198. data/test/hpricot/files/boingboing.html +2266 -0
  199. data/test/hpricot/files/cy0.html +3653 -0
  200. data/test/hpricot/files/immob.html +400 -0
  201. data/test/hpricot/files/pace_application.html +1320 -0
  202. data/test/hpricot/files/tenderlove.html +16 -0
  203. data/test/hpricot/files/uswebgen.html +220 -0
  204. data/test/hpricot/files/utf8.html +1054 -0
  205. data/test/hpricot/files/week9.html +1723 -0
  206. data/test/hpricot/files/why.xml +19 -0
  207. data/test/hpricot/load_files.rb +11 -0
  208. data/test/hpricot/test_alter.rb +68 -0
  209. data/test/hpricot/test_builder.rb +20 -0
  210. data/test/hpricot/test_parser.rb +426 -0
  211. data/test/hpricot/test_paths.rb +15 -0
  212. data/test/hpricot/test_preserved.rb +77 -0
  213. data/test/hpricot/test_xml.rb +30 -0
  214. data/test/html/sax/test_parser.rb +52 -0
  215. data/test/html/test_builder.rb +156 -0
  216. data/test/html/test_document.rb +361 -0
  217. data/test/html/test_document_encoding.rb +46 -0
  218. data/test/html/test_document_fragment.rb +97 -0
  219. data/test/html/test_element_description.rb +95 -0
  220. data/test/html/test_named_characters.rb +14 -0
  221. data/test/html/test_node.rb +165 -0
  222. data/test/test_convert_xpath.rb +186 -0
  223. data/test/test_css_cache.rb +56 -0
  224. data/test/test_gc.rb +15 -0
  225. data/test/test_memory_leak.rb +77 -0
  226. data/test/test_nokogiri.rb +127 -0
  227. data/test/test_reader.rb +316 -0
  228. data/test/test_xslt_transforms.rb +131 -0
  229. data/test/xml/node/test_save_options.rb +20 -0
  230. data/test/xml/node/test_subclass.rb +44 -0
  231. data/test/xml/sax/test_parser.rb +169 -0
  232. data/test/xml/sax/test_push_parser.rb +92 -0
  233. data/test/xml/test_attr.rb +38 -0
  234. data/test/xml/test_builder.rb +73 -0
  235. data/test/xml/test_cdata.rb +38 -0
  236. data/test/xml/test_comment.rb +23 -0
  237. data/test/xml/test_document.rb +397 -0
  238. data/test/xml/test_document_encoding.rb +26 -0
  239. data/test/xml/test_document_fragment.rb +76 -0
  240. data/test/xml/test_dtd.rb +42 -0
  241. data/test/xml/test_dtd_encoding.rb +31 -0
  242. data/test/xml/test_entity_reference.rb +21 -0
  243. data/test/xml/test_namespace.rb +43 -0
  244. data/test/xml/test_node.rb +808 -0
  245. data/test/xml/test_node_attributes.rb +34 -0
  246. data/test/xml/test_node_encoding.rb +84 -0
  247. data/test/xml/test_node_set.rb +368 -0
  248. data/test/xml/test_parse_options.rb +52 -0
  249. data/test/xml/test_processing_instruction.rb +30 -0
  250. data/test/xml/test_reader_encoding.rb +126 -0
  251. data/test/xml/test_relax_ng.rb +60 -0
  252. data/test/xml/test_schema.rb +65 -0
  253. data/test/xml/test_text.rb +18 -0
  254. data/test/xml/test_unparented_node.rb +381 -0
  255. data/test/xml/test_xpath.rb +106 -0
  256. metadata +409 -0
@@ -0,0 +1,277 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', "helper"))
2
+
3
+ module Nokogiri
4
+ module CSS
5
+ class TestParser < Nokogiri::TestCase
6
+ def setup
7
+ super
8
+ @parser = Nokogiri::CSS::Parser.new
9
+ end
10
+
11
+ def test_extra_single_quote
12
+ assert_raises(CSS::SyntaxError) { @parser.parse("'") }
13
+ end
14
+
15
+ def test_syntax_error_raised
16
+ assert_raises(CSS::SyntaxError) { @parser.parse("a[x=]") }
17
+ end
18
+
19
+ def test_find_by_type
20
+ ast = @parser.parse("a:nth-child(2)").first
21
+ matches = ast.find_by_type(
22
+ [:CONDITIONAL_SELECTOR,
23
+ [:ELEMENT_NAME],
24
+ [:PSEUDO_CLASS,
25
+ [:FUNCTION]
26
+ ]
27
+ ]
28
+ )
29
+ assert_equal(1, matches.length)
30
+ assert_equal(ast, matches.first)
31
+ end
32
+
33
+ def test_to_type
34
+ ast = @parser.parse("a:nth-child(2)").first
35
+ assert_equal(
36
+ [:CONDITIONAL_SELECTOR,
37
+ [:ELEMENT_NAME],
38
+ [:PSEUDO_CLASS,
39
+ [:FUNCTION]
40
+ ]
41
+ ], ast.to_type
42
+ )
43
+ end
44
+
45
+ def test_to_a
46
+ asts = @parser.parse("a:nth-child(2)")
47
+ assert_equal(
48
+ [:CONDITIONAL_SELECTOR,
49
+ [:ELEMENT_NAME, ["a"]],
50
+ [:PSEUDO_CLASS,
51
+ [:FUNCTION, ["nth-child("], ["2"]]
52
+ ]
53
+ ], asts.first.to_a
54
+ )
55
+ end
56
+
57
+ def test_dashmatch
58
+ assert_xpath "//a[@class = 'bar' or starts-with(@class, concat('bar', '-'))]",
59
+ @parser.parse("a[@class|='bar']")
60
+ assert_xpath "//a[@class = 'bar' or starts-with(@class, concat('bar', '-'))]",
61
+ @parser.parse("a[@class |= 'bar']")
62
+ end
63
+
64
+ def test_includes
65
+ assert_xpath "//a[contains(concat(\" \", @class, \" \"),concat(\" \", 'bar', \" \"))]",
66
+ @parser.parse("a[@class~='bar']")
67
+ assert_xpath "//a[contains(concat(\" \", @class, \" \"),concat(\" \", 'bar', \" \"))]",
68
+ @parser.parse("a[@class ~= 'bar']")
69
+ end
70
+
71
+ def test_function_with_arguments
72
+ assert_xpath "//*[position() = 2 and self::a]",
73
+ @parser.parse("a[2]")
74
+ assert_xpath "//*[position() = 2 and self::a]",
75
+ @parser.parse("a:nth-child(2)")
76
+ end
77
+
78
+ def test_carrot
79
+ assert_xpath "//a[starts-with(@id, 'Boing')]",
80
+ @parser.parse("a[id^='Boing']")
81
+ assert_xpath "//a[starts-with(@id, 'Boing')]",
82
+ @parser.parse("a[id ^= 'Boing']")
83
+ end
84
+
85
+ def test_suffix_match
86
+ assert_xpath "//a[substring(@id, string-length(@id) - string-length('Boing') + 1, string-length('Boing')) = 'Boing']",
87
+ @parser.parse("a[id$='Boing']")
88
+ assert_xpath "//a[substring(@id, string-length(@id) - string-length('Boing') + 1, string-length('Boing')) = 'Boing']",
89
+ @parser.parse("a[id $= 'Boing']")
90
+ end
91
+
92
+ def test_attributes_with_at
93
+ ## This is non standard CSS
94
+ assert_xpath "//a[@id = 'Boing']",
95
+ @parser.parse("a[@id='Boing']")
96
+ assert_xpath "//a[@id = 'Boing']",
97
+ @parser.parse("a[@id = 'Boing']")
98
+ end
99
+
100
+ def test_attributes_with_at_and_stuff
101
+ ## This is non standard CSS
102
+ assert_xpath "//a[@id = 'Boing']//div",
103
+ @parser.parse("a[@id='Boing'] div")
104
+ end
105
+
106
+ def test_not_equal
107
+ ## This is non standard CSS
108
+ assert_xpath "//a[child::text() != 'Boing']",
109
+ @parser.parse("a[text()!='Boing']")
110
+ assert_xpath "//a[child::text() != 'Boing']",
111
+ @parser.parse("a[text() != 'Boing']")
112
+ end
113
+
114
+ def test_function
115
+ ## This is non standard CSS
116
+ assert_xpath "//a[child::text()]",
117
+ @parser.parse("a[text()]")
118
+
119
+ ## This is non standard CSS
120
+ assert_xpath "//child::text()",
121
+ @parser.parse("text()")
122
+
123
+ ## This is non standard CSS
124
+ assert_xpath "//a[contains(child::text(), 'Boing')]",
125
+ @parser.parse("a[text()*='Boing']")
126
+ assert_xpath "//a[contains(child::text(), 'Boing')]",
127
+ @parser.parse("a[text() *= 'Boing']")
128
+
129
+ ## This is non standard CSS
130
+ assert_xpath "//script//comment()",
131
+ @parser.parse("script comment()")
132
+ end
133
+
134
+ def test_nonstandard_nth_selectors
135
+ ## These are non standard CSS
136
+ assert_xpath '//a[position() = 99]', @parser.parse('a:eq(99)')
137
+ assert_xpath '//a[position() = 1]', @parser.parse('a:first') # no parens
138
+ assert_xpath '//a[position() = last()]', @parser.parse('a:last') # no parens
139
+ assert_xpath '//a[position() = 99]', @parser.parse('a:nth(99)')
140
+ assert_xpath '//a[position() = 1]', @parser.parse('a:first()')
141
+ assert_xpath '//a[position() = last()]', @parser.parse('a:last()')
142
+ assert_xpath '//a[node()]', @parser.parse('a:parent')
143
+ end
144
+
145
+ def test_standard_nth_selectors
146
+ assert_xpath '//a[position() = 99]', @parser.parse('a:nth-of-type(99)')
147
+ assert_xpath '//a[position() = 1]', @parser.parse('a:first-of-type()')
148
+ assert_xpath '//a[position() = last()]', @parser.parse('a:last-of-type()')
149
+ assert_xpath '//a[position() = 1]', @parser.parse('a:first-of-type') # no parens
150
+ assert_xpath '//a[position() = last()]', @parser.parse('a:last-of-type') # no parens
151
+ assert_xpath '//a[position() = last() - 99]', @parser.parse('a:nth-last-of-type(99)')
152
+ assert_xpath '//a[position() = last() - 99]', @parser.parse('a:nth-last-of-type(99)')
153
+ end
154
+
155
+ def test_nth_child_selectors
156
+ assert_xpath '//*[position() = 1 and self::a]', @parser.parse('a:first-child')
157
+ assert_xpath '//*[position() = last() and self::a]', @parser.parse('a:last-child')
158
+ assert_xpath '//*[position() = 99 and self::a]', @parser.parse('a:nth-child(99)')
159
+ assert_xpath '//*[position() = last() - 99 and self::a]', @parser.parse('a:nth-last-child(99)')
160
+ end
161
+
162
+ def test_miscellaneous_selectors
163
+ assert_xpath '//*[last() = 1 and self::a]',
164
+ @parser.parse('a:only-child')
165
+ assert_xpath '//a[last() = 1]', @parser.parse('a:only-of-type')
166
+ assert_xpath '//a[not(node())]', @parser.parse('a:empty')
167
+ end
168
+
169
+ def test_nth_a_n_plus_b
170
+ assert_xpath '//a[(position() mod 2) = 0]', @parser.parse('a:nth-of-type(2n)')
171
+ assert_xpath '//a[(position() >= 1) and (((position()-1) mod 2) = 0)]', @parser.parse('a:nth-of-type(2n+1)')
172
+ assert_xpath '//a[(position() mod 2) = 0]', @parser.parse('a:nth-of-type(even)')
173
+ assert_xpath '//a[(position() >= 1) and (((position()-1) mod 2) = 0)]', @parser.parse('a:nth-of-type(odd)')
174
+ assert_xpath '//a[(position() >= 3) and (((position()-3) mod 4) = 0)]', @parser.parse('a:nth-of-type(4n+3)')
175
+ assert_xpath '//a[(position() <= 3) and (((position()-3) mod 1) = 0)]', @parser.parse('a:nth-of-type(-1n+3)')
176
+ assert_xpath '//a[(position() <= 3) and (((position()-3) mod 1) = 0)]', @parser.parse('a:nth-of-type(-n+3)')
177
+ assert_xpath '//a[(position() >= 3) and (((position()-3) mod 1) = 0)]', @parser.parse('a:nth-of-type(1n+3)')
178
+ assert_xpath '//a[(position() >= 3) and (((position()-3) mod 1) = 0)]', @parser.parse('a:nth-of-type(n+3)')
179
+ end
180
+
181
+ def test_preceding_selector
182
+ assert_xpath "//F[preceding-sibling::E]",
183
+ @parser.parse("E ~ F")
184
+ end
185
+
186
+ def test_direct_preceding_selector
187
+ assert_xpath "//E/following-sibling::*[1]/self::F",
188
+ @parser.parse("E + F")
189
+ end
190
+
191
+ def test_attribute
192
+ assert_xpath "//h1[@a = 'Tender Lovemaking']",
193
+ @parser.parse("h1[a='Tender Lovemaking']")
194
+ end
195
+
196
+ def test_id
197
+ assert_xpath "//*[@id = 'foo']", @parser.parse('#foo')
198
+ end
199
+
200
+ def test_pseudo_class_no_ident
201
+ assert_xpath "//*[link(.)]", @parser.parse(':link')
202
+ end
203
+
204
+ def test_pseudo_class
205
+ assert_xpath "//a[link(.)]", @parser.parse('a:link')
206
+ assert_xpath "//a[visited(.)]", @parser.parse('a:visited')
207
+ assert_xpath "//a[hover(.)]", @parser.parse('a:hover')
208
+ assert_xpath "//a[active(.)]", @parser.parse('a:active')
209
+ assert_xpath "//a[active(.) and contains(concat(' ', @class, ' '), ' foo ')]",
210
+ @parser.parse('a:active.foo')
211
+ end
212
+
213
+ def test_star
214
+ assert_xpath "//*", @parser.parse('*')
215
+ assert_xpath "//*[contains(concat(' ', @class, ' '), ' pastoral ')]",
216
+ @parser.parse('*.pastoral')
217
+ end
218
+
219
+ def test_class
220
+ assert_xpath "//*[contains(concat(' ', @class, ' '), ' a ') and contains(concat(' ', @class, ' '), ' b ')]",
221
+ @parser.parse('.a.b')
222
+ assert_xpath "//*[contains(concat(' ', @class, ' '), ' awesome ')]",
223
+ @parser.parse('.awesome')
224
+ assert_xpath "//foo[contains(concat(' ', @class, ' '), ' awesome ')]",
225
+ @parser.parse('foo.awesome')
226
+ assert_xpath "//foo//*[contains(concat(' ', @class, ' '), ' awesome ')]",
227
+ @parser.parse('foo .awesome')
228
+ end
229
+
230
+ def test_not_so_simple_not
231
+ assert_xpath "//*[@id = 'p' and not(contains(concat(' ', @class, ' '), ' a '))]",
232
+ @parser.parse('#p:not(.a)')
233
+ assert_xpath "//p[contains(concat(' ', @class, ' '), ' a ') and not(contains(concat(' ', @class, ' '), ' b '))]",
234
+ @parser.parse('p.a:not(.b)')
235
+ assert_xpath "//p[@a = 'foo' and not(contains(concat(' ', @class, ' '), ' b '))]",
236
+ @parser.parse("p[a='foo']:not(.b)")
237
+ end
238
+
239
+ def test_ident
240
+ assert_xpath '//x', @parser.parse('x')
241
+ end
242
+
243
+ def test_parse_space
244
+ assert_xpath '//x//y', @parser.parse('x y')
245
+ end
246
+
247
+ def test_parse_descendant
248
+ assert_xpath '//x/y', @parser.parse('x > y')
249
+ end
250
+
251
+ def test_parse_slash
252
+ ## This is non standard CSS
253
+ assert_xpath '//x/y', @parser.parse('x/y')
254
+ end
255
+
256
+ def test_parse_doubleslash
257
+ ## This is non standard CSS
258
+ assert_xpath '//x//y', @parser.parse('x//y')
259
+ end
260
+
261
+ def test_multi_path
262
+ assert_xpath ['//x/y', '//y/z'], @parser.parse('x > y, y > z')
263
+ assert_xpath ['//x/y', '//y/z'], @parser.parse('x > y,y > z')
264
+ ###
265
+ # TODO: should we make this work?
266
+ # assert_xpath ['//x/y', '//y/z'], @parser.parse('x > y | y > z')
267
+ end
268
+
269
+ def assert_xpath expecteds, asts
270
+ expecteds = [expecteds].flatten
271
+ expecteds.zip(asts).each do |expected, actual|
272
+ assert_equal expected, actual.to_xpath
273
+ end
274
+ end
275
+ end
276
+ end
277
+ end
@@ -0,0 +1,176 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', "helper"))
2
+
3
+ module Nokogiri
4
+ module CSS
5
+ class TestTokenizer < Nokogiri::TestCase
6
+ def setup
7
+ super
8
+ @scanner = Nokogiri::CSS::Tokenizer.new
9
+ end
10
+
11
+ def test_tokenize_bad_single_quote
12
+ @scanner.scan("'")
13
+ assert_tokens([["'", "'"]], @scanner)
14
+ end
15
+
16
+ def test_not_equal
17
+ @scanner.scan("h1[a!='Tender Lovemaking']")
18
+ assert_tokens([ [:IDENT, 'h1'],
19
+ [:LSQUARE, '['],
20
+ [:IDENT, 'a'],
21
+ [:NOT_EQUAL, '!='],
22
+ [:STRING, "'Tender Lovemaking'"],
23
+ [:RSQUARE, ']'],
24
+ ], @scanner)
25
+ end
26
+
27
+ def test_negation
28
+ @scanner.scan("p:not(.a)")
29
+ assert_tokens([ [:IDENT, 'p'],
30
+ [:NOT, ':not('],
31
+ ['.', '.'],
32
+ [:IDENT, 'a'],
33
+ [:RPAREN, ')'],
34
+ ], @scanner)
35
+ end
36
+
37
+ def test_function
38
+ @scanner.scan("script comment()")
39
+ assert_tokens([ [:IDENT, 'script'],
40
+ [:S, ' '],
41
+ [:FUNCTION, 'comment('],
42
+ [:RPAREN, ')'],
43
+ ], @scanner)
44
+ end
45
+
46
+ def test_preceding_selector
47
+ @scanner.scan("E ~ F")
48
+ assert_tokens([ [:IDENT, 'E'],
49
+ [:TILDE, ' ~ '],
50
+ [:IDENT, 'F'],
51
+ ], @scanner)
52
+ end
53
+
54
+ def test_scan_attribute_string
55
+ @scanner.scan("h1[a='Tender Lovemaking']")
56
+ assert_tokens([ [:IDENT, 'h1'],
57
+ [:LSQUARE, '['],
58
+ [:IDENT, 'a'],
59
+ [:EQUAL, '='],
60
+ [:STRING, "'Tender Lovemaking'"],
61
+ [:RSQUARE, ']'],
62
+ ], @scanner)
63
+ @scanner.scan('h1[a="Tender Lovemaking"]')
64
+ assert_tokens([ [:IDENT, 'h1'],
65
+ [:LSQUARE, '['],
66
+ [:IDENT, 'a'],
67
+ [:EQUAL, '='],
68
+ [:STRING, '"Tender Lovemaking"'],
69
+ [:RSQUARE, ']'],
70
+ ], @scanner)
71
+ end
72
+
73
+ def test_scan_id
74
+ @scanner.scan('#foo')
75
+ assert_tokens([ [:HASH, '#foo'] ], @scanner)
76
+ end
77
+
78
+ def test_scan_pseudo
79
+ @scanner.scan('a:visited')
80
+ assert_tokens([ [:IDENT, 'a'],
81
+ [':', ':'],
82
+ [:IDENT, 'visited']
83
+ ], @scanner)
84
+ end
85
+
86
+ def test_scan_star
87
+ @scanner.scan('*')
88
+ assert_tokens([ ['*', '*'], ], @scanner)
89
+ end
90
+
91
+ def test_scan_class
92
+ @scanner.scan('x.awesome')
93
+ assert_tokens([ [:IDENT, 'x'],
94
+ ['.', '.'],
95
+ [:IDENT, 'awesome'],
96
+ ], @scanner)
97
+ end
98
+
99
+ def test_scan_greater
100
+ @scanner.scan('x > y')
101
+ assert_tokens([ [:IDENT, 'x'],
102
+ [:GREATER, ' > '],
103
+ [:IDENT, 'y']
104
+ ], @scanner)
105
+ end
106
+
107
+ def test_scan_slash
108
+ @scanner.scan('x/y')
109
+ assert_tokens([ [:IDENT, 'x'],
110
+ [:SLASH, '/'],
111
+ [:IDENT, 'y']
112
+ ], @scanner)
113
+ end
114
+
115
+ def test_scan_doubleslash
116
+ @scanner.scan('x//y')
117
+ assert_tokens([ [:IDENT, 'x'],
118
+ [:DOUBLESLASH, '//'],
119
+ [:IDENT, 'y']
120
+ ], @scanner)
121
+ end
122
+
123
+ def test_scan_function_selector
124
+ @scanner.scan('x:eq(0)')
125
+ assert_tokens([ [:IDENT, 'x'],
126
+ [':', ':'],
127
+ [:FUNCTION, 'eq('],
128
+ [:NUMBER, "0"],
129
+ [:RPAREN, ')'],
130
+ ], @scanner)
131
+ end
132
+
133
+ def test_scan_an_plus_b
134
+ @scanner.scan('x:nth-child(5n+3)')
135
+ assert_tokens([ [:IDENT, 'x'],
136
+ [':', ':'],
137
+ [:FUNCTION, 'nth-child('],
138
+ [:NUMBER, '5'],
139
+ [:IDENT, 'n'],
140
+ [:PLUS, '+'],
141
+ [:NUMBER, '3'],
142
+ [:RPAREN, ')'],
143
+ ], @scanner)
144
+
145
+ @scanner.scan('x:nth-child(-1n+3)')
146
+ assert_tokens([ [:IDENT, 'x'],
147
+ [':', ':'],
148
+ [:FUNCTION, 'nth-child('],
149
+ [:NUMBER, '-1'],
150
+ [:IDENT, 'n'],
151
+ [:PLUS, '+'],
152
+ [:NUMBER, '3'],
153
+ [:RPAREN, ')'],
154
+ ], @scanner)
155
+
156
+ @scanner.scan('x:nth-child(-n+3)')
157
+ assert_tokens([ [:IDENT, 'x'],
158
+ [':', ':'],
159
+ [:FUNCTION, 'nth-child('],
160
+ [:IDENT, '-n'],
161
+ [:PLUS, '+'],
162
+ [:NUMBER, '3'],
163
+ [:RPAREN, ')'],
164
+ ], @scanner)
165
+ end
166
+
167
+ def assert_tokens(tokens, scanner)
168
+ toks = []
169
+ while tok = @scanner.next_token
170
+ toks << tok
171
+ end
172
+ assert_equal(tokens, toks)
173
+ end
174
+ end
175
+ end
176
+ end