##// END OF EJS Templates
Do not cache I18n strings when truncating a long diff (#5089)....
Jean-Baptiste Barth -
r5953:115d22729848
parent child
Show More
@@ -1,374 +1,374
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require 'SVG/Graph/Bar'
18 require 'SVG/Graph/Bar'
19 require 'SVG/Graph/BarHorizontal'
19 require 'SVG/Graph/BarHorizontal'
20 require 'digest/sha1'
20 require 'digest/sha1'
21
21
22 class ChangesetNotFound < Exception; end
22 class ChangesetNotFound < Exception; end
23 class InvalidRevisionParam < Exception; end
23 class InvalidRevisionParam < Exception; end
24
24
25 class RepositoriesController < ApplicationController
25 class RepositoriesController < ApplicationController
26 menu_item :repository
26 menu_item :repository
27 menu_item :settings, :only => :edit
27 menu_item :settings, :only => :edit
28 default_search_scope :changesets
28 default_search_scope :changesets
29
29
30 before_filter :find_repository, :except => :edit
30 before_filter :find_repository, :except => :edit
31 before_filter :find_project, :only => :edit
31 before_filter :find_project, :only => :edit
32 before_filter :authorize
32 before_filter :authorize
33 accept_key_auth :revisions
33 accept_key_auth :revisions
34
34
35 rescue_from Redmine::Scm::Adapters::CommandFailed, :with => :show_error_command_failed
35 rescue_from Redmine::Scm::Adapters::CommandFailed, :with => :show_error_command_failed
36
36
37 def edit
37 def edit
38 @repository = @project.repository
38 @repository = @project.repository
39 if !@repository && !params[:repository_scm].blank?
39 if !@repository && !params[:repository_scm].blank?
40 @repository = Repository.factory(params[:repository_scm])
40 @repository = Repository.factory(params[:repository_scm])
41 @repository.project = @project if @repository
41 @repository.project = @project if @repository
42 end
42 end
43 if request.post? && @repository
43 if request.post? && @repository
44 p1 = params[:repository]
44 p1 = params[:repository]
45 p = {}
45 p = {}
46 p_extra = {}
46 p_extra = {}
47 p1.each do |k, v|
47 p1.each do |k, v|
48 if k =~ /^extra_/
48 if k =~ /^extra_/
49 p_extra[k] = v
49 p_extra[k] = v
50 else
50 else
51 p[k] = v
51 p[k] = v
52 end
52 end
53 end
53 end
54 @repository.attributes = p
54 @repository.attributes = p
55 @repository.merge_extra_info(p_extra)
55 @repository.merge_extra_info(p_extra)
56 @repository.save
56 @repository.save
57 end
57 end
58 render(:update) do |page|
58 render(:update) do |page|
59 page.replace_html "tab-content-repository",
59 page.replace_html "tab-content-repository",
60 :partial => 'projects/settings/repository'
60 :partial => 'projects/settings/repository'
61 if @repository && !@project.repository
61 if @repository && !@project.repository
62 @project.reload # needed to reload association
62 @project.reload # needed to reload association
63 page.replace_html "main-menu", render_main_menu(@project)
63 page.replace_html "main-menu", render_main_menu(@project)
64 end
64 end
65 end
65 end
66 end
66 end
67
67
68 def committers
68 def committers
69 @committers = @repository.committers
69 @committers = @repository.committers
70 @users = @project.users
70 @users = @project.users
71 additional_user_ids = @committers.collect(&:last).collect(&:to_i) - @users.collect(&:id)
71 additional_user_ids = @committers.collect(&:last).collect(&:to_i) - @users.collect(&:id)
72 @users += User.find_all_by_id(additional_user_ids) unless additional_user_ids.empty?
72 @users += User.find_all_by_id(additional_user_ids) unless additional_user_ids.empty?
73 @users.compact!
73 @users.compact!
74 @users.sort!
74 @users.sort!
75 if request.post? && params[:committers].is_a?(Hash)
75 if request.post? && params[:committers].is_a?(Hash)
76 # Build a hash with repository usernames as keys and corresponding user ids as values
76 # Build a hash with repository usernames as keys and corresponding user ids as values
77 @repository.committer_ids = params[:committers].values.inject({}) {|h, c| h[c.first] = c.last; h}
77 @repository.committer_ids = params[:committers].values.inject({}) {|h, c| h[c.first] = c.last; h}
78 flash[:notice] = l(:notice_successful_update)
78 flash[:notice] = l(:notice_successful_update)
79 redirect_to :action => 'committers', :id => @project
79 redirect_to :action => 'committers', :id => @project
80 end
80 end
81 end
81 end
82
82
83 def destroy
83 def destroy
84 @repository.destroy
84 @repository.destroy
85 redirect_to :controller => 'projects',
85 redirect_to :controller => 'projects',
86 :action => 'settings',
86 :action => 'settings',
87 :id => @project,
87 :id => @project,
88 :tab => 'repository'
88 :tab => 'repository'
89 end
89 end
90
90
91 def show
91 def show
92 @repository.fetch_changesets if Setting.autofetch_changesets? && @path.empty?
92 @repository.fetch_changesets if Setting.autofetch_changesets? && @path.empty?
93
93
94 @entries = @repository.entries(@path, @rev)
94 @entries = @repository.entries(@path, @rev)
95 @changeset = @repository.find_changeset_by_name(@rev)
95 @changeset = @repository.find_changeset_by_name(@rev)
96 if request.xhr?
96 if request.xhr?
97 @entries ? render(:partial => 'dir_list_content') : render(:nothing => true)
97 @entries ? render(:partial => 'dir_list_content') : render(:nothing => true)
98 else
98 else
99 (show_error_not_found; return) unless @entries
99 (show_error_not_found; return) unless @entries
100 @changesets = @repository.latest_changesets(@path, @rev)
100 @changesets = @repository.latest_changesets(@path, @rev)
101 @properties = @repository.properties(@path, @rev)
101 @properties = @repository.properties(@path, @rev)
102 render :action => 'show'
102 render :action => 'show'
103 end
103 end
104 end
104 end
105
105
106 alias_method :browse, :show
106 alias_method :browse, :show
107
107
108 def changes
108 def changes
109 @entry = @repository.entry(@path, @rev)
109 @entry = @repository.entry(@path, @rev)
110 (show_error_not_found; return) unless @entry
110 (show_error_not_found; return) unless @entry
111 @changesets = @repository.latest_changesets(@path, @rev, Setting.repository_log_display_limit.to_i)
111 @changesets = @repository.latest_changesets(@path, @rev, Setting.repository_log_display_limit.to_i)
112 @properties = @repository.properties(@path, @rev)
112 @properties = @repository.properties(@path, @rev)
113 @changeset = @repository.find_changeset_by_name(@rev)
113 @changeset = @repository.find_changeset_by_name(@rev)
114 end
114 end
115
115
116 def revisions
116 def revisions
117 @changeset_count = @repository.changesets.count
117 @changeset_count = @repository.changesets.count
118 @changeset_pages = Paginator.new self, @changeset_count,
118 @changeset_pages = Paginator.new self, @changeset_count,
119 per_page_option,
119 per_page_option,
120 params['page']
120 params['page']
121 @changesets = @repository.changesets.find(:all,
121 @changesets = @repository.changesets.find(:all,
122 :limit => @changeset_pages.items_per_page,
122 :limit => @changeset_pages.items_per_page,
123 :offset => @changeset_pages.current.offset,
123 :offset => @changeset_pages.current.offset,
124 :include => [:user, :repository])
124 :include => [:user, :repository])
125
125
126 respond_to do |format|
126 respond_to do |format|
127 format.html { render :layout => false if request.xhr? }
127 format.html { render :layout => false if request.xhr? }
128 format.atom { render_feed(@changesets, :title => "#{@project.name}: #{l(:label_revision_plural)}") }
128 format.atom { render_feed(@changesets, :title => "#{@project.name}: #{l(:label_revision_plural)}") }
129 end
129 end
130 end
130 end
131
131
132 def entry
132 def entry
133 @entry = @repository.entry(@path, @rev)
133 @entry = @repository.entry(@path, @rev)
134 (show_error_not_found; return) unless @entry
134 (show_error_not_found; return) unless @entry
135
135
136 # If the entry is a dir, show the browser
136 # If the entry is a dir, show the browser
137 (show; return) if @entry.is_dir?
137 (show; return) if @entry.is_dir?
138
138
139 @content = @repository.cat(@path, @rev)
139 @content = @repository.cat(@path, @rev)
140 (show_error_not_found; return) unless @content
140 (show_error_not_found; return) unless @content
141 if 'raw' == params[:format] ||
141 if 'raw' == params[:format] ||
142 (@content.size && @content.size > Setting.file_max_size_displayed.to_i.kilobyte) ||
142 (@content.size && @content.size > Setting.file_max_size_displayed.to_i.kilobyte) ||
143 ! is_entry_text_data?(@content, @path)
143 ! is_entry_text_data?(@content, @path)
144 # Force the download
144 # Force the download
145 send_opt = { :filename => filename_for_content_disposition(@path.split('/').last) }
145 send_opt = { :filename => filename_for_content_disposition(@path.split('/').last) }
146 send_type = Redmine::MimeType.of(@path)
146 send_type = Redmine::MimeType.of(@path)
147 send_opt[:type] = send_type.to_s if send_type
147 send_opt[:type] = send_type.to_s if send_type
148 send_data @content, send_opt
148 send_data @content, send_opt
149 else
149 else
150 # Prevent empty lines when displaying a file with Windows style eol
150 # Prevent empty lines when displaying a file with Windows style eol
151 # TODO: UTF-16
151 # TODO: UTF-16
152 # Is this needs? AttachmentsController reads file simply.
152 # Is this needs? AttachmentsController reads file simply.
153 @content.gsub!("\r\n", "\n")
153 @content.gsub!("\r\n", "\n")
154 @changeset = @repository.find_changeset_by_name(@rev)
154 @changeset = @repository.find_changeset_by_name(@rev)
155 end
155 end
156 end
156 end
157
157
158 def is_entry_text_data?(ent, path)
158 def is_entry_text_data?(ent, path)
159 # UTF-16 contains "\x00".
159 # UTF-16 contains "\x00".
160 # It is very strict that file contains less than 30% of ascii symbols
160 # It is very strict that file contains less than 30% of ascii symbols
161 # in non Western Europe.
161 # in non Western Europe.
162 return true if Redmine::MimeType.is_type?('text', path)
162 return true if Redmine::MimeType.is_type?('text', path)
163 # Ruby 1.8.6 has a bug of integer divisions.
163 # Ruby 1.8.6 has a bug of integer divisions.
164 # http://apidock.com/ruby/v1_8_6_287/String/is_binary_data%3F
164 # http://apidock.com/ruby/v1_8_6_287/String/is_binary_data%3F
165 return false if ent.is_binary_data?
165 return false if ent.is_binary_data?
166 true
166 true
167 end
167 end
168 private :is_entry_text_data?
168 private :is_entry_text_data?
169
169
170 def annotate
170 def annotate
171 @entry = @repository.entry(@path, @rev)
171 @entry = @repository.entry(@path, @rev)
172 (show_error_not_found; return) unless @entry
172 (show_error_not_found; return) unless @entry
173
173
174 @annotate = @repository.scm.annotate(@path, @rev)
174 @annotate = @repository.scm.annotate(@path, @rev)
175 (render_error l(:error_scm_annotate); return) if @annotate.nil? || @annotate.empty?
175 (render_error l(:error_scm_annotate); return) if @annotate.nil? || @annotate.empty?
176 @changeset = @repository.find_changeset_by_name(@rev)
176 @changeset = @repository.find_changeset_by_name(@rev)
177 end
177 end
178
178
179 def revision
179 def revision
180 raise ChangesetNotFound if @rev.blank?
180 raise ChangesetNotFound if @rev.blank?
181 @changeset = @repository.find_changeset_by_name(@rev)
181 @changeset = @repository.find_changeset_by_name(@rev)
182 raise ChangesetNotFound unless @changeset
182 raise ChangesetNotFound unless @changeset
183
183
184 respond_to do |format|
184 respond_to do |format|
185 format.html
185 format.html
186 format.js {render :layout => false}
186 format.js {render :layout => false}
187 end
187 end
188 rescue ChangesetNotFound
188 rescue ChangesetNotFound
189 show_error_not_found
189 show_error_not_found
190 end
190 end
191
191
192 def diff
192 def diff
193 if params[:format] == 'diff'
193 if params[:format] == 'diff'
194 @diff = @repository.diff(@path, @rev, @rev_to)
194 @diff = @repository.diff(@path, @rev, @rev_to)
195 (show_error_not_found; return) unless @diff
195 (show_error_not_found; return) unless @diff
196 filename = "changeset_r#{@rev}"
196 filename = "changeset_r#{@rev}"
197 filename << "_r#{@rev_to}" if @rev_to
197 filename << "_r#{@rev_to}" if @rev_to
198 send_data @diff.join, :filename => "#{filename}.diff",
198 send_data @diff.join, :filename => "#{filename}.diff",
199 :type => 'text/x-patch',
199 :type => 'text/x-patch',
200 :disposition => 'attachment'
200 :disposition => 'attachment'
201 else
201 else
202 @diff_type = params[:type] || User.current.pref[:diff_type] || 'inline'
202 @diff_type = params[:type] || User.current.pref[:diff_type] || 'inline'
203 @diff_type = 'inline' unless %w(inline sbs).include?(@diff_type)
203 @diff_type = 'inline' unless %w(inline sbs).include?(@diff_type)
204
204
205 # Save diff type as user preference
205 # Save diff type as user preference
206 if User.current.logged? && @diff_type != User.current.pref[:diff_type]
206 if User.current.logged? && @diff_type != User.current.pref[:diff_type]
207 User.current.pref[:diff_type] = @diff_type
207 User.current.pref[:diff_type] = @diff_type
208 User.current.preference.save
208 User.current.preference.save
209 end
209 end
210 @cache_key = "repositories/diff/#{@repository.id}/" +
210 @cache_key = "repositories/diff/#{@repository.id}/" +
211 Digest::MD5.hexdigest("#{@path}-#{@rev}-#{@rev_to}-#{@diff_type}")
211 Digest::MD5.hexdigest("#{@path}-#{@rev}-#{@rev_to}-#{@diff_type}-#{current_language}")
212 unless read_fragment(@cache_key)
212 unless read_fragment(@cache_key)
213 @diff = @repository.diff(@path, @rev, @rev_to)
213 @diff = @repository.diff(@path, @rev, @rev_to)
214 show_error_not_found unless @diff
214 show_error_not_found unless @diff
215 end
215 end
216
216
217 @changeset = @repository.find_changeset_by_name(@rev)
217 @changeset = @repository.find_changeset_by_name(@rev)
218 @changeset_to = @rev_to ? @repository.find_changeset_by_name(@rev_to) : nil
218 @changeset_to = @rev_to ? @repository.find_changeset_by_name(@rev_to) : nil
219 @diff_format_revisions = @repository.diff_format_revisions(@changeset, @changeset_to)
219 @diff_format_revisions = @repository.diff_format_revisions(@changeset, @changeset_to)
220 end
220 end
221 end
221 end
222
222
223 def stats
223 def stats
224 end
224 end
225
225
226 def graph
226 def graph
227 data = nil
227 data = nil
228 case params[:graph]
228 case params[:graph]
229 when "commits_per_month"
229 when "commits_per_month"
230 data = graph_commits_per_month(@repository)
230 data = graph_commits_per_month(@repository)
231 when "commits_per_author"
231 when "commits_per_author"
232 data = graph_commits_per_author(@repository)
232 data = graph_commits_per_author(@repository)
233 end
233 end
234 if data
234 if data
235 headers["Content-Type"] = "image/svg+xml"
235 headers["Content-Type"] = "image/svg+xml"
236 send_data(data, :type => "image/svg+xml", :disposition => "inline")
236 send_data(data, :type => "image/svg+xml", :disposition => "inline")
237 else
237 else
238 render_404
238 render_404
239 end
239 end
240 end
240 end
241
241
242 private
242 private
243
243
244 REV_PARAM_RE = %r{\A[a-f0-9]*\Z}i
244 REV_PARAM_RE = %r{\A[a-f0-9]*\Z}i
245
245
246 def find_repository
246 def find_repository
247 @project = Project.find(params[:id])
247 @project = Project.find(params[:id])
248 @repository = @project.repository
248 @repository = @project.repository
249 (render_404; return false) unless @repository
249 (render_404; return false) unless @repository
250 @path = params[:path].join('/') unless params[:path].nil?
250 @path = params[:path].join('/') unless params[:path].nil?
251 @path ||= ''
251 @path ||= ''
252 @rev = params[:rev].blank? ? @repository.default_branch : params[:rev].strip
252 @rev = params[:rev].blank? ? @repository.default_branch : params[:rev].strip
253 @rev_to = params[:rev_to]
253 @rev_to = params[:rev_to]
254
254
255 unless @rev.to_s.match(REV_PARAM_RE) && @rev_to.to_s.match(REV_PARAM_RE)
255 unless @rev.to_s.match(REV_PARAM_RE) && @rev_to.to_s.match(REV_PARAM_RE)
256 if @repository.branches.blank?
256 if @repository.branches.blank?
257 raise InvalidRevisionParam
257 raise InvalidRevisionParam
258 end
258 end
259 end
259 end
260 rescue ActiveRecord::RecordNotFound
260 rescue ActiveRecord::RecordNotFound
261 render_404
261 render_404
262 rescue InvalidRevisionParam
262 rescue InvalidRevisionParam
263 show_error_not_found
263 show_error_not_found
264 end
264 end
265
265
266 def show_error_not_found
266 def show_error_not_found
267 render_error :message => l(:error_scm_not_found), :status => 404
267 render_error :message => l(:error_scm_not_found), :status => 404
268 end
268 end
269
269
270 # Handler for Redmine::Scm::Adapters::CommandFailed exception
270 # Handler for Redmine::Scm::Adapters::CommandFailed exception
271 def show_error_command_failed(exception)
271 def show_error_command_failed(exception)
272 render_error l(:error_scm_command_failed, exception.message)
272 render_error l(:error_scm_command_failed, exception.message)
273 end
273 end
274
274
275 def graph_commits_per_month(repository)
275 def graph_commits_per_month(repository)
276 @date_to = Date.today
276 @date_to = Date.today
277 @date_from = @date_to << 11
277 @date_from = @date_to << 11
278 @date_from = Date.civil(@date_from.year, @date_from.month, 1)
278 @date_from = Date.civil(@date_from.year, @date_from.month, 1)
279 commits_by_day = repository.changesets.count(
279 commits_by_day = repository.changesets.count(
280 :all, :group => :commit_date,
280 :all, :group => :commit_date,
281 :conditions => ["commit_date BETWEEN ? AND ?", @date_from, @date_to])
281 :conditions => ["commit_date BETWEEN ? AND ?", @date_from, @date_to])
282 commits_by_month = [0] * 12
282 commits_by_month = [0] * 12
283 commits_by_day.each {|c| commits_by_month[c.first.to_date.months_ago] += c.last }
283 commits_by_day.each {|c| commits_by_month[c.first.to_date.months_ago] += c.last }
284
284
285 changes_by_day = repository.changes.count(
285 changes_by_day = repository.changes.count(
286 :all, :group => :commit_date,
286 :all, :group => :commit_date,
287 :conditions => ["commit_date BETWEEN ? AND ?", @date_from, @date_to])
287 :conditions => ["commit_date BETWEEN ? AND ?", @date_from, @date_to])
288 changes_by_month = [0] * 12
288 changes_by_month = [0] * 12
289 changes_by_day.each {|c| changes_by_month[c.first.to_date.months_ago] += c.last }
289 changes_by_day.each {|c| changes_by_month[c.first.to_date.months_ago] += c.last }
290
290
291 fields = []
291 fields = []
292 12.times {|m| fields << month_name(((Date.today.month - 1 - m) % 12) + 1)}
292 12.times {|m| fields << month_name(((Date.today.month - 1 - m) % 12) + 1)}
293
293
294 graph = SVG::Graph::Bar.new(
294 graph = SVG::Graph::Bar.new(
295 :height => 300,
295 :height => 300,
296 :width => 800,
296 :width => 800,
297 :fields => fields.reverse,
297 :fields => fields.reverse,
298 :stack => :side,
298 :stack => :side,
299 :scale_integers => true,
299 :scale_integers => true,
300 :step_x_labels => 2,
300 :step_x_labels => 2,
301 :show_data_values => false,
301 :show_data_values => false,
302 :graph_title => l(:label_commits_per_month),
302 :graph_title => l(:label_commits_per_month),
303 :show_graph_title => true
303 :show_graph_title => true
304 )
304 )
305
305
306 graph.add_data(
306 graph.add_data(
307 :data => commits_by_month[0..11].reverse,
307 :data => commits_by_month[0..11].reverse,
308 :title => l(:label_revision_plural)
308 :title => l(:label_revision_plural)
309 )
309 )
310
310
311 graph.add_data(
311 graph.add_data(
312 :data => changes_by_month[0..11].reverse,
312 :data => changes_by_month[0..11].reverse,
313 :title => l(:label_change_plural)
313 :title => l(:label_change_plural)
314 )
314 )
315
315
316 graph.burn
316 graph.burn
317 end
317 end
318
318
319 def graph_commits_per_author(repository)
319 def graph_commits_per_author(repository)
320 commits_by_author = repository.changesets.count(:all, :group => :committer)
320 commits_by_author = repository.changesets.count(:all, :group => :committer)
321 commits_by_author.to_a.sort! {|x, y| x.last <=> y.last}
321 commits_by_author.to_a.sort! {|x, y| x.last <=> y.last}
322
322
323 changes_by_author = repository.changes.count(:all, :group => :committer)
323 changes_by_author = repository.changes.count(:all, :group => :committer)
324 h = changes_by_author.inject({}) {|o, i| o[i.first] = i.last; o}
324 h = changes_by_author.inject({}) {|o, i| o[i.first] = i.last; o}
325
325
326 fields = commits_by_author.collect {|r| r.first}
326 fields = commits_by_author.collect {|r| r.first}
327 commits_data = commits_by_author.collect {|r| r.last}
327 commits_data = commits_by_author.collect {|r| r.last}
328 changes_data = commits_by_author.collect {|r| h[r.first] || 0}
328 changes_data = commits_by_author.collect {|r| h[r.first] || 0}
329
329
330 fields = fields + [""]*(10 - fields.length) if fields.length<10
330 fields = fields + [""]*(10 - fields.length) if fields.length<10
331 commits_data = commits_data + [0]*(10 - commits_data.length) if commits_data.length<10
331 commits_data = commits_data + [0]*(10 - commits_data.length) if commits_data.length<10
332 changes_data = changes_data + [0]*(10 - changes_data.length) if changes_data.length<10
332 changes_data = changes_data + [0]*(10 - changes_data.length) if changes_data.length<10
333
333
334 # Remove email adress in usernames
334 # Remove email adress in usernames
335 fields = fields.collect {|c| c.gsub(%r{<.+@.+>}, '') }
335 fields = fields.collect {|c| c.gsub(%r{<.+@.+>}, '') }
336
336
337 graph = SVG::Graph::BarHorizontal.new(
337 graph = SVG::Graph::BarHorizontal.new(
338 :height => 400,
338 :height => 400,
339 :width => 800,
339 :width => 800,
340 :fields => fields,
340 :fields => fields,
341 :stack => :side,
341 :stack => :side,
342 :scale_integers => true,
342 :scale_integers => true,
343 :show_data_values => false,
343 :show_data_values => false,
344 :rotate_y_labels => false,
344 :rotate_y_labels => false,
345 :graph_title => l(:label_commits_per_author),
345 :graph_title => l(:label_commits_per_author),
346 :show_graph_title => true
346 :show_graph_title => true
347 )
347 )
348 graph.add_data(
348 graph.add_data(
349 :data => commits_data,
349 :data => commits_data,
350 :title => l(:label_revision_plural)
350 :title => l(:label_revision_plural)
351 )
351 )
352 graph.add_data(
352 graph.add_data(
353 :data => changes_data,
353 :data => changes_data,
354 :title => l(:label_change_plural)
354 :title => l(:label_change_plural)
355 )
355 )
356 graph.burn
356 graph.burn
357 end
357 end
358 end
358 end
359
359
360 class Date
360 class Date
361 def months_ago(date = Date.today)
361 def months_ago(date = Date.today)
362 (date.year - self.year)*12 + (date.month - self.month)
362 (date.year - self.year)*12 + (date.month - self.month)
363 end
363 end
364
364
365 def weeks_ago(date = Date.today)
365 def weeks_ago(date = Date.today)
366 (date.year - self.year)*52 + (date.cweek - self.cweek)
366 (date.year - self.year)*52 + (date.cweek - self.cweek)
367 end
367 end
368 end
368 end
369
369
370 class String
370 class String
371 def with_leading_slash
371 def with_leading_slash
372 starts_with?('/') ? self : "/#{self}"
372 starts_with?('/') ? self : "/#{self}"
373 end
373 end
374 end
374 end
@@ -1,364 +1,395
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19 require 'repositories_controller'
19 require 'repositories_controller'
20
20
21 # Re-raise errors caught by the controller.
21 # Re-raise errors caught by the controller.
22 class RepositoriesController; def rescue_action(e) raise e end; end
22 class RepositoriesController; def rescue_action(e) raise e end; end
23
23
24 class RepositoriesGitControllerTest < ActionController::TestCase
24 class RepositoriesGitControllerTest < ActionController::TestCase
25 fixtures :projects, :users, :roles, :members, :member_roles,
25 fixtures :projects, :users, :roles, :members, :member_roles,
26 :repositories, :enabled_modules
26 :repositories, :enabled_modules
27
27
28 REPOSITORY_PATH = Rails.root.join('tmp/test/git_repository').to_s
28 REPOSITORY_PATH = Rails.root.join('tmp/test/git_repository').to_s
29 REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin?
29 REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin?
30 PRJ_ID = 3
30 PRJ_ID = 3
31 CHAR_1_HEX = "\xc3\x9c"
31 CHAR_1_HEX = "\xc3\x9c"
32
32
33 ## Git, Mercurial and CVS path encodings are binary.
33 ## Git, Mercurial and CVS path encodings are binary.
34 ## Subversion supports URL encoding for path.
34 ## Subversion supports URL encoding for path.
35 ## Redmine Mercurial adapter and extension use URL encoding.
35 ## Redmine Mercurial adapter and extension use URL encoding.
36 ## Git accepts only binary path in command line parameter.
36 ## Git accepts only binary path in command line parameter.
37 ## So, there is no way to use binary command line parameter in JRuby.
37 ## So, there is no way to use binary command line parameter in JRuby.
38 JRUBY_SKIP = (RUBY_PLATFORM == 'java')
38 JRUBY_SKIP = (RUBY_PLATFORM == 'java')
39 JRUBY_SKIP_STR = "TODO: This test fails in JRuby"
39 JRUBY_SKIP_STR = "TODO: This test fails in JRuby"
40
40
41 def setup
41 def setup
42 @ruby19_non_utf8_pass =
42 @ruby19_non_utf8_pass =
43 (RUBY_VERSION >= '1.9' && Encoding.default_external.to_s != 'UTF-8')
43 (RUBY_VERSION >= '1.9' && Encoding.default_external.to_s != 'UTF-8')
44
44
45 @controller = RepositoriesController.new
45 @controller = RepositoriesController.new
46 @request = ActionController::TestRequest.new
46 @request = ActionController::TestRequest.new
47 @response = ActionController::TestResponse.new
47 @response = ActionController::TestResponse.new
48 User.current = nil
48 User.current = nil
49 @repository = Repository::Git.create(
49 @repository = Repository::Git.create(
50 :project => Project.find(3),
50 :project => Project.find(3),
51 :url => REPOSITORY_PATH,
51 :url => REPOSITORY_PATH,
52 :path_encoding => 'ISO-8859-1'
52 :path_encoding => 'ISO-8859-1'
53 )
53 )
54 assert @repository
54 assert @repository
55 @char_1 = CHAR_1_HEX.dup
55 @char_1 = CHAR_1_HEX.dup
56 if @char_1.respond_to?(:force_encoding)
56 if @char_1.respond_to?(:force_encoding)
57 @char_1.force_encoding('UTF-8')
57 @char_1.force_encoding('UTF-8')
58 end
58 end
59
60 Setting.default_language = 'en'
59 end
61 end
60
62
61 if File.directory?(REPOSITORY_PATH)
63 if File.directory?(REPOSITORY_PATH)
62 def test_browse_root
64 def test_browse_root
63 @repository.fetch_changesets
65 @repository.fetch_changesets
64 @repository.reload
66 @repository.reload
65 get :show, :id => PRJ_ID
67 get :show, :id => PRJ_ID
66 assert_response :success
68 assert_response :success
67 assert_template 'show'
69 assert_template 'show'
68 assert_not_nil assigns(:entries)
70 assert_not_nil assigns(:entries)
69 assert_equal 9, assigns(:entries).size
71 assert_equal 9, assigns(:entries).size
70 assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'}
72 assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'}
71 assert assigns(:entries).detect {|e| e.name == 'this_is_a_really_long_and_verbose_directory_name' && e.kind == 'dir'}
73 assert assigns(:entries).detect {|e| e.name == 'this_is_a_really_long_and_verbose_directory_name' && e.kind == 'dir'}
72 assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'}
74 assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'}
73 assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'}
75 assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'}
74 assert assigns(:entries).detect {|e| e.name == 'copied_README' && e.kind == 'file'}
76 assert assigns(:entries).detect {|e| e.name == 'copied_README' && e.kind == 'file'}
75 assert assigns(:entries).detect {|e| e.name == 'new_file.txt' && e.kind == 'file'}
77 assert assigns(:entries).detect {|e| e.name == 'new_file.txt' && e.kind == 'file'}
76 assert assigns(:entries).detect {|e| e.name == 'renamed_test.txt' && e.kind == 'file'}
78 assert assigns(:entries).detect {|e| e.name == 'renamed_test.txt' && e.kind == 'file'}
77 assert assigns(:entries).detect {|e| e.name == 'filemane with spaces.txt' && e.kind == 'file'}
79 assert assigns(:entries).detect {|e| e.name == 'filemane with spaces.txt' && e.kind == 'file'}
78 assert assigns(:entries).detect {|e| e.name == ' filename with a leading space.txt ' && e.kind == 'file'}
80 assert assigns(:entries).detect {|e| e.name == ' filename with a leading space.txt ' && e.kind == 'file'}
79 assert_not_nil assigns(:changesets)
81 assert_not_nil assigns(:changesets)
80 assigns(:changesets).size > 0
82 assigns(:changesets).size > 0
81 end
83 end
82
84
83 def test_browse_branch
85 def test_browse_branch
84 @repository.fetch_changesets
86 @repository.fetch_changesets
85 @repository.reload
87 @repository.reload
86 get :show, :id => PRJ_ID, :rev => 'test_branch'
88 get :show, :id => PRJ_ID, :rev => 'test_branch'
87 assert_response :success
89 assert_response :success
88 assert_template 'show'
90 assert_template 'show'
89 assert_not_nil assigns(:entries)
91 assert_not_nil assigns(:entries)
90 assert_equal 4, assigns(:entries).size
92 assert_equal 4, assigns(:entries).size
91 assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'}
93 assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'}
92 assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'}
94 assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'}
93 assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'}
95 assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'}
94 assert assigns(:entries).detect {|e| e.name == 'test.txt' && e.kind == 'file'}
96 assert assigns(:entries).detect {|e| e.name == 'test.txt' && e.kind == 'file'}
95 assert_not_nil assigns(:changesets)
97 assert_not_nil assigns(:changesets)
96 assigns(:changesets).size > 0
98 assigns(:changesets).size > 0
97 end
99 end
98
100
99 def test_browse_tag
101 def test_browse_tag
100 @repository.fetch_changesets
102 @repository.fetch_changesets
101 @repository.reload
103 @repository.reload
102 [
104 [
103 "tag00.lightweight",
105 "tag00.lightweight",
104 "tag01.annotated",
106 "tag01.annotated",
105 ].each do |t1|
107 ].each do |t1|
106 get :show, :id => PRJ_ID, :rev => t1
108 get :show, :id => PRJ_ID, :rev => t1
107 assert_response :success
109 assert_response :success
108 assert_template 'show'
110 assert_template 'show'
109 assert_not_nil assigns(:entries)
111 assert_not_nil assigns(:entries)
110 assigns(:entries).size > 0
112 assigns(:entries).size > 0
111 assert_not_nil assigns(:changesets)
113 assert_not_nil assigns(:changesets)
112 assigns(:changesets).size > 0
114 assigns(:changesets).size > 0
113 end
115 end
114 end
116 end
115
117
116 def test_browse_directory
118 def test_browse_directory
117 @repository.fetch_changesets
119 @repository.fetch_changesets
118 @repository.reload
120 @repository.reload
119 get :show, :id => PRJ_ID, :path => ['images']
121 get :show, :id => PRJ_ID, :path => ['images']
120 assert_response :success
122 assert_response :success
121 assert_template 'show'
123 assert_template 'show'
122 assert_not_nil assigns(:entries)
124 assert_not_nil assigns(:entries)
123 assert_equal ['edit.png'], assigns(:entries).collect(&:name)
125 assert_equal ['edit.png'], assigns(:entries).collect(&:name)
124 entry = assigns(:entries).detect {|e| e.name == 'edit.png'}
126 entry = assigns(:entries).detect {|e| e.name == 'edit.png'}
125 assert_not_nil entry
127 assert_not_nil entry
126 assert_equal 'file', entry.kind
128 assert_equal 'file', entry.kind
127 assert_equal 'images/edit.png', entry.path
129 assert_equal 'images/edit.png', entry.path
128 assert_not_nil assigns(:changesets)
130 assert_not_nil assigns(:changesets)
129 assigns(:changesets).size > 0
131 assigns(:changesets).size > 0
130 end
132 end
131
133
132 def test_browse_at_given_revision
134 def test_browse_at_given_revision
133 @repository.fetch_changesets
135 @repository.fetch_changesets
134 @repository.reload
136 @repository.reload
135 get :show, :id => PRJ_ID, :path => ['images'],
137 get :show, :id => PRJ_ID, :path => ['images'],
136 :rev => '7234cb2750b63f47bff735edc50a1c0a433c2518'
138 :rev => '7234cb2750b63f47bff735edc50a1c0a433c2518'
137 assert_response :success
139 assert_response :success
138 assert_template 'show'
140 assert_template 'show'
139 assert_not_nil assigns(:entries)
141 assert_not_nil assigns(:entries)
140 assert_equal ['delete.png'], assigns(:entries).collect(&:name)
142 assert_equal ['delete.png'], assigns(:entries).collect(&:name)
141 assert_not_nil assigns(:changesets)
143 assert_not_nil assigns(:changesets)
142 assigns(:changesets).size > 0
144 assigns(:changesets).size > 0
143 end
145 end
144
146
145 def test_changes
147 def test_changes
146 get :changes, :id => PRJ_ID, :path => ['images', 'edit.png']
148 get :changes, :id => PRJ_ID, :path => ['images', 'edit.png']
147 assert_response :success
149 assert_response :success
148 assert_template 'changes'
150 assert_template 'changes'
149 assert_tag :tag => 'h2', :content => 'edit.png'
151 assert_tag :tag => 'h2', :content => 'edit.png'
150 end
152 end
151
153
152 def test_entry_show
154 def test_entry_show
153 get :entry, :id => PRJ_ID, :path => ['sources', 'watchers_controller.rb']
155 get :entry, :id => PRJ_ID, :path => ['sources', 'watchers_controller.rb']
154 assert_response :success
156 assert_response :success
155 assert_template 'entry'
157 assert_template 'entry'
156 # Line 19
158 # Line 19
157 assert_tag :tag => 'th',
159 assert_tag :tag => 'th',
158 :content => '11',
160 :content => '11',
159 :attributes => { :class => 'line-num' },
161 :attributes => { :class => 'line-num' },
160 :sibling => { :tag => 'td', :content => /WITHOUT ANY WARRANTY/ }
162 :sibling => { :tag => 'td', :content => /WITHOUT ANY WARRANTY/ }
161 end
163 end
162
164
163 def test_entry_show_latin_1
165 def test_entry_show_latin_1
164 if @ruby19_non_utf8_pass
166 if @ruby19_non_utf8_pass
165 puts_ruby19_non_utf8_pass()
167 puts_ruby19_non_utf8_pass()
166 elsif JRUBY_SKIP
168 elsif JRUBY_SKIP
167 puts JRUBY_SKIP_STR
169 puts JRUBY_SKIP_STR
168 else
170 else
169 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
171 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
170 ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1|
172 ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1|
171 get :entry, :id => PRJ_ID,
173 get :entry, :id => PRJ_ID,
172 :path => ['latin-1-dir', "test-#{@char_1}.txt"], :rev => r1
174 :path => ['latin-1-dir', "test-#{@char_1}.txt"], :rev => r1
173 assert_response :success
175 assert_response :success
174 assert_template 'entry'
176 assert_template 'entry'
175 assert_tag :tag => 'th',
177 assert_tag :tag => 'th',
176 :content => '1',
178 :content => '1',
177 :attributes => { :class => 'line-num' },
179 :attributes => { :class => 'line-num' },
178 :sibling => { :tag => 'td',
180 :sibling => { :tag => 'td',
179 :content => /test-#{@char_1}.txt/ }
181 :content => /test-#{@char_1}.txt/ }
180 end
182 end
181 end
183 end
182 end
184 end
183 end
185 end
184
186
185 def test_entry_download
187 def test_entry_download
186 get :entry, :id => PRJ_ID, :path => ['sources', 'watchers_controller.rb'],
188 get :entry, :id => PRJ_ID, :path => ['sources', 'watchers_controller.rb'],
187 :format => 'raw'
189 :format => 'raw'
188 assert_response :success
190 assert_response :success
189 # File content
191 # File content
190 assert @response.body.include?('WITHOUT ANY WARRANTY')
192 assert @response.body.include?('WITHOUT ANY WARRANTY')
191 end
193 end
192
194
193 def test_directory_entry
195 def test_directory_entry
194 get :entry, :id => PRJ_ID, :path => ['sources']
196 get :entry, :id => PRJ_ID, :path => ['sources']
195 assert_response :success
197 assert_response :success
196 assert_template 'show'
198 assert_template 'show'
197 assert_not_nil assigns(:entry)
199 assert_not_nil assigns(:entry)
198 assert_equal 'sources', assigns(:entry).name
200 assert_equal 'sources', assigns(:entry).name
199 end
201 end
200
202
201 def test_diff
203 def test_diff
202 @repository.fetch_changesets
204 @repository.fetch_changesets
203 @repository.reload
205 @repository.reload
204 # Full diff of changeset 2f9c0091
206 # Full diff of changeset 2f9c0091
205 ['inline', 'sbs'].each do |dt|
207 ['inline', 'sbs'].each do |dt|
206 get :diff,
208 get :diff,
207 :id => PRJ_ID,
209 :id => PRJ_ID,
208 :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7',
210 :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7',
209 :type => dt
211 :type => dt
210 assert_response :success
212 assert_response :success
211 assert_template 'diff'
213 assert_template 'diff'
212 # Line 22 removed
214 # Line 22 removed
213 assert_tag :tag => 'th',
215 assert_tag :tag => 'th',
214 :content => /22/,
216 :content => /22/,
215 :sibling => { :tag => 'td',
217 :sibling => { :tag => 'td',
216 :attributes => { :class => /diff_out/ },
218 :attributes => { :class => /diff_out/ },
217 :content => /def remove/ }
219 :content => /def remove/ }
218 assert_tag :tag => 'h2', :content => /2f9c0091/
220 assert_tag :tag => 'h2', :content => /2f9c0091/
219 end
221 end
220 end
222 end
221
223
224 def test_diff_truncated
225 @repository.fetch_changesets
226 @repository.reload
227 Setting.diff_max_lines_displayed = 5
228
229 # Truncated diff of changeset 2f9c0091
230 with_cache do
231 get :diff, :id => PRJ_ID, :type => 'inline',
232 :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
233 assert_response :success
234 assert @response.body.include?("... This diff was truncated")
235
236 Setting.default_language = 'fr'
237 get :diff, :id => PRJ_ID, :type => 'inline',
238 :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
239 assert_response :success
240 assert ! @response.body.include?("... This diff was truncated")
241 assert @response.body.include?("... Ce diff")
242 end
243 end
244
222 def test_diff_two_revs
245 def test_diff_two_revs
223 @repository.fetch_changesets
246 @repository.fetch_changesets
224 @repository.reload
247 @repository.reload
225 ['inline', 'sbs'].each do |dt|
248 ['inline', 'sbs'].each do |dt|
226 get :diff,
249 get :diff,
227 :id => PRJ_ID,
250 :id => PRJ_ID,
228 :rev => '61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
251 :rev => '61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
229 :rev_to => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7',
252 :rev_to => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7',
230 :type => dt
253 :type => dt
231 assert_response :success
254 assert_response :success
232 assert_template 'diff'
255 assert_template 'diff'
233 diff = assigns(:diff)
256 diff = assigns(:diff)
234 assert_not_nil diff
257 assert_not_nil diff
235 assert_tag :tag => 'h2', :content => /2f9c0091:61b685fb/
258 assert_tag :tag => 'h2', :content => /2f9c0091:61b685fb/
236 end
259 end
237 end
260 end
238
261
239 def test_diff_latin_1
262 def test_diff_latin_1
240 if @ruby19_non_utf8_pass
263 if @ruby19_non_utf8_pass
241 puts_ruby19_non_utf8_pass()
264 puts_ruby19_non_utf8_pass()
242 else
265 else
243 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
266 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
244 ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1|
267 ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1|
245 ['inline', 'sbs'].each do |dt|
268 ['inline', 'sbs'].each do |dt|
246 get :diff, :id => PRJ_ID, :rev => r1, :type => dt
269 get :diff, :id => PRJ_ID, :rev => r1, :type => dt
247 assert_response :success
270 assert_response :success
248 assert_template 'diff'
271 assert_template 'diff'
249 assert_tag :tag => 'thead',
272 assert_tag :tag => 'thead',
250 :descendant => {
273 :descendant => {
251 :tag => 'th',
274 :tag => 'th',
252 :attributes => { :class => 'filename' } ,
275 :attributes => { :class => 'filename' } ,
253 :content => /latin-1-dir\/test-#{@char_1}.txt/ ,
276 :content => /latin-1-dir\/test-#{@char_1}.txt/ ,
254 },
277 },
255 :sibling => {
278 :sibling => {
256 :tag => 'tbody',
279 :tag => 'tbody',
257 :descendant => {
280 :descendant => {
258 :tag => 'td',
281 :tag => 'td',
259 :attributes => { :class => /diff_in/ },
282 :attributes => { :class => /diff_in/ },
260 :content => /test-#{@char_1}.txt/
283 :content => /test-#{@char_1}.txt/
261 }
284 }
262 }
285 }
263 end
286 end
264 end
287 end
265 end
288 end
266 end
289 end
267 end
290 end
268
291
269 def test_annotate
292 def test_annotate
270 get :annotate, :id => PRJ_ID, :path => ['sources', 'watchers_controller.rb']
293 get :annotate, :id => PRJ_ID, :path => ['sources', 'watchers_controller.rb']
271 assert_response :success
294 assert_response :success
272 assert_template 'annotate'
295 assert_template 'annotate'
273 # Line 24, changeset 2f9c0091
296 # Line 24, changeset 2f9c0091
274 assert_tag :tag => 'th', :content => '24',
297 assert_tag :tag => 'th', :content => '24',
275 :sibling => {
298 :sibling => {
276 :tag => 'td',
299 :tag => 'td',
277 :child => {
300 :child => {
278 :tag => 'a',
301 :tag => 'a',
279 :content => /2f9c0091/
302 :content => /2f9c0091/
280 }
303 }
281 }
304 }
282 assert_tag :tag => 'th', :content => '24',
305 assert_tag :tag => 'th', :content => '24',
283 :sibling => { :tag => 'td', :content => /jsmith/ }
306 :sibling => { :tag => 'td', :content => /jsmith/ }
284 assert_tag :tag => 'th', :content => '24',
307 assert_tag :tag => 'th', :content => '24',
285 :sibling => {
308 :sibling => {
286 :tag => 'td',
309 :tag => 'td',
287 :child => {
310 :child => {
288 :tag => 'a',
311 :tag => 'a',
289 :content => /2f9c0091/
312 :content => /2f9c0091/
290 }
313 }
291 }
314 }
292 assert_tag :tag => 'th', :content => '24',
315 assert_tag :tag => 'th', :content => '24',
293 :sibling => { :tag => 'td', :content => /watcher =/ }
316 :sibling => { :tag => 'td', :content => /watcher =/ }
294 end
317 end
295
318
296 def test_annotate_at_given_revision
319 def test_annotate_at_given_revision
297 @repository.fetch_changesets
320 @repository.fetch_changesets
298 @repository.reload
321 @repository.reload
299 get :annotate, :id => PRJ_ID, :rev => 'deff7',
322 get :annotate, :id => PRJ_ID, :rev => 'deff7',
300 :path => ['sources', 'watchers_controller.rb']
323 :path => ['sources', 'watchers_controller.rb']
301 assert_response :success
324 assert_response :success
302 assert_template 'annotate'
325 assert_template 'annotate'
303 assert_tag :tag => 'h2', :content => /@ deff712f/
326 assert_tag :tag => 'h2', :content => /@ deff712f/
304 end
327 end
305
328
306 def test_annotate_binary_file
329 def test_annotate_binary_file
307 get :annotate, :id => PRJ_ID, :path => ['images', 'edit.png']
330 get :annotate, :id => PRJ_ID, :path => ['images', 'edit.png']
308 assert_response 500
331 assert_response 500
309 assert_tag :tag => 'p', :attributes => { :id => /errorExplanation/ },
332 assert_tag :tag => 'p', :attributes => { :id => /errorExplanation/ },
310 :content => /cannot be annotated/
333 :content => /cannot be annotated/
311 end
334 end
312
335
313 def test_annotate_latin_1
336 def test_annotate_latin_1
314 if @ruby19_non_utf8_pass
337 if @ruby19_non_utf8_pass
315 puts_ruby19_non_utf8_pass()
338 puts_ruby19_non_utf8_pass()
316 elsif JRUBY_SKIP
339 elsif JRUBY_SKIP
317 puts JRUBY_SKIP_STR
340 puts JRUBY_SKIP_STR
318 else
341 else
319 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
342 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
320 ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1|
343 ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1|
321 get :annotate, :id => PRJ_ID,
344 get :annotate, :id => PRJ_ID,
322 :path => ['latin-1-dir', "test-#{@char_1}.txt"], :rev => r1
345 :path => ['latin-1-dir', "test-#{@char_1}.txt"], :rev => r1
323 assert_tag :tag => 'th',
346 assert_tag :tag => 'th',
324 :content => '1',
347 :content => '1',
325 :attributes => { :class => 'line-num' },
348 :attributes => { :class => 'line-num' },
326 :sibling => { :tag => 'td',
349 :sibling => { :tag => 'td',
327 :content => /test-#{@char_1}.txt/ }
350 :content => /test-#{@char_1}.txt/ }
328 end
351 end
329 end
352 end
330 end
353 end
331 end
354 end
332
355
333 def test_revision
356 def test_revision
334 @repository.fetch_changesets
357 @repository.fetch_changesets
335 @repository.reload
358 @repository.reload
336 ['61b685fbe55ab05b5ac68402d5720c1a6ac973d1', '61b685f'].each do |r|
359 ['61b685fbe55ab05b5ac68402d5720c1a6ac973d1', '61b685f'].each do |r|
337 get :revision, :id => PRJ_ID, :rev => r
360 get :revision, :id => PRJ_ID, :rev => r
338 assert_response :success
361 assert_response :success
339 assert_template 'revision'
362 assert_template 'revision'
340 end
363 end
341 end
364 end
342
365
343 def test_empty_revision
366 def test_empty_revision
344 @repository.fetch_changesets
367 @repository.fetch_changesets
345 @repository.reload
368 @repository.reload
346 ['', ' ', nil].each do |r|
369 ['', ' ', nil].each do |r|
347 get :revision, :id => PRJ_ID, :rev => r
370 get :revision, :id => PRJ_ID, :rev => r
348 assert_response 404
371 assert_response 404
349 assert_error_tag :content => /was not found/
372 assert_error_tag :content => /was not found/
350 end
373 end
351 end
374 end
352
375
353 private
376 private
354
377
355 def puts_ruby19_non_utf8_pass
378 def puts_ruby19_non_utf8_pass
356 puts "TODO: This test fails in Ruby 1.9 " +
379 puts "TODO: This test fails in Ruby 1.9 " +
357 "and Encoding.default_external is not UTF-8. " +
380 "and Encoding.default_external is not UTF-8. " +
358 "Current value is '#{Encoding.default_external.to_s}'"
381 "Current value is '#{Encoding.default_external.to_s}'"
359 end
382 end
360 else
383 else
361 puts "Git test repository NOT FOUND. Skipping functional tests !!!"
384 puts "Git test repository NOT FOUND. Skipping functional tests !!!"
362 def test_fake; assert true end
385 def test_fake; assert true end
363 end
386 end
387
388 private
389 def with_cache(&block)
390 before = ActionController::Base.perform_caching
391 ActionController::Base.perform_caching = true
392 block.call
393 ActionController::Base.perform_caching = before
394 end
364 end
395 end
General Comments 0
You need to be logged in to leave comments. Login now