Defect #7064 » hg-2010-12-10.diff
app/helpers/repositories_helper.rb | ||
---|---|---|
166 | 166 |
end |
167 | 167 |
|
168 | 168 |
def mercurial_field_tags(form, repository) |
169 |
content_tag('p', form.text_field(:url, :label => 'Root directory', :size => 60, :required => true, :disabled => (repository && !repository.root_url.blank?))) |
|
169 |
content_tag('p', form.text_field(:url, :label => 'Root directory', :size => 60, :required => true, :disabled => (repository && !repository.root_url.blank?))) + |
|
170 |
content_tag('p', form.select(:path_encoding, [nil] + Setting::ENCODINGS, |
|
171 |
:label => 'Path encoding')) |
|
170 | 172 |
end |
171 | 173 | |
172 | 174 |
def git_field_tags(form, repository) |
app/models/repository.rb | ||
---|---|---|
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 |
require 'redmine/scm/adapters/path_encodable_wrapper' |
|
19 | ||
18 | 20 |
class Repository < ActiveRecord::Base |
19 | 21 |
belongs_to :project |
20 | 22 |
has_many :changesets, :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC" |
... | ... | |
38 | 40 |
end |
39 | 41 | |
40 | 42 |
def scm |
41 |
@scm ||= self.scm_adapter.new url, root_url, login, password
|
|
43 |
@scm ||= new_scm
|
|
42 | 44 |
update_attribute(:root_url, @scm.root_url) if root_url.blank? |
43 | 45 |
@scm |
44 | 46 |
end |
... | ... | |
105 | 107 |
# Default behaviour is to search in cached changesets |
106 | 108 |
def latest_changesets(path, rev, limit=10) |
107 | 109 |
if path.blank? |
108 |
changesets.find(:all, :include => :user, |
|
109 |
:order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC", |
|
110 |
:limit => limit) |
|
110 |
changesets.find(:all, :include => :user, :limit => limit) |
|
111 | 111 |
else |
112 |
changes.find(:all, :include => {:changeset => :user}, |
|
113 |
:conditions => ["path = ?", path.with_leading_slash], |
|
114 |
:order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC", |
|
115 |
:limit => limit).collect(&:changeset) |
|
112 |
changesets.find(:all, :select => "DISTINCT #{Changeset.table_name}.*", |
|
113 |
:joins => :changes, |
|
114 |
:conditions => ["#{Change.table_name}.path = ? OR #{Change.table_name}.path LIKE ? ESCAPE ?", |
|
115 |
path.with_leading_slash, |
|
116 |
"#{path.with_leading_slash.gsub(/[%_\\]/) { |s| "\\#{s}" }}/%", '\\'], |
|
117 |
:include => :user, :limit => limit) |
|
116 | 118 |
end |
117 | 119 |
end |
118 | 120 |
|
... | ... | |
198 | 200 |
end |
199 | 201 |
|
200 | 202 |
private |
203 | ||
204 |
def new_scm |
|
205 |
scm = self.scm_adapter.new url, root_url, login, password |
|
206 |
scm = Redmine::Scm::Adapters::PathEncodableWrapper.new(scm, path_encoding) unless path_encoding.blank? |
|
207 |
scm |
|
208 |
end |
|
201 | 209 |
|
202 | 210 |
def before_save |
203 | 211 |
# Strips url and root_url |
app/models/repository/mercurial.rb | ||
---|---|---|
18 | 18 |
require 'redmine/scm/adapters/mercurial_adapter' |
19 | 19 | |
20 | 20 |
class Repository::Mercurial < Repository |
21 |
# sort changesets by revision number |
|
22 |
has_many :changesets, :order => "#{Changeset.table_name}.id DESC", :foreign_key => 'repository_id' |
|
23 | ||
21 | 24 |
attr_protected :root_url |
22 | 25 |
validates_presence_of :url |
23 | 26 |
db/migrate/20101115000000_add_repositories_path_encoding.rb | ||
---|---|---|
1 |
class AddRepositoriesPathEncoding < ActiveRecord::Migration |
|
2 |
def self.up |
|
3 |
add_column :repositories, :path_encoding, :string, :limit => 64, :default => nil |
|
4 |
end |
|
5 | ||
6 |
def self.down |
|
7 |
remove_column :repositories, :path_encoding |
|
8 |
end |
|
9 |
end |
lib/redmine/scm/adapters/mercurial/hg-template-0.9.5.tmpl | ||
---|---|---|
3 | 3 |
changeset_verbose = 'This template must be used with --debug option\n' |
4 | 4 |
changeset_debug = '<logentry revision="{rev}" node="{node|short}">\n<author>{author|escape}</author>\n<date>{date|isodate}</date>\n<paths>\n{files}{file_adds}{file_dels}{file_copies}</paths>\n<msg>{desc|escape}</msg>\n{tags}</logentry>\n\n' |
5 | 5 | |
6 |
file = '<path action="M">{file|escape}</path>\n' |
|
7 |
file_add = '<path action="A">{file_add|escape}</path>\n' |
|
8 |
file_del = '<path action="D">{file_del|escape}</path>\n' |
|
9 |
file_copy = '<path-copied copyfrom-path="{source|escape}">{name|urlescape}</path-copied>\n' |
|
6 |
file = '<path action="M">{file|urlescape}</path>\n'
|
|
7 |
file_add = '<path action="A">{file_add|urlescape}</path>\n'
|
|
8 |
file_del = '<path action="D">{file_del|urlescape}</path>\n'
|
|
9 |
file_copy = '<path-copied copyfrom-path="{source|urlescape}">{name|urlescape}</path-copied>\n'
|
|
10 | 10 |
tag = '<tag>{tag|escape}</tag>\n' |
11 | 11 |
header='<?xml version="1.0" encoding="UTF-8" ?>\n<log>\n\n' |
12 | 12 |
# footer="</log>" |
lib/redmine/scm/adapters/mercurial/hg-template-1.0.tmpl | ||
---|---|---|
3 | 3 |
changeset_verbose = 'This template must be used with --debug option\n' |
4 | 4 |
changeset_debug = '<logentry revision="{rev}" node="{node|short}">\n<author>{author|escape}</author>\n<date>{date|isodate}</date>\n<paths>\n{file_mods}{file_adds}{file_dels}{file_copies}</paths>\n<msg>{desc|escape}</msg>\n{tags}</logentry>\n\n' |
5 | 5 | |
6 |
file_mod = '<path action="M">{file_mod|escape}</path>\n' |
|
7 |
file_add = '<path action="A">{file_add|escape}</path>\n' |
|
8 |
file_del = '<path action="D">{file_del|escape}</path>\n' |
|
9 |
file_copy = '<path-copied copyfrom-path="{source|escape}">{name|urlescape}</path-copied>\n' |
|
6 |
file_mod = '<path action="M">{file_mod|urlescape}</path>\n'
|
|
7 |
file_add = '<path action="A">{file_add|urlescape}</path>\n'
|
|
8 |
file_del = '<path action="D">{file_del|urlescape}</path>\n'
|
|
9 |
file_copy = '<path-copied copyfrom-path="{source|urlescape}">{name|urlescape}</path-copied>\n'
|
|
10 | 10 |
tag = '<tag>{tag|escape}</tag>\n' |
11 | 11 |
header='<?xml version="1.0" encoding="UTF-8" ?>\n<log>\n\n' |
12 | 12 |
# footer="</log>" |
lib/redmine/scm/adapters/mercurial_adapter.rb | ||
---|---|---|
16 | 16 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
17 | 17 | |
18 | 18 |
require 'redmine/scm/adapters/abstract_adapter' |
19 |
require 'cgi' |
|
19 | 20 | |
20 | 21 |
module Redmine |
21 | 22 |
module Scm |
... | ... | |
127 | 128 |
from_rev = logentry.attributes['revision'] |
128 | 129 |
end |
129 | 130 |
paths << {:action => path.attributes['action'], |
130 |
:path => "/#{path.text}",
|
|
131 |
:from_path => from_path ? "/#{from_path}" : nil,
|
|
131 |
:path => "/#{CGI.unescape(path.text)}",
|
|
132 |
:from_path => from_path ? "/#{CGI.unescape(from_path)}" : nil,
|
|
132 | 133 |
:from_revision => from_rev ? from_rev : nil |
133 | 134 |
} |
134 | 135 |
end |
lib/redmine/scm/adapters/path_encodable_wrapper.rb | ||
---|---|---|
1 |
# redMine - project management software |
|
2 |
# Copyright (C) 2006-2010 Jean-Philippe Lang |
|
3 |
# Copyright (C) 2010 Yuya Nishihara <yuya@tcha.org> |
|
4 |
# |
|
5 |
# This program is free software; you can redistribute it and/or |
|
6 |
# modify it under the terms of the GNU General Public License |
|
7 |
# as published by the Free Software Foundation; either version 2 |
|
8 |
# of the License, or (at your option) any later version. |
|
9 |
# |
|
10 |
# This program is distributed in the hope that it will be useful, |
|
11 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 |
# GNU General Public License for more details. |
|
14 |
# |
|
15 |
# You should have received a copy of the GNU General Public License |
|
16 |
# along with this program; if not, write to the Free Software |
|
17 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
18 | ||
19 |
require 'delegate' |
|
20 |
require 'iconv' |
|
21 | ||
22 |
module Redmine |
|
23 |
module Scm |
|
24 |
module Adapters |
|
25 |
# wraps scm adapter to convert path encodings |
|
26 |
class PathEncodableWrapper < SimpleDelegator # :nodoc: |
|
27 |
def initialize(scm, path_encoding) |
|
28 |
super(scm) |
|
29 |
@path_encoding = path_encoding |
|
30 |
end |
|
31 | ||
32 |
def entry(path=nil, identifier=nil) |
|
33 |
convert_entry!(super(to_scm_path(path), identifier)) |
|
34 |
end |
|
35 | ||
36 |
def entries(path=nil, identifier=nil) |
|
37 |
convert_entries!(super(to_scm_path(path), identifier)) |
|
38 |
end |
|
39 | ||
40 |
def properties(path, identifier=nil) |
|
41 |
super(to_scm_path(path), identifier) |
|
42 |
end |
|
43 | ||
44 |
def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={}) |
|
45 |
convert_revisions!(super(to_scm_path(path), identifier_from, identifier_to, options)) |
|
46 |
end |
|
47 | ||
48 |
def diff(path, identifier_from, identifier_to=nil) |
|
49 |
super(to_scm_path(path), identifier_from, identifier_to) |
|
50 |
end |
|
51 | ||
52 |
def cat(path, identifier=nil) |
|
53 |
super(to_scm_path(path), identifier) |
|
54 |
end |
|
55 | ||
56 |
def annotate(path, identifier=nil) |
|
57 |
super(to_scm_path(path), identifier) |
|
58 |
end |
|
59 | ||
60 |
private |
|
61 | ||
62 |
def convert_entry!(entry) |
|
63 |
return unless entry |
|
64 |
entry.name = from_scm_path(entry.name) |
|
65 |
entry.path = from_scm_path(entry.path) |
|
66 |
entry |
|
67 |
end |
|
68 | ||
69 |
def convert_entries!(entries) |
|
70 |
return unless entries |
|
71 |
entries.each { |e| convert_entry!(e) } |
|
72 |
entries |
|
73 |
end |
|
74 | ||
75 |
def convert_revisions!(revisions) |
|
76 |
return unless revisions |
|
77 |
revisions.each do |rev| |
|
78 |
next unless rev.paths |
|
79 |
rev.paths.each do |e| |
|
80 |
e[:path] = from_scm_path(e[:path]) |
|
81 |
e[:from_path] = from_scm_path(e[:from_path]) |
|
82 |
end |
|
83 |
end |
|
84 |
revisions |
|
85 |
end |
|
86 | ||
87 |
# convert repository path string to utf-8 |
|
88 |
def from_scm_path(s) |
|
89 |
return unless s |
|
90 |
begin |
|
91 |
Iconv.conv('UTF-8', @path_encoding, s) |
|
92 |
rescue Iconv::Failure => err |
|
93 |
raise CommandFailed, "failed to convert path from #{@path_encoding} to UTF-8. #{err}" |
|
94 |
end |
|
95 |
end |
|
96 | ||
97 |
# convert utf-8 path string to repository encoding |
|
98 |
def to_scm_path(s) |
|
99 |
return unless s |
|
100 |
begin |
|
101 |
Iconv.conv(@path_encoding, 'UTF-8', s) |
|
102 |
rescue Iconv::Failure => err |
|
103 |
raise CommandFailed, "failed to convert path from UTF-8 to #{@path_encoding}. #{err}" |
|
104 |
end |
|
105 |
end |
|
106 |
end |
|
107 |
end |
|
108 |
end |
|
109 |
end |
test/functional/repositories_mercurial_controller_test.rb | ||
---|---|---|
32 | 32 |
@request = ActionController::TestRequest.new |
33 | 33 |
@response = ActionController::TestResponse.new |
34 | 34 |
User.current = nil |
35 |
Repository::Mercurial.create(:project => Project.find(3), :url => REPOSITORY_PATH) |
|
35 |
assert @repository = Repository::Mercurial.create( |
|
36 |
:project => Project.find(3), |
|
37 |
:url => REPOSITORY_PATH, |
|
38 |
:path_encoding => 'ISO-8859-1' |
|
39 |
) |
|
40 |
@repository.fetch_changesets |
|
41 |
@repository.reload |
|
36 | 42 |
end |
37 | 43 |
|
38 | 44 |
if File.directory?(REPOSITORY_PATH) |
... | ... | |
49 | 55 |
assert_response :success |
50 | 56 |
assert_template 'show' |
51 | 57 |
assert_not_nil assigns(:entries) |
52 |
assert_equal 3, assigns(:entries).size
|
|
58 |
assert_equal 4, assigns(:entries).size
|
|
53 | 59 |
assert assigns(:entries).detect {|e| e.name == 'images' && e.kind == 'dir'} |
54 | 60 |
assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'} |
55 | 61 |
assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'} |
... | ... | |
74 | 80 |
assert_not_nil assigns(:entries) |
75 | 81 |
assert_equal ['delete.png'], assigns(:entries).collect(&:name) |
76 | 82 |
end |
77 |
|
|
83 | ||
84 |
def test_show_directory_sql_escape_percent |
|
85 |
get :show, :id => 3, :path => ['sql_escape', 'percent%dir'], :rev => 13 |
|
86 |
assert_response :success |
|
87 |
assert_template 'show' |
|
88 | ||
89 |
assert_not_nil assigns(:entries) |
|
90 |
assert_equal ['percent%file1.txt', 'percentfile1.txt'], assigns(:entries).collect(&:name) |
|
91 |
changesets = assigns(:changesets) |
|
92 |
assert_not_nil changesets |
|
93 |
assert_equal %w(13 11 10 9), changesets.collect(&:revision) |
|
94 |
end |
|
95 | ||
96 |
def test_show_directory_latin_1 |
|
97 |
get :show, :id => 3, :path => ['latin-1-dir'], :rev => 19 |
|
98 |
assert_response :success |
|
99 |
assert_template 'show' |
|
100 | ||
101 |
assert_not_nil assigns(:entries) |
|
102 |
assert_equal ["make-latin-1-file.rb", "test-\xc3\x9c-1.txt","test-\xc3\x9c-2.txt", "test-\xc3\x9c.txt"], assigns(:entries).collect(&:name) |
|
103 |
changesets = assigns(:changesets) |
|
104 |
assert_not_nil changesets |
|
105 |
assert_equal %w(19 18 17 16 15), changesets.collect(&:revision) |
|
106 |
end |
|
107 | ||
78 | 108 |
def test_changes |
79 | 109 |
get :changes, :id => 3, :path => ['images', 'edit.png'] |
80 | 110 |
assert_response :success |
... | ... | |
88 | 118 |
assert_template 'entry' |
89 | 119 |
# Line 19 |
90 | 120 |
assert_tag :tag => 'th', |
91 |
:content => /10/,
|
|
92 |
:attributes => { :class => /line-num/ },
|
|
121 |
:content => '10',
|
|
122 |
:attributes => { :class => 'line-num' },
|
|
93 | 123 |
:sibling => { :tag => 'td', :content => /WITHOUT ANY WARRANTY/ } |
94 | 124 |
end |
125 | ||
126 |
def test_entry_show_latin_1 |
|
127 |
get :entry, :id => 3, :path => ['latin-1-dir', "test-\xc3\x9c-2.txt"], :rev => 19 |
|
128 |
assert_response :success |
|
129 |
assert_template 'entry' |
|
130 |
# Line 19 |
|
131 |
assert_tag :tag => 'th', |
|
132 |
:content => '1', |
|
133 |
:attributes => { :class => 'line-num' }, |
|
134 |
:sibling => { :tag => 'td', :content => /Mercurial is a distributed version control system/ } |
|
135 |
end |
|
95 | 136 |
|
96 | 137 |
def test_entry_download |
97 | 138 |
get :entry, :id => 3, :path => ['sources', 'watchers_controller.rb'], :format => 'raw' |
... | ... | |
115 | 156 |
assert_template 'diff' |
116 | 157 |
# Line 22 removed |
117 | 158 |
assert_tag :tag => 'th', |
118 |
:content => /22/,
|
|
159 |
:content => '22',
|
|
119 | 160 |
:sibling => { :tag => 'td', |
120 | 161 |
:attributes => { :class => /diff_out/ }, |
121 | 162 |
:content => /def remove/ } |
122 | 163 |
end |
123 | 164 |
|
165 |
def test_diff_latin_1 |
|
166 |
get :diff, :id => 3, :rev => 19 |
|
167 |
assert_response :success |
|
168 |
assert_template 'diff' |
|
169 |
assert_tag :tag => 'th', |
|
170 |
:content => '2', |
|
171 |
:sibling => { :tag => 'td', |
|
172 |
:attributes => { :class => /diff_in/ }, |
|
173 |
:content => /It is written in Python/ } |
|
174 |
end |
|
175 | ||
124 | 176 |
def test_annotate |
125 | 177 |
get :annotate, :id => 3, :path => ['sources', 'watchers_controller.rb'] |
126 | 178 |
assert_response :success |
127 | 179 |
assert_template 'annotate' |
128 |
# Line 23, revision 4 |
|
129 |
assert_tag :tag => 'th', :content => /23/, |
|
130 |
:sibling => { :tag => 'td', :child => { :tag => 'a', :content => /4/ } }, |
|
131 |
:sibling => { :tag => 'td', :content => /jsmith/ }, |
|
180 |
# Line 23, revision 4:def6d2f1254a |
|
181 |
assert_tag :tag => 'th', |
|
182 |
:content => '23', |
|
183 |
:attributes => { :class => 'line-num' }, |
|
184 |
:sibling => |
|
185 |
{ |
|
186 |
:tag => 'td', |
|
187 |
:attributes => { :class => 'revision' }, |
|
188 |
:child => { :tag => 'a', :content => '4' } |
|
189 |
# :child => { :tag => 'a', :content => /4:def6d2f1/ } |
|
190 |
} |
|
191 |
assert_tag :tag => 'th', |
|
192 |
:content => '23', |
|
193 |
:attributes => { :class => 'line-num' }, |
|
194 |
:sibling => |
|
195 |
{ |
|
196 |
:tag => 'td' , |
|
197 |
:content => 'jsmith' , |
|
198 |
:attributes => { :class => 'author' }, |
|
199 |
|
|
200 |
} |
|
201 |
assert_tag :tag => 'th', |
|
202 |
:content => '23', |
|
203 |
:attributes => { :class => 'line-num' }, |
|
132 | 204 |
:sibling => { :tag => 'td', :content => /watcher =/ } |
133 | 205 |
end |
206 | ||
207 |
def test_annotate_latin_1 |
|
208 |
get :annotate, :id => 3, :path => ['latin-1-dir', "test-\xc3\x9c-2.txt"], :rev => 19 |
|
209 |
assert_response :success |
|
210 |
assert_template 'annotate' |
|
211 |
assert_tag :tag => 'th', |
|
212 |
:content => '1', |
|
213 |
:attributes => { :class => 'line-num' }, |
|
214 |
:sibling => |
|
215 |
{ |
|
216 |
:tag => 'td', |
|
217 |
:attributes => { :class => 'revision' }, |
|
218 |
:child => { :tag => 'a', :content => '18' } |
|
219 |
} |
|
220 |
assert_tag :tag => 'th', |
|
221 |
:content => '1', |
|
222 |
:attributes => { :class => 'line-num' }, |
|
223 |
:sibling => |
|
224 |
{ |
|
225 |
:tag => 'td' , |
|
226 |
:content => 'jsmith' , |
|
227 |
:attributes => { :class => 'author' }, |
|
228 |
|
|
229 |
} |
|
230 |
assert_tag :tag => 'th', |
|
231 |
:content => '1', |
|
232 |
:attributes => { :class => 'line-num' }, |
|
233 |
:sibling => { :tag => 'td', :content => /Mercurial is a distributed version control system/ } |
|
234 | ||
235 |
end |
|
236 | ||
134 | 237 |
else |
135 | 238 |
puts "Mercurial test repository NOT FOUND. Skipping functional tests !!!" |
136 | 239 |
def test_fake; assert true end |
137 | 240 |
end |
138 | 241 |
end |
242 |
test/unit/lib/redmine/scm/adapters/mercurial_adapter_test.rb | ||
---|---|---|
9 | 9 |
TEMPLATE_EXTENSION = Redmine::Scm::Adapters::MercurialAdapter::TEMPLATE_EXTENSION |
10 | 10 |
|
11 | 11 |
REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/mercurial_repository' |
12 |
|
|
13 |
def test_hgversion |
|
14 |
to_test = { "Mercurial Distributed SCM (version 0.9.5)\n" => [0,9,5], |
|
15 |
"Mercurial Distributed SCM (1.0)\n" => [1,0], |
|
16 |
"Mercurial Distributed SCM (1e4ddc9ac9f7+20080325)\n" => nil, |
|
17 |
"Mercurial Distributed SCM (1.0.1+20080525)\n" => [1,0,1], |
|
18 |
"Mercurial Distributed SCM (1916e629a29d)\n" => nil, |
|
19 |
"Mercurial SCM Distribuito (versione 0.9.5)\n" => [0,9,5], |
|
20 |
"(1.6)\n(1.7)\n(1.8)" => [1,6], |
|
21 |
"(1.7.1)\r\n(1.8.1)\r\n(1.9.1)" => [1,7,1]} |
|
22 | 12 | |
23 |
to_test.each do |s, v| |
|
24 |
test_hgversion_for(s, v) |
|
13 |
if File.directory?(REPOSITORY_PATH) |
|
14 |
def setup |
|
15 |
@adapter = Redmine::Scm::Adapters::MercurialAdapter.new(REPOSITORY_PATH) |
|
25 | 16 |
end |
26 |
end |
|
27 |
|
|
28 |
def test_template_path |
|
29 |
to_test = { [0,9,5] => "0.9.5", |
|
30 |
[1,0] => "1.0", |
|
31 |
[] => "1.0", |
|
32 |
[1,0,1] => "1.0", |
|
33 |
[1,7] => "1.0", |
|
34 |
[1,7,1] => "1.0"} |
|
35 |
to_test.each do |v, template| |
|
36 |
test_template_path_for(v, template) |
|
17 | ||
18 |
def test_hgversion |
|
19 |
to_test = { "Mercurial Distributed SCM (version 0.9.5)\n" => [0,9,5], |
|
20 |
"Mercurial Distributed SCM (1.0)\n" => [1,0], |
|
21 |
"Mercurial Distributed SCM (1e4ddc9ac9f7+20080325)\n" => nil, |
|
22 |
"Mercurial Distributed SCM (1.0.1+20080525)\n" => [1,0,1], |
|
23 |
"Mercurial Distributed SCM (1916e629a29d)\n" => nil, |
|
24 |
"Mercurial SCM Distribuito (versione 0.9.5)\n" => [0,9,5], |
|
25 |
"(1.6)\n(1.7)\n(1.8)" => [1,6], |
|
26 |
"(1.7.1)\r\n(1.8.1)\r\n(1.9.1)" => [1,7,1]} |
|
27 | ||
28 |
to_test.each do |s, v| |
|
29 |
test_hgversion_for(s, v) |
|
30 |
end |
|
37 | 31 |
end |
38 |
end |
|
39 |
|
|
40 |
private |
|
41 |
|
|
42 |
def test_hgversion_for(hgversion, version) |
|
43 |
Redmine::Scm::Adapters::MercurialAdapter.expects(:hgversion_from_command_line).returns(hgversion) |
|
44 |
adapter = Redmine::Scm::Adapters::MercurialAdapter |
|
45 |
assert_equal version, adapter.hgversion |
|
46 |
end |
|
47 |
|
|
48 |
def test_template_path_for(version, template) |
|
49 |
adapter = Redmine::Scm::Adapters::MercurialAdapter |
|
50 |
assert_equal "#{TEMPLATES_DIR}/#{TEMPLATE_NAME}-#{template}.#{TEMPLATE_EXTENSION}", adapter.template_path_for(version) |
|
51 |
assert File.exist?(adapter.template_path_for(version)) |
|
32 | ||
33 |
def test_template_path |
|
34 |
to_test = { [0,9,5] => "0.9.5", |
|
35 |
[1,0] => "1.0", |
|
36 |
[] => "1.0", |
|
37 |
[1,0,1] => "1.0", |
|
38 |
[1,7] => "1.0", |
|
39 |
[1,7,1] => "1.0"} |
|
40 |
to_test.each do |v, template| |
|
41 |
test_template_path_for(v, template) |
|
42 |
end |
|
43 |
end |
|
44 | ||
45 |
def test_cat |
|
46 |
assert @adapter.cat("sources/welcome_controller.rb", 2) |
|
47 |
assert_nil @adapter.cat("sources/welcome_controller.rb") |
|
48 |
end |
|
49 | ||
50 |
private |
|
51 | ||
52 |
def test_hgversion_for(hgversion, version) |
|
53 |
@adapter.class.expects(:hgversion_from_command_line).returns(hgversion) |
|
54 |
assert_equal version, @adapter.class.hgversion |
|
55 |
end |
|
56 | ||
57 |
def test_template_path_for(version, template) |
|
58 |
assert_equal "#{TEMPLATES_DIR}/#{TEMPLATE_NAME}-#{template}.#{TEMPLATE_EXTENSION}", |
|
59 |
@adapter.class.template_path_for(version) |
|
60 |
assert File.exist?(@adapter.class.template_path_for(version)) |
|
61 |
end |
|
62 |
else |
|
63 |
puts "Mercurial test repository NOT FOUND. Skipping unit tests !!!" |
|
64 |
def test_fake; assert true end |
|
52 | 65 |
end |
53 | 66 |
end |
54 |
|
|
67 | ||
55 | 68 |
rescue LoadError |
56 | 69 |
class MercurialMochaFake < ActiveSupport::TestCase |
57 | 70 |
def test_fake; assert(false, "Requires mocha to run those tests") end |
test/unit/repository_mercurial_test.rb | ||
---|---|---|
19 | 19 | |
20 | 20 |
class RepositoryMercurialTest < ActiveSupport::TestCase |
21 | 21 |
fixtures :projects |
22 |
|
|
22 | ||
23 | 23 |
# No '..' in the repository path |
24 | 24 |
REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/mercurial_repository' |
25 |
|
|
25 | ||
26 | 26 |
def setup |
27 | 27 |
@project = Project.find(1) |
28 |
assert @repository = Repository::Mercurial.create(:project => @project, :url => REPOSITORY_PATH) |
|
28 |
assert @repository = Repository::Mercurial.create( |
|
29 |
:project => @project, |
|
30 |
:url => REPOSITORY_PATH, |
|
31 |
:path_encoding => 'ISO-8859-1' |
|
32 |
) |
|
29 | 33 |
end |
30 |
|
|
34 | ||
31 | 35 |
if File.directory?(REPOSITORY_PATH) |
32 | 36 |
def test_fetch_changesets_from_scratch |
33 | 37 |
@repository.fetch_changesets |
34 | 38 |
@repository.reload |
35 | 39 |
|
36 |
assert_equal 6, @repository.changesets.count |
|
37 |
assert_equal 11, @repository.changes.count |
|
38 |
assert_equal "Initial import.\nThe repository contains 3 files.", @repository.changesets.find_by_revision('0').comments |
|
40 |
assert_equal 21, @repository.changesets.count |
|
41 |
assert_equal 30, @repository.changes.count |
|
42 |
assert_equal "Initial import.\nThe repository contains 3 files.", |
|
43 |
@repository.changesets.find_by_revision('0').comments |
|
39 | 44 |
end |
40 | 45 |
|
41 | 46 |
def test_fetch_changesets_incremental |
... | ... | |
46 | 51 |
assert_equal 3, @repository.changesets.count |
47 | 52 |
|
48 | 53 |
@repository.fetch_changesets |
49 |
assert_equal 6, @repository.changesets.count
|
|
54 |
assert_equal 21, @repository.changesets.count
|
|
50 | 55 |
end |
51 |
|
|
56 | ||
52 | 57 |
def test_entries |
53 | 58 |
assert_equal 2, @repository.entries("sources", 2).size |
54 | 59 |
assert_equal 1, @repository.entries("sources", 3).size |
55 | 60 |
end |
56 | 61 | |
57 | 62 |
def test_locate_on_outdated_repository |
58 |
# Change the working dir state |
|
59 |
%x{hg -R #{REPOSITORY_PATH} up -r 0} |
|
63 |
# For bare repository; that is, a repository without a working copy |
|
64 |
# $ hg update null |
|
65 |
# See http://mercurial.selenic.com/wiki/GitConcepts?action=recall&rev=46#Bare_repositories |
|
60 | 66 |
assert_equal 1, @repository.entries("images", 0).size |
61 | 67 |
assert_equal 2, @repository.entries("images").size |
62 | 68 |
assert_equal 2, @repository.entries("images", 2).size |
63 | 69 |
end |
64 | 70 | |
71 |
def test_changeset_order_by_revision |
|
72 |
@repository.fetch_changesets |
|
73 |
@repository.reload |
|
65 | 74 | |
66 |
def test_cat |
|
67 |
assert @repository.scm.cat("sources/welcome_controller.rb", 2) |
|
68 |
assert_nil @repository.scm.cat("sources/welcome_controller.rb") |
|
75 |
c0 = @repository.latest_changeset |
|
76 |
c1 = @repository.changesets.find_by_revision('0') |
|
77 |
# sorted by revision (id), not by date |
|
78 |
assert c0.revision.to_i > c1.revision.to_i |
|
79 |
assert c0.committed_on < c1.committed_on |
|
69 | 80 |
end |
70 | 81 | |
82 |
def test_latest_changesets |
|
83 |
@repository.fetch_changesets |
|
84 |
@repository.reload |
|
85 | ||
86 |
# with_limit |
|
87 |
changesets = @repository.latest_changesets('', nil, 2) |
|
88 |
assert_equal @repository.latest_changesets('', nil)[0, 2], changesets |
|
89 | ||
90 |
# with_filepath |
|
91 |
changesets = @repository.latest_changesets('sql_escape/percent%dir/percent%file1.txt', nil) |
|
92 |
assert_equal %w|11 10 9|, changesets.collect(&:revision) |
|
93 | ||
94 |
changesets = @repository.latest_changesets('/sql_escape/underscore_dir/understrike_file.txt', nil) |
|
95 |
assert_equal %w|12 9|, changesets.collect(&:revision) |
|
96 | ||
97 |
# with_dirpath |
|
98 |
changesets = @repository.latest_changesets('sql_escape/percent%dir', nil) |
|
99 |
assert_equal %w|13 11 10 9|, changesets.collect(&:revision) |
|
100 |
end |
|
101 | ||
102 |
def test_copied_files |
|
103 |
@repository.fetch_changesets |
|
104 |
@repository.reload |
|
105 | ||
106 |
cs1 = @repository.changesets.find_by_revision('13') |
|
107 |
c1 = cs1.changes |
|
108 |
assert_equal 2, c1.size |
|
109 |
assert_equal 'A', c1[0].action |
|
110 |
assert_equal '/sql_escape/percent%dir/percentfile1.txt', c1[0].path |
|
111 |
assert_equal '/sql_escape/percent%dir/percent%file1.txt', c1[0].from_path |
|
112 | ||
113 |
assert_equal 'A', c1[1].action |
|
114 |
assert_equal '/sql_escape/underscore_dir/understrike-file.txt', c1[1].path |
|
115 |
assert_equal '/sql_escape/underscore_dir/understrike_file.txt', c1[1].from_path |
|
116 | ||
117 |
cs2 = @repository.changesets.find_by_revision('17') |
|
118 |
c2 = cs2.changes |
|
119 |
assert_equal 1, c2.size |
|
120 |
assert_equal 'A', c2[0].action |
|
121 |
assert_equal "/latin-1-dir/test-\xc3\x9c-1.txt", c2[0].path |
|
122 |
assert_equal "/latin-1-dir/test-\xc3\x9c.txt", c2[0].from_path |
|
123 |
end |
|
71 | 124 |
else |
72 | 125 |
puts "Mercurial test repository NOT FOUND. Skipping unit tests !!!" |
73 | 126 |
def test_fake; assert true end |
74 | 127 |
end |
75 | 128 |
end |
129 |