##// END OF EJS Templates
Redcarpet not available with jruby (#19313)....
Jean-Philippe Lang -
r13723:c7510519e2fc
parent child
Show More
@@ -1,1533 +1,1535
1 # encoding: utf-8
1 # encoding: utf-8
2 #
2 #
3 # Redmine - project management software
3 # Redmine - project management software
4 # Copyright (C) 2006-2015 Jean-Philippe Lang
4 # Copyright (C) 2006-2015 Jean-Philippe Lang
5 #
5 #
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
9 # of the License, or (at your option) any later version.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
19
20 require File.expand_path('../../../test_helper', __FILE__)
20 require File.expand_path('../../../test_helper', __FILE__)
21
21
22 class ApplicationHelperTest < ActionView::TestCase
22 class ApplicationHelperTest < ActionView::TestCase
23 include Redmine::I18n
23 include Redmine::I18n
24 include ERB::Util
24 include ERB::Util
25 include Rails.application.routes.url_helpers
25 include Rails.application.routes.url_helpers
26
26
27 fixtures :projects, :roles, :enabled_modules, :users,
27 fixtures :projects, :roles, :enabled_modules, :users,
28 :repositories, :changesets,
28 :repositories, :changesets,
29 :projects_trackers,
29 :projects_trackers,
30 :trackers, :issue_statuses, :issues, :versions, :documents,
30 :trackers, :issue_statuses, :issues, :versions, :documents,
31 :wikis, :wiki_pages, :wiki_contents,
31 :wikis, :wiki_pages, :wiki_contents,
32 :boards, :messages, :news,
32 :boards, :messages, :news,
33 :attachments, :enumerations
33 :attachments, :enumerations
34
34
35 def setup
35 def setup
36 super
36 super
37 set_tmp_attachments_directory
37 set_tmp_attachments_directory
38 @russian_test = "\xd1\x82\xd0\xb5\xd1\x81\xd1\x82"
38 @russian_test = "\xd1\x82\xd0\xb5\xd1\x81\xd1\x82"
39 if @russian_test.respond_to?(:force_encoding)
39 if @russian_test.respond_to?(:force_encoding)
40 @russian_test.force_encoding('UTF-8')
40 @russian_test.force_encoding('UTF-8')
41 end
41 end
42 end
42 end
43
43
44 test "#link_to_if_authorized for authorized user should allow using the :controller and :action for the target link" do
44 test "#link_to_if_authorized for authorized user should allow using the :controller and :action for the target link" do
45 User.current = User.find_by_login('admin')
45 User.current = User.find_by_login('admin')
46
46
47 @project = Issue.first.project # Used by helper
47 @project = Issue.first.project # Used by helper
48 response = link_to_if_authorized('By controller/actionr',
48 response = link_to_if_authorized('By controller/actionr',
49 {:controller => 'issues', :action => 'edit', :id => Issue.first.id})
49 {:controller => 'issues', :action => 'edit', :id => Issue.first.id})
50 assert_match /href/, response
50 assert_match /href/, response
51 end
51 end
52
52
53 test "#link_to_if_authorized for unauthorized user should display nothing if user isn't authorized" do
53 test "#link_to_if_authorized for unauthorized user should display nothing if user isn't authorized" do
54 User.current = User.find_by_login('dlopper')
54 User.current = User.find_by_login('dlopper')
55 @project = Project.find('private-child')
55 @project = Project.find('private-child')
56 issue = @project.issues.first
56 issue = @project.issues.first
57 assert !issue.visible?
57 assert !issue.visible?
58
58
59 response = link_to_if_authorized('Never displayed',
59 response = link_to_if_authorized('Never displayed',
60 {:controller => 'issues', :action => 'show', :id => issue})
60 {:controller => 'issues', :action => 'show', :id => issue})
61 assert_nil response
61 assert_nil response
62 end
62 end
63
63
64 def test_auto_links
64 def test_auto_links
65 to_test = {
65 to_test = {
66 'http://foo.bar' => '<a class="external" href="http://foo.bar">http://foo.bar</a>',
66 'http://foo.bar' => '<a class="external" href="http://foo.bar">http://foo.bar</a>',
67 'http://foo.bar/~user' => '<a class="external" href="http://foo.bar/~user">http://foo.bar/~user</a>',
67 'http://foo.bar/~user' => '<a class="external" href="http://foo.bar/~user">http://foo.bar/~user</a>',
68 'http://foo.bar.' => '<a class="external" href="http://foo.bar">http://foo.bar</a>.',
68 'http://foo.bar.' => '<a class="external" href="http://foo.bar">http://foo.bar</a>.',
69 'https://foo.bar.' => '<a class="external" href="https://foo.bar">https://foo.bar</a>.',
69 'https://foo.bar.' => '<a class="external" href="https://foo.bar">https://foo.bar</a>.',
70 'This is a link: http://foo.bar.' => 'This is a link: <a class="external" href="http://foo.bar">http://foo.bar</a>.',
70 'This is a link: http://foo.bar.' => 'This is a link: <a class="external" href="http://foo.bar">http://foo.bar</a>.',
71 'A link (eg. http://foo.bar).' => 'A link (eg. <a class="external" href="http://foo.bar">http://foo.bar</a>).',
71 'A link (eg. http://foo.bar).' => 'A link (eg. <a class="external" href="http://foo.bar">http://foo.bar</a>).',
72 'http://foo.bar/foo.bar#foo.bar.' => '<a class="external" href="http://foo.bar/foo.bar#foo.bar">http://foo.bar/foo.bar#foo.bar</a>.',
72 'http://foo.bar/foo.bar#foo.bar.' => '<a class="external" href="http://foo.bar/foo.bar#foo.bar">http://foo.bar/foo.bar#foo.bar</a>.',
73 'http://www.foo.bar/Test_(foobar)' => '<a class="external" href="http://www.foo.bar/Test_(foobar)">http://www.foo.bar/Test_(foobar)</a>',
73 'http://www.foo.bar/Test_(foobar)' => '<a class="external" href="http://www.foo.bar/Test_(foobar)">http://www.foo.bar/Test_(foobar)</a>',
74 '(see inline link : http://www.foo.bar/Test_(foobar))' => '(see inline link : <a class="external" href="http://www.foo.bar/Test_(foobar)">http://www.foo.bar/Test_(foobar)</a>)',
74 '(see inline link : http://www.foo.bar/Test_(foobar))' => '(see inline link : <a class="external" href="http://www.foo.bar/Test_(foobar)">http://www.foo.bar/Test_(foobar)</a>)',
75 '(see inline link : http://www.foo.bar/Test)' => '(see inline link : <a class="external" href="http://www.foo.bar/Test">http://www.foo.bar/Test</a>)',
75 '(see inline link : http://www.foo.bar/Test)' => '(see inline link : <a class="external" href="http://www.foo.bar/Test">http://www.foo.bar/Test</a>)',
76 '(see inline link : http://www.foo.bar/Test).' => '(see inline link : <a class="external" href="http://www.foo.bar/Test">http://www.foo.bar/Test</a>).',
76 '(see inline link : http://www.foo.bar/Test).' => '(see inline link : <a class="external" href="http://www.foo.bar/Test">http://www.foo.bar/Test</a>).',
77 '(see "inline link":http://www.foo.bar/Test_(foobar))' => '(see <a href="http://www.foo.bar/Test_(foobar)" class="external">inline link</a>)',
77 '(see "inline link":http://www.foo.bar/Test_(foobar))' => '(see <a href="http://www.foo.bar/Test_(foobar)" class="external">inline link</a>)',
78 '(see "inline link":http://www.foo.bar/Test)' => '(see <a href="http://www.foo.bar/Test" class="external">inline link</a>)',
78 '(see "inline link":http://www.foo.bar/Test)' => '(see <a href="http://www.foo.bar/Test" class="external">inline link</a>)',
79 '(see "inline link":http://www.foo.bar/Test).' => '(see <a href="http://www.foo.bar/Test" class="external">inline link</a>).',
79 '(see "inline link":http://www.foo.bar/Test).' => '(see <a href="http://www.foo.bar/Test" class="external">inline link</a>).',
80 'www.foo.bar' => '<a class="external" href="http://www.foo.bar">www.foo.bar</a>',
80 'www.foo.bar' => '<a class="external" href="http://www.foo.bar">www.foo.bar</a>',
81 'http://foo.bar/page?p=1&t=z&s=' => '<a class="external" href="http://foo.bar/page?p=1&#38;t=z&#38;s=">http://foo.bar/page?p=1&#38;t=z&#38;s=</a>',
81 'http://foo.bar/page?p=1&t=z&s=' => '<a class="external" href="http://foo.bar/page?p=1&#38;t=z&#38;s=">http://foo.bar/page?p=1&#38;t=z&#38;s=</a>',
82 'http://foo.bar/page#125' => '<a class="external" href="http://foo.bar/page#125">http://foo.bar/page#125</a>',
82 'http://foo.bar/page#125' => '<a class="external" href="http://foo.bar/page#125">http://foo.bar/page#125</a>',
83 'http://foo@www.bar.com' => '<a class="external" href="http://foo@www.bar.com">http://foo@www.bar.com</a>',
83 'http://foo@www.bar.com' => '<a class="external" href="http://foo@www.bar.com">http://foo@www.bar.com</a>',
84 'http://foo:bar@www.bar.com' => '<a class="external" href="http://foo:bar@www.bar.com">http://foo:bar@www.bar.com</a>',
84 'http://foo:bar@www.bar.com' => '<a class="external" href="http://foo:bar@www.bar.com">http://foo:bar@www.bar.com</a>',
85 'ftp://foo.bar' => '<a class="external" href="ftp://foo.bar">ftp://foo.bar</a>',
85 'ftp://foo.bar' => '<a class="external" href="ftp://foo.bar">ftp://foo.bar</a>',
86 'ftps://foo.bar' => '<a class="external" href="ftps://foo.bar">ftps://foo.bar</a>',
86 'ftps://foo.bar' => '<a class="external" href="ftps://foo.bar">ftps://foo.bar</a>',
87 'sftp://foo.bar' => '<a class="external" href="sftp://foo.bar">sftp://foo.bar</a>',
87 'sftp://foo.bar' => '<a class="external" href="sftp://foo.bar">sftp://foo.bar</a>',
88 # two exclamation marks
88 # two exclamation marks
89 'http://example.net/path!602815048C7B5C20!302.html' => '<a class="external" href="http://example.net/path!602815048C7B5C20!302.html">http://example.net/path!602815048C7B5C20!302.html</a>',
89 'http://example.net/path!602815048C7B5C20!302.html' => '<a class="external" href="http://example.net/path!602815048C7B5C20!302.html">http://example.net/path!602815048C7B5C20!302.html</a>',
90 # escaping
90 # escaping
91 'http://foo"bar' => '<a class="external" href="http://foo&quot;bar">http://foo&quot;bar</a>',
91 'http://foo"bar' => '<a class="external" href="http://foo&quot;bar">http://foo&quot;bar</a>',
92 # wrap in angle brackets
92 # wrap in angle brackets
93 '<http://foo.bar>' => '&lt;<a class="external" href="http://foo.bar">http://foo.bar</a>&gt;',
93 '<http://foo.bar>' => '&lt;<a class="external" href="http://foo.bar">http://foo.bar</a>&gt;',
94 # invalid urls
94 # invalid urls
95 'http://' => 'http://',
95 'http://' => 'http://',
96 'www.' => 'www.',
96 'www.' => 'www.',
97 'test-www.bar.com' => 'test-www.bar.com',
97 'test-www.bar.com' => 'test-www.bar.com',
98 }
98 }
99 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
99 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
100 end
100 end
101
101
102 if 'ruby'.respond_to?(:encoding)
102 if 'ruby'.respond_to?(:encoding)
103 def test_auto_links_with_non_ascii_characters
103 def test_auto_links_with_non_ascii_characters
104 to_test = {
104 to_test = {
105 "http://foo.bar/#{@russian_test}" =>
105 "http://foo.bar/#{@russian_test}" =>
106 %|<a class="external" href="http://foo.bar/#{@russian_test}">http://foo.bar/#{@russian_test}</a>|
106 %|<a class="external" href="http://foo.bar/#{@russian_test}">http://foo.bar/#{@russian_test}</a>|
107 }
107 }
108 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
108 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
109 end
109 end
110 else
110 else
111 puts 'Skipping test_auto_links_with_non_ascii_characters, unsupported ruby version'
111 puts 'Skipping test_auto_links_with_non_ascii_characters, unsupported ruby version'
112 end
112 end
113
113
114 def test_auto_mailto
114 def test_auto_mailto
115 to_test = {
115 to_test = {
116 'test@foo.bar' => '<a class="email" href="mailto:test@foo.bar">test@foo.bar</a>',
116 'test@foo.bar' => '<a class="email" href="mailto:test@foo.bar">test@foo.bar</a>',
117 'test@www.foo.bar' => '<a class="email" href="mailto:test@www.foo.bar">test@www.foo.bar</a>',
117 'test@www.foo.bar' => '<a class="email" href="mailto:test@www.foo.bar">test@www.foo.bar</a>',
118 }
118 }
119 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
119 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
120 end
120 end
121
121
122 def test_inline_images
122 def test_inline_images
123 to_test = {
123 to_test = {
124 '!http://foo.bar/image.jpg!' => '<img src="http://foo.bar/image.jpg" alt="" />',
124 '!http://foo.bar/image.jpg!' => '<img src="http://foo.bar/image.jpg" alt="" />',
125 'floating !>http://foo.bar/image.jpg!' => 'floating <div style="float:right"><img src="http://foo.bar/image.jpg" alt="" /></div>',
125 'floating !>http://foo.bar/image.jpg!' => 'floating <div style="float:right"><img src="http://foo.bar/image.jpg" alt="" /></div>',
126 'with class !(some-class)http://foo.bar/image.jpg!' => 'with class <img src="http://foo.bar/image.jpg" class="some-class" alt="" />',
126 'with class !(some-class)http://foo.bar/image.jpg!' => 'with class <img src="http://foo.bar/image.jpg" class="some-class" alt="" />',
127 'with style !{width:100px;height:100px}http://foo.bar/image.jpg!' => 'with style <img src="http://foo.bar/image.jpg" style="width:100px;height:100px;" alt="" />',
127 'with style !{width:100px;height:100px}http://foo.bar/image.jpg!' => 'with style <img src="http://foo.bar/image.jpg" style="width:100px;height:100px;" alt="" />',
128 'with title !http://foo.bar/image.jpg(This is a title)!' => 'with title <img src="http://foo.bar/image.jpg" title="This is a title" alt="This is a title" />',
128 'with title !http://foo.bar/image.jpg(This is a title)!' => 'with title <img src="http://foo.bar/image.jpg" title="This is a title" alt="This is a title" />',
129 'with title !http://foo.bar/image.jpg(This is a double-quoted "title")!' => 'with title <img src="http://foo.bar/image.jpg" title="This is a double-quoted &quot;title&quot;" alt="This is a double-quoted &quot;title&quot;" />',
129 'with title !http://foo.bar/image.jpg(This is a double-quoted "title")!' => 'with title <img src="http://foo.bar/image.jpg" title="This is a double-quoted &quot;title&quot;" alt="This is a double-quoted &quot;title&quot;" />',
130 }
130 }
131 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
131 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
132 end
132 end
133
133
134 def test_inline_images_inside_tags
134 def test_inline_images_inside_tags
135 raw = <<-RAW
135 raw = <<-RAW
136 h1. !foo.png! Heading
136 h1. !foo.png! Heading
137
137
138 Centered image:
138 Centered image:
139
139
140 p=. !bar.gif!
140 p=. !bar.gif!
141 RAW
141 RAW
142
142
143 assert textilizable(raw).include?('<img src="foo.png" alt="" />')
143 assert textilizable(raw).include?('<img src="foo.png" alt="" />')
144 assert textilizable(raw).include?('<img src="bar.gif" alt="" />')
144 assert textilizable(raw).include?('<img src="bar.gif" alt="" />')
145 end
145 end
146
146
147 def test_attached_images
147 def test_attached_images
148 to_test = {
148 to_test = {
149 'Inline image: !logo.gif!' => 'Inline image: <img src="/attachments/download/3/logo.gif" title="This is a logo" alt="This is a logo" />',
149 'Inline image: !logo.gif!' => 'Inline image: <img src="/attachments/download/3/logo.gif" title="This is a logo" alt="This is a logo" />',
150 'Inline image: !logo.GIF!' => 'Inline image: <img src="/attachments/download/3/logo.gif" title="This is a logo" alt="This is a logo" />',
150 'Inline image: !logo.GIF!' => 'Inline image: <img src="/attachments/download/3/logo.gif" title="This is a logo" alt="This is a logo" />',
151 'No match: !ogo.gif!' => 'No match: <img src="ogo.gif" alt="" />',
151 'No match: !ogo.gif!' => 'No match: <img src="ogo.gif" alt="" />',
152 'No match: !ogo.GIF!' => 'No match: <img src="ogo.GIF" alt="" />',
152 'No match: !ogo.GIF!' => 'No match: <img src="ogo.GIF" alt="" />',
153 # link image
153 # link image
154 '!logo.gif!:http://foo.bar/' => '<a href="http://foo.bar/"><img src="/attachments/download/3/logo.gif" title="This is a logo" alt="This is a logo" /></a>',
154 '!logo.gif!:http://foo.bar/' => '<a href="http://foo.bar/"><img src="/attachments/download/3/logo.gif" title="This is a logo" alt="This is a logo" /></a>',
155 }
155 }
156 attachments = Attachment.all
156 attachments = Attachment.all
157 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text, :attachments => attachments) }
157 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text, :attachments => attachments) }
158 end
158 end
159
159
160 def test_attached_images_with_textile_and_non_ascii_filename
160 def test_attached_images_with_textile_and_non_ascii_filename
161 attachment = Attachment.generate!(:filename => 'cafΓ©.jpg')
161 attachment = Attachment.generate!(:filename => 'cafΓ©.jpg')
162 with_settings :text_formatting => 'textile' do
162 with_settings :text_formatting => 'textile' do
163 assert_include %(<img src="/attachments/download/#{attachment.id}/caf%C3%A9.jpg" alt="" />),
163 assert_include %(<img src="/attachments/download/#{attachment.id}/caf%C3%A9.jpg" alt="" />),
164 textilizable("!cafΓ©.jpg!)", :attachments => [attachment])
164 textilizable("!cafΓ©.jpg!)", :attachments => [attachment])
165 end
165 end
166 end
166 end
167
167
168 if Object.const_defined?(:Redcarpet)
168 def test_attached_images_with_markdown_and_non_ascii_filename
169 def test_attached_images_with_markdown_and_non_ascii_filename
169 attachment = Attachment.generate!(:filename => 'cafΓ©.jpg')
170 attachment = Attachment.generate!(:filename => 'cafΓ©.jpg')
170 with_settings :text_formatting => 'markdown' do
171 with_settings :text_formatting => 'markdown' do
171 assert_include %(<img src="/attachments/download/#{attachment.id}/caf%C3%A9.jpg" alt="">),
172 assert_include %(<img src="/attachments/download/#{attachment.id}/caf%C3%A9.jpg" alt="">),
172 textilizable("![](cafΓ©.jpg)", :attachments => [attachment])
173 textilizable("![](cafΓ©.jpg)", :attachments => [attachment])
173 end
174 end
174 end
175 end
176 end
175
177
176 def test_attached_images_filename_extension
178 def test_attached_images_filename_extension
177 set_tmp_attachments_directory
179 set_tmp_attachments_directory
178 a1 = Attachment.new(
180 a1 = Attachment.new(
179 :container => Issue.find(1),
181 :container => Issue.find(1),
180 :file => mock_file_with_options({:original_filename => "testtest.JPG"}),
182 :file => mock_file_with_options({:original_filename => "testtest.JPG"}),
181 :author => User.find(1))
183 :author => User.find(1))
182 assert a1.save
184 assert a1.save
183 assert_equal "testtest.JPG", a1.filename
185 assert_equal "testtest.JPG", a1.filename
184 assert_equal "image/jpeg", a1.content_type
186 assert_equal "image/jpeg", a1.content_type
185 assert a1.image?
187 assert a1.image?
186
188
187 a2 = Attachment.new(
189 a2 = Attachment.new(
188 :container => Issue.find(1),
190 :container => Issue.find(1),
189 :file => mock_file_with_options({:original_filename => "testtest.jpeg"}),
191 :file => mock_file_with_options({:original_filename => "testtest.jpeg"}),
190 :author => User.find(1))
192 :author => User.find(1))
191 assert a2.save
193 assert a2.save
192 assert_equal "testtest.jpeg", a2.filename
194 assert_equal "testtest.jpeg", a2.filename
193 assert_equal "image/jpeg", a2.content_type
195 assert_equal "image/jpeg", a2.content_type
194 assert a2.image?
196 assert a2.image?
195
197
196 a3 = Attachment.new(
198 a3 = Attachment.new(
197 :container => Issue.find(1),
199 :container => Issue.find(1),
198 :file => mock_file_with_options({:original_filename => "testtest.JPE"}),
200 :file => mock_file_with_options({:original_filename => "testtest.JPE"}),
199 :author => User.find(1))
201 :author => User.find(1))
200 assert a3.save
202 assert a3.save
201 assert_equal "testtest.JPE", a3.filename
203 assert_equal "testtest.JPE", a3.filename
202 assert_equal "image/jpeg", a3.content_type
204 assert_equal "image/jpeg", a3.content_type
203 assert a3.image?
205 assert a3.image?
204
206
205 a4 = Attachment.new(
207 a4 = Attachment.new(
206 :container => Issue.find(1),
208 :container => Issue.find(1),
207 :file => mock_file_with_options({:original_filename => "Testtest.BMP"}),
209 :file => mock_file_with_options({:original_filename => "Testtest.BMP"}),
208 :author => User.find(1))
210 :author => User.find(1))
209 assert a4.save
211 assert a4.save
210 assert_equal "Testtest.BMP", a4.filename
212 assert_equal "Testtest.BMP", a4.filename
211 assert_equal "image/x-ms-bmp", a4.content_type
213 assert_equal "image/x-ms-bmp", a4.content_type
212 assert a4.image?
214 assert a4.image?
213
215
214 to_test = {
216 to_test = {
215 'Inline image: !testtest.jpg!' =>
217 'Inline image: !testtest.jpg!' =>
216 'Inline image: <img src="/attachments/download/' + a1.id.to_s + '/testtest.JPG" alt="" />',
218 'Inline image: <img src="/attachments/download/' + a1.id.to_s + '/testtest.JPG" alt="" />',
217 'Inline image: !testtest.jpeg!' =>
219 'Inline image: !testtest.jpeg!' =>
218 'Inline image: <img src="/attachments/download/' + a2.id.to_s + '/testtest.jpeg" alt="" />',
220 'Inline image: <img src="/attachments/download/' + a2.id.to_s + '/testtest.jpeg" alt="" />',
219 'Inline image: !testtest.jpe!' =>
221 'Inline image: !testtest.jpe!' =>
220 'Inline image: <img src="/attachments/download/' + a3.id.to_s + '/testtest.JPE" alt="" />',
222 'Inline image: <img src="/attachments/download/' + a3.id.to_s + '/testtest.JPE" alt="" />',
221 'Inline image: !testtest.bmp!' =>
223 'Inline image: !testtest.bmp!' =>
222 'Inline image: <img src="/attachments/download/' + a4.id.to_s + '/Testtest.BMP" alt="" />',
224 'Inline image: <img src="/attachments/download/' + a4.id.to_s + '/Testtest.BMP" alt="" />',
223 }
225 }
224
226
225 attachments = [a1, a2, a3, a4]
227 attachments = [a1, a2, a3, a4]
226 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text, :attachments => attachments) }
228 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text, :attachments => attachments) }
227 end
229 end
228
230
229 def test_attached_images_should_read_later
231 def test_attached_images_should_read_later
230 set_fixtures_attachments_directory
232 set_fixtures_attachments_directory
231 a1 = Attachment.find(16)
233 a1 = Attachment.find(16)
232 assert_equal "testfile.png", a1.filename
234 assert_equal "testfile.png", a1.filename
233 assert a1.readable?
235 assert a1.readable?
234 assert (! a1.visible?(User.anonymous))
236 assert (! a1.visible?(User.anonymous))
235 assert a1.visible?(User.find(2))
237 assert a1.visible?(User.find(2))
236 a2 = Attachment.find(17)
238 a2 = Attachment.find(17)
237 assert_equal "testfile.PNG", a2.filename
239 assert_equal "testfile.PNG", a2.filename
238 assert a2.readable?
240 assert a2.readable?
239 assert (! a2.visible?(User.anonymous))
241 assert (! a2.visible?(User.anonymous))
240 assert a2.visible?(User.find(2))
242 assert a2.visible?(User.find(2))
241 assert a1.created_on < a2.created_on
243 assert a1.created_on < a2.created_on
242
244
243 to_test = {
245 to_test = {
244 'Inline image: !testfile.png!' =>
246 'Inline image: !testfile.png!' =>
245 'Inline image: <img src="/attachments/download/' + a2.id.to_s + '/testfile.PNG" alt="" />',
247 'Inline image: <img src="/attachments/download/' + a2.id.to_s + '/testfile.PNG" alt="" />',
246 'Inline image: !Testfile.PNG!' =>
248 'Inline image: !Testfile.PNG!' =>
247 'Inline image: <img src="/attachments/download/' + a2.id.to_s + '/testfile.PNG" alt="" />',
249 'Inline image: <img src="/attachments/download/' + a2.id.to_s + '/testfile.PNG" alt="" />',
248 }
250 }
249 attachments = [a1, a2]
251 attachments = [a1, a2]
250 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text, :attachments => attachments) }
252 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text, :attachments => attachments) }
251 set_tmp_attachments_directory
253 set_tmp_attachments_directory
252 end
254 end
253
255
254 def test_textile_external_links
256 def test_textile_external_links
255 to_test = {
257 to_test = {
256 'This is a "link":http://foo.bar' => 'This is a <a href="http://foo.bar" class="external">link</a>',
258 'This is a "link":http://foo.bar' => 'This is a <a href="http://foo.bar" class="external">link</a>',
257 'This is an intern "link":/foo/bar' => 'This is an intern <a href="/foo/bar">link</a>',
259 'This is an intern "link":/foo/bar' => 'This is an intern <a href="/foo/bar">link</a>',
258 '"link (Link title)":http://foo.bar' => '<a href="http://foo.bar" title="Link title" class="external">link</a>',
260 '"link (Link title)":http://foo.bar' => '<a href="http://foo.bar" title="Link title" class="external">link</a>',
259 '"link (Link title with "double-quotes")":http://foo.bar' => '<a href="http://foo.bar" title="Link title with &quot;double-quotes&quot;" class="external">link</a>',
261 '"link (Link title with "double-quotes")":http://foo.bar' => '<a href="http://foo.bar" title="Link title with &quot;double-quotes&quot;" class="external">link</a>',
260 "This is not a \"Link\":\n\nAnother paragraph" => "This is not a \"Link\":</p>\n\n\n\t<p>Another paragraph",
262 "This is not a \"Link\":\n\nAnother paragraph" => "This is not a \"Link\":</p>\n\n\n\t<p>Another paragraph",
261 # no multiline link text
263 # no multiline link text
262 "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<br />and another on a second line\":test",
264 "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<br />and another on a second line\":test",
263 # mailto link
265 # mailto link
264 "\"system administrator\":mailto:sysadmin@example.com?subject=redmine%20permissions" => "<a href=\"mailto:sysadmin@example.com?subject=redmine%20permissions\">system administrator</a>",
266 "\"system administrator\":mailto:sysadmin@example.com?subject=redmine%20permissions" => "<a href=\"mailto:sysadmin@example.com?subject=redmine%20permissions\">system administrator</a>",
265 # two exclamation marks
267 # two exclamation marks
266 '"a link":http://example.net/path!602815048C7B5C20!302.html' => '<a href="http://example.net/path!602815048C7B5C20!302.html" class="external">a link</a>',
268 '"a link":http://example.net/path!602815048C7B5C20!302.html' => '<a href="http://example.net/path!602815048C7B5C20!302.html" class="external">a link</a>',
267 # escaping
269 # escaping
268 '"test":http://foo"bar' => '<a href="http://foo&quot;bar" class="external">test</a>',
270 '"test":http://foo"bar' => '<a href="http://foo&quot;bar" class="external">test</a>',
269 }
271 }
270 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
272 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
271 end
273 end
272
274
273 if 'ruby'.respond_to?(:encoding)
275 if 'ruby'.respond_to?(:encoding)
274 def test_textile_external_links_with_non_ascii_characters
276 def test_textile_external_links_with_non_ascii_characters
275 to_test = {
277 to_test = {
276 %|This is a "link":http://foo.bar/#{@russian_test}| =>
278 %|This is a "link":http://foo.bar/#{@russian_test}| =>
277 %|This is a <a href="http://foo.bar/#{@russian_test}" class="external">link</a>|
279 %|This is a <a href="http://foo.bar/#{@russian_test}" class="external">link</a>|
278 }
280 }
279 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
281 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
280 end
282 end
281 else
283 else
282 puts 'Skipping test_textile_external_links_with_non_ascii_characters, unsupported ruby version'
284 puts 'Skipping test_textile_external_links_with_non_ascii_characters, unsupported ruby version'
283 end
285 end
284
286
285 def test_redmine_links
287 def test_redmine_links
286 issue_link = link_to('#3', {:controller => 'issues', :action => 'show', :id => 3},
288 issue_link = link_to('#3', {:controller => 'issues', :action => 'show', :id => 3},
287 :class => Issue.find(3).css_classes, :title => 'Error 281 when updating a recipe (New)')
289 :class => Issue.find(3).css_classes, :title => 'Error 281 when updating a recipe (New)')
288 note_link = link_to('#3-14', {:controller => 'issues', :action => 'show', :id => 3, :anchor => 'note-14'},
290 note_link = link_to('#3-14', {:controller => 'issues', :action => 'show', :id => 3, :anchor => 'note-14'},
289 :class => Issue.find(3).css_classes, :title => 'Error 281 when updating a recipe (New)')
291 :class => Issue.find(3).css_classes, :title => 'Error 281 when updating a recipe (New)')
290 note_link2 = link_to('#3#note-14', {:controller => 'issues', :action => 'show', :id => 3, :anchor => 'note-14'},
292 note_link2 = link_to('#3#note-14', {:controller => 'issues', :action => 'show', :id => 3, :anchor => 'note-14'},
291 :class => Issue.find(3).css_classes, :title => 'Error 281 when updating a recipe (New)')
293 :class => Issue.find(3).css_classes, :title => 'Error 281 when updating a recipe (New)')
292
294
293 revision_link = link_to('r1', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 1},
295 revision_link = link_to('r1', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 1},
294 :class => 'changeset', :title => 'My very first commit do not escaping #<>&')
296 :class => 'changeset', :title => 'My very first commit do not escaping #<>&')
295 revision_link2 = link_to('r2', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 2},
297 revision_link2 = link_to('r2', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 2},
296 :class => 'changeset', :title => 'This commit fixes #1, #2 and references #1 & #3')
298 :class => 'changeset', :title => 'This commit fixes #1, #2 and references #1 & #3')
297
299
298 changeset_link2 = link_to('691322a8eb01e11fd7',
300 changeset_link2 = link_to('691322a8eb01e11fd7',
299 {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 1},
301 {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 1},
300 :class => 'changeset', :title => 'My very first commit do not escaping #<>&')
302 :class => 'changeset', :title => 'My very first commit do not escaping #<>&')
301
303
302 document_link = link_to('Test document', {:controller => 'documents', :action => 'show', :id => 1},
304 document_link = link_to('Test document', {:controller => 'documents', :action => 'show', :id => 1},
303 :class => 'document')
305 :class => 'document')
304
306
305 version_link = link_to('1.0', {:controller => 'versions', :action => 'show', :id => 2},
307 version_link = link_to('1.0', {:controller => 'versions', :action => 'show', :id => 2},
306 :class => 'version')
308 :class => 'version')
307
309
308 board_url = {:controller => 'boards', :action => 'show', :id => 2, :project_id => 'ecookbook'}
310 board_url = {:controller => 'boards', :action => 'show', :id => 2, :project_id => 'ecookbook'}
309
311
310 message_url = {:controller => 'messages', :action => 'show', :board_id => 1, :id => 4}
312 message_url = {:controller => 'messages', :action => 'show', :board_id => 1, :id => 4}
311
313
312 news_url = {:controller => 'news', :action => 'show', :id => 1}
314 news_url = {:controller => 'news', :action => 'show', :id => 1}
313
315
314 project_url = {:controller => 'projects', :action => 'show', :id => 'subproject1'}
316 project_url = {:controller => 'projects', :action => 'show', :id => 'subproject1'}
315
317
316 source_url = '/projects/ecookbook/repository/entry/some/file'
318 source_url = '/projects/ecookbook/repository/entry/some/file'
317 source_url_with_rev = '/projects/ecookbook/repository/revisions/52/entry/some/file'
319 source_url_with_rev = '/projects/ecookbook/repository/revisions/52/entry/some/file'
318 source_url_with_ext = '/projects/ecookbook/repository/entry/some/file.ext'
320 source_url_with_ext = '/projects/ecookbook/repository/entry/some/file.ext'
319 source_url_with_rev_and_ext = '/projects/ecookbook/repository/revisions/52/entry/some/file.ext'
321 source_url_with_rev_and_ext = '/projects/ecookbook/repository/revisions/52/entry/some/file.ext'
320 source_url_with_branch = '/projects/ecookbook/repository/revisions/branch/entry/some/file'
322 source_url_with_branch = '/projects/ecookbook/repository/revisions/branch/entry/some/file'
321
323
322 export_url = '/projects/ecookbook/repository/raw/some/file'
324 export_url = '/projects/ecookbook/repository/raw/some/file'
323 export_url_with_rev = '/projects/ecookbook/repository/revisions/52/raw/some/file'
325 export_url_with_rev = '/projects/ecookbook/repository/revisions/52/raw/some/file'
324 export_url_with_ext = '/projects/ecookbook/repository/raw/some/file.ext'
326 export_url_with_ext = '/projects/ecookbook/repository/raw/some/file.ext'
325 export_url_with_rev_and_ext = '/projects/ecookbook/repository/revisions/52/raw/some/file.ext'
327 export_url_with_rev_and_ext = '/projects/ecookbook/repository/revisions/52/raw/some/file.ext'
326 export_url_with_branch = '/projects/ecookbook/repository/revisions/branch/raw/some/file'
328 export_url_with_branch = '/projects/ecookbook/repository/revisions/branch/raw/some/file'
327
329
328 to_test = {
330 to_test = {
329 # tickets
331 # tickets
330 '#3, [#3], (#3) and #3.' => "#{issue_link}, [#{issue_link}], (#{issue_link}) and #{issue_link}.",
332 '#3, [#3], (#3) and #3.' => "#{issue_link}, [#{issue_link}], (#{issue_link}) and #{issue_link}.",
331 # ticket notes
333 # ticket notes
332 '#3-14' => note_link,
334 '#3-14' => note_link,
333 '#3#note-14' => note_link2,
335 '#3#note-14' => note_link2,
334 # should not ignore leading zero
336 # should not ignore leading zero
335 '#03' => '#03',
337 '#03' => '#03',
336 # changesets
338 # changesets
337 'r1' => revision_link,
339 'r1' => revision_link,
338 'r1.' => "#{revision_link}.",
340 'r1.' => "#{revision_link}.",
339 'r1, r2' => "#{revision_link}, #{revision_link2}",
341 'r1, r2' => "#{revision_link}, #{revision_link2}",
340 'r1,r2' => "#{revision_link},#{revision_link2}",
342 'r1,r2' => "#{revision_link},#{revision_link2}",
341 'commit:691322a8eb01e11fd7' => changeset_link2,
343 'commit:691322a8eb01e11fd7' => changeset_link2,
342 # documents
344 # documents
343 'document#1' => document_link,
345 'document#1' => document_link,
344 'document:"Test document"' => document_link,
346 'document:"Test document"' => document_link,
345 # versions
347 # versions
346 'version#2' => version_link,
348 'version#2' => version_link,
347 'version:1.0' => version_link,
349 'version:1.0' => version_link,
348 'version:"1.0"' => version_link,
350 'version:"1.0"' => version_link,
349 # source
351 # source
350 'source:some/file' => link_to('source:some/file', source_url, :class => 'source'),
352 'source:some/file' => link_to('source:some/file', source_url, :class => 'source'),
351 'source:/some/file' => link_to('source:/some/file', source_url, :class => 'source'),
353 'source:/some/file' => link_to('source:/some/file', source_url, :class => 'source'),
352 'source:/some/file.' => link_to('source:/some/file', source_url, :class => 'source') + ".",
354 'source:/some/file.' => link_to('source:/some/file', source_url, :class => 'source') + ".",
353 'source:/some/file.ext.' => link_to('source:/some/file.ext', source_url_with_ext, :class => 'source') + ".",
355 'source:/some/file.ext.' => link_to('source:/some/file.ext', source_url_with_ext, :class => 'source') + ".",
354 'source:/some/file. ' => link_to('source:/some/file', source_url, :class => 'source') + ".",
356 'source:/some/file. ' => link_to('source:/some/file', source_url, :class => 'source') + ".",
355 'source:/some/file.ext. ' => link_to('source:/some/file.ext', source_url_with_ext, :class => 'source') + ".",
357 'source:/some/file.ext. ' => link_to('source:/some/file.ext', source_url_with_ext, :class => 'source') + ".",
356 'source:/some/file, ' => link_to('source:/some/file', source_url, :class => 'source') + ",",
358 'source:/some/file, ' => link_to('source:/some/file', source_url, :class => 'source') + ",",
357 'source:/some/file@52' => link_to('source:/some/file@52', source_url_with_rev, :class => 'source'),
359 'source:/some/file@52' => link_to('source:/some/file@52', source_url_with_rev, :class => 'source'),
358 'source:/some/file@branch' => link_to('source:/some/file@branch', source_url_with_branch, :class => 'source'),
360 'source:/some/file@branch' => link_to('source:/some/file@branch', source_url_with_branch, :class => 'source'),
359 'source:/some/file.ext@52' => link_to('source:/some/file.ext@52', source_url_with_rev_and_ext, :class => 'source'),
361 'source:/some/file.ext@52' => link_to('source:/some/file.ext@52', source_url_with_rev_and_ext, :class => 'source'),
360 'source:/some/file#L110' => link_to('source:/some/file#L110', source_url + "#L110", :class => 'source'),
362 'source:/some/file#L110' => link_to('source:/some/file#L110', source_url + "#L110", :class => 'source'),
361 'source:/some/file.ext#L110' => link_to('source:/some/file.ext#L110', source_url_with_ext + "#L110", :class => 'source'),
363 'source:/some/file.ext#L110' => link_to('source:/some/file.ext#L110', source_url_with_ext + "#L110", :class => 'source'),
362 'source:/some/file@52#L110' => link_to('source:/some/file@52#L110', source_url_with_rev + "#L110", :class => 'source'),
364 'source:/some/file@52#L110' => link_to('source:/some/file@52#L110', source_url_with_rev + "#L110", :class => 'source'),
363 # export
365 # export
364 'export:/some/file' => link_to('export:/some/file', export_url, :class => 'source download'),
366 'export:/some/file' => link_to('export:/some/file', export_url, :class => 'source download'),
365 'export:/some/file.ext' => link_to('export:/some/file.ext', export_url_with_ext, :class => 'source download'),
367 'export:/some/file.ext' => link_to('export:/some/file.ext', export_url_with_ext, :class => 'source download'),
366 'export:/some/file@52' => link_to('export:/some/file@52', export_url_with_rev, :class => 'source download'),
368 'export:/some/file@52' => link_to('export:/some/file@52', export_url_with_rev, :class => 'source download'),
367 'export:/some/file.ext@52' => link_to('export:/some/file.ext@52', export_url_with_rev_and_ext, :class => 'source download'),
369 'export:/some/file.ext@52' => link_to('export:/some/file.ext@52', export_url_with_rev_and_ext, :class => 'source download'),
368 'export:/some/file@branch' => link_to('export:/some/file@branch', export_url_with_branch, :class => 'source download'),
370 'export:/some/file@branch' => link_to('export:/some/file@branch', export_url_with_branch, :class => 'source download'),
369 # forum
371 # forum
370 'forum#2' => link_to('Discussion', board_url, :class => 'board'),
372 'forum#2' => link_to('Discussion', board_url, :class => 'board'),
371 'forum:Discussion' => link_to('Discussion', board_url, :class => 'board'),
373 'forum:Discussion' => link_to('Discussion', board_url, :class => 'board'),
372 # message
374 # message
373 'message#4' => link_to('Post 2', message_url, :class => 'message'),
375 'message#4' => link_to('Post 2', message_url, :class => 'message'),
374 'message#5' => link_to('RE: post 2', message_url.merge(:anchor => 'message-5', :r => 5), :class => 'message'),
376 'message#5' => link_to('RE: post 2', message_url.merge(:anchor => 'message-5', :r => 5), :class => 'message'),
375 # news
377 # news
376 'news#1' => link_to('eCookbook first release !', news_url, :class => 'news'),
378 'news#1' => link_to('eCookbook first release !', news_url, :class => 'news'),
377 'news:"eCookbook first release !"' => link_to('eCookbook first release !', news_url, :class => 'news'),
379 'news:"eCookbook first release !"' => link_to('eCookbook first release !', news_url, :class => 'news'),
378 # project
380 # project
379 'project#3' => link_to('eCookbook Subproject 1', project_url, :class => 'project'),
381 'project#3' => link_to('eCookbook Subproject 1', project_url, :class => 'project'),
380 'project:subproject1' => link_to('eCookbook Subproject 1', project_url, :class => 'project'),
382 'project:subproject1' => link_to('eCookbook Subproject 1', project_url, :class => 'project'),
381 'project:"eCookbook subProject 1"' => link_to('eCookbook Subproject 1', project_url, :class => 'project'),
383 'project:"eCookbook subProject 1"' => link_to('eCookbook Subproject 1', project_url, :class => 'project'),
382 # not found
384 # not found
383 '#0123456789' => '#0123456789',
385 '#0123456789' => '#0123456789',
384 # invalid expressions
386 # invalid expressions
385 'source:' => 'source:',
387 'source:' => 'source:',
386 # url hash
388 # url hash
387 "http://foo.bar/FAQ#3" => '<a class="external" href="http://foo.bar/FAQ#3">http://foo.bar/FAQ#3</a>',
389 "http://foo.bar/FAQ#3" => '<a class="external" href="http://foo.bar/FAQ#3">http://foo.bar/FAQ#3</a>',
388 }
390 }
389 @project = Project.find(1)
391 @project = Project.find(1)
390 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text), "#{text} failed" }
392 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text), "#{text} failed" }
391 end
393 end
392
394
393 def test_redmine_links_with_a_different_project_before_current_project
395 def test_redmine_links_with_a_different_project_before_current_project
394 vp1 = Version.generate!(:project_id => 1, :name => '1.4.4')
396 vp1 = Version.generate!(:project_id => 1, :name => '1.4.4')
395 vp3 = Version.generate!(:project_id => 3, :name => '1.4.4')
397 vp3 = Version.generate!(:project_id => 3, :name => '1.4.4')
396 @project = Project.find(3)
398 @project = Project.find(3)
397 result1 = link_to("1.4.4", "/versions/#{vp1.id}", :class => "version")
399 result1 = link_to("1.4.4", "/versions/#{vp1.id}", :class => "version")
398 result2 = link_to("1.4.4", "/versions/#{vp3.id}", :class => "version")
400 result2 = link_to("1.4.4", "/versions/#{vp3.id}", :class => "version")
399 assert_equal "<p>#{result1} #{result2}</p>",
401 assert_equal "<p>#{result1} #{result2}</p>",
400 textilizable("ecookbook:version:1.4.4 version:1.4.4")
402 textilizable("ecookbook:version:1.4.4 version:1.4.4")
401 end
403 end
402
404
403 def test_escaped_redmine_links_should_not_be_parsed
405 def test_escaped_redmine_links_should_not_be_parsed
404 to_test = [
406 to_test = [
405 '#3.',
407 '#3.',
406 '#3-14.',
408 '#3-14.',
407 '#3#-note14.',
409 '#3#-note14.',
408 'r1',
410 'r1',
409 'document#1',
411 'document#1',
410 'document:"Test document"',
412 'document:"Test document"',
411 'version#2',
413 'version#2',
412 'version:1.0',
414 'version:1.0',
413 'version:"1.0"',
415 'version:"1.0"',
414 'source:/some/file'
416 'source:/some/file'
415 ]
417 ]
416 @project = Project.find(1)
418 @project = Project.find(1)
417 to_test.each { |text| assert_equal "<p>#{text}</p>", textilizable("!" + text), "#{text} failed" }
419 to_test.each { |text| assert_equal "<p>#{text}</p>", textilizable("!" + text), "#{text} failed" }
418 end
420 end
419
421
420 def test_cross_project_redmine_links
422 def test_cross_project_redmine_links
421 source_link = link_to('ecookbook:source:/some/file',
423 source_link = link_to('ecookbook:source:/some/file',
422 {:controller => 'repositories', :action => 'entry',
424 {:controller => 'repositories', :action => 'entry',
423 :id => 'ecookbook', :path => ['some', 'file']},
425 :id => 'ecookbook', :path => ['some', 'file']},
424 :class => 'source')
426 :class => 'source')
425 changeset_link = link_to('ecookbook:r2',
427 changeset_link = link_to('ecookbook:r2',
426 {:controller => 'repositories', :action => 'revision',
428 {:controller => 'repositories', :action => 'revision',
427 :id => 'ecookbook', :rev => 2},
429 :id => 'ecookbook', :rev => 2},
428 :class => 'changeset',
430 :class => 'changeset',
429 :title => 'This commit fixes #1, #2 and references #1 & #3')
431 :title => 'This commit fixes #1, #2 and references #1 & #3')
430 to_test = {
432 to_test = {
431 # documents
433 # documents
432 'document:"Test document"' => 'document:"Test document"',
434 'document:"Test document"' => 'document:"Test document"',
433 'ecookbook:document:"Test document"' =>
435 'ecookbook:document:"Test document"' =>
434 link_to("Test document", "/documents/1", :class => "document"),
436 link_to("Test document", "/documents/1", :class => "document"),
435 'invalid:document:"Test document"' => 'invalid:document:"Test document"',
437 'invalid:document:"Test document"' => 'invalid:document:"Test document"',
436 # versions
438 # versions
437 'version:"1.0"' => 'version:"1.0"',
439 'version:"1.0"' => 'version:"1.0"',
438 'ecookbook:version:"1.0"' =>
440 'ecookbook:version:"1.0"' =>
439 link_to("1.0", "/versions/2", :class => "version"),
441 link_to("1.0", "/versions/2", :class => "version"),
440 'invalid:version:"1.0"' => 'invalid:version:"1.0"',
442 'invalid:version:"1.0"' => 'invalid:version:"1.0"',
441 # changeset
443 # changeset
442 'r2' => 'r2',
444 'r2' => 'r2',
443 'ecookbook:r2' => changeset_link,
445 'ecookbook:r2' => changeset_link,
444 'invalid:r2' => 'invalid:r2',
446 'invalid:r2' => 'invalid:r2',
445 # source
447 # source
446 'source:/some/file' => 'source:/some/file',
448 'source:/some/file' => 'source:/some/file',
447 'ecookbook:source:/some/file' => source_link,
449 'ecookbook:source:/some/file' => source_link,
448 'invalid:source:/some/file' => 'invalid:source:/some/file',
450 'invalid:source:/some/file' => 'invalid:source:/some/file',
449 }
451 }
450 @project = Project.find(3)
452 @project = Project.find(3)
451 to_test.each do |text, result|
453 to_test.each do |text, result|
452 assert_equal "<p>#{result}</p>", textilizable(text), "#{text} failed"
454 assert_equal "<p>#{result}</p>", textilizable(text), "#{text} failed"
453 end
455 end
454 end
456 end
455
457
456 def test_redmine_links_by_name_should_work_with_html_escaped_characters
458 def test_redmine_links_by_name_should_work_with_html_escaped_characters
457 v = Version.generate!(:name => "Test & Show.txt", :project_id => 1)
459 v = Version.generate!(:name => "Test & Show.txt", :project_id => 1)
458 link = link_to("Test & Show.txt", "/versions/#{v.id}", :class => "version")
460 link = link_to("Test & Show.txt", "/versions/#{v.id}", :class => "version")
459
461
460 @project = v.project
462 @project = v.project
461 assert_equal "<p>#{link}</p>", textilizable('version:"Test & Show.txt"')
463 assert_equal "<p>#{link}</p>", textilizable('version:"Test & Show.txt"')
462 end
464 end
463
465
464 def test_link_to_issue_subject
466 def test_link_to_issue_subject
465 issue = Issue.generate!(:subject => "01234567890123456789")
467 issue = Issue.generate!(:subject => "01234567890123456789")
466 str = link_to_issue(issue, :truncate => 10)
468 str = link_to_issue(issue, :truncate => 10)
467 result = link_to("Bug ##{issue.id}", "/issues/#{issue.id}", :class => issue.css_classes)
469 result = link_to("Bug ##{issue.id}", "/issues/#{issue.id}", :class => issue.css_classes)
468 assert_equal "#{result}: 0123456...", str
470 assert_equal "#{result}: 0123456...", str
469
471
470 issue = Issue.generate!(:subject => "<&>")
472 issue = Issue.generate!(:subject => "<&>")
471 str = link_to_issue(issue)
473 str = link_to_issue(issue)
472 result = link_to("Bug ##{issue.id}", "/issues/#{issue.id}", :class => issue.css_classes)
474 result = link_to("Bug ##{issue.id}", "/issues/#{issue.id}", :class => issue.css_classes)
473 assert_equal "#{result}: &lt;&amp;&gt;", str
475 assert_equal "#{result}: &lt;&amp;&gt;", str
474
476
475 issue = Issue.generate!(:subject => "<&>0123456789012345")
477 issue = Issue.generate!(:subject => "<&>0123456789012345")
476 str = link_to_issue(issue, :truncate => 10)
478 str = link_to_issue(issue, :truncate => 10)
477 result = link_to("Bug ##{issue.id}", "/issues/#{issue.id}", :class => issue.css_classes)
479 result = link_to("Bug ##{issue.id}", "/issues/#{issue.id}", :class => issue.css_classes)
478 assert_equal "#{result}: &lt;&amp;&gt;0123...", str
480 assert_equal "#{result}: &lt;&amp;&gt;0123...", str
479 end
481 end
480
482
481 def test_link_to_issue_title
483 def test_link_to_issue_title
482 long_str = "0123456789" * 5
484 long_str = "0123456789" * 5
483
485
484 issue = Issue.generate!(:subject => "#{long_str}01234567890123456789")
486 issue = Issue.generate!(:subject => "#{long_str}01234567890123456789")
485 str = link_to_issue(issue, :subject => false)
487 str = link_to_issue(issue, :subject => false)
486 result = link_to("Bug ##{issue.id}", "/issues/#{issue.id}",
488 result = link_to("Bug ##{issue.id}", "/issues/#{issue.id}",
487 :class => issue.css_classes,
489 :class => issue.css_classes,
488 :title => "#{long_str}0123456...")
490 :title => "#{long_str}0123456...")
489 assert_equal result, str
491 assert_equal result, str
490
492
491 issue = Issue.generate!(:subject => "<&>#{long_str}01234567890123456789")
493 issue = Issue.generate!(:subject => "<&>#{long_str}01234567890123456789")
492 str = link_to_issue(issue, :subject => false)
494 str = link_to_issue(issue, :subject => false)
493 result = link_to("Bug ##{issue.id}", "/issues/#{issue.id}",
495 result = link_to("Bug ##{issue.id}", "/issues/#{issue.id}",
494 :class => issue.css_classes,
496 :class => issue.css_classes,
495 :title => "<&>#{long_str}0123...")
497 :title => "<&>#{long_str}0123...")
496 assert_equal result, str
498 assert_equal result, str
497 end
499 end
498
500
499 def test_multiple_repositories_redmine_links
501 def test_multiple_repositories_redmine_links
500 svn = Repository::Subversion.create!(:project_id => 1, :identifier => 'svn_repo-1', :url => 'file:///foo/hg')
502 svn = Repository::Subversion.create!(:project_id => 1, :identifier => 'svn_repo-1', :url => 'file:///foo/hg')
501 Changeset.create!(:repository => svn, :committed_on => Time.now, :revision => '123')
503 Changeset.create!(:repository => svn, :committed_on => Time.now, :revision => '123')
502 hg = Repository::Mercurial.create!(:project_id => 1, :identifier => 'hg1', :url => '/foo/hg')
504 hg = Repository::Mercurial.create!(:project_id => 1, :identifier => 'hg1', :url => '/foo/hg')
503 Changeset.create!(:repository => hg, :committed_on => Time.now, :revision => '123', :scmid => 'abcd')
505 Changeset.create!(:repository => hg, :committed_on => Time.now, :revision => '123', :scmid => 'abcd')
504
506
505 changeset_link = link_to('r2', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 2},
507 changeset_link = link_to('r2', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 2},
506 :class => 'changeset', :title => 'This commit fixes #1, #2 and references #1 & #3')
508 :class => 'changeset', :title => 'This commit fixes #1, #2 and references #1 & #3')
507 svn_changeset_link = link_to('svn_repo-1|r123', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :repository_id => 'svn_repo-1', :rev => 123},
509 svn_changeset_link = link_to('svn_repo-1|r123', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :repository_id => 'svn_repo-1', :rev => 123},
508 :class => 'changeset', :title => '')
510 :class => 'changeset', :title => '')
509 hg_changeset_link = link_to('hg1|abcd', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :repository_id => 'hg1', :rev => 'abcd'},
511 hg_changeset_link = link_to('hg1|abcd', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :repository_id => 'hg1', :rev => 'abcd'},
510 :class => 'changeset', :title => '')
512 :class => 'changeset', :title => '')
511
513
512 source_link = link_to('source:some/file', {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :path => ['some', 'file']}, :class => 'source')
514 source_link = link_to('source:some/file', {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :path => ['some', 'file']}, :class => 'source')
513 hg_source_link = link_to('source:hg1|some/file', {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :repository_id => 'hg1', :path => ['some', 'file']}, :class => 'source')
515 hg_source_link = link_to('source:hg1|some/file', {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :repository_id => 'hg1', :path => ['some', 'file']}, :class => 'source')
514
516
515 to_test = {
517 to_test = {
516 'r2' => changeset_link,
518 'r2' => changeset_link,
517 'svn_repo-1|r123' => svn_changeset_link,
519 'svn_repo-1|r123' => svn_changeset_link,
518 'invalid|r123' => 'invalid|r123',
520 'invalid|r123' => 'invalid|r123',
519 'commit:hg1|abcd' => hg_changeset_link,
521 'commit:hg1|abcd' => hg_changeset_link,
520 'commit:invalid|abcd' => 'commit:invalid|abcd',
522 'commit:invalid|abcd' => 'commit:invalid|abcd',
521 # source
523 # source
522 'source:some/file' => source_link,
524 'source:some/file' => source_link,
523 'source:hg1|some/file' => hg_source_link,
525 'source:hg1|some/file' => hg_source_link,
524 'source:invalid|some/file' => 'source:invalid|some/file',
526 'source:invalid|some/file' => 'source:invalid|some/file',
525 }
527 }
526
528
527 @project = Project.find(1)
529 @project = Project.find(1)
528 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text), "#{text} failed" }
530 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text), "#{text} failed" }
529 end
531 end
530
532
531 def test_cross_project_multiple_repositories_redmine_links
533 def test_cross_project_multiple_repositories_redmine_links
532 svn = Repository::Subversion.create!(:project_id => 1, :identifier => 'svn1', :url => 'file:///foo/hg')
534 svn = Repository::Subversion.create!(:project_id => 1, :identifier => 'svn1', :url => 'file:///foo/hg')
533 Changeset.create!(:repository => svn, :committed_on => Time.now, :revision => '123')
535 Changeset.create!(:repository => svn, :committed_on => Time.now, :revision => '123')
534 hg = Repository::Mercurial.create!(:project_id => 1, :identifier => 'hg1', :url => '/foo/hg')
536 hg = Repository::Mercurial.create!(:project_id => 1, :identifier => 'hg1', :url => '/foo/hg')
535 Changeset.create!(:repository => hg, :committed_on => Time.now, :revision => '123', :scmid => 'abcd')
537 Changeset.create!(:repository => hg, :committed_on => Time.now, :revision => '123', :scmid => 'abcd')
536
538
537 changeset_link = link_to('ecookbook:r2', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 2},
539 changeset_link = link_to('ecookbook:r2', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 2},
538 :class => 'changeset', :title => 'This commit fixes #1, #2 and references #1 & #3')
540 :class => 'changeset', :title => 'This commit fixes #1, #2 and references #1 & #3')
539 svn_changeset_link = link_to('ecookbook:svn1|r123', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :repository_id => 'svn1', :rev => 123},
541 svn_changeset_link = link_to('ecookbook:svn1|r123', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :repository_id => 'svn1', :rev => 123},
540 :class => 'changeset', :title => '')
542 :class => 'changeset', :title => '')
541 hg_changeset_link = link_to('ecookbook:hg1|abcd', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :repository_id => 'hg1', :rev => 'abcd'},
543 hg_changeset_link = link_to('ecookbook:hg1|abcd', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :repository_id => 'hg1', :rev => 'abcd'},
542 :class => 'changeset', :title => '')
544 :class => 'changeset', :title => '')
543
545
544 source_link = link_to('ecookbook:source:some/file', {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :path => ['some', 'file']}, :class => 'source')
546 source_link = link_to('ecookbook:source:some/file', {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :path => ['some', 'file']}, :class => 'source')
545 hg_source_link = link_to('ecookbook:source:hg1|some/file', {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :repository_id => 'hg1', :path => ['some', 'file']}, :class => 'source')
547 hg_source_link = link_to('ecookbook:source:hg1|some/file', {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :repository_id => 'hg1', :path => ['some', 'file']}, :class => 'source')
546
548
547 to_test = {
549 to_test = {
548 'ecookbook:r2' => changeset_link,
550 'ecookbook:r2' => changeset_link,
549 'ecookbook:svn1|r123' => svn_changeset_link,
551 'ecookbook:svn1|r123' => svn_changeset_link,
550 'ecookbook:invalid|r123' => 'ecookbook:invalid|r123',
552 'ecookbook:invalid|r123' => 'ecookbook:invalid|r123',
551 'ecookbook:commit:hg1|abcd' => hg_changeset_link,
553 'ecookbook:commit:hg1|abcd' => hg_changeset_link,
552 'ecookbook:commit:invalid|abcd' => 'ecookbook:commit:invalid|abcd',
554 'ecookbook:commit:invalid|abcd' => 'ecookbook:commit:invalid|abcd',
553 'invalid:commit:invalid|abcd' => 'invalid:commit:invalid|abcd',
555 'invalid:commit:invalid|abcd' => 'invalid:commit:invalid|abcd',
554 # source
556 # source
555 'ecookbook:source:some/file' => source_link,
557 'ecookbook:source:some/file' => source_link,
556 'ecookbook:source:hg1|some/file' => hg_source_link,
558 'ecookbook:source:hg1|some/file' => hg_source_link,
557 'ecookbook:source:invalid|some/file' => 'ecookbook:source:invalid|some/file',
559 'ecookbook:source:invalid|some/file' => 'ecookbook:source:invalid|some/file',
558 'invalid:source:invalid|some/file' => 'invalid:source:invalid|some/file',
560 'invalid:source:invalid|some/file' => 'invalid:source:invalid|some/file',
559 }
561 }
560
562
561 @project = Project.find(3)
563 @project = Project.find(3)
562 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text), "#{text} failed" }
564 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text), "#{text} failed" }
563 end
565 end
564
566
565 def test_redmine_links_git_commit
567 def test_redmine_links_git_commit
566 changeset_link = link_to('abcd',
568 changeset_link = link_to('abcd',
567 {
569 {
568 :controller => 'repositories',
570 :controller => 'repositories',
569 :action => 'revision',
571 :action => 'revision',
570 :id => 'subproject1',
572 :id => 'subproject1',
571 :rev => 'abcd',
573 :rev => 'abcd',
572 },
574 },
573 :class => 'changeset', :title => 'test commit')
575 :class => 'changeset', :title => 'test commit')
574 to_test = {
576 to_test = {
575 'commit:abcd' => changeset_link,
577 'commit:abcd' => changeset_link,
576 }
578 }
577 @project = Project.find(3)
579 @project = Project.find(3)
578 r = Repository::Git.create!(:project => @project, :url => '/tmp/test/git')
580 r = Repository::Git.create!(:project => @project, :url => '/tmp/test/git')
579 assert r
581 assert r
580 c = Changeset.new(:repository => r,
582 c = Changeset.new(:repository => r,
581 :committed_on => Time.now,
583 :committed_on => Time.now,
582 :revision => 'abcd',
584 :revision => 'abcd',
583 :scmid => 'abcd',
585 :scmid => 'abcd',
584 :comments => 'test commit')
586 :comments => 'test commit')
585 assert( c.save )
587 assert( c.save )
586 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
588 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
587 end
589 end
588
590
589 # TODO: Bazaar commit id contains mail address, so it contains '@' and '_'.
591 # TODO: Bazaar commit id contains mail address, so it contains '@' and '_'.
590 def test_redmine_links_darcs_commit
592 def test_redmine_links_darcs_commit
591 changeset_link = link_to('20080308225258-98289-abcd456efg.gz',
593 changeset_link = link_to('20080308225258-98289-abcd456efg.gz',
592 {
594 {
593 :controller => 'repositories',
595 :controller => 'repositories',
594 :action => 'revision',
596 :action => 'revision',
595 :id => 'subproject1',
597 :id => 'subproject1',
596 :rev => '123',
598 :rev => '123',
597 },
599 },
598 :class => 'changeset', :title => 'test commit')
600 :class => 'changeset', :title => 'test commit')
599 to_test = {
601 to_test = {
600 'commit:20080308225258-98289-abcd456efg.gz' => changeset_link,
602 'commit:20080308225258-98289-abcd456efg.gz' => changeset_link,
601 }
603 }
602 @project = Project.find(3)
604 @project = Project.find(3)
603 r = Repository::Darcs.create!(
605 r = Repository::Darcs.create!(
604 :project => @project, :url => '/tmp/test/darcs',
606 :project => @project, :url => '/tmp/test/darcs',
605 :log_encoding => 'UTF-8')
607 :log_encoding => 'UTF-8')
606 assert r
608 assert r
607 c = Changeset.new(:repository => r,
609 c = Changeset.new(:repository => r,
608 :committed_on => Time.now,
610 :committed_on => Time.now,
609 :revision => '123',
611 :revision => '123',
610 :scmid => '20080308225258-98289-abcd456efg.gz',
612 :scmid => '20080308225258-98289-abcd456efg.gz',
611 :comments => 'test commit')
613 :comments => 'test commit')
612 assert( c.save )
614 assert( c.save )
613 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
615 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
614 end
616 end
615
617
616 def test_redmine_links_mercurial_commit
618 def test_redmine_links_mercurial_commit
617 changeset_link_rev = link_to('r123',
619 changeset_link_rev = link_to('r123',
618 {
620 {
619 :controller => 'repositories',
621 :controller => 'repositories',
620 :action => 'revision',
622 :action => 'revision',
621 :id => 'subproject1',
623 :id => 'subproject1',
622 :rev => '123' ,
624 :rev => '123' ,
623 },
625 },
624 :class => 'changeset', :title => 'test commit')
626 :class => 'changeset', :title => 'test commit')
625 changeset_link_commit = link_to('abcd',
627 changeset_link_commit = link_to('abcd',
626 {
628 {
627 :controller => 'repositories',
629 :controller => 'repositories',
628 :action => 'revision',
630 :action => 'revision',
629 :id => 'subproject1',
631 :id => 'subproject1',
630 :rev => 'abcd' ,
632 :rev => 'abcd' ,
631 },
633 },
632 :class => 'changeset', :title => 'test commit')
634 :class => 'changeset', :title => 'test commit')
633 to_test = {
635 to_test = {
634 'r123' => changeset_link_rev,
636 'r123' => changeset_link_rev,
635 'commit:abcd' => changeset_link_commit,
637 'commit:abcd' => changeset_link_commit,
636 }
638 }
637 @project = Project.find(3)
639 @project = Project.find(3)
638 r = Repository::Mercurial.create!(:project => @project, :url => '/tmp/test')
640 r = Repository::Mercurial.create!(:project => @project, :url => '/tmp/test')
639 assert r
641 assert r
640 c = Changeset.new(:repository => r,
642 c = Changeset.new(:repository => r,
641 :committed_on => Time.now,
643 :committed_on => Time.now,
642 :revision => '123',
644 :revision => '123',
643 :scmid => 'abcd',
645 :scmid => 'abcd',
644 :comments => 'test commit')
646 :comments => 'test commit')
645 assert( c.save )
647 assert( c.save )
646 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
648 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
647 end
649 end
648
650
649 def test_attachment_links
651 def test_attachment_links
650 text = 'attachment:error281.txt'
652 text = 'attachment:error281.txt'
651 result = link_to("error281.txt", "/attachments/download/1/error281.txt",
653 result = link_to("error281.txt", "/attachments/download/1/error281.txt",
652 :class => "attachment")
654 :class => "attachment")
653 assert_equal "<p>#{result}</p>",
655 assert_equal "<p>#{result}</p>",
654 textilizable(text,
656 textilizable(text,
655 :attachments => Issue.find(3).attachments),
657 :attachments => Issue.find(3).attachments),
656 "#{text} failed"
658 "#{text} failed"
657 end
659 end
658
660
659 def test_attachment_link_should_link_to_latest_attachment
661 def test_attachment_link_should_link_to_latest_attachment
660 set_tmp_attachments_directory
662 set_tmp_attachments_directory
661 a1 = Attachment.generate!(:filename => "test.txt", :created_on => 1.hour.ago)
663 a1 = Attachment.generate!(:filename => "test.txt", :created_on => 1.hour.ago)
662 a2 = Attachment.generate!(:filename => "test.txt")
664 a2 = Attachment.generate!(:filename => "test.txt")
663 result = link_to("test.txt", "/attachments/download/#{a2.id}/test.txt",
665 result = link_to("test.txt", "/attachments/download/#{a2.id}/test.txt",
664 :class => "attachment")
666 :class => "attachment")
665 assert_equal "<p>#{result}</p>",
667 assert_equal "<p>#{result}</p>",
666 textilizable('attachment:test.txt', :attachments => [a1, a2])
668 textilizable('attachment:test.txt', :attachments => [a1, a2])
667 end
669 end
668
670
669 def test_wiki_links
671 def test_wiki_links
670 russian_eacape = CGI.escape(@russian_test)
672 russian_eacape = CGI.escape(@russian_test)
671 to_test = {
673 to_test = {
672 '[[CookBook documentation]]' =>
674 '[[CookBook documentation]]' =>
673 link_to("CookBook documentation",
675 link_to("CookBook documentation",
674 "/projects/ecookbook/wiki/CookBook_documentation",
676 "/projects/ecookbook/wiki/CookBook_documentation",
675 :class => "wiki-page"),
677 :class => "wiki-page"),
676 '[[Another page|Page]]' =>
678 '[[Another page|Page]]' =>
677 link_to("Page",
679 link_to("Page",
678 "/projects/ecookbook/wiki/Another_page",
680 "/projects/ecookbook/wiki/Another_page",
679 :class => "wiki-page"),
681 :class => "wiki-page"),
680 # title content should be formatted
682 # title content should be formatted
681 '[[Another page|With _styled_ *title*]]' =>
683 '[[Another page|With _styled_ *title*]]' =>
682 link_to("With <em>styled</em> <strong>title</strong>".html_safe,
684 link_to("With <em>styled</em> <strong>title</strong>".html_safe,
683 "/projects/ecookbook/wiki/Another_page",
685 "/projects/ecookbook/wiki/Another_page",
684 :class => "wiki-page"),
686 :class => "wiki-page"),
685 '[[Another page|With title containing <strong>HTML entities &amp; markups</strong>]]' =>
687 '[[Another page|With title containing <strong>HTML entities &amp; markups</strong>]]' =>
686 link_to("With title containing &lt;strong&gt;HTML entities &amp; markups&lt;/strong&gt;".html_safe,
688 link_to("With title containing &lt;strong&gt;HTML entities &amp; markups&lt;/strong&gt;".html_safe,
687 "/projects/ecookbook/wiki/Another_page",
689 "/projects/ecookbook/wiki/Another_page",
688 :class => "wiki-page"),
690 :class => "wiki-page"),
689 # link with anchor
691 # link with anchor
690 '[[CookBook documentation#One-section]]' =>
692 '[[CookBook documentation#One-section]]' =>
691 link_to("CookBook documentation",
693 link_to("CookBook documentation",
692 "/projects/ecookbook/wiki/CookBook_documentation#One-section",
694 "/projects/ecookbook/wiki/CookBook_documentation#One-section",
693 :class => "wiki-page"),
695 :class => "wiki-page"),
694 '[[Another page#anchor|Page]]' =>
696 '[[Another page#anchor|Page]]' =>
695 link_to("Page",
697 link_to("Page",
696 "/projects/ecookbook/wiki/Another_page#anchor",
698 "/projects/ecookbook/wiki/Another_page#anchor",
697 :class => "wiki-page"),
699 :class => "wiki-page"),
698 # UTF8 anchor
700 # UTF8 anchor
699 "[[Another_page##{@russian_test}|#{@russian_test}]]" =>
701 "[[Another_page##{@russian_test}|#{@russian_test}]]" =>
700 link_to(@russian_test,
702 link_to(@russian_test,
701 "/projects/ecookbook/wiki/Another_page##{russian_eacape}",
703 "/projects/ecookbook/wiki/Another_page##{russian_eacape}",
702 :class => "wiki-page"),
704 :class => "wiki-page"),
703 # page that doesn't exist
705 # page that doesn't exist
704 '[[Unknown page]]' =>
706 '[[Unknown page]]' =>
705 link_to("Unknown page",
707 link_to("Unknown page",
706 "/projects/ecookbook/wiki/Unknown_page",
708 "/projects/ecookbook/wiki/Unknown_page",
707 :class => "wiki-page new"),
709 :class => "wiki-page new"),
708 '[[Unknown page|404]]' =>
710 '[[Unknown page|404]]' =>
709 link_to("404",
711 link_to("404",
710 "/projects/ecookbook/wiki/Unknown_page",
712 "/projects/ecookbook/wiki/Unknown_page",
711 :class => "wiki-page new"),
713 :class => "wiki-page new"),
712 # link to another project wiki
714 # link to another project wiki
713 '[[onlinestore:]]' =>
715 '[[onlinestore:]]' =>
714 link_to("onlinestore",
716 link_to("onlinestore",
715 "/projects/onlinestore/wiki",
717 "/projects/onlinestore/wiki",
716 :class => "wiki-page"),
718 :class => "wiki-page"),
717 '[[onlinestore:|Wiki]]' =>
719 '[[onlinestore:|Wiki]]' =>
718 link_to("Wiki",
720 link_to("Wiki",
719 "/projects/onlinestore/wiki",
721 "/projects/onlinestore/wiki",
720 :class => "wiki-page"),
722 :class => "wiki-page"),
721 '[[onlinestore:Start page]]' =>
723 '[[onlinestore:Start page]]' =>
722 link_to("Start page",
724 link_to("Start page",
723 "/projects/onlinestore/wiki/Start_page",
725 "/projects/onlinestore/wiki/Start_page",
724 :class => "wiki-page"),
726 :class => "wiki-page"),
725 '[[onlinestore:Start page|Text]]' =>
727 '[[onlinestore:Start page|Text]]' =>
726 link_to("Text",
728 link_to("Text",
727 "/projects/onlinestore/wiki/Start_page",
729 "/projects/onlinestore/wiki/Start_page",
728 :class => "wiki-page"),
730 :class => "wiki-page"),
729 '[[onlinestore:Unknown page]]' =>
731 '[[onlinestore:Unknown page]]' =>
730 link_to("Unknown page",
732 link_to("Unknown page",
731 "/projects/onlinestore/wiki/Unknown_page",
733 "/projects/onlinestore/wiki/Unknown_page",
732 :class => "wiki-page new"),
734 :class => "wiki-page new"),
733 # struck through link
735 # struck through link
734 '-[[Another page|Page]]-' =>
736 '-[[Another page|Page]]-' =>
735 "<del>".html_safe +
737 "<del>".html_safe +
736 link_to("Page",
738 link_to("Page",
737 "/projects/ecookbook/wiki/Another_page",
739 "/projects/ecookbook/wiki/Another_page",
738 :class => "wiki-page").html_safe +
740 :class => "wiki-page").html_safe +
739 "</del>".html_safe,
741 "</del>".html_safe,
740 '-[[Another page|Page]] link-' =>
742 '-[[Another page|Page]] link-' =>
741 "<del>".html_safe +
743 "<del>".html_safe +
742 link_to("Page",
744 link_to("Page",
743 "/projects/ecookbook/wiki/Another_page",
745 "/projects/ecookbook/wiki/Another_page",
744 :class => "wiki-page").html_safe +
746 :class => "wiki-page").html_safe +
745 " link</del>".html_safe,
747 " link</del>".html_safe,
746 # escaping
748 # escaping
747 '![[Another page|Page]]' => '[[Another page|Page]]',
749 '![[Another page|Page]]' => '[[Another page|Page]]',
748 # project does not exist
750 # project does not exist
749 '[[unknowproject:Start]]' => '[[unknowproject:Start]]',
751 '[[unknowproject:Start]]' => '[[unknowproject:Start]]',
750 '[[unknowproject:Start|Page title]]' => '[[unknowproject:Start|Page title]]',
752 '[[unknowproject:Start|Page title]]' => '[[unknowproject:Start|Page title]]',
751 }
753 }
752 @project = Project.find(1)
754 @project = Project.find(1)
753 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
755 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
754 end
756 end
755
757
756 def test_wiki_links_within_local_file_generation_context
758 def test_wiki_links_within_local_file_generation_context
757 to_test = {
759 to_test = {
758 # link to a page
760 # link to a page
759 '[[CookBook documentation]]' =>
761 '[[CookBook documentation]]' =>
760 link_to("CookBook documentation", "CookBook_documentation.html",
762 link_to("CookBook documentation", "CookBook_documentation.html",
761 :class => "wiki-page"),
763 :class => "wiki-page"),
762 '[[CookBook documentation|documentation]]' =>
764 '[[CookBook documentation|documentation]]' =>
763 link_to("documentation", "CookBook_documentation.html",
765 link_to("documentation", "CookBook_documentation.html",
764 :class => "wiki-page"),
766 :class => "wiki-page"),
765 '[[CookBook documentation#One-section]]' =>
767 '[[CookBook documentation#One-section]]' =>
766 link_to("CookBook documentation", "CookBook_documentation.html#One-section",
768 link_to("CookBook documentation", "CookBook_documentation.html#One-section",
767 :class => "wiki-page"),
769 :class => "wiki-page"),
768 '[[CookBook documentation#One-section|documentation]]' =>
770 '[[CookBook documentation#One-section|documentation]]' =>
769 link_to("documentation", "CookBook_documentation.html#One-section",
771 link_to("documentation", "CookBook_documentation.html#One-section",
770 :class => "wiki-page"),
772 :class => "wiki-page"),
771 # page that doesn't exist
773 # page that doesn't exist
772 '[[Unknown page]]' =>
774 '[[Unknown page]]' =>
773 link_to("Unknown page", "Unknown_page.html",
775 link_to("Unknown page", "Unknown_page.html",
774 :class => "wiki-page new"),
776 :class => "wiki-page new"),
775 '[[Unknown page|404]]' =>
777 '[[Unknown page|404]]' =>
776 link_to("404", "Unknown_page.html",
778 link_to("404", "Unknown_page.html",
777 :class => "wiki-page new"),
779 :class => "wiki-page new"),
778 '[[Unknown page#anchor]]' =>
780 '[[Unknown page#anchor]]' =>
779 link_to("Unknown page", "Unknown_page.html#anchor",
781 link_to("Unknown page", "Unknown_page.html#anchor",
780 :class => "wiki-page new"),
782 :class => "wiki-page new"),
781 '[[Unknown page#anchor|404]]' =>
783 '[[Unknown page#anchor|404]]' =>
782 link_to("404", "Unknown_page.html#anchor",
784 link_to("404", "Unknown_page.html#anchor",
783 :class => "wiki-page new"),
785 :class => "wiki-page new"),
784 }
786 }
785 @project = Project.find(1)
787 @project = Project.find(1)
786 to_test.each do |text, result|
788 to_test.each do |text, result|
787 assert_equal "<p>#{result}</p>", textilizable(text, :wiki_links => :local)
789 assert_equal "<p>#{result}</p>", textilizable(text, :wiki_links => :local)
788 end
790 end
789 end
791 end
790
792
791 def test_wiki_links_within_wiki_page_context
793 def test_wiki_links_within_wiki_page_context
792 page = WikiPage.find_by_title('Another_page' )
794 page = WikiPage.find_by_title('Another_page' )
793 to_test = {
795 to_test = {
794 '[[CookBook documentation]]' =>
796 '[[CookBook documentation]]' =>
795 link_to("CookBook documentation",
797 link_to("CookBook documentation",
796 "/projects/ecookbook/wiki/CookBook_documentation",
798 "/projects/ecookbook/wiki/CookBook_documentation",
797 :class => "wiki-page"),
799 :class => "wiki-page"),
798 '[[CookBook documentation|documentation]]' =>
800 '[[CookBook documentation|documentation]]' =>
799 link_to("documentation",
801 link_to("documentation",
800 "/projects/ecookbook/wiki/CookBook_documentation",
802 "/projects/ecookbook/wiki/CookBook_documentation",
801 :class => "wiki-page"),
803 :class => "wiki-page"),
802 '[[CookBook documentation#One-section]]' =>
804 '[[CookBook documentation#One-section]]' =>
803 link_to("CookBook documentation",
805 link_to("CookBook documentation",
804 "/projects/ecookbook/wiki/CookBook_documentation#One-section",
806 "/projects/ecookbook/wiki/CookBook_documentation#One-section",
805 :class => "wiki-page"),
807 :class => "wiki-page"),
806 '[[CookBook documentation#One-section|documentation]]' =>
808 '[[CookBook documentation#One-section|documentation]]' =>
807 link_to("documentation",
809 link_to("documentation",
808 "/projects/ecookbook/wiki/CookBook_documentation#One-section",
810 "/projects/ecookbook/wiki/CookBook_documentation#One-section",
809 :class => "wiki-page"),
811 :class => "wiki-page"),
810 # link to the current page
812 # link to the current page
811 '[[Another page]]' =>
813 '[[Another page]]' =>
812 link_to("Another page",
814 link_to("Another page",
813 "/projects/ecookbook/wiki/Another_page",
815 "/projects/ecookbook/wiki/Another_page",
814 :class => "wiki-page"),
816 :class => "wiki-page"),
815 '[[Another page|Page]]' =>
817 '[[Another page|Page]]' =>
816 link_to("Page",
818 link_to("Page",
817 "/projects/ecookbook/wiki/Another_page",
819 "/projects/ecookbook/wiki/Another_page",
818 :class => "wiki-page"),
820 :class => "wiki-page"),
819 '[[Another page#anchor]]' =>
821 '[[Another page#anchor]]' =>
820 link_to("Another page",
822 link_to("Another page",
821 "#anchor",
823 "#anchor",
822 :class => "wiki-page"),
824 :class => "wiki-page"),
823 '[[Another page#anchor|Page]]' =>
825 '[[Another page#anchor|Page]]' =>
824 link_to("Page",
826 link_to("Page",
825 "#anchor",
827 "#anchor",
826 :class => "wiki-page"),
828 :class => "wiki-page"),
827 # page that doesn't exist
829 # page that doesn't exist
828 '[[Unknown page]]' =>
830 '[[Unknown page]]' =>
829 link_to("Unknown page",
831 link_to("Unknown page",
830 "/projects/ecookbook/wiki/Unknown_page?parent=Another_page",
832 "/projects/ecookbook/wiki/Unknown_page?parent=Another_page",
831 :class => "wiki-page new"),
833 :class => "wiki-page new"),
832 '[[Unknown page|404]]' =>
834 '[[Unknown page|404]]' =>
833 link_to("404",
835 link_to("404",
834 "/projects/ecookbook/wiki/Unknown_page?parent=Another_page",
836 "/projects/ecookbook/wiki/Unknown_page?parent=Another_page",
835 :class => "wiki-page new"),
837 :class => "wiki-page new"),
836 '[[Unknown page#anchor]]' =>
838 '[[Unknown page#anchor]]' =>
837 link_to("Unknown page",
839 link_to("Unknown page",
838 "/projects/ecookbook/wiki/Unknown_page?parent=Another_page#anchor",
840 "/projects/ecookbook/wiki/Unknown_page?parent=Another_page#anchor",
839 :class => "wiki-page new"),
841 :class => "wiki-page new"),
840 '[[Unknown page#anchor|404]]' =>
842 '[[Unknown page#anchor|404]]' =>
841 link_to("404",
843 link_to("404",
842 "/projects/ecookbook/wiki/Unknown_page?parent=Another_page#anchor",
844 "/projects/ecookbook/wiki/Unknown_page?parent=Another_page#anchor",
843 :class => "wiki-page new"),
845 :class => "wiki-page new"),
844 }
846 }
845 @project = Project.find(1)
847 @project = Project.find(1)
846 to_test.each do |text, result|
848 to_test.each do |text, result|
847 assert_equal "<p>#{result}</p>",
849 assert_equal "<p>#{result}</p>",
848 textilizable(WikiContent.new( :text => text, :page => page ), :text)
850 textilizable(WikiContent.new( :text => text, :page => page ), :text)
849 end
851 end
850 end
852 end
851
853
852 def test_wiki_links_anchor_option_should_prepend_page_title_to_href
854 def test_wiki_links_anchor_option_should_prepend_page_title_to_href
853 to_test = {
855 to_test = {
854 # link to a page
856 # link to a page
855 '[[CookBook documentation]]' =>
857 '[[CookBook documentation]]' =>
856 link_to("CookBook documentation",
858 link_to("CookBook documentation",
857 "#CookBook_documentation",
859 "#CookBook_documentation",
858 :class => "wiki-page"),
860 :class => "wiki-page"),
859 '[[CookBook documentation|documentation]]' =>
861 '[[CookBook documentation|documentation]]' =>
860 link_to("documentation",
862 link_to("documentation",
861 "#CookBook_documentation",
863 "#CookBook_documentation",
862 :class => "wiki-page"),
864 :class => "wiki-page"),
863 '[[CookBook documentation#One-section]]' =>
865 '[[CookBook documentation#One-section]]' =>
864 link_to("CookBook documentation",
866 link_to("CookBook documentation",
865 "#CookBook_documentation_One-section",
867 "#CookBook_documentation_One-section",
866 :class => "wiki-page"),
868 :class => "wiki-page"),
867 '[[CookBook documentation#One-section|documentation]]' =>
869 '[[CookBook documentation#One-section|documentation]]' =>
868 link_to("documentation",
870 link_to("documentation",
869 "#CookBook_documentation_One-section",
871 "#CookBook_documentation_One-section",
870 :class => "wiki-page"),
872 :class => "wiki-page"),
871 # page that doesn't exist
873 # page that doesn't exist
872 '[[Unknown page]]' =>
874 '[[Unknown page]]' =>
873 link_to("Unknown page",
875 link_to("Unknown page",
874 "#Unknown_page",
876 "#Unknown_page",
875 :class => "wiki-page new"),
877 :class => "wiki-page new"),
876 '[[Unknown page|404]]' =>
878 '[[Unknown page|404]]' =>
877 link_to("404",
879 link_to("404",
878 "#Unknown_page",
880 "#Unknown_page",
879 :class => "wiki-page new"),
881 :class => "wiki-page new"),
880 '[[Unknown page#anchor]]' =>
882 '[[Unknown page#anchor]]' =>
881 link_to("Unknown page",
883 link_to("Unknown page",
882 "#Unknown_page_anchor",
884 "#Unknown_page_anchor",
883 :class => "wiki-page new"),
885 :class => "wiki-page new"),
884 '[[Unknown page#anchor|404]]' =>
886 '[[Unknown page#anchor|404]]' =>
885 link_to("404",
887 link_to("404",
886 "#Unknown_page_anchor",
888 "#Unknown_page_anchor",
887 :class => "wiki-page new"),
889 :class => "wiki-page new"),
888 }
890 }
889 @project = Project.find(1)
891 @project = Project.find(1)
890 to_test.each do |text, result|
892 to_test.each do |text, result|
891 assert_equal "<p>#{result}</p>", textilizable(text, :wiki_links => :anchor)
893 assert_equal "<p>#{result}</p>", textilizable(text, :wiki_links => :anchor)
892 end
894 end
893 end
895 end
894
896
895 def test_html_tags
897 def test_html_tags
896 to_test = {
898 to_test = {
897 "<div>content</div>" => "<p>&lt;div&gt;content&lt;/div&gt;</p>",
899 "<div>content</div>" => "<p>&lt;div&gt;content&lt;/div&gt;</p>",
898 "<div class=\"bold\">content</div>" => "<p>&lt;div class=\"bold\"&gt;content&lt;/div&gt;</p>",
900 "<div class=\"bold\">content</div>" => "<p>&lt;div class=\"bold\"&gt;content&lt;/div&gt;</p>",
899 "<script>some script;</script>" => "<p>&lt;script&gt;some script;&lt;/script&gt;</p>",
901 "<script>some script;</script>" => "<p>&lt;script&gt;some script;&lt;/script&gt;</p>",
900 # do not escape pre/code tags
902 # do not escape pre/code tags
901 "<pre>\nline 1\nline2</pre>" => "<pre>\nline 1\nline2</pre>",
903 "<pre>\nline 1\nline2</pre>" => "<pre>\nline 1\nline2</pre>",
902 "<pre><code>\nline 1\nline2</code></pre>" => "<pre><code>\nline 1\nline2</code></pre>",
904 "<pre><code>\nline 1\nline2</code></pre>" => "<pre><code>\nline 1\nline2</code></pre>",
903 "<pre><div>content</div></pre>" => "<pre>&lt;div&gt;content&lt;/div&gt;</pre>",
905 "<pre><div>content</div></pre>" => "<pre>&lt;div&gt;content&lt;/div&gt;</pre>",
904 "HTML comment: <!-- no comments -->" => "<p>HTML comment: &lt;!-- no comments --&gt;</p>",
906 "HTML comment: <!-- no comments -->" => "<p>HTML comment: &lt;!-- no comments --&gt;</p>",
905 "<!-- opening comment" => "<p>&lt;!-- opening comment</p>",
907 "<!-- opening comment" => "<p>&lt;!-- opening comment</p>",
906 # remove attributes except class
908 # remove attributes except class
907 "<pre class='foo'>some text</pre>" => "<pre class='foo'>some text</pre>",
909 "<pre class='foo'>some text</pre>" => "<pre class='foo'>some text</pre>",
908 '<pre class="foo">some text</pre>' => '<pre class="foo">some text</pre>',
910 '<pre class="foo">some text</pre>' => '<pre class="foo">some text</pre>',
909 "<pre class='foo bar'>some text</pre>" => "<pre class='foo bar'>some text</pre>",
911 "<pre class='foo bar'>some text</pre>" => "<pre class='foo bar'>some text</pre>",
910 '<pre class="foo bar">some text</pre>' => '<pre class="foo bar">some text</pre>',
912 '<pre class="foo bar">some text</pre>' => '<pre class="foo bar">some text</pre>',
911 "<pre onmouseover='alert(1)'>some text</pre>" => "<pre>some text</pre>",
913 "<pre onmouseover='alert(1)'>some text</pre>" => "<pre>some text</pre>",
912 # xss
914 # xss
913 '<pre><code class=""onmouseover="alert(1)">text</code></pre>' => '<pre><code>text</code></pre>',
915 '<pre><code class=""onmouseover="alert(1)">text</code></pre>' => '<pre><code>text</code></pre>',
914 '<pre class=""onmouseover="alert(1)">text</pre>' => '<pre>text</pre>',
916 '<pre class=""onmouseover="alert(1)">text</pre>' => '<pre>text</pre>',
915 }
917 }
916 to_test.each { |text, result| assert_equal result, textilizable(text) }
918 to_test.each { |text, result| assert_equal result, textilizable(text) }
917 end
919 end
918
920
919 def test_allowed_html_tags
921 def test_allowed_html_tags
920 to_test = {
922 to_test = {
921 "<pre>preformatted text</pre>" => "<pre>preformatted text</pre>",
923 "<pre>preformatted text</pre>" => "<pre>preformatted text</pre>",
922 "<notextile>no *textile* formatting</notextile>" => "no *textile* formatting",
924 "<notextile>no *textile* formatting</notextile>" => "no *textile* formatting",
923 "<notextile>this is <tag>a tag</tag></notextile>" => "this is &lt;tag&gt;a tag&lt;/tag&gt;"
925 "<notextile>this is <tag>a tag</tag></notextile>" => "this is &lt;tag&gt;a tag&lt;/tag&gt;"
924 }
926 }
925 to_test.each { |text, result| assert_equal result, textilizable(text) }
927 to_test.each { |text, result| assert_equal result, textilizable(text) }
926 end
928 end
927
929
928 def test_pre_tags
930 def test_pre_tags
929 raw = <<-RAW
931 raw = <<-RAW
930 Before
932 Before
931
933
932 <pre>
934 <pre>
933 <prepared-statement-cache-size>32</prepared-statement-cache-size>
935 <prepared-statement-cache-size>32</prepared-statement-cache-size>
934 </pre>
936 </pre>
935
937
936 After
938 After
937 RAW
939 RAW
938
940
939 expected = <<-EXPECTED
941 expected = <<-EXPECTED
940 <p>Before</p>
942 <p>Before</p>
941 <pre>
943 <pre>
942 &lt;prepared-statement-cache-size&gt;32&lt;/prepared-statement-cache-size&gt;
944 &lt;prepared-statement-cache-size&gt;32&lt;/prepared-statement-cache-size&gt;
943 </pre>
945 </pre>
944 <p>After</p>
946 <p>After</p>
945 EXPECTED
947 EXPECTED
946
948
947 assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(raw).gsub(%r{[\r\n\t]}, '')
949 assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(raw).gsub(%r{[\r\n\t]}, '')
948 end
950 end
949
951
950 def test_pre_content_should_not_parse_wiki_and_redmine_links
952 def test_pre_content_should_not_parse_wiki_and_redmine_links
951 raw = <<-RAW
953 raw = <<-RAW
952 [[CookBook documentation]]
954 [[CookBook documentation]]
953
955
954 #1
956 #1
955
957
956 <pre>
958 <pre>
957 [[CookBook documentation]]
959 [[CookBook documentation]]
958
960
959 #1
961 #1
960 </pre>
962 </pre>
961 RAW
963 RAW
962
964
963 result1 = link_to("CookBook documentation",
965 result1 = link_to("CookBook documentation",
964 "/projects/ecookbook/wiki/CookBook_documentation",
966 "/projects/ecookbook/wiki/CookBook_documentation",
965 :class => "wiki-page")
967 :class => "wiki-page")
966 result2 = link_to('#1',
968 result2 = link_to('#1',
967 "/issues/1",
969 "/issues/1",
968 :class => Issue.find(1).css_classes,
970 :class => Issue.find(1).css_classes,
969 :title => "Can't print recipes (New)")
971 :title => "Can't print recipes (New)")
970
972
971 expected = <<-EXPECTED
973 expected = <<-EXPECTED
972 <p>#{result1}</p>
974 <p>#{result1}</p>
973 <p>#{result2}</p>
975 <p>#{result2}</p>
974 <pre>
976 <pre>
975 [[CookBook documentation]]
977 [[CookBook documentation]]
976
978
977 #1
979 #1
978 </pre>
980 </pre>
979 EXPECTED
981 EXPECTED
980
982
981 @project = Project.find(1)
983 @project = Project.find(1)
982 assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(raw).gsub(%r{[\r\n\t]}, '')
984 assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(raw).gsub(%r{[\r\n\t]}, '')
983 end
985 end
984
986
985 def test_non_closing_pre_blocks_should_be_closed
987 def test_non_closing_pre_blocks_should_be_closed
986 raw = <<-RAW
988 raw = <<-RAW
987 <pre><code>
989 <pre><code>
988 RAW
990 RAW
989
991
990 expected = <<-EXPECTED
992 expected = <<-EXPECTED
991 <pre><code>
993 <pre><code>
992 </code></pre>
994 </code></pre>
993 EXPECTED
995 EXPECTED
994
996
995 @project = Project.find(1)
997 @project = Project.find(1)
996 assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(raw).gsub(%r{[\r\n\t]}, '')
998 assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(raw).gsub(%r{[\r\n\t]}, '')
997 end
999 end
998
1000
999 def test_syntax_highlight
1001 def test_syntax_highlight
1000 raw = <<-RAW
1002 raw = <<-RAW
1001 <pre><code class="ruby">
1003 <pre><code class="ruby">
1002 # Some ruby code here
1004 # Some ruby code here
1003 </code></pre>
1005 </code></pre>
1004 RAW
1006 RAW
1005
1007
1006 expected = <<-EXPECTED
1008 expected = <<-EXPECTED
1007 <pre><code class="ruby syntaxhl"><span class=\"CodeRay\"><span class="comment"># Some ruby code here</span></span>
1009 <pre><code class="ruby syntaxhl"><span class=\"CodeRay\"><span class="comment"># Some ruby code here</span></span>
1008 </code></pre>
1010 </code></pre>
1009 EXPECTED
1011 EXPECTED
1010
1012
1011 assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(raw).gsub(%r{[\r\n\t]}, '')
1013 assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(raw).gsub(%r{[\r\n\t]}, '')
1012 end
1014 end
1013
1015
1014 def test_to_path_param
1016 def test_to_path_param
1015 assert_equal 'test1/test2', to_path_param('test1/test2')
1017 assert_equal 'test1/test2', to_path_param('test1/test2')
1016 assert_equal 'test1/test2', to_path_param('/test1/test2/')
1018 assert_equal 'test1/test2', to_path_param('/test1/test2/')
1017 assert_equal 'test1/test2', to_path_param('//test1/test2/')
1019 assert_equal 'test1/test2', to_path_param('//test1/test2/')
1018 assert_equal nil, to_path_param('/')
1020 assert_equal nil, to_path_param('/')
1019 end
1021 end
1020
1022
1021 def test_wiki_links_in_tables
1023 def test_wiki_links_in_tables
1022 text = "|[[Page|Link title]]|[[Other Page|Other title]]|\n|Cell 21|[[Last page]]|"
1024 text = "|[[Page|Link title]]|[[Other Page|Other title]]|\n|Cell 21|[[Last page]]|"
1023 link1 = link_to("Link title", "/projects/ecookbook/wiki/Page", :class => "wiki-page new")
1025 link1 = link_to("Link title", "/projects/ecookbook/wiki/Page", :class => "wiki-page new")
1024 link2 = link_to("Other title", "/projects/ecookbook/wiki/Other_Page", :class => "wiki-page new")
1026 link2 = link_to("Other title", "/projects/ecookbook/wiki/Other_Page", :class => "wiki-page new")
1025 link3 = link_to("Last page", "/projects/ecookbook/wiki/Last_page", :class => "wiki-page new")
1027 link3 = link_to("Last page", "/projects/ecookbook/wiki/Last_page", :class => "wiki-page new")
1026 result = "<tr><td>#{link1}</td>" +
1028 result = "<tr><td>#{link1}</td>" +
1027 "<td>#{link2}</td>" +
1029 "<td>#{link2}</td>" +
1028 "</tr><tr><td>Cell 21</td><td>#{link3}</td></tr>"
1030 "</tr><tr><td>Cell 21</td><td>#{link3}</td></tr>"
1029 @project = Project.find(1)
1031 @project = Project.find(1)
1030 assert_equal "<table>#{result}</table>", textilizable(text).gsub(/[\t\n]/, '')
1032 assert_equal "<table>#{result}</table>", textilizable(text).gsub(/[\t\n]/, '')
1031 end
1033 end
1032
1034
1033 def test_text_formatting
1035 def test_text_formatting
1034 to_test = {'*_+bold, italic and underline+_*' => '<strong><em><ins>bold, italic and underline</ins></em></strong>',
1036 to_test = {'*_+bold, italic and underline+_*' => '<strong><em><ins>bold, italic and underline</ins></em></strong>',
1035 '(_text within parentheses_)' => '(<em>text within parentheses</em>)',
1037 '(_text within parentheses_)' => '(<em>text within parentheses</em>)',
1036 'a *Humane Web* Text Generator' => 'a <strong>Humane Web</strong> Text Generator',
1038 'a *Humane Web* Text Generator' => 'a <strong>Humane Web</strong> Text Generator',
1037 'a H *umane* W *eb* T *ext* G *enerator*' => 'a H <strong>umane</strong> W <strong>eb</strong> T <strong>ext</strong> G <strong>enerator</strong>',
1039 'a H *umane* W *eb* T *ext* G *enerator*' => 'a H <strong>umane</strong> W <strong>eb</strong> T <strong>ext</strong> G <strong>enerator</strong>',
1038 'a *H* umane *W* eb *T* ext *G* enerator' => 'a <strong>H</strong> umane <strong>W</strong> eb <strong>T</strong> ext <strong>G</strong> enerator',
1040 'a *H* umane *W* eb *T* ext *G* enerator' => 'a <strong>H</strong> umane <strong>W</strong> eb <strong>T</strong> ext <strong>G</strong> enerator',
1039 }
1041 }
1040 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
1042 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
1041 end
1043 end
1042
1044
1043 def test_wiki_horizontal_rule
1045 def test_wiki_horizontal_rule
1044 assert_equal '<hr />', textilizable('---')
1046 assert_equal '<hr />', textilizable('---')
1045 assert_equal '<p>Dashes: ---</p>', textilizable('Dashes: ---')
1047 assert_equal '<p>Dashes: ---</p>', textilizable('Dashes: ---')
1046 end
1048 end
1047
1049
1048 def test_footnotes
1050 def test_footnotes
1049 raw = <<-RAW
1051 raw = <<-RAW
1050 This is some text[1].
1052 This is some text[1].
1051
1053
1052 fn1. This is the foot note
1054 fn1. This is the foot note
1053 RAW
1055 RAW
1054
1056
1055 expected = <<-EXPECTED
1057 expected = <<-EXPECTED
1056 <p>This is some text<sup><a href=\"#fn1\">1</a></sup>.</p>
1058 <p>This is some text<sup><a href=\"#fn1\">1</a></sup>.</p>
1057 <p id="fn1" class="footnote"><sup>1</sup> This is the foot note</p>
1059 <p id="fn1" class="footnote"><sup>1</sup> This is the foot note</p>
1058 EXPECTED
1060 EXPECTED
1059
1061
1060 assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(raw).gsub(%r{[\r\n\t]}, '')
1062 assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(raw).gsub(%r{[\r\n\t]}, '')
1061 end
1063 end
1062
1064
1063 def test_headings
1065 def test_headings
1064 raw = 'h1. Some heading'
1066 raw = 'h1. Some heading'
1065 expected = %|<a name="Some-heading"></a>\n<h1 >Some heading<a href="#Some-heading" class="wiki-anchor">&para;</a></h1>|
1067 expected = %|<a name="Some-heading"></a>\n<h1 >Some heading<a href="#Some-heading" class="wiki-anchor">&para;</a></h1>|
1066
1068
1067 assert_equal expected, textilizable(raw)
1069 assert_equal expected, textilizable(raw)
1068 end
1070 end
1069
1071
1070 def test_headings_with_special_chars
1072 def test_headings_with_special_chars
1071 # This test makes sure that the generated anchor names match the expected
1073 # This test makes sure that the generated anchor names match the expected
1072 # ones even if the heading text contains unconventional characters
1074 # ones even if the heading text contains unconventional characters
1073 raw = 'h1. Some heading related to version 0.5'
1075 raw = 'h1. Some heading related to version 0.5'
1074 anchor = sanitize_anchor_name("Some-heading-related-to-version-0.5")
1076 anchor = sanitize_anchor_name("Some-heading-related-to-version-0.5")
1075 expected = %|<a name="#{anchor}"></a>\n<h1 >Some heading related to version 0.5<a href="##{anchor}" class="wiki-anchor">&para;</a></h1>|
1077 expected = %|<a name="#{anchor}"></a>\n<h1 >Some heading related to version 0.5<a href="##{anchor}" class="wiki-anchor">&para;</a></h1>|
1076
1078
1077 assert_equal expected, textilizable(raw)
1079 assert_equal expected, textilizable(raw)
1078 end
1080 end
1079
1081
1080 def test_headings_in_wiki_single_page_export_should_be_prepended_with_page_title
1082 def test_headings_in_wiki_single_page_export_should_be_prepended_with_page_title
1081 page = WikiPage.new( :title => 'Page Title', :wiki_id => 1 )
1083 page = WikiPage.new( :title => 'Page Title', :wiki_id => 1 )
1082 content = WikiContent.new( :text => 'h1. Some heading', :page => page )
1084 content = WikiContent.new( :text => 'h1. Some heading', :page => page )
1083
1085
1084 expected = %|<a name="Page_Title_Some-heading"></a>\n<h1 >Some heading<a href="#Page_Title_Some-heading" class="wiki-anchor">&para;</a></h1>|
1086 expected = %|<a name="Page_Title_Some-heading"></a>\n<h1 >Some heading<a href="#Page_Title_Some-heading" class="wiki-anchor">&para;</a></h1>|
1085
1087
1086 assert_equal expected, textilizable(content, :text, :wiki_links => :anchor )
1088 assert_equal expected, textilizable(content, :text, :wiki_links => :anchor )
1087 end
1089 end
1088
1090
1089 def test_table_of_content
1091 def test_table_of_content
1090 raw = <<-RAW
1092 raw = <<-RAW
1091 {{toc}}
1093 {{toc}}
1092
1094
1093 h1. Title
1095 h1. Title
1094
1096
1095 Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas sed libero.
1097 Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas sed libero.
1096
1098
1097 h2. Subtitle with a [[Wiki]] link
1099 h2. Subtitle with a [[Wiki]] link
1098
1100
1099 Nullam commodo metus accumsan nulla. Curabitur lobortis dui id dolor.
1101 Nullam commodo metus accumsan nulla. Curabitur lobortis dui id dolor.
1100
1102
1101 h2. Subtitle with [[Wiki|another Wiki]] link
1103 h2. Subtitle with [[Wiki|another Wiki]] link
1102
1104
1103 h2. Subtitle with %{color:red}red text%
1105 h2. Subtitle with %{color:red}red text%
1104
1106
1105 <pre>
1107 <pre>
1106 some code
1108 some code
1107 </pre>
1109 </pre>
1108
1110
1109 h3. Subtitle with *some* _modifiers_
1111 h3. Subtitle with *some* _modifiers_
1110
1112
1111 h3. Subtitle with @inline code@
1113 h3. Subtitle with @inline code@
1112
1114
1113 h1. Another title
1115 h1. Another title
1114
1116
1115 h3. An "Internet link":http://www.redmine.org/ inside subtitle
1117 h3. An "Internet link":http://www.redmine.org/ inside subtitle
1116
1118
1117 h2. "Project Name !/attachments/1234/logo_small.gif! !/attachments/5678/logo_2.png!":/projects/projectname/issues
1119 h2. "Project Name !/attachments/1234/logo_small.gif! !/attachments/5678/logo_2.png!":/projects/projectname/issues
1118
1120
1119 RAW
1121 RAW
1120
1122
1121 expected = '<ul class="toc">' +
1123 expected = '<ul class="toc">' +
1122 '<li><a href="#Title">Title</a>' +
1124 '<li><a href="#Title">Title</a>' +
1123 '<ul>' +
1125 '<ul>' +
1124 '<li><a href="#Subtitle-with-a-Wiki-link">Subtitle with a Wiki link</a></li>' +
1126 '<li><a href="#Subtitle-with-a-Wiki-link">Subtitle with a Wiki link</a></li>' +
1125 '<li><a href="#Subtitle-with-another-Wiki-link">Subtitle with another Wiki link</a></li>' +
1127 '<li><a href="#Subtitle-with-another-Wiki-link">Subtitle with another Wiki link</a></li>' +
1126 '<li><a href="#Subtitle-with-red-text">Subtitle with red text</a>' +
1128 '<li><a href="#Subtitle-with-red-text">Subtitle with red text</a>' +
1127 '<ul>' +
1129 '<ul>' +
1128 '<li><a href="#Subtitle-with-some-modifiers">Subtitle with some modifiers</a></li>' +
1130 '<li><a href="#Subtitle-with-some-modifiers">Subtitle with some modifiers</a></li>' +
1129 '<li><a href="#Subtitle-with-inline-code">Subtitle with inline code</a></li>' +
1131 '<li><a href="#Subtitle-with-inline-code">Subtitle with inline code</a></li>' +
1130 '</ul>' +
1132 '</ul>' +
1131 '</li>' +
1133 '</li>' +
1132 '</ul>' +
1134 '</ul>' +
1133 '</li>' +
1135 '</li>' +
1134 '<li><a href="#Another-title">Another title</a>' +
1136 '<li><a href="#Another-title">Another title</a>' +
1135 '<ul>' +
1137 '<ul>' +
1136 '<li>' +
1138 '<li>' +
1137 '<ul>' +
1139 '<ul>' +
1138 '<li><a href="#An-Internet-link-inside-subtitle">An Internet link inside subtitle</a></li>' +
1140 '<li><a href="#An-Internet-link-inside-subtitle">An Internet link inside subtitle</a></li>' +
1139 '</ul>' +
1141 '</ul>' +
1140 '</li>' +
1142 '</li>' +
1141 '<li><a href="#Project-Name">Project Name</a></li>' +
1143 '<li><a href="#Project-Name">Project Name</a></li>' +
1142 '</ul>' +
1144 '</ul>' +
1143 '</li>' +
1145 '</li>' +
1144 '</ul>'
1146 '</ul>'
1145
1147
1146 @project = Project.find(1)
1148 @project = Project.find(1)
1147 assert textilizable(raw).gsub("\n", "").include?(expected)
1149 assert textilizable(raw).gsub("\n", "").include?(expected)
1148 end
1150 end
1149
1151
1150 def test_table_of_content_should_generate_unique_anchors
1152 def test_table_of_content_should_generate_unique_anchors
1151 raw = <<-RAW
1153 raw = <<-RAW
1152 {{toc}}
1154 {{toc}}
1153
1155
1154 h1. Title
1156 h1. Title
1155
1157
1156 h2. Subtitle
1158 h2. Subtitle
1157
1159
1158 h2. Subtitle
1160 h2. Subtitle
1159 RAW
1161 RAW
1160
1162
1161 expected = '<ul class="toc">' +
1163 expected = '<ul class="toc">' +
1162 '<li><a href="#Title">Title</a>' +
1164 '<li><a href="#Title">Title</a>' +
1163 '<ul>' +
1165 '<ul>' +
1164 '<li><a href="#Subtitle">Subtitle</a></li>' +
1166 '<li><a href="#Subtitle">Subtitle</a></li>' +
1165 '<li><a href="#Subtitle-2">Subtitle</a></li>'
1167 '<li><a href="#Subtitle-2">Subtitle</a></li>'
1166 '</ul>'
1168 '</ul>'
1167 '</li>' +
1169 '</li>' +
1168 '</ul>'
1170 '</ul>'
1169
1171
1170 @project = Project.find(1)
1172 @project = Project.find(1)
1171 result = textilizable(raw).gsub("\n", "")
1173 result = textilizable(raw).gsub("\n", "")
1172 assert_include expected, result
1174 assert_include expected, result
1173 assert_include '<a name="Subtitle">', result
1175 assert_include '<a name="Subtitle">', result
1174 assert_include '<a name="Subtitle-2">', result
1176 assert_include '<a name="Subtitle-2">', result
1175 end
1177 end
1176
1178
1177 def test_table_of_content_should_contain_included_page_headings
1179 def test_table_of_content_should_contain_included_page_headings
1178 raw = <<-RAW
1180 raw = <<-RAW
1179 {{toc}}
1181 {{toc}}
1180
1182
1181 h1. Included
1183 h1. Included
1182
1184
1183 {{include(Child_1)}}
1185 {{include(Child_1)}}
1184 RAW
1186 RAW
1185
1187
1186 expected = '<ul class="toc">' +
1188 expected = '<ul class="toc">' +
1187 '<li><a href="#Included">Included</a></li>' +
1189 '<li><a href="#Included">Included</a></li>' +
1188 '<li><a href="#Child-page-1">Child page 1</a></li>' +
1190 '<li><a href="#Child-page-1">Child page 1</a></li>' +
1189 '</ul>'
1191 '</ul>'
1190
1192
1191 @project = Project.find(1)
1193 @project = Project.find(1)
1192 assert textilizable(raw).gsub("\n", "").include?(expected)
1194 assert textilizable(raw).gsub("\n", "").include?(expected)
1193 end
1195 end
1194
1196
1195 def test_toc_with_textile_formatting_should_be_parsed
1197 def test_toc_with_textile_formatting_should_be_parsed
1196 with_settings :text_formatting => 'textile' do
1198 with_settings :text_formatting => 'textile' do
1197 assert_select_in textilizable("{{toc}}\n\nh1. Heading"), 'ul.toc li', :text => 'Heading'
1199 assert_select_in textilizable("{{toc}}\n\nh1. Heading"), 'ul.toc li', :text => 'Heading'
1198 assert_select_in textilizable("{{<toc}}\n\nh1. Heading"), 'ul.toc.left li', :text => 'Heading'
1200 assert_select_in textilizable("{{<toc}}\n\nh1. Heading"), 'ul.toc.left li', :text => 'Heading'
1199 assert_select_in textilizable("{{>toc}}\n\nh1. Heading"), 'ul.toc.right li', :text => 'Heading'
1201 assert_select_in textilizable("{{>toc}}\n\nh1. Heading"), 'ul.toc.right li', :text => 'Heading'
1200 end
1202 end
1201 end
1203 end
1202
1204
1203 if Object.const_defined?(:Redcarpet)
1205 if Object.const_defined?(:Redcarpet)
1204 def test_toc_with_markdown_formatting_should_be_parsed
1206 def test_toc_with_markdown_formatting_should_be_parsed
1205 with_settings :text_formatting => 'markdown' do
1207 with_settings :text_formatting => 'markdown' do
1206 assert_select_in textilizable("{{toc}}\n\n# Heading"), 'ul.toc li', :text => 'Heading'
1208 assert_select_in textilizable("{{toc}}\n\n# Heading"), 'ul.toc li', :text => 'Heading'
1207 assert_select_in textilizable("{{<toc}}\n\n# Heading"), 'ul.toc.left li', :text => 'Heading'
1209 assert_select_in textilizable("{{<toc}}\n\n# Heading"), 'ul.toc.left li', :text => 'Heading'
1208 assert_select_in textilizable("{{>toc}}\n\n# Heading"), 'ul.toc.right li', :text => 'Heading'
1210 assert_select_in textilizable("{{>toc}}\n\n# Heading"), 'ul.toc.right li', :text => 'Heading'
1209 end
1211 end
1210 end
1212 end
1211 end
1213 end
1212
1214
1213 def test_section_edit_links
1215 def test_section_edit_links
1214 raw = <<-RAW
1216 raw = <<-RAW
1215 h1. Title
1217 h1. Title
1216
1218
1217 Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas sed libero.
1219 Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas sed libero.
1218
1220
1219 h2. Subtitle with a [[Wiki]] link
1221 h2. Subtitle with a [[Wiki]] link
1220
1222
1221 h2. Subtitle with *some* _modifiers_
1223 h2. Subtitle with *some* _modifiers_
1222
1224
1223 h2. Subtitle with @inline code@
1225 h2. Subtitle with @inline code@
1224
1226
1225 <pre>
1227 <pre>
1226 some code
1228 some code
1227
1229
1228 h2. heading inside pre
1230 h2. heading inside pre
1229
1231
1230 <h2>html heading inside pre</h2>
1232 <h2>html heading inside pre</h2>
1231 </pre>
1233 </pre>
1232
1234
1233 h2. Subtitle after pre tag
1235 h2. Subtitle after pre tag
1234 RAW
1236 RAW
1235
1237
1236 @project = Project.find(1)
1238 @project = Project.find(1)
1237 set_language_if_valid 'en'
1239 set_language_if_valid 'en'
1238 result = textilizable(raw, :edit_section_links => {:controller => 'wiki', :action => 'edit', :project_id => '1', :id => 'Test'}).gsub("\n", "")
1240 result = textilizable(raw, :edit_section_links => {:controller => 'wiki', :action => 'edit', :project_id => '1', :id => 'Test'}).gsub("\n", "")
1239
1241
1240 # heading that contains inline code
1242 # heading that contains inline code
1241 assert_match Regexp.new('<div class="contextual" id="section-4" title="Edit this section">' +
1243 assert_match Regexp.new('<div class="contextual" id="section-4" title="Edit this section">' +
1242 '<a href="/projects/1/wiki/Test/edit\?section=4"><img alt="Edit" src="/images/edit.png(\?\d+)?" /></a></div>' +
1244 '<a href="/projects/1/wiki/Test/edit\?section=4"><img alt="Edit" src="/images/edit.png(\?\d+)?" /></a></div>' +
1243 '<a name="Subtitle-with-inline-code"></a>' +
1245 '<a name="Subtitle-with-inline-code"></a>' +
1244 '<h2 >Subtitle with <code>inline code</code><a href="#Subtitle-with-inline-code" class="wiki-anchor">&para;</a></h2>'),
1246 '<h2 >Subtitle with <code>inline code</code><a href="#Subtitle-with-inline-code" class="wiki-anchor">&para;</a></h2>'),
1245 result
1247 result
1246
1248
1247 # last heading
1249 # last heading
1248 assert_match Regexp.new('<div class="contextual" id="section-5" title="Edit this section">' +
1250 assert_match Regexp.new('<div class="contextual" id="section-5" title="Edit this section">' +
1249 '<a href="/projects/1/wiki/Test/edit\?section=5"><img alt="Edit" src="/images/edit.png(\?\d+)?" /></a></div>' +
1251 '<a href="/projects/1/wiki/Test/edit\?section=5"><img alt="Edit" src="/images/edit.png(\?\d+)?" /></a></div>' +
1250 '<a name="Subtitle-after-pre-tag"></a>' +
1252 '<a name="Subtitle-after-pre-tag"></a>' +
1251 '<h2 >Subtitle after pre tag<a href="#Subtitle-after-pre-tag" class="wiki-anchor">&para;</a></h2>'),
1253 '<h2 >Subtitle after pre tag<a href="#Subtitle-after-pre-tag" class="wiki-anchor">&para;</a></h2>'),
1252 result
1254 result
1253 end
1255 end
1254
1256
1255 def test_default_formatter
1257 def test_default_formatter
1256 with_settings :text_formatting => 'unknown' do
1258 with_settings :text_formatting => 'unknown' do
1257 text = 'a *link*: http://www.example.net/'
1259 text = 'a *link*: http://www.example.net/'
1258 assert_equal '<p>a *link*: <a class="external" href="http://www.example.net/">http://www.example.net/</a></p>', textilizable(text)
1260 assert_equal '<p>a *link*: <a class="external" href="http://www.example.net/">http://www.example.net/</a></p>', textilizable(text)
1259 end
1261 end
1260 end
1262 end
1261
1263
1262 def test_due_date_distance_in_words
1264 def test_due_date_distance_in_words
1263 to_test = { Date.today => 'Due in 0 days',
1265 to_test = { Date.today => 'Due in 0 days',
1264 Date.today + 1 => 'Due in 1 day',
1266 Date.today + 1 => 'Due in 1 day',
1265 Date.today + 100 => 'Due in about 3 months',
1267 Date.today + 100 => 'Due in about 3 months',
1266 Date.today + 20000 => 'Due in over 54 years',
1268 Date.today + 20000 => 'Due in over 54 years',
1267 Date.today - 1 => '1 day late',
1269 Date.today - 1 => '1 day late',
1268 Date.today - 100 => 'about 3 months late',
1270 Date.today - 100 => 'about 3 months late',
1269 Date.today - 20000 => 'over 54 years late',
1271 Date.today - 20000 => 'over 54 years late',
1270 }
1272 }
1271 ::I18n.locale = :en
1273 ::I18n.locale = :en
1272 to_test.each do |date, expected|
1274 to_test.each do |date, expected|
1273 assert_equal expected, due_date_distance_in_words(date)
1275 assert_equal expected, due_date_distance_in_words(date)
1274 end
1276 end
1275 end
1277 end
1276
1278
1277 def test_avatar_enabled
1279 def test_avatar_enabled
1278 with_settings :gravatar_enabled => '1' do
1280 with_settings :gravatar_enabled => '1' do
1279 assert avatar(User.find_by_mail('jsmith@somenet.foo')).include?(Digest::MD5.hexdigest('jsmith@somenet.foo'))
1281 assert avatar(User.find_by_mail('jsmith@somenet.foo')).include?(Digest::MD5.hexdigest('jsmith@somenet.foo'))
1280 assert avatar('jsmith <jsmith@somenet.foo>').include?(Digest::MD5.hexdigest('jsmith@somenet.foo'))
1282 assert avatar('jsmith <jsmith@somenet.foo>').include?(Digest::MD5.hexdigest('jsmith@somenet.foo'))
1281 # Default size is 50
1283 # Default size is 50
1282 assert avatar('jsmith <jsmith@somenet.foo>').include?('size=50')
1284 assert avatar('jsmith <jsmith@somenet.foo>').include?('size=50')
1283 assert avatar('jsmith <jsmith@somenet.foo>', :size => 24).include?('size=24')
1285 assert avatar('jsmith <jsmith@somenet.foo>', :size => 24).include?('size=24')
1284 # Non-avatar options should be considered html options
1286 # Non-avatar options should be considered html options
1285 assert avatar('jsmith <jsmith@somenet.foo>', :title => 'John Smith').include?('title="John Smith"')
1287 assert avatar('jsmith <jsmith@somenet.foo>', :title => 'John Smith').include?('title="John Smith"')
1286 # The default class of the img tag should be gravatar
1288 # The default class of the img tag should be gravatar
1287 assert avatar('jsmith <jsmith@somenet.foo>').include?('class="gravatar"')
1289 assert avatar('jsmith <jsmith@somenet.foo>').include?('class="gravatar"')
1288 assert !avatar('jsmith <jsmith@somenet.foo>', :class => 'picture').include?('class="gravatar"')
1290 assert !avatar('jsmith <jsmith@somenet.foo>', :class => 'picture').include?('class="gravatar"')
1289 assert_nil avatar('jsmith')
1291 assert_nil avatar('jsmith')
1290 assert_nil avatar(nil)
1292 assert_nil avatar(nil)
1291 end
1293 end
1292 end
1294 end
1293
1295
1294 def test_avatar_disabled
1296 def test_avatar_disabled
1295 with_settings :gravatar_enabled => '0' do
1297 with_settings :gravatar_enabled => '0' do
1296 assert_equal '', avatar(User.find_by_mail('jsmith@somenet.foo'))
1298 assert_equal '', avatar(User.find_by_mail('jsmith@somenet.foo'))
1297 end
1299 end
1298 end
1300 end
1299
1301
1300 def test_link_to_user
1302 def test_link_to_user
1301 user = User.find(2)
1303 user = User.find(2)
1302 result = link_to("John Smith", "/users/2", :class => "user active")
1304 result = link_to("John Smith", "/users/2", :class => "user active")
1303 assert_equal result, link_to_user(user)
1305 assert_equal result, link_to_user(user)
1304 end
1306 end
1305
1307
1306 def test_link_to_user_should_not_link_to_locked_user
1308 def test_link_to_user_should_not_link_to_locked_user
1307 with_current_user nil do
1309 with_current_user nil do
1308 user = User.find(5)
1310 user = User.find(5)
1309 assert user.locked?
1311 assert user.locked?
1310 assert_equal 'Dave2 Lopper2', link_to_user(user)
1312 assert_equal 'Dave2 Lopper2', link_to_user(user)
1311 end
1313 end
1312 end
1314 end
1313
1315
1314 def test_link_to_user_should_link_to_locked_user_if_current_user_is_admin
1316 def test_link_to_user_should_link_to_locked_user_if_current_user_is_admin
1315 with_current_user User.find(1) do
1317 with_current_user User.find(1) do
1316 user = User.find(5)
1318 user = User.find(5)
1317 assert user.locked?
1319 assert user.locked?
1318 result = link_to("Dave2 Lopper2", "/users/5", :class => "user locked")
1320 result = link_to("Dave2 Lopper2", "/users/5", :class => "user locked")
1319 assert_equal result, link_to_user(user)
1321 assert_equal result, link_to_user(user)
1320 end
1322 end
1321 end
1323 end
1322
1324
1323 def test_link_to_user_should_not_link_to_anonymous
1325 def test_link_to_user_should_not_link_to_anonymous
1324 user = User.anonymous
1326 user = User.anonymous
1325 assert user.anonymous?
1327 assert user.anonymous?
1326 t = link_to_user(user)
1328 t = link_to_user(user)
1327 assert_equal ::I18n.t(:label_user_anonymous), t
1329 assert_equal ::I18n.t(:label_user_anonymous), t
1328 end
1330 end
1329
1331
1330 def test_link_to_attachment
1332 def test_link_to_attachment
1331 a = Attachment.find(3)
1333 a = Attachment.find(3)
1332 assert_equal '<a href="/attachments/3/logo.gif">logo.gif</a>',
1334 assert_equal '<a href="/attachments/3/logo.gif">logo.gif</a>',
1333 link_to_attachment(a)
1335 link_to_attachment(a)
1334 assert_equal '<a href="/attachments/3/logo.gif">Text</a>',
1336 assert_equal '<a href="/attachments/3/logo.gif">Text</a>',
1335 link_to_attachment(a, :text => 'Text')
1337 link_to_attachment(a, :text => 'Text')
1336 result = link_to("logo.gif", "/attachments/3/logo.gif", :class => "foo")
1338 result = link_to("logo.gif", "/attachments/3/logo.gif", :class => "foo")
1337 assert_equal result,
1339 assert_equal result,
1338 link_to_attachment(a, :class => 'foo')
1340 link_to_attachment(a, :class => 'foo')
1339 assert_equal '<a href="/attachments/download/3/logo.gif">logo.gif</a>',
1341 assert_equal '<a href="/attachments/download/3/logo.gif">logo.gif</a>',
1340 link_to_attachment(a, :download => true)
1342 link_to_attachment(a, :download => true)
1341 assert_equal '<a href="http://test.host/attachments/3/logo.gif">logo.gif</a>',
1343 assert_equal '<a href="http://test.host/attachments/3/logo.gif">logo.gif</a>',
1342 link_to_attachment(a, :only_path => false)
1344 link_to_attachment(a, :only_path => false)
1343 end
1345 end
1344
1346
1345 def test_thumbnail_tag
1347 def test_thumbnail_tag
1346 a = Attachment.find(3)
1348 a = Attachment.find(3)
1347 assert_equal '<a href="/attachments/3/logo.gif" title="logo.gif"><img alt="3" src="/attachments/thumbnail/3" /></a>',
1349 assert_equal '<a href="/attachments/3/logo.gif" title="logo.gif"><img alt="3" src="/attachments/thumbnail/3" /></a>',
1348 thumbnail_tag(a)
1350 thumbnail_tag(a)
1349 end
1351 end
1350
1352
1351 def test_link_to_project
1353 def test_link_to_project
1352 project = Project.find(1)
1354 project = Project.find(1)
1353 assert_equal %(<a href="/projects/ecookbook">eCookbook</a>),
1355 assert_equal %(<a href="/projects/ecookbook">eCookbook</a>),
1354 link_to_project(project)
1356 link_to_project(project)
1355 assert_equal %(<a href="/projects/ecookbook/settings">eCookbook</a>),
1357 assert_equal %(<a href="/projects/ecookbook/settings">eCookbook</a>),
1356 link_to_project(project, :action => 'settings')
1358 link_to_project(project, :action => 'settings')
1357 assert_equal %(<a href="http://test.host/projects/ecookbook?jump=blah">eCookbook</a>),
1359 assert_equal %(<a href="http://test.host/projects/ecookbook?jump=blah">eCookbook</a>),
1358 link_to_project(project, {:only_path => false, :jump => 'blah'})
1360 link_to_project(project, {:only_path => false, :jump => 'blah'})
1359 result = link_to("eCookbook", "/projects/ecookbook/settings", :class => "project")
1361 result = link_to("eCookbook", "/projects/ecookbook/settings", :class => "project")
1360 assert_equal result,
1362 assert_equal result,
1361 link_to_project(project, {:action => 'settings'}, :class => "project")
1363 link_to_project(project, {:action => 'settings'}, :class => "project")
1362 end
1364 end
1363
1365
1364 def test_link_to_project_settings
1366 def test_link_to_project_settings
1365 project = Project.find(1)
1367 project = Project.find(1)
1366 assert_equal '<a href="/projects/ecookbook/settings">eCookbook</a>', link_to_project_settings(project)
1368 assert_equal '<a href="/projects/ecookbook/settings">eCookbook</a>', link_to_project_settings(project)
1367
1369
1368 project.status = Project::STATUS_CLOSED
1370 project.status = Project::STATUS_CLOSED
1369 assert_equal '<a href="/projects/ecookbook">eCookbook</a>', link_to_project_settings(project)
1371 assert_equal '<a href="/projects/ecookbook">eCookbook</a>', link_to_project_settings(project)
1370
1372
1371 project.status = Project::STATUS_ARCHIVED
1373 project.status = Project::STATUS_ARCHIVED
1372 assert_equal 'eCookbook', link_to_project_settings(project)
1374 assert_equal 'eCookbook', link_to_project_settings(project)
1373 end
1375 end
1374
1376
1375 def test_link_to_legacy_project_with_numerical_identifier_should_use_id
1377 def test_link_to_legacy_project_with_numerical_identifier_should_use_id
1376 # numeric identifier are no longer allowed
1378 # numeric identifier are no longer allowed
1377 Project.where(:id => 1).update_all(:identifier => 25)
1379 Project.where(:id => 1).update_all(:identifier => 25)
1378 assert_equal '<a href="/projects/1">eCookbook</a>',
1380 assert_equal '<a href="/projects/1">eCookbook</a>',
1379 link_to_project(Project.find(1))
1381 link_to_project(Project.find(1))
1380 end
1382 end
1381
1383
1382 def test_principals_options_for_select_with_users
1384 def test_principals_options_for_select_with_users
1383 User.current = nil
1385 User.current = nil
1384 users = [User.find(2), User.find(4)]
1386 users = [User.find(2), User.find(4)]
1385 assert_equal %(<option value="2">John Smith</option><option value="4">Robert Hill</option>),
1387 assert_equal %(<option value="2">John Smith</option><option value="4">Robert Hill</option>),
1386 principals_options_for_select(users)
1388 principals_options_for_select(users)
1387 end
1389 end
1388
1390
1389 def test_principals_options_for_select_with_selected
1391 def test_principals_options_for_select_with_selected
1390 User.current = nil
1392 User.current = nil
1391 users = [User.find(2), User.find(4)]
1393 users = [User.find(2), User.find(4)]
1392 assert_equal %(<option value="2">John Smith</option><option value="4" selected="selected">Robert Hill</option>),
1394 assert_equal %(<option value="2">John Smith</option><option value="4" selected="selected">Robert Hill</option>),
1393 principals_options_for_select(users, User.find(4))
1395 principals_options_for_select(users, User.find(4))
1394 end
1396 end
1395
1397
1396 def test_principals_options_for_select_with_users_and_groups
1398 def test_principals_options_for_select_with_users_and_groups
1397 User.current = nil
1399 User.current = nil
1398 users = [User.find(2), Group.find(11), User.find(4), Group.find(10)]
1400 users = [User.find(2), Group.find(11), User.find(4), Group.find(10)]
1399 assert_equal %(<option value="2">John Smith</option><option value="4">Robert Hill</option>) +
1401 assert_equal %(<option value="2">John Smith</option><option value="4">Robert Hill</option>) +
1400 %(<optgroup label="Groups"><option value="10">A Team</option><option value="11">B Team</option></optgroup>),
1402 %(<optgroup label="Groups"><option value="10">A Team</option><option value="11">B Team</option></optgroup>),
1401 principals_options_for_select(users)
1403 principals_options_for_select(users)
1402 end
1404 end
1403
1405
1404 def test_principals_options_for_select_with_empty_collection
1406 def test_principals_options_for_select_with_empty_collection
1405 assert_equal '', principals_options_for_select([])
1407 assert_equal '', principals_options_for_select([])
1406 end
1408 end
1407
1409
1408 def test_principals_options_for_select_should_include_me_option_when_current_user_is_in_collection
1410 def test_principals_options_for_select_should_include_me_option_when_current_user_is_in_collection
1409 users = [User.find(2), User.find(4)]
1411 users = [User.find(2), User.find(4)]
1410 User.current = User.find(4)
1412 User.current = User.find(4)
1411 assert_include '<option value="4">&lt;&lt; me &gt;&gt;</option>', principals_options_for_select(users)
1413 assert_include '<option value="4">&lt;&lt; me &gt;&gt;</option>', principals_options_for_select(users)
1412 end
1414 end
1413
1415
1414 def test_stylesheet_link_tag_should_pick_the_default_stylesheet
1416 def test_stylesheet_link_tag_should_pick_the_default_stylesheet
1415 assert_match 'href="/stylesheets/styles.css"', stylesheet_link_tag("styles")
1417 assert_match 'href="/stylesheets/styles.css"', stylesheet_link_tag("styles")
1416 end
1418 end
1417
1419
1418 def test_stylesheet_link_tag_for_plugin_should_pick_the_plugin_stylesheet
1420 def test_stylesheet_link_tag_for_plugin_should_pick_the_plugin_stylesheet
1419 assert_match 'href="/plugin_assets/foo/stylesheets/styles.css"', stylesheet_link_tag("styles", :plugin => :foo)
1421 assert_match 'href="/plugin_assets/foo/stylesheets/styles.css"', stylesheet_link_tag("styles", :plugin => :foo)
1420 end
1422 end
1421
1423
1422 def test_image_tag_should_pick_the_default_image
1424 def test_image_tag_should_pick_the_default_image
1423 assert_match 'src="/images/image.png"', image_tag("image.png")
1425 assert_match 'src="/images/image.png"', image_tag("image.png")
1424 end
1426 end
1425
1427
1426 def test_image_tag_should_pick_the_theme_image_if_it_exists
1428 def test_image_tag_should_pick_the_theme_image_if_it_exists
1427 theme = Redmine::Themes.themes.last
1429 theme = Redmine::Themes.themes.last
1428 theme.images << 'image.png'
1430 theme.images << 'image.png'
1429
1431
1430 with_settings :ui_theme => theme.id do
1432 with_settings :ui_theme => theme.id do
1431 assert_match %|src="/themes/#{theme.dir}/images/image.png"|, image_tag("image.png")
1433 assert_match %|src="/themes/#{theme.dir}/images/image.png"|, image_tag("image.png")
1432 assert_match %|src="/images/other.png"|, image_tag("other.png")
1434 assert_match %|src="/images/other.png"|, image_tag("other.png")
1433 end
1435 end
1434 ensure
1436 ensure
1435 theme.images.delete 'image.png'
1437 theme.images.delete 'image.png'
1436 end
1438 end
1437
1439
1438 def test_image_tag_sfor_plugin_should_pick_the_plugin_image
1440 def test_image_tag_sfor_plugin_should_pick_the_plugin_image
1439 assert_match 'src="/plugin_assets/foo/images/image.png"', image_tag("image.png", :plugin => :foo)
1441 assert_match 'src="/plugin_assets/foo/images/image.png"', image_tag("image.png", :plugin => :foo)
1440 end
1442 end
1441
1443
1442 def test_javascript_include_tag_should_pick_the_default_javascript
1444 def test_javascript_include_tag_should_pick_the_default_javascript
1443 assert_match 'src="/javascripts/scripts.js"', javascript_include_tag("scripts")
1445 assert_match 'src="/javascripts/scripts.js"', javascript_include_tag("scripts")
1444 end
1446 end
1445
1447
1446 def test_javascript_include_tag_for_plugin_should_pick_the_plugin_javascript
1448 def test_javascript_include_tag_for_plugin_should_pick_the_plugin_javascript
1447 assert_match 'src="/plugin_assets/foo/javascripts/scripts.js"', javascript_include_tag("scripts", :plugin => :foo)
1449 assert_match 'src="/plugin_assets/foo/javascripts/scripts.js"', javascript_include_tag("scripts", :plugin => :foo)
1448 end
1450 end
1449
1451
1450 def test_raw_json_should_escape_closing_tags
1452 def test_raw_json_should_escape_closing_tags
1451 s = raw_json(["<foo>bar</foo>"])
1453 s = raw_json(["<foo>bar</foo>"])
1452 assert_equal '["<foo>bar<\/foo>"]', s
1454 assert_equal '["<foo>bar<\/foo>"]', s
1453 end
1455 end
1454
1456
1455 def test_raw_json_should_be_html_safe
1457 def test_raw_json_should_be_html_safe
1456 s = raw_json(["foo"])
1458 s = raw_json(["foo"])
1457 assert s.html_safe?
1459 assert s.html_safe?
1458 end
1460 end
1459
1461
1460 def test_html_title_should_app_title_if_not_set
1462 def test_html_title_should_app_title_if_not_set
1461 assert_equal 'Redmine', html_title
1463 assert_equal 'Redmine', html_title
1462 end
1464 end
1463
1465
1464 def test_html_title_should_join_items
1466 def test_html_title_should_join_items
1465 html_title 'Foo', 'Bar'
1467 html_title 'Foo', 'Bar'
1466 assert_equal 'Foo - Bar - Redmine', html_title
1468 assert_equal 'Foo - Bar - Redmine', html_title
1467 end
1469 end
1468
1470
1469 def test_html_title_should_append_current_project_name
1471 def test_html_title_should_append_current_project_name
1470 @project = Project.find(1)
1472 @project = Project.find(1)
1471 html_title 'Foo', 'Bar'
1473 html_title 'Foo', 'Bar'
1472 assert_equal 'Foo - Bar - eCookbook - Redmine', html_title
1474 assert_equal 'Foo - Bar - eCookbook - Redmine', html_title
1473 end
1475 end
1474
1476
1475 def test_title_should_return_a_h2_tag
1477 def test_title_should_return_a_h2_tag
1476 assert_equal '<h2>Foo</h2>', title('Foo')
1478 assert_equal '<h2>Foo</h2>', title('Foo')
1477 end
1479 end
1478
1480
1479 def test_title_should_set_html_title
1481 def test_title_should_set_html_title
1480 title('Foo')
1482 title('Foo')
1481 assert_equal 'Foo - Redmine', html_title
1483 assert_equal 'Foo - Redmine', html_title
1482 end
1484 end
1483
1485
1484 def test_title_should_turn_arrays_into_links
1486 def test_title_should_turn_arrays_into_links
1485 assert_equal '<h2><a href="/foo">Foo</a></h2>', title(['Foo', '/foo'])
1487 assert_equal '<h2><a href="/foo">Foo</a></h2>', title(['Foo', '/foo'])
1486 assert_equal 'Foo - Redmine', html_title
1488 assert_equal 'Foo - Redmine', html_title
1487 end
1489 end
1488
1490
1489 def test_title_should_join_items
1491 def test_title_should_join_items
1490 assert_equal '<h2>Foo &#187; Bar</h2>', title('Foo', 'Bar')
1492 assert_equal '<h2>Foo &#187; Bar</h2>', title('Foo', 'Bar')
1491 assert_equal 'Bar - Foo - Redmine', html_title
1493 assert_equal 'Bar - Foo - Redmine', html_title
1492 end
1494 end
1493
1495
1494 def test_favicon_path
1496 def test_favicon_path
1495 assert_match %r{^/favicon\.ico}, favicon_path
1497 assert_match %r{^/favicon\.ico}, favicon_path
1496 end
1498 end
1497
1499
1498 def test_favicon_path_with_suburi
1500 def test_favicon_path_with_suburi
1499 Redmine::Utils.relative_url_root = '/foo'
1501 Redmine::Utils.relative_url_root = '/foo'
1500 assert_match %r{^/foo/favicon\.ico}, favicon_path
1502 assert_match %r{^/foo/favicon\.ico}, favicon_path
1501 ensure
1503 ensure
1502 Redmine::Utils.relative_url_root = ''
1504 Redmine::Utils.relative_url_root = ''
1503 end
1505 end
1504
1506
1505 def test_favicon_url
1507 def test_favicon_url
1506 assert_match %r{^http://test\.host/favicon\.ico}, favicon_url
1508 assert_match %r{^http://test\.host/favicon\.ico}, favicon_url
1507 end
1509 end
1508
1510
1509 def test_favicon_url_with_suburi
1511 def test_favicon_url_with_suburi
1510 Redmine::Utils.relative_url_root = '/foo'
1512 Redmine::Utils.relative_url_root = '/foo'
1511 assert_match %r{^http://test\.host/foo/favicon\.ico}, favicon_url
1513 assert_match %r{^http://test\.host/foo/favicon\.ico}, favicon_url
1512 ensure
1514 ensure
1513 Redmine::Utils.relative_url_root = ''
1515 Redmine::Utils.relative_url_root = ''
1514 end
1516 end
1515
1517
1516 def test_truncate_single_line
1518 def test_truncate_single_line
1517 str = "01234"
1519 str = "01234"
1518 result = truncate_single_line_raw("#{str}\n#{str}", 10)
1520 result = truncate_single_line_raw("#{str}\n#{str}", 10)
1519 assert_equal "01234 0...", result
1521 assert_equal "01234 0...", result
1520 assert !result.html_safe?
1522 assert !result.html_safe?
1521 result = truncate_single_line_raw("#{str}<&#>\n#{str}#{str}", 16)
1523 result = truncate_single_line_raw("#{str}<&#>\n#{str}#{str}", 16)
1522 assert_equal "01234<&#> 012...", result
1524 assert_equal "01234<&#> 012...", result
1523 assert !result.html_safe?
1525 assert !result.html_safe?
1524 end
1526 end
1525
1527
1526 def test_truncate_single_line_non_ascii
1528 def test_truncate_single_line_non_ascii
1527 ja = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"
1529 ja = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"
1528 ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding)
1530 ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding)
1529 result = truncate_single_line_raw("#{ja}\n#{ja}\n#{ja}", 10)
1531 result = truncate_single_line_raw("#{ja}\n#{ja}\n#{ja}", 10)
1530 assert_equal "#{ja} #{ja}...", result
1532 assert_equal "#{ja} #{ja}...", result
1531 assert !result.html_safe?
1533 assert !result.html_safe?
1532 end
1534 end
1533 end
1535 end
General Comments 0
You need to be logged in to leave comments. Login now