Spaces:
Running
Running
| """ | |
| Unit tests for add_task tool. | |
| """ | |
| import pytest | |
| from unittest.mock import MagicMock, patch | |
| from sqlmodel import Session | |
| from backend.mcp_server.tools.add_task import add_task | |
| from backend.mcp_server.schemas import ErrorCode | |
| def test_add_task_valid_input(): | |
| """Test adding a task with valid input.""" | |
| mock_task = MagicMock() | |
| mock_task.id = 1 | |
| mock_task.title = "Buy groceries" | |
| mock_task.description = "Milk, eggs, bread" | |
| mock_task.completed = False | |
| with patch('backend.mcp_server.tools.add_task.get_engine') as mock_get_engine, \ | |
| patch('backend.mcp_server.tools.add_task.Session') as mock_session_class: | |
| mock_get_engine.return_value = MagicMock() | |
| mock_session = MagicMock() | |
| mock_session_class.return_value.__enter__.return_value = mock_session | |
| mock_session_class.return_value.__exit__.return_value = False | |
| mock_session.add.return_value = None | |
| mock_session.commit.return_value = None | |
| mock_session.refresh.side_effect = lambda task: setattr(task, 'id', 1) | |
| result = add_task( | |
| user_id="user_abc123", | |
| title="Buy groceries", | |
| description="Milk, eggs, bread" | |
| ) | |
| assert result["success"] is True | |
| assert result["data"]["task_id"] == 1 | |
| assert result["data"]["status"] == "created" | |
| assert result["data"]["title"] == "Buy groceries" | |
| assert result["error"] is None | |
| def test_add_task_without_description(): | |
| """Test adding a task without description (optional field).""" | |
| mock_task = MagicMock() | |
| mock_task.id = 1 | |
| mock_task.title = "Call mom" | |
| mock_task.description = None | |
| mock_task.completed = False | |
| with patch('backend.mcp_server.tools.add_task.get_engine') as mock_get_engine, \ | |
| patch('backend.mcp_server.tools.add_task.Session') as mock_session_class: | |
| mock_get_engine.return_value = MagicMock() | |
| mock_session = MagicMock() | |
| mock_session_class.return_value.__enter__.return_value = mock_session | |
| mock_session_class.return_value.__exit__.return_value = False | |
| mock_session.add.return_value = None | |
| mock_session.commit.return_value = None | |
| mock_session.refresh.side_effect = lambda task: setattr(task, 'id', 1) | |
| result = add_task( | |
| user_id="user_abc123", | |
| title="Call mom" | |
| ) | |
| assert result["success"] is True | |
| assert result["data"]["status"] == "created" | |
| assert result["data"]["title"] == "Call mom" | |
| def test_add_task_title_validation_empty(): | |
| """Test add_task rejects empty title.""" | |
| result = add_task( | |
| user_id="user_abc123", | |
| title="" | |
| ) | |
| assert result["success"] is False | |
| assert result["data"] is None | |
| assert result["error"]["code"] == ErrorCode.INVALID_INPUT | |
| assert "title" in result["error"]["message"].lower() | |
| def test_add_task_title_validation_too_short(): | |
| """Test add_task rejects title shorter than 1 character.""" | |
| result = add_task( | |
| user_id="user_abc123", | |
| title="" | |
| ) | |
| assert result["success"] is False | |
| assert result["error"]["code"] == ErrorCode.INVALID_INPUT | |
| def test_add_task_title_validation_too_long(): | |
| """Test add_task rejects title longer than 200 characters.""" | |
| long_title = "A" * 201 | |
| result = add_task( | |
| user_id="user_abc123", | |
| title=long_title | |
| ) | |
| assert result["success"] is False | |
| assert result["data"] is None | |
| assert result["error"]["code"] == ErrorCode.INVALID_INPUT | |
| assert "title" in result["error"]["message"].lower() | |
| def test_add_task_description_validation_too_long(): | |
| """Test add_task rejects description longer than 1000 characters.""" | |
| long_desc = "A" * 1001 | |
| result = add_task( | |
| user_id="user_abc123", | |
| title="Valid title", | |
| description=long_desc | |
| ) | |
| assert result["success"] is False | |
| assert result["data"] is None | |
| assert result["error"]["code"] == ErrorCode.INVALID_INPUT | |
| def test_add_task_user_association(): | |
| """Test task is created with correct user association.""" | |
| mock_task = MagicMock() | |
| mock_task.id = 1 | |
| mock_task.title = "User specific task" | |
| mock_task.user_id = "user_xyz456" | |
| mock_task.completed = False | |
| with patch('backend.mcp_server.tools.add_task.get_engine') as mock_get_engine, \ | |
| patch('backend.mcp_server.tools.add_task.Session') as mock_session_class: | |
| mock_get_engine.return_value = MagicMock() | |
| mock_session = MagicMock() | |
| mock_session_class.return_value.__enter__.return_value = mock_session | |
| mock_session_class.return_value.__exit__.return_value = False | |
| mock_session.add.return_value = None | |
| mock_session.commit.return_value = None | |
| mock_session.refresh.side_effect = lambda task: setattr(task, 'id', 1) | |
| result = add_task( | |
| user_id="user_xyz456", | |
| title="User specific task" | |
| ) | |
| assert result["success"] is True | |
| # The task should be associated with user_xyz456 | |
| def test_add_task_returns_correct_format(): | |
| """Test add_task returns consistent response format.""" | |
| mock_task = MagicMock() | |
| mock_task.id = 1 | |
| mock_task.title = "Test task" | |
| mock_task.completed = False | |
| with patch('backend.mcp_server.tools.add_task.get_engine') as mock_get_engine, \ | |
| patch('backend.mcp_server.tools.add_task.Session') as mock_session_class: | |
| mock_get_engine.return_value = MagicMock() | |
| mock_session = MagicMock() | |
| mock_session_class.return_value.__enter__.return_value = mock_session | |
| mock_session_class.return_value.__exit__.return_value = False | |
| mock_session.add.return_value = None | |
| mock_session.commit.return_value = None | |
| mock_session.refresh.side_effect = lambda task: setattr(task, 'id', 1) | |
| result = add_task( | |
| user_id="user_abc123", | |
| title="Test task" | |
| ) | |
| # Response must have all three top-level keys | |
| assert "success" in result | |
| assert "data" in result | |
| assert "error" in result | |
| # Data must have required fields | |
| assert result["data"]["task_id"] is not None | |
| assert result["data"]["status"] is not None | |
| assert result["data"]["title"] is not None | |
| def test_add_task_special_characters_in_title(): | |
| """Test add_task handles special characters in title.""" | |
| special_title = "Buy groceries! 🛒 (milk, eggs)" | |
| mock_task = MagicMock() | |
| mock_task.id = 1 | |
| mock_task.title = special_title | |
| mock_task.completed = False | |
| with patch('backend.mcp_server.tools.add_task.get_engine') as mock_get_engine, \ | |
| patch('backend.mcp_server.tools.add_task.Session') as mock_session_class: | |
| mock_get_engine.return_value = MagicMock() | |
| mock_session = MagicMock() | |
| mock_session_class.return_value.__enter__.return_value = mock_session | |
| mock_session_class.return_value.__exit__.return_value = False | |
| mock_session.add.return_value = None | |
| mock_session.commit.return_value = None | |
| mock_session.refresh.side_effect = lambda task: setattr(task, 'id', 1) | |
| result = add_task( | |
| user_id="user_abc123", | |
| title=special_title | |
| ) | |
| assert result["success"] is True | |
| assert result["data"]["title"] == special_title | |
| def test_add_task_special_characters_in_description(): | |
| """Test add_task handles special characters in description.""" | |
| special_desc = "Remember to: buy milk 🥛, eggs 🥚, bread 🍞" | |
| mock_task = MagicMock() | |
| mock_task.id = 1 | |
| mock_task.title = "Shopping list" | |
| mock_task.description = special_desc | |
| mock_task.completed = False | |
| with patch('backend.mcp_server.tools.add_task.get_engine') as mock_get_engine, \ | |
| patch('backend.mcp_server.tools.add_task.Session') as mock_session_class: | |
| mock_get_engine.return_value = MagicMock() | |
| mock_session = MagicMock() | |
| mock_session_class.return_value.__enter__.return_value = mock_session | |
| mock_session_class.return_value.__exit__.return_value = False | |
| mock_session.add.return_value = None | |
| mock_session.commit.return_value = None | |
| mock_session.refresh.side_effect = lambda task: setattr(task, 'id', 1) | |
| result = add_task( | |
| user_id="user_abc123", | |
| title="Shopping list", | |
| description=special_desc | |
| ) | |
| assert result["success"] is True | |
| assert result["data"]["title"] == "Shopping list" | |
| def test_add_task_minimal_title(): | |
| """Test add_task accepts minimum title length (1 character).""" | |
| mock_task = MagicMock() | |
| mock_task.id = 1 | |
| mock_task.title = "A" | |
| mock_task.completed = False | |
| with patch('backend.mcp_server.tools.add_task.get_engine') as mock_get_engine, \ | |
| patch('backend.mcp_server.tools.add_task.Session') as mock_session_class: | |
| mock_get_engine.return_value = MagicMock() | |
| mock_session = MagicMock() | |
| mock_session_class.return_value.__enter__.return_value = mock_session | |
| mock_session_class.return_value.__exit__.return_value = False | |
| mock_session.add.return_value = None | |
| mock_session.commit.return_value = None | |
| mock_session.refresh.side_effect = lambda task: setattr(task, 'id', 1) | |
| result = add_task( | |
| user_id="user_abc123", | |
| title="A" | |
| ) | |
| assert result["success"] is True | |
| assert result["data"]["title"] == "A" | |
| def test_add_task_max_title(): | |
| """Test add_task accepts maximum title length (200 characters).""" | |
| max_title = "A" * 200 | |
| mock_task = MagicMock() | |
| mock_task.id = 1 | |
| mock_task.title = max_title | |
| mock_task.completed = False | |
| with patch('backend.mcp_server.tools.add_task.get_engine') as mock_get_engine, \ | |
| patch('backend.mcp_server.tools.add_task.Session') as mock_session_class: | |
| mock_get_engine.return_value = MagicMock() | |
| mock_session = MagicMock() | |
| mock_session_class.return_value.__enter__.return_value = mock_session | |
| mock_session_class.return_value.__exit__.return_value = False | |
| mock_session.add.return_value = None | |
| mock_session.commit.return_value = None | |
| mock_session.refresh.side_effect = lambda task: setattr(task, 'id', 1) | |
| result = add_task( | |
| user_id="user_abc123", | |
| title=max_title | |
| ) | |
| assert result["success"] is True | |
| assert len(result["data"]["title"]) == 200 | |
| def test_add_task_max_description(): | |
| """Test add_task accepts maximum description length (1000 characters).""" | |
| max_desc = "A" * 1000 | |
| mock_task = MagicMock() | |
| mock_task.id = 1 | |
| mock_task.title = "Task" | |
| mock_task.description = max_desc | |
| mock_task.completed = False | |
| with patch('backend.mcp_server.tools.add_task.get_engine') as mock_get_engine, \ | |
| patch('backend.mcp_server.tools.add_task.Session') as mock_session_class: | |
| mock_get_engine.return_value = MagicMock() | |
| mock_session = MagicMock() | |
| mock_session_class.return_value.__enter__.return_value = mock_session | |
| mock_session_class.return_value.__exit__.return_value = False | |
| mock_session.add.return_value = None | |
| mock_session.commit.return_value = None | |
| mock_session.refresh.side_effect = lambda task: setattr(task, 'id', 1) | |
| result = add_task( | |
| user_id="user_abc123", | |
| title="Task", | |
| description=max_desc | |
| ) | |
| assert result["success"] is True | |