Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6)

Side by Side Diff: tests/git_hyper_blame_test.py

Issue 1559943003: Added git hyper-blame, a tool that skips unwanted commits in git blame. (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/depot_tools.git@master
Patch Set: Fix comment. Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« man/src/git-hyper-blame.txt ('K') | « tests/git_dates_test.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/env python
2 # Copyright 2016 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5 """Tests for git_dates."""
6
7 import datetime
8 import os
9 import StringIO
10 import sys
11 import unittest
12
13 DEPOT_TOOLS_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
14 sys.path.insert(0, DEPOT_TOOLS_ROOT)
15
16 from testing_support import coverage_utils
17 from testing_support import git_test_utils
18
19 import git_common
20
21
22 class GitHyperBlameTestBase(git_test_utils.GitRepoReadOnlyTestBase):
23 @classmethod
24 def setUpClass(cls):
25 super(GitHyperBlameTestBase, cls).setUpClass()
26 import git_hyper_blame
27 cls.git_hyper_blame = git_hyper_blame
28
29 def run_hyperblame(self, ignored, filename, revision):
30 buf = StringIO.StringIO()
31 ignored = [self.repo[c] for c in ignored]
32 retval = self.repo.run(self.git_hyper_blame.hyperblame, ignored, filename,
33 revision=revision, out=buf)
34 return retval, buf.getvalue().rstrip().split('\n')
35
36 def blame_line(self, commit_name, rest, filename=None):
37 """Generate a blame line from a commit.
38
39 Args:
40 commit_name: The commit's schema name.
41 rest: The blame line after the timestamp. e.g., '2) file2 - merged'.
42 """
43 short = self.repo[commit_name][:8]
44 start = '%s %s' % (short, filename) if filename else short
45 author = self.repo.show_commit(commit_name, format_string='%an %ai')
46 return '%s (%s %s' % (start, author, rest)
47
48 class GitHyperBlameSimpleTest(GitHyperBlameTestBase):
49 REPO_SCHEMA = """
50 A B D E F G H
51 A C D
52 """
53
54 COMMIT_A = {
55 'some/files/file1': {'data': 'file1'},
56 'some/files/file2': {'data': 'file2'},
57 'some/files/empty': {'data': ''},
58 'some/other/file': {'data': 'otherfile'},
59 }
60
61 COMMIT_B = {
62 'some/files/file2': {
63 'mode': 0755,
64 'data': 'file2 - vanilla\n'},
65 'some/files/empty': {'data': 'not anymore'},
66 'some/files/file3': {'data': 'file3'},
67 }
68
69 COMMIT_C = {
70 'some/files/file2': {'data': 'file2 - merged\n'},
71 }
72
73 COMMIT_D = {
74 'some/files/file2': {'data': 'file2 - vanilla\nfile2 - merged\n'},
75 }
76
77 COMMIT_E = {
78 'some/files/file2': {'data': 'file2 - vanilla\nfile_x - merged\n'},
79 }
80
81 COMMIT_F = {
82 'some/files/file2': {'data': 'file2 - vanilla\nfile_y - merged\n'},
83 }
84
85 # Move file2 from files to other.
86 COMMIT_G = {
87 'some/files/file2': {'data': None},
88 'some/other/file2': {'data': 'file2 - vanilla\nfile_y - merged\n'},
89 }
90
91 COMMIT_H = {
92 'some/other/file2': {'data': 'file2 - vanilla\nfile_z - merged\n'},
93 }
94
95 def testBlameError(self):
96 """Tests a blame on a non-existent file."""
97 expected_output = ['']
98 retval, output = self.run_hyperblame([], 'some/other/file2', 'tag_D')
99 self.assertNotEqual(0, retval)
100 self.assertEqual(expected_output, output)
101
102 def testBlameEmpty(self):
103 """Tests a blame of an empty file with no ignores."""
104 expected_output = ['']
105 retval, output = self.run_hyperblame([], 'some/files/empty', 'tag_A')
106 self.assertEqual(0, retval)
107 self.assertEqual(expected_output, output)
108
109 def testBasicBlame(self):
110 """Tests a basic blame with no ignores."""
111 # Expect to blame line 1 on B, line 2 on C.
112 expected_output = [self.blame_line('B', '1) file2 - vanilla'),
113 self.blame_line('C', '2) file2 - merged')]
114 retval, output = self.run_hyperblame([], 'some/files/file2', 'tag_D')
115 self.assertEqual(0, retval)
116 self.assertEqual(expected_output, output)
117
118 def testBlameRenamed(self):
119 """Tests a blame with no ignores on a renamed file."""
120 # Expect to blame line 1 on B, line 2 on H.
121 # Because the file has a different name than it had when (some of) these
122 # lines were changed, expect the filenames to be displayed.
123 expected_output = [self.blame_line('B', '1) file2 - vanilla',
124 filename='some/files/file2'),
125 self.blame_line('H', '2) file_z - merged',
126 filename='some/other/file2')]
127 retval, output = self.run_hyperblame([], 'some/other/file2', 'tag_H')
128 self.assertEqual(0, retval)
129 self.assertEqual(expected_output, output)
130
131 def testIgnoreSimpleEdits(self):
132 """Tests a blame with simple (line-level changes) commits ignored."""
133 # Expect to blame line 1 on B, line 2 on E.
134 expected_output = [self.blame_line('B', '1) file2 - vanilla'),
135 self.blame_line('E', '2) file_x - merged')]
136 retval, output = self.run_hyperblame([], 'some/files/file2', 'tag_E')
137 self.assertEqual(0, retval)
138 self.assertEqual(expected_output, output)
139
140 # Ignore E; blame line 1 on B, line 2 on C.
141 expected_output = [self.blame_line('B', ' 1) file2 - vanilla'),
142 self.blame_line('C', '2*) file_x - merged')]
143 retval, output = self.run_hyperblame(['E'], 'some/files/file2', 'tag_E')
144 self.assertEqual(0, retval)
145 self.assertEqual(expected_output, output)
146
147 # Ignore E and F; blame line 1 on B, line 2 on C.
148 expected_output = [self.blame_line('B', ' 1) file2 - vanilla'),
149 self.blame_line('C', '2*) file_y - merged')]
150 retval, output = self.run_hyperblame(['E', 'F'], 'some/files/file2',
151 'tag_F')
152 self.assertEqual(0, retval)
153 self.assertEqual(expected_output, output)
154
155 def testIgnoreInitialCommit(self):
156 """Tests a blame with the initial commit ignored."""
157 # Ignore A. Expect A to get blamed anyway.
158 expected_output = [self.blame_line('A', '1) file1')]
159 retval, output = self.run_hyperblame(['A'], 'some/files/file1', 'tag_A')
160 self.assertEqual(0, retval)
161 self.assertEqual(expected_output, output)
162
163 def testIgnoreFileAdd(self):
164 """Tests a blame ignoring the commit that added this file."""
165 # Ignore A. Expect A to get blamed anyway.
166 expected_output = [self.blame_line('B', '1) file3')]
167 retval, output = self.run_hyperblame(['B'], 'some/files/file3', 'tag_B')
168 self.assertEqual(0, retval)
169 self.assertEqual(expected_output, output)
170
171 def testIgnoreFilePopulate(self):
172 """Tests a blame ignoring the commit that added data to an empty file."""
173 # Ignore A. Expect A to get blamed anyway.
174 expected_output = [self.blame_line('B', '1) not anymore')]
175 retval, output = self.run_hyperblame(['B'], 'some/files/empty', 'tag_B')
176 self.assertEqual(0, retval)
177 self.assertEqual(expected_output, output)
178
179 class GitHyperBlameLineMotionTest(GitHyperBlameTestBase):
180 REPO_SCHEMA = """
181 A B C D E
182 """
183
184 COMMIT_A = {
185 'file': {'data': 'A\ngreen\nblue\n'},
186 }
187
188 # Change "green" to "yellow".
189 COMMIT_B = {
190 'file': {'data': 'A\nyellow\nblue\n'},
191 }
192
193 # Insert 2 lines at the top,
194 # Change "yellow" to "red".
195 COMMIT_C = {
196 'file': {'data': 'X\nY\nA\nred\nblue\n'},
197 }
198
199 # Insert 2 more lines at the top.
200 COMMIT_D = {
201 'file': {'data': 'earth\nfire\nX\nY\nA\nred\nblue\n'},
202 }
203
204 # Insert a line before "red", and indent "red" and "blue".
205 COMMIT_E = {
206 'file': {'data': 'earth\nfire\nX\nY\nA\ncolors:\n red\n blue\n'},
207 }
208
209 def testInterHunkLineMotion(self):
210 """Tests a blame with line motion in another hunk in the ignored commit."""
211 # This test was mostly written as a demonstration of the limitations of the
212 # current algorithm (it exhibits non-ideal behaviour).
213
214 # Blame from D, ignoring C.
215 # Lines 1, 2 were added by D.
216 # Lines 3, 4 were added by C (but ignored, so blame A, B, respectively).
217 # TODO(mgiuca): Ideally, this would blame both of these lines on A, because
218 # they add lines nowhere near the changes made by B.
219 # Line 5 was added by A.
220 # Line 6 was modified by C (but ignored, so blame A).
221 # TODO(mgiuca): Ideally, Line 6 would be blamed on B, because that was the
222 # last commit to touch that line (changing "green" to "yellow"), but the
223 # algorithm isn't yet able to figure out that Line 6 in D == Line 4 in C ~=
224 # Line 2 in B.
225 # Line 7 was added by A.
226 expected_output = [self.blame_line('D', ' 1) earth'),
227 self.blame_line('D', ' 2) fire'),
228 self.blame_line('A', '3*) X'),
229 self.blame_line('B', '4*) Y'),
230 self.blame_line('A', ' 5) A'),
231 self.blame_line('A', '6*) red'),
232 self.blame_line('A', ' 7) blue'),
233 ]
234 retval, output = self.run_hyperblame(['C'], 'file', 'tag_D')
235 self.assertEqual(0, retval)
236 self.assertEqual(expected_output, output)
237
238 def testIntraHunkLineMotion(self):
239 """Tests a blame with line motion in the same hunk in the ignored commit."""
240 # This test was mostly written as a demonstration of the limitations of the
241 # current algorithm (it exhibits non-ideal behaviour).
242
243 # Blame from E, ignoring E.
244 # Line 6 was added by E (but ignored, so blame C).
245 # Lines 7, 8 were modified by E (but ignored, so blame A).
246 # TODO(mgiuca): Ideally, this would blame Line 7 on C, because the line
247 # "red" was added by C, and this is just a small change to that line. But
248 # the current algorithm can't deal with line motion within a hunk, so it
249 # just assumes Line 7 in E ~= Line 7 in D == Line 3 in A (which was "blue").
250 expected_output = [self.blame_line('D', ' 1) earth'),
251 self.blame_line('D', ' 2) fire'),
252 self.blame_line('C', ' 3) X'),
253 self.blame_line('C', ' 4) Y'),
254 self.blame_line('A', ' 5) A'),
255 self.blame_line('C', '6*) colors:'),
256 self.blame_line('A', '7*) red'),
257 self.blame_line('A', '8*) blue'),
258 ]
259 retval, output = self.run_hyperblame(['E'], 'file', 'tag_E')
260 self.assertEqual(0, retval)
261 self.assertEqual(expected_output, output)
262
263
264 if __name__ == '__main__':
265 sys.exit(coverage_utils.covered_main(
266 os.path.join(DEPOT_TOOLS_ROOT, 'git_hyper_blame.py')))
OLDNEW
« man/src/git-hyper-blame.txt ('K') | « tests/git_dates_test.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698