rubyjedi-nokogiri_java 1.4.0.20100513161003-java

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.
Files changed (285) hide show
  1. data/.autotest +26 -0
  2. data/CHANGELOG.ja.rdoc +330 -0
  3. data/CHANGELOG.rdoc +341 -0
  4. data/Manifest.txt +277 -0
  5. data/README.ja.rdoc +105 -0
  6. data/README.rdoc +125 -0
  7. data/Rakefile +307 -0
  8. data/bin/nokogiri +49 -0
  9. data/deps.rip +5 -0
  10. data/ext/nokogiri/extconf.rb +149 -0
  11. data/ext/nokogiri/html_document.c +145 -0
  12. data/ext/nokogiri/html_document.h +10 -0
  13. data/ext/nokogiri/html_element_description.c +272 -0
  14. data/ext/nokogiri/html_element_description.h +10 -0
  15. data/ext/nokogiri/html_entity_lookup.c +32 -0
  16. data/ext/nokogiri/html_entity_lookup.h +8 -0
  17. data/ext/nokogiri/html_sax_parser_context.c +92 -0
  18. data/ext/nokogiri/html_sax_parser_context.h +11 -0
  19. data/ext/nokogiri/nokogiri.c +96 -0
  20. data/ext/nokogiri/nokogiri.h +148 -0
  21. data/ext/nokogiri/xml_attr.c +92 -0
  22. data/ext/nokogiri/xml_attr.h +9 -0
  23. data/ext/nokogiri/xml_attribute_decl.c +67 -0
  24. data/ext/nokogiri/xml_attribute_decl.h +9 -0
  25. data/ext/nokogiri/xml_cdata.c +54 -0
  26. data/ext/nokogiri/xml_cdata.h +9 -0
  27. data/ext/nokogiri/xml_comment.c +52 -0
  28. data/ext/nokogiri/xml_comment.h +9 -0
  29. data/ext/nokogiri/xml_document.c +386 -0
  30. data/ext/nokogiri/xml_document.h +24 -0
  31. data/ext/nokogiri/xml_document_fragment.c +46 -0
  32. data/ext/nokogiri/xml_document_fragment.h +10 -0
  33. data/ext/nokogiri/xml_dtd.c +192 -0
  34. data/ext/nokogiri/xml_dtd.h +10 -0
  35. data/ext/nokogiri/xml_element_content.c +123 -0
  36. data/ext/nokogiri/xml_element_content.h +10 -0
  37. data/ext/nokogiri/xml_element_decl.c +69 -0
  38. data/ext/nokogiri/xml_element_decl.h +9 -0
  39. data/ext/nokogiri/xml_encoding_handler.c +79 -0
  40. data/ext/nokogiri/xml_encoding_handler.h +8 -0
  41. data/ext/nokogiri/xml_entity_decl.c +97 -0
  42. data/ext/nokogiri/xml_entity_decl.h +10 -0
  43. data/ext/nokogiri/xml_entity_reference.c +50 -0
  44. data/ext/nokogiri/xml_entity_reference.h +9 -0
  45. data/ext/nokogiri/xml_io.c +31 -0
  46. data/ext/nokogiri/xml_io.h +11 -0
  47. data/ext/nokogiri/xml_namespace.c +82 -0
  48. data/ext/nokogiri/xml_namespace.h +13 -0
  49. data/ext/nokogiri/xml_node.c +1080 -0
  50. data/ext/nokogiri/xml_node.h +13 -0
  51. data/ext/nokogiri/xml_node_set.c +405 -0
  52. data/ext/nokogiri/xml_node_set.h +9 -0
  53. data/ext/nokogiri/xml_processing_instruction.c +54 -0
  54. data/ext/nokogiri/xml_processing_instruction.h +9 -0
  55. data/ext/nokogiri/xml_reader.c +593 -0
  56. data/ext/nokogiri/xml_reader.h +10 -0
  57. data/ext/nokogiri/xml_relax_ng.c +159 -0
  58. data/ext/nokogiri/xml_relax_ng.h +9 -0
  59. data/ext/nokogiri/xml_sax_parser.c +283 -0
  60. data/ext/nokogiri/xml_sax_parser.h +43 -0
  61. data/ext/nokogiri/xml_sax_parser_context.c +157 -0
  62. data/ext/nokogiri/xml_sax_parser_context.h +10 -0
  63. data/ext/nokogiri/xml_sax_push_parser.c +114 -0
  64. data/ext/nokogiri/xml_sax_push_parser.h +9 -0
  65. data/ext/nokogiri/xml_schema.c +156 -0
  66. data/ext/nokogiri/xml_schema.h +9 -0
  67. data/ext/nokogiri/xml_syntax_error.c +52 -0
  68. data/ext/nokogiri/xml_syntax_error.h +13 -0
  69. data/ext/nokogiri/xml_text.c +48 -0
  70. data/ext/nokogiri/xml_text.h +9 -0
  71. data/ext/nokogiri/xml_xpath.c +53 -0
  72. data/ext/nokogiri/xml_xpath.h +11 -0
  73. data/ext/nokogiri/xml_xpath_context.c +239 -0
  74. data/ext/nokogiri/xml_xpath_context.h +9 -0
  75. data/ext/nokogiri/xslt_stylesheet.c +131 -0
  76. data/ext/nokogiri/xslt_stylesheet.h +9 -0
  77. data/lib/isorelax.jar +0 -0
  78. data/lib/jing.jar +0 -0
  79. data/lib/nekodtd.jar +0 -0
  80. data/lib/nekohtml.jar +0 -0
  81. data/lib/nokogiri.rb +123 -0
  82. data/lib/nokogiri/css.rb +25 -0
  83. data/lib/nokogiri/css/generated_parser.rb +659 -0
  84. data/lib/nokogiri/css/generated_tokenizer.rb +145 -0
  85. data/lib/nokogiri/css/node.rb +99 -0
  86. data/lib/nokogiri/css/parser.rb +82 -0
  87. data/lib/nokogiri/css/parser.y +230 -0
  88. data/lib/nokogiri/css/syntax_error.rb +7 -0
  89. data/lib/nokogiri/css/tokenizer.rb +7 -0
  90. data/lib/nokogiri/css/tokenizer.rex +55 -0
  91. data/lib/nokogiri/css/xpath_visitor.rb +164 -0
  92. data/lib/nokogiri/decorators/slop.rb +33 -0
  93. data/lib/nokogiri/ffi/encoding_handler.rb +42 -0
  94. data/lib/nokogiri/ffi/html/document.rb +28 -0
  95. data/lib/nokogiri/ffi/html/element_description.rb +81 -0
  96. data/lib/nokogiri/ffi/html/entity_lookup.rb +16 -0
  97. data/lib/nokogiri/ffi/html/sax/parser_context.rb +38 -0
  98. data/lib/nokogiri/ffi/io_callbacks.rb +42 -0
  99. data/lib/nokogiri/ffi/libxml.rb +372 -0
  100. data/lib/nokogiri/ffi/structs/common_node.rb +26 -0
  101. data/lib/nokogiri/ffi/structs/html_elem_desc.rb +24 -0
  102. data/lib/nokogiri/ffi/structs/html_entity_desc.rb +13 -0
  103. data/lib/nokogiri/ffi/structs/xml_alloc.rb +16 -0
  104. data/lib/nokogiri/ffi/structs/xml_attr.rb +19 -0
  105. data/lib/nokogiri/ffi/structs/xml_attribute.rb +27 -0
  106. data/lib/nokogiri/ffi/structs/xml_buffer.rb +16 -0
  107. data/lib/nokogiri/ffi/structs/xml_char_encoding_handler.rb +11 -0
  108. data/lib/nokogiri/ffi/structs/xml_document.rb +108 -0
  109. data/lib/nokogiri/ffi/structs/xml_dtd.rb +28 -0
  110. data/lib/nokogiri/ffi/structs/xml_element.rb +26 -0
  111. data/lib/nokogiri/ffi/structs/xml_element_content.rb +17 -0
  112. data/lib/nokogiri/ffi/structs/xml_entity.rb +32 -0
  113. data/lib/nokogiri/ffi/structs/xml_enumeration.rb +12 -0
  114. data/lib/nokogiri/ffi/structs/xml_node.rb +28 -0
  115. data/lib/nokogiri/ffi/structs/xml_node_set.rb +53 -0
  116. data/lib/nokogiri/ffi/structs/xml_notation.rb +11 -0
  117. data/lib/nokogiri/ffi/structs/xml_ns.rb +15 -0
  118. data/lib/nokogiri/ffi/structs/xml_parser_context.rb +19 -0
  119. data/lib/nokogiri/ffi/structs/xml_relax_ng.rb +14 -0
  120. data/lib/nokogiri/ffi/structs/xml_sax_handler.rb +51 -0
  121. data/lib/nokogiri/ffi/structs/xml_sax_push_parser_context.rb +124 -0
  122. data/lib/nokogiri/ffi/structs/xml_schema.rb +13 -0
  123. data/lib/nokogiri/ffi/structs/xml_syntax_error.rb +31 -0
  124. data/lib/nokogiri/ffi/structs/xml_text_reader.rb +12 -0
  125. data/lib/nokogiri/ffi/structs/xml_xpath_context.rb +37 -0
  126. data/lib/nokogiri/ffi/structs/xml_xpath_object.rb +35 -0
  127. data/lib/nokogiri/ffi/structs/xml_xpath_parser_context.rb +20 -0
  128. data/lib/nokogiri/ffi/structs/xslt_stylesheet.rb +13 -0
  129. data/lib/nokogiri/ffi/xml/attr.rb +41 -0
  130. data/lib/nokogiri/ffi/xml/attribute_decl.rb +27 -0
  131. data/lib/nokogiri/ffi/xml/cdata.rb +19 -0
  132. data/lib/nokogiri/ffi/xml/comment.rb +18 -0
  133. data/lib/nokogiri/ffi/xml/document.rb +135 -0
  134. data/lib/nokogiri/ffi/xml/document_fragment.rb +21 -0
  135. data/lib/nokogiri/ffi/xml/dtd.rb +67 -0
  136. data/lib/nokogiri/ffi/xml/element_content.rb +43 -0
  137. data/lib/nokogiri/ffi/xml/element_decl.rb +19 -0
  138. data/lib/nokogiri/ffi/xml/entity_decl.rb +27 -0
  139. data/lib/nokogiri/ffi/xml/entity_reference.rb +19 -0
  140. data/lib/nokogiri/ffi/xml/namespace.rb +44 -0
  141. data/lib/nokogiri/ffi/xml/node.rb +465 -0
  142. data/lib/nokogiri/ffi/xml/node_set.rb +146 -0
  143. data/lib/nokogiri/ffi/xml/processing_instruction.rb +20 -0
  144. data/lib/nokogiri/ffi/xml/reader.rb +227 -0
  145. data/lib/nokogiri/ffi/xml/relax_ng.rb +85 -0
  146. data/lib/nokogiri/ffi/xml/sax/parser.rb +135 -0
  147. data/lib/nokogiri/ffi/xml/sax/parser_context.rb +67 -0
  148. data/lib/nokogiri/ffi/xml/sax/push_parser.rb +55 -0
  149. data/lib/nokogiri/ffi/xml/schema.rb +92 -0
  150. data/lib/nokogiri/ffi/xml/syntax_error.rb +98 -0
  151. data/lib/nokogiri/ffi/xml/text.rb +18 -0
  152. data/lib/nokogiri/ffi/xml/xpath.rb +19 -0
  153. data/lib/nokogiri/ffi/xml/xpath_context.rb +135 -0
  154. data/lib/nokogiri/ffi/xslt/stylesheet.rb +50 -0
  155. data/lib/nokogiri/html.rb +36 -0
  156. data/lib/nokogiri/html/builder.rb +35 -0
  157. data/lib/nokogiri/html/document.rb +88 -0
  158. data/lib/nokogiri/html/document_fragment.rb +15 -0
  159. data/lib/nokogiri/html/element_description.rb +23 -0
  160. data/lib/nokogiri/html/element_description_defaults.rb +671 -0
  161. data/lib/nokogiri/html/entity_lookup.rb +13 -0
  162. data/lib/nokogiri/html/sax/parser.rb +48 -0
  163. data/lib/nokogiri/html/sax/parser_context.rb +16 -0
  164. data/lib/nokogiri/nokogiri.jar +0 -0
  165. data/lib/nokogiri/syntax_error.rb +4 -0
  166. data/lib/nokogiri/version.rb +33 -0
  167. data/lib/nokogiri/version_warning.rb +11 -0
  168. data/lib/nokogiri/xml.rb +67 -0
  169. data/lib/nokogiri/xml/attr.rb +14 -0
  170. data/lib/nokogiri/xml/attribute_decl.rb +18 -0
  171. data/lib/nokogiri/xml/builder.rb +405 -0
  172. data/lib/nokogiri/xml/cdata.rb +11 -0
  173. data/lib/nokogiri/xml/character_data.rb +7 -0
  174. data/lib/nokogiri/xml/document.rb +163 -0
  175. data/lib/nokogiri/xml/document_fragment.rb +73 -0
  176. data/lib/nokogiri/xml/dtd.rb +11 -0
  177. data/lib/nokogiri/xml/element_content.rb +36 -0
  178. data/lib/nokogiri/xml/element_decl.rb +13 -0
  179. data/lib/nokogiri/xml/entity_decl.rb +15 -0
  180. data/lib/nokogiri/xml/fragment_handler.rb +73 -0
  181. data/lib/nokogiri/xml/namespace.rb +13 -0
  182. data/lib/nokogiri/xml/node.rb +730 -0
  183. data/lib/nokogiri/xml/node/save_options.rb +42 -0
  184. data/lib/nokogiri/xml/node_set.rb +318 -0
  185. data/lib/nokogiri/xml/notation.rb +6 -0
  186. data/lib/nokogiri/xml/parse_options.rb +85 -0
  187. data/lib/nokogiri/xml/pp.rb +2 -0
  188. data/lib/nokogiri/xml/pp/character_data.rb +18 -0
  189. data/lib/nokogiri/xml/pp/node.rb +56 -0
  190. data/lib/nokogiri/xml/processing_instruction.rb +8 -0
  191. data/lib/nokogiri/xml/reader.rb +74 -0
  192. data/lib/nokogiri/xml/relax_ng.rb +32 -0
  193. data/lib/nokogiri/xml/sax.rb +4 -0
  194. data/lib/nokogiri/xml/sax/document.rb +160 -0
  195. data/lib/nokogiri/xml/sax/parser.rb +115 -0
  196. data/lib/nokogiri/xml/sax/parser_context.rb +16 -0
  197. data/lib/nokogiri/xml/sax/push_parser.rb +60 -0
  198. data/lib/nokogiri/xml/schema.rb +61 -0
  199. data/lib/nokogiri/xml/syntax_error.rb +43 -0
  200. data/lib/nokogiri/xml/xpath.rb +10 -0
  201. data/lib/nokogiri/xml/xpath/syntax_error.rb +8 -0
  202. data/lib/nokogiri/xml/xpath_context.rb +16 -0
  203. data/lib/nokogiri/xslt.rb +48 -0
  204. data/lib/nokogiri/xslt/stylesheet.rb +25 -0
  205. data/lib/xercesImpl.jar +0 -0
  206. data/lib/xsd/xmlparser/nokogiri.rb +90 -0
  207. data/tasks/test.rb +100 -0
  208. data/test/css/test_nthiness.rb +159 -0
  209. data/test/css/test_parser.rb +282 -0
  210. data/test/css/test_tokenizer.rb +190 -0
  211. data/test/css/test_xpath_visitor.rb +76 -0
  212. data/test/ffi/test_document.rb +35 -0
  213. data/test/files/2ch.html +108 -0
  214. data/test/files/address_book.rlx +12 -0
  215. data/test/files/address_book.xml +10 -0
  216. data/test/files/bar/bar.xsd +4 -0
  217. data/test/files/dont_hurt_em_why.xml +422 -0
  218. data/test/files/exslt.xml +8 -0
  219. data/test/files/exslt.xslt +35 -0
  220. data/test/files/foo/foo.xsd +4 -0
  221. data/test/files/po.xml +32 -0
  222. data/test/files/po.xsd +66 -0
  223. data/test/files/shift_jis.html +10 -0
  224. data/test/files/shift_jis.xml +5 -0
  225. data/test/files/snuggles.xml +3 -0
  226. data/test/files/staff.dtd +10 -0
  227. data/test/files/staff.xml +59 -0
  228. data/test/files/staff.xslt +32 -0
  229. data/test/files/tlm.html +850 -0
  230. data/test/files/valid_bar.xml +2 -0
  231. data/test/helper.rb +137 -0
  232. data/test/html/sax/test_parser.rb +83 -0
  233. data/test/html/sax/test_parser_context.rb +48 -0
  234. data/test/html/test_builder.rb +164 -0
  235. data/test/html/test_document.rb +385 -0
  236. data/test/html/test_document_encoding.rb +77 -0
  237. data/test/html/test_document_fragment.rb +157 -0
  238. data/test/html/test_element_description.rb +98 -0
  239. data/test/html/test_named_characters.rb +14 -0
  240. data/test/html/test_node.rb +242 -0
  241. data/test/html/test_node_encoding.rb +27 -0
  242. data/test/test_convert_xpath.rb +135 -0
  243. data/test/test_css_cache.rb +45 -0
  244. data/test/test_encoding_handler.rb +46 -0
  245. data/test/test_jruby.rb +40 -0
  246. data/test/test_memory_leak.rb +87 -0
  247. data/test/test_nokogiri.rb +140 -0
  248. data/test/test_reader.rb +358 -0
  249. data/test/test_soap4r_sax.rb +52 -0
  250. data/test/test_xslt_transforms.rb +150 -0
  251. data/test/xml/node/test_save_options.rb +20 -0
  252. data/test/xml/node/test_subclass.rb +44 -0
  253. data/test/xml/sax/test_parser.rb +314 -0
  254. data/test/xml/sax/test_parser_context.rb +63 -0
  255. data/test/xml/sax/test_push_parser.rb +135 -0
  256. data/test/xml/test_attr.rb +38 -0
  257. data/test/xml/test_attribute_decl.rb +90 -0
  258. data/test/xml/test_builder.rb +167 -0
  259. data/test/xml/test_cdata.rb +38 -0
  260. data/test/xml/test_comment.rb +29 -0
  261. data/test/xml/test_document.rb +638 -0
  262. data/test/xml/test_document_encoding.rb +26 -0
  263. data/test/xml/test_document_fragment.rb +149 -0
  264. data/test/xml/test_dtd.rb +92 -0
  265. data/test/xml/test_dtd_encoding.rb +33 -0
  266. data/test/xml/test_element_content.rb +56 -0
  267. data/test/xml/test_element_decl.rb +73 -0
  268. data/test/xml/test_entity_decl.rb +83 -0
  269. data/test/xml/test_entity_reference.rb +21 -0
  270. data/test/xml/test_namespace.rb +70 -0
  271. data/test/xml/test_node.rb +740 -0
  272. data/test/xml/test_node_attributes.rb +34 -0
  273. data/test/xml/test_node_encoding.rb +107 -0
  274. data/test/xml/test_node_reparenting.rb +279 -0
  275. data/test/xml/test_node_set.rb +577 -0
  276. data/test/xml/test_parse_options.rb +52 -0
  277. data/test/xml/test_processing_instruction.rb +30 -0
  278. data/test/xml/test_reader_encoding.rb +126 -0
  279. data/test/xml/test_relax_ng.rb +60 -0
  280. data/test/xml/test_schema.rb +89 -0
  281. data/test/xml/test_syntax_error.rb +12 -0
  282. data/test/xml/test_text.rb +30 -0
  283. data/test/xml/test_unparented_node.rb +381 -0
  284. data/test/xml/test_xpath.rb +169 -0
  285. metadata +477 -0
@@ -0,0 +1,159 @@
1
+ require "helper"
2
+
3
+ module Nokogiri
4
+ module CSS
5
+ class TestNthiness < Nokogiri::TestCase
6
+ def setup
7
+ super
8
+ doc = <<EOF
9
+ <html>
10
+ <table>
11
+ <tr><td>row1 </td></tr>
12
+ <tr><td>row2 </td></tr>
13
+ <tr><td>row3 </td></tr>
14
+ <tr><td>row4 </td></tr>
15
+ <tr><td>row5 </td></tr>
16
+ <tr><td>row6 </td></tr>
17
+ <tr><td>row7 </td></tr>
18
+ <tr><td>row8 </td></tr>
19
+ <tr><td>row9 </td></tr>
20
+ <tr><td>row10 </td></tr>
21
+ <tr><td>row11 </td></tr>
22
+ <tr><td>row12 </td></tr>
23
+ <tr><td>row13 </td></tr>
24
+ <tr><td>row14 </td></tr>
25
+ </table>
26
+ <div>
27
+ <b>bold1 </b>
28
+ <i>italic1 </i>
29
+ <b>bold2 </b>
30
+ <i>italic2 </i>
31
+ <p>para1 </p>
32
+ <b>bold3 </b>
33
+ </div>
34
+ <div>
35
+ <p>para2 </p>
36
+ <p>para3 </p>
37
+ </div>
38
+ <div>
39
+ <p>para4 </p>
40
+ </div>
41
+ <p class='empty'></p>
42
+ <p class='not-empty'><b></b></p>
43
+ </html>
44
+ EOF
45
+ @parser = Nokogiri.HTML doc
46
+ end
47
+
48
+
49
+ def test_even
50
+ assert_result_rows [2,4,6,8,10,12,14], @parser.search("table/tr:nth(even)")
51
+ end
52
+
53
+ def test_odd
54
+ assert_result_rows [1,3,5,7,9,11,13], @parser.search("table/tr:nth(odd)")
55
+ end
56
+
57
+ def test_2n
58
+ assert_equal @parser.search("table/tr:nth(even)").inner_text, @parser.search("table/tr:nth(2n)").inner_text
59
+ end
60
+
61
+ def test_2np1
62
+ assert_equal @parser.search("table/tr:nth(odd)").inner_text, @parser.search("table/tr:nth(2n+1)").inner_text
63
+ end
64
+
65
+ def test_4np3
66
+ assert_result_rows [3,7,11], @parser.search("table/tr:nth(4n+3)")
67
+ end
68
+
69
+ def test_3np4
70
+ assert_result_rows [4,7,10,13], @parser.search("table/tr:nth(3n+4)")
71
+ end
72
+
73
+ def test_mnp3
74
+ assert_result_rows [1,2,3], @parser.search("table/tr:nth(-n+3)")
75
+ end
76
+
77
+ def test_np3
78
+ assert_result_rows [3,4,5,6,7,8,9,10,11,12,13,14], @parser.search("table/tr:nth(n+3)")
79
+ end
80
+
81
+ def test_first
82
+ assert_result_rows [1], @parser.search("table/tr:first")
83
+ assert_result_rows [1], @parser.search("table/tr:first()")
84
+ end
85
+
86
+ def test_last
87
+ assert_result_rows [14], @parser.search("table/tr:last")
88
+ assert_result_rows [14], @parser.search("table/tr:last()")
89
+ end
90
+
91
+ def test_first_child
92
+ assert_result_rows [1], @parser.search("div/b:first-child"), "bold"
93
+ assert_result_rows [1], @parser.search("table/tr:first-child")
94
+ end
95
+
96
+ def test_last_child
97
+ assert_result_rows [3], @parser.search("div/b:last-child"), "bold"
98
+ assert_result_rows [14], @parser.search("table/tr:last-child")
99
+ end
100
+
101
+ def test_first_of_type
102
+ assert_result_rows [1], @parser.search("table/tr:first-of-type")
103
+ assert_result_rows [1], @parser.search("div/b:first-of-type"), "bold"
104
+ end
105
+
106
+ def test_last_of_type
107
+ assert_result_rows [14], @parser.search("table/tr:last-of-type")
108
+ assert_result_rows [3], @parser.search("div/b:last-of-type"), "bold"
109
+ end
110
+
111
+ def test_only_of_type
112
+ assert_result_rows [1,4], @parser.search("div/p:only-of-type"), "para"
113
+ end
114
+
115
+ def test_only_child
116
+ assert_result_rows [4], @parser.search("div/p:only-child"), "para"
117
+ end
118
+
119
+ def test_empty
120
+ result = @parser.search("p:empty")
121
+ assert_equal 1, result.size, "unexpected number of rows returned: '#{result.inner_text}'"
122
+ assert_equal 'empty', result.first['class']
123
+ end
124
+
125
+ def test_parent
126
+ result = @parser.search("p:parent")
127
+ assert_equal 5, result.size
128
+ 0.upto(3) do |j|
129
+ assert_equal "para#{j+1} ", result[j].inner_text
130
+ end
131
+ assert_equal "not-empty", result[4]['class']
132
+ end
133
+
134
+ def test_siblings
135
+ doc = <<-EOF
136
+ <html><body><div>
137
+ <p id="1">p1 </p>
138
+ <p id="2">p2 </p>
139
+ <p id="3">p3 </p>
140
+ <p id="4">p4 </p>
141
+ <p id="5">p5 </p>
142
+ EOF
143
+ parser = Nokogiri.HTML doc
144
+ assert_equal 2, parser.search("#3 ~ p").size
145
+ assert_equal "p4 p5 ", parser.search("#3 ~ p").inner_text
146
+ assert_equal 0, parser.search("#5 ~ p").size
147
+
148
+ assert_equal 1, parser.search("#3 + p").size
149
+ assert_equal "p4 ", parser.search("#3 + p").inner_text
150
+ assert_equal 0, parser.search("#5 + p").size
151
+ end
152
+
153
+ def assert_result_rows intarray, result, word="row"
154
+ assert_equal intarray.size, result.size, "unexpected number of rows returned: '#{result.inner_text}'"
155
+ assert_equal intarray.map{|j| "#{word}#{j}"}.join(' '), result.inner_text.strip, result.inner_text
156
+ end
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,282 @@
1
+ require "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_has
58
+ assert_xpath "//a[b]", @parser.parse("a:has(b)")
59
+ assert_xpath "//a[b/c]", @parser.parse("a:has(b > c)")
60
+ end
61
+
62
+ def test_dashmatch
63
+ assert_xpath "//a[@class = 'bar' or starts-with(@class, concat('bar', '-'))]",
64
+ @parser.parse("a[@class|='bar']")
65
+ assert_xpath "//a[@class = 'bar' or starts-with(@class, concat('bar', '-'))]",
66
+ @parser.parse("a[@class |= 'bar']")
67
+ end
68
+
69
+ def test_includes
70
+ assert_xpath "//a[contains(concat(\" \", @class, \" \"),concat(\" \", 'bar', \" \"))]",
71
+ @parser.parse("a[@class~='bar']")
72
+ assert_xpath "//a[contains(concat(\" \", @class, \" \"),concat(\" \", 'bar', \" \"))]",
73
+ @parser.parse("a[@class ~= 'bar']")
74
+ end
75
+
76
+ def test_function_with_arguments
77
+ assert_xpath "//*[position() = 2 and self::a]",
78
+ @parser.parse("a[2]")
79
+ assert_xpath "//*[position() = 2 and self::a]",
80
+ @parser.parse("a:nth-child(2)")
81
+ end
82
+
83
+ def test_carrot
84
+ assert_xpath "//a[starts-with(@id, 'Boing')]",
85
+ @parser.parse("a[id^='Boing']")
86
+ assert_xpath "//a[starts-with(@id, 'Boing')]",
87
+ @parser.parse("a[id ^= 'Boing']")
88
+ end
89
+
90
+ def test_suffix_match
91
+ assert_xpath "//a[substring(@id, string-length(@id) - string-length('Boing') + 1, string-length('Boing')) = 'Boing']",
92
+ @parser.parse("a[id$='Boing']")
93
+ assert_xpath "//a[substring(@id, string-length(@id) - string-length('Boing') + 1, string-length('Boing')) = 'Boing']",
94
+ @parser.parse("a[id $= 'Boing']")
95
+ end
96
+
97
+ def test_attributes_with_at
98
+ ## This is non standard CSS
99
+ assert_xpath "//a[@id = 'Boing']",
100
+ @parser.parse("a[@id='Boing']")
101
+ assert_xpath "//a[@id = 'Boing']",
102
+ @parser.parse("a[@id = 'Boing']")
103
+ end
104
+
105
+ def test_attributes_with_at_and_stuff
106
+ ## This is non standard CSS
107
+ assert_xpath "//a[@id = 'Boing']//div",
108
+ @parser.parse("a[@id='Boing'] div")
109
+ end
110
+
111
+ def test_not_equal
112
+ ## This is non standard CSS
113
+ assert_xpath "//a[child::text() != 'Boing']",
114
+ @parser.parse("a[text()!='Boing']")
115
+ assert_xpath "//a[child::text() != 'Boing']",
116
+ @parser.parse("a[text() != 'Boing']")
117
+ end
118
+
119
+ def test_function
120
+ ## This is non standard CSS
121
+ assert_xpath "//a[child::text()]",
122
+ @parser.parse("a[text()]")
123
+
124
+ ## This is non standard CSS
125
+ assert_xpath "//child::text()",
126
+ @parser.parse("text()")
127
+
128
+ ## This is non standard CSS
129
+ assert_xpath "//a[contains(child::text(), 'Boing')]",
130
+ @parser.parse("a[text()*='Boing']")
131
+ assert_xpath "//a[contains(child::text(), 'Boing')]",
132
+ @parser.parse("a[text() *= 'Boing']")
133
+
134
+ ## This is non standard CSS
135
+ assert_xpath "//script//comment()",
136
+ @parser.parse("script comment()")
137
+ end
138
+
139
+ def test_nonstandard_nth_selectors
140
+ ## These are non standard CSS
141
+ assert_xpath '//a[position() = 99]', @parser.parse('a:eq(99)')
142
+ assert_xpath '//a[position() = 1]', @parser.parse('a:first') # no parens
143
+ assert_xpath '//a[position() = last()]', @parser.parse('a:last') # no parens
144
+ assert_xpath '//a[position() = 99]', @parser.parse('a:nth(99)')
145
+ assert_xpath '//a[position() = 1]', @parser.parse('a:first()')
146
+ assert_xpath '//a[position() = last()]', @parser.parse('a:last()')
147
+ assert_xpath '//a[node()]', @parser.parse('a:parent')
148
+ end
149
+
150
+ def test_standard_nth_selectors
151
+ assert_xpath '//a[position() = 99]', @parser.parse('a:nth-of-type(99)')
152
+ assert_xpath '//a[position() = 1]', @parser.parse('a:first-of-type()')
153
+ assert_xpath '//a[position() = last()]', @parser.parse('a:last-of-type()')
154
+ assert_xpath '//a[position() = 1]', @parser.parse('a:first-of-type') # no parens
155
+ assert_xpath '//a[position() = last()]', @parser.parse('a:last-of-type') # no parens
156
+ assert_xpath '//a[position() = last() - 99]', @parser.parse('a:nth-last-of-type(99)')
157
+ assert_xpath '//a[position() = last() - 99]', @parser.parse('a:nth-last-of-type(99)')
158
+ end
159
+
160
+ def test_nth_child_selectors
161
+ assert_xpath '//*[position() = 1 and self::a]', @parser.parse('a:first-child')
162
+ assert_xpath '//*[position() = last() and self::a]', @parser.parse('a:last-child')
163
+ assert_xpath '//*[position() = 99 and self::a]', @parser.parse('a:nth-child(99)')
164
+ assert_xpath '//*[position() = last() - 99 and self::a]', @parser.parse('a:nth-last-child(99)')
165
+ end
166
+
167
+ def test_miscellaneous_selectors
168
+ assert_xpath '//*[last() = 1 and self::a]',
169
+ @parser.parse('a:only-child')
170
+ assert_xpath '//a[last() = 1]', @parser.parse('a:only-of-type')
171
+ assert_xpath '//a[not(node())]', @parser.parse('a:empty')
172
+ end
173
+
174
+ def test_nth_a_n_plus_b
175
+ assert_xpath '//a[(position() mod 2) = 0]', @parser.parse('a:nth-of-type(2n)')
176
+ assert_xpath '//a[(position() >= 1) and (((position()-1) mod 2) = 0)]', @parser.parse('a:nth-of-type(2n+1)')
177
+ assert_xpath '//a[(position() mod 2) = 0]', @parser.parse('a:nth-of-type(even)')
178
+ assert_xpath '//a[(position() >= 1) and (((position()-1) mod 2) = 0)]', @parser.parse('a:nth-of-type(odd)')
179
+ assert_xpath '//a[(position() >= 3) and (((position()-3) mod 4) = 0)]', @parser.parse('a:nth-of-type(4n+3)')
180
+ assert_xpath '//a[(position() <= 3) and (((position()-3) mod 1) = 0)]', @parser.parse('a:nth-of-type(-1n+3)')
181
+ assert_xpath '//a[(position() <= 3) and (((position()-3) mod 1) = 0)]', @parser.parse('a:nth-of-type(-n+3)')
182
+ assert_xpath '//a[(position() >= 3) and (((position()-3) mod 1) = 0)]', @parser.parse('a:nth-of-type(1n+3)')
183
+ assert_xpath '//a[(position() >= 3) and (((position()-3) mod 1) = 0)]', @parser.parse('a:nth-of-type(n+3)')
184
+ end
185
+
186
+ def test_preceding_selector
187
+ assert_xpath "//F[preceding-sibling::E]",
188
+ @parser.parse("E ~ F")
189
+ end
190
+
191
+ def test_direct_preceding_selector
192
+ assert_xpath "//E/following-sibling::*[1]/self::F",
193
+ @parser.parse("E + F")
194
+ end
195
+
196
+ def test_attribute
197
+ assert_xpath "//h1[@a = 'Tender Lovemaking']",
198
+ @parser.parse("h1[a='Tender Lovemaking']")
199
+ end
200
+
201
+ def test_id
202
+ assert_xpath "//*[@id = 'foo']", @parser.parse('#foo')
203
+ end
204
+
205
+ def test_pseudo_class_no_ident
206
+ assert_xpath "//*[link(.)]", @parser.parse(':link')
207
+ end
208
+
209
+ def test_pseudo_class
210
+ assert_xpath "//a[link(.)]", @parser.parse('a:link')
211
+ assert_xpath "//a[visited(.)]", @parser.parse('a:visited')
212
+ assert_xpath "//a[hover(.)]", @parser.parse('a:hover')
213
+ assert_xpath "//a[active(.)]", @parser.parse('a:active')
214
+ assert_xpath "//a[active(.) and contains(concat(' ', @class, ' '), ' foo ')]",
215
+ @parser.parse('a:active.foo')
216
+ end
217
+
218
+ def test_star
219
+ assert_xpath "//*", @parser.parse('*')
220
+ assert_xpath "//*[contains(concat(' ', @class, ' '), ' pastoral ')]",
221
+ @parser.parse('*.pastoral')
222
+ end
223
+
224
+ def test_class
225
+ assert_xpath "//*[contains(concat(' ', @class, ' '), ' a ') and contains(concat(' ', @class, ' '), ' b ')]",
226
+ @parser.parse('.a.b')
227
+ assert_xpath "//*[contains(concat(' ', @class, ' '), ' awesome ')]",
228
+ @parser.parse('.awesome')
229
+ assert_xpath "//foo[contains(concat(' ', @class, ' '), ' awesome ')]",
230
+ @parser.parse('foo.awesome')
231
+ assert_xpath "//foo//*[contains(concat(' ', @class, ' '), ' awesome ')]",
232
+ @parser.parse('foo .awesome')
233
+ end
234
+
235
+ def test_not_so_simple_not
236
+ assert_xpath "//*[@id = 'p' and not(contains(concat(' ', @class, ' '), ' a '))]",
237
+ @parser.parse('#p:not(.a)')
238
+ assert_xpath "//p[contains(concat(' ', @class, ' '), ' a ') and not(contains(concat(' ', @class, ' '), ' b '))]",
239
+ @parser.parse('p.a:not(.b)')
240
+ assert_xpath "//p[@a = 'foo' and not(contains(concat(' ', @class, ' '), ' b '))]",
241
+ @parser.parse("p[a='foo']:not(.b)")
242
+ end
243
+
244
+ def test_ident
245
+ assert_xpath '//x', @parser.parse('x')
246
+ end
247
+
248
+ def test_parse_space
249
+ assert_xpath '//x//y', @parser.parse('x y')
250
+ end
251
+
252
+ def test_parse_descendant
253
+ assert_xpath '//x/y', @parser.parse('x > y')
254
+ end
255
+
256
+ def test_parse_slash
257
+ ## This is non standard CSS
258
+ assert_xpath '//x/y', @parser.parse('x/y')
259
+ end
260
+
261
+ def test_parse_doubleslash
262
+ ## This is non standard CSS
263
+ assert_xpath '//x//y', @parser.parse('x//y')
264
+ end
265
+
266
+ def test_multi_path
267
+ assert_xpath ['//x/y', '//y/z'], @parser.parse('x > y, y > z')
268
+ assert_xpath ['//x/y', '//y/z'], @parser.parse('x > y,y > z')
269
+ ###
270
+ # TODO: should we make this work?
271
+ # assert_xpath ['//x/y', '//y/z'], @parser.parse('x > y | y > z')
272
+ end
273
+
274
+ def assert_xpath expecteds, asts
275
+ expecteds = [expecteds].flatten
276
+ expecteds.zip(asts).each do |expected, actual|
277
+ assert_equal expected, actual.to_xpath
278
+ end
279
+ end
280
+ end
281
+ end
282
+ end
@@ -0,0 +1,190 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require "helper"
4
+
5
+ module Nokogiri
6
+ module CSS
7
+ class TestTokenizer < Nokogiri::TestCase
8
+ def setup
9
+ super
10
+ @scanner = Nokogiri::CSS::Tokenizer.new
11
+ end
12
+
13
+ def test_has
14
+ @scanner.scan("a:has(b)")
15
+ assert_tokens(
16
+ [[:IDENT, "a"], [":", ":"], [:HAS, "has("], [:IDENT, "b"], [:RPAREN, ")"]],
17
+ @scanner)
18
+ end
19
+
20
+ def test_unicode
21
+ @scanner.scan("a日本語")
22
+ assert_tokens([[:IDENT, 'a日本語']], @scanner)
23
+ end
24
+
25
+ def test_tokenize_bad_single_quote
26
+ @scanner.scan("'")
27
+ assert_tokens([["'", "'"]], @scanner)
28
+ end
29
+
30
+ def test_not_equal
31
+ @scanner.scan("h1[a!='Tender Lovemaking']")
32
+ assert_tokens([ [:IDENT, 'h1'],
33
+ [:LSQUARE, '['],
34
+ [:IDENT, 'a'],
35
+ [:NOT_EQUAL, '!='],
36
+ [:STRING, "'Tender Lovemaking'"],
37
+ [:RSQUARE, ']'],
38
+ ], @scanner)
39
+ end
40
+
41
+ def test_negation
42
+ @scanner.scan("p:not(.a)")
43
+ assert_tokens([ [:IDENT, 'p'],
44
+ [:NOT, ':not('],
45
+ ['.', '.'],
46
+ [:IDENT, 'a'],
47
+ [:RPAREN, ')'],
48
+ ], @scanner)
49
+ end
50
+
51
+ def test_function
52
+ @scanner.scan("script comment()")
53
+ assert_tokens([ [:IDENT, 'script'],
54
+ [:S, ' '],
55
+ [:FUNCTION, 'comment('],
56
+ [:RPAREN, ')'],
57
+ ], @scanner)
58
+ end
59
+
60
+ def test_preceding_selector
61
+ @scanner.scan("E ~ F")
62
+ assert_tokens([ [:IDENT, 'E'],
63
+ [:TILDE, ' ~ '],
64
+ [:IDENT, 'F'],
65
+ ], @scanner)
66
+ end
67
+
68
+ def test_scan_attribute_string
69
+ @scanner.scan("h1[a='Tender Lovemaking']")
70
+ assert_tokens([ [:IDENT, 'h1'],
71
+ [:LSQUARE, '['],
72
+ [:IDENT, 'a'],
73
+ [:EQUAL, '='],
74
+ [:STRING, "'Tender Lovemaking'"],
75
+ [:RSQUARE, ']'],
76
+ ], @scanner)
77
+ @scanner.scan('h1[a="Tender Lovemaking"]')
78
+ assert_tokens([ [:IDENT, 'h1'],
79
+ [:LSQUARE, '['],
80
+ [:IDENT, 'a'],
81
+ [:EQUAL, '='],
82
+ [:STRING, '"Tender Lovemaking"'],
83
+ [:RSQUARE, ']'],
84
+ ], @scanner)
85
+ end
86
+
87
+ def test_scan_id
88
+ @scanner.scan('#foo')
89
+ assert_tokens([ [:HASH, '#foo'] ], @scanner)
90
+ end
91
+
92
+ def test_scan_pseudo
93
+ @scanner.scan('a:visited')
94
+ assert_tokens([ [:IDENT, 'a'],
95
+ [':', ':'],
96
+ [:IDENT, 'visited']
97
+ ], @scanner)
98
+ end
99
+
100
+ def test_scan_star
101
+ @scanner.scan('*')
102
+ assert_tokens([ ['*', '*'], ], @scanner)
103
+ end
104
+
105
+ def test_scan_class
106
+ @scanner.scan('x.awesome')
107
+ assert_tokens([ [:IDENT, 'x'],
108
+ ['.', '.'],
109
+ [:IDENT, 'awesome'],
110
+ ], @scanner)
111
+ end
112
+
113
+ def test_scan_greater
114
+ @scanner.scan('x > y')
115
+ assert_tokens([ [:IDENT, 'x'],
116
+ [:GREATER, ' > '],
117
+ [:IDENT, 'y']
118
+ ], @scanner)
119
+ end
120
+
121
+ def test_scan_slash
122
+ @scanner.scan('x/y')
123
+ assert_tokens([ [:IDENT, 'x'],
124
+ [:SLASH, '/'],
125
+ [:IDENT, 'y']
126
+ ], @scanner)
127
+ end
128
+
129
+ def test_scan_doubleslash
130
+ @scanner.scan('x//y')
131
+ assert_tokens([ [:IDENT, 'x'],
132
+ [:DOUBLESLASH, '//'],
133
+ [:IDENT, 'y']
134
+ ], @scanner)
135
+ end
136
+
137
+ def test_scan_function_selector
138
+ @scanner.scan('x:eq(0)')
139
+ assert_tokens([ [:IDENT, 'x'],
140
+ [':', ':'],
141
+ [:FUNCTION, 'eq('],
142
+ [:NUMBER, "0"],
143
+ [:RPAREN, ')'],
144
+ ], @scanner)
145
+ end
146
+
147
+ def test_scan_an_plus_b
148
+ @scanner.scan('x:nth-child(5n+3)')
149
+ assert_tokens([ [:IDENT, 'x'],
150
+ [':', ':'],
151
+ [:FUNCTION, 'nth-child('],
152
+ [:NUMBER, '5'],
153
+ [:IDENT, 'n'],
154
+ [:PLUS, '+'],
155
+ [:NUMBER, '3'],
156
+ [:RPAREN, ')'],
157
+ ], @scanner)
158
+
159
+ @scanner.scan('x:nth-child(-1n+3)')
160
+ assert_tokens([ [:IDENT, 'x'],
161
+ [':', ':'],
162
+ [:FUNCTION, 'nth-child('],
163
+ [:NUMBER, '-1'],
164
+ [:IDENT, 'n'],
165
+ [:PLUS, '+'],
166
+ [:NUMBER, '3'],
167
+ [:RPAREN, ')'],
168
+ ], @scanner)
169
+
170
+ @scanner.scan('x:nth-child(-n+3)')
171
+ assert_tokens([ [:IDENT, 'x'],
172
+ [':', ':'],
173
+ [:FUNCTION, 'nth-child('],
174
+ [:IDENT, '-n'],
175
+ [:PLUS, '+'],
176
+ [:NUMBER, '3'],
177
+ [:RPAREN, ')'],
178
+ ], @scanner)
179
+ end
180
+
181
+ def assert_tokens(tokens, scanner)
182
+ toks = []
183
+ while tok = @scanner.next_token
184
+ toks << tok
185
+ end
186
+ assert_equal(tokens, toks)
187
+ end
188
+ end
189
+ end
190
+ end