# Redmine - project management software # Copyright (C) 2006-2009 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.dirname(__FILE__) + '/../../test_helper' class ApplicationHelperTest < HelperTestCase include ApplicationHelper include ActionView::Helpers::TextHelper include ActionView::Helpers::DateHelper fixtures :projects, :roles, :enabled_modules, :users, :repositories, :changesets, :trackers, :issue_statuses, :issues, :versions, :documents, :wikis, :wiki_pages, :wiki_contents, :boards, :messages, :attachments, :enumerations def setup super end def test_auto_links to_test = { 'http://foo.bar' => 'http://foo.bar', 'http://foo.bar/~user' => 'http://foo.bar/~user', 'http://foo.bar.' => 'http://foo.bar.', 'https://foo.bar.' => 'https://foo.bar.', 'This is a link: http://foo.bar.' => 'This is a link: http://foo.bar.', 'A link (eg. http://foo.bar).' => 'A link (eg. http://foo.bar).', 'http://foo.bar/foo.bar#foo.bar.' => 'http://foo.bar/foo.bar#foo.bar.', 'http://www.foo.bar/Test_(foobar)' => 'http://www.foo.bar/Test_(foobar)', '(see inline link : http://www.foo.bar/Test_(foobar))' => '(see inline link : http://www.foo.bar/Test_(foobar))', '(see inline link : http://www.foo.bar/Test)' => '(see inline link : http://www.foo.bar/Test)', '(see inline link : http://www.foo.bar/Test).' => '(see inline link : http://www.foo.bar/Test).', '(see "inline link":http://www.foo.bar/Test_(foobar))' => '(see inline link)', '(see "inline link":http://www.foo.bar/Test)' => '(see inline link)', '(see "inline link":http://www.foo.bar/Test).' => '(see inline link).', 'www.foo.bar' => 'www.foo.bar', 'http://foo.bar/page?p=1&t=z&s=' => 'http://foo.bar/page?p=1&t=z&s=', 'http://foo.bar/page#125' => 'http://foo.bar/page#125', 'http://foo@www.bar.com' => 'http://foo@www.bar.com', 'http://foo:bar@www.bar.com' => 'http://foo:bar@www.bar.com', 'ftp://foo.bar' => 'ftp://foo.bar', 'ftps://foo.bar' => 'ftps://foo.bar', 'sftp://foo.bar' => 'sftp://foo.bar', # two exclamation marks 'http://example.net/path!602815048C7B5C20!302.html' => 'http://example.net/path!602815048C7B5C20!302.html', # escaping 'http://foo"bar' => 'http://foo"bar', } to_test.each { |text, result| assert_equal "
#{result}
", textilizable(text) } end def test_auto_mailto assert_equal '', textilizable('test@foo.bar') end def test_inline_images to_test = { '!http://foo.bar/image.jpg!' => '', 'floating !>http://foo.bar/image.jpg!' => 'floating ', 'with class !(some-class)http://foo.bar/image.jpg!' => 'with class ', # inline styles should be stripped 'with style !{width:100px;height100px}http://foo.bar/image.jpg!' => 'with style ', 'with title !http://foo.bar/image.jpg(This is a title)!' => 'with title ', 'with title !http://foo.bar/image.jpg(This is a double-quoted "title")!' => 'with title ', } to_test.each { |text, result| assert_equal "#{result}
", textilizable(text) } end def test_inline_images_inside_tags raw = <<-RAW h1. !foo.png! Heading Centered image: p=. !bar.gif! RAW assert textilizable(raw).include?('') assert textilizable(raw).include?('') end def test_acronyms to_test = { 'this is an acronym: GPL(General Public License)' => 'this is an acronym: GPL', 'GPL(This is a double-quoted "title")' => 'GPL', } to_test.each { |text, result| assert_equal "#{result}
", textilizable(text) } end def test_attached_images to_test = { 'Inline image: !logo.gif!' => 'Inline image: ', 'Inline image: !logo.GIF!' => 'Inline image: ', 'No match: !ogo.gif!' => 'No match: ', 'No match: !ogo.GIF!' => 'No match: ', # link image '!logo.gif!:http://foo.bar/' => '', } attachments = Attachment.find(:all) to_test.each { |text, result| assert_equal "#{result}
", textilizable(text, :attachments => attachments) } end def test_textile_external_links to_test = { 'This is a "link":http://foo.bar' => 'This is a link', 'This is an intern "link":/foo/bar' => 'This is an intern link', '"link (Link title)":http://foo.bar' => 'link', '"link (Link title with "double-quotes")":http://foo.bar' => 'link', "This is not a \"Link\":\n\nAnother paragraph" => "This is not a \"Link\":\n\n\n\tAnother paragraph",
# no multiline link text
"This is a double quote \"on the first line\nand another on a second line\":test" => "This is a double quote \"on the first line
and another on a second line\":test",
# mailto link
"\"system administrator\":mailto:sysadmin@example.com?subject=redmine%20permissions" => "system administrator",
# two exclamation marks
'"a link":http://example.net/path!602815048C7B5C20!302.html' => 'a link',
# escaping
'"test":http://foo"bar' => 'test',
}
to_test.each { |text, result| assert_equal "
#{result}
", textilizable(text) } end def test_redmine_links issue_link = link_to('#3', {:controller => 'issues', :action => 'show', :id => 3}, :class => 'issue status-1 priority-1 overdue', :title => 'Error 281 when updating a recipe (New)') changeset_link = link_to('r1', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 1}, :class => 'changeset', :title => 'My very first commit') changeset_link2 = link_to('r2', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 2}, :class => 'changeset', :title => 'This commit fixes #1, #2 and references #1 & #3') document_link = link_to('Test document', {:controller => 'documents', :action => 'show', :id => 1}, :class => 'document') version_link = link_to('1.0', {:controller => 'versions', :action => 'show', :id => 2}, :class => 'version') message_url = {:controller => 'messages', :action => 'show', :board_id => 1, :id => 4} project_url = {:controller => 'projects', :action => 'show', :id => 'subproject1'} source_url = {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :path => ['some', 'file']} source_url_with_ext = {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :path => ['some', 'file.ext']} to_test = { # tickets '#3, [#3], (#3) and #3.' => "#{issue_link}, [#{issue_link}], (#{issue_link}) and #{issue_link}.", # changesets 'r1' => changeset_link, 'r1.' => "#{changeset_link}.", 'r1, r2' => "#{changeset_link}, #{changeset_link2}", 'r1,r2' => "#{changeset_link},#{changeset_link2}", # documents 'document#1' => document_link, 'document:"Test document"' => document_link, # versions 'version#2' => version_link, 'version:1.0' => version_link, 'version:"1.0"' => version_link, # source 'source:/some/file' => link_to('source:/some/file', source_url, :class => 'source'), 'source:/some/file.' => link_to('source:/some/file', source_url, :class => 'source') + ".", 'source:/some/file.ext.' => link_to('source:/some/file.ext', source_url_with_ext, :class => 'source') + ".", 'source:/some/file. ' => link_to('source:/some/file', source_url, :class => 'source') + ".", 'source:/some/file.ext. ' => link_to('source:/some/file.ext', source_url_with_ext, :class => 'source') + ".", 'source:/some/file, ' => link_to('source:/some/file', source_url, :class => 'source') + ",", 'source:/some/file@52' => link_to('source:/some/file@52', source_url.merge(:rev => 52), :class => 'source'), 'source:/some/file.ext@52' => link_to('source:/some/file.ext@52', source_url_with_ext.merge(:rev => 52), :class => 'source'), 'source:/some/file#L110' => link_to('source:/some/file#L110', source_url.merge(:anchor => 'L110'), :class => 'source'), 'source:/some/file.ext#L110' => link_to('source:/some/file.ext#L110', source_url_with_ext.merge(:anchor => 'L110'), :class => 'source'), 'source:/some/file@52#L110' => link_to('source:/some/file@52#L110', source_url.merge(:rev => 52, :anchor => 'L110'), :class => 'source'), 'export:/some/file' => link_to('export:/some/file', source_url.merge(:format => 'raw'), :class => 'source download'), # message 'message#4' => link_to('Post 2', message_url, :class => 'message'), 'message#5' => link_to('RE: post 2', message_url.merge(:anchor => 'message-5'), :class => 'message'), # project 'project#3' => link_to('eCookbook Subproject 1', project_url, :class => 'project'), 'project:subproject1' => link_to('eCookbook Subproject 1', project_url, :class => 'project'), 'project:"eCookbook subProject 1"' => link_to('eCookbook Subproject 1', project_url, :class => 'project'), # escaping '!#3.' => '#3.', '!r1' => 'r1', '!document#1' => 'document#1', '!document:"Test document"' => 'document:"Test document"', '!version#2' => 'version#2', '!version:1.0' => 'version:1.0', '!version:"1.0"' => 'version:"1.0"', '!source:/some/file' => 'source:/some/file', # not found '#0123456789' => '#0123456789', # invalid expressions 'source:' => 'source:', # url hash "http://foo.bar/FAQ#3" => 'http://foo.bar/FAQ#3', } @project = Project.find(1) to_test.each { |text, result| assert_equal "#{result}
", textilizable(text), "#{text} failed" } end def test_attachment_links attachment_link = link_to('error281.txt', {:controller => 'attachments', :action => 'download', :id => '1'}, :class => 'attachment') to_test = { 'attachment:error281.txt' => attachment_link } to_test.each { |text, result| assert_equal "#{result}
", textilizable(text, :attachments => Issue.find(3).attachments), "#{text} failed" } end def test_wiki_links to_test = { '[[CookBook documentation]]' => 'CookBook documentation', '[[Another page|Page]]' => 'Page', # link with anchor '[[CookBook documentation#One-section]]' => 'CookBook documentation', '[[Another page#anchor|Page]]' => 'Page', # page that doesn't exist '[[Unknown page]]' => 'Unknown page', '[[Unknown page|404]]' => '404', # link to another project wiki '[[onlinestore:]]' => 'onlinestore', '[[onlinestore:|Wiki]]' => 'Wiki', '[[onlinestore:Start page]]' => 'Start page', '[[onlinestore:Start page|Text]]' => 'Text', '[[onlinestore:Unknown page]]' => 'Unknown page', # striked through link '-[[Another page|Page]]-' => '#{result}
", textilizable(text) } end def test_html_tags to_test = { "<div>content</div>
", "<div class=\"bold\">content</div>
", "" => "<script>some script;</script>
", # do not escape pre/code tags "\nline 1\nline2" => "
\nline 1\nline2", "
\nline 1\nline2
" => "\nline 1\nline2
",
"" => "content
<div>content</div>", "HTML comment: " => "
HTML comment: <!-- no comments -->
", "