diff --git a/fimfarchive/tasks/update.py b/fimfarchive/tasks/update.py index b25f700..084e9d0 100644 --- a/fimfarchive/tasks/update.py +++ b/fimfarchive/tasks/update.py @@ -24,6 +24,7 @@ Update task. import os import time +from copy import deepcopy from typing import Optional from fimfarchive.exceptions import InvalidStoryError @@ -172,6 +173,29 @@ class UpdateTask(SignalSender): else: raise ValueError("Unsupported story flavor.") + def copy_archive_meta( + self, + old: Optional[Story], + new: Optional[Story], + ) -> None: + """ + Copies archive meta from old story to new. + + Args: + old: The story to copy from. + new: The story to copy to. + + Raises: + ValueError: If new story already contains archive meta. + """ + try: + if 'archive' in new.meta: + raise ValueError("New story contains archive meta.") + + new.meta['archive'] = deepcopy(old.meta['archive']) + except (AttributeError, InvalidStoryError, KeyError): + return + def update(self, key: int) -> Optional[Story]: """ Updates the specified story. @@ -184,6 +208,8 @@ class UpdateTask(SignalSender): """ old = self.fetch(self.fimfarchive, key) new = self.fetch(self.fimfiction, key) + + self.copy_archive_meta(old, new) selected = self.select(old, new) if selected and UpdateStatus.REVIVED in selected.flavors: diff --git a/tests/tasks/test_update.py b/tests/tasks/test_update.py index b0fa66f..3e061d3 100644 --- a/tests/tasks/test_update.py +++ b/tests/tasks/test_update.py @@ -22,6 +22,7 @@ Update task tests. # +from typing import Dict from unittest.mock import MagicMock, call, patch import pytest @@ -45,7 +46,7 @@ class DummyFetcher(Fetcher): """ Constructor. """ - self.stories = dict() + self.stories: Dict[int, Story] = dict() def add(self, key, date, flavors=()): """ @@ -111,6 +112,13 @@ class TestUpdateTask: """ return MagicMock() + @pytest.fixture + def archive(self): + """ + Returns an archive meta dictionary. + """ + return {'key': 'value'} + @pytest.fixture def task(self, fimfarchive, fimfiction, selector, stamper, tmpdir): """ @@ -199,25 +207,31 @@ class TestUpdateTask: self.verify_fetch(task, target, UpdateStatus.CREATED) - def test_revived_story(self, task, fimfarchive, fimfiction): + def test_revived_story(self, task, fimfarchive, fimfiction, archive): """ Tests updating for a revived story. """ target = fimfarchive.add(key=1, date=1) other = fimfiction.add(key=1, date=1) + target.meta['archive'] = archive target.merge = MagicMock(return_value=target) self.verify_fetch(task, target, UpdateStatus.REVIVED) target.merge.assert_called_once_with(meta=other.meta) + assert other.meta['archive'] is not archive + assert other.meta['archive'] == archive - def test_updated_story(self, task, fimfarchive, fimfiction): + def test_updated_story(self, task, fimfarchive, fimfiction, archive): """ Tests updating for an updated story. """ - fimfarchive.add(key=1, date=0) + other = fimfarchive.add(key=1, date=0) target = fimfiction.add(key=1, date=1) + other.meta['archive'] = archive self.verify_fetch(task, target, UpdateStatus.UPDATED) + assert target.meta['archive'] is not archive + assert target.meta['archive'] == archive def test_deleted_story(self, task, fimfarchive): """ @@ -317,6 +331,17 @@ class TestUpdateTask: with pytest.raises(ValueError): task.write(story) + def test_remote_archive(self, task, fimfarchive, fimfiction, archive): + """ + Tests `ValueError` is raised if Fimfiction returns archive meta. + """ + old = fimfarchive.add(key=1, date=0) + new = fimfiction.add(key=1, date=1) + new.meta['archive'] = archive + + with pytest.raises(ValueError): + task.copy_archive_meta(old, new) + class TestRefetchingUpdateTask(TestUpdateTask): """