Skip to content

Commit cae9b3c

Browse files
authored
fix: improve General topic test suite — rename data, add edge cases, use fixture (#132)
- Rename unprofessional "sexy" test data to neutral names - Remove redundant @pytest.mark.asyncio decorators (asyncio_mode=auto) - Convert manual setup/teardown to pytest_asyncio fixture - Add edge case tests: nonexistent topic, topic_id=0, topic+search filter
1 parent e0a7df2 commit cae9b3c

4 files changed

Lines changed: 60 additions & 36 deletions

File tree

docs/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ All notable changes to this project are documented here.
44

55
For upgrade instructions, see [Upgrading](#upgrading) at the bottom.
66

7+
## [7.6.4] - 2026-04-25
8+
9+
### Fixed
10+
11+
- **Improved General topic test suite** — Renamed unprofessional test data, removed redundant `@pytest.mark.asyncio` decorators (project uses `asyncio_mode = "auto"`), converted setup to a proper pytest fixture, and added edge case tests for nonexistent topics, `topic_id=0`, and topic+search filter interaction. Contributed by @tondeaf in #122 (follow-up).
12+
713
## [7.6.3] - 2026-04-25
814

915
### Fixed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "telegram-archive"
7-
version = "7.6.3"
7+
version = "7.6.4"
88
description = "Automated Telegram backup with Docker. Performs incremental backups of messages and media on a configurable schedule."
99
readme = "README.md"
1010
requires-python = ">=3.14"

src/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
Telegram Backup Automation - Main Package
33
"""
44

5-
__version__ = "7.6.3"
5+
__version__ = "7.6.4"

tests/test_general_topic_messages.py

Lines changed: 52 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
import sys
1616
from datetime import datetime
1717

18-
import pytest
18+
import pytest_asyncio
1919
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
2020
from sqlalchemy.pool import StaticPool
2121

@@ -26,8 +26,9 @@
2626
from src.db.models import Base, Chat, Message
2727

2828

29-
async def _make_adapter_with_messages():
30-
"""Spin up an in-memory SQLite DB seeded with a forum chat + mixed-topic messages."""
29+
@pytest_asyncio.fixture
30+
async def forum_adapter():
31+
"""In-memory SQLite DB seeded with a forum chat + mixed-topic messages."""
3132
engine = create_async_engine(
3233
"sqlite+aiosqlite://",
3334
poolclass=StaticPool,
@@ -50,9 +51,9 @@ async def _make_adapter_with_messages():
5051
# (id, date, text, reply_to_top_id)
5152
(1, datetime(2024, 1, 1, 10), "pre-forum general #1", None),
5253
(2, datetime(2024, 1, 2, 10), "pre-forum general #2", None),
53-
(3, datetime(2024, 3, 1, 10), "sexy topic msg", 47),
54-
(4, datetime(2024, 3, 2, 10), "another sexy msg", 47),
55-
(5, datetime(2024, 4, 1, 10), "photos topic", 144),
54+
(3, datetime(2024, 3, 1, 10), "topic-47 msg #1", 47),
55+
(4, datetime(2024, 3, 2, 10), "topic-47 msg #2", 47),
56+
(5, datetime(2024, 4, 1, 10), "topic-144 photos", 144),
5657
# Post-forum-enable: Telegram sets reply_to_top_id=1 explicitly on
5758
# new General messages. Must appear alongside NULL rows under topic_id=1.
5859
(6, datetime(2024, 5, 1, 10), "post-forum general (explicit 1)", 1),
@@ -61,42 +62,59 @@ async def _make_adapter_with_messages():
6162
session.add(Message(id=mid, chat_id=chat_id, date=dt, text=body, reply_to_top_id=top))
6263
await session.commit()
6364

64-
return DatabaseAdapter(db_manager), engine, chat_id
65+
yield DatabaseAdapter(db_manager), chat_id
6566

67+
await engine.dispose()
6668

67-
@pytest.mark.asyncio
68-
async def test_general_topic_includes_null_and_explicit_one():
69+
70+
async def test_general_topic_includes_null_and_explicit_one(forum_adapter):
6971
"""topic_id=1 (General) must match both NULL reply_to_top_id (pre-forum) and
7072
explicit reply_to_top_id=1 (post-forum-enable) messages."""
71-
adapter, engine, chat_id = await _make_adapter_with_messages()
72-
try:
73-
messages = await adapter.get_messages_paginated(chat_id=chat_id, topic_id=1)
74-
ids = sorted(m["id"] for m in messages)
75-
assert ids == [1, 2, 6], f"General (topic_id=1) must return NULL and explicit-1 messages, got {ids}"
76-
finally:
77-
await engine.dispose()
73+
adapter, chat_id = forum_adapter
74+
messages = await adapter.get_messages_paginated(chat_id=chat_id, topic_id=1)
75+
ids = sorted(m["id"] for m in messages)
76+
assert ids == [1, 2, 6], f"General (topic_id=1) must return NULL and explicit-1 messages, got {ids}"
7877

7978

80-
@pytest.mark.asyncio
81-
async def test_non_general_topic_filters_strictly():
79+
async def test_non_general_topic_filters_strictly(forum_adapter):
8280
"""Non-General topic IDs must still filter by strict equality on reply_to_top_id."""
83-
adapter, engine, chat_id = await _make_adapter_with_messages()
84-
try:
85-
sexy = await adapter.get_messages_paginated(chat_id=chat_id, topic_id=47)
86-
assert sorted(m["id"] for m in sexy) == [3, 4]
81+
adapter, chat_id = forum_adapter
82+
topic_47 = await adapter.get_messages_paginated(chat_id=chat_id, topic_id=47)
83+
assert sorted(m["id"] for m in topic_47) == [3, 4]
8784

88-
photos = await adapter.get_messages_paginated(chat_id=chat_id, topic_id=144)
89-
assert sorted(m["id"] for m in photos) == [5]
90-
finally:
91-
await engine.dispose()
85+
photos = await adapter.get_messages_paginated(chat_id=chat_id, topic_id=144)
86+
assert sorted(m["id"] for m in photos) == [5]
9287

9388

94-
@pytest.mark.asyncio
95-
async def test_no_topic_filter_returns_all():
89+
async def test_no_topic_filter_returns_all(forum_adapter):
9690
"""Without topic_id, all messages in the chat must be returned regardless of reply_to_top_id."""
97-
adapter, engine, chat_id = await _make_adapter_with_messages()
98-
try:
99-
all_msgs = await adapter.get_messages_paginated(chat_id=chat_id)
100-
assert sorted(m["id"] for m in all_msgs) == [1, 2, 3, 4, 5, 6]
101-
finally:
102-
await engine.dispose()
91+
adapter, chat_id = forum_adapter
92+
all_msgs = await adapter.get_messages_paginated(chat_id=chat_id)
93+
assert sorted(m["id"] for m in all_msgs) == [1, 2, 3, 4, 5, 6]
94+
95+
96+
async def test_nonexistent_topic_returns_empty(forum_adapter):
97+
"""A topic_id with no matching messages must return an empty list."""
98+
adapter, chat_id = forum_adapter
99+
messages = await adapter.get_messages_paginated(chat_id=chat_id, topic_id=999)
100+
assert messages == []
101+
102+
103+
async def test_topic_zero_returns_empty(forum_adapter):
104+
"""topic_id=0 is not a valid Telegram topic — must not match NULL rows via coalesce."""
105+
adapter, chat_id = forum_adapter
106+
messages = await adapter.get_messages_paginated(chat_id=chat_id, topic_id=0)
107+
assert messages == []
108+
109+
110+
async def test_topic_filter_combined_with_search(forum_adapter):
111+
"""topic_id and search filters must both apply — only matching messages returned."""
112+
adapter, chat_id = forum_adapter
113+
# Search within General topic (id=1) — only "pre-forum general #1" matches
114+
messages = await adapter.get_messages_paginated(chat_id=chat_id, topic_id=1, search="general #1")
115+
ids = sorted(m["id"] for m in messages)
116+
assert ids == [1]
117+
118+
# Search term exists in topic-47 but not in General
119+
messages = await adapter.get_messages_paginated(chat_id=chat_id, topic_id=1, search="topic-47")
120+
assert messages == []

0 commit comments

Comments
 (0)