summaryrefslogtreecommitdiffstats
path: root/test/unit/lib/redmine
diff options
context:
space:
mode:
Diffstat (limited to 'test/unit/lib/redmine')
-rw-r--r--test/unit/lib/redmine/field_format/progressbar_format_test.rb12
-rw-r--r--test/unit/lib/redmine/quote_reply_helper_test.rb2
-rw-r--r--test/unit/lib/redmine/reaction_test.rb189
-rw-r--r--test/unit/lib/redmine/wiki_formatting/common_mark/formatter_test.rb65
-rw-r--r--test/unit/lib/redmine/wiki_formatting/common_mark/sanitization_filter_test.rb38
-rw-r--r--test/unit/lib/redmine/wiki_formatting/html_sanitizer_test.rb20
-rw-r--r--test/unit/lib/redmine/wiki_formatting/textile_formatter_test.rb12
7 files changed, 316 insertions, 22 deletions
diff --git a/test/unit/lib/redmine/field_format/progressbar_format_test.rb b/test/unit/lib/redmine/field_format/progressbar_format_test.rb
index 51bd8bc5f..6e0df724d 100644
--- a/test/unit/lib/redmine/field_format/progressbar_format_test.rb
+++ b/test/unit/lib/redmine/field_format/progressbar_format_test.rb
@@ -116,5 +116,17 @@ module Redmine::FieldFormat
end
end
end
+
+ def test_formatted_value_with_html_true
+ expected = progress_bar(50)
+ formatted = @format.formatted_value(self, @field, 50, Issue.new, true)
+ assert_equal expected, formatted
+ assert formatted.html_safe?
+ end
+
+ def test_formatted_value_with_html_false
+ formatted = @format.formatted_value(self, @field, 50, Issue.new, false)
+ assert_equal '50', formatted
+ end
end
end
diff --git a/test/unit/lib/redmine/quote_reply_helper_test.rb b/test/unit/lib/redmine/quote_reply_helper_test.rb
index 43adb521b..cbac1f6d0 100644
--- a/test/unit/lib/redmine/quote_reply_helper_test.rb
+++ b/test/unit/lib/redmine/quote_reply_helper_test.rb
@@ -29,7 +29,7 @@ class QuoteReplyHelperTest < ActionView::TestCase
a_tag = quote_reply(url, '#issue_description_wiki')
assert_includes a_tag, %|onclick="#{h "quoteReply('/issues/1/quoted', '#issue_description_wiki', 'common_mark'); return false;"}"|
- assert_includes a_tag, %|class="icon icon-comment"|
+ assert_includes a_tag, %|class="icon icon-quote"|
assert_not_includes a_tag, 'title='
# When icon_only is true
diff --git a/test/unit/lib/redmine/reaction_test.rb b/test/unit/lib/redmine/reaction_test.rb
new file mode 100644
index 000000000..f3228a3bd
--- /dev/null
+++ b/test/unit/lib/redmine/reaction_test.rb
@@ -0,0 +1,189 @@
+# frozen_string_literal: true
+
+# Redmine - project management software
+# Copyright (C) 2006- 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_relative '../../../test_helper'
+
+class Redmine::ReactionTest < ActiveSupport::TestCase
+ setup do
+ @user = users(:users_002)
+ @issue = issues(:issues_007)
+ Setting.reactions_enabled = '1'
+ end
+
+ teardown do
+ Setting.clear_cache
+ end
+
+ test 'preload_reaction_details preloads ReactionDetail for all objects in the collection' do
+ User.current = users(:users_002)
+
+ issue1 = issues(:issues_001)
+ issue2 = issues(:issues_002)
+
+ assert_nil issue1.instance_variable_get(:@reaction_detail)
+ assert_nil issue2.instance_variable_get(:@reaction_detail)
+
+ Issue.preload_reaction_details([issue1, issue2])
+
+ expected_issue1_reaction_detail = Reaction::Detail.new(
+ visible_users: [users(:users_003), users(:users_002), users(:users_001)],
+ user_reaction: reactions(:reaction_002)
+ )
+
+ # ReactionDetail is already preloaded, so calling reaction_detail does not execute any query.
+ assert_no_queries do
+ assert_equal expected_issue1_reaction_detail, issue1.reaction_detail
+
+ # Even when an object has no reactions, an empty ReactionDetail is set.
+ assert_equal Reaction::Detail.new(
+ visible_users: [],
+ user_reaction: nil
+ ), issue2.reaction_detail
+ end
+ end
+
+ test 'visible_users in ReactionDetail preloaded by preload_reaction_details does not include non-visible users' do
+ current_user = User.current = User.generate!
+ visible_user = users(:users_002)
+ non_visible_user = User.generate!
+
+ project = Project.generate!
+ role = Role.generate!(users_visibility: 'members_of_visible_projects')
+
+ User.add_to_project(current_user, project, role)
+ User.add_to_project(visible_user, project, roles(:roles_001))
+
+ issue = Issue.generate!(project: project)
+
+ [current_user, visible_user, non_visible_user].each do |user|
+ issue.reactions.create!(user: user)
+ end
+
+ Issue.preload_reaction_details([issue])
+
+ # non_visible_user is not visible to current_user because they do not belong to any project.
+ assert_equal [visible_user, current_user], issue.reaction_detail.visible_users
+ end
+
+ test 'preload_reaction_details does nothing when the reaction feature is disabled' do
+ Setting.reactions_enabled = '0'
+
+ User.current = users(:users_002)
+ news1 = news(:news_001)
+
+ # Stub the Setting to avoid executing queries for retrieving settings,
+ # making it easier to confirm no queries are executed by preload_reaction_details().
+ Setting.stubs(:reactions_enabled?).returns(false)
+
+ assert_no_queries do
+ News.preload_reaction_details([news1])
+ end
+
+ assert_nil news1.instance_variable_get(:@reaction_detail)
+ end
+
+ test 'reaction_detail loads and returns ReactionDetail if it is not preloaded' do
+ message7 = messages(:messages_007)
+
+ User.current = users(:users_002)
+ assert_nil message7.instance_variable_get(:@reaction_detail)
+
+ assert_equal Reaction::Detail.new(
+ visible_users: [users(:users_002)],
+ user_reaction: reactions(:reaction_009)
+ ), message7.reaction_detail
+ end
+
+ test 'load_reaction_detail loads ReactionDetail for the object itself' do
+ comment1 = comments(:comments_001)
+
+ User.current = users(:users_001)
+ assert_nil comment1.instance_variable_get(:@reaction_detail)
+
+ comment1.load_reaction_detail
+
+ assert_equal Reaction::Detail.new(
+ visible_users: [users(:users_002)],
+ user_reaction: nil
+ ), comment1.reaction_detail
+ end
+
+ test 'visible? returns true when reactions are enabled and object is visible to user' do
+ object = issues(:issues_007)
+ user = users(:users_002)
+
+ assert Redmine::Reaction.visible?(object, user)
+ end
+
+ test 'visible? returns false when reactions are disabled' do
+ Setting.reactions_enabled = '0'
+
+ object = issues(:issues_007)
+ user = users(:users_002)
+
+ assert_not Redmine::Reaction.visible?(object, user)
+ end
+
+ test 'visible? returns false when object is not visible to user' do
+ object = issues(:issues_007)
+ user = users(:users_002)
+
+ object.expects(:visible?).with(user).returns(false)
+
+ assert_not Redmine::Reaction.visible?(object, user)
+ end
+
+ test 'editable? returns true for various reactable objects when user is logged in, object is visible, and project is active' do
+ reactable_objects = {
+ issue: issues(:issues_007),
+ message: messages(:messages_001),
+ news: news(:news_001),
+ journal: journals(:journals_001),
+ comment: comments(:comments_002)
+ }
+ user = users(:users_002)
+
+ reactable_objects.each do |type, object|
+ assert Redmine::Reaction.editable?(object, user), "Expected editable? to return true for #{type}"
+ end
+ end
+
+ test 'editable? returns false when user is not logged in' do
+ object = issues(:issues_007)
+ user = User.anonymous
+
+ assert_not Redmine::Reaction.editable?(object, user)
+ end
+
+ test 'editable? returns false when project is inactive' do
+ object = issues(:issues_007)
+ user = users(:users_002)
+ object.project.update!(status: Project::STATUS_ARCHIVED)
+
+ assert_not Redmine::Reaction.editable?(object, user)
+ end
+
+ test 'editable? returns false when project is closed' do
+ object = issues(:issues_007)
+ user = users(:users_002)
+ object.project.update!(status: Project::STATUS_CLOSED)
+
+ assert_not Redmine::Reaction.editable?(object, user)
+ 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
index 11d5913ce..bb0c5d450 100644
--- a/test/unit/lib/redmine/wiki_formatting/common_mark/formatter_test.rb
+++ b/test/unit/lib/redmine/wiki_formatting/common_mark/formatter_test.rb
@@ -163,39 +163,39 @@ class Redmine::WikiFormatting::CommonMark::FormatterTest < ActionView::TestCase
# 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
]
@@ -226,7 +226,7 @@ class Redmine::WikiFormatting::CommonMark::FormatterTest < ActionView::TestCase
text = STR_WITH_PRE.join("\n\n")
replacement = "New text"
- assert_equal [STR_WITH_PRE[0..1], "New text"].flatten.join("\n\n"),
+ assert_equal [STR_WITH_PRE[0..1], "New text"].join("\n\n"),
@formatter.new(text).update_section(3, replacement)
end
@@ -287,7 +287,7 @@ class Redmine::WikiFormatting::CommonMark::FormatterTest < ActionView::TestCase
expected = <<~EXPECTED
<p>Task list:</p>
- <ul class="task-list">
+ <ul class="contains-task-list">
<li class="task-list-item">
<input type="checkbox" class="task-list-item-checkbox" disabled> Task 1
</li>
@@ -299,6 +299,49 @@ class Redmine::WikiFormatting::CommonMark::FormatterTest < ActionView::TestCase
assert_equal expected.gsub(%r{[\r\n\t]}, ''), to_html(text).gsub(%r{[\r\n\t]}, '').rstrip
end
+ def test_should_render_alert_blocks
+ text = <<~MD
+ > [!note]
+ > This is a note.
+
+ > [!tip]
+ > This is a tip.
+
+ > [!warning]
+ > This is a warning.
+
+ > [!caution]
+ > This is a caution.
+
+ > [!important]
+ > This is a important.
+ MD
+
+ html = to_html(text)
+ %w[note tip warning caution important].each do |alert|
+ icon = Redmine::WikiFormatting::CommonMark::ALERT_TYPE_TO_ICON_NAME[alert]
+ # rubocop:disable Layout/LineLength
+ expected = %r{<div class="markdown-alert markdown-alert-#{alert}">\n<p class="markdown-alert-title"><svg class="s18 icon-svg" aria-hidden="true"><use href="/assets/icons-\w+.svg\#icon--#{icon}"></use></svg><span class="icon-label">#{alert.capitalize}</span></p>\n<p>This is a #{alert}.</p>\n</div>}
+ # rubocop:enable Layout/LineLength
+ assert_match expected, html
+ end
+ end
+
+ def test_should_not_render_unknown_alert_type
+ text = <<~MD
+ > [!unknown]
+ > This should not become an alert.
+ MD
+
+ html = to_html(text)
+
+ assert_include "<blockquote>", html
+ assert_include "[!unknown]", html
+ assert_include "This should not become an alert.", html
+
+ assert_not_include 'markdown-alert', html
+ end
+
private
def assert_section_with_hash(expected, text, index)
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
index 4c0282f2d..b2d19eab9 100644
--- 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
@@ -47,10 +47,14 @@ if Object.const_defined?(:Commonmarker)
end
def test_should_support_footnotes
- input = %(<a href="#fn-1" id="fnref-1">foo</a>)
- assert_equal input, filter(input)
- input = %(<ol><li id="fn-1">footnote</li></ol>)
- assert_equal input, filter(input)
+ [
+ %(<a href="#fn-1" id="fnref-1">foo</a>),
+ %(<a href="#fn-1" id="fnref-1-2">foo</a>),
+ %(<ol><li id="fn-1">footnote</li></ol>),
+ ].each do |input|
+ assert_equal input, filter(input)
+ assert_equal input, filter(input)
+ end
end
def test_should_remove_invalid_ids
@@ -71,6 +75,32 @@ if Object.const_defined?(:Commonmarker)
assert_equal %(<code>foo</code>), filter(input)
end
+ def test_should_allow_valid_alert_div_and_p_classes
+ html = <<~HTML
+ <div class="markdown-alert markdown-alert-tip">
+ <p class="markdown-alert-title">Tip</p>
+ <p>Useful tip.</p>
+ </div>
+ HTML
+
+ sanitized = filter(html)
+
+ assert_include 'class="markdown-alert markdown-alert-tip"', sanitized
+ assert_include 'class="markdown-alert-title"', sanitized
+ end
+
+ def test_should_remove_invalid_div_class
+ html = '<div class="bad-class">Text</div>'
+ sanitized = filter(html)
+ assert_not_includes 'bad-class', sanitized
+ end
+
+ def test_should_remove_invalid_p_class
+ html = '<p class="bad-class">Text</p>'
+ sanitized = filter(html)
+ assert_not_include 'bad-class', sanitized
+ end
+
def test_should_allow_links_with_safe_url_schemes
%w(http https ftp ssh foo).each do |scheme|
input = %(<a href="#{scheme}://example.org/">foo</a>)
diff --git a/test/unit/lib/redmine/wiki_formatting/html_sanitizer_test.rb b/test/unit/lib/redmine/wiki_formatting/html_sanitizer_test.rb
index 11dddb5f8..f8793cf9f 100644
--- a/test/unit/lib/redmine/wiki_formatting/html_sanitizer_test.rb
+++ b/test/unit/lib/redmine/wiki_formatting/html_sanitizer_test.rb
@@ -35,4 +35,24 @@ class Redmine::WikiFormatting::HtmlSanitizerTest < ActiveSupport::TestCase
input = %(<a href="javascript:alert('hello');">foo</a>)
assert_equal "<a>foo</a>", @sanitizer.call(input)
end
+
+ def test_should_be_strict_with_task_list_items
+ to_test = {
+ %(<input type="checkbox" class="">) => "",
+ %(<input type="checkbox" class="task-list-item-checkbox other">) => "",
+ %(<input type="checkbox" class="task-list-item-checkbox" id="item1">) => %(<input type="checkbox" class="task-list-item-checkbox">),
+ %(<input type="text" class="">) => "",
+ %(<input />) => "",
+ %(<ul class="other"></ul) => "<ul></ul>",
+ %(<ul class="contains-task-list"></ul) => "<ul class=\"contains-task-list\"></ul>",
+ %(<ul class="contains-task-list" id="list1"></ul) => "<ul class=\"contains-task-list\"></ul>",
+ %(<li class="other"></li>) => "",
+ %(<li id="other"></li>) => "",
+ %(<li class="task-list-item"></li>) => "",
+ %(<li class="task-list-item">Item 1</li>) => "Item 1",
+ }
+ to_test.each do |input, result|
+ assert_equal result, @sanitizer.call(input)
+ end
+ end
end
diff --git a/test/unit/lib/redmine/wiki_formatting/textile_formatter_test.rb b/test/unit/lib/redmine/wiki_formatting/textile_formatter_test.rb
index 32280cfdf..678d4c6b2 100644
--- a/test/unit/lib/redmine/wiki_formatting/textile_formatter_test.rb
+++ b/test/unit/lib/redmine/wiki_formatting/textile_formatter_test.rb
@@ -466,19 +466,19 @@ class Redmine::WikiFormatting::TextileFormatterTest < ActionView::TestCase
replacement = "New text"
assert_equal(
- [STR_WITHOUT_PRE[0], replacement, STR_WITHOUT_PRE[2..4]].flatten.join("\n\n"),
+ [STR_WITHOUT_PRE[0], replacement, STR_WITHOUT_PRE[2..4]].join("\n\n"),
@formatter.new(TEXT_WITHOUT_PRE).update_section(2, replacement)
)
assert_equal(
- [STR_WITHOUT_PRE[0..1], replacement, STR_WITHOUT_PRE[4]].flatten.join("\n\n"),
+ [STR_WITHOUT_PRE[0..1], replacement, STR_WITHOUT_PRE[4]].join("\n\n"),
@formatter.new(TEXT_WITHOUT_PRE).update_section(3, replacement)
)
assert_equal(
- [STR_WITHOUT_PRE[0..2], replacement, STR_WITHOUT_PRE[4]].flatten.join("\n\n"),
+ [STR_WITHOUT_PRE[0..2], replacement, STR_WITHOUT_PRE[4]].join("\n\n"),
@formatter.new(TEXT_WITHOUT_PRE).update_section(5, replacement)
)
assert_equal(
- [STR_WITHOUT_PRE[0..3], replacement].flatten.join("\n\n"),
+ [STR_WITHOUT_PRE[0..3], replacement].join("\n\n"),
@formatter.new(TEXT_WITHOUT_PRE).update_section(6, replacement)
)
assert_equal TEXT_WITHOUT_PRE, @formatter.new(TEXT_WITHOUT_PRE).update_section(0, replacement)
@@ -488,7 +488,7 @@ class Redmine::WikiFormatting::TextileFormatterTest < ActionView::TestCase
def test_update_section_with_hash_should_update_the_requested_section
replacement = "New text"
assert_equal(
- [STR_WITHOUT_PRE[0], replacement, STR_WITHOUT_PRE[2..4]].flatten.join("\n\n"),
+ [STR_WITHOUT_PRE[0], replacement, STR_WITHOUT_PRE[2..4]].join("\n\n"),
@formatter.new(TEXT_WITHOUT_PRE).
update_section(2, replacement, ActiveSupport::Digest.hexdigest(STR_WITHOUT_PRE[1]))
)
@@ -552,7 +552,7 @@ class Redmine::WikiFormatting::TextileFormatterTest < ActionView::TestCase
text = STR_WITH_PRE.join("\n\n")
replacement = "New text"
assert_equal(
- [STR_WITH_PRE[0..1], "New text"].flatten.join("\n\n"),
+ [STR_WITH_PRE[0..1], "New text"].join("\n\n"),
@formatter.new(text).update_section(3, replacement)
)
end