##// END OF EJS Templates
scm: replace invalid utf-8 sequences in comments instead of stripping on Ruby 1.8....
Toshi MARUYAMA -
r5253:6536c53e0973
parent child
Show More
@@ -1,288 +1,287
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2010 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
26 26 acts_as_event :title => Proc.new {|o| "#{l(:label_revision)} #{o.format_identifier}" + (o.short_comments.blank? ? '' : (': ' + o.short_comments))},
27 27 :description => :long_comments,
28 28 :datetime => :committed_on,
29 29 :url => Proc.new {|o| {:controller => 'repositories', :action => 'revision', :id => o.repository.project, :rev => o.identifier}}
30 30
31 31 acts_as_searchable :columns => 'comments',
32 32 :include => {:repository => :project},
33 33 :project_key => "#{Repository.table_name}.project_id",
34 34 :date_column => 'committed_on'
35 35
36 36 acts_as_activity_provider :timestamp => "#{table_name}.committed_on",
37 37 :author_key => :user_id,
38 38 :find_options => {:include => [:user, {:repository => :project}]}
39 39
40 40 validates_presence_of :repository_id, :revision, :committed_on, :commit_date
41 41 validates_uniqueness_of :revision, :scope => :repository_id
42 42 validates_uniqueness_of :scmid, :scope => :repository_id, :allow_nil => true
43 43
44 44 named_scope :visible, lambda {|*args| { :include => {:repository => :project},
45 45 :conditions => Project.allowed_to_condition(args.shift || User.current, :view_changesets, *args) } }
46 46
47 47 def revision=(r)
48 48 write_attribute :revision, (r.nil? ? nil : r.to_s)
49 49 end
50 50
51 51 # Returns the identifier of this changeset; depending on repository backends
52 52 def identifier
53 53 if repository.class.respond_to? :changeset_identifier
54 54 repository.class.changeset_identifier self
55 55 else
56 56 revision.to_s
57 57 end
58 58 end
59 59
60 60 def committed_on=(date)
61 61 self.commit_date = date
62 62 super
63 63 end
64 64
65 65 # Returns the readable identifier
66 66 def format_identifier
67 67 if repository.class.respond_to? :format_changeset_identifier
68 68 repository.class.format_changeset_identifier self
69 69 else
70 70 identifier
71 71 end
72 72 end
73 73
74 74 def project
75 75 repository.project
76 76 end
77 77
78 78 def author
79 79 user || committer.to_s.split('<').first
80 80 end
81 81
82 82 def before_create
83 83 self.committer = self.class.to_utf8(self.committer, repository.repo_log_encoding)
84 84 self.comments = self.class.normalize_comments(
85 85 self.comments, repository.repo_log_encoding)
86 86 self.user = repository.find_committer_user(self.committer)
87 87 end
88 88
89 89 def after_create
90 90 scan_comment_for_issue_ids
91 91 end
92 92
93 93 TIMELOG_RE = /
94 94 (
95 95 ((\d+)(h|hours?))((\d+)(m|min)?)?
96 96 |
97 97 ((\d+)(h|hours?|m|min))
98 98 |
99 99 (\d+):(\d+)
100 100 |
101 101 (\d+([\.,]\d+)?)h?
102 102 )
103 103 /x
104 104
105 105 def scan_comment_for_issue_ids
106 106 return if comments.blank?
107 107 # keywords used to reference issues
108 108 ref_keywords = Setting.commit_ref_keywords.downcase.split(",").collect(&:strip)
109 109 ref_keywords_any = ref_keywords.delete('*')
110 110 # keywords used to fix issues
111 111 fix_keywords = Setting.commit_fix_keywords.downcase.split(",").collect(&:strip)
112 112
113 113 kw_regexp = (ref_keywords + fix_keywords).collect{|kw| Regexp.escape(kw)}.join("|")
114 114
115 115 referenced_issues = []
116 116
117 117 comments.scan(/([\s\(\[,-]|^)((#{kw_regexp})[\s:]+)?(#\d+(\s+@#{TIMELOG_RE})?([\s,;&]+#\d+(\s+@#{TIMELOG_RE})?)*)(?=[[:punct:]]|\s|<|$)/i) do |match|
118 118 action, refs = match[2], match[3]
119 119 next unless action.present? || ref_keywords_any
120 120
121 121 refs.scan(/#(\d+)(\s+@#{TIMELOG_RE})?/).each do |m|
122 122 issue, hours = find_referenced_issue_by_id(m[0].to_i), m[2]
123 123 if issue
124 124 referenced_issues << issue
125 125 fix_issue(issue) if fix_keywords.include?(action.to_s.downcase)
126 126 log_time(issue, hours) if hours && Setting.commit_logtime_enabled?
127 127 end
128 128 end
129 129 end
130 130
131 131 referenced_issues.uniq!
132 132 self.issues = referenced_issues unless referenced_issues.empty?
133 133 end
134 134
135 135 def short_comments
136 136 @short_comments || split_comments.first
137 137 end
138 138
139 139 def long_comments
140 140 @long_comments || split_comments.last
141 141 end
142 142
143 143 def text_tag
144 144 if scmid?
145 145 "commit:#{scmid}"
146 146 else
147 147 "r#{revision}"
148 148 end
149 149 end
150 150
151 151 # Returns the previous changeset
152 152 def previous
153 153 @previous ||= Changeset.find(:first, :conditions => ['id < ? AND repository_id = ?', self.id, self.repository_id], :order => 'id DESC')
154 154 end
155 155
156 156 # Returns the next changeset
157 157 def next
158 158 @next ||= Changeset.find(:first, :conditions => ['id > ? AND repository_id = ?', self.id, self.repository_id], :order => 'id ASC')
159 159 end
160 160
161 161 # Creates a new Change from it's common parameters
162 162 def create_change(change)
163 163 Change.create(:changeset => self,
164 164 :action => change[:action],
165 165 :path => change[:path],
166 166 :from_path => change[:from_path],
167 167 :from_revision => change[:from_revision])
168 168 end
169 169
170 170 private
171 171
172 172 # Finds an issue that can be referenced by the commit message
173 173 # i.e. an issue that belong to the repository project, a subproject or a parent project
174 174 def find_referenced_issue_by_id(id)
175 175 return nil if id.blank?
176 176 issue = Issue.find_by_id(id.to_i, :include => :project)
177 177 if issue
178 178 unless issue.project &&
179 179 (project == issue.project || project.is_ancestor_of?(issue.project) ||
180 180 project.is_descendant_of?(issue.project))
181 181 issue = nil
182 182 end
183 183 end
184 184 issue
185 185 end
186 186
187 187 def fix_issue(issue)
188 188 status = IssueStatus.find_by_id(Setting.commit_fix_status_id.to_i)
189 189 if status.nil?
190 190 logger.warn("No status macthes commit_fix_status_id setting (#{Setting.commit_fix_status_id})") if logger
191 191 return issue
192 192 end
193 193
194 194 # the issue may have been updated by the closure of another one (eg. duplicate)
195 195 issue.reload
196 196 # don't change the status is the issue is closed
197 197 return if issue.status && issue.status.is_closed?
198 198
199 199 journal = issue.init_journal(user || User.anonymous, ll(Setting.default_language, :text_status_changed_by_changeset, text_tag))
200 200 issue.status = status
201 201 unless Setting.commit_fix_done_ratio.blank?
202 202 issue.done_ratio = Setting.commit_fix_done_ratio.to_i
203 203 end
204 204 Redmine::Hook.call_hook(:model_changeset_scan_commit_for_issue_ids_pre_issue_update,
205 205 { :changeset => self, :issue => issue })
206 206 unless issue.save
207 207 logger.warn("Issue ##{issue.id} could not be saved by changeset #{id}: #{issue.errors.full_messages}") if logger
208 208 end
209 209 issue
210 210 end
211 211
212 212 def log_time(issue, hours)
213 213 time_entry = TimeEntry.new(
214 214 :user => user,
215 215 :hours => hours,
216 216 :issue => issue,
217 217 :spent_on => commit_date,
218 218 :comments => l(:text_time_logged_by_changeset, :value => text_tag,
219 219 :locale => Setting.default_language)
220 220 )
221 221 time_entry.activity = log_time_activity unless log_time_activity.nil?
222 222
223 223 unless time_entry.save
224 224 logger.warn("TimeEntry could not be created by changeset #{id}: #{time_entry.errors.full_messages}") if logger
225 225 end
226 226 time_entry
227 227 end
228 228
229 229 def log_time_activity
230 230 if Setting.commit_logtime_activity_id.to_i > 0
231 231 TimeEntryActivity.find_by_id(Setting.commit_logtime_activity_id.to_i)
232 232 end
233 233 end
234 234
235 235 def split_comments
236 236 comments =~ /\A(.+?)\r?\n(.*)$/m
237 237 @short_comments = $1 || comments
238 238 @long_comments = $2.to_s.strip
239 239 return @short_comments, @long_comments
240 240 end
241 241
242 242 public
243 243
244 244 # Strips and reencodes a commit log before insertion into the database
245 245 def self.normalize_comments(str, encoding)
246 246 Changeset.to_utf8(str.to_s.strip, encoding)
247 247 end
248 248
249 249 private
250 250
251 251 def self.to_utf8(str, encoding)
252 252 return str if str.nil?
253 253 str.force_encoding("ASCII-8BIT") if str.respond_to?(:force_encoding)
254 254 if str.empty?
255 255 str.force_encoding("UTF-8") if str.respond_to?(:force_encoding)
256 256 return str
257 257 end
258 enc = encoding.blank? ? "UTF-8" : encoding
258 259 if str.respond_to?(:force_encoding)
259 enc = encoding.blank? ? "UTF-8" : encoding
260 260 if enc != "UTF-8"
261 261 str.force_encoding(enc)
262 262 str = str.encode("UTF-8", :invalid => :replace,
263 263 :undef => :replace, :replace => '?')
264 264 else
265 265 str.force_encoding("UTF-8")
266 266 if ! str.valid_encoding?
267 267 str = str.encode("US-ASCII", :invalid => :replace,
268 268 :undef => :replace, :replace => '?').encode("UTF-8")
269 269 end
270 270 end
271 271 else
272 unless encoding.blank? || encoding == 'UTF-8'
273 begin
274 str = Iconv.conv('UTF-8', encoding, str)
275 rescue Iconv::Failure
276 # do nothing here
277 end
278 end
279 # removes invalid UTF8 sequences
272 ic = Iconv.new('UTF-8', enc)
273 txtar = ""
280 274 begin
281 str = Iconv.conv('UTF-8//IGNORE', 'UTF-8', str + ' ')[0..-3]
282 rescue Iconv::InvalidEncoding
283 # "UTF-8//IGNORE" is not supported on some OS
275 txtar += ic.iconv(str)
276 rescue Iconv::IllegalSequence
277 txtar += $!.success
278 str = '?' + $!.failed[1,$!.failed.length]
279 retry
280 rescue
281 txtar += $!.success
284 282 end
283 str = txtar
285 284 end
286 285 str
287 286 end
288 287 end
@@ -1,365 +1,359
1 1 # encoding: utf-8
2 2 #
3 3 # Redmine - project management software
4 4 # Copyright (C) 2006-2010 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, :issues, :issue_statuses,
24 :changesets, :changes, :issue_categories, :enumerations, :custom_fields, :custom_values, :users, :members, :member_roles, :trackers
24 :changesets, :changes, :issue_categories, :enumerations,
25 :custom_fields, :custom_values, :users, :members, :member_roles, :trackers
25 26
26 27 def setup
27 28 end
28 29
29 30 def test_ref_keywords_any
30 31 ActionMailer::Base.deliveries.clear
31 32 Setting.commit_fix_status_id = IssueStatus.find(
32 33 :first, :conditions => ["is_closed = ?", true]).id
33 34 Setting.commit_fix_done_ratio = '90'
34 35 Setting.commit_ref_keywords = '*'
35 36 Setting.commit_fix_keywords = 'fixes , closes'
36 37
37 38 c = Changeset.new(:repository => Project.find(1).repository,
38 39 :committed_on => Time.now,
39 40 :comments => 'New commit (#2). Fixes #1')
40 41 c.scan_comment_for_issue_ids
41 42
42 43 assert_equal [1, 2], c.issue_ids.sort
43 44 fixed = Issue.find(1)
44 45 assert fixed.closed?
45 46 assert_equal 90, fixed.done_ratio
46 47 assert_equal 1, ActionMailer::Base.deliveries.size
47 48 end
48 49
49 50 def test_ref_keywords
50 51 Setting.commit_ref_keywords = 'refs'
51 52 Setting.commit_fix_keywords = ''
52 53
53 54 c = Changeset.new(:repository => Project.find(1).repository,
54 55 :committed_on => Time.now,
55 56 :comments => 'Ignores #2. Refs #1')
56 57 c.scan_comment_for_issue_ids
57 58
58 59 assert_equal [1], c.issue_ids.sort
59 60 end
60 61
61 62 def test_ref_keywords_any_only
62 63 Setting.commit_ref_keywords = '*'
63 64 Setting.commit_fix_keywords = ''
64 65
65 66 c = Changeset.new(:repository => Project.find(1).repository,
66 67 :committed_on => Time.now,
67 68 :comments => 'Ignores #2. Refs #1')
68 69 c.scan_comment_for_issue_ids
69 70
70 71 assert_equal [1, 2], c.issue_ids.sort
71 72 end
72 73
73 74 def test_ref_keywords_any_with_timelog
74 75 Setting.commit_ref_keywords = '*'
75 76 Setting.commit_logtime_enabled = '1'
76 77
77 78 {
78 79 '2' => 2.0,
79 80 '2h' => 2.0,
80 81 '2hours' => 2.0,
81 82 '15m' => 0.25,
82 83 '15min' => 0.25,
83 84 '3h15' => 3.25,
84 85 '3h15m' => 3.25,
85 86 '3h15min' => 3.25,
86 87 '3:15' => 3.25,
87 88 '3.25' => 3.25,
88 89 '3.25h' => 3.25,
89 90 '3,25' => 3.25,
90 91 '3,25h' => 3.25,
91 92 }.each do |syntax, expected_hours|
92 93 c = Changeset.new(:repository => Project.find(1).repository,
93 94 :committed_on => 24.hours.ago,
94 95 :comments => "Worked on this issue #1 @#{syntax}",
95 96 :revision => '520',
96 97 :user => User.find(2))
97 98 assert_difference 'TimeEntry.count' do
98 99 c.scan_comment_for_issue_ids
99 100 end
100 101 assert_equal [1], c.issue_ids.sort
101 102
102 103 time = TimeEntry.first(:order => 'id desc')
103 104 assert_equal 1, time.issue_id
104 105 assert_equal 1, time.project_id
105 106 assert_equal 2, time.user_id
106 107 assert_equal expected_hours, time.hours,
107 108 "@#{syntax} should be logged as #{expected_hours} hours but was #{time.hours}"
108 109 assert_equal Date.yesterday, time.spent_on
109 110 assert time.activity.is_default?
110 111 assert time.comments.include?('r520'),
111 112 "r520 was expected in time_entry comments: #{time.comments}"
112 113 end
113 114 end
114 115
115 116 def test_ref_keywords_closing_with_timelog
116 117 Setting.commit_fix_status_id = IssueStatus.find(
117 118 :first, :conditions => ["is_closed = ?", true]).id
118 119 Setting.commit_ref_keywords = '*'
119 120 Setting.commit_fix_keywords = 'fixes , closes'
120 121 Setting.commit_logtime_enabled = '1'
121 122
122 123 c = Changeset.new(:repository => Project.find(1).repository,
123 124 :committed_on => Time.now,
124 125 :comments => 'This is a comment. Fixes #1 @4.5, #2 @1',
125 126 :user => User.find(2))
126 127 assert_difference 'TimeEntry.count', 2 do
127 128 c.scan_comment_for_issue_ids
128 129 end
129 130
130 131 assert_equal [1, 2], c.issue_ids.sort
131 132 assert Issue.find(1).closed?
132 133 assert Issue.find(2).closed?
133 134
134 135 times = TimeEntry.all(:order => 'id desc', :limit => 2)
135 136 assert_equal [1, 2], times.collect(&:issue_id).sort
136 137 end
137 138
138 139 def test_ref_keywords_any_line_start
139 140 Setting.commit_ref_keywords = '*'
140 141
141 142 c = Changeset.new(:repository => Project.find(1).repository,
142 143 :committed_on => Time.now,
143 144 :comments => '#1 is the reason of this commit')
144 145 c.scan_comment_for_issue_ids
145 146
146 147 assert_equal [1], c.issue_ids.sort
147 148 end
148 149
149 150 def test_ref_keywords_allow_brackets_around_a_issue_number
150 151 Setting.commit_ref_keywords = '*'
151 152
152 153 c = Changeset.new(:repository => Project.find(1).repository,
153 154 :committed_on => Time.now,
154 155 :comments => '[#1] Worked on this issue')
155 156 c.scan_comment_for_issue_ids
156 157
157 158 assert_equal [1], c.issue_ids.sort
158 159 end
159 160
160 161 def test_ref_keywords_allow_brackets_around_multiple_issue_numbers
161 162 Setting.commit_ref_keywords = '*'
162 163
163 164 c = Changeset.new(:repository => Project.find(1).repository,
164 165 :committed_on => Time.now,
165 166 :comments => '[#1 #2, #3] Worked on these')
166 167 c.scan_comment_for_issue_ids
167 168
168 169 assert_equal [1,2,3], c.issue_ids.sort
169 170 end
170 171
171 172 def test_commit_referencing_a_subproject_issue
172 173 c = Changeset.new(:repository => Project.find(1).repository,
173 174 :committed_on => Time.now,
174 175 :comments => 'refs #5, a subproject issue')
175 176 c.scan_comment_for_issue_ids
176 177
177 178 assert_equal [5], c.issue_ids.sort
178 179 assert c.issues.first.project != c.project
179 180 end
180 181
181 182 def test_commit_referencing_a_parent_project_issue
182 183 # repository of child project
183 184 r = Repository::Subversion.create!(
184 185 :project => Project.find(3),
185 186 :url => 'svn://localhost/test')
186 187
187 188 c = Changeset.new(:repository => r,
188 189 :committed_on => Time.now,
189 190 :comments => 'refs #2, an issue of a parent project')
190 191 c.scan_comment_for_issue_ids
191 192
192 193 assert_equal [2], c.issue_ids.sort
193 194 assert c.issues.first.project != c.project
194 195 end
195 196
196 197 def test_text_tag_revision
197 198 c = Changeset.new(:revision => '520')
198 199 assert_equal 'r520', c.text_tag
199 200 end
200 201
201 202 def test_text_tag_hash
202 203 c = Changeset.new(
203 204 :scmid => '7234cb2750b63f47bff735edc50a1c0a433c2518',
204 205 :revision => '7234cb2750b63f47bff735edc50a1c0a433c2518')
205 206 assert_equal 'commit:7234cb2750b63f47bff735edc50a1c0a433c2518', c.text_tag
206 207 end
207 208
208 209 def test_text_tag_hash_all_number
209 210 c = Changeset.new(:scmid => '0123456789', :revision => '0123456789')
210 211 assert_equal 'commit:0123456789', c.text_tag
211 212 end
212 213
213 214 def test_previous
214 215 changeset = Changeset.find_by_revision('3')
215 216 assert_equal Changeset.find_by_revision('2'), changeset.previous
216 217 end
217 218
218 219 def test_previous_nil
219 220 changeset = Changeset.find_by_revision('1')
220 221 assert_nil changeset.previous
221 222 end
222 223
223 224 def test_next
224 225 changeset = Changeset.find_by_revision('2')
225 226 assert_equal Changeset.find_by_revision('3'), changeset.next
226 227 end
227 228
228 229 def test_next_nil
229 230 changeset = Changeset.find_by_revision('10')
230 231 assert_nil changeset.next
231 232 end
232 233
233 234 def test_comments_should_be_converted_to_utf8
234 235 proj = Project.find(3)
235 236 # str = File.read("#{RAILS_ROOT}/test/fixtures/encoding/iso-8859-1.txt")
236 237 str = "Texte encod\xe9 en ISO-8859-1."
237 238 str.force_encoding("ASCII-8BIT") if str.respond_to?(:force_encoding)
238 239 r = Repository::Bazaar.create!(
239 240 :project => proj, :url => '/tmp/test/bazaar',
240 241 :log_encoding => 'ISO-8859-1' )
241 242 assert r
242 243 c = Changeset.new(:repository => r,
243 244 :committed_on => Time.now,
244 245 :revision => '123',
245 246 :scmid => '12345',
246 247 :comments => str)
247 248 assert( c.save )
248 249 str_utf8 = "Texte encod\xc3\xa9 en ISO-8859-1."
249 250 str_utf8.force_encoding("UTF-8") if str_utf8.respond_to?(:force_encoding)
250 251 assert_equal str_utf8, c.comments
251 252 end
252 253
253 def test_invalid_utf8_sequences_in_comments_should_be_stripped
254 def test_invalid_utf8_sequences_in_comments_should_be_replaced_latin1
254 255 proj = Project.find(3)
255 256 # str = File.read("#{RAILS_ROOT}/test/fixtures/encoding/iso-8859-1.txt")
256 257 str = "Texte encod\xe9 en ISO-8859-1."
257 258 str.force_encoding("ASCII-8BIT") if str.respond_to?(:force_encoding)
258 259 r = Repository::Bazaar.create!(
259 :project => proj, :url => '/tmp/test/bazaar',
260 :project => proj,
261 :url => '/tmp/test/bazaar',
260 262 :log_encoding => 'UTF-8' )
261 263 assert r
262 c = Changeset.new(:repository => r,
264 c = Changeset.new(:repository => r,
263 265 :committed_on => Time.now,
264 :revision => '123',
265 :scmid => '12345',
266 :comments => str)
266 :revision => '123',
267 :scmid => '12345',
268 :comments => str)
267 269 assert( c.save )
268 if str.respond_to?(:force_encoding)
269 assert_equal "Texte encod? en ISO-8859-1.", c.comments
270 else
271 assert_equal "Texte encod en ISO-8859-1.", c.comments
272 end
270 assert_equal "Texte encod? en ISO-8859-1.", c.comments
273 271 end
274 272
275 def test_invalid_utf8_sequences_in_comments_should_be_stripped_ja_jis
273 def test_invalid_utf8_sequences_in_comments_should_be_replaced_ja_jis
276 274 proj = Project.find(3)
277 275 str = "test\xb5\xfetest\xb5\xfe"
278 276 if str.respond_to?(:force_encoding)
279 277 str.force_encoding('ASCII-8BIT')
280 278 end
281 279 r = Repository::Bazaar.create!(
282 280 :project => proj,
283 :url => '/tmp/test/bazaar',
281 :url => '/tmp/test/bazaar',
284 282 :log_encoding => 'ISO-2022-JP' )
285 283 assert r
286 284 c = Changeset.new(:repository => r,
287 285 :committed_on => Time.now,
288 286 :revision => '123',
289 287 :scmid => '12345',
290 288 :comments => str)
291 289 assert( c.save )
292 if str.respond_to?(:force_encoding)
293 assert_equal "test??test??", c.comments
294 else
295 assert_equal "testtest", c.comments
296 end
290 assert_equal "test??test??", c.comments
297 291 end
298 292
299 293 def test_comments_should_be_converted_all_latin1_to_utf8
300 294 s1 = "\xC2\x80"
301 295 s2 = "\xc3\x82\xc2\x80"
302 296 s4 = s2.dup
303 297 if s1.respond_to?(:force_encoding)
304 298 s3 = s1.dup
305 299 s1.force_encoding('ASCII-8BIT')
306 300 s2.force_encoding('ASCII-8BIT')
307 301 s3.force_encoding('ISO-8859-1')
308 302 s4.force_encoding('UTF-8')
309 303 assert_equal s3.encode('UTF-8'), s4
310 304 end
311 305 proj = Project.find(3)
312 306 r = Repository::Bazaar.create!(
313 307 :project => proj, :url => '/tmp/test/bazaar',
314 308 :log_encoding => 'ISO-8859-1' )
315 309 assert r
316 310 c = Changeset.new(:repository => r,
317 311 :committed_on => Time.now,
318 312 :revision => '123',
319 313 :scmid => '12345',
320 314 :comments => s1)
321 315 assert( c.save )
322 316 assert_equal s4, c.comments
323 317 end
324 318
325 319 def test_comments_nil
326 320 proj = Project.find(3)
327 321 r = Repository::Bazaar.create!(
328 322 :project => proj, :url => '/tmp/test/bazaar',
329 323 :log_encoding => 'ISO-8859-1' )
330 324 assert r
331 325 c = Changeset.new(:repository => r,
332 326 :committed_on => Time.now,
333 327 :revision => '123',
334 328 :scmid => '12345',
335 329 :comments => nil)
336 330 assert( c.save )
337 331 assert_equal "", c.comments
338 332 if c.comments.respond_to?(:force_encoding)
339 333 assert_equal "UTF-8", c.comments.encoding.to_s
340 334 end
341 335 end
342 336
343 337 def test_comments_empty
344 338 proj = Project.find(3)
345 339 r = Repository::Bazaar.create!(
346 340 :project => proj, :url => '/tmp/test/bazaar',
347 341 :log_encoding => 'ISO-8859-1' )
348 342 assert r
349 343 c = Changeset.new(:repository => r,
350 344 :committed_on => Time.now,
351 345 :revision => '123',
352 346 :scmid => '12345',
353 347 :comments => "")
354 348 assert( c.save )
355 349 assert_equal "", c.comments
356 350 if c.comments.respond_to?(:force_encoding)
357 351 assert_equal "UTF-8", c.comments.encoding.to_s
358 352 end
359 353 end
360 354
361 355 def test_identifier
362 356 c = Changeset.find_by_revision('1')
363 357 assert_equal c.revision, c.identifier
364 358 end
365 359 end
General Comments 0
You need to be logged in to leave comments. Login now