|
17 | 17 |
|
18 | 18 | from git import Actor, Commit, Repo |
19 | 19 | from git.exc import UnsafeOptionError |
| 20 | +from git.index.typ import BaseIndexEntry |
20 | 21 | from git.objects.util import tzoffset, utc |
21 | 22 | from git.repo.fun import touch |
22 | 23 |
|
@@ -166,6 +167,39 @@ def check_entries(d, has_change_type=False): |
166 | 167 | self.assertEqual(commit.committer_tz_offset, 14400, commit.committer_tz_offset) |
167 | 168 | self.assertEqual(commit.message, "initial project\n") |
168 | 169 |
|
| 170 | + @with_rw_directory |
| 171 | + def test_stats_preserve_filename_spaces(self, rw_dir): |
| 172 | + repo = Repo.init(rw_dir) |
| 173 | + actor = Actor("Test", "test@example.com") |
| 174 | + paths = ("name", " name", "name ", " name ", " ") |
| 175 | + # Store blobs directly so trailing spaces work on Windows as well. |
| 176 | + for multiplier, change_type in ((1, "A"), (2, "M")): |
| 177 | + for count, path in enumerate(paths, 1): |
| 178 | + data = b"line\n" * count * multiplier |
| 179 | + blob = repo.odb.store(IStream("blob", len(data), BytesIO(data))) |
| 180 | + repo.index.add([BaseIndexEntry((0o100644, blob.binsha, 0, path))]) |
| 181 | + commit = repo.index.commit("Update files", author=actor, committer=actor) |
| 182 | + stats = commit.stats |
| 183 | + assert stats.total == {"insertions": 15, "deletions": 0, "lines": 15, "files": 5} |
| 184 | + assert stats.files == { |
| 185 | + path: {"insertions": count, "deletions": 0, "lines": count, "change_type": change_type} |
| 186 | + for count, path in enumerate(paths, 1) |
| 187 | + } |
| 188 | + empty_stats = repo.index.commit("No changes", author=actor, committer=actor).stats |
| 189 | + assert empty_stats.files == {} |
| 190 | + assert empty_stats.total == {"insertions": 0, "deletions": 0, "lines": 0, "files": 0} |
| 191 | + |
| 192 | + # Avoid filesystem path normalization of space-only names on Windows. |
| 193 | + index = repo.index |
| 194 | + index.entries.clear() |
| 195 | + index.write() |
| 196 | + removed_stats = repo.index.commit("Remove files", author=actor, committer=actor).stats |
| 197 | + assert removed_stats.files == { |
| 198 | + path: {"insertions": 0, "deletions": 2 * count, "lines": 2 * count, "change_type": "D"} |
| 199 | + for count, path in enumerate(paths, 1) |
| 200 | + } |
| 201 | + assert removed_stats.total == {"insertions": 0, "deletions": 30, "lines": 30, "files": 5} |
| 202 | + |
169 | 203 | def test_renames(self): |
170 | 204 | commit = self.rorepo.commit("185d847ec7647fd2642a82d9205fb3d07ea71715") |
171 | 205 | files = commit.stats.files |
|
0 commit comments