|
1 | 1 | from collections.abc import AsyncIterator, Iterator |
2 | 2 | from contextlib import asynccontextmanager, contextmanager |
3 | 3 | from crystal.browser import MainWindow as RealMainWindow |
| 4 | +from crystal.browser.tasktree import TaskTreeNode |
4 | 5 | from crystal.model import ( |
5 | 6 | Project, ProjectReadOnlyError, Resource, ResourceGroup, RootResource, |
6 | 7 | ) |
|
32 | 33 | from crystal.util.wx_dialog import mocked_show_modal |
33 | 34 | from crystal.util.xappdirs import user_untitled_projects_dir |
34 | 35 | from crystal.util.xos import is_ci, is_linux, is_mac_os, is_windows |
| 36 | +from crystal.util.xtyping import not_none |
35 | 37 | from dataclasses import dataclass |
36 | 38 | import errno |
37 | 39 | from functools import cache, wraps |
@@ -137,6 +139,8 @@ async def test_when_project_properties_changed_then_untitled_project_becomes_dir |
137 | 139 |
|
138 | 140 | @awith_subtests |
139 | 141 | async def test_when_untitled_project_saved_then_becomes_clean_and_titled(subtests: SubtestsContext) -> None: |
| 142 | + DEBUG_TASK_TREE = False |
| 143 | + |
140 | 144 | with scheduler_disabled() as disabled_scheduler, \ |
141 | 145 | served_project('testdata_xkcd.crystalproj.zip') as sp: |
142 | 146 | atom_feed_url = sp.get_request_url('https://xkcd.com/atom.xml') |
@@ -256,40 +260,78 @@ async def test_when_untitled_project_saved_then_becomes_clean_and_titled(subtest |
256 | 260 | # Test saving an untitled project while downloads are in progress |
257 | 261 | # AKA: test_when_save_as_project_with_active_tasks_then_hibernates_and_restores_tasks |
258 | 262 | with subtests.test(tasks_running=True), \ |
259 | | - _untitled_project() as project, \ |
260 | 263 | xtempfile.TemporaryDirectory() as new_container_dirpath: |
261 | | - # Download a resource revision, so that comic URLs are discovered |
262 | | - r = Resource(project, home_url) |
263 | | - rr_future = r.download() |
264 | | - await step_scheduler_until_done(project) |
265 | | - |
266 | | - # Start downloading a group and an individual resource |
267 | | - g = ResourceGroup(project, 'Comic', comic_pattern) |
268 | | - g.download() |
269 | | - await step_scheduler(project) |
270 | | - root_r = RootResource(project, '', Resource(project, comic50_url)) |
271 | | - root_r.download() |
272 | | - await step_scheduler(project) |
273 | | - (old_drg_task, old_dr_task) = project.root_task.children |
274 | | - assert isinstance(old_drg_task, DownloadResourceGroupTask) |
275 | | - assert isinstance(old_dr_task, DownloadResourceTask) |
276 | | - |
277 | | - # Save untitled project to somewhere else |
278 | | - new_project_dirpath = os.path.join( |
279 | | - new_container_dirpath, |
280 | | - os.path.basename(old_project_dirpath)) |
281 | | - await save_as_without_ui(project, new_project_dirpath) |
282 | | - append_deferred_top_level_tasks(project) |
283 | | - |
284 | | - # Ensure tasks are restored |
285 | | - (new_drg_task, new_dr_task) = project.root_task.children |
286 | | - assert isinstance(new_drg_task, DownloadResourceGroupTask) |
287 | | - assert isinstance(new_dr_task, DownloadResourceTask) |
288 | | - assert new_drg_task is not old_drg_task |
289 | | - assert new_dr_task is not old_dr_task |
290 | | - |
291 | | - # Ensure tasks can still be stepped without error |
292 | | - await step_scheduler(project) |
| 264 | + # Create untitled project with UI |
| 265 | + async with (await OpenOrCreateDialog.wait_for()).create() as (mw, project): |
| 266 | + rmw = RealMainWindow._last_created |
| 267 | + assert rmw is not None |
| 268 | + |
| 269 | + # Download a resource revision, so that comic URLs are discovered |
| 270 | + r = Resource(project, home_url) |
| 271 | + rr_future = r.download() |
| 272 | + await step_scheduler_until_done(project) |
| 273 | + |
| 274 | + # Start downloading a group and an individual resource |
| 275 | + g = ResourceGroup(project, 'Comic', comic_pattern) |
| 276 | + g.download() |
| 277 | + await step_scheduler(project) |
| 278 | + root_r = RootResource(project, '', Resource(project, comic50_url)) |
| 279 | + root_r.download() |
| 280 | + await step_scheduler(project) |
| 281 | + (old_drg_task, old_dr_task) = project.root_task.children |
| 282 | + assert isinstance(old_drg_task, DownloadResourceGroupTask) |
| 283 | + assert isinstance(old_dr_task, DownloadResourceTask) |
| 284 | + |
| 285 | + if DEBUG_TASK_TREE: |
| 286 | + print(f'Task tree before save:') |
| 287 | + project.root_task.print_tree() |
| 288 | + |
| 289 | + # Save untitled project to somewhere else |
| 290 | + new_project_dirpath = os.path.join( |
| 291 | + new_container_dirpath, |
| 292 | + os.path.basename(old_project_dirpath)) |
| 293 | + await save_as_with_ui(rmw, new_project_dirpath) |
| 294 | + append_deferred_top_level_tasks(project) |
| 295 | + |
| 296 | + # Ensure tasks are restored (in Task Tree) |
| 297 | + (new_drg_task, new_dr_task) = project.root_task.children |
| 298 | + assert isinstance(new_drg_task, DownloadResourceGroupTask) |
| 299 | + assert isinstance(new_dr_task, DownloadResourceTask) |
| 300 | + assert new_drg_task is not old_drg_task |
| 301 | + assert new_dr_task is not old_dr_task |
| 302 | + |
| 303 | + # Ensure tasks are restored (in Task Tree UI) |
| 304 | + top_level_ttns = [ |
| 305 | + not_none(TaskTreeNode.for_node_view(nv)) |
| 306 | + for nv in rmw.task_tree.root.tree_node.children |
| 307 | + ] |
| 308 | + (new_drg_ttn, new_dr_ttn) = top_level_ttns |
| 309 | + assert isinstance(new_drg_ttn.task, DownloadResourceGroupTask) |
| 310 | + assert isinstance(new_dr_ttn.task, DownloadResourceTask) |
| 311 | + assert new_drg_ttn.task is new_drg_task |
| 312 | + assert new_dr_ttn.task is new_dr_task |
| 313 | + |
| 314 | + # Ensure tasks are restored (in low level Task Tree UI) |
| 315 | + assert 2 == rmw.task_tree.peer.GetChildrenCount(rmw.task_tree.peer.GetRootItem(), recursively=False) |
| 316 | + |
| 317 | + # 1. Ensure restored tasks can still be stepped without error |
| 318 | + # 2. Ensure restored tasks will complete |
| 319 | + done = False |
| 320 | + step_count = 0 |
| 321 | + if DEBUG_TASK_TREE: |
| 322 | + print(f'Task tree after save + 0 step(s):') |
| 323 | + project.root_task.print_tree() |
| 324 | + while not done: |
| 325 | + done = await step_scheduler(project, expect_done=None) |
| 326 | + step_count += 1 |
| 327 | + if DEBUG_TASK_TREE: |
| 328 | + print(f'Task tree after save + {step_count} step(s):') |
| 329 | + project.root_task.print_tree() |
| 330 | + |
| 331 | + # Ensure effects of restored tasks are correct |
| 332 | + assert root_r.resource.has_any_revisions() |
| 333 | + for member in g.members: |
| 334 | + assert member.has_any_revisions(), f'Member {member.url!r} did not finish downloading' |
293 | 335 |
|
294 | 336 |
|
295 | 337 | # === Untitled Project: Create Tests === |
|
0 commit comments