home · contact · privacy
Extend template testing to /balance, improve its template code. master
authorChristian Heller <c.heller@plomlompom.de>
Tue, 13 Jan 2026 20:40:16 +0000 (21:40 +0100)
committerChristian Heller <c.heller@plomlompom.de>
Tue, 13 Jan 2026 20:40:16 +0000 (21:40 +0100)
src/ledgplom/http.py
src/ledgplom/testing.py
src/templates/balance.tmpl
src/tests/empty.balance [new file with mode: 0644]
src/tests/full.balance [new file with mode: 0644]
src/tests/full.dat
src/tests/full.ledger_raw
src/tests/full.ledger_structured

index 1938525b13638dc15af4fdb8e95265f3459bfbc1..3306a8df34cd47968c9ac57f2f23a77ba4277cc1 100644 (file)
@@ -16,6 +16,7 @@ _SERVER_HOST = '127.0.0.1'
 _SERVER_PORT = 8084
 _TOK_RAW = 'raw'
 _TOK_STRUCTURED = 'structured'
+PAGENAME_BALANCE = 'balance'
 _PAGENAME_EDIT_RAW = f'{_PREFIX_EDIT}{_TOK_RAW}'
 _PAGENAME_EDIT_STRUCTURED = f'{_PREFIX_EDIT}{_TOK_STRUCTURED}'
 PAGENAME_LEDGER_RAW = f'{_PREFIX_LEDGER}{_TOK_RAW}'
@@ -111,7 +112,7 @@ class _Handler(PlomHttpHandler):
         ### start = time_ns()
         ctx = {'unsaved_changes': self.server.ledger.tainted,
                'path': self.path}
-        if self.pagename == 'balance':
+        if self.pagename == PAGENAME_BALANCE:
             self.get_balance(ctx)
         elif self.pagename.startswith(_PREFIX_EDIT):
             self.get_edit(ctx, self.pagename == _PAGENAME_EDIT_RAW)
@@ -133,7 +134,7 @@ class _Handler(PlomHttpHandler):
         ctx['valid'] = self.server.ledger.blocks_valid_up_incl(id_)
         ctx['block'] = self.server.ledger.blocks[id_]
         ctx['path_up_incl'] = f'{self.path_toks[1]}?up_incl='
-        self._send_rendered('balance', ctx)
+        self._send_rendered(PAGENAME_BALANCE, ctx)
 
     def get_edit(self, ctx, raw: bool) -> None:
         'Display edit form for individual Booking.'
index 844128d0f0c8dc9311165366e4bcf20e8371b198..8e7a53aa22b37627c63a46b5cc52d1514d332ebb 100644 (file)
@@ -2,13 +2,14 @@
 # built-ins
 from sys import exit as sys_exit
 from pathlib import Path
-from typing import Optional
+from typing import Any, Optional
 # requirements.txt
 from jinja2 import (Environment as JinjaEnv,
                     FileSystemLoader as JinjaFSLoader)
 # ourselves
-from ledgplom.http import (PAGENAME_LEDGER_RAW, PAGENAME_LEDGER_STRUCTURED,
-                           PATH_TEMPLATES)
+from ledgplom.http import (
+        PAGENAME_BALANCE, PAGENAME_LEDGER_RAW, PAGENAME_LEDGER_STRUCTURED,
+        PATH_TEMPLATES)
 from ledgplom.ledger import Ledger
 
 
@@ -27,10 +28,11 @@ def run_tests() -> None:
     jinja = JinjaEnv(loader=JinjaFSLoader(PATH_TEMPLATES),
                      autoescape=True,
                      trim_blocks=True)
-    templates = {item: jinja.get_template(f'{item}.tmpl')
-                 for item in (PAGENAME_LEDGER_RAW, PAGENAME_LEDGER_STRUCTURED)}
+    templates = {item: jinja.get_template(f'{item}.tmpl') for item in (
+        PAGENAME_BALANCE, PAGENAME_LEDGER_RAW, PAGENAME_LEDGER_STRUCTURED)}
     for path in [p for p in _PATH_TESTS.iterdir()
                  if p.parts[-1].endswith(_EXT_DAT)]:
+        ledger = Ledger(path)
         for key, template in templates.items():
             test_path = Path(str(path)[:-len(_EXT_DAT)] + f'.{key}')
             if not test_path.exists():
@@ -38,10 +40,20 @@ def run_tests() -> None:
             with test_path.open('r', encoding='utf8') as f:
                 lines_expected = [line.rstrip('\n')
                                   for line in f.readlines()]
-            ledger = Ledger(path)
-            ctx = {
-                'blocks': ledger.blocks,
-                'has_redundant_empty_lines': ledger.has_redundant_empty_lines}
+            ctx: dict[str, Any] = {}
+            if key == PAGENAME_BALANCE:
+                id_ = len(ledger.blocks) - 1
+                ctx['roots'] = sorted([ac for
+                                       ac in ledger.calc_accounts().values()
+                                       if not ac.parent],
+                                      key=lambda r: r.basename)
+                ctx['valid'] = ledger.blocks_valid_up_incl(id_)
+                ctx['block'] = ledger.blocks[id_]
+                ctx['path_up_incl'] = f'{PAGENAME_BALANCE}?up_incl='
+            else:
+                ctx['blocks'] = ledger.blocks
+                ctx['has_redundant_empty_lines'] =\
+                    ledger.has_redundant_empty_lines
             lines_rendered = template.render(**ctx).split('\n')
             msg_prefix = f'test for {test_path}:'
             for idx0, line in enumerate(lines_rendered):
index f9eece8d1fa360bd463d5b05f4d0c0abb2337376..1812ce9fdf863891f08c9d21783dae7e1f68d378 100644 (file)
@@ -9,7 +9,7 @@ td.money table {
     float: left;
 }
 summary::marker {
-    {{ macros.css_noninput_monospace() }}
+{{ macros.css_noninput_monospace() -}}
 }
 summary {
     list-style-type: "[…]";
@@ -24,62 +24,65 @@ span.indent {
 
 
 
-{% macro account_with_children(block_id, account, indent) %}
-{% macro tr_money_balance(amount, currency) %}
-    <tr>
-    <td class="balance amount">{{amount}}</td>
-    <td class="balance currency">{{ macros.currency_short(currency) }}</td>
-    </tr>
+{% macro account_with_children(block_id, account, name_indent) %}
+
+{%- macro _(code_indent=1) %}
+{{- " " * 4 * code_indent -}}
+{% endmacro %}
+
+{%- macro tr_money_balance(amount, currency, i=4) %}
+{{_(i)}}<tr>
+{{_(i)}}    <td class="balance amount">
+                {{- amount -}}
+            </td>
+{{_(i)}}    <td class="balance currency">
+                {{- macros.currency_short(currency) -}}
+            </td>
+{{_(i)}}</tr>
 {% endmacro %}
-{% if account.get_wealth_at(block_id).moneys|length > 0 %}
-    <tr>
-    <td class="money">
-    {% if account.get_wealth_at(block_id).moneys|length == 1 %}
-        <table>
-        {% for currency, amount in account.get_wealth_at(block_id).moneys.items() %}
-            {{tr_money_balance(amount, currency)}}
-        {% endfor %}
-        </table>
-    {% else %}
-        <details>
-        <summary>
-        <table>
-        {% for currency, amount in account.get_wealth_at(block_id).moneys.items() %}
-            {% if 1 == loop.index %}
-                {{tr_money_balance(amount, currency)}}
-            {% endif %}
-        {% endfor %}
-        </table>
-        </summary>
-        <table>
-        {% for currency, amount in account.get_wealth_at(block_id).moneys.items() %}
-            {% if 1 < loop.index %}
-                {{tr_money_balance(amount, currency)}}
-            {% endif %}
-        {% endfor %}
-        </table>
-        </details>
-    {% endif %}
-    </td>
-    <td>
-    <span class="indent">{%
-      for i in range(indent) %}&nbsp;{%
-      endfor
-    %}</span>{%
-      if account.parent
-      %}:{%
-      endif
-      %}{{account.basename}}{%
-      if account.children
-      %}:{%
-      endif
-    %}
-    </td>
-    <td>{{account.desc}}</td>
-    </tr>
-    {% for child in account.children_euro_sorted_at(block_id) %}
-        {{account_with_children(block_id, child, indent=indent+1)}}
-    {% endfor %}
+
+{%- if account.get_wealth_at(block_id).moneys | length > 0 %}
+{{_()}}<tr>
+{{_()}}    <td class="money">
+{##}{% if account.get_wealth_at(block_id).moneys | length == 1 %}
+{{_()}}        <table>
+{######}{% for cur, amt in account.get_wealth_at(block_id).moneys.items() %}
+                   {{- tr_money_balance(amt, cur) -}}
+{######}{% endfor %}
+{{_()}}        </table>
+{##}{% else %}
+{{_()}}        <details>
+{{_()}}            <summary>
+{{_()}}                <table>
+{######}{% for cur, amt in account.get_wealth_at(block_id).moneys.items() %}
+                           {{- tr_money_balance(amt, cur, i=6)
+                               if 1 == loop.index -}}
+{######}{% endfor %}
+{{_()}}                </table>
+{{_()}}            </summary>
+{{_()}}            <table>
+{######}{% for cur, amt in account.get_wealth_at(block_id).moneys.items() %}
+                       {{- tr_money_balance(amt, cur, 5) if 1 < loop.index -}}
+{######}{% endfor %}
+{{_()}}            </table>
+{{_()}}        </details>
+{##}{% endif %}
+{{_()}}    </td>
+{{_()}}    <td>
+{{_()}}        <span class="indent">{##}
+{######}{% for n in range(name_indent) -%}
+                   &nbsp;{# -#}
+{######}{% endfor -%}
+               </span>
+               {{- ":" if account.parent }}
+               {{- account.basename }}
+               {{- ":" if account.children }}
+{{_()}}    </td>
+{{_()}}    <td>{{ account.desc }}</td>
+{{_()}}</tr>
+{##}{% for child in account.children_euro_sorted_at(block_id) %}
+      {{- account_with_children(block_id, child, name_indent=name_indent+1) -}}
+{##}{% endfor %}
 {% endif %}
 {% endmacro %}
 
@@ -87,14 +90,18 @@ span.indent {
 
 {% block content %}
 <p>
-{{macros.conditional_block_nav(path_up_incl,'prev',block)}}
-{{macros.conditional_block_nav(path_up_incl,'next',block)}}
-|
-balance after <a href="/blocks/{{block.id_}}">booking {{block.id_}} ({{block.booking.date}}: {{block.booking.target}})</a>
+    {{ macros.conditional_block_nav(path_up_incl, 'prev', block) -}}{##}
+    {{ macros.conditional_block_nav(path_up_incl, 'next', block) }}{##}
+    |
+    balance after {# -#}
+    <a href="/blocks/{{block.id_}}">{# -#}
+        booking {{block.id_}} {# -#}
+        ({{ block.booking.date }}: {{ block.booking.target }}){# -#}
+    </a>
 </p>
 <table class="alternating {% if not valid %}critical{% endif %}">
 {% for root in roots %}
-    {{account_with_children(block.id_,root,indent=0)}}
+{{ account_with_children(block.id_, root, name_indent=0) -}}
 {% endfor %}
 </table>
 {% endblock %}
diff --git a/src/tests/empty.balance b/src/tests/empty.balance
new file mode 100644 (file)
index 0000000..cfd8da5
--- /dev/null
@@ -0,0 +1,93 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+<script>
+</script>
+<style>
+html {
+    scroll-padding-top: 2em;
+}
+body {
+    background: #ffffff;
+    font-family: sans-serif;
+    text-align: left;
+    margin: 0;
+    padding: 0;
+}
+#header {
+    background: #ffffff;
+    position: sticky;
+    top: 0;
+    padding-left: 0.5em;
+    padding-bottom: 0.25em;
+    border-bottom: 1px solid black;
+}
+table.alternating > tbody > tr:nth-child(odd) {
+    background-color: #dcdcdc;
+}
+table.alternating > tbody > tr:nth-child(even) {
+    background: #ffffff;
+}
+td {
+    vertical-align: top;
+}
+.critical {
+    background: #ff6666 !important;
+}
+td.amount {
+    text-align: right;
+}
+td.amount,
+td.currency {
+    font-family: monospace;
+    font-size: 1.25em;
+}
+table.alternating.critical > tbody > tr:nth-child(even) {
+    background-color: #ff8a8a;
+}
+td.balance.amount {
+    width: 10em;
+}
+td.balance.currency {
+    width: 3em;
+}
+td.money table {
+    float: left;
+}
+summary::marker {
+    font-family: monospace;
+    font-size: 1.25em;
+}
+summary {
+    list-style-type: "[…]";
+}
+details[open] > summary {
+    list-style-type: "[^]";
+}
+span.indent {
+    letter-spacing: 3em;
+}
+</style>
+</head>
+<body>
+<div id="header">
+    <form action="" method="POST">
+        <span class="disable_on_change">
+            ledger <a href="/ledger_structured">structured</a>
+            / <a href="/ledger_raw">raw</a>
+            · <a href="/balance">balance</a>
+            · <input type="submit"name="file_load" value="reload" />
+        </span>
+    </form>
+</div>
+<p>
+    <del>prev</del>
+    <del>next</del>
+    |
+    balance after <a href="/blocks/0">booking 0 (: )</a>
+</p>
+<table class="alternating ">
+</table>
+</body>
+</html>
diff --git a/src/tests/full.balance b/src/tests/full.balance
new file mode 100644 (file)
index 0000000..c348be1
--- /dev/null
@@ -0,0 +1,221 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+<script>
+</script>
+<style>
+html {
+    scroll-padding-top: 2em;
+}
+body {
+    background: #ffffff;
+    font-family: sans-serif;
+    text-align: left;
+    margin: 0;
+    padding: 0;
+}
+#header {
+    background: #ffffff;
+    position: sticky;
+    top: 0;
+    padding-left: 0.5em;
+    padding-bottom: 0.25em;
+    border-bottom: 1px solid black;
+}
+table.alternating > tbody > tr:nth-child(odd) {
+    background-color: #dcdcdc;
+}
+table.alternating > tbody > tr:nth-child(even) {
+    background: #ffffff;
+}
+td {
+    vertical-align: top;
+}
+.critical {
+    background: #ff6666 !important;
+}
+td.amount {
+    text-align: right;
+}
+td.amount,
+td.currency {
+    font-family: monospace;
+    font-size: 1.25em;
+}
+table.alternating.critical > tbody > tr:nth-child(even) {
+    background-color: #ff8a8a;
+}
+td.balance.amount {
+    width: 10em;
+}
+td.balance.currency {
+    width: 3em;
+}
+td.money table {
+    float: left;
+}
+summary::marker {
+    font-family: monospace;
+    font-size: 1.25em;
+}
+summary {
+    list-style-type: "[…]";
+}
+details[open] > summary {
+    list-style-type: "[^]";
+}
+span.indent {
+    letter-spacing: 3em;
+}
+</style>
+</head>
+<body>
+<div id="header">
+    <form action="" method="POST">
+        <span class="disable_on_change">
+            ledger <a href="/ledger_structured">structured</a>
+            / <a href="/ledger_raw">raw</a>
+            · <a href="/balance">balance</a>
+            · <input type="submit"name="file_load" value="reload" />
+        </span>
+    </form>
+</div>
+<p>
+    <a href="balance?up_incl=3">prev</a>
+    <del>next</del>
+    |
+    balance after <a href="/blocks/4">booking 4 (2001-01-01: test)</a>
+</p>
+<table class="alternating ">
+    <tr>
+        <td class="money">
+            <details>
+                <summary>
+                    <table>
+                        <tr>
+                            <td class="balance amount">-10</td>
+                            <td class="balance currency">€</td>
+                        </tr>
+                    </table>
+                </summary>
+                <table>
+                    <tr>
+                        <td class="balance amount">-1</td>
+                        <td class="balance currency">USD</td>
+                    </tr>
+                </table>
+            </details>
+        </td>
+        <td>
+            <span class="indent"></span>bar:
+        </td>
+        <td></td>
+    </tr>
+    <tr>
+        <td class="money">
+            <table>
+                <tr>
+                    <td class="balance amount">-10</td>
+                    <td class="balance currency">€</td>
+                </tr>
+            </table>
+        </td>
+        <td>
+            <span class="indent">&nbsp;</span>:x:
+        </td>
+        <td></td>
+    </tr>
+    <tr>
+        <td class="money">
+            <table>
+                <tr>
+                    <td class="balance amount">-10</td>
+                    <td class="balance currency">€</td>
+                </tr>
+            </table>
+        </td>
+        <td>
+            <span class="indent">&nbsp;&nbsp;</span>:y
+        </td>
+        <td></td>
+    </tr>
+    <tr>
+        <td class="money">
+            <table>
+                <tr>
+                    <td class="balance amount">-1</td>
+                    <td class="balance currency">USD</td>
+                </tr>
+            </table>
+        </td>
+        <td>
+            <span class="indent">&nbsp;</span>:z
+        </td>
+        <td></td>
+    </tr>
+    <tr>
+        <td class="money">
+            <table>
+                <tr>
+                    <td class="balance amount">-10</td>
+                    <td class="balance currency">€</td>
+                </tr>
+            </table>
+        </td>
+        <td>
+            <span class="indent"></span>baz
+        </td>
+        <td></td>
+    </tr>
+    <tr>
+        <td class="money">
+            <details>
+                <summary>
+                    <table>
+                        <tr>
+                            <td class="balance amount">20</td>
+                            <td class="balance currency">€</td>
+                        </tr>
+                    </table>
+                </summary>
+                <table>
+                    <tr>
+                        <td class="balance amount">1</td>
+                        <td class="balance currency">USD</td>
+                    </tr>
+                </table>
+            </details>
+        </td>
+        <td>
+            <span class="indent"></span>foo:
+        </td>
+        <td></td>
+    </tr>
+    <tr>
+        <td class="money">
+            <details>
+                <summary>
+                    <table>
+                        <tr>
+                            <td class="balance amount">10</td>
+                            <td class="balance currency">€</td>
+                        </tr>
+                    </table>
+                </summary>
+                <table>
+                    <tr>
+                        <td class="balance amount">1</td>
+                        <td class="balance currency">USD</td>
+                    </tr>
+                </table>
+            </details>
+        </td>
+        <td>
+            <span class="indent">&nbsp;</span>:x
+        </td>
+        <td></td>
+    </tr>
+</table>
+</body>
+</html>
index 2866ede4e46b563ca0e89dc3e13136eb57f32cff..1f7f85a4ecc1f4ff878e92e023c1e0df18664ef4 100644 (file)
@@ -12,6 +12,7 @@
     baz   -20 €  ; baz
 
 2001-01-01 test
-    foo    10 €
-    bar   -10 €
-
+    foo:x    10 €
+    foo:x    1 USD
+    bar:x:y   -10 €
+    bar:z   -1 USD
index 50bf269a7465de3510a8678a6a90aee16dc2e0c8..7134672eff38183045ee2ade26a7f5b7d5c8aa0d 100644 (file)
@@ -163,7 +163,7 @@ Detected redundant empty lines in gaps, <input type="submit" name="remove_redund
     <tr><td>&nbsp;</td></tr>
     <tr></tr><!-- keep the background-color alternation in proper order -->
     <tr id="block_4">
-        <td rowspan=5 class="block_column critical">
+        <td rowspan=7 class="block_column critical">
             <input type="submit"
                    name="ledger_moveup_4"
                    value="^"
@@ -178,15 +178,17 @@ Detected redundant empty lines in gaps, <input type="submit" name="remove_redund
             <br />
             <input type="submit" name="ledger_copy_4" value="C"/>
         </td>
-        <td rowspan=5 class="block_column">
+        <td rowspan=7 class="block_column">
             [<a href="#block_4">#</a>]<br />
             [<a href="/balance?up_incl=4">b</a>]<br />
             [<a href="/edit_raw/4">e</a>]
         </td>
     </tr>
     <tr><td>2001-01-01 test&nbsp;</td></tr>
-    <tr><td>  foo  10 €&nbsp;</td></tr>
-    <tr><td>  bar  -10 €&nbsp;</td></tr>
+    <tr><td>  foo:x  10 €&nbsp;</td></tr>
+    <tr><td>  foo:x  1 USD&nbsp;</td></tr>
+    <tr><td>  bar:x:y  -10 €&nbsp;</td></tr>
+    <tr><td>  bar:z  -1 USD&nbsp;</td></tr>
     <tr><td>&nbsp;</td></tr>
 </table>
 </form>
index d572547e6a722c3e24c3ca198587b69b81475d38..f83b1a65198cb729818cbd1cca6cfb641af7a18b 100644 (file)
@@ -215,7 +215,7 @@ Detected redundant empty lines in gaps, <input type="submit" name="remove_redund
     </tr>
     <tr></tr><!-- keep the background-color alternation in proper order -->
     <tr id="block_4">
-        <td rowspan=5 class="block_column critical">
+        <td rowspan=7 class="block_column critical">
             <input type="submit"
                    name="ledger_moveup_4"
                    value="^"
@@ -230,7 +230,7 @@ Detected redundant empty lines in gaps, <input type="submit" name="remove_redund
             <br />
             <input type="submit" name="ledger_copy_4" value="C"/>
         </td>
-        <td rowspan=5 class="block_column">
+        <td rowspan=7 class="block_column">
             [<a href="#block_4">#</a>]<br />
             [<a href="/balance?up_incl=4">b</a>]<br />
             [<a href="/edit_structured/4">e</a>]
@@ -243,13 +243,25 @@ Detected redundant empty lines in gaps, <input type="submit" name="remove_redund
     <tr>
         <td class="amount">10.00</td>
         <td class="currency">€</td>
-        <td>foo</td>
+        <td>foo:x</td>
+        <td></td>
+    </tr>
+    <tr>
+        <td class="amount">1.00</td>
+        <td class="currency">USD</td>
+        <td>foo:x</td>
         <td></td>
     </tr>
     <tr>
         <td class="amount">-10.00</td>
         <td class="currency">€</td>
-        <td>bar</td>
+        <td>bar:x:y</td>
+        <td></td>
+    </tr>
+    <tr>
+        <td class="amount">-1.00</td>
+        <td class="currency">USD</td>
+        <td>bar:z</td>
         <td></td>
     </tr>
     <tr>