diff --git a/tests/test_doc_sync_executor.py b/tests/test_doc_sync_executor.py index cb8ac70..b9a4064 100644 --- a/tests/test_doc_sync_executor.py +++ b/tests/test_doc_sync_executor.py @@ -60,23 +60,36 @@ class TestDocSyncExecutor: mock_upstream_dir = MagicMock() mock_gitea_dir = MagicMock() - # Setup directory mocking - mock_upstream_dir.iterdir.return_value = [ - MagicMock(name=".git", is_dir=lambda: True), - MagicMock(name="README.md", is_dir=lambda: False), - MagicMock(name="docs", is_dir=lambda: True), - ] - mock_gitea_dir.iterdir.return_value = [ - MagicMock(name=".git", is_dir=lambda: True) - ] + # Setup directory mocking. MagicMock(name=...) sets the mock's + # repr, not its .name attribute (classic gotcha — see + # test_executor_sync_specific_paths) — set .name explicitly so + # execute()'s `item.name != '.git'` check actually excludes it. + git_item = MagicMock(is_dir=lambda: True) + git_item.name = ".git" + readme_item = MagicMock(is_dir=lambda: False) + readme_item.name = "README.md" + docs_item = MagicMock(is_dir=lambda: True) + docs_item.name = "docs" + mock_upstream_dir.iterdir.return_value = [git_item, readme_item, docs_item] + + gitea_git_item = MagicMock(is_dir=lambda: True) + gitea_git_item.name = ".git" + mock_gitea_dir.iterdir.return_value = [gitea_git_item] mock_path.return_value = mock_work_dir mock_work_dir.__truediv__.side_effect = [mock_upstream_dir, mock_gitea_dir] - # Mock git status to show changes + # Mock git status to show changes. _get_git_commit is patched + # separately above and never calls the real _run_command, so it + # does not consume a slot in this side_effect list — the actual + # call order for this (clone-succeeds, entire-repo) path is: + # clone upstream, clone gitea, add, status, commit, tag, push + # branch, push tag. The list previously reserved a slot for + # "git rev-parse HEAD" that _run_command is never asked for, + # which shifted "M README.md\n" one call late and made + # `git status --porcelain` see "" (no changes) instead. mock_run.side_effect = [ "", # git clone upstream - "", # git rev-parse HEAD "", # git clone gitea "", # git add "M README.md\n", # git status --porcelain (has changes) @@ -108,7 +121,15 @@ class TestDocSyncExecutor: mock_get_commit.return_value = "abc123" - # Mock path operations + # Mock path operations. work_dir = Path(...) resolves to + # mock_path.return_value — mock_upstream_dir/mock_gitea_dir have + # to be reachable from there via __truediv__, the same way + # test_executor_successful_sync_entire_repo wires it, or + # `upstream_dir / doc_path` never reaches these mocks at all and + # falls through to an unconfigured auto-generated MagicMock + # instead (observed failure: TypeError joining a MagicMock into + # ', '.join(copied_paths)). + mock_work_dir = MagicMock() mock_upstream_dir = MagicMock() mock_gitea_dir = MagicMock() mock_docs = MagicMock(name="docs") @@ -121,6 +142,8 @@ class TestDocSyncExecutor: mock_examples.is_dir.return_value = True mock_examples.name = "examples" + mock_path.return_value = mock_work_dir + mock_work_dir.__truediv__.side_effect = [mock_upstream_dir, mock_gitea_dir] mock_upstream_dir.__truediv__.side_effect = [mock_docs, mock_examples] mock_gitea_dir.iterdir.return_value = [] @@ -159,13 +182,27 @@ class TestDocSyncExecutor: mock_run.side_effect = run_command_side_effect - # Setup minimal mocking + # Setup minimal mocking. sample_doc_sync_config's docs_paths is + # ["/docs"] (tests/conftest.py), so execute() takes the + # specific-paths branch and needs `upstream_dir / "docs"` wired + # to something with a real string .name — see + # test_executor_sync_specific_paths for the same wiring gap and + # the TypeError it produces unwired. mock_work_dir = MagicMock() mock_upstream_dir = MagicMock() mock_gitea_dir = MagicMock() mock_gitea_dir.iterdir.return_value = [] mock_upstream_dir.iterdir.return_value = [] + mock_docs = MagicMock() + mock_docs.exists.return_value = True + mock_docs.is_dir.return_value = True + mock_docs.name = "docs" + + mock_path.return_value = mock_work_dir + mock_work_dir.__truediv__.side_effect = [mock_upstream_dir, mock_gitea_dir] + mock_upstream_dir.__truediv__.side_effect = [mock_docs] + result = await doc_sync_executor.execute(sample_doc_sync_config, test_settings) assert "already up to date" in result.lower() or "no changes" in result.lower()