summaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorMarius Balteanu <marius.balteanu@zitec.com>2021-08-11 21:40:56 +0000
committerMarius Balteanu <marius.balteanu@zitec.com>2021-08-11 21:40:56 +0000
commit9af2ba2c13d2dc706bdf1387110c13b82175a0cf (patch)
treeeab705cebf67e7daaa30532a62dbdb1c8dfba205 /test
parentfe4d0d93da6f95408582e53b425e89fc40751f6f (diff)
downloadredmine-9af2ba2c13d2dc706bdf1387110c13b82175a0cf.tar.gz
redmine-9af2ba2c13d2dc706bdf1387110c13b82175a0cf.zip
Adds CommonMark Markdown (GitHub Flavored) as third text formatting option (#32424).
Patch by Jens Krämer. git-svn-id: http://svn.redmine.org/redmine/trunk@21156 e93f8b46-1217-0410-a6f0-8f06a7374b81
Diffstat (limited to 'test')
-rw-r--r--test/unit/lib/redmine/wiki_formatting/common_mark/application_helper_test.rb66
-rw-r--r--test/unit/lib/redmine/wiki_formatting/common_mark/external_links_filter_test.rb48
-rw-r--r--test/unit/lib/redmine/wiki_formatting/common_mark/fixup_auto_links_filter_test.rb50
-rw-r--r--test/unit/lib/redmine/wiki_formatting/common_mark/formatter_test.rb270
-rw-r--r--test/unit/lib/redmine/wiki_formatting/common_mark/markdown_filter_test.rb35
-rw-r--r--test/unit/lib/redmine/wiki_formatting/common_mark/sanitization_filter_test.rb211
-rw-r--r--test/unit/lib/redmine/wiki_formatting/common_mark/syntax_highlight_filter_test.rb75
7 files changed, 755 insertions, 0 deletions
diff --git a/test/unit/lib/redmine/wiki_formatting/common_mark/application_helper_test.rb b/test/unit/lib/redmine/wiki_formatting/common_mark/application_helper_test.rb
new file mode 100644
index 000000000..fecafd660
--- /dev/null
+++ b/test/unit/lib/redmine/wiki_formatting/common_mark/application_helper_test.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+# Redmine - project management software
+# Copyright (C) 2006-2021 Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+require File.expand_path('../../../../../../test_helper', __FILE__)
+
+class Redmine::WikiFormatting::CommonMark::ApplicationHelperTest < Redmine::HelperTest
+ if Object.const_defined?(:CommonMarker)
+
+ include ERB::Util
+ include Rails.application.routes.url_helpers
+
+ fixtures :projects, :enabled_modules,
+ :users, :email_addresses,
+ :members, :member_roles, :roles,
+ :repositories, :changesets,
+ :projects_trackers,
+ :trackers, :issue_statuses, :issues, :versions, :documents, :journals,
+ :wikis, :wiki_pages, :wiki_contents,
+ :boards, :messages, :news,
+ :attachments, :enumerations,
+ :custom_values, :custom_fields, :custom_fields_projects
+
+ def setup
+ super
+ set_tmp_attachments_directory
+ end
+
+ def test_attached_images_with_markdown_and_non_ascii_filename
+ to_test = {
+ 'CAFÉ.JPG' => 'CAF%C3%89.JPG',
+ 'crème.jpg' => 'cr%C3%A8me.jpg',
+ }
+ with_settings :text_formatting => 'common_mark' do
+ to_test.each do |filename, result|
+ attachment = Attachment.generate!(:filename => filename)
+ assert_include %(<img src="/attachments/download/#{attachment.id}/#{result}" alt="">), textilizable("![](#{filename})", :attachments => [attachment])
+ end
+ end
+ end
+
+ def test_toc_with_markdown_formatting_should_be_parsed
+ with_settings :text_formatting => 'common_mark' do
+ assert_select_in textilizable("{{toc}}\n\n# Heading"), 'ul.toc li', :text => 'Heading'
+ assert_select_in textilizable("{{<toc}}\n\n# Heading"), 'ul.toc.left li', :text => 'Heading'
+ assert_select_in textilizable("{{>toc}}\n\n# Heading"), 'ul.toc.right li', :text => 'Heading'
+ end
+ end
+
+ end
+end
diff --git a/test/unit/lib/redmine/wiki_formatting/common_mark/external_links_filter_test.rb b/test/unit/lib/redmine/wiki_formatting/common_mark/external_links_filter_test.rb
new file mode 100644
index 000000000..d4e8fa0df
--- /dev/null
+++ b/test/unit/lib/redmine/wiki_formatting/common_mark/external_links_filter_test.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+# Redmine - project management software
+# Copyright (C) 2006-2021 Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+require File.expand_path('../../../../../../test_helper', __FILE__)
+
+if Object.const_defined?(:CommonMarker)
+ require 'redmine/wiki_formatting/common_mark/external_links_filter'
+
+ class Redmine::WikiFormatting::CommonMark::ExternalLinksFilterTest < ActiveSupport::TestCase
+ def filter(html)
+ Redmine::WikiFormatting::CommonMark::ExternalLinksFilter.to_html(html, @options)
+ end
+
+ def setup
+ @options = { }
+ end
+
+ def test_external_links_should_have_external_css_class
+ assert_equal %(<a href="http://example.net/" class="external">link</a>), filter(%(<a href="http://example.net/">link</a>))
+ end
+
+ def test_locals_links_should_not_have_external_css_class
+ assert_equal %(<a href="/">home</a>), filter(%(<a href="/">home</a>))
+ assert_equal %(<a href="relative">relative</a>), filter(%(<a href="relative">relative</a>))
+ assert_equal %(<a href="#anchor">anchor</a>), filter(%(<a href="#anchor">anchor</a>))
+ end
+
+ def test_mailto_links_should_have_email_class
+ assert_equal %(<a href="mailto:user@example.org" class="email">user</a>), filter(%(<a href="mailto:user@example.org">user</a>))
+ end
+ end
+end
diff --git a/test/unit/lib/redmine/wiki_formatting/common_mark/fixup_auto_links_filter_test.rb b/test/unit/lib/redmine/wiki_formatting/common_mark/fixup_auto_links_filter_test.rb
new file mode 100644
index 000000000..92b324151
--- /dev/null
+++ b/test/unit/lib/redmine/wiki_formatting/common_mark/fixup_auto_links_filter_test.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+# Redmine - project management software
+# Copyright (C) 2006-2021 Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+require File.expand_path('../../../../../../test_helper', __FILE__)
+
+if Object.const_defined?(:CommonMarker)
+ require 'redmine/wiki_formatting/common_mark/fixup_auto_links_filter'
+
+ class Redmine::WikiFormatting::CommonMark::FixupAutoLinksFilterTest < ActiveSupport::TestCase
+ def filter(html)
+ Redmine::WikiFormatting::CommonMark::FixupAutoLinksFilter.to_html(html, @options)
+ end
+
+ def format(markdown)
+ Redmine::WikiFormatting::CommonMark::MarkdownFilter.to_html(markdown, Redmine::WikiFormatting::CommonMark::PIPELINE_CONFIG)
+ end
+
+ def setup
+ @options = { }
+ end
+
+ def test_should_fixup_autolinked_user_references
+ text = "user:user@example.org"
+ assert_equal "<p>#{text}</p>", filter(format(text))
+ text = "@user@example.org"
+ assert_equal "<p>#{text}</p>", filter(format(text))
+ end
+
+ def test_should_fixup_autolinked_hires_files
+ text = "printscreen@2x.png"
+ assert_equal "<p>#{text}</p>", filter(format(text))
+ end
+ end
+end
diff --git a/test/unit/lib/redmine/wiki_formatting/common_mark/formatter_test.rb b/test/unit/lib/redmine/wiki_formatting/common_mark/formatter_test.rb
new file mode 100644
index 000000000..9f23dba30
--- /dev/null
+++ b/test/unit/lib/redmine/wiki_formatting/common_mark/formatter_test.rb
@@ -0,0 +1,270 @@
+# frozen_string_literal: true
+
+# Redmine - project management software
+# Copyright (C) 2006-2021 Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+require File.expand_path('../../../../../../test_helper', __FILE__)
+
+class Redmine::WikiFormatting::CommonMark::FormatterTest < ActionView::TestCase
+ if Object.const_defined?(:CommonMarker)
+
+ def setup
+ @formatter = Redmine::WikiFormatting::CommonMark::Formatter
+ end
+
+ def format(text)
+ @formatter.new(text).to_html
+ end
+
+ def test_should_render_hard_breaks
+ html ="<p>foo<br>\nbar</p>"
+ assert_equal html, format("foo\\\nbar")
+ assert_equal html, format("foo \nbar")
+ end
+
+ def test_should_ignore_soft_breaks
+ assert_equal "<p>foo\nbar</p>", format("foo\nbar")
+ end
+
+ def test_syntax_error_in_image_reference_should_not_raise_exception
+ assert format("!>[](foo.png)")
+ end
+
+ def test_empty_image_should_not_raise_exception
+ assert format("![]()")
+ end
+
+ def test_inline_style
+ assert_equal "<p><strong>foo</strong></p>", format("**foo**")
+ end
+
+ def test_not_set_intra_emphasis
+ assert_equal "<p>foo_bar_baz</p>", format("foo_bar_baz")
+ end
+
+ def test_wiki_links_should_be_preserved
+ text = 'This is a wiki link: [[Foo]]'
+ assert_include '[[Foo]]', format(text)
+ end
+
+ def test_redmine_links_with_double_quotes_should_be_preserved
+ text = 'This is a redmine link: version:"1.0"'
+ assert_include 'version:"1.0"', format(text)
+ end
+
+ def test_links_by_id_should_be_preserved
+ text = "[project#3]"
+ assert_equal "<p>#{text}</p>", format(text)
+ end
+
+ def test_links_to_users_should_be_preserved
+ text = "[@login]"
+ assert_equal "<p>#{text}</p>", format(text)
+ text = "[user:login]"
+ assert_equal "<p>#{text}</p>", format(text)
+ text = "user:user@example.org"
+ assert_equal "<p>#{text}</p>", format(text)
+ text = "[user:user@example.org]"
+ assert_equal "<p>#{text}</p>", format(text)
+ text = "@user@example.org"
+ assert_equal "<p>#{text}</p>", format(text)
+ text = "[@user@example.org]"
+ assert_equal "<p>#{text}</p>", format(text)
+ end
+
+ def test_files_with_at_should_not_end_up_as_mailto_links
+ text = "printscreen@2x.png"
+ assert_equal "<p>#{text}</p>", format(text)
+ text = "[printscreen@2x.png]"
+ assert_equal "<p>#{text}</p>", format(text)
+ end
+
+ def test_should_support_syntax_highlight
+ text = <<-STR
+ ~~~ruby
+ def foo
+ end
+ ~~~
+ STR
+ assert_select_in format(text), 'pre code.ruby.syntaxhl' do
+ assert_select 'span.k', :text => 'def'
+ end
+ end
+
+ def test_should_not_allow_invalid_language_for_code_blocks
+ text = <<-STR
+ ~~~foo
+ test
+ ~~~
+ STR
+ assert_equal "<pre>test\n</pre>", format(text)
+ end
+
+ def test_external_links_should_have_external_css_class
+ text = 'This is a [link](http://example.net/)'
+ assert_equal '<p>This is a <a href="http://example.net/" class="external">link</a></p>', format(text)
+ end
+
+ def test_locals_links_should_not_have_external_css_class
+ text = 'This is a [link](/issues)'
+ assert_equal '<p>This is a <a href="/issues">link</a></p>', format(text)
+ end
+
+ def test_markdown_should_not_require_surrounded_empty_line
+ text = <<-STR
+ This is a list:
+ * One
+ * Two
+ STR
+ assert_equal "<p>This is a list:</p>\n<ul>\n<li>One</li>\n<li>Two</li>\n</ul>", format(text)
+ end
+
+ def test_footnotes
+ text = <<-STR
+ This is some text[^1].
+
+ [^1]: This is the foot note
+ STR
+
+ expected = <<-EXPECTED
+ <p>This is some text<sup><a href="#fn1" id="fnref1">1</a></sup>.</p>
+ <ol>
+ <li id="fn1">
+ <p>This is the foot note <a href="#fnref1">↩</a></p>
+ </li>
+ </ol>
+ EXPECTED
+
+ assert_equal expected.gsub(%r{[\r\n\t]}, ''), format(text).gsub(%r{[\r\n\t]}, '')
+ end
+
+ STR_WITH_PRE = [
+ # 0
+ <<~STR.chomp,
+ # Title
+
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas sed libero.
+ STR
+ # 1
+ <<~STR.chomp,
+ ## Heading 2
+
+ ~~~ruby
+ def foo
+ end
+ ~~~
+
+ Morbi facilisis accumsan orci non pharetra.
+
+ ~~~ ruby
+ def foo
+ end
+ ~~~
+
+ ```
+ Pre Content:
+
+ ## Inside pre
+
+ <tag> inside pre block
+
+ Morbi facilisis accumsan orci non pharetra.
+ ```
+ STR
+ # 2
+ <<~STR.chomp,
+ ### Heading 3
+
+ Nulla nunc nisi, egestas in ornare vel, posuere ac libero.
+ STR
+ ]
+
+ def test_get_section_should_ignore_pre_content
+ text = STR_WITH_PRE.join("\n\n")
+
+ assert_section_with_hash STR_WITH_PRE[1..2].join("\n\n"), text, 2
+ assert_section_with_hash STR_WITH_PRE[2], text, 3
+ end
+
+ def test_update_section_should_not_escape_pre_content_outside_section
+ text = STR_WITH_PRE.join("\n\n")
+ replacement = "New text"
+
+ assert_equal [STR_WITH_PRE[0..1], "New text"].flatten.join("\n\n"),
+ @formatter.new(text).update_section(3, replacement)
+ end
+
+ def test_should_emphasize_text
+ text = 'This _text_ should be emphasized'
+ assert_equal '<p>This <em>text</em> should be emphasized</p>', format(text)
+ end
+
+ def test_should_strike_through_text
+ text = 'This ~~text~~ should be striked through'
+ assert_equal '<p>This <del>text</del> should be striked through</p>', format(text)
+ end
+
+ def test_should_autolink_urls_and_emails
+ [
+ ["http://example.org", '<p><a href="http://example.org" class="external">http://example.org</a></p>'],
+ ["http://www.redmine.org/projects/redmine/issues?utf8=✓",
+ '<p><a href="http://www.redmine.org/projects/redmine/issues?utf8=%E2%9C%93" class="external">http://www.redmine.org/projects/redmine/issues?utf8=✓</a></p>'],
+ ['[Letters](https://yandex.ru/search/?text=кол-во)', '<p><a href="https://yandex.ru/search/?text=%D0%BA%D0%BE%D0%BB-%D0%B2%D0%BE" class="external">Letters</a></p>'],
+ ["www.example.org", '<p><a href="http://www.example.org" class="external">www.example.org</a></p>'],
+ ["user@example.org", '<p><a href="mailto:user@example.org" class="email">user@example.org</a></p>']
+ ].each do |text, html|
+ assert_equal html, format(text)
+ end
+ end
+
+ def test_should_support_html_tables
+ text = '<table style="background: red"><tr><td>Cell</td></tr></table>'
+ assert_equal '<table><tr><td>Cell</td></tr></table>', format(text)
+ end
+
+ def test_should_remove_unsafe_uris
+ [
+ ['<img src="data:foobar">', '<img>'],
+ ['<a href="javascript:bla">click me</a>', '<p><a>click me</a></p>'],
+ ].each do |text, html|
+ assert_equal html, format(text)
+ end
+ end
+
+ def test_should_escape_unwanted_tags
+ [
+ [
+ %[<p>sit<br>amet &lt;style&gt;.foo { color: #fff; }&lt;/style&gt; &lt;script&gt;alert("hello world");&lt;/script&gt;</p>],
+ %[sit<br/>amet <style>.foo { color: #fff; }</style> <script>alert("hello world");</script>]
+ ]
+ ].each do |expected, input|
+ assert_equal expected, format(input)
+ end
+ end
+
+ private
+
+ def assert_section_with_hash(expected, text, index)
+ result = @formatter.new(text).get_section(index)
+
+ assert_kind_of Array, result
+ assert_equal 2, result.size
+ assert_equal expected, result.first, "section content did not match"
+ assert_equal Digest::MD5.hexdigest(expected), result.last, "section hash did not match"
+ end
+ end
+end
diff --git a/test/unit/lib/redmine/wiki_formatting/common_mark/markdown_filter_test.rb b/test/unit/lib/redmine/wiki_formatting/common_mark/markdown_filter_test.rb
new file mode 100644
index 000000000..195c3e11e
--- /dev/null
+++ b/test/unit/lib/redmine/wiki_formatting/common_mark/markdown_filter_test.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+# Redmine - project management software
+# Copyright (C) 2006-2021 Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+require File.expand_path('../../../../../../test_helper', __FILE__)
+
+if Object.const_defined?(:CommonMarker)
+ require 'redmine/wiki_formatting/common_mark/markdown_filter'
+
+ class Redmine::WikiFormatting::CommonMark::MarkdownFilterTest < ActiveSupport::TestCase
+ def filter(markdown)
+ Redmine::WikiFormatting::CommonMark::MarkdownFilter.to_html(markdown)
+ end
+
+ # just a basic sanity test. more formatting tests in the formatter_test
+ def test_should_render_markdown
+ assert_equal "<p><strong>bold</strong></p>", filter("**bold**")
+ end
+ end
+end
diff --git a/test/unit/lib/redmine/wiki_formatting/common_mark/sanitization_filter_test.rb b/test/unit/lib/redmine/wiki_formatting/common_mark/sanitization_filter_test.rb
new file mode 100644
index 000000000..72ef52a63
--- /dev/null
+++ b/test/unit/lib/redmine/wiki_formatting/common_mark/sanitization_filter_test.rb
@@ -0,0 +1,211 @@
+# frozen_string_literal: true
+
+# Redmine - project management software
+# Copyright (C) 2006-2021 Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+require File.expand_path('../../../../../../test_helper', __FILE__)
+
+if Object.const_defined?(:CommonMarker)
+ require 'redmine/wiki_formatting/common_mark/sanitization_filter'
+
+ class Redmine::WikiFormatting::CommonMark::SanitizationFilterTest < ActiveSupport::TestCase
+ def filter(html)
+ Redmine::WikiFormatting::CommonMark::SanitizationFilter.to_html(html, @options)
+ end
+
+ def setup
+ @options = { }
+ end
+
+ def test_should_filter_tags
+ input = %(<textarea>foo</textarea> <blink>dont blink</blink>)
+ assert_equal %(foo dont blink), filter(input)
+ end
+
+ def test_should_sanitize_attributes
+ input = %(<a href="foo" onclick="bar" baz="foo">link</a>)
+ assert_equal %(<a href="foo">link</a>), filter(input)
+ end
+
+ def test_should_allow_relative_links
+ input = %(<a href="foo/bar">foo/bar</a>)
+ assert_equal input, filter(input)
+ end
+
+ def test_should_support_footnotes
+ input = %(<a href="#fn1" id="fnref1">foo</a>)
+ assert_equal input, filter(input)
+ input = %(<ol><li id="fn1">footnote</li></ol>)
+ assert_equal input, filter(input)
+ end
+
+ def test_should_remove_invalid_ids
+ input = %(<a href="#fn1" id="foo">foo</a>)
+ assert_equal %(<a href="#fn1">foo</a>), filter(input)
+ input = %(<ol><li id="foo">footnote</li></ol>)
+ assert_equal %(<ol><li>footnote</li></ol>), filter(input)
+ end
+
+ def test_should_allow_class_on_code_only
+ input = %(<p class="foo">bar</p>)
+ assert_equal %(<p>bar</p>), filter(input)
+
+ input = %(<code class="language-ruby">foo</code>)
+ assert_equal input, filter(input)
+
+ input = %(<code class="foo">foo</code>)
+ assert_equal %(<code>foo</code>), filter(input)
+ end
+
+ # samples taken from the Sanitize test suite
+ # rubocop:disable Layout/LineLength
+ STRINGS = [
+ [
+ '<b>Lo<!-- comment -->rem</b> <a href="pants" title="foo" style="text-decoration: underline;">ipsum</a> <a href="http://foo.com/"><strong>dolor</strong></a> sit<br/>amet <style>.foo { color: #fff; }</style> <script>alert("hello world");</script>',
+ '<b>Lorem</b> <a href="pants" title="foo">ipsum</a> <a href="http://foo.com/"><strong>dolor</strong></a> sit<br>amet .foo { color: #fff; } '
+ ],
+ [
+ 'Lo<!-- comment -->rem</b> <a href=pants title="foo>ipsum <a href="http://foo.com/"><strong>dolor</a></strong> sit<br/>amet <script>alert("hello world");',
+ 'Lorem <a href="pants" title="foo&gt;ipsum &lt;a href="><strong>dolor</strong></a> sit<br>amet '
+ ],
+ [
+ '<p>a</p><blockquote>b',
+ '<p>a</p><blockquote>b</blockquote>'
+ ],
+ [
+ '<b>Lo<!-- comment -->rem</b> <a href="javascript:pants" title="foo">ipsum</a> <a href="http://foo.com/"><strong>dolor</strong></a> sit<br/>amet <<foo>script>alert("hello world");</script>',
+ '<b>Lorem</b> <a title="foo">ipsum</a> <a href="http://foo.com/"><strong>dolor</strong></a> sit<br>amet &lt;script&gt;alert("hello world");'
+ ]
+ ]
+ # rubocop:enable Layout/LineLength
+
+ def test_should_sanitize_html_strings
+ STRINGS.each do |input, expected|
+ assert_equal expected, filter(input)
+ end
+ end
+
+ # samples taken from the Sanitize test suite
+ PROTOCOLS = {
+ 'protocol-based JS injection: simple, no spaces' => [
+ '<a href="javascript:alert(\'XSS\');">foo</a>',
+ '<a>foo</a>'
+ ],
+
+ 'protocol-based JS injection: simple, spaces before' => [
+ '<a href="javascript :alert(\'XSS\');">foo</a>',
+ '<a>foo</a>'
+ ],
+
+ 'protocol-based JS injection: simple, spaces after' => [
+ '<a href="javascript: alert(\'XSS\');">foo</a>',
+ '<a>foo</a>'
+ ],
+
+ 'protocol-based JS injection: simple, spaces before and after' => [
+ '<a href="javascript : alert(\'XSS\');">foo</a>',
+ '<a>foo</a>'
+ ],
+
+ 'protocol-based JS injection: preceding colon' => [
+ '<a href=":javascript:alert(\'XSS\');">foo</a>',
+ '<a>foo</a>'
+ ],
+
+ 'protocol-based JS injection: UTF-8 encoding' => [
+ '<a href="javascript&#58;">foo</a>',
+ '<a>foo</a>'
+ ],
+
+ 'protocol-based JS injection: long UTF-8 encoding' => [
+ '<a href="javascript&#0058;">foo</a>',
+ '<a>foo</a>'
+ ],
+
+ # rubocop:disable Layout/LineLength
+ 'protocol-based JS injection: long UTF-8 encoding without semicolons' => [
+ '<a href=&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#0000112&#0000116&#0000058&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0000039&#0000088&#0000083&#0000083&#0000039&#0000041>foo</a>',
+ '<a>foo</a>'
+ ],
+ # rubocop:enable Layout/LineLength
+
+ 'protocol-based JS injection: hex encoding' => [
+ '<a href="javascript&#x3A;">foo</a>',
+ '<a>foo</a>'
+ ],
+
+ 'protocol-based JS injection: long hex encoding' => [
+ '<a href="javascript&#x003A;">foo</a>',
+ '<a>foo</a>'
+ ],
+
+ 'protocol-based JS injection: hex encoding without semicolons' => [
+ '<a href=&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29>foo</a>',
+ '<a>foo</a>'
+ ],
+
+ 'protocol-based JS injection: null char' => [
+ "<img src=java\0script:alert(\"XSS\")>",
+ '<img src="java">'
+ # '<img>'
+ ],
+
+ 'protocol-based JS injection: invalid URL char' => [
+ '<img src=java\script:alert("XSS")>',
+ '<img>'
+ ],
+
+ 'protocol-based JS injection: spaces and entities' => [
+ '<img src=" &#14; javascript:alert(\'XSS\');">',
+ '<img src="">'
+ # '<img>'
+ ],
+
+ 'protocol whitespace' => [
+ '<a href=" http://example.com/"></a>',
+ '<a href="http://example.com/"></a>'
+ ],
+
+ 'data images sources' => [
+ '<img src="data:image/png;base64,foobar">',
+ '<img>'
+ ],
+
+ 'data URIs' => [
+ '<a href="data:text/html;base64,foobar">XSS</a>',
+ '<a>XSS</a>'
+ ],
+
+ 'vbscript URIs' => [
+ '<a href="vbscript:foobar">XSS</a>',
+ '<a>XSS</a>'
+ ],
+
+ 'invalid URIs' => [
+ '<a href="foo://example.org">link</a>',
+ '<a>link</a>'
+ ],
+ }
+
+ PROTOCOLS.each do |name, strings|
+ test "should not allow #{name}" do
+ input, expected = *strings
+ assert_equal expected, filter(input)
+ end
+ end
+ end
+end
diff --git a/test/unit/lib/redmine/wiki_formatting/common_mark/syntax_highlight_filter_test.rb b/test/unit/lib/redmine/wiki_formatting/common_mark/syntax_highlight_filter_test.rb
new file mode 100644
index 000000000..e7e782d53
--- /dev/null
+++ b/test/unit/lib/redmine/wiki_formatting/common_mark/syntax_highlight_filter_test.rb
@@ -0,0 +1,75 @@
+# frozen_string_literal: true
+
+# Redmine - project management software
+# Copyright (C) 2006-2021 Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+require File.expand_path('../../../../../../test_helper', __FILE__)
+if Object.const_defined?(:CommonMarker)
+ require 'redmine/wiki_formatting/common_mark/syntax_highlight_filter'
+
+ class Redmine::WikiFormatting::CommonMark::SyntaxHighlightFilterTest < ActiveSupport::TestCase
+ def filter(html)
+ Redmine::WikiFormatting::CommonMark::SyntaxHighlightFilter.to_html(html, @options)
+ end
+
+ def setup
+ @options = { }
+ end
+
+ def test_should_highlight_supported_language
+ input = <<~HTML
+ <pre><code class="language-ruby">
+ def foo
+ end
+ </code></pre>
+ HTML
+ expected = <<~HTML
+ <pre><code class="ruby syntaxhl">
+ <span class="k">def</span> <span class="nf">foo</span>
+ <span class="k">end</span>
+ </code></pre>
+ HTML
+ assert_equal expected, filter(input)
+ end
+
+ def test_should_strip_code_for_unknown_lang
+ input = <<~HTML
+ <pre><code class="language-foobar">
+ def foo
+ end
+ </code></pre>
+ HTML
+ expected = <<~HTML
+ <pre>
+ def foo
+ end
+ </pre>
+ HTML
+ assert_equal expected, filter(input)
+ end
+
+ def test_should_ignore_code_without_class
+ input = <<~HTML
+ <pre><code>
+ def foo
+ end
+ </code></pre>
+ HTML
+ assert_equal input, filter(input)
+ end
+ end
+end