##// END OF EJS Templates
Don't repeat revision on annotate view....
Jean-Philippe Lang -
r9922:65524cc1cc63
parent child
Show More
@@ -1,36 +1,36
1 1 <%= call_hook(:view_repositories_show_contextual, { :repository => @repository, :project => @project }) %>
2 2
3 3 <div class="contextual">
4 4 <%= render :partial => 'navigation' %>
5 5 </div>
6 6
7 7 <h2><%= render :partial => 'breadcrumbs', :locals => { :path => @path, :kind => 'file', :revision => @rev } %></h2>
8 8
9 9 <%= render :partial => 'link_to_functions' %>
10 10
11 11 <% colors = Hash.new {|k,v| k[v] = (k.size % 12) } %>
12 12
13 13 <div class="autoscroll">
14 14 <table class="filecontent annotate syntaxhl">
15 15 <tbody>
16 <% line_num = 1 %>
16 <% line_num = 1; previous_revision = nil %>
17 17 <% syntax_highlight_lines(@path, Redmine::CodesetUtil.to_utf8_by_setting(@annotate.content)).each do |line| %>
18 18 <% revision = @annotate.revisions[line_num - 1] %>
19 19 <tr class="bloc-<%= revision.nil? ? 0 : colors[revision.identifier || revision.revision] %>">
20 20 <th class="line-num" id="L<%= line_num %>"><a href="#L<%= line_num %>"><%= line_num %></a></th>
21 21 <td class="revision">
22 <%= (revision.identifier ? link_to_revision(revision, @repository) : format_revision(revision)) if revision %></td>
23 <td class="author"><%= h(revision.author.to_s.split('<').first) if revision %></td>
22 <%= (revision.identifier ? link_to_revision(revision, @repository) : format_revision(revision)) if revision && revision != previous_revision %></td>
23 <td class="author"><%= h(revision.author.to_s.split('<').first) if revision && revision != previous_revision %></td>
24 24 <td class="line-code"><pre><%= line.html_safe %></pre></td>
25 25 </tr>
26 <% line_num += 1 %>
26 <% line_num += 1; previous_revision = revision %>
27 27 <% end %>
28 28 </tbody>
29 29 </table>
30 30 </div>
31 31
32 32 <% html_title(l(:button_annotate)) -%>
33 33
34 34 <% content_for :header_tags do %>
35 35 <%= stylesheet_link_tag 'scm' %>
36 36 <% end %>
@@ -1,398 +1,410
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2012 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 'cgi'
19 19
20 20 module Redmine
21 21 module Scm
22 22 module Adapters
23 23 class CommandFailed < StandardError #:nodoc:
24 24 end
25 25
26 26 class AbstractAdapter #:nodoc:
27 27
28 28 # raised if scm command exited with error, e.g. unknown revision.
29 29 class ScmCommandAborted < CommandFailed; end
30 30
31 31 class << self
32 32 def client_command
33 33 ""
34 34 end
35 35
36 36 def shell_quote_command
37 37 if Redmine::Platform.mswin? && RUBY_PLATFORM == 'java'
38 38 client_command
39 39 else
40 40 shell_quote(client_command)
41 41 end
42 42 end
43 43
44 44 # Returns the version of the scm client
45 45 # Eg: [1, 5, 0] or [] if unknown
46 46 def client_version
47 47 []
48 48 end
49 49
50 50 # Returns the version string of the scm client
51 51 # Eg: '1.5.0' or 'Unknown version' if unknown
52 52 def client_version_string
53 53 v = client_version || 'Unknown version'
54 54 v.is_a?(Array) ? v.join('.') : v.to_s
55 55 end
56 56
57 57 # Returns true if the current client version is above
58 58 # or equals the given one
59 59 # If option is :unknown is set to true, it will return
60 60 # true if the client version is unknown
61 61 def client_version_above?(v, options={})
62 62 ((client_version <=> v) >= 0) || (client_version.empty? && options[:unknown])
63 63 end
64 64
65 65 def client_available
66 66 true
67 67 end
68 68
69 69 def shell_quote(str)
70 70 if Redmine::Platform.mswin?
71 71 '"' + str.gsub(/"/, '\\"') + '"'
72 72 else
73 73 "'" + str.gsub(/'/, "'\"'\"'") + "'"
74 74 end
75 75 end
76 76 end
77 77
78 78 def initialize(url, root_url=nil, login=nil, password=nil,
79 79 path_encoding=nil)
80 80 @url = url
81 81 @login = login if login && !login.empty?
82 82 @password = (password || "") if @login
83 83 @root_url = root_url.blank? ? retrieve_root_url : root_url
84 84 end
85 85
86 86 def adapter_name
87 87 'Abstract'
88 88 end
89 89
90 90 def supports_cat?
91 91 true
92 92 end
93 93
94 94 def supports_annotate?
95 95 respond_to?('annotate')
96 96 end
97 97
98 98 def root_url
99 99 @root_url
100 100 end
101 101
102 102 def url
103 103 @url
104 104 end
105 105
106 106 def path_encoding
107 107 nil
108 108 end
109 109
110 110 # get info about the svn repository
111 111 def info
112 112 return nil
113 113 end
114 114
115 115 # Returns the entry identified by path and revision identifier
116 116 # or nil if entry doesn't exist in the repository
117 117 def entry(path=nil, identifier=nil)
118 118 parts = path.to_s.split(%r{[\/\\]}).select {|n| !n.blank?}
119 119 search_path = parts[0..-2].join('/')
120 120 search_name = parts[-1]
121 121 if search_path.blank? && search_name.blank?
122 122 # Root entry
123 123 Entry.new(:path => '', :kind => 'dir')
124 124 else
125 125 # Search for the entry in the parent directory
126 126 es = entries(search_path, identifier)
127 127 es ? es.detect {|e| e.name == search_name} : nil
128 128 end
129 129 end
130 130
131 131 # Returns an Entries collection
132 132 # or nil if the given path doesn't exist in the repository
133 133 def entries(path=nil, identifier=nil, options={})
134 134 return nil
135 135 end
136 136
137 137 def branches
138 138 return nil
139 139 end
140 140
141 141 def tags
142 142 return nil
143 143 end
144 144
145 145 def default_branch
146 146 return nil
147 147 end
148 148
149 149 def properties(path, identifier=nil)
150 150 return nil
151 151 end
152 152
153 153 def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
154 154 return nil
155 155 end
156 156
157 157 def diff(path, identifier_from, identifier_to=nil)
158 158 return nil
159 159 end
160 160
161 161 def cat(path, identifier=nil)
162 162 return nil
163 163 end
164 164
165 165 def with_leading_slash(path)
166 166 path ||= ''
167 167 (path[0,1]!="/") ? "/#{path}" : path
168 168 end
169 169
170 170 def with_trailling_slash(path)
171 171 path ||= ''
172 172 (path[-1,1] == "/") ? path : "#{path}/"
173 173 end
174 174
175 175 def without_leading_slash(path)
176 176 path ||= ''
177 177 path.gsub(%r{^/+}, '')
178 178 end
179 179
180 180 def without_trailling_slash(path)
181 181 path ||= ''
182 182 (path[-1,1] == "/") ? path[0..-2] : path
183 183 end
184 184
185 185 def shell_quote(str)
186 186 self.class.shell_quote(str)
187 187 end
188 188
189 189 private
190 190 def retrieve_root_url
191 191 info = self.info
192 192 info ? info.root_url : nil
193 193 end
194 194
195 195 def target(path, sq=true)
196 196 path ||= ''
197 197 base = path.match(/^\//) ? root_url : url
198 198 str = "#{base}/#{path}".gsub(/[?<>\*]/, '')
199 199 if sq
200 200 str = shell_quote(str)
201 201 end
202 202 str
203 203 end
204 204
205 205 def logger
206 206 self.class.logger
207 207 end
208 208
209 209 def shellout(cmd, options = {}, &block)
210 210 self.class.shellout(cmd, options, &block)
211 211 end
212 212
213 213 def self.logger
214 214 Rails.logger
215 215 end
216 216
217 217 def self.shellout(cmd, options = {}, &block)
218 218 if logger && logger.debug?
219 219 logger.debug "Shelling out: #{strip_credential(cmd)}"
220 220 end
221 221 if Rails.env == 'development'
222 222 # Capture stderr when running in dev environment
223 223 cmd = "#{cmd} 2>>#{shell_quote(Rails.root.join('log/scm.stderr.log').to_s)}"
224 224 end
225 225 begin
226 226 mode = "r+"
227 227 IO.popen(cmd, mode) do |io|
228 228 io.set_encoding("ASCII-8BIT") if io.respond_to?(:set_encoding)
229 229 io.close_write unless options[:write_stdin]
230 230 block.call(io) if block_given?
231 231 end
232 232 ## If scm command does not exist,
233 233 ## Linux JRuby 1.6.2 (ruby-1.8.7-p330) raises java.io.IOException
234 234 ## in production environment.
235 235 # rescue Errno::ENOENT => e
236 236 rescue Exception => e
237 237 msg = strip_credential(e.message)
238 238 # The command failed, log it and re-raise
239 239 logmsg = "SCM command failed, "
240 240 logmsg += "make sure that your SCM command (e.g. svn) is "
241 241 logmsg += "in PATH (#{ENV['PATH']})\n"
242 242 logmsg += "You can configure your scm commands in config/configuration.yml.\n"
243 243 logmsg += "#{strip_credential(cmd)}\n"
244 244 logmsg += "with: #{msg}"
245 245 logger.error(logmsg)
246 246 raise CommandFailed.new(msg)
247 247 end
248 248 end
249 249
250 250 # Hides username/password in a given command
251 251 def self.strip_credential(cmd)
252 252 q = (Redmine::Platform.mswin? ? '"' : "'")
253 253 cmd.to_s.gsub(/(\-\-(password|username))\s+(#{q}[^#{q}]+#{q}|[^#{q}]\S+)/, '\\1 xxxx')
254 254 end
255 255
256 256 def strip_credential(cmd)
257 257 self.class.strip_credential(cmd)
258 258 end
259 259
260 260 def scm_iconv(to, from, str)
261 261 return nil if str.nil?
262 262 return str if to == from
263 263 begin
264 264 Iconv.conv(to, from, str)
265 265 rescue Iconv::Failure => err
266 266 logger.error("failed to convert from #{from} to #{to}. #{err}")
267 267 nil
268 268 end
269 269 end
270 270
271 271 def parse_xml(xml)
272 272 if RUBY_PLATFORM == 'java'
273 273 xml = xml.sub(%r{<\?xml[^>]*\?>}, '')
274 274 end
275 275 ActiveSupport::XmlMini.parse(xml)
276 276 end
277 277 end
278 278
279 279 class Entries < Array
280 280 def sort_by_name
281 281 dup.sort! {|x,y|
282 282 if x.kind == y.kind
283 283 x.name.to_s <=> y.name.to_s
284 284 else
285 285 x.kind <=> y.kind
286 286 end
287 287 }
288 288 end
289 289
290 290 def revisions
291 291 revisions ||= Revisions.new(collect{|entry| entry.lastrev}.compact)
292 292 end
293 293 end
294 294
295 295 class Info
296 296 attr_accessor :root_url, :lastrev
297 297 def initialize(attributes={})
298 298 self.root_url = attributes[:root_url] if attributes[:root_url]
299 299 self.lastrev = attributes[:lastrev]
300 300 end
301 301 end
302 302
303 303 class Entry
304 304 attr_accessor :name, :path, :kind, :size, :lastrev, :changeset
305 305
306 306 def initialize(attributes={})
307 307 self.name = attributes[:name] if attributes[:name]
308 308 self.path = attributes[:path] if attributes[:path]
309 309 self.kind = attributes[:kind] if attributes[:kind]
310 310 self.size = attributes[:size].to_i if attributes[:size]
311 311 self.lastrev = attributes[:lastrev]
312 312 end
313 313
314 314 def is_file?
315 315 'file' == self.kind
316 316 end
317 317
318 318 def is_dir?
319 319 'dir' == self.kind
320 320 end
321 321
322 322 def is_text?
323 323 Redmine::MimeType.is_type?('text', name)
324 324 end
325 325
326 326 def author
327 327 if changeset
328 328 changeset.author.to_s
329 329 elsif lastrev
330 330 Redmine::CodesetUtil.replace_invalid_utf8(lastrev.author.to_s.split('<').first)
331 331 end
332 332 end
333 333 end
334 334
335 335 class Revisions < Array
336 336 def latest
337 337 sort {|x,y|
338 338 unless x.time.nil? or y.time.nil?
339 339 x.time <=> y.time
340 340 else
341 341 0
342 342 end
343 343 }.last
344 344 end
345 345 end
346 346
347 347 class Revision
348 348 attr_accessor :scmid, :name, :author, :time, :message,
349 349 :paths, :revision, :branch, :identifier,
350 350 :parents
351 351
352 352 def initialize(attributes={})
353 353 self.identifier = attributes[:identifier]
354 354 self.scmid = attributes[:scmid]
355 355 self.name = attributes[:name] || self.identifier
356 356 self.author = attributes[:author]
357 357 self.time = attributes[:time]
358 358 self.message = attributes[:message] || ""
359 359 self.paths = attributes[:paths]
360 360 self.revision = attributes[:revision]
361 361 self.branch = attributes[:branch]
362 362 self.parents = attributes[:parents]
363 363 end
364 364
365 365 # Returns the readable identifier.
366 366 def format_identifier
367 367 self.identifier.to_s
368 368 end
369
370 def ==(other)
371 if other.nil?
372 false
373 elsif scmid.present?
374 scmid == other.scmid
375 elsif identifier.present?
376 identifier == other.identifier
377 elsif revision.present?
378 revision == other.revision
379 end
380 end
369 381 end
370 382
371 383 class Annotate
372 384 attr_reader :lines, :revisions
373 385
374 386 def initialize
375 387 @lines = []
376 388 @revisions = []
377 389 end
378 390
379 391 def add_line(line, revision)
380 392 @lines << line
381 393 @revisions << revision
382 394 end
383 395
384 396 def content
385 397 content = lines.join("\n")
386 398 end
387 399
388 400 def empty?
389 401 lines.empty?
390 402 end
391 403 end
392 404
393 405 class Branch < String
394 406 attr_accessor :revision, :scmid
395 407 end
396 408 end
397 409 end
398 410 end
@@ -1,289 +1,289
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2012 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.expand_path('../../test_helper', __FILE__)
19 19
20 20 class RepositoriesCvsControllerTest < ActionController::TestCase
21 21 tests RepositoriesController
22 22
23 23 fixtures :projects, :users, :roles, :members, :member_roles,
24 24 :repositories, :enabled_modules
25 25
26 26 REPOSITORY_PATH = Rails.root.join('tmp/test/cvs_repository').to_s
27 27 REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin?
28 28 # CVS module
29 29 MODULE_NAME = 'test'
30 30 PRJ_ID = 3
31 31 NUM_REV = 7
32 32
33 33 def setup
34 34 Setting.default_language = 'en'
35 35 User.current = nil
36 36
37 37 @project = Project.find(PRJ_ID)
38 38 @repository = Repository::Cvs.create(:project => Project.find(PRJ_ID),
39 39 :root_url => REPOSITORY_PATH,
40 40 :url => MODULE_NAME,
41 41 :log_encoding => 'UTF-8')
42 42 assert @repository
43 43 end
44 44
45 45 if File.directory?(REPOSITORY_PATH)
46 46 def test_get_new
47 47 @request.session[:user_id] = 1
48 48 @project.repository.destroy
49 49 get :new, :project_id => 'subproject1', :repository_scm => 'Cvs'
50 50 assert_response :success
51 51 assert_template 'new'
52 52 assert_kind_of Repository::Cvs, assigns(:repository)
53 53 assert assigns(:repository).new_record?
54 54 end
55 55
56 56 def test_browse_root
57 57 assert_equal 0, @repository.changesets.count
58 58 @repository.fetch_changesets
59 59 @project.reload
60 60 assert_equal NUM_REV, @repository.changesets.count
61 61 get :show, :id => PRJ_ID
62 62 assert_response :success
63 63 assert_template 'show'
64 64 assert_not_nil assigns(:entries)
65 65 assert_equal 3, assigns(:entries).size
66 66
67 67 entry = assigns(:entries).detect {|e| e.name == 'images'}
68 68 assert_equal 'dir', entry.kind
69 69
70 70 entry = assigns(:entries).detect {|e| e.name == 'README'}
71 71 assert_equal 'file', entry.kind
72 72
73 73 assert_not_nil assigns(:changesets)
74 74 assert assigns(:changesets).size > 0
75 75 end
76 76
77 77 def test_browse_directory
78 78 assert_equal 0, @repository.changesets.count
79 79 @repository.fetch_changesets
80 80 @project.reload
81 81 assert_equal NUM_REV, @repository.changesets.count
82 82 get :show, :id => PRJ_ID, :path => repository_path_hash(['images'])[:param]
83 83 assert_response :success
84 84 assert_template 'show'
85 85 assert_not_nil assigns(:entries)
86 86 assert_equal ['add.png', 'delete.png', 'edit.png'], assigns(:entries).collect(&:name)
87 87 entry = assigns(:entries).detect {|e| e.name == 'edit.png'}
88 88 assert_not_nil entry
89 89 assert_equal 'file', entry.kind
90 90 assert_equal 'images/edit.png', entry.path
91 91 end
92 92
93 93 def test_browse_at_given_revision
94 94 assert_equal 0, @repository.changesets.count
95 95 @repository.fetch_changesets
96 96 @project.reload
97 97 assert_equal NUM_REV, @repository.changesets.count
98 98 get :show, :id => PRJ_ID, :path => repository_path_hash(['images'])[:param],
99 99 :rev => 1
100 100 assert_response :success
101 101 assert_template 'show'
102 102 assert_not_nil assigns(:entries)
103 103 assert_equal ['delete.png', 'edit.png'], assigns(:entries).collect(&:name)
104 104 end
105 105
106 106 def test_entry
107 107 assert_equal 0, @repository.changesets.count
108 108 @repository.fetch_changesets
109 109 @project.reload
110 110 assert_equal NUM_REV, @repository.changesets.count
111 111 get :entry, :id => PRJ_ID,
112 112 :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param]
113 113 assert_response :success
114 114 assert_template 'entry'
115 115 assert_no_tag :tag => 'td',
116 116 :attributes => { :class => /line-code/},
117 117 :content => /before_filter/
118 118 end
119 119
120 120 def test_entry_at_given_revision
121 121 # changesets must be loaded
122 122 assert_equal 0, @repository.changesets.count
123 123 @repository.fetch_changesets
124 124 @project.reload
125 125 assert_equal NUM_REV, @repository.changesets.count
126 126 get :entry, :id => PRJ_ID,
127 127 :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param],
128 128 :rev => 2
129 129 assert_response :success
130 130 assert_template 'entry'
131 131 # this line was removed in r3
132 132 assert_tag :tag => 'td',
133 133 :attributes => { :class => /line-code/},
134 134 :content => /before_filter/
135 135 end
136 136
137 137 def test_entry_not_found
138 138 assert_equal 0, @repository.changesets.count
139 139 @repository.fetch_changesets
140 140 @project.reload
141 141 assert_equal NUM_REV, @repository.changesets.count
142 142 get :entry, :id => PRJ_ID,
143 143 :path => repository_path_hash(['sources', 'zzz.c'])[:param]
144 144 assert_tag :tag => 'p',
145 145 :attributes => { :id => /errorExplanation/ },
146 146 :content => /The entry or revision was not found in the repository/
147 147 end
148 148
149 149 def test_entry_download
150 150 assert_equal 0, @repository.changesets.count
151 151 @repository.fetch_changesets
152 152 @project.reload
153 153 assert_equal NUM_REV, @repository.changesets.count
154 154 get :entry, :id => PRJ_ID,
155 155 :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param],
156 156 :format => 'raw'
157 157 assert_response :success
158 158 end
159 159
160 160 def test_directory_entry
161 161 assert_equal 0, @repository.changesets.count
162 162 @repository.fetch_changesets
163 163 @project.reload
164 164 assert_equal NUM_REV, @repository.changesets.count
165 165 get :entry, :id => PRJ_ID,
166 166 :path => repository_path_hash(['sources'])[:param]
167 167 assert_response :success
168 168 assert_template 'show'
169 169 assert_not_nil assigns(:entry)
170 170 assert_equal 'sources', assigns(:entry).name
171 171 end
172 172
173 173 def test_diff
174 174 assert_equal 0, @repository.changesets.count
175 175 @repository.fetch_changesets
176 176 @project.reload
177 177 assert_equal NUM_REV, @repository.changesets.count
178 178 ['inline', 'sbs'].each do |dt|
179 179 get :diff, :id => PRJ_ID, :rev => 3, :type => dt
180 180 assert_response :success
181 181 assert_template 'diff'
182 182 assert_tag :tag => 'td', :attributes => { :class => 'line-code diff_out' },
183 183 :content => /before_filter :require_login/
184 184 assert_tag :tag => 'td', :attributes => { :class => 'line-code diff_in' },
185 185 :content => /with one change/
186 186 end
187 187 end
188 188
189 189 def test_diff_new_files
190 190 assert_equal 0, @repository.changesets.count
191 191 @repository.fetch_changesets
192 192 @project.reload
193 193 assert_equal NUM_REV, @repository.changesets.count
194 194 ['inline', 'sbs'].each do |dt|
195 195 get :diff, :id => PRJ_ID, :rev => 1, :type => dt
196 196 assert_response :success
197 197 assert_template 'diff'
198 198 assert_tag :tag => 'td', :attributes => { :class => 'line-code diff_in' },
199 199 :content => /watched.remove_watcher/
200 200 assert_tag :tag => 'th', :attributes => { :class => 'filename' },
201 201 :content => /test\/README/
202 202 assert_tag :tag => 'th', :attributes => { :class => 'filename' },
203 203 :content => /test\/images\/delete.png /
204 204 assert_tag :tag => 'th', :attributes => { :class => 'filename' },
205 205 :content => /test\/images\/edit.png/
206 206 assert_tag :tag => 'th', :attributes => { :class => 'filename' },
207 207 :content => /test\/sources\/watchers_controller.rb/
208 208 end
209 209 end
210 210
211 211 def test_annotate
212 212 assert_equal 0, @repository.changesets.count
213 213 @repository.fetch_changesets
214 214 @project.reload
215 215 assert_equal NUM_REV, @repository.changesets.count
216 216 get :annotate, :id => PRJ_ID,
217 217 :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param]
218 218 assert_response :success
219 219 assert_template 'annotate'
220 220 # 1.1 line
221 221 assert_tag :tag => 'th',
222 222 :attributes => { :class => 'line-num' },
223 :content => '18',
223 :content => '21',
224 224 :sibling => {
225 225 :tag => 'td',
226 226 :attributes => { :class => 'revision' },
227 227 :content => /1.1/,
228 228 :sibling => {
229 229 :tag => 'td',
230 230 :attributes => { :class => 'author' },
231 231 :content => /LANG/
232 232 }
233 233 }
234 234 # 1.2 line
235 235 assert_tag :tag => 'th',
236 236 :attributes => { :class => 'line-num' },
237 237 :content => '32',
238 238 :sibling => {
239 239 :tag => 'td',
240 240 :attributes => { :class => 'revision' },
241 241 :content => /1.2/,
242 242 :sibling => {
243 243 :tag => 'td',
244 244 :attributes => { :class => 'author' },
245 245 :content => /LANG/
246 246 }
247 247 }
248 248 end
249 249
250 250 def test_destroy_valid_repository
251 251 @request.session[:user_id] = 1 # admin
252 252 assert_equal 0, @repository.changesets.count
253 253 @repository.fetch_changesets
254 254 @project.reload
255 255 assert_equal NUM_REV, @repository.changesets.count
256 256
257 257 assert_difference 'Repository.count', -1 do
258 258 delete :destroy, :id => @repository.id
259 259 end
260 260 assert_response 302
261 261 @project.reload
262 262 assert_nil @project.repository
263 263 end
264 264
265 265 def test_destroy_invalid_repository
266 266 @request.session[:user_id] = 1 # admin
267 267 @project.repository.destroy
268 268 @repository = Repository::Cvs.create!(
269 269 :project => Project.find(PRJ_ID),
270 270 :root_url => "/invalid",
271 271 :url => MODULE_NAME,
272 272 :log_encoding => 'UTF-8'
273 273 )
274 274 @repository.fetch_changesets
275 275 @project.reload
276 276 assert_equal 0, @repository.changesets.count
277 277
278 278 assert_difference 'Repository.count', -1 do
279 279 delete :destroy, :id => @repository.id
280 280 end
281 281 assert_response 302
282 282 @project.reload
283 283 assert_nil @project.repository
284 284 end
285 285 else
286 286 puts "CVS test repository NOT FOUND. Skipping functional tests !!!"
287 287 def test_fake; assert true end
288 288 end
289 289 end
@@ -1,547 +1,547
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2012 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.expand_path('../../test_helper', __FILE__)
19 19
20 20 class RepositoriesGitControllerTest < ActionController::TestCase
21 21 tests RepositoriesController
22 22
23 23 fixtures :projects, :users, :roles, :members, :member_roles,
24 24 :repositories, :enabled_modules
25 25
26 26 REPOSITORY_PATH = Rails.root.join('tmp/test/git_repository').to_s
27 27 REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin?
28 28 PRJ_ID = 3
29 29 CHAR_1_HEX = "\xc3\x9c"
30 30 NUM_REV = 28
31 31
32 32 ## Git, Mercurial and CVS path encodings are binary.
33 33 ## Subversion supports URL encoding for path.
34 34 ## Redmine Mercurial adapter and extension use URL encoding.
35 35 ## Git accepts only binary path in command line parameter.
36 36 ## So, there is no way to use binary command line parameter in JRuby.
37 37 JRUBY_SKIP = (RUBY_PLATFORM == 'java')
38 38 JRUBY_SKIP_STR = "TODO: This test fails in JRuby"
39 39
40 40 def setup
41 41 @ruby19_non_utf8_pass =
42 42 (RUBY_VERSION >= '1.9' && Encoding.default_external.to_s != 'UTF-8')
43 43
44 44 User.current = nil
45 45 @project = Project.find(PRJ_ID)
46 46 @repository = Repository::Git.create(
47 47 :project => @project,
48 48 :url => REPOSITORY_PATH,
49 49 :path_encoding => 'ISO-8859-1'
50 50 )
51 51 assert @repository
52 52 @char_1 = CHAR_1_HEX.dup
53 53 if @char_1.respond_to?(:force_encoding)
54 54 @char_1.force_encoding('UTF-8')
55 55 end
56 56
57 57 Setting.default_language = 'en'
58 58 end
59 59
60 60 def test_create_and_update
61 61 @request.session[:user_id] = 1
62 62 assert_difference 'Repository.count' do
63 63 post :create, :project_id => 'subproject1',
64 64 :repository_scm => 'Git',
65 65 :repository => {
66 66 :url => '/test',
67 67 :is_default => '0',
68 68 :identifier => 'test-create',
69 69 :extra_report_last_commit => '1',
70 70 }
71 71 end
72 72 assert_response 302
73 73 repository = Repository.first(:order => 'id DESC')
74 74 assert_kind_of Repository::Git, repository
75 75 assert_equal '/test', repository.url
76 76 assert_equal true, repository.extra_report_last_commit
77 77
78 78 put :update, :id => repository.id,
79 79 :repository => {
80 80 :extra_report_last_commit => '0'
81 81 }
82 82 assert_response 302
83 83 repo2 = Repository.find(repository.id)
84 84 assert_equal false, repo2.extra_report_last_commit
85 85 end
86 86
87 87 if File.directory?(REPOSITORY_PATH)
88 88 ## Ruby uses ANSI api to fork a process on Windows.
89 89 ## Japanese Shift_JIS and Traditional Chinese Big5 have 0x5c(backslash) problem
90 90 ## and these are incompatible with ASCII.
91 91 ## Git for Windows (msysGit) changed internal API from ANSI to Unicode in 1.7.10
92 92 ## http://code.google.com/p/msysgit/issues/detail?id=80
93 93 ## So, Latin-1 path tests fail on Japanese Windows
94 94 WINDOWS_PASS = (Redmine::Platform.mswin? &&
95 95 Redmine::Scm::Adapters::GitAdapter.client_version_above?([1, 7, 10]))
96 96 WINDOWS_SKIP_STR = "TODO: This test fails in Git for Windows above 1.7.10"
97 97
98 98 def test_get_new
99 99 @request.session[:user_id] = 1
100 100 @project.repository.destroy
101 101 get :new, :project_id => 'subproject1', :repository_scm => 'Git'
102 102 assert_response :success
103 103 assert_template 'new'
104 104 assert_kind_of Repository::Git, assigns(:repository)
105 105 assert assigns(:repository).new_record?
106 106 end
107 107
108 108 def test_browse_root
109 109 assert_equal 0, @repository.changesets.count
110 110 @repository.fetch_changesets
111 111 @project.reload
112 112 assert_equal NUM_REV, @repository.changesets.count
113 113
114 114 get :show, :id => PRJ_ID
115 115 assert_response :success
116 116 assert_template 'show'
117 117 assert_not_nil assigns(:entries)
118 118 assert_equal 9, assigns(:entries).size
119 119 assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'}
120 120 assert assigns(:entries).detect {|e| e.name == 'this_is_a_really_long_and_verbose_directory_name' && e.kind == 'dir'}
121 121 assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'}
122 122 assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'}
123 123 assert assigns(:entries).detect {|e| e.name == 'copied_README' && e.kind == 'file'}
124 124 assert assigns(:entries).detect {|e| e.name == 'new_file.txt' && e.kind == 'file'}
125 125 assert assigns(:entries).detect {|e| e.name == 'renamed_test.txt' && e.kind == 'file'}
126 126 assert assigns(:entries).detect {|e| e.name == 'filemane with spaces.txt' && e.kind == 'file'}
127 127 assert assigns(:entries).detect {|e| e.name == ' filename with a leading space.txt ' && e.kind == 'file'}
128 128 assert_not_nil assigns(:changesets)
129 129 assert assigns(:changesets).size > 0
130 130 end
131 131
132 132 def test_browse_branch
133 133 assert_equal 0, @repository.changesets.count
134 134 @repository.fetch_changesets
135 135 @project.reload
136 136 assert_equal NUM_REV, @repository.changesets.count
137 137 get :show, :id => PRJ_ID, :rev => 'test_branch'
138 138 assert_response :success
139 139 assert_template 'show'
140 140 assert_not_nil assigns(:entries)
141 141 assert_equal 4, assigns(:entries).size
142 142 assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'}
143 143 assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'}
144 144 assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'}
145 145 assert assigns(:entries).detect {|e| e.name == 'test.txt' && e.kind == 'file'}
146 146 assert_not_nil assigns(:changesets)
147 147 assert assigns(:changesets).size > 0
148 148 end
149 149
150 150 def test_browse_tag
151 151 assert_equal 0, @repository.changesets.count
152 152 @repository.fetch_changesets
153 153 @project.reload
154 154 assert_equal NUM_REV, @repository.changesets.count
155 155 [
156 156 "tag00.lightweight",
157 157 "tag01.annotated",
158 158 ].each do |t1|
159 159 get :show, :id => PRJ_ID, :rev => t1
160 160 assert_response :success
161 161 assert_template 'show'
162 162 assert_not_nil assigns(:entries)
163 163 assert assigns(:entries).size > 0
164 164 assert_not_nil assigns(:changesets)
165 165 assert assigns(:changesets).size > 0
166 166 end
167 167 end
168 168
169 169 def test_browse_directory
170 170 assert_equal 0, @repository.changesets.count
171 171 @repository.fetch_changesets
172 172 @project.reload
173 173 assert_equal NUM_REV, @repository.changesets.count
174 174 get :show, :id => PRJ_ID, :path => repository_path_hash(['images'])[:param]
175 175 assert_response :success
176 176 assert_template 'show'
177 177 assert_not_nil assigns(:entries)
178 178 assert_equal ['edit.png'], assigns(:entries).collect(&:name)
179 179 entry = assigns(:entries).detect {|e| e.name == 'edit.png'}
180 180 assert_not_nil entry
181 181 assert_equal 'file', entry.kind
182 182 assert_equal 'images/edit.png', entry.path
183 183 assert_not_nil assigns(:changesets)
184 184 assert assigns(:changesets).size > 0
185 185 end
186 186
187 187 def test_browse_at_given_revision
188 188 assert_equal 0, @repository.changesets.count
189 189 @repository.fetch_changesets
190 190 @project.reload
191 191 assert_equal NUM_REV, @repository.changesets.count
192 192 get :show, :id => PRJ_ID, :path => repository_path_hash(['images'])[:param],
193 193 :rev => '7234cb2750b63f47bff735edc50a1c0a433c2518'
194 194 assert_response :success
195 195 assert_template 'show'
196 196 assert_not_nil assigns(:entries)
197 197 assert_equal ['delete.png'], assigns(:entries).collect(&:name)
198 198 assert_not_nil assigns(:changesets)
199 199 assert assigns(:changesets).size > 0
200 200 end
201 201
202 202 def test_changes
203 203 get :changes, :id => PRJ_ID,
204 204 :path => repository_path_hash(['images', 'edit.png'])[:param]
205 205 assert_response :success
206 206 assert_template 'changes'
207 207 assert_tag :tag => 'h2', :content => 'edit.png'
208 208 end
209 209
210 210 def test_entry_show
211 211 get :entry, :id => PRJ_ID,
212 212 :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param]
213 213 assert_response :success
214 214 assert_template 'entry'
215 215 # Line 19
216 216 assert_tag :tag => 'th',
217 217 :content => '11',
218 218 :attributes => { :class => 'line-num' },
219 219 :sibling => { :tag => 'td', :content => /WITHOUT ANY WARRANTY/ }
220 220 end
221 221
222 222 def test_entry_show_latin_1
223 223 if @ruby19_non_utf8_pass
224 224 puts_ruby19_non_utf8_pass()
225 225 elsif WINDOWS_PASS
226 226 puts WINDOWS_SKIP_STR
227 227 elsif JRUBY_SKIP
228 228 puts JRUBY_SKIP_STR
229 229 else
230 230 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
231 231 ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1|
232 232 get :entry, :id => PRJ_ID,
233 233 :path => repository_path_hash(['latin-1-dir', "test-#{@char_1}.txt"])[:param],
234 234 :rev => r1
235 235 assert_response :success
236 236 assert_template 'entry'
237 237 assert_tag :tag => 'th',
238 238 :content => '1',
239 239 :attributes => { :class => 'line-num' },
240 240 :sibling => { :tag => 'td',
241 241 :content => /test-#{@char_1}.txt/ }
242 242 end
243 243 end
244 244 end
245 245 end
246 246
247 247 def test_entry_download
248 248 get :entry, :id => PRJ_ID,
249 249 :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param],
250 250 :format => 'raw'
251 251 assert_response :success
252 252 # File content
253 253 assert @response.body.include?('WITHOUT ANY WARRANTY')
254 254 end
255 255
256 256 def test_directory_entry
257 257 get :entry, :id => PRJ_ID,
258 258 :path => repository_path_hash(['sources'])[:param]
259 259 assert_response :success
260 260 assert_template 'show'
261 261 assert_not_nil assigns(:entry)
262 262 assert_equal 'sources', assigns(:entry).name
263 263 end
264 264
265 265 def test_diff
266 266 assert_equal 0, @repository.changesets.count
267 267 @repository.fetch_changesets
268 268 @project.reload
269 269 assert_equal NUM_REV, @repository.changesets.count
270 270 # Full diff of changeset 2f9c0091
271 271 ['inline', 'sbs'].each do |dt|
272 272 get :diff,
273 273 :id => PRJ_ID,
274 274 :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7',
275 275 :type => dt
276 276 assert_response :success
277 277 assert_template 'diff'
278 278 # Line 22 removed
279 279 assert_tag :tag => 'th',
280 280 :content => /22/,
281 281 :sibling => { :tag => 'td',
282 282 :attributes => { :class => /diff_out/ },
283 283 :content => /def remove/ }
284 284 assert_tag :tag => 'h2', :content => /2f9c0091/
285 285 end
286 286 end
287 287
288 288 def test_diff_truncated
289 289 assert_equal 0, @repository.changesets.count
290 290 @repository.fetch_changesets
291 291 @project.reload
292 292 assert_equal NUM_REV, @repository.changesets.count
293 293
294 294 with_settings :diff_max_lines_displayed => 5 do
295 295 # Truncated diff of changeset 2f9c0091
296 296 with_cache do
297 297 get :diff, :id => PRJ_ID, :type => 'inline',
298 298 :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
299 299 assert_response :success
300 300 assert @response.body.include?("... This diff was truncated")
301 301
302 302 Setting.default_language = 'fr'
303 303 get :diff, :id => PRJ_ID, :type => 'inline',
304 304 :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
305 305 assert_response :success
306 306 assert ! @response.body.include?("... This diff was truncated")
307 307 assert @response.body.include?("... Ce diff")
308 308 end
309 309 end
310 310 end
311 311
312 312 def test_diff_two_revs
313 313 assert_equal 0, @repository.changesets.count
314 314 @repository.fetch_changesets
315 315 @project.reload
316 316 assert_equal NUM_REV, @repository.changesets.count
317 317 ['inline', 'sbs'].each do |dt|
318 318 get :diff,
319 319 :id => PRJ_ID,
320 320 :rev => '61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
321 321 :rev_to => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7',
322 322 :type => dt
323 323 assert_response :success
324 324 assert_template 'diff'
325 325 diff = assigns(:diff)
326 326 assert_not_nil diff
327 327 assert_tag :tag => 'h2', :content => /2f9c0091:61b685fb/
328 328 end
329 329 end
330 330
331 331 def test_diff_latin_1
332 332 if @ruby19_non_utf8_pass
333 333 puts_ruby19_non_utf8_pass()
334 334 else
335 335 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
336 336 ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1|
337 337 ['inline', 'sbs'].each do |dt|
338 338 get :diff, :id => PRJ_ID, :rev => r1, :type => dt
339 339 assert_response :success
340 340 assert_template 'diff'
341 341 assert_tag :tag => 'thead',
342 342 :descendant => {
343 343 :tag => 'th',
344 344 :attributes => { :class => 'filename' } ,
345 345 :content => /latin-1-dir\/test-#{@char_1}.txt/ ,
346 346 },
347 347 :sibling => {
348 348 :tag => 'tbody',
349 349 :descendant => {
350 350 :tag => 'td',
351 351 :attributes => { :class => /diff_in/ },
352 352 :content => /test-#{@char_1}.txt/
353 353 }
354 354 }
355 355 end
356 356 end
357 357 end
358 358 end
359 359 end
360 360
361 361 def test_save_diff_type
362 362 @request.session[:user_id] = 1 # admin
363 363 user = User.find(1)
364 364 get :diff,
365 365 :id => PRJ_ID,
366 366 :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
367 367 assert_response :success
368 368 assert_template 'diff'
369 369 user.reload
370 370 assert_equal "inline", user.pref[:diff_type]
371 371 get :diff,
372 372 :id => PRJ_ID,
373 373 :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7',
374 374 :type => 'sbs'
375 375 assert_response :success
376 376 assert_template 'diff'
377 377 user.reload
378 378 assert_equal "sbs", user.pref[:diff_type]
379 379 end
380 380
381 381 def test_annotate
382 382 get :annotate, :id => PRJ_ID,
383 383 :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param]
384 384 assert_response :success
385 385 assert_template 'annotate'
386 # Line 24, changeset 2f9c0091
387 assert_tag :tag => 'th', :content => '24',
386 # Line 23, changeset 2f9c0091
387 assert_tag :tag => 'th', :content => '23',
388 388 :sibling => {
389 389 :tag => 'td',
390 390 :child => {
391 391 :tag => 'a',
392 392 :content => /2f9c0091/
393 393 }
394 394 }
395 assert_tag :tag => 'th', :content => '24',
395 assert_tag :tag => 'th', :content => '23',
396 396 :sibling => { :tag => 'td', :content => /jsmith/ }
397 assert_tag :tag => 'th', :content => '24',
397 assert_tag :tag => 'th', :content => '23',
398 398 :sibling => {
399 399 :tag => 'td',
400 400 :child => {
401 401 :tag => 'a',
402 402 :content => /2f9c0091/
403 403 }
404 404 }
405 assert_tag :tag => 'th', :content => '24',
406 :sibling => { :tag => 'td', :content => /watcher =/ }
405 assert_tag :tag => 'th', :content => '23',
406 :sibling => { :tag => 'td', :content => /remove_watcher/ }
407 407 end
408 408
409 409 def test_annotate_at_given_revision
410 410 assert_equal 0, @repository.changesets.count
411 411 @repository.fetch_changesets
412 412 @project.reload
413 413 assert_equal NUM_REV, @repository.changesets.count
414 414 get :annotate, :id => PRJ_ID, :rev => 'deff7',
415 415 :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param]
416 416 assert_response :success
417 417 assert_template 'annotate'
418 418 assert_tag :tag => 'h2', :content => /@ deff712f/
419 419 end
420 420
421 421 def test_annotate_binary_file
422 422 get :annotate, :id => PRJ_ID,
423 423 :path => repository_path_hash(['images', 'edit.png'])[:param]
424 424 assert_response 500
425 425 assert_tag :tag => 'p', :attributes => { :id => /errorExplanation/ },
426 426 :content => /cannot be annotated/
427 427 end
428 428
429 429 def test_annotate_error_when_too_big
430 430 with_settings :file_max_size_displayed => 1 do
431 431 get :annotate, :id => PRJ_ID,
432 432 :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param],
433 433 :rev => 'deff712f'
434 434 assert_response 500
435 435 assert_tag :tag => 'p', :attributes => { :id => /errorExplanation/ },
436 436 :content => /exceeds the maximum text file size/
437 437
438 438 get :annotate, :id => PRJ_ID,
439 439 :path => repository_path_hash(['README'])[:param],
440 440 :rev => '7234cb2'
441 441 assert_response :success
442 442 assert_template 'annotate'
443 443 end
444 444 end
445 445
446 446 def test_annotate_latin_1
447 447 if @ruby19_non_utf8_pass
448 448 puts_ruby19_non_utf8_pass()
449 449 elsif WINDOWS_PASS
450 450 puts WINDOWS_SKIP_STR
451 451 elsif JRUBY_SKIP
452 452 puts JRUBY_SKIP_STR
453 453 else
454 454 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
455 455 ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1|
456 456 get :annotate, :id => PRJ_ID,
457 457 :path => repository_path_hash(['latin-1-dir', "test-#{@char_1}.txt"])[:param],
458 458 :rev => r1
459 459 assert_tag :tag => 'th',
460 460 :content => '1',
461 461 :attributes => { :class => 'line-num' },
462 462 :sibling => { :tag => 'td',
463 463 :content => /test-#{@char_1}.txt/ }
464 464 end
465 465 end
466 466 end
467 467 end
468 468
469 469 def test_revision
470 470 assert_equal 0, @repository.changesets.count
471 471 @repository.fetch_changesets
472 472 @project.reload
473 473 assert_equal NUM_REV, @repository.changesets.count
474 474 ['61b685fbe55ab05b5ac68402d5720c1a6ac973d1', '61b685f'].each do |r|
475 475 get :revision, :id => PRJ_ID, :rev => r
476 476 assert_response :success
477 477 assert_template 'revision'
478 478 end
479 479 end
480 480
481 481 def test_empty_revision
482 482 assert_equal 0, @repository.changesets.count
483 483 @repository.fetch_changesets
484 484 @project.reload
485 485 assert_equal NUM_REV, @repository.changesets.count
486 486 ['', ' ', nil].each do |r|
487 487 get :revision, :id => PRJ_ID, :rev => r
488 488 assert_response 404
489 489 assert_error_tag :content => /was not found/
490 490 end
491 491 end
492 492
493 493 def test_destroy_valid_repository
494 494 @request.session[:user_id] = 1 # admin
495 495 assert_equal 0, @repository.changesets.count
496 496 @repository.fetch_changesets
497 497 @project.reload
498 498 assert_equal NUM_REV, @repository.changesets.count
499 499
500 500 assert_difference 'Repository.count', -1 do
501 501 delete :destroy, :id => @repository.id
502 502 end
503 503 assert_response 302
504 504 @project.reload
505 505 assert_nil @project.repository
506 506 end
507 507
508 508 def test_destroy_invalid_repository
509 509 @request.session[:user_id] = 1 # admin
510 510 @project.repository.destroy
511 511 @repository = Repository::Git.create!(
512 512 :project => @project,
513 513 :url => "/invalid",
514 514 :path_encoding => 'ISO-8859-1'
515 515 )
516 516 @repository.fetch_changesets
517 517 @repository.reload
518 518 assert_equal 0, @repository.changesets.count
519 519
520 520 assert_difference 'Repository.count', -1 do
521 521 delete :destroy, :id => @repository.id
522 522 end
523 523 assert_response 302
524 524 @project.reload
525 525 assert_nil @project.repository
526 526 end
527 527
528 528 private
529 529
530 530 def puts_ruby19_non_utf8_pass
531 531 puts "TODO: This test fails in Ruby 1.9 " +
532 532 "and Encoding.default_external is not UTF-8. " +
533 533 "Current value is '#{Encoding.default_external.to_s}'"
534 534 end
535 535 else
536 536 puts "Git test repository NOT FOUND. Skipping functional tests !!!"
537 537 def test_fake; assert true end
538 538 end
539 539
540 540 private
541 541 def with_cache(&block)
542 542 before = ActionController::Base.perform_caching
543 543 ActionController::Base.perform_caching = true
544 544 block.call
545 545 ActionController::Base.perform_caching = before
546 546 end
547 547 end
@@ -1,526 +1,526
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2012 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.expand_path('../../test_helper', __FILE__)
19 19
20 20 class RepositoriesMercurialControllerTest < ActionController::TestCase
21 21 tests RepositoriesController
22 22
23 23 fixtures :projects, :users, :roles, :members, :member_roles,
24 24 :repositories, :enabled_modules
25 25
26 26 REPOSITORY_PATH = Rails.root.join('tmp/test/mercurial_repository').to_s
27 27 CHAR_1_HEX = "\xc3\x9c"
28 28 PRJ_ID = 3
29 29 NUM_REV = 32
30 30
31 31 ruby19_non_utf8_pass =
32 32 (RUBY_VERSION >= '1.9' && Encoding.default_external.to_s != 'UTF-8')
33 33
34 34 def setup
35 35 User.current = nil
36 36 @project = Project.find(PRJ_ID)
37 37 @repository = Repository::Mercurial.create(
38 38 :project => @project,
39 39 :url => REPOSITORY_PATH,
40 40 :path_encoding => 'ISO-8859-1'
41 41 )
42 42 assert @repository
43 43 @diff_c_support = true
44 44 @char_1 = CHAR_1_HEX.dup
45 45 @tag_char_1 = "tag-#{CHAR_1_HEX}-00"
46 46 @branch_char_0 = "branch-#{CHAR_1_HEX}-00"
47 47 @branch_char_1 = "branch-#{CHAR_1_HEX}-01"
48 48 if @char_1.respond_to?(:force_encoding)
49 49 @char_1.force_encoding('UTF-8')
50 50 @tag_char_1.force_encoding('UTF-8')
51 51 @branch_char_0.force_encoding('UTF-8')
52 52 @branch_char_1.force_encoding('UTF-8')
53 53 end
54 54 end
55 55
56 56 if ruby19_non_utf8_pass
57 57 puts "TODO: Mercurial functional test fails in Ruby 1.9 " +
58 58 "and Encoding.default_external is not UTF-8. " +
59 59 "Current value is '#{Encoding.default_external.to_s}'"
60 60 def test_fake; assert true end
61 61 elsif File.directory?(REPOSITORY_PATH)
62 62
63 63 def test_get_new
64 64 @request.session[:user_id] = 1
65 65 @project.repository.destroy
66 66 get :new, :project_id => 'subproject1', :repository_scm => 'Mercurial'
67 67 assert_response :success
68 68 assert_template 'new'
69 69 assert_kind_of Repository::Mercurial, assigns(:repository)
70 70 assert assigns(:repository).new_record?
71 71 end
72 72
73 73 def test_show_root
74 74 assert_equal 0, @repository.changesets.count
75 75 @repository.fetch_changesets
76 76 @project.reload
77 77 assert_equal NUM_REV, @repository.changesets.count
78 78 get :show, :id => PRJ_ID
79 79 assert_response :success
80 80 assert_template 'show'
81 81 assert_not_nil assigns(:entries)
82 82 assert_equal 4, assigns(:entries).size
83 83 assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'}
84 84 assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'}
85 85 assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'}
86 86 assert_not_nil assigns(:changesets)
87 87 assert assigns(:changesets).size > 0
88 88 end
89 89
90 90 def test_show_directory
91 91 assert_equal 0, @repository.changesets.count
92 92 @repository.fetch_changesets
93 93 @project.reload
94 94 assert_equal NUM_REV, @repository.changesets.count
95 95 get :show, :id => PRJ_ID, :path => repository_path_hash(['images'])[:param]
96 96 assert_response :success
97 97 assert_template 'show'
98 98 assert_not_nil assigns(:entries)
99 99 assert_equal ['delete.png', 'edit.png'], assigns(:entries).collect(&:name)
100 100 entry = assigns(:entries).detect {|e| e.name == 'edit.png'}
101 101 assert_not_nil entry
102 102 assert_equal 'file', entry.kind
103 103 assert_equal 'images/edit.png', entry.path
104 104 assert_not_nil assigns(:changesets)
105 105 assert assigns(:changesets).size > 0
106 106 end
107 107
108 108 def test_show_at_given_revision
109 109 assert_equal 0, @repository.changesets.count
110 110 @repository.fetch_changesets
111 111 @project.reload
112 112 assert_equal NUM_REV, @repository.changesets.count
113 113 [0, '0', '0885933ad4f6'].each do |r1|
114 114 get :show, :id => PRJ_ID, :path => repository_path_hash(['images'])[:param],
115 115 :rev => r1
116 116 assert_response :success
117 117 assert_template 'show'
118 118 assert_not_nil assigns(:entries)
119 119 assert_equal ['delete.png'], assigns(:entries).collect(&:name)
120 120 assert_not_nil assigns(:changesets)
121 121 assert assigns(:changesets).size > 0
122 122 end
123 123 end
124 124
125 125 def test_show_directory_sql_escape_percent
126 126 assert_equal 0, @repository.changesets.count
127 127 @repository.fetch_changesets
128 128 @project.reload
129 129 assert_equal NUM_REV, @repository.changesets.count
130 130 [13, '13', '3a330eb32958'].each do |r1|
131 131 get :show, :id => PRJ_ID,
132 132 :path => repository_path_hash(['sql_escape', 'percent%dir'])[:param],
133 133 :rev => r1
134 134 assert_response :success
135 135 assert_template 'show'
136 136
137 137 assert_not_nil assigns(:entries)
138 138 assert_equal ['percent%file1.txt', 'percentfile1.txt'],
139 139 assigns(:entries).collect(&:name)
140 140 changesets = assigns(:changesets)
141 141 assert_not_nil changesets
142 142 assert assigns(:changesets).size > 0
143 143 assert_equal %w(13 11 10 9), changesets.collect(&:revision)
144 144 end
145 145 end
146 146
147 147 def test_show_directory_latin_1_path
148 148 assert_equal 0, @repository.changesets.count
149 149 @repository.fetch_changesets
150 150 @project.reload
151 151 assert_equal NUM_REV, @repository.changesets.count
152 152 [21, '21', 'adf805632193'].each do |r1|
153 153 get :show, :id => PRJ_ID,
154 154 :path => repository_path_hash(['latin-1-dir'])[:param],
155 155 :rev => r1
156 156 assert_response :success
157 157 assert_template 'show'
158 158
159 159 assert_not_nil assigns(:entries)
160 160 assert_equal ["make-latin-1-file.rb",
161 161 "test-#{@char_1}-1.txt",
162 162 "test-#{@char_1}-2.txt",
163 163 "test-#{@char_1}.txt"], assigns(:entries).collect(&:name)
164 164 changesets = assigns(:changesets)
165 165 assert_not_nil changesets
166 166 assert_equal %w(21 20 19 18 17), changesets.collect(&:revision)
167 167 end
168 168 end
169 169
170 170 def show_should_show_branch_selection_form
171 171 @repository.fetch_changesets
172 172 @project.reload
173 173 get :show, :id => PRJ_ID
174 174 assert_tag 'form', :attributes => {:id => 'revision_selector', :action => '/projects/subproject1/repository/show'}
175 175 assert_tag 'select', :attributes => {:name => 'branch'},
176 176 :child => {:tag => 'option', :attributes => {:value => 'test-branch-01'}},
177 177 :parent => {:tag => 'form', :attributes => {:id => 'revision_selector'}}
178 178 end
179 179
180 180 def test_show_branch
181 181 assert_equal 0, @repository.changesets.count
182 182 @repository.fetch_changesets
183 183 @project.reload
184 184 assert_equal NUM_REV, @repository.changesets.count
185 185 [
186 186 'default',
187 187 @branch_char_1,
188 188 'branch (1)[2]&,%.-3_4',
189 189 @branch_char_0,
190 190 'test_branch.latin-1',
191 191 'test-branch-00',
192 192 ].each do |bra|
193 193 get :show, :id => PRJ_ID, :rev => bra
194 194 assert_response :success
195 195 assert_template 'show'
196 196 assert_not_nil assigns(:entries)
197 197 assert assigns(:entries).size > 0
198 198 assert_not_nil assigns(:changesets)
199 199 assert assigns(:changesets).size > 0
200 200 end
201 201 end
202 202
203 203 def test_show_tag
204 204 assert_equal 0, @repository.changesets.count
205 205 @repository.fetch_changesets
206 206 @project.reload
207 207 assert_equal NUM_REV, @repository.changesets.count
208 208 [
209 209 @tag_char_1,
210 210 'tag_test.00',
211 211 'tag-init-revision'
212 212 ].each do |tag|
213 213 get :show, :id => PRJ_ID, :rev => tag
214 214 assert_response :success
215 215 assert_template 'show'
216 216 assert_not_nil assigns(:entries)
217 217 assert assigns(:entries).size > 0
218 218 assert_not_nil assigns(:changesets)
219 219 assert assigns(:changesets).size > 0
220 220 end
221 221 end
222 222
223 223 def test_changes
224 224 get :changes, :id => PRJ_ID,
225 225 :path => repository_path_hash(['images', 'edit.png'])[:param]
226 226 assert_response :success
227 227 assert_template 'changes'
228 228 assert_tag :tag => 'h2', :content => 'edit.png'
229 229 end
230 230
231 231 def test_entry_show
232 232 get :entry, :id => PRJ_ID,
233 233 :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param]
234 234 assert_response :success
235 235 assert_template 'entry'
236 236 # Line 10
237 237 assert_tag :tag => 'th',
238 238 :content => '10',
239 239 :attributes => { :class => 'line-num' },
240 240 :sibling => { :tag => 'td', :content => /WITHOUT ANY WARRANTY/ }
241 241 end
242 242
243 243 def test_entry_show_latin_1_path
244 244 [21, '21', 'adf805632193'].each do |r1|
245 245 get :entry, :id => PRJ_ID,
246 246 :path => repository_path_hash(['latin-1-dir', "test-#{@char_1}-2.txt"])[:param],
247 247 :rev => r1
248 248 assert_response :success
249 249 assert_template 'entry'
250 250 assert_tag :tag => 'th',
251 251 :content => '1',
252 252 :attributes => { :class => 'line-num' },
253 253 :sibling => { :tag => 'td',
254 254 :content => /Mercurial is a distributed version control system/ }
255 255 end
256 256 end
257 257
258 258 def test_entry_show_latin_1_contents
259 259 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
260 260 [27, '27', '7bbf4c738e71'].each do |r1|
261 261 get :entry, :id => PRJ_ID,
262 262 :path => repository_path_hash(['latin-1-dir', "test-#{@char_1}.txt"])[:param],
263 263 :rev => r1
264 264 assert_response :success
265 265 assert_template 'entry'
266 266 assert_tag :tag => 'th',
267 267 :content => '1',
268 268 :attributes => { :class => 'line-num' },
269 269 :sibling => { :tag => 'td',
270 270 :content => /test-#{@char_1}.txt/ }
271 271 end
272 272 end
273 273 end
274 274
275 275 def test_entry_download
276 276 get :entry, :id => PRJ_ID,
277 277 :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param],
278 278 :format => 'raw'
279 279 assert_response :success
280 280 # File content
281 281 assert @response.body.include?('WITHOUT ANY WARRANTY')
282 282 end
283 283
284 284 def test_entry_binary_force_download
285 285 get :entry, :id => PRJ_ID, :rev => 1,
286 286 :path => repository_path_hash(['images', 'edit.png'])[:param]
287 287 assert_response :success
288 288 assert_equal 'image/png', @response.content_type
289 289 end
290 290
291 291 def test_directory_entry
292 292 get :entry, :id => PRJ_ID,
293 293 :path => repository_path_hash(['sources'])[:param]
294 294 assert_response :success
295 295 assert_template 'show'
296 296 assert_not_nil assigns(:entry)
297 297 assert_equal 'sources', assigns(:entry).name
298 298 end
299 299
300 300 def test_diff
301 301 assert_equal 0, @repository.changesets.count
302 302 @repository.fetch_changesets
303 303 @project.reload
304 304 assert_equal NUM_REV, @repository.changesets.count
305 305 [4, '4', 'def6d2f1254a'].each do |r1|
306 306 # Full diff of changeset 4
307 307 ['inline', 'sbs'].each do |dt|
308 308 get :diff, :id => PRJ_ID, :rev => r1, :type => dt
309 309 assert_response :success
310 310 assert_template 'diff'
311 311 if @diff_c_support
312 312 # Line 22 removed
313 313 assert_tag :tag => 'th',
314 314 :content => '22',
315 315 :sibling => { :tag => 'td',
316 316 :attributes => { :class => /diff_out/ },
317 317 :content => /def remove/ }
318 318 assert_tag :tag => 'h2', :content => /4:def6d2f1254a/
319 319 end
320 320 end
321 321 end
322 322 end
323 323
324 324 def test_diff_two_revs
325 325 assert_equal 0, @repository.changesets.count
326 326 @repository.fetch_changesets
327 327 @project.reload
328 328 assert_equal NUM_REV, @repository.changesets.count
329 329 [2, '400bb8672109', '400', 400].each do |r1|
330 330 [4, 'def6d2f1254a'].each do |r2|
331 331 ['inline', 'sbs'].each do |dt|
332 332 get :diff,
333 333 :id => PRJ_ID,
334 334 :rev => r1,
335 335 :rev_to => r2,
336 336 :type => dt
337 337 assert_response :success
338 338 assert_template 'diff'
339 339 diff = assigns(:diff)
340 340 assert_not_nil diff
341 341 assert_tag :tag => 'h2',
342 342 :content => /4:def6d2f1254a 2:400bb8672109/
343 343 end
344 344 end
345 345 end
346 346 end
347 347
348 348 def test_diff_latin_1_path
349 349 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
350 350 [21, 'adf805632193'].each do |r1|
351 351 ['inline', 'sbs'].each do |dt|
352 352 get :diff, :id => PRJ_ID, :rev => r1, :type => dt
353 353 assert_response :success
354 354 assert_template 'diff'
355 355 assert_tag :tag => 'thead',
356 356 :descendant => {
357 357 :tag => 'th',
358 358 :attributes => { :class => 'filename' } ,
359 359 :content => /latin-1-dir\/test-#{@char_1}-2.txt/ ,
360 360 },
361 361 :sibling => {
362 362 :tag => 'tbody',
363 363 :descendant => {
364 364 :tag => 'td',
365 365 :attributes => { :class => /diff_in/ },
366 366 :content => /It is written in Python/
367 367 }
368 368 }
369 369 end
370 370 end
371 371 end
372 372 end
373 373
374 374 def test_annotate
375 375 get :annotate, :id => PRJ_ID,
376 376 :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param]
377 377 assert_response :success
378 378 assert_template 'annotate'
379 # Line 23, revision 4:def6d2f1254a
379 # Line 22, revision 4:def6d2f1254a
380 380 assert_tag :tag => 'th',
381 :content => '23',
381 :content => '22',
382 382 :attributes => { :class => 'line-num' },
383 383 :sibling =>
384 384 {
385 385 :tag => 'td',
386 386 :attributes => { :class => 'revision' },
387 387 :child => { :tag => 'a', :content => '4:def6d2f1254a' }
388 388 }
389 389 assert_tag :tag => 'th',
390 :content => '23',
390 :content => '22',
391 391 :attributes => { :class => 'line-num' },
392 392 :sibling =>
393 393 {
394 394 :tag => 'td' ,
395 395 :content => 'jsmith' ,
396 396 :attributes => { :class => 'author' },
397 397 }
398 398 assert_tag :tag => 'th',
399 :content => '23',
399 :content => '22',
400 400 :attributes => { :class => 'line-num' },
401 :sibling => { :tag => 'td', :content => /watcher =/ }
401 :sibling => { :tag => 'td', :content => /remove_watcher/ }
402 402 end
403 403
404 404 def test_annotate_not_in_tip
405 405 assert_equal 0, @repository.changesets.count
406 406 @repository.fetch_changesets
407 407 @project.reload
408 408 assert_equal NUM_REV, @repository.changesets.count
409 409 get :annotate, :id => PRJ_ID,
410 410 :path => repository_path_hash(['sources', 'welcome_controller.rb'])[:param]
411 411 assert_response 404
412 412 assert_error_tag :content => /was not found/
413 413 end
414 414
415 415 def test_annotate_at_given_revision
416 416 assert_equal 0, @repository.changesets.count
417 417 @repository.fetch_changesets
418 418 @project.reload
419 419 assert_equal NUM_REV, @repository.changesets.count
420 420 [2, '400bb8672109', '400', 400].each do |r1|
421 421 get :annotate, :id => PRJ_ID, :rev => r1,
422 422 :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param]
423 423 assert_response :success
424 424 assert_template 'annotate'
425 425 assert_tag :tag => 'h2', :content => /@ 2:400bb8672109/
426 426 end
427 427 end
428 428
429 429 def test_annotate_latin_1_path
430 430 [21, '21', 'adf805632193'].each do |r1|
431 431 get :annotate, :id => PRJ_ID,
432 432 :path => repository_path_hash(['latin-1-dir', "test-#{@char_1}-2.txt"])[:param],
433 433 :rev => r1
434 434 assert_response :success
435 435 assert_template 'annotate'
436 436 assert_tag :tag => 'th',
437 437 :content => '1',
438 438 :attributes => { :class => 'line-num' },
439 439 :sibling =>
440 440 {
441 441 :tag => 'td',
442 442 :attributes => { :class => 'revision' },
443 443 :child => { :tag => 'a', :content => '20:709858aafd1b' }
444 444 }
445 445 assert_tag :tag => 'th',
446 446 :content => '1',
447 447 :attributes => { :class => 'line-num' },
448 448 :sibling =>
449 449 {
450 450 :tag => 'td' ,
451 451 :content => 'jsmith' ,
452 452 :attributes => { :class => 'author' },
453 453 }
454 454 assert_tag :tag => 'th',
455 455 :content => '1',
456 456 :attributes => { :class => 'line-num' },
457 457 :sibling => { :tag => 'td',
458 458 :content => /Mercurial is a distributed version control system/ }
459 459
460 460 end
461 461 end
462 462
463 463 def test_annotate_latin_1_contents
464 464 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
465 465 [27, '7bbf4c738e71'].each do |r1|
466 466 get :annotate, :id => PRJ_ID,
467 467 :path => repository_path_hash(['latin-1-dir', "test-#{@char_1}.txt"])[:param],
468 468 :rev => r1
469 469 assert_tag :tag => 'th',
470 470 :content => '1',
471 471 :attributes => { :class => 'line-num' },
472 472 :sibling => { :tag => 'td',
473 473 :content => /test-#{@char_1}.txt/ }
474 474 end
475 475 end
476 476 end
477 477
478 478 def test_empty_revision
479 479 assert_equal 0, @repository.changesets.count
480 480 @repository.fetch_changesets
481 481 @project.reload
482 482 assert_equal NUM_REV, @repository.changesets.count
483 483 ['', ' ', nil].each do |r|
484 484 get :revision, :id => PRJ_ID, :rev => r
485 485 assert_response 404
486 486 assert_error_tag :content => /was not found/
487 487 end
488 488 end
489 489
490 490 def test_destroy_valid_repository
491 491 @request.session[:user_id] = 1 # admin
492 492 assert_equal 0, @repository.changesets.count
493 493 @repository.fetch_changesets
494 494 assert_equal NUM_REV, @repository.changesets.count
495 495
496 496 assert_difference 'Repository.count', -1 do
497 497 delete :destroy, :id => @repository.id
498 498 end
499 499 assert_response 302
500 500 @project.reload
501 501 assert_nil @project.repository
502 502 end
503 503
504 504 def test_destroy_invalid_repository
505 505 @request.session[:user_id] = 1 # admin
506 506 @project.repository.destroy
507 507 @repository = Repository::Mercurial.create!(
508 508 :project => Project.find(PRJ_ID),
509 509 :url => "/invalid",
510 510 :path_encoding => 'ISO-8859-1'
511 511 )
512 512 @repository.fetch_changesets
513 513 assert_equal 0, @repository.changesets.count
514 514
515 515 assert_difference 'Repository.count', -1 do
516 516 delete :destroy, :id => @repository.id
517 517 end
518 518 assert_response 302
519 519 @project.reload
520 520 assert_nil @project.repository
521 521 end
522 522 else
523 523 puts "Mercurial test repository NOT FOUND. Skipping functional tests !!!"
524 524 def test_fake; assert true end
525 525 end
526 526 end
General Comments 0
You need to be logged in to leave comments. Login now