##// END OF EJS Templates
Merged r11473 from trunk (#3676)....
Jean-Philippe Lang -
r11334:998a29cbaf24
parent child
Show More
@@ -1,173 +1,173
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2013 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require 'digest/md5'
19 19
20 20 module Redmine
21 21 module WikiFormatting
22 22 class StaleSectionError < Exception; end
23 23
24 24 @@formatters = {}
25 25
26 26 class << self
27 27 def map
28 28 yield self
29 29 end
30 30
31 31 def register(name, formatter, helper)
32 32 raise ArgumentError, "format name '#{name}' is already taken" if @@formatters[name.to_s]
33 33 @@formatters[name.to_s] = {:formatter => formatter, :helper => helper}
34 34 end
35 35
36 36 def formatter
37 37 formatter_for(Setting.text_formatting)
38 38 end
39 39
40 40 def formatter_for(name)
41 41 entry = @@formatters[name.to_s]
42 42 (entry && entry[:formatter]) || Redmine::WikiFormatting::NullFormatter::Formatter
43 43 end
44 44
45 45 def helper_for(name)
46 46 entry = @@formatters[name.to_s]
47 47 (entry && entry[:helper]) || Redmine::WikiFormatting::NullFormatter::Helper
48 48 end
49 49
50 50 def format_names
51 51 @@formatters.keys.map
52 52 end
53 53
54 54 def to_html(format, text, options = {})
55 55 text = if Setting.cache_formatted_text? && text.size > 2.kilobyte && cache_store && cache_key = cache_key_for(format, text, options[:object], options[:attribute])
56 56 # Text retrieved from the cache store may be frozen
57 57 # We need to dup it so we can do in-place substitutions with gsub!
58 58 cache_store.fetch cache_key do
59 59 formatter_for(format).new(text).to_html
60 60 end.dup
61 61 else
62 62 formatter_for(format).new(text).to_html
63 63 end
64 64 text
65 65 end
66 66
67 67 # Returns true if the text formatter supports single section edit
68 68 def supports_section_edit?
69 69 (formatter.instance_methods & ['update_section', :update_section]).any?
70 70 end
71 71
72 72 # Returns a cache key for the given text +format+, +text+, +object+ and +attribute+ or nil if no caching should be done
73 73 def cache_key_for(format, text, object, attribute)
74 74 if object && attribute && !object.new_record? && format.present?
75 75 "formatted_text/#{format}/#{object.class.model_name.cache_key}/#{object.id}-#{attribute}-#{Digest::MD5.hexdigest text}"
76 76 end
77 77 end
78 78
79 79 # Returns the cache store used to cache HTML output
80 80 def cache_store
81 81 ActionController::Base.cache_store
82 82 end
83 83 end
84 84
85 85 module LinksHelper
86 86 AUTO_LINK_RE = %r{
87 87 ( # leading text
88 88 <\w+.*?>| # leading HTML tag, or
89 89 [^=<>!:'"/]| # leading punctuation, or
90 90 ^ # beginning of line
91 91 )
92 92 (
93 93 (?:https?://)| # protocol spec, or
94 94 (?:s?ftps?://)|
95 95 (?:www\.) # www.*
96 96 )
97 97 (
98 (\S+?) # url
98 ([^<]\S*?) # url
99 99 (\/)? # slash
100 100 )
101 101 ((?:&gt;)?|[^[:alnum:]_\=\/;\(\)]*?) # post
102 102 (?=<|\s|$)
103 103 }x unless const_defined?(:AUTO_LINK_RE)
104 104
105 105 # Destructively remplaces urls into clickable links
106 106 def auto_link!(text)
107 107 text.gsub!(AUTO_LINK_RE) do
108 108 all, leading, proto, url, post = $&, $1, $2, $3, $6
109 109 if leading =~ /<a\s/i || leading =~ /![<>=]?/
110 110 # don't replace URL's that are already linked
111 111 # and URL's prefixed with ! !> !< != (textile images)
112 112 all
113 113 else
114 114 # Idea below : an URL with unbalanced parethesis and
115 115 # ending by ')' is put into external parenthesis
116 116 if ( url[-1]==?) and ((url.count("(") - url.count(")")) < 0 ) )
117 117 url=url[0..-2] # discard closing parenth from url
118 118 post = ")"+post # add closing parenth to post
119 119 end
120 120 content = proto + url
121 121 href = "#{proto=="www."?"http://www.":proto}#{url}"
122 122 %(#{leading}<a class="external" href="#{ERB::Util.html_escape href}">#{ERB::Util.html_escape content}</a>#{post}).html_safe
123 123 end
124 124 end
125 125 end
126 126
127 127 # Destructively remplaces email addresses into clickable links
128 128 def auto_mailto!(text)
129 129 text.gsub!(/([\w\.!#\$%\-+.]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/) do
130 130 mail = $1
131 131 if text.match(/<a\b[^>]*>(.*)(#{Regexp.escape(mail)})(.*)<\/a>/)
132 132 mail
133 133 else
134 134 %(<a class="email" href="mailto:#{ERB::Util.html_escape mail}">#{ERB::Util.html_escape mail}</a>).html_safe
135 135 end
136 136 end
137 137 end
138 138 end
139 139
140 140 # Default formatter module
141 141 module NullFormatter
142 142 class Formatter
143 143 include ActionView::Helpers::TagHelper
144 144 include ActionView::Helpers::TextHelper
145 145 include ActionView::Helpers::UrlHelper
146 146 include Redmine::WikiFormatting::LinksHelper
147 147
148 148 def initialize(text)
149 149 @text = text
150 150 end
151 151
152 152 def to_html(*args)
153 153 t = CGI::escapeHTML(@text)
154 154 auto_link!(t)
155 155 auto_mailto!(t)
156 156 simple_format(t, {}, :sanitize => false)
157 157 end
158 158 end
159 159
160 160 module Helper
161 161 def wikitoolbar_for(field_id)
162 162 end
163 163
164 164 def heads_for_wiki_formatter
165 165 end
166 166
167 167 def initial_page_content(page)
168 168 page.pretty_title.to_s
169 169 end
170 170 end
171 171 end
172 172 end
173 173 end
@@ -1,1201 +1,1204
1 1 # encoding: utf-8
2 2 #
3 3 # Redmine - project management software
4 4 # Copyright (C) 2006-2013 Jean-Philippe Lang
5 5 #
6 6 # This program is free software; you can redistribute it and/or
7 7 # modify it under the terms of the GNU General Public License
8 8 # as published by the Free Software Foundation; either version 2
9 9 # of the License, or (at your option) any later version.
10 10 #
11 11 # This program is distributed in the hope that it will be useful,
12 12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 14 # GNU General Public License for more details.
15 15 #
16 16 # You should have received a copy of the GNU General Public License
17 17 # along with this program; if not, write to the Free Software
18 18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 19
20 20 require File.expand_path('../../../test_helper', __FILE__)
21 21
22 22 class ApplicationHelperTest < ActionView::TestCase
23 23 include ERB::Util
24 24 include Rails.application.routes.url_helpers
25 25
26 26 fixtures :projects, :roles, :enabled_modules, :users,
27 27 :repositories, :changesets,
28 28 :trackers, :issue_statuses, :issues, :versions, :documents,
29 29 :wikis, :wiki_pages, :wiki_contents,
30 30 :boards, :messages, :news,
31 31 :attachments, :enumerations
32 32
33 33 def setup
34 34 super
35 35 set_tmp_attachments_directory
36 36 end
37 37
38 38 context "#link_to_if_authorized" do
39 39 context "authorized user" do
40 40 should "be tested"
41 41 end
42 42
43 43 context "unauthorized user" do
44 44 should "be tested"
45 45 end
46 46
47 47 should "allow using the :controller and :action for the target link" do
48 48 User.current = User.find_by_login('admin')
49 49
50 50 @project = Issue.first.project # Used by helper
51 51 response = link_to_if_authorized("By controller/action",
52 52 {:controller => 'issues', :action => 'edit', :id => Issue.first.id})
53 53 assert_match /href/, response
54 54 end
55 55
56 56 end
57 57
58 58 def test_auto_links
59 59 to_test = {
60 60 'http://foo.bar' => '<a class="external" href="http://foo.bar">http://foo.bar</a>',
61 61 'http://foo.bar/~user' => '<a class="external" href="http://foo.bar/~user">http://foo.bar/~user</a>',
62 62 'http://foo.bar.' => '<a class="external" href="http://foo.bar">http://foo.bar</a>.',
63 63 'https://foo.bar.' => '<a class="external" href="https://foo.bar">https://foo.bar</a>.',
64 64 'This is a link: http://foo.bar.' => 'This is a link: <a class="external" href="http://foo.bar">http://foo.bar</a>.',
65 65 'A link (eg. http://foo.bar).' => 'A link (eg. <a class="external" href="http://foo.bar">http://foo.bar</a>).',
66 66 '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>.',
67 67 'http://www.foo.bar/Test_(foobar)' => '<a class="external" href="http://www.foo.bar/Test_(foobar)">http://www.foo.bar/Test_(foobar)</a>',
68 68 '(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>)',
69 69 '(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>)',
70 70 '(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>).',
71 71 '(see "inline link":http://www.foo.bar/Test_(foobar))' => '(see <a href="http://www.foo.bar/Test_(foobar)" class="external">inline link</a>)',
72 72 '(see "inline link":http://www.foo.bar/Test)' => '(see <a href="http://www.foo.bar/Test" class="external">inline link</a>)',
73 73 '(see "inline link":http://www.foo.bar/Test).' => '(see <a href="http://www.foo.bar/Test" class="external">inline link</a>).',
74 74 'www.foo.bar' => '<a class="external" href="http://www.foo.bar">www.foo.bar</a>',
75 75 '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>',
76 76 'http://foo.bar/page#125' => '<a class="external" href="http://foo.bar/page#125">http://foo.bar/page#125</a>',
77 77 'http://foo@www.bar.com' => '<a class="external" href="http://foo@www.bar.com">http://foo@www.bar.com</a>',
78 78 'http://foo:bar@www.bar.com' => '<a class="external" href="http://foo:bar@www.bar.com">http://foo:bar@www.bar.com</a>',
79 79 'ftp://foo.bar' => '<a class="external" href="ftp://foo.bar">ftp://foo.bar</a>',
80 80 'ftps://foo.bar' => '<a class="external" href="ftps://foo.bar">ftps://foo.bar</a>',
81 81 'sftp://foo.bar' => '<a class="external" href="sftp://foo.bar">sftp://foo.bar</a>',
82 82 # two exclamation marks
83 83 '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>',
84 84 # escaping
85 85 'http://foo"bar' => '<a class="external" href="http://foo&quot;bar">http://foo&quot;bar</a>',
86 86 # wrap in angle brackets
87 '<http://foo.bar>' => '&lt;<a class="external" href="http://foo.bar">http://foo.bar</a>&gt;'
87 '<http://foo.bar>' => '&lt;<a class="external" href="http://foo.bar">http://foo.bar</a>&gt;',
88 # invalid urls
89 'http://' => 'http://',
90 'www.' => 'www.',
88 91 }
89 92 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
90 93 end
91 94
92 95 if 'ruby'.respond_to?(:encoding)
93 96 def test_auto_links_with_non_ascii_characters
94 97 to_test = {
95 98 'http://foo.bar/тСст' => '<a class="external" href="http://foo.bar/тСст">http://foo.bar/тСст</a>'
96 99 }
97 100 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
98 101 end
99 102 else
100 103 puts 'Skipping test_auto_links_with_non_ascii_characters, unsupported ruby version'
101 104 end
102 105
103 106 def test_auto_mailto
104 107 assert_equal '<p><a class="email" href="mailto:test@foo.bar">test@foo.bar</a></p>',
105 108 textilizable('test@foo.bar')
106 109 end
107 110
108 111 def test_inline_images
109 112 to_test = {
110 113 '!http://foo.bar/image.jpg!' => '<img src="http://foo.bar/image.jpg" alt="" />',
111 114 'floating !>http://foo.bar/image.jpg!' => 'floating <div style="float:right"><img src="http://foo.bar/image.jpg" alt="" /></div>',
112 115 'with class !(some-class)http://foo.bar/image.jpg!' => 'with class <img src="http://foo.bar/image.jpg" class="some-class" alt="" />',
113 116 '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="" />',
114 117 '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" />',
115 118 '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;" />',
116 119 }
117 120 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
118 121 end
119 122
120 123 def test_inline_images_inside_tags
121 124 raw = <<-RAW
122 125 h1. !foo.png! Heading
123 126
124 127 Centered image:
125 128
126 129 p=. !bar.gif!
127 130 RAW
128 131
129 132 assert textilizable(raw).include?('<img src="foo.png" alt="" />')
130 133 assert textilizable(raw).include?('<img src="bar.gif" alt="" />')
131 134 end
132 135
133 136 def test_attached_images
134 137 to_test = {
135 138 'Inline image: !logo.gif!' => 'Inline image: <img src="/attachments/download/3/logo.gif" title="This is a logo" alt="This is a logo" />',
136 139 'Inline image: !logo.GIF!' => 'Inline image: <img src="/attachments/download/3/logo.gif" title="This is a logo" alt="This is a logo" />',
137 140 'No match: !ogo.gif!' => 'No match: <img src="ogo.gif" alt="" />',
138 141 'No match: !ogo.GIF!' => 'No match: <img src="ogo.GIF" alt="" />',
139 142 # link image
140 143 '!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>',
141 144 }
142 145 attachments = Attachment.all
143 146 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text, :attachments => attachments) }
144 147 end
145 148
146 149 def test_attached_images_filename_extension
147 150 set_tmp_attachments_directory
148 151 a1 = Attachment.new(
149 152 :container => Issue.find(1),
150 153 :file => mock_file_with_options({:original_filename => "testtest.JPG"}),
151 154 :author => User.find(1))
152 155 assert a1.save
153 156 assert_equal "testtest.JPG", a1.filename
154 157 assert_equal "image/jpeg", a1.content_type
155 158 assert a1.image?
156 159
157 160 a2 = Attachment.new(
158 161 :container => Issue.find(1),
159 162 :file => mock_file_with_options({:original_filename => "testtest.jpeg"}),
160 163 :author => User.find(1))
161 164 assert a2.save
162 165 assert_equal "testtest.jpeg", a2.filename
163 166 assert_equal "image/jpeg", a2.content_type
164 167 assert a2.image?
165 168
166 169 a3 = Attachment.new(
167 170 :container => Issue.find(1),
168 171 :file => mock_file_with_options({:original_filename => "testtest.JPE"}),
169 172 :author => User.find(1))
170 173 assert a3.save
171 174 assert_equal "testtest.JPE", a3.filename
172 175 assert_equal "image/jpeg", a3.content_type
173 176 assert a3.image?
174 177
175 178 a4 = Attachment.new(
176 179 :container => Issue.find(1),
177 180 :file => mock_file_with_options({:original_filename => "Testtest.BMP"}),
178 181 :author => User.find(1))
179 182 assert a4.save
180 183 assert_equal "Testtest.BMP", a4.filename
181 184 assert_equal "image/x-ms-bmp", a4.content_type
182 185 assert a4.image?
183 186
184 187 to_test = {
185 188 'Inline image: !testtest.jpg!' =>
186 189 'Inline image: <img src="/attachments/download/' + a1.id.to_s + '/testtest.JPG" alt="" />',
187 190 'Inline image: !testtest.jpeg!' =>
188 191 'Inline image: <img src="/attachments/download/' + a2.id.to_s + '/testtest.jpeg" alt="" />',
189 192 'Inline image: !testtest.jpe!' =>
190 193 'Inline image: <img src="/attachments/download/' + a3.id.to_s + '/testtest.JPE" alt="" />',
191 194 'Inline image: !testtest.bmp!' =>
192 195 'Inline image: <img src="/attachments/download/' + a4.id.to_s + '/Testtest.BMP" alt="" />',
193 196 }
194 197
195 198 attachments = [a1, a2, a3, a4]
196 199 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text, :attachments => attachments) }
197 200 end
198 201
199 202 def test_attached_images_should_read_later
200 203 set_fixtures_attachments_directory
201 204 a1 = Attachment.find(16)
202 205 assert_equal "testfile.png", a1.filename
203 206 assert a1.readable?
204 207 assert (! a1.visible?(User.anonymous))
205 208 assert a1.visible?(User.find(2))
206 209 a2 = Attachment.find(17)
207 210 assert_equal "testfile.PNG", a2.filename
208 211 assert a2.readable?
209 212 assert (! a2.visible?(User.anonymous))
210 213 assert a2.visible?(User.find(2))
211 214 assert a1.created_on < a2.created_on
212 215
213 216 to_test = {
214 217 'Inline image: !testfile.png!' =>
215 218 'Inline image: <img src="/attachments/download/' + a2.id.to_s + '/testfile.PNG" alt="" />',
216 219 'Inline image: !Testfile.PNG!' =>
217 220 'Inline image: <img src="/attachments/download/' + a2.id.to_s + '/testfile.PNG" alt="" />',
218 221 }
219 222 attachments = [a1, a2]
220 223 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text, :attachments => attachments) }
221 224 set_tmp_attachments_directory
222 225 end
223 226
224 227 def test_textile_external_links
225 228 to_test = {
226 229 'This is a "link":http://foo.bar' => 'This is a <a href="http://foo.bar" class="external">link</a>',
227 230 'This is an intern "link":/foo/bar' => 'This is an intern <a href="/foo/bar">link</a>',
228 231 '"link (Link title)":http://foo.bar' => '<a href="http://foo.bar" title="Link title" class="external">link</a>',
229 232 '"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>',
230 233 "This is not a \"Link\":\n\nAnother paragraph" => "This is not a \"Link\":</p>\n\n\n\t<p>Another paragraph",
231 234 # no multiline link text
232 235 "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",
233 236 # mailto link
234 237 "\"system administrator\":mailto:sysadmin@example.com?subject=redmine%20permissions" => "<a href=\"mailto:sysadmin@example.com?subject=redmine%20permissions\">system administrator</a>",
235 238 # two exclamation marks
236 239 '"a link":http://example.net/path!602815048C7B5C20!302.html' => '<a href="http://example.net/path!602815048C7B5C20!302.html" class="external">a link</a>',
237 240 # escaping
238 241 '"test":http://foo"bar' => '<a href="http://foo&quot;bar" class="external">test</a>',
239 242 }
240 243 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
241 244 end
242 245
243 246 if 'ruby'.respond_to?(:encoding)
244 247 def test_textile_external_links_with_non_ascii_characters
245 248 to_test = {
246 249 'This is a "link":http://foo.bar/тСст' => 'This is a <a href="http://foo.bar/тСст" class="external">link</a>'
247 250 }
248 251 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
249 252 end
250 253 else
251 254 puts 'Skipping test_textile_external_links_with_non_ascii_characters, unsupported ruby version'
252 255 end
253 256
254 257 def test_redmine_links
255 258 issue_link = link_to('#3', {:controller => 'issues', :action => 'show', :id => 3},
256 259 :class => Issue.find(3).css_classes, :title => 'Error 281 when updating a recipe (New)')
257 260 note_link = link_to('#3', {:controller => 'issues', :action => 'show', :id => 3, :anchor => 'note-14'},
258 261 :class => Issue.find(3).css_classes, :title => 'Error 281 when updating a recipe (New)')
259 262
260 263 changeset_link = link_to('r1', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 1},
261 264 :class => 'changeset', :title => 'My very first commit')
262 265 changeset_link2 = link_to('r2', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 2},
263 266 :class => 'changeset', :title => 'This commit fixes #1, #2 and references #1 & #3')
264 267
265 268 document_link = link_to('Test document', {:controller => 'documents', :action => 'show', :id => 1},
266 269 :class => 'document')
267 270
268 271 version_link = link_to('1.0', {:controller => 'versions', :action => 'show', :id => 2},
269 272 :class => 'version')
270 273
271 274 board_url = {:controller => 'boards', :action => 'show', :id => 2, :project_id => 'ecookbook'}
272 275
273 276 message_url = {:controller => 'messages', :action => 'show', :board_id => 1, :id => 4}
274 277
275 278 news_url = {:controller => 'news', :action => 'show', :id => 1}
276 279
277 280 project_url = {:controller => 'projects', :action => 'show', :id => 'subproject1'}
278 281
279 282 source_url = '/projects/ecookbook/repository/entry/some/file'
280 283 source_url_with_rev = '/projects/ecookbook/repository/revisions/52/entry/some/file'
281 284 source_url_with_ext = '/projects/ecookbook/repository/entry/some/file.ext'
282 285 source_url_with_rev_and_ext = '/projects/ecookbook/repository/revisions/52/entry/some/file.ext'
283 286 source_url_with_branch = '/projects/ecookbook/repository/revisions/branch/entry/some/file'
284 287
285 288 export_url = '/projects/ecookbook/repository/raw/some/file'
286 289 export_url_with_rev = '/projects/ecookbook/repository/revisions/52/raw/some/file'
287 290 export_url_with_ext = '/projects/ecookbook/repository/raw/some/file.ext'
288 291 export_url_with_rev_and_ext = '/projects/ecookbook/repository/revisions/52/raw/some/file.ext'
289 292 export_url_with_branch = '/projects/ecookbook/repository/revisions/branch/raw/some/file'
290 293
291 294 to_test = {
292 295 # tickets
293 296 '#3, [#3], (#3) and #3.' => "#{issue_link}, [#{issue_link}], (#{issue_link}) and #{issue_link}.",
294 297 # ticket notes
295 298 '#3-14' => note_link,
296 299 '#3#note-14' => note_link,
297 300 # should not ignore leading zero
298 301 '#03' => '#03',
299 302 # changesets
300 303 'r1' => changeset_link,
301 304 'r1.' => "#{changeset_link}.",
302 305 'r1, r2' => "#{changeset_link}, #{changeset_link2}",
303 306 'r1,r2' => "#{changeset_link},#{changeset_link2}",
304 307 # documents
305 308 'document#1' => document_link,
306 309 'document:"Test document"' => document_link,
307 310 # versions
308 311 'version#2' => version_link,
309 312 'version:1.0' => version_link,
310 313 'version:"1.0"' => version_link,
311 314 # source
312 315 'source:some/file' => link_to('source:some/file', source_url, :class => 'source'),
313 316 'source:/some/file' => link_to('source:/some/file', source_url, :class => 'source'),
314 317 'source:/some/file.' => link_to('source:/some/file', source_url, :class => 'source') + ".",
315 318 'source:/some/file.ext.' => link_to('source:/some/file.ext', source_url_with_ext, :class => 'source') + ".",
316 319 'source:/some/file. ' => link_to('source:/some/file', source_url, :class => 'source') + ".",
317 320 'source:/some/file.ext. ' => link_to('source:/some/file.ext', source_url_with_ext, :class => 'source') + ".",
318 321 'source:/some/file, ' => link_to('source:/some/file', source_url, :class => 'source') + ",",
319 322 'source:/some/file@52' => link_to('source:/some/file@52', source_url_with_rev, :class => 'source'),
320 323 'source:/some/file@branch' => link_to('source:/some/file@branch', source_url_with_branch, :class => 'source'),
321 324 'source:/some/file.ext@52' => link_to('source:/some/file.ext@52', source_url_with_rev_and_ext, :class => 'source'),
322 325 'source:/some/file#L110' => link_to('source:/some/file#L110', source_url + "#L110", :class => 'source'),
323 326 'source:/some/file.ext#L110' => link_to('source:/some/file.ext#L110', source_url_with_ext + "#L110", :class => 'source'),
324 327 'source:/some/file@52#L110' => link_to('source:/some/file@52#L110', source_url_with_rev + "#L110", :class => 'source'),
325 328 # export
326 329 'export:/some/file' => link_to('export:/some/file', export_url, :class => 'source download'),
327 330 'export:/some/file.ext' => link_to('export:/some/file.ext', export_url_with_ext, :class => 'source download'),
328 331 'export:/some/file@52' => link_to('export:/some/file@52', export_url_with_rev, :class => 'source download'),
329 332 'export:/some/file.ext@52' => link_to('export:/some/file.ext@52', export_url_with_rev_and_ext, :class => 'source download'),
330 333 'export:/some/file@branch' => link_to('export:/some/file@branch', export_url_with_branch, :class => 'source download'),
331 334 # forum
332 335 'forum#2' => link_to('Discussion', board_url, :class => 'board'),
333 336 'forum:Discussion' => link_to('Discussion', board_url, :class => 'board'),
334 337 # message
335 338 'message#4' => link_to('Post 2', message_url, :class => 'message'),
336 339 'message#5' => link_to('RE: post 2', message_url.merge(:anchor => 'message-5', :r => 5), :class => 'message'),
337 340 # news
338 341 'news#1' => link_to('eCookbook first release !', news_url, :class => 'news'),
339 342 'news:"eCookbook first release !"' => link_to('eCookbook first release !', news_url, :class => 'news'),
340 343 # project
341 344 'project#3' => link_to('eCookbook Subproject 1', project_url, :class => 'project'),
342 345 'project:subproject1' => link_to('eCookbook Subproject 1', project_url, :class => 'project'),
343 346 'project:"eCookbook subProject 1"' => link_to('eCookbook Subproject 1', project_url, :class => 'project'),
344 347 # not found
345 348 '#0123456789' => '#0123456789',
346 349 # invalid expressions
347 350 'source:' => 'source:',
348 351 # url hash
349 352 "http://foo.bar/FAQ#3" => '<a class="external" href="http://foo.bar/FAQ#3">http://foo.bar/FAQ#3</a>',
350 353 }
351 354 @project = Project.find(1)
352 355 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text), "#{text} failed" }
353 356 end
354 357
355 358 def test_redmine_links_with_a_different_project_before_current_project
356 359 vp1 = Version.generate!(:project_id => 1, :name => '1.4.4')
357 360 vp3 = Version.generate!(:project_id => 3, :name => '1.4.4')
358 361
359 362 @project = Project.find(3)
360 363 assert_equal %(<p><a href="/versions/#{vp1.id}" class="version">1.4.4</a> <a href="/versions/#{vp3.id}" class="version">1.4.4</a></p>),
361 364 textilizable("ecookbook:version:1.4.4 version:1.4.4")
362 365 end
363 366
364 367 def test_escaped_redmine_links_should_not_be_parsed
365 368 to_test = [
366 369 '#3.',
367 370 '#3-14.',
368 371 '#3#-note14.',
369 372 'r1',
370 373 'document#1',
371 374 'document:"Test document"',
372 375 'version#2',
373 376 'version:1.0',
374 377 'version:"1.0"',
375 378 'source:/some/file'
376 379 ]
377 380 @project = Project.find(1)
378 381 to_test.each { |text| assert_equal "<p>#{text}</p>", textilizable("!" + text), "#{text} failed" }
379 382 end
380 383
381 384 def test_cross_project_redmine_links
382 385 source_link = link_to('ecookbook:source:/some/file', {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :path => ['some', 'file']},
383 386 :class => 'source')
384 387
385 388 changeset_link = link_to('ecookbook:r2', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 2},
386 389 :class => 'changeset', :title => 'This commit fixes #1, #2 and references #1 & #3')
387 390
388 391 to_test = {
389 392 # documents
390 393 'document:"Test document"' => 'document:"Test document"',
391 394 'ecookbook:document:"Test document"' => '<a href="/documents/1" class="document">Test document</a>',
392 395 'invalid:document:"Test document"' => 'invalid:document:"Test document"',
393 396 # versions
394 397 'version:"1.0"' => 'version:"1.0"',
395 398 'ecookbook:version:"1.0"' => '<a href="/versions/2" class="version">1.0</a>',
396 399 'invalid:version:"1.0"' => 'invalid:version:"1.0"',
397 400 # changeset
398 401 'r2' => 'r2',
399 402 'ecookbook:r2' => changeset_link,
400 403 'invalid:r2' => 'invalid:r2',
401 404 # source
402 405 'source:/some/file' => 'source:/some/file',
403 406 'ecookbook:source:/some/file' => source_link,
404 407 'invalid:source:/some/file' => 'invalid:source:/some/file',
405 408 }
406 409 @project = Project.find(3)
407 410 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text), "#{text} failed" }
408 411 end
409 412
410 413 def test_multiple_repositories_redmine_links
411 414 svn = Repository::Subversion.create!(:project_id => 1, :identifier => 'svn_repo-1', :url => 'file:///foo/hg')
412 415 Changeset.create!(:repository => svn, :committed_on => Time.now, :revision => '123')
413 416 hg = Repository::Mercurial.create!(:project_id => 1, :identifier => 'hg1', :url => '/foo/hg')
414 417 Changeset.create!(:repository => hg, :committed_on => Time.now, :revision => '123', :scmid => 'abcd')
415 418
416 419 changeset_link = link_to('r2', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 2},
417 420 :class => 'changeset', :title => 'This commit fixes #1, #2 and references #1 & #3')
418 421 svn_changeset_link = link_to('svn_repo-1|r123', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :repository_id => 'svn_repo-1', :rev => 123},
419 422 :class => 'changeset', :title => '')
420 423 hg_changeset_link = link_to('hg1|abcd', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :repository_id => 'hg1', :rev => 'abcd'},
421 424 :class => 'changeset', :title => '')
422 425
423 426 source_link = link_to('source:some/file', {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :path => ['some', 'file']}, :class => 'source')
424 427 hg_source_link = link_to('source:hg1|some/file', {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :repository_id => 'hg1', :path => ['some', 'file']}, :class => 'source')
425 428
426 429 to_test = {
427 430 'r2' => changeset_link,
428 431 'svn_repo-1|r123' => svn_changeset_link,
429 432 'invalid|r123' => 'invalid|r123',
430 433 'commit:hg1|abcd' => hg_changeset_link,
431 434 'commit:invalid|abcd' => 'commit:invalid|abcd',
432 435 # source
433 436 'source:some/file' => source_link,
434 437 'source:hg1|some/file' => hg_source_link,
435 438 'source:invalid|some/file' => 'source:invalid|some/file',
436 439 }
437 440
438 441 @project = Project.find(1)
439 442 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text), "#{text} failed" }
440 443 end
441 444
442 445 def test_cross_project_multiple_repositories_redmine_links
443 446 svn = Repository::Subversion.create!(:project_id => 1, :identifier => 'svn1', :url => 'file:///foo/hg')
444 447 Changeset.create!(:repository => svn, :committed_on => Time.now, :revision => '123')
445 448 hg = Repository::Mercurial.create!(:project_id => 1, :identifier => 'hg1', :url => '/foo/hg')
446 449 Changeset.create!(:repository => hg, :committed_on => Time.now, :revision => '123', :scmid => 'abcd')
447 450
448 451 changeset_link = link_to('ecookbook:r2', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 2},
449 452 :class => 'changeset', :title => 'This commit fixes #1, #2 and references #1 & #3')
450 453 svn_changeset_link = link_to('ecookbook:svn1|r123', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :repository_id => 'svn1', :rev => 123},
451 454 :class => 'changeset', :title => '')
452 455 hg_changeset_link = link_to('ecookbook:hg1|abcd', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :repository_id => 'hg1', :rev => 'abcd'},
453 456 :class => 'changeset', :title => '')
454 457
455 458 source_link = link_to('ecookbook:source:some/file', {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :path => ['some', 'file']}, :class => 'source')
456 459 hg_source_link = link_to('ecookbook:source:hg1|some/file', {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :repository_id => 'hg1', :path => ['some', 'file']}, :class => 'source')
457 460
458 461 to_test = {
459 462 'ecookbook:r2' => changeset_link,
460 463 'ecookbook:svn1|r123' => svn_changeset_link,
461 464 'ecookbook:invalid|r123' => 'ecookbook:invalid|r123',
462 465 'ecookbook:commit:hg1|abcd' => hg_changeset_link,
463 466 'ecookbook:commit:invalid|abcd' => 'ecookbook:commit:invalid|abcd',
464 467 'invalid:commit:invalid|abcd' => 'invalid:commit:invalid|abcd',
465 468 # source
466 469 'ecookbook:source:some/file' => source_link,
467 470 'ecookbook:source:hg1|some/file' => hg_source_link,
468 471 'ecookbook:source:invalid|some/file' => 'ecookbook:source:invalid|some/file',
469 472 'invalid:source:invalid|some/file' => 'invalid:source:invalid|some/file',
470 473 }
471 474
472 475 @project = Project.find(3)
473 476 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text), "#{text} failed" }
474 477 end
475 478
476 479 def test_redmine_links_git_commit
477 480 changeset_link = link_to('abcd',
478 481 {
479 482 :controller => 'repositories',
480 483 :action => 'revision',
481 484 :id => 'subproject1',
482 485 :rev => 'abcd',
483 486 },
484 487 :class => 'changeset', :title => 'test commit')
485 488 to_test = {
486 489 'commit:abcd' => changeset_link,
487 490 }
488 491 @project = Project.find(3)
489 492 r = Repository::Git.create!(:project => @project, :url => '/tmp/test/git')
490 493 assert r
491 494 c = Changeset.new(:repository => r,
492 495 :committed_on => Time.now,
493 496 :revision => 'abcd',
494 497 :scmid => 'abcd',
495 498 :comments => 'test commit')
496 499 assert( c.save )
497 500 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
498 501 end
499 502
500 503 # TODO: Bazaar commit id contains mail address, so it contains '@' and '_'.
501 504 def test_redmine_links_darcs_commit
502 505 changeset_link = link_to('20080308225258-98289-abcd456efg.gz',
503 506 {
504 507 :controller => 'repositories',
505 508 :action => 'revision',
506 509 :id => 'subproject1',
507 510 :rev => '123',
508 511 },
509 512 :class => 'changeset', :title => 'test commit')
510 513 to_test = {
511 514 'commit:20080308225258-98289-abcd456efg.gz' => changeset_link,
512 515 }
513 516 @project = Project.find(3)
514 517 r = Repository::Darcs.create!(
515 518 :project => @project, :url => '/tmp/test/darcs',
516 519 :log_encoding => 'UTF-8')
517 520 assert r
518 521 c = Changeset.new(:repository => r,
519 522 :committed_on => Time.now,
520 523 :revision => '123',
521 524 :scmid => '20080308225258-98289-abcd456efg.gz',
522 525 :comments => 'test commit')
523 526 assert( c.save )
524 527 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
525 528 end
526 529
527 530 def test_redmine_links_mercurial_commit
528 531 changeset_link_rev = link_to('r123',
529 532 {
530 533 :controller => 'repositories',
531 534 :action => 'revision',
532 535 :id => 'subproject1',
533 536 :rev => '123' ,
534 537 },
535 538 :class => 'changeset', :title => 'test commit')
536 539 changeset_link_commit = link_to('abcd',
537 540 {
538 541 :controller => 'repositories',
539 542 :action => 'revision',
540 543 :id => 'subproject1',
541 544 :rev => 'abcd' ,
542 545 },
543 546 :class => 'changeset', :title => 'test commit')
544 547 to_test = {
545 548 'r123' => changeset_link_rev,
546 549 'commit:abcd' => changeset_link_commit,
547 550 }
548 551 @project = Project.find(3)
549 552 r = Repository::Mercurial.create!(:project => @project, :url => '/tmp/test')
550 553 assert r
551 554 c = Changeset.new(:repository => r,
552 555 :committed_on => Time.now,
553 556 :revision => '123',
554 557 :scmid => 'abcd',
555 558 :comments => 'test commit')
556 559 assert( c.save )
557 560 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
558 561 end
559 562
560 563 def test_attachment_links
561 564 to_test = {
562 565 'attachment:error281.txt' => '<a href="/attachments/download/1/error281.txt" class="attachment">error281.txt</a>'
563 566 }
564 567 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text, :attachments => Issue.find(3).attachments), "#{text} failed" }
565 568 end
566 569
567 570 def test_attachment_link_should_link_to_latest_attachment
568 571 set_tmp_attachments_directory
569 572 a1 = Attachment.generate!(:filename => "test.txt", :created_on => 1.hour.ago)
570 573 a2 = Attachment.generate!(:filename => "test.txt")
571 574
572 575 assert_equal %(<p><a href="/attachments/download/#{a2.id}/test.txt" class="attachment">test.txt</a></p>),
573 576 textilizable('attachment:test.txt', :attachments => [a1, a2])
574 577 end
575 578
576 579 def test_wiki_links
577 580 to_test = {
578 581 '[[CookBook documentation]]' => '<a href="/projects/ecookbook/wiki/CookBook_documentation" class="wiki-page">CookBook documentation</a>',
579 582 '[[Another page|Page]]' => '<a href="/projects/ecookbook/wiki/Another_page" class="wiki-page">Page</a>',
580 583 # title content should be formatted
581 584 '[[Another page|With _styled_ *title*]]' => '<a href="/projects/ecookbook/wiki/Another_page" class="wiki-page">With <em>styled</em> <strong>title</strong></a>',
582 585 '[[Another page|With title containing <strong>HTML entities &amp; markups</strong>]]' => '<a href="/projects/ecookbook/wiki/Another_page" class="wiki-page">With title containing &lt;strong&gt;HTML entities &amp; markups&lt;/strong&gt;</a>',
583 586 # link with anchor
584 587 '[[CookBook documentation#One-section]]' => '<a href="/projects/ecookbook/wiki/CookBook_documentation#One-section" class="wiki-page">CookBook documentation</a>',
585 588 '[[Another page#anchor|Page]]' => '<a href="/projects/ecookbook/wiki/Another_page#anchor" class="wiki-page">Page</a>',
586 589 # UTF8 anchor
587 590 '[[Another_page#ВСст|ВСст]]' => %|<a href="/projects/ecookbook/wiki/Another_page##{CGI.escape 'ВСст'}" class="wiki-page">ВСст</a>|,
588 591 # page that doesn't exist
589 592 '[[Unknown page]]' => '<a href="/projects/ecookbook/wiki/Unknown_page" class="wiki-page new">Unknown page</a>',
590 593 '[[Unknown page|404]]' => '<a href="/projects/ecookbook/wiki/Unknown_page" class="wiki-page new">404</a>',
591 594 # link to another project wiki
592 595 '[[onlinestore:]]' => '<a href="/projects/onlinestore/wiki" class="wiki-page">onlinestore</a>',
593 596 '[[onlinestore:|Wiki]]' => '<a href="/projects/onlinestore/wiki" class="wiki-page">Wiki</a>',
594 597 '[[onlinestore:Start page]]' => '<a href="/projects/onlinestore/wiki/Start_page" class="wiki-page">Start page</a>',
595 598 '[[onlinestore:Start page|Text]]' => '<a href="/projects/onlinestore/wiki/Start_page" class="wiki-page">Text</a>',
596 599 '[[onlinestore:Unknown page]]' => '<a href="/projects/onlinestore/wiki/Unknown_page" class="wiki-page new">Unknown page</a>',
597 600 # striked through link
598 601 '-[[Another page|Page]]-' => '<del><a href="/projects/ecookbook/wiki/Another_page" class="wiki-page">Page</a></del>',
599 602 '-[[Another page|Page]] link-' => '<del><a href="/projects/ecookbook/wiki/Another_page" class="wiki-page">Page</a> link</del>',
600 603 # escaping
601 604 '![[Another page|Page]]' => '[[Another page|Page]]',
602 605 # project does not exist
603 606 '[[unknowproject:Start]]' => '[[unknowproject:Start]]',
604 607 '[[unknowproject:Start|Page title]]' => '[[unknowproject:Start|Page title]]',
605 608 }
606 609
607 610 @project = Project.find(1)
608 611 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
609 612 end
610 613
611 614 def test_wiki_links_within_local_file_generation_context
612 615
613 616 to_test = {
614 617 # link to a page
615 618 '[[CookBook documentation]]' => '<a href="CookBook_documentation.html" class="wiki-page">CookBook documentation</a>',
616 619 '[[CookBook documentation|documentation]]' => '<a href="CookBook_documentation.html" class="wiki-page">documentation</a>',
617 620 '[[CookBook documentation#One-section]]' => '<a href="CookBook_documentation.html#One-section" class="wiki-page">CookBook documentation</a>',
618 621 '[[CookBook documentation#One-section|documentation]]' => '<a href="CookBook_documentation.html#One-section" class="wiki-page">documentation</a>',
619 622 # page that doesn't exist
620 623 '[[Unknown page]]' => '<a href="Unknown_page.html" class="wiki-page new">Unknown page</a>',
621 624 '[[Unknown page|404]]' => '<a href="Unknown_page.html" class="wiki-page new">404</a>',
622 625 '[[Unknown page#anchor]]' => '<a href="Unknown_page.html#anchor" class="wiki-page new">Unknown page</a>',
623 626 '[[Unknown page#anchor|404]]' => '<a href="Unknown_page.html#anchor" class="wiki-page new">404</a>',
624 627 }
625 628
626 629 @project = Project.find(1)
627 630
628 631 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text, :wiki_links => :local) }
629 632 end
630 633
631 634 def test_wiki_links_within_wiki_page_context
632 635
633 636 page = WikiPage.find_by_title('Another_page' )
634 637
635 638 to_test = {
636 639 # link to another page
637 640 '[[CookBook documentation]]' => '<a href="/projects/ecookbook/wiki/CookBook_documentation" class="wiki-page">CookBook documentation</a>',
638 641 '[[CookBook documentation|documentation]]' => '<a href="/projects/ecookbook/wiki/CookBook_documentation" class="wiki-page">documentation</a>',
639 642 '[[CookBook documentation#One-section]]' => '<a href="/projects/ecookbook/wiki/CookBook_documentation#One-section" class="wiki-page">CookBook documentation</a>',
640 643 '[[CookBook documentation#One-section|documentation]]' => '<a href="/projects/ecookbook/wiki/CookBook_documentation#One-section" class="wiki-page">documentation</a>',
641 644 # link to the current page
642 645 '[[Another page]]' => '<a href="/projects/ecookbook/wiki/Another_page" class="wiki-page">Another page</a>',
643 646 '[[Another page|Page]]' => '<a href="/projects/ecookbook/wiki/Another_page" class="wiki-page">Page</a>',
644 647 '[[Another page#anchor]]' => '<a href="#anchor" class="wiki-page">Another page</a>',
645 648 '[[Another page#anchor|Page]]' => '<a href="#anchor" class="wiki-page">Page</a>',
646 649 # page that doesn't exist
647 650 '[[Unknown page]]' => '<a href="/projects/ecookbook/wiki/Unknown_page?parent=Another_page" class="wiki-page new">Unknown page</a>',
648 651 '[[Unknown page|404]]' => '<a href="/projects/ecookbook/wiki/Unknown_page?parent=Another_page" class="wiki-page new">404</a>',
649 652 '[[Unknown page#anchor]]' => '<a href="/projects/ecookbook/wiki/Unknown_page?parent=Another_page#anchor" class="wiki-page new">Unknown page</a>',
650 653 '[[Unknown page#anchor|404]]' => '<a href="/projects/ecookbook/wiki/Unknown_page?parent=Another_page#anchor" class="wiki-page new">404</a>',
651 654 }
652 655
653 656 @project = Project.find(1)
654 657
655 658 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(WikiContent.new( :text => text, :page => page ), :text) }
656 659 end
657 660
658 661 def test_wiki_links_anchor_option_should_prepend_page_title_to_href
659 662
660 663 to_test = {
661 664 # link to a page
662 665 '[[CookBook documentation]]' => '<a href="#CookBook_documentation" class="wiki-page">CookBook documentation</a>',
663 666 '[[CookBook documentation|documentation]]' => '<a href="#CookBook_documentation" class="wiki-page">documentation</a>',
664 667 '[[CookBook documentation#One-section]]' => '<a href="#CookBook_documentation_One-section" class="wiki-page">CookBook documentation</a>',
665 668 '[[CookBook documentation#One-section|documentation]]' => '<a href="#CookBook_documentation_One-section" class="wiki-page">documentation</a>',
666 669 # page that doesn't exist
667 670 '[[Unknown page]]' => '<a href="#Unknown_page" class="wiki-page new">Unknown page</a>',
668 671 '[[Unknown page|404]]' => '<a href="#Unknown_page" class="wiki-page new">404</a>',
669 672 '[[Unknown page#anchor]]' => '<a href="#Unknown_page_anchor" class="wiki-page new">Unknown page</a>',
670 673 '[[Unknown page#anchor|404]]' => '<a href="#Unknown_page_anchor" class="wiki-page new">404</a>',
671 674 }
672 675
673 676 @project = Project.find(1)
674 677
675 678 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text, :wiki_links => :anchor) }
676 679 end
677 680
678 681 def test_html_tags
679 682 to_test = {
680 683 "<div>content</div>" => "<p>&lt;div&gt;content&lt;/div&gt;</p>",
681 684 "<div class=\"bold\">content</div>" => "<p>&lt;div class=\"bold\"&gt;content&lt;/div&gt;</p>",
682 685 "<script>some script;</script>" => "<p>&lt;script&gt;some script;&lt;/script&gt;</p>",
683 686 # do not escape pre/code tags
684 687 "<pre>\nline 1\nline2</pre>" => "<pre>\nline 1\nline2</pre>",
685 688 "<pre><code>\nline 1\nline2</code></pre>" => "<pre><code>\nline 1\nline2</code></pre>",
686 689 "<pre><div>content</div></pre>" => "<pre>&lt;div&gt;content&lt;/div&gt;</pre>",
687 690 "HTML comment: <!-- no comments -->" => "<p>HTML comment: &lt;!-- no comments --&gt;</p>",
688 691 "<!-- opening comment" => "<p>&lt;!-- opening comment</p>",
689 692 # remove attributes except class
690 693 "<pre class='foo'>some text</pre>" => "<pre class='foo'>some text</pre>",
691 694 '<pre class="foo">some text</pre>' => '<pre class="foo">some text</pre>',
692 695 "<pre class='foo bar'>some text</pre>" => "<pre class='foo bar'>some text</pre>",
693 696 '<pre class="foo bar">some text</pre>' => '<pre class="foo bar">some text</pre>',
694 697 "<pre onmouseover='alert(1)'>some text</pre>" => "<pre>some text</pre>",
695 698 # xss
696 699 '<pre><code class=""onmouseover="alert(1)">text</code></pre>' => '<pre><code>text</code></pre>',
697 700 '<pre class=""onmouseover="alert(1)">text</pre>' => '<pre>text</pre>',
698 701 }
699 702 to_test.each { |text, result| assert_equal result, textilizable(text) }
700 703 end
701 704
702 705 def test_allowed_html_tags
703 706 to_test = {
704 707 "<pre>preformatted text</pre>" => "<pre>preformatted text</pre>",
705 708 "<notextile>no *textile* formatting</notextile>" => "no *textile* formatting",
706 709 "<notextile>this is <tag>a tag</tag></notextile>" => "this is &lt;tag&gt;a tag&lt;/tag&gt;"
707 710 }
708 711 to_test.each { |text, result| assert_equal result, textilizable(text) }
709 712 end
710 713
711 714 def test_pre_tags
712 715 raw = <<-RAW
713 716 Before
714 717
715 718 <pre>
716 719 <prepared-statement-cache-size>32</prepared-statement-cache-size>
717 720 </pre>
718 721
719 722 After
720 723 RAW
721 724
722 725 expected = <<-EXPECTED
723 726 <p>Before</p>
724 727 <pre>
725 728 &lt;prepared-statement-cache-size&gt;32&lt;/prepared-statement-cache-size&gt;
726 729 </pre>
727 730 <p>After</p>
728 731 EXPECTED
729 732
730 733 assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(raw).gsub(%r{[\r\n\t]}, '')
731 734 end
732 735
733 736 def test_pre_content_should_not_parse_wiki_and_redmine_links
734 737 raw = <<-RAW
735 738 [[CookBook documentation]]
736 739
737 740 #1
738 741
739 742 <pre>
740 743 [[CookBook documentation]]
741 744
742 745 #1
743 746 </pre>
744 747 RAW
745 748
746 749 expected = <<-EXPECTED
747 750 <p><a href="/projects/ecookbook/wiki/CookBook_documentation" class="wiki-page">CookBook documentation</a></p>
748 751 <p><a href="/issues/1" class="#{Issue.find(1).css_classes}" title="Can&#x27;t print recipes (New)">#1</a></p>
749 752 <pre>
750 753 [[CookBook documentation]]
751 754
752 755 #1
753 756 </pre>
754 757 EXPECTED
755 758
756 759 @project = Project.find(1)
757 760 assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(raw).gsub(%r{[\r\n\t]}, '')
758 761 end
759 762
760 763 def test_non_closing_pre_blocks_should_be_closed
761 764 raw = <<-RAW
762 765 <pre><code>
763 766 RAW
764 767
765 768 expected = <<-EXPECTED
766 769 <pre><code>
767 770 </code></pre>
768 771 EXPECTED
769 772
770 773 @project = Project.find(1)
771 774 assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(raw).gsub(%r{[\r\n\t]}, '')
772 775 end
773 776
774 777 def test_syntax_highlight
775 778 raw = <<-RAW
776 779 <pre><code class="ruby">
777 780 # Some ruby code here
778 781 </code></pre>
779 782 RAW
780 783
781 784 expected = <<-EXPECTED
782 785 <pre><code class="ruby syntaxhl"><span class=\"CodeRay\"><span class="comment"># Some ruby code here</span></span>
783 786 </code></pre>
784 787 EXPECTED
785 788
786 789 assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(raw).gsub(%r{[\r\n\t]}, '')
787 790 end
788 791
789 792 def test_to_path_param
790 793 assert_equal 'test1/test2', to_path_param('test1/test2')
791 794 assert_equal 'test1/test2', to_path_param('/test1/test2/')
792 795 assert_equal 'test1/test2', to_path_param('//test1/test2/')
793 796 assert_equal nil, to_path_param('/')
794 797 end
795 798
796 799 def test_wiki_links_in_tables
797 800 to_test = {"|[[Page|Link title]]|[[Other Page|Other title]]|\n|Cell 21|[[Last page]]|" =>
798 801 '<tr><td><a href="/projects/ecookbook/wiki/Page" class="wiki-page new">Link title</a></td>' +
799 802 '<td><a href="/projects/ecookbook/wiki/Other_Page" class="wiki-page new">Other title</a></td>' +
800 803 '</tr><tr><td>Cell 21</td><td><a href="/projects/ecookbook/wiki/Last_page" class="wiki-page new">Last page</a></td></tr>'
801 804 }
802 805 @project = Project.find(1)
803 806 to_test.each { |text, result| assert_equal "<table>#{result}</table>", textilizable(text).gsub(/[\t\n]/, '') }
804 807 end
805 808
806 809 def test_text_formatting
807 810 to_test = {'*_+bold, italic and underline+_*' => '<strong><em><ins>bold, italic and underline</ins></em></strong>',
808 811 '(_text within parentheses_)' => '(<em>text within parentheses</em>)',
809 812 'a *Humane Web* Text Generator' => 'a <strong>Humane Web</strong> Text Generator',
810 813 '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>',
811 814 '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',
812 815 }
813 816 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
814 817 end
815 818
816 819 def test_wiki_horizontal_rule
817 820 assert_equal '<hr />', textilizable('---')
818 821 assert_equal '<p>Dashes: ---</p>', textilizable('Dashes: ---')
819 822 end
820 823
821 824 def test_footnotes
822 825 raw = <<-RAW
823 826 This is some text[1].
824 827
825 828 fn1. This is the foot note
826 829 RAW
827 830
828 831 expected = <<-EXPECTED
829 832 <p>This is some text<sup><a href=\"#fn1\">1</a></sup>.</p>
830 833 <p id="fn1" class="footnote"><sup>1</sup> This is the foot note</p>
831 834 EXPECTED
832 835
833 836 assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(raw).gsub(%r{[\r\n\t]}, '')
834 837 end
835 838
836 839 def test_headings
837 840 raw = 'h1. Some heading'
838 841 expected = %|<a name="Some-heading"></a>\n<h1 >Some heading<a href="#Some-heading" class="wiki-anchor">&para;</a></h1>|
839 842
840 843 assert_equal expected, textilizable(raw)
841 844 end
842 845
843 846 def test_headings_with_special_chars
844 847 # This test makes sure that the generated anchor names match the expected
845 848 # ones even if the heading text contains unconventional characters
846 849 raw = 'h1. Some heading related to version 0.5'
847 850 anchor = sanitize_anchor_name("Some-heading-related-to-version-0.5")
848 851 expected = %|<a name="#{anchor}"></a>\n<h1 >Some heading related to version 0.5<a href="##{anchor}" class="wiki-anchor">&para;</a></h1>|
849 852
850 853 assert_equal expected, textilizable(raw)
851 854 end
852 855
853 856 def test_headings_in_wiki_single_page_export_should_be_prepended_with_page_title
854 857 page = WikiPage.new( :title => 'Page Title', :wiki_id => 1 )
855 858 content = WikiContent.new( :text => 'h1. Some heading', :page => page )
856 859
857 860 expected = %|<a name="Page_Title_Some-heading"></a>\n<h1 >Some heading<a href="#Page_Title_Some-heading" class="wiki-anchor">&para;</a></h1>|
858 861
859 862 assert_equal expected, textilizable(content, :text, :wiki_links => :anchor )
860 863 end
861 864
862 865 def test_table_of_content
863 866 raw = <<-RAW
864 867 {{toc}}
865 868
866 869 h1. Title
867 870
868 871 Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas sed libero.
869 872
870 873 h2. Subtitle with a [[Wiki]] link
871 874
872 875 Nullam commodo metus accumsan nulla. Curabitur lobortis dui id dolor.
873 876
874 877 h2. Subtitle with [[Wiki|another Wiki]] link
875 878
876 879 h2. Subtitle with %{color:red}red text%
877 880
878 881 <pre>
879 882 some code
880 883 </pre>
881 884
882 885 h3. Subtitle with *some* _modifiers_
883 886
884 887 h3. Subtitle with @inline code@
885 888
886 889 h1. Another title
887 890
888 891 h3. An "Internet link":http://www.redmine.org/ inside subtitle
889 892
890 893 h2. "Project Name !/attachments/1234/logo_small.gif! !/attachments/5678/logo_2.png!":/projects/projectname/issues
891 894
892 895 RAW
893 896
894 897 expected = '<ul class="toc">' +
895 898 '<li><a href="#Title">Title</a>' +
896 899 '<ul>' +
897 900 '<li><a href="#Subtitle-with-a-Wiki-link">Subtitle with a Wiki link</a></li>' +
898 901 '<li><a href="#Subtitle-with-another-Wiki-link">Subtitle with another Wiki link</a></li>' +
899 902 '<li><a href="#Subtitle-with-red-text">Subtitle with red text</a>' +
900 903 '<ul>' +
901 904 '<li><a href="#Subtitle-with-some-modifiers">Subtitle with some modifiers</a></li>' +
902 905 '<li><a href="#Subtitle-with-inline-code">Subtitle with inline code</a></li>' +
903 906 '</ul>' +
904 907 '</li>' +
905 908 '</ul>' +
906 909 '</li>' +
907 910 '<li><a href="#Another-title">Another title</a>' +
908 911 '<ul>' +
909 912 '<li>' +
910 913 '<ul>' +
911 914 '<li><a href="#An-Internet-link-inside-subtitle">An Internet link inside subtitle</a></li>' +
912 915 '</ul>' +
913 916 '</li>' +
914 917 '<li><a href="#Project-Name">Project Name</a></li>' +
915 918 '</ul>' +
916 919 '</li>' +
917 920 '</ul>'
918 921
919 922 @project = Project.find(1)
920 923 assert textilizable(raw).gsub("\n", "").include?(expected)
921 924 end
922 925
923 926 def test_table_of_content_should_generate_unique_anchors
924 927 raw = <<-RAW
925 928 {{toc}}
926 929
927 930 h1. Title
928 931
929 932 h2. Subtitle
930 933
931 934 h2. Subtitle
932 935 RAW
933 936
934 937 expected = '<ul class="toc">' +
935 938 '<li><a href="#Title">Title</a>' +
936 939 '<ul>' +
937 940 '<li><a href="#Subtitle">Subtitle</a></li>' +
938 941 '<li><a href="#Subtitle-2">Subtitle</a></li>'
939 942 '</ul>'
940 943 '</li>' +
941 944 '</ul>'
942 945
943 946 @project = Project.find(1)
944 947 result = textilizable(raw).gsub("\n", "")
945 948 assert_include expected, result
946 949 assert_include '<a name="Subtitle">', result
947 950 assert_include '<a name="Subtitle-2">', result
948 951 end
949 952
950 953 def test_table_of_content_should_contain_included_page_headings
951 954 raw = <<-RAW
952 955 {{toc}}
953 956
954 957 h1. Included
955 958
956 959 {{include(Child_1)}}
957 960 RAW
958 961
959 962 expected = '<ul class="toc">' +
960 963 '<li><a href="#Included">Included</a></li>' +
961 964 '<li><a href="#Child-page-1">Child page 1</a></li>' +
962 965 '</ul>'
963 966
964 967 @project = Project.find(1)
965 968 assert textilizable(raw).gsub("\n", "").include?(expected)
966 969 end
967 970
968 971 def test_section_edit_links
969 972 raw = <<-RAW
970 973 h1. Title
971 974
972 975 Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas sed libero.
973 976
974 977 h2. Subtitle with a [[Wiki]] link
975 978
976 979 h2. Subtitle with *some* _modifiers_
977 980
978 981 h2. Subtitle with @inline code@
979 982
980 983 <pre>
981 984 some code
982 985
983 986 h2. heading inside pre
984 987
985 988 <h2>html heading inside pre</h2>
986 989 </pre>
987 990
988 991 h2. Subtitle after pre tag
989 992 RAW
990 993
991 994 @project = Project.find(1)
992 995 set_language_if_valid 'en'
993 996 result = textilizable(raw, :edit_section_links => {:controller => 'wiki', :action => 'edit', :project_id => '1', :id => 'Test'}).gsub("\n", "")
994 997
995 998 # heading that contains inline code
996 999 assert_match Regexp.new('<div class="contextual" title="Edit this section">' +
997 1000 '<a href="/projects/1/wiki/Test/edit\?section=4"><img alt="Edit" src="/images/edit.png(\?\d+)?" /></a></div>' +
998 1001 '<a name="Subtitle-with-inline-code"></a>' +
999 1002 '<h2 >Subtitle with <code>inline code</code><a href="#Subtitle-with-inline-code" class="wiki-anchor">&para;</a></h2>'),
1000 1003 result
1001 1004
1002 1005 # last heading
1003 1006 assert_match Regexp.new('<div class="contextual" title="Edit this section">' +
1004 1007 '<a href="/projects/1/wiki/Test/edit\?section=5"><img alt="Edit" src="/images/edit.png(\?\d+)?" /></a></div>' +
1005 1008 '<a name="Subtitle-after-pre-tag"></a>' +
1006 1009 '<h2 >Subtitle after pre tag<a href="#Subtitle-after-pre-tag" class="wiki-anchor">&para;</a></h2>'),
1007 1010 result
1008 1011 end
1009 1012
1010 1013 def test_default_formatter
1011 1014 with_settings :text_formatting => 'unknown' do
1012 1015 text = 'a *link*: http://www.example.net/'
1013 1016 assert_equal '<p>a *link*: <a class="external" href="http://www.example.net/">http://www.example.net/</a></p>', textilizable(text)
1014 1017 end
1015 1018 end
1016 1019
1017 1020 def test_due_date_distance_in_words
1018 1021 to_test = { Date.today => 'Due in 0 days',
1019 1022 Date.today + 1 => 'Due in 1 day',
1020 1023 Date.today + 100 => 'Due in about 3 months',
1021 1024 Date.today + 20000 => 'Due in over 54 years',
1022 1025 Date.today - 1 => '1 day late',
1023 1026 Date.today - 100 => 'about 3 months late',
1024 1027 Date.today - 20000 => 'over 54 years late',
1025 1028 }
1026 1029 ::I18n.locale = :en
1027 1030 to_test.each do |date, expected|
1028 1031 assert_equal expected, due_date_distance_in_words(date)
1029 1032 end
1030 1033 end
1031 1034
1032 1035 def test_avatar_enabled
1033 1036 with_settings :gravatar_enabled => '1' do
1034 1037 assert avatar(User.find_by_mail('jsmith@somenet.foo')).include?(Digest::MD5.hexdigest('jsmith@somenet.foo'))
1035 1038 assert avatar('jsmith <jsmith@somenet.foo>').include?(Digest::MD5.hexdigest('jsmith@somenet.foo'))
1036 1039 # Default size is 50
1037 1040 assert avatar('jsmith <jsmith@somenet.foo>').include?('size=50')
1038 1041 assert avatar('jsmith <jsmith@somenet.foo>', :size => 24).include?('size=24')
1039 1042 # Non-avatar options should be considered html options
1040 1043 assert avatar('jsmith <jsmith@somenet.foo>', :title => 'John Smith').include?('title="John Smith"')
1041 1044 # The default class of the img tag should be gravatar
1042 1045 assert avatar('jsmith <jsmith@somenet.foo>').include?('class="gravatar"')
1043 1046 assert !avatar('jsmith <jsmith@somenet.foo>', :class => 'picture').include?('class="gravatar"')
1044 1047 assert_nil avatar('jsmith')
1045 1048 assert_nil avatar(nil)
1046 1049 end
1047 1050 end
1048 1051
1049 1052 def test_avatar_disabled
1050 1053 with_settings :gravatar_enabled => '0' do
1051 1054 assert_equal '', avatar(User.find_by_mail('jsmith@somenet.foo'))
1052 1055 end
1053 1056 end
1054 1057
1055 1058 def test_link_to_user
1056 1059 user = User.find(2)
1057 1060 assert_equal '<a href="/users/2" class="user active">John Smith</a>', link_to_user(user)
1058 1061 end
1059 1062
1060 1063 def test_link_to_user_should_not_link_to_locked_user
1061 1064 with_current_user nil do
1062 1065 user = User.find(5)
1063 1066 assert user.locked?
1064 1067 assert_equal 'Dave2 Lopper2', link_to_user(user)
1065 1068 end
1066 1069 end
1067 1070
1068 1071 def test_link_to_user_should_link_to_locked_user_if_current_user_is_admin
1069 1072 with_current_user User.find(1) do
1070 1073 user = User.find(5)
1071 1074 assert user.locked?
1072 1075 assert_equal '<a href="/users/5" class="user locked">Dave2 Lopper2</a>', link_to_user(user)
1073 1076 end
1074 1077 end
1075 1078
1076 1079 def test_link_to_user_should_not_link_to_anonymous
1077 1080 user = User.anonymous
1078 1081 assert user.anonymous?
1079 1082 t = link_to_user(user)
1080 1083 assert_equal ::I18n.t(:label_user_anonymous), t
1081 1084 end
1082 1085
1083 1086 def test_link_to_attachment
1084 1087 a = Attachment.find(3)
1085 1088 assert_equal '<a href="/attachments/3/logo.gif">logo.gif</a>',
1086 1089 link_to_attachment(a)
1087 1090 assert_equal '<a href="/attachments/3/logo.gif">Text</a>',
1088 1091 link_to_attachment(a, :text => 'Text')
1089 1092 assert_equal '<a href="/attachments/3/logo.gif" class="foo">logo.gif</a>',
1090 1093 link_to_attachment(a, :class => 'foo')
1091 1094 assert_equal '<a href="/attachments/download/3/logo.gif">logo.gif</a>',
1092 1095 link_to_attachment(a, :download => true)
1093 1096 assert_equal '<a href="http://test.host/attachments/3/logo.gif">logo.gif</a>',
1094 1097 link_to_attachment(a, :only_path => false)
1095 1098 end
1096 1099
1097 1100 def test_thumbnail_tag
1098 1101 a = Attachment.find(3)
1099 1102 assert_equal '<a href="/attachments/3/logo.gif" title="logo.gif"><img alt="3" src="/attachments/thumbnail/3" /></a>',
1100 1103 thumbnail_tag(a)
1101 1104 end
1102 1105
1103 1106 def test_link_to_project
1104 1107 project = Project.find(1)
1105 1108 assert_equal %(<a href="/projects/ecookbook">eCookbook</a>),
1106 1109 link_to_project(project)
1107 1110 assert_equal %(<a href="/projects/ecookbook/settings">eCookbook</a>),
1108 1111 link_to_project(project, :action => 'settings')
1109 1112 assert_equal %(<a href="http://test.host/projects/ecookbook?jump=blah">eCookbook</a>),
1110 1113 link_to_project(project, {:only_path => false, :jump => 'blah'})
1111 1114 assert_equal %(<a href="/projects/ecookbook/settings" class="project">eCookbook</a>),
1112 1115 link_to_project(project, {:action => 'settings'}, :class => "project")
1113 1116 end
1114 1117
1115 1118 def test_link_to_project_settings
1116 1119 project = Project.find(1)
1117 1120 assert_equal '<a href="/projects/ecookbook/settings">eCookbook</a>', link_to_project_settings(project)
1118 1121
1119 1122 project.status = Project::STATUS_CLOSED
1120 1123 assert_equal '<a href="/projects/ecookbook">eCookbook</a>', link_to_project_settings(project)
1121 1124
1122 1125 project.status = Project::STATUS_ARCHIVED
1123 1126 assert_equal 'eCookbook', link_to_project_settings(project)
1124 1127 end
1125 1128
1126 1129 def test_link_to_legacy_project_with_numerical_identifier_should_use_id
1127 1130 # numeric identifier are no longer allowed
1128 1131 Project.update_all "identifier=25", "id=1"
1129 1132
1130 1133 assert_equal '<a href="/projects/1">eCookbook</a>',
1131 1134 link_to_project(Project.find(1))
1132 1135 end
1133 1136
1134 1137 def test_principals_options_for_select_with_users
1135 1138 User.current = nil
1136 1139 users = [User.find(2), User.find(4)]
1137 1140 assert_equal %(<option value="2">John Smith</option><option value="4">Robert Hill</option>),
1138 1141 principals_options_for_select(users)
1139 1142 end
1140 1143
1141 1144 def test_principals_options_for_select_with_selected
1142 1145 User.current = nil
1143 1146 users = [User.find(2), User.find(4)]
1144 1147 assert_equal %(<option value="2">John Smith</option><option value="4" selected="selected">Robert Hill</option>),
1145 1148 principals_options_for_select(users, User.find(4))
1146 1149 end
1147 1150
1148 1151 def test_principals_options_for_select_with_users_and_groups
1149 1152 User.current = nil
1150 1153 users = [User.find(2), Group.find(11), User.find(4), Group.find(10)]
1151 1154 assert_equal %(<option value="2">John Smith</option><option value="4">Robert Hill</option>) +
1152 1155 %(<optgroup label="Groups"><option value="10">A Team</option><option value="11">B Team</option></optgroup>),
1153 1156 principals_options_for_select(users)
1154 1157 end
1155 1158
1156 1159 def test_principals_options_for_select_with_empty_collection
1157 1160 assert_equal '', principals_options_for_select([])
1158 1161 end
1159 1162
1160 1163 def test_principals_options_for_select_should_include_me_option_when_current_user_is_in_collection
1161 1164 users = [User.find(2), User.find(4)]
1162 1165 User.current = User.find(4)
1163 1166 assert_include '<option value="4">&lt;&lt; me &gt;&gt;</option>', principals_options_for_select(users)
1164 1167 end
1165 1168
1166 1169 def test_stylesheet_link_tag_should_pick_the_default_stylesheet
1167 1170 assert_match 'href="/stylesheets/styles.css"', stylesheet_link_tag("styles")
1168 1171 end
1169 1172
1170 1173 def test_stylesheet_link_tag_for_plugin_should_pick_the_plugin_stylesheet
1171 1174 assert_match 'href="/plugin_assets/foo/stylesheets/styles.css"', stylesheet_link_tag("styles", :plugin => :foo)
1172 1175 end
1173 1176
1174 1177 def test_image_tag_should_pick_the_default_image
1175 1178 assert_match 'src="/images/image.png"', image_tag("image.png")
1176 1179 end
1177 1180
1178 1181 def test_image_tag_should_pick_the_theme_image_if_it_exists
1179 1182 theme = Redmine::Themes.themes.last
1180 1183 theme.images << 'image.png'
1181 1184
1182 1185 with_settings :ui_theme => theme.id do
1183 1186 assert_match %|src="/themes/#{theme.dir}/images/image.png"|, image_tag("image.png")
1184 1187 assert_match %|src="/images/other.png"|, image_tag("other.png")
1185 1188 end
1186 1189 ensure
1187 1190 theme.images.delete 'image.png'
1188 1191 end
1189 1192
1190 1193 def test_image_tag_sfor_plugin_should_pick_the_plugin_image
1191 1194 assert_match 'src="/plugin_assets/foo/images/image.png"', image_tag("image.png", :plugin => :foo)
1192 1195 end
1193 1196
1194 1197 def test_javascript_include_tag_should_pick_the_default_javascript
1195 1198 assert_match 'src="/javascripts/scripts.js"', javascript_include_tag("scripts")
1196 1199 end
1197 1200
1198 1201 def test_javascript_include_tag_for_plugin_should_pick_the_plugin_javascript
1199 1202 assert_match 'src="/plugin_assets/foo/javascripts/scripts.js"', javascript_include_tag("scripts", :plugin => :foo)
1200 1203 end
1201 1204 end
General Comments 0
You need to be logged in to leave comments. Login now