From 4a855e6a832f92c5fa8a8056f40d83a8affbb4d5 Mon Sep 17 00:00:00 2001 From: agent_coder Date: Mon, 6 Jul 2026 18:26:50 +0300 Subject: [PATCH] =?UTF-8?q?refactor(render):=20=D1=8D=D1=82=D0=B0=D0=BF=20?= =?UTF-8?q?5b=20=E2=80=94=20=D0=B7=D0=B0=D1=80=D0=B5=D0=B3=D0=B8=D1=81?= =?UTF-8?q?=D1=82=D1=80=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=BD=D1=8B?= =?UTF-8?q?=D0=B5=20=D1=84=D0=B8=D0=BA=D1=81=D1=8B=20=D0=BC=D0=B5=D0=B4?= =?UTF-8?q?=D0=B8=D0=B0-=D1=82=D0=B0=D0=B1=D0=BB=D0=B8=D1=86=D1=8B=20?= =?UTF-8?q?=C2=A73.13/=C2=A73.14=20(#32)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Поверх байт-в-байт 5a — только фиксы реестра: - §3.14: закрывающий эмитится в КАЖДОЙ ветке media-рендера (раньше несбалансированный div в конце фрагмента авто-закрывался bleach позже). На фрагмент-оракуле изменились ровно 2 кейса (file_unique_id_none, webpage_without_photo); в feed-голденах — чисто РЕЛОКАЦИЯ с конца поста на место сразу после пустого media-div (счётчик не меняется, контент идентичен). Затронуты каналы с webpage-без-фото (theyforcedme без изменений). - §3.13: гард >100MB теперь на ЛЮБОЙ media-объект (не только message.video); collection-only, байты фида не трогает. test_stage5b_media_fixes.py (14 тестов). Полный сюит 427 passed, PYTHONHASHSEED 1/42. Golden строго по §3 (проверял независимо: net-теги 0, только -релокация). Co-Authored-By: Claude Opus 4.8 (1M context) --- post_parser.py | 34 ++--- .../golden/bladerunnerblues.feed.html | 12 +- .../test_data/golden/bladerunnerblues.rss.xml | 12 +- tests/test_data/golden/embedoka.feed.html | 3 +- tests/test_data/golden/embedoka.rss.xml | 3 +- tests/test_data/golden/meow_design.feed.html | 3 +- tests/test_data/golden/meow_design.rss.xml | 3 +- tests/test_data/media_fragments.json | 4 +- tests/test_stage5b_media_fixes.py | 137 ++++++++++++++++++ 9 files changed, 177 insertions(+), 34 deletions(-) create mode 100644 tests/test_stage5b_media_fixes.py diff --git a/post_parser.py b/post_parser.py index 5d8bb6a..1b306e3 100644 --- a/post_parser.py +++ b/post_parser.py @@ -973,7 +973,6 @@ class PostParser: # Guard: channel_username may be None for private chats without a username if not channel_username: logger.warning(f"Could not generate media URL for message {message.id}: channel username is missing.") - content_media.append('') else: file = f"{channel_username}/{message.id}/{file_unique_id}" digest = generate_media_digest(file) @@ -1004,7 +1003,11 @@ class PostParser: elif kind == 'img_200_sticker': ctx.emoji = getattr(message.sticker, 'emoji', '') content_media.extend(renderer(ctx)) - content_media.append('') + # Registry §3.14: close the message-media container in EVERY branch. It used + # to be closed only when a URL was built (or the username guard fired), so a + # None file_unique_id (e.g. WEB_PAGE without photo) left an open
that + # html5lib later swallowed the following posts into. + content_media.append('
') if webpage := getattr(message, "web_page", None): # Web page preview if webpage_html := self._format_webpage(webpage, message): @@ -1365,27 +1368,18 @@ class PostParser: return if message.media: - # Skip large videos - they shouldn't be cached permanently. - # 5a keeps this message.video-only guard verbatim; registry §3.13 - # generalises the >100MB rule to every selected object in 5b. - if message.video and message.video.file_size and message.video.file_size > 100 * 1024 * 1024: - return - - # Object selection now goes through the single MEDIA_SOURCES table - # instead of the old truthy-attribute if/elif ladder. paid_media has no - # table entry and is deliberately NOT collected (paid content). + # Object selection goes through the single MEDIA_SOURCES table instead + # of the old truthy-attribute if/elif ladder. paid_media has no table + # entry and is deliberately NOT collected (paid content). selector = MEDIA_SOURCES.get(message.media) selected_obj = selector(message)[0] if selector is not None else None - # The message.video guard above does not cover the Kurigram 2.2.23 - # sources (live photo, story video, poll description video) — apply the - # same "don't cache large videos" rule to them (5b unifies this — §3.13). - if message.media in (MessageMediaType.LIVE_PHOTO, - MessageMediaType.STORY, - MessageMediaType.POLL): - file_size = getattr(selected_obj, 'file_size', None) - if isinstance(file_size, int) and file_size > 100 * 1024 * 1024: - return + # Registry §3.13: the ">100MB don't cache" rule applies to ANY selected + # media object, not just message.video (the old code guarded only the + # video type here, plus the newer live_photo/story/poll sources). + file_size = getattr(selected_obj, 'file_size', None) + if isinstance(file_size, int) and file_size > 100 * 1024 * 1024: + return file_unique_id = getattr(selected_obj, 'file_unique_id', '') or '' diff --git a/tests/test_data/golden/bladerunnerblues.feed.html b/tests/test_data/golden/bladerunnerblues.feed.html index 94063fb..b385409 100644 --- a/tests/test_data/golden/bladerunnerblues.feed.html +++ b/tests/test_data/golden/bladerunnerblues.feed.html @@ -982,33 +982,36 @@
+

Я тут одним днем был в Екатеринбурге. На конференции по кибербезопасности. На уральском ТВ записали короткое интервью. Не для экспертов, для обычных жителей планеты Земля - что такое кибербез простыми словами, какие угрозы сейчас и что делать - быть может кому-то будет полезно.

*** по каким-то мистическим причинам, не всегда с мобилы проигрывается, с десктопа - точно работает. Не знаю, почему.

p.s. На Мэта Деймона времени не хватило (с) :))

https://www.obltv.ru/broadcasting/programs/479443-sobytija_akcent/releases/4840574-evgeniy-chereshnev-seychas-khakery-eto-ne-studenty-idealisty-a-organizovannye-nayemniki/

+
🏷 link

+

[ХОРОШИЕ НОВОСТИ ОБ ИННОВАЦИЯХ НА НЕСКОЛЬКО МИЛЛИАРДОВ ЗА ГОД И ДЕТЯХ, РОЖДЕННЫХ В СССР]

Дорогой экипаж!

Вдохновения и мотивации пост.
Не собирался писать именно это и так эмоционально, но потом перечитал и решил, что не буду редактировать.
И, даже если кто-то отпишется, – я никого не держу. Просто в это турбулентное время, хочется продолжать дарить вам надежду в лучшее, а не поощрять самоуничижение, как это делают многие.

Хочу констатировать факты: не все уехали, не все плохо, нет, мы умеем делать сильные инженерные рывки в России (а не только в ВПК), нам есть, чем гордится и да, я считаю, что мы единый народ.
Хочу, чтобы кому-то этот пост помог улыбнуться и ступать легко и уверенно.

https://blog.cheresh.me/2024/02/20/billions-in-innovations-and-ussr/

P.S. Репосты приветствуются. А вот воровать не надо. Кто ворует мои посты - вы выглядите не очень умно:) Вы думаете, люди не видят, что ли?:) Карма is a bitch.

+
🏷 link

+

Экипаж!

Менять мир непросто. Иногда нам нужна правильная музыка. Приказ по радиорубке - включаем с утра на всех палубах и заряжаемся. Нас ждет прыжок в созвездие Ориона.

https://youtu.be/9N_AinKeT_g?si=SFAulfGSNuGmh9QU

P.S. если сегодня будете где-то слышать этот трек - знайте, что его поставил ваш брат или сестра с этого корабля:) и улыбнитесь:)
с пятницей!

+
🏷 link

@@ -1087,13 +1090,14 @@
+

[ПРОГНОЗЫ 2024, Часть 1/14: Выборы на Тайване]

Дорогой экипаж!
Завтра очень важный день для планеты Земля - пройдут выборы президента Тайваня. Почему они критичны для всех и каждого и причем тут Искусственный Интеллект и триллионы долларов - постарался описать максимально коротко. Прогнозы делать - дело неблагодарное, но я решил начать цикл постов о том, что нас ждет в 2024, что важно и что имеет все шансы навсегда изменить мир.

https://blog.cheresh.me/2024/01/12/really-unreal-forecasts-2024_114/

+
🏷 link

diff --git a/tests/test_data/golden/bladerunnerblues.rss.xml b/tests/test_data/golden/bladerunnerblues.rss.xml index 8762c20..1691d5a 100644 --- a/tests/test_data/golden/bladerunnerblues.rss.xml +++ b/tests/test_data/golden/bladerunnerblues.rss.xml @@ -32,13 +32,14 @@ [ПРОГНОЗЫ 2024, Часть 1/14: Выборы на Тайване] Дорогой экипаж! Завтра очень важный день для планеты Земля - пройдут выборы президента Тайваня. Почему они критичны для всех и каждого и причем тут Искусственный Интеллект и триллионы долларов - постарался описать максимально коротко. Прогнозы делать - дело неблагодарное, но я решил начать цикл постов о том, что нас ждет в 2024, что важно и что имеет все шансы навсегда изменить мир. https://blog.cheresh.me/2024/01/12/really-unreal-forecasts-2024_114/
+

[ПРОГНОЗЫ 2024, Часть 1/14: Выборы на Тайване]

Дорогой экипаж!
Завтра очень важный день для планеты Земля - пройдут выборы президента Тайваня. Почему они критичны для всех и каждого и причем тут Искусственный Интеллект и триллионы долларов - постарался описать максимально коротко. Прогнозы делать - дело неблагодарное, но я решил начать цикл постов о том, что нас ждет в 2024, что важно и что имеет все шансы навсегда изменить мир.

https://blog.cheresh.me/2024/01/12/really-unreal-forecasts-2024_114/

]]> +
🏷 link
]]> https://t.me/bladerunnerblues/296 Fri, 12 Jan 2024 16:52:43 +0000 @@ -153,13 +154,14 @@ Экипаж! Менять мир непросто. Иногда нам нужна правильная музыка. Приказ по радиорубке - включаем с утра на всех палубах и заряжаемся. Нас ждет прыжок в созвездие Ориона. https://youtu.be/9N_AinKeT_g?si=SFAulfGSNuGmh9QU P.S. если сегодня будете где-то слышать этот трек - знайте, что его поставил ваш брат или сестра с этого корабля:) и улыбнитесь:) с пятницей!
+

Экипаж!

Менять мир непросто. Иногда нам нужна правильная музыка. Приказ по радиорубке - включаем с утра на всех палубах и заряжаемся. Нас ждет прыжок в созвездие Ориона.

https://youtu.be/9N_AinKeT_g?si=SFAulfGSNuGmh9QU

P.S. если сегодня будете где-то слышать этот трек - знайте, что его поставил ваш брат или сестра с этого корабля:) и улыбнитесь:)
с пятницей!

]]> +
🏷 link
]]> https://t.me/bladerunnerblues/304 Fri, 16 Feb 2024 05:23:23 +0000 @@ -169,13 +171,14 @@ [ХОРОШИЕ НОВОСТИ ОБ ИННОВАЦИЯХ НА НЕСКОЛЬКО МИЛЛИАРДОВ ЗА ГОД И ДЕТЯХ, РОЖДЕННЫХ В СССР] Дорогой экипаж! Вдохновения и мотивации пост. Не собирался писать именно это и так эмоционально, но потом перечитал и решил, что не буду редактировать. И, даже если кто-то отпишется, – я никого не держу. Просто в это турбулентное время, хочется продолжать дарить вам надежду в лучшее, а не поощрять самоуничижение, как это делают многие. Хочу констатировать факты: не все уехали, не все плохо, нет, мы умеем делать сильные инженерные рывки в России (а не только в ВПК), нам есть, чем гордится и да, я считаю, что мы единый народ. Хочу, чтобы кому-то этот пост помог улыбнуться и ступать легко и уверенно. https://blog.cheresh.me/2024/02/20/billions-in-innovations-and-ussr/ P.S. Репосты приветствуются. А вот воровать не надо. Кто ворует мои посты - вы выглядите не очень умно:) Вы думаете, люди не видят, что ли?:) Карма is a bitch.
+

[ХОРОШИЕ НОВОСТИ ОБ ИННОВАЦИЯХ НА НЕСКОЛЬКО МИЛЛИАРДОВ ЗА ГОД И ДЕТЯХ, РОЖДЕННЫХ В СССР]

Дорогой экипаж!

Вдохновения и мотивации пост.
Не собирался писать именно это и так эмоционально, но потом перечитал и решил, что не буду редактировать.
И, даже если кто-то отпишется, – я никого не держу. Просто в это турбулентное время, хочется продолжать дарить вам надежду в лучшее, а не поощрять самоуничижение, как это делают многие.

Хочу констатировать факты: не все уехали, не все плохо, нет, мы умеем делать сильные инженерные рывки в России (а не только в ВПК), нам есть, чем гордится и да, я считаю, что мы единый народ.
Хочу, чтобы кому-то этот пост помог улыбнуться и ступать легко и уверенно.

https://blog.cheresh.me/2024/02/20/billions-in-innovations-and-ussr/

P.S. Репосты приветствуются. А вот воровать не надо. Кто ворует мои посты - вы выглядите не очень умно:) Вы думаете, люди не видят, что ли?:) Карма is a bitch.

]]>
+
🏷 link
]]> https://t.me/bladerunnerblues/305 Tue, 20 Feb 2024 10:10:22 +0000 @@ -185,13 +188,14 @@ Я тут одним днем был в Екатеринбурге. На конференции по кибербезопасности. На уральском ТВ записали короткое интервью. Не для экспертов, для обычных жителей планеты Земля - что такое кибербез простыми словами, какие угрозы сейчас и что делать - быть может кому-то будет полезно. *** по каким-то мистическим причинам, не всегда с мобилы проигрывается, с десктопа - точно работает. Не знаю, почему. p.s. На Мэта Деймона времени не хватило (с) :)) https://www.obltv.ru/broadcasting/programs/479443-sobytija_akcent/releases/4840574-evgeniy-chereshnev-seychas-khakery-eto-ne-studenty-idealisty-a-organizovannye-nayemniki/
+

Я тут одним днем был в Екатеринбурге. На конференции по кибербезопасности. На уральском ТВ записали короткое интервью. Не для экспертов, для обычных жителей планеты Земля - что такое кибербез простыми словами, какие угрозы сейчас и что делать - быть может кому-то будет полезно.

*** по каким-то мистическим причинам, не всегда с мобилы проигрывается, с десктопа - точно работает. Не знаю, почему.

p.s. На Мэта Деймона времени не хватило (с) :))

https://www.obltv.ru/broadcasting/programs/479443-sobytija_akcent/releases/4840574-evgeniy-chereshnev-seychas-khakery-eto-ne-studenty-idealisty-a-organizovannye-nayemniki/

]]>
+
🏷 link
]]> https://t.me/bladerunnerblues/306 Tue, 20 Feb 2024 14:01:23 +0000 diff --git a/tests/test_data/golden/embedoka.feed.html b/tests/test_data/golden/embedoka.feed.html index fc0e518..9128211 100644 --- a/tests/test_data/golden/embedoka.feed.html +++ b/tests/test_data/golden/embedoka.feed.html @@ -1014,6 +1014,7 @@ The SM9 module boasts hardware compatibility with NVIDIA Jetson series mo
--- Forwarded from асоциальный пикотранзистор ᶘಠᴥಠᶅ ---

+

Парсинг через описание структуры мне сразу напомнил про https://kaitai.io/, но кажется проект больше мёртв, чем жив.
@@ -1021,7 +1022,7 @@ The SM9 module boasts hardware compatibility with NVIDIA Jetson series mo
+
🏷 fwd 🏷 link

--- Forwarded from kitnerlive (@kitnerlive) ---
diff --git a/tests/test_data/golden/embedoka.rss.xml b/tests/test_data/golden/embedoka.rss.xml index 7a20ade..ddc9ae3 100644 --- a/tests/test_data/golden/embedoka.rss.xml +++ b/tests/test_data/golden/embedoka.rss.xml @@ -168,6 +168,7 @@
--- Forwarded from асоциальный пикотранзистор ᶘಠᴥಠᶅ ---

+

Парсинг через описание структуры мне сразу напомнил про https://kaitai.io/, но кажется проект больше мёртв, чем жив.
@@ -175,7 +176,7 @@

]]> +
🏷 fwd 🏷 link
]]> https://t.me/embedoka/1347 Thu, 13 Mar 2025 17:42:49 +0000 diff --git a/tests/test_data/golden/meow_design.feed.html b/tests/test_data/golden/meow_design.feed.html index 51b44c0..7c726eb 100644 --- a/tests/test_data/golden/meow_design.feed.html +++ b/tests/test_data/golden/meow_design.feed.html @@ -609,6 +609,7 @@
+

Илья Бирман в последнем выпуске своего подкаста вместе с Мишей Нозиком обсудили исследование, которое я проводил для внедрения изменений в шрифт Карт (https://t.me/meow_design/2090).

Фрагмент начинается с 56:45.
@@ -623,7 +624,7 @@

+
🏷 fwd 🏷 no_image 🏷 link 🏷 mention 🏷 foreign_channel 🏷 merged

diff --git a/tests/test_data/golden/meow_design.rss.xml b/tests/test_data/golden/meow_design.rss.xml index 8ec966f..1574a11 100644 --- a/tests/test_data/golden/meow_design.rss.xml +++ b/tests/test_data/golden/meow_design.rss.xml @@ -311,6 +311,7 @@ Илья Бирман в последнем выпуске своего подкаста вместе с Мишей Нозиком обсудили исследование, которое я проводил для внедрения изменений в шрифт Карт (https://t.me/meow_design/2090). Фрагмент начинается с 56:45. Думаем дальше № 51 — «Три варианта апокалипсиса» c Мишей Нозиком С Мишей Нозиком обсуждаем хороший дизайн, хороший маркетинг, хорошее исследование (!) и пару вопросов по нейросетям. 0:00 — Миша оказался против горизонтальной прокрутки на мобиле 7:06 — Обсуждение: аналогия с теоремой о попапах, когда подойдёт, топ дизайнерских костылей 20:20 — Критерий хорошего дизайна 27:43 — Разбираем на примере полководцев, учителя русского языка, авиакомпании и чего-то ещё. Репутация и долгосрочное планирование 45:29 — Про маркетинг в бюро 52:41 — «Пипл хавает» против «дизайна для дизайнеров» 56:45 — Яндекс исследовал размер строчных букв в шрифте на картах 1:03:01 — ЧатГПТ и непонятная кнопка «Скачать» 1:13:26 — Как нейросеть решила убить человека Эпл · Ютюб · Я.Музыка · Мейв Но лучше подписаться по РСС в подкастном приложении: https://cloud.mave.digital/51724
+

Илья Бирман в последнем выпуске своего подкаста вместе с Мишей Нозиком обсудили исследование, которое я проводил для внедрения изменений в шрифт Карт (https://t.me/meow_design/2090).

Фрагмент начинается с 56:45.
@@ -325,7 +326,7 @@

]]> +
🏷 fwd 🏷 no_image 🏷 link 🏷 mention 🏷 foreign_channel 🏷 merged
]]> https://t.me/meow_design/2183 Mon, 22 Dec 2025 15:22:09 +0000 diff --git a/tests/test_data/media_fragments.json b/tests/test_data/media_fragments.json index cb0462d..d62a926 100644 --- a/tests/test_data/media_fragments.json +++ b/tests/test_data/media_fragments.json @@ -65,7 +65,7 @@ }, "file_unique_id_none": { "collected": [], - "html": "
" + "html": "
\n
" }, "live_photo": { "collected": [ @@ -213,6 +213,6 @@ }, "webpage_without_photo": { "collected": [], - "html": "
\n
\n
\n\n
https://example.com
\n
\n
" + "html": "
\n
\n
\n
\n\n
https://example.com
\n
\n
" } } \ No newline at end of file diff --git a/tests/test_stage5b_media_fixes.py b/tests/test_stage5b_media_fixes.py new file mode 100644 index 0000000..c68f1a3 --- /dev/null +++ b/tests/test_stage5b_media_fixes.py @@ -0,0 +1,137 @@ +# flake8: noqa +# pylint: disable=protected-access, missing-function-docstring, redefined-outer-name, line-too-long +"""Stage-5b registered media fixes (render-pipeline refactor epic, issue #32/#34). + +Two registry items, both routed through the single MEDIA_SOURCES table: + * §3.13 — the ">100MB don't cache" rule now applies to ANY selected media object, + not just message.video (previously only video, plus live_photo/story/poll). + * §3.14 — the
container is CLOSED in every branch; + a None file_unique_id used to leave it open (html5lib then swallowed following + posts / webpage previews into it). + +The fragment snapshot (tests/test_data/media_fragments.json) was regenerated in the 5b +changeset: exactly two cases moved — `file_unique_id_none` and `webpage_without_photo` +each gained the now-balanced `
` (see test_stage5_media_table for the oracle). +The feed goldens moved only by the same `
` relocation on webpage-without-photo posts. +""" +from types import SimpleNamespace + +import pytest + +from pyrogram.enums import MessageMediaType + +from post_parser import PostParser +from url_signer import KeyManager + +from tests import media_fragment_replay as fr + + +@pytest.fixture(autouse=True) +def _pin_signing_key(monkeypatch): + monkeypatch.setattr(KeyManager, "signing_key", fr.FRAGMENT_SIGNING_KEY) + + +@pytest.fixture +def parser(): + return PostParser(SimpleNamespace()) + + +def _msg(mid, media, **extra): + return fr._msg(mid, media, **extra) + + +# --------------------------------------------------------------------------- # +# §3.14 — the message-media div is closed in every branch. +# --------------------------------------------------------------------------- # +def test_none_file_unique_id_closes_media_div(parser): + # A media type whose object has no usable file_unique_id: the container used to + # be left open. Now it must be closed. + msg = _msg(1, MessageMediaType.PHOTO, photo=SimpleNamespace(file_unique_id=None, file_id="x")) + html = parser._generate_html_media(msg) + assert html == '
\n
' + + +def test_webpage_without_photo_closes_media_div_before_preview(parser): + # WEB_PAGE without photo: the empty media div must close BEFORE the webpage-preview + # block (previously the open div swallowed the preview and, at feed level, following + # posts). Every
is now paired with a
. + msg = _msg(2, MessageMediaType.WEB_PAGE, text="hi", + web_page=SimpleNamespace(photo=None, url="https://e.com", title="E", + description=None, site_name=None, type="", display_url=None)) + html = parser._generate_html_media(msg) + assert html.startswith('
\n
\n
') + assert html.count('
') == 1 + # The media container is now empty and closed, not wrapping the preview. + assert '
\n
' in html + + +def test_channel_username_missing_still_closes_div(parser): + # The username-guard branch also closes the div (unchanged behavior, asserted so a + # future refactor cannot regress it). + msg = _msg(3, MessageMediaType.PHOTO, username=None, chat_id=555, + photo=SimpleNamespace(file_unique_id="u", file_id="f")) + html = parser._generate_html_media(msg) + assert html == '
\n
' + + +@pytest.mark.parametrize("case_name", ["file_unique_id_none", "webpage_without_photo"]) +def test_5b_fragment_cases_are_now_balanced(parser, case_name): + """The two fragments that 5b intentionally changed must have a balanced media div.""" + factory = fr.build_cases()[case_name] + html = parser._generate_html_media(factory()) + assert html.count('
') == 1 + # There is at least one closing tag for the media container now. + assert '
' in html + + +# --------------------------------------------------------------------------- # +# §3.13 — the >100MB guard applies to ANY selected object, not only video. +# --------------------------------------------------------------------------- # +BIG = 200 * 1024 * 1024 +SMALL = 5 * 1024 * 1024 + + +@pytest.mark.parametrize("media_type,attr", [ + (MessageMediaType.PHOTO, "photo"), + (MessageMediaType.DOCUMENT, "document"), + (MessageMediaType.AUDIO, "audio"), + (MessageMediaType.ANIMATION, "animation"), +]) +def test_large_non_video_object_not_collected(parser, media_type, attr): + """§3.13: a >100MB photo/document/audio/animation is no longer collected for the + download cache (before 5b only large VIDEO objects were skipped).""" + obj = SimpleNamespace(file_unique_id="big", file_id="f", file_size=BIG, mime_type="image/png") + msg = _msg(10, media_type, **{attr: obj}) + parser._pending_media_ids = [] + parser._save_media_file_ids(msg) + assert parser._pending_media_ids == [] + + +@pytest.mark.parametrize("media_type,attr", [ + (MessageMediaType.PHOTO, "photo"), + (MessageMediaType.DOCUMENT, "document"), + (MessageMediaType.AUDIO, "audio"), +]) +def test_small_non_video_object_still_collected(parser, media_type, attr): + obj = SimpleNamespace(file_unique_id="small", file_id="f", file_size=SMALL, mime_type="image/png") + msg = _msg(11, media_type, **{attr: obj}) + parser._pending_media_ids = [] + parser._save_media_file_ids(msg) + assert [(c, p, f) for c, p, f, _ in parser._pending_media_ids] == [("testchan", 11, "small")] + + +def test_large_video_still_not_collected(parser): + # Regression: the video case (the only one guarded before 5b) still works. + msg = _msg(12, MessageMediaType.VIDEO, + video=SimpleNamespace(file_unique_id="v", file_id="f", file_size=BIG)) + parser._pending_media_ids = [] + parser._save_media_file_ids(msg) + assert parser._pending_media_ids == [] + + +def test_object_without_file_size_is_collected(parser): + # No file_size attribute -> not guarded (the common case for photos). + msg = _msg(13, MessageMediaType.PHOTO, photo=SimpleNamespace(file_unique_id="nofs", file_id="f")) + parser._pending_media_ids = [] + parser._save_media_file_ids(msg) + assert [(c, p, f) for c, p, f, _ in parser._pending_media_ids] == [("testchan", 13, "nofs")]