Skip to content

Commit

Permalink
document tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Ahmad-mtos committed Apr 29, 2024
1 parent 7aea17c commit dca0448
Show file tree
Hide file tree
Showing 9 changed files with 195 additions and 6 deletions.
37 changes: 37 additions & 0 deletions tests/test_add_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@


class MockUpdate:
"""
Mocks Telegram's Update object for testing. Simulates the structure and
behavior of the Telegram Bot API's Update object, including user and chat
identification and reply methods.
"""
def __init__(self, message_text, user_id, chat_id=1):
self.message = MagicMock()
self.message.text = message_text
Expand All @@ -25,6 +30,10 @@ def __init__(self, message_text, user_id, chat_id=1):

@pytest.mark.asyncio
async def test_add_task_valid_input():
"""
Ensures the add_task function handles valid input correctly by adding the
task and sending a success message.
"""
future = datetime.now() + timedelta(minutes=10)
future = future.strftime("%Y-%m-%d %H:%M")

Expand All @@ -46,6 +55,10 @@ async def test_add_task_valid_input():

@pytest.mark.asyncio
async def test_add_task_invalid_input1():
"""
Verifies add_task response to empty input, ensuring no database operation
is attempted and correct usage is communicated.
"""
update = MockUpdate("/add", user_id=12345)
context = MagicMock()
context.args = [""]
Expand All @@ -66,6 +79,10 @@ async def test_add_task_invalid_input1():

@pytest.mark.asyncio
async def test_add_task_invalid_input2():
"""
Checks add_task's handling of input with only a description, ensuring it
prompts with correct usage instructions.
"""
update = MockUpdate("/add", user_id=12345)
context = MagicMock()
context.args = ["Prepare presentation"]
Expand All @@ -85,6 +102,10 @@ async def test_add_task_invalid_input2():

@pytest.mark.asyncio
async def test_add_task_invalid_input3():
"""
Tests add_task's response to input missing the deadline, ensuring correct
format usage message is returned.
"""
update = MockUpdate("/add", user_id=12345)
context = MagicMock()
context.args = ["Prepare presentation; work"]
Expand All @@ -105,6 +126,10 @@ async def test_add_task_invalid_input3():

@pytest.mark.asyncio
async def test_add_task_invalid_input4():
"""
Ensures add_task validates time format correctly, responding with an error
message for incorrect time components.
"""
update = MockUpdate("/add", user_id=12345)
context = MagicMock()
context.args = ["Prepare presentation; work; 25:50:21"]
Expand All @@ -123,6 +148,10 @@ async def test_add_task_invalid_input4():

@pytest.mark.asyncio
async def test_add_task_invalid_input5():
"""
Checks how add_task handles a date not in the future, ensuring it
appropriately identifies and rejects such dates.
"""
update = MockUpdate("/add", user_id=12345)
context = MagicMock()
context.args = ["Prepare presentation; work; 2023-10-15 22:20"]
Expand All @@ -141,6 +170,10 @@ async def test_add_task_invalid_input5():

@pytest.mark.asyncio
async def test_add_task_with_db_error():
"""
Simulates a database error during the add_task operation to test error
handling and logging functionality.
"""
future = datetime.now() + timedelta(minutes=10)
future = future.strftime("%Y-%m-%d %H:%M")

Expand Down Expand Up @@ -171,6 +204,10 @@ async def test_add_task_with_db_error():

@pytest.mark.asyncio
async def test_add_tasks_unexpected_error():
"""
Simulates an unexpected error in add_task to verify the robustness of
error handling and user communication.
"""
future = datetime.now() + timedelta(minutes=10)
future = future.strftime("%Y-%m-%d %H:%M")

Expand Down
22 changes: 22 additions & 0 deletions tests/test_delete_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@


class MockUpdate:
"""
Mocks Telegram's Update object for testing. Simulates the structure and
behavior of the Telegram Bot API's Update object, including user and chat
identification and reply methods.
"""
def __init__(self, message_text, user_id, chat_id=1):
self.message = MagicMock()
self.message.text = message_text
Expand All @@ -24,6 +29,10 @@ def __init__(self, message_text, user_id, chat_id=1):

@pytest.mark.asyncio
async def test_delete_task_success():
"""
Tests successful deletion of a task from the database. Verifies that the
correct SQL DELETE command is executed and confirms with a success message
"""
update = MockUpdate("/delete", user_id=12345)
context = MagicMock()
context.args = ["3"]
Expand All @@ -45,6 +54,11 @@ async def test_delete_task_success():

@pytest.mark.asyncio
async def test_delete_task_not_found():
"""
Tests the delete_task function's handling when a specified task ID does
not exist. Ensures that it correctly informs the user that the task is
not found.
"""
update = MockUpdate("/delete", user_id=12345)
context = MagicMock()
context.args = ["99"]
Expand All @@ -63,6 +77,10 @@ async def test_delete_task_not_found():

@pytest.mark.asyncio
async def test_delete_tasks_with_db_error():
"""
Simulates a database error during task deletion to test the bot's error
handling capabilities and logging of database errors.
"""
update = MockUpdate("/delete", user_id=12345)
context = MagicMock()
context.args = ["4"]
Expand Down Expand Up @@ -90,6 +108,10 @@ async def test_delete_tasks_with_db_error():

@pytest.mark.asyncio
async def test_delete_tasks_unexpected_error():
"""
Simulates an unexpected error to test how the delete_task function handles
unexpected situations and communicates failure to the user.
"""
update = MockUpdate("/delete", user_id=12345)
context = MagicMock()
context.args = ["4"]
Expand Down
10 changes: 10 additions & 0 deletions tests/test_help_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@


class MockUpdate:
"""
Mocks Telegram's Update object for testing. Simulates the structure and
behavior of the Telegram Bot API's Update object, including user and chat
identification and reply methods.
"""
def __init__(self, message_text, user_id, chat_id=1):
self.message = MagicMock()
self.message.text = message_text
Expand All @@ -23,6 +28,11 @@ def __init__(self, message_text, user_id, chat_id=1):

@pytest.mark.asyncio
async def test_help_command():
"""
Tests the help_command function to ensure it responds with the correct help
message. This test verifies that the function sends a comprehensive guide
outlining all the bot commands and their usage.
"""
update = MockUpdate("/help", user_id=12345)
context = MagicMock()
await help_command(update, context)
Expand Down
22 changes: 21 additions & 1 deletion tests/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import re
from unittest.mock import MagicMock, patch

import pytest
from dotenv import load_dotenv

from app.bot import DAILY_REMINDER_START, DATABASE_URL, TOKEN, init_db
Expand All @@ -13,23 +12,44 @@


def test_api_token():
"""
Tests that the TELEGRAM_TOKEN is correctly set in the environment and
matches the expected token stored in the TOKEN constant.
This ensures that the environment is correctly configured
for the bot to authenticate with Telegram.
"""
token = os.getenv("TELEGRAM_TOKEN")
assert token is not None
assert TOKEN == token


def test_database_url():
"""
Tests that the DATABASE_URL is properly set in the environment and verifie
it matches the DATABASE_URL constant. This is crucial for ensuring the bot
can successfully connect to the expected database.
"""
url = os.getenv("DATABASE_URL")
assert url is not None
assert DATABASE_URL == url


def test_daily_reminder_start():
"""
Validates that the DAILY_REMINDER_START time is a correct HH:MM:SS format.
This test confirms the time pattern validity to prevent scheduling errors.
"""
pattern = re.compile(r'^([01]\d|2[0-3]):([0-5]\d):([0-5]\d)$')
assert pattern.match(DAILY_REMINDER_START) is not None


def test_init_db():
"""
Tests the initialization of the database, ensuring that the SQL command to
create the tasks table is executed correctly. This function checks if the
table creation process is handled as expected, including if the database
commits and closes the connection properly.
"""
with patch("sqlite3.connect") as mock_connect:
mock_cursor = MagicMock()
mock_connect.return_value.cursor.return_value = mock_cursor
Expand Down
27 changes: 27 additions & 0 deletions tests/test_list_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@


class MockUpdate:
"""
Mocks Telegram's Update object for testing. Simulates the structure and
behavior of the Telegram Bot API's Update object, including user and chat
identification and reply methods.
"""
def __init__(self, message_text, user_id, chat_id=1):
self.message = MagicMock()
self.message.text = message_text
Expand All @@ -24,6 +29,11 @@ def __init__(self, message_text, user_id, chat_id=1):

@pytest.mark.asyncio
async def test_list_tasks_with_no_tasks():
"""
Tests the list_tasks function to ensure it correctly handles the scenario
where no tasks are present in the database. This test verifies that
the appropriate message "No tasks found." is sent to the user.
"""
user_id = 12345
update = MockUpdate("/list", user_id)
context = MagicMock()
Expand All @@ -41,6 +51,11 @@ async def test_list_tasks_with_no_tasks():

@pytest.mark.asyncio
async def test_list_tasks_with_db_error():
"""
Simulates a database error during the retrieval of tasks to test the bot's
error handling capabilities. This test ensures that the function logs the
error and informs user of a failure to list tasks due to a database error.
"""
update = MockUpdate("/list", user_id=12345)
context = MagicMock()

Expand All @@ -67,6 +82,12 @@ async def test_list_tasks_with_db_error():

@pytest.mark.asyncio
async def test_list_tasks_unexpected_error():
"""
Simulates an unexpected error to test how the list_tasks function handles
unexpected situations and communicates failure to the user. This test
verifies the bot's ability to log unexpected errors and provide a user
message that indicates a failure to list tasks.
"""
update = MockUpdate("/list", user_id=12345)
context = MagicMock()

Expand All @@ -86,6 +107,12 @@ async def test_list_tasks_unexpected_error():

@pytest.mark.asyncio
async def test_list_tasks_with_multiple_tasks():
"""
Tests the list_tasks function to ensure it correctly formats and sends a
message listing multiple tasks. This test checks the function's ability to
construct a detailed message including task details such as description,
category, completion status, and deadline, and then sends it correctly.
"""
user_id = 12345
update = MockUpdate("/list", user_id)
context = MagicMock()
Expand Down
16 changes: 15 additions & 1 deletion tests/test_main.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from unittest.mock import ANY, MagicMock, patch

import pytest
from dotenv import load_dotenv

from app.bot import (add_task, delete_task, help_command, list_tasks, main,
Expand All @@ -12,6 +11,11 @@


def test_main_db_init():
"""
Tests that the main function correctly initializes the database by calling
the init_db function upon startup. Ensures that database initialization is
a part of the app's startup routine.
"""
with patch('app.bot.init_db') as mock_init_db, patch(
'app.bot.Application.builder'
), patch('app.bot.run_notifiers'):
Expand All @@ -23,6 +27,11 @@ def test_main_db_init():


def test_main_command_handler():
"""
Tests that the main function correctly sets up all command handlers in the
application. Verifies each command has the proper callback linked to the
correct functionality.
"""
with patch('app.bot.init_db'), patch(
'app.bot.Application.builder'
) as mock_builder, patch(
Expand Down Expand Up @@ -54,6 +63,11 @@ def test_main_command_handler():


def test_main_threading():
"""
Tests the main function's threading setup, specifically verifying that a
thread for running notifiers is correctly initiated. Ensures the thread
starts as expected, which is crucial for background tasks.
"""
with patch('app.bot.init_db'), patch('app.bot.Application.builder'), patch(
'app.bot.run_notifiers'
), patch('app.bot.Thread') as mock_thread:
Expand Down
Loading

0 comments on commit dca0448

Please sign in to comment.