##// END OF EJS Templates
Merged r8917 from trunk....
Jean-Philippe Lang -
r8997:41dba6864aa0
parent child
Show More
@@ -1,269 +1,273
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 'iconv'
19 19
20 20 class Changeset < ActiveRecord::Base
21 21 belongs_to :repository
22 22 belongs_to :user
23 23 has_many :changes, :dependent => :delete_all
24 24 has_and_belongs_to_many :issues
25 25 has_and_belongs_to_many :parents,
26 26 :class_name => "Changeset",
27 27 :join_table => "#{table_name_prefix}changeset_parents#{table_name_suffix}",
28 28 :association_foreign_key => 'parent_id', :foreign_key => 'changeset_id'
29 29 has_and_belongs_to_many :children,
30 30 :class_name => "Changeset",
31 31 :join_table => "#{table_name_prefix}changeset_parents#{table_name_suffix}",
32 32 :association_foreign_key => 'changeset_id', :foreign_key => 'parent_id'
33 33
34 34 acts_as_event :title => Proc.new {|o| "#{l(:label_revision)} #{o.format_identifier}" + (o.short_comments.blank? ? '' : (': ' + o.short_comments))},
35 35 :description => :long_comments,
36 36 :datetime => :committed_on,
37 37 :url => Proc.new {|o| {:controller => 'repositories', :action => 'revision', :id => o.repository.project, :rev => o.identifier}}
38 38
39 39 acts_as_searchable :columns => 'comments',
40 40 :include => {:repository => :project},
41 41 :project_key => "#{Repository.table_name}.project_id",
42 42 :date_column => 'committed_on'
43 43
44 44 acts_as_activity_provider :timestamp => "#{table_name}.committed_on",
45 45 :author_key => :user_id,
46 46 :find_options => {:include => [:user, {:repository => :project}]}
47 47
48 48 validates_presence_of :repository_id, :revision, :committed_on, :commit_date
49 49 validates_uniqueness_of :revision, :scope => :repository_id
50 50 validates_uniqueness_of :scmid, :scope => :repository_id, :allow_nil => true
51 51
52 52 named_scope :visible, lambda {|*args| { :include => {:repository => :project},
53 53 :conditions => Project.allowed_to_condition(args.shift || User.current, :view_changesets, *args) } }
54 54
55 55 after_create :scan_for_issues
56 56 before_create :before_create_cs
57 57
58 58 def revision=(r)
59 59 write_attribute :revision, (r.nil? ? nil : r.to_s)
60 60 end
61 61
62 62 # Returns the identifier of this changeset; depending on repository backends
63 63 def identifier
64 64 if repository.class.respond_to? :changeset_identifier
65 65 repository.class.changeset_identifier self
66 66 else
67 67 revision.to_s
68 68 end
69 69 end
70 70
71 71 def committed_on=(date)
72 72 self.commit_date = date
73 73 super
74 74 end
75 75
76 76 # Returns the readable identifier
77 77 def format_identifier
78 78 if repository.class.respond_to? :format_changeset_identifier
79 79 repository.class.format_changeset_identifier self
80 80 else
81 81 identifier
82 82 end
83 83 end
84 84
85 85 def project
86 86 repository.project
87 87 end
88 88
89 89 def author
90 90 user || committer.to_s.split('<').first
91 91 end
92 92
93 93 def before_create_cs
94 94 self.committer = self.class.to_utf8(self.committer, repository.repo_log_encoding)
95 95 self.comments = self.class.normalize_comments(
96 96 self.comments, repository.repo_log_encoding)
97 97 self.user = repository.find_committer_user(self.committer)
98 98 end
99 99
100 100 def scan_for_issues
101 101 scan_comment_for_issue_ids
102 102 end
103 103
104 104 TIMELOG_RE = /
105 105 (
106 106 ((\d+)(h|hours?))((\d+)(m|min)?)?
107 107 |
108 108 ((\d+)(h|hours?|m|min))
109 109 |
110 110 (\d+):(\d+)
111 111 |
112 112 (\d+([\.,]\d+)?)h?
113 113 )
114 114 /x
115 115
116 116 def scan_comment_for_issue_ids
117 117 return if comments.blank?
118 118 # keywords used to reference issues
119 119 ref_keywords = Setting.commit_ref_keywords.downcase.split(",").collect(&:strip)
120 120 ref_keywords_any = ref_keywords.delete('*')
121 121 # keywords used to fix issues
122 122 fix_keywords = Setting.commit_fix_keywords.downcase.split(",").collect(&:strip)
123 123
124 124 kw_regexp = (ref_keywords + fix_keywords).collect{|kw| Regexp.escape(kw)}.join("|")
125 125
126 126 referenced_issues = []
127 127
128 128 comments.scan(/([\s\(\[,-]|^)((#{kw_regexp})[\s:]+)?(#\d+(\s+@#{TIMELOG_RE})?([\s,;&]+#\d+(\s+@#{TIMELOG_RE})?)*)(?=[[:punct:]]|\s|<|$)/i) do |match|
129 129 action, refs = match[2], match[3]
130 130 next unless action.present? || ref_keywords_any
131 131
132 132 refs.scan(/#(\d+)(\s+@#{TIMELOG_RE})?/).each do |m|
133 133 issue, hours = find_referenced_issue_by_id(m[0].to_i), m[2]
134 134 if issue
135 135 referenced_issues << issue
136 136 fix_issue(issue) if fix_keywords.include?(action.to_s.downcase)
137 137 log_time(issue, hours) if hours && Setting.commit_logtime_enabled?
138 138 end
139 139 end
140 140 end
141 141
142 142 referenced_issues.uniq!
143 143 self.issues = referenced_issues unless referenced_issues.empty?
144 144 end
145 145
146 146 def short_comments
147 147 @short_comments || split_comments.first
148 148 end
149 149
150 150 def long_comments
151 151 @long_comments || split_comments.last
152 152 end
153 153
154 def text_tag
155 if scmid?
154 def text_tag(ref_project=nil)
155 tag = if scmid?
156 156 "commit:#{scmid}"
157 157 else
158 158 "r#{revision}"
159 159 end
160 if ref_project && project && ref_project != project
161 tag = "#{project.identifier}:#{tag}"
162 end
163 tag
160 164 end
161 165
162 166 # Returns the previous changeset
163 167 def previous
164 168 @previous ||= Changeset.find(:first,
165 169 :conditions => ['id < ? AND repository_id = ?',
166 170 self.id, self.repository_id],
167 171 :order => 'id DESC')
168 172 end
169 173
170 174 # Returns the next changeset
171 175 def next
172 176 @next ||= Changeset.find(:first,
173 177 :conditions => ['id > ? AND repository_id = ?',
174 178 self.id, self.repository_id],
175 179 :order => 'id ASC')
176 180 end
177 181
178 182 # Creates a new Change from it's common parameters
179 183 def create_change(change)
180 184 Change.create(:changeset => self,
181 185 :action => change[:action],
182 186 :path => change[:path],
183 187 :from_path => change[:from_path],
184 188 :from_revision => change[:from_revision])
185 189 end
186 190
187 191 private
188 192
189 193 # Finds an issue that can be referenced by the commit message
190 194 # i.e. an issue that belong to the repository project, a subproject or a parent project
191 195 def find_referenced_issue_by_id(id)
192 196 return nil if id.blank?
193 197 issue = Issue.find_by_id(id.to_i, :include => :project)
194 198 if issue
195 199 unless issue.project &&
196 200 (project == issue.project || project.is_ancestor_of?(issue.project) ||
197 201 project.is_descendant_of?(issue.project))
198 202 issue = nil
199 203 end
200 204 end
201 205 issue
202 206 end
203 207
204 208 def fix_issue(issue)
205 209 status = IssueStatus.find_by_id(Setting.commit_fix_status_id.to_i)
206 210 if status.nil?
207 211 logger.warn("No status matches commit_fix_status_id setting (#{Setting.commit_fix_status_id})") if logger
208 212 return issue
209 213 end
210 214
211 215 # the issue may have been updated by the closure of another one (eg. duplicate)
212 216 issue.reload
213 217 # don't change the status is the issue is closed
214 218 return if issue.status && issue.status.is_closed?
215 219
216 journal = issue.init_journal(user || User.anonymous, ll(Setting.default_language, :text_status_changed_by_changeset, text_tag))
220 journal = issue.init_journal(user || User.anonymous, ll(Setting.default_language, :text_status_changed_by_changeset, text_tag(issue.project)))
217 221 issue.status = status
218 222 unless Setting.commit_fix_done_ratio.blank?
219 223 issue.done_ratio = Setting.commit_fix_done_ratio.to_i
220 224 end
221 225 Redmine::Hook.call_hook(:model_changeset_scan_commit_for_issue_ids_pre_issue_update,
222 226 { :changeset => self, :issue => issue })
223 227 unless issue.save
224 228 logger.warn("Issue ##{issue.id} could not be saved by changeset #{id}: #{issue.errors.full_messages}") if logger
225 229 end
226 230 issue
227 231 end
228 232
229 233 def log_time(issue, hours)
230 234 time_entry = TimeEntry.new(
231 235 :user => user,
232 236 :hours => hours,
233 237 :issue => issue,
234 238 :spent_on => commit_date,
235 :comments => l(:text_time_logged_by_changeset, :value => text_tag,
239 :comments => l(:text_time_logged_by_changeset, :value => text_tag(issue.project),
236 240 :locale => Setting.default_language)
237 241 )
238 242 time_entry.activity = log_time_activity unless log_time_activity.nil?
239 243
240 244 unless time_entry.save
241 245 logger.warn("TimeEntry could not be created by changeset #{id}: #{time_entry.errors.full_messages}") if logger
242 246 end
243 247 time_entry
244 248 end
245 249
246 250 def log_time_activity
247 251 if Setting.commit_logtime_activity_id.to_i > 0
248 252 TimeEntryActivity.find_by_id(Setting.commit_logtime_activity_id.to_i)
249 253 end
250 254 end
251 255
252 256 def split_comments
253 257 comments =~ /\A(.+?)\r?\n(.*)$/m
254 258 @short_comments = $1 || comments
255 259 @long_comments = $2.to_s.strip
256 260 return @short_comments, @long_comments
257 261 end
258 262
259 263 public
260 264
261 265 # Strips and reencodes a commit log before insertion into the database
262 266 def self.normalize_comments(str, encoding)
263 267 Changeset.to_utf8(str.to_s.strip, encoding)
264 268 end
265 269
266 270 def self.to_utf8(str, encoding)
267 271 Redmine::CodesetUtil.to_utf8(str, encoding)
268 272 end
269 273 end
@@ -1,399 +1,437
1 1 # encoding: utf-8
2 2 #
3 3 # Redmine - project management software
4 4 # Copyright (C) 2006-2011 Jean-Philippe Lang
5 5 #
6 6 # This program is free software; you can redistribute it and/or
7 7 # modify it under the terms of the GNU General Public License
8 8 # as published by the Free Software Foundation; either version 2
9 9 # of the License, or (at your option) any later version.
10 10 #
11 11 # This program is distributed in the hope that it will be useful,
12 12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 14 # GNU General Public License for more details.
15 15 #
16 16 # You should have received a copy of the GNU General Public License
17 17 # along with this program; if not, write to the Free Software
18 18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 19
20 20 require File.expand_path('../../test_helper', __FILE__)
21 21
22 22 class ChangesetTest < ActiveSupport::TestCase
23 23 fixtures :projects, :repositories,
24 24 :issues, :issue_statuses, :issue_categories,
25 25 :changesets, :changes,
26 26 :enumerations,
27 27 :custom_fields, :custom_values,
28 28 :users, :members, :member_roles, :trackers,
29 29 :enabled_modules, :roles
30 30
31 31 def setup
32 32 end
33 33
34 34 def test_ref_keywords_any
35 35 ActionMailer::Base.deliveries.clear
36 36 Setting.commit_fix_status_id = IssueStatus.find(
37 37 :first, :conditions => ["is_closed = ?", true]).id
38 38 Setting.commit_fix_done_ratio = '90'
39 39 Setting.commit_ref_keywords = '*'
40 40 Setting.commit_fix_keywords = 'fixes , closes'
41 41
42 42 c = Changeset.new(:repository => Project.find(1).repository,
43 43 :committed_on => Time.now,
44 44 :comments => 'New commit (#2). Fixes #1',
45 45 :revision => '12345')
46 46 assert c.save
47 47 assert_equal [1, 2], c.issue_ids.sort
48 48 fixed = Issue.find(1)
49 49 assert fixed.closed?
50 50 assert_equal 90, fixed.done_ratio
51 51 assert_equal 1, ActionMailer::Base.deliveries.size
52 52 end
53 53
54 54 def test_ref_keywords
55 55 Setting.commit_ref_keywords = 'refs'
56 56 Setting.commit_fix_keywords = ''
57 57 c = Changeset.new(:repository => Project.find(1).repository,
58 58 :committed_on => Time.now,
59 59 :comments => 'Ignores #2. Refs #1',
60 60 :revision => '12345')
61 61 assert c.save
62 62 assert_equal [1], c.issue_ids.sort
63 63 end
64 64
65 65 def test_ref_keywords_any_only
66 66 Setting.commit_ref_keywords = '*'
67 67 Setting.commit_fix_keywords = ''
68 68 c = Changeset.new(:repository => Project.find(1).repository,
69 69 :committed_on => Time.now,
70 70 :comments => 'Ignores #2. Refs #1',
71 71 :revision => '12345')
72 72 assert c.save
73 73 assert_equal [1, 2], c.issue_ids.sort
74 74 end
75 75
76 76 def test_ref_keywords_any_with_timelog
77 77 Setting.commit_ref_keywords = '*'
78 78 Setting.commit_logtime_enabled = '1'
79 79
80 80 {
81 81 '2' => 2.0,
82 82 '2h' => 2.0,
83 83 '2hours' => 2.0,
84 84 '15m' => 0.25,
85 85 '15min' => 0.25,
86 86 '3h15' => 3.25,
87 87 '3h15m' => 3.25,
88 88 '3h15min' => 3.25,
89 89 '3:15' => 3.25,
90 90 '3.25' => 3.25,
91 91 '3.25h' => 3.25,
92 92 '3,25' => 3.25,
93 93 '3,25h' => 3.25,
94 94 }.each do |syntax, expected_hours|
95 95 c = Changeset.new(:repository => Project.find(1).repository,
96 96 :committed_on => 24.hours.ago,
97 97 :comments => "Worked on this issue #1 @#{syntax}",
98 98 :revision => '520',
99 99 :user => User.find(2))
100 100 assert_difference 'TimeEntry.count' do
101 101 c.scan_comment_for_issue_ids
102 102 end
103 103 assert_equal [1], c.issue_ids.sort
104 104
105 105 time = TimeEntry.first(:order => 'id desc')
106 106 assert_equal 1, time.issue_id
107 107 assert_equal 1, time.project_id
108 108 assert_equal 2, time.user_id
109 109 assert_equal expected_hours, time.hours,
110 110 "@#{syntax} should be logged as #{expected_hours} hours but was #{time.hours}"
111 111 assert_equal Date.yesterday, time.spent_on
112 112 assert time.activity.is_default?
113 113 assert time.comments.include?('r520'),
114 114 "r520 was expected in time_entry comments: #{time.comments}"
115 115 end
116 116 end
117 117
118 118 def test_ref_keywords_closing_with_timelog
119 119 Setting.commit_fix_status_id = IssueStatus.find(
120 120 :first, :conditions => ["is_closed = ?", true]).id
121 121 Setting.commit_ref_keywords = '*'
122 122 Setting.commit_fix_keywords = 'fixes , closes'
123 123 Setting.commit_logtime_enabled = '1'
124 124
125 125 c = Changeset.new(:repository => Project.find(1).repository,
126 126 :committed_on => Time.now,
127 127 :comments => 'This is a comment. Fixes #1 @4.5, #2 @1',
128 128 :user => User.find(2))
129 129 assert_difference 'TimeEntry.count', 2 do
130 130 c.scan_comment_for_issue_ids
131 131 end
132 132
133 133 assert_equal [1, 2], c.issue_ids.sort
134 134 assert Issue.find(1).closed?
135 135 assert Issue.find(2).closed?
136 136
137 137 times = TimeEntry.all(:order => 'id desc', :limit => 2)
138 138 assert_equal [1, 2], times.collect(&:issue_id).sort
139 139 end
140 140
141 141 def test_ref_keywords_any_line_start
142 142 Setting.commit_ref_keywords = '*'
143 143 c = Changeset.new(:repository => Project.find(1).repository,
144 144 :committed_on => Time.now,
145 145 :comments => '#1 is the reason of this commit',
146 146 :revision => '12345')
147 147 assert c.save
148 148 assert_equal [1], c.issue_ids.sort
149 149 end
150 150
151 151 def test_ref_keywords_allow_brackets_around_a_issue_number
152 152 Setting.commit_ref_keywords = '*'
153 153 c = Changeset.new(:repository => Project.find(1).repository,
154 154 :committed_on => Time.now,
155 155 :comments => '[#1] Worked on this issue',
156 156 :revision => '12345')
157 157 assert c.save
158 158 assert_equal [1], c.issue_ids.sort
159 159 end
160 160
161 161 def test_ref_keywords_allow_brackets_around_multiple_issue_numbers
162 162 Setting.commit_ref_keywords = '*'
163 163 c = Changeset.new(:repository => Project.find(1).repository,
164 164 :committed_on => Time.now,
165 165 :comments => '[#1 #2, #3] Worked on these',
166 166 :revision => '12345')
167 167 assert c.save
168 168 assert_equal [1,2,3], c.issue_ids.sort
169 169 end
170 170
171 171 def test_commit_referencing_a_subproject_issue
172 172 c = Changeset.new(:repository => Project.find(1).repository,
173 173 :committed_on => Time.now,
174 174 :comments => 'refs #5, a subproject issue',
175 175 :revision => '12345')
176 176 assert c.save
177 177 assert_equal [5], c.issue_ids.sort
178 178 assert c.issues.first.project != c.project
179 179 end
180 180
181 def test_commit_closing_a_subproject_issue
182 with_settings :commit_fix_status_id => 5, :commit_fix_keywords => 'closes' do
183 issue = Issue.find(5)
184 assert !issue.closed?
185 assert_difference 'Journal.count' do
186 c = Changeset.new(:repository => Project.find(1).repository,
187 :committed_on => Time.now,
188 :comments => 'closes #5, a subproject issue',
189 :revision => '12345')
190 assert c.save
191 end
192 assert issue.reload.closed?
193 journal = Journal.first(:order => 'id DESC')
194 assert_equal issue, journal.issue
195 assert_include "Applied in changeset ecookbook:r12345.", journal.notes
196 end
197 end
198
181 199 def test_commit_referencing_a_parent_project_issue
182 200 # repository of child project
183 201 r = Repository::Subversion.create!(
184 202 :project => Project.find(3),
185 203 :url => 'svn://localhost/test')
186 204 c = Changeset.new(:repository => r,
187 205 :committed_on => Time.now,
188 206 :comments => 'refs #2, an issue of a parent project',
189 207 :revision => '12345')
190 208 assert c.save
191 209 assert_equal [2], c.issue_ids.sort
192 210 assert c.issues.first.project != c.project
193 211 end
194 212
195 213 def test_text_tag_revision
196 214 c = Changeset.new(:revision => '520')
197 215 assert_equal 'r520', c.text_tag
198 216 end
199 217
218 def test_text_tag_revision_with_same_project
219 c = Changeset.new(:revision => '520', :repository => Project.find(1).repository)
220 assert_equal 'r520', c.text_tag(Project.find(1))
221 end
222
223 def test_text_tag_revision_with_different_project
224 c = Changeset.new(:revision => '520', :repository => Project.find(1).repository)
225 assert_equal 'ecookbook:r520', c.text_tag(Project.find(2))
226 end
227
200 228 def test_text_tag_hash
201 229 c = Changeset.new(
202 230 :scmid => '7234cb2750b63f47bff735edc50a1c0a433c2518',
203 231 :revision => '7234cb2750b63f47bff735edc50a1c0a433c2518')
204 232 assert_equal 'commit:7234cb2750b63f47bff735edc50a1c0a433c2518', c.text_tag
205 233 end
206 234
235 def test_text_tag_hash_with_same_project
236 c = Changeset.new(:revision => '7234cb27', :scmid => '7234cb27', :repository => Project.find(1).repository)
237 assert_equal 'commit:7234cb27', c.text_tag(Project.find(1))
238 end
239
240 def test_text_tag_hash_with_different_project
241 c = Changeset.new(:revision => '7234cb27', :scmid => '7234cb27', :repository => Project.find(1).repository)
242 assert_equal 'ecookbook:commit:7234cb27', c.text_tag(Project.find(2))
243 end
244
207 245 def test_text_tag_hash_all_number
208 246 c = Changeset.new(:scmid => '0123456789', :revision => '0123456789')
209 247 assert_equal 'commit:0123456789', c.text_tag
210 248 end
211 249
212 250 def test_previous
213 251 changeset = Changeset.find_by_revision('3')
214 252 assert_equal Changeset.find_by_revision('2'), changeset.previous
215 253 end
216 254
217 255 def test_previous_nil
218 256 changeset = Changeset.find_by_revision('1')
219 257 assert_nil changeset.previous
220 258 end
221 259
222 260 def test_next
223 261 changeset = Changeset.find_by_revision('2')
224 262 assert_equal Changeset.find_by_revision('3'), changeset.next
225 263 end
226 264
227 265 def test_next_nil
228 266 changeset = Changeset.find_by_revision('10')
229 267 assert_nil changeset.next
230 268 end
231 269
232 270 def test_comments_should_be_converted_to_utf8
233 271 proj = Project.find(3)
234 272 # str = File.read("#{RAILS_ROOT}/test/fixtures/encoding/iso-8859-1.txt")
235 273 str = "Texte encod\xe9 en ISO-8859-1."
236 274 str.force_encoding("ASCII-8BIT") if str.respond_to?(:force_encoding)
237 275 r = Repository::Bazaar.create!(
238 276 :project => proj,
239 277 :url => '/tmp/test/bazaar',
240 278 :log_encoding => 'ISO-8859-1' )
241 279 assert r
242 280 c = Changeset.new(:repository => r,
243 281 :committed_on => Time.now,
244 282 :revision => '123',
245 283 :scmid => '12345',
246 284 :comments => str)
247 285 assert( c.save )
248 286 str_utf8 = "Texte encod\xc3\xa9 en ISO-8859-1."
249 287 str_utf8.force_encoding("UTF-8") if str_utf8.respond_to?(:force_encoding)
250 288 assert_equal str_utf8, c.comments
251 289 end
252 290
253 291 def test_invalid_utf8_sequences_in_comments_should_be_replaced_latin1
254 292 proj = Project.find(3)
255 293 # str = File.read("#{RAILS_ROOT}/test/fixtures/encoding/iso-8859-1.txt")
256 294 str1 = "Texte encod\xe9 en ISO-8859-1."
257 295 str2 = "\xe9a\xe9b\xe9c\xe9d\xe9e test"
258 296 str1.force_encoding("UTF-8") if str1.respond_to?(:force_encoding)
259 297 str2.force_encoding("ASCII-8BIT") if str2.respond_to?(:force_encoding)
260 298 r = Repository::Bazaar.create!(
261 299 :project => proj,
262 300 :url => '/tmp/test/bazaar',
263 301 :log_encoding => 'UTF-8' )
264 302 assert r
265 303 c = Changeset.new(:repository => r,
266 304 :committed_on => Time.now,
267 305 :revision => '123',
268 306 :scmid => '12345',
269 307 :comments => str1,
270 308 :committer => str2)
271 309 assert( c.save )
272 310 assert_equal "Texte encod? en ISO-8859-1.", c.comments
273 311 assert_equal "?a?b?c?d?e test", c.committer
274 312 end
275 313
276 314 def test_invalid_utf8_sequences_in_comments_should_be_replaced_ja_jis
277 315 proj = Project.find(3)
278 316 str = "test\xb5\xfetest\xb5\xfe"
279 317 if str.respond_to?(:force_encoding)
280 318 str.force_encoding('ASCII-8BIT')
281 319 end
282 320 r = Repository::Bazaar.create!(
283 321 :project => proj,
284 322 :url => '/tmp/test/bazaar',
285 323 :log_encoding => 'ISO-2022-JP' )
286 324 assert r
287 325 c = Changeset.new(:repository => r,
288 326 :committed_on => Time.now,
289 327 :revision => '123',
290 328 :scmid => '12345',
291 329 :comments => str)
292 330 assert( c.save )
293 331 assert_equal "test??test??", c.comments
294 332 end
295 333
296 334 def test_comments_should_be_converted_all_latin1_to_utf8
297 335 s1 = "\xC2\x80"
298 336 s2 = "\xc3\x82\xc2\x80"
299 337 s4 = s2.dup
300 338 if s1.respond_to?(:force_encoding)
301 339 s3 = s1.dup
302 340 s1.force_encoding('ASCII-8BIT')
303 341 s2.force_encoding('ASCII-8BIT')
304 342 s3.force_encoding('ISO-8859-1')
305 343 s4.force_encoding('UTF-8')
306 344 assert_equal s3.encode('UTF-8'), s4
307 345 end
308 346 proj = Project.find(3)
309 347 r = Repository::Bazaar.create!(
310 348 :project => proj,
311 349 :url => '/tmp/test/bazaar',
312 350 :log_encoding => 'ISO-8859-1' )
313 351 assert r
314 352 c = Changeset.new(:repository => r,
315 353 :committed_on => Time.now,
316 354 :revision => '123',
317 355 :scmid => '12345',
318 356 :comments => s1)
319 357 assert( c.save )
320 358 assert_equal s4, c.comments
321 359 end
322 360
323 361 def test_invalid_utf8_sequences_in_paths_should_be_replaced
324 362 proj = Project.find(3)
325 363 str1 = "Texte encod\xe9 en ISO-8859-1"
326 364 str2 = "\xe9a\xe9b\xe9c\xe9d\xe9e test"
327 365 str1.force_encoding("UTF-8") if str1.respond_to?(:force_encoding)
328 366 str2.force_encoding("ASCII-8BIT") if str2.respond_to?(:force_encoding)
329 367 r = Repository::Bazaar.create!(
330 368 :project => proj,
331 369 :url => '/tmp/test/bazaar',
332 370 :log_encoding => 'UTF-8' )
333 371 assert r
334 372 cs = Changeset.new(
335 373 :repository => r,
336 374 :committed_on => Time.now,
337 375 :revision => '123',
338 376 :scmid => '12345',
339 377 :comments => "test")
340 378 assert(cs.save)
341 379 ch = Change.new(
342 380 :changeset => cs,
343 381 :action => "A",
344 382 :path => str1,
345 383 :from_path => str2,
346 384 :from_revision => "345")
347 385 assert(ch.save)
348 386 assert_equal "Texte encod? en ISO-8859-1", ch.path
349 387 assert_equal "?a?b?c?d?e test", ch.from_path
350 388 end
351 389
352 390 def test_comments_nil
353 391 proj = Project.find(3)
354 392 r = Repository::Bazaar.create!(
355 393 :project => proj,
356 394 :url => '/tmp/test/bazaar',
357 395 :log_encoding => 'ISO-8859-1' )
358 396 assert r
359 397 c = Changeset.new(:repository => r,
360 398 :committed_on => Time.now,
361 399 :revision => '123',
362 400 :scmid => '12345',
363 401 :comments => nil,
364 402 :committer => nil)
365 403 assert( c.save )
366 404 assert_equal "", c.comments
367 405 assert_equal nil, c.committer
368 406 if c.comments.respond_to?(:force_encoding)
369 407 assert_equal "UTF-8", c.comments.encoding.to_s
370 408 end
371 409 end
372 410
373 411 def test_comments_empty
374 412 proj = Project.find(3)
375 413 r = Repository::Bazaar.create!(
376 414 :project => proj,
377 415 :url => '/tmp/test/bazaar',
378 416 :log_encoding => 'ISO-8859-1' )
379 417 assert r
380 418 c = Changeset.new(:repository => r,
381 419 :committed_on => Time.now,
382 420 :revision => '123',
383 421 :scmid => '12345',
384 422 :comments => "",
385 423 :committer => "")
386 424 assert( c.save )
387 425 assert_equal "", c.comments
388 426 assert_equal "", c.committer
389 427 if c.comments.respond_to?(:force_encoding)
390 428 assert_equal "UTF-8", c.comments.encoding.to_s
391 429 assert_equal "UTF-8", c.committer.encoding.to_s
392 430 end
393 431 end
394 432
395 433 def test_identifier
396 434 c = Changeset.find_by_revision('1')
397 435 assert_equal c.revision, c.identifier
398 436 end
399 437 end
General Comments 0
You need to be logged in to leave comments. Login now