|
7 | 7 |
|
8 | 8 | import pytest |
9 | 9 |
|
10 | | -from git import Git, Repo, _backend |
| 10 | +from git import Actor, Commit, Git, Repo, _backend |
11 | 11 | from git.exc import GitCommandError, InvalidGitRepositoryError |
12 | 12 | from gitdb import IStream |
13 | 13 |
|
@@ -54,6 +54,45 @@ def test_native_worktree_inventory_includes_bare_main(repo, tmp_path): |
54 | 54 | assert current.git._call_process_safe("worktree", "list", "--porcelain", "-z") == expected |
55 | 55 |
|
56 | 56 |
|
| 57 | +def test_native_objects_trees_commits_and_index_reads(repo): |
| 58 | + actor = Actor("Example", "example@example.invalid") |
| 59 | + paths = ["file", "dir/with space", "dir/unicode-é", "--option"] |
| 60 | + for name in paths: |
| 61 | + path = Path(repo.working_dir, name) |
| 62 | + path.parent.mkdir(exist_ok=True) |
| 63 | + path.write_bytes(name.encode()) |
| 64 | + index = repo.index |
| 65 | + # All setup has finished; these operations must succeed without a subprocess. |
| 66 | + with patch.object(Git, "execute", side_effect=AssertionError("unexpected CLI call")): |
| 67 | + index.add(paths) |
| 68 | + tree = index.write_tree() |
| 69 | + assert {blob.path for blob in tree.traverse() if blob.type == "blob"} == set(paths) |
| 70 | + assert tree["file"].data_stream.read() == b"file" |
| 71 | + assert set(repo.index.entries) == {(name, 0) for name in paths} |
| 72 | + stream = IStream("blob", 4, BytesIO(b"data")) |
| 73 | + assert repo.odb.store(stream) is stream |
| 74 | + assert repo.odb.stream(stream.binsha).read(2) == b"da" |
| 75 | + commit = index.commit("message without a trailing newline", author=actor, committer=actor, skip_hooks=True) |
| 76 | + with patch.object(Git, "execute", side_effect=AssertionError("unexpected CLI call")): |
| 77 | + assert repo.commit(commit.hexsha).message == "message without a trailing newline" |
| 78 | + assert repo.merge_base(commit, commit) == [commit] |
| 79 | + assert repo.is_ancestor(commit, commit) |
| 80 | + assert commit.replace(message="changed").message == "changed" |
| 81 | + |
| 82 | + |
| 83 | +def test_native_tree_and_commit_bytes_match_cli(repo): |
| 84 | + actor = Actor("Example", "example@example.invalid") |
| 85 | + Path(repo.working_dir, "file").write_bytes(b"payload\n") |
| 86 | + index = repo.index |
| 87 | + index.add(["file"]) |
| 88 | + native_tree = index.write_tree() |
| 89 | + commit = index.commit("message", author=actor, committer=actor, skip_hooks=True) |
| 90 | + native = commit.replace(message="a changed message") |
| 91 | + with patch.object(_backend, "gix", None): |
| 92 | + assert index.write_tree().hexsha == native_tree.hexsha |
| 93 | + assert commit.replace(message="a changed message").hexsha == native.hexsha |
| 94 | + |
| 95 | + |
57 | 96 | def test_unknown_command_and_storage_environment_use_cli(repo): |
58 | 97 | before = _backend.statistics() |
59 | 98 | assert repo.git._call_process_safe("status", "--porcelain") == "" |
@@ -99,6 +138,21 @@ def test_tree_writes_validate_child_object_kinds(repo, mode, kind): |
99 | 138 | repo.git._call_process_safe("mktree", "-z", "--missing", istream=stream) |
100 | 139 |
|
101 | 140 |
|
| 141 | +def test_commit_identity_cleanup_matches_git(repo): |
| 142 | + actor = Actor(" Name. ", " email@example.invalid ") |
| 143 | + tree = repo.index.write_tree() |
| 144 | + kwargs = { |
| 145 | + "author": actor, |
| 146 | + "committer": actor, |
| 147 | + "author_date": "1100000000 +0000", |
| 148 | + "commit_date": "1100000000 +0000", |
| 149 | + "parent_commits": [], |
| 150 | + } |
| 151 | + commit = Commit.create_from_tree(repo, tree, "message", **kwargs) |
| 152 | + with patch.object(_backend, "gix", None): |
| 153 | + assert commit == Commit.create_from_tree(repo, tree, "message", **kwargs) |
| 154 | + |
| 155 | + |
102 | 156 | def test_partial_native_stream_does_not_corrupt_next_read(repo): |
103 | 157 | one = repo.odb.store(IStream("blob", 6, BytesIO(b"abcdef"))).binsha |
104 | 158 | two = repo.odb.store(IStream("blob", 3, BytesIO(b"xyz"))).binsha |
|
0 commit comments