From 5b0cac515745102c1e3555da13b98c40baa2bd92 Mon Sep 17 00:00:00 2001 From: David Luevano Alvarado Date: Mon, 1 May 2023 06:58:27 -0600 Subject: add page class testing --- setup.cfg | 1 + src/pyssg/page.py | 59 ++++++++++----------------------- tests/conftest.py | 80 ++++++++++++++++++++++++++++++++++++++++++--- tests/test_configuration.py | 10 +++--- tests/test_page.py | 62 +++++++++++++++++++++++++++++++++++ 5 files changed, 161 insertions(+), 51 deletions(-) create mode 100644 tests/test_page.py diff --git a/setup.cfg b/setup.cfg index bf05793..9fcde08 100644 --- a/setup.cfg +++ b/setup.cfg @@ -64,6 +64,7 @@ per-file-ignores = custom_logger.py: E501 test_database_entry.py: E501 test_configuration.py: E501 + test_page.py: E501 [pbr] skip_authors = True diff --git a/src/pyssg/page.py b/src/pyssg/page.py index 4902bea..40eb41a 100644 --- a/src/pyssg/page.py +++ b/src/pyssg/page.py @@ -7,14 +7,14 @@ log: Logger = getLogger(__name__) class Page: def __init__(self, name: str, - ctime: float, - mtime: float, - html: str, - toc: str, - toc_tokens: list[str], - meta: dict[str, Any], - config: dict[str, Any], - dir_config: dict[str, Any]) -> None: + ctime: float, + mtime: float, + html: str, + toc: str, + toc_tokens: list[str], + meta: dict[str, Any], + config: dict[str, Any], + dir_config: dict[str, Any]) -> None: log.debug('initializing a page object with name "%s"', name) # initial data self.name: str = name @@ -38,7 +38,6 @@ class Page: # constructed self.url: str - self.image_url: str self.cdate_rss: str self.cdate_sitemap: str self.mdate_rss: str | None = None @@ -60,30 +59,29 @@ class Page: var, or_else) return or_else - def cdate(self, format: str) -> str: + # these date/cdate/mdate might be a bit overcomplicated + + def __date(self, dt: datetime, format: str) -> str: if format in self.config['fmt']: - return self.cdatetime.strftime(self.config['fmt'][format]) + return dt.strftime(self.config['fmt'][format]) else: log.warning('format "%s" not found in config, returning ' 'empty string', format) return '' + def cdate(self, format: str) -> str: + return self.__date(self.cdatetime, format) + def mdate(self, format: str) -> str: if self.mdatetime is None: log.warning('no mdatetime found, can\'t return a formatted string') return '' - if format in self.config['fmt']: - return self.mdatetime.strftime(self.config['fmt'][format]) - else: - log.warning('format "%s" not found in config, returning ' - 'empty string', format) - return '' + return self.__date(self.mdatetime, format) def from_timestamp(self, timestamp: float) -> datetime: return datetime.fromtimestamp(timestamp, tz=timezone.utc) - # parses meta from self.meta, for og, it prioritizes, - # the actual og meta + # parses meta from self.meta def parse_metadata(self): log.debug('parsing metadata for file "%s"', self.name) self.title = str(self.__get_meta('title')) @@ -124,26 +122,3 @@ class Page: name_html: str = self.name.replace(".md", ".html") self.url = f'{self.config["url"]["main"]}/{name_html}' log.debug('final url "%s"', self.url) - - log.debug('parsing image url') - default_image_url: str = '' - if 'default_image' in self.config['url']: - log.debug('"default_image" url found, will use if no "image_url" ' - 'is found') - default_image_url = self.config['url']['default_image'] - - image_url: str - image_url = str(self.__get_meta('image_url', default_image_url)) - - if image_url != '': - if 'static' in self.config['url']: - self.image_url = f'{self.config["url"]["static"]}/{image_url}' - else: - log.debug('no static url set, using main url') - self.image_url = f'{self.config["url"]["main"]}/{image_url}' - log.debug('final image url "%s"', self.image_url) - else: - self.image_url = '' - log.debug('no image url set for the page, could be because no' - ' "image_url" was found in the metadata and/or no ' - ' "default_image" set in the config file') diff --git a/tests/conftest.py b/tests/conftest.py index aaf0b3a..dc92eb1 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -9,10 +9,12 @@ from argparse import ArgumentParser from datetime import datetime, timezone from importlib.metadata import version as v from logging import Logger, getLogger, DEBUG +from copy import deepcopy from pyssg.arg_parser import get_parser from pyssg.custom_logger import setup_logger from pyssg.database_entry import DatabaseEntry +from pyssg.page import Page @pytest.fixture(scope='session') @@ -56,7 +58,7 @@ def logger() -> Logger: return getLogger(__name__) -@pytest.fixture +@pytest.fixture(scope='function') def capture_stdout(monkeypatch: MonkeyPatch) -> dict[str, str | int]: buffer: dict[str, str | int] = {'stdout': '', 'write_calls': 0} @@ -68,15 +70,15 @@ def capture_stdout(monkeypatch: MonkeyPatch) -> dict[str, str | int]: return buffer -@pytest.fixture +@pytest.fixture(scope='session') def get_fmt_time() -> Callable[..., str]: def fmt_time(fmt: str) -> str: return datetime.now(tz=timezone.utc).strftime(fmt) return fmt_time -@pytest.fixture -def default_config_dict() -> dict[str, Any]: +@pytest.fixture(scope='function') +def default_config() -> dict[str, Any]: return {'define': '$PYSSG_HOME/pyssg/site_example/', 'title': 'Example site', 'path': { @@ -98,6 +100,18 @@ def default_config_dict() -> dict[str, Any]: 'sitemap': False}}}} +@pytest.fixture(scope='function') +def root_dir_config() -> dict[str, Any]: + return {'plt': 'page.html', + 'tags': False, + 'index': False, + 'rss': False, + 'sitemap': False, + 'src': '/tmp/pyssg/pyssg/site_example/src', + 'dst': '/tmp/pyssg/pyssg/site_example/dst', + 'url': 'https://example.com'} + + @pytest.fixture(scope='function') def tmp_dir_structure(tmp_path: Path) -> Path: root: Path = tmp_path/'dir_structure' @@ -171,3 +185,61 @@ def tmp_src_dir(tmp_path: Path, for f in files: shutil.copy2(f'{src_test}/{f}', f'{str(src)}/{f}') return src + + +@pytest.fixture(scope='function') +def page_simple(default_config: dict[str, Any], + root_dir_config: dict[str, Any], + rss_date_fmt: str, + sitemap_date_fmt: str) -> Page: + # adding the fmt as it is added on the code before being passed to the page + config: dict[str, Any] = deepcopy(default_config) + config['fmt']['rss_date'] = rss_date_fmt + config['fmt']['sitemap_date'] = sitemap_date_fmt + + return Page( + name='simple.md', + ctime=1682418172.291993, + mtime=0.0, + html='

Simple converted md with nothing but this text.

', + toc='
\n\n
\n', + toc_tokens=[], + meta=dict(), + config=config, + dir_config=root_dir_config + ) + + +# this is basically page_simple with extras +@pytest.fixture(scope='function') +def page_simple_modified(default_config: dict[str, Any], + root_dir_config: dict[str, Any], + rss_date_fmt: str, + sitemap_date_fmt: str) -> Page: + config: dict[str, Any] = deepcopy(default_config) + config['fmt']['rss_date'] = rss_date_fmt + config['fmt']['sitemap_date'] = sitemap_date_fmt + + dir_config: dict[str, Any] = deepcopy(root_dir_config) + dir_config['tags'] = True + tags: list[str] = ['blog', 'english', 'etc'] + + basic_meta: dict[str, Any] = { + 'title': 'Example title', + 'author': 'Single Author', + 'summary': 'Some summary.', + 'lang': 'es', + 'tags': tags + } + + return Page( + name='simple_modified.md', + ctime=1682418300.291993, + mtime=1682418350.291993, + html='

Simple converted md with nothing but this text, modified.

', + toc='
\n\n
\n', + toc_tokens=[], + meta=basic_meta, + config=config, + dir_config=dir_config + ) diff --git a/tests/test_configuration.py b/tests/test_configuration.py index 36761eb..1b16441 100644 --- a/tests/test_configuration.py +++ b/tests/test_configuration.py @@ -24,11 +24,11 @@ def test_static_config(rss_date_fmt: str, def test_default_config(sample_files_path: str, default_yaml: str, - default_config_dict: dict[str, Any]) -> None: + default_config: dict[str, Any]) -> None: yaml_path: str = f'{sample_files_path}/config/{default_yaml}' yaml: list[dict[str, Any]] = get_parsed_config(yaml_path) assert len(yaml) == 1 - assert yaml[0] == default_config_dict + assert yaml[0] == default_config def test_default_config_mising_mandatory_key(sample_files_path: str, @@ -73,12 +73,12 @@ def test_default_config_root_dir(sample_files_path: str, # this really just tests that both documents in the yaml file are read, # both documents are the same (the default.yaml) def test_multiple_default_config(sample_files_path: str, - default_config_dict: dict[str, Any]) -> None: + default_config: dict[str, Any]) -> None: yaml_path: str = f'{sample_files_path}/config/multiple_default.yaml' yaml: list[dict[str, Any]] = get_parsed_config(yaml_path) assert len(yaml) == 2 - assert yaml[0] == default_config_dict - assert yaml[1] == default_config_dict + assert yaml[0] == default_config + assert yaml[1] == default_config # also, this just tests that the checks for a well formed config file are diff --git a/tests/test_page.py b/tests/test_page.py new file mode 100644 index 0000000..0ffaff8 --- /dev/null +++ b/tests/test_page.py @@ -0,0 +1,62 @@ +from copy import deepcopy +from logging import WARNING +from typing import Any +from pytest import LogCaptureFixture +from pyssg.page import Page + + +# TODO: this probably needs more testing, but I'm doing the coverage for now + + +def test_page_basic(page_simple: Page) -> None: + page_simple.parse_metadata() + assert page_simple.title == '' + assert page_simple.author == [''] + assert page_simple.summary == '' + assert page_simple.lang == 'en' + assert page_simple.url == f"{page_simple.dir_config['url']}/{page_simple.name.replace('.md', '.html')}" + + +def test_page_no_mdate(page_simple: Page, + caplog: LogCaptureFixture) -> None: + page_simple.parse_metadata() + war: tuple[str, int, str] = ('pyssg.page', + WARNING, + 'no mdatetime found, can\'t return a formatted string') + assert page_simple.mdate('date') == '' + assert caplog.record_tuples[-1] == war + + +def test_page_no_fmt(page_simple: Page, + caplog: LogCaptureFixture) -> None: + page_simple.parse_metadata() + war: tuple[str, int, str] = ('pyssg.page', + WARNING, + 'format "something" not found in config, ' + 'returning empty string') + assert page_simple.cdate('something') == '' + assert caplog.record_tuples[-1] == war + + +def test_page_comparison(page_simple: Page, + page_simple_modified: Page) -> None: + assert not page_simple > page_simple_modified + assert page_simple < page_simple_modified + assert page_simple != page_simple_modified + + +def test_page_modified(page_simple_modified: Page) -> None: + page_simple_modified.parse_metadata() + meta: dict[str, Any] = deepcopy(page_simple_modified.meta) + assert page_simple_modified.title == meta['title'] + assert page_simple_modified.author == list(meta['author']) + assert page_simple_modified.summary == meta['summary'] + assert page_simple_modified.lang == meta['lang'] + assert page_simple_modified.url == f"{page_simple_modified.dir_config['url']}/{page_simple_modified.name.replace('.md', '.html')}" + + +def test_page_modified_no_tags(page_simple_modified: Page) -> None: + meta: dict[str, Any] = deepcopy(page_simple_modified.meta) + meta['tags'] = [] + page_simple_modified.meta = meta + page_simple_modified.parse_metadata() -- cgit v1.2.3-70-g09d2