|
3 | 3 |
|
4 | 4 | import git |
5 | 5 |
|
6 | | -from codeflash.code_utils.git_utils import check_and_push_branch, check_running_in_git_repo, get_repo_owner_and_name |
| 6 | +from codeflash.code_utils.git_utils import ( |
| 7 | + check_and_push_branch, |
| 8 | + check_running_in_git_repo, |
| 9 | + get_git_diff, |
| 10 | + get_repo_owner_and_name, |
| 11 | +) |
7 | 12 |
|
8 | 13 |
|
9 | 14 | class TestGitUtils(unittest.TestCase): |
@@ -115,5 +120,136 @@ def test_check_and_push_branch_detached_head(self, mock_repo): |
115 | 120 | mock_origin.push.assert_not_called() |
116 | 121 |
|
117 | 122 |
|
| 123 | +DELETION_ONLY_DIFF = """\ |
| 124 | +--- a/example.py |
| 125 | ++++ b/example.py |
| 126 | +@@ -5,7 +5,5 @@ def foo(): |
| 127 | + a = 1 |
| 128 | + b = 2 |
| 129 | +- c = 3 |
| 130 | +- d = 4 |
| 131 | + e = 5 |
| 132 | + return a + b + e |
| 133 | +
|
| 134 | +""" |
| 135 | + |
| 136 | +ADDITION_ONLY_DIFF = """\ |
| 137 | +--- a/example.py |
| 138 | ++++ b/example.py |
| 139 | +@@ -5,5 +5,7 @@ def foo(): |
| 140 | + a = 1 |
| 141 | + b = 2 |
| 142 | ++ c = 3 |
| 143 | ++ d = 4 |
| 144 | + e = 5 |
| 145 | + return a + b + e |
| 146 | +
|
| 147 | +""" |
| 148 | + |
| 149 | +MIXED_DIFF = """\ |
| 150 | +--- a/example.py |
| 151 | ++++ b/example.py |
| 152 | +@@ -5,6 +5,6 @@ def foo(): |
| 153 | + a = 1 |
| 154 | + b = 2 |
| 155 | +- c = 3 |
| 156 | ++ c = 30 |
| 157 | + e = 5 |
| 158 | + return a + b + e |
| 159 | +
|
| 160 | +""" |
| 161 | + |
| 162 | +MULTI_HUNK_DELETION_ONLY_DIFF = """\ |
| 163 | +--- a/example.py |
| 164 | ++++ b/example.py |
| 165 | +@@ -5,7 +5,5 @@ def foo(): |
| 166 | + a = 1 |
| 167 | + b = 2 |
| 168 | +- c = 3 |
| 169 | +- d = 4 |
| 170 | + e = 5 |
| 171 | + return a + b + e |
| 172 | +
|
| 173 | +@@ -20,6 +18,4 @@ def bar(): |
| 174 | + x = 1 |
| 175 | + y = 2 |
| 176 | +- z = 3 |
| 177 | +- w = 4 |
| 178 | + return x + y |
| 179 | +
|
| 180 | +""" |
| 181 | + |
| 182 | + |
| 183 | +class TestGetGitDiffDeletionOnly(unittest.TestCase): |
| 184 | + @patch("codeflash.code_utils.git_utils.git.Repo") |
| 185 | + def test_deletion_only_diff_returns_hunk_target_starts(self, mock_repo_cls): |
| 186 | + repo = mock_repo_cls.return_value |
| 187 | + repo.head.commit.hexsha = "abc123" |
| 188 | + repo.working_dir = "/repo" |
| 189 | + repo.git.diff.return_value = DELETION_ONLY_DIFF |
| 190 | + |
| 191 | + result = get_git_diff(repo_directory=None, uncommitted_changes=True) |
| 192 | + |
| 193 | + assert len(result) == 1 |
| 194 | + key = list(result.keys())[0] |
| 195 | + assert str(key).endswith("example.py") |
| 196 | + # The hunk target_start is 5 — this is the fix: deletion-only diffs |
| 197 | + # should still report line numbers so the surrounding function is found. |
| 198 | + assert result[key] == [5] |
| 199 | + |
| 200 | + @patch("codeflash.code_utils.git_utils.git.Repo") |
| 201 | + def test_addition_only_diff_returns_added_lines(self, mock_repo_cls): |
| 202 | + repo = mock_repo_cls.return_value |
| 203 | + repo.head.commit.hexsha = "abc123" |
| 204 | + repo.working_dir = "/repo" |
| 205 | + repo.git.diff.return_value = ADDITION_ONLY_DIFF |
| 206 | + |
| 207 | + result = get_git_diff(repo_directory=None, uncommitted_changes=True) |
| 208 | + |
| 209 | + key = list(result.keys())[0] |
| 210 | + # Added lines are at target line numbers 7 and 8 |
| 211 | + assert result[key] == [7, 8] |
| 212 | + |
| 213 | + @patch("codeflash.code_utils.git_utils.git.Repo") |
| 214 | + def test_mixed_diff_returns_only_added_lines(self, mock_repo_cls): |
| 215 | + repo = mock_repo_cls.return_value |
| 216 | + repo.head.commit.hexsha = "abc123" |
| 217 | + repo.working_dir = "/repo" |
| 218 | + repo.git.diff.return_value = MIXED_DIFF |
| 219 | + |
| 220 | + result = get_git_diff(repo_directory=None, uncommitted_changes=True) |
| 221 | + |
| 222 | + key = list(result.keys())[0] |
| 223 | + # Only the added line (c = 30) at target line 7 |
| 224 | + assert result[key] == [7] |
| 225 | + |
| 226 | + @patch("codeflash.code_utils.git_utils.git.Repo") |
| 227 | + def test_multi_hunk_deletion_only_returns_all_hunk_starts(self, mock_repo_cls): |
| 228 | + repo = mock_repo_cls.return_value |
| 229 | + repo.head.commit.hexsha = "abc123" |
| 230 | + repo.working_dir = "/repo" |
| 231 | + repo.git.diff.return_value = MULTI_HUNK_DELETION_ONLY_DIFF |
| 232 | + |
| 233 | + result = get_git_diff(repo_directory=None, uncommitted_changes=True) |
| 234 | + |
| 235 | + key = list(result.keys())[0] |
| 236 | + # Two hunks with target_start 5 and 18 |
| 237 | + assert result[key] == [5, 18] |
| 238 | + |
| 239 | + @patch("codeflash.code_utils.git_utils.git.Repo") |
| 240 | + def test_deletion_only_diff_does_not_return_empty_list(self, mock_repo_cls): |
| 241 | + repo = mock_repo_cls.return_value |
| 242 | + repo.head.commit.hexsha = "abc123" |
| 243 | + repo.working_dir = "/repo" |
| 244 | + repo.git.diff.return_value = DELETION_ONLY_DIFF |
| 245 | + |
| 246 | + result = get_git_diff(repo_directory=None, uncommitted_changes=True) |
| 247 | + |
| 248 | + key = list(result.keys())[0] |
| 249 | + # Without the fix, this would be an empty list, causing the function |
| 250 | + # to be missed during discovery. |
| 251 | + assert len(result[key]) > 0 |
| 252 | + |
| 253 | + |
118 | 254 | if __name__ == "__main__": |
119 | 255 | unittest.main() |
0 commit comments