pyrtan / tests / test_template.py
2,282 bytes · last changed 2026-10-25 in Initial public release
| 1 | import pytest |
| 2 | |
| 3 | from pyrtan.template import MISSING, TemplateError, placeholders, render, resolve |
| 4 | |
| 5 | SCOPE = {"inputs": {"city": "New York", "n": 3}, "state": {"resp": {"json": {"items": [{"title": "a"}, {"title": "b"}]}, "status": 200}, "ids": [1, 2, 3]}} |
| 6 | |
| 7 | |
| 8 | def test_resolve_paths(): |
| 9 | assert resolve("inputs.city", SCOPE) == "New York" |
| 10 | assert resolve("state.resp.json.items[1].title", SCOPE) == "b" |
| 11 | assert resolve("state.resp.json.items[-1].title", SCOPE) == "b" |
| 12 | assert resolve("state.ids[5]", SCOPE) is MISSING |
| 13 | assert resolve("state.nope.deeper", SCOPE) is MISSING |
| 14 | assert resolve('state.resp["status"]', SCOPE) == 200 |
| 15 | |
| 16 | |
| 17 | def test_whole_placeholder_keeps_type(): |
| 18 | assert render("{{ state.ids }}", SCOPE) == [1, 2, 3] |
| 19 | assert render("{{ state.resp.status }}", SCOPE) == 200 |
| 20 | |
| 21 | |
| 22 | def test_interpolation_and_filters(): |
| 23 | assert render("city={{ inputs.city | url }}", SCOPE) == "city=New%20York" |
| 24 | assert render("{{ inputs.city | lower }} x{{ inputs.n }}", SCOPE) == "new york x3" |
| 25 | assert render("{{ state.ids | length }}", SCOPE) == 3 |
| 26 | assert render("{{ state.ids | first }}", SCOPE) == 1 |
| 27 | assert render("{{ state.resp.json.items | json }}", SCOPE) == '[{"title": "a"}, {"title": "b"}]' |
| 28 | |
| 29 | |
| 30 | def test_nested_structures_render(): |
| 31 | out = render({"url": "https://x/{{ inputs.n }}", "list": ["{{ inputs.city }}", 1]}, SCOPE) |
| 32 | assert out == {"url": "https://x/3", "list": ["New York", 1]} |
| 33 | |
| 34 | |
| 35 | def test_missing_is_an_error_unless_lenient(): |
| 36 | with pytest.raises(TemplateError): |
| 37 | render("{{ state.nothing }}", SCOPE) |
| 38 | with pytest.raises(TemplateError): |
| 39 | render("x {{ state.nothing }} y", SCOPE) |
| 40 | assert render("x {{ state.nothing }} y", SCOPE, strict=False) == "x y" |
| 41 | assert render("{{ state.nothing }}", SCOPE, strict=False) is None |
| 42 | |
| 43 | |
| 44 | def test_unknown_filter(): |
| 45 | with pytest.raises(TemplateError): |
| 46 | render("{{ inputs.city | shout }}", SCOPE) |
| 47 | |
| 48 | |
| 49 | def test_multiple_placeholders_are_not_one(): |
| 50 | # A regression: a greedy placeholder regex once swallowed the text between two. |
| 51 | assert render("{{ inputs.city }} ({{ inputs.n }})", SCOPE) == "New York (3)" |
| 52 | |
| 53 | |
| 54 | def test_placeholders_listing(): |
| 55 | assert placeholders({"a": "{{ inputs.x | url }}", "b": ["{{ state.y }}", "{{ item }}"]}) == ["inputs.x", "state.y", "item"] |