greenmat 3.2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/COPYING +14 -0
  3. data/Gemfile +9 -0
  4. data/README.md +36 -0
  5. data/Rakefile +62 -0
  6. data/bin/greenmat +7 -0
  7. data/ext/greenmat/autolink.c +296 -0
  8. data/ext/greenmat/autolink.h +49 -0
  9. data/ext/greenmat/buffer.c +196 -0
  10. data/ext/greenmat/buffer.h +83 -0
  11. data/ext/greenmat/extconf.rb +6 -0
  12. data/ext/greenmat/gm_markdown.c +161 -0
  13. data/ext/greenmat/gm_render.c +534 -0
  14. data/ext/greenmat/greenmat.h +30 -0
  15. data/ext/greenmat/houdini.h +29 -0
  16. data/ext/greenmat/houdini_href_e.c +108 -0
  17. data/ext/greenmat/houdini_html_e.c +83 -0
  18. data/ext/greenmat/html.c +826 -0
  19. data/ext/greenmat/html.h +84 -0
  20. data/ext/greenmat/html_blocks.h +229 -0
  21. data/ext/greenmat/html_smartypants.c +445 -0
  22. data/ext/greenmat/markdown.c +2912 -0
  23. data/ext/greenmat/markdown.h +138 -0
  24. data/ext/greenmat/stack.c +62 -0
  25. data/ext/greenmat/stack.h +26 -0
  26. data/greenmat.gemspec +72 -0
  27. data/lib/greenmat.rb +92 -0
  28. data/lib/greenmat/compat.rb +73 -0
  29. data/lib/greenmat/render_man.rb +65 -0
  30. data/lib/greenmat/render_strip.rb +48 -0
  31. data/test/benchmark.rb +24 -0
  32. data/test/custom_render_test.rb +28 -0
  33. data/test/greenmat_compat_test.rb +38 -0
  34. data/test/html5_test.rb +69 -0
  35. data/test/html_render_test.rb +241 -0
  36. data/test/html_toc_render_test.rb +76 -0
  37. data/test/markdown_test.rb +337 -0
  38. data/test/pathological_inputs_test.rb +34 -0
  39. data/test/safe_render_test.rb +36 -0
  40. data/test/smarty_html_test.rb +45 -0
  41. data/test/smarty_pants_test.rb +48 -0
  42. data/test/stripdown_render_test.rb +40 -0
  43. data/test/test_helper.rb +33 -0
  44. metadata +158 -0
@@ -0,0 +1,76 @@
1
+ # coding: UTF-8
2
+ require 'test_helper'
3
+
4
+ class HTMLTOCRenderTest < Greenmat::TestCase
5
+ def setup
6
+ @renderer = Greenmat::Render::HTML_TOC
7
+ @markdown = "# A title \n## A __nice__ subtitle\n## Another one \n### A sub-sub-title"
8
+ end
9
+
10
+ def test_simple_toc_render
11
+ output = render(@markdown).strip
12
+
13
+ assert output.start_with?("<ul>")
14
+ assert output.end_with?("</ul>")
15
+
16
+ assert_equal 3, output.scan("<ul>").length
17
+ assert_equal 4, output.scan("<li>").length
18
+ end
19
+
20
+ def test_granular_toc_render
21
+ output = render(@markdown, with: { nesting_level: 2 }).strip
22
+
23
+ assert output.start_with?("<ul>")
24
+ assert output.end_with?("</ul>")
25
+
26
+ assert_equal 3, output.scan("<li>").length
27
+ assert !output.include?("A sub-sub title")
28
+ end
29
+
30
+ def test_toc_heading_id
31
+ output = render(@markdown)
32
+
33
+ assert_match /a-title/, output
34
+ assert_match /a-nice-subtitle/, output
35
+ assert_match /another-one/, output
36
+ assert_match /a-sub-sub-title/, output
37
+ end
38
+
39
+ def test_toc_heading_with_hyphen_and_equal
40
+ output = render("# Hello World\n\n-\n\n=")
41
+
42
+ assert_equal 1, output.scan("<li>").length
43
+ assert !output.include?('<a href=\"#\"></a>')
44
+ end
45
+
46
+ def test_anchor_generation_with_edge_cases
47
+ # Imported from ActiveSupport::Inflector#parameterize's tests
48
+ titles = {
49
+ "Donald E. Knuth" => "donald-e-knuth",
50
+ "Random text with *(bad)* characters" => "random-text-with-bad-characters",
51
+ "Trailing bad characters!@#" => "trailing-bad-characters",
52
+ "!@#Leading bad characters" => "leading-bad-characters",
53
+ "Squeeze separators" => "squeeze-separators",
54
+ "Test with + sign" => "test-with-sign",
55
+ "Test with a Namespaced::Class" => "test-with-a-namespaced-class"
56
+ }
57
+
58
+ titles.each do |title, anchor|
59
+ assert_match anchor, render("# #{title}")
60
+ end
61
+ end
62
+
63
+ def test_inline_markup_is_not_escaped
64
+ output = render(@markdown)
65
+
66
+ assert_match "A <strong>nice</strong> subtitle", output
67
+ assert_no_match %r{&lt;}, output
68
+ end
69
+
70
+ def test_inline_markup_escaping
71
+ output = render(@markdown, with: [:escape_html])
72
+
73
+ assert_match "&lt;strong&gt;", output
74
+ assert_no_match %r{<strong>}, output
75
+ end
76
+ end
@@ -0,0 +1,337 @@
1
+ # coding: UTF-8
2
+ require 'test_helper'
3
+
4
+ class MarkdownTest < Greenmat::TestCase
5
+
6
+ def setup
7
+ @markdown = Greenmat::Markdown.new(Greenmat::Render::HTML)
8
+ end
9
+
10
+ def render_with(flags, text)
11
+ Greenmat::Markdown.new(Greenmat::Render::HTML, flags).render(text)
12
+ end
13
+
14
+ def test_that_simple_one_liner_goes_to_html
15
+ assert_respond_to @markdown, :render
16
+ assert_equal "<p>Hello World.</p>\n", @markdown.render("Hello World.")
17
+ end
18
+
19
+ def test_that_inline_markdown_goes_to_html
20
+ markdown = @markdown.render('_Hello World_!')
21
+ assert_equal "<p><em>Hello World</em>!</p>\n", markdown
22
+ end
23
+
24
+ def test_that_inline_markdown_starts_and_ends_correctly
25
+ markdown = render_with({:no_intra_emphasis => true}, '_start _ foo_bar bar_baz _ end_ *italic* **bold** <a>_blah_</a>')
26
+
27
+ assert_equal "<p><em>start _ foo_bar bar_baz _ end</em> <em>italic</em> <strong>bold</strong> <a><em>blah</em></a></p>\n", markdown
28
+
29
+ markdown = @markdown.render("Run 'rake radiant:extensions:rbac_base:migrate'")
30
+ assert_equal "<p>Run &#39;rake radiant:extensions:rbac_base:migrate&#39;</p>\n", markdown
31
+ end
32
+
33
+ def test_that_urls_are_not_doubly_escaped
34
+ markdown = @markdown.render('[Page 2](/search?query=Markdown+Test&page=2)')
35
+ assert_equal "<p><a href=\"/search?query=Markdown+Test&amp;page=2\">Page 2</a></p>\n", markdown
36
+ end
37
+
38
+ def test_simple_inline_html
39
+ #markdown = Markdown.new("before\n\n<div>\n foo\n</div>\nafter")
40
+ markdown = @markdown.render("before\n\n<div>\n foo\n</div>\n\nafter")
41
+ assert_equal "<p>before</p>\n\n<div>\n foo\n</div>\n\n<p>after</p>\n", markdown
42
+ end
43
+
44
+ def test_that_html_blocks_do_not_require_their_own_end_tag_line
45
+ markdown = @markdown.render("Para 1\n\n<div><pre>HTML block\n</pre></div>\n\nPara 2 [Link](#anchor)")
46
+ assert_equal "<p>Para 1</p>\n\n<div><pre>HTML block\n</pre></div>\n\n<p>Para 2 <a href=\"#anchor\">Link</a></p>\n",
47
+ markdown
48
+ end
49
+
50
+ # This isn't in the spec but is Markdown.pl behavior.
51
+ def test_block_quotes_preceded_by_spaces
52
+ markdown = @markdown.render(
53
+ "A wise man once said:\n\n" +
54
+ " > Isn't it wonderful just to be alive.\n"
55
+ )
56
+ assert_equal "<p>A wise man once said:</p>\n\n" +
57
+ "<blockquote>\n<p>Isn&#39;t it wonderful just to be alive.</p>\n</blockquote>\n",
58
+ markdown
59
+ end
60
+
61
+ def test_para_before_block_html_should_not_wrap_in_p_tag
62
+ markdown = render_with({:lax_spacing => true},
63
+ "Things to watch out for\n" +
64
+ "<ul>\n<li>Blah</li>\n</ul>\n")
65
+
66
+ assert_equal "<p>Things to watch out for</p>\n\n" +
67
+ "<ul>\n<li>Blah</li>\n</ul>\n", markdown
68
+ end
69
+
70
+ # https://github.com/vmg/greenmat/issues/111
71
+ def test_p_with_less_than_4space_indent_should_not_be_part_of_last_list_item
72
+ text = <<MARKDOWN
73
+ * a
74
+ * b
75
+ * c
76
+
77
+ This paragraph is not part of the list.
78
+ MARKDOWN
79
+ expected = <<HTML
80
+ <ul>
81
+ <li>a</li>
82
+ <li>b</li>
83
+ <li>c</li>
84
+ </ul>
85
+
86
+ <p>This paragraph is not part of the list.</p>
87
+ HTML
88
+ assert_equal expected, @markdown.render(text)
89
+ end
90
+
91
+ # http://github.com/rtomayko/rdiscount/issues/#issue/13
92
+ def test_headings_with_trailing_space
93
+ text = "The Ant-Sugar Tales \n" +
94
+ "=================== \n\n" +
95
+ "By Candice Yellowflower \n"
96
+ assert_equal "<h1>The Ant-Sugar Tales </h1>\n\n<p>By Candice Yellowflower </p>\n", @markdown.render(text)
97
+ end
98
+
99
+ def test_that_intra_emphasis_works
100
+ rd = render_with({}, "foo_bar_baz")
101
+ assert_equal "<p>foo<em>bar</em>baz</p>\n", rd
102
+
103
+ rd = render_with({:no_intra_emphasis => true},"foo_bar_baz")
104
+ assert_equal "<p>foo_bar_baz</p>\n", rd
105
+ end
106
+
107
+ def test_that_autolink_flag_works
108
+ rd = render_with({:autolink => true}, "http://github.com/rtomayko/rdiscount")
109
+ assert_equal "<p><a href=\"http://github.com/rtomayko/rdiscount\">http://github.com/rtomayko/rdiscount</a></p>\n", rd
110
+ end
111
+
112
+ def test_that_tags_can_have_dashes_and_underscores
113
+ rd = @markdown.render("foo <asdf-qwerty>bar</asdf-qwerty> and <a_b>baz</a_b>")
114
+ assert_equal "<p>foo <asdf-qwerty>bar</asdf-qwerty> and <a_b>baz</a_b></p>\n", rd
115
+ end
116
+
117
+ def test_link_syntax_is_not_processed_within_code_blocks
118
+ markdown = @markdown.render(" This is a code block\n This is a link [[1]] inside\n")
119
+ assert_equal "<pre><code>This is a code block\nThis is a link [[1]] inside\n</code></pre>\n",
120
+ markdown
121
+ end
122
+
123
+ def test_whitespace_after_urls
124
+ rd = render_with({:autolink => true}, "Japan: http://www.abc.net.au/news/events/japan-quake-2011/beforeafter.htm (yes, japan)")
125
+ exp = %{<p>Japan: <a href="http://www.abc.net.au/news/events/japan-quake-2011/beforeafter.htm">http://www.abc.net.au/news/events/japan-quake-2011/beforeafter.htm</a> (yes, japan)</p>\n}
126
+ assert_equal exp, rd
127
+ end
128
+
129
+ def test_memory_leak_when_parsing_char_links
130
+ @markdown.render(<<-leaks)
131
+ 2. Identify the wild-type cluster and determine all clusters
132
+ containing or contained by it:
133
+
134
+ wildtype <- wildtype.cluster(h)
135
+ wildtype.mask <- logical(nclust)
136
+ wildtype.mask[c(contains(h, wildtype),
137
+ wildtype,
138
+ contained.by(h, wildtype))] <- TRUE
139
+
140
+ This could be more elegant.
141
+ leaks
142
+ end
143
+
144
+ def test_infinite_loop_in_header
145
+ assert_equal "<h1>Body</h1>\n", @markdown.render(<<-header)
146
+ ######
147
+ #Body#
148
+ ######
149
+ header
150
+ end
151
+
152
+ def test_a_hyphen_and_a_equal_should_not_be_converted_to_heading
153
+ assert_equal "<p>-</p>\n", @markdown.render("-")
154
+ assert_equal "<p>=</p>\n", @markdown.render("=")
155
+ end
156
+
157
+ def test_that_tables_flag_works
158
+ text = <<EOS
159
+ aaa | bbbb
160
+ -----|------
161
+ hello|sailor
162
+ EOS
163
+
164
+ assert render_with({}, text) !~ /<table/
165
+
166
+ assert render_with({:tables => true}, text) =~ /<table/
167
+ end
168
+
169
+ def test_that_tables_work_with_org_table_syntax
170
+ text = <<EOS
171
+ | aaa | bbbb |
172
+ |-----+------|
173
+ |hello|sailor|
174
+ EOS
175
+
176
+ assert render_with({}, text) !~ /<table/
177
+
178
+ assert render_with({:tables => true}, text) =~ /<table/
179
+ end
180
+
181
+ def test_strikethrough_flag_works
182
+ text = "this is ~some~ striked ~~text~~"
183
+
184
+ assert render_with({}, text) !~ /<del/
185
+
186
+ assert render_with({:strikethrough => true}, text) =~ /<del/
187
+ end
188
+
189
+ def test_underline_flag_works
190
+ text = "this is *some* text that is _underlined_. ___boom___"
191
+
192
+ refute render_with({}, text).include? '<u>underlined</u>'
193
+
194
+ output = render_with({:underline => true}, text)
195
+ assert output.include? '<u>underlined</u>'
196
+ assert output.include? '<em>some</em>'
197
+ end
198
+
199
+ def test_highlight_flag_works
200
+ text = "this is ==highlighted=="
201
+
202
+ refute render_with({}, text).include? '<mark>highlighted</mark>'
203
+
204
+ output = render_with({:highlight => true}, text)
205
+ assert output.include? '<mark>highlighted</mark>'
206
+ end
207
+
208
+ def test_quote_flag_works
209
+ text = 'this is "quote"'
210
+
211
+ refute render_with({}, text).include? '<q>quote</q>'
212
+
213
+ output = render_with({:quote => true}, text)
214
+ assert output.include? '<q>quote</q>'
215
+ end
216
+
217
+ def test_that_fenced_flag_works
218
+ text = <<fenced
219
+ This is a simple test
220
+
221
+ ~~~~~
222
+ This is some awesome code
223
+ with tabs and shit
224
+ ~~~
225
+ fenced
226
+
227
+ assert render_with({}, text) !~ /<code/
228
+
229
+ assert render_with({:fenced_code_blocks => true}, text) =~ /<code/
230
+ end
231
+
232
+ def test_that_fenced_flag_works_without_space
233
+ text = "foo\nbar\n```\nsome\ncode\n```\nbaz"
234
+ out = Greenmat::Markdown.new(Greenmat::Render::HTML, :fenced_code_blocks => true, :lax_spacing => true).render(text)
235
+ assert out.include?("<pre><code>")
236
+
237
+ out = Greenmat::Markdown.new(Greenmat::Render::HTML, :fenced_code_blocks => true).render(text)
238
+ assert !out.include?("<pre><code>")
239
+ end
240
+
241
+ def test_that_indented_code_preserves_references
242
+ text = <<indented
243
+ This is normal text
244
+
245
+ Link to [Google][1]
246
+
247
+ [1]: http://google.com
248
+ indented
249
+ out = Greenmat::Markdown.new(Greenmat::Render::HTML, :fenced_code_blocks => true).render(text)
250
+ assert out.include?("[1]: http://google.com")
251
+ end
252
+
253
+ def test_that_fenced_flag_preserves_references
254
+ text = <<fenced
255
+ This is normal text
256
+
257
+ ```
258
+ Link to [Google][1]
259
+
260
+ [1]: http://google.com
261
+ ```
262
+ fenced
263
+ out = Greenmat::Markdown.new(Greenmat::Render::HTML, :fenced_code_blocks => true).render(text)
264
+ assert out.include?("[1]: http://google.com")
265
+ end
266
+
267
+ def test_that_indented_flag_works
268
+ text = <<indented
269
+ This is a simple text
270
+
271
+ This is some awesome code
272
+ with shit
273
+
274
+ And this is again a simple text
275
+ indented
276
+
277
+ assert render_with({}, text) =~ /<code/
278
+ assert render_with({:disable_indented_code_blocks => true}, text) !~ /<code/
279
+ end
280
+
281
+ def test_that_headers_are_linkable
282
+ markdown = @markdown.render('### Hello [GitHub](http://github.com)')
283
+ assert_equal "<h3>Hello <a href=\"http://github.com\">GitHub</a></h3>\n", markdown
284
+ end
285
+
286
+ def test_autolinking_with_ent_chars
287
+ markdown = render_with({:autolink => true}, <<text)
288
+ This a stupid link: https://github.com/rtomayko/tilt/issues?milestone=1&state=open
289
+ text
290
+ assert_equal "<p>This a stupid link: <a href=\"https://github.com/rtomayko/tilt/issues?milestone=1&amp;state=open\">https://github.com/rtomayko/tilt/issues?milestone=1&amp;state=open</a></p>\n", markdown
291
+ end
292
+
293
+ def test_spaced_headers
294
+ rd = render_with({:space_after_headers => true}, "#123 a header yes\n")
295
+ assert rd !~ /<h1>/
296
+ end
297
+
298
+ def test_proper_intra_emphasis
299
+ assert render_with({:no_intra_emphasis => true}, "http://en.wikipedia.org/wiki/Dave_Allen_(comedian)") !~ /<em>/
300
+ assert render_with({:no_intra_emphasis => true}, "this fails: hello_world_") !~ /<em>/
301
+ assert render_with({:no_intra_emphasis => true}, "this also fails: hello_world_#bye") !~ /<em>/
302
+ assert render_with({:no_intra_emphasis => true}, "this works: hello_my_world") !~ /<em>/
303
+ assert render_with({:no_intra_emphasis => true}, "句中**粗體**測試") =~ /<strong>/
304
+
305
+ markdown = "This is (**bold**) and this_is_not_italic!"
306
+ html = "<p>This is (<strong>bold</strong>) and this_is_not_italic!</p>\n"
307
+ assert_equal html, render_with({:no_intra_emphasis => true}, markdown)
308
+
309
+ markdown = "This is \"**bold**\""
310
+ html = "<p>This is &quot;<strong>bold</strong>&quot;</p>\n"
311
+ assert_equal html, render_with({:no_intra_emphasis => true}, markdown)
312
+ end
313
+
314
+ def test_emphasis_escaping
315
+ markdown = @markdown.render("**foo\\*** _dd\\_dd_")
316
+ assert_equal "<p><strong>foo*</strong> <em>dd_dd</em></p>\n", markdown
317
+ end
318
+
319
+ def test_char_escaping_when_highlighting
320
+ markdown = "==attribute\\==="
321
+ output = render_with({highlight: true}, markdown)
322
+ assert_equal "<p><mark>attribute=</mark></p>\n", output
323
+ end
324
+
325
+ def test_ordered_lists_with_lax_spacing
326
+ markdown = "Foo:\n1. Foo\n2. Bar"
327
+ output = render_with({lax_spacing: true}, markdown)
328
+
329
+ assert_match /<ol>/, output
330
+ assert_match /<li>Foo<\/li>/, output
331
+ end
332
+
333
+ def test_references_with_tabs_after_colon
334
+ markdown = @markdown.render("[Link][id]\n[id]:\t\t\thttp://google.es")
335
+ assert_equal "<p><a href=\"http://google.es\">Link</a></p>\n", markdown
336
+ end
337
+ end
@@ -0,0 +1,34 @@
1
+ # coding: UTF-8
2
+ require 'test_helper'
3
+
4
+ # Disabled by default
5
+ # (these are the easy ones -- the evil ones are not disclosed)
6
+ class PathologicalInputsTest # < Greenmat::TestCase
7
+ def setup
8
+ @markdown = Greenmat::Markdown.new(Greenmat::Render::HTML)
9
+ end
10
+
11
+ def test_pathological_1
12
+ star = '*' * 250000
13
+ @markdown.render("#{star}#{star} hi #{star}#{star}")
14
+ end
15
+
16
+ def test_pathological_2
17
+ crt = '^' * 255
18
+ str = "#{crt}(\\)"
19
+ @markdown.render("#{str*300}")
20
+ end
21
+
22
+ def test_pathological_3
23
+ c = "`t`t`t`t`t`t" * 20000000
24
+ @markdown.render(c)
25
+ end
26
+
27
+ def test_pathological_4
28
+ @markdown.render(" [^a]: #{ "A" * 10000 }\n#{ "[^a][]" * 1000000 }\n")
29
+ end
30
+
31
+ def test_unbound_recursion
32
+ @markdown.render(("[" * 10000) + "foo" + ("](bar)" * 10000))
33
+ end
34
+ end
@@ -0,0 +1,36 @@
1
+ require 'test_helper'
2
+
3
+ class SafeRenderTest < Greenmat::TestCase
4
+ def setup
5
+ @render = Greenmat::Render::Safe
6
+ @parser = Greenmat::Markdown.new(@render, fenced_code_blocks: true)
7
+ end
8
+
9
+ def test_safe_links_only_is_enabled_by_default
10
+ markdown = "[foo](javascript:alert('foo'))"
11
+ output = @parser.render(markdown)
12
+
13
+ assert_not_match %r{a href}, output
14
+ end
15
+
16
+ def test_escape_html_is_enabled_by_default
17
+ markdown = "<p>Hello world!</p>"
18
+ output = @parser.render(markdown)
19
+
20
+ assert_match %r{&lt;}, output
21
+ end
22
+
23
+ def test_html_escaping_in_code_blocks
24
+ markdown = "~~~\n<p>Hello!</p>\n~~~"
25
+ output = @parser.render(markdown)
26
+
27
+ assert_match %r{&lt;p&gt;}, output
28
+ end
29
+
30
+ def test_lang_class_is_removed
31
+ markdown = "~~~ruby\nclass Foo; end\n~~~"
32
+ output = @parser.render(markdown)
33
+
34
+ assert_not_match %r{ruby}, output
35
+ end
36
+ end