"""
JSON to FPUB converter tests.
"""
#
# Fimfarchive, preserves stories from Fimfiction.
# Copyright (C) 2019 Joakim Soderlund
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see
REDACTED
' elif key == 'short_description': data[key] = "REDACTED" else: self.walk(value) class JsonFpubConverterSampler: """ Generates sample conversions for tests. Samples must be manually inspected for correctness. """ def __init__(self, token: str, *keys: int) -> None: """ Constructor. Args: token: Fimfiction APIv2 access token. keys: Stories to generate samples for. """ self.keys = sorted(int(key) for key in keys) self.fetcher = Fimfiction2Fetcher(token) self.convert = JsonFpubConverter() self.redactor = Redactor() def sample(self, key: int) -> Dict[str, Any]: """ Generates a sample conversion. """ story = self.fetcher.fetch(key) redacted = self.redact(story) converted = self.convert(redacted) return { 'key': int(key), 'meta': redacted.meta, 'json': json.loads(redacted.data.decode()), 'fpub': self.extract(converted.data), } def redact(self, story: Story) -> Story: """ Redacts a story. """ meta = deepcopy(story.meta) data = json.loads(story.data.decode()) self.redactor.walk(meta) self.redactor.walk(data) raw_data = json.dumps(data).encode() return story.merge(meta=meta, data=raw_data) def extract(self, data: bytes) -> List[Dict[str, Any]]: """ Lists the contents of a ZIP-file. """ output: List[Dict[str, Any]] = [] zobj = ZipFile(BytesIO(data)) for info in zobj.infolist(): output.append({ 'name': info.filename, 'text': zobj.read(info).decode(), }) return output def __iter__(self) -> Iterator[Dict[str, Any]]: """ Yields all samples. """ for key in self.keys: yield self.sample(key) def __str__(self) -> str: """ Serializes all samples. """ return json.dumps( obj={'pairs': list(self)}, ensure_ascii=False, sort_keys=True, indent=4, ) class TestJsonFpubConverter: """ JsonFpubConverter tests. """ @pytest.fixture def converter(self): """ Returns a JSON to FPUB converter instance. """ return JsonFpubConverter() @pytest.fixture(params=range(1)) def pair(self, request, data): """ Returns test data pairs. """ return data['pairs'][request.param] @pytest.fixture def json_story(self, pair): """ Returns a story in the JSON data format. """ return Story( key=pair['key'], meta=deepcopy(pair['meta']), data=json.dumps(pair['json']).encode(), flavors={MetaFormat.BETA, DataFormat.JSON}, ) @pytest.fixture def fpub_story(self, pair): """ Returns a story in the FPUB data format. """ stream = BytesIO() with ZipFile(stream, 'w') as zobj: for info in pair['fpub']: zobj.writestr(info['name'], info['text']) return Story( key=pair['key'], meta=deepcopy(pair['meta']), data=stream.getvalue(), flavors={MetaFormat.BETA, DataFormat.FPUB}, ) def test_conversion(self, converter, json_story, fpub_story): """ Tests conversion of story data from JSON to FPUB format. """ converted = converter(json_story) exp = ZipFile(BytesIO(fpub_story.data)) act = ZipFile(BytesIO(converted.data)) for einfo, ainfo in zip(exp.infolist(), act.infolist()): assert einfo.filename == ainfo.filename assert exp.read(einfo) == act.read(ainfo) def test_mimetype(self, converter, json_story): """ Tests mimetype is included correctly. """ converted = converter(json_story) zobj = ZipFile(BytesIO(converted.data)) info = zobj.infolist()[0] read = zobj.read(info).decode() assert 0 == info.compress_type assert 'mimetype' == info.filename assert 'application/epub+zip' == read def test_immutablilty(self, converter, json_story): """ Tests converter doesn't modify original. """ clone = deepcopy(json_story) converter(json_story) for attr in ('key', 'fetcher', 'meta', 'data', 'flavors'): assert getattr(clone, attr) == getattr(json_story, attr)