Introduce markdown renderer for templates
Change-Id: Ia0166b5c7f3b80f70902c97653e517968d39dcf5
diff --git a/t/plugin/markdown.t b/t/plugin/markdown.t
new file mode 100644
index 0000000..f9bb0ae
--- /dev/null
+++ b/t/plugin/markdown.t
@@ -0,0 +1,234 @@
+use Mojo::Base -strict;
+use Test::More;
+use Test::Mojo;
+use Mojolicious::Lite;
+
+my $link_cb_called = 0;
+
+plugin 'TagHelpers::ContentBlock';
+
+plugin 'Kalamar::Plugin::Markdown' => {
+ heading_offset => 2,
+ link_callback => sub {
+ my ($c, $url, $text) = @_;
+ $link_cb_called++;
+ if ($url =~ m{^/doc/}) {
+ return qq{<a href="$url" class="embedded-link">$text</a>};
+ }
+ if ($url =~ m{^https?://}) {
+ return qq{<a href="$url" target="_top">$text</a>};
+ }
+ return undef;
+ },
+};
+
+get '/md-inline' => sub {
+ shift->render(
+ handler => 'md',
+ inline => "# Heading\n\nSome **bold** text.\n"
+ );
+};
+
+get '/md-page' => sub {
+ shift->render(
+ template => 'test_page',
+ handler => 'md',
+ format => 'html',
+ name => 'World'
+ );
+};
+
+get '/md-helper' => sub {
+ shift->render(
+ template => 'test_helper',
+ handler => 'ep',
+ format => 'html'
+ );
+};
+
+get '/md-links' => sub {
+ shift->render(
+ handler => 'md',
+ inline => "[FAQ](/doc/faq)\n\n[GitHub](https://github.com)\n\n[relative](page)\n"
+ );
+};
+
+get '/md-html' => sub {
+ shift->render(
+ handler => 'md',
+ inline => qq{<pre class="query tutorial"><code>Baum</code></pre>\n\nSome text.\n}
+ );
+};
+
+get '/md-ep' => sub {
+ shift->render(
+ template => 'test_ep',
+ handler => 'md',
+ format => 'html',
+ title => 'Test Title'
+ );
+};
+
+get '/md-table' => sub {
+ shift->render(
+ handler => 'md',
+ inline => "| A | B |\n|---|---|\n| 1 | 2 |\n"
+ );
+};
+
+get '/md-comment' => sub {
+ shift->render(
+ handler => 'md',
+ inline => "<!-- maintenance note -->\n\nVisible text.\n\n"
+ . "Inline <!-- hidden --> text.\n\n"
+ . " <!-- in a code block -->\n"
+ );
+};
+
+get '/md-content-block' => sub {
+ my $c = shift;
+ $c->content_block('test_block' => { inline => '<span class="from-block">block content</span>' });
+ $c->render(
+ template => 'test_content_block',
+ handler => 'md',
+ format => 'html'
+ );
+};
+
+get '/md-details' => sub {
+ shift->render(
+ handler => 'md',
+ inline => "<details>\n<summary>More</summary>\n\n### Section\n\n- item\n\n</details>\n"
+ );
+};
+
+my $t = Test::Mojo->new;
+
+ok($t->app->renderer->handlers->{md}, 'md handler registered');
+
+ok($t->app->renderer->helpers->{markdown}, 'markdown helper registered');
+
+$t->get_ok('/md-inline')
+ ->status_is(200)
+ ->content_like(qr/<h3>Heading<\/h3>/)
+ ->content_like(qr/<strong>bold<\/strong>/)
+ ;
+
+$t->get_ok('/md-inline')
+ ->content_like(qr/<h3>/)
+ ->content_unlike(qr/<h1>/)
+ ;
+
+$t->get_ok('/md-page')
+ ->status_is(200)
+ ->content_like(qr/Hello, World/)
+ ->content_like(qr/<h3>/)
+ ;
+
+$t->get_ok('/md-helper')
+ ->status_is(200)
+ ->content_like(qr/<h3>Helper Section<\/h3>/)
+ ->content_like(qr/<strong>works<\/strong>/)
+ ;
+
+$link_cb_called = 0;
+$t->get_ok('/md-links')
+ ->status_is(200)
+ ->content_like(qr/class="embedded-link"/)
+ ->content_like(qr/target="_top"/)
+ ->content_like(qr/<a href="page">relative/)
+ ;
+ok($link_cb_called >= 3, 'link callback was called');
+
+$t->get_ok('/md-html')
+ ->status_is(200)
+ ->content_like(qr/<pre class="query tutorial">/)
+ ->content_like(qr/<code>Baum<\/code>/)
+ ;
+
+$t->get_ok('/md-ep')
+ ->status_is(200)
+ ->content_like(qr/Test Title/)
+ ;
+
+$t->get_ok('/md-table')
+ ->status_is(200)
+ ->content_like(qr/<table>/)
+ ->content_like(qr/<td>1<\/td>/)
+ ;
+
+$t->get_ok('/md-content-block')
+ ->status_is(200)
+ ->content_like(qr/class="from-block"/)
+ ->content_like(qr/block content/)
+ ;
+
+# HTML5 block elements (details/summary/...) survive conversion: the stray
+# <p> wrapper Text::MultiMarkdown adds is removed and the inner Markdown is
+# still converted.
+$t->get_ok('/md-details')
+ ->status_is(200)
+ ->content_like(qr/<details>/)
+ ->content_like(qr/<summary>More<\/summary>/)
+ ->content_like(qr/<\/details>/)
+ ->content_unlike(qr/<p>\s*<details>/)
+ ->content_unlike(qr/<p>\s*<summary>/)
+ ->content_unlike(qr/<p>\s*<\/details>/)
+ ->content_like(qr/<li>item<\/li>/)
+ ;
+
+# Unwrapping can be disabled
+my $wrapped = Mojolicious->new;
+$wrapped->plugin('Kalamar::Plugin::Markdown' => { unwrap_html5_blocks => 0 });
+like(
+ $wrapped->build_controller->markdown("<details>\n<summary>x</summary>\n</details>\n"),
+ qr/<p>\s*<details>/,
+ 'block unwrapping skipped with unwrap_html5_blocks => 0'
+);
+
+$t->get_ok('/md-comment')
+ ->status_is(200)
+ ->content_unlike(qr/maintenance note/)
+ ->content_unlike(qr/hidden/)
+ ->content_like(qr/Visible text\./)
+ ->content_like(qr/Inline\s*text\./)
+ ->content_like(qr/<!-- in a code block -->/)
+ ;
+
+# Comments are kept when the option is disabled
+my $keep = Mojolicious->new;
+$keep->plugin('Kalamar::Plugin::Markdown' => { strip_comments => 0 });
+like(
+ $keep->build_controller->markdown("<!-- kept -->\n\nText.\n"),
+ qr/<!-- kept -->/,
+ 'comment kept with strip_comments => 0'
+);
+
+done_testing;
+
+__DATA__
+
+@@ test_page.html.md
+# Welcome
+
+Hello, <%= $name %>!
+
+@@ test_helper.html.ep
+<div>
+%= markdown begin
+# Helper Section
+This **works** well.
+% end
+</div>
+
+@@ test_ep.html.md
+# Page: <%= $title %>
+
+This page is about **<%= $title %>**.
+
+@@ test_content_block.html.md
+# Content Block Test
+
+%= content_block 'test_block'
+
+Some **markdown** after the block.