Add Linkki broadcast image
Build custom container images / build (map[base_image:php:8-fpm-alpine build_args:PHP_VERSION=8
context:php8-pgsql fingerprint_command:{ apk info -v | LC_ALL=C sort; find /usr/local/lib/php/extensions /usr/local/etc/php/conf.d -type f -exec sha256sum {} + | LC_ALL=C sort; }
name:ph… (push) Successful in 48s
Build custom container images / build (map[base_image:postgres:18 build_args:PG_VERSION=18
POSTGIS_VERSION=3
VCHORD_VERSION=0.5.3
context:postgres fingerprint_command:{ dpkg-query -W -f='${binary:Package}=${Version}\n' | LC_ALL=C sort; find /usr/lib/postgresql -type f -exec sha256su… (push) Successful in 55s
Build custom container images / build (map[base_image:python:3 build_args:PYTHON_VERSION=3
context:python-tools fingerprint_command:{ dpkg-query -W -f='${binary:Package}=${Version}\n' | LC_ALL=C sort; pip freeze | LC_ALL=C sort; }
name:python-tools oci_labels:org.opencontainers.ima… (push) Successful in 54s
Build custom container images / build (map[base_image:python:3.12-slim build_args:PYTHON_VERSION=3.12-slim
context:linkki-tiedotus fingerprint_command:{ dpkg-query -W -f='${binary:Package}=${Version}\n' | LC_ALL=C sort; pip freeze | LC_ALL=C sort; }
name:linkki-tiedotus oci_labels:… (push) Successful in 39s
Build custom container images / build (map[base_image:php:8-fpm-alpine build_args:PHP_VERSION=8
context:php8-pgsql fingerprint_command:{ apk info -v | LC_ALL=C sort; find /usr/local/lib/php/extensions /usr/local/etc/php/conf.d -type f -exec sha256sum {} + | LC_ALL=C sort; }
name:ph… (push) Successful in 48s
Build custom container images / build (map[base_image:postgres:18 build_args:PG_VERSION=18
POSTGIS_VERSION=3
VCHORD_VERSION=0.5.3
context:postgres fingerprint_command:{ dpkg-query -W -f='${binary:Package}=${Version}\n' | LC_ALL=C sort; find /usr/lib/postgresql -type f -exec sha256su… (push) Successful in 55s
Build custom container images / build (map[base_image:python:3 build_args:PYTHON_VERSION=3
context:python-tools fingerprint_command:{ dpkg-query -W -f='${binary:Package}=${Version}\n' | LC_ALL=C sort; pip freeze | LC_ALL=C sort; }
name:python-tools oci_labels:org.opencontainers.ima… (push) Successful in 54s
Build custom container images / build (map[base_image:python:3.12-slim build_args:PYTHON_VERSION=3.12-slim
context:linkki-tiedotus fingerprint_command:{ dpkg-query -W -f='${binary:Package}=${Version}\n' | LC_ALL=C sort; pip freeze | LC_ALL=C sort; }
name:linkki-tiedotus oci_labels:… (push) Successful in 39s
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
from linkki_poster.formatting import (
|
||||
CAPTION_LIMIT,
|
||||
estimate_caption_length,
|
||||
parse_markdown_template,
|
||||
render_preview_html,
|
||||
render_template,
|
||||
validate_markdown_syntax,
|
||||
)
|
||||
from linkki_poster.models import Language
|
||||
|
||||
|
||||
def test_markdown_subset_and_placeholder_rendering() -> None:
|
||||
raw = (
|
||||
"# title\n"
|
||||
"**bold** _italic_ ++under++ ~~strike~~ ||spoil|| `code` [site](https://example.com)\n"
|
||||
"Go [English](en) and [Finnish](fi)\n"
|
||||
)
|
||||
parsed = parse_markdown_template(raw)
|
||||
|
||||
unresolved = render_template(parsed, {})
|
||||
assert "<b>TITLE</b>" in unresolved
|
||||
assert "<b>bold</b>" in unresolved
|
||||
assert "<i>italic</i>" in unresolved
|
||||
assert "<u>under</u>" in unresolved
|
||||
assert "<s>strike</s>" in unresolved
|
||||
assert "<tg-spoiler>spoil</tg-spoiler>" in unresolved
|
||||
assert "<code>code</code>" in unresolved
|
||||
assert '<a href="https://example.com">site</a>' in unresolved
|
||||
assert "English" in unresolved
|
||||
assert "Finnish" in unresolved
|
||||
assert 'href="https://t.me/' not in unresolved
|
||||
|
||||
resolved = render_template(
|
||||
parsed,
|
||||
{
|
||||
Language.EN: "https://t.me/testchan/123",
|
||||
Language.FI: "https://t.me/testchan/456",
|
||||
},
|
||||
)
|
||||
assert '<a href="https://t.me/testchan/123">English</a>' in resolved
|
||||
assert '<a href="https://t.me/testchan/456">Finnish</a>' in resolved
|
||||
|
||||
|
||||
def test_caption_length_estimate_uses_worst_case_links() -> None:
|
||||
parsed = parse_markdown_template("[EN](en) " * 80)
|
||||
assert estimate_caption_length(parsed, "channel") > CAPTION_LIMIT
|
||||
|
||||
|
||||
def test_multiline_spoiler_is_supported() -> None:
|
||||
parsed = parse_markdown_template("||line1\n\nline2||")
|
||||
rendered = render_template(parsed, {})
|
||||
assert "<tg-spoiler>line1\n\nline2</tg-spoiler>" in rendered
|
||||
|
||||
|
||||
def test_validate_markdown_syntax_finds_unclosed_markers() -> None:
|
||||
issues = validate_markdown_syntax("Can we do **[bold links](fi)")
|
||||
messages = [issue.message for issue in issues]
|
||||
assert any("**" in message for message in messages)
|
||||
|
||||
|
||||
def test_lists_and_blockquotes_are_rendered_for_telegram_html() -> None:
|
||||
parsed = parse_markdown_template(
|
||||
"- item\n"
|
||||
" - nested\n"
|
||||
"1. first\n"
|
||||
" 1. nested first\n"
|
||||
"> quoted\n"
|
||||
"> text\n"
|
||||
)
|
||||
rendered = render_template(parsed, {})
|
||||
assert "• item" in rendered
|
||||
assert "\u00a0\u00a0\u00a0\u00a0• nested" in rendered
|
||||
assert "1. first" in rendered
|
||||
assert "\u00a0\u00a0\u00a0\u00a01. nested first" in rendered
|
||||
assert "<blockquote>quoted\ntext</blockquote>" in rendered
|
||||
|
||||
|
||||
def test_escaped_list_markers_and_heading_markers_stay_literal() -> None:
|
||||
parsed = parse_markdown_template("\\* not a list\n1\\. not numbered\n\\# not a heading")
|
||||
rendered = render_template(parsed, {})
|
||||
assert "* not a list" in rendered
|
||||
assert "1. not numbered" in rendered
|
||||
assert "# not a heading" in rendered
|
||||
|
||||
|
||||
def test_escaped_backticks_and_link_brackets_stay_literal() -> None:
|
||||
parsed = parse_markdown_template(
|
||||
r"test \`code` test" "\n"
|
||||
r"\```" "\n"
|
||||
"code\n"
|
||||
"```\n"
|
||||
r"\[label\]\(url\)"
|
||||
)
|
||||
rendered = render_template(parsed, {})
|
||||
assert r"test `code` test" in rendered
|
||||
assert "<code>code</code>" not in rendered
|
||||
assert "<pre><code>" not in rendered
|
||||
assert "[label](url)" in rendered
|
||||
|
||||
|
||||
def test_escaped_cross_language_link_stays_literal() -> None:
|
||||
parsed = parse_markdown_template(r"\[English](en)")
|
||||
rendered = render_template(parsed, {Language.EN: "https://t.me/test/123"})
|
||||
assert "[English](en)" in rendered
|
||||
assert 'href="https://t.me/test/123"' not in rendered
|
||||
|
||||
|
||||
def test_preview_renders_fake_links_for_available_targets() -> None:
|
||||
preview = render_preview_html("[English](en) [Finnish](fi)", {Language.EN})
|
||||
assert '<a href="#en">English</a>' in preview
|
||||
assert "Finnish" in preview
|
||||
assert 'href="#fi"' not in preview
|
||||
|
||||
|
||||
def test_apostrophes_are_not_escaped_in_headings_or_plain_text() -> None:
|
||||
heading = render_template(parse_markdown_template("#THERE'S"), {})
|
||||
plain_heading_char = render_template(parse_markdown_template("#'"), {})
|
||||
bold = render_template(parse_markdown_template("**THERE'S**"), {})
|
||||
|
||||
assert "<b>THERE'S</b>" in heading
|
||||
assert "<b>'</b>" in plain_heading_char
|
||||
assert "<b>THERE'S</b>" in bold
|
||||
assert "'" not in heading
|
||||
assert "'" not in plain_heading_char
|
||||
assert "'" not in bold
|
||||
Reference in New Issue
Block a user