##// END OF EJS Templates
Fixed: urls containing @ are parsed as email adress by the wiki formatter (#1456)....
Jean-Philippe Lang -
r1545:d991e46f122d
parent child
Show More
@@ -1,171 +1,175
1 1 # redMine - project management software
2 2 # Copyright (C) 2006-2007 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 'redcloth'
19 19 require 'coderay'
20 20
21 21 module Redmine
22 22 module WikiFormatting
23 23
24 24 private
25 25
26 26 class TextileFormatter < RedCloth
27 27
28 28 # auto_link rule after textile rules so that it doesn't break !image_url! tags
29 29 RULES = [:textile, :block_markdown_rule, :inline_auto_link, :inline_auto_mailto, :inline_toc, :inline_macros]
30 30
31 31 def initialize(*args)
32 32 super
33 33 self.hard_breaks=true
34 34 self.no_span_caps=true
35 35 end
36 36
37 37 def to_html(*rules, &block)
38 38 @toc = []
39 39 @macros_runner = block
40 40 super(*RULES).to_s
41 41 end
42 42
43 43 private
44 44
45 45 # Patch for RedCloth. Fixed in RedCloth r128 but _why hasn't released it yet.
46 46 # <a href="http://code.whytheluckystiff.net/redcloth/changeset/128">http://code.whytheluckystiff.net/redcloth/changeset/128</a>
47 47 def hard_break( text )
48 48 text.gsub!( /(.)\n(?!\n|\Z|>| *(>? *[#*=]+(\s|$)|[{|]))/, "\\1<br />\n" ) if hard_breaks
49 49 end
50 50
51 51 # Patch to add code highlighting support to RedCloth
52 52 def smooth_offtags( text )
53 53 unless @pre_list.empty?
54 54 ## replace <pre> content
55 55 text.gsub!(/<redpre#(\d+)>/) do
56 56 content = @pre_list[$1.to_i]
57 57 if content.match(/<code\s+class="(\w+)">\s?(.+)/m)
58 58 content = "<code class=\"#{$1} CodeRay\">" +
59 59 CodeRay.scan($2, $1.downcase).html(:escape => false, :line_numbers => :inline)
60 60 end
61 61 content
62 62 end
63 63 end
64 64 end
65 65
66 66 # Patch to add 'table of content' support to RedCloth
67 67 def textile_p_withtoc(tag, atts, cite, content)
68 68 if tag =~ /^h(\d)$/
69 69 @toc << [$1.to_i, content]
70 70 end
71 71 content = "<a name=\"#{@toc.length}\" class=\"wiki-page\"></a>" + content
72 72 textile_p(tag, atts, cite, content)
73 73 end
74 74
75 75 alias :textile_h1 :textile_p_withtoc
76 76 alias :textile_h2 :textile_p_withtoc
77 77 alias :textile_h3 :textile_p_withtoc
78 78
79 79 def inline_toc(text)
80 80 text.gsub!(/<p>\{\{([<>]?)toc\}\}<\/p>/i) do
81 81 div_class = 'toc'
82 82 div_class << ' right' if $1 == '>'
83 83 div_class << ' left' if $1 == '<'
84 84 out = "<div class=\"#{div_class}\">"
85 85 @toc.each_with_index do |heading, index|
86 86 # remove wiki links from the item
87 87 toc_item = heading.last.gsub(/(\[\[|\]\])/, '')
88 88 # remove styles
89 89 # eg. %{color:red}Triggers% => Triggers
90 90 toc_item.gsub! %r[%\{[^\}]*\}([^%]+)%], '\\1'
91 91 out << "<a href=\"##{index+1}\" class=\"heading#{heading.first}\">#{toc_item}</a>"
92 92 end
93 93 out << '</div>'
94 94 out
95 95 end
96 96 end
97 97
98 98 MACROS_RE = /
99 99 (!)? # escaping
100 100 (
101 101 \{\{ # opening tag
102 102 ([\w]+) # macro name
103 103 (\(([^\}]*)\))? # optional arguments
104 104 \}\} # closing tag
105 105 )
106 106 /x unless const_defined?(:MACROS_RE)
107 107
108 108 def inline_macros(text)
109 109 text.gsub!(MACROS_RE) do
110 110 esc, all, macro = $1, $2, $3.downcase
111 111 args = ($5 || '').split(',').each(&:strip)
112 112 if esc.nil?
113 113 begin
114 114 @macros_runner.call(macro, args)
115 115 rescue => e
116 116 "<div class=\"flash error\">Error executing the <strong>#{macro}</strong> macro (#{e})</div>"
117 117 end || all
118 118 else
119 119 all
120 120 end
121 121 end
122 122 end
123 123
124 124 AUTO_LINK_RE = %r{
125 125 ( # leading text
126 126 <\w+.*?>| # leading HTML tag, or
127 127 [^=<>!:'"/]| # leading punctuation, or
128 128 ^ # beginning of line
129 129 )
130 130 (
131 131 (?:https?://)| # protocol spec, or
132 132 (?:www\.) # www.*
133 133 )
134 134 (
135 135 (\S+?) # url
136 136 (\/)? # slash
137 137 )
138 138 ([^\w\=\/;]*?) # post
139 139 (?=<|\s|$)
140 140 }x unless const_defined?(:AUTO_LINK_RE)
141 141
142 142 # Turns all urls into clickable links (code from Rails).
143 143 def inline_auto_link(text)
144 144 text.gsub!(AUTO_LINK_RE) do
145 145 all, leading, proto, url, post = $&, $1, $2, $3, $6
146 146 if leading =~ /<a\s/i || leading =~ /![<>=]?/
147 147 # don't replace URL's that are already linked
148 148 # and URL's prefixed with ! !> !< != (textile images)
149 149 all
150 150 else
151 151 %(#{leading}<a class="external" href="#{proto=="www."?"http://www.":proto}#{url}">#{proto + url}</a>#{post})
152 152 end
153 153 end
154 154 end
155
155
156 156 # Turns all email addresses into clickable links (code from Rails).
157 157 def inline_auto_mailto(text)
158 158 text.gsub!(/([\w\.!#\$%\-+.]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/) do
159 text = $1
160 %{<a href="mailto:#{$1}" class="email">#{text}</a>}
159 mail = $1
160 if text.match(/<a\b[^>]*>(.*)(#{Regexp.escape(mail)})(.*)<\/a>/)
161 mail
162 else
163 %{<a href="mailto:#{mail}" class="email">#{mail}</a>}
164 end
161 165 end
162 166 end
163 167 end
164 168
165 169 public
166 170
167 171 def self.to_html(text, options = {}, &block)
168 172 TextileFormatter.new(text).to_html(&block)
169 173 end
170 174 end
171 175 end
@@ -1,330 +1,331
1 1 # redMine - project management software
2 2 # Copyright (C) 2006-2007 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 File.dirname(__FILE__) + '/../../test_helper'
19 19
20 20 class ApplicationHelperTest < HelperTestCase
21 21 include ApplicationHelper
22 22 include ActionView::Helpers::TextHelper
23 23 fixtures :projects, :repositories, :changesets, :trackers, :issue_statuses, :issues, :documents, :versions, :wikis, :wiki_pages, :wiki_contents, :roles, :enabled_modules
24 24
25 25 def setup
26 26 super
27 27 end
28 28
29 29 def test_auto_links
30 30 to_test = {
31 31 'http://foo.bar' => '<a class="external" href="http://foo.bar">http://foo.bar</a>',
32 32 'http://foo.bar/~user' => '<a class="external" href="http://foo.bar/~user">http://foo.bar/~user</a>',
33 33 'http://foo.bar.' => '<a class="external" href="http://foo.bar">http://foo.bar</a>.',
34 34 '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>.',
35 35 'www.foo.bar' => '<a class="external" href="http://www.foo.bar">www.foo.bar</a>',
36 36 '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>',
37 'http://foo.bar/page#125' => '<a class="external" href="http://foo.bar/page#125">http://foo.bar/page#125</a>'
37 'http://foo.bar/page#125' => '<a class="external" href="http://foo.bar/page#125">http://foo.bar/page#125</a>',
38 'http://foo@www.bar.com' => '<a class="external" href="http://foo@www.bar.com">http://foo@www.bar.com</a>',
38 39 }
39 40 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
40 41 end
41 42
42 43 def test_auto_mailto
43 44 assert_equal '<p><a href="mailto:test@foo.bar" class="email">test@foo.bar</a></p>',
44 45 textilizable('test@foo.bar')
45 46 end
46 47
47 48 def test_inline_images
48 49 to_test = {
49 50 '!http://foo.bar/image.jpg!' => '<img src="http://foo.bar/image.jpg" alt="" />',
50 51 'floating !>http://foo.bar/image.jpg!' => 'floating <div style="float:right"><img src="http://foo.bar/image.jpg" alt="" /></div>',
51 52 'with class !(some-class)http://foo.bar/image.jpg!' => 'with class <img src="http://foo.bar/image.jpg" class="some-class" alt="" />',
52 53 'with style !{width:100px;height100px}http://foo.bar/image.jpg!' => 'with style <img src="http://foo.bar/image.jpg" style="width:100px;height100px;" alt="" />',
53 54 }
54 55 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
55 56 end
56 57
57 58 def test_textile_external_links
58 59 to_test = {
59 60 'This is a "link":http://foo.bar' => 'This is a <a href="http://foo.bar" class="external">link</a>',
60 61 'This is an intern "link":/foo/bar' => 'This is an intern <a href="/foo/bar">link</a>',
61 62 '"link (Link title)":http://foo.bar' => '<a href="http://foo.bar" title="Link title" class="external">link</a>',
62 63 "This is not a \"Link\":\n\nAnother paragraph" => "This is not a \"Link\":</p>\n\n\n\t<p>Another paragraph",
63 64 # no multiline link text
64 65 "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 />\nand another on a second line\":test"
65 66 }
66 67 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
67 68 end
68 69
69 70 def test_redmine_links
70 71 issue_link = link_to('#3', {:controller => 'issues', :action => 'show', :id => 3},
71 72 :class => 'issue', :title => 'Error 281 when updating a recipe (New)')
72 73
73 74 changeset_link = link_to('r1', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 1},
74 75 :class => 'changeset', :title => 'My very first commit')
75 76
76 77 document_link = link_to('Test document', {:controller => 'documents', :action => 'show', :id => 1},
77 78 :class => 'document')
78 79
79 80 version_link = link_to('1.0', {:controller => 'versions', :action => 'show', :id => 2},
80 81 :class => 'version')
81 82
82 83 source_url = {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :path => 'some/file'}
83 84
84 85 to_test = {
85 86 # tickets
86 87 '#3, #3 and #3.' => "#{issue_link}, #{issue_link} and #{issue_link}.",
87 88 # changesets
88 89 'r1' => changeset_link,
89 90 # documents
90 91 'document#1' => document_link,
91 92 'document:"Test document"' => document_link,
92 93 # versions
93 94 'version#2' => version_link,
94 95 'version:1.0' => version_link,
95 96 'version:"1.0"' => version_link,
96 97 # source
97 98 'source:/some/file' => link_to('source:/some/file', source_url, :class => 'source'),
98 99 'source:/some/file@52' => link_to('source:/some/file@52', source_url.merge(:rev => 52), :class => 'source'),
99 100 'source:/some/file#L110' => link_to('source:/some/file#L110', source_url.merge(:anchor => 'L110'), :class => 'source'),
100 101 'source:/some/file@52#L110' => link_to('source:/some/file@52#L110', source_url.merge(:rev => 52, :anchor => 'L110'), :class => 'source'),
101 102 'export:/some/file' => link_to('export:/some/file', source_url.merge(:format => 'raw'), :class => 'source download'),
102 103 # escaping
103 104 '!#3.' => '#3.',
104 105 '!r1' => 'r1',
105 106 '!document#1' => 'document#1',
106 107 '!document:"Test document"' => 'document:"Test document"',
107 108 '!version#2' => 'version#2',
108 109 '!version:1.0' => 'version:1.0',
109 110 '!version:"1.0"' => 'version:"1.0"',
110 111 '!source:/some/file' => 'source:/some/file',
111 112 # invalid expressions
112 113 'source:' => 'source:',
113 114 # url hash
114 115 "http://foo.bar/FAQ#3" => '<a class="external" href="http://foo.bar/FAQ#3">http://foo.bar/FAQ#3</a>',
115 116 }
116 117 @project = Project.find(1)
117 118 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
118 119 end
119 120
120 121 def test_wiki_links
121 122 to_test = {
122 123 '[[CookBook documentation]]' => '<a href="/wiki/ecookbook/CookBook_documentation" class="wiki-page">CookBook documentation</a>',
123 124 '[[Another page|Page]]' => '<a href="/wiki/ecookbook/Another_page" class="wiki-page">Page</a>',
124 125 # page that doesn't exist
125 126 '[[Unknown page]]' => '<a href="/wiki/ecookbook/Unknown_page" class="wiki-page new">Unknown page</a>',
126 127 '[[Unknown page|404]]' => '<a href="/wiki/ecookbook/Unknown_page" class="wiki-page new">404</a>',
127 128 # link to another project wiki
128 129 '[[onlinestore:]]' => '<a href="/wiki/onlinestore/" class="wiki-page">onlinestore</a>',
129 130 '[[onlinestore:|Wiki]]' => '<a href="/wiki/onlinestore/" class="wiki-page">Wiki</a>',
130 131 '[[onlinestore:Start page]]' => '<a href="/wiki/onlinestore/Start_page" class="wiki-page">Start page</a>',
131 132 '[[onlinestore:Start page|Text]]' => '<a href="/wiki/onlinestore/Start_page" class="wiki-page">Text</a>',
132 133 '[[onlinestore:Unknown page]]' => '<a href="/wiki/onlinestore/Unknown_page" class="wiki-page new">Unknown page</a>',
133 134 # striked through link
134 135 '-[[Another page|Page]]-' => '<del><a href="/wiki/ecookbook/Another_page" class="wiki-page">Page</a></del>',
135 136 # escaping
136 137 '![[Another page|Page]]' => '[[Another page|Page]]',
137 138 }
138 139 @project = Project.find(1)
139 140 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
140 141 end
141 142
142 143 def test_html_tags
143 144 to_test = {
144 145 "<div>content</div>" => "<p>&lt;div&gt;content&lt;/div&gt;</p>",
145 146 "<div class=\"bold\">content</div>" => "<p>&lt;div class=\"bold\"&gt;content&lt;/div&gt;</p>",
146 147 "<script>some script;</script>" => "<p>&lt;script&gt;some script;&lt;/script&gt;</p>",
147 148 # do not escape pre/code tags
148 149 "<pre>\nline 1\nline2</pre>" => "<pre>\nline 1\nline2</pre>",
149 150 "<pre><code>\nline 1\nline2</code></pre>" => "<pre><code>\nline 1\nline2</code></pre>",
150 151 "<pre><div>content</div></pre>" => "<pre>&lt;div&gt;content&lt;/div&gt;</pre>",
151 152 "HTML comment: <!-- no comments -->" => "<p>HTML comment: &lt;!-- no comments --&gt;</p>",
152 153 "<!-- opening comment" => "<p>&lt;!-- opening comment</p>"
153 154 }
154 155 to_test.each { |text, result| assert_equal result, textilizable(text) }
155 156 end
156 157
157 158 def test_allowed_html_tags
158 159 to_test = {
159 160 "<pre>preformatted text</pre>" => "<pre>preformatted text</pre>",
160 161 "<notextile>no *textile* formatting</notextile>" => "no *textile* formatting",
161 162 }
162 163 to_test.each { |text, result| assert_equal result, textilizable(text) }
163 164 end
164 165
165 166 def test_wiki_links_in_tables
166 167 to_test = {"|[[Page|Link title]]|[[Other Page|Other title]]|\n|Cell 21|[[Last page]]|" =>
167 168 '<tr><td><a href="/wiki/ecookbook/Page" class="wiki-page new">Link title</a></td>' +
168 169 '<td><a href="/wiki/ecookbook/Other_Page" class="wiki-page new">Other title</a></td>' +
169 170 '</tr><tr><td>Cell 21</td><td><a href="/wiki/ecookbook/Last_page" class="wiki-page new">Last page</a></td></tr>'
170 171 }
171 172 @project = Project.find(1)
172 173 to_test.each { |text, result| assert_equal "<table>#{result}</table>", textilizable(text).gsub(/[\t\n]/, '') }
173 174 end
174 175
175 176 def test_text_formatting
176 177 to_test = {'*_+bold, italic and underline+_*' => '<strong><em><ins>bold, italic and underline</ins></em></strong>',
177 178 '(_text within parentheses_)' => '(<em>text within parentheses</em>)'
178 179 }
179 180 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
180 181 end
181 182
182 183 def test_wiki_horizontal_rule
183 184 assert_equal '<hr />', textilizable('---')
184 185 assert_equal '<p>Dashes: ---</p>', textilizable('Dashes: ---')
185 186 end
186 187
187 188 def test_table_of_content
188 189 raw = <<-RAW
189 190 {{toc}}
190 191
191 192 h1. Title
192 193
193 194 Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas sed libero.
194 195
195 196 h2. Subtitle
196 197
197 198 Nullam commodo metus accumsan nulla. Curabitur lobortis dui id dolor.
198 199
199 200 h2. Subtitle with %{color:red}red text%
200 201
201 202 h1. Another title
202 203
203 204 RAW
204 205
205 206 expected = '<div class="toc">' +
206 207 '<a href="#1" class="heading1">Title</a>' +
207 208 '<a href="#2" class="heading2">Subtitle</a>' +
208 209 '<a href="#3" class="heading2">Subtitle with red text</a>' +
209 210 '<a href="#4" class="heading1">Another title</a>' +
210 211 '</div>'
211 212
212 213 assert textilizable(raw).include?(expected)
213 214 end
214 215
215 216 def test_blockquote
216 217 # orig raw text
217 218 raw = <<-RAW
218 219 John said:
219 220 > Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas sed libero.
220 221 > Nullam commodo metus accumsan nulla. Curabitur lobortis dui id dolor.
221 222 > * Donec odio lorem,
222 223 > * sagittis ac,
223 224 > * malesuada in,
224 225 > * adipiscing eu, dolor.
225 226 >
226 227 > >Nulla varius pulvinar diam. Proin id arcu id lorem scelerisque condimentum. Proin vehicula turpis vitae lacus.
227 228 > Proin a tellus. Nam vel neque.
228 229
229 230 He's right.
230 231 RAW
231 232
232 233 # expected html
233 234 expected = <<-EXPECTED
234 235 <p>John said:</p>
235 236 <blockquote>
236 237 Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas sed libero.
237 238 Nullam commodo metus accumsan nulla. Curabitur lobortis dui id dolor.
238 239 <ul>
239 240 <li>Donec odio lorem,</li>
240 241 <li>sagittis ac,</li>
241 242 <li>malesuada in,</li>
242 243 <li>adipiscing eu, dolor.</li>
243 244 </ul>
244 245 <blockquote>
245 246 <p>Nulla varius pulvinar diam. Proin id arcu id lorem scelerisque condimentum. Proin vehicula turpis vitae lacus.</p>
246 247 </blockquote>
247 248 <p>Proin a tellus. Nam vel neque.</p>
248 249 </blockquote>
249 250 <p>He's right.</p>
250 251 EXPECTED
251 252
252 253 assert_equal expected.gsub(%r{\s+}, ''), textilizable(raw).gsub(%r{\s+}, '')
253 254 end
254 255
255 256 def test_table
256 257 raw = <<-RAW
257 258 This is a table with empty cells:
258 259
259 260 |cell11|cell12||
260 261 |cell21||cell23|
261 262 |cell31|cell32|cell33|
262 263 RAW
263 264
264 265 expected = <<-EXPECTED
265 266 <p>This is a table with empty cells:</p>
266 267
267 268 <table>
268 269 <tr><td>cell11</td><td>cell12</td><td></td></tr>
269 270 <tr><td>cell21</td><td></td><td>cell23</td></tr>
270 271 <tr><td>cell31</td><td>cell32</td><td>cell33</td></tr>
271 272 </table>
272 273 EXPECTED
273 274
274 275 assert_equal expected.gsub(%r{\s+}, ''), textilizable(raw).gsub(%r{\s+}, '')
275 276 end
276 277
277 278 def test_macro_hello_world
278 279 text = "{{hello_world}}"
279 280 assert textilizable(text).match(/Hello world!/)
280 281 # escaping
281 282 text = "!{{hello_world}}"
282 283 assert_equal '<p>{{hello_world}}</p>', textilizable(text)
283 284 end
284 285
285 286 def test_macro_include
286 287 @project = Project.find(1)
287 288 # include a page of the current project wiki
288 289 text = "{{include(Another page)}}"
289 290 assert textilizable(text).match(/This is a link to a ticket/)
290 291
291 292 @project = nil
292 293 # include a page of a specific project wiki
293 294 text = "{{include(ecookbook:Another page)}}"
294 295 assert textilizable(text).match(/This is a link to a ticket/)
295 296
296 297 text = "{{include(ecookbook:)}}"
297 298 assert textilizable(text).match(/CookBook documentation/)
298 299
299 300 text = "{{include(unknowidentifier:somepage)}}"
300 301 assert textilizable(text).match(/Unknow project/)
301 302 end
302 303
303 304 def test_date_format_default
304 305 today = Date.today
305 306 Setting.date_format = ''
306 307 assert_equal l_date(today), format_date(today)
307 308 end
308 309
309 310 def test_date_format
310 311 today = Date.today
311 312 Setting.date_format = '%d %m %Y'
312 313 assert_equal today.strftime('%d %m %Y'), format_date(today)
313 314 end
314 315
315 316 def test_time_format_default
316 317 now = Time.now
317 318 Setting.date_format = ''
318 319 Setting.time_format = ''
319 320 assert_equal l_datetime(now), format_time(now)
320 321 assert_equal l_time(now), format_time(now, false)
321 322 end
322 323
323 324 def test_time_format
324 325 now = Time.now
325 326 Setting.date_format = '%d %m %Y'
326 327 Setting.time_format = '%H %M'
327 328 assert_equal now.strftime('%d %m %Y %H %M'), format_time(now)
328 329 assert_equal now.strftime('%H %M'), format_time(now, false)
329 330 end
330 331 end
General Comments 0
You need to be logged in to leave comments. Login now