# Path: fimfarchive/flavors.py
# class DataFormat(Flavor):
#     """
#     Indicates the file format of story data.
#     """
#     EPUB = ()
#     FPUB = ()
#     HTML = ()
#     JSON = ()
# 
# class MetaFormat(Flavor):
#     """
#     Indicates the general structure of story meta.
#     """
#     ALPHA = ()
#     BETA = ()
# 
# class UpdateStatus(Flavor):
#     """
#     Indicates if and how a story has changed.
#     """
#     CREATED = ()
#     REVIVED = ()
#     UPDATED = ()
#     DELETED = ()
# 
# Path: fimfarchive/mappers.py
# class StaticMapper(Mapper[T]):
#     """
#     Returns the supplied value for any call.
#     """
# 
#     def __init__(self, value: T) -> None:
#         self.value = value
# 
#     def __call__(self, story: Story) -> T:
#         return self.value
# 
# Path: fimfarchive/stampers.py
# class Stamper:
#     """
#     Adds archive-related information to stories.
#     """
# 
#     def get_archive(self, story: Story) -> Dict[str, Any]:
#         """
#         Finds or creates an archive dict.
# 
#         Args:
#             story: The story to stamp.
# 
#         Returns:
#             An archive dict for the story.
#         """
#         meta = story.meta
# 
#         if 'archive' not in meta:
#             meta['archive'] = dict()
# 
#         return meta['archive']
# 
#     def __call__(self, story: Story) -> None:
#         """
#         Applies the stamp to the story.
# 
#         Args:
#             story: The story to stamp.
#         """
#         raise NotImplementedError()
# 
# class FlavorStamper(Stamper):
#     """
#     Adds flavors to stories.
#     """
# 
#     def __init__(self, mapper: Callable[[Story], Optional[Flavor]]) -> None:
#         """
#         Constructor.
# 
#         Args:
#             mapper: Callable returning the flavor to stamp with.
#         """
#         self.map = mapper
# 
#     def __call__(self, story: Story) -> None:
#         flavor = self.map(story)
# 
#         if flavor:
#             story.flavors.add(flavor)
# 
# class PathStamper(Stamper):
#     """
#     Adds archive paths to stories.
#     """
# 
#     def __init__(self, mapper: Callable[[Story], Optional[str]]) -> None:
#         """
#         Constructor.
# 
#         Args:
#             mapper: Callable returning the path to stamp with.
#         """
#         self.map = mapper
# 
#     def __call__(self, story: Story) -> None:
#         archive = self.get_archive(story)
#         path = self.map(story)
# 
#         if 'path' in archive:
#             del archive['path']
# 
#         if 'path' in story.meta:
#             del story.meta['path']
# 
#         if path:
#             archive['path'] = path
# 
# class UpdateStamper(Stamper):
#     """
#     Adds modification dates to stories.
#     """
#     spec: Dict[str, Set[UpdateStatus]] = {
#         'date_created': {
#             UpdateStatus.CREATED,
#         },
#         'date_fetched': {
#             UpdateStatus.CREATED,
#             UpdateStatus.REVIVED,
#             UpdateStatus.UPDATED,
#         },
#         'date_updated': {
#             UpdateStatus.CREATED,
#             UpdateStatus.UPDATED,
#         },
#     }
# 
#     def __call__(self, story: Story) -> None:
#         """
#         Applies modification dates to a story.
# 
#         Args:
#             story: The story to stamp.
#         """
#         timestamp = arrow.utcnow().isoformat()
#         flavor = find_flavor(story, UpdateStatus)
#         archive = self.get_archive(story)
# 
#         archive['date_checked'] = timestamp
# 
#         for key, value in self.spec.items():
#             if flavor in value:
#                 archive[key] = timestamp
#             elif key not in archive:
#                 archive[key] = None


from unittest.mock import patch
from typing import Dict
from fimfarchive.flavors import DataFormat, MetaFormat, UpdateStatus
from fimfarchive.mappers import StaticMapper
from fimfarchive.stampers import (
    Stamper, FlavorStamper, PathStamper, UpdateStamper,
)
import arrow
import pytest
        meta = story.meta
        original: Dict = dict()
        meta['archive'] = original
        archive = stamper.get_archive(story)

        assert meta['archive'] is original
        assert archive is original


class TestUpdateStamper:
    """
    UpdateStamper tests.
    """

    @pytest.fixture
    def time(self):
        """
        Returns a timestamp for the mocked utcnow.
        """
        stamp = arrow.get(1)

        with patch('arrow.utcnow') as m:
            m.return_value = stamp
            yield stamp.isoformat()

    @pytest.fixture
    def stamper(self, time):
        """
        Returns an update stamper instance.
        """

# Path: fimfarchive/flavors.py
# class DataFormat(Flavor):
#     """
#     Indicates the file format of story data.
#     """
#     EPUB = ()
#     FPUB = ()
#     HTML = ()
#     JSON = ()
# 
# class MetaFormat(Flavor):
#     """
#     Indicates the general structure of story meta.
#     """
#     ALPHA = ()
#     BETA = ()
# 
# class UpdateStatus(Flavor):
#     """
#     Indicates if and how a story has changed.
#     """
#     CREATED = ()
#     REVIVED = ()
#     UPDATED = ()
#     DELETED = ()
# 
# Path: fimfarchive/mappers.py
# class StaticMapper(Mapper[T]):
#     """
#     Returns the supplied value for any call.
#     """
# 
#     def __init__(self, value: T) -> None:
#         self.value = value
# 
#     def __call__(self, story: Story) -> T:
#         return self.value
# 
# Path: fimfarchive/stampers.py
# class Stamper:
#     """
#     Adds archive-related information to stories.
#     """
# 
#     def get_archive(self, story: Story) -> Dict[str, Any]:
#         """
#         Finds or creates an archive dict.
# 
#         Args:
#             story: The story to stamp.
# 
#         Returns:
#             An archive dict for the story.
#         """
#         meta = story.meta
# 
#         if 'archive' not in meta:
#             meta['archive'] = dict()
# 
#         return meta['archive']
# 
#     def __call__(self, story: Story) -> None:
#         """
#         Applies the stamp to the story.
# 
#         Args:
#             story: The story to stamp.
#         """
#         raise NotImplementedError()
# 
# class FlavorStamper(Stamper):
#     """
#     Adds flavors to stories.
#     """
# 
#     def __init__(self, mapper: Callable[[Story], Optional[Flavor]]) -> None:
#         """
#         Constructor.
# 
#         Args:
#             mapper: Callable returning the flavor to stamp with.
#         """
#         self.map = mapper
# 
#     def __call__(self, story: Story) -> None:
#         flavor = self.map(story)
# 
#         if flavor:
#             story.flavors.add(flavor)
# 
# class PathStamper(Stamper):
#     """
#     Adds archive paths to stories.
#     """
# 
#     def __init__(self, mapper: Callable[[Story], Optional[str]]) -> None:
#         """
#         Constructor.
# 
#         Args:
#             mapper: Callable returning the path to stamp with.
#         """
#         self.map = mapper
# 
#     def __call__(self, story: Story) -> None:
#         archive = self.get_archive(story)
#         path = self.map(story)
# 
#         if 'path' in archive:
#             del archive['path']
# 
#         if 'path' in story.meta:
#             del story.meta['path']
# 
#         if path:
#             archive['path'] = path
# 
# class UpdateStamper(Stamper):
#     """
#     Adds modification dates to stories.
#     """
#     spec: Dict[str, Set[UpdateStatus]] = {
#         'date_created': {
#             UpdateStatus.CREATED,
#         },
#         'date_fetched': {
#             UpdateStatus.CREATED,
#             UpdateStatus.REVIVED,
#             UpdateStatus.UPDATED,
#         },
#         'date_updated': {
#             UpdateStatus.CREATED,
#             UpdateStatus.UPDATED,
#         },
#     }
# 
#     def __call__(self, story: Story) -> None:
#         """
#         Applies modification dates to a story.
# 
#         Args:
#             story: The story to stamp.
#         """
#         timestamp = arrow.utcnow().isoformat()
#         flavor = find_flavor(story, UpdateStatus)
#         archive = self.get_archive(story)
# 
#         archive['date_checked'] = timestamp
# 
#         for key, value in self.spec.items():
#             if flavor in value:
#                 archive[key] = timestamp
#             elif key not in archive:
#                 archive[key] = None


# Path: tests/test_stampers.py
from unittest.mock import patch
from typing import Dict
from fimfarchive.flavors import DataFormat, MetaFormat, UpdateStatus
from fimfarchive.mappers import StaticMapper
from fimfarchive.stampers import (
    Stamper, FlavorStamper, PathStamper, UpdateStamper,
)
import arrow
import pytest

        meta = story.meta
        original: Dict = dict()
        meta['archive'] = original
        archive = stamper.get_archive(story)

        assert meta['archive'] is original
        assert archive is original


class TestUpdateStamper:
    """
    UpdateStamper tests.
    """

    @pytest.fixture
    def time(self):
        """
        Returns a timestamp for the mocked utcnow.
        """
        stamp = arrow.get(1)

        with patch('arrow.utcnow') as m:
            m.return_value = stamp
            yield stamp.isoformat()

    @pytest.fixture
    def stamper(self, time):
        """
        Returns an update stamper instance.
        """

        return UpdateStamper()