greenmat 3.2.0.0

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 (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