From: Christian Heller Date: Wed, 7 Jan 2026 18:41:40 +0000 (+0100) Subject: Add basic testing infrastructure. X-Git-Url: https://plomlompom.com/repos/booking/%7B%7B%20web_path%20%7D%7D/decks/%7B%7Bprefix%7D%7D/copy_structured?a=commitdiff_plain;p=ledgplom Add basic testing infrastructure. --- diff --git a/src/ledgplom/http.py b/src/ledgplom/http.py index 4efc05a..85d4aa3 100644 --- a/src/ledgplom/http.py +++ b/src/ledgplom/http.py @@ -1,13 +1,14 @@ 'Collect directly HTTP-related elements.' -# standard libs +# built-ins from pathlib import Path from typing import Any -# non-standard libs +# plomlib from plomlib.web import PlomHttpHandler, PlomHttpServer, PlomQueryMap +# ourselves from ledgplom.ledger import Account, DatBlock, DEFAULT_INDENT, Ledger -_PATH_TEMPLATES = Path('templates') +PATH_TEMPLATES = Path('templates') _PREFIX_EDIT = 'edit_' _PREFIX_FILE = 'file_' _PREFIX_LEDGER = 'ledger_' @@ -18,14 +19,14 @@ _TOK_STRUCTURED = 'structured' _PAGENAME_EDIT_RAW = f'{_PREFIX_EDIT}{_TOK_RAW}' _PAGENAME_EDIT_STRUCTURED = f'{_PREFIX_EDIT}{_TOK_STRUCTURED}' _PAGENAME_LEDGER_RAW = f'{_PREFIX_LEDGER}{_TOK_RAW}' -_PAGENAME_LEDGER_STRUCTURED = f'{_PREFIX_LEDGER}{_TOK_STRUCTURED}' +PAGENAME_LEDGER_STRUCTURED = f'{_PREFIX_LEDGER}{_TOK_STRUCTURED}' class Server(PlomHttpServer): 'Extends parent by loading .dat file into database for Handler.' def __init__(self, path_dat: Path, *args, **kwargs) -> None: - super().__init__(_PATH_TEMPLATES, + super().__init__(PATH_TEMPLATES, (_SERVER_HOST, _SERVER_PORT), _Handler) self.ledger = Ledger(path_dat) @@ -106,6 +107,8 @@ class _Handler(PlomHttpHandler): self.redirect( Path('/', _PAGENAME_EDIT_STRUCTURED, self.path_toks[2])) return + ### from time import time_ns + ### start = time_ns() ctx = {'unsaved_changes': self.server.ledger.tainted, 'path': self.path} if self.pagename == 'balance': @@ -116,6 +119,9 @@ class _Handler(PlomHttpHandler): self.get_ledger(ctx, self.pagename == _PAGENAME_LEDGER_RAW) else: self.get_ledger(ctx, False) + ### end = time_ns() + ### duration = (end - start) / (10 ** 9) + ### print("DEBUG GET", self.pagename, f'{duration:8.5f}') def get_balance(self, ctx) -> None: 'Display tree of calculated Accounts over blocks up_incl+1.' @@ -187,4 +193,4 @@ class _Handler(PlomHttpHandler): ctx['has_redundant_empty_lines'] =\ self.server.ledger.has_redundant_empty_lines self._send_rendered( - _PAGENAME_LEDGER_RAW if raw else _PAGENAME_LEDGER_STRUCTURED, ctx) + _PAGENAME_LEDGER_RAW if raw else PAGENAME_LEDGER_STRUCTURED, ctx) diff --git a/src/ledgplom/testing.py b/src/ledgplom/testing.py new file mode 100644 index 0000000..4bc4ba9 --- /dev/null +++ b/src/ledgplom/testing.py @@ -0,0 +1,47 @@ +'To run tests.' +# built-ins +from sys import exit as sys_exit +from pathlib import Path +from typing import Optional +# requirements.txt +from jinja2 import (Environment as JinjaEnv, + FileSystemLoader as JinjaFSLoader) +# ourselves +from ledgplom.http import PAGENAME_LEDGER_STRUCTURED, PATH_TEMPLATES +from ledgplom.ledger import Ledger + + +_EXT_DAT = '.dat' +_EXT_HTML = '.html' +_PATH_TESTS = Path('tests') + + +def run_tests() -> None: + 'Run tests from tests directory.' + def fail(abort_msg: str, msg_prefix: str, idx: Optional[int]) -> None: + for jdx, line in enumerate(lines_rendered[:idx], start=1): + print(f'{jdx}: [{line}]') + print(f'{msg_prefix} FAILED – {abort_msg}') + sys_exit(1) + + jinja = JinjaEnv(loader=JinjaFSLoader(PATH_TEMPLATES), autoescape=True) + tmpl = jinja.get_template(f'{PAGENAME_LEDGER_STRUCTURED}.tmpl') + for path in [p for p in _PATH_TESTS.iterdir() + if p.parts[-1].endswith(_EXT_DAT)]: + with Path(str(path)[:-len(_EXT_DAT)] + _EXT_HTML + ).open('r', encoding='utf8') as f: + lines_expected = [line.rstrip('\n') for line in f.readlines()] + lines_rendered = tmpl.render(blocks=Ledger(path).blocks).split('\n') + msg_prefix = f'test for {path}:' + for idx0, line in enumerate(lines_rendered): + idx1 = idx0 + 1 + abort_msg = '' + if idx1 > len(lines_expected): + abort_msg = f'only {idx0} lines expected' + elif lines_expected[idx0] != line: + abort_msg = f'line differs, expected: [{lines_expected[idx0]}]' + if abort_msg: + fail(abort_msg, msg_prefix, idx1) + if len(lines_expected) > idx1: + fail(f'more lines expected line {idx1}', msg_prefix, None) + print(f'{msg_prefix} passed') diff --git a/src/run.py b/src/run.py index 077e62a..c6546d0 100755 --- a/src/run.py +++ b/src/run.py @@ -1,22 +1,35 @@ #!/usr/bin/env python3 'Viewer and editor for ledger .dat files.' -# standard libs +# built-ins from os import environ from pathlib import Path -from sys import exit as sys_exit -# non-standard libs +from sys import argv, exit as sys_exit +# plomlib from plomlib.setup import dependency_hint +# ourselves try: from ledgplom.http import Server + from ledgplom.testing import run_tests except ModuleNotFoundError as e: dependency_hint(e) -LEDGER_DAT = environ.get('LEDGER_DAT') +_ARG_TEST = 'test' +_NAME_ENV_LEDGER_DAT = 'LEDGER_DAT' +_LEDGER_DAT = environ.get(_NAME_ENV_LEDGER_DAT) if __name__ == '__main__': - if not LEDGER_DAT: - print('LEDGER_DAT environment variable not set.') + if len(argv) == 1: + if not _LEDGER_DAT: + print(f'{_NAME_ENV_LEDGER_DAT} environment variable not set.') + sys_exit(1) + Server(Path(_LEDGER_DAT)).serve() + elif len(argv) == 2: + if argv[1] != _ARG_TEST: + print('fail: unknown arg argument') + sys_exit(1) + run_tests() + else: + print('fail: expected zero or one arguments') sys_exit(1) - Server(Path(LEDGER_DAT)).serve() diff --git a/src/tests/test.dat b/src/tests/test.dat new file mode 100644 index 0000000..e69de29 diff --git a/src/tests/test.html b/src/tests/test.html new file mode 100644 index 0000000..fd0e2f5 --- /dev/null +++ b/src/tests/test.html @@ -0,0 +1,119 @@ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
+
+
+ +
+[#]
+[b]
+[e] +
 
+ +
+ + +