OLD | NEW |
| (Empty) |
1 # Copyright (C) 2009 Google Inc. All rights reserved. | |
2 # Copyright (C) 2009 Apple Inc. All rights reserved. | |
3 # Copyright (C) 2011 Daniel Bates (dbates@intudata.com). All rights reserved. | |
4 # | |
5 # Redistribution and use in source and binary forms, with or without | |
6 # modification, are permitted provided that the following conditions are | |
7 # met: | |
8 # | |
9 # * Redistributions of source code must retain the above copyright | |
10 # notice, this list of conditions and the following disclaimer. | |
11 # * Redistributions in binary form must reproduce the above | |
12 # copyright notice, this list of conditions and the following disclaimer | |
13 # in the documentation and/or other materials provided with the | |
14 # distribution. | |
15 # * Neither the name of Google Inc. nor the names of its | |
16 # contributors may be used to endorse or promote products derived from | |
17 # this software without specific prior written permission. | |
18 # | |
19 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
20 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
21 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
22 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
23 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
24 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
25 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
26 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
27 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
28 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
29 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
30 | |
31 import unittest | |
32 | |
33 from webkitpy.common.system.executive import Executive, ScriptError | |
34 from webkitpy.common.system.executive_mock import MockExecutive | |
35 from webkitpy.common.system.filesystem import FileSystem | |
36 from webkitpy.common.system.filesystem_mock import MockFileSystem | |
37 from webkitpy.common.checkout.scm.detection import detect_scm_system | |
38 from webkitpy.common.checkout.scm.git import Git | |
39 | |
40 | |
41 class SCMTestBase(unittest.TestCase): | |
42 | |
43 def __init__(self, *args, **kwargs): | |
44 super(SCMTestBase, self).__init__(*args, **kwargs) | |
45 self.scm = None | |
46 self.executive = None | |
47 self.fs = None | |
48 self.original_cwd = None | |
49 | |
50 def setUp(self): | |
51 self.executive = Executive() | |
52 self.fs = FileSystem() | |
53 self.original_cwd = self.fs.getcwd() | |
54 | |
55 def tearDown(self): | |
56 self._chdir(self.original_cwd) | |
57 | |
58 def _join(self, *comps): | |
59 return self.fs.join(*comps) | |
60 | |
61 def _chdir(self, path): | |
62 self.fs.chdir(path) | |
63 | |
64 def _mkdir(self, path): | |
65 assert not self.fs.exists(path) | |
66 self.fs.maybe_make_directory(path) | |
67 | |
68 def _mkdtemp(self, **kwargs): | |
69 return str(self.fs.mkdtemp(**kwargs)) | |
70 | |
71 def _remove(self, path): | |
72 self.fs.remove(path) | |
73 | |
74 def _rmtree(self, path): | |
75 self.fs.rmtree(path) | |
76 | |
77 def _run(self, *args, **kwargs): | |
78 return self.executive.run_command(*args, **kwargs) | |
79 | |
80 def _run_silent(self, args, **kwargs): | |
81 self.executive.run_command(args, **kwargs) | |
82 | |
83 def _write_text_file(self, path, contents): | |
84 self.fs.write_text_file(path, contents) | |
85 | |
86 def _write_binary_file(self, path, contents): | |
87 self.fs.write_binary_file(path, contents) | |
88 | |
89 def _make_diff(self, command, *args): | |
90 # We use this wrapper to disable output decoding. diffs should be treate
d as | |
91 # binary files since they may include text files of multiple different e
ncodings. | |
92 return self._run([command, "diff"] + list(args), decode_output=False) | |
93 | |
94 def _git_diff(self, *args): | |
95 return self._make_diff("git", *args) | |
96 | |
97 def _shared_test_add_recursively(self): | |
98 self._mkdir("added_dir") | |
99 self._write_text_file("added_dir/added_file", "new stuff") | |
100 self.scm.add("added_dir/added_file") | |
101 self.assertIn("added_dir/added_file", self.scm._added_files()) | |
102 | |
103 def _shared_test_delete_recursively(self): | |
104 self._mkdir("added_dir") | |
105 self._write_text_file("added_dir/added_file", "new stuff") | |
106 self.scm.add("added_dir/added_file") | |
107 self.assertIn("added_dir/added_file", self.scm._added_files()) | |
108 self.scm.delete("added_dir/added_file") | |
109 self.assertNotIn("added_dir", self.scm._added_files()) | |
110 | |
111 def _shared_test_delete_recursively_or_not(self): | |
112 self._mkdir("added_dir") | |
113 self._write_text_file("added_dir/added_file", "new stuff") | |
114 self._write_text_file("added_dir/another_added_file", "more new stuff") | |
115 self.scm.add("added_dir/added_file") | |
116 self.scm.add("added_dir/another_added_file") | |
117 self.assertIn("added_dir/added_file", self.scm._added_files()) | |
118 self.assertIn("added_dir/another_added_file", self.scm._added_files()) | |
119 self.scm.delete("added_dir/added_file") | |
120 self.assertIn("added_dir/another_added_file", self.scm._added_files()) | |
121 | |
122 def _shared_test_exists(self, scm, commit_function): | |
123 self._chdir(scm.checkout_root) | |
124 self.assertFalse(scm.exists('foo.txt')) | |
125 self._write_text_file('foo.txt', 'some stuff') | |
126 self.assertFalse(scm.exists('foo.txt')) | |
127 scm.add('foo.txt') | |
128 commit_function('adding foo') | |
129 self.assertTrue(scm.exists('foo.txt')) | |
130 scm.delete('foo.txt') | |
131 commit_function('deleting foo') | |
132 self.assertFalse(scm.exists('foo.txt')) | |
133 | |
134 def _shared_test_move(self): | |
135 self._write_text_file('added_file', 'new stuff') | |
136 self.scm.add('added_file') | |
137 self.scm.move('added_file', 'moved_file') | |
138 self.assertIn('moved_file', self.scm._added_files()) | |
139 | |
140 def _shared_test_move_recursive(self): | |
141 self._mkdir("added_dir") | |
142 self._write_text_file('added_dir/added_file', 'new stuff') | |
143 self._write_text_file('added_dir/another_added_file', 'more new stuff') | |
144 self.scm.add('added_dir') | |
145 self.scm.move('added_dir', 'moved_dir') | |
146 self.assertIn('moved_dir/added_file', self.scm._added_files()) | |
147 self.assertIn('moved_dir/another_added_file', self.scm._added_files()) | |
148 | |
149 | |
150 class GitTest(SCMTestBase): | |
151 | |
152 def setUp(self): | |
153 super(GitTest, self).setUp() | |
154 self._set_up_git_checkouts() | |
155 | |
156 def tearDown(self): | |
157 super(GitTest, self).tearDown() | |
158 self._tear_down_git_checkouts() | |
159 | |
160 def _set_up_git_checkouts(self): | |
161 """Sets up fresh git repository with one commit. Then sets up a second g
it repo that tracks the first one.""" | |
162 | |
163 self.untracking_checkout_path = self._mkdtemp(suffix="git_test_checkout2
") | |
164 self._run(['git', 'init', self.untracking_checkout_path]) | |
165 | |
166 self._chdir(self.untracking_checkout_path) | |
167 self._write_text_file('foo_file', 'foo') | |
168 self._run(['git', 'add', 'foo_file']) | |
169 self._run(['git', 'commit', '-am', 'dummy commit']) | |
170 self.untracking_scm = detect_scm_system(self.untracking_checkout_path) | |
171 | |
172 self.tracking_git_checkout_path = self._mkdtemp(suffix="git_test_checkou
t") | |
173 self._run(['git', 'clone', '--quiet', self.untracking_checkout_path, sel
f.tracking_git_checkout_path]) | |
174 self._chdir(self.tracking_git_checkout_path) | |
175 self.tracking_scm = detect_scm_system(self.tracking_git_checkout_path) | |
176 | |
177 def _tear_down_git_checkouts(self): | |
178 self._run(['rm', '-rf', self.tracking_git_checkout_path]) | |
179 self._run(['rm', '-rf', self.untracking_checkout_path]) | |
180 | |
181 def test_remote_branch_ref(self): | |
182 self.assertEqual(self.tracking_scm._remote_branch_ref(), 'refs/remotes/o
rigin/master') | |
183 self._chdir(self.untracking_checkout_path) | |
184 self.assertRaises(ScriptError, self.untracking_scm._remote_branch_ref) | |
185 | |
186 def test_create_patch(self): | |
187 self._write_text_file('test_file_commit1', 'contents') | |
188 self._run(['git', 'add', 'test_file_commit1']) | |
189 scm = self.tracking_scm | |
190 scm.commit_locally_with_message('message') | |
191 | |
192 patch = scm.create_patch() | |
193 self.assertNotRegexpMatches(patch, r'Subversion Revision:') | |
194 | |
195 def test_patches_have_filenames_with_prefixes(self): | |
196 self._write_text_file('test_file_commit1', 'contents') | |
197 self._run(['git', 'add', 'test_file_commit1']) | |
198 scm = self.tracking_scm | |
199 scm.commit_locally_with_message('message') | |
200 | |
201 # Even if diff.noprefix is enabled, create_patch() produces diffs with p
refixes. | |
202 self._run(['git', 'config', 'diff.noprefix', 'true']) | |
203 patch = scm.create_patch() | |
204 self.assertRegexpMatches(patch, r'^diff --git a/test_file_commit1 b/test
_file_commit1') | |
205 | |
206 def test_exists(self): | |
207 scm = self.untracking_scm | |
208 self._shared_test_exists(scm, scm.commit_locally_with_message) | |
209 | |
210 def test_rename_files(self): | |
211 scm = self.tracking_scm | |
212 scm.move('foo_file', 'bar_file') | |
213 scm.commit_locally_with_message('message') | |
214 | |
215 def test_commit_position_from_git_log(self): | |
216 git_log = """ | |
217 commit 624c3081c0 | |
218 Author: foobarbaz1 <foobarbaz1@chromium.org> | |
219 Date: Mon Sep 28 19:10:30 2015 -0700 | |
220 | |
221 Test foo bar baz qux 123. | |
222 | |
223 BUG=000000 | |
224 | |
225 Review URL: https://codereview.chromium.org/999999999 | |
226 | |
227 Cr-Commit-Position: refs/heads/master@{#1234567} | |
228 """ | |
229 scm = self.tracking_scm | |
230 self.assertEqual(scm._commit_position_from_git_log(git_log), 1234567) | |
231 | |
232 def test_timestamp_of_revision(self): | |
233 scm = self.tracking_scm | |
234 scm.most_recent_log_matching(scm._commit_position_regex_for_timestamp(),
scm.checkout_root) | |
235 | |
236 | |
237 class GitTestWithMock(SCMTestBase): | |
238 | |
239 def make_scm(self): | |
240 scm = Git(cwd=".", executive=MockExecutive(), filesystem=MockFileSystem(
)) | |
241 scm.read_git_config = lambda *args, **kw: "MOCKKEY:MOCKVALUE" | |
242 return scm | |
243 | |
244 def test_timestamp_of_revision(self): | |
245 scm = self.make_scm() | |
246 scm.find_checkout_root = lambda path: '' | |
247 scm._run_git = lambda args: 'Date: 2013-02-08 08:05:49 +0000' | |
248 self.assertEqual(scm.timestamp_of_revision('some-path', '12345'), '2013-
02-08T08:05:49Z') | |
249 | |
250 scm._run_git = lambda args: 'Date: 2013-02-08 01:02:03 +0130' | |
251 self.assertEqual(scm.timestamp_of_revision('some-path', '12345'), '2013-
02-07T23:32:03Z') | |
252 | |
253 scm._run_git = lambda args: 'Date: 2013-02-08 01:55:21 -0800' | |
254 self.assertEqual(scm.timestamp_of_revision('some-path', '12345'), '2013-
02-08T09:55:21Z') | |
255 | |
256 def test_unstaged_files(self): | |
257 scm = self.make_scm() | |
258 status_lines = [ | |
259 ' M d/modified.txt', | |
260 ' D d/deleted.txt', | |
261 '?? d/untracked.txt', | |
262 'D d/deleted.txt', | |
263 'M d/modified-staged.txt', | |
264 'A d/added-staged.txt', | |
265 ] | |
266 # pylint: disable=protected-access | |
267 scm._run_git = lambda args: '\x00'.join(status_lines) + '\x00' | |
268 self.assertEqual( | |
269 scm.unstaged_changes(), | |
270 { | |
271 'd/modified.txt': 'M', | |
272 'd/deleted.txt': 'D', | |
273 'd/untracked.txt': '?', | |
274 }) | |
OLD | NEW |