mirror of
https://github.com/JockeTF/fimfarchive.git
synced 2025-02-08 14:56:44 +01:00
Add mapper for story date
This commit is contained in:
parent
d2601f6966
commit
2015d184d8
2 changed files with 227 additions and 2 deletions
|
@ -24,10 +24,13 @@ Mappers for Fimfarchive.
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
from fimfarchive.exceptions import InvalidStoryError
|
||||||
|
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'Mapper',
|
'Mapper',
|
||||||
'StaticMapper',
|
'StaticMapper',
|
||||||
|
'StoryDateMapper',
|
||||||
'StoryPathMapper',
|
'StoryPathMapper',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -53,6 +56,35 @@ class StaticMapper(Mapper):
|
||||||
return self.value
|
return self.value
|
||||||
|
|
||||||
|
|
||||||
|
class StoryDateMapper(Mapper):
|
||||||
|
"""
|
||||||
|
Returns the latest timestamp in a story, or None.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __call__(self, story):
|
||||||
|
try:
|
||||||
|
meta = getattr(story, 'meta', None)
|
||||||
|
except InvalidStoryError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if not meta:
|
||||||
|
return None
|
||||||
|
|
||||||
|
dates = {
|
||||||
|
meta.get('date_modified'),
|
||||||
|
}
|
||||||
|
|
||||||
|
for chapter in meta.get('chapters') or tuple():
|
||||||
|
dates.add(chapter.get('date_modified'))
|
||||||
|
|
||||||
|
dates.discard(None)
|
||||||
|
|
||||||
|
if dates:
|
||||||
|
return max(dates)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
class StoryPathMapper(Mapper):
|
class StoryPathMapper(Mapper):
|
||||||
"""
|
"""
|
||||||
Returns a key-based file path for a story.
|
Returns a key-based file path for a story.
|
||||||
|
|
|
@ -23,11 +23,17 @@ Mapper tests.
|
||||||
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import patch, MagicMock, PropertyMock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from fimfarchive.mappers import StaticMapper, StoryPathMapper
|
from fimfarchive.exceptions import InvalidStoryError
|
||||||
|
from fimfarchive.mappers import StaticMapper, StoryDateMapper, StoryPathMapper
|
||||||
|
from fimfarchive.stories import Story
|
||||||
|
|
||||||
|
|
||||||
|
CHAPTERS = 'chapters'
|
||||||
|
MODIFIED = 'date_modified'
|
||||||
|
|
||||||
|
|
||||||
class TestStaticMapper:
|
class TestStaticMapper:
|
||||||
|
@ -71,6 +77,193 @@ class TestStaticMapper:
|
||||||
assert mapper(a=1, b=2) is value
|
assert mapper(a=1, b=2) is value
|
||||||
|
|
||||||
|
|
||||||
|
class TestStoryDateMapper:
|
||||||
|
"""
|
||||||
|
StoryDateMapper tests.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def mapper(self):
|
||||||
|
"""
|
||||||
|
Returns a new StoryDateMapper.
|
||||||
|
"""
|
||||||
|
return StoryDateMapper()
|
||||||
|
|
||||||
|
def merge(self, story, meta):
|
||||||
|
"""
|
||||||
|
Returns a cloned story containing the supplied meta.
|
||||||
|
"""
|
||||||
|
return Story(
|
||||||
|
key=story.key,
|
||||||
|
fetcher=None,
|
||||||
|
meta=meta,
|
||||||
|
data=story.data,
|
||||||
|
flavors=story.flavors,
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_missing_story(self, mapper):
|
||||||
|
"""
|
||||||
|
Tests `None` is returned when story is `None`.
|
||||||
|
"""
|
||||||
|
assert mapper(None) is None
|
||||||
|
|
||||||
|
def test_invalid_story(self, mapper, story):
|
||||||
|
"""
|
||||||
|
Tests `None` is returned when `InvalidStoryError` is raised.
|
||||||
|
"""
|
||||||
|
with patch.object(Story, 'meta', new_callable=PropertyMock) as m:
|
||||||
|
m.side_effect = InvalidStoryError
|
||||||
|
|
||||||
|
assert mapper(story) is None
|
||||||
|
assert m.called_once_with(story)
|
||||||
|
|
||||||
|
def test_empty_meta(self, mapper, story):
|
||||||
|
"""
|
||||||
|
Tests `None` is returned when meta is empty.
|
||||||
|
"""
|
||||||
|
story = self.merge(story, dict())
|
||||||
|
|
||||||
|
assert mapper(story) is None
|
||||||
|
|
||||||
|
def test_meta_without_dates(self, mapper, story):
|
||||||
|
"""
|
||||||
|
Tests `None` is returned when meta contains no dates.
|
||||||
|
"""
|
||||||
|
meta = {
|
||||||
|
CHAPTERS: [
|
||||||
|
dict(),
|
||||||
|
dict(),
|
||||||
|
dict(),
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
story = self.merge(story, meta)
|
||||||
|
|
||||||
|
assert mapper(story) is None
|
||||||
|
|
||||||
|
def test_meta_without_chapters(self, mapper, story):
|
||||||
|
"""
|
||||||
|
Tests timestamp is returned when no chapters are present.
|
||||||
|
"""
|
||||||
|
meta = {
|
||||||
|
MODIFIED: 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
story = self.merge(story, meta)
|
||||||
|
|
||||||
|
assert mapper(story) == 5
|
||||||
|
|
||||||
|
def test_meta_with_none_chapters(self, mapper, story):
|
||||||
|
"""
|
||||||
|
Tests timestamp is returned when chapters is `None`.
|
||||||
|
"""
|
||||||
|
meta = {
|
||||||
|
MODIFIED: 5,
|
||||||
|
CHAPTERS: None,
|
||||||
|
}
|
||||||
|
|
||||||
|
story = self.merge(story, meta)
|
||||||
|
|
||||||
|
assert mapper(story) == 5
|
||||||
|
|
||||||
|
def test_meta_with_empty_chapters(self, mapper, story):
|
||||||
|
"""
|
||||||
|
Tests timestamp is returned when chapters is empty.
|
||||||
|
"""
|
||||||
|
meta = {
|
||||||
|
MODIFIED: 5,
|
||||||
|
CHAPTERS: [],
|
||||||
|
}
|
||||||
|
|
||||||
|
story = self.merge(story, meta)
|
||||||
|
|
||||||
|
assert mapper(story) == 5
|
||||||
|
|
||||||
|
def test_meta_with_only_chapter_dates(self, mapper, story):
|
||||||
|
"""
|
||||||
|
Tests timestamp is returned when only chapter dates are present.
|
||||||
|
"""
|
||||||
|
meta = {
|
||||||
|
CHAPTERS: [
|
||||||
|
{MODIFIED: 3},
|
||||||
|
{MODIFIED: 5},
|
||||||
|
{MODIFIED: 4},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
story = self.merge(story, meta)
|
||||||
|
|
||||||
|
assert mapper(story) == 5
|
||||||
|
|
||||||
|
def test_meta_with_only_story_date(self, mapper, story):
|
||||||
|
"""
|
||||||
|
Tests timestamp is returned when only story date is present.
|
||||||
|
"""
|
||||||
|
meta = {
|
||||||
|
MODIFIED: 5,
|
||||||
|
CHAPTERS: [
|
||||||
|
dict(),
|
||||||
|
dict(),
|
||||||
|
dict(),
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
story = self.merge(story, meta)
|
||||||
|
|
||||||
|
assert mapper(story) == 5
|
||||||
|
|
||||||
|
def test_meta_with_latest_chapter_date(self, mapper, story):
|
||||||
|
"""
|
||||||
|
Tests latests timestamp is returned when in chapter dates.
|
||||||
|
"""
|
||||||
|
meta = {
|
||||||
|
MODIFIED: 3,
|
||||||
|
CHAPTERS: [
|
||||||
|
{MODIFIED: 1},
|
||||||
|
{MODIFIED: 5},
|
||||||
|
{MODIFIED: 3},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
story = self.merge(story, meta)
|
||||||
|
|
||||||
|
assert mapper(story) == 5
|
||||||
|
|
||||||
|
def test_meta_with_latest_story_date(self, mapper, story):
|
||||||
|
"""
|
||||||
|
Tests latest timestamp is returned when in story date.
|
||||||
|
"""
|
||||||
|
meta = {
|
||||||
|
MODIFIED: 5,
|
||||||
|
CHAPTERS: [
|
||||||
|
{MODIFIED: 1},
|
||||||
|
{MODIFIED: 3},
|
||||||
|
{MODIFIED: 2},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
story = self.merge(story, meta)
|
||||||
|
|
||||||
|
assert mapper(story) == 5
|
||||||
|
|
||||||
|
def test_meta_with_both_latest(self, mapper, story):
|
||||||
|
"""
|
||||||
|
Tests latest timestamp is returned when in both.
|
||||||
|
"""
|
||||||
|
meta = {
|
||||||
|
MODIFIED: 5,
|
||||||
|
CHAPTERS: [
|
||||||
|
{MODIFIED: 1},
|
||||||
|
{MODIFIED: 5},
|
||||||
|
{MODIFIED: 3},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
story = self.merge(story, meta)
|
||||||
|
|
||||||
|
assert mapper(story) == 5
|
||||||
|
|
||||||
|
|
||||||
class TestStoryPathMapper:
|
class TestStoryPathMapper:
|
||||||
"""
|
"""
|
||||||
StoryPathMapper tests.
|
StoryPathMapper tests.
|
||||||
|
|
Loading…
Reference in a new issue