|
5 | 5 |
|
6 | 6 | import argparse |
7 | 7 | from pathlib import Path |
8 | | -from unittest.mock import Mock, patch |
| 8 | +from unittest.mock import Mock, call, patch |
9 | 9 |
|
10 | 10 | import pytest |
11 | 11 |
|
@@ -105,6 +105,7 @@ def test_remove_nonexistent_project_logs_error() -> None: |
105 | 105 | "nonexistent", "project 'nonexistent' not found in manifest" |
106 | 106 | ) |
107 | 107 |
|
| 108 | + |
108 | 109 | def test_remove_with_empty_projects_list_does_nothing() -> None: |
109 | 110 | """Remove command should do nothing when no projects are specified.""" |
110 | 111 | remove = Remove() |
@@ -158,33 +159,34 @@ def test_remove_multiple_projects_atomically() -> None: |
158 | 159 | patch("dfetch.commands.remove.safe_rm") as mocked_safe_rm, |
159 | 160 | patch("dfetch.commands.remove.shutil.copyfile") as mocked_copyfile, |
160 | 161 | ): |
| 162 | + |
161 | 163 | def _dump_side_effect(): |
162 | 164 | # Ensure no filesystem deletion happened before persistence |
163 | 165 | mocked_safe_rm.assert_not_called() |
| 166 | + |
164 | 167 | fake_manifest.dump.side_effect = _dump_side_effect |
165 | 168 |
|
166 | 169 | remove(args) |
167 | 170 |
|
168 | | - # Verify validation and manifest updates happened before deletions |
169 | | - # selected_projects should be called 3 times (once for each project validation) |
170 | | - assert fake_manifest.selected_projects.call_count == 3 |
171 | | - fake_manifest.selected_projects.assert_any_call(["project1"]) |
172 | | - fake_manifest.selected_projects.assert_any_call(["project2"]) |
173 | | - fake_manifest.selected_projects.assert_any_call(["project3"]) |
174 | | - |
175 | | - # remove should be called 2 times (once for each existing project) |
176 | | - assert fake_manifest.remove.call_count == 2 |
177 | | - fake_manifest.remove.assert_any_call("project1") |
178 | | - fake_manifest.remove.assert_any_call("project3") |
179 | | - |
180 | | - # dump should be called once (after all manifest changes) |
181 | | - fake_manifest.dump.assert_called_once() |
| 171 | + # Verify exact call order: validate all, then remove found projects, then dump, then delete |
| 172 | + fake_manifest.assert_has_calls( |
| 173 | + [ |
| 174 | + call.selected_projects(["project1"]), |
| 175 | + call.selected_projects(["project2"]), |
| 176 | + call.selected_projects(["project3"]), |
| 177 | + call.remove("project1"), |
| 178 | + call.remove("project3"), |
| 179 | + call.dump(), |
| 180 | + ], |
| 181 | + any_order=False, |
| 182 | + ) |
182 | 183 |
|
183 | | - # safe_rm should be called 2 times (once for each existing destination, after persistence) |
| 184 | + # safe_rm called once per existing project destination, after dump |
184 | 185 | assert mocked_safe_rm.call_count == 2 |
185 | | - mocked_safe_rm.assert_any_call( |
186 | | - "some_dest" |
187 | | - ) # All destinations are mocked as "some_dest" |
| 186 | + mocked_safe_rm.assert_has_calls( |
| 187 | + [call("some_dest"), call("some_dest")], |
| 188 | + any_order=False, |
| 189 | + ) |
188 | 190 |
|
189 | 191 | # No backup should be created (VCS superproject) |
190 | 192 | mocked_copyfile.assert_not_called() |
0 commit comments