##// END OF EJS Templates
Fixed undefined method `<=>' for nil:NilClass when sorting repositories with nil identifiers (#10827)....
Jean-Philippe Lang -
r9436:9f396a6dfbb9
parent child
Show More
@@ -1,397 +1,397
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2011 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 class ScmFetchError < Exception; end
19 19
20 20 class Repository < ActiveRecord::Base
21 21 include Redmine::Ciphering
22 22
23 23 belongs_to :project
24 24 has_many :changesets, :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC"
25 25 has_many :changes, :through => :changesets
26 26
27 27 serialize :extra_info
28 28
29 29 before_save :check_default
30 30
31 31 # Raw SQL to delete changesets and changes in the database
32 32 # has_many :changesets, :dependent => :destroy is too slow for big repositories
33 33 before_destroy :clear_changesets
34 34
35 35 validates_length_of :password, :maximum => 255, :allow_nil => true
36 36 validates_length_of :identifier, :maximum => 255, :allow_blank => true
37 37 validates_presence_of :identifier, :unless => Proc.new { |r| r.is_default? || r.set_as_default? }
38 38 validates_uniqueness_of :identifier, :scope => :project_id, :allow_blank => true
39 39 validates_exclusion_of :identifier, :in => %w(show entry raw changes annotate diff show stats graph)
40 40 # donwcase letters, digits, dashes but not digits only
41 41 validates_format_of :identifier, :with => /^(?!\d+$)[a-z0-9\-]*$/, :allow_blank => true
42 42 # Checks if the SCM is enabled when creating a repository
43 43 validate :repo_create_validation, :on => :create
44 44
45 45 def repo_create_validation
46 46 unless Setting.enabled_scm.include?(self.class.name.demodulize)
47 47 errors.add(:type, :invalid)
48 48 end
49 49 end
50 50
51 51 def self.human_attribute_name(attribute_key_name, *args)
52 52 attr_name = attribute_key_name.to_s
53 53 if attr_name == "log_encoding"
54 54 attr_name = "commit_logs_encoding"
55 55 end
56 56 super(attr_name, *args)
57 57 end
58 58
59 59 # Removes leading and trailing whitespace
60 60 def url=(arg)
61 61 write_attribute(:url, arg ? arg.to_s.strip : nil)
62 62 end
63 63
64 64 # Removes leading and trailing whitespace
65 65 def root_url=(arg)
66 66 write_attribute(:root_url, arg ? arg.to_s.strip : nil)
67 67 end
68 68
69 69 def password
70 70 read_ciphered_attribute(:password)
71 71 end
72 72
73 73 def password=(arg)
74 74 write_ciphered_attribute(:password, arg)
75 75 end
76 76
77 77 def scm_adapter
78 78 self.class.scm_adapter_class
79 79 end
80 80
81 81 def scm
82 82 unless @scm
83 83 @scm = self.scm_adapter.new(url, root_url,
84 84 login, password, path_encoding)
85 85 if root_url.blank? && @scm.root_url.present?
86 86 update_attribute(:root_url, @scm.root_url)
87 87 end
88 88 end
89 89 @scm
90 90 end
91 91
92 92 def scm_name
93 93 self.class.scm_name
94 94 end
95 95
96 96 def name
97 97 if identifier.present?
98 98 identifier
99 99 elsif is_default?
100 100 l(:field_repository_is_default)
101 101 else
102 102 scm_name
103 103 end
104 104 end
105 105
106 106 def identifier_param
107 107 if is_default?
108 108 nil
109 109 elsif identifier.present?
110 110 identifier
111 111 else
112 112 id.to_s
113 113 end
114 114 end
115 115
116 116 def <=>(repository)
117 117 if is_default?
118 118 -1
119 119 elsif repository.is_default?
120 120 1
121 121 else
122 identifier <=> repository.identifier
122 identifier.to_s <=> repository.identifier.to_s
123 123 end
124 124 end
125 125
126 126 def self.find_by_identifier_param(param)
127 127 if param.to_s =~ /^\d+$/
128 128 find_by_id(param)
129 129 else
130 130 find_by_identifier(param)
131 131 end
132 132 end
133 133
134 134 def merge_extra_info(arg)
135 135 h = extra_info || {}
136 136 return h if arg.nil?
137 137 h.merge!(arg)
138 138 write_attribute(:extra_info, h)
139 139 end
140 140
141 141 def report_last_commit
142 142 true
143 143 end
144 144
145 145 def supports_cat?
146 146 scm.supports_cat?
147 147 end
148 148
149 149 def supports_annotate?
150 150 scm.supports_annotate?
151 151 end
152 152
153 153 def supports_all_revisions?
154 154 true
155 155 end
156 156
157 157 def supports_directory_revisions?
158 158 false
159 159 end
160 160
161 161 def supports_revision_graph?
162 162 false
163 163 end
164 164
165 165 def entry(path=nil, identifier=nil)
166 166 scm.entry(path, identifier)
167 167 end
168 168
169 169 def entries(path=nil, identifier=nil)
170 170 scm.entries(path, identifier)
171 171 end
172 172
173 173 def branches
174 174 scm.branches
175 175 end
176 176
177 177 def tags
178 178 scm.tags
179 179 end
180 180
181 181 def default_branch
182 182 nil
183 183 end
184 184
185 185 def properties(path, identifier=nil)
186 186 scm.properties(path, identifier)
187 187 end
188 188
189 189 def cat(path, identifier=nil)
190 190 scm.cat(path, identifier)
191 191 end
192 192
193 193 def diff(path, rev, rev_to)
194 194 scm.diff(path, rev, rev_to)
195 195 end
196 196
197 197 def diff_format_revisions(cs, cs_to, sep=':')
198 198 text = ""
199 199 text << cs_to.format_identifier + sep if cs_to
200 200 text << cs.format_identifier if cs
201 201 text
202 202 end
203 203
204 204 # Returns a path relative to the url of the repository
205 205 def relative_path(path)
206 206 path
207 207 end
208 208
209 209 # Finds and returns a revision with a number or the beginning of a hash
210 210 def find_changeset_by_name(name)
211 211 return nil if name.blank?
212 212 s = name.to_s
213 213 changesets.find(:first, :conditions => (s.match(/^\d*$/) ?
214 214 ["revision = ?", s] : ["revision LIKE ?", s + '%']))
215 215 end
216 216
217 217 def latest_changeset
218 218 @latest_changeset ||= changesets.find(:first)
219 219 end
220 220
221 221 # Returns the latest changesets for +path+
222 222 # Default behaviour is to search in cached changesets
223 223 def latest_changesets(path, rev, limit=10)
224 224 if path.blank?
225 225 changesets.find(
226 226 :all,
227 227 :include => :user,
228 228 :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC",
229 229 :limit => limit)
230 230 else
231 231 changes.find(
232 232 :all,
233 233 :include => {:changeset => :user},
234 234 :conditions => ["path = ?", path.with_leading_slash],
235 235 :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC",
236 236 :limit => limit
237 237 ).collect(&:changeset)
238 238 end
239 239 end
240 240
241 241 def scan_changesets_for_issue_ids
242 242 self.changesets.each(&:scan_comment_for_issue_ids)
243 243 end
244 244
245 245 # Returns an array of committers usernames and associated user_id
246 246 def committers
247 247 @committers ||= Changeset.connection.select_rows(
248 248 "SELECT DISTINCT committer, user_id FROM #{Changeset.table_name} WHERE repository_id = #{id}")
249 249 end
250 250
251 251 # Maps committers username to a user ids
252 252 def committer_ids=(h)
253 253 if h.is_a?(Hash)
254 254 committers.each do |committer, user_id|
255 255 new_user_id = h[committer]
256 256 if new_user_id && (new_user_id.to_i != user_id.to_i)
257 257 new_user_id = (new_user_id.to_i > 0 ? new_user_id.to_i : nil)
258 258 Changeset.update_all(
259 259 "user_id = #{ new_user_id.nil? ? 'NULL' : new_user_id }",
260 260 ["repository_id = ? AND committer = ?", id, committer])
261 261 end
262 262 end
263 263 @committers = nil
264 264 @found_committer_users = nil
265 265 true
266 266 else
267 267 false
268 268 end
269 269 end
270 270
271 271 # Returns the Redmine User corresponding to the given +committer+
272 272 # It will return nil if the committer is not yet mapped and if no User
273 273 # with the same username or email was found
274 274 def find_committer_user(committer)
275 275 unless committer.blank?
276 276 @found_committer_users ||= {}
277 277 return @found_committer_users[committer] if @found_committer_users.has_key?(committer)
278 278
279 279 user = nil
280 280 c = changesets.find(:first, :conditions => {:committer => committer}, :include => :user)
281 281 if c && c.user
282 282 user = c.user
283 283 elsif committer.strip =~ /^([^<]+)(<(.*)>)?$/
284 284 username, email = $1.strip, $3
285 285 u = User.find_by_login(username)
286 286 u ||= User.find_by_mail(email) unless email.blank?
287 287 user = u
288 288 end
289 289 @found_committer_users[committer] = user
290 290 user
291 291 end
292 292 end
293 293
294 294 def repo_log_encoding
295 295 encoding = log_encoding.to_s.strip
296 296 encoding.blank? ? 'UTF-8' : encoding
297 297 end
298 298
299 299 # Fetches new changesets for all repositories of active projects
300 300 # Can be called periodically by an external script
301 301 # eg. ruby script/runner "Repository.fetch_changesets"
302 302 def self.fetch_changesets
303 303 Project.active.has_module(:repository).all.each do |project|
304 304 project.repositories.each do |repository|
305 305 begin
306 306 repository.fetch_changesets
307 307 rescue Redmine::Scm::Adapters::CommandFailed => e
308 308 logger.error "scm: error during fetching changesets: #{e.message}"
309 309 end
310 310 end
311 311 end
312 312 end
313 313
314 314 # scan changeset comments to find related and fixed issues for all repositories
315 315 def self.scan_changesets_for_issue_ids
316 316 find(:all).each(&:scan_changesets_for_issue_ids)
317 317 end
318 318
319 319 def self.scm_name
320 320 'Abstract'
321 321 end
322 322
323 323 def self.available_scm
324 324 subclasses.collect {|klass| [klass.scm_name, klass.name]}
325 325 end
326 326
327 327 def self.factory(klass_name, *args)
328 328 klass = "Repository::#{klass_name}".constantize
329 329 klass.new(*args)
330 330 rescue
331 331 nil
332 332 end
333 333
334 334 def self.scm_adapter_class
335 335 nil
336 336 end
337 337
338 338 def self.scm_command
339 339 ret = ""
340 340 begin
341 341 ret = self.scm_adapter_class.client_command if self.scm_adapter_class
342 342 rescue Exception => e
343 343 logger.error "scm: error during get command: #{e.message}"
344 344 end
345 345 ret
346 346 end
347 347
348 348 def self.scm_version_string
349 349 ret = ""
350 350 begin
351 351 ret = self.scm_adapter_class.client_version_string if self.scm_adapter_class
352 352 rescue Exception => e
353 353 logger.error "scm: error during get version string: #{e.message}"
354 354 end
355 355 ret
356 356 end
357 357
358 358 def self.scm_available
359 359 ret = false
360 360 begin
361 361 ret = self.scm_adapter_class.client_available if self.scm_adapter_class
362 362 rescue Exception => e
363 363 logger.error "scm: error during get scm available: #{e.message}"
364 364 end
365 365 ret
366 366 end
367 367
368 368 def set_as_default?
369 369 new_record? && project && !Repository.first(:conditions => {:project_id => project.id})
370 370 end
371 371
372 372 protected
373 373
374 374 def check_default
375 375 if !is_default? && set_as_default?
376 376 self.is_default = true
377 377 end
378 378 if is_default? && is_default_changed?
379 379 Repository.update_all(["is_default = ?", false], ["project_id = ?", project_id])
380 380 end
381 381 end
382 382
383 383 private
384 384
385 385 # Deletes repository data
386 386 def clear_changesets
387 387 cs = Changeset.table_name
388 388 ch = Change.table_name
389 389 ci = "#{table_name_prefix}changesets_issues#{table_name_suffix}"
390 390 cp = "#{table_name_prefix}changeset_parents#{table_name_suffix}"
391 391
392 392 connection.delete("DELETE FROM #{ch} WHERE #{ch}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
393 393 connection.delete("DELETE FROM #{ci} WHERE #{ci}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
394 394 connection.delete("DELETE FROM #{cp} WHERE #{cp}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
395 395 connection.delete("DELETE FROM #{cs} WHERE #{cs}.repository_id = #{id}")
396 396 end
397 397 end
@@ -1,321 +1,330
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2011 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 RepositoryTest < ActiveSupport::TestCase
21 21 fixtures :projects,
22 22 :trackers,
23 23 :projects_trackers,
24 24 :enabled_modules,
25 25 :repositories,
26 26 :issues,
27 27 :issue_statuses,
28 28 :issue_categories,
29 29 :changesets,
30 30 :changes,
31 31 :users,
32 32 :members,
33 33 :member_roles,
34 34 :roles,
35 35 :enumerations
36 36
37 37 include Redmine::I18n
38 38
39 39 def setup
40 40 @repository = Project.find(1).repository
41 41 end
42 42
43 43 def test_blank_log_encoding_error_message
44 44 set_language_if_valid 'en'
45 45 repo = Repository::Bazaar.new(
46 46 :project => Project.find(3),
47 47 :url => "/test",
48 48 :log_encoding => ''
49 49 )
50 50 assert !repo.save
51 51 assert_include "Commit messages encoding can't be blank",
52 52 repo.errors.full_messages
53 53 end
54 54
55 55 def test_blank_log_encoding_error_message_fr
56 56 set_language_if_valid 'fr'
57 57 str = "Encodage des messages de commit doit \xc3\xaatre renseign\xc3\xa9(e)"
58 58 str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
59 59 repo = Repository::Bazaar.new(
60 60 :project => Project.find(3),
61 61 :url => "/test"
62 62 )
63 63 assert !repo.save
64 64 assert_include str, repo.errors.full_messages
65 65 end
66 66
67 67 def test_create
68 68 repository = Repository::Subversion.new(:project => Project.find(3))
69 69 assert !repository.save
70 70
71 71 repository.url = "svn://localhost"
72 72 assert repository.save
73 73 repository.reload
74 74
75 75 project = Project.find(3)
76 76 assert_equal repository, project.repository
77 77 end
78 78
79 79 def test_first_repository_should_be_set_as_default
80 80 repository1 = Repository::Subversion.new(
81 81 :project => Project.find(3),
82 82 :identifier => 'svn1',
83 83 :url => 'file:///svn1'
84 84 )
85 85 assert repository1.save
86 86 assert repository1.is_default?
87 87
88 88 repository2 = Repository::Subversion.new(
89 89 :project => Project.find(3),
90 90 :identifier => 'svn2',
91 91 :url => 'file:///svn2'
92 92 )
93 93 assert repository2.save
94 94 assert !repository2.is_default?
95 95
96 96 assert_equal repository1, Project.find(3).repository
97 97 assert_equal [repository1, repository2], Project.find(3).repositories.sort
98 98 end
99 99
100 100 def test_destroy
101 101 changesets = Changeset.count(:all, :conditions => "repository_id = 10")
102 102 changes = Change.count(:all, :conditions => "repository_id = 10",
103 103 :joins => :changeset)
104 104 assert_difference 'Changeset.count', -changesets do
105 105 assert_difference 'Change.count', -changes do
106 106 Repository.find(10).destroy
107 107 end
108 108 end
109 109 end
110 110
111 111 def test_destroy_should_delete_parents_associations
112 112 changeset = Changeset.find(102)
113 113 changeset.parents = Changeset.find_all_by_id([100, 101])
114 114
115 115 assert_difference 'Changeset.connection.select_all("select * from changeset_parents").size', -2 do
116 116 Repository.find(10).destroy
117 117 end
118 118 end
119 119
120 120 def test_destroy_should_delete_issues_associations
121 121 changeset = Changeset.find(102)
122 122 changeset.issues = Issue.find_all_by_id([1, 2])
123 123
124 124 assert_difference 'Changeset.connection.select_all("select * from changesets_issues").size', -2 do
125 125 Repository.find(10).destroy
126 126 end
127 127 end
128 128
129 129 def test_should_not_create_with_disabled_scm
130 130 # disable Subversion
131 131 with_settings :enabled_scm => ['Darcs', 'Git'] do
132 132 repository = Repository::Subversion.new(
133 133 :project => Project.find(3), :url => "svn://localhost")
134 134 assert !repository.save
135 135 assert_include I18n.translate('activerecord.errors.messages.invalid'),
136 136 repository.errors[:type]
137 137 end
138 138 end
139 139
140 140 def test_scan_changesets_for_issue_ids
141 141 Setting.default_language = 'en'
142 142 Setting.notified_events = ['issue_added','issue_updated']
143 143
144 144 # choosing a status to apply to fix issues
145 145 Setting.commit_fix_status_id = IssueStatus.find(
146 146 :first,
147 147 :conditions => ["is_closed = ?", true]).id
148 148 Setting.commit_fix_done_ratio = "90"
149 149 Setting.commit_ref_keywords = 'refs , references, IssueID'
150 150 Setting.commit_fix_keywords = 'fixes , closes'
151 151 Setting.default_language = 'en'
152 152 ActionMailer::Base.deliveries.clear
153 153
154 154 # make sure issue 1 is not already closed
155 155 fixed_issue = Issue.find(1)
156 156 assert !fixed_issue.status.is_closed?
157 157 old_status = fixed_issue.status
158 158
159 159 Repository.scan_changesets_for_issue_ids
160 160 assert_equal [101, 102], Issue.find(3).changeset_ids
161 161
162 162 # fixed issues
163 163 fixed_issue.reload
164 164 assert fixed_issue.status.is_closed?
165 165 assert_equal 90, fixed_issue.done_ratio
166 166 assert_equal [101], fixed_issue.changeset_ids
167 167
168 168 # issue change
169 169 journal = fixed_issue.journals.find(:first, :order => 'created_on desc')
170 170 assert_equal User.find_by_login('dlopper'), journal.user
171 171 assert_equal 'Applied in changeset r2.', journal.notes
172 172
173 173 # 2 email notifications
174 174 assert_equal 2, ActionMailer::Base.deliveries.size
175 175 mail = ActionMailer::Base.deliveries.first
176 176 assert_not_nil mail
177 177 assert mail.subject.starts_with?(
178 178 "[#{fixed_issue.project.name} - #{fixed_issue.tracker.name} ##{fixed_issue.id}]")
179 179 assert_mail_body_match(
180 180 "Status changed from #{old_status} to #{fixed_issue.status}", mail)
181 181
182 182 # ignoring commits referencing an issue of another project
183 183 assert_equal [], Issue.find(4).changesets
184 184 end
185 185
186 186 def test_for_changeset_comments_strip
187 187 repository = Repository::Mercurial.create(
188 188 :project => Project.find( 4 ),
189 189 :url => '/foo/bar/baz' )
190 190 comment = <<-COMMENT
191 191 This is a loooooooooooooooooooooooooooong comment
192 192
193 193
194 194 COMMENT
195 195 changeset = Changeset.new(
196 196 :comments => comment, :commit_date => Time.now,
197 197 :revision => 0, :scmid => 'f39b7922fb3c',
198 198 :committer => 'foo <foo@example.com>',
199 199 :committed_on => Time.now, :repository => repository )
200 200 assert( changeset.save )
201 201 assert_not_equal( comment, changeset.comments )
202 202 assert_equal( 'This is a loooooooooooooooooooooooooooong comment',
203 203 changeset.comments )
204 204 end
205 205
206 206 def test_for_urls_strip_cvs
207 207 repository = Repository::Cvs.create(
208 208 :project => Project.find(4),
209 209 :url => ' :pserver:login:password@host:/path/to/the/repository',
210 210 :root_url => 'foo ',
211 211 :log_encoding => 'UTF-8')
212 212 assert repository.save
213 213 repository.reload
214 214 assert_equal ':pserver:login:password@host:/path/to/the/repository',
215 215 repository.url
216 216 assert_equal 'foo', repository.root_url
217 217 end
218 218
219 219 def test_for_urls_strip_subversion
220 220 repository = Repository::Subversion.create(
221 221 :project => Project.find(4),
222 222 :url => ' file:///dummy ')
223 223 assert repository.save
224 224 repository.reload
225 225 assert_equal 'file:///dummy', repository.url
226 226 end
227 227
228 228 def test_for_urls_strip_git
229 229 repository = Repository::Git.create(
230 230 :project => Project.find(4),
231 231 :url => ' c:\dummy ')
232 232 assert repository.save
233 233 repository.reload
234 234 assert_equal 'c:\dummy', repository.url
235 235 end
236 236
237 237 def test_manual_user_mapping
238 238 assert_no_difference "Changeset.count(:conditions => 'user_id <> 2')" do
239 239 c = Changeset.create!(
240 240 :repository => @repository,
241 241 :committer => 'foo',
242 242 :committed_on => Time.now,
243 243 :revision => 100,
244 244 :comments => 'Committed by foo.'
245 245 )
246 246 assert_nil c.user
247 247 @repository.committer_ids = {'foo' => '2'}
248 248 assert_equal User.find(2), c.reload.user
249 249 # committer is now mapped
250 250 c = Changeset.create!(
251 251 :repository => @repository,
252 252 :committer => 'foo',
253 253 :committed_on => Time.now,
254 254 :revision => 101,
255 255 :comments => 'Another commit by foo.'
256 256 )
257 257 assert_equal User.find(2), c.user
258 258 end
259 259 end
260 260
261 261 def test_auto_user_mapping_by_username
262 262 c = Changeset.create!(
263 263 :repository => @repository,
264 264 :committer => 'jsmith',
265 265 :committed_on => Time.now,
266 266 :revision => 100,
267 267 :comments => 'Committed by john.'
268 268 )
269 269 assert_equal User.find(2), c.user
270 270 end
271 271
272 272 def test_auto_user_mapping_by_email
273 273 c = Changeset.create!(
274 274 :repository => @repository,
275 275 :committer => 'john <jsmith@somenet.foo>',
276 276 :committed_on => Time.now,
277 277 :revision => 100,
278 278 :comments => 'Committed by john.'
279 279 )
280 280 assert_equal User.find(2), c.user
281 281 end
282 282
283 283 def test_filesystem_avaialbe
284 284 klass = Repository::Filesystem
285 285 assert klass.scm_adapter_class
286 286 assert_equal true, klass.scm_available
287 287 end
288 288
289 289 def test_merge_extra_info
290 290 repo = Repository::Subversion.new(:project => Project.find(3))
291 291 assert !repo.save
292 292 repo.url = "svn://localhost"
293 293 assert repo.save
294 294 repo.reload
295 295 project = Project.find(3)
296 296 assert_equal repo, project.repository
297 297 assert_nil repo.extra_info
298 298 h1 = {"test_1" => {"test_11" => "test_value_11"}}
299 299 repo.merge_extra_info(h1)
300 300 assert_equal h1, repo.extra_info
301 301 h2 = {"test_2" => {
302 302 "test_21" => "test_value_21",
303 303 "test_22" => "test_value_22",
304 304 }}
305 305 repo.merge_extra_info(h2)
306 306 assert_equal (h = {"test_11" => "test_value_11"}),
307 307 repo.extra_info["test_1"]
308 308 assert_equal "test_value_21",
309 309 repo.extra_info["test_2"]["test_21"]
310 310 h3 = {"test_2" => {
311 311 "test_23" => "test_value_23",
312 312 "test_24" => "test_value_24",
313 313 }}
314 314 repo.merge_extra_info(h3)
315 315 assert_equal (h = {"test_11" => "test_value_11"}),
316 316 repo.extra_info["test_1"]
317 317 assert_nil repo.extra_info["test_2"]["test_21"]
318 318 assert_equal "test_value_23",
319 319 repo.extra_info["test_2"]["test_23"]
320 320 end
321
322 def test_sort_should_not_raise_an_error_with_nil_identifiers
323 r1 = Repository.new
324 r2 = Repository.new
325
326 assert_nothing_raised do
327 [r1, r2].sort
328 end
329 end
321 330 end
General Comments 0
You need to be logged in to leave comments. Login now