@@ -0,0 +1,22 | |||
|
1 | require File.dirname(__FILE__) + '/../test_helper' | |
|
2 | require 'issue_relations_controller' | |
|
3 | ||
|
4 | # Re-raise errors caught by the controller. | |
|
5 | class IssueRelationsController; def rescue_action(e) raise e end; end | |
|
6 | ||
|
7 | ||
|
8 | class IssueRelationsControllerTest < Test::Unit::TestCase | |
|
9 | def test_new_routing | |
|
10 | assert_routing( | |
|
11 | {:method => :post, :path => '/issues/1/relations'}, | |
|
12 | {:controller => 'issue_relations', :action => 'new', :issue_id => '1'} | |
|
13 | ) | |
|
14 | end | |
|
15 | ||
|
16 | def test_destroy_routing | |
|
17 | assert_recognizes( #TODO: use DELETE on issue URI | |
|
18 | {:controller => 'issue_relations', :action => 'destroy', :issue_id => '1', :id => '23'}, | |
|
19 | {:method => :post, :path => '/issues/1/relations/23/destroy'} | |
|
20 | ) | |
|
21 | end | |
|
22 | end |
@@ -0,0 +1,15 | |||
|
1 | require File.dirname(__FILE__) + '/../test_helper' | |
|
2 | require 'members_controller' | |
|
3 | ||
|
4 | # Re-raise errors caught by the controller. | |
|
5 | class MembersController; def rescue_action(e) raise e end; end | |
|
6 | ||
|
7 | ||
|
8 | class MembersControllerTest < Test::Unit::TestCase | |
|
9 | def test_members_routing | |
|
10 | assert_routing( | |
|
11 | {:method => :post, :path => 'projects/5234/members/new'}, | |
|
12 | :controller => 'members', :action => 'new', :id => '5234' | |
|
13 | ) | |
|
14 | end | |
|
15 | end |
@@ -0,0 +1,20 | |||
|
1 | require File.dirname(__FILE__) + '/../test_helper' | |
|
2 | require 'reports_controller' | |
|
3 | ||
|
4 | # Re-raise errors caught by the controller. | |
|
5 | class ReportsController; def rescue_action(e) raise e end; end | |
|
6 | ||
|
7 | ||
|
8 | class ReportsControllerTest < Test::Unit::TestCase | |
|
9 | def test_issue_report_routing | |
|
10 | assert_routing( | |
|
11 | {:method => :get, :path => '/projects/567/issues/report'}, | |
|
12 | :controller => 'reports', :action => 'issue_report', :id => '567' | |
|
13 | ) | |
|
14 | assert_routing( | |
|
15 | {:method => :get, :path => '/projects/567/issues/report/assigned_to'}, | |
|
16 | :controller => 'reports', :action => 'issue_report', :id => '567', :detail => 'assigned_to' | |
|
17 | ) | |
|
18 | ||
|
19 | end | |
|
20 | end |
@@ -1,667 +1,672 | |||
|
1 | 1 | # redMine - project management software |
|
2 | 2 | # Copyright (C) 2006-2007 Jean-Philippe Lang |
|
3 | 3 | # |
|
4 | 4 | # This program is free software; you can redistribute it and/or |
|
5 | 5 | # modify it under the terms of the GNU General Public License |
|
6 | 6 | # as published by the Free Software Foundation; either version 2 |
|
7 | 7 | # of the License, or (at your option) any later version. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU General Public License |
|
15 | 15 | # along with this program; if not, write to the Free Software |
|
16 | 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 | 17 | |
|
18 | 18 | require 'coderay' |
|
19 | 19 | require 'coderay/helpers/file_type' |
|
20 | 20 | require 'forwardable' |
|
21 | 21 | require 'cgi' |
|
22 | 22 | |
|
23 | 23 | module ApplicationHelper |
|
24 | 24 | include Redmine::WikiFormatting::Macros::Definitions |
|
25 | 25 | include GravatarHelper::PublicMethods |
|
26 | 26 | |
|
27 | 27 | extend Forwardable |
|
28 | 28 | def_delegators :wiki_helper, :wikitoolbar_for, :heads_for_wiki_formatter |
|
29 | 29 | |
|
30 | 30 | def current_role |
|
31 | 31 | @current_role ||= User.current.role_for_project(@project) |
|
32 | 32 | end |
|
33 | 33 | |
|
34 | 34 | # Return true if user is authorized for controller/action, otherwise false |
|
35 | 35 | def authorize_for(controller, action) |
|
36 | 36 | User.current.allowed_to?({:controller => controller, :action => action}, @project) |
|
37 | 37 | end |
|
38 | 38 | |
|
39 | 39 | # Display a link if user is authorized |
|
40 | 40 | def link_to_if_authorized(name, options = {}, html_options = nil, *parameters_for_method_reference) |
|
41 | 41 | link_to(name, options, html_options, *parameters_for_method_reference) if authorize_for(options[:controller] || params[:controller], options[:action]) |
|
42 | 42 | end |
|
43 | 43 | |
|
44 | 44 | # Display a link to remote if user is authorized |
|
45 | 45 | def link_to_remote_if_authorized(name, options = {}, html_options = nil) |
|
46 | 46 | url = options[:url] || {} |
|
47 | 47 | link_to_remote(name, options, html_options) if authorize_for(url[:controller] || params[:controller], url[:action]) |
|
48 | 48 | end |
|
49 | 49 | |
|
50 | 50 | # Display a link to user's account page |
|
51 | 51 | def link_to_user(user, options={}) |
|
52 | 52 | (user && !user.anonymous?) ? link_to(user.name(options[:format]), :controller => 'account', :action => 'show', :id => user) : 'Anonymous' |
|
53 | 53 | end |
|
54 | 54 | |
|
55 | 55 | def link_to_issue(issue, options={}) |
|
56 | 56 | options[:class] ||= '' |
|
57 | 57 | options[:class] << ' issue' |
|
58 | 58 | options[:class] << ' closed' if issue.closed? |
|
59 | 59 | link_to "#{issue.tracker.name} ##{issue.id}", {:controller => "issues", :action => "show", :id => issue}, options |
|
60 | 60 | end |
|
61 | 61 | |
|
62 | 62 | # Generates a link to an attachment. |
|
63 | 63 | # Options: |
|
64 | 64 | # * :text - Link text (default to attachment filename) |
|
65 | 65 | # * :download - Force download (default: false) |
|
66 | 66 | def link_to_attachment(attachment, options={}) |
|
67 | 67 | text = options.delete(:text) || attachment.filename |
|
68 | 68 | action = options.delete(:download) ? 'download' : 'show' |
|
69 | 69 | |
|
70 | 70 | link_to(h(text), {:controller => 'attachments', :action => action, :id => attachment, :filename => attachment.filename }, options) |
|
71 | 71 | end |
|
72 | 72 | |
|
73 | 73 | def toggle_link(name, id, options={}) |
|
74 | 74 | onclick = "Element.toggle('#{id}'); " |
|
75 | 75 | onclick << (options[:focus] ? "Form.Element.focus('#{options[:focus]}'); " : "this.blur(); ") |
|
76 | 76 | onclick << "return false;" |
|
77 | 77 | link_to(name, "#", :onclick => onclick) |
|
78 | 78 | end |
|
79 | 79 | |
|
80 | 80 | def image_to_function(name, function, html_options = {}) |
|
81 | 81 | html_options.symbolize_keys! |
|
82 | 82 | tag(:input, html_options.merge({ |
|
83 | 83 | :type => "image", :src => image_path(name), |
|
84 | 84 | :onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function};" |
|
85 | 85 | })) |
|
86 | 86 | end |
|
87 | 87 | |
|
88 | 88 | def prompt_to_remote(name, text, param, url, html_options = {}) |
|
89 | 89 | html_options[:onclick] = "promptToRemote('#{text}', '#{param}', '#{url_for(url)}'); return false;" |
|
90 | 90 | link_to name, {}, html_options |
|
91 | 91 | end |
|
92 | 92 | |
|
93 | 93 | def format_date(date) |
|
94 | 94 | return nil unless date |
|
95 | 95 | # "Setting.date_format.size < 2" is a temporary fix (content of date_format setting changed) |
|
96 | 96 | @date_format ||= (Setting.date_format.blank? || Setting.date_format.size < 2 ? l(:general_fmt_date) : Setting.date_format) |
|
97 | 97 | date.strftime(@date_format) |
|
98 | 98 | end |
|
99 | 99 | |
|
100 | 100 | def format_time(time, include_date = true) |
|
101 | 101 | return nil unless time |
|
102 | 102 | time = time.to_time if time.is_a?(String) |
|
103 | 103 | zone = User.current.time_zone |
|
104 | 104 | local = zone ? time.in_time_zone(zone) : (time.utc? ? time.localtime : time) |
|
105 | 105 | @date_format ||= (Setting.date_format.blank? || Setting.date_format.size < 2 ? l(:general_fmt_date) : Setting.date_format) |
|
106 | 106 | @time_format ||= (Setting.time_format.blank? ? l(:general_fmt_time) : Setting.time_format) |
|
107 | 107 | include_date ? local.strftime("#{@date_format} #{@time_format}") : local.strftime(@time_format) |
|
108 | 108 | end |
|
109 | 109 | |
|
110 | 110 | def format_activity_title(text) |
|
111 | 111 | h(truncate_single_line(text, 100)) |
|
112 | 112 | end |
|
113 | 113 | |
|
114 | 114 | def format_activity_day(date) |
|
115 | 115 | date == Date.today ? l(:label_today).titleize : format_date(date) |
|
116 | 116 | end |
|
117 | 117 | |
|
118 | 118 | def format_activity_description(text) |
|
119 | 119 | h(truncate(text.to_s, 250).gsub(%r{<(pre|code)>.*$}m, '...')) |
|
120 | 120 | end |
|
121 | 121 | |
|
122 | 122 | def distance_of_date_in_words(from_date, to_date = 0) |
|
123 | 123 | from_date = from_date.to_date if from_date.respond_to?(:to_date) |
|
124 | 124 | to_date = to_date.to_date if to_date.respond_to?(:to_date) |
|
125 | 125 | distance_in_days = (to_date - from_date).abs |
|
126 | 126 | lwr(:actionview_datehelper_time_in_words_day, distance_in_days) |
|
127 | 127 | end |
|
128 | 128 | |
|
129 | 129 | def due_date_distance_in_words(date) |
|
130 | 130 | if date |
|
131 | 131 | l((date < Date.today ? :label_roadmap_overdue : :label_roadmap_due_in), distance_of_date_in_words(Date.today, date)) |
|
132 | 132 | end |
|
133 | 133 | end |
|
134 | 134 | |
|
135 | 135 | def render_page_hierarchy(pages, node=nil) |
|
136 | 136 | content = '' |
|
137 | 137 | if pages[node] |
|
138 | 138 | content << "<ul class=\"pages-hierarchy\">\n" |
|
139 | 139 | pages[node].each do |page| |
|
140 | 140 | content << "<li>" |
|
141 | 141 | content << link_to(h(page.pretty_title), {:controller => 'wiki', :action => 'index', :id => page.project, :page => page.title}, |
|
142 | 142 | :title => (page.respond_to?(:updated_on) ? l(:label_updated_time, distance_of_time_in_words(Time.now, page.updated_on)) : nil)) |
|
143 | 143 | content << "\n" + render_page_hierarchy(pages, page.id) if pages[page.id] |
|
144 | 144 | content << "</li>\n" |
|
145 | 145 | end |
|
146 | 146 | content << "</ul>\n" |
|
147 | 147 | end |
|
148 | 148 | content |
|
149 | 149 | end |
|
150 | 150 | |
|
151 | 151 | # Renders flash messages |
|
152 | 152 | def render_flash_messages |
|
153 | 153 | s = '' |
|
154 | 154 | flash.each do |k,v| |
|
155 | 155 | s << content_tag('div', v, :class => "flash #{k}") |
|
156 | 156 | end |
|
157 | 157 | s |
|
158 | 158 | end |
|
159 | 159 | |
|
160 | 160 | # Renders the project quick-jump box |
|
161 | 161 | def render_project_jump_box |
|
162 | 162 | # Retrieve them now to avoid a COUNT query |
|
163 | 163 | projects = User.current.projects.all |
|
164 | 164 | if projects.any? |
|
165 | 165 | s = '<select onchange="if (this.value != \'\') { window.location = this.value; }">' + |
|
166 | 166 | "<option selected='selected'>#{ l(:label_jump_to_a_project) }</option>" + |
|
167 | 167 | '<option disabled="disabled">---</option>' |
|
168 | 168 | s << project_tree_options_for_select(projects) do |p| |
|
169 | 169 | { :value => url_for(:controller => 'projects', :action => 'show', :id => p, :jump => current_menu_item) } |
|
170 | 170 | end |
|
171 | 171 | s << '</select>' |
|
172 | 172 | s |
|
173 | 173 | end |
|
174 | 174 | end |
|
175 | 175 | |
|
176 | 176 | def project_tree_options_for_select(projects, options = {}) |
|
177 | 177 | s = '' |
|
178 | 178 | project_tree(projects) do |project, level| |
|
179 | 179 | name_prefix = (level > 0 ? (' ' * 2 * level + '» ') : '') |
|
180 | 180 | tag_options = {:value => project.id, :selected => ((project == options[:selected]) ? 'selected' : nil)} |
|
181 | 181 | tag_options.merge!(yield(project)) if block_given? |
|
182 | 182 | s << content_tag('option', name_prefix + h(project), tag_options) |
|
183 | 183 | end |
|
184 | 184 | s |
|
185 | 185 | end |
|
186 | 186 | |
|
187 | 187 | # Yields the given block for each project with its level in the tree |
|
188 | 188 | def project_tree(projects, &block) |
|
189 | 189 | ancestors = [] |
|
190 | 190 | projects.sort_by(&:lft).each do |project| |
|
191 | 191 | while (ancestors.any? && !project.is_descendant_of?(ancestors.last)) |
|
192 | 192 | ancestors.pop |
|
193 | 193 | end |
|
194 | 194 | yield project, ancestors.size |
|
195 | 195 | ancestors << project |
|
196 | 196 | end |
|
197 | 197 | end |
|
198 | 198 | |
|
199 | 199 | # Truncates and returns the string as a single line |
|
200 | 200 | def truncate_single_line(string, *args) |
|
201 | 201 | truncate(string, *args).gsub(%r{[\r\n]+}m, ' ') |
|
202 | 202 | end |
|
203 | 203 | |
|
204 | 204 | def html_hours(text) |
|
205 | 205 | text.gsub(%r{(\d+)\.(\d+)}, '<span class="hours hours-int">\1</span><span class="hours hours-dec">.\2</span>') |
|
206 | 206 | end |
|
207 | 207 | |
|
208 | 208 | def authoring(created, author, options={}) |
|
209 | 209 | time_tag = @project.nil? ? content_tag('acronym', distance_of_time_in_words(Time.now, created), :title => format_time(created)) : |
|
210 | 210 | link_to(distance_of_time_in_words(Time.now, created), |
|
211 | 211 | {:controller => 'projects', :action => 'activity', :id => @project, :from => created.to_date}, |
|
212 | 212 | :title => format_time(created)) |
|
213 | 213 | author_tag = (author.is_a?(User) && !author.anonymous?) ? link_to(h(author), :controller => 'account', :action => 'show', :id => author) : h(author || 'Anonymous') |
|
214 | 214 | l(options[:label] || :label_added_time_by, author_tag, time_tag) |
|
215 | 215 | end |
|
216 | 216 | |
|
217 | 217 | def l_or_humanize(s, options={}) |
|
218 | 218 | k = "#{options[:prefix]}#{s}".to_sym |
|
219 | 219 | l_has_string?(k) ? l(k) : s.to_s.humanize |
|
220 | 220 | end |
|
221 | 221 | |
|
222 | 222 | def day_name(day) |
|
223 | 223 | l(:general_day_names).split(',')[day-1] |
|
224 | 224 | end |
|
225 | 225 | |
|
226 | 226 | def month_name(month) |
|
227 | 227 | l(:actionview_datehelper_select_month_names).split(',')[month-1] |
|
228 | 228 | end |
|
229 | 229 | |
|
230 | 230 | def syntax_highlight(name, content) |
|
231 | 231 | type = CodeRay::FileType[name] |
|
232 | 232 | type ? CodeRay.scan(content, type).html : h(content) |
|
233 | 233 | end |
|
234 | 234 | |
|
235 | 235 | def to_path_param(path) |
|
236 | 236 | path.to_s.split(%r{[/\\]}).select {|p| !p.blank?} |
|
237 | 237 | end |
|
238 | 238 | |
|
239 | 239 | def pagination_links_full(paginator, count=nil, options={}) |
|
240 | 240 | page_param = options.delete(:page_param) || :page |
|
241 | 241 | url_param = params.dup |
|
242 | 242 | # don't reuse params if filters are present |
|
243 | 243 | url_param.clear if url_param.has_key?(:set_filter) |
|
244 | 244 | |
|
245 | 245 | html = '' |
|
246 | html << link_to_remote(('« ' + l(:label_previous)), | |
|
247 | {:update => 'content', | |
|
248 | :url => url_param.merge(page_param => paginator.current.previous), | |
|
249 | :complete => 'window.scrollTo(0,0)'}, | |
|
250 | {:href => url_for(:params => url_param.merge(page_param => paginator.current.previous))}) + ' ' if paginator.current.previous | |
|
246 | if paginator.current.previous | |
|
247 | html << link_to_remote_content_update('« ' + l(:label_previous), url_param.merge(page_param => paginator.current.previous)) + ' ' | |
|
248 | end | |
|
251 | 249 | |
|
252 | 250 | html << (pagination_links_each(paginator, options) do |n| |
|
253 | link_to_remote(n.to_s, | |
|
254 | {:url => {:params => url_param.merge(page_param => n)}, | |
|
255 | :update => 'content', | |
|
256 | :complete => 'window.scrollTo(0,0)'}, | |
|
257 | {:href => url_for(:params => url_param.merge(page_param => n))}) | |
|
251 | link_to_remote_content_update(n.to_s, url_param.merge(page_param => n)) | |
|
258 | 252 | end || '') |
|
259 | 253 | |
|
260 | html << ' ' + link_to_remote((l(:label_next) + ' »'), | |
|
261 | {:update => 'content', | |
|
262 | :url => url_param.merge(page_param => paginator.current.next), | |
|
263 | :complete => 'window.scrollTo(0,0)'}, | |
|
264 | {:href => url_for(:params => url_param.merge(page_param => paginator.current.next))}) if paginator.current.next | |
|
254 | if paginator.current.next | |
|
255 | html << ' ' + link_to_remote_content_update((l(:label_next) + ' »'), url_param.merge(page_param => paginator.current.next)) | |
|
256 | end | |
|
265 | 257 | |
|
266 | 258 | unless count.nil? |
|
267 | html << [" (#{paginator.current.first_item}-#{paginator.current.last_item}/#{count})", per_page_links(paginator.items_per_page)].compact.join(' | ') | |
|
259 | html << [ | |
|
260 | " (#{paginator.current.first_item}-#{paginator.current.last_item}/#{count})", | |
|
261 | per_page_links(paginator.items_per_page) | |
|
262 | ].compact.join(' | ') | |
|
268 | 263 | end |
|
269 | 264 | |
|
270 | 265 | html |
|
271 | 266 | end |
|
272 | 267 | |
|
273 | 268 | def per_page_links(selected=nil) |
|
274 | 269 | url_param = params.dup |
|
275 | 270 | url_param.clear if url_param.has_key?(:set_filter) |
|
276 | 271 | |
|
277 | 272 | links = Setting.per_page_options_array.collect do |n| |
|
278 |
n == selected ? n : link_to_remote(n, {:update => "content", |
|
|
273 | n == selected ? n : link_to_remote(n, {:update => "content", | |
|
274 | :url => params.dup.merge(:per_page => n), | |
|
275 | :method => :get}, | |
|
279 | 276 | {:href => url_for(url_param.merge(:per_page => n))}) |
|
280 | 277 | end |
|
281 | 278 | links.size > 1 ? l(:label_display_per_page, links.join(', ')) : nil |
|
282 | 279 | end |
|
283 | 280 | |
|
284 | 281 | def breadcrumb(*args) |
|
285 | 282 | elements = args.flatten |
|
286 | 283 | elements.any? ? content_tag('p', args.join(' » ') + ' » ', :class => 'breadcrumb') : nil |
|
287 | 284 | end |
|
288 | 285 | |
|
289 | 286 | def html_title(*args) |
|
290 | 287 | if args.empty? |
|
291 | 288 | title = [] |
|
292 | 289 | title << @project.name if @project |
|
293 | 290 | title += @html_title if @html_title |
|
294 | 291 | title << Setting.app_title |
|
295 | 292 | title.compact.join(' - ') |
|
296 | 293 | else |
|
297 | 294 | @html_title ||= [] |
|
298 | 295 | @html_title += args |
|
299 | 296 | end |
|
300 | 297 | end |
|
301 | 298 | |
|
302 | 299 | def accesskey(s) |
|
303 | 300 | Redmine::AccessKeys.key_for s |
|
304 | 301 | end |
|
305 | 302 | |
|
306 | 303 | # Formats text according to system settings. |
|
307 | 304 | # 2 ways to call this method: |
|
308 | 305 | # * with a String: textilizable(text, options) |
|
309 | 306 | # * with an object and one of its attribute: textilizable(issue, :description, options) |
|
310 | 307 | def textilizable(*args) |
|
311 | 308 | options = args.last.is_a?(Hash) ? args.pop : {} |
|
312 | 309 | case args.size |
|
313 | 310 | when 1 |
|
314 | 311 | obj = options[:object] |
|
315 | 312 | text = args.shift |
|
316 | 313 | when 2 |
|
317 | 314 | obj = args.shift |
|
318 | 315 | text = obj.send(args.shift).to_s |
|
319 | 316 | else |
|
320 | 317 | raise ArgumentError, 'invalid arguments to textilizable' |
|
321 | 318 | end |
|
322 | 319 | return '' if text.blank? |
|
323 | 320 | |
|
324 | 321 | only_path = options.delete(:only_path) == false ? false : true |
|
325 | 322 | |
|
326 | 323 | # when using an image link, try to use an attachment, if possible |
|
327 | 324 | attachments = options[:attachments] || (obj && obj.respond_to?(:attachments) ? obj.attachments : nil) |
|
328 | 325 | |
|
329 | 326 | if attachments |
|
330 | 327 | attachments = attachments.sort_by(&:created_on).reverse |
|
331 | 328 | text = text.gsub(/!((\<|\=|\>)?(\([^\)]+\))?(\[[^\]]+\])?(\{[^\}]+\})?)(\S+\.(bmp|gif|jpg|jpeg|png))!/i) do |m| |
|
332 | 329 | style = $1 |
|
333 | 330 | filename = $6 |
|
334 | 331 | rf = Regexp.new(Regexp.escape(filename), Regexp::IGNORECASE) |
|
335 | 332 | # search for the picture in attachments |
|
336 | 333 | if found = attachments.detect { |att| att.filename =~ rf } |
|
337 | 334 | image_url = url_for :only_path => only_path, :controller => 'attachments', :action => 'download', :id => found |
|
338 | 335 | desc = found.description.to_s.gsub(/^([^\(\)]*).*$/, "\\1") |
|
339 | 336 | alt = desc.blank? ? nil : "(#{desc})" |
|
340 | 337 | "!#{style}#{image_url}#{alt}!" |
|
341 | 338 | else |
|
342 | 339 | "!#{style}#{filename}!" |
|
343 | 340 | end |
|
344 | 341 | end |
|
345 | 342 | end |
|
346 | 343 | |
|
347 | 344 | text = Redmine::WikiFormatting.to_html(Setting.text_formatting, text) { |macro, args| exec_macro(macro, obj, args) } |
|
348 | 345 | |
|
349 | 346 | # different methods for formatting wiki links |
|
350 | 347 | case options[:wiki_links] |
|
351 | 348 | when :local |
|
352 | 349 | # used for local links to html files |
|
353 | 350 | format_wiki_link = Proc.new {|project, title, anchor| "#{title}.html" } |
|
354 | 351 | when :anchor |
|
355 | 352 | # used for single-file wiki export |
|
356 | 353 | format_wiki_link = Proc.new {|project, title, anchor| "##{title}" } |
|
357 | 354 | else |
|
358 | 355 | format_wiki_link = Proc.new {|project, title, anchor| url_for(:only_path => only_path, :controller => 'wiki', :action => 'index', :id => project, :page => title, :anchor => anchor) } |
|
359 | 356 | end |
|
360 | 357 | |
|
361 | 358 | project = options[:project] || @project || (obj && obj.respond_to?(:project) ? obj.project : nil) |
|
362 | 359 | |
|
363 | 360 | # Wiki links |
|
364 | 361 | # |
|
365 | 362 | # Examples: |
|
366 | 363 | # [[mypage]] |
|
367 | 364 | # [[mypage|mytext]] |
|
368 | 365 | # wiki links can refer other project wikis, using project name or identifier: |
|
369 | 366 | # [[project:]] -> wiki starting page |
|
370 | 367 | # [[project:|mytext]] |
|
371 | 368 | # [[project:mypage]] |
|
372 | 369 | # [[project:mypage|mytext]] |
|
373 | 370 | text = text.gsub(/(!)?(\[\[([^\]\n\|]+)(\|([^\]\n\|]+))?\]\])/) do |m| |
|
374 | 371 | link_project = project |
|
375 | 372 | esc, all, page, title = $1, $2, $3, $5 |
|
376 | 373 | if esc.nil? |
|
377 | 374 | if page =~ /^([^\:]+)\:(.*)$/ |
|
378 | 375 | link_project = Project.find_by_name($1) || Project.find_by_identifier($1) |
|
379 | 376 | page = $2 |
|
380 | 377 | title ||= $1 if page.blank? |
|
381 | 378 | end |
|
382 | 379 | |
|
383 | 380 | if link_project && link_project.wiki |
|
384 | 381 | # extract anchor |
|
385 | 382 | anchor = nil |
|
386 | 383 | if page =~ /^(.+?)\#(.+)$/ |
|
387 | 384 | page, anchor = $1, $2 |
|
388 | 385 | end |
|
389 | 386 | # check if page exists |
|
390 | 387 | wiki_page = link_project.wiki.find_page(page) |
|
391 | 388 | link_to((title || page), format_wiki_link.call(link_project, Wiki.titleize(page), anchor), |
|
392 | 389 | :class => ('wiki-page' + (wiki_page ? '' : ' new'))) |
|
393 | 390 | else |
|
394 | 391 | # project or wiki doesn't exist |
|
395 | 392 | title || page |
|
396 | 393 | end |
|
397 | 394 | else |
|
398 | 395 | all |
|
399 | 396 | end |
|
400 | 397 | end |
|
401 | 398 | |
|
402 | 399 | # Redmine links |
|
403 | 400 | # |
|
404 | 401 | # Examples: |
|
405 | 402 | # Issues: |
|
406 | 403 | # #52 -> Link to issue #52 |
|
407 | 404 | # Changesets: |
|
408 | 405 | # r52 -> Link to revision 52 |
|
409 | 406 | # commit:a85130f -> Link to scmid starting with a85130f |
|
410 | 407 | # Documents: |
|
411 | 408 | # document#17 -> Link to document with id 17 |
|
412 | 409 | # document:Greetings -> Link to the document with title "Greetings" |
|
413 | 410 | # document:"Some document" -> Link to the document with title "Some document" |
|
414 | 411 | # Versions: |
|
415 | 412 | # version#3 -> Link to version with id 3 |
|
416 | 413 | # version:1.0.0 -> Link to version named "1.0.0" |
|
417 | 414 | # version:"1.0 beta 2" -> Link to version named "1.0 beta 2" |
|
418 | 415 | # Attachments: |
|
419 | 416 | # attachment:file.zip -> Link to the attachment of the current object named file.zip |
|
420 | 417 | # Source files: |
|
421 | 418 | # source:some/file -> Link to the file located at /some/file in the project's repository |
|
422 | 419 | # source:some/file@52 -> Link to the file's revision 52 |
|
423 | 420 | # source:some/file#L120 -> Link to line 120 of the file |
|
424 | 421 | # source:some/file@52#L120 -> Link to line 120 of the file's revision 52 |
|
425 | 422 | # export:some/file -> Force the download of the file |
|
426 | 423 | # Forum messages: |
|
427 | 424 | # message#1218 -> Link to message with id 1218 |
|
428 | 425 | text = text.gsub(%r{([\s\(,\-\>]|^)(!)?(attachment|document|version|commit|source|export|message)?((#|r)(\d+)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]]\W)|\s|<|$)}) do |m| |
|
429 | 426 | leading, esc, prefix, sep, oid = $1, $2, $3, $5 || $7, $6 || $8 |
|
430 | 427 | link = nil |
|
431 | 428 | if esc.nil? |
|
432 | 429 | if prefix.nil? && sep == 'r' |
|
433 | 430 | if project && (changeset = project.changesets.find_by_revision(oid)) |
|
434 | 431 | link = link_to("r#{oid}", {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => oid}, |
|
435 | 432 | :class => 'changeset', |
|
436 | 433 | :title => truncate_single_line(changeset.comments, 100)) |
|
437 | 434 | end |
|
438 | 435 | elsif sep == '#' |
|
439 | 436 | oid = oid.to_i |
|
440 | 437 | case prefix |
|
441 | 438 | when nil |
|
442 | 439 | if issue = Issue.find_by_id(oid, :include => [:project, :status], :conditions => Project.visible_by(User.current)) |
|
443 | 440 | link = link_to("##{oid}", {:only_path => only_path, :controller => 'issues', :action => 'show', :id => oid}, |
|
444 | 441 | :class => (issue.closed? ? 'issue closed' : 'issue'), |
|
445 | 442 | :title => "#{truncate(issue.subject, 100)} (#{issue.status.name})") |
|
446 | 443 | link = content_tag('del', link) if issue.closed? |
|
447 | 444 | end |
|
448 | 445 | when 'document' |
|
449 | 446 | if document = Document.find_by_id(oid, :include => [:project], :conditions => Project.visible_by(User.current)) |
|
450 | 447 | link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document}, |
|
451 | 448 | :class => 'document' |
|
452 | 449 | end |
|
453 | 450 | when 'version' |
|
454 | 451 | if version = Version.find_by_id(oid, :include => [:project], :conditions => Project.visible_by(User.current)) |
|
455 | 452 | link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version}, |
|
456 | 453 | :class => 'version' |
|
457 | 454 | end |
|
458 | 455 | when 'message' |
|
459 | 456 | if message = Message.find_by_id(oid, :include => [:parent, {:board => :project}], :conditions => Project.visible_by(User.current)) |
|
460 | 457 | link = link_to h(truncate(message.subject, 60)), {:only_path => only_path, |
|
461 | 458 | :controller => 'messages', |
|
462 | 459 | :action => 'show', |
|
463 | 460 | :board_id => message.board, |
|
464 | 461 | :id => message.root, |
|
465 | 462 | :anchor => (message.parent ? "message-#{message.id}" : nil)}, |
|
466 | 463 | :class => 'message' |
|
467 | 464 | end |
|
468 | 465 | end |
|
469 | 466 | elsif sep == ':' |
|
470 | 467 | # removes the double quotes if any |
|
471 | 468 | name = oid.gsub(%r{^"(.*)"$}, "\\1") |
|
472 | 469 | case prefix |
|
473 | 470 | when 'document' |
|
474 | 471 | if project && document = project.documents.find_by_title(name) |
|
475 | 472 | link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document}, |
|
476 | 473 | :class => 'document' |
|
477 | 474 | end |
|
478 | 475 | when 'version' |
|
479 | 476 | if project && version = project.versions.find_by_name(name) |
|
480 | 477 | link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version}, |
|
481 | 478 | :class => 'version' |
|
482 | 479 | end |
|
483 | 480 | when 'commit' |
|
484 | 481 | if project && (changeset = project.changesets.find(:first, :conditions => ["scmid LIKE ?", "#{name}%"])) |
|
485 | 482 | link = link_to h("#{name}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.revision}, |
|
486 | 483 | :class => 'changeset', |
|
487 | 484 | :title => truncate_single_line(changeset.comments, 100) |
|
488 | 485 | end |
|
489 | 486 | when 'source', 'export' |
|
490 | 487 | if project && project.repository |
|
491 | 488 | name =~ %r{^[/\\]*(.*?)(@([0-9a-f]+))?(#(L\d+))?$} |
|
492 | 489 | path, rev, anchor = $1, $3, $5 |
|
493 | 490 | link = link_to h("#{prefix}:#{name}"), {:controller => 'repositories', :action => 'entry', :id => project, |
|
494 | 491 | :path => to_path_param(path), |
|
495 | 492 | :rev => rev, |
|
496 | 493 | :anchor => anchor, |
|
497 | 494 | :format => (prefix == 'export' ? 'raw' : nil)}, |
|
498 | 495 | :class => (prefix == 'export' ? 'source download' : 'source') |
|
499 | 496 | end |
|
500 | 497 | when 'attachment' |
|
501 | 498 | if attachments && attachment = attachments.detect {|a| a.filename == name } |
|
502 | 499 | link = link_to h(attachment.filename), {:only_path => only_path, :controller => 'attachments', :action => 'download', :id => attachment}, |
|
503 | 500 | :class => 'attachment' |
|
504 | 501 | end |
|
505 | 502 | end |
|
506 | 503 | end |
|
507 | 504 | end |
|
508 | 505 | leading + (link || "#{prefix}#{sep}#{oid}") |
|
509 | 506 | end |
|
510 | 507 | |
|
511 | 508 | text |
|
512 | 509 | end |
|
513 | 510 | |
|
514 | 511 | # Same as Rails' simple_format helper without using paragraphs |
|
515 | 512 | def simple_format_without_paragraph(text) |
|
516 | 513 | text.to_s. |
|
517 | 514 | gsub(/\r\n?/, "\n"). # \r\n and \r -> \n |
|
518 | 515 | gsub(/\n\n+/, "<br /><br />"). # 2+ newline -> 2 br |
|
519 | 516 | gsub(/([^\n]\n)(?=[^\n])/, '\1<br />') # 1 newline -> br |
|
520 | 517 | end |
|
521 | 518 | |
|
522 | 519 | def error_messages_for(object_name, options = {}) |
|
523 | 520 | options = options.symbolize_keys |
|
524 | 521 | object = instance_variable_get("@#{object_name}") |
|
525 | 522 | if object && !object.errors.empty? |
|
526 | 523 | # build full_messages here with controller current language |
|
527 | 524 | full_messages = [] |
|
528 | 525 | object.errors.each do |attr, msg| |
|
529 | 526 | next if msg.nil? |
|
530 | 527 | msg = msg.first if msg.is_a? Array |
|
531 | 528 | if attr == "base" |
|
532 | 529 | full_messages << l(msg) |
|
533 | 530 | else |
|
534 | 531 | full_messages << "« " + (l_has_string?("field_" + attr) ? l("field_" + attr) : object.class.human_attribute_name(attr)) + " » " + l(msg) unless attr == "custom_values" |
|
535 | 532 | end |
|
536 | 533 | end |
|
537 | 534 | # retrieve custom values error messages |
|
538 | 535 | if object.errors[:custom_values] |
|
539 | 536 | object.custom_values.each do |v| |
|
540 | 537 | v.errors.each do |attr, msg| |
|
541 | 538 | next if msg.nil? |
|
542 | 539 | msg = msg.first if msg.is_a? Array |
|
543 | 540 | full_messages << "« " + v.custom_field.name + " » " + l(msg) |
|
544 | 541 | end |
|
545 | 542 | end |
|
546 | 543 | end |
|
547 | 544 | content_tag("div", |
|
548 | 545 | content_tag( |
|
549 | 546 | options[:header_tag] || "span", lwr(:gui_validation_error, full_messages.length) + ":" |
|
550 | 547 | ) + |
|
551 | 548 | content_tag("ul", full_messages.collect { |msg| content_tag("li", msg) }), |
|
552 | 549 | "id" => options[:id] || "errorExplanation", "class" => options[:class] || "errorExplanation" |
|
553 | 550 | ) |
|
554 | 551 | else |
|
555 | 552 | "" |
|
556 | 553 | end |
|
557 | 554 | end |
|
558 | 555 | |
|
559 | 556 | def lang_options_for_select(blank=true) |
|
560 | 557 | (blank ? [["(auto)", ""]] : []) + |
|
561 | 558 | GLoc.valid_languages.collect{|lang| [ ll(lang.to_s, :general_lang_name), lang.to_s]}.sort{|x,y| x.last <=> y.last } |
|
562 | 559 | end |
|
563 | 560 | |
|
564 | 561 | def label_tag_for(name, option_tags = nil, options = {}) |
|
565 | 562 | label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "") |
|
566 | 563 | content_tag("label", label_text) |
|
567 | 564 | end |
|
568 | 565 | |
|
569 | 566 | def labelled_tabular_form_for(name, object, options, &proc) |
|
570 | 567 | options[:html] ||= {} |
|
571 | 568 | options[:html][:class] = 'tabular' unless options[:html].has_key?(:class) |
|
572 | 569 | form_for(name, object, options.merge({ :builder => TabularFormBuilder, :lang => current_language}), &proc) |
|
573 | 570 | end |
|
574 | 571 | |
|
575 | 572 | def back_url_hidden_field_tag |
|
576 | 573 | back_url = params[:back_url] || request.env['HTTP_REFERER'] |
|
577 | 574 | back_url = CGI.unescape(back_url.to_s) |
|
578 | 575 | hidden_field_tag('back_url', CGI.escape(back_url)) unless back_url.blank? |
|
579 | 576 | end |
|
580 | 577 | |
|
581 | 578 | def check_all_links(form_name) |
|
582 | 579 | link_to_function(l(:button_check_all), "checkAll('#{form_name}', true)") + |
|
583 | 580 | " | " + |
|
584 | 581 | link_to_function(l(:button_uncheck_all), "checkAll('#{form_name}', false)") |
|
585 | 582 | end |
|
586 | 583 | |
|
587 | 584 | def progress_bar(pcts, options={}) |
|
588 | 585 | pcts = [pcts, pcts] unless pcts.is_a?(Array) |
|
589 | 586 | pcts[1] = pcts[1] - pcts[0] |
|
590 | 587 | pcts << (100 - pcts[1] - pcts[0]) |
|
591 | 588 | width = options[:width] || '100px;' |
|
592 | 589 | legend = options[:legend] || '' |
|
593 | 590 | content_tag('table', |
|
594 | 591 | content_tag('tr', |
|
595 | 592 | (pcts[0] > 0 ? content_tag('td', '', :style => "width: #{pcts[0].floor}%;", :class => 'closed') : '') + |
|
596 | 593 | (pcts[1] > 0 ? content_tag('td', '', :style => "width: #{pcts[1].floor}%;", :class => 'done') : '') + |
|
597 | 594 | (pcts[2] > 0 ? content_tag('td', '', :style => "width: #{pcts[2].floor}%;", :class => 'todo') : '') |
|
598 | 595 | ), :class => 'progress', :style => "width: #{width};") + |
|
599 | 596 | content_tag('p', legend, :class => 'pourcent') |
|
600 | 597 | end |
|
601 | 598 | |
|
602 | 599 | def context_menu_link(name, url, options={}) |
|
603 | 600 | options[:class] ||= '' |
|
604 | 601 | if options.delete(:selected) |
|
605 | 602 | options[:class] << ' icon-checked disabled' |
|
606 | 603 | options[:disabled] = true |
|
607 | 604 | end |
|
608 | 605 | if options.delete(:disabled) |
|
609 | 606 | options.delete(:method) |
|
610 | 607 | options.delete(:confirm) |
|
611 | 608 | options.delete(:onclick) |
|
612 | 609 | options[:class] << ' disabled' |
|
613 | 610 | url = '#' |
|
614 | 611 | end |
|
615 | 612 | link_to name, url, options |
|
616 | 613 | end |
|
617 | 614 | |
|
618 | 615 | def calendar_for(field_id) |
|
619 | 616 | include_calendar_headers_tags |
|
620 | 617 | image_tag("calendar.png", {:id => "#{field_id}_trigger",:class => "calendar-trigger"}) + |
|
621 | 618 | javascript_tag("Calendar.setup({inputField : '#{field_id}', ifFormat : '%Y-%m-%d', button : '#{field_id}_trigger' });") |
|
622 | 619 | end |
|
623 | 620 | |
|
624 | 621 | def include_calendar_headers_tags |
|
625 | 622 | unless @calendar_headers_tags_included |
|
626 | 623 | @calendar_headers_tags_included = true |
|
627 | 624 | content_for :header_tags do |
|
628 | 625 | javascript_include_tag('calendar/calendar') + |
|
629 | 626 | javascript_include_tag("calendar/lang/calendar-#{current_language}.js") + |
|
630 | 627 | javascript_include_tag('calendar/calendar-setup') + |
|
631 | 628 | stylesheet_link_tag('calendar') |
|
632 | 629 | end |
|
633 | 630 | end |
|
634 | 631 | end |
|
635 | 632 | |
|
636 | 633 | def content_for(name, content = nil, &block) |
|
637 | 634 | @has_content ||= {} |
|
638 | 635 | @has_content[name] = true |
|
639 | 636 | super(name, content, &block) |
|
640 | 637 | end |
|
641 | 638 | |
|
642 | 639 | def has_content?(name) |
|
643 | 640 | (@has_content && @has_content[name]) || false |
|
644 | 641 | end |
|
645 | 642 | |
|
646 | 643 | # Returns the avatar image tag for the given +user+ if avatars are enabled |
|
647 | 644 | # +user+ can be a User or a string that will be scanned for an email address (eg. 'joe <joe@foo.bar>') |
|
648 | 645 | def avatar(user, options = { }) |
|
649 | 646 | if Setting.gravatar_enabled? |
|
650 | 647 | email = nil |
|
651 | 648 | if user.respond_to?(:mail) |
|
652 | 649 | email = user.mail |
|
653 | 650 | elsif user.to_s =~ %r{<(.+?)>} |
|
654 | 651 | email = $1 |
|
655 | 652 | end |
|
656 | 653 | return gravatar(email.to_s.downcase, options) unless email.blank? rescue nil |
|
657 | 654 | end |
|
658 | 655 | end |
|
659 | 656 | |
|
660 | 657 | private |
|
661 | 658 | |
|
662 | 659 | def wiki_helper |
|
663 | 660 | helper = Redmine::WikiFormatting.helper_for(Setting.text_formatting) |
|
664 | 661 | extend helper |
|
665 | 662 | return self |
|
666 | 663 | end |
|
664 | ||
|
665 | def link_to_remote_content_update(text, url_params) | |
|
666 | link_to_remote(text, | |
|
667 | {:url => url_params, :method => :get, :update => 'content', :complete => 'window.scrollTo(0,0)'}, | |
|
668 | {:href => url_for(:params => url_params)} | |
|
669 | ) | |
|
670 | end | |
|
671 | ||
|
667 | 672 | end |
@@ -1,168 +1,168 | |||
|
1 | 1 | # Helpers to sort tables using clickable column headers. |
|
2 | 2 | # |
|
3 | 3 | # Author: Stuart Rackham <srackham@methods.co.nz>, March 2005. |
|
4 | 4 | # License: This source code is released under the MIT license. |
|
5 | 5 | # |
|
6 | 6 | # - Consecutive clicks toggle the column's sort order. |
|
7 | 7 | # - Sort state is maintained by a session hash entry. |
|
8 | 8 | # - Icon image identifies sort column and state. |
|
9 | 9 | # - Typically used in conjunction with the Pagination module. |
|
10 | 10 | # |
|
11 | 11 | # Example code snippets: |
|
12 | 12 | # |
|
13 | 13 | # Controller: |
|
14 | 14 | # |
|
15 | 15 | # helper :sort |
|
16 | 16 | # include SortHelper |
|
17 | 17 | # |
|
18 | 18 | # def list |
|
19 | 19 | # sort_init 'last_name' |
|
20 | 20 | # sort_update |
|
21 | 21 | # @items = Contact.find_all nil, sort_clause |
|
22 | 22 | # end |
|
23 | 23 | # |
|
24 | 24 | # Controller (using Pagination module): |
|
25 | 25 | # |
|
26 | 26 | # helper :sort |
|
27 | 27 | # include SortHelper |
|
28 | 28 | # |
|
29 | 29 | # def list |
|
30 | 30 | # sort_init 'last_name' |
|
31 | 31 | # sort_update |
|
32 | 32 | # @contact_pages, @items = paginate :contacts, |
|
33 | 33 | # :order_by => sort_clause, |
|
34 | 34 | # :per_page => 10 |
|
35 | 35 | # end |
|
36 | 36 | # |
|
37 | 37 | # View (table header in list.rhtml): |
|
38 | 38 | # |
|
39 | 39 | # <thead> |
|
40 | 40 | # <tr> |
|
41 | 41 | # <%= sort_header_tag('id', :title => 'Sort by contact ID') %> |
|
42 | 42 | # <%= sort_header_tag('last_name', :caption => 'Name') %> |
|
43 | 43 | # <%= sort_header_tag('phone') %> |
|
44 | 44 | # <%= sort_header_tag('address', :width => 200) %> |
|
45 | 45 | # </tr> |
|
46 | 46 | # </thead> |
|
47 | 47 | # |
|
48 | 48 | # - The ascending and descending sort icon images are sort_asc.png and |
|
49 | 49 | # sort_desc.png and reside in the application's images directory. |
|
50 | 50 | # - Introduces instance variables: @sort_name, @sort_default. |
|
51 | 51 | # - Introduces params :sort_key and :sort_order. |
|
52 | 52 | # |
|
53 | 53 | module SortHelper |
|
54 | 54 | |
|
55 | 55 | # Initializes the default sort column (default_key) and sort order |
|
56 | 56 | # (default_order). |
|
57 | 57 | # |
|
58 | 58 | # - default_key is a column attribute name. |
|
59 | 59 | # - default_order is 'asc' or 'desc'. |
|
60 | 60 | # - name is the name of the session hash entry that stores the sort state, |
|
61 | 61 | # defaults to '<controller_name>_sort'. |
|
62 | 62 | # |
|
63 | 63 | def sort_init(default_key, default_order='asc', name=nil) |
|
64 | 64 | @sort_name = name || params[:controller] + params[:action] + '_sort' |
|
65 | 65 | @sort_default = {:key => default_key, :order => default_order} |
|
66 | 66 | end |
|
67 | 67 | |
|
68 | 68 | # Updates the sort state. Call this in the controller prior to calling |
|
69 | 69 | # sort_clause. |
|
70 | 70 | # sort_keys can be either an array or a hash of allowed keys |
|
71 | 71 | def sort_update(sort_keys) |
|
72 | 72 | sort_key = params[:sort_key] |
|
73 | 73 | sort_key = nil unless (sort_keys.is_a?(Array) ? sort_keys.include?(sort_key) : sort_keys[sort_key]) |
|
74 | 74 | |
|
75 | 75 | sort_order = (params[:sort_order] == 'desc' ? 'DESC' : 'ASC') |
|
76 | 76 | |
|
77 | 77 | if sort_key |
|
78 | 78 | sort = {:key => sort_key, :order => sort_order} |
|
79 | 79 | elsif session[@sort_name] |
|
80 | 80 | sort = session[@sort_name] # Previous sort. |
|
81 | 81 | else |
|
82 | 82 | sort = @sort_default |
|
83 | 83 | end |
|
84 | 84 | session[@sort_name] = sort |
|
85 | 85 | |
|
86 | 86 | sort_column = (sort_keys.is_a?(Hash) ? sort_keys[sort[:key]] : sort[:key]) |
|
87 | 87 | @sort_clause = (sort_column.blank? ? nil : "#{sort_column} #{sort[:order]}") |
|
88 | 88 | end |
|
89 | 89 | |
|
90 | 90 | # Returns an SQL sort clause corresponding to the current sort state. |
|
91 | 91 | # Use this to sort the controller's table items collection. |
|
92 | 92 | # |
|
93 | 93 | def sort_clause() |
|
94 | 94 | @sort_clause |
|
95 | 95 | end |
|
96 | 96 | |
|
97 | 97 | # Returns a link which sorts by the named column. |
|
98 | 98 | # |
|
99 | 99 | # - column is the name of an attribute in the sorted record collection. |
|
100 | 100 | # - The optional caption explicitly specifies the displayed link text. |
|
101 | 101 | # - A sort icon image is positioned to the right of the sort link. |
|
102 | 102 | # |
|
103 | 103 | def sort_link(column, caption, default_order) |
|
104 | 104 | key, order = session[@sort_name][:key], session[@sort_name][:order] |
|
105 | 105 | if key == column |
|
106 | 106 | if order.downcase == 'asc' |
|
107 | 107 | icon = 'sort_asc.png' |
|
108 | 108 | order = 'desc' |
|
109 | 109 | else |
|
110 | 110 | icon = 'sort_desc.png' |
|
111 | 111 | order = 'asc' |
|
112 | 112 | end |
|
113 | 113 | else |
|
114 | 114 | icon = nil |
|
115 | 115 | order = default_order |
|
116 | 116 | end |
|
117 | 117 | caption = titleize(Inflector::humanize(column)) unless caption |
|
118 | 118 | |
|
119 | 119 | sort_options = { :sort_key => column, :sort_order => order } |
|
120 | 120 | # don't reuse params if filters are present |
|
121 | 121 | url_options = params.has_key?(:set_filter) ? sort_options : params.merge(sort_options) |
|
122 | 122 | |
|
123 | 123 | link_to_remote(caption, |
|
124 | {:update => "content", :url => url_options}, | |
|
124 | {:update => "content", :url => url_options, :method => :get}, | |
|
125 | 125 | {:href => url_for(url_options)}) + |
|
126 | 126 | (icon ? nbsp(2) + image_tag(icon) : '') |
|
127 | 127 | end |
|
128 | 128 | |
|
129 | 129 | # Returns a table header <th> tag with a sort link for the named column |
|
130 | 130 | # attribute. |
|
131 | 131 | # |
|
132 | 132 | # Options: |
|
133 | 133 | # :caption The displayed link name (defaults to titleized column name). |
|
134 | 134 | # :title The tag's 'title' attribute (defaults to 'Sort by :caption'). |
|
135 | 135 | # |
|
136 | 136 | # Other options hash entries generate additional table header tag attributes. |
|
137 | 137 | # |
|
138 | 138 | # Example: |
|
139 | 139 | # |
|
140 | 140 | # <%= sort_header_tag('id', :title => 'Sort by contact ID', :width => 40) %> |
|
141 | 141 | # |
|
142 | 142 | # Renders: |
|
143 | 143 | # |
|
144 | 144 | # <th title="Sort by contact ID" width="40"> |
|
145 | 145 | # <a href="/contact/list?sort_order=desc&sort_key=id">Id</a> |
|
146 | 146 | # <img alt="Sort_asc" src="/images/sort_asc.png" /> |
|
147 | 147 | # </th> |
|
148 | 148 | # |
|
149 | 149 | def sort_header_tag(column, options = {}) |
|
150 | 150 | caption = options.delete(:caption) || titleize(Inflector::humanize(column)) |
|
151 | 151 | default_order = options.delete(:default_order) || 'asc' |
|
152 | 152 | options[:title]= l(:label_sort_by, "\"#{caption}\"") unless options[:title] |
|
153 | 153 | content_tag('th', sort_link(column, caption, default_order), options) |
|
154 | 154 | end |
|
155 | 155 | |
|
156 | 156 | private |
|
157 | 157 | |
|
158 | 158 | # Return n non-breaking spaces. |
|
159 | 159 | def nbsp(n) |
|
160 | 160 | ' ' * n |
|
161 | 161 | end |
|
162 | 162 | |
|
163 | 163 | # Return capitalized title. |
|
164 | 164 | def titleize(title) |
|
165 | 165 | title.split.map {|w| w.capitalize }.join(' ') |
|
166 | 166 | end |
|
167 | 167 | |
|
168 | 168 | end |
@@ -1,42 +1,42 | |||
|
1 | 1 | <h2><%=l(:label_change_log)%></h2> |
|
2 | 2 | |
|
3 | 3 | <% if @versions.empty? %> |
|
4 | 4 | <p class="nodata"><%= l(:label_no_data) %></p> |
|
5 | 5 | <% end %> |
|
6 | 6 | |
|
7 | 7 | <% @versions.each do |version| %> |
|
8 | 8 | <a name="<%= version.name %>"><h3 class="icon22 icon22-package"><%= version.name %></h3></a> |
|
9 | 9 | <% if version.effective_date %> |
|
10 | 10 | <p><%= format_date(version.effective_date) %></p> |
|
11 | 11 | <% end %> |
|
12 | 12 | <p><%=h version.description %></p> |
|
13 | 13 | <% issues = version.fixed_issues.find(:all, |
|
14 | 14 | :include => [:status, :tracker], |
|
15 | 15 | :conditions => ["#{IssueStatus.table_name}.is_closed=? AND #{Issue.table_name}.tracker_id in (#{@selected_tracker_ids.join(',')})", true], |
|
16 | 16 | :order => "#{Tracker.table_name}.position") unless @selected_tracker_ids.empty? |
|
17 | 17 | issues ||= [] |
|
18 | 18 | %> |
|
19 | 19 | <% if !issues.empty? %> |
|
20 | 20 | <ul> |
|
21 | 21 | <% issues.each do |issue| %> |
|
22 | 22 | <li><%= link_to_issue(issue) %>: <%=h issue.subject %></li> |
|
23 | 23 | <% end %> |
|
24 | 24 | </ul> |
|
25 | 25 | <% end %> |
|
26 | 26 | <% end %> |
|
27 | 27 | |
|
28 | 28 | <% content_for :sidebar do %> |
|
29 | <% form_tag do %> | |
|
29 | <% form_tag({},:method => :get) do %> | |
|
30 | 30 | <h3><%= l(:label_change_log) %></h3> |
|
31 | 31 | <% @trackers.each do |tracker| %> |
|
32 | 32 | <label><%= check_box_tag "tracker_ids[]", tracker.id, (@selected_tracker_ids.include? tracker.id.to_s) %> |
|
33 | 33 | <%= tracker.name %></label><br /> |
|
34 | 34 | <% end %> |
|
35 | 35 | <p><%= submit_tag l(:button_apply), :class => 'button-small' %></p> |
|
36 | 36 | <% end %> |
|
37 | 37 | |
|
38 | 38 | <h3><%= l(:label_version_plural) %></h3> |
|
39 | 39 | <% @versions.each do |version| %> |
|
40 | 40 | <%= link_to version.name, :anchor => version.name %><br /> |
|
41 | 41 | <% end %> |
|
42 | 42 | <% end %> |
@@ -1,34 +1,36 | |||
|
1 | 1 | <div class="contextual"> |
|
2 | 2 | <%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'edit', :project_id => @project, :issue_id => @issue}, :class => 'icon icon-time' %> |
|
3 | 3 | </div> |
|
4 | 4 | |
|
5 | 5 | <%= render_timelog_breadcrumb %> |
|
6 | 6 | |
|
7 | 7 | <h2><%= l(:label_spent_time) %></h2> |
|
8 | 8 | |
|
9 | <% form_remote_tag( :url => {}, :method => :get, :update => 'content' ) do %> | |
|
9 | <% form_remote_tag( :url => {}, :html => {:method => :get}, :method => :get, :update => 'content' ) do %> | |
|
10 | <%# TOOD: remove the project_id and issue_id hidden fields, that information is | |
|
11 | already in the URI %> | |
|
10 | 12 | <%= hidden_field_tag 'project_id', params[:project_id] %> |
|
11 | 13 | <%= hidden_field_tag 'issue_id', params[:issue_id] if @issue %> |
|
12 | 14 | <%= render :partial => 'date_range' %> |
|
13 | 15 | <% end %> |
|
14 | 16 | |
|
15 | 17 | <div class="total-hours"> |
|
16 | 18 | <p><%= l(:label_total) %>: <%= html_hours(lwr(:label_f_hour, @total_hours)) %></p> |
|
17 | 19 | </div> |
|
18 | 20 | |
|
19 | 21 | <% unless @entries.empty? %> |
|
20 | 22 | <%= render :partial => 'list', :locals => { :entries => @entries }%> |
|
21 | 23 | <p class="pagination"><%= pagination_links_full @entry_pages, @entry_count %></p> |
|
22 | 24 | |
|
23 | 25 | <p class="other-formats"> |
|
24 | 26 | <%= l(:label_export_to) %> |
|
25 | 27 | <span><%= link_to 'Atom', {:issue_id => @issue, :format => 'atom', :key => User.current.rss_key}, :class => 'feed' %></span> |
|
26 | 28 | <span><%= link_to 'CSV', params.merge(:format => 'csv'), :class => 'csv' %></span> |
|
27 | 29 | </p> |
|
28 | 30 | <% end %> |
|
29 | 31 | |
|
30 | 32 | <% html_title l(:label_spent_time), l(:label_details) %> |
|
31 | 33 | |
|
32 | 34 | <% content_for :header_tags do %> |
|
33 | 35 | <%= auto_discovery_link_tag(:atom, {:issue_id => @issue, :format => 'atom', :key => User.current.rss_key}, :title => l(:label_spent_time)) %> |
|
34 | 36 | <% end %> |
@@ -1,74 +1,76 | |||
|
1 | 1 | <div class="contextual"> |
|
2 | 2 | <%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'edit', :project_id => @project, :issue_id => @issue}, :class => 'icon icon-time' %> |
|
3 | 3 | </div> |
|
4 | 4 | |
|
5 | 5 | <%= render_timelog_breadcrumb %> |
|
6 | 6 | |
|
7 | 7 | <h2><%= l(:label_spent_time) %></h2> |
|
8 | 8 | |
|
9 | <% form_remote_tag(:url => {}, :update => 'content') do %> | |
|
9 | <% form_remote_tag(:url => {}, :html => {:method => :get}, :method => :get, :update => 'content') do %> | |
|
10 | 10 | <% @criterias.each do |criteria| %> |
|
11 | 11 | <%= hidden_field_tag 'criterias[]', criteria, :id => nil %> |
|
12 | 12 | <% end %> |
|
13 | <%# TODO: get rid of the project_id field, that should already be in the URL %> | |
|
13 | 14 | <%= hidden_field_tag 'project_id', params[:project_id] %> |
|
14 | 15 | <%= render :partial => 'date_range' %> |
|
15 | 16 | |
|
16 | 17 | <p><%= l(:label_details) %>: <%= select_tag 'columns', options_for_select([[l(:label_year), 'year'], |
|
17 | 18 | [l(:label_month), 'month'], |
|
18 | 19 | [l(:label_week), 'week'], |
|
19 | 20 | [l(:label_day_plural).titleize, 'day']], @columns), |
|
20 | 21 | :onchange => "this.form.onsubmit();" %> |
|
21 | 22 | |
|
22 | 23 | <%= l(:button_add) %>: <%= select_tag('criterias[]', options_for_select([[]] + (@available_criterias.keys - @criterias).collect{|k| [l(@available_criterias[k][:label]), k]}), |
|
23 | 24 | :onchange => "this.form.onsubmit();", |
|
24 | 25 | :style => 'width: 200px', |
|
25 | 26 | :id => nil, |
|
26 | 27 | :disabled => (@criterias.length >= 3)) %> |
|
27 | 28 | <%= link_to_remote l(:button_clear), {:url => {:project_id => @project, :period_type => params[:period_type], :period => params[:period], :from => @from, :to => @to, :columns => @columns}, |
|
29 | :method => :get, | |
|
28 | 30 | :update => 'content' |
|
29 | 31 | }, :class => 'icon icon-reload' %></p> |
|
30 | 32 | <% end %> |
|
31 | 33 | |
|
32 | 34 | <% unless @criterias.empty? %> |
|
33 | 35 | <div class="total-hours"> |
|
34 | 36 | <p><%= l(:label_total) %>: <%= html_hours(lwr(:label_f_hour, @total_hours)) %></p> |
|
35 | 37 | </div> |
|
36 | 38 | |
|
37 | 39 | <% unless @hours.empty? %> |
|
38 | 40 | <table class="list" id="time-report"> |
|
39 | 41 | <thead> |
|
40 | 42 | <tr> |
|
41 | 43 | <% @criterias.each do |criteria| %> |
|
42 | 44 | <th><%= l(@available_criterias[criteria][:label]) %></th> |
|
43 | 45 | <% end %> |
|
44 | 46 | <% columns_width = (40 / (@periods.length+1)).to_i %> |
|
45 | 47 | <% @periods.each do |period| %> |
|
46 | 48 | <th class="period" width="<%= columns_width %>%"><%= period %></th> |
|
47 | 49 | <% end %> |
|
48 | 50 | <th class="total" width="<%= columns_width %>%"><%= l(:label_total) %></th> |
|
49 | 51 | </tr> |
|
50 | 52 | </thead> |
|
51 | 53 | <tbody> |
|
52 | 54 | <%= render :partial => 'report_criteria', :locals => {:criterias => @criterias, :hours => @hours, :level => 0} %> |
|
53 | 55 | <tr class="total"> |
|
54 | 56 | <td><%= l(:label_total) %></td> |
|
55 | 57 | <%= '<td></td>' * (@criterias.size - 1) %> |
|
56 | 58 | <% total = 0 -%> |
|
57 | 59 | <% @periods.each do |period| -%> |
|
58 | 60 | <% sum = sum_hours(select_hours(@hours, @columns, period.to_s)); total += sum -%> |
|
59 | 61 | <td class="hours"><%= html_hours("%.2f" % sum) if sum > 0 %></td> |
|
60 | 62 | <% end -%> |
|
61 | 63 | <td class="hours"><%= html_hours("%.2f" % total) if total > 0 %></td> |
|
62 | 64 | </tr> |
|
63 | 65 | </tbody> |
|
64 | 66 | </table> |
|
65 | 67 | |
|
66 | 68 | <p class="other-formats"> |
|
67 | 69 | <%= l(:label_export_to) %> |
|
68 | 70 | <span><%= link_to 'CSV', params.merge({:format => 'csv'}), :class => 'csv' %></span> |
|
69 | 71 | </p> |
|
70 | 72 | <% end %> |
|
71 | 73 | <% end %> |
|
72 | 74 | |
|
73 | 75 | <% html_title l(:label_spent_time), l(:label_report) %> |
|
74 | 76 |
@@ -1,4 +1,4 | |||
|
1 | <% labelled_tabular_form_for :user, @user, :url => { :action => "edit" } do |f| %> | |
|
1 | <% labelled_tabular_form_for :user, @user, :url => { :action => "edit", :tab => nil } do |f| %> | |
|
2 | 2 | <%= render :partial => 'form', :locals => { :f => f } %> |
|
3 | 3 | <%= submit_tag l(:button_save) %> |
|
4 | 4 | <% end %> |
@@ -1,51 +1,253 | |||
|
1 | 1 | ActionController::Routing::Routes.draw do |map| |
|
2 | 2 | # Add your own custom routes here. |
|
3 | 3 | # The priority is based upon order of creation: first created -> highest priority. |
|
4 | 4 | |
|
5 | 5 | # Here's a sample route: |
|
6 | 6 | # map.connect 'products/:id', :controller => 'catalog', :action => 'view' |
|
7 | 7 | # Keep in mind you can assign values other than :controller and :action |
|
8 | 8 | |
|
9 | 9 | # Allow Redmine plugins to map routes and potentially override them |
|
10 | 10 | Rails.plugins.each do |plugin| |
|
11 | 11 | map.from_plugin plugin.name.to_sym |
|
12 | 12 | end |
|
13 | 13 | |
|
14 | 14 | map.home '', :controller => 'welcome' |
|
15 | ||
|
15 | 16 | map.signin 'login', :controller => 'account', :action => 'login' |
|
16 | 17 | map.signout 'logout', :controller => 'account', :action => 'logout' |
|
17 | 18 | |
|
18 | map.connect 'wiki/:id/:page/:action', :controller => 'wiki', :page => nil | |
|
19 | 19 | map.connect 'roles/workflow/:id/:role_id/:tracker_id', :controller => 'roles', :action => 'workflow' |
|
20 | 20 | map.connect 'help/:ctrl/:page', :controller => 'help' |
|
21 | #map.connect ':controller/:action/:id/:sort_key/:sort_order' | |
|
22 | 21 | |
|
23 |
map.connect ' |
|
|
22 | map.connect 'time_entries/:id/edit', :action => 'edit', :controller => 'timelog' | |
|
23 | map.connect 'projects/:project_id/time_entries/new', :action => 'edit', :controller => 'timelog' | |
|
24 | map.connect 'projects/:project_id/issues/:issue_id/time_entries/new', :action => 'edit', :controller => 'timelog' | |
|
25 | ||
|
26 | map.with_options :controller => 'timelog' do |timelog| | |
|
27 | timelog.connect 'projects/:project_id/time_entries', :action => 'details' | |
|
28 | ||
|
29 | timelog.with_options :action => 'details', :conditions => {:method => :get} do |time_details| | |
|
30 | time_details.connect 'time_entries' | |
|
31 | time_details.connect 'time_entries.:format' | |
|
32 | time_details.connect 'issues/:issue_id/time_entries' | |
|
33 | time_details.connect 'issues/:issue_id/time_entries.:format' | |
|
34 | time_details.connect 'projects/:project_id/time_entries.:format' | |
|
35 | time_details.connect 'projects/:project_id/issues/:issue_id/time_entries' | |
|
36 | time_details.connect 'projects/:project_id/issues/:issue_id/time_entries.:format' | |
|
37 | end | |
|
38 | timelog.connect 'projects/:project_id/time_entries/report', :action => 'report' | |
|
39 | timelog.with_options :action => 'report',:conditions => {:method => :get} do |time_report| | |
|
40 | time_report.connect 'time_entries/report' | |
|
41 | time_report.connect 'time_entries/report.:format' | |
|
42 | time_report.connect 'projects/:project_id/time_entries/report.:format' | |
|
43 | end | |
|
44 | ||
|
45 | timelog.with_options :action => 'edit', :conditions => {:method => :get} do |time_edit| | |
|
46 | time_edit.connect 'issues/:issue_id/time_entries/new' | |
|
47 | end | |
|
48 | ||
|
49 | timelog.connect 'time_entries/:id/destroy', :action => 'destroy', :conditions => {:method => :post} | |
|
50 | end | |
|
51 | ||
|
52 | map.connect 'projects/:id/wiki', :controller => 'wikis', :action => 'edit', :conditions => {:method => :post} | |
|
53 | map.connect 'projects/:id/wiki/destroy', :controller => 'wikis', :action => 'destroy', :conditions => {:method => :get} | |
|
54 | map.connect 'projects/:id/wiki/destroy', :controller => 'wikis', :action => 'destroy', :conditions => {:method => :post} | |
|
55 | map.with_options :controller => 'wiki' do |wiki_routes| | |
|
56 | wiki_routes.with_options :conditions => {:method => :get} do |wiki_views| | |
|
57 | wiki_views.connect 'projects/:id/wiki/:page', :action => 'special', :page => /page_index|date_index|export/i | |
|
58 | wiki_views.connect 'projects/:id/wiki/:page', :action => 'index', :page => nil | |
|
59 | wiki_views.connect 'projects/:id/wiki/:page/edit', :action => 'edit' | |
|
60 | wiki_views.connect 'projects/:id/wiki/:page/rename', :action => 'rename' | |
|
61 | wiki_views.connect 'projects/:id/wiki/:page/history', :action => 'history' | |
|
62 | wiki_views.connect 'projects/:id/wiki/:page/diff/:version/vs/:version_from', :action => 'diff' | |
|
63 | wiki_views.connect 'projects/:id/wiki/:page/annotate/:version', :action => 'annotate' | |
|
64 | end | |
|
65 | ||
|
66 | wiki_routes.connect 'projects/:id/wiki/:page/:action', | |
|
67 | :action => /edit|rename|destroy|preview|protect/, | |
|
68 | :conditions => {:method => :post} | |
|
69 | end | |
|
70 | ||
|
71 | map.with_options :controller => 'messages' do |messages_routes| | |
|
72 | messages_routes.with_options :conditions => {:method => :get} do |messages_views| | |
|
73 | messages_views.connect 'boards/:board_id/topics/new', :action => 'new' | |
|
74 | messages_views.connect 'boards/:board_id/topics/:id', :action => 'show' | |
|
75 | messages_views.connect 'boards/:board_id/topics/:id/edit', :action => 'edit' | |
|
76 | end | |
|
77 | messages_routes.with_options :conditions => {:method => :post} do |messages_actions| | |
|
78 | messages_actions.connect 'boards/:board_id/topics/new', :action => 'new' | |
|
79 | messages_actions.connect 'boards/:board_id/topics/:id/replies', :action => 'reply' | |
|
80 | messages_actions.connect 'boards/:board_id/topics/:id/:action', :action => /edit|destroy/ | |
|
81 | end | |
|
82 | end | |
|
83 | ||
|
84 | map.with_options :controller => 'boards' do |board_routes| | |
|
85 | board_routes.with_options :conditions => {:method => :get} do |board_views| | |
|
86 | board_views.connect 'projects/:project_id/boards', :action => 'index' | |
|
87 | board_views.connect 'projects/:project_id/boards/new', :action => 'new' | |
|
88 | board_views.connect 'projects/:project_id/boards/:id', :action => 'show' | |
|
89 | board_views.connect 'projects/:project_id/boards/:id/edit', :action => 'edit' | |
|
90 | end | |
|
91 | board_routes.with_options :conditions => {:method => :post} do |board_actions| | |
|
92 | board_actions.connect 'projects/:project_id/boards', :action => 'new' | |
|
93 | board_actions.connect 'projects/:project_id/boards/:id/:action', :action => /edit|destroy/ | |
|
94 | end | |
|
95 | end | |
|
96 | ||
|
97 | map.with_options :controller => 'documents' do |document_routes| | |
|
98 | document_routes.with_options :conditions => {:method => :get} do |document_views| | |
|
99 | document_views.connect 'projects/:project_id/documents', :action => 'index' | |
|
100 | document_views.connect 'projects/:project_id/documents/new', :action => 'new' | |
|
101 | document_views.connect 'documents/:id', :action => 'show' | |
|
102 | document_views.connect 'documents/:id/edit', :action => 'edit' | |
|
103 | end | |
|
104 | document_routes.with_options :conditions => {:method => :post} do |document_actions| | |
|
105 | document_actions.connect 'projects/:project_id/documents', :action => 'new' | |
|
106 | document_actions.connect 'documents/:id/:action', :action => /destroy|edit/ | |
|
107 | end | |
|
108 | end | |
|
109 | ||
|
110 | map.with_options :controller => 'issues' do |issues_routes| | |
|
111 | issues_routes.with_options :conditions => {:method => :get} do |issues_views| | |
|
112 | issues_views.connect 'issues', :action => 'index' | |
|
113 | issues_views.connect 'issues.:format', :action => 'index' | |
|
114 | issues_views.connect 'projects/:project_id/issues.:format', :action => 'index' | |
|
115 | issues_views.connect 'projects/:project_id/issues/new', :action => 'new' | |
|
116 | issues_views.connect 'projects/:project_id/issues/:copy_from/copy', :action => 'new' | |
|
117 | issues_views.connect 'issues/:id', :action => 'show' | |
|
118 | issues_views.connect 'issues/:id.:format', :action => 'show' | |
|
119 | issues_views.connect 'issues/:id/edit', :action => 'edit' | |
|
120 | issues_views.connect 'issues/:id/move', :action => 'move' | |
|
121 | end | |
|
122 | issues_routes.with_options :conditions => {:method => :post} do |issues_actions| | |
|
123 | issues_actions.connect 'projects/:project_id/issues', :action => 'new' | |
|
124 | issues_actions.connect 'issues/:id/quoted', :action => 'reply' | |
|
125 | issues_actions.connect 'issues/:id/:action', | |
|
126 | :action => /edit|move|destroy/ | |
|
127 | end | |
|
128 | end | |
|
129 | ||
|
130 | map.with_options :controller => 'issue_relations', :conditions => {:method => :post} do |relations| | |
|
131 | relations.connect 'issues/:issue_id/relations/:id', :action => 'new' | |
|
132 | relations.connect 'issues/:issue_id/relations/:id/destroy', :action => 'destroy' | |
|
133 | end | |
|
134 | ||
|
135 | map.with_options :controller => 'reports', :action => 'issue_report', :conditions => {:method => :get} do |reports| | |
|
136 | reports.connect 'projects/:id/issues/report' | |
|
137 | reports.connect 'projects/:id/issues/report/:detail' | |
|
138 | end | |
|
139 | ||
|
140 | map.with_options :controller => 'news' do |news_routes| | |
|
141 | news_routes.with_options :conditions => {:method => :get} do |news_views| | |
|
142 | news_views.connect 'news', :action => 'index' | |
|
143 | news_views.connect 'projects/:project_id/news', :action => 'index' | |
|
144 | news_views.connect 'projects/:project_id/news.:format', :action => 'index' | |
|
145 | news_views.connect 'news.:format', :action => 'index' | |
|
146 | news_views.connect 'projects/:project_id/news/new', :action => 'new' | |
|
147 | news_views.connect 'news/:id', :action => 'show' | |
|
148 | news_views.connect 'news/:id/edit', :action => 'edit' | |
|
149 | end | |
|
150 | news_routes.with_options do |news_actions| | |
|
151 | news_actions.connect 'projects/:project_id/news', :action => 'new' | |
|
152 | news_actions.connect 'news/:id/edit', :action => 'edit' | |
|
153 | news_actions.connect 'news/:id/destroy', :action => 'destroy' | |
|
154 | end | |
|
155 | end | |
|
156 | ||
|
157 | map.connect 'projects/:id/members/new', :controller => 'members', :action => 'new' | |
|
158 | ||
|
159 | map.with_options :controller => 'users' do |users| | |
|
160 | users.with_options :conditions => {:method => :get} do |user_views| | |
|
161 | user_views.connect 'users', :action => 'list' | |
|
162 | user_views.connect 'users', :action => 'index' | |
|
163 | user_views.connect 'users/new', :action => 'add' | |
|
164 | user_views.connect 'users/:id/edit/:tab', :action => 'edit', :tab => nil | |
|
165 | end | |
|
166 | users.with_options :conditions => {:method => :post} do |user_actions| | |
|
167 | user_actions.connect 'users', :action => 'add' | |
|
168 | user_actions.connect 'users/new', :action => 'add' | |
|
169 | user_actions.connect 'users/:id/edit', :action => 'edit' | |
|
170 | user_actions.connect 'users/:id/memberships', :action => 'edit_membership' | |
|
171 | user_actions.connect 'users/:id/memberships/:membership_id', :action => 'edit_membership' | |
|
172 | user_actions.connect 'users/:id/memberships/:membership_id/destroy', :action => 'destroy_membership' | |
|
173 | end | |
|
174 | end | |
|
175 | ||
|
176 | map.with_options :controller => 'projects' do |projects| | |
|
177 | projects.with_options :conditions => {:method => :get} do |project_views| | |
|
178 | project_views.connect 'projects', :action => 'index' | |
|
179 | project_views.connect 'projects.:format', :action => 'index' | |
|
180 | project_views.connect 'projects/new', :action => 'add' | |
|
181 | project_views.connect 'projects/:id', :action => 'show' | |
|
182 | project_views.connect 'projects/:id/:action', :action => /roadmap|changelog|destroy|settings/ | |
|
183 | project_views.connect 'projects/:id/files', :action => 'list_files' | |
|
184 | project_views.connect 'projects/:id/files/new', :action => 'add_file' | |
|
185 | project_views.connect 'projects/:id/versions/new', :action => 'add_version' | |
|
186 | project_views.connect 'projects/:id/categories/new', :action => 'add_issue_category' | |
|
187 | project_views.connect 'projects/:id/settings/:tab', :action => 'settings' | |
|
188 | end | |
|
189 | ||
|
190 | projects.with_options :action => 'activity', :conditions => {:method => :get} do |activity| | |
|
191 | activity.connect 'projects/:id/activity' | |
|
192 | activity.connect 'projects/:id/activity.:format' | |
|
193 | activity.connect 'activity' | |
|
194 | activity.connect 'activity.:format' | |
|
195 | end | |
|
196 | ||
|
197 | projects.with_options :conditions => {:method => :post} do |project_actions| | |
|
198 | project_actions.connect 'projects/new', :action => 'add' | |
|
199 | project_actions.connect 'projects', :action => 'add' | |
|
200 | project_actions.connect 'projects/:id/:action', :action => /destroy|archive|unarchive/ | |
|
201 | project_actions.connect 'projects/:id/files/new', :action => 'add_file' | |
|
202 | project_actions.connect 'projects/:id/versions/new', :action => 'add_version' | |
|
203 | project_actions.connect 'projects/:id/categories/new', :action => 'add_issue_category' | |
|
204 | end | |
|
205 | end | |
|
206 | ||
|
207 | map.with_options :controller => 'repositories' do |repositories| | |
|
208 | repositories.with_options :conditions => {:method => :get} do |repository_views| | |
|
209 | repositories.connect 'projects/:id/repository', :action => 'show' | |
|
210 | repositories.connect 'projects/:id/repository/edit', :action => 'edit' | |
|
211 | repositories.connect 'projects/:id/repository/statistics', :action => 'stats' | |
|
212 | repositories.connect 'projects/:id/repository/revisions', :action => 'revisions' | |
|
213 | repositories.connect 'projects/:id/repository/revisions.:format', :action => 'revisions' | |
|
214 | repositories.connect 'projects/:id/repository/revisions/:rev', :action => 'revision' | |
|
215 | repositories.connect 'projects/:id/repository/revisions/:rev/diff', :action => 'diff' | |
|
216 | repositories.connect 'projects/:id/repository/revisions/:rev/diff.:format', :action => 'diff' | |
|
217 | repositories.connect 'projects/:id/repository/revisions/:rev/:action/*path' | |
|
218 | repositories.connect 'projects/:id/repository/:action/*path' | |
|
219 | end | |
|
220 | ||
|
221 | repositories.connect 'projects/:id/repository/edit', :action => 'edit', :conditions => {:method => :post} | |
|
222 | end | |
|
223 | ||
|
224 | map.connect 'attachments/:id', :controller => 'attachments', :action => 'show', :id => /\d+/ | |
|
225 | map.connect 'attachments/:id/:filename', :controller => 'attachments', :action => 'show', :id => /\d+/, :filename => /.*/ | |
|
226 | map.connect 'attachments/download/:id/:filename', :controller => 'attachments', :action => 'download', :id => /\d+/, :filename => /.*/ | |
|
227 | ||
|
228 | ||
|
229 | #left old routes at the bottom for backwards compat | |
|
24 | 230 | map.connect 'projects/:project_id/issues/:action', :controller => 'issues' |
|
25 | map.connect 'projects/:project_id/news/:action', :controller => 'news' | |
|
26 | 231 | map.connect 'projects/:project_id/documents/:action', :controller => 'documents' |
|
27 | 232 | map.connect 'projects/:project_id/boards/:action/:id', :controller => 'boards' |
|
28 | map.connect 'projects/:project_id/timelog/:action/:id', :controller => 'timelog', :project_id => /.+/ | |
|
29 | 233 | map.connect 'boards/:board_id/topics/:action/:id', :controller => 'messages' |
|
30 | ||
|
234 | map.connect 'wiki/:id/:page/:action', :page => nil, :controller => 'wiki' | |
|
235 | map.connect 'issues/:issue_id/relations/:action/:id', :controller => 'issue_relations' | |
|
236 | map.connect 'projects/:project_id/news/:action', :controller => 'news' | |
|
237 | map.connect 'projects/:project_id/timelog/:action/:id', :controller => 'timelog', :project_id => /.+/ | |
|
31 | 238 | map.with_options :controller => 'repositories' do |omap| |
|
32 | 239 | omap.repositories_show 'repositories/browse/:id/*path', :action => 'browse' |
|
33 | 240 | omap.repositories_changes 'repositories/changes/:id/*path', :action => 'changes' |
|
34 | 241 | omap.repositories_diff 'repositories/diff/:id/*path', :action => 'diff' |
|
35 | 242 | omap.repositories_entry 'repositories/entry/:id/*path', :action => 'entry' |
|
36 | 243 | omap.repositories_entry 'repositories/annotate/:id/*path', :action => 'annotate' |
|
37 |
omap. |
|
|
244 | omap.connect 'repositories/revision/:id/:rev', :action => 'revision' | |
|
38 | 245 | end |
|
39 | 246 | |
|
40 | map.connect 'attachments/:id', :controller => 'attachments', :action => 'show', :id => /\d+/ | |
|
41 | map.connect 'attachments/:id/:filename', :controller => 'attachments', :action => 'show', :id => /\d+/, :filename => /.*/ | |
|
42 | map.connect 'attachments/download/:id/:filename', :controller => 'attachments', :action => 'download', :id => /\d+/, :filename => /.*/ | |
|
43 | ||
|
44 | 247 | # Allow downloading Web Service WSDL as a file with an extension |
|
45 | 248 | # instead of a file named 'wsdl' |
|
46 | 249 | map.connect ':controller/service.wsdl', :action => 'wsdl' |
|
47 | 250 | |
|
48 | ||
|
49 | 251 | # Install the default route as the lowest priority. |
|
50 | 252 | map.connect ':controller/:action/:id' |
|
51 | 253 | end |
@@ -1,124 +1,131 | |||
|
1 | 1 | # redMine - project management software |
|
2 | 2 | # Copyright (C) 2006-2007 Jean-Philippe Lang |
|
3 | 3 | # |
|
4 | 4 | # This program is free software; you can redistribute it and/or |
|
5 | 5 | # modify it under the terms of the GNU General Public License |
|
6 | 6 | # as published by the Free Software Foundation; either version 2 |
|
7 | 7 | # of the License, or (at your option) any later version. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU General Public License |
|
15 | 15 | # along with this program; if not, write to the Free Software |
|
16 | 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 | 17 | |
|
18 | 18 | require File.dirname(__FILE__) + '/../test_helper' |
|
19 | 19 | require 'admin_controller' |
|
20 | 20 | |
|
21 | 21 | # Re-raise errors caught by the controller. |
|
22 | 22 | class AdminController; def rescue_action(e) raise e end; end |
|
23 | 23 | |
|
24 | 24 | class AdminControllerTest < Test::Unit::TestCase |
|
25 | 25 | fixtures :projects, :users, :roles |
|
26 | 26 | |
|
27 | 27 | def setup |
|
28 | 28 | @controller = AdminController.new |
|
29 | 29 | @request = ActionController::TestRequest.new |
|
30 | 30 | @response = ActionController::TestResponse.new |
|
31 | 31 | User.current = nil |
|
32 | 32 | @request.session[:user_id] = 1 # admin |
|
33 | 33 | end |
|
34 | 34 | |
|
35 | 35 | def test_index |
|
36 | 36 | get :index |
|
37 | 37 | assert_no_tag :tag => 'div', |
|
38 | 38 | :attributes => { :class => /nodata/ } |
|
39 | 39 | end |
|
40 | 40 | |
|
41 | def test_projects_routing | |
|
42 | assert_routing( | |
|
43 | {:method => :get, :path => '/admin/projects'}, | |
|
44 | :controller => 'admin', :action => 'projects' | |
|
45 | ) | |
|
46 | end | |
|
47 | ||
|
41 | 48 | def test_index_with_no_configuration_data |
|
42 | 49 | delete_configuration_data |
|
43 | 50 | get :index |
|
44 | 51 | assert_tag :tag => 'div', |
|
45 | 52 | :attributes => { :class => /nodata/ } |
|
46 | 53 | end |
|
47 | 54 | |
|
48 | 55 | def test_projects |
|
49 | 56 | get :projects |
|
50 | 57 | assert_response :success |
|
51 | 58 | assert_template 'projects' |
|
52 | 59 | assert_not_nil assigns(:projects) |
|
53 | 60 | # active projects only |
|
54 | 61 | assert_nil assigns(:projects).detect {|u| !u.active?} |
|
55 | 62 | end |
|
56 | 63 | |
|
57 | 64 | def test_projects_with_name_filter |
|
58 | 65 | get :projects, :name => 'store', :status => '' |
|
59 | 66 | assert_response :success |
|
60 | 67 | assert_template 'projects' |
|
61 | 68 | projects = assigns(:projects) |
|
62 | 69 | assert_not_nil projects |
|
63 | 70 | assert_equal 1, projects.size |
|
64 | 71 | assert_equal 'OnlineStore', projects.first.name |
|
65 | 72 | end |
|
66 | 73 | |
|
67 | 74 | def test_load_default_configuration_data |
|
68 | 75 | delete_configuration_data |
|
69 | 76 | post :default_configuration, :lang => 'fr' |
|
70 | 77 | assert IssueStatus.find_by_name('Nouveau') |
|
71 | 78 | end |
|
72 | 79 | |
|
73 | 80 | def test_test_email |
|
74 | 81 | get :test_email |
|
75 | 82 | assert_redirected_to '/settings/edit?tab=notifications' |
|
76 | 83 | mail = ActionMailer::Base.deliveries.last |
|
77 | 84 | assert_kind_of TMail::Mail, mail |
|
78 | 85 | user = User.find(1) |
|
79 | 86 | assert_equal [user.mail], mail.bcc |
|
80 | 87 | end |
|
81 | 88 | |
|
82 | 89 | def test_no_plugins |
|
83 | 90 | Redmine::Plugin.clear |
|
84 | 91 | |
|
85 | 92 | get :plugins |
|
86 | 93 | assert_response :success |
|
87 | 94 | assert_template 'plugins' |
|
88 | 95 | end |
|
89 | 96 | |
|
90 | 97 | def test_plugins |
|
91 | 98 | # Register a few plugins |
|
92 | 99 | Redmine::Plugin.register :foo do |
|
93 | 100 | name 'Foo plugin' |
|
94 | 101 | author 'John Smith' |
|
95 | 102 | description 'This is a test plugin' |
|
96 | 103 | version '0.0.1' |
|
97 | 104 | settings :default => {'sample_setting' => 'value', 'foo'=>'bar'}, :partial => 'foo/settings' |
|
98 | 105 | end |
|
99 | 106 | Redmine::Plugin.register :bar do |
|
100 | 107 | end |
|
101 | 108 | |
|
102 | 109 | get :plugins |
|
103 | 110 | assert_response :success |
|
104 | 111 | assert_template 'plugins' |
|
105 | 112 | |
|
106 | 113 | assert_tag :td, :child => { :tag => 'span', :content => 'Foo plugin' } |
|
107 | 114 | assert_tag :td, :child => { :tag => 'span', :content => 'Bar' } |
|
108 | 115 | end |
|
109 | 116 | |
|
110 | 117 | def test_info |
|
111 | 118 | get :info |
|
112 | 119 | assert_response :success |
|
113 | 120 | assert_template 'info' |
|
114 | 121 | end |
|
115 | 122 | |
|
116 | 123 | private |
|
117 | 124 | |
|
118 | 125 | def delete_configuration_data |
|
119 | 126 | Role.delete_all('builtin = 0') |
|
120 | 127 | Tracker.delete_all |
|
121 | 128 | IssueStatus.delete_all |
|
122 | 129 | Enumeration.delete_all |
|
123 | 130 | end |
|
124 | 131 | end |
@@ -1,50 +1,93 | |||
|
1 | 1 | # redMine - project management software |
|
2 | 2 | # Copyright (C) 2006-2007 Jean-Philippe Lang |
|
3 | 3 | # |
|
4 | 4 | # This program is free software; you can redistribute it and/or |
|
5 | 5 | # modify it under the terms of the GNU General Public License |
|
6 | 6 | # as published by the Free Software Foundation; either version 2 |
|
7 | 7 | # of the License, or (at your option) any later version. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU General Public License |
|
15 | 15 | # along with this program; if not, write to the Free Software |
|
16 | 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 | 17 | |
|
18 | 18 | require File.dirname(__FILE__) + '/../test_helper' |
|
19 | 19 | require 'boards_controller' |
|
20 | 20 | |
|
21 | 21 | # Re-raise errors caught by the controller. |
|
22 | 22 | class BoardsController; def rescue_action(e) raise e end; end |
|
23 | 23 | |
|
24 | 24 | class BoardsControllerTest < Test::Unit::TestCase |
|
25 | 25 | fixtures :projects, :users, :members, :roles, :boards, :messages, :enabled_modules |
|
26 | 26 | |
|
27 | 27 | def setup |
|
28 | 28 | @controller = BoardsController.new |
|
29 | 29 | @request = ActionController::TestRequest.new |
|
30 | 30 | @response = ActionController::TestResponse.new |
|
31 | 31 | User.current = nil |
|
32 | 32 | end |
|
33 | 33 | |
|
34 | def test_index_routing | |
|
35 | assert_routing( | |
|
36 | {:method => :get, :path => '/projects/world_domination/boards'}, | |
|
37 | :controller => 'boards', :action => 'index', :project_id => 'world_domination' | |
|
38 | ) | |
|
39 | end | |
|
40 | ||
|
34 | 41 | def test_index |
|
35 | 42 | get :index, :project_id => 1 |
|
36 | 43 | assert_response :success |
|
37 | 44 | assert_template 'index' |
|
38 | 45 | assert_not_nil assigns(:boards) |
|
39 | 46 | assert_not_nil assigns(:project) |
|
40 | 47 | end |
|
41 | 48 | |
|
49 | def test_new_routing | |
|
50 | assert_routing( | |
|
51 | {:method => :get, :path => '/projects/world_domination/boards/new'}, | |
|
52 | :controller => 'boards', :action => 'new', :project_id => 'world_domination' | |
|
53 | ) | |
|
54 | assert_recognizes( | |
|
55 | {:controller => 'boards', :action => 'new', :project_id => 'world_domination'}, | |
|
56 | {:method => :post, :path => '/projects/world_domination/boards'} | |
|
57 | ) | |
|
58 | end | |
|
59 | ||
|
60 | def test_show_routing | |
|
61 | assert_routing( | |
|
62 | {:method => :get, :path => '/projects/world_domination/boards/44'}, | |
|
63 | :controller => 'boards', :action => 'show', :id => '44', :project_id => 'world_domination' | |
|
64 | ) | |
|
65 | end | |
|
66 | ||
|
42 | 67 | def test_show |
|
43 | 68 | get :show, :project_id => 1, :id => 1 |
|
44 | 69 | assert_response :success |
|
45 | 70 | assert_template 'show' |
|
46 | 71 | assert_not_nil assigns(:board) |
|
47 | 72 | assert_not_nil assigns(:project) |
|
48 | 73 | assert_not_nil assigns(:topics) |
|
49 | 74 | end |
|
75 | ||
|
76 | def test_edit_routing | |
|
77 | assert_routing( | |
|
78 | {:method => :get, :path => '/projects/world_domination/boards/44/edit'}, | |
|
79 | :controller => 'boards', :action => 'edit', :id => '44', :project_id => 'world_domination' | |
|
80 | ) | |
|
81 | assert_recognizes(#TODO: use PUT method to board_path, modify form accordingly | |
|
82 | {:controller => 'boards', :action => 'edit', :id => '44', :project_id => 'world_domination'}, | |
|
83 | {:method => :post, :path => '/projects/world_domination/boards/44/edit'} | |
|
84 | ) | |
|
85 | end | |
|
86 | ||
|
87 | def test_destroy_routing | |
|
88 | assert_routing(#TODO: use DELETE method to board_path, modify form accoringly | |
|
89 | {:method => :post, :path => '/projects/world_domination/boards/44/destroy'}, | |
|
90 | :controller => 'boards', :action => 'destroy', :id => '44', :project_id => 'world_domination' | |
|
91 | ) | |
|
92 | end | |
|
50 | 93 | end |
@@ -1,75 +1,118 | |||
|
1 | 1 | # redMine - project management software |
|
2 | 2 | # Copyright (C) 2006-2007 Jean-Philippe Lang |
|
3 | 3 | # |
|
4 | 4 | # This program is free software; you can redistribute it and/or |
|
5 | 5 | # modify it under the terms of the GNU General Public License |
|
6 | 6 | # as published by the Free Software Foundation; either version 2 |
|
7 | 7 | # of the License, or (at your option) any later version. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU General Public License |
|
15 | 15 | # along with this program; if not, write to the Free Software |
|
16 | 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 | 17 | |
|
18 | 18 | require File.dirname(__FILE__) + '/../test_helper' |
|
19 | 19 | require 'documents_controller' |
|
20 | 20 | |
|
21 | 21 | # Re-raise errors caught by the controller. |
|
22 | 22 | class DocumentsController; def rescue_action(e) raise e end; end |
|
23 | 23 | |
|
24 | 24 | class DocumentsControllerTest < Test::Unit::TestCase |
|
25 | 25 | fixtures :projects, :users, :roles, :members, :enabled_modules, :documents, :enumerations |
|
26 | 26 | |
|
27 | 27 | def setup |
|
28 | 28 | @controller = DocumentsController.new |
|
29 | 29 | @request = ActionController::TestRequest.new |
|
30 | 30 | @response = ActionController::TestResponse.new |
|
31 | 31 | User.current = nil |
|
32 | 32 | end |
|
33 | 33 | |
|
34 | def test_index_routing | |
|
35 | assert_routing( | |
|
36 | {:method => :get, :path => '/projects/567/documents'}, | |
|
37 | :controller => 'documents', :action => 'index', :project_id => '567' | |
|
38 | ) | |
|
39 | end | |
|
40 | ||
|
34 | 41 | def test_index |
|
35 | 42 | # Sets a default category |
|
36 | 43 | e = Enumeration.find_by_name('Technical documentation') |
|
37 | 44 | e.update_attributes(:is_default => true) |
|
38 | 45 | |
|
39 | 46 | get :index, :project_id => 'ecookbook' |
|
40 | 47 | assert_response :success |
|
41 | 48 | assert_template 'index' |
|
42 | 49 | assert_not_nil assigns(:grouped) |
|
43 | 50 | |
|
44 | 51 | # Default category selected in the new document form |
|
45 | 52 | assert_tag :select, :attributes => {:name => 'document[category_id]'}, |
|
46 | 53 | :child => {:tag => 'option', :attributes => {:selected => 'selected'}, |
|
47 | 54 | :content => 'Technical documentation'} |
|
48 | 55 | end |
|
49 | 56 | |
|
57 | def test_new_routing | |
|
58 | assert_routing( | |
|
59 | {:method => :get, :path => '/projects/567/documents/new'}, | |
|
60 | :controller => 'documents', :action => 'new', :project_id => '567' | |
|
61 | ) | |
|
62 | assert_recognizes( | |
|
63 | {:controller => 'documents', :action => 'new', :project_id => '567'}, | |
|
64 | {:method => :post, :path => '/projects/567/documents'} | |
|
65 | ) | |
|
66 | end | |
|
67 | ||
|
50 | 68 | def test_new_with_one_attachment |
|
51 | 69 | @request.session[:user_id] = 2 |
|
52 | 70 | set_tmp_attachments_directory |
|
53 | 71 | |
|
54 | 72 | post :new, :project_id => 'ecookbook', |
|
55 | 73 | :document => { :title => 'DocumentsControllerTest#test_post_new', |
|
56 | 74 | :description => 'This is a new document', |
|
57 | 75 | :category_id => 2}, |
|
58 | 76 | :attachments => {'1' => {'file' => test_uploaded_file('testfile.txt', 'text/plain')}} |
|
59 | 77 | |
|
60 | 78 | assert_redirected_to 'projects/ecookbook/documents' |
|
61 | 79 | |
|
62 | 80 | document = Document.find_by_title('DocumentsControllerTest#test_post_new') |
|
63 | 81 | assert_not_nil document |
|
64 | 82 | assert_equal Enumeration.find(2), document.category |
|
65 | 83 | assert_equal 1, document.attachments.size |
|
66 | 84 | assert_equal 'testfile.txt', document.attachments.first.filename |
|
67 | 85 | end |
|
68 | 86 | |
|
87 | def test_edit_routing | |
|
88 | assert_routing( | |
|
89 | {:method => :get, :path => '/documents/22/edit'}, | |
|
90 | :controller => 'documents', :action => 'edit', :id => '22' | |
|
91 | ) | |
|
92 | assert_recognizes(#TODO: should be using PUT on document URI | |
|
93 | {:controller => 'documents', :action => 'edit', :id => '567'}, | |
|
94 | {:method => :post, :path => '/documents/567/edit'} | |
|
95 | ) | |
|
96 | end | |
|
97 | ||
|
98 | def test_show_routing | |
|
99 | assert_routing( | |
|
100 | {:method => :get, :path => '/documents/22'}, | |
|
101 | :controller => 'documents', :action => 'show', :id => '22' | |
|
102 | ) | |
|
103 | end | |
|
104 | ||
|
105 | def test_destroy_routing | |
|
106 | assert_recognizes(#TODO: should be using DELETE on document URI | |
|
107 | {:controller => 'documents', :action => 'destroy', :id => '567'}, | |
|
108 | {:method => :post, :path => '/documents/567/destroy'} | |
|
109 | ) | |
|
110 | end | |
|
111 | ||
|
69 | 112 | def test_destroy |
|
70 | 113 | @request.session[:user_id] = 2 |
|
71 | 114 | post :destroy, :id => 1 |
|
72 | 115 | assert_redirected_to 'projects/ecookbook/documents' |
|
73 | 116 | assert_nil Document.find_by_id(1) |
|
74 | 117 | end |
|
75 | 118 | end |
@@ -1,822 +1,948 | |||
|
1 | 1 | # Redmine - project management software |
|
2 | 2 | # Copyright (C) 2006-2008 Jean-Philippe Lang |
|
3 | 3 | # |
|
4 | 4 | # This program is free software; you can redistribute it and/or |
|
5 | 5 | # modify it under the terms of the GNU General Public License |
|
6 | 6 | # as published by the Free Software Foundation; either version 2 |
|
7 | 7 | # of the License, or (at your option) any later version. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU General Public License |
|
15 | 15 | # along with this program; if not, write to the Free Software |
|
16 | 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 | 17 | |
|
18 | 18 | require File.dirname(__FILE__) + '/../test_helper' |
|
19 | 19 | require 'issues_controller' |
|
20 | 20 | |
|
21 | 21 | # Re-raise errors caught by the controller. |
|
22 | 22 | class IssuesController; def rescue_action(e) raise e end; end |
|
23 | 23 | |
|
24 | 24 | class IssuesControllerTest < Test::Unit::TestCase |
|
25 | 25 | fixtures :projects, |
|
26 | 26 | :users, |
|
27 | 27 | :roles, |
|
28 | 28 | :members, |
|
29 | 29 | :issues, |
|
30 | 30 | :issue_statuses, |
|
31 | 31 | :versions, |
|
32 | 32 | :trackers, |
|
33 | 33 | :projects_trackers, |
|
34 | 34 | :issue_categories, |
|
35 | 35 | :enabled_modules, |
|
36 | 36 | :enumerations, |
|
37 | 37 | :attachments, |
|
38 | 38 | :workflows, |
|
39 | 39 | :custom_fields, |
|
40 | 40 | :custom_values, |
|
41 | 41 | :custom_fields_trackers, |
|
42 | 42 | :time_entries, |
|
43 | 43 | :journals, |
|
44 | 44 | :journal_details |
|
45 | 45 | |
|
46 | 46 | def setup |
|
47 | 47 | @controller = IssuesController.new |
|
48 | 48 | @request = ActionController::TestRequest.new |
|
49 | 49 | @response = ActionController::TestResponse.new |
|
50 | 50 | User.current = nil |
|
51 | 51 | end |
|
52 | 52 | |
|
53 | def test_index_routing | |
|
54 | assert_routing( | |
|
55 | {:method => :get, :path => '/issues'}, | |
|
56 | :controller => 'issues', :action => 'index' | |
|
57 | ) | |
|
58 | end | |
|
59 | ||
|
53 | 60 | def test_index |
|
54 | 61 | get :index |
|
55 | 62 | assert_response :success |
|
56 | 63 | assert_template 'index.rhtml' |
|
57 | 64 | assert_not_nil assigns(:issues) |
|
58 | 65 | assert_nil assigns(:project) |
|
59 | 66 | assert_tag :tag => 'a', :content => /Can't print recipes/ |
|
60 | 67 | assert_tag :tag => 'a', :content => /Subproject issue/ |
|
61 | 68 | # private projects hidden |
|
62 | 69 | assert_no_tag :tag => 'a', :content => /Issue of a private subproject/ |
|
63 | 70 | assert_no_tag :tag => 'a', :content => /Issue on project 2/ |
|
64 | 71 | end |
|
65 | 72 | |
|
66 | 73 | def test_index_should_not_list_issues_when_module_disabled |
|
67 | 74 | EnabledModule.delete_all("name = 'issue_tracking' AND project_id = 1") |
|
68 | 75 | get :index |
|
69 | 76 | assert_response :success |
|
70 | 77 | assert_template 'index.rhtml' |
|
71 | 78 | assert_not_nil assigns(:issues) |
|
72 | 79 | assert_nil assigns(:project) |
|
73 | 80 | assert_no_tag :tag => 'a', :content => /Can't print recipes/ |
|
74 | 81 | assert_tag :tag => 'a', :content => /Subproject issue/ |
|
75 | 82 | end |
|
76 | 83 | |
|
84 | def test_index_with_project_routing | |
|
85 | assert_routing( | |
|
86 | {:method => :get, :path => '/projects/23/issues'}, | |
|
87 | :controller => 'issues', :action => 'index', :project_id => '23' | |
|
88 | ) | |
|
89 | end | |
|
90 | ||
|
91 | def test_index_should_not_list_issues_when_module_disabled | |
|
92 | EnabledModule.delete_all("name = 'issue_tracking' AND project_id = 1") | |
|
93 | get :index | |
|
94 | assert_response :success | |
|
95 | assert_template 'index.rhtml' | |
|
96 | assert_not_nil assigns(:issues) | |
|
97 | assert_nil assigns(:project) | |
|
98 | assert_no_tag :tag => 'a', :content => /Can't print recipes/ | |
|
99 | assert_tag :tag => 'a', :content => /Subproject issue/ | |
|
100 | end | |
|
101 | ||
|
102 | def test_index_with_project_routing | |
|
103 | assert_routing( | |
|
104 | {:method => :get, :path => 'projects/23/issues'}, | |
|
105 | :controller => 'issues', :action => 'index', :project_id => '23' | |
|
106 | ) | |
|
107 | end | |
|
108 | ||
|
77 | 109 | def test_index_with_project |
|
78 | 110 | Setting.display_subprojects_issues = 0 |
|
79 | 111 | get :index, :project_id => 1 |
|
80 | 112 | assert_response :success |
|
81 | 113 | assert_template 'index.rhtml' |
|
82 | 114 | assert_not_nil assigns(:issues) |
|
83 | 115 | assert_tag :tag => 'a', :content => /Can't print recipes/ |
|
84 | 116 | assert_no_tag :tag => 'a', :content => /Subproject issue/ |
|
85 | 117 | end |
|
86 | 118 | |
|
87 | 119 | def test_index_with_project_and_subprojects |
|
88 | 120 | Setting.display_subprojects_issues = 1 |
|
89 | 121 | get :index, :project_id => 1 |
|
90 | 122 | assert_response :success |
|
91 | 123 | assert_template 'index.rhtml' |
|
92 | 124 | assert_not_nil assigns(:issues) |
|
93 | 125 | assert_tag :tag => 'a', :content => /Can't print recipes/ |
|
94 | 126 | assert_tag :tag => 'a', :content => /Subproject issue/ |
|
95 | 127 | assert_no_tag :tag => 'a', :content => /Issue of a private subproject/ |
|
96 | 128 | end |
|
97 | 129 | |
|
98 | 130 | def test_index_with_project_and_subprojects_should_show_private_subprojects |
|
99 | 131 | @request.session[:user_id] = 2 |
|
100 | 132 | Setting.display_subprojects_issues = 1 |
|
101 | 133 | get :index, :project_id => 1 |
|
102 | 134 | assert_response :success |
|
103 | 135 | assert_template 'index.rhtml' |
|
104 | 136 | assert_not_nil assigns(:issues) |
|
105 | 137 | assert_tag :tag => 'a', :content => /Can't print recipes/ |
|
106 | 138 | assert_tag :tag => 'a', :content => /Subproject issue/ |
|
107 | 139 | assert_tag :tag => 'a', :content => /Issue of a private subproject/ |
|
108 | 140 | end |
|
109 | 141 | |
|
142 | def test_index_with_project_routing_formatted | |
|
143 | assert_routing( | |
|
144 | {:method => :get, :path => 'projects/23/issues.pdf'}, | |
|
145 | :controller => 'issues', :action => 'index', :project_id => '23', :format => 'pdf' | |
|
146 | ) | |
|
147 | assert_routing( | |
|
148 | {:method => :get, :path => 'projects/23/issues.atom'}, | |
|
149 | :controller => 'issues', :action => 'index', :project_id => '23', :format => 'atom' | |
|
150 | ) | |
|
151 | end | |
|
152 | ||
|
110 | 153 | def test_index_with_project_and_filter |
|
111 | 154 | get :index, :project_id => 1, :set_filter => 1 |
|
112 | 155 | assert_response :success |
|
113 | 156 | assert_template 'index.rhtml' |
|
114 | 157 | assert_not_nil assigns(:issues) |
|
115 | 158 | end |
|
116 | 159 | |
|
117 | 160 | def test_index_csv_with_project |
|
118 | 161 | get :index, :format => 'csv' |
|
119 | 162 | assert_response :success |
|
120 | 163 | assert_not_nil assigns(:issues) |
|
121 | 164 | assert_equal 'text/csv', @response.content_type |
|
122 | 165 | |
|
123 | 166 | get :index, :project_id => 1, :format => 'csv' |
|
124 | 167 | assert_response :success |
|
125 | 168 | assert_not_nil assigns(:issues) |
|
126 | 169 | assert_equal 'text/csv', @response.content_type |
|
127 | 170 | end |
|
128 | 171 | |
|
172 | def test_index_formatted | |
|
173 | assert_routing( | |
|
174 | {:method => :get, :path => 'issues.pdf'}, | |
|
175 | :controller => 'issues', :action => 'index', :format => 'pdf' | |
|
176 | ) | |
|
177 | assert_routing( | |
|
178 | {:method => :get, :path => 'issues.atom'}, | |
|
179 | :controller => 'issues', :action => 'index', :format => 'atom' | |
|
180 | ) | |
|
181 | end | |
|
182 | ||
|
129 | 183 | def test_index_pdf |
|
130 | 184 | get :index, :format => 'pdf' |
|
131 | 185 | assert_response :success |
|
132 | 186 | assert_not_nil assigns(:issues) |
|
133 | 187 | assert_equal 'application/pdf', @response.content_type |
|
134 | 188 | |
|
135 | 189 | get :index, :project_id => 1, :format => 'pdf' |
|
136 | 190 | assert_response :success |
|
137 | 191 | assert_not_nil assigns(:issues) |
|
138 | 192 | assert_equal 'application/pdf', @response.content_type |
|
139 | 193 | end |
|
140 | 194 | |
|
141 | 195 | def test_index_sort |
|
142 | 196 | get :index, :sort_key => 'tracker' |
|
143 | 197 | assert_response :success |
|
144 | 198 | |
|
145 | 199 | sort_params = @request.session['issuesindex_sort'] |
|
146 | 200 | assert sort_params.is_a?(Hash) |
|
147 | 201 | assert_equal 'tracker', sort_params[:key] |
|
148 | 202 | assert_equal 'ASC', sort_params[:order] |
|
149 | 203 | end |
|
150 | 204 | |
|
151 | 205 | def test_gantt |
|
152 | 206 | get :gantt, :project_id => 1 |
|
153 | 207 | assert_response :success |
|
154 | 208 | assert_template 'gantt.rhtml' |
|
155 | 209 | assert_not_nil assigns(:gantt) |
|
156 | 210 | events = assigns(:gantt).events |
|
157 | 211 | assert_not_nil events |
|
158 | 212 | # Issue with start and due dates |
|
159 | 213 | i = Issue.find(1) |
|
160 | 214 | assert_not_nil i.due_date |
|
161 | 215 | assert events.include?(Issue.find(1)) |
|
162 | 216 | # Issue with without due date but targeted to a version with date |
|
163 | 217 | i = Issue.find(2) |
|
164 | 218 | assert_nil i.due_date |
|
165 | 219 | assert events.include?(i) |
|
166 | 220 | end |
|
167 | 221 | |
|
168 | 222 | def test_cross_project_gantt |
|
169 | 223 | get :gantt |
|
170 | 224 | assert_response :success |
|
171 | 225 | assert_template 'gantt.rhtml' |
|
172 | 226 | assert_not_nil assigns(:gantt) |
|
173 | 227 | events = assigns(:gantt).events |
|
174 | 228 | assert_not_nil events |
|
175 | 229 | end |
|
176 | 230 | |
|
177 | 231 | def test_gantt_export_to_pdf |
|
178 | 232 | get :gantt, :project_id => 1, :format => 'pdf' |
|
179 | 233 | assert_response :success |
|
180 | 234 | assert_equal 'application/pdf', @response.content_type |
|
181 | 235 | assert @response.body.starts_with?('%PDF') |
|
182 | 236 | assert_not_nil assigns(:gantt) |
|
183 | 237 | end |
|
184 | 238 | |
|
185 | 239 | def test_cross_project_gantt_export_to_pdf |
|
186 | 240 | get :gantt, :format => 'pdf' |
|
187 | 241 | assert_response :success |
|
188 | 242 | assert_equal 'application/pdf', @response.content_type |
|
189 | 243 | assert @response.body.starts_with?('%PDF') |
|
190 | 244 | assert_not_nil assigns(:gantt) |
|
191 | 245 | end |
|
192 | 246 | |
|
193 | 247 | if Object.const_defined?(:Magick) |
|
194 | 248 | def test_gantt_image |
|
195 | 249 | get :gantt, :project_id => 1, :format => 'png' |
|
196 | 250 | assert_response :success |
|
197 | 251 | assert_equal 'image/png', @response.content_type |
|
198 | 252 | end |
|
199 | 253 | else |
|
200 | 254 | puts "RMagick not installed. Skipping tests !!!" |
|
201 | 255 | end |
|
202 | 256 | |
|
203 | 257 | def test_calendar |
|
204 | 258 | get :calendar, :project_id => 1 |
|
205 | 259 | assert_response :success |
|
206 | 260 | assert_template 'calendar' |
|
207 | 261 | assert_not_nil assigns(:calendar) |
|
208 | 262 | end |
|
209 | 263 | |
|
210 | 264 | def test_cross_project_calendar |
|
211 | 265 | get :calendar |
|
212 | 266 | assert_response :success |
|
213 | 267 | assert_template 'calendar' |
|
214 | 268 | assert_not_nil assigns(:calendar) |
|
215 | 269 | end |
|
216 | 270 | |
|
217 | 271 | def test_changes |
|
218 | 272 | get :changes, :project_id => 1 |
|
219 | 273 | assert_response :success |
|
220 | 274 | assert_not_nil assigns(:journals) |
|
221 | 275 | assert_equal 'application/atom+xml', @response.content_type |
|
222 | 276 | end |
|
223 | 277 | |
|
278 | def test_show_routing | |
|
279 | assert_routing( | |
|
280 | {:method => :get, :path => '/issues/64'}, | |
|
281 | :controller => 'issues', :action => 'show', :id => '64' | |
|
282 | ) | |
|
283 | end | |
|
284 | ||
|
285 | def test_show_routing_formatted | |
|
286 | assert_routing( | |
|
287 | {:method => :get, :path => '/issues/2332.pdf'}, | |
|
288 | :controller => 'issues', :action => 'show', :id => '2332', :format => 'pdf' | |
|
289 | ) | |
|
290 | assert_routing( | |
|
291 | {:method => :get, :path => '/issues/23123.atom'}, | |
|
292 | :controller => 'issues', :action => 'show', :id => '23123', :format => 'atom' | |
|
293 | ) | |
|
294 | end | |
|
295 | ||
|
224 | 296 | def test_show_by_anonymous |
|
225 | 297 | get :show, :id => 1 |
|
226 | 298 | assert_response :success |
|
227 | 299 | assert_template 'show.rhtml' |
|
228 | 300 | assert_not_nil assigns(:issue) |
|
229 | 301 | assert_equal Issue.find(1), assigns(:issue) |
|
230 | 302 | |
|
231 | 303 | # anonymous role is allowed to add a note |
|
232 | 304 | assert_tag :tag => 'form', |
|
233 | 305 | :descendant => { :tag => 'fieldset', |
|
234 | 306 | :child => { :tag => 'legend', |
|
235 | 307 | :content => /Notes/ } } |
|
236 | 308 | end |
|
237 | 309 | |
|
238 | 310 | def test_show_by_manager |
|
239 | 311 | @request.session[:user_id] = 2 |
|
240 | 312 | get :show, :id => 1 |
|
241 | 313 | assert_response :success |
|
242 | 314 | |
|
243 | 315 | assert_tag :tag => 'form', |
|
244 | 316 | :descendant => { :tag => 'fieldset', |
|
245 | 317 | :child => { :tag => 'legend', |
|
246 | 318 | :content => /Change properties/ } }, |
|
247 | 319 | :descendant => { :tag => 'fieldset', |
|
248 | 320 | :child => { :tag => 'legend', |
|
249 | 321 | :content => /Log time/ } }, |
|
250 | 322 | :descendant => { :tag => 'fieldset', |
|
251 | 323 | :child => { :tag => 'legend', |
|
252 | 324 | :content => /Notes/ } } |
|
253 | 325 | end |
|
254 | 326 | |
|
327 | def test_new_routing | |
|
328 | assert_routing( | |
|
329 | {:method => :get, :path => '/projects/1/issues/new'}, | |
|
330 | :controller => 'issues', :action => 'new', :project_id => '1' | |
|
331 | ) | |
|
332 | assert_recognizes( | |
|
333 | {:controller => 'issues', :action => 'new', :project_id => '1'}, | |
|
334 | {:method => :post, :path => '/projects/1/issues'} | |
|
335 | ) | |
|
336 | end | |
|
337 | ||
|
255 | 338 | def test_show_export_to_pdf |
|
256 | 339 | get :show, :id => 3, :format => 'pdf' |
|
257 | 340 | assert_response :success |
|
258 | 341 | assert_equal 'application/pdf', @response.content_type |
|
259 | 342 | assert @response.body.starts_with?('%PDF') |
|
260 | 343 | assert_not_nil assigns(:issue) |
|
261 | 344 | end |
|
262 | 345 | |
|
263 | 346 | def test_get_new |
|
264 | 347 | @request.session[:user_id] = 2 |
|
265 | 348 | get :new, :project_id => 1, :tracker_id => 1 |
|
266 | 349 | assert_response :success |
|
267 | 350 | assert_template 'new' |
|
268 | 351 | |
|
269 | 352 | assert_tag :tag => 'input', :attributes => { :name => 'issue[custom_field_values][2]', |
|
270 | 353 | :value => 'Default string' } |
|
271 | 354 | end |
|
272 | 355 | |
|
273 | 356 | def test_get_new_without_tracker_id |
|
274 | 357 | @request.session[:user_id] = 2 |
|
275 | 358 | get :new, :project_id => 1 |
|
276 | 359 | assert_response :success |
|
277 | 360 | assert_template 'new' |
|
278 | 361 | |
|
279 | 362 | issue = assigns(:issue) |
|
280 | 363 | assert_not_nil issue |
|
281 | 364 | assert_equal Project.find(1).trackers.first, issue.tracker |
|
282 | 365 | end |
|
283 | 366 | |
|
284 | 367 | def test_update_new_form |
|
285 | 368 | @request.session[:user_id] = 2 |
|
286 | 369 | xhr :post, :new, :project_id => 1, |
|
287 | 370 | :issue => {:tracker_id => 2, |
|
288 | 371 | :subject => 'This is the test_new issue', |
|
289 | 372 | :description => 'This is the description', |
|
290 | 373 | :priority_id => 5} |
|
291 | 374 | assert_response :success |
|
292 | 375 | assert_template 'new' |
|
293 | 376 | end |
|
294 | 377 | |
|
295 | 378 | def test_post_new |
|
296 | 379 | @request.session[:user_id] = 2 |
|
297 | 380 | post :new, :project_id => 1, |
|
298 | 381 | :issue => {:tracker_id => 3, |
|
299 | 382 | :subject => 'This is the test_new issue', |
|
300 | 383 | :description => 'This is the description', |
|
301 | 384 | :priority_id => 5, |
|
302 | 385 | :estimated_hours => '', |
|
303 | 386 | :custom_field_values => {'2' => 'Value for field 2'}} |
|
304 |
assert_redirected_to |
|
|
387 | assert_redirected_to :action => 'show' | |
|
305 | 388 | |
|
306 | 389 | issue = Issue.find_by_subject('This is the test_new issue') |
|
307 | 390 | assert_not_nil issue |
|
308 | 391 | assert_equal 2, issue.author_id |
|
309 | 392 | assert_equal 3, issue.tracker_id |
|
310 | 393 | assert_nil issue.estimated_hours |
|
311 | 394 | v = issue.custom_values.find(:first, :conditions => {:custom_field_id => 2}) |
|
312 | 395 | assert_not_nil v |
|
313 | 396 | assert_equal 'Value for field 2', v.value |
|
314 | 397 | end |
|
315 | 398 | |
|
316 | 399 | def test_post_new_and_continue |
|
317 | 400 | @request.session[:user_id] = 2 |
|
318 | 401 | post :new, :project_id => 1, |
|
319 | 402 | :issue => {:tracker_id => 3, |
|
320 | 403 | :subject => 'This is first issue', |
|
321 | 404 | :priority_id => 5}, |
|
322 | 405 | :continue => '' |
|
323 | 406 | assert_redirected_to :controller => 'issues', :action => 'new', :tracker_id => 3 |
|
324 | 407 | end |
|
325 | 408 | |
|
326 | 409 | def test_post_new_without_custom_fields_param |
|
327 | 410 | @request.session[:user_id] = 2 |
|
328 | 411 | post :new, :project_id => 1, |
|
329 | 412 | :issue => {:tracker_id => 1, |
|
330 | 413 | :subject => 'This is the test_new issue', |
|
331 | 414 | :description => 'This is the description', |
|
332 | 415 | :priority_id => 5} |
|
333 |
assert_redirected_to |
|
|
416 | assert_redirected_to :action => 'show' | |
|
334 | 417 | end |
|
335 | 418 | |
|
336 | 419 | def test_post_new_with_required_custom_field_and_without_custom_fields_param |
|
337 | 420 | field = IssueCustomField.find_by_name('Database') |
|
338 | 421 | field.update_attribute(:is_required, true) |
|
339 | 422 | |
|
340 | 423 | @request.session[:user_id] = 2 |
|
341 | 424 | post :new, :project_id => 1, |
|
342 | 425 | :issue => {:tracker_id => 1, |
|
343 | 426 | :subject => 'This is the test_new issue', |
|
344 | 427 | :description => 'This is the description', |
|
345 | 428 | :priority_id => 5} |
|
346 | 429 | assert_response :success |
|
347 | 430 | assert_template 'new' |
|
348 | 431 | issue = assigns(:issue) |
|
349 | 432 | assert_not_nil issue |
|
350 | 433 | assert_equal 'activerecord_error_invalid', issue.errors.on(:custom_values) |
|
351 | 434 | end |
|
352 | 435 | |
|
353 | 436 | def test_post_new_with_watchers |
|
354 | 437 | @request.session[:user_id] = 2 |
|
355 | 438 | ActionMailer::Base.deliveries.clear |
|
356 | 439 | |
|
357 | 440 | assert_difference 'Watcher.count', 2 do |
|
358 | 441 | post :new, :project_id => 1, |
|
359 | 442 | :issue => {:tracker_id => 1, |
|
360 | 443 | :subject => 'This is a new issue with watchers', |
|
361 | 444 | :description => 'This is the description', |
|
362 | 445 | :priority_id => 5, |
|
363 | 446 | :watcher_user_ids => ['2', '3']} |
|
364 | 447 | end |
|
365 | 448 | issue = Issue.find_by_subject('This is a new issue with watchers') |
|
366 | 449 | assert_not_nil issue |
|
367 | 450 | assert_redirected_to :controller => 'issues', :action => 'show', :id => issue |
|
368 | 451 | |
|
369 | 452 | # Watchers added |
|
370 | 453 | assert_equal [2, 3], issue.watcher_user_ids.sort |
|
371 | 454 | assert issue.watched_by?(User.find(3)) |
|
372 | 455 | # Watchers notified |
|
373 | 456 | mail = ActionMailer::Base.deliveries.last |
|
374 | 457 | assert_kind_of TMail::Mail, mail |
|
375 | 458 | assert [mail.bcc, mail.cc].flatten.include?(User.find(3).mail) |
|
376 | 459 | end |
|
377 | 460 | |
|
378 | 461 | def test_post_should_preserve_fields_values_on_validation_failure |
|
379 | 462 | @request.session[:user_id] = 2 |
|
380 | 463 | post :new, :project_id => 1, |
|
381 | 464 | :issue => {:tracker_id => 1, |
|
382 | 465 | # empty subject |
|
383 | 466 | :subject => '', |
|
384 | 467 | :description => 'This is a description', |
|
385 | 468 | :priority_id => 6, |
|
386 | 469 | :custom_field_values => {'1' => 'Oracle', '2' => 'Value for field 2'}} |
|
387 | 470 | assert_response :success |
|
388 | 471 | assert_template 'new' |
|
389 | 472 | |
|
390 | 473 | assert_tag :textarea, :attributes => { :name => 'issue[description]' }, |
|
391 | 474 | :content => 'This is a description' |
|
392 | 475 | assert_tag :select, :attributes => { :name => 'issue[priority_id]' }, |
|
393 | 476 | :child => { :tag => 'option', :attributes => { :selected => 'selected', |
|
394 | 477 | :value => '6' }, |
|
395 | 478 | :content => 'High' } |
|
396 | 479 | # Custom fields |
|
397 | 480 | assert_tag :select, :attributes => { :name => 'issue[custom_field_values][1]' }, |
|
398 | 481 | :child => { :tag => 'option', :attributes => { :selected => 'selected', |
|
399 | 482 | :value => 'Oracle' }, |
|
400 | 483 | :content => 'Oracle' } |
|
401 | 484 | assert_tag :input, :attributes => { :name => 'issue[custom_field_values][2]', |
|
402 | 485 | :value => 'Value for field 2'} |
|
403 | 486 | end |
|
404 | 487 | |
|
488 | def test_copy_routing | |
|
489 | assert_routing( | |
|
490 | {:method => :get, :path => '/projects/world_domination/issues/567/copy'}, | |
|
491 | :controller => 'issues', :action => 'new', :project_id => 'world_domination', :copy_from => '567' | |
|
492 | ) | |
|
493 | end | |
|
494 | ||
|
405 | 495 | def test_copy_issue |
|
406 | 496 | @request.session[:user_id] = 2 |
|
407 | 497 | get :new, :project_id => 1, :copy_from => 1 |
|
408 | 498 | assert_template 'new' |
|
409 | 499 | assert_not_nil assigns(:issue) |
|
410 | 500 | orig = Issue.find(1) |
|
411 | 501 | assert_equal orig.subject, assigns(:issue).subject |
|
412 | 502 | end |
|
413 | 503 | |
|
504 | def test_edit_routing | |
|
505 | assert_routing( | |
|
506 | {:method => :get, :path => '/issues/1/edit'}, | |
|
507 | :controller => 'issues', :action => 'edit', :id => '1' | |
|
508 | ) | |
|
509 | assert_recognizes( #TODO: use a PUT on the issue URI isntead, need to adjust form | |
|
510 | {:controller => 'issues', :action => 'edit', :id => '1'}, | |
|
511 | {:method => :post, :path => '/issues/1/edit'} | |
|
512 | ) | |
|
513 | end | |
|
514 | ||
|
414 | 515 | def test_get_edit |
|
415 | 516 | @request.session[:user_id] = 2 |
|
416 | 517 | get :edit, :id => 1 |
|
417 | 518 | assert_response :success |
|
418 | 519 | assert_template 'edit' |
|
419 | 520 | assert_not_nil assigns(:issue) |
|
420 | 521 | assert_equal Issue.find(1), assigns(:issue) |
|
421 | 522 | end |
|
422 | 523 | |
|
423 | 524 | def test_get_edit_with_params |
|
424 | 525 | @request.session[:user_id] = 2 |
|
425 | 526 | get :edit, :id => 1, :issue => { :status_id => 5, :priority_id => 7 } |
|
426 | 527 | assert_response :success |
|
427 | 528 | assert_template 'edit' |
|
428 | 529 | |
|
429 | 530 | issue = assigns(:issue) |
|
430 | 531 | assert_not_nil issue |
|
431 | 532 | |
|
432 | 533 | assert_equal 5, issue.status_id |
|
433 | 534 | assert_tag :select, :attributes => { :name => 'issue[status_id]' }, |
|
434 | 535 | :child => { :tag => 'option', |
|
435 | 536 | :content => 'Closed', |
|
436 | 537 | :attributes => { :selected => 'selected' } } |
|
437 | 538 | |
|
438 | 539 | assert_equal 7, issue.priority_id |
|
439 | 540 | assert_tag :select, :attributes => { :name => 'issue[priority_id]' }, |
|
440 | 541 | :child => { :tag => 'option', |
|
441 | 542 | :content => 'Urgent', |
|
442 | 543 | :attributes => { :selected => 'selected' } } |
|
443 | 544 | end |
|
444 | 545 | |
|
546 | def test_reply_routing | |
|
547 | assert_routing( | |
|
548 | {:method => :post, :path => '/issues/1/quoted'}, | |
|
549 | :controller => 'issues', :action => 'reply', :id => '1' | |
|
550 | ) | |
|
551 | end | |
|
552 | ||
|
445 | 553 | def test_reply_to_issue |
|
446 | 554 | @request.session[:user_id] = 2 |
|
447 | 555 | get :reply, :id => 1 |
|
448 | 556 | assert_response :success |
|
449 | 557 | assert_select_rjs :show, "update" |
|
450 | 558 | end |
|
451 | 559 | |
|
452 | 560 | def test_reply_to_note |
|
453 | 561 | @request.session[:user_id] = 2 |
|
454 | 562 | get :reply, :id => 1, :journal_id => 2 |
|
455 | 563 | assert_response :success |
|
456 | 564 | assert_select_rjs :show, "update" |
|
457 | 565 | end |
|
458 | 566 | |
|
459 | 567 | def test_post_edit_without_custom_fields_param |
|
460 | 568 | @request.session[:user_id] = 2 |
|
461 | 569 | ActionMailer::Base.deliveries.clear |
|
462 | 570 | |
|
463 | 571 | issue = Issue.find(1) |
|
464 | 572 | assert_equal '125', issue.custom_value_for(2).value |
|
465 | 573 | old_subject = issue.subject |
|
466 | 574 | new_subject = 'Subject modified by IssuesControllerTest#test_post_edit' |
|
467 | 575 | |
|
468 | 576 | assert_difference('Journal.count') do |
|
469 | 577 | assert_difference('JournalDetail.count', 2) do |
|
470 | 578 | post :edit, :id => 1, :issue => {:subject => new_subject, |
|
471 | 579 | :priority_id => '6', |
|
472 | 580 | :category_id => '1' # no change |
|
473 | 581 | } |
|
474 | 582 | end |
|
475 | 583 | end |
|
476 |
assert_redirected_to |
|
|
584 | assert_redirected_to :action => 'show', :id => '1' | |
|
477 | 585 | issue.reload |
|
478 | 586 | assert_equal new_subject, issue.subject |
|
479 | 587 | # Make sure custom fields were not cleared |
|
480 | 588 | assert_equal '125', issue.custom_value_for(2).value |
|
481 | 589 | |
|
482 | 590 | mail = ActionMailer::Base.deliveries.last |
|
483 | 591 | assert_kind_of TMail::Mail, mail |
|
484 | 592 | assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]") |
|
485 | 593 | assert mail.body.include?("Subject changed from #{old_subject} to #{new_subject}") |
|
486 | 594 | end |
|
487 | 595 | |
|
488 | 596 | def test_post_edit_with_custom_field_change |
|
489 | 597 | @request.session[:user_id] = 2 |
|
490 | 598 | issue = Issue.find(1) |
|
491 | 599 | assert_equal '125', issue.custom_value_for(2).value |
|
492 | 600 | |
|
493 | 601 | assert_difference('Journal.count') do |
|
494 | 602 | assert_difference('JournalDetail.count', 3) do |
|
495 | 603 | post :edit, :id => 1, :issue => {:subject => 'Custom field change', |
|
496 | 604 | :priority_id => '6', |
|
497 | 605 | :category_id => '1', # no change |
|
498 | 606 | :custom_field_values => { '2' => 'New custom value' } |
|
499 | 607 | } |
|
500 | 608 | end |
|
501 | 609 | end |
|
502 |
assert_redirected_to |
|
|
610 | assert_redirected_to :action => 'show', :id => '1' | |
|
503 | 611 | issue.reload |
|
504 | 612 | assert_equal 'New custom value', issue.custom_value_for(2).value |
|
505 | 613 | |
|
506 | 614 | mail = ActionMailer::Base.deliveries.last |
|
507 | 615 | assert_kind_of TMail::Mail, mail |
|
508 | 616 | assert mail.body.include?("Searchable field changed from 125 to New custom value") |
|
509 | 617 | end |
|
510 | 618 | |
|
511 | 619 | def test_post_edit_with_status_and_assignee_change |
|
512 | 620 | issue = Issue.find(1) |
|
513 | 621 | assert_equal 1, issue.status_id |
|
514 | 622 | @request.session[:user_id] = 2 |
|
515 | 623 | assert_difference('TimeEntry.count', 0) do |
|
516 | 624 | post :edit, |
|
517 | 625 | :id => 1, |
|
518 | 626 | :issue => { :status_id => 2, :assigned_to_id => 3 }, |
|
519 | 627 | :notes => 'Assigned to dlopper', |
|
520 | 628 | :time_entry => { :hours => '', :comments => '', :activity_id => Enumeration.get_values('ACTI').first } |
|
521 | 629 | end |
|
522 |
assert_redirected_to |
|
|
630 | assert_redirected_to :action => 'show', :id => '1' | |
|
523 | 631 | issue.reload |
|
524 | 632 | assert_equal 2, issue.status_id |
|
525 | 633 | j = issue.journals.find(:first, :order => 'id DESC') |
|
526 | 634 | assert_equal 'Assigned to dlopper', j.notes |
|
527 | 635 | assert_equal 2, j.details.size |
|
528 | 636 | |
|
529 | 637 | mail = ActionMailer::Base.deliveries.last |
|
530 | 638 | assert mail.body.include?("Status changed from New to Assigned") |
|
531 | 639 | end |
|
532 | 640 | |
|
533 | 641 | def test_post_edit_with_note_only |
|
534 | 642 | notes = 'Note added by IssuesControllerTest#test_update_with_note_only' |
|
535 | 643 | # anonymous user |
|
536 | 644 | post :edit, |
|
537 | 645 | :id => 1, |
|
538 | 646 | :notes => notes |
|
539 |
assert_redirected_to |
|
|
647 | assert_redirected_to :action => 'show', :id => '1' | |
|
540 | 648 | j = Issue.find(1).journals.find(:first, :order => 'id DESC') |
|
541 | 649 | assert_equal notes, j.notes |
|
542 | 650 | assert_equal 0, j.details.size |
|
543 | 651 | assert_equal User.anonymous, j.user |
|
544 | 652 | |
|
545 | 653 | mail = ActionMailer::Base.deliveries.last |
|
546 | 654 | assert mail.body.include?(notes) |
|
547 | 655 | end |
|
548 | 656 | |
|
549 | 657 | def test_post_edit_with_note_and_spent_time |
|
550 | 658 | @request.session[:user_id] = 2 |
|
551 | 659 | spent_hours_before = Issue.find(1).spent_hours |
|
552 | 660 | assert_difference('TimeEntry.count') do |
|
553 | 661 | post :edit, |
|
554 | 662 | :id => 1, |
|
555 | 663 | :notes => '2.5 hours added', |
|
556 | 664 | :time_entry => { :hours => '2.5', :comments => '', :activity_id => Enumeration.get_values('ACTI').first } |
|
557 | 665 | end |
|
558 |
assert_redirected_to |
|
|
666 | assert_redirected_to :action => 'show', :id => '1' | |
|
559 | 667 | |
|
560 | 668 | issue = Issue.find(1) |
|
561 | 669 | |
|
562 | 670 | j = issue.journals.find(:first, :order => 'id DESC') |
|
563 | 671 | assert_equal '2.5 hours added', j.notes |
|
564 | 672 | assert_equal 0, j.details.size |
|
565 | 673 | |
|
566 | 674 | t = issue.time_entries.find(:first, :order => 'id DESC') |
|
567 | 675 | assert_not_nil t |
|
568 | 676 | assert_equal 2.5, t.hours |
|
569 | 677 | assert_equal spent_hours_before + 2.5, issue.spent_hours |
|
570 | 678 | end |
|
571 | 679 | |
|
572 | 680 | def test_post_edit_with_attachment_only |
|
573 | 681 | set_tmp_attachments_directory |
|
574 | 682 | |
|
575 | 683 | # Delete all fixtured journals, a race condition can occur causing the wrong |
|
576 | 684 | # journal to get fetched in the next find. |
|
577 | 685 | Journal.delete_all |
|
578 | 686 | |
|
579 | 687 | # anonymous user |
|
580 | 688 | post :edit, |
|
581 | 689 | :id => 1, |
|
582 | 690 | :notes => '', |
|
583 | 691 | :attachments => {'1' => {'file' => test_uploaded_file('testfile.txt', 'text/plain')}} |
|
584 |
assert_redirected_to |
|
|
692 | assert_redirected_to :action => 'show', :id => '1' | |
|
585 | 693 | j = Issue.find(1).journals.find(:first, :order => 'id DESC') |
|
586 | 694 | assert j.notes.blank? |
|
587 | 695 | assert_equal 1, j.details.size |
|
588 | 696 | assert_equal 'testfile.txt', j.details.first.value |
|
589 | 697 | assert_equal User.anonymous, j.user |
|
590 | 698 | |
|
591 | 699 | mail = ActionMailer::Base.deliveries.last |
|
592 | 700 | assert mail.body.include?('testfile.txt') |
|
593 | 701 | end |
|
594 | 702 | |
|
595 | 703 | def test_post_edit_with_no_change |
|
596 | 704 | issue = Issue.find(1) |
|
597 | 705 | issue.journals.clear |
|
598 | 706 | ActionMailer::Base.deliveries.clear |
|
599 | 707 | |
|
600 | 708 | post :edit, |
|
601 | 709 | :id => 1, |
|
602 | 710 | :notes => '' |
|
603 |
assert_redirected_to |
|
|
711 | assert_redirected_to :action => 'show', :id => '1' | |
|
604 | 712 | |
|
605 | 713 | issue.reload |
|
606 | 714 | assert issue.journals.empty? |
|
607 | 715 | # No email should be sent |
|
608 | 716 | assert ActionMailer::Base.deliveries.empty? |
|
609 | 717 | end |
|
610 | 718 | |
|
611 | 719 | def test_post_edit_with_invalid_spent_time |
|
612 | 720 | @request.session[:user_id] = 2 |
|
613 | 721 | notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time' |
|
614 | 722 | |
|
615 | 723 | assert_no_difference('Journal.count') do |
|
616 | 724 | post :edit, |
|
617 | 725 | :id => 1, |
|
618 | 726 | :notes => notes, |
|
619 | 727 | :time_entry => {"comments"=>"", "activity_id"=>"", "hours"=>"2z"} |
|
620 | 728 | end |
|
621 | 729 | assert_response :success |
|
622 | 730 | assert_template 'edit' |
|
623 | 731 | |
|
624 | 732 | assert_tag :textarea, :attributes => { :name => 'notes' }, |
|
625 | 733 | :content => notes |
|
626 | 734 | assert_tag :input, :attributes => { :name => 'time_entry[hours]', :value => "2z" } |
|
627 | 735 | end |
|
628 | 736 | |
|
629 | 737 | def test_bulk_edit |
|
630 | 738 | @request.session[:user_id] = 2 |
|
631 | 739 | # update issues priority |
|
632 | 740 | post :bulk_edit, :ids => [1, 2], :priority_id => 7, |
|
633 | 741 | :assigned_to_id => '', |
|
634 | 742 | :custom_field_values => {'2' => ''}, |
|
635 | 743 | :notes => 'Bulk editing' |
|
636 | 744 | assert_response 302 |
|
637 | 745 | # check that the issues were updated |
|
638 | 746 | assert_equal [7, 7], Issue.find_all_by_id([1, 2]).collect {|i| i.priority.id} |
|
639 | 747 | |
|
640 | 748 | issue = Issue.find(1) |
|
641 | 749 | journal = issue.journals.find(:first, :order => 'created_on DESC') |
|
642 | 750 | assert_equal '125', issue.custom_value_for(2).value |
|
643 | 751 | assert_equal 'Bulk editing', journal.notes |
|
644 | 752 | assert_equal 1, journal.details.size |
|
645 | 753 | end |
|
646 | 754 | |
|
647 | 755 | def test_bulk_edit_custom_field |
|
648 | 756 | @request.session[:user_id] = 2 |
|
649 | 757 | # update issues priority |
|
650 | 758 | post :bulk_edit, :ids => [1, 2], :priority_id => '', |
|
651 | 759 | :assigned_to_id => '', |
|
652 | 760 | :custom_field_values => {'2' => '777'}, |
|
653 | 761 | :notes => 'Bulk editing custom field' |
|
654 | 762 | assert_response 302 |
|
655 | 763 | |
|
656 | 764 | issue = Issue.find(1) |
|
657 | 765 | journal = issue.journals.find(:first, :order => 'created_on DESC') |
|
658 | 766 | assert_equal '777', issue.custom_value_for(2).value |
|
659 | 767 | assert_equal 1, journal.details.size |
|
660 | 768 | assert_equal '125', journal.details.first.old_value |
|
661 | 769 | assert_equal '777', journal.details.first.value |
|
662 | 770 | end |
|
663 | 771 | |
|
664 | 772 | def test_bulk_unassign |
|
665 | 773 | assert_not_nil Issue.find(2).assigned_to |
|
666 | 774 | @request.session[:user_id] = 2 |
|
667 | 775 | # unassign issues |
|
668 | 776 | post :bulk_edit, :ids => [1, 2], :notes => 'Bulk unassigning', :assigned_to_id => 'none' |
|
669 | 777 | assert_response 302 |
|
670 | 778 | # check that the issues were updated |
|
671 | 779 | assert_nil Issue.find(2).assigned_to |
|
672 | 780 | end |
|
673 | 781 | |
|
782 | def test_move_routing | |
|
783 | assert_routing( | |
|
784 | {:method => :get, :path => '/issues/1/move'}, | |
|
785 | :controller => 'issues', :action => 'move', :id => '1' | |
|
786 | ) | |
|
787 | assert_recognizes( | |
|
788 | {:controller => 'issues', :action => 'move', :id => '1'}, | |
|
789 | {:method => :post, :path => '/issues/1/move'} | |
|
790 | ) | |
|
791 | end | |
|
792 | ||
|
674 | 793 | def test_move_one_issue_to_another_project |
|
675 | 794 | @request.session[:user_id] = 1 |
|
676 | 795 | post :move, :id => 1, :new_project_id => 2 |
|
677 |
assert_redirected_to 'project |
|
|
796 | assert_redirected_to :action => 'index', :project_id => 'ecookbook' | |
|
678 | 797 | assert_equal 2, Issue.find(1).project_id |
|
679 | 798 | end |
|
680 | 799 | |
|
681 | 800 | def test_bulk_move_to_another_project |
|
682 | 801 | @request.session[:user_id] = 1 |
|
683 | 802 | post :move, :ids => [1, 2], :new_project_id => 2 |
|
684 |
assert_redirected_to 'project |
|
|
803 | assert_redirected_to :action => 'index', :project_id => 'ecookbook' | |
|
685 | 804 | # Issues moved to project 2 |
|
686 | 805 | assert_equal 2, Issue.find(1).project_id |
|
687 | 806 | assert_equal 2, Issue.find(2).project_id |
|
688 | 807 | # No tracker change |
|
689 | 808 | assert_equal 1, Issue.find(1).tracker_id |
|
690 | 809 | assert_equal 2, Issue.find(2).tracker_id |
|
691 | 810 | end |
|
692 | 811 | |
|
693 | 812 | def test_bulk_move_to_another_tracker |
|
694 | 813 | @request.session[:user_id] = 1 |
|
695 | 814 | post :move, :ids => [1, 2], :new_tracker_id => 2 |
|
696 |
assert_redirected_to 'project |
|
|
815 | assert_redirected_to :action => 'index', :project_id => 'ecookbook' | |
|
697 | 816 | assert_equal 2, Issue.find(1).tracker_id |
|
698 | 817 | assert_equal 2, Issue.find(2).tracker_id |
|
699 | 818 | end |
|
700 | 819 | |
|
701 | 820 | def test_bulk_copy_to_another_project |
|
702 | 821 | @request.session[:user_id] = 1 |
|
703 | 822 | assert_difference 'Issue.count', 2 do |
|
704 | 823 | assert_no_difference 'Project.find(1).issues.count' do |
|
705 | 824 | post :move, :ids => [1, 2], :new_project_id => 2, :copy_options => {:copy => '1'} |
|
706 | 825 | end |
|
707 | 826 | end |
|
708 | 827 | assert_redirected_to 'projects/ecookbook/issues' |
|
709 | 828 | end |
|
710 | 829 | |
|
711 | 830 | def test_context_menu_one_issue |
|
712 | 831 | @request.session[:user_id] = 2 |
|
713 | 832 | get :context_menu, :ids => [1] |
|
714 | 833 | assert_response :success |
|
715 | 834 | assert_template 'context_menu' |
|
716 | 835 | assert_tag :tag => 'a', :content => 'Edit', |
|
717 |
:attributes => { :href => '/issues/edit |
|
|
836 | :attributes => { :href => '/issues/1/edit', | |
|
718 | 837 | :class => 'icon-edit' } |
|
719 | 838 | assert_tag :tag => 'a', :content => 'Closed', |
|
720 |
:attributes => { :href => '/issues/edit |
|
|
839 | :attributes => { :href => '/issues/1/edit?issue%5Bstatus_id%5D=5', | |
|
721 | 840 | :class => '' } |
|
722 | 841 | assert_tag :tag => 'a', :content => 'Immediate', |
|
723 | 842 | :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&priority_id=8', |
|
724 | 843 | :class => '' } |
|
725 | 844 | assert_tag :tag => 'a', :content => 'Dave Lopper', |
|
726 | 845 | :attributes => { :href => '/issues/bulk_edit?assigned_to_id=3&ids%5B%5D=1', |
|
727 | 846 | :class => '' } |
|
728 | 847 | assert_tag :tag => 'a', :content => 'Copy', |
|
729 |
:attributes => { :href => '/projects/ecookbook/issues/ |
|
|
848 | :attributes => { :href => '/projects/ecookbook/issues/1/copy', | |
|
730 | 849 | :class => 'icon-copy' } |
|
731 | 850 | assert_tag :tag => 'a', :content => 'Move', |
|
732 | 851 | :attributes => { :href => '/issues/move?ids%5B%5D=1', |
|
733 | 852 | :class => 'icon-move' } |
|
734 | 853 | assert_tag :tag => 'a', :content => 'Delete', |
|
735 | 854 | :attributes => { :href => '/issues/destroy?ids%5B%5D=1', |
|
736 | 855 | :class => 'icon-del' } |
|
737 | 856 | end |
|
738 | 857 | |
|
739 | 858 | def test_context_menu_one_issue_by_anonymous |
|
740 | 859 | get :context_menu, :ids => [1] |
|
741 | 860 | assert_response :success |
|
742 | 861 | assert_template 'context_menu' |
|
743 | 862 | assert_tag :tag => 'a', :content => 'Delete', |
|
744 | 863 | :attributes => { :href => '#', |
|
745 | 864 | :class => 'icon-del disabled' } |
|
746 | 865 | end |
|
747 | 866 | |
|
748 | 867 | def test_context_menu_multiple_issues_of_same_project |
|
749 | 868 | @request.session[:user_id] = 2 |
|
750 | 869 | get :context_menu, :ids => [1, 2] |
|
751 | 870 | assert_response :success |
|
752 | 871 | assert_template 'context_menu' |
|
753 | 872 | assert_tag :tag => 'a', :content => 'Edit', |
|
754 | 873 | :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&ids%5B%5D=2', |
|
755 | 874 | :class => 'icon-edit' } |
|
756 | 875 | assert_tag :tag => 'a', :content => 'Immediate', |
|
757 | 876 | :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&ids%5B%5D=2&priority_id=8', |
|
758 | 877 | :class => '' } |
|
759 | 878 | assert_tag :tag => 'a', :content => 'Dave Lopper', |
|
760 | 879 | :attributes => { :href => '/issues/bulk_edit?assigned_to_id=3&ids%5B%5D=1&ids%5B%5D=2', |
|
761 | 880 | :class => '' } |
|
762 | 881 | assert_tag :tag => 'a', :content => 'Move', |
|
763 | 882 | :attributes => { :href => '/issues/move?ids%5B%5D=1&ids%5B%5D=2', |
|
764 | 883 | :class => 'icon-move' } |
|
765 | 884 | assert_tag :tag => 'a', :content => 'Delete', |
|
766 | 885 | :attributes => { :href => '/issues/destroy?ids%5B%5D=1&ids%5B%5D=2', |
|
767 | 886 | :class => 'icon-del' } |
|
768 | 887 | end |
|
769 | 888 | |
|
770 | 889 | def test_context_menu_multiple_issues_of_different_project |
|
771 | 890 | @request.session[:user_id] = 2 |
|
772 | 891 | get :context_menu, :ids => [1, 2, 4] |
|
773 | 892 | assert_response :success |
|
774 | 893 | assert_template 'context_menu' |
|
775 | 894 | assert_tag :tag => 'a', :content => 'Delete', |
|
776 | 895 | :attributes => { :href => '#', |
|
777 | 896 | :class => 'icon-del disabled' } |
|
778 | 897 | end |
|
779 | 898 | |
|
899 | def test_destroy_routing | |
|
900 | assert_recognizes( #TODO: use DELETE on issue URI (need to change forms) | |
|
901 | {:controller => 'issues', :action => 'destroy', :id => '1'}, | |
|
902 | {:method => :post, :path => '/issues/1/destroy'} | |
|
903 | ) | |
|
904 | end | |
|
905 | ||
|
780 | 906 | def test_destroy_issue_with_no_time_entries |
|
781 | 907 | assert_nil TimeEntry.find_by_issue_id(2) |
|
782 | 908 | @request.session[:user_id] = 2 |
|
783 | 909 | post :destroy, :id => 2 |
|
784 |
assert_redirected_to 'project |
|
|
910 | assert_redirected_to :action => 'index', :project_id => 'ecookbook' | |
|
785 | 911 | assert_nil Issue.find_by_id(2) |
|
786 | 912 | end |
|
787 | 913 | |
|
788 | 914 | def test_destroy_issues_with_time_entries |
|
789 | 915 | @request.session[:user_id] = 2 |
|
790 | 916 | post :destroy, :ids => [1, 3] |
|
791 | 917 | assert_response :success |
|
792 | 918 | assert_template 'destroy' |
|
793 | 919 | assert_not_nil assigns(:hours) |
|
794 | 920 | assert Issue.find_by_id(1) && Issue.find_by_id(3) |
|
795 | 921 | end |
|
796 | 922 | |
|
797 | 923 | def test_destroy_issues_and_destroy_time_entries |
|
798 | 924 | @request.session[:user_id] = 2 |
|
799 | 925 | post :destroy, :ids => [1, 3], :todo => 'destroy' |
|
800 |
assert_redirected_to 'project |
|
|
926 | assert_redirected_to :action => 'index', :project_id => 'ecookbook' | |
|
801 | 927 | assert !(Issue.find_by_id(1) || Issue.find_by_id(3)) |
|
802 | 928 | assert_nil TimeEntry.find_by_id([1, 2]) |
|
803 | 929 | end |
|
804 | 930 | |
|
805 | 931 | def test_destroy_issues_and_assign_time_entries_to_project |
|
806 | 932 | @request.session[:user_id] = 2 |
|
807 | 933 | post :destroy, :ids => [1, 3], :todo => 'nullify' |
|
808 |
assert_redirected_to 'project |
|
|
934 | assert_redirected_to :action => 'index', :project_id => 'ecookbook' | |
|
809 | 935 | assert !(Issue.find_by_id(1) || Issue.find_by_id(3)) |
|
810 | 936 | assert_nil TimeEntry.find(1).issue_id |
|
811 | 937 | assert_nil TimeEntry.find(2).issue_id |
|
812 | 938 | end |
|
813 | 939 | |
|
814 | 940 | def test_destroy_issues_and_reassign_time_entries_to_another_issue |
|
815 | 941 | @request.session[:user_id] = 2 |
|
816 | 942 | post :destroy, :ids => [1, 3], :todo => 'reassign', :reassign_to_id => 2 |
|
817 |
assert_redirected_to 'project |
|
|
943 | assert_redirected_to :action => 'index', :project_id => 'ecookbook' | |
|
818 | 944 | assert !(Issue.find_by_id(1) || Issue.find_by_id(3)) |
|
819 | 945 | assert_equal 2, TimeEntry.find(1).issue_id |
|
820 | 946 | assert_equal 2, TimeEntry.find(2).issue_id |
|
821 | 947 | end |
|
822 | 948 | end |
@@ -1,127 +1,170 | |||
|
1 | 1 | # redMine - project management software |
|
2 | 2 | # Copyright (C) 2006-2007 Jean-Philippe Lang |
|
3 | 3 | # |
|
4 | 4 | # This program is free software; you can redistribute it and/or |
|
5 | 5 | # modify it under the terms of the GNU General Public License |
|
6 | 6 | # as published by the Free Software Foundation; either version 2 |
|
7 | 7 | # of the License, or (at your option) any later version. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU General Public License |
|
15 | 15 | # along with this program; if not, write to the Free Software |
|
16 | 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 | 17 | |
|
18 | 18 | require File.dirname(__FILE__) + '/../test_helper' |
|
19 | 19 | require 'messages_controller' |
|
20 | 20 | |
|
21 | 21 | # Re-raise errors caught by the controller. |
|
22 | 22 | class MessagesController; def rescue_action(e) raise e end; end |
|
23 | 23 | |
|
24 | 24 | class MessagesControllerTest < Test::Unit::TestCase |
|
25 | 25 | fixtures :projects, :users, :members, :roles, :boards, :messages, :enabled_modules |
|
26 | 26 | |
|
27 | 27 | def setup |
|
28 | 28 | @controller = MessagesController.new |
|
29 | 29 | @request = ActionController::TestRequest.new |
|
30 | 30 | @response = ActionController::TestResponse.new |
|
31 | 31 | User.current = nil |
|
32 | 32 | end |
|
33 | 33 | |
|
34 | def test_show_routing | |
|
35 | assert_routing( | |
|
36 | {:method => :get, :path => '/boards/22/topics/2'}, | |
|
37 | :controller => 'messages', :action => 'show', :id => '2', :board_id => '22' | |
|
38 | ) | |
|
39 | end | |
|
40 | ||
|
34 | 41 | def test_show |
|
35 | 42 | get :show, :board_id => 1, :id => 1 |
|
36 | 43 | assert_response :success |
|
37 | 44 | assert_template 'show' |
|
38 | 45 | assert_not_nil assigns(:board) |
|
39 | 46 | assert_not_nil assigns(:project) |
|
40 | 47 | assert_not_nil assigns(:topic) |
|
41 | 48 | end |
|
42 | 49 | |
|
43 | 50 | def test_show_with_reply_permission |
|
44 | 51 | @request.session[:user_id] = 2 |
|
45 | 52 | get :show, :board_id => 1, :id => 1 |
|
46 | 53 | assert_response :success |
|
47 | 54 | assert_template 'show' |
|
48 | 55 | assert_tag :div, :attributes => { :id => 'reply' }, |
|
49 | 56 | :descendant => { :tag => 'textarea', :attributes => { :id => 'message_content' } } |
|
50 | 57 | end |
|
51 | 58 | |
|
52 | 59 | def test_show_message_not_found |
|
53 | 60 | get :show, :board_id => 1, :id => 99999 |
|
54 | 61 | assert_response 404 |
|
55 | 62 | end |
|
56 | 63 | |
|
64 | def test_new_routing | |
|
65 | assert_routing( | |
|
66 | {:method => :get, :path => '/boards/lala/topics/new'}, | |
|
67 | :controller => 'messages', :action => 'new', :board_id => 'lala' | |
|
68 | ) | |
|
69 | assert_recognizes(#TODO: POST to collection, need to adjust form accordingly | |
|
70 | {:controller => 'messages', :action => 'new', :board_id => 'lala'}, | |
|
71 | {:method => :post, :path => '/boards/lala/topics/new'} | |
|
72 | ) | |
|
73 | end | |
|
74 | ||
|
57 | 75 | def test_get_new |
|
58 | 76 | @request.session[:user_id] = 2 |
|
59 | 77 | get :new, :board_id => 1 |
|
60 | 78 | assert_response :success |
|
61 | 79 | assert_template 'new' |
|
62 | 80 | end |
|
63 | 81 | |
|
64 | 82 | def test_post_new |
|
65 | 83 | @request.session[:user_id] = 2 |
|
66 | 84 | ActionMailer::Base.deliveries.clear |
|
67 | 85 | Setting.notified_events = ['message_posted'] |
|
68 | 86 | |
|
69 | 87 | post :new, :board_id => 1, |
|
70 | 88 | :message => { :subject => 'Test created message', |
|
71 | 89 | :content => 'Message body'} |
|
72 | 90 | assert_redirected_to 'messages/show' |
|
73 | 91 | message = Message.find_by_subject('Test created message') |
|
74 | 92 | assert_not_nil message |
|
75 | 93 | assert_equal 'Message body', message.content |
|
76 | 94 | assert_equal 2, message.author_id |
|
77 | 95 | assert_equal 1, message.board_id |
|
78 | 96 | |
|
79 | 97 | mail = ActionMailer::Base.deliveries.last |
|
80 | 98 | assert_kind_of TMail::Mail, mail |
|
81 | 99 | assert_equal "[#{message.board.project.name} - #{message.board.name} - msg#{message.root.id}] Test created message", mail.subject |
|
82 | 100 | assert mail.body.include?('Message body') |
|
83 | 101 | # author |
|
84 | 102 | assert mail.bcc.include?('jsmith@somenet.foo') |
|
85 | 103 | # project member |
|
86 | 104 | assert mail.bcc.include?('dlopper@somenet.foo') |
|
87 | 105 | end |
|
88 | 106 | |
|
107 | def test_edit_routing | |
|
108 | assert_routing( | |
|
109 | {:method => :get, :path => '/boards/lala/topics/22/edit'}, | |
|
110 | :controller => 'messages', :action => 'edit', :board_id => 'lala', :id => '22' | |
|
111 | ) | |
|
112 | assert_recognizes( #TODO: use PUT to topic_path, modify form accordingly | |
|
113 | {:controller => 'messages', :action => 'edit', :board_id => 'lala', :id => '22'}, | |
|
114 | {:method => :post, :path => '/boards/lala/topics/22/edit'} | |
|
115 | ) | |
|
116 | end | |
|
117 | ||
|
89 | 118 | def test_get_edit |
|
90 | 119 | @request.session[:user_id] = 2 |
|
91 | 120 | get :edit, :board_id => 1, :id => 1 |
|
92 | 121 | assert_response :success |
|
93 | 122 | assert_template 'edit' |
|
94 | 123 | end |
|
95 | 124 | |
|
96 | 125 | def test_post_edit |
|
97 | 126 | @request.session[:user_id] = 2 |
|
98 | 127 | post :edit, :board_id => 1, :id => 1, |
|
99 | 128 | :message => { :subject => 'New subject', |
|
100 | 129 | :content => 'New body'} |
|
101 | 130 | assert_redirected_to 'messages/show' |
|
102 | 131 | message = Message.find(1) |
|
103 | 132 | assert_equal 'New subject', message.subject |
|
104 | 133 | assert_equal 'New body', message.content |
|
105 | 134 | end |
|
106 | 135 | |
|
136 | def test_reply_routing | |
|
137 | assert_recognizes( | |
|
138 | {:controller => 'messages', :action => 'reply', :board_id => '22', :id => '555'}, | |
|
139 | {:method => :post, :path => '/boards/22/topics/555/replies'} | |
|
140 | ) | |
|
141 | end | |
|
142 | ||
|
107 | 143 | def test_reply |
|
108 | 144 | @request.session[:user_id] = 2 |
|
109 | 145 | post :reply, :board_id => 1, :id => 1, :reply => { :content => 'This is a test reply', :subject => 'Test reply' } |
|
110 | 146 | assert_redirected_to 'messages/show' |
|
111 | 147 | assert Message.find_by_subject('Test reply') |
|
112 | 148 | end |
|
113 | 149 | |
|
150 | def test_destroy_routing | |
|
151 | assert_recognizes(#TODO: use DELETE to topic_path, adjust form accordingly | |
|
152 | {:controller => 'messages', :action => 'destroy', :board_id => '22', :id => '555'}, | |
|
153 | {:method => :post, :path => '/boards/22/topics/555/destroy'} | |
|
154 | ) | |
|
155 | end | |
|
156 | ||
|
114 | 157 | def test_destroy_topic |
|
115 | 158 | @request.session[:user_id] = 2 |
|
116 | 159 | post :destroy, :board_id => 1, :id => 1 |
|
117 | 160 | assert_redirected_to 'boards/show' |
|
118 | 161 | assert_nil Message.find_by_id(1) |
|
119 | 162 | end |
|
120 | 163 | |
|
121 | 164 | def test_quote |
|
122 | 165 | @request.session[:user_id] = 2 |
|
123 | 166 | xhr :get, :quote, :board_id => 1, :id => 3 |
|
124 | 167 | assert_response :success |
|
125 | 168 | assert_select_rjs :show, 'reply' |
|
126 | 169 | end |
|
127 | 170 | end |
@@ -1,147 +1,211 | |||
|
1 | 1 | # redMine - project management software |
|
2 | 2 | # Copyright (C) 2006-2007 Jean-Philippe Lang |
|
3 | 3 | # |
|
4 | 4 | # This program is free software; you can redistribute it and/or |
|
5 | 5 | # modify it under the terms of the GNU General Public License |
|
6 | 6 | # as published by the Free Software Foundation; either version 2 |
|
7 | 7 | # of the License, or (at your option) any later version. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU General Public License |
|
15 | 15 | # along with this program; if not, write to the Free Software |
|
16 | 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 | 17 | |
|
18 | 18 | require File.dirname(__FILE__) + '/../test_helper' |
|
19 | 19 | require 'news_controller' |
|
20 | 20 | |
|
21 | 21 | # Re-raise errors caught by the controller. |
|
22 | 22 | class NewsController; def rescue_action(e) raise e end; end |
|
23 | 23 | |
|
24 | 24 | class NewsControllerTest < Test::Unit::TestCase |
|
25 | 25 | fixtures :projects, :users, :roles, :members, :enabled_modules, :news, :comments |
|
26 | 26 | |
|
27 | 27 | def setup |
|
28 | 28 | @controller = NewsController.new |
|
29 | 29 | @request = ActionController::TestRequest.new |
|
30 | 30 | @response = ActionController::TestResponse.new |
|
31 | 31 | User.current = nil |
|
32 | 32 | end |
|
33 | 33 | |
|
34 | def test_index_routing | |
|
35 | assert_routing( | |
|
36 | {:method => :get, :path => '/news'}, | |
|
37 | :controller => 'news', :action => 'index' | |
|
38 | ) | |
|
39 | end | |
|
40 | ||
|
41 | def test_index_routing_formatted | |
|
42 | assert_routing( | |
|
43 | {:method => :get, :path => '/news.atom'}, | |
|
44 | :controller => 'news', :action => 'index', :format => 'atom' | |
|
45 | ) | |
|
46 | end | |
|
47 | ||
|
34 | 48 | def test_index |
|
35 | 49 | get :index |
|
36 | 50 | assert_response :success |
|
37 | 51 | assert_template 'index' |
|
38 | 52 | assert_not_nil assigns(:newss) |
|
39 | 53 | assert_nil assigns(:project) |
|
40 | 54 | end |
|
41 | 55 | |
|
56 | def test_index_with_project_routing | |
|
57 | assert_routing( | |
|
58 | {:method => :get, :path => '/projects/567/news'}, | |
|
59 | :controller => 'news', :action => 'index', :project_id => '567' | |
|
60 | ) | |
|
61 | end | |
|
62 | ||
|
63 | def test_index_with_project_routing_formatted | |
|
64 | assert_routing( | |
|
65 | {:method => :get, :path => '/projects/567/news.atom'}, | |
|
66 | :controller => 'news', :action => 'index', :project_id => '567', :format => 'atom' | |
|
67 | ) | |
|
68 | end | |
|
69 | ||
|
42 | 70 | def test_index_with_project |
|
43 | 71 | get :index, :project_id => 1 |
|
44 | 72 | assert_response :success |
|
45 | 73 | assert_template 'index' |
|
46 | 74 | assert_not_nil assigns(:newss) |
|
47 | 75 | end |
|
48 | 76 | |
|
77 | def test_show_routing | |
|
78 | assert_routing( | |
|
79 | {:method => :get, :path => '/news/2'}, | |
|
80 | :controller => 'news', :action => 'show', :id => '2' | |
|
81 | ) | |
|
82 | end | |
|
83 | ||
|
49 | 84 | def test_show |
|
50 | 85 | get :show, :id => 1 |
|
51 | 86 | assert_response :success |
|
52 | 87 | assert_template 'show' |
|
53 | 88 | assert_tag :tag => 'h2', :content => /eCookbook first release/ |
|
54 | 89 | end |
|
55 | 90 | |
|
56 | 91 | def test_show_not_found |
|
57 | 92 | get :show, :id => 999 |
|
58 | 93 | assert_response 404 |
|
59 | 94 | end |
|
60 | 95 | |
|
96 | def test_new_routing | |
|
97 | assert_routing( | |
|
98 | {:method => :get, :path => '/projects/567/news/new'}, | |
|
99 | :controller => 'news', :action => 'new', :project_id => '567' | |
|
100 | ) | |
|
101 | assert_recognizes( | |
|
102 | {:controller => 'news', :action => 'new', :project_id => '567'}, | |
|
103 | {:method => :post, :path => '/projects/567/news'} | |
|
104 | ) | |
|
105 | end | |
|
106 | ||
|
61 | 107 | def test_get_new |
|
62 | 108 | @request.session[:user_id] = 2 |
|
63 | 109 | get :new, :project_id => 1 |
|
64 | 110 | assert_response :success |
|
65 | 111 | assert_template 'new' |
|
66 | 112 | end |
|
67 | 113 | |
|
68 | 114 | def test_post_new |
|
69 | 115 | @request.session[:user_id] = 2 |
|
70 | 116 | post :new, :project_id => 1, :news => { :title => 'NewsControllerTest', |
|
71 | 117 | :description => 'This is the description', |
|
72 | 118 | :summary => '' } |
|
73 | 119 | assert_redirected_to 'projects/ecookbook/news' |
|
74 | 120 | |
|
75 | 121 | news = News.find_by_title('NewsControllerTest') |
|
76 | 122 | assert_not_nil news |
|
77 | 123 | assert_equal 'This is the description', news.description |
|
78 | 124 | assert_equal User.find(2), news.author |
|
79 | 125 | assert_equal Project.find(1), news.project |
|
80 | 126 | end |
|
81 | 127 | |
|
128 | def test_edit_routing | |
|
129 | assert_routing( | |
|
130 | {:method => :get, :path => '/news/234'}, | |
|
131 | :controller => 'news', :action => 'show', :id => '234' | |
|
132 | ) | |
|
133 | assert_recognizes(#TODO: PUT to news URI instead, need to modify form | |
|
134 | {:controller => 'news', :action => 'edit', :id => '567'}, | |
|
135 | {:method => :post, :path => '/news/567/edit'} | |
|
136 | ) | |
|
137 | end | |
|
138 | ||
|
82 | 139 | def test_get_edit |
|
83 | 140 | @request.session[:user_id] = 2 |
|
84 | 141 | get :edit, :id => 1 |
|
85 | 142 | assert_response :success |
|
86 | 143 | assert_template 'edit' |
|
87 | 144 | end |
|
88 | 145 | |
|
89 | 146 | def test_post_edit |
|
90 | 147 | @request.session[:user_id] = 2 |
|
91 | 148 | post :edit, :id => 1, :news => { :description => 'Description changed by test_post_edit' } |
|
92 | 149 | assert_redirected_to 'news/show/1' |
|
93 | 150 | news = News.find(1) |
|
94 | 151 | assert_equal 'Description changed by test_post_edit', news.description |
|
95 | 152 | end |
|
96 | 153 | |
|
97 | 154 | def test_post_new_with_validation_failure |
|
98 | 155 | @request.session[:user_id] = 2 |
|
99 | 156 | post :new, :project_id => 1, :news => { :title => '', |
|
100 | 157 | :description => 'This is the description', |
|
101 | 158 | :summary => '' } |
|
102 | 159 | assert_response :success |
|
103 | 160 | assert_template 'new' |
|
104 | 161 | assert_not_nil assigns(:news) |
|
105 | 162 | assert assigns(:news).new_record? |
|
106 | 163 | assert_tag :tag => 'div', :attributes => { :id => 'errorExplanation' }, |
|
107 | 164 | :content => /1 error/ |
|
108 | 165 | end |
|
109 | 166 | |
|
110 | 167 | def test_add_comment |
|
111 | 168 | @request.session[:user_id] = 2 |
|
112 | 169 | post :add_comment, :id => 1, :comment => { :comments => 'This is a NewsControllerTest comment' } |
|
113 | 170 | assert_redirected_to 'news/show/1' |
|
114 | 171 | |
|
115 | 172 | comment = News.find(1).comments.find(:first, :order => 'created_on DESC') |
|
116 | 173 | assert_not_nil comment |
|
117 | 174 | assert_equal 'This is a NewsControllerTest comment', comment.comments |
|
118 | 175 | assert_equal User.find(2), comment.author |
|
119 | 176 | end |
|
120 | 177 | |
|
121 | 178 | def test_destroy_comment |
|
122 | 179 | comments_count = News.find(1).comments.size |
|
123 | 180 | @request.session[:user_id] = 2 |
|
124 | 181 | post :destroy_comment, :id => 1, :comment_id => 2 |
|
125 | 182 | assert_redirected_to 'news/show/1' |
|
126 | 183 | assert_nil Comment.find_by_id(2) |
|
127 | 184 | assert_equal comments_count - 1, News.find(1).comments.size |
|
128 | 185 | end |
|
129 | 186 | |
|
187 | def test_destroy_routing | |
|
188 | assert_recognizes(#TODO: should use DELETE to news URI, need to change form | |
|
189 | {:controller => 'news', :action => 'destroy', :id => '567'}, | |
|
190 | {:method => :post, :path => '/news/567/destroy'} | |
|
191 | ) | |
|
192 | end | |
|
193 | ||
|
130 | 194 | def test_destroy |
|
131 | 195 | @request.session[:user_id] = 2 |
|
132 | 196 | post :destroy, :id => 1 |
|
133 | 197 | assert_redirected_to 'projects/ecookbook/news' |
|
134 | 198 | assert_nil News.find_by_id(1) |
|
135 | 199 | end |
|
136 | 200 | |
|
137 | 201 | def test_preview |
|
138 | 202 | get :preview, :project_id => 1, |
|
139 | 203 | :news => {:title => '', |
|
140 | 204 | :description => 'News description', |
|
141 | 205 | :summary => ''} |
|
142 | 206 | assert_response :success |
|
143 | 207 | assert_template 'common/_preview' |
|
144 | 208 | assert_tag :tag => 'fieldset', :attributes => { :class => 'preview' }, |
|
145 | 209 | :content => /News description/ |
|
146 | 210 | end |
|
147 | 211 | end |
@@ -1,364 +1,517 | |||
|
1 | 1 | # Redmine - project management software |
|
2 | 2 | # Copyright (C) 2006-2008 Jean-Philippe Lang |
|
3 | 3 | # |
|
4 | 4 | # This program is free software; you can redistribute it and/or |
|
5 | 5 | # modify it under the terms of the GNU General Public License |
|
6 | 6 | # as published by the Free Software Foundation; either version 2 |
|
7 | 7 | # of the License, or (at your option) any later version. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU General Public License |
|
15 | 15 | # along with this program; if not, write to the Free Software |
|
16 | 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 | 17 | |
|
18 | 18 | require File.dirname(__FILE__) + '/../test_helper' |
|
19 | 19 | require 'projects_controller' |
|
20 | 20 | |
|
21 | 21 | # Re-raise errors caught by the controller. |
|
22 | 22 | class ProjectsController; def rescue_action(e) raise e end; end |
|
23 | 23 | |
|
24 | 24 | class ProjectsControllerTest < Test::Unit::TestCase |
|
25 | 25 | fixtures :projects, :versions, :users, :roles, :members, :issues, :journals, :journal_details, |
|
26 | 26 | :trackers, :projects_trackers, :issue_statuses, :enabled_modules, :enumerations, :boards, :messages, |
|
27 | 27 | :attachments |
|
28 | 28 | |
|
29 | 29 | def setup |
|
30 | 30 | @controller = ProjectsController.new |
|
31 | 31 | @request = ActionController::TestRequest.new |
|
32 | 32 | @response = ActionController::TestResponse.new |
|
33 | 33 | @request.session[:user_id] = nil |
|
34 | 34 | Setting.default_language = 'en' |
|
35 | 35 | end |
|
36 | 36 | |
|
37 | def test_index_routing | |
|
38 | assert_routing( | |
|
39 | {:method => :get, :path => '/projects'}, | |
|
40 | :controller => 'projects', :action => 'index' | |
|
41 | ) | |
|
42 | end | |
|
43 | ||
|
37 | 44 | def test_index |
|
38 | 45 | get :index |
|
39 | 46 | assert_response :success |
|
40 | 47 | assert_template 'index' |
|
41 | 48 | assert_not_nil assigns(:projects) |
|
42 | 49 | |
|
43 | 50 | assert_tag :ul, :child => {:tag => 'li', |
|
44 | 51 | :descendant => {:tag => 'a', :content => 'eCookbook'}, |
|
45 | 52 | :child => { :tag => 'ul', |
|
46 | 53 | :descendant => { :tag => 'a', |
|
47 | 54 | :content => 'Child of private child' |
|
48 | 55 | } |
|
49 | 56 | } |
|
50 | 57 | } |
|
51 | 58 | |
|
52 | 59 | assert_no_tag :a, :content => /Private child of eCookbook/ |
|
53 | 60 | end |
|
54 | 61 | |
|
62 | def test_index_atom_routing | |
|
63 | assert_routing( | |
|
64 | {:method => :get, :path => '/projects.atom'}, | |
|
65 | :controller => 'projects', :action => 'index', :format => 'atom' | |
|
66 | ) | |
|
67 | end | |
|
68 | ||
|
55 | 69 | def test_index_atom |
|
56 | 70 | get :index, :format => 'atom' |
|
57 | 71 | assert_response :success |
|
58 | 72 | assert_template 'common/feed.atom.rxml' |
|
59 | 73 | assert_select 'feed>title', :text => 'Redmine: Latest projects' |
|
60 | 74 | assert_select 'feed>entry', :count => Project.count(:conditions => Project.visible_by(User.current)) |
|
61 | 75 | end |
|
62 | 76 | |
|
77 | def test_add_routing | |
|
78 | assert_routing( | |
|
79 | {:method => :get, :path => '/projects/new'}, | |
|
80 | :controller => 'projects', :action => 'add' | |
|
81 | ) | |
|
82 | assert_recognizes( | |
|
83 | {:controller => 'projects', :action => 'add'}, | |
|
84 | {:method => :post, :path => '/projects/new'} | |
|
85 | ) | |
|
86 | assert_recognizes( | |
|
87 | {:controller => 'projects', :action => 'add'}, | |
|
88 | {:method => :post, :path => '/projects'} | |
|
89 | ) | |
|
90 | end | |
|
91 | ||
|
92 | def test_show_routing | |
|
93 | assert_routing( | |
|
94 | {:method => :get, :path => '/projects/test'}, | |
|
95 | :controller => 'projects', :action => 'show', :id => 'test' | |
|
96 | ) | |
|
97 | end | |
|
98 | ||
|
63 | 99 | def test_show_by_id |
|
64 | 100 | get :show, :id => 1 |
|
65 | 101 | assert_response :success |
|
66 | 102 | assert_template 'show' |
|
67 | 103 | assert_not_nil assigns(:project) |
|
68 | 104 | end |
|
69 | 105 | |
|
70 | 106 | def test_show_by_identifier |
|
71 | 107 | get :show, :id => 'ecookbook' |
|
72 | 108 | assert_response :success |
|
73 | 109 | assert_template 'show' |
|
74 | 110 | assert_not_nil assigns(:project) |
|
75 | 111 | assert_equal Project.find_by_identifier('ecookbook'), assigns(:project) |
|
76 | 112 | end |
|
77 | 113 | |
|
78 | 114 | def test_private_subprojects_hidden |
|
79 | 115 | get :show, :id => 'ecookbook' |
|
80 | 116 | assert_response :success |
|
81 | 117 | assert_template 'show' |
|
82 | 118 | assert_no_tag :tag => 'a', :content => /Private child/ |
|
83 | 119 | end |
|
84 | 120 | |
|
85 | 121 | def test_private_subprojects_visible |
|
86 | 122 | @request.session[:user_id] = 2 # manager who is a member of the private subproject |
|
87 | 123 | get :show, :id => 'ecookbook' |
|
88 | 124 | assert_response :success |
|
89 | 125 | assert_template 'show' |
|
90 | 126 | assert_tag :tag => 'a', :content => /Private child/ |
|
91 | 127 | end |
|
92 | 128 | |
|
129 | def test_settings_routing | |
|
130 | assert_routing( | |
|
131 | {:method => :get, :path => '/projects/4223/settings'}, | |
|
132 | :controller => 'projects', :action => 'settings', :id => '4223' | |
|
133 | ) | |
|
134 | assert_routing( | |
|
135 | {:method => :get, :path => '/projects/4223/settings/members'}, | |
|
136 | :controller => 'projects', :action => 'settings', :id => '4223', :tab => 'members' | |
|
137 | ) | |
|
138 | end | |
|
139 | ||
|
93 | 140 | def test_settings |
|
94 | 141 | @request.session[:user_id] = 2 # manager |
|
95 | 142 | get :settings, :id => 1 |
|
96 | 143 | assert_response :success |
|
97 | 144 | assert_template 'settings' |
|
98 | 145 | end |
|
99 | 146 | |
|
100 | 147 | def test_edit |
|
101 | 148 | @request.session[:user_id] = 2 # manager |
|
102 | 149 | post :edit, :id => 1, :project => {:name => 'Test changed name', |
|
103 | 150 | :issue_custom_field_ids => ['']} |
|
104 | 151 | assert_redirected_to 'projects/settings/ecookbook' |
|
105 | 152 | project = Project.find(1) |
|
106 | 153 | assert_equal 'Test changed name', project.name |
|
107 | 154 | end |
|
108 | 155 | |
|
156 | def test_add_version_routing | |
|
157 | assert_routing( | |
|
158 | {:method => :get, :path => 'projects/64/versions/new'}, | |
|
159 | :controller => 'projects', :action => 'add_version', :id => '64' | |
|
160 | ) | |
|
161 | assert_routing( | |
|
162 | #TODO: use PUT | |
|
163 | {:method => :post, :path => 'projects/64/versions/new'}, | |
|
164 | :controller => 'projects', :action => 'add_version', :id => '64' | |
|
165 | ) | |
|
166 | end | |
|
167 | ||
|
168 | def test_add_issue_category_routing | |
|
169 | assert_routing( | |
|
170 | {:method => :get, :path => 'projects/test/categories/new'}, | |
|
171 | :controller => 'projects', :action => 'add_issue_category', :id => 'test' | |
|
172 | ) | |
|
173 | assert_routing( | |
|
174 | #TODO: use PUT and update form | |
|
175 | {:method => :post, :path => 'projects/64/categories/new'}, | |
|
176 | :controller => 'projects', :action => 'add_issue_category', :id => '64' | |
|
177 | ) | |
|
178 | end | |
|
179 | ||
|
180 | def test_destroy_routing | |
|
181 | assert_routing( | |
|
182 | {:method => :get, :path => '/projects/567/destroy'}, | |
|
183 | :controller => 'projects', :action => 'destroy', :id => '567' | |
|
184 | ) | |
|
185 | assert_routing( | |
|
186 | #TODO: use DELETE and update form | |
|
187 | {:method => :post, :path => 'projects/64/destroy'}, | |
|
188 | :controller => 'projects', :action => 'destroy', :id => '64' | |
|
189 | ) | |
|
190 | end | |
|
191 | ||
|
109 | 192 | def test_get_destroy |
|
110 | 193 | @request.session[:user_id] = 1 # admin |
|
111 | 194 | get :destroy, :id => 1 |
|
112 | 195 | assert_response :success |
|
113 | 196 | assert_template 'destroy' |
|
114 | 197 | assert_not_nil Project.find_by_id(1) |
|
115 | 198 | end |
|
116 | 199 | |
|
117 | 200 | def test_post_destroy |
|
118 | 201 | @request.session[:user_id] = 1 # admin |
|
119 | 202 | post :destroy, :id => 1, :confirm => 1 |
|
120 | 203 | assert_redirected_to 'admin/projects' |
|
121 | 204 | assert_nil Project.find_by_id(1) |
|
122 | 205 | end |
|
123 | 206 | |
|
124 | 207 | def test_add_file |
|
125 | 208 | set_tmp_attachments_directory |
|
126 | 209 | @request.session[:user_id] = 2 |
|
127 | 210 | Setting.notified_events = ['file_added'] |
|
128 | 211 | ActionMailer::Base.deliveries.clear |
|
129 | 212 | |
|
130 | 213 | assert_difference 'Attachment.count' do |
|
131 | 214 | post :add_file, :id => 1, :version_id => '', |
|
132 | 215 | :attachments => {'1' => {'file' => test_uploaded_file('testfile.txt', 'text/plain')}} |
|
133 | 216 | end |
|
134 | 217 | assert_redirected_to 'projects/list_files/ecookbook' |
|
135 | 218 | a = Attachment.find(:first, :order => 'created_on DESC') |
|
136 | 219 | assert_equal 'testfile.txt', a.filename |
|
137 | 220 | assert_equal Project.find(1), a.container |
|
138 | 221 | |
|
139 | 222 | mail = ActionMailer::Base.deliveries.last |
|
140 | 223 | assert_kind_of TMail::Mail, mail |
|
141 | 224 | assert_equal "[eCookbook] New file", mail.subject |
|
142 | 225 | assert mail.body.include?('testfile.txt') |
|
143 | 226 | end |
|
144 | 227 | |
|
228 | def test_add_file_routing | |
|
229 | assert_routing( | |
|
230 | {:method => :get, :path => '/projects/33/files/new'}, | |
|
231 | :controller => 'projects', :action => 'add_file', :id => '33' | |
|
232 | ) | |
|
233 | assert_routing( | |
|
234 | {:method => :post, :path => '/projects/33/files/new'}, | |
|
235 | :controller => 'projects', :action => 'add_file', :id => '33' | |
|
236 | ) | |
|
237 | end | |
|
238 | ||
|
145 | 239 | def test_add_version_file |
|
146 | 240 | set_tmp_attachments_directory |
|
147 | 241 | @request.session[:user_id] = 2 |
|
148 | 242 | Setting.notified_events = ['file_added'] |
|
149 | 243 | |
|
150 | 244 | assert_difference 'Attachment.count' do |
|
151 | 245 | post :add_file, :id => 1, :version_id => '2', |
|
152 | 246 | :attachments => {'1' => {'file' => test_uploaded_file('testfile.txt', 'text/plain')}} |
|
153 | 247 | end |
|
154 | 248 | assert_redirected_to 'projects/list_files/ecookbook' |
|
155 | 249 | a = Attachment.find(:first, :order => 'created_on DESC') |
|
156 | 250 | assert_equal 'testfile.txt', a.filename |
|
157 | 251 | assert_equal Version.find(2), a.container |
|
158 | 252 | end |
|
159 | 253 | |
|
160 | 254 | def test_list_files |
|
161 | 255 | get :list_files, :id => 1 |
|
162 | 256 | assert_response :success |
|
163 | 257 | assert_template 'list_files' |
|
164 | 258 | assert_not_nil assigns(:containers) |
|
165 | 259 | |
|
166 | 260 | # file attached to the project |
|
167 | 261 | assert_tag :a, :content => 'project_file.zip', |
|
168 | 262 | :attributes => { :href => '/attachments/download/8/project_file.zip' } |
|
169 | 263 | |
|
170 | 264 | # file attached to a project's version |
|
171 | 265 | assert_tag :a, :content => 'version_file.zip', |
|
172 | 266 | :attributes => { :href => '/attachments/download/9/version_file.zip' } |
|
173 | 267 | end |
|
174 | 268 | |
|
269 | def test_list_files_routing | |
|
270 | assert_routing( | |
|
271 | {:method => :get, :path => '/projects/33/files'}, | |
|
272 | :controller => 'projects', :action => 'list_files', :id => '33' | |
|
273 | ) | |
|
274 | end | |
|
275 | ||
|
276 | def test_changelog_routing | |
|
277 | assert_routing( | |
|
278 | {:method => :get, :path => '/projects/44/changelog'}, | |
|
279 | :controller => 'projects', :action => 'changelog', :id => '44' | |
|
280 | ) | |
|
281 | end | |
|
282 | ||
|
175 | 283 | def test_changelog |
|
176 | 284 | get :changelog, :id => 1 |
|
177 | 285 | assert_response :success |
|
178 | 286 | assert_template 'changelog' |
|
179 | 287 | assert_not_nil assigns(:versions) |
|
180 | 288 | end |
|
181 | 289 | |
|
290 | def test_roadmap_routing | |
|
291 | assert_routing( | |
|
292 | {:method => :get, :path => 'projects/33/roadmap'}, | |
|
293 | :controller => 'projects', :action => 'roadmap', :id => '33' | |
|
294 | ) | |
|
295 | end | |
|
296 | ||
|
182 | 297 | def test_roadmap |
|
183 | 298 | get :roadmap, :id => 1 |
|
184 | 299 | assert_response :success |
|
185 | 300 | assert_template 'roadmap' |
|
186 | 301 | assert_not_nil assigns(:versions) |
|
187 | 302 | # Version with no date set appears |
|
188 | 303 | assert assigns(:versions).include?(Version.find(3)) |
|
189 | 304 | # Completed version doesn't appear |
|
190 | 305 | assert !assigns(:versions).include?(Version.find(1)) |
|
191 | 306 | end |
|
192 | 307 | |
|
193 | 308 | def test_roadmap_with_completed_versions |
|
194 | 309 | get :roadmap, :id => 1, :completed => 1 |
|
195 | 310 | assert_response :success |
|
196 | 311 | assert_template 'roadmap' |
|
197 | 312 | assert_not_nil assigns(:versions) |
|
198 | 313 | # Version with no date set appears |
|
199 | 314 | assert assigns(:versions).include?(Version.find(3)) |
|
200 | 315 | # Completed version appears |
|
201 | 316 | assert assigns(:versions).include?(Version.find(1)) |
|
202 | 317 | end |
|
203 | 318 | |
|
319 | def test_project_activity_routing | |
|
320 | assert_routing( | |
|
321 | {:method => :get, :path => '/projects/1/activity'}, | |
|
322 | :controller => 'projects', :action => 'activity', :id => '1' | |
|
323 | ) | |
|
324 | end | |
|
325 | ||
|
326 | def test_project_activity_atom_routing | |
|
327 | assert_routing( | |
|
328 | {:method => :get, :path => '/projects/1/activity.atom'}, | |
|
329 | :controller => 'projects', :action => 'activity', :id => '1', :format => 'atom' | |
|
330 | ) | |
|
331 | end | |
|
332 | ||
|
204 | 333 | def test_project_activity |
|
205 | 334 | get :activity, :id => 1, :with_subprojects => 0 |
|
206 | 335 | assert_response :success |
|
207 | 336 | assert_template 'activity' |
|
208 | 337 | assert_not_nil assigns(:events_by_day) |
|
209 | 338 | |
|
210 | 339 | assert_tag :tag => "h3", |
|
211 | 340 | :content => /#{2.days.ago.to_date.day}/, |
|
212 | 341 | :sibling => { :tag => "dl", |
|
213 | 342 | :child => { :tag => "dt", |
|
214 | 343 | :attributes => { :class => /issue-edit/ }, |
|
215 | 344 | :child => { :tag => "a", |
|
216 | 345 | :content => /(#{IssueStatus.find(2).name})/, |
|
217 | 346 | } |
|
218 | 347 | } |
|
219 | 348 | } |
|
220 | 349 | end |
|
221 | 350 | |
|
222 | 351 | def test_previous_project_activity |
|
223 | 352 | get :activity, :id => 1, :from => 3.days.ago.to_date |
|
224 | 353 | assert_response :success |
|
225 | 354 | assert_template 'activity' |
|
226 | 355 | assert_not_nil assigns(:events_by_day) |
|
227 | 356 | |
|
228 | 357 | assert_tag :tag => "h3", |
|
229 | 358 | :content => /#{3.day.ago.to_date.day}/, |
|
230 | 359 | :sibling => { :tag => "dl", |
|
231 | 360 | :child => { :tag => "dt", |
|
232 | 361 | :attributes => { :class => /issue/ }, |
|
233 | 362 | :child => { :tag => "a", |
|
234 | 363 | :content => /#{Issue.find(1).subject}/, |
|
235 | 364 | } |
|
236 | 365 | } |
|
237 | 366 | } |
|
238 | 367 | end |
|
239 | 368 | |
|
369 | def test_global_activity_routing | |
|
370 | assert_routing({:method => :get, :path => '/activity'}, :controller => 'projects', :action => 'activity') | |
|
371 | end | |
|
372 | ||
|
240 | 373 | def test_global_activity |
|
241 | 374 | get :activity |
|
242 | 375 | assert_response :success |
|
243 | 376 | assert_template 'activity' |
|
244 | 377 | assert_not_nil assigns(:events_by_day) |
|
245 | 378 | |
|
246 | 379 | assert_tag :tag => "h3", |
|
247 | 380 | :content => /#{5.day.ago.to_date.day}/, |
|
248 | 381 | :sibling => { :tag => "dl", |
|
249 | 382 | :child => { :tag => "dt", |
|
250 | 383 | :attributes => { :class => /issue/ }, |
|
251 | 384 | :child => { :tag => "a", |
|
252 | 385 | :content => /#{Issue.find(5).subject}/, |
|
253 | 386 | } |
|
254 | 387 | } |
|
255 | 388 | } |
|
256 | 389 | end |
|
257 | 390 | |
|
258 | 391 | def test_user_activity |
|
259 | 392 | get :activity, :user_id => 2 |
|
260 | 393 | assert_response :success |
|
261 | 394 | assert_template 'activity' |
|
262 | 395 | assert_not_nil assigns(:events_by_day) |
|
263 | 396 | |
|
264 | 397 | assert_tag :tag => "h3", |
|
265 | 398 | :content => /#{3.day.ago.to_date.day}/, |
|
266 | 399 | :sibling => { :tag => "dl", |
|
267 | 400 | :child => { :tag => "dt", |
|
268 | 401 | :attributes => { :class => /issue/ }, |
|
269 | 402 | :child => { :tag => "a", |
|
270 | 403 | :content => /#{Issue.find(1).subject}/, |
|
271 | 404 | } |
|
272 | 405 | } |
|
273 | 406 | } |
|
274 | 407 | end |
|
275 | 408 | |
|
409 | def test_global_activity_atom_routing | |
|
410 | assert_routing({:method => :get, :path => '/activity.atom'}, :controller => 'projects', :action => 'activity', :format => 'atom') | |
|
411 | end | |
|
412 | ||
|
276 | 413 | def test_activity_atom_feed |
|
277 | 414 | get :activity, :format => 'atom' |
|
278 | 415 | assert_response :success |
|
279 | 416 | assert_template 'common/feed.atom.rxml' |
|
280 | 417 | end |
|
281 | 418 | |
|
419 | def test_archive_routing | |
|
420 | assert_routing( | |
|
421 | #TODO: use PUT to project path and modify form | |
|
422 | {:method => :post, :path => 'projects/64/archive'}, | |
|
423 | :controller => 'projects', :action => 'archive', :id => '64' | |
|
424 | ) | |
|
425 | end | |
|
426 | ||
|
282 | 427 |
def test_archive |
|
283 | 428 | @request.session[:user_id] = 1 # admin |
|
284 | 429 | post :archive, :id => 1 |
|
285 | 430 | assert_redirected_to 'admin/projects' |
|
286 | 431 | assert !Project.find(1).active? |
|
287 | 432 | end |
|
288 | 433 | |
|
434 | def test_unarchive_routing | |
|
435 | assert_routing( | |
|
436 | #TODO: use PUT to project path and modify form | |
|
437 | {:method => :post, :path => '/projects/567/unarchive'}, | |
|
438 | :controller => 'projects', :action => 'unarchive', :id => '567' | |
|
439 | ) | |
|
440 | end | |
|
441 | ||
|
289 | 442 | def test_unarchive |
|
290 | 443 | @request.session[:user_id] = 1 # admin |
|
291 | 444 | Project.find(1).archive |
|
292 | 445 | post :unarchive, :id => 1 |
|
293 | 446 | assert_redirected_to 'admin/projects' |
|
294 | 447 | assert Project.find(1).active? |
|
295 | 448 | end |
|
296 | 449 | |
|
297 | 450 | def test_jump_should_redirect_to_active_tab |
|
298 | 451 | get :show, :id => 1, :jump => 'issues' |
|
299 | 452 | assert_redirected_to 'projects/ecookbook/issues' |
|
300 | 453 | end |
|
301 | 454 | |
|
302 | 455 | def test_jump_should_not_redirect_to_inactive_tab |
|
303 | 456 | get :show, :id => 3, :jump => 'documents' |
|
304 | 457 | assert_response :success |
|
305 | 458 | assert_template 'show' |
|
306 | 459 | end |
|
307 | 460 | |
|
308 | 461 | def test_jump_should_not_redirect_to_unknown_tab |
|
309 | 462 | get :show, :id => 3, :jump => 'foobar' |
|
310 | 463 | assert_response :success |
|
311 | 464 | assert_template 'show' |
|
312 | 465 | end |
|
313 | 466 | |
|
314 | 467 | def test_project_menu |
|
315 | 468 | assert_no_difference 'Redmine::MenuManager.items(:project_menu).size' do |
|
316 | 469 | Redmine::MenuManager.map :project_menu do |menu| |
|
317 | 470 | menu.push :foo, { :controller => 'projects', :action => 'show' }, :cation => 'Foo' |
|
318 | 471 | menu.push :bar, { :controller => 'projects', :action => 'show' }, :before => :activity |
|
319 | 472 | menu.push :hello, { :controller => 'projects', :action => 'show' }, :caption => Proc.new {|p| p.name.upcase }, :after => :bar |
|
320 | 473 | end |
|
321 | 474 | |
|
322 | 475 | get :show, :id => 1 |
|
323 | 476 | assert_tag :div, :attributes => { :id => 'main-menu' }, |
|
324 | 477 | :descendant => { :tag => 'li', :child => { :tag => 'a', :content => 'Foo', |
|
325 | 478 | :attributes => { :class => 'foo' } } } |
|
326 | 479 | |
|
327 | 480 | assert_tag :div, :attributes => { :id => 'main-menu' }, |
|
328 | 481 | :descendant => { :tag => 'li', :child => { :tag => 'a', :content => 'Bar', |
|
329 | 482 | :attributes => { :class => 'bar' } }, |
|
330 | 483 | :before => { :tag => 'li', :child => { :tag => 'a', :content => 'ECOOKBOOK' } } } |
|
331 | 484 | |
|
332 | 485 | assert_tag :div, :attributes => { :id => 'main-menu' }, |
|
333 | 486 | :descendant => { :tag => 'li', :child => { :tag => 'a', :content => 'ECOOKBOOK', |
|
334 | 487 | :attributes => { :class => 'hello' } }, |
|
335 | 488 | :before => { :tag => 'li', :child => { :tag => 'a', :content => 'Activity' } } } |
|
336 | 489 | |
|
337 | 490 | # Remove the menu items |
|
338 | 491 | Redmine::MenuManager.map :project_menu do |menu| |
|
339 | 492 | menu.delete :foo |
|
340 | 493 | menu.delete :bar |
|
341 | 494 | menu.delete :hello |
|
342 | 495 | end |
|
343 | 496 | end |
|
344 | 497 | end |
|
345 | 498 | |
|
346 | 499 | # A hook that is manually registered later |
|
347 | 500 | class ProjectBasedTemplate < Redmine::Hook::ViewListener |
|
348 | 501 | def view_layouts_base_html_head(context) |
|
349 | 502 | # Adds a project stylesheet |
|
350 | 503 | stylesheet_link_tag(context[:project].identifier) if context[:project] |
|
351 | 504 | end |
|
352 | 505 | end |
|
353 | 506 | # Don't use this hook now |
|
354 | 507 | Redmine::Hook.clear_listeners |
|
355 | 508 | |
|
356 | 509 | def test_hook_response |
|
357 | 510 | Redmine::Hook.add_listener(ProjectBasedTemplate) |
|
358 | 511 | get :show, :id => 1 |
|
359 | 512 | assert_tag :tag => 'link', :attributes => {:href => '/stylesheets/ecookbook.css'}, |
|
360 | 513 | :parent => {:tag => 'head'} |
|
361 | 514 | |
|
362 | 515 | Redmine::Hook.clear_listeners |
|
363 | 516 | end |
|
364 | 517 | end |
@@ -1,98 +1,207 | |||
|
1 | 1 | # redMine - project management software |
|
2 | 2 | # Copyright (C) 2006-2007 Jean-Philippe Lang |
|
3 | 3 | # |
|
4 | 4 | # This program is free software; you can redistribute it and/or |
|
5 | 5 | # modify it under the terms of the GNU General Public License |
|
6 | 6 | # as published by the Free Software Foundation; either version 2 |
|
7 | 7 | # of the License, or (at your option) any later version. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU General Public License |
|
15 | 15 | # along with this program; if not, write to the Free Software |
|
16 | 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 | 17 | |
|
18 | 18 | require File.dirname(__FILE__) + '/../test_helper' |
|
19 | 19 | require 'repositories_controller' |
|
20 | 20 | |
|
21 | 21 | # Re-raise errors caught by the controller. |
|
22 | 22 | class RepositoriesController; def rescue_action(e) raise e end; end |
|
23 | 23 | |
|
24 | 24 | class RepositoriesControllerTest < Test::Unit::TestCase |
|
25 | 25 | fixtures :projects, :users, :roles, :members, :repositories, :issues, :issue_statuses, :changesets, :changes, :issue_categories, :enumerations, :custom_fields, :custom_values, :trackers |
|
26 | 26 | |
|
27 | 27 | def setup |
|
28 | 28 | @controller = RepositoriesController.new |
|
29 | 29 | @request = ActionController::TestRequest.new |
|
30 | 30 | @response = ActionController::TestResponse.new |
|
31 | 31 | User.current = nil |
|
32 | 32 | end |
|
33 | 33 | |
|
34 | def test_show_routing | |
|
35 | assert_routing( | |
|
36 | {:method => :get, :path => '/projects/redmine/repository'}, | |
|
37 | :controller => 'repositories', :action => 'show', :id => 'redmine' | |
|
38 | ) | |
|
39 | end | |
|
40 | ||
|
41 | def test_edit_routing | |
|
42 | assert_routing( | |
|
43 | {:method => :get, :path => '/projects/world_domination/repository/edit'}, | |
|
44 | :controller => 'repositories', :action => 'edit', :id => 'world_domination' | |
|
45 | ) | |
|
46 | assert_routing( | |
|
47 | {:method => :post, :path => '/projects/world_domination/repository/edit'}, | |
|
48 | :controller => 'repositories', :action => 'edit', :id => 'world_domination' | |
|
49 | ) | |
|
50 | end | |
|
51 | ||
|
52 | def test_revisions_routing | |
|
53 | assert_routing( | |
|
54 | {:method => :get, :path => '/projects/redmine/repository/revisions'}, | |
|
55 | :controller => 'repositories', :action => 'revisions', :id => 'redmine' | |
|
56 | ) | |
|
57 | end | |
|
58 | ||
|
59 | def test_revisions_atom_routing | |
|
60 | assert_routing( | |
|
61 | {:method => :get, :path => '/projects/redmine/repository/revisions.atom'}, | |
|
62 | :controller => 'repositories', :action => 'revisions', :id => 'redmine', :format => 'atom' | |
|
63 | ) | |
|
64 | end | |
|
65 | ||
|
34 | 66 | def test_revisions |
|
35 | 67 | get :revisions, :id => 1 |
|
36 | 68 | assert_response :success |
|
37 | 69 | assert_template 'revisions' |
|
38 | 70 | assert_not_nil assigns(:changesets) |
|
39 | 71 | end |
|
40 | 72 | |
|
73 | def test_revision_routing | |
|
74 | assert_routing( | |
|
75 | {:method => :get, :path => '/projects/restmine/repository/revisions/2457'}, | |
|
76 | :controller => 'repositories', :action => 'revision', :id => 'restmine', :rev => '2457' | |
|
77 | ) | |
|
78 | end | |
|
79 | ||
|
41 | 80 | def test_revision_with_before_nil_and_afer_normal |
|
42 | 81 | get :revision, {:id => 1, :rev => 1} |
|
43 | 82 | assert_response :success |
|
44 | 83 | assert_template 'revision' |
|
45 | 84 | assert_no_tag :tag => "div", :attributes => { :class => "contextual" }, |
|
46 |
:child => { :tag => "a", :attributes => { :href => '/repositor |
|
|
85 | :child => { :tag => "a", :attributes => { :href => '/projects/ecookbook/repository/revisions/0'} | |
|
47 | 86 | } |
|
48 | 87 | assert_tag :tag => "div", :attributes => { :class => "contextual" }, |
|
49 |
:child => { :tag => "a", :attributes => { :href => '/repositor |
|
|
88 | :child => { :tag => "a", :attributes => { :href => '/projects/ecookbook/repository/revisions/2'} | |
|
50 | 89 | } |
|
51 | 90 | end |
|
52 | 91 | |
|
92 | def test_diff_routing | |
|
93 | assert_routing( | |
|
94 | {:method => :get, :path => '/projects/restmine/repository/revisions/2457/diff'}, | |
|
95 | :controller => 'repositories', :action => 'diff', :id => 'restmine', :rev => '2457' | |
|
96 | ) | |
|
97 | end | |
|
98 | ||
|
99 | def test_unified_diff_routing | |
|
100 | assert_routing( | |
|
101 | {:method => :get, :path => '/projects/restmine/repository/revisions/2457/diff.diff'}, | |
|
102 | :controller => 'repositories', :action => 'diff', :id => 'restmine', :rev => '2457', :format => 'diff' | |
|
103 | ) | |
|
104 | end | |
|
105 | ||
|
106 | def test_diff_path_routing | |
|
107 | assert_routing( | |
|
108 | {:method => :get, :path => '/projects/restmine/repository/diff/path/to/file.c'}, | |
|
109 | :controller => 'repositories', :action => 'diff', :id => 'restmine', :path => %w[path to file.c] | |
|
110 | ) | |
|
111 | end | |
|
112 | ||
|
113 | def test_diff_path_routing_with_revision | |
|
114 | assert_routing( | |
|
115 | {:method => :get, :path => '/projects/restmine/repository/revisions/2/diff/path/to/file.c'}, | |
|
116 | :controller => 'repositories', :action => 'diff', :id => 'restmine', :path => %w[path to file.c], :rev => '2' | |
|
117 | ) | |
|
118 | end | |
|
119 | ||
|
120 | def test_browse_routing | |
|
121 | assert_routing( | |
|
122 | {:method => :get, :path => '/projects/restmine/repository/browse/path/to/dir'}, | |
|
123 | :controller => 'repositories', :action => 'browse', :id => 'restmine', :path => %w[path to dir] | |
|
124 | ) | |
|
125 | end | |
|
126 | ||
|
127 | def test_entry_routing | |
|
128 | assert_routing( | |
|
129 | {:method => :get, :path => '/projects/restmine/repository/entry/path/to/file.c'}, | |
|
130 | :controller => 'repositories', :action => 'entry', :id => 'restmine', :path => %w[path to file.c] | |
|
131 | ) | |
|
132 | end | |
|
133 | ||
|
134 | def test_entry_routing_with_revision | |
|
135 | assert_routing( | |
|
136 | {:method => :get, :path => '/projects/restmine/repository/revisions/2/entry/path/to/file.c'}, | |
|
137 | :controller => 'repositories', :action => 'entry', :id => 'restmine', :path => %w[path to file.c], :rev => '2' | |
|
138 | ) | |
|
139 | end | |
|
140 | ||
|
141 | def test_annotate_routing | |
|
142 | assert_routing( | |
|
143 | {:method => :get, :path => '/projects/restmine/repository/annotate/path/to/file.c'}, | |
|
144 | :controller => 'repositories', :action => 'annotate', :id => 'restmine', :path => %w[path to file.c] | |
|
145 | ) | |
|
146 | end | |
|
147 | ||
|
148 | def test_changesrouting | |
|
149 | assert_routing( | |
|
150 | {:method => :get, :path => '/projects/restmine/repository/changes/path/to/file.c'}, | |
|
151 | :controller => 'repositories', :action => 'changes', :id => 'restmine', :path => %w[path to file.c] | |
|
152 | ) | |
|
153 | end | |
|
154 | ||
|
155 | def test_statistics_routing | |
|
156 | assert_routing( | |
|
157 | {:method => :get, :path => '/projects/restmine/repository/statistics'}, | |
|
158 | :controller => 'repositories', :action => 'stats', :id => 'restmine' | |
|
159 | ) | |
|
160 | end | |
|
161 | ||
|
53 | 162 | def test_graph_commits_per_month |
|
54 | 163 | get :graph, :id => 1, :graph => 'commits_per_month' |
|
55 | 164 | assert_response :success |
|
56 | 165 | assert_equal 'image/svg+xml', @response.content_type |
|
57 | 166 | end |
|
58 | 167 | |
|
59 | 168 | def test_graph_commits_per_author |
|
60 | 169 | get :graph, :id => 1, :graph => 'commits_per_author' |
|
61 | 170 | assert_response :success |
|
62 | 171 | assert_equal 'image/svg+xml', @response.content_type |
|
63 | 172 | end |
|
64 | 173 | |
|
65 | 174 | def test_committers |
|
66 | 175 | @request.session[:user_id] = 2 |
|
67 | 176 | # add a commit with an unknown user |
|
68 | 177 | Changeset.create!(:repository => Project.find(1).repository, :committer => 'foo', :committed_on => Time.now, :revision => 100, :comments => 'Committed by foo.') |
|
69 | 178 | |
|
70 | 179 | get :committers, :id => 1 |
|
71 | 180 | assert_response :success |
|
72 | 181 | assert_template 'committers' |
|
73 | 182 | |
|
74 | 183 | assert_tag :td, :content => 'dlopper', |
|
75 | 184 | :sibling => { :tag => 'td', |
|
76 | 185 | :child => { :tag => 'select', :attributes => { :name => %r{^committers\[\d+\]\[\]$} }, |
|
77 | 186 | :child => { :tag => 'option', :content => 'Dave Lopper', |
|
78 | 187 | :attributes => { :value => '3', :selected => 'selected' }}}} |
|
79 | 188 | assert_tag :td, :content => 'foo', |
|
80 | 189 | :sibling => { :tag => 'td', |
|
81 | 190 | :child => { :tag => 'select', :attributes => { :name => %r{^committers\[\d+\]\[\]$} }}} |
|
82 | 191 | assert_no_tag :td, :content => 'foo', |
|
83 | 192 | :sibling => { :tag => 'td', |
|
84 | 193 | :descendant => { :tag => 'option', :attributes => { :selected => 'selected' }}} |
|
85 | 194 | end |
|
86 | 195 | |
|
87 | 196 | def test_map_committers |
|
88 | 197 | @request.session[:user_id] = 2 |
|
89 | 198 | # add a commit with an unknown user |
|
90 | 199 | c = Changeset.create!(:repository => Project.find(1).repository, :committer => 'foo', :committed_on => Time.now, :revision => 100, :comments => 'Committed by foo.') |
|
91 | 200 | |
|
92 | 201 | assert_no_difference "Changeset.count(:conditions => 'user_id = 3')" do |
|
93 | 202 | post :committers, :id => 1, :committers => { '0' => ['foo', '2'], '1' => ['dlopper', '3']} |
|
94 | 203 | assert_redirected_to '/repositories/committers/ecookbook' |
|
95 | 204 | assert_equal User.find(2), c.reload.user |
|
96 | 205 | end |
|
97 | 206 | end |
|
98 | 207 | end |
@@ -1,181 +1,181 | |||
|
1 | 1 | # redMine - project management software |
|
2 | 2 | # Copyright (C) 2006-2008 Jean-Philippe Lang |
|
3 | 3 | # |
|
4 | 4 | # This program is free software; you can redistribute it and/or |
|
5 | 5 | # modify it under the terms of the GNU General Public License |
|
6 | 6 | # as published by the Free Software Foundation; either version 2 |
|
7 | 7 | # of the License, or (at your option) any later version. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU General Public License |
|
15 | 15 | # along with this program; if not, write to the Free Software |
|
16 | 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 | 17 | |
|
18 | 18 | require File.dirname(__FILE__) + '/../test_helper' |
|
19 | 19 | require 'repositories_controller' |
|
20 | 20 | |
|
21 | 21 | # Re-raise errors caught by the controller. |
|
22 | 22 | class RepositoriesController; def rescue_action(e) raise e end; end |
|
23 | 23 | |
|
24 | 24 | class RepositoriesSubversionControllerTest < Test::Unit::TestCase |
|
25 | 25 | fixtures :projects, :users, :roles, :members, :enabled_modules, |
|
26 | 26 | :repositories, :issues, :issue_statuses, :changesets, :changes, |
|
27 | 27 | :issue_categories, :enumerations, :custom_fields, :custom_values, :trackers |
|
28 | 28 | |
|
29 | 29 | # No '..' in the repository path for svn |
|
30 | 30 | REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/subversion_repository' |
|
31 | 31 | |
|
32 | 32 | def setup |
|
33 | 33 | @controller = RepositoriesController.new |
|
34 | 34 | @request = ActionController::TestRequest.new |
|
35 | 35 | @response = ActionController::TestResponse.new |
|
36 | 36 | Setting.default_language = 'en' |
|
37 | 37 | User.current = nil |
|
38 | 38 | end |
|
39 | 39 | |
|
40 | 40 | if File.directory?(REPOSITORY_PATH) |
|
41 | 41 | def test_show |
|
42 | 42 | get :show, :id => 1 |
|
43 | 43 | assert_response :success |
|
44 | 44 | assert_template 'show' |
|
45 | 45 | assert_not_nil assigns(:entries) |
|
46 | 46 | assert_not_nil assigns(:changesets) |
|
47 | 47 | end |
|
48 | 48 | |
|
49 | 49 | def test_browse_root |
|
50 | 50 | get :browse, :id => 1 |
|
51 | 51 | assert_response :success |
|
52 | 52 | assert_template 'browse' |
|
53 | 53 | assert_not_nil assigns(:entries) |
|
54 | 54 | entry = assigns(:entries).detect {|e| e.name == 'subversion_test'} |
|
55 | 55 | assert_equal 'dir', entry.kind |
|
56 | 56 | end |
|
57 | 57 | |
|
58 | 58 | def test_browse_directory |
|
59 | 59 | get :browse, :id => 1, :path => ['subversion_test'] |
|
60 | 60 | assert_response :success |
|
61 | 61 | assert_template 'browse' |
|
62 | 62 | assert_not_nil assigns(:entries) |
|
63 | 63 | assert_equal ['folder', '.project', 'helloworld.c', 'textfile.txt'], assigns(:entries).collect(&:name) |
|
64 | 64 | entry = assigns(:entries).detect {|e| e.name == 'helloworld.c'} |
|
65 | 65 | assert_equal 'file', entry.kind |
|
66 | 66 | assert_equal 'subversion_test/helloworld.c', entry.path |
|
67 | 67 | end |
|
68 | 68 | |
|
69 | 69 | def test_browse_at_given_revision |
|
70 | 70 | get :browse, :id => 1, :path => ['subversion_test'], :rev => 4 |
|
71 | 71 | assert_response :success |
|
72 | 72 | assert_template 'browse' |
|
73 | 73 | assert_not_nil assigns(:entries) |
|
74 | 74 | assert_equal ['folder', '.project', 'helloworld.c', 'helloworld.rb', 'textfile.txt'], assigns(:entries).collect(&:name) |
|
75 | 75 | end |
|
76 | 76 | |
|
77 | 77 | def test_changes |
|
78 | 78 | get :changes, :id => 1, :path => ['subversion_test', 'folder', 'helloworld.rb' ] |
|
79 | 79 | assert_response :success |
|
80 | 80 | assert_template 'changes' |
|
81 | 81 | # svn properties displayed with svn >= 1.5 only |
|
82 | 82 | if Redmine::Scm::Adapters::SubversionAdapter.client_version_above?([1, 5, 0]) |
|
83 | 83 | assert_not_nil assigns(:properties) |
|
84 | 84 | assert_equal 'native', assigns(:properties)['svn:eol-style'] |
|
85 | 85 | assert_tag :ul, |
|
86 | 86 | :child => { :tag => 'li', |
|
87 | 87 | :child => { :tag => 'b', :content => 'svn:eol-style' }, |
|
88 | 88 | :child => { :tag => 'span', :content => 'native' } } |
|
89 | 89 | end |
|
90 | 90 | end |
|
91 | 91 | |
|
92 | 92 | def test_entry |
|
93 | 93 | get :entry, :id => 1, :path => ['subversion_test', 'helloworld.c'] |
|
94 | 94 | assert_response :success |
|
95 | 95 | assert_template 'entry' |
|
96 | 96 | end |
|
97 | 97 | |
|
98 | 98 | def test_entry_at_given_revision |
|
99 | 99 | get :entry, :id => 1, :path => ['subversion_test', 'helloworld.rb'], :rev => 2 |
|
100 | 100 | assert_response :success |
|
101 | 101 | assert_template 'entry' |
|
102 | 102 | # this line was removed in r3 and file was moved in r6 |
|
103 | 103 | assert_tag :tag => 'td', :attributes => { :class => /line-code/}, |
|
104 | 104 | :content => /Here's the code/ |
|
105 | 105 | end |
|
106 | 106 | |
|
107 | 107 | def test_entry_not_found |
|
108 | 108 | get :entry, :id => 1, :path => ['subversion_test', 'zzz.c'] |
|
109 | 109 | assert_tag :tag => 'div', :attributes => { :class => /error/ }, |
|
110 | 110 | :content => /The entry or revision was not found in the repository/ |
|
111 | 111 | end |
|
112 | 112 | |
|
113 | 113 | def test_entry_download |
|
114 | 114 | get :entry, :id => 1, :path => ['subversion_test', 'helloworld.c'], :format => 'raw' |
|
115 | 115 | assert_response :success |
|
116 | 116 | end |
|
117 | 117 | |
|
118 | 118 | def test_directory_entry |
|
119 | 119 | get :entry, :id => 1, :path => ['subversion_test', 'folder'] |
|
120 | 120 | assert_response :success |
|
121 | 121 | assert_template 'browse' |
|
122 | 122 | assert_not_nil assigns(:entry) |
|
123 | 123 | assert_equal 'folder', assigns(:entry).name |
|
124 | 124 | end |
|
125 | 125 | |
|
126 | 126 | def test_revision |
|
127 | 127 | get :revision, :id => 1, :rev => 2 |
|
128 | 128 | assert_response :success |
|
129 | 129 | assert_template 'revision' |
|
130 | 130 | assert_tag :tag => 'ul', |
|
131 | 131 | :child => { :tag => 'li', |
|
132 | 132 | # link to the entry at rev 2 |
|
133 | 133 | :child => { :tag => 'a', |
|
134 |
:attributes => {:href => '/repositor |
|
|
134 | :attributes => {:href => '/projects/ecookbook/repository/revisions/2/entry/test/some/path/in/the/repo'}, | |
|
135 | 135 | :content => 'repo', |
|
136 | 136 | # link to partial diff |
|
137 | 137 | :sibling => { :tag => 'a', |
|
138 |
:attributes => { :href => '/repositor |
|
|
138 | :attributes => { :href => '/projects/ecookbook/repository/revisions/2/diff/test/some/path/in/the/repo' } | |
|
139 | 139 | } |
|
140 | 140 | } |
|
141 | 141 | } |
|
142 | 142 | end |
|
143 | 143 | |
|
144 | 144 | def test_revision_with_repository_pointing_to_a_subdirectory |
|
145 | 145 | r = Project.find(1).repository |
|
146 | 146 | # Changes repository url to a subdirectory |
|
147 | 147 | r.update_attribute :url, (r.url + '/test/some') |
|
148 | 148 | |
|
149 | 149 | get :revision, :id => 1, :rev => 2 |
|
150 | 150 | assert_response :success |
|
151 | 151 | assert_template 'revision' |
|
152 | 152 | assert_tag :tag => 'ul', |
|
153 | 153 | :child => { :tag => 'li', |
|
154 | 154 | # link to the entry at rev 2 |
|
155 | 155 | :child => { :tag => 'a', |
|
156 |
:attributes => {:href => '/repositor |
|
|
156 | :attributes => {:href => '/projects/ecookbook/repository/revisions/2/entry/path/in/the/repo'}, | |
|
157 | 157 | :content => 'repo', |
|
158 | 158 | # link to partial diff |
|
159 | 159 | :sibling => { :tag => 'a', |
|
160 |
:attributes => { :href => '/repositor |
|
|
160 | :attributes => { :href => '/projects/ecookbook/repository/revisions/2/diff/path/in/the/repo' } | |
|
161 | 161 | } |
|
162 | 162 | } |
|
163 | 163 | } |
|
164 | 164 | end |
|
165 | 165 | |
|
166 | 166 | def test_diff |
|
167 | 167 | get :diff, :id => 1, :rev => 3 |
|
168 | 168 | assert_response :success |
|
169 | 169 | assert_template 'diff' |
|
170 | 170 | end |
|
171 | 171 | |
|
172 | 172 | def test_annotate |
|
173 | 173 | get :annotate, :id => 1, :path => ['subversion_test', 'helloworld.c'] |
|
174 | 174 | assert_response :success |
|
175 | 175 | assert_template 'annotate' |
|
176 | 176 | end |
|
177 | 177 | else |
|
178 | 178 | puts "Subversion test repository NOT FOUND. Skipping functional tests !!!" |
|
179 | 179 | def test_fake; assert true end |
|
180 | 180 | end |
|
181 | 181 | end |
@@ -1,278 +1,385 | |||
|
1 | 1 | # redMine - project management software |
|
2 | 2 | # Copyright (C) 2006-2007 Jean-Philippe Lang |
|
3 | 3 | # |
|
4 | 4 | # This program is free software; you can redistribute it and/or |
|
5 | 5 | # modify it under the terms of the GNU General Public License |
|
6 | 6 | # as published by the Free Software Foundation; either version 2 |
|
7 | 7 | # of the License, or (at your option) any later version. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU General Public License |
|
15 | 15 | # along with this program; if not, write to the Free Software |
|
16 | 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 | 17 | |
|
18 | 18 | require File.dirname(__FILE__) + '/../test_helper' |
|
19 | 19 | require 'timelog_controller' |
|
20 | 20 | |
|
21 | 21 | # Re-raise errors caught by the controller. |
|
22 | 22 | class TimelogController; def rescue_action(e) raise e end; end |
|
23 | 23 | |
|
24 | 24 | class TimelogControllerTest < Test::Unit::TestCase |
|
25 | 25 | fixtures :projects, :enabled_modules, :roles, :members, :issues, :time_entries, :users, :trackers, :enumerations, :issue_statuses, :custom_fields, :custom_values |
|
26 | 26 | |
|
27 | 27 | def setup |
|
28 | 28 | @controller = TimelogController.new |
|
29 | 29 | @request = ActionController::TestRequest.new |
|
30 | 30 | @response = ActionController::TestResponse.new |
|
31 | 31 | end |
|
32 | 32 | |
|
33 | def test_edit_routing | |
|
34 | assert_routing( | |
|
35 | {:method => :get, :path => '/issues/567/time_entries/new'}, | |
|
36 | :controller => 'timelog', :action => 'edit', :issue_id => '567' | |
|
37 | ) | |
|
38 | assert_routing( | |
|
39 | {:method => :get, :path => '/projects/ecookbook/time_entries/new'}, | |
|
40 | :controller => 'timelog', :action => 'edit', :project_id => 'ecookbook' | |
|
41 | ) | |
|
42 | assert_routing( | |
|
43 | {:method => :get, :path => '/projects/ecookbook/issues/567/time_entries/new'}, | |
|
44 | :controller => 'timelog', :action => 'edit', :project_id => 'ecookbook', :issue_id => '567' | |
|
45 | ) | |
|
46 | ||
|
47 | #TODO: change new form to POST to issue_time_entries_path instead of to edit action | |
|
48 | #TODO: change edit form to PUT to time_entry_path | |
|
49 | assert_routing( | |
|
50 | {:method => :get, :path => '/time_entries/22/edit'}, | |
|
51 | :controller => 'timelog', :action => 'edit', :id => '22' | |
|
52 | ) | |
|
53 | end | |
|
54 | ||
|
33 | 55 | def test_get_edit |
|
34 | 56 | @request.session[:user_id] = 3 |
|
35 | 57 | get :edit, :project_id => 1 |
|
36 | 58 | assert_response :success |
|
37 | 59 | assert_template 'edit' |
|
38 | 60 | # Default activity selected |
|
39 | 61 | assert_tag :tag => 'option', :attributes => { :selected => 'selected' }, |
|
40 | 62 | :content => 'Development' |
|
41 | 63 | end |
|
42 | 64 | |
|
43 | 65 | def test_post_edit |
|
66 | # TODO: should POST to issuesβ time log instead of project. change form | |
|
67 | # and routing | |
|
44 | 68 | @request.session[:user_id] = 3 |
|
45 | 69 | post :edit, :project_id => 1, |
|
46 | 70 | :time_entry => {:comments => 'Some work on TimelogControllerTest', |
|
47 | 71 | # Not the default activity |
|
48 | 72 | :activity_id => '11', |
|
49 | 73 | :spent_on => '2008-03-14', |
|
50 | 74 | :issue_id => '1', |
|
51 | 75 | :hours => '7.3'} |
|
52 |
assert_redirected_to 'project |
|
|
76 | assert_redirected_to :action => 'details', :project_id => 'ecookbook' | |
|
53 | 77 | |
|
54 | 78 | i = Issue.find(1) |
|
55 | 79 | t = TimeEntry.find_by_comments('Some work on TimelogControllerTest') |
|
56 | 80 | assert_not_nil t |
|
57 | 81 | assert_equal 11, t.activity_id |
|
58 | 82 | assert_equal 7.3, t.hours |
|
59 | 83 | assert_equal 3, t.user_id |
|
60 | 84 | assert_equal i, t.issue |
|
61 | 85 | assert_equal i.project, t.project |
|
62 | 86 | end |
|
63 | 87 | |
|
64 | 88 | def test_update |
|
65 | 89 | entry = TimeEntry.find(1) |
|
66 | 90 | assert_equal 1, entry.issue_id |
|
67 | 91 | assert_equal 2, entry.user_id |
|
68 | 92 | |
|
69 | 93 | @request.session[:user_id] = 1 |
|
70 | 94 | post :edit, :id => 1, |
|
71 | 95 | :time_entry => {:issue_id => '2', |
|
72 | 96 | :hours => '8'} |
|
73 |
assert_redirected_to 'project |
|
|
97 | assert_redirected_to :action => 'details', :project_id => 'ecookbook' | |
|
74 | 98 | entry.reload |
|
75 | 99 | |
|
76 | 100 | assert_equal 8, entry.hours |
|
77 | 101 | assert_equal 2, entry.issue_id |
|
78 | 102 | assert_equal 2, entry.user_id |
|
79 | 103 | end |
|
80 | 104 | |
|
105 | def test_destroy_routing | |
|
106 | #TODO: use DELETE to time_entry_path | |
|
107 | assert_routing( | |
|
108 | {:method => :post, :path => '/time_entries/55/destroy'}, | |
|
109 | :controller => 'timelog', :action => 'destroy', :id => '55' | |
|
110 | ) | |
|
111 | end | |
|
112 | ||
|
81 | 113 | def test_destroy |
|
82 | 114 | @request.session[:user_id] = 2 |
|
83 | 115 | post :destroy, :id => 1 |
|
84 |
assert_redirected_to 'project |
|
|
116 | assert_redirected_to :action => 'details', :project_id => 'ecookbook' | |
|
85 | 117 | assert_nil TimeEntry.find_by_id(1) |
|
86 | 118 | end |
|
87 | 119 | |
|
120 | def test_report_routing | |
|
121 | assert_routing( | |
|
122 | {:method => :get, :path => '/projects/567/time_entries/report'}, | |
|
123 | :controller => 'timelog', :action => 'report', :project_id => '567' | |
|
124 | ) | |
|
125 | assert_routing( | |
|
126 | {:method => :get, :path => '/projects/567/time_entries/report.csv'}, | |
|
127 | :controller => 'timelog', :action => 'report', :project_id => '567', :format => 'csv' | |
|
128 | ) | |
|
129 | end | |
|
130 | ||
|
88 | 131 | def test_report_no_criteria |
|
89 | 132 | get :report, :project_id => 1 |
|
90 | 133 | assert_response :success |
|
91 | 134 | assert_template 'report' |
|
92 | 135 | end |
|
93 | 136 | |
|
137 | def test_report_routing_for_all_projects | |
|
138 | assert_routing( | |
|
139 | {:method => :get, :path => '/time_entries/report'}, | |
|
140 | :controller => 'timelog', :action => 'report' | |
|
141 | ) | |
|
142 | end | |
|
143 | ||
|
94 | 144 | def test_report_all_projects |
|
95 | 145 | get :report |
|
96 | 146 | assert_response :success |
|
97 | 147 | assert_template 'report' |
|
98 | 148 | end |
|
99 | 149 | |
|
100 | 150 | def test_report_all_projects_denied |
|
101 | 151 | r = Role.anonymous |
|
102 | 152 | r.permissions.delete(:view_time_entries) |
|
103 | 153 | r.permissions_will_change! |
|
104 | 154 | r.save |
|
105 | 155 | get :report |
|
106 |
assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Ftime |
|
|
156 | assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Ftime_entries%2Freport' | |
|
107 | 157 | end |
|
108 | 158 | |
|
109 | 159 | def test_report_all_projects_one_criteria |
|
110 | 160 | get :report, :columns => 'week', :from => "2007-04-01", :to => "2007-04-30", :criterias => ['project'] |
|
111 | 161 | assert_response :success |
|
112 | 162 | assert_template 'report' |
|
113 | 163 | assert_not_nil assigns(:total_hours) |
|
114 | 164 | assert_equal "8.65", "%.2f" % assigns(:total_hours) |
|
115 | 165 | end |
|
116 | 166 | |
|
117 | 167 | def test_report_all_time |
|
118 | 168 | get :report, :project_id => 1, :criterias => ['project', 'issue'] |
|
119 | 169 | assert_response :success |
|
120 | 170 | assert_template 'report' |
|
121 | 171 | assert_not_nil assigns(:total_hours) |
|
122 | 172 | assert_equal "162.90", "%.2f" % assigns(:total_hours) |
|
123 | 173 | end |
|
124 | 174 | |
|
125 | 175 | def test_report_all_time_by_day |
|
126 | 176 | get :report, :project_id => 1, :criterias => ['project', 'issue'], :columns => 'day' |
|
127 | 177 | assert_response :success |
|
128 | 178 | assert_template 'report' |
|
129 | 179 | assert_not_nil assigns(:total_hours) |
|
130 | 180 | assert_equal "162.90", "%.2f" % assigns(:total_hours) |
|
131 | 181 | assert_tag :tag => 'th', :content => '2007-03-12' |
|
132 | 182 | end |
|
133 | 183 | |
|
134 | 184 | def test_report_one_criteria |
|
135 | 185 | get :report, :project_id => 1, :columns => 'week', :from => "2007-04-01", :to => "2007-04-30", :criterias => ['project'] |
|
136 | 186 | assert_response :success |
|
137 | 187 | assert_template 'report' |
|
138 | 188 | assert_not_nil assigns(:total_hours) |
|
139 | 189 | assert_equal "8.65", "%.2f" % assigns(:total_hours) |
|
140 | 190 | end |
|
141 | 191 | |
|
142 | 192 | def test_report_two_criterias |
|
143 | 193 | get :report, :project_id => 1, :columns => 'month', :from => "2007-01-01", :to => "2007-12-31", :criterias => ["member", "activity"] |
|
144 | 194 | assert_response :success |
|
145 | 195 | assert_template 'report' |
|
146 | 196 | assert_not_nil assigns(:total_hours) |
|
147 | 197 | assert_equal "162.90", "%.2f" % assigns(:total_hours) |
|
148 | 198 | end |
|
149 | 199 | |
|
150 | 200 | def test_report_custom_field_criteria |
|
151 | 201 | get :report, :project_id => 1, :criterias => ['project', 'cf_1'] |
|
152 | 202 | assert_response :success |
|
153 | 203 | assert_template 'report' |
|
154 | 204 | assert_not_nil assigns(:total_hours) |
|
155 | 205 | assert_not_nil assigns(:criterias) |
|
156 | 206 | assert_equal 2, assigns(:criterias).size |
|
157 | 207 | assert_equal "162.90", "%.2f" % assigns(:total_hours) |
|
158 | 208 | # Custom field column |
|
159 | 209 | assert_tag :tag => 'th', :content => 'Database' |
|
160 | 210 | # Custom field row |
|
161 | 211 | assert_tag :tag => 'td', :content => 'MySQL', |
|
162 | 212 | :sibling => { :tag => 'td', :attributes => { :class => 'hours' }, |
|
163 | 213 | :child => { :tag => 'span', :attributes => { :class => 'hours hours-int' }, |
|
164 | 214 | :content => '1' }} |
|
165 | 215 | end |
|
166 | 216 | |
|
167 | 217 | def test_report_one_criteria_no_result |
|
168 | 218 | get :report, :project_id => 1, :columns => 'week', :from => "1998-04-01", :to => "1998-04-30", :criterias => ['project'] |
|
169 | 219 | assert_response :success |
|
170 | 220 | assert_template 'report' |
|
171 | 221 | assert_not_nil assigns(:total_hours) |
|
172 | 222 | assert_equal "0.00", "%.2f" % assigns(:total_hours) |
|
173 | 223 | end |
|
174 | 224 | |
|
175 | 225 | def test_report_all_projects_csv_export |
|
176 | 226 | get :report, :columns => 'month', :from => "2007-01-01", :to => "2007-06-30", :criterias => ["project", "member", "activity"], :format => "csv" |
|
177 | 227 | assert_response :success |
|
178 | 228 | assert_equal 'text/csv', @response.content_type |
|
179 | 229 | lines = @response.body.chomp.split("\n") |
|
180 | 230 | # Headers |
|
181 | 231 | assert_equal 'Project,Member,Activity,2007-1,2007-2,2007-3,2007-4,2007-5,2007-6,Total', lines.first |
|
182 | 232 | # Total row |
|
183 | 233 | assert_equal 'Total,"","","","",154.25,8.65,"","",162.90', lines.last |
|
184 | 234 | end |
|
185 | 235 | |
|
186 | 236 | def test_report_csv_export |
|
187 | 237 | get :report, :project_id => 1, :columns => 'month', :from => "2007-01-01", :to => "2007-06-30", :criterias => ["project", "member", "activity"], :format => "csv" |
|
188 | 238 | assert_response :success |
|
189 | 239 | assert_equal 'text/csv', @response.content_type |
|
190 | 240 | lines = @response.body.chomp.split("\n") |
|
191 | 241 | # Headers |
|
192 | 242 | assert_equal 'Project,Member,Activity,2007-1,2007-2,2007-3,2007-4,2007-5,2007-6,Total', lines.first |
|
193 | 243 | # Total row |
|
194 | 244 | assert_equal 'Total,"","","","",154.25,8.65,"","",162.90', lines.last |
|
195 | 245 | end |
|
196 | 246 | |
|
197 | 247 | def test_details_all_projects |
|
198 | 248 | get :details |
|
199 | 249 | assert_response :success |
|
200 | 250 | assert_template 'details' |
|
201 | 251 | assert_not_nil assigns(:total_hours) |
|
202 | 252 | assert_equal "162.90", "%.2f" % assigns(:total_hours) |
|
203 | 253 | end |
|
204 | 254 | |
|
255 | def test_project_details_routing | |
|
256 | assert_routing( | |
|
257 | {:method => :get, :path => '/projects/567/time_entries'}, | |
|
258 | :controller => 'timelog', :action => 'details', :project_id => '567' | |
|
259 | ) | |
|
260 | end | |
|
261 | ||
|
205 | 262 | def test_details_at_project_level |
|
206 | 263 | get :details, :project_id => 1 |
|
207 | 264 | assert_response :success |
|
208 | 265 | assert_template 'details' |
|
209 | 266 | assert_not_nil assigns(:entries) |
|
210 | 267 | assert_equal 4, assigns(:entries).size |
|
211 | 268 | # project and subproject |
|
212 | 269 | assert_equal [1, 3], assigns(:entries).collect(&:project_id).uniq.sort |
|
213 | 270 | assert_not_nil assigns(:total_hours) |
|
214 | 271 | assert_equal "162.90", "%.2f" % assigns(:total_hours) |
|
215 | 272 | # display all time by default |
|
216 | 273 | assert_equal '2007-03-11'.to_date, assigns(:from) |
|
217 | 274 | assert_equal '2007-04-22'.to_date, assigns(:to) |
|
218 | 275 | end |
|
219 | 276 | |
|
220 | 277 | def test_details_at_project_level_with_date_range |
|
221 | 278 | get :details, :project_id => 1, :from => '2007-03-20', :to => '2007-04-30' |
|
222 | 279 | assert_response :success |
|
223 | 280 | assert_template 'details' |
|
224 | 281 | assert_not_nil assigns(:entries) |
|
225 | 282 | assert_equal 3, assigns(:entries).size |
|
226 | 283 | assert_not_nil assigns(:total_hours) |
|
227 | 284 | assert_equal "12.90", "%.2f" % assigns(:total_hours) |
|
228 | 285 | assert_equal '2007-03-20'.to_date, assigns(:from) |
|
229 | 286 | assert_equal '2007-04-30'.to_date, assigns(:to) |
|
230 | 287 | end |
|
231 | 288 | |
|
232 | 289 | def test_details_at_project_level_with_period |
|
233 | 290 | get :details, :project_id => 1, :period => '7_days' |
|
234 | 291 | assert_response :success |
|
235 | 292 | assert_template 'details' |
|
236 | 293 | assert_not_nil assigns(:entries) |
|
237 | 294 | assert_not_nil assigns(:total_hours) |
|
238 | 295 | assert_equal Date.today - 7, assigns(:from) |
|
239 | 296 | assert_equal Date.today, assigns(:to) |
|
240 | 297 | end |
|
241 | 298 | |
|
299 | def test_issue_details_routing | |
|
300 | assert_routing( | |
|
301 | {:method => :get, :path => 'time_entries'}, | |
|
302 | :controller => 'timelog', :action => 'details' | |
|
303 | ) | |
|
304 | assert_routing( | |
|
305 | {:method => :get, :path => '/issues/234/time_entries'}, | |
|
306 | :controller => 'timelog', :action => 'details', :issue_id => '234' | |
|
307 | ) | |
|
308 | # TODO: issue detail page shouldnt link to project_issue_time_entries_path but to normal issues one | |
|
309 | # doesnt seem to have effect on resulting page so controller can be left untouched | |
|
310 | assert_routing( | |
|
311 | {:method => :get, :path => '/projects/ecookbook/issues/123/time_entries'}, | |
|
312 | :controller => 'timelog', :action => 'details', :project_id => 'ecookbook', :issue_id => '123' | |
|
313 | ) | |
|
314 | end | |
|
315 | ||
|
242 | 316 | def test_details_at_issue_level |
|
243 | 317 | get :details, :issue_id => 1 |
|
244 | 318 | assert_response :success |
|
245 | 319 | assert_template 'details' |
|
246 | 320 | assert_not_nil assigns(:entries) |
|
247 | 321 | assert_equal 2, assigns(:entries).size |
|
248 | 322 | assert_not_nil assigns(:total_hours) |
|
249 | 323 | assert_equal 154.25, assigns(:total_hours) |
|
250 | 324 | # display all time by default |
|
251 | 325 | assert_equal '2007-03-11'.to_date, assigns(:from) |
|
252 | 326 | assert_equal '2007-04-22'.to_date, assigns(:to) |
|
253 | 327 | end |
|
254 | 328 | |
|
329 | def test_details_formatted_routing | |
|
330 | assert_routing( | |
|
331 | {:method => :get, :path => 'time_entries.atom'}, | |
|
332 | :controller => 'timelog', :action => 'details', :format => 'atom' | |
|
333 | ) | |
|
334 | assert_routing( | |
|
335 | {:method => :get, :path => 'time_entries.csv'}, | |
|
336 | :controller => 'timelog', :action => 'details', :format => 'csv' | |
|
337 | ) | |
|
338 | end | |
|
339 | ||
|
340 | def test_details_for_project_formatted_routing | |
|
341 | assert_routing( | |
|
342 | {:method => :get, :path => '/projects/567/time_entries.atom'}, | |
|
343 | :controller => 'timelog', :action => 'details', :format => 'atom', :project_id => '567' | |
|
344 | ) | |
|
345 | assert_routing( | |
|
346 | {:method => :get, :path => '/projects/567/time_entries.csv'}, | |
|
347 | :controller => 'timelog', :action => 'details', :format => 'csv', :project_id => '567' | |
|
348 | ) | |
|
349 | end | |
|
350 | ||
|
351 | def test_details_for_issue_formatted_routing | |
|
352 | assert_routing( | |
|
353 | {:method => :get, :path => '/projects/ecookbook/issues/123/time_entries.atom'}, | |
|
354 | :controller => 'timelog', :action => 'details', :project_id => 'ecookbook', :issue_id => '123', :format => 'atom' | |
|
355 | ) | |
|
356 | assert_routing( | |
|
357 | {:method => :get, :path => '/projects/ecookbook/issues/123/time_entries.csv'}, | |
|
358 | :controller => 'timelog', :action => 'details', :project_id => 'ecookbook', :issue_id => '123', :format => 'csv' | |
|
359 | ) | |
|
360 | end | |
|
361 | ||
|
255 | 362 | def test_details_atom_feed |
|
256 | 363 | get :details, :project_id => 1, :format => 'atom' |
|
257 | 364 | assert_response :success |
|
258 | 365 | assert_equal 'application/atom+xml', @response.content_type |
|
259 | 366 | assert_not_nil assigns(:items) |
|
260 | 367 | assert assigns(:items).first.is_a?(TimeEntry) |
|
261 | 368 | end |
|
262 | 369 | |
|
263 | 370 | def test_details_all_projects_csv_export |
|
264 | 371 | get :details, :format => 'csv' |
|
265 | 372 | assert_response :success |
|
266 | 373 | assert_equal 'text/csv', @response.content_type |
|
267 | 374 | assert @response.body.include?("Date,User,Activity,Project,Issue,Tracker,Subject,Hours,Comment\n") |
|
268 | 375 | assert @response.body.include?("\n04/21/2007,redMine Admin,Design,eCookbook,3,Bug,Error 281 when updating a recipe,1.0,\"\"\n") |
|
269 | 376 | end |
|
270 | 377 | |
|
271 | 378 | def test_details_csv_export |
|
272 | 379 | get :details, :project_id => 1, :format => 'csv' |
|
273 | 380 | assert_response :success |
|
274 | 381 | assert_equal 'text/csv', @response.content_type |
|
275 | 382 | assert @response.body.include?("Date,User,Activity,Project,Issue,Tracker,Subject,Hours,Comment\n") |
|
276 | 383 | assert @response.body.include?("\n04/21/2007,redMine Admin,Design,eCookbook,3,Bug,Error 281 when updating a recipe,1.0,\"\"\n") |
|
277 | 384 | end |
|
278 | 385 | end |
@@ -1,72 +1,142 | |||
|
1 | 1 | # redMine - project management software |
|
2 | 2 | # Copyright (C) 2006-2007 Jean-Philippe Lang |
|
3 | 3 | # |
|
4 | 4 | # This program is free software; you can redistribute it and/or |
|
5 | 5 | # modify it under the terms of the GNU General Public License |
|
6 | 6 | # as published by the Free Software Foundation; either version 2 |
|
7 | 7 | # of the License, or (at your option) any later version. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU General Public License |
|
15 | 15 | # along with this program; if not, write to the Free Software |
|
16 | 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 | 17 | |
|
18 | 18 | require File.dirname(__FILE__) + '/../test_helper' |
|
19 | 19 | require 'users_controller' |
|
20 | 20 | |
|
21 | 21 | # Re-raise errors caught by the controller. |
|
22 | 22 | class UsersController; def rescue_action(e) raise e end; end |
|
23 | 23 | |
|
24 | 24 | class UsersControllerTest < Test::Unit::TestCase |
|
25 | 25 | fixtures :users, :projects, :members |
|
26 | 26 | |
|
27 | 27 | def setup |
|
28 | 28 | @controller = UsersController.new |
|
29 | 29 | @request = ActionController::TestRequest.new |
|
30 | 30 | @response = ActionController::TestResponse.new |
|
31 | 31 | User.current = nil |
|
32 | 32 | @request.session[:user_id] = 1 # admin |
|
33 | 33 | end |
|
34 | 34 | |
|
35 | def test_index_routing | |
|
36 | #TODO: unify with list | |
|
37 | assert_generates( | |
|
38 | '/users', | |
|
39 | :controller => 'users', :action => 'index' | |
|
40 | ) | |
|
41 | end | |
|
42 | ||
|
35 | 43 | def test_index |
|
36 | 44 | get :index |
|
37 | 45 | assert_response :success |
|
38 | 46 | assert_template 'list' |
|
39 | 47 | end |
|
40 | 48 | |
|
49 | def test_list_routing | |
|
50 | #TODO: rename action to index | |
|
51 | assert_routing( | |
|
52 | {:method => :get, :path => '/users'}, | |
|
53 | :controller => 'users', :action => 'list' | |
|
54 | ) | |
|
55 | end | |
|
56 | ||
|
41 | 57 | def test_list |
|
42 | 58 | get :list |
|
43 | 59 | assert_response :success |
|
44 | 60 | assert_template 'list' |
|
45 | 61 | assert_not_nil assigns(:users) |
|
46 | 62 | # active users only |
|
47 | 63 | assert_nil assigns(:users).detect {|u| !u.active?} |
|
48 | 64 | end |
|
49 | 65 | |
|
50 | 66 | def test_list_with_name_filter |
|
51 | 67 | get :list, :name => 'john' |
|
52 | 68 | assert_response :success |
|
53 | 69 | assert_template 'list' |
|
54 | 70 | users = assigns(:users) |
|
55 | 71 | assert_not_nil users |
|
56 | 72 | assert_equal 1, users.size |
|
57 | 73 | assert_equal 'John', users.first.firstname |
|
58 | 74 | end |
|
59 | 75 | |
|
76 | def test_add_routing | |
|
77 | assert_routing( | |
|
78 | {:method => :get, :path => '/users/new'}, | |
|
79 | :controller => 'users', :action => 'add' | |
|
80 | ) | |
|
81 | assert_recognizes( | |
|
82 | #TODO: remove this and replace with POST to collection, need to modify form | |
|
83 | {:controller => 'users', :action => 'add'}, | |
|
84 | {:method => :post, :path => '/users/new'} | |
|
85 | ) | |
|
86 | assert_recognizes( | |
|
87 | {:controller => 'users', :action => 'add'}, | |
|
88 | {:method => :post, :path => '/users'} | |
|
89 | ) | |
|
90 | end | |
|
91 | ||
|
92 | def test_edit_routing | |
|
93 | assert_routing( | |
|
94 | {:method => :get, :path => '/users/444/edit'}, | |
|
95 | :controller => 'users', :action => 'edit', :id => '444' | |
|
96 | ) | |
|
97 | assert_routing( | |
|
98 | {:method => :get, :path => '/users/222/edit/membership'}, | |
|
99 | :controller => 'users', :action => 'edit', :id => '222', :tab => 'membership' | |
|
100 | ) | |
|
101 | assert_recognizes( | |
|
102 | #TODO: use PUT on user_path, modify form | |
|
103 | {:controller => 'users', :action => 'edit', :id => '444'}, | |
|
104 | {:method => :post, :path => '/users/444/edit'} | |
|
105 | ) | |
|
106 | end | |
|
107 | ||
|
108 | def test_add_membership_routing | |
|
109 | assert_routing( | |
|
110 | {:method => :post, :path => '/users/123/memberships'}, | |
|
111 | :controller => 'users', :action => 'edit_membership', :id => '123' | |
|
112 | ) | |
|
113 | end | |
|
114 | ||
|
115 | def test_edit_membership_routing | |
|
116 | assert_routing( | |
|
117 | {:method => :post, :path => '/users/123/memberships/55'}, | |
|
118 | :controller => 'users', :action => 'edit_membership', :id => '123', :membership_id => '55' | |
|
119 | ) | |
|
120 | end | |
|
121 | ||
|
60 | 122 | def test_edit_membership |
|
61 | 123 | post :edit_membership, :id => 2, :membership_id => 1, |
|
62 | 124 | :membership => { :role_id => 2} |
|
63 |
assert_redirected_to |
|
|
125 | assert_redirected_to :action => 'edit', :id => '2', :tab => 'memberships' | |
|
64 | 126 | assert_equal 2, Member.find(1).role_id |
|
65 | 127 | end |
|
66 | 128 | |
|
67 | 129 | def test_destroy_membership |
|
130 | assert_routing( | |
|
131 | #TODO: use DELETE method on user_membership_path, modify form | |
|
132 | {:method => :post, :path => '/users/567/memberships/12/destroy'}, | |
|
133 | :controller => 'users', :action => 'destroy_membership', :id => '567', :membership_id => '12' | |
|
134 | ) | |
|
135 | end | |
|
136 | ||
|
137 | def test_destroy_membership | |
|
68 | 138 | post :destroy_membership, :id => 2, :membership_id => 1 |
|
69 |
assert_redirected_to |
|
|
139 | assert_redirected_to :action => 'edit', :id => '2', :tab => 'memberships' | |
|
70 | 140 | assert_nil Member.find_by_id(1) |
|
71 | 141 | end |
|
72 | 142 | end |
@@ -1,73 +1,73 | |||
|
1 | 1 | # redMine - project management software |
|
2 | 2 | # Copyright (C) 2006-2007 Jean-Philippe Lang |
|
3 | 3 | # |
|
4 | 4 | # This program is free software; you can redistribute it and/or |
|
5 | 5 | # modify it under the terms of the GNU General Public License |
|
6 | 6 | # as published by the Free Software Foundation; either version 2 |
|
7 | 7 | # of the License, or (at your option) any later version. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU General Public License |
|
15 | 15 | # along with this program; if not, write to the Free Software |
|
16 | 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 | 17 | |
|
18 | 18 | require File.dirname(__FILE__) + '/../test_helper' |
|
19 | 19 | require 'versions_controller' |
|
20 | 20 | |
|
21 | 21 | # Re-raise errors caught by the controller. |
|
22 | 22 | class VersionsController; def rescue_action(e) raise e end; end |
|
23 | 23 | |
|
24 | 24 | class VersionsControllerTest < Test::Unit::TestCase |
|
25 | 25 | fixtures :projects, :versions, :issues, :users, :roles, :members, :enabled_modules |
|
26 | 26 | |
|
27 | 27 | def setup |
|
28 | 28 | @controller = VersionsController.new |
|
29 | 29 | @request = ActionController::TestRequest.new |
|
30 | 30 | @response = ActionController::TestResponse.new |
|
31 | 31 | User.current = nil |
|
32 | 32 | end |
|
33 | 33 | |
|
34 | 34 | def test_show |
|
35 | 35 | get :show, :id => 2 |
|
36 | 36 | assert_response :success |
|
37 | 37 | assert_template 'show' |
|
38 | 38 | assert_not_nil assigns(:version) |
|
39 | 39 | |
|
40 | 40 | assert_tag :tag => 'h2', :content => /1.0/ |
|
41 | 41 | end |
|
42 | 42 | |
|
43 | 43 | def test_get_edit |
|
44 | 44 | @request.session[:user_id] = 2 |
|
45 | 45 | get :edit, :id => 2 |
|
46 | 46 | assert_response :success |
|
47 | 47 | assert_template 'edit' |
|
48 | 48 | end |
|
49 | 49 | |
|
50 | 50 | def test_post_edit |
|
51 | 51 | @request.session[:user_id] = 2 |
|
52 | 52 | post :edit, :id => 2, |
|
53 | 53 | :version => { :name => 'New version name', |
|
54 | 54 | :effective_date => Date.today.strftime("%Y-%m-%d")} |
|
55 | assert_redirected_to '/projects/settings/ecookbook?tab=versions' | |
|
55 | assert_redirected_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => 'ecookbook' | |
|
56 | 56 | version = Version.find(2) |
|
57 | 57 | assert_equal 'New version name', version.name |
|
58 | 58 | assert_equal Date.today, version.effective_date |
|
59 | 59 | end |
|
60 | 60 | |
|
61 | 61 | def test_destroy |
|
62 | 62 | @request.session[:user_id] = 2 |
|
63 | 63 | post :destroy, :id => 3 |
|
64 | assert_redirected_to '/projects/settings/ecookbook?tab=versions' | |
|
64 | assert_redirected_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => 'ecookbook' | |
|
65 | 65 | assert_nil Version.find_by_id(3) |
|
66 | 66 | end |
|
67 | 67 | |
|
68 | 68 | def test_issue_status_by |
|
69 | 69 | xhr :get, :status_by, :id => 2 |
|
70 | 70 | assert_response :success |
|
71 | 71 | assert_template '_issue_counts' |
|
72 | 72 | end |
|
73 | 73 | end |
@@ -1,259 +1,359 | |||
|
1 | 1 | # redMine - project management software |
|
2 | 2 | # Copyright (C) 2006-2007 Jean-Philippe Lang |
|
3 | 3 | # |
|
4 | 4 | # This program is free software; you can redistribute it and/or |
|
5 | 5 | # modify it under the terms of the GNU General Public License |
|
6 | 6 | # as published by the Free Software Foundation; either version 2 |
|
7 | 7 | # of the License, or (at your option) any later version. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU General Public License |
|
15 | 15 | # along with this program; if not, write to the Free Software |
|
16 | 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 | 17 | |
|
18 | 18 | require File.dirname(__FILE__) + '/../test_helper' |
|
19 | 19 | require 'wiki_controller' |
|
20 | 20 | |
|
21 | 21 | # Re-raise errors caught by the controller. |
|
22 | 22 | class WikiController; def rescue_action(e) raise e end; end |
|
23 | 23 | |
|
24 | 24 | class WikiControllerTest < Test::Unit::TestCase |
|
25 | 25 | fixtures :projects, :users, :roles, :members, :enabled_modules, :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions, :attachments |
|
26 | 26 | |
|
27 | 27 | def setup |
|
28 | 28 | @controller = WikiController.new |
|
29 | 29 | @request = ActionController::TestRequest.new |
|
30 | 30 | @response = ActionController::TestResponse.new |
|
31 | 31 | User.current = nil |
|
32 | 32 | end |
|
33 | 33 | |
|
34 | def test_index_routing | |
|
35 | assert_routing( | |
|
36 | {:method => :get, :path => '/projects/567/wiki'}, | |
|
37 | :controller => 'wiki', :action => 'index', :id => '567' | |
|
38 | ) | |
|
39 | assert_routing( | |
|
40 | {:method => :get, :path => '/projects/567/wiki/lalala'}, | |
|
41 | :controller => 'wiki', :action => 'index', :id => '567', :page => 'lalala' | |
|
42 | ) | |
|
43 | assert_generates( | |
|
44 | '/projects/567/wiki', | |
|
45 | :controller => 'wiki', :action => 'index', :id => '567', :page => nil | |
|
46 | ) | |
|
47 | end | |
|
48 | ||
|
34 | 49 | def test_show_start_page |
|
35 | 50 | get :index, :id => 'ecookbook' |
|
36 | 51 | assert_response :success |
|
37 | 52 | assert_template 'show' |
|
38 | 53 | assert_tag :tag => 'h1', :content => /CookBook documentation/ |
|
39 | 54 | |
|
40 | 55 | # child_pages macro |
|
41 | 56 | assert_tag :ul, :attributes => { :class => 'pages-hierarchy' }, |
|
42 | 57 | :child => { :tag => 'li', |
|
43 |
:child => { :tag => 'a', :attributes => { :href => '/ |
|
|
58 | :child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/Page_with_an_inline_image' }, | |
|
44 | 59 | :content => 'Page with an inline image' } } |
|
45 | 60 | end |
|
46 | 61 | |
|
47 | 62 | def test_show_page_with_name |
|
48 | 63 | get :index, :id => 1, :page => 'Another_page' |
|
49 | 64 | assert_response :success |
|
50 | 65 | assert_template 'show' |
|
51 | 66 | assert_tag :tag => 'h1', :content => /Another page/ |
|
52 | 67 | # Included page with an inline image |
|
53 | 68 | assert_tag :tag => 'p', :content => /This is an inline image/ |
|
54 | 69 | assert_tag :tag => 'img', :attributes => { :src => '/attachments/download/3', |
|
55 | 70 | :alt => 'This is a logo' } |
|
56 | 71 | end |
|
57 | 72 | |
|
58 | 73 | def test_show_unexistent_page_without_edit_right |
|
59 | 74 | get :index, :id => 1, :page => 'Unexistent page' |
|
60 | 75 | assert_response 404 |
|
61 | 76 | end |
|
62 | 77 | |
|
63 | 78 | def test_show_unexistent_page_with_edit_right |
|
64 | 79 | @request.session[:user_id] = 2 |
|
65 | 80 | get :index, :id => 1, :page => 'Unexistent page' |
|
66 | 81 | assert_response :success |
|
67 | 82 | assert_template 'edit' |
|
68 | 83 | end |
|
69 | 84 | |
|
85 | def test_edit_routing | |
|
86 | assert_routing( | |
|
87 | {:method => :get, :path => '/projects/567/wiki/my_page/edit'}, | |
|
88 | :controller => 'wiki', :action => 'edit', :id => '567', :page => 'my_page' | |
|
89 | ) | |
|
90 | assert_recognizes(#TODO: use PUT to page path, adjust forms accordingly | |
|
91 | {:controller => 'wiki', :action => 'edit', :id => '567', :page => 'my_page'}, | |
|
92 | {:method => :post, :path => '/projects/567/wiki/my_page/edit'} | |
|
93 | ) | |
|
94 | end | |
|
95 | ||
|
70 | 96 | def test_create_page |
|
71 | 97 | @request.session[:user_id] = 2 |
|
72 | 98 | post :edit, :id => 1, |
|
73 | 99 | :page => 'New page', |
|
74 | 100 | :content => {:comments => 'Created the page', |
|
75 | 101 | :text => "h1. New page\n\nThis is a new page", |
|
76 | 102 | :version => 0} |
|
77 |
assert_redirected_to |
|
|
103 | assert_redirected_to :action => 'index', :id => 'ecookbook', :page => 'New_page' | |
|
78 | 104 | page = Project.find(1).wiki.find_page('New page') |
|
79 | 105 | assert !page.new_record? |
|
80 | 106 | assert_not_nil page.content |
|
81 | 107 | assert_equal 'Created the page', page.content.comments |
|
82 | 108 | end |
|
83 | 109 | |
|
110 | def test_preview_routing | |
|
111 | assert_routing( | |
|
112 | {:method => :post, :path => '/projects/567/wiki/CookBook_documentation/preview'}, | |
|
113 | :controller => 'wiki', :action => 'preview', :id => '567', :page => 'CookBook_documentation' | |
|
114 | ) | |
|
115 | end | |
|
116 | ||
|
84 | 117 | def test_preview |
|
85 | 118 | @request.session[:user_id] = 2 |
|
86 | 119 | xhr :post, :preview, :id => 1, :page => 'CookBook_documentation', |
|
87 | 120 | :content => { :comments => '', |
|
88 | 121 | :text => 'this is a *previewed text*', |
|
89 | 122 | :version => 3 } |
|
90 | 123 | assert_response :success |
|
91 | 124 | assert_template 'common/_preview' |
|
92 | 125 | assert_tag :tag => 'strong', :content => /previewed text/ |
|
93 | 126 | end |
|
94 | 127 | |
|
95 | 128 | def test_preview_new_page |
|
96 | 129 | @request.session[:user_id] = 2 |
|
97 | 130 | xhr :post, :preview, :id => 1, :page => 'New page', |
|
98 | 131 | :content => { :text => 'h1. New page', |
|
99 | 132 | :comments => '', |
|
100 | 133 | :version => 0 } |
|
101 | 134 | assert_response :success |
|
102 | 135 | assert_template 'common/_preview' |
|
103 | 136 | assert_tag :tag => 'h1', :content => /New page/ |
|
104 | 137 | end |
|
105 | 138 | |
|
139 | def test_history_routing | |
|
140 | assert_routing( | |
|
141 | {:method => :get, :path => '/projects/1/wiki/CookBook_documentation/history'}, | |
|
142 | :controller => 'wiki', :action => 'history', :id => '1', :page => 'CookBook_documentation' | |
|
143 | ) | |
|
144 | end | |
|
145 | ||
|
106 | 146 | def test_history |
|
107 | 147 | get :history, :id => 1, :page => 'CookBook_documentation' |
|
108 | 148 | assert_response :success |
|
109 | 149 | assert_template 'history' |
|
110 | 150 | assert_not_nil assigns(:versions) |
|
111 | 151 | assert_equal 3, assigns(:versions).size |
|
112 | 152 | assert_select "input[type=submit][name=commit]" |
|
113 | 153 | end |
|
114 | 154 | |
|
115 | 155 | def test_history_with_one_version |
|
116 | 156 | get :history, :id => 1, :page => 'Another_page' |
|
117 | 157 | assert_response :success |
|
118 | 158 | assert_template 'history' |
|
119 | 159 | assert_not_nil assigns(:versions) |
|
120 | 160 | assert_equal 1, assigns(:versions).size |
|
121 | 161 | assert_select "input[type=submit][name=commit]", false |
|
122 | 162 | end |
|
123 | 163 | |
|
164 | def test_diff_routing | |
|
165 | assert_routing( | |
|
166 | {:method => :get, :path => '/projects/1/wiki/CookBook_documentation/diff/2/vs/1'}, | |
|
167 | :controller => 'wiki', :action => 'diff', :id => '1', :page => 'CookBook_documentation', :version => '2', :version_from => '1' | |
|
168 | ) | |
|
169 | end | |
|
170 | ||
|
124 | 171 | def test_diff |
|
125 | 172 | get :diff, :id => 1, :page => 'CookBook_documentation', :version => 2, :version_from => 1 |
|
126 | 173 | assert_response :success |
|
127 | 174 | assert_template 'diff' |
|
128 | 175 | assert_tag :tag => 'span', :attributes => { :class => 'diff_in'}, |
|
129 | 176 | :content => /updated/ |
|
130 | 177 | end |
|
131 | 178 | |
|
179 | def test_annotate_routing | |
|
180 | assert_routing( | |
|
181 | {:method => :get, :path => '/projects/1/wiki/CookBook_documentation/annotate/2'}, | |
|
182 | :controller => 'wiki', :action => 'annotate', :id => '1', :page => 'CookBook_documentation', :version => '2' | |
|
183 | ) | |
|
184 | end | |
|
185 | ||
|
132 | 186 | def test_annotate |
|
133 | 187 | get :annotate, :id => 1, :page => 'CookBook_documentation', :version => 2 |
|
134 | 188 | assert_response :success |
|
135 | 189 | assert_template 'annotate' |
|
136 | 190 | # Line 1 |
|
137 | 191 | assert_tag :tag => 'tr', :child => { :tag => 'th', :attributes => {:class => 'line-num'}, :content => '1' }, |
|
138 | 192 | :child => { :tag => 'td', :attributes => {:class => 'author'}, :content => /John Smith/ }, |
|
139 | 193 | :child => { :tag => 'td', :content => /h1\. CookBook documentation/ } |
|
140 | 194 | # Line 2 |
|
141 | 195 | assert_tag :tag => 'tr', :child => { :tag => 'th', :attributes => {:class => 'line-num'}, :content => '2' }, |
|
142 | 196 | :child => { :tag => 'td', :attributes => {:class => 'author'}, :content => /redMine Admin/ }, |
|
143 | 197 | :child => { :tag => 'td', :content => /Some updated \[\[documentation\]\] here/ } |
|
144 | 198 | end |
|
145 | 199 | |
|
200 | def test_rename_routing | |
|
201 | assert_routing( | |
|
202 | {:method => :get, :path => '/projects/22/wiki/ladida/rename'}, | |
|
203 | :controller => 'wiki', :action => 'rename', :id => '22', :page => 'ladida' | |
|
204 | ) | |
|
205 | assert_recognizes( | |
|
206 | #TODO: should be moved into a update action and use a PUT to the page URI | |
|
207 | {:controller => 'wiki', :action => 'rename', :id => '22', :page => 'ladida'}, | |
|
208 | {:method => :post, :path => '/projects/22/wiki/ladida/rename'} | |
|
209 | ) | |
|
210 | end | |
|
211 | ||
|
146 | 212 | def test_rename_with_redirect |
|
147 | 213 | @request.session[:user_id] = 2 |
|
148 | 214 | post :rename, :id => 1, :page => 'Another_page', |
|
149 | 215 | :wiki_page => { :title => 'Another renamed page', |
|
150 | 216 | :redirect_existing_links => 1 } |
|
151 |
assert_redirected_to |
|
|
217 | assert_redirected_to :action => 'index', :id => 'ecookbook', :page => 'Another_renamed_page' | |
|
152 | 218 | wiki = Project.find(1).wiki |
|
153 | 219 | # Check redirects |
|
154 | 220 | assert_not_nil wiki.find_page('Another page') |
|
155 | 221 | assert_nil wiki.find_page('Another page', :with_redirect => false) |
|
156 | 222 | end |
|
157 | 223 | |
|
158 | 224 | def test_rename_without_redirect |
|
159 | 225 | @request.session[:user_id] = 2 |
|
160 | 226 | post :rename, :id => 1, :page => 'Another_page', |
|
161 | 227 | :wiki_page => { :title => 'Another renamed page', |
|
162 | 228 | :redirect_existing_links => "0" } |
|
163 |
assert_redirected_to |
|
|
229 | assert_redirected_to :action => 'index', :id => 'ecookbook', :page => 'Another_renamed_page' | |
|
164 | 230 | wiki = Project.find(1).wiki |
|
165 | 231 | # Check that there's no redirects |
|
166 | 232 | assert_nil wiki.find_page('Another page') |
|
167 | 233 | end |
|
168 | 234 | |
|
235 | def test_destroy_routing | |
|
236 | assert_recognizes( | |
|
237 | #TODO: should use DELETE on page URI | |
|
238 | {:controller => 'wiki', :action => 'destroy', :id => '22', :page => 'ladida'}, | |
|
239 | {:method => :post, :path => 'projects/22/wiki/ladida/destroy'} | |
|
240 | ) | |
|
241 | end | |
|
242 | ||
|
169 | 243 | def test_destroy |
|
170 | 244 | @request.session[:user_id] = 2 |
|
171 | 245 | post :destroy, :id => 1, :page => 'CookBook_documentation' |
|
172 |
assert_redirected_to |
|
|
246 | assert_redirected_to :action => 'special', :id => 'ecookbook', :page => 'Page_index' | |
|
247 | end | |
|
248 | ||
|
249 | def test_special_routing | |
|
250 | assert_routing( | |
|
251 | {:method => :get, :path => '/projects/567/wiki/page_index'}, | |
|
252 | :controller => 'wiki', :action => 'special', :id => '567', :page => 'page_index' | |
|
253 | ) | |
|
254 | assert_routing( | |
|
255 | {:method => :get, :path => '/projects/567/wiki/Page_Index'}, | |
|
256 | :controller => 'wiki', :action => 'special', :id => '567', :page => 'Page_Index' | |
|
257 | ) | |
|
258 | assert_routing( | |
|
259 | {:method => :get, :path => '/projects/567/wiki/date_index'}, | |
|
260 | :controller => 'wiki', :action => 'special', :id => '567', :page => 'date_index' | |
|
261 | ) | |
|
262 | assert_routing( | |
|
263 | {:method => :get, :path => '/projects/567/wiki/export'}, | |
|
264 | :controller => 'wiki', :action => 'special', :id => '567', :page => 'export' | |
|
265 | ) | |
|
173 | 266 | end |
|
174 | 267 | |
|
175 | 268 | def test_page_index |
|
176 | 269 | get :special, :id => 'ecookbook', :page => 'Page_index' |
|
177 | 270 | assert_response :success |
|
178 | 271 | assert_template 'special_page_index' |
|
179 | 272 | pages = assigns(:pages) |
|
180 | 273 | assert_not_nil pages |
|
181 | 274 | assert_equal Project.find(1).wiki.pages.size, pages.size |
|
182 | 275 | |
|
183 | 276 | assert_tag :ul, :attributes => { :class => 'pages-hierarchy' }, |
|
184 |
:child => { :tag => 'li', :child => { :tag => 'a', :attributes => { :href => '/ |
|
|
277 | :child => { :tag => 'li', :child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/CookBook_documentation' }, | |
|
185 | 278 | :content => 'CookBook documentation' }, |
|
186 | 279 | :child => { :tag => 'ul', |
|
187 | 280 | :child => { :tag => 'li', |
|
188 |
:child => { :tag => 'a', :attributes => { :href => '/ |
|
|
281 | :child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/Page_with_an_inline_image' }, | |
|
189 | 282 | :content => 'Page with an inline image' } } } }, |
|
190 |
:child => { :tag => 'li', :child => { :tag => 'a', :attributes => { :href => '/ |
|
|
283 | :child => { :tag => 'li', :child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/Another_page' }, | |
|
191 | 284 | :content => 'Another page' } } |
|
192 | 285 | end |
|
193 | 286 | |
|
194 | 287 | def test_not_found |
|
195 | 288 | get :index, :id => 999 |
|
196 | 289 | assert_response 404 |
|
197 | 290 | end |
|
198 | 291 | |
|
292 | def test_protect_routing | |
|
293 | assert_routing( | |
|
294 | {:method => :post, :path => 'projects/22/wiki/ladida/protect'}, | |
|
295 | {:controller => 'wiki', :action => 'protect', :id => '22', :page => 'ladida'} | |
|
296 | ) | |
|
297 | end | |
|
298 | ||
|
199 | 299 | def test_protect_page |
|
200 | 300 | page = WikiPage.find_by_wiki_id_and_title(1, 'Another_page') |
|
201 | 301 | assert !page.protected? |
|
202 | 302 | @request.session[:user_id] = 2 |
|
203 | 303 | post :protect, :id => 1, :page => page.title, :protected => '1' |
|
204 |
assert_redirected_to |
|
|
304 | assert_redirected_to :action => 'index', :id => 'ecookbook', :page => 'Another_page' | |
|
205 | 305 | assert page.reload.protected? |
|
206 | 306 | end |
|
207 | 307 | |
|
208 | 308 | def test_unprotect_page |
|
209 | 309 | page = WikiPage.find_by_wiki_id_and_title(1, 'CookBook_documentation') |
|
210 | 310 | assert page.protected? |
|
211 | 311 | @request.session[:user_id] = 2 |
|
212 | 312 | post :protect, :id => 1, :page => page.title, :protected => '0' |
|
213 |
assert_redirected_to |
|
|
313 | assert_redirected_to :action => 'index', :id => 'ecookbook', :page => 'CookBook_documentation' | |
|
214 | 314 | assert !page.reload.protected? |
|
215 | 315 | end |
|
216 | 316 | |
|
217 | 317 | def test_show_page_with_edit_link |
|
218 | 318 | @request.session[:user_id] = 2 |
|
219 | 319 | get :index, :id => 1 |
|
220 | 320 | assert_response :success |
|
221 | 321 | assert_template 'show' |
|
222 |
assert_tag :tag => 'a', :attributes => { :href => '/wiki |
|
|
322 | assert_tag :tag => 'a', :attributes => { :href => '/projects/1/wiki/CookBook_documentation/edit' } | |
|
223 | 323 | end |
|
224 | 324 | |
|
225 | 325 | def test_show_page_without_edit_link |
|
226 | 326 | @request.session[:user_id] = 4 |
|
227 | 327 | get :index, :id => 1 |
|
228 | 328 | assert_response :success |
|
229 | 329 | assert_template 'show' |
|
230 |
assert_no_tag :tag => 'a', :attributes => { :href => '/wiki |
|
|
330 | assert_no_tag :tag => 'a', :attributes => { :href => '/projects/1/wiki/CookBook_documentation/edit' } | |
|
231 | 331 | end |
|
232 | 332 | |
|
233 | 333 | def test_edit_unprotected_page |
|
234 | 334 | # Non members can edit unprotected wiki pages |
|
235 | 335 | @request.session[:user_id] = 4 |
|
236 | 336 | get :edit, :id => 1, :page => 'Another_page' |
|
237 | 337 | assert_response :success |
|
238 | 338 | assert_template 'edit' |
|
239 | 339 | end |
|
240 | 340 | |
|
241 | 341 | def test_edit_protected_page_by_nonmember |
|
242 | 342 | # Non members can't edit protected wiki pages |
|
243 | 343 | @request.session[:user_id] = 4 |
|
244 | 344 | get :edit, :id => 1, :page => 'CookBook_documentation' |
|
245 | 345 | assert_response 403 |
|
246 | 346 | end |
|
247 | 347 | |
|
248 | 348 | def test_edit_protected_page_by_member |
|
249 | 349 | @request.session[:user_id] = 2 |
|
250 | 350 | get :edit, :id => 1, :page => 'CookBook_documentation' |
|
251 | 351 | assert_response :success |
|
252 | 352 | assert_template 'edit' |
|
253 | 353 | end |
|
254 | 354 | |
|
255 | 355 | def test_history_of_non_existing_page_should_return_404 |
|
256 | 356 | get :history, :id => 1, :page => 'Unknown_page' |
|
257 | 357 | assert_response 404 |
|
258 | 358 | end |
|
259 | 359 | end |
@@ -1,56 +1,75 | |||
|
1 | 1 | # redMine - project management software |
|
2 | 2 | # Copyright (C) 2006-2007 Jean-Philippe Lang |
|
3 | 3 | # |
|
4 | 4 | # This program is free software; you can redistribute it and/or |
|
5 | 5 | # modify it under the terms of the GNU General Public License |
|
6 | 6 | # as published by the Free Software Foundation; either version 2 |
|
7 | 7 | # of the License, or (at your option) any later version. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU General Public License |
|
15 | 15 | # along with this program; if not, write to the Free Software |
|
16 | 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 | 17 | |
|
18 | 18 | require File.dirname(__FILE__) + '/../test_helper' |
|
19 | 19 | require 'wikis_controller' |
|
20 | 20 | |
|
21 | 21 | # Re-raise errors caught by the controller. |
|
22 | 22 | class WikisController; def rescue_action(e) raise e end; end |
|
23 | 23 | |
|
24 | 24 | class WikisControllerTest < Test::Unit::TestCase |
|
25 | 25 | fixtures :projects, :users, :roles, :members, :enabled_modules, :wikis |
|
26 | 26 | |
|
27 | 27 | def setup |
|
28 | 28 | @controller = WikisController.new |
|
29 | 29 | @request = ActionController::TestRequest.new |
|
30 | 30 | @response = ActionController::TestResponse.new |
|
31 | 31 | User.current = nil |
|
32 | 32 | end |
|
33 | 33 | |
|
34 | def test_edit_routing | |
|
35 | assert_routing( | |
|
36 | #TODO: use PUT | |
|
37 | {:method => :post, :path => 'projects/ladida/wiki'}, | |
|
38 | :controller => 'wikis', :action => 'edit', :id => 'ladida' | |
|
39 | ) | |
|
40 | end | |
|
41 | ||
|
34 | 42 | def test_create |
|
35 | 43 | @request.session[:user_id] = 1 |
|
36 | 44 | assert_nil Project.find(3).wiki |
|
37 | 45 | post :edit, :id => 3, :wiki => { :start_page => 'Start page' } |
|
38 | 46 | assert_response :success |
|
39 | 47 | wiki = Project.find(3).wiki |
|
40 | 48 | assert_not_nil wiki |
|
41 | 49 | assert_equal 'Start page', wiki.start_page |
|
42 | 50 | end |
|
43 | 51 | |
|
52 | def test_destroy_routing | |
|
53 | assert_routing( | |
|
54 | {:method => :get, :path => 'projects/ladida/wiki/destroy'}, | |
|
55 | :controller => 'wikis', :action => 'destroy', :id => 'ladida' | |
|
56 | ) | |
|
57 | assert_recognizes( #TODO: use DELETE and update form | |
|
58 | {:controller => 'wikis', :action => 'destroy', :id => 'ladida'}, | |
|
59 | {:method => :post, :path => 'projects/ladida/wiki/destroy'} | |
|
60 | ) | |
|
61 | end | |
|
62 | ||
|
44 | 63 | def test_destroy |
|
45 | 64 | @request.session[:user_id] = 1 |
|
46 | 65 | post :destroy, :id => 1, :confirm => 1 |
|
47 |
assert_redirected_to |
|
|
66 | assert_redirected_to :action => 'settings', :id => 'ecookbook', :tab => 'wiki' | |
|
48 | 67 | assert_nil Project.find(1).wiki |
|
49 | 68 | end |
|
50 | 69 | |
|
51 | 70 | def test_not_found |
|
52 | 71 | @request.session[:user_id] = 1 |
|
53 | 72 | post :destroy, :id => 999, :confirm => 1 |
|
54 | 73 | assert_response 404 |
|
55 | 74 | end |
|
56 | 75 | end |
@@ -1,66 +1,66 | |||
|
1 | 1 | # redMine - project management software |
|
2 | 2 | # Copyright (C) 2006 Jean-Philippe Lang |
|
3 | 3 | # |
|
4 | 4 | # This program is free software; you can redistribute it and/or |
|
5 | 5 | # modify it under the terms of the GNU General Public License |
|
6 | 6 | # as published by the Free Software Foundation; either version 2 |
|
7 | 7 | # of the License, or (at your option) any later version. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU General Public License |
|
15 | 15 | # along with this program; if not, write to the Free Software |
|
16 | 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 | 17 | |
|
18 | 18 | require "#{File.dirname(__FILE__)}/../test_helper" |
|
19 | 19 | |
|
20 | 20 | class AdminTest < ActionController::IntegrationTest |
|
21 | 21 | fixtures :users |
|
22 | 22 | |
|
23 | 23 | def test_add_user |
|
24 | 24 | log_user("admin", "admin") |
|
25 | 25 | get "/users/add" |
|
26 | 26 | assert_response :success |
|
27 | 27 | assert_template "users/add" |
|
28 | 28 | post "/users/add", :user => { :login => "psmith", :firstname => "Paul", :lastname => "Smith", :mail => "psmith@somenet.foo", :language => "en" }, :password => "psmith09", :password_confirmation => "psmith09" |
|
29 | 29 | assert_redirected_to "users/list" |
|
30 | 30 | |
|
31 | 31 | user = User.find_by_login("psmith") |
|
32 | 32 | assert_kind_of User, user |
|
33 | 33 | logged_user = User.try_to_login("psmith", "psmith09") |
|
34 | 34 | assert_kind_of User, logged_user |
|
35 | 35 | assert_equal "Paul", logged_user.firstname |
|
36 | 36 | |
|
37 | 37 | post "users/edit", :id => user.id, :user => { :status => User::STATUS_LOCKED } |
|
38 | 38 | assert_redirected_to "users/list" |
|
39 | 39 | locked_user = User.try_to_login("psmith", "psmith09") |
|
40 | 40 | assert_equal nil, locked_user |
|
41 | 41 | end |
|
42 | 42 | |
|
43 | 43 | def test_add_project |
|
44 | 44 | log_user("admin", "admin") |
|
45 |
get "projects/ |
|
|
45 | get "projects/new" | |
|
46 | 46 | assert_response :success |
|
47 | 47 | assert_template "projects/add" |
|
48 |
post "projects |
|
|
48 | post "projects", :project => { :name => "blog", | |
|
49 | 49 | :description => "weblog", |
|
50 | 50 | :identifier => "blog", |
|
51 | 51 | :is_public => 1, |
|
52 | 52 | :custom_field_values => { '3' => 'Beta' } |
|
53 | 53 | } |
|
54 | 54 | assert_redirected_to "admin/projects" |
|
55 | 55 | assert_equal 'Successful creation.', flash[:notice] |
|
56 | 56 | |
|
57 | 57 | project = Project.find_by_name("blog") |
|
58 | 58 | assert_kind_of Project, project |
|
59 | 59 | assert_equal "weblog", project.description |
|
60 | 60 | assert_equal true, project.is_public? |
|
61 | 61 | |
|
62 | 62 | get "admin/projects" |
|
63 | 63 | assert_response :success |
|
64 | 64 | assert_template "admin/projects" |
|
65 | 65 | end |
|
66 | 66 | end |
@@ -1,92 +1,92 | |||
|
1 | 1 | # redMine - project management software |
|
2 | 2 | # Copyright (C) 2006-2008 Jean-Philippe Lang |
|
3 | 3 | # |
|
4 | 4 | # This program is free software; you can redistribute it and/or |
|
5 | 5 | # modify it under the terms of the GNU General Public License |
|
6 | 6 | # as published by the Free Software Foundation; either version 2 |
|
7 | 7 | # of the License, or (at your option) any later version. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU General Public License |
|
15 | 15 | # along with this program; if not, write to the Free Software |
|
16 | 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 | 17 | |
|
18 | 18 | require "#{File.dirname(__FILE__)}/../test_helper" |
|
19 | 19 | |
|
20 | 20 | class IssuesTest < ActionController::IntegrationTest |
|
21 | 21 | fixtures :projects, |
|
22 | 22 | :users, |
|
23 | 23 | :roles, |
|
24 | 24 | :members, |
|
25 | 25 | :trackers, |
|
26 | 26 | :projects_trackers, |
|
27 | 27 | :enabled_modules, |
|
28 | 28 | :issue_statuses, |
|
29 | 29 | :issues, |
|
30 | 30 | :enumerations, |
|
31 | 31 | :custom_fields, |
|
32 | 32 | :custom_values, |
|
33 | 33 | :custom_fields_trackers |
|
34 | 34 | |
|
35 | 35 | # create an issue |
|
36 | 36 | def test_add_issue |
|
37 | 37 | log_user('jsmith', 'jsmith') |
|
38 | 38 | get 'projects/1/issues/new', :tracker_id => '1' |
|
39 | 39 | assert_response :success |
|
40 | 40 | assert_template 'issues/new' |
|
41 | 41 | |
|
42 |
post 'projects/1/issues |
|
|
42 | post 'projects/1/issues', :tracker_id => "1", | |
|
43 | 43 | :issue => { :start_date => "2006-12-26", |
|
44 | 44 | :priority_id => "3", |
|
45 | 45 | :subject => "new test issue", |
|
46 | 46 | :category_id => "", |
|
47 | 47 | :description => "new issue", |
|
48 | 48 | :done_ratio => "0", |
|
49 | 49 | :due_date => "", |
|
50 | 50 | :assigned_to_id => "" }, |
|
51 | 51 | :custom_fields => {'2' => 'Value for field 2'} |
|
52 | 52 | # find created issue |
|
53 | 53 | issue = Issue.find_by_subject("new test issue") |
|
54 | 54 | assert_kind_of Issue, issue |
|
55 | 55 | |
|
56 | 56 | # check redirection |
|
57 |
assert_redirected_to |
|
|
57 | assert_redirected_to :controller => 'issues', :action => 'show' | |
|
58 | 58 | follow_redirect! |
|
59 | 59 | assert_equal issue, assigns(:issue) |
|
60 | 60 | |
|
61 | 61 | # check issue attributes |
|
62 | 62 | assert_equal 'jsmith', issue.author.login |
|
63 | 63 | assert_equal 1, issue.project.id |
|
64 | 64 | assert_equal 1, issue.status.id |
|
65 | 65 | end |
|
66 | 66 | |
|
67 | 67 | # add then remove 2 attachments to an issue |
|
68 | 68 | def test_issue_attachements |
|
69 | 69 | log_user('jsmith', 'jsmith') |
|
70 | 70 | set_tmp_attachments_directory |
|
71 | 71 | |
|
72 |
post 'issues/edit |
|
|
72 | post 'issues/1/edit', | |
|
73 | 73 | :notes => 'Some notes', |
|
74 | 74 | :attachments => {'1' => {'file' => test_uploaded_file('testfile.txt', 'text/plain'), 'description' => 'This is an attachment'}} |
|
75 |
assert_redirected_to "issues/ |
|
|
75 | assert_redirected_to "issues/1" | |
|
76 | 76 | |
|
77 | 77 | # make sure attachment was saved |
|
78 | 78 | attachment = Issue.find(1).attachments.find_by_filename("testfile.txt") |
|
79 | 79 | assert_kind_of Attachment, attachment |
|
80 | 80 | assert_equal Issue.find(1), attachment.container |
|
81 | 81 | assert_equal 'This is an attachment', attachment.description |
|
82 | 82 | # verify the size of the attachment stored in db |
|
83 | 83 | #assert_equal file_data_1.length, attachment.filesize |
|
84 | 84 | # verify that the attachment was written to disk |
|
85 | 85 | assert File.exist?(attachment.diskfile) |
|
86 | 86 | |
|
87 | 87 | # remove the attachments |
|
88 | 88 | Issue.find(1).attachments.each(&:destroy) |
|
89 | 89 | assert_equal 0, Issue.find(1).attachments.length |
|
90 | 90 | end |
|
91 | 91 | |
|
92 | 92 | end |
@@ -1,44 +1,44 | |||
|
1 | 1 | # redMine - project management software |
|
2 | 2 | # Copyright (C) 2006-2007 Jean-Philippe Lang |
|
3 | 3 | # |
|
4 | 4 | # This program is free software; you can redistribute it and/or |
|
5 | 5 | # modify it under the terms of the GNU General Public License |
|
6 | 6 | # as published by the Free Software Foundation; either version 2 |
|
7 | 7 | # of the License, or (at your option) any later version. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU General Public License |
|
15 | 15 | # along with this program; if not, write to the Free Software |
|
16 | 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 | 17 | |
|
18 | 18 | require "#{File.dirname(__FILE__)}/../test_helper" |
|
19 | 19 | |
|
20 | 20 | class ProjectsTest < ActionController::IntegrationTest |
|
21 | 21 | fixtures :projects, :users, :members |
|
22 | 22 | |
|
23 | 23 | def test_archive_project |
|
24 | 24 | subproject = Project.find(1).children.first |
|
25 | 25 | log_user("admin", "admin") |
|
26 | 26 | get "admin/projects" |
|
27 | 27 | assert_response :success |
|
28 | 28 | assert_template "admin/projects" |
|
29 | 29 | post "projects/archive", :id => 1 |
|
30 | 30 |
assert_redirected_to "admin/projects" |
|
31 | 31 | assert !Project.find(1).active? |
|
32 | 32 | |
|
33 |
get |
|
|
33 | get 'projects/1' | |
|
34 | 34 | assert_response 403 |
|
35 |
get "projects/ |
|
|
35 | get "projects/#{subproject.id}" | |
|
36 | 36 | assert_response 403 |
|
37 | 37 | |
|
38 | 38 | post "projects/unarchive", :id => 1 |
|
39 | 39 |
assert_redirected_to "admin/projects" |
|
40 | 40 | assert Project.find(1).active? |
|
41 |
get "projects/ |
|
|
41 | get "projects/1" | |
|
42 | 42 | assert_response :success |
|
43 | 43 | end |
|
44 | 44 | end |
@@ -1,447 +1,447 | |||
|
1 | 1 | # redMine - project management software |
|
2 | 2 | # Copyright (C) 2006-2007 Jean-Philippe Lang |
|
3 | 3 | # |
|
4 | 4 | # This program is free software; you can redistribute it and/or |
|
5 | 5 | # modify it under the terms of the GNU General Public License |
|
6 | 6 | # as published by the Free Software Foundation; either version 2 |
|
7 | 7 | # of the License, or (at your option) any later version. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU General Public License |
|
15 | 15 | # along with this program; if not, write to the Free Software |
|
16 | 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 | 17 | |
|
18 | 18 | require File.dirname(__FILE__) + '/../../test_helper' |
|
19 | 19 | |
|
20 | 20 | class ApplicationHelperTest < HelperTestCase |
|
21 | 21 | include ApplicationHelper |
|
22 | 22 | include ActionView::Helpers::TextHelper |
|
23 | 23 | fixtures :projects, :roles, :enabled_modules, :users, |
|
24 | 24 | :repositories, :changesets, |
|
25 | 25 | :trackers, :issue_statuses, :issues, :versions, :documents, |
|
26 | 26 | :wikis, :wiki_pages, :wiki_contents, |
|
27 | 27 | :boards, :messages, |
|
28 | 28 | :attachments |
|
29 | 29 | |
|
30 | 30 | def setup |
|
31 | 31 | super |
|
32 | 32 | end |
|
33 | 33 | |
|
34 | 34 | def test_auto_links |
|
35 | 35 | to_test = { |
|
36 | 36 | 'http://foo.bar' => '<a class="external" href="http://foo.bar">http://foo.bar</a>', |
|
37 | 37 | 'http://foo.bar/~user' => '<a class="external" href="http://foo.bar/~user">http://foo.bar/~user</a>', |
|
38 | 38 | 'http://foo.bar.' => '<a class="external" href="http://foo.bar">http://foo.bar</a>.', |
|
39 | 39 | 'https://foo.bar.' => '<a class="external" href="https://foo.bar">https://foo.bar</a>.', |
|
40 | 40 | 'This is a link: http://foo.bar.' => 'This is a link: <a class="external" href="http://foo.bar">http://foo.bar</a>.', |
|
41 | 41 | 'A link (eg. http://foo.bar).' => 'A link (eg. <a class="external" href="http://foo.bar">http://foo.bar</a>).', |
|
42 | 42 | '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>.', |
|
43 | 43 | 'http://www.foo.bar/Test_(foobar)' => '<a class="external" href="http://www.foo.bar/Test_(foobar)">http://www.foo.bar/Test_(foobar)</a>', |
|
44 | 44 | '(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>)', |
|
45 | 45 | '(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>)', |
|
46 | 46 | '(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>).', |
|
47 | 47 | '(see "inline link":http://www.foo.bar/Test_(foobar))' => '(see <a href="http://www.foo.bar/Test_(foobar)" class="external">inline link</a>)', |
|
48 | 48 | '(see "inline link":http://www.foo.bar/Test)' => '(see <a href="http://www.foo.bar/Test" class="external">inline link</a>)', |
|
49 | 49 | '(see "inline link":http://www.foo.bar/Test).' => '(see <a href="http://www.foo.bar/Test" class="external">inline link</a>).', |
|
50 | 50 | 'www.foo.bar' => '<a class="external" href="http://www.foo.bar">www.foo.bar</a>', |
|
51 | 51 | 'http://foo.bar/page?p=1&t=z&s=' => '<a class="external" href="http://foo.bar/page?p=1&t=z&s=">http://foo.bar/page?p=1&t=z&s=</a>', |
|
52 | 52 | 'http://foo.bar/page#125' => '<a class="external" href="http://foo.bar/page#125">http://foo.bar/page#125</a>', |
|
53 | 53 | 'http://foo@www.bar.com' => '<a class="external" href="http://foo@www.bar.com">http://foo@www.bar.com</a>', |
|
54 | 54 | 'http://foo:bar@www.bar.com' => '<a class="external" href="http://foo:bar@www.bar.com">http://foo:bar@www.bar.com</a>', |
|
55 | 55 | 'ftp://foo.bar' => '<a class="external" href="ftp://foo.bar">ftp://foo.bar</a>', |
|
56 | 56 | 'ftps://foo.bar' => '<a class="external" href="ftps://foo.bar">ftps://foo.bar</a>', |
|
57 | 57 | 'sftp://foo.bar' => '<a class="external" href="sftp://foo.bar">sftp://foo.bar</a>', |
|
58 | 58 | } |
|
59 | 59 | to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) } |
|
60 | 60 | end |
|
61 | 61 | |
|
62 | 62 | def test_auto_mailto |
|
63 | 63 | assert_equal '<p><a href="mailto:test@foo.bar" class="email">test@foo.bar</a></p>', |
|
64 | 64 | textilizable('test@foo.bar') |
|
65 | 65 | end |
|
66 | 66 | |
|
67 | 67 | def test_inline_images |
|
68 | 68 | to_test = { |
|
69 | 69 | '!http://foo.bar/image.jpg!' => '<img src="http://foo.bar/image.jpg" alt="" />', |
|
70 | 70 | 'floating !>http://foo.bar/image.jpg!' => 'floating <div style="float:right"><img src="http://foo.bar/image.jpg" alt="" /></div>', |
|
71 | 71 | 'with class !(some-class)http://foo.bar/image.jpg!' => 'with class <img src="http://foo.bar/image.jpg" class="some-class" alt="" />', |
|
72 | 72 | # inline styles should be stripped |
|
73 | 73 | 'with style !{width:100px;height100px}http://foo.bar/image.jpg!' => 'with style <img src="http://foo.bar/image.jpg" alt="" />', |
|
74 | 74 | '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" />', |
|
75 | 75 | '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 "title"" alt="This is a double-quoted "title"" />', |
|
76 | 76 | } |
|
77 | 77 | to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) } |
|
78 | 78 | end |
|
79 | 79 | |
|
80 | 80 | def test_acronyms |
|
81 | 81 | to_test = { |
|
82 | 82 | 'this is an acronym: GPL(General Public License)' => 'this is an acronym: <acronym title="General Public License">GPL</acronym>', |
|
83 | 83 | 'GPL(This is a double-quoted "title")' => '<acronym title="This is a double-quoted "title"">GPL</acronym>', |
|
84 | 84 | } |
|
85 | 85 | to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) } |
|
86 | 86 | |
|
87 | 87 | end |
|
88 | 88 | |
|
89 | 89 | def test_attached_images |
|
90 | 90 | to_test = { |
|
91 | 91 | 'Inline image: !logo.gif!' => 'Inline image: <img src="/attachments/download/3" title="This is a logo" alt="This is a logo" />', |
|
92 | 92 | 'Inline image: !logo.GIF!' => 'Inline image: <img src="/attachments/download/3" title="This is a logo" alt="This is a logo" />' |
|
93 | 93 | } |
|
94 | 94 | attachments = Attachment.find(:all) |
|
95 | 95 | to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text, :attachments => attachments) } |
|
96 | 96 | end |
|
97 | 97 | |
|
98 | 98 | def test_textile_external_links |
|
99 | 99 | to_test = { |
|
100 | 100 | 'This is a "link":http://foo.bar' => 'This is a <a href="http://foo.bar" class="external">link</a>', |
|
101 | 101 | 'This is an intern "link":/foo/bar' => 'This is an intern <a href="/foo/bar">link</a>', |
|
102 | 102 | '"link (Link title)":http://foo.bar' => '<a href="http://foo.bar" title="Link title" class="external">link</a>', |
|
103 | 103 | '"link (Link title with "double-quotes")":http://foo.bar' => '<a href="http://foo.bar" title="Link title with "double-quotes"" class="external">link</a>', |
|
104 | 104 | "This is not a \"Link\":\n\nAnother paragraph" => "This is not a \"Link\":</p>\n\n\n\t<p>Another paragraph", |
|
105 | 105 | # no multiline link text |
|
106 | 106 | "This is a double quote \"on the first line\nand another on a second line\":test" => "This is a double quote \"on the first line<br />\nand another on a second line\":test" |
|
107 | 107 | } |
|
108 | 108 | to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) } |
|
109 | 109 | end |
|
110 | 110 | |
|
111 | 111 | def test_redmine_links |
|
112 | 112 | issue_link = link_to('#3', {:controller => 'issues', :action => 'show', :id => 3}, |
|
113 | 113 | :class => 'issue', :title => 'Error 281 when updating a recipe (New)') |
|
114 | 114 | |
|
115 | 115 | changeset_link = link_to('r1', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 1}, |
|
116 | 116 | :class => 'changeset', :title => 'My very first commit') |
|
117 | 117 | |
|
118 | 118 | document_link = link_to('Test document', {:controller => 'documents', :action => 'show', :id => 1}, |
|
119 | 119 | :class => 'document') |
|
120 | 120 | |
|
121 | 121 | version_link = link_to('1.0', {:controller => 'versions', :action => 'show', :id => 2}, |
|
122 | 122 | :class => 'version') |
|
123 | 123 | |
|
124 | 124 | message_url = {:controller => 'messages', :action => 'show', :board_id => 1, :id => 4} |
|
125 | 125 | |
|
126 | 126 | source_url = {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :path => ['some', 'file']} |
|
127 | 127 | source_url_with_ext = {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :path => ['some', 'file.ext']} |
|
128 | 128 | |
|
129 | 129 | to_test = { |
|
130 | 130 | # tickets |
|
131 | 131 | '#3, #3 and #3.' => "#{issue_link}, #{issue_link} and #{issue_link}.", |
|
132 | 132 | # changesets |
|
133 | 133 | 'r1' => changeset_link, |
|
134 | 134 | # documents |
|
135 | 135 | 'document#1' => document_link, |
|
136 | 136 | 'document:"Test document"' => document_link, |
|
137 | 137 | # versions |
|
138 | 138 | 'version#2' => version_link, |
|
139 | 139 | 'version:1.0' => version_link, |
|
140 | 140 | 'version:"1.0"' => version_link, |
|
141 | 141 | # source |
|
142 | 142 | 'source:/some/file' => link_to('source:/some/file', source_url, :class => 'source'), |
|
143 | 143 | 'source:/some/file.' => link_to('source:/some/file', source_url, :class => 'source') + ".", |
|
144 | 144 | 'source:/some/file.ext.' => link_to('source:/some/file.ext', source_url_with_ext, :class => 'source') + ".", |
|
145 | 145 | 'source:/some/file. ' => link_to('source:/some/file', source_url, :class => 'source') + ".", |
|
146 | 146 | 'source:/some/file.ext. ' => link_to('source:/some/file.ext', source_url_with_ext, :class => 'source') + ".", |
|
147 | 147 | 'source:/some/file, ' => link_to('source:/some/file', source_url, :class => 'source') + ",", |
|
148 | 148 | 'source:/some/file@52' => link_to('source:/some/file@52', source_url.merge(:rev => 52), :class => 'source'), |
|
149 | 149 | 'source:/some/file.ext@52' => link_to('source:/some/file.ext@52', source_url_with_ext.merge(:rev => 52), :class => 'source'), |
|
150 | 150 | 'source:/some/file#L110' => link_to('source:/some/file#L110', source_url.merge(:anchor => 'L110'), :class => 'source'), |
|
151 | 151 | 'source:/some/file.ext#L110' => link_to('source:/some/file.ext#L110', source_url_with_ext.merge(:anchor => 'L110'), :class => 'source'), |
|
152 | 152 | 'source:/some/file@52#L110' => link_to('source:/some/file@52#L110', source_url.merge(:rev => 52, :anchor => 'L110'), :class => 'source'), |
|
153 | 153 | 'export:/some/file' => link_to('export:/some/file', source_url.merge(:format => 'raw'), :class => 'source download'), |
|
154 | 154 | # message |
|
155 | 155 | 'message#4' => link_to('Post 2', message_url, :class => 'message'), |
|
156 | 156 | 'message#5' => link_to('RE: post 2', message_url.merge(:anchor => 'message-5'), :class => 'message'), |
|
157 | 157 | # escaping |
|
158 | 158 | '!#3.' => '#3.', |
|
159 | 159 | '!r1' => 'r1', |
|
160 | 160 | '!document#1' => 'document#1', |
|
161 | 161 | '!document:"Test document"' => 'document:"Test document"', |
|
162 | 162 | '!version#2' => 'version#2', |
|
163 | 163 | '!version:1.0' => 'version:1.0', |
|
164 | 164 | '!version:"1.0"' => 'version:"1.0"', |
|
165 | 165 | '!source:/some/file' => 'source:/some/file', |
|
166 | 166 | # invalid expressions |
|
167 | 167 | 'source:' => 'source:', |
|
168 | 168 | # url hash |
|
169 | 169 | "http://foo.bar/FAQ#3" => '<a class="external" href="http://foo.bar/FAQ#3">http://foo.bar/FAQ#3</a>', |
|
170 | 170 | } |
|
171 | 171 | @project = Project.find(1) |
|
172 | 172 | to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) } |
|
173 | 173 | end |
|
174 | 174 | |
|
175 | 175 | def test_wiki_links |
|
176 | 176 | to_test = { |
|
177 |
'[[CookBook documentation]]' => '<a href="/ |
|
|
178 |
'[[Another page|Page]]' => '<a href="/ |
|
|
177 | '[[CookBook documentation]]' => '<a href="/projects/ecookbook/wiki/CookBook_documentation" class="wiki-page">CookBook documentation</a>', | |
|
178 | '[[Another page|Page]]' => '<a href="/projects/ecookbook/wiki/Another_page" class="wiki-page">Page</a>', | |
|
179 | 179 | # link with anchor |
|
180 |
'[[CookBook documentation#One-section]]' => '<a href="/ |
|
|
181 |
'[[Another page#anchor|Page]]' => '<a href="/ |
|
|
180 | '[[CookBook documentation#One-section]]' => '<a href="/projects/ecookbook/wiki/CookBook_documentation#One-section" class="wiki-page">CookBook documentation</a>', | |
|
181 | '[[Another page#anchor|Page]]' => '<a href="/projects/ecookbook/wiki/Another_page#anchor" class="wiki-page">Page</a>', | |
|
182 | 182 | # page that doesn't exist |
|
183 |
'[[Unknown page]]' => '<a href="/ |
|
|
184 |
'[[Unknown page|404]]' => '<a href="/ |
|
|
183 | '[[Unknown page]]' => '<a href="/projects/ecookbook/wiki/Unknown_page" class="wiki-page new">Unknown page</a>', | |
|
184 | '[[Unknown page|404]]' => '<a href="/projects/ecookbook/wiki/Unknown_page" class="wiki-page new">404</a>', | |
|
185 | 185 | # link to another project wiki |
|
186 |
'[[onlinestore:]]' => '<a href="/ |
|
|
187 |
'[[onlinestore:|Wiki]]' => '<a href="/ |
|
|
188 |
'[[onlinestore:Start page]]' => '<a href="/ |
|
|
189 |
'[[onlinestore:Start page|Text]]' => '<a href="/ |
|
|
190 |
'[[onlinestore:Unknown page]]' => '<a href="/ |
|
|
186 | '[[onlinestore:]]' => '<a href="/projects/onlinestore/wiki/" class="wiki-page">onlinestore</a>', | |
|
187 | '[[onlinestore:|Wiki]]' => '<a href="/projects/onlinestore/wiki/" class="wiki-page">Wiki</a>', | |
|
188 | '[[onlinestore:Start page]]' => '<a href="/projects/onlinestore/wiki/Start_page" class="wiki-page">Start page</a>', | |
|
189 | '[[onlinestore:Start page|Text]]' => '<a href="/projects/onlinestore/wiki/Start_page" class="wiki-page">Text</a>', | |
|
190 | '[[onlinestore:Unknown page]]' => '<a href="/projects/onlinestore/wiki/Unknown_page" class="wiki-page new">Unknown page</a>', | |
|
191 | 191 | # striked through link |
|
192 |
'-[[Another page|Page]]-' => '<del><a href="/ |
|
|
193 |
'-[[Another page|Page]] link-' => '<del><a href="/ |
|
|
192 | '-[[Another page|Page]]-' => '<del><a href="/projects/ecookbook/wiki/Another_page" class="wiki-page">Page</a></del>', | |
|
193 | '-[[Another page|Page]] link-' => '<del><a href="/projects/ecookbook/wiki/Another_page" class="wiki-page">Page</a> link</del>', | |
|
194 | 194 | # escaping |
|
195 | 195 | '![[Another page|Page]]' => '[[Another page|Page]]', |
|
196 | 196 | } |
|
197 | 197 | @project = Project.find(1) |
|
198 | 198 | to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) } |
|
199 | 199 | end |
|
200 | 200 | |
|
201 | 201 | def test_html_tags |
|
202 | 202 | to_test = { |
|
203 | 203 | "<div>content</div>" => "<p><div>content</div></p>", |
|
204 | 204 | "<div class=\"bold\">content</div>" => "<p><div class=\"bold\">content</div></p>", |
|
205 | 205 | "<script>some script;</script>" => "<p><script>some script;</script></p>", |
|
206 | 206 | # do not escape pre/code tags |
|
207 | 207 | "<pre>\nline 1\nline2</pre>" => "<pre>\nline 1\nline2</pre>", |
|
208 | 208 | "<pre><code>\nline 1\nline2</code></pre>" => "<pre><code>\nline 1\nline2</code></pre>", |
|
209 | 209 | "<pre><div>content</div></pre>" => "<pre><div>content</div></pre>", |
|
210 | 210 | "HTML comment: <!-- no comments -->" => "<p>HTML comment: <!-- no comments --></p>", |
|
211 | 211 | "<!-- opening comment" => "<p><!-- opening comment</p>", |
|
212 | 212 | # remove attributes except class |
|
213 | 213 | "<pre class='foo'>some text</pre>" => "<pre class='foo'>some text</pre>", |
|
214 | 214 | "<pre onmouseover='alert(1)'>some text</pre>" => "<pre>some text</pre>", |
|
215 | 215 | } |
|
216 | 216 | to_test.each { |text, result| assert_equal result, textilizable(text) } |
|
217 | 217 | end |
|
218 | 218 | |
|
219 | 219 | def test_allowed_html_tags |
|
220 | 220 | to_test = { |
|
221 | 221 | "<pre>preformatted text</pre>" => "<pre>preformatted text</pre>", |
|
222 | 222 | "<notextile>no *textile* formatting</notextile>" => "no *textile* formatting", |
|
223 | 223 | "<notextile>this is <tag>a tag</tag></notextile>" => "this is <tag>a tag</tag>" |
|
224 | 224 | } |
|
225 | 225 | to_test.each { |text, result| assert_equal result, textilizable(text) } |
|
226 | 226 | end |
|
227 | 227 | |
|
228 | 228 | def syntax_highlight |
|
229 | 229 | raw = <<-RAW |
|
230 | 230 | <pre><code class="ruby"> |
|
231 | 231 | # Some ruby code here |
|
232 | 232 | </pre></code> |
|
233 | 233 | RAW |
|
234 | 234 | |
|
235 | 235 | expected = <<-EXPECTED |
|
236 | 236 | <pre><code class="ruby CodeRay"><span class="no">1</span> <span class="c"># Some ruby code here</span> |
|
237 | 237 | </pre></code> |
|
238 | 238 | EXPECTED |
|
239 | 239 | |
|
240 | 240 | assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(raw).gsub(%r{[\r\n\t]}, '') |
|
241 | 241 | end |
|
242 | 242 | |
|
243 | 243 | def test_wiki_links_in_tables |
|
244 | 244 | to_test = {"|[[Page|Link title]]|[[Other Page|Other title]]|\n|Cell 21|[[Last page]]|" => |
|
245 |
'<tr><td><a href="/ |
|
|
246 |
'<td><a href="/ |
|
|
247 |
'</tr><tr><td>Cell 21</td><td><a href="/ |
|
|
245 | '<tr><td><a href="/projects/ecookbook/wiki/Page" class="wiki-page new">Link title</a></td>' + | |
|
246 | '<td><a href="/projects/ecookbook/wiki/Other_Page" class="wiki-page new">Other title</a></td>' + | |
|
247 | '</tr><tr><td>Cell 21</td><td><a href="/projects/ecookbook/wiki/Last_page" class="wiki-page new">Last page</a></td></tr>' | |
|
248 | 248 | } |
|
249 | 249 | @project = Project.find(1) |
|
250 | 250 | to_test.each { |text, result| assert_equal "<table>#{result}</table>", textilizable(text).gsub(/[\t\n]/, '') } |
|
251 | 251 | end |
|
252 | 252 | |
|
253 | 253 | def test_text_formatting |
|
254 | 254 | to_test = {'*_+bold, italic and underline+_*' => '<strong><em><ins>bold, italic and underline</ins></em></strong>', |
|
255 | 255 | '(_text within parentheses_)' => '(<em>text within parentheses</em>)', |
|
256 | 256 | 'a *Humane Web* Text Generator' => 'a <strong>Humane Web</strong> Text Generator', |
|
257 | 257 | '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>', |
|
258 | 258 | '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', |
|
259 | 259 | } |
|
260 | 260 | to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) } |
|
261 | 261 | end |
|
262 | 262 | |
|
263 | 263 | def test_wiki_horizontal_rule |
|
264 | 264 | assert_equal '<hr />', textilizable('---') |
|
265 | 265 | assert_equal '<p>Dashes: ---</p>', textilizable('Dashes: ---') |
|
266 | 266 | end |
|
267 | 267 | |
|
268 | 268 | def test_acronym |
|
269 | 269 | assert_equal '<p>This is an acronym: <acronym title="American Civil Liberties Union">ACLU</acronym>.</p>', |
|
270 | 270 | textilizable('This is an acronym: ACLU(American Civil Liberties Union).') |
|
271 | 271 | end |
|
272 | 272 | |
|
273 | 273 | def test_footnotes |
|
274 | 274 | raw = <<-RAW |
|
275 | 275 | This is some text[1]. |
|
276 | 276 | |
|
277 | 277 | fn1. This is the foot note |
|
278 | 278 | RAW |
|
279 | 279 | |
|
280 | 280 | expected = <<-EXPECTED |
|
281 | 281 | <p>This is some text<sup><a href=\"#fn1\">1</a></sup>.</p> |
|
282 | 282 | <p id="fn1" class="footnote"><sup>1</sup> This is the foot note</p> |
|
283 | 283 | EXPECTED |
|
284 | 284 | |
|
285 | 285 | assert_equal expected.gsub(%r{[\r\n\t]}, ''), textilizable(raw).gsub(%r{[\r\n\t]}, '') |
|
286 | 286 | end |
|
287 | 287 | |
|
288 | 288 | def test_table_of_content |
|
289 | 289 | raw = <<-RAW |
|
290 | 290 | {{toc}} |
|
291 | 291 | |
|
292 | 292 | h1. Title |
|
293 | 293 | |
|
294 | 294 | Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas sed libero. |
|
295 | 295 | |
|
296 | 296 | h2. Subtitle |
|
297 | 297 | |
|
298 | 298 | Nullam commodo metus accumsan nulla. Curabitur lobortis dui id dolor. |
|
299 | 299 | |
|
300 | 300 | h2. Subtitle with %{color:red}red text% |
|
301 | 301 | |
|
302 | 302 | h1. Another title |
|
303 | 303 | |
|
304 | 304 | RAW |
|
305 | 305 | |
|
306 | 306 | expected = '<ul class="toc">' + |
|
307 | 307 | '<li class="heading1"><a href="#Title">Title</a></li>' + |
|
308 | 308 | '<li class="heading2"><a href="#Subtitle">Subtitle</a></li>' + |
|
309 | 309 | '<li class="heading2"><a href="#Subtitle-with-red-text">Subtitle with red text</a></li>' + |
|
310 | 310 | '<li class="heading1"><a href="#Another-title">Another title</a></li>' + |
|
311 | 311 | '</ul>' |
|
312 | 312 | |
|
313 | 313 | assert textilizable(raw).gsub("\n", "").include?(expected) |
|
314 | 314 | end |
|
315 | 315 | |
|
316 | 316 | def test_blockquote |
|
317 | 317 | # orig raw text |
|
318 | 318 | raw = <<-RAW |
|
319 | 319 | John said: |
|
320 | 320 | > Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas sed libero. |
|
321 | 321 | > Nullam commodo metus accumsan nulla. Curabitur lobortis dui id dolor. |
|
322 | 322 | > * Donec odio lorem, |
|
323 | 323 | > * sagittis ac, |
|
324 | 324 | > * malesuada in, |
|
325 | 325 | > * adipiscing eu, dolor. |
|
326 | 326 | > |
|
327 | 327 | > >Nulla varius pulvinar diam. Proin id arcu id lorem scelerisque condimentum. Proin vehicula turpis vitae lacus. |
|
328 | 328 | > Proin a tellus. Nam vel neque. |
|
329 | 329 | |
|
330 | 330 | He's right. |
|
331 | 331 | RAW |
|
332 | 332 | |
|
333 | 333 | # expected html |
|
334 | 334 | expected = <<-EXPECTED |
|
335 | 335 | <p>John said:</p> |
|
336 | 336 | <blockquote> |
|
337 | 337 | Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas sed libero. |
|
338 | 338 | Nullam commodo metus accumsan nulla. Curabitur lobortis dui id dolor. |
|
339 | 339 | <ul> |
|
340 | 340 | <li>Donec odio lorem,</li> |
|
341 | 341 | <li>sagittis ac,</li> |
|
342 | 342 | <li>malesuada in,</li> |
|
343 | 343 | <li>adipiscing eu, dolor.</li> |
|
344 | 344 | </ul> |
|
345 | 345 | <blockquote> |
|
346 | 346 | <p>Nulla varius pulvinar diam. Proin id arcu id lorem scelerisque condimentum. Proin vehicula turpis vitae lacus.</p> |
|
347 | 347 | </blockquote> |
|
348 | 348 | <p>Proin a tellus. Nam vel neque.</p> |
|
349 | 349 | </blockquote> |
|
350 | 350 | <p>He's right.</p> |
|
351 | 351 | EXPECTED |
|
352 | 352 | |
|
353 | 353 | assert_equal expected.gsub(%r{\s+}, ''), textilizable(raw).gsub(%r{\s+}, '') |
|
354 | 354 | end |
|
355 | 355 | |
|
356 | 356 | def test_table |
|
357 | 357 | raw = <<-RAW |
|
358 | 358 | This is a table with empty cells: |
|
359 | 359 | |
|
360 | 360 | |cell11|cell12|| |
|
361 | 361 | |cell21||cell23| |
|
362 | 362 | |cell31|cell32|cell33| |
|
363 | 363 | RAW |
|
364 | 364 | |
|
365 | 365 | expected = <<-EXPECTED |
|
366 | 366 | <p>This is a table with empty cells:</p> |
|
367 | 367 | |
|
368 | 368 | <table> |
|
369 | 369 | <tr><td>cell11</td><td>cell12</td><td></td></tr> |
|
370 | 370 | <tr><td>cell21</td><td></td><td>cell23</td></tr> |
|
371 | 371 | <tr><td>cell31</td><td>cell32</td><td>cell33</td></tr> |
|
372 | 372 | </table> |
|
373 | 373 | EXPECTED |
|
374 | 374 | |
|
375 | 375 | assert_equal expected.gsub(%r{\s+}, ''), textilizable(raw).gsub(%r{\s+}, '') |
|
376 | 376 | end |
|
377 | 377 | |
|
378 | 378 | def test_default_formatter |
|
379 | 379 | Setting.text_formatting = 'unknown' |
|
380 | 380 | text = 'a *link*: http://www.example.net/' |
|
381 | 381 | assert_equal '<p>a *link*: <a href="http://www.example.net/">http://www.example.net/</a></p>', textilizable(text) |
|
382 | 382 | Setting.text_formatting = 'textile' |
|
383 | 383 | end |
|
384 | 384 | |
|
385 | 385 | def test_date_format_default |
|
386 | 386 | today = Date.today |
|
387 | 387 | Setting.date_format = '' |
|
388 | 388 | assert_equal l_date(today), format_date(today) |
|
389 | 389 | end |
|
390 | 390 | |
|
391 | 391 | def test_date_format |
|
392 | 392 | today = Date.today |
|
393 | 393 | Setting.date_format = '%d %m %Y' |
|
394 | 394 | assert_equal today.strftime('%d %m %Y'), format_date(today) |
|
395 | 395 | end |
|
396 | 396 | |
|
397 | 397 | def test_time_format_default |
|
398 | 398 | now = Time.now |
|
399 | 399 | Setting.date_format = '' |
|
400 | 400 | Setting.time_format = '' |
|
401 | 401 | assert_equal l_datetime(now), format_time(now) |
|
402 | 402 | assert_equal l_time(now), format_time(now, false) |
|
403 | 403 | end |
|
404 | 404 | |
|
405 | 405 | def test_time_format |
|
406 | 406 | now = Time.now |
|
407 | 407 | Setting.date_format = '%d %m %Y' |
|
408 | 408 | Setting.time_format = '%H %M' |
|
409 | 409 | assert_equal now.strftime('%d %m %Y %H %M'), format_time(now) |
|
410 | 410 | assert_equal now.strftime('%H %M'), format_time(now, false) |
|
411 | 411 | end |
|
412 | 412 | |
|
413 | 413 | def test_utc_time_format |
|
414 | 414 | now = Time.now.utc |
|
415 | 415 | Setting.date_format = '%d %m %Y' |
|
416 | 416 | Setting.time_format = '%H %M' |
|
417 | 417 | assert_equal Time.now.strftime('%d %m %Y %H %M'), format_time(now) |
|
418 | 418 | assert_equal Time.now.strftime('%H %M'), format_time(now, false) |
|
419 | 419 | end |
|
420 | 420 | |
|
421 | 421 | def test_due_date_distance_in_words |
|
422 | 422 | to_test = { Date.today => 'Due in 0 days', |
|
423 | 423 | Date.today + 1 => 'Due in 1 day', |
|
424 | 424 | Date.today + 100 => 'Due in 100 days', |
|
425 | 425 | Date.today + 20000 => 'Due in 20000 days', |
|
426 | 426 | Date.today - 1 => '1 day late', |
|
427 | 427 | Date.today - 100 => '100 days late', |
|
428 | 428 | Date.today - 20000 => '20000 days late', |
|
429 | 429 | } |
|
430 | 430 | to_test.each do |date, expected| |
|
431 | 431 | assert_equal expected, due_date_distance_in_words(date) |
|
432 | 432 | end |
|
433 | 433 | end |
|
434 | 434 | |
|
435 | 435 | def test_avatar |
|
436 | 436 | # turn on avatars |
|
437 | 437 | Setting.gravatar_enabled = '1' |
|
438 | 438 | assert avatar(User.find_by_mail('jsmith@somenet.foo')).include?(Digest::MD5.hexdigest('jsmith@somenet.foo')) |
|
439 | 439 | assert avatar('jsmith <jsmith@somenet.foo>').include?(Digest::MD5.hexdigest('jsmith@somenet.foo')) |
|
440 | 440 | assert_nil avatar('jsmith') |
|
441 | 441 | assert_nil avatar(nil) |
|
442 | 442 | |
|
443 | 443 | # turn off avatars |
|
444 | 444 | Setting.gravatar_enabled = '0' |
|
445 | 445 | assert_nil avatar(User.find_by_mail('jsmith@somenet.foo')) |
|
446 | 446 | end |
|
447 | 447 | end |
@@ -1,98 +1,98 | |||
|
1 | 1 | # Redmine - project management software |
|
2 | 2 | # Copyright (C) 2006-2008 Jean-Philippe Lang |
|
3 | 3 | # |
|
4 | 4 | # This program is free software; you can redistribute it and/or |
|
5 | 5 | # modify it under the terms of the GNU General Public License |
|
6 | 6 | # as published by the Free Software Foundation; either version 2 |
|
7 | 7 | # of the License, or (at your option) any later version. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU General Public License |
|
15 | 15 | # along with this program; if not, write to the Free Software |
|
16 | 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 | 17 | |
|
18 | 18 | require File.dirname(__FILE__) + '/../../../../test_helper' |
|
19 | 19 | |
|
20 | 20 | class Redmine::WikiFormatting::MacrosTest < HelperTestCase |
|
21 | 21 | include ApplicationHelper |
|
22 | 22 | include ActionView::Helpers::TextHelper |
|
23 | 23 | fixtures :projects, :roles, :enabled_modules, :users, |
|
24 | 24 | :repositories, :changesets, |
|
25 | 25 | :trackers, :issue_statuses, :issues, |
|
26 | 26 | :versions, :documents, |
|
27 | 27 | :wikis, :wiki_pages, :wiki_contents, |
|
28 | 28 | :boards, :messages, |
|
29 | 29 | :attachments |
|
30 | 30 | |
|
31 | 31 | def setup |
|
32 | 32 | super |
|
33 | 33 | @project = nil |
|
34 | 34 | end |
|
35 | 35 | |
|
36 | 36 | def teardown |
|
37 | 37 | end |
|
38 | 38 | |
|
39 | 39 | def test_macro_hello_world |
|
40 | 40 | text = "{{hello_world}}" |
|
41 | 41 | assert textilizable(text).match(/Hello world!/) |
|
42 | 42 | # escaping |
|
43 | 43 | text = "!{{hello_world}}" |
|
44 | 44 | assert_equal '<p>{{hello_world}}</p>', textilizable(text) |
|
45 | 45 | end |
|
46 | 46 | |
|
47 | 47 | def test_macro_include |
|
48 | 48 | @project = Project.find(1) |
|
49 | 49 | # include a page of the current project wiki |
|
50 | 50 | text = "{{include(Another page)}}" |
|
51 | 51 | assert textilizable(text).match(/This is a link to a ticket/) |
|
52 | 52 | |
|
53 | 53 | @project = nil |
|
54 | 54 | # include a page of a specific project wiki |
|
55 | 55 | text = "{{include(ecookbook:Another page)}}" |
|
56 | 56 | assert textilizable(text).match(/This is a link to a ticket/) |
|
57 | 57 | |
|
58 | 58 | text = "{{include(ecookbook:)}}" |
|
59 | 59 | assert textilizable(text).match(/CookBook documentation/) |
|
60 | 60 | |
|
61 | 61 | text = "{{include(unknowidentifier:somepage)}}" |
|
62 | 62 | assert textilizable(text).match(/Page not found/) |
|
63 | 63 | end |
|
64 | 64 | |
|
65 | 65 | def test_macro_child_pages |
|
66 | 66 | expected = "<p><ul class=\"pages-hierarchy\">\n" + |
|
67 |
"<li><a href=\"/ |
|
|
68 |
"<li><a href=\"/ |
|
|
67 | "<li><a href=\"/projects/ecookbook/wiki/Child_1\">Child 1</a></li>\n" + | |
|
68 | "<li><a href=\"/projects/ecookbook/wiki/Child_2\">Child 2</a></li>\n" + | |
|
69 | 69 | "</ul>\n</p>" |
|
70 | 70 | |
|
71 | 71 | @project = Project.find(1) |
|
72 | 72 | # child pages of the current wiki page |
|
73 | 73 | assert_equal expected, textilizable("{{child_pages}}", :object => WikiPage.find(2).content) |
|
74 | 74 | # child pages of another page |
|
75 | 75 | assert_equal expected, textilizable("{{child_pages(Another_page)}}", :object => WikiPage.find(1).content) |
|
76 | 76 | |
|
77 | 77 | @project = Project.find(2) |
|
78 | 78 | assert_equal expected, textilizable("{{child_pages(ecookbook:Another_page)}}", :object => WikiPage.find(1).content) |
|
79 | 79 | end |
|
80 | 80 | |
|
81 | 81 | def test_macro_child_pages_with_option |
|
82 | 82 | expected = "<p><ul class=\"pages-hierarchy\">\n" + |
|
83 |
"<li><a href=\"/ |
|
|
83 | "<li><a href=\"/projects/ecookbook/wiki/Another_page\">Another page</a>\n" + | |
|
84 | 84 | "<ul class=\"pages-hierarchy\">\n" + |
|
85 |
"<li><a href=\"/ |
|
|
86 |
"<li><a href=\"/ |
|
|
85 | "<li><a href=\"/projects/ecookbook/wiki/Child_1\">Child 1</a></li>\n" + | |
|
86 | "<li><a href=\"/projects/ecookbook/wiki/Child_2\">Child 2</a></li>\n" + | |
|
87 | 87 | "</ul>\n</li>\n</ul>\n</p>" |
|
88 | 88 | |
|
89 | 89 | @project = Project.find(1) |
|
90 | 90 | # child pages of the current wiki page |
|
91 | 91 | assert_equal expected, textilizable("{{child_pages(parent=1)}}", :object => WikiPage.find(2).content) |
|
92 | 92 | # child pages of another page |
|
93 | 93 | assert_equal expected, textilizable("{{child_pages(Another_page, parent=1)}}", :object => WikiPage.find(1).content) |
|
94 | 94 | |
|
95 | 95 | @project = Project.find(2) |
|
96 | 96 | assert_equal expected, textilizable("{{child_pages(ecookbook:Another_page, parent=1)}}", :object => WikiPage.find(1).content) |
|
97 | 97 | end |
|
98 | 98 | end |
@@ -1,224 +1,224 | |||
|
1 | 1 | # redMine - project management software |
|
2 | 2 | # Copyright (C) 2006-2007 Jean-Philippe Lang |
|
3 | 3 | # |
|
4 | 4 | # This program is free software; you can redistribute it and/or |
|
5 | 5 | # modify it under the terms of the GNU General Public License |
|
6 | 6 | # as published by the Free Software Foundation; either version 2 |
|
7 | 7 | # of the License, or (at your option) any later version. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU General Public License |
|
15 | 15 | # along with this program; if not, write to the Free Software |
|
16 | 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 | 17 | |
|
18 | 18 | require File.dirname(__FILE__) + '/../test_helper' |
|
19 | 19 | |
|
20 | 20 | class MailerTest < Test::Unit::TestCase |
|
21 | 21 | fixtures :projects, :issues, :users, :members, :documents, :attachments, :news, :tokens, :journals, :journal_details, :changesets, :trackers, :issue_statuses, :enumerations, :messages, :boards, :repositories |
|
22 | 22 | |
|
23 | 23 | def test_generated_links_in_emails |
|
24 | 24 | ActionMailer::Base.deliveries.clear |
|
25 | 25 | Setting.host_name = 'mydomain.foo' |
|
26 | 26 | Setting.protocol = 'https' |
|
27 | 27 | |
|
28 | 28 | journal = Journal.find(2) |
|
29 | 29 | assert Mailer.deliver_issue_edit(journal) |
|
30 | 30 | |
|
31 | 31 | mail = ActionMailer::Base.deliveries.last |
|
32 | 32 | assert_kind_of TMail::Mail, mail |
|
33 | 33 | # link to the main ticket |
|
34 |
assert mail.body.include?('<a href="https://mydomain.foo/issues/ |
|
|
34 | assert mail.body.include?('<a href="https://mydomain.foo/issues/1">Bug #1: Can\'t print recipes</a>') | |
|
35 | 35 | |
|
36 | 36 | # link to a referenced ticket |
|
37 |
assert mail.body.include?('<a href="https://mydomain.foo/issues/ |
|
|
37 | assert mail.body.include?('<a href="https://mydomain.foo/issues/2" class="issue" title="Add ingredients categories (Assigned)">#2</a>') | |
|
38 | 38 | # link to a changeset |
|
39 |
assert mail.body.include?('<a href="https://mydomain.foo/repositor |
|
|
39 | assert mail.body.include?('<a href="https://mydomain.foo/projects/ecookbook/repository/revisions/2" class="changeset" title="This commit fixes #1, #2 and references #1 & #3">r2</a>') | |
|
40 | 40 | end |
|
41 | 41 | |
|
42 | 42 | def test_generated_links_with_prefix |
|
43 | 43 | relative_url_root = Redmine::Utils.relative_url_root |
|
44 | 44 | ActionMailer::Base.deliveries.clear |
|
45 | 45 | Setting.host_name = 'mydomain.foo/rdm' |
|
46 | 46 | Setting.protocol = 'http' |
|
47 | 47 | Redmine::Utils.relative_url_root = '/rdm' |
|
48 | 48 | |
|
49 | 49 | journal = Journal.find(2) |
|
50 | 50 | assert Mailer.deliver_issue_edit(journal) |
|
51 | 51 | |
|
52 | 52 | mail = ActionMailer::Base.deliveries.last |
|
53 | 53 | assert_kind_of TMail::Mail, mail |
|
54 | 54 | # link to the main ticket |
|
55 |
assert mail.body.include?('<a href="http://mydomain.foo/rdm/issues/ |
|
|
55 | assert mail.body.include?('<a href="http://mydomain.foo/rdm/issues/1">Bug #1: Can\'t print recipes</a>') | |
|
56 | 56 | |
|
57 | 57 | # link to a referenced ticket |
|
58 |
assert mail.body.include?('<a href="http://mydomain.foo/rdm/issues/ |
|
|
58 | assert mail.body.include?('<a href="http://mydomain.foo/rdm/issues/2" class="issue" title="Add ingredients categories (Assigned)">#2</a>') | |
|
59 | 59 | # link to a changeset |
|
60 |
assert mail.body.include?('<a href="http://mydomain.foo/rdm/repositor |
|
|
60 | assert mail.body.include?('<a href="http://mydomain.foo/rdm/projects/ecookbook/repository/revisions/2" class="changeset" title="This commit fixes #1, #2 and references #1 & #3">r2</a>') | |
|
61 | 61 | ensure |
|
62 | 62 | # restore it |
|
63 | 63 | Redmine::Utils.relative_url_root = relative_url_root |
|
64 | 64 | end |
|
65 | 65 | |
|
66 | 66 | def test_generated_links_with_prefix_and_no_relative_url_root |
|
67 | 67 | relative_url_root = Redmine::Utils.relative_url_root |
|
68 | 68 | ActionMailer::Base.deliveries.clear |
|
69 | 69 | Setting.host_name = 'mydomain.foo/rdm' |
|
70 | 70 | Setting.protocol = 'http' |
|
71 | 71 | Redmine::Utils.relative_url_root = nil |
|
72 | 72 | |
|
73 | 73 | journal = Journal.find(2) |
|
74 | 74 | assert Mailer.deliver_issue_edit(journal) |
|
75 | 75 | |
|
76 | 76 | mail = ActionMailer::Base.deliveries.last |
|
77 | 77 | assert_kind_of TMail::Mail, mail |
|
78 | 78 | # link to the main ticket |
|
79 |
assert mail.body.include?('<a href="http://mydomain.foo/rdm/issues/ |
|
|
79 | assert mail.body.include?('<a href="http://mydomain.foo/rdm/issues/1">Bug #1: Can\'t print recipes</a>') | |
|
80 | 80 | |
|
81 | 81 | # link to a referenced ticket |
|
82 |
assert mail.body.include?('<a href="http://mydomain.foo/rdm/issues/ |
|
|
82 | assert mail.body.include?('<a href="http://mydomain.foo/rdm/issues/2" class="issue" title="Add ingredients categories (Assigned)">#2</a>') | |
|
83 | 83 | # link to a changeset |
|
84 |
assert mail.body.include?('<a href="http://mydomain.foo/rdm/repositor |
|
|
84 | assert mail.body.include?('<a href="http://mydomain.foo/rdm/projects/ecookbook/repository/revisions/2" class="changeset" title="This commit fixes #1, #2 and references #1 & #3">r2</a>') | |
|
85 | 85 | ensure |
|
86 | 86 | # restore it |
|
87 | 87 | Redmine::Utils.relative_url_root = relative_url_root |
|
88 | 88 | end |
|
89 | 89 | |
|
90 | 90 | def test_plain_text_mail |
|
91 | 91 | Setting.plain_text_mail = 1 |
|
92 | 92 | journal = Journal.find(2) |
|
93 | 93 | Mailer.deliver_issue_edit(journal) |
|
94 | 94 | mail = ActionMailer::Base.deliveries.last |
|
95 |
assert !mail.body.include?('<a href="https://mydomain.foo/issues/ |
|
|
95 | assert !mail.body.include?('<a href="https://mydomain.foo/issues/1">Bug #1: Can\'t print recipes</a>') | |
|
96 | 96 | end |
|
97 | 97 | |
|
98 | 98 | def test_issue_add_message_id |
|
99 | 99 | ActionMailer::Base.deliveries.clear |
|
100 | 100 | issue = Issue.find(1) |
|
101 | 101 | Mailer.deliver_issue_add(issue) |
|
102 | 102 | mail = ActionMailer::Base.deliveries.last |
|
103 | 103 | assert_not_nil mail |
|
104 | 104 | assert_equal Mailer.message_id_for(issue), mail.message_id |
|
105 | 105 | assert_nil mail.references |
|
106 | 106 | end |
|
107 | 107 | |
|
108 | 108 | def test_issue_edit_message_id |
|
109 | 109 | ActionMailer::Base.deliveries.clear |
|
110 | 110 | journal = Journal.find(1) |
|
111 | 111 | Mailer.deliver_issue_edit(journal) |
|
112 | 112 | mail = ActionMailer::Base.deliveries.last |
|
113 | 113 | assert_not_nil mail |
|
114 | 114 | assert_equal Mailer.message_id_for(journal), mail.message_id |
|
115 | 115 | assert_equal Mailer.message_id_for(journal.issue), mail.references.to_s |
|
116 | 116 | end |
|
117 | 117 | |
|
118 | 118 | def test_message_posted_message_id |
|
119 | 119 | ActionMailer::Base.deliveries.clear |
|
120 | 120 | message = Message.find(1) |
|
121 | 121 | Mailer.deliver_message_posted(message, message.author.mail) |
|
122 | 122 | mail = ActionMailer::Base.deliveries.last |
|
123 | 123 | assert_not_nil mail |
|
124 | 124 | assert_equal Mailer.message_id_for(message), mail.message_id |
|
125 | 125 | assert_nil mail.references |
|
126 | 126 | end |
|
127 | 127 | |
|
128 | 128 | def test_reply_posted_message_id |
|
129 | 129 | ActionMailer::Base.deliveries.clear |
|
130 | 130 | message = Message.find(3) |
|
131 | 131 | Mailer.deliver_message_posted(message, message.author.mail) |
|
132 | 132 | mail = ActionMailer::Base.deliveries.last |
|
133 | 133 | assert_not_nil mail |
|
134 | 134 | assert_equal Mailer.message_id_for(message), mail.message_id |
|
135 | 135 | assert_equal Mailer.message_id_for(message.parent), mail.references.to_s |
|
136 | 136 | end |
|
137 | 137 | |
|
138 | 138 | # test mailer methods for each language |
|
139 | 139 | def test_issue_add |
|
140 | 140 | issue = Issue.find(1) |
|
141 | 141 | GLoc.valid_languages.each do |lang| |
|
142 | 142 | Setting.default_language = lang.to_s |
|
143 | 143 | assert Mailer.deliver_issue_add(issue) |
|
144 | 144 | end |
|
145 | 145 | end |
|
146 | 146 | |
|
147 | 147 | def test_issue_edit |
|
148 | 148 | journal = Journal.find(1) |
|
149 | 149 | GLoc.valid_languages.each do |lang| |
|
150 | 150 | Setting.default_language = lang.to_s |
|
151 | 151 | assert Mailer.deliver_issue_edit(journal) |
|
152 | 152 | end |
|
153 | 153 | end |
|
154 | 154 | |
|
155 | 155 | def test_document_added |
|
156 | 156 | document = Document.find(1) |
|
157 | 157 | GLoc.valid_languages.each do |lang| |
|
158 | 158 | Setting.default_language = lang.to_s |
|
159 | 159 | assert Mailer.deliver_document_added(document) |
|
160 | 160 | end |
|
161 | 161 | end |
|
162 | 162 | |
|
163 | 163 | def test_attachments_added |
|
164 | 164 | attachements = [ Attachment.find_by_container_type('Document') ] |
|
165 | 165 | GLoc.valid_languages.each do |lang| |
|
166 | 166 | Setting.default_language = lang.to_s |
|
167 | 167 | assert Mailer.deliver_attachments_added(attachements) |
|
168 | 168 | end |
|
169 | 169 | end |
|
170 | 170 | |
|
171 | 171 | def test_news_added |
|
172 | 172 | news = News.find(:first) |
|
173 | 173 | GLoc.valid_languages.each do |lang| |
|
174 | 174 | Setting.default_language = lang.to_s |
|
175 | 175 | assert Mailer.deliver_news_added(news) |
|
176 | 176 | end |
|
177 | 177 | end |
|
178 | 178 | |
|
179 | 179 | def test_message_posted |
|
180 | 180 | message = Message.find(:first) |
|
181 | 181 | recipients = ([message.root] + message.root.children).collect {|m| m.author.mail if m.author} |
|
182 | 182 | recipients = recipients.compact.uniq |
|
183 | 183 | GLoc.valid_languages.each do |lang| |
|
184 | 184 | Setting.default_language = lang.to_s |
|
185 | 185 | assert Mailer.deliver_message_posted(message, recipients) |
|
186 | 186 | end |
|
187 | 187 | end |
|
188 | 188 | |
|
189 | 189 | def test_account_information |
|
190 | 190 | user = User.find(:first) |
|
191 | 191 | GLoc.valid_languages.each do |lang| |
|
192 | 192 | user.update_attribute :language, lang.to_s |
|
193 | 193 | user.reload |
|
194 | 194 | assert Mailer.deliver_account_information(user, 'pAsswORd') |
|
195 | 195 | end |
|
196 | 196 | end |
|
197 | 197 | |
|
198 | 198 | def test_lost_password |
|
199 | 199 | token = Token.find(2) |
|
200 | 200 | GLoc.valid_languages.each do |lang| |
|
201 | 201 | token.user.update_attribute :language, lang.to_s |
|
202 | 202 | token.reload |
|
203 | 203 | assert Mailer.deliver_lost_password(token) |
|
204 | 204 | end |
|
205 | 205 | end |
|
206 | 206 | |
|
207 | 207 | def test_register |
|
208 | 208 | token = Token.find(1) |
|
209 | 209 | GLoc.valid_languages.each do |lang| |
|
210 | 210 | token.user.update_attribute :language, lang.to_s |
|
211 | 211 | token.reload |
|
212 | 212 | assert Mailer.deliver_register(token) |
|
213 | 213 | end |
|
214 | 214 | end |
|
215 | 215 | |
|
216 | 216 | def test_reminders |
|
217 | 217 | ActionMailer::Base.deliveries.clear |
|
218 | 218 | Mailer.reminders(:days => 42) |
|
219 | 219 | assert_equal 1, ActionMailer::Base.deliveries.size |
|
220 | 220 | mail = ActionMailer::Base.deliveries.last |
|
221 | 221 | assert mail.bcc.include?('dlopper@somenet.foo') |
|
222 | 222 | assert mail.body.include?('Bug #3: Error 281 when updating a recipe') |
|
223 | 223 | end |
|
224 | 224 | end |
General Comments 0
You need to be logged in to leave comments.
Login now