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