nokogiri 1.0.0 → 1.6.8.1

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 (309) hide show
  1. checksums.yaml +7 -0
  2. data/.autotest +26 -0
  3. data/.cross_rubies +9 -0
  4. data/.editorconfig +17 -0
  5. data/.gemtest +0 -0
  6. data/.travis.yml +51 -0
  7. data/CHANGELOG.rdoc +1160 -0
  8. data/CONTRIBUTING.md +42 -0
  9. data/C_CODING_STYLE.rdoc +33 -0
  10. data/Gemfile +22 -0
  11. data/LICENSE.txt +31 -0
  12. data/Manifest.txt +284 -40
  13. data/README.md +166 -0
  14. data/ROADMAP.md +111 -0
  15. data/Rakefile +310 -199
  16. data/STANDARD_RESPONSES.md +47 -0
  17. data/Y_U_NO_GEMSPEC.md +155 -0
  18. data/appveyor.yml +22 -0
  19. data/bin/nokogiri +118 -0
  20. data/build_all +45 -0
  21. data/dependencies.yml +29 -0
  22. data/ext/nokogiri/depend +358 -0
  23. data/ext/nokogiri/extconf.rb +664 -34
  24. data/ext/nokogiri/html_document.c +120 -33
  25. data/ext/nokogiri/html_document.h +1 -1
  26. data/ext/nokogiri/html_element_description.c +279 -0
  27. data/ext/nokogiri/html_element_description.h +10 -0
  28. data/ext/nokogiri/html_entity_lookup.c +32 -0
  29. data/ext/nokogiri/html_entity_lookup.h +8 -0
  30. data/ext/nokogiri/html_sax_parser_context.c +116 -0
  31. data/ext/nokogiri/html_sax_parser_context.h +11 -0
  32. data/ext/nokogiri/html_sax_push_parser.c +87 -0
  33. data/ext/nokogiri/html_sax_push_parser.h +9 -0
  34. data/ext/nokogiri/nokogiri.c +145 -0
  35. data/ext/nokogiri/nokogiri.h +131 -0
  36. data/ext/nokogiri/xml_attr.c +94 -0
  37. data/ext/nokogiri/xml_attr.h +9 -0
  38. data/ext/nokogiri/xml_attribute_decl.c +70 -0
  39. data/ext/nokogiri/xml_attribute_decl.h +9 -0
  40. data/ext/nokogiri/xml_cdata.c +23 -19
  41. data/ext/nokogiri/xml_cdata.h +1 -1
  42. data/ext/nokogiri/xml_comment.c +69 -0
  43. data/ext/nokogiri/xml_comment.h +9 -0
  44. data/ext/nokogiri/xml_document.c +501 -54
  45. data/ext/nokogiri/xml_document.h +14 -1
  46. data/ext/nokogiri/xml_document_fragment.c +48 -0
  47. data/ext/nokogiri/xml_document_fragment.h +10 -0
  48. data/ext/nokogiri/xml_dtd.c +109 -24
  49. data/ext/nokogiri/xml_dtd.h +3 -1
  50. data/ext/nokogiri/xml_element_content.c +123 -0
  51. data/ext/nokogiri/xml_element_content.h +10 -0
  52. data/ext/nokogiri/xml_element_decl.c +69 -0
  53. data/ext/nokogiri/xml_element_decl.h +9 -0
  54. data/ext/nokogiri/xml_encoding_handler.c +79 -0
  55. data/ext/nokogiri/xml_encoding_handler.h +8 -0
  56. data/ext/nokogiri/xml_entity_decl.c +110 -0
  57. data/ext/nokogiri/xml_entity_decl.h +10 -0
  58. data/ext/nokogiri/xml_entity_reference.c +52 -0
  59. data/ext/nokogiri/xml_entity_reference.h +9 -0
  60. data/ext/nokogiri/xml_io.c +60 -0
  61. data/ext/nokogiri/xml_io.h +11 -0
  62. data/ext/nokogiri/xml_libxml2_hacks.c +112 -0
  63. data/ext/nokogiri/xml_libxml2_hacks.h +12 -0
  64. data/ext/nokogiri/xml_namespace.c +117 -0
  65. data/ext/nokogiri/xml_namespace.h +13 -0
  66. data/ext/nokogiri/xml_node.c +1285 -315
  67. data/ext/nokogiri/xml_node.h +4 -6
  68. data/ext/nokogiri/xml_node_set.c +415 -54
  69. data/ext/nokogiri/xml_node_set.h +6 -2
  70. data/ext/nokogiri/xml_processing_instruction.c +56 -0
  71. data/ext/nokogiri/xml_processing_instruction.h +9 -0
  72. data/ext/nokogiri/xml_reader.c +316 -77
  73. data/ext/nokogiri/xml_reader.h +1 -1
  74. data/ext/nokogiri/xml_relax_ng.c +161 -0
  75. data/ext/nokogiri/xml_relax_ng.h +9 -0
  76. data/ext/nokogiri/xml_sax_parser.c +215 -80
  77. data/ext/nokogiri/xml_sax_parser.h +30 -1
  78. data/ext/nokogiri/xml_sax_parser_context.c +262 -0
  79. data/ext/nokogiri/xml_sax_parser_context.h +10 -0
  80. data/ext/nokogiri/xml_sax_push_parser.c +115 -0
  81. data/ext/nokogiri/xml_sax_push_parser.h +9 -0
  82. data/ext/nokogiri/xml_schema.c +205 -0
  83. data/ext/nokogiri/xml_schema.h +9 -0
  84. data/ext/nokogiri/xml_syntax_error.c +45 -175
  85. data/ext/nokogiri/xml_syntax_error.h +4 -2
  86. data/ext/nokogiri/xml_text.c +37 -14
  87. data/ext/nokogiri/xml_text.h +1 -1
  88. data/ext/nokogiri/xml_xpath_context.c +230 -13
  89. data/ext/nokogiri/xml_xpath_context.h +2 -1
  90. data/ext/nokogiri/xslt_stylesheet.c +196 -34
  91. data/ext/nokogiri/xslt_stylesheet.h +6 -1
  92. data/lib/nokogiri/css/node.rb +18 -61
  93. data/lib/nokogiri/css/parser.rb +725 -17
  94. data/lib/nokogiri/css/parser.y +126 -63
  95. data/lib/nokogiri/css/parser_extras.rb +91 -0
  96. data/lib/nokogiri/css/syntax_error.rb +7 -0
  97. data/lib/nokogiri/css/tokenizer.rb +148 -5
  98. data/lib/nokogiri/css/tokenizer.rex +31 -39
  99. data/lib/nokogiri/css/xpath_visitor.rb +109 -51
  100. data/lib/nokogiri/css.rb +24 -3
  101. data/lib/nokogiri/decorators/slop.rb +42 -0
  102. data/lib/nokogiri/html/builder.rb +27 -1
  103. data/lib/nokogiri/html/document.rb +329 -3
  104. data/lib/nokogiri/html/document_fragment.rb +39 -0
  105. data/lib/nokogiri/html/element_description.rb +23 -0
  106. data/lib/nokogiri/html/element_description_defaults.rb +671 -0
  107. data/lib/nokogiri/html/entity_lookup.rb +13 -0
  108. data/lib/nokogiri/html/sax/parser.rb +35 -4
  109. data/lib/nokogiri/html/sax/parser_context.rb +16 -0
  110. data/lib/nokogiri/html/sax/push_parser.rb +36 -0
  111. data/lib/nokogiri/html.rb +18 -76
  112. data/lib/nokogiri/syntax_error.rb +4 -0
  113. data/lib/nokogiri/version.rb +106 -1
  114. data/lib/nokogiri/xml/attr.rb +14 -0
  115. data/lib/nokogiri/xml/attribute_decl.rb +18 -0
  116. data/lib/nokogiri/xml/builder.rb +395 -31
  117. data/lib/nokogiri/xml/cdata.rb +4 -2
  118. data/lib/nokogiri/xml/character_data.rb +7 -0
  119. data/lib/nokogiri/xml/document.rb +267 -12
  120. data/lib/nokogiri/xml/document_fragment.rb +149 -0
  121. data/lib/nokogiri/xml/dtd.rb +27 -1
  122. data/lib/nokogiri/xml/element_content.rb +36 -0
  123. data/lib/nokogiri/xml/element_decl.rb +13 -0
  124. data/lib/nokogiri/xml/entity_decl.rb +19 -0
  125. data/lib/nokogiri/xml/namespace.rb +13 -0
  126. data/lib/nokogiri/xml/node/save_options.rb +61 -0
  127. data/lib/nokogiri/xml/node.rb +748 -109
  128. data/lib/nokogiri/xml/node_set.rb +200 -72
  129. data/lib/nokogiri/xml/parse_options.rb +120 -0
  130. data/lib/nokogiri/xml/pp/character_data.rb +18 -0
  131. data/lib/nokogiri/xml/pp/node.rb +56 -0
  132. data/lib/nokogiri/xml/pp.rb +2 -0
  133. data/lib/nokogiri/xml/processing_instruction.rb +8 -0
  134. data/lib/nokogiri/xml/reader.rb +102 -4
  135. data/lib/nokogiri/xml/relax_ng.rb +32 -0
  136. data/lib/nokogiri/xml/sax/document.rb +114 -2
  137. data/lib/nokogiri/xml/sax/parser.rb +97 -7
  138. data/lib/nokogiri/xml/sax/parser_context.rb +16 -0
  139. data/lib/nokogiri/xml/sax/push_parser.rb +60 -0
  140. data/lib/nokogiri/xml/sax.rb +2 -7
  141. data/lib/nokogiri/xml/schema.rb +63 -0
  142. data/lib/nokogiri/xml/searchable.rb +221 -0
  143. data/lib/nokogiri/xml/syntax_error.rb +27 -1
  144. data/lib/nokogiri/xml/text.rb +4 -1
  145. data/lib/nokogiri/xml/xpath/syntax_error.rb +11 -0
  146. data/lib/nokogiri/xml/xpath.rb +4 -0
  147. data/lib/nokogiri/xml/xpath_context.rb +3 -1
  148. data/lib/nokogiri/xml.rb +45 -38
  149. data/lib/nokogiri/xslt/stylesheet.rb +19 -0
  150. data/lib/nokogiri/xslt.rb +47 -2
  151. data/lib/nokogiri.rb +117 -24
  152. data/lib/xsd/xmlparser/nokogiri.rb +102 -0
  153. data/patches/sort-patches-by-date +25 -0
  154. data/ports/archives/libxml2-2.9.4.tar.gz +0 -0
  155. data/ports/archives/libxslt-1.1.29.tar.gz +0 -0
  156. data/suppressions/README.txt +1 -0
  157. data/suppressions/nokogiri_ree-1.8.7.358.supp +61 -0
  158. data/suppressions/nokogiri_ruby-1.8.7.370.supp +0 -0
  159. data/suppressions/nokogiri_ruby-1.9.2.320.supp +28 -0
  160. data/suppressions/nokogiri_ruby-1.9.3.327.supp +28 -0
  161. data/tasks/test.rb +100 -0
  162. data/test/css/test_nthiness.rb +73 -6
  163. data/test/css/test_parser.rb +184 -39
  164. data/test/css/test_tokenizer.rb +72 -19
  165. data/test/css/test_xpath_visitor.rb +44 -2
  166. data/test/decorators/test_slop.rb +20 -0
  167. data/test/files/2ch.html +108 -0
  168. data/test/files/GH_1042.html +18 -0
  169. data/test/files/address_book.rlx +12 -0
  170. data/test/files/address_book.xml +10 -0
  171. data/test/files/atom.xml +344 -0
  172. data/test/files/bar/bar.xsd +4 -0
  173. data/test/files/bogus.xml +0 -0
  174. data/test/files/dont_hurt_em_why.xml +422 -0
  175. data/test/files/encoding.html +82 -0
  176. data/test/files/encoding.xhtml +84 -0
  177. data/test/files/exslt.xml +8 -0
  178. data/test/files/exslt.xslt +35 -0
  179. data/test/files/foo/foo.xsd +4 -0
  180. data/test/files/metacharset.html +10 -0
  181. data/test/files/namespace_pressure_test.xml +1684 -0
  182. data/test/files/noencoding.html +47 -0
  183. data/test/files/po.xml +32 -0
  184. data/test/files/po.xsd +66 -0
  185. data/test/files/saml/saml20assertion_schema.xsd +283 -0
  186. data/test/files/saml/saml20protocol_schema.xsd +302 -0
  187. data/test/files/saml/xenc_schema.xsd +146 -0
  188. data/test/files/saml/xmldsig_schema.xsd +318 -0
  189. data/test/files/shift_jis.html +10 -0
  190. data/test/files/shift_jis.xml +5 -0
  191. data/test/files/shift_jis_no_charset.html +9 -0
  192. data/test/files/slow-xpath.xml +25509 -0
  193. data/test/files/snuggles.xml +3 -0
  194. data/test/files/staff.dtd +10 -0
  195. data/test/files/test_document_url/bar.xml +2 -0
  196. data/test/files/test_document_url/document.dtd +4 -0
  197. data/test/files/test_document_url/document.xml +6 -0
  198. data/test/files/tlm.html +2 -1
  199. data/test/files/to_be_xincluded.xml +2 -0
  200. data/test/files/valid_bar.xml +2 -0
  201. data/test/files/xinclude.xml +4 -0
  202. data/test/helper.rb +124 -13
  203. data/test/html/sax/test_parser.rb +118 -4
  204. data/test/html/sax/test_parser_context.rb +46 -0
  205. data/test/html/sax/test_push_parser.rb +87 -0
  206. data/test/html/test_builder.rb +94 -8
  207. data/test/html/test_document.rb +626 -11
  208. data/test/html/test_document_encoding.rb +145 -0
  209. data/test/html/test_document_fragment.rb +301 -0
  210. data/test/html/test_element_description.rb +105 -0
  211. data/test/html/test_named_characters.rb +14 -0
  212. data/test/html/test_node.rb +212 -0
  213. data/test/html/test_node_encoding.rb +85 -0
  214. data/test/namespaces/test_additional_namespaces_in_builder_doc.rb +14 -0
  215. data/test/namespaces/test_namespaces_aliased_default.rb +24 -0
  216. data/test/namespaces/test_namespaces_in_builder_doc.rb +75 -0
  217. data/test/namespaces/test_namespaces_in_cloned_doc.rb +31 -0
  218. data/test/namespaces/test_namespaces_in_created_doc.rb +75 -0
  219. data/test/namespaces/test_namespaces_in_parsed_doc.rb +80 -0
  220. data/test/namespaces/test_namespaces_preservation.rb +31 -0
  221. data/test/test_convert_xpath.rb +2 -47
  222. data/test/test_css_cache.rb +45 -0
  223. data/test/test_encoding_handler.rb +48 -0
  224. data/test/test_memory_leak.rb +156 -0
  225. data/test/test_nokogiri.rb +103 -1
  226. data/test/test_soap4r_sax.rb +52 -0
  227. data/test/test_xslt_transforms.rb +293 -8
  228. data/test/xml/node/test_save_options.rb +28 -0
  229. data/test/xml/node/test_subclass.rb +44 -0
  230. data/test/xml/sax/test_parser.rb +309 -8
  231. data/test/xml/sax/test_parser_context.rb +115 -0
  232. data/test/xml/sax/test_push_parser.rb +157 -0
  233. data/test/xml/test_attr.rb +67 -0
  234. data/test/xml/test_attribute_decl.rb +86 -0
  235. data/test/xml/test_builder.rb +327 -2
  236. data/test/xml/test_c14n.rb +180 -0
  237. data/test/xml/test_cdata.rb +32 -2
  238. data/test/xml/test_comment.rb +40 -0
  239. data/test/xml/test_document.rb +846 -35
  240. data/test/xml/test_document_encoding.rb +31 -0
  241. data/test/xml/test_document_fragment.rb +271 -0
  242. data/test/xml/test_dtd.rb +153 -9
  243. data/test/xml/test_dtd_encoding.rb +31 -0
  244. data/test/xml/test_element_content.rb +56 -0
  245. data/test/xml/test_element_decl.rb +73 -0
  246. data/test/xml/test_entity_decl.rb +122 -0
  247. data/test/xml/test_entity_reference.rb +251 -0
  248. data/test/xml/test_namespace.rb +96 -0
  249. data/test/xml/test_node.rb +1126 -105
  250. data/test/xml/test_node_attributes.rb +115 -0
  251. data/test/xml/test_node_encoding.rb +69 -0
  252. data/test/xml/test_node_inheritance.rb +32 -0
  253. data/test/xml/test_node_reparenting.rb +549 -0
  254. data/test/xml/test_node_set.rb +668 -9
  255. data/test/xml/test_parse_options.rb +64 -0
  256. data/test/xml/test_processing_instruction.rb +30 -0
  257. data/test/xml/test_reader.rb +589 -0
  258. data/test/xml/test_reader_encoding.rb +134 -0
  259. data/test/xml/test_relax_ng.rb +60 -0
  260. data/test/xml/test_schema.rb +142 -0
  261. data/test/xml/test_syntax_error.rb +30 -0
  262. data/test/xml/test_text.rb +49 -2
  263. data/test/xml/test_unparented_node.rb +440 -0
  264. data/test/xml/test_xinclude.rb +83 -0
  265. data/test/xml/test_xpath.rb +445 -0
  266. data/test/xslt/test_custom_functions.rb +133 -0
  267. data/test/xslt/test_exception_handling.rb +37 -0
  268. data/test_all +107 -0
  269. metadata +459 -115
  270. data/History.txt +0 -6
  271. data/README.ja.txt +0 -86
  272. data/README.txt +0 -87
  273. data/ext/nokogiri/html_sax_parser.c +0 -32
  274. data/ext/nokogiri/html_sax_parser.h +0 -11
  275. data/ext/nokogiri/native.c +0 -40
  276. data/ext/nokogiri/native.h +0 -51
  277. data/ext/nokogiri/xml_xpath.c +0 -46
  278. data/ext/nokogiri/xml_xpath.h +0 -11
  279. data/lib/nokogiri/css/generated_parser.rb +0 -653
  280. data/lib/nokogiri/css/generated_tokenizer.rb +0 -159
  281. data/lib/nokogiri/decorators/hpricot/node.rb +0 -58
  282. data/lib/nokogiri/decorators/hpricot/node_set.rb +0 -14
  283. data/lib/nokogiri/decorators/hpricot/xpath_visitor.rb +0 -17
  284. data/lib/nokogiri/decorators/hpricot.rb +0 -3
  285. data/lib/nokogiri/decorators.rb +0 -1
  286. data/lib/nokogiri/hpricot.rb +0 -47
  287. data/lib/nokogiri/xml/after_handler.rb +0 -18
  288. data/lib/nokogiri/xml/before_handler.rb +0 -32
  289. data/lib/nokogiri/xml/element.rb +0 -6
  290. data/lib/nokogiri/xml/entity_declaration.rb +0 -9
  291. data/nokogiri.gemspec +0 -34
  292. data/test/hpricot/files/basic.xhtml +0 -17
  293. data/test/hpricot/files/boingboing.html +0 -2266
  294. data/test/hpricot/files/cy0.html +0 -3653
  295. data/test/hpricot/files/immob.html +0 -400
  296. data/test/hpricot/files/pace_application.html +0 -1320
  297. data/test/hpricot/files/tenderlove.html +0 -16
  298. data/test/hpricot/files/uswebgen.html +0 -220
  299. data/test/hpricot/files/utf8.html +0 -1054
  300. data/test/hpricot/files/week9.html +0 -1723
  301. data/test/hpricot/files/why.xml +0 -19
  302. data/test/hpricot/load_files.rb +0 -7
  303. data/test/hpricot/test_alter.rb +0 -67
  304. data/test/hpricot/test_builder.rb +0 -27
  305. data/test/hpricot/test_parser.rb +0 -423
  306. data/test/hpricot/test_paths.rb +0 -15
  307. data/test/hpricot/test_preserved.rb +0 -78
  308. data/test/hpricot/test_xml.rb +0 -30
  309. data/test/test_reader.rb +0 -222
@@ -0,0 +1,28 @@
1
+ {
2
+ <insert_a_suppression_name_here>
3
+ Memcheck:Addr4
4
+ fun:glob_helper
5
+ fun:ruby_glob0
6
+ fun:rb_push_glob
7
+ fun:vm_call_method
8
+ fun:vm_exec_core
9
+ fun:vm_exec
10
+ fun:rb_yield
11
+ fun:rb_ary_each
12
+ fun:vm_call_method
13
+ fun:vm_exec_core
14
+ fun:vm_exec
15
+ fun:vm_call0
16
+ fun:rb_iterate
17
+ fun:rb_block_call
18
+ fun:enum_find_all
19
+ fun:vm_call_method
20
+ fun:vm_exec_core
21
+ fun:vm_exec
22
+ fun:vm_call0
23
+ fun:rb_class_new_instance
24
+ fun:vm_call_method
25
+ fun:vm_exec_core
26
+ fun:vm_exec
27
+ fun:vm_call0
28
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ <insert_a_suppression_name_here>
3
+ Memcheck:Addr4
4
+ fun:glob_helper
5
+ fun:ruby_glob0
6
+ fun:rb_push_glob
7
+ fun:vm_call_method
8
+ fun:vm_exec_core
9
+ fun:vm_exec
10
+ fun:rb_yield
11
+ fun:rb_ary_each
12
+ fun:vm_call_method
13
+ fun:vm_exec_core
14
+ fun:vm_exec
15
+ fun:vm_call0
16
+ fun:rb_iterate
17
+ fun:rb_block_call
18
+ fun:enum_find_all
19
+ fun:vm_call_method
20
+ fun:vm_exec_core
21
+ fun:vm_exec
22
+ fun:vm_call0
23
+ fun:rb_class_new_instance
24
+ fun:vm_call_method
25
+ fun:vm_exec_core
26
+ fun:vm_exec
27
+ fun:vm_call0
28
+ }
data/tasks/test.rb ADDED
@@ -0,0 +1,100 @@
1
+ namespace :test do
2
+ desc "run test suite with aggressive GC"
3
+ task :gc => :build do
4
+ ENV['NOKOGIRI_GC'] = "true"
5
+ Rake::Task["test"].invoke
6
+ end
7
+
8
+ task :installed do
9
+ ENV['RUBY_FLAGS'] = "-w -Itest:."
10
+ sh 'rake test'
11
+ end
12
+
13
+ desc "find call-seq in the rdoc"
14
+ task :rdoc_call_seq => 'docs' do
15
+ Dir['doc/**/*.html'].each { |docfile|
16
+ next if docfile =~ /\.src/
17
+ puts "FAIL: #{docfile}" if File.read(docfile) =~ /call-seq/
18
+ }
19
+ end
20
+
21
+ desc "find all undocumented things"
22
+ task :rdoc => 'docs' do
23
+ base = File.expand_path(File.join(File.dirname(__FILE__), '..', 'doc'))
24
+ require 'test/unit'
25
+ test = Class.new(Test::Unit::TestCase)
26
+ Dir["#{base}/**/*.html"].each { |docfile|
27
+ test.class_eval(<<-eotest)
28
+ def test_#{docfile.sub("#{base}/", '').gsub(/[\/\.-]/, '_')}
29
+ assert_no_match(
30
+ /Not documented/,
31
+ File.read('#{docfile}'),
32
+ '#{docfile} has undocumented things'
33
+ )
34
+ end
35
+ eotest
36
+ }
37
+ end
38
+
39
+ desc "Test against multiple versions of libxml2 (MULTIXML2_DIR=directory)"
40
+ task :multixml2 do
41
+ MULTI_XML = File.join(ENV['HOME'], '.multixml2')
42
+ unless File.exists?(MULTI_XML)
43
+ %w{ versions install build }.each { |x|
44
+ FileUtils.mkdir_p(File.join(MULTI_XML, x))
45
+ }
46
+ Dir.chdir File.join(MULTI_XML, 'versions') do
47
+ require 'net/ftp'
48
+ puts "Contacting xmlsoft.org ..."
49
+ ftp = Net::FTP.new('xmlsoft.org')
50
+ ftp.login('anonymous', 'anonymous')
51
+ ftp.chdir('libxml2')
52
+ ftp.list('libxml2-2.*.tar.gz').each do |x|
53
+ file = x[/[^\s]*$/]
54
+ puts "Downloading #{file}"
55
+ ftp.getbinaryfile(file)
56
+ end
57
+ end
58
+ end
59
+
60
+ # Build any libxml2 versions in $HOME/.multixml2/versions that
61
+ # haven't been built yet
62
+ Dir[File.join(MULTI_XML, 'versions','*.tar.gz')].each do |f|
63
+ filename = File.basename(f, '.tar.gz')
64
+
65
+ install_dir = File.join(MULTI_XML, 'install', filename)
66
+ next if File.exists?(install_dir)
67
+
68
+ Dir.chdir File.join(MULTI_XML, 'versions') do
69
+ system "tar zxvf #{f} -C #{File.join(MULTI_XML, 'build')}"
70
+ end
71
+
72
+ Dir.chdir File.join(MULTI_XML, 'build', filename) do
73
+ system "./configure --without-http --prefix=#{install_dir}"
74
+ system "make && make install"
75
+ end
76
+ end
77
+
78
+ test_results = {}
79
+ libxslt = Dir[File.join(MULTI_XML, 'install', 'libxslt*')].first
80
+
81
+ directories = ENV['MULTIXML2_DIR'] ? [ENV['MULTIXML2_DIR']] : Dir[File.join(MULTI_XML, 'install', '*')]
82
+ directories.sort.reverse_each do |xml2_version|
83
+ next unless xml2_version =~ /libxml2/
84
+ extopts = "--with-xml2-include=#{xml2_version}/include/libxml2 --with-xml2-lib=#{xml2_version}/lib --with-xslt-dir=#{libxslt} --with-iconv-dir=/usr"
85
+ cmd = "#{$0} clean test EXTOPTS='#{extopts}' LD_LIBRARY_PATH='#{xml2_version}/lib'"
86
+
87
+ version = File.basename(xml2_version)
88
+ result = system(cmd)
89
+ test_results[version] = {
90
+ :result => result,
91
+ :cmd => cmd
92
+ }
93
+ end
94
+ test_results.sort_by { |k,v| k }.each do |k,v|
95
+ passed = v[:result]
96
+ puts "#{k}: #{passed ? 'PASS' : 'FAIL'}"
97
+ puts "repro: #{v[:cmd]}" unless passed
98
+ end
99
+ end
100
+ end
@@ -1,9 +1,10 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', "helper"))
1
+ require "helper"
2
2
 
3
3
  module Nokogiri
4
4
  module CSS
5
5
  class TestNthiness < Nokogiri::TestCase
6
6
  def setup
7
+ super
7
8
  doc = <<EOF
8
9
  <html>
9
10
  <table>
@@ -25,10 +26,20 @@ module Nokogiri
25
26
  <div>
26
27
  <b>bold1 </b>
27
28
  <i>italic1 </i>
28
- <b>bold2 </b>
29
+ <b class="a">bold2 </b>
30
+ <em class="a">emphasis1 </em>
29
31
  <i>italic2 </i>
30
32
  <p>para1 </p>
31
- <b>bold3 </b>
33
+ <b class="a">bold3 </b>
34
+ </div>
35
+ <div>
36
+ <i class="b">italic3 </i>
37
+ <em>emphasis2 </em>
38
+ <i class="b">italic4 </i>
39
+ <em>emphasis3 </em>
40
+ <i class="c">italic5 </i>
41
+ <span><i class="b">italic6 </i></span>
42
+ <i>italic7 </i>
32
43
  </div>
33
44
  <div>
34
45
  <p>para2 </p>
@@ -37,11 +48,25 @@ module Nokogiri
37
48
  <div>
38
49
  <p>para4 </p>
39
50
  </div>
51
+
52
+ <div>
53
+ <h2></h2>
54
+ <h1 class='c'>header1 </h1>
55
+ <h2></h2>
56
+ </div>
57
+ <div>
58
+ <h1 class='c'>header2 </h1>
59
+ <h1 class='c'>header3 </h1>
60
+ </div>
61
+ <div>
62
+ <h1 class='c'>header4</h1>
63
+ </div>
64
+
40
65
  <p class='empty'></p>
41
66
  <p class='not-empty'><b></b></p>
42
67
  </html>
43
68
  EOF
44
- @parser = Nokogiri.Hpricot doc
69
+ @parser = Nokogiri.HTML doc
45
70
  end
46
71
 
47
72
 
@@ -53,6 +78,10 @@ EOF
53
78
  assert_result_rows [1,3,5,7,9,11,13], @parser.search("table/tr:nth(odd)")
54
79
  end
55
80
 
81
+ def test_n
82
+ assert_result_rows((1..14).to_a, @parser.search("table/tr:nth(n)"))
83
+ end
84
+
56
85
  def test_2n
57
86
  assert_equal @parser.search("table/tr:nth(even)").inner_text, @parser.search("table/tr:nth(2n)").inner_text
58
87
  end
@@ -73,6 +102,10 @@ EOF
73
102
  assert_result_rows [1,2,3], @parser.search("table/tr:nth(-n+3)")
74
103
  end
75
104
 
105
+ def test_4nm1
106
+ assert_result_rows [3,7,11], @parser.search("table/tr:nth(4n-1)")
107
+ end
108
+
76
109
  def test_np3
77
110
  assert_result_rows [3,4,5,6,7,8,9,10,11,12,13,14], @parser.search("table/tr:nth(n+3)")
78
111
  end
@@ -90,29 +123,64 @@ EOF
90
123
  def test_first_child
91
124
  assert_result_rows [1], @parser.search("div/b:first-child"), "bold"
92
125
  assert_result_rows [1], @parser.search("table/tr:first-child")
126
+ assert_result_rows [2,4], @parser.search("div/h1.c:first-child"), "header"
93
127
  end
94
128
 
95
129
  def test_last_child
96
130
  assert_result_rows [3], @parser.search("div/b:last-child"), "bold"
97
131
  assert_result_rows [14], @parser.search("table/tr:last-child")
132
+ assert_result_rows [3,4], @parser.search("div/h1.c:last-child"), "header"
133
+ end
134
+
135
+ def test_nth_child
136
+ assert_result_rows [2], @parser.search("div/b:nth-child(3)"), "bold"
137
+ assert_result_rows [5], @parser.search("table/tr:nth-child(5)")
138
+ assert_result_rows [1,3], @parser.search("div/h1.c:nth-child(2)"), "header"
139
+ assert_result_rows [3,4], @parser.search("div/i.b:nth-child(2n+1)"), "italic"
98
140
  end
99
141
 
100
142
  def test_first_of_type
101
143
  assert_result_rows [1], @parser.search("table/tr:first-of-type")
102
144
  assert_result_rows [1], @parser.search("div/b:first-of-type"), "bold"
145
+ assert_result_rows [2], @parser.search("div/b.a:first-of-type"), "bold"
146
+ assert_result_rows [3], @parser.search("div/i.b:first-of-type"), "italic"
103
147
  end
104
148
 
105
149
  def test_last_of_type
106
150
  assert_result_rows [14], @parser.search("table/tr:last-of-type")
107
151
  assert_result_rows [3], @parser.search("div/b:last-of-type"), "bold"
152
+ assert_result_rows [2,7], @parser.search("div/i:last-of-type"), "italic"
153
+ assert_result_rows [2,6,7], @parser.search("div i:last-of-type"), "italic"
154
+ assert_result_rows [4], @parser.search("div/i.b:last-of-type"), "italic"
155
+ end
156
+
157
+ def test_nth_of_type
158
+ assert_result_rows [1], @parser.search("div/b:nth-of-type(1)"), "bold"
159
+ assert_result_rows [2], @parser.search("div/b:nth-of-type(2)"), "bold"
160
+ assert_result_rows [2], @parser.search("div/.a:nth-of-type(1)"), "bold"
161
+ assert_result_rows [2,4,7], @parser.search("div i:nth-of-type(2n)"), "italic"
162
+ assert_result_rows [1,3,5,6], @parser.search("div i:nth-of-type(2n+1)"), "italic"
163
+ assert_result_rows [1], @parser.search("div .a:nth-of-type(2n)"), "emphasis"
164
+ assert_result_rows [2,3], @parser.search("div .a:nth-of-type(2n+1)"), "bold"
165
+ end
166
+
167
+ def test_nth_last_of_type
168
+ assert_result_rows [14], @parser.search("table/tr:nth-last-of-type(1)")
169
+ assert_result_rows [12], @parser.search("table/tr:nth-last-of-type(3)")
170
+ assert_result_rows [2,6,7], @parser.search("div i:nth-last-of-type(1)"), "italic"
171
+ assert_result_rows [1,5], @parser.search("div i:nth-last-of-type(2)"), "italic"
172
+ assert_result_rows [4], @parser.search("div/i.b:nth-last-of-type(1)"), "italic"
173
+ assert_result_rows [3], @parser.search("div/i.b:nth-last-of-type(2)"), "italic"
108
174
  end
109
175
 
110
176
  def test_only_of_type
111
177
  assert_result_rows [1,4], @parser.search("div/p:only-of-type"), "para"
178
+ assert_result_rows [5], @parser.search("div/i.c:only-of-type"), "italic"
112
179
  end
113
180
 
114
181
  def test_only_child
115
182
  assert_result_rows [4], @parser.search("div/p:only-child"), "para"
183
+ assert_result_rows [4], @parser.search("div/h1.c:only-child"), "header"
116
184
  end
117
185
 
118
186
  def test_empty
@@ -139,8 +207,7 @@ EOF
139
207
  <p id="4">p4 </p>
140
208
  <p id="5">p5 </p>
141
209
  EOF
142
- parser = Nokogiri.Hpricot doc
143
-
210
+ parser = Nokogiri.HTML doc
144
211
  assert_equal 2, parser.search("#3 ~ p").size
145
212
  assert_equal "p4 p5 ", parser.search("#3 ~ p").inner_text
146
213
  assert_equal 0, parser.search("#5 ~ p").size
@@ -1,10 +1,27 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', "helper"))
1
+ require "helper"
2
2
 
3
3
  module Nokogiri
4
4
  module CSS
5
5
  class TestParser < Nokogiri::TestCase
6
6
  def setup
7
+ super
7
8
  @parser = Nokogiri::CSS::Parser.new
9
+ @parser_with_ns = Nokogiri::CSS::Parser.new({
10
+ "xmlns" => "http://default.example.com/",
11
+ "hoge" => "http://hoge.example.com/",
12
+ })
13
+ end
14
+
15
+ def test_extra_single_quote
16
+ assert_raises(CSS::SyntaxError) { @parser.parse("'") }
17
+ end
18
+
19
+ def test_syntax_error_raised
20
+ assert_raises(CSS::SyntaxError) { @parser.parse("a[x=]") }
21
+ end
22
+
23
+ def test_function_and_pseudo
24
+ assert_xpath '//child::text()[position() = 99]', @parser.parse('text():nth-of-type(99)')
8
25
  end
9
26
 
10
27
  def test_find_by_type
@@ -45,28 +62,66 @@ module Nokogiri
45
62
  )
46
63
  end
47
64
 
65
+ def test_has
66
+ assert_xpath "//a[b]", @parser.parse("a:has(b)")
67
+ assert_xpath "//a[b/c]", @parser.parse("a:has(b > c)")
68
+ end
69
+
70
+ def test_dashmatch
71
+ assert_xpath "//a[@class = 'bar' or starts-with(@class, concat('bar', '-'))]",
72
+ @parser.parse("a[@class|='bar']")
73
+ assert_xpath "//a[@class = 'bar' or starts-with(@class, concat('bar', '-'))]",
74
+ @parser.parse("a[@class |= 'bar']")
75
+ end
76
+
77
+ def test_includes
78
+ assert_xpath "//a[contains(concat(\" \", @class, \" \"),concat(\" \", 'bar', \" \"))]",
79
+ @parser.parse("a[@class~='bar']")
80
+ assert_xpath "//a[contains(concat(\" \", @class, \" \"),concat(\" \", 'bar', \" \"))]",
81
+ @parser.parse("a[@class ~= 'bar']")
82
+ end
83
+
48
84
  def test_function_with_arguments
49
- assert_xpath "//*[position() = 2 and self::a]",
85
+ assert_xpath "//a[count(preceding-sibling::*) = 1]",
50
86
  @parser.parse("a[2]")
51
- assert_xpath "//*[position() = 2 and self::a]",
87
+ assert_xpath "//a[count(preceding-sibling::*) = 1]",
52
88
  @parser.parse("a:nth-child(2)")
53
89
  end
54
90
 
55
91
  def test_carrot
56
92
  assert_xpath "//a[starts-with(@id, 'Boing')]",
57
93
  @parser.parse("a[id^='Boing']")
94
+ assert_xpath "//a[starts-with(@id, 'Boing')]",
95
+ @parser.parse("a[id ^= 'Boing']")
96
+ end
97
+
98
+ def test_suffix_match
99
+ assert_xpath "//a[substring(@id, string-length(@id) - string-length('Boing') + 1, string-length('Boing')) = 'Boing']",
100
+ @parser.parse("a[id$='Boing']")
101
+ assert_xpath "//a[substring(@id, string-length(@id) - string-length('Boing') + 1, string-length('Boing')) = 'Boing']",
102
+ @parser.parse("a[id $= 'Boing']")
58
103
  end
59
104
 
60
105
  def test_attributes_with_at
61
106
  ## This is non standard CSS
62
107
  assert_xpath "//a[@id = 'Boing']",
63
108
  @parser.parse("a[@id='Boing']")
109
+ assert_xpath "//a[@id = 'Boing']",
110
+ @parser.parse("a[@id = 'Boing']")
111
+ end
112
+
113
+ def test_attributes_with_at_and_stuff
114
+ ## This is non standard CSS
115
+ assert_xpath "//a[@id = 'Boing']//div",
116
+ @parser.parse("a[@id='Boing'] div")
64
117
  end
65
118
 
66
119
  def test_not_equal
67
120
  ## This is non standard CSS
68
121
  assert_xpath "//a[child::text() != 'Boing']",
69
122
  @parser.parse("a[text()!='Boing']")
123
+ assert_xpath "//a[child::text() != 'Boing']",
124
+ @parser.parse("a[text() != 'Boing']")
70
125
  end
71
126
 
72
127
  def test_function
@@ -81,6 +136,8 @@ module Nokogiri
81
136
  ## This is non standard CSS
82
137
  assert_xpath "//a[contains(child::text(), 'Boing')]",
83
138
  @parser.parse("a[text()*='Boing']")
139
+ assert_xpath "//a[contains(child::text(), 'Boing')]",
140
+ @parser.parse("a[text() *= 'Boing']")
84
141
 
85
142
  ## This is non standard CSS
86
143
  assert_xpath "//script//comment()",
@@ -89,35 +146,43 @@ module Nokogiri
89
146
 
90
147
  def test_nonstandard_nth_selectors
91
148
  ## These are non standard CSS
92
- assert_xpath '//a[position() = 99]', @parser.parse('a:eq(99)')
93
- assert_xpath '//a[position() = 1]', @parser.parse('a:first') # no parens
94
- assert_xpath '//a[position() = last()]', @parser.parse('a:last') # no parens
95
- assert_xpath '//a[position() = 99]', @parser.parse('a:nth(99)')
96
- assert_xpath '//a[position() = 1]', @parser.parse('a:first()')
97
- assert_xpath '//a[position() = last()]', @parser.parse('a:last()')
98
- assert_xpath '//a[node()]', @parser.parse('a:parent')
149
+ assert_xpath '//a[position() = 1]', @parser.parse('a:first()')
150
+ assert_xpath '//a[position() = 1]', @parser.parse('a:first') # no parens
151
+ assert_xpath '//a[position() = 99]', @parser.parse('a:eq(99)')
152
+ assert_xpath '//a[position() = 99]', @parser.parse('a:nth(99)')
153
+ assert_xpath '//a[position() = last()]', @parser.parse('a:last()')
154
+ assert_xpath '//a[position() = last()]', @parser.parse('a:last') # no parens
155
+ assert_xpath '//a[node()]', @parser.parse('a:parent')
99
156
  end
100
157
 
101
158
  def test_standard_nth_selectors
102
- assert_xpath '//a[position() = 99]', @parser.parse('a:nth-of-type(99)')
103
- assert_xpath '//a[position() = 1]', @parser.parse('a:first-of-type()')
104
- assert_xpath '//a[position() = last()]', @parser.parse('a:last-of-type()')
105
- assert_xpath '//a[position() = 1]', @parser.parse('a:first-of-type') # no parens
106
- assert_xpath '//a[position() = last()]', @parser.parse('a:last-of-type') # no parens
107
- assert_xpath '//a[position() = last() - 99]', @parser.parse('a:nth-last-of-type(99)')
108
- assert_xpath '//a[position() = last() - 99]', @parser.parse('a:nth-last-of-type(99)')
159
+ assert_xpath '//a[position() = 1]', @parser.parse('a:first-of-type()')
160
+ assert_xpath '//a[position() = 1]', @parser.parse('a:first-of-type') # no parens
161
+ assert_xpath "//a[contains(concat(' ', normalize-space(@class), ' '), ' b ')][position() = 1]",
162
+ @parser.parse('a.b:first-of-type') # no parens
163
+ assert_xpath '//a[position() = 99]', @parser.parse('a:nth-of-type(99)')
164
+ assert_xpath "//a[contains(concat(' ', normalize-space(@class), ' '), ' b ')][position() = 99]",
165
+ @parser.parse('a.b:nth-of-type(99)')
166
+ assert_xpath '//a[position() = last()]', @parser.parse('a:last-of-type()')
167
+ assert_xpath '//a[position() = last()]', @parser.parse('a:last-of-type') # no parens
168
+ assert_xpath "//a[contains(concat(' ', normalize-space(@class), ' '), ' b ')][position() = last()]",
169
+ @parser.parse('a.b:last-of-type') # no parens
170
+ assert_xpath '//a[position() = last()]', @parser.parse('a:nth-last-of-type(1)')
171
+ assert_xpath '//a[position() = last() - 98]', @parser.parse('a:nth-last-of-type(99)')
172
+ assert_xpath "//a[contains(concat(' ', normalize-space(@class), ' '), ' b ')][position() = last() - 98]",
173
+ @parser.parse('a.b:nth-last-of-type(99)')
109
174
  end
110
175
 
111
176
  def test_nth_child_selectors
112
- assert_xpath '//*[position() = 1 and self::a]', @parser.parse('a:first-child')
113
- assert_xpath '//*[position() = last() and self::a]', @parser.parse('a:last-child')
114
- assert_xpath '//*[position() = 99 and self::a]', @parser.parse('a:nth-child(99)')
115
- assert_xpath '//*[position() = last() - 99 and self::a]', @parser.parse('a:nth-last-child(99)')
177
+ assert_xpath '//a[count(preceding-sibling::*) = 0]', @parser.parse('a:first-child')
178
+ assert_xpath '//a[count(preceding-sibling::*) = 98]', @parser.parse('a:nth-child(99)')
179
+ assert_xpath '//a[count(following-sibling::*) = 0]', @parser.parse('a:last-child')
180
+ assert_xpath '//a[count(following-sibling::*) = 0]', @parser.parse('a:nth-last-child(1)')
181
+ assert_xpath '//a[count(following-sibling::*) = 98]', @parser.parse('a:nth-last-child(99)')
116
182
  end
117
183
 
118
184
  def test_miscellaneous_selectors
119
- assert_xpath '//*[last() = 1 and self::a]',
120
- @parser.parse('a:only-child')
185
+ assert_xpath '//a[count(preceding-sibling::*) = 0 and count(following-sibling::*) = 0]', @parser.parse('a:only-child')
121
186
  assert_xpath '//a[last() = 1]', @parser.parse('a:only-of-type')
122
187
  assert_xpath '//a[not(node())]', @parser.parse('a:empty')
123
188
  end
@@ -128,20 +193,63 @@ module Nokogiri
128
193
  assert_xpath '//a[(position() mod 2) = 0]', @parser.parse('a:nth-of-type(even)')
129
194
  assert_xpath '//a[(position() >= 1) and (((position()-1) mod 2) = 0)]', @parser.parse('a:nth-of-type(odd)')
130
195
  assert_xpath '//a[(position() >= 3) and (((position()-3) mod 4) = 0)]', @parser.parse('a:nth-of-type(4n+3)')
131
- assert_xpath '//a[(position() <= 3) and (((position()-3) mod 1) = 0)]', @parser.parse('a:nth-of-type(-1n+3)')
132
- assert_xpath '//a[(position() <= 3) and (((position()-3) mod 1) = 0)]', @parser.parse('a:nth-of-type(-n+3)')
133
- assert_xpath '//a[(position() >= 3) and (((position()-3) mod 1) = 0)]', @parser.parse('a:nth-of-type(1n+3)')
134
- assert_xpath '//a[(position() >= 3) and (((position()-3) mod 1) = 0)]', @parser.parse('a:nth-of-type(n+3)')
196
+ assert_xpath '//a[position() <= 3]', @parser.parse('a:nth-of-type(-1n+3)')
197
+ assert_xpath '//a[position() <= 3]', @parser.parse('a:nth-of-type(-n+3)')
198
+ assert_xpath '//a[position() >= 3]', @parser.parse('a:nth-of-type(1n+3)')
199
+ assert_xpath '//a[position() >= 3]', @parser.parse('a:nth-of-type(n+3)')
200
+
201
+ assert_xpath '//a[((last()-position()+1) mod 2) = 0]', @parser.parse('a:nth-last-of-type(2n)')
202
+ assert_xpath '//a[((last()-position()+1) >= 1) and ((((last()-position()+1)-1) mod 2) = 0)]', @parser.parse('a:nth-last-of-type(2n+1)')
203
+ assert_xpath '//a[((last()-position()+1) mod 2) = 0]', @parser.parse('a:nth-last-of-type(even)')
204
+ assert_xpath '//a[((last()-position()+1) >= 1) and ((((last()-position()+1)-1) mod 2) = 0)]', @parser.parse('a:nth-last-of-type(odd)')
205
+ assert_xpath '//a[((last()-position()+1) >= 3) and ((((last()-position()+1)-3) mod 4) = 0)]', @parser.parse('a:nth-last-of-type(4n+3)')
206
+ assert_xpath '//a[(last()-position()+1) <= 3]', @parser.parse('a:nth-last-of-type(-1n+3)')
207
+ assert_xpath '//a[(last()-position()+1) <= 3]', @parser.parse('a:nth-last-of-type(-n+3)')
208
+ assert_xpath '//a[(last()-position()+1) >= 3]', @parser.parse('a:nth-last-of-type(1n+3)')
209
+ assert_xpath '//a[(last()-position()+1) >= 3]', @parser.parse('a:nth-last-of-type(n+3)')
135
210
  end
136
211
 
137
212
  def test_preceding_selector
138
- assert_xpath "//F[preceding-sibling::E]",
213
+ assert_xpath "//E/following-sibling::F",
139
214
  @parser.parse("E ~ F")
215
+
216
+ assert_xpath "//E/following-sibling::F//G",
217
+ @parser.parse("E ~ F G")
140
218
  end
141
219
 
142
220
  def test_direct_preceding_selector
143
221
  assert_xpath "//E/following-sibling::*[1]/self::F",
144
222
  @parser.parse("E + F")
223
+
224
+ assert_xpath "//E/following-sibling::*[1]/self::F//G",
225
+ @parser.parse("E + F G")
226
+ end
227
+
228
+ def test_child_selector
229
+ assert_xpath("//a//b/i", @parser.parse('a b>i'))
230
+ assert_xpath("//a//b/i", @parser.parse('a b > i'))
231
+ assert_xpath("//a/b/i", @parser.parse('a > b > i'))
232
+ end
233
+
234
+ def test_prefixless_child_selector
235
+ assert_xpath("./a", @parser.parse('>a'))
236
+ assert_xpath("./a", @parser.parse('> a'))
237
+ assert_xpath("./a//b/i", @parser.parse('>a b>i'))
238
+ assert_xpath("./a/b/i", @parser.parse('> a > b > i'))
239
+ end
240
+
241
+ def test_prefixless_preceding_sibling_selector
242
+ assert_xpath("./following-sibling::a", @parser.parse('~a'))
243
+ assert_xpath("./following-sibling::a", @parser.parse('~ a'))
244
+ assert_xpath("./following-sibling::a//b/following-sibling::i", @parser.parse('~a b~i'))
245
+ assert_xpath("./following-sibling::a//b/following-sibling::i", @parser.parse('~ a b ~ i'))
246
+ end
247
+
248
+ def test_prefixless_direct_adjacent_selector
249
+ assert_xpath("./following-sibling::*[1]/self::a", @parser.parse('+a'))
250
+ assert_xpath("./following-sibling::*[1]/self::a", @parser.parse('+ a'))
251
+ assert_xpath("./following-sibling::*[1]/self::a/following-sibling::*[1]/self::b", @parser.parse('+a+b'))
252
+ assert_xpath("./following-sibling::*[1]/self::a/following-sibling::*[1]/self::b", @parser.parse('+ a + b'))
145
253
  end
146
254
 
147
255
  def test_attribute
@@ -151,36 +259,66 @@ module Nokogiri
151
259
 
152
260
  def test_id
153
261
  assert_xpath "//*[@id = 'foo']", @parser.parse('#foo')
262
+ assert_xpath "//*[@id = 'escape:needed,']", @parser.parse('#escape\:needed\,')
263
+ assert_xpath "//*[@id = 'escape:needed,']", @parser.parse('#escape\3Aneeded\,')
264
+ assert_xpath "//*[@id = 'escape:needed,']", @parser.parse('#escape\3A needed\2C')
265
+ assert_xpath "//*[@id = 'escape:needed']", @parser.parse('#escape\00003Aneeded')
154
266
  end
155
267
 
156
268
  def test_pseudo_class_no_ident
157
- assert_xpath "//*[1 = 1]", @parser.parse(':link')
269
+ assert_xpath "//*[link(.)]", @parser.parse(':link')
158
270
  end
159
271
 
160
272
  def test_pseudo_class
161
- assert_xpath "//a[1 = 1]", @parser.parse('a:link')
162
- assert_xpath "//a[1 = 1]", @parser.parse('a:visited')
163
- assert_xpath "//a[1 = 1]", @parser.parse('a:hover')
164
- assert_xpath "//a[1 = 1]", @parser.parse('a:active')
165
- assert_xpath "//a[1 = 1 and contains(concat(' ', @class, ' '), ' foo ')]",
273
+ assert_xpath "//a[link(.)]", @parser.parse('a:link')
274
+ assert_xpath "//a[visited(.)]", @parser.parse('a:visited')
275
+ assert_xpath "//a[hover(.)]", @parser.parse('a:hover')
276
+ assert_xpath "//a[active(.)]", @parser.parse('a:active')
277
+ assert_xpath "//a[active(.) and contains(concat(' ', normalize-space(@class), ' '), ' foo ')]",
166
278
  @parser.parse('a:active.foo')
167
279
  end
168
280
 
281
+ def test_significant_space
282
+ assert_xpath "//x//*[count(preceding-sibling::*) = 0]//*[@a]//*[@b]", @parser.parse("x :first-child [a] [b]")
283
+ assert_xpath "//*[@a]//*[@b]", @parser.parse(" [a] [b]")
284
+ end
285
+
169
286
  def test_star
170
287
  assert_xpath "//*", @parser.parse('*')
171
- assert_xpath "//*[contains(concat(' ', @class, ' '), ' pastoral ')]",
288
+ assert_xpath "//*[contains(concat(' ', normalize-space(@class), ' '), ' pastoral ')]",
172
289
  @parser.parse('*.pastoral')
173
290
  end
174
291
 
175
292
  def test_class
176
- assert_xpath "//*[contains(concat(' ', @class, ' '), ' a ') and contains(concat(' ', @class, ' '), ' b ')]",
293
+ assert_xpath "//*[contains(concat(' ', normalize-space(@class), ' '), ' a ') and contains(concat(' ', normalize-space(@class), ' '), ' b ')]",
177
294
  @parser.parse('.a.b')
178
- assert_xpath "//*[contains(concat(' ', @class, ' '), ' awesome ')]",
295
+ assert_xpath "//*[contains(concat(' ', normalize-space(@class), ' '), ' awesome ')]",
179
296
  @parser.parse('.awesome')
180
- assert_xpath "//foo[contains(concat(' ', @class, ' '), ' awesome ')]",
297
+ assert_xpath "//foo[contains(concat(' ', normalize-space(@class), ' '), ' awesome ')]",
181
298
  @parser.parse('foo.awesome')
182
- assert_xpath "//foo//*[contains(concat(' ', @class, ' '), ' awesome ')]",
299
+ assert_xpath "//foo//*[contains(concat(' ', normalize-space(@class), ' '), ' awesome ')]",
183
300
  @parser.parse('foo .awesome')
301
+ assert_xpath "//foo//*[contains(concat(' ', normalize-space(@class), ' '), ' awe.some ')]",
302
+ @parser.parse('foo .awe\.some')
303
+ end
304
+
305
+ def test_bare_not
306
+ assert_xpath "//*[not(contains(concat(' ', normalize-space(@class), ' '), ' a '))]",
307
+ @parser.parse(':not(.a)')
308
+ end
309
+
310
+ def test_not_so_simple_not
311
+ assert_xpath "//*[@id = 'p' and not(contains(concat(' ', normalize-space(@class), ' '), ' a '))]",
312
+ @parser.parse('#p:not(.a)')
313
+ assert_xpath "//p[contains(concat(' ', normalize-space(@class), ' '), ' a ') and not(contains(concat(' ', normalize-space(@class), ' '), ' b '))]",
314
+ @parser.parse('p.a:not(.b)')
315
+ assert_xpath "//p[@a = 'foo' and not(contains(concat(' ', normalize-space(@class), ' '), ' b '))]",
316
+ @parser.parse("p[a='foo']:not(.b)")
317
+ end
318
+
319
+ def test_multiple_not
320
+ assert_xpath "//p[not(contains(concat(' ', normalize-space(@class), ' '), ' a ')) and not(contains(concat(' ', normalize-space(@class), ' '), ' b ')) and not(contains(concat(' ', normalize-space(@class), ' '), ' c '))]",
321
+ @parser.parse("p:not(.a):not(.b):not(.c)")
184
322
  end
185
323
 
186
324
  def test_ident
@@ -213,6 +351,13 @@ module Nokogiri
213
351
  # assert_xpath ['//x/y', '//y/z'], @parser.parse('x > y | y > z')
214
352
  end
215
353
 
354
+ def test_attributes_with_namespace
355
+ ## Default namespace is not applied to attributes.
356
+ ## So this must be @class, not @xmlns:class.
357
+ assert_xpath "//xmlns:a[@class = 'bar']", @parser_with_ns.parse("a[class='bar']")
358
+ assert_xpath "//xmlns:a[@hoge:class = 'bar']", @parser_with_ns.parse("a[hoge|class='bar']")
359
+ end
360
+
216
361
  def assert_xpath expecteds, asts
217
362
  expecteds = [expecteds].flatten
218
363
  expecteds.zip(asts).each do |expected, actual|