loofah 2.2.3 → 2.21.1

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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +269 -31
  3. data/README.md +109 -124
  4. data/lib/loofah/concerns.rb +207 -0
  5. data/lib/loofah/elements.rb +85 -79
  6. data/lib/loofah/helpers.rb +37 -20
  7. data/lib/loofah/{html → html4}/document.rb +6 -7
  8. data/lib/loofah/html4/document_fragment.rb +15 -0
  9. data/lib/loofah/html5/document.rb +17 -0
  10. data/lib/loofah/html5/document_fragment.rb +15 -0
  11. data/lib/loofah/html5/libxml2_workarounds.rb +10 -8
  12. data/lib/loofah/html5/safelist.rb +1055 -0
  13. data/lib/loofah/html5/scrub.rb +153 -58
  14. data/lib/loofah/metahelpers.rb +11 -6
  15. data/lib/loofah/scrubber.rb +22 -15
  16. data/lib/loofah/scrubbers.rb +66 -55
  17. data/lib/loofah/version.rb +6 -0
  18. data/lib/loofah/xml/document.rb +2 -0
  19. data/lib/loofah/xml/document_fragment.rb +4 -7
  20. data/lib/loofah.rb +131 -38
  21. metadata +28 -216
  22. data/.gemtest +0 -0
  23. data/Gemfile +0 -22
  24. data/Manifest.txt +0 -40
  25. data/Rakefile +0 -79
  26. data/benchmark/benchmark.rb +0 -149
  27. data/benchmark/fragment.html +0 -96
  28. data/benchmark/helper.rb +0 -73
  29. data/benchmark/www.slashdot.com.html +0 -2560
  30. data/lib/loofah/html/document_fragment.rb +0 -40
  31. data/lib/loofah/html5/whitelist.rb +0 -186
  32. data/lib/loofah/instance_methods.rb +0 -127
  33. data/test/assets/msword.html +0 -63
  34. data/test/assets/testdata_sanitizer_tests1.dat +0 -502
  35. data/test/helper.rb +0 -18
  36. data/test/html5/test_sanitizer.rb +0 -382
  37. data/test/integration/test_ad_hoc.rb +0 -204
  38. data/test/integration/test_helpers.rb +0 -43
  39. data/test/integration/test_html.rb +0 -72
  40. data/test/integration/test_scrubbers.rb +0 -400
  41. data/test/integration/test_xml.rb +0 -55
  42. data/test/unit/test_api.rb +0 -142
  43. data/test/unit/test_encoding.rb +0 -20
  44. data/test/unit/test_helpers.rb +0 -62
  45. data/test/unit/test_scrubber.rb +0 -229
  46. data/test/unit/test_scrubbers.rb +0 -14
@@ -1,502 +0,0 @@
1
- [
2
- {
3
- "name": "IE_Comments",
4
- "input": "<!--[if gte IE 4]><script>alert('XSS');</script><![endif]-->",
5
- "output": "&lt;!--[if gte IE 4]&gt;&lt;script&gt;alert('XSS');&lt;/script&gt;&lt;![endif]--&gt;"
6
- },
7
-
8
- {
9
- "name": "IE_Comments_2",
10
- "input": "<![if !IE 5]><script>alert('XSS');</script><![endif]>",
11
- "output": "&lt;script&gt;alert('XSS');&lt;/script&gt;",
12
- "rexml": "Ill-formed XHTML!"
13
- },
14
-
15
- {
16
- "name": "allow_colons_in_path_component",
17
- "input": "<a href=\"./this:that\">foo</a>",
18
- "output": "<a href='./this:that'>foo</a>"
19
- },
20
-
21
- {
22
- "name": "background_attribute",
23
- "input": "<div background=\"javascript:alert('XSS')\"></div>",
24
- "output": "<div/>",
25
- "xhtml": "<div></div>",
26
- "rexml": "<div></div>"
27
- },
28
-
29
- {
30
- "name": "bgsound",
31
- "input": "<bgsound src=\"javascript:alert('XSS');\" />",
32
- "output": "&lt;bgsound src=\"javascript:alert('XSS');\"/&gt;",
33
- "rexml": "&lt;bgsound src=\"javascript:alert('XSS');\"&gt;&lt;/bgsound&gt;"
34
- },
35
-
36
- {
37
- "name": "div_background_image_unicode_encoded",
38
- "input": "<div style=\"background-image:\u00a5\u00a2\u006C\u0028'\u006a\u0061\u00a6\u0061\u00a3\u0063\u00a2\u0069\u00a0\u00a4\u003a\u0061\u006c\u0065\u00a2\u00a4\u0028.1027\u0058.1053\u0053\u0027\u0029'\u0029\">foo</div>",
39
- "output": "<div>foo</div>"
40
- },
41
-
42
- {
43
- "name": "div_expression",
44
- "input": "<div style=\"width: expression(alert('XSS'));\">foo</div>",
45
- "output": "<div>foo</div>"
46
- },
47
-
48
- {
49
- "name": "double_open_angle_brackets",
50
- "input": "<img src=http://ha.ckers.org/scriptlet.html <",
51
- "output": "<img src='http://ha.ckers.org/scriptlet.html'>",
52
- "rexml": "Ill-formed XHTML!"
53
- },
54
-
55
- {
56
- "name": "double_open_angle_brackets_2",
57
- "input": "<script src=http://ha.ckers.org/scriptlet.html <",
58
- "output": "&lt;script src=\"http://ha.ckers.org/scriptlet.html\"&gt;&lt;/script&gt;",
59
- "rexml": "Ill-formed XHTML!"
60
- },
61
-
62
- {
63
- "name": "grave_accents",
64
- "input": "<img src=`javascript:alert('XSS')` />",
65
- "output": "<img>",
66
- "rexml": "Ill-formed XHTML!"
67
- },
68
-
69
- {
70
- "name": "img_dynsrc_lowsrc",
71
- "input": "<img dynsrc=\"javascript:alert('XSS')\" />",
72
- "output": "<img>",
73
- "rexml": "<img />"
74
- },
75
-
76
- {
77
- "name": "img_vbscript",
78
- "input": "<img src='vbscript:msgbox(\"XSS\")' />",
79
- "output": "<img>",
80
- "rexml": "<img />"
81
- },
82
-
83
- {
84
- "name": "input_image",
85
- "input": "<input type=\"image\" src=\"javascript:alert('XSS');\" />",
86
- "output": "<input type='image'>",
87
- "rexml": "<input type='image' />"
88
- },
89
-
90
- {
91
- "name": "link_stylesheets",
92
- "input": "<link rel=\"stylesheet\" href=\"javascript:alert('XSS');\" />",
93
- "output": "&lt;link rel=\"stylesheet\" href=\"javascript:alert('XSS');\"&gt;",
94
- "rexml": "&lt;link href=\"javascript:alert('XSS');\" rel=\"stylesheet\"/&gt;"
95
- },
96
-
97
- {
98
- "name": "link_stylesheets_2",
99
- "input": "<link rel=\"stylesheet\" href=\"http://ha.ckers.org/xss.css\" />",
100
- "output": "&lt;link rel=\"stylesheet\" href=\"http://ha.ckers.org/xss.css\"&gt;",
101
- "rexml": "&lt;link href=\"http://ha.ckers.org/xss.css\" rel=\"stylesheet\"/&gt;"
102
- },
103
-
104
- {
105
- "name": "list_style_image",
106
- "input": "<li style=\"list-style-image: url(javascript:alert('XSS'))\">foo</li>",
107
- "output": "<li>foo</li>"
108
- },
109
-
110
- {
111
- "name": "no_closing_script_tags",
112
- "input": "<script src=http://ha.ckers.org/xss.js?<b>",
113
- "output": "&lt;script src=\"http://ha.ckers.org/xss.js?&amp;lt;b\"&gt;&lt;/script&gt;",
114
- "rexml": "Ill-formed XHTML!"
115
- },
116
-
117
- {
118
- "name": "non_alpha_non_digit",
119
- "input": "<script/XSS src=\"http://ha.ckers.org/xss.js\"></script>",
120
- "output": "&lt;script src=\"http://ha.ckers.org/xss.js\"&gt;&lt;/script&gt;",
121
- "rexml": "Ill-formed XHTML!"
122
- },
123
-
124
- {
125
- "name": "non_alpha_non_digit_2",
126
- "input": "<a onclick!\\#$%&()*~+-_.,:;?@[/|\\]^`=alert(\"XSS\")>foo</a>",
127
- "output": "<a>foo</a>",
128
- "rexml": "Ill-formed XHTML!"
129
- },
130
-
131
- {
132
- "name": "non_alpha_non_digit_3",
133
- "input": "<img/src=\"http://ha.ckers.org/xss.js\"/>",
134
- "output": "<img>",
135
- "rexml": "Ill-formed XHTML!"
136
- },
137
-
138
- {
139
- "name": "non_alpha_non_digit_II",
140
- "input": "<a href!\\#$%&()*~+-_.,:;?@[/|]^`=alert('XSS')>foo</a>",
141
- "output": "<a>foo</a>",
142
- "rexml": "Ill-formed XHTML!"
143
- },
144
-
145
- {
146
- "name": "non_alpha_non_digit_III",
147
- "input": "<a/href=\"javascript:alert('XSS');\">foo</a>",
148
- "output": "<a>foo</a>",
149
- "rexml": "Ill-formed XHTML!"
150
- },
151
-
152
- {
153
- "name": "platypus",
154
- "input": "<a href=\"http://www.ragingplatypus.com/\" style=\"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;\">never trust your upstream platypus</a>",
155
- "output": "<a href='http://www.ragingplatypus.com/' style='display:block;width:100%;height:100%;background-color:black;background-x:center;background-y:center;'>never trust your upstream platypus</a>"
156
- },
157
-
158
- {
159
- "name": "protocol_resolution_in_script_tag",
160
- "input": "<script src=//ha.ckers.org/.j></script>",
161
- "output": "&lt;script src=\"//ha.ckers.org/.j\"&gt;&lt;/script&gt;",
162
- "rexml": "Ill-formed XHTML!"
163
- },
164
-
165
- {
166
- "name": "should_allow_anchors",
167
- "input": "<a href='foo' onclick='bar'><script>baz</script></a>",
168
- "output": "<a href='foo'>&lt;script&gt;baz&lt;/script&gt;</a>"
169
- },
170
-
171
- {
172
- "name": "should_allow_image_alt_attribute",
173
- "input": "<img alt='foo' onclick='bar' />",
174
- "output": "<img alt='foo'>",
175
- "rexml": "<img alt='foo' />"
176
- },
177
-
178
- {
179
- "name": "should_allow_image_height_attribute",
180
- "input": "<img height='foo' onclick='bar' />",
181
- "output": "<img height='foo'>",
182
- "rexml": "<img height='foo' />"
183
- },
184
-
185
- {
186
- "name": "should_allow_image_src_attribute",
187
- "input": "<img src='foo' onclick='bar' />",
188
- "output": "<img src='foo'>",
189
- "rexml": "<img src='foo' />"
190
- },
191
-
192
- {
193
- "name": "should_allow_image_width_attribute",
194
- "input": "<img width='foo' onclick='bar' />",
195
- "output": "<img width='foo'>",
196
- "rexml": "<img width='foo' />"
197
- },
198
-
199
- {
200
- "name": "should_handle_blank_text",
201
- "input": "",
202
- "output": ""
203
- },
204
-
205
- {
206
- "name": "should_handle_malformed_image_tags",
207
- "input": "<img \"\"\"><script>alert(\"XSS\")</script>\">",
208
- "output": "<img>&lt;script&gt;alert(\"XSS\")&lt;/script&gt;\"&gt;",
209
- "rexml": "Ill-formed XHTML!"
210
- },
211
-
212
- {
213
- "name": "should_handle_non_html",
214
- "input": "abc",
215
- "output": "abc"
216
- },
217
-
218
- {
219
- "name": "should_not_fall_for_ridiculous_hack",
220
- "input": "<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 />",
221
- "output": "<img>",
222
- "rexml": "<img />"
223
- },
224
-
225
- {
226
- "name": "should_not_fall_for_xss_image_hack_0",
227
- "input": "<img src=\"javascript:alert('XSS');\" />",
228
- "output": "<img>",
229
- "rexml": "<img />"
230
- },
231
-
232
- {
233
- "name": "should_not_fall_for_xss_image_hack_1",
234
- "input": "<img src=javascript:alert('XSS') />",
235
- "output": "<img>",
236
- "rexml": "Ill-formed XHTML!"
237
- },
238
-
239
- {
240
- "name": "should_not_fall_for_xss_image_hack_10",
241
- "input": "<img src=\"jav&#x0A;ascript:alert('XSS');\" />",
242
- "output": "<img>",
243
- "rexml": "<img />"
244
- },
245
-
246
- {
247
- "name": "should_not_fall_for_xss_image_hack_11",
248
- "input": "<img src=\"jav&#x0D;ascript:alert('XSS');\" />",
249
- "output": "<img>",
250
- "rexml": "<img />"
251
- },
252
-
253
- {
254
- "name": "should_not_fall_for_xss_image_hack_12",
255
- "input": "<img src=\" &#14; javascript:alert('XSS');\" />",
256
- "output": "<img>",
257
- "rexml": "<img />"
258
- },
259
-
260
- {
261
- "name": "should_not_fall_for_xss_image_hack_13",
262
- "input": "<img src=\"&#x20;javascript:alert('XSS');\" />",
263
- "output": "<img>",
264
- "rexml": "<img />"
265
- },
266
-
267
- {
268
- "name": "should_not_fall_for_xss_image_hack_14",
269
- "input": "<img src=\"&#xA0;javascript:alert('XSS');\" />",
270
- "output": "<img>",
271
- "rexml": "<img />"
272
- },
273
-
274
- {
275
- "name": "should_not_fall_for_xss_image_hack_2",
276
- "input": "<img src=\"JaVaScRiPt:alert('XSS')\" />",
277
- "output": "<img>",
278
- "rexml": "<img />"
279
- },
280
-
281
- {
282
- "name": "should_not_fall_for_xss_image_hack_3",
283
- "input": "<img src='javascript:alert(&quot;XSS&quot;)' />",
284
- "output": "<img>",
285
- "rexml": "<img />"
286
- },
287
-
288
- {
289
- "name": "should_not_fall_for_xss_image_hack_4",
290
- "input": "<img src='javascript:alert(String.fromCharCode(88,83,83))' />",
291
- "output": "<img>",
292
- "rexml": "<img />"
293
- },
294
-
295
- {
296
- "name": "should_not_fall_for_xss_image_hack_5",
297
- "input": "<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;' />",
298
- "output": "<img>",
299
- "rexml": "<img />"
300
- },
301
-
302
- {
303
- "name": "should_not_fall_for_xss_image_hack_6",
304
- "input": "<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' />",
305
- "output": "<img>",
306
- "rexml": "<img />"
307
- },
308
-
309
- {
310
- "name": "should_not_fall_for_xss_image_hack_7",
311
- "input": "<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' />",
312
- "output": "<img>",
313
- "rexml": "<img />"
314
- },
315
-
316
- {
317
- "name": "should_not_fall_for_xss_image_hack_8",
318
- "input": "<img src=\"jav\tascript:alert('XSS');\" />",
319
- "output": "<img>",
320
- "rexml": "<img />"
321
- },
322
-
323
- {
324
- "name": "should_not_fall_for_xss_image_hack_9",
325
- "input": "<img src=\"jav&#x09;ascript:alert('XSS');\" />",
326
- "output": "<img>",
327
- "rexml": "<img />"
328
- },
329
-
330
- {
331
- "name": "should_sanitize_half_open_scripts",
332
- "input": "<img src=\"javascript:alert('XSS')\"",
333
- "output": "<img>",
334
- "rexml": "Ill-formed XHTML!"
335
- },
336
-
337
- {
338
- "name": "should_sanitize_invalid_script_tag",
339
- "input": "<script/XSS SRC=\"http://ha.ckers.org/xss.js\"></script>",
340
- "output": "&lt;script src=\"http://ha.ckers.org/xss.js\"&gt;&lt;/script&gt;",
341
- "rexml": "Ill-formed XHTML!"
342
- },
343
-
344
- {
345
- "name": "should_sanitize_script_tag_with_multiple_open_brackets",
346
- "input": "<<script>alert(\"XSS\");//<</script>",
347
- "output": "alert(\"XSS\");//",
348
- "xhtml": "&lt;&lt;script&gt;alert('XSS');//&lt;&lt;/script&gt;",
349
- "rexml": "Ill-formed XHTML!"
350
- },
351
-
352
- {
353
- "name": "should_sanitize_script_tag_with_multiple_open_brackets_2",
354
- "input": "<iframe src=http://ha.ckers.org/scriptlet.html\n<",
355
- "output": "&lt;iframe src=\"http://ha.ckers.org/scriptlet.html\"&gt;&lt;/iframe&gt;",
356
- "rexml": "Ill-formed XHTML!"
357
- },
358
-
359
- {
360
- "name": "should_sanitize_tag_broken_up_by_null",
361
- "input": "<scr\u0000ipt>alert(\"XSS\")</scr\u0000ipt>",
362
- "output": "&lt;scr&gt;&lt;/scr&gt;",
363
- "rexml": "Ill-formed XHTML!"
364
- },
365
-
366
- {
367
- "name": "should_sanitize_unclosed_script",
368
- "input": "<script src=http://ha.ckers.org/xss.js?<b>",
369
- "output": "&lt;script src=\"http://ha.ckers.org/xss.js?&amp;lt;b\"&gt;&lt;/script&gt;",
370
- "rexml": "Ill-formed XHTML!"
371
- },
372
-
373
- {
374
- "name": "should_strip_href_attribute_in_a_with_bad_protocols",
375
- "input": "<a href=\"javascript:XSS\" title=\"1\">boo</a>",
376
- "output": "<a title='1'>boo</a>"
377
- },
378
-
379
- {
380
- "name": "should_strip_href_attribute_in_a_with_bad_protocols_and_whitespace",
381
- "input": "<a href=\" javascript:XSS\" title=\"1\">boo</a>",
382
- "output": "<a title='1'>boo</a>"
383
- },
384
-
385
- {
386
- "name": "should_strip_src_attribute_in_img_with_bad_protocols",
387
- "input": "<img src=\"javascript:XSS\" title=\"1\">boo</img>",
388
- "output": "<img title='1'>boo",
389
- "rexml": "<img title='1' />"
390
- },
391
-
392
- {
393
- "name": "should_strip_src_attribute_in_img_with_bad_protocols_and_whitespace",
394
- "input": "<img src=\" javascript:XSS\" title=\"1\">boo</img>",
395
- "output": "<img title='1'>boo",
396
- "rexml": "<img title='1' />"
397
- },
398
-
399
- {
400
- "name": "xml_base",
401
- "input": "<div xml:base=\"javascript:alert('XSS');//\">foo</div>",
402
- "output": "<div>foo</div>"
403
- },
404
-
405
- {
406
- "name": "xul",
407
- "input": "<p style=\"-moz-binding:url('http://ha.ckers.org/xssmoz.xml#xss')\">fubar</p>",
408
- "output": "<p>fubar</p>"
409
- },
410
-
411
- {
412
- "name": "quotes_in_attributes",
413
- "input": "<img src='foo' title='\"foo\" bar' />",
414
- "rexml": "<img src='foo' title='\"foo\" bar' />",
415
- "output": "<img src='foo' title='\"foo\" bar'>"
416
- },
417
-
418
- {
419
- "name": "uri_refs_in_svg_attributes",
420
- "input": "<rect fill='url(#foo)' />",
421
- "rexml": "<rect fill='url(#foo)'></rect>",
422
- "xhtml": "<rect fill='url(#foo)'></rect>",
423
- "output": "<rect fill='url(#foo)'/>"
424
- },
425
-
426
- {
427
- "name": "absolute_uri_refs_in_svg_attributes",
428
- "input": "<rect fill='url(http://bad.com/) #fff' />",
429
- "rexml": "<rect fill=' #fff'></rect>",
430
- "xhtml": "<rect fill=' #fff'></rect>",
431
- "output": "<rect fill=' #fff'/>"
432
- },
433
-
434
- {
435
- "name": "uri_ref_with_space_in svg_attribute",
436
- "input": "<rect fill='url(\n#foo)' />",
437
- "rexml": "<rect fill='url(\n#foo)'></rect>",
438
- "xhtml": "<rect fill='url(\n#foo)'></rect>",
439
- "output": "<rect fill='url(\n#foo)'/>"
440
- },
441
-
442
- {
443
- "name": "absolute_uri_ref_with_space_in svg_attribute",
444
- "input": "<rect fill=\"url(\nhttp://bad.com/)\" />",
445
- "rexml": "<rect></rect>",
446
- "xhtml": "<rect></rect>",
447
- "output": "<rect/>"
448
- },
449
-
450
- {
451
- "name": "allow_html5_image_tag",
452
- "input": "<image src='foo' />",
453
- "rexml": "&lt;image src=\"foo\"&gt;&lt;/image&gt;",
454
- "output": "&lt;image src=\"foo\"/&gt;"
455
- },
456
-
457
- {
458
- "name": "style_attr_end_with_nothing",
459
- "input": "<div style=\"color: blue\" />",
460
- "output": "<div style='color: blue;'/>",
461
- "xhtml": "<div style='color: blue;'></div>",
462
- "rexml": "<div style='color: blue;'></div>"
463
- },
464
-
465
- {
466
- "name": "style_attr_end_with_space",
467
- "input": "<div style=\"color: blue \" />",
468
- "output": "<div style='color: blue ;'/>",
469
- "xhtml": "<div style='color: blue ;'></div>",
470
- "rexml": "<div style='color: blue ;'></div>"
471
- },
472
-
473
- {
474
- "name": "style_attr_end_with_semicolon",
475
- "input": "<div style=\"color: blue;\" />",
476
- "output": "<div style='color: blue;'/>",
477
- "xhtml": "<div style='color: blue;'></div>",
478
- "rexml": "<div style='color: blue;'></div>"
479
- },
480
-
481
- {
482
- "name": "style_attr_end_with_semicolon_space",
483
- "input": "<div style=\"color: blue; \" />",
484
- "output": "<div style='color: blue;'/>",
485
- "xhtml": "<div style='color: blue;'></div>",
486
- "rexml": "<div style='color: blue;'></div>"
487
- },
488
-
489
- {
490
- "name": "attributes_with_embedded_quotes",
491
- "input": "<img src=doesntexist.jpg\"'onerror=\"alert(1) />",
492
- "output": "<img src='doesntexist.jpg%22'onerror=%22alert(1)'>",
493
- "rexml": "Ill-formed XHTML!"
494
- },
495
-
496
- {
497
- "name": "attributes_with_embedded_quotes_II",
498
- "input": "<img src=notthere.jpg\"\"onerror=\"alert(2) />",
499
- "output": "<img src='notthere.jpg%22%22onerror=%22alert(2)'>",
500
- "rexml": "Ill-formed XHTML!"
501
- }
502
- ]
data/test/helper.rb DELETED
@@ -1,18 +0,0 @@
1
- require 'rubygems'
2
- require 'minitest/unit'
3
- require 'minitest/spec'
4
- require 'minitest/autorun'
5
- require 'rr'
6
-
7
- require File.expand_path(File.join(File.dirname(__FILE__), "..", "lib", "loofah"))
8
-
9
- # require the ActionView helpers here, since they are no longer required automatically
10
- require File.expand_path(File.join(File.dirname(__FILE__), "..", "lib", "loofah", "helpers"))
11
-
12
- puts "=> testing with Nokogiri #{Nokogiri::VERSION_INFO.inspect}"
13
-
14
- class Loofah::TestCase < MiniTest::Spec
15
- class << self
16
- alias_method :context, :describe
17
- end
18
- end