eactionpack 2.1.2

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 (338) hide show
  1. data/CHANGELOG +7 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README +469 -0
  4. data/RUNNING_UNIT_TESTS +24 -0
  5. data/Rakefile +146 -0
  6. data/install.rb +30 -0
  7. data/lib/action_controller.rb +79 -0
  8. data/lib/action_controller/assertions.rb +69 -0
  9. data/lib/action_controller/assertions/dom_assertions.rb +39 -0
  10. data/lib/action_controller/assertions/model_assertions.rb +20 -0
  11. data/lib/action_controller/assertions/response_assertions.rb +172 -0
  12. data/lib/action_controller/assertions/routing_assertions.rb +146 -0
  13. data/lib/action_controller/assertions/selector_assertions.rb +491 -0
  14. data/lib/action_controller/assertions/tag_assertions.rb +130 -0
  15. data/lib/action_controller/base.rb +1288 -0
  16. data/lib/action_controller/benchmarking.rb +94 -0
  17. data/lib/action_controller/caching.rb +72 -0
  18. data/lib/action_controller/caching/actions.rb +144 -0
  19. data/lib/action_controller/caching/fragments.rb +138 -0
  20. data/lib/action_controller/caching/pages.rb +154 -0
  21. data/lib/action_controller/caching/sql_cache.rb +18 -0
  22. data/lib/action_controller/caching/sweeping.rb +97 -0
  23. data/lib/action_controller/cgi_ext.rb +16 -0
  24. data/lib/action_controller/cgi_ext/cookie.rb +110 -0
  25. data/lib/action_controller/cgi_ext/query_extension.rb +22 -0
  26. data/lib/action_controller/cgi_ext/session.rb +73 -0
  27. data/lib/action_controller/cgi_ext/stdinput.rb +24 -0
  28. data/lib/action_controller/cgi_process.rb +223 -0
  29. data/lib/action_controller/components.rb +166 -0
  30. data/lib/action_controller/cookies.rb +96 -0
  31. data/lib/action_controller/dispatcher.rb +162 -0
  32. data/lib/action_controller/filters.rb +642 -0
  33. data/lib/action_controller/flash.rb +172 -0
  34. data/lib/action_controller/headers.rb +31 -0
  35. data/lib/action_controller/helpers.rb +221 -0
  36. data/lib/action_controller/http_authentication.rb +124 -0
  37. data/lib/action_controller/integration.rb +634 -0
  38. data/lib/action_controller/layout.rb +309 -0
  39. data/lib/action_controller/mime_responds.rb +173 -0
  40. data/lib/action_controller/mime_type.rb +186 -0
  41. data/lib/action_controller/mime_types.rb +20 -0
  42. data/lib/action_controller/polymorphic_routes.rb +191 -0
  43. data/lib/action_controller/record_identifier.rb +102 -0
  44. data/lib/action_controller/request.rb +764 -0
  45. data/lib/action_controller/request_forgery_protection.rb +140 -0
  46. data/lib/action_controller/request_profiler.rb +169 -0
  47. data/lib/action_controller/rescue.rb +258 -0
  48. data/lib/action_controller/resources.rb +572 -0
  49. data/lib/action_controller/response.rb +76 -0
  50. data/lib/action_controller/routing.rb +387 -0
  51. data/lib/action_controller/routing/builder.rb +203 -0
  52. data/lib/action_controller/routing/optimisations.rb +120 -0
  53. data/lib/action_controller/routing/recognition_optimisation.rb +162 -0
  54. data/lib/action_controller/routing/route.rb +240 -0
  55. data/lib/action_controller/routing/route_set.rb +436 -0
  56. data/lib/action_controller/routing/routing_ext.rb +46 -0
  57. data/lib/action_controller/routing/segments.rb +283 -0
  58. data/lib/action_controller/session/active_record_store.rb +340 -0
  59. data/lib/action_controller/session/cookie_store.rb +166 -0
  60. data/lib/action_controller/session/drb_server.rb +32 -0
  61. data/lib/action_controller/session/drb_store.rb +35 -0
  62. data/lib/action_controller/session/mem_cache_store.rb +98 -0
  63. data/lib/action_controller/session_management.rb +158 -0
  64. data/lib/action_controller/status_codes.rb +88 -0
  65. data/lib/action_controller/streaming.rb +155 -0
  66. data/lib/action_controller/templates/rescues/_request_and_response.erb +24 -0
  67. data/lib/action_controller/templates/rescues/_trace.erb +26 -0
  68. data/lib/action_controller/templates/rescues/diagnostics.erb +11 -0
  69. data/lib/action_controller/templates/rescues/layout.erb +29 -0
  70. data/lib/action_controller/templates/rescues/missing_template.erb +2 -0
  71. data/lib/action_controller/templates/rescues/routing_error.erb +10 -0
  72. data/lib/action_controller/templates/rescues/template_error.erb +21 -0
  73. data/lib/action_controller/templates/rescues/unknown_action.erb +2 -0
  74. data/lib/action_controller/test_case.rb +83 -0
  75. data/lib/action_controller/test_process.rb +526 -0
  76. data/lib/action_controller/url_rewriter.rb +142 -0
  77. data/lib/action_controller/vendor/html-scanner/html/document.rb +68 -0
  78. data/lib/action_controller/vendor/html-scanner/html/node.rb +537 -0
  79. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +173 -0
  80. data/lib/action_controller/vendor/html-scanner/html/selector.rb +828 -0
  81. data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +105 -0
  82. data/lib/action_controller/vendor/html-scanner/html/version.rb +11 -0
  83. data/lib/action_controller/verification.rb +130 -0
  84. data/lib/action_pack.rb +24 -0
  85. data/lib/action_pack/version.rb +9 -0
  86. data/lib/action_view.rb +44 -0
  87. data/lib/action_view/base.rb +335 -0
  88. data/lib/action_view/helpers/active_record_helper.rb +276 -0
  89. data/lib/action_view/helpers/asset_tag_helper.rb +599 -0
  90. data/lib/action_view/helpers/atom_feed_helper.rb +143 -0
  91. data/lib/action_view/helpers/benchmark_helper.rb +33 -0
  92. data/lib/action_view/helpers/cache_helper.rb +40 -0
  93. data/lib/action_view/helpers/capture_helper.rb +161 -0
  94. data/lib/action_view/helpers/date_helper.rb +711 -0
  95. data/lib/action_view/helpers/debug_helper.rb +31 -0
  96. data/lib/action_view/helpers/form_helper.rb +767 -0
  97. data/lib/action_view/helpers/form_options_helper.rb +458 -0
  98. data/lib/action_view/helpers/form_tag_helper.rb +458 -0
  99. data/lib/action_view/helpers/javascript_helper.rb +148 -0
  100. data/lib/action_view/helpers/number_helper.rb +186 -0
  101. data/lib/action_view/helpers/record_identification_helper.rb +20 -0
  102. data/lib/action_view/helpers/record_tag_helper.rb +59 -0
  103. data/lib/action_view/helpers/sanitize_helper.rb +229 -0
  104. data/lib/action_view/helpers/tag_helper.rb +134 -0
  105. data/lib/action_view/helpers/text_helper.rb +507 -0
  106. data/lib/action_view/helpers/url_helper.rb +573 -0
  107. data/lib/action_view/inline_template.rb +20 -0
  108. data/lib/action_view/partial_template.rb +70 -0
  109. data/lib/action_view/partials.rb +158 -0
  110. data/lib/action_view/template.rb +125 -0
  111. data/lib/action_view/template_error.rb +110 -0
  112. data/lib/action_view/template_finder.rb +176 -0
  113. data/lib/action_view/template_handler.rb +34 -0
  114. data/lib/action_view/template_handlers/builder.rb +27 -0
  115. data/lib/action_view/template_handlers/compilable.rb +128 -0
  116. data/lib/action_view/template_handlers/erb.rb +56 -0
  117. data/lib/action_view/test_case.rb +58 -0
  118. data/lib/actionpack.rb +1 -0
  119. data/test/abstract_unit.rb +36 -0
  120. data/test/active_record_unit.rb +105 -0
  121. data/test/activerecord/active_record_store_test.rb +141 -0
  122. data/test/activerecord/render_partial_with_record_identification_test.rb +191 -0
  123. data/test/adv_attr_test.rb +20 -0
  124. data/test/controller/action_pack_assertions_test.rb +543 -0
  125. data/test/controller/addresses_render_test.rb +43 -0
  126. data/test/controller/assert_select_test.rb +331 -0
  127. data/test/controller/base_test.rb +219 -0
  128. data/test/controller/benchmark_test.rb +32 -0
  129. data/test/controller/caching_test.rb +581 -0
  130. data/test/controller/capture_test.rb +89 -0
  131. data/test/controller/cgi_test.rb +116 -0
  132. data/test/controller/components_test.rb +140 -0
  133. data/test/controller/content_type_test.rb +139 -0
  134. data/test/controller/controller_fixtures/app/controllers/admin/user_controller.rb +0 -0
  135. data/test/controller/controller_fixtures/app/controllers/user_controller.rb +0 -0
  136. data/test/controller/controller_fixtures/vendor/plugins/bad_plugin/lib/plugin_controller.rb +0 -0
  137. data/test/controller/cookie_test.rb +146 -0
  138. data/test/controller/custom_handler_test.rb +45 -0
  139. data/test/controller/deprecation/deprecated_base_methods_test.rb +37 -0
  140. data/test/controller/dispatcher_test.rb +105 -0
  141. data/test/controller/fake_controllers.rb +33 -0
  142. data/test/controller/fake_models.rb +11 -0
  143. data/test/controller/filter_params_test.rb +49 -0
  144. data/test/controller/filters_test.rb +881 -0
  145. data/test/controller/flash_test.rb +146 -0
  146. data/test/controller/header_test.rb +14 -0
  147. data/test/controller/helper_test.rb +210 -0
  148. data/test/controller/html-scanner/cdata_node_test.rb +15 -0
  149. data/test/controller/html-scanner/document_test.rb +148 -0
  150. data/test/controller/html-scanner/node_test.rb +89 -0
  151. data/test/controller/html-scanner/sanitizer_test.rb +269 -0
  152. data/test/controller/html-scanner/tag_node_test.rb +238 -0
  153. data/test/controller/html-scanner/text_node_test.rb +50 -0
  154. data/test/controller/html-scanner/tokenizer_test.rb +131 -0
  155. data/test/controller/http_authentication_test.rb +54 -0
  156. data/test/controller/integration_test.rb +252 -0
  157. data/test/controller/integration_upload_test.rb +43 -0
  158. data/test/controller/layout_test.rb +255 -0
  159. data/test/controller/mime_responds_test.rb +514 -0
  160. data/test/controller/mime_type_test.rb +84 -0
  161. data/test/controller/new_render_test.rb +843 -0
  162. data/test/controller/polymorphic_routes_test.rb +174 -0
  163. data/test/controller/record_identifier_test.rb +139 -0
  164. data/test/controller/redirect_test.rb +289 -0
  165. data/test/controller/render_test.rb +484 -0
  166. data/test/controller/request_forgery_protection_test.rb +305 -0
  167. data/test/controller/request_test.rb +928 -0
  168. data/test/controller/rescue_test.rb +517 -0
  169. data/test/controller/resources_test.rb +873 -0
  170. data/test/controller/routing_test.rb +2464 -0
  171. data/test/controller/selector_test.rb +628 -0
  172. data/test/controller/send_file_test.rb +138 -0
  173. data/test/controller/session/cookie_store_test.rb +258 -0
  174. data/test/controller/session/mem_cache_store_test.rb +181 -0
  175. data/test/controller/session_fixation_test.rb +89 -0
  176. data/test/controller/session_management_test.rb +178 -0
  177. data/test/controller/test_test.rb +695 -0
  178. data/test/controller/url_rewriter_test.rb +310 -0
  179. data/test/controller/verification_test.rb +270 -0
  180. data/test/controller/view_paths_test.rb +140 -0
  181. data/test/controller/webservice_test.rb +229 -0
  182. data/test/fixtures/addresses/list.erb +1 -0
  183. data/test/fixtures/bad_customers/_bad_customer.html.erb +1 -0
  184. data/test/fixtures/companies.yml +24 -0
  185. data/test/fixtures/company.rb +10 -0
  186. data/test/fixtures/content_type/render_default_content_types_for_respond_to.rhtml +1 -0
  187. data/test/fixtures/content_type/render_default_for_js.js.erb +1 -0
  188. data/test/fixtures/content_type/render_default_for_rhtml.rhtml +1 -0
  189. data/test/fixtures/content_type/render_default_for_rxml.rxml +1 -0
  190. data/test/fixtures/customers/_customer.html.erb +1 -0
  191. data/test/fixtures/db_definitions/sqlite.sql +49 -0
  192. data/test/fixtures/developer.rb +9 -0
  193. data/test/fixtures/developers.yml +21 -0
  194. data/test/fixtures/developers_projects.yml +13 -0
  195. data/test/fixtures/fun/games/hello_world.erb +1 -0
  196. data/test/fixtures/functional_caching/_partial.erb +3 -0
  197. data/test/fixtures/functional_caching/fragment_cached.html.erb +2 -0
  198. data/test/fixtures/functional_caching/html_fragment_cached_with_partial.html.erb +1 -0
  199. data/test/fixtures/functional_caching/js_fragment_cached_with_partial.js.rjs +1 -0
  200. data/test/fixtures/good_customers/_good_customer.html.erb +1 -0
  201. data/test/fixtures/helpers/abc_helper.rb +5 -0
  202. data/test/fixtures/helpers/fun/games_helper.rb +3 -0
  203. data/test/fixtures/helpers/fun/pdf_helper.rb +3 -0
  204. data/test/fixtures/layout_tests/alt/hello.rhtml +1 -0
  205. data/test/fixtures/layout_tests/layouts/controller_name_space/nested.rhtml +1 -0
  206. data/test/fixtures/layout_tests/layouts/item.rhtml +1 -0
  207. data/test/fixtures/layout_tests/layouts/layout_test.rhtml +1 -0
  208. data/test/fixtures/layout_tests/layouts/multiple_extensions.html.erb +1 -0
  209. data/test/fixtures/layout_tests/layouts/third_party_template_library.mab +1 -0
  210. data/test/fixtures/layout_tests/views/hello.rhtml +1 -0
  211. data/test/fixtures/layouts/block_with_layout.erb +3 -0
  212. data/test/fixtures/layouts/builder.builder +3 -0
  213. data/test/fixtures/layouts/partial_with_layout.erb +3 -0
  214. data/test/fixtures/layouts/standard.erb +1 -0
  215. data/test/fixtures/layouts/talk_from_action.erb +2 -0
  216. data/test/fixtures/layouts/yield.erb +2 -0
  217. data/test/fixtures/mascot.rb +3 -0
  218. data/test/fixtures/mascots.yml +4 -0
  219. data/test/fixtures/mascots/_mascot.html.erb +1 -0
  220. data/test/fixtures/multipart/binary_file +0 -0
  221. data/test/fixtures/multipart/boundary_problem_file +10 -0
  222. data/test/fixtures/multipart/bracketed_param +5 -0
  223. data/test/fixtures/multipart/large_text_file +10 -0
  224. data/test/fixtures/multipart/mixed_files +0 -0
  225. data/test/fixtures/multipart/mona_lisa.jpg +0 -0
  226. data/test/fixtures/multipart/single_parameter +5 -0
  227. data/test/fixtures/multipart/text_file +10 -0
  228. data/test/fixtures/override/test/hello_world.erb +1 -0
  229. data/test/fixtures/override2/layouts/test/sub.erb +1 -0
  230. data/test/fixtures/post_test/layouts/post.html.erb +1 -0
  231. data/test/fixtures/post_test/layouts/super_post.iphone.erb +1 -0
  232. data/test/fixtures/post_test/post/index.html.erb +1 -0
  233. data/test/fixtures/post_test/post/index.iphone.erb +1 -0
  234. data/test/fixtures/post_test/super_post/index.html.erb +1 -0
  235. data/test/fixtures/post_test/super_post/index.iphone.erb +1 -0
  236. data/test/fixtures/project.rb +3 -0
  237. data/test/fixtures/projects.yml +7 -0
  238. data/test/fixtures/public/404.html +1 -0
  239. data/test/fixtures/public/500.html +1 -0
  240. data/test/fixtures/public/images/rails.png +0 -0
  241. data/test/fixtures/public/javascripts/application.js +1 -0
  242. data/test/fixtures/public/javascripts/bank.js +1 -0
  243. data/test/fixtures/public/javascripts/robber.js +1 -0
  244. data/test/fixtures/public/javascripts/version.1.0.js +1 -0
  245. data/test/fixtures/public/stylesheets/bank.css +1 -0
  246. data/test/fixtures/public/stylesheets/robber.css +1 -0
  247. data/test/fixtures/public/stylesheets/version.1.0.css +1 -0
  248. data/test/fixtures/replies.yml +15 -0
  249. data/test/fixtures/reply.rb +7 -0
  250. data/test/fixtures/respond_to/all_types_with_layout.html.erb +1 -0
  251. data/test/fixtures/respond_to/custom_constant_handling_without_block.mobile.erb +1 -0
  252. data/test/fixtures/respond_to/iphone_with_html_response_type.html.erb +1 -0
  253. data/test/fixtures/respond_to/iphone_with_html_response_type.iphone.erb +1 -0
  254. data/test/fixtures/respond_to/layouts/missing.html.erb +1 -0
  255. data/test/fixtures/respond_to/layouts/standard.html.erb +1 -0
  256. data/test/fixtures/respond_to/layouts/standard.iphone.erb +1 -0
  257. data/test/fixtures/respond_to/using_defaults.html.erb +1 -0
  258. data/test/fixtures/respond_to/using_defaults.js.rjs +1 -0
  259. data/test/fixtures/respond_to/using_defaults.xml.builder +1 -0
  260. data/test/fixtures/respond_to/using_defaults_with_type_list.html.erb +1 -0
  261. data/test/fixtures/respond_to/using_defaults_with_type_list.js.rjs +1 -0
  262. data/test/fixtures/respond_to/using_defaults_with_type_list.xml.builder +1 -0
  263. data/test/fixtures/scope/test/modgreet.erb +1 -0
  264. data/test/fixtures/shared.html.erb +1 -0
  265. data/test/fixtures/symlink_parent/symlinked_layout.erb +5 -0
  266. data/test/fixtures/test/_customer.erb +1 -0
  267. data/test/fixtures/test/_customer_counter.erb +1 -0
  268. data/test/fixtures/test/_customer_greeting.erb +1 -0
  269. data/test/fixtures/test/_form.erb +1 -0
  270. data/test/fixtures/test/_hash_greeting.erb +1 -0
  271. data/test/fixtures/test/_hash_object.erb +2 -0
  272. data/test/fixtures/test/_hello.builder +1 -0
  273. data/test/fixtures/test/_labelling_form.erb +1 -0
  274. data/test/fixtures/test/_layout_for_partial.html.erb +3 -0
  275. data/test/fixtures/test/_partial.erb +1 -0
  276. data/test/fixtures/test/_partial.html.erb +1 -0
  277. data/test/fixtures/test/_partial.js.erb +1 -0
  278. data/test/fixtures/test/_partial_for_use_in_layout.html.erb +1 -0
  279. data/test/fixtures/test/_partial_only.erb +1 -0
  280. data/test/fixtures/test/_person.erb +2 -0
  281. data/test/fixtures/test/_raise.html.erb +1 -0
  282. data/test/fixtures/test/action_talk_to_layout.erb +2 -0
  283. data/test/fixtures/test/block_content_for.erb +2 -0
  284. data/test/fixtures/test/calling_partial_with_layout.html.erb +1 -0
  285. data/test/fixtures/test/capturing.erb +4 -0
  286. data/test/fixtures/test/content_for.erb +2 -0
  287. data/test/fixtures/test/content_for_concatenated.erb +3 -0
  288. data/test/fixtures/test/content_for_with_parameter.erb +2 -0
  289. data/test/fixtures/test/delete_with_js.rjs +2 -0
  290. data/test/fixtures/test/dot.directory/render_file_with_ivar.erb +1 -0
  291. data/test/fixtures/test/enum_rjs_test.rjs +6 -0
  292. data/test/fixtures/test/erb_content_for.erb +2 -0
  293. data/test/fixtures/test/formatted_html_erb.html.erb +1 -0
  294. data/test/fixtures/test/formatted_xml_erb.builder +1 -0
  295. data/test/fixtures/test/formatted_xml_erb.html.erb +1 -0
  296. data/test/fixtures/test/formatted_xml_erb.xml.erb +1 -0
  297. data/test/fixtures/test/greeting.erb +1 -0
  298. data/test/fixtures/test/greeting.js.rjs +1 -0
  299. data/test/fixtures/test/hello.builder +4 -0
  300. data/test/fixtures/test/hello_world.erb +1 -0
  301. data/test/fixtures/test/hello_world_container.builder +3 -0
  302. data/test/fixtures/test/hello_world_from_rxml.builder +4 -0
  303. data/test/fixtures/test/hello_world_with_layout_false.erb +1 -0
  304. data/test/fixtures/test/hello_xml_world.builder +11 -0
  305. data/test/fixtures/test/list.erb +1 -0
  306. data/test/fixtures/test/non_erb_block_content_for.builder +4 -0
  307. data/test/fixtures/test/potential_conflicts.erb +4 -0
  308. data/test/fixtures/test/render_file_from_template.html.erb +1 -0
  309. data/test/fixtures/test/render_file_with_ivar.erb +1 -0
  310. data/test/fixtures/test/render_file_with_locals.erb +1 -0
  311. data/test/fixtures/test/render_to_string_test.erb +1 -0
  312. data/test/fixtures/test/update_element_with_capture.erb +9 -0
  313. data/test/fixtures/test/using_layout_around_block.html.erb +1 -0
  314. data/test/fixtures/topic.rb +3 -0
  315. data/test/fixtures/topics.yml +22 -0
  316. data/test/fixtures/topics/_topic.html.erb +1 -0
  317. data/test/template/active_record_helper_test.rb +268 -0
  318. data/test/template/asset_tag_helper_test.rb +514 -0
  319. data/test/template/atom_feed_helper_test.rb +179 -0
  320. data/test/template/benchmark_helper_test.rb +60 -0
  321. data/test/template/date_helper_test.rb +1791 -0
  322. data/test/template/deprecated_erb_variable_test.rb +9 -0
  323. data/test/template/erb_util_test.rb +24 -0
  324. data/test/template/form_helper_test.rb +885 -0
  325. data/test/template/form_options_helper_test.rb +1333 -0
  326. data/test/template/form_tag_helper_test.rb +272 -0
  327. data/test/template/javascript_helper_test.rb +73 -0
  328. data/test/template/number_helper_test.rb +97 -0
  329. data/test/template/record_tag_helper_test.rb +54 -0
  330. data/test/template/sanitize_helper_test.rb +48 -0
  331. data/test/template/tag_helper_test.rb +77 -0
  332. data/test/template/template_finder_test.rb +73 -0
  333. data/test/template/template_object_test.rb +95 -0
  334. data/test/template/test_test.rb +56 -0
  335. data/test/template/text_helper_test.rb +367 -0
  336. data/test/template/url_helper_test.rb +544 -0
  337. data/test/testing_sandbox.rb +15 -0
  338. metadata +469 -0
@@ -0,0 +1,89 @@
1
+ require 'abstract_unit'
2
+
3
+ class NodeTest < Test::Unit::TestCase
4
+
5
+ class MockNode
6
+ def initialize(matched, value)
7
+ @matched = matched
8
+ @value = value
9
+ end
10
+
11
+ def find(conditions)
12
+ @matched && self
13
+ end
14
+
15
+ def to_s
16
+ @value.to_s
17
+ end
18
+ end
19
+
20
+ def setup
21
+ @node = HTML::Node.new("parent")
22
+ @node.children.concat [MockNode.new(false,1), MockNode.new(true,"two"), MockNode.new(false,:three)]
23
+ end
24
+
25
+ def test_match
26
+ assert !@node.match("foo")
27
+ end
28
+
29
+ def test_tag
30
+ assert !@node.tag?
31
+ end
32
+
33
+ def test_to_s
34
+ assert_equal "1twothree", @node.to_s
35
+ end
36
+
37
+ def test_find
38
+ assert_equal "two", @node.find('blah').to_s
39
+ end
40
+
41
+ def test_parse_strict
42
+ s = "<b foo='hello'' bar='baz'>"
43
+ assert_raise(RuntimeError) { HTML::Node.parse(nil,0,0,s) }
44
+ end
45
+
46
+ def test_parse_relaxed
47
+ s = "<b foo='hello'' bar='baz'>"
48
+ node = nil
49
+ assert_nothing_raised { node = HTML::Node.parse(nil,0,0,s,false) }
50
+ assert node.attributes.has_key?("foo")
51
+ assert !node.attributes.has_key?("bar")
52
+ end
53
+
54
+ def test_to_s_with_boolean_attrs
55
+ s = "<b foo bar>"
56
+ node = HTML::Node.parse(nil,0,0,s)
57
+ assert node.attributes.has_key?("foo")
58
+ assert node.attributes.has_key?("bar")
59
+ assert "<b foo bar>", node.to_s
60
+ end
61
+
62
+ def test_parse_with_unclosed_tag
63
+ s = "<span onmouseover='bang'"
64
+ node = nil
65
+ assert_nothing_raised { node = HTML::Node.parse(nil,0,0,s,false) }
66
+ assert node.attributes.has_key?("onmouseover")
67
+ end
68
+
69
+ def test_parse_with_valid_cdata_section
70
+ s = "<![CDATA[<span>contents</span>]]>"
71
+ node = nil
72
+ assert_nothing_raised { node = HTML::Node.parse(nil,0,0,s,false) }
73
+ assert_kind_of HTML::CDATA, node
74
+ assert_equal '<span>contents</span>', node.content
75
+ end
76
+
77
+ def test_parse_strict_with_unterminated_cdata_section
78
+ s = "<![CDATA[neverending..."
79
+ assert_raise(RuntimeError) { HTML::Node.parse(nil,0,0,s) }
80
+ end
81
+
82
+ def test_parse_relaxed_with_unterminated_cdata_section
83
+ s = "<![CDATA[neverending..."
84
+ node = nil
85
+ assert_nothing_raised { node = HTML::Node.parse(nil,0,0,s,false) }
86
+ assert_kind_of HTML::CDATA, node
87
+ assert_equal 'neverending...', node.content
88
+ end
89
+ end
@@ -0,0 +1,269 @@
1
+ require 'abstract_unit'
2
+
3
+ class SanitizerTest < Test::Unit::TestCase
4
+ def setup
5
+ @sanitizer = nil # used by assert_sanitizer
6
+ end
7
+
8
+ def test_strip_tags
9
+ sanitizer = HTML::FullSanitizer.new
10
+ assert_equal("<<<bad html", sanitizer.sanitize("<<<bad html"))
11
+ assert_equal("<<", sanitizer.sanitize("<<<bad html>"))
12
+ assert_equal("Dont touch me", sanitizer.sanitize("Dont touch me"))
13
+ assert_equal("This is a test.", sanitizer.sanitize("<p>This <u>is<u> a <a href='test.html'><strong>test</strong></a>.</p>"))
14
+ assert_equal("Weirdos", sanitizer.sanitize("Wei<<a>a onclick='alert(document.cookie);'</a>/>rdos"))
15
+ assert_equal("This is a test.", sanitizer.sanitize("This is a test."))
16
+ assert_equal(
17
+ %{This is a test.\n\n\nIt no longer contains any HTML.\n}, sanitizer.sanitize(
18
+ %{<title>This is <b>a <a href="" target="_blank">test</a></b>.</title>\n\n<!-- it has a comment -->\n\n<p>It no <b>longer <strong>contains <em>any <strike>HTML</strike></em>.</strong></b></p>\n}))
19
+ assert_equal "This has a here.", sanitizer.sanitize("This has a <!-- comment --> here.")
20
+ assert_equal "This has a here.", sanitizer.sanitize("This has a <![CDATA[<section>]]> here.")
21
+ assert_equal "This has an unclosed ", sanitizer.sanitize("This has an unclosed <![CDATA[<section>]] here...")
22
+ [nil, '', ' '].each { |blank| assert_equal blank, sanitizer.sanitize(blank) }
23
+ end
24
+
25
+ def test_strip_links
26
+ sanitizer = HTML::LinkSanitizer.new
27
+ assert_equal "Dont touch me", sanitizer.sanitize("Dont touch me")
28
+ assert_equal "on my mind\nall day long", sanitizer.sanitize("<a href='almost'>on my mind</a>\n<A href='almost'>all day long</A>")
29
+ assert_equal "0wn3d", sanitizer.sanitize("<a href='http://www.rubyonrails.com/'><a href='http://www.rubyonrails.com/' onlclick='steal()'>0wn3d</a></a>")
30
+ assert_equal "Magic", sanitizer.sanitize("<a href='http://www.rubyonrails.com/'>Mag<a href='http://www.ruby-lang.org/'>ic")
31
+ assert_equal "FrrFox", sanitizer.sanitize("<href onlclick='steal()'>FrrFox</a></href>")
32
+ assert_equal "My mind\nall <b>day</b> long", sanitizer.sanitize("<a href='almost'>My mind</a>\n<A href='almost'>all <b>day</b> long</A>")
33
+ assert_equal "all <b>day</b> long", sanitizer.sanitize("<<a>a href='hello'>all <b>day</b> long<</A>/a>")
34
+
35
+ assert_equal "<a<a", sanitizer.sanitize("<a<a")
36
+ end
37
+
38
+ def test_sanitize_form
39
+ assert_sanitized "<form action=\"/foo/bar\" method=\"post\"><input></form>", ''
40
+ end
41
+
42
+ def test_sanitize_plaintext
43
+ raw = "<plaintext><span>foo</span></plaintext>"
44
+ assert_sanitized raw, "<span>foo</span>"
45
+ end
46
+
47
+ def test_sanitize_script
48
+ assert_sanitized "a b c<script language=\"Javascript\">blah blah blah</script>d e f", "a b cd e f"
49
+ end
50
+
51
+ # fucked
52
+ def test_sanitize_js_handlers
53
+ raw = %{onthis="do that" <a href="#" onclick="hello" name="foo" onbogus="remove me">hello</a>}
54
+ assert_sanitized raw, %{onthis="do that" <a name="foo" href="#">hello</a>}
55
+ end
56
+
57
+ def test_sanitize_javascript_href
58
+ raw = %{href="javascript:bang" <a href="javascript:bang" name="hello">foo</a>, <span href="javascript:bang">bar</span>}
59
+ assert_sanitized raw, %{href="javascript:bang" <a name="hello">foo</a>, <span>bar</span>}
60
+ end
61
+
62
+ def test_sanitize_image_src
63
+ raw = %{src="javascript:bang" <img src="javascript:bang" width="5">foo</img>, <span src="javascript:bang">bar</span>}
64
+ assert_sanitized raw, %{src="javascript:bang" <img width="5">foo</img>, <span>bar</span>}
65
+ end
66
+
67
+ HTML::WhiteListSanitizer.allowed_tags.each do |tag_name|
68
+ define_method "test_should_allow_#{tag_name}_tag" do
69
+ assert_sanitized "start <#{tag_name} title=\"1\" onclick=\"foo\">foo <bad>bar</bad> baz</#{tag_name}> end", %(start <#{tag_name} title="1">foo bar baz</#{tag_name}> end)
70
+ end
71
+ end
72
+
73
+ def test_should_allow_anchors
74
+ assert_sanitized %(<a href="foo" onclick="bar"><script>baz</script></a>), %(<a href="foo"></a>)
75
+ end
76
+
77
+ # RFC 3986, sec 4.2
78
+ def test_allow_colons_in_path_component
79
+ assert_sanitized("<a href=\"./this:that\">foo</a>")
80
+ end
81
+
82
+ %w(src width height alt).each do |img_attr|
83
+ define_method "test_should_allow_image_#{img_attr}_attribute" do
84
+ assert_sanitized %(<img #{img_attr}="foo" onclick="bar" />), %(<img #{img_attr}="foo" />)
85
+ end
86
+ end
87
+
88
+ def test_should_handle_non_html
89
+ assert_sanitized 'abc'
90
+ end
91
+
92
+ def test_should_handle_blank_text
93
+ assert_sanitized nil
94
+ assert_sanitized ''
95
+ end
96
+
97
+ def test_should_allow_custom_tags
98
+ text = "<u>foo</u>"
99
+ sanitizer = HTML::WhiteListSanitizer.new
100
+ assert_equal(text, sanitizer.sanitize(text, :tags => %w(u)))
101
+ end
102
+
103
+ def test_should_allow_only_custom_tags
104
+ text = "<u>foo</u> with <i>bar</i>"
105
+ sanitizer = HTML::WhiteListSanitizer.new
106
+ assert_equal("<u>foo</u> with bar", sanitizer.sanitize(text, :tags => %w(u)))
107
+ end
108
+
109
+ def test_should_allow_custom_tags_with_attributes
110
+ text = %(<blockquote cite="http://example.com/">foo</blockquote>)
111
+ sanitizer = HTML::WhiteListSanitizer.new
112
+ assert_equal(text, sanitizer.sanitize(text))
113
+ end
114
+
115
+ def test_should_allow_custom_tags_with_custom_attributes
116
+ text = %(<blockquote foo="bar">Lorem ipsum</blockquote>)
117
+ sanitizer = HTML::WhiteListSanitizer.new
118
+ assert_equal(text, sanitizer.sanitize(text, :attributes => ['foo']))
119
+ end
120
+
121
+ [%w(img src), %w(a href)].each do |(tag, attr)|
122
+ define_method "test_should_strip_#{attr}_attribute_in_#{tag}_with_bad_protocols" do
123
+ assert_sanitized %(<#{tag} #{attr}="javascript:bang" title="1">boo</#{tag}>), %(<#{tag} title="1">boo</#{tag}>)
124
+ end
125
+ end
126
+
127
+ def test_should_flag_bad_protocols
128
+ sanitizer = HTML::WhiteListSanitizer.new
129
+ %w(about chrome data disk hcp help javascript livescript lynxcgi lynxexec ms-help ms-its mhtml mocha opera res resource shell vbscript view-source vnd.ms.radio wysiwyg).each do |proto|
130
+ assert sanitizer.send(:contains_bad_protocols?, 'src', "#{proto}://bad")
131
+ end
132
+ end
133
+
134
+ def test_should_accept_good_protocols
135
+ sanitizer = HTML::WhiteListSanitizer.new
136
+ HTML::WhiteListSanitizer.allowed_protocols.each do |proto|
137
+ assert !sanitizer.send(:contains_bad_protocols?, 'src', "#{proto}://good")
138
+ end
139
+ end
140
+
141
+ def test_should_reject_hex_codes_in_protocol
142
+ assert_sanitized %(<a href="&#37;6A&#37;61&#37;76&#37;61&#37;73&#37;63&#37;72&#37;69&#37;70&#37;74&#37;3A&#37;61&#37;6C&#37;65&#37;72&#37;74&#37;28&#37;22&#37;58&#37;53&#37;53&#37;22&#37;29">1</a>), "<a>1</a>"
143
+ assert @sanitizer.send(:contains_bad_protocols?, 'src', "%6A%61%76%61%73%63%72%69%70%74%3A%61%6C%65%72%74%28%22%58%53%53%22%29")
144
+ end
145
+
146
+ def test_should_block_script_tag
147
+ assert_sanitized %(<SCRIPT\nSRC=http://ha.ckers.org/xss.js></SCRIPT>), ""
148
+ end
149
+
150
+ [%(<IMG SRC="javascript:alert('XSS');">),
151
+ %(<IMG SRC=javascript:alert('XSS')>),
152
+ %(<IMG SRC=JaVaScRiPt:alert('XSS')>),
153
+ %(<IMG """><SCRIPT>alert("XSS")</SCRIPT>">),
154
+ %(<IMG SRC=javascript:alert(&quot;XSS&quot;)>),
155
+ %(<IMG SRC=javascript:alert(String.fromCharCode(88,83,83))>),
156
+ %(<IMG SRC=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41;>),
157
+ %(<IMG SRC=&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#0000112&#0000116&#0000058&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0000039&#0000088&#0000083&#0000083&#0000039&#0000041>),
158
+ %(<IMG SRC=&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29>),
159
+ %(<IMG SRC="jav\tascript:alert('XSS');">),
160
+ %(<IMG SRC="jav&#x09;ascript:alert('XSS');">),
161
+ %(<IMG SRC="jav&#x0A;ascript:alert('XSS');">),
162
+ %(<IMG SRC="jav&#x0D;ascript:alert('XSS');">),
163
+ %(<IMG SRC=" &#14; javascript:alert('XSS');">),
164
+ %(<IMG SRC=`javascript:alert("RSnake says, 'XSS'")`>)].each_with_index do |img_hack, i|
165
+ define_method "test_should_not_fall_for_xss_image_hack_#{i+1}" do
166
+ assert_sanitized img_hack, "<img>"
167
+ end
168
+ end
169
+
170
+ def test_should_sanitize_tag_broken_up_by_null
171
+ assert_sanitized %(<SCR\0IPT>alert(\"XSS\")</SCR\0IPT>), "alert(\"XSS\")"
172
+ end
173
+
174
+ def test_should_sanitize_invalid_script_tag
175
+ assert_sanitized %(<SCRIPT/XSS SRC="http://ha.ckers.org/xss.js"></SCRIPT>), ""
176
+ end
177
+
178
+ def test_should_sanitize_script_tag_with_multiple_open_brackets
179
+ assert_sanitized %(<<SCRIPT>alert("XSS");//<</SCRIPT>), "&lt;"
180
+ assert_sanitized %(<iframe src=http://ha.ckers.org/scriptlet.html\n<a), %(&lt;a)
181
+ end
182
+
183
+ def test_should_sanitize_unclosed_script
184
+ assert_sanitized %(<SCRIPT SRC=http://ha.ckers.org/xss.js?<B>), "<b>"
185
+ end
186
+
187
+ def test_should_sanitize_half_open_scripts
188
+ assert_sanitized %(<IMG SRC="javascript:alert('XSS')"), "<img>"
189
+ end
190
+
191
+ def test_should_not_fall_for_ridiculous_hack
192
+ img_hack = %(<IMG\nSRC\n=\n"\nj\na\nv\na\ns\nc\nr\ni\np\nt\n:\na\nl\ne\nr\nt\n(\n'\nX\nS\nS\n'\n)\n"\n>)
193
+ assert_sanitized img_hack, "<img>"
194
+ end
195
+
196
+ # fucked
197
+ def test_should_sanitize_attributes
198
+ assert_sanitized %(<SPAN title="'><script>alert()</script>">blah</SPAN>), %(<span title="'&gt;&lt;script&gt;alert()&lt;/script&gt;">blah</span>)
199
+ end
200
+
201
+ def test_should_sanitize_illegal_style_properties
202
+ raw = %(display:block; position:absolute; left:0; top:0; width:100%; height:100%; z-index:1; background-color:black; background-image:url(http://www.ragingplatypus.com/i/cam-full.jpg); background-x:center; background-y:center; background-repeat:repeat;)
203
+ expected = %(display: block; width: 100%; height: 100%; background-color: black; background-image: ; background-x: center; background-y: center;)
204
+ assert_equal expected, sanitize_css(raw)
205
+ end
206
+
207
+ def test_should_sanitize_with_trailing_space
208
+ raw = "display:block; "
209
+ expected = "display: block;"
210
+ assert_equal expected, sanitize_css(raw)
211
+ end
212
+
213
+ def test_should_sanitize_xul_style_attributes
214
+ raw = %(-moz-binding:url('http://ha.ckers.org/xssmoz.xml#xss'))
215
+ assert_equal '', sanitize_css(raw)
216
+ end
217
+
218
+ def test_should_sanitize_invalid_tag_names
219
+ assert_sanitized(%(a b c<script/XSS src="http://ha.ckers.org/xss.js"></script>d e f), "a b cd e f")
220
+ end
221
+
222
+ def test_should_sanitize_non_alpha_and_non_digit_characters_in_tags
223
+ assert_sanitized('<a onclick!#$%&()*~+-_.,:;?@[/|\]^`=alert("XSS")>foo</a>', "<a>foo</a>")
224
+ end
225
+
226
+ def test_should_sanitize_invalid_tag_names_in_single_tags
227
+ assert_sanitized('<img/src="http://ha.ckers.org/xss.js"/>', "<img />")
228
+ end
229
+
230
+ def test_should_sanitize_img_dynsrc_lowsrc
231
+ assert_sanitized(%(<img lowsrc="javascript:alert('XSS')" />), "<img />")
232
+ end
233
+
234
+ def test_should_sanitize_div_background_image_unicode_encoded
235
+ raw = %(background-image:\0075\0072\006C\0028'\006a\0061\0076\0061\0073\0063\0072\0069\0070\0074\003a\0061\006c\0065\0072\0074\0028.1027\0058.1053\0053\0027\0029'\0029)
236
+ assert_equal '', sanitize_css(raw)
237
+ end
238
+
239
+ def test_should_sanitize_div_style_expression
240
+ raw = %(width: expression(alert('XSS'));)
241
+ assert_equal '', sanitize_css(raw)
242
+ end
243
+
244
+ def test_should_sanitize_img_vbscript
245
+ assert_sanitized %(<img src='vbscript:msgbox("XSS")' />), '<img />'
246
+ end
247
+
248
+ def test_should_sanitize_cdata_section
249
+ assert_sanitized "<![CDATA[<span>section</span>]]>", "&lt;![CDATA[&lt;span>section&lt;/span>]]>"
250
+ end
251
+
252
+ def test_should_sanitize_unterminated_cdata_section
253
+ assert_sanitized "<![CDATA[<span>neverending...", "&lt;![CDATA[&lt;span>neverending...]]>"
254
+ end
255
+
256
+ protected
257
+ def assert_sanitized(input, expected = nil)
258
+ @sanitizer ||= HTML::WhiteListSanitizer.new
259
+ if input
260
+ assert_dom_equal expected || input, @sanitizer.sanitize(input)
261
+ else
262
+ assert_nil @sanitizer.sanitize(input)
263
+ end
264
+ end
265
+
266
+ def sanitize_css(input)
267
+ (@sanitizer ||= HTML::WhiteListSanitizer.new).sanitize_css(input)
268
+ end
269
+ end
@@ -0,0 +1,238 @@
1
+ require 'abstract_unit'
2
+
3
+ class TagNodeTest < Test::Unit::TestCase
4
+ def test_open_without_attributes
5
+ node = tag("<tag>")
6
+ assert_equal "tag", node.name
7
+ assert_equal Hash.new, node.attributes
8
+ assert_nil node.closing
9
+ end
10
+
11
+ def test_open_with_attributes
12
+ node = tag("<TAG1 foo=hey_ho x:bar=\"blah blah\" BAZ='blah blah blah' >")
13
+ assert_equal "tag1", node.name
14
+ assert_equal "hey_ho", node["foo"]
15
+ assert_equal "blah blah", node["x:bar"]
16
+ assert_equal "blah blah blah", node["baz"]
17
+ end
18
+
19
+ def test_self_closing_without_attributes
20
+ node = tag("<tag/>")
21
+ assert_equal "tag", node.name
22
+ assert_equal Hash.new, node.attributes
23
+ assert_equal :self, node.closing
24
+ end
25
+
26
+ def test_self_closing_with_attributes
27
+ node = tag("<tag a=b/>")
28
+ assert_equal "tag", node.name
29
+ assert_equal( { "a" => "b" }, node.attributes )
30
+ assert_equal :self, node.closing
31
+ end
32
+
33
+ def test_closing_without_attributes
34
+ node = tag("</tag>")
35
+ assert_equal "tag", node.name
36
+ assert_nil node.attributes
37
+ assert_equal :close, node.closing
38
+ end
39
+
40
+ def test_bracket_op_when_no_attributes
41
+ node = tag("</tag>")
42
+ assert_nil node["foo"]
43
+ end
44
+
45
+ def test_bracket_op_when_attributes
46
+ node = tag("<tag a=b/>")
47
+ assert_equal "b", node["a"]
48
+ end
49
+
50
+ def test_attributes_with_escaped_quotes
51
+ node = tag("<tag a='b\\'c' b=\"bob \\\"float\\\"\">")
52
+ assert_equal "b\\'c", node["a"]
53
+ assert_equal "bob \\\"float\\\"", node["b"]
54
+ end
55
+
56
+ def test_to_s
57
+ node = tag("<a b=c d='f' g=\"h 'i'\" />")
58
+ assert_equal %(<a b='c' d='f' g='h \\'i\\'' />), node.to_s
59
+ end
60
+
61
+ def test_tag
62
+ assert tag("<tag>").tag?
63
+ end
64
+
65
+ def test_match_tag_as_string
66
+ assert tag("<tag>").match(:tag => "tag")
67
+ assert !tag("<tag>").match(:tag => "b")
68
+ end
69
+
70
+ def test_match_tag_as_regexp
71
+ assert tag("<tag>").match(:tag => /t.g/)
72
+ assert !tag("<tag>").match(:tag => /t[bqs]g/)
73
+ end
74
+
75
+ def test_match_attributes_as_string
76
+ t = tag("<tag a=something b=else />")
77
+ assert t.match(:attributes => {"a" => "something"})
78
+ assert t.match(:attributes => {"b" => "else"})
79
+ end
80
+
81
+ def test_match_attributes_as_regexp
82
+ t = tag("<tag a=something b=else />")
83
+ assert t.match(:attributes => {"a" => /^something$/})
84
+ assert t.match(:attributes => {"b" => /e.*e/})
85
+ assert t.match(:attributes => {"a" => /me..i/, "b" => /.ls.$/})
86
+ end
87
+
88
+ def test_match_attributes_as_number
89
+ t = tag("<tag a=15 b=3.1415 />")
90
+ assert t.match(:attributes => {"a" => 15})
91
+ assert t.match(:attributes => {"b" => 3.1415})
92
+ assert t.match(:attributes => {"a" => 15, "b" => 3.1415})
93
+ end
94
+
95
+ def test_match_attributes_exist
96
+ t = tag("<tag a=15 b=3.1415 />")
97
+ assert t.match(:attributes => {"a" => true})
98
+ assert t.match(:attributes => {"b" => true})
99
+ assert t.match(:attributes => {"a" => true, "b" => true})
100
+ end
101
+
102
+ def test_match_attributes_not_exist
103
+ t = tag("<tag a=15 b=3.1415 />")
104
+ assert t.match(:attributes => {"c" => false})
105
+ assert t.match(:attributes => {"c" => nil})
106
+ assert t.match(:attributes => {"a" => true, "c" => false})
107
+ end
108
+
109
+ def test_match_parent_success
110
+ t = tag("<tag a=15 b='hello'>", tag("<foo k='value'>"))
111
+ assert t.match(:parent => {:tag => "foo", :attributes => {"k" => /v.l/, "j" => false}})
112
+ end
113
+
114
+ def test_match_parent_fail
115
+ t = tag("<tag a=15 b='hello'>", tag("<foo k='value'>"))
116
+ assert !t.match(:parent => {:tag => /kafka/})
117
+ end
118
+
119
+ def test_match_child_success
120
+ t = tag("<tag x:k='something'>")
121
+ tag("<child v=john a=kelly>", t)
122
+ tag("<sib m=vaughn v=james>", t)
123
+ assert t.match(:child => { :tag => "sib", :attributes => {"v" => /j/}})
124
+ assert t.match(:child => { :attributes => {"a" => "kelly"}})
125
+ end
126
+
127
+ def test_match_child_fail
128
+ t = tag("<tag x:k='something'>")
129
+ tag("<child v=john a=kelly>", t)
130
+ tag("<sib m=vaughn v=james>", t)
131
+ assert !t.match(:child => { :tag => "sib", :attributes => {"v" => /r/}})
132
+ assert !t.match(:child => { :attributes => {"v" => false}})
133
+ end
134
+
135
+ def test_match_ancestor_success
136
+ t = tag("<tag x:k='something'>", tag("<parent v=john a=kelly>", tag("<grandparent m=vaughn v=james>")))
137
+ assert t.match(:ancestor => {:tag => "parent", :attributes => {"a" => /ll/}})
138
+ assert t.match(:ancestor => {:attributes => {"m" => "vaughn"}})
139
+ end
140
+
141
+ def test_match_ancestor_fail
142
+ t = tag("<tag x:k='something'>", tag("<parent v=john a=kelly>", tag("<grandparent m=vaughn v=james>")))
143
+ assert !t.match(:ancestor => {:tag => /^parent/, :attributes => {"v" => /m/}})
144
+ assert !t.match(:ancestor => {:attributes => {"v" => false}})
145
+ end
146
+
147
+ def test_match_descendant_success
148
+ tag("<grandchild m=vaughn v=james>", tag("<child v=john a=kelly>", t = tag("<tag x:k='something'>")))
149
+ assert t.match(:descendant => {:tag => "child", :attributes => {"a" => /ll/}})
150
+ assert t.match(:descendant => {:attributes => {"m" => "vaughn"}})
151
+ end
152
+
153
+ def test_match_descendant_fail
154
+ tag("<grandchild m=vaughn v=james>", tag("<child v=john a=kelly>", t = tag("<tag x:k='something'>")))
155
+ assert !t.match(:descendant => {:tag => /^child/, :attributes => {"v" => /m/}})
156
+ assert !t.match(:descendant => {:attributes => {"v" => false}})
157
+ end
158
+
159
+ def test_match_child_count
160
+ t = tag("<tag x:k='something'>")
161
+ tag("hello", t)
162
+ tag("<child v=john a=kelly>", t)
163
+ tag("<sib m=vaughn v=james>", t)
164
+ assert t.match(:children => { :count => 2 })
165
+ assert t.match(:children => { :count => 2..4 })
166
+ assert t.match(:children => { :less_than => 4 })
167
+ assert t.match(:children => { :greater_than => 1 })
168
+ assert !t.match(:children => { :count => 3 })
169
+ end
170
+
171
+ def test_conditions_as_strings
172
+ t = tag("<tag x:k='something'>")
173
+ assert t.match("tag" => "tag")
174
+ assert t.match("attributes" => { "x:k" => "something" })
175
+ assert !t.match("tag" => "gat")
176
+ assert !t.match("attributes" => { "x:j" => "something" })
177
+ end
178
+
179
+ def test_attributes_as_symbols
180
+ t = tag("<child v=john a=kelly>")
181
+ assert t.match(:attributes => { :v => /oh/ })
182
+ assert t.match(:attributes => { :a => /ll/ })
183
+ end
184
+
185
+ def test_match_sibling
186
+ t = tag("<tag x:k='something'>")
187
+ tag("hello", t)
188
+ tag("<span a=b>", t)
189
+ tag("world", t)
190
+ m = tag("<span k=r>", t)
191
+ tag("<span m=l>", t)
192
+
193
+ assert m.match(:sibling => {:tag => "span", :attributes => {:a => true}})
194
+ assert m.match(:sibling => {:tag => "span", :attributes => {:m => true}})
195
+ assert !m.match(:sibling => {:tag => "span", :attributes => {:k => true}})
196
+ end
197
+
198
+ def test_match_sibling_before
199
+ t = tag("<tag x:k='something'>")
200
+ tag("hello", t)
201
+ tag("<span a=b>", t)
202
+ tag("world", t)
203
+ m = tag("<span k=r>", t)
204
+ tag("<span m=l>", t)
205
+
206
+ assert m.match(:before => {:tag => "span", :attributes => {:m => true}})
207
+ assert !m.match(:before => {:tag => "span", :attributes => {:a => true}})
208
+ assert !m.match(:before => {:tag => "span", :attributes => {:k => true}})
209
+ end
210
+
211
+ def test_match_sibling_after
212
+ t = tag("<tag x:k='something'>")
213
+ tag("hello", t)
214
+ tag("<span a=b>", t)
215
+ tag("world", t)
216
+ m = tag("<span k=r>", t)
217
+ tag("<span m=l>", t)
218
+
219
+ assert m.match(:after => {:tag => "span", :attributes => {:a => true}})
220
+ assert !m.match(:after => {:tag => "span", :attributes => {:m => true}})
221
+ assert !m.match(:after => {:tag => "span", :attributes => {:k => true}})
222
+ end
223
+
224
+ def test_to_s
225
+ t = tag("<b x='foo'>")
226
+ tag("hello", t)
227
+ tag("<hr />", t)
228
+ assert_equal %(<b x="foo">hello<hr /></b>), t.to_s
229
+ end
230
+
231
+ private
232
+
233
+ def tag(content, parent=nil)
234
+ node = HTML::Node.parse(parent,0,0,content)
235
+ parent.children << node if parent
236
+ node
237
+ end
238
+ end