File size: 7,318 Bytes
310260a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
"""
Unit Tests for create_task MCP Tool

Tests the create_task tool functionality including:
- Valid task creation with title only
- Task creation with title and description
- Validation errors for empty title
- Validation errors for title exceeding 200 chars
- Validation errors for description exceeding 2000 chars
- User_id scoping from MCPContext
"""

import pytest
from datetime import datetime

from src.tools.create_task import create_task_internal
from tests.utils.task_helpers import get_task_by_id, count_tasks


@pytest.mark.unit
@pytest.mark.asyncio
async def test_create_task_with_valid_title(mock_mcp_context, test_session):
    """
    Test: create_task with valid title

    Verifies that create_task successfully creates a task with just a title.
    """
    # Execute
    result = await create_task_internal(
        ctx=mock_mcp_context,
        title="Buy groceries"
    )

    # Assert
    assert result["status"] == "success"
    assert "task" in result
    assert result["task"]["title"] == "Buy groceries"
    assert result["task"]["description"] is None
    assert result["task"]["completed"] is False
    assert "id" in result["task"]
    assert "created_at" in result["task"]
    assert "updated_at" in result["task"]

    # Verify task persisted in database
    task_id = result["task"]["id"]
    task = get_task_by_id(test_session, task_id)
    assert task is not None
    assert task.title == "Buy groceries"
    assert task.user_id == mock_mcp_context.user_id


@pytest.mark.unit
@pytest.mark.asyncio
async def test_create_task_with_title_and_description(mock_mcp_context, test_session):
    """
    Test: create_task with title and description

    Verifies that create_task successfully creates a task with both title and description.
    """
    # Execute
    result = await create_task_internal(
        ctx=mock_mcp_context,
        title="Review PR",
        description="Check code quality and test coverage"
    )

    # Assert
    assert result["status"] == "success"
    assert result["task"]["title"] == "Review PR"
    assert result["task"]["description"] == "Check code quality and test coverage"
    assert result["task"]["completed"] is False

    # Verify task persisted in database
    task_id = result["task"]["id"]
    task = get_task_by_id(test_session, task_id)
    assert task is not None
    assert task.title == "Review PR"
    assert task.description == "Check code quality and test coverage"
    assert task.user_id == mock_mcp_context.user_id


@pytest.mark.unit
@pytest.mark.asyncio
async def test_create_task_with_empty_title_returns_error(mock_mcp_context):
    """
    Test: create_task with empty title returns error

    Verifies that create_task returns validation error for empty title.
    """
    # Execute
    result = await create_task_internal(
        ctx=mock_mcp_context,
        title=""
    )

    # Assert
    assert result["status"] == "error"
    assert "error" in result
    assert "Title is required" in result["error"]


@pytest.mark.unit
@pytest.mark.asyncio
async def test_create_task_with_whitespace_only_title_returns_error(mock_mcp_context):
    """
    Test: create_task with whitespace-only title returns error

    Verifies that create_task returns validation error for whitespace-only title.
    """
    # Execute
    result = await create_task_internal(
        ctx=mock_mcp_context,
        title="   "
    )

    # Assert
    assert result["status"] == "error"
    assert "error" in result
    assert "Title is required" in result["error"]


@pytest.mark.unit
@pytest.mark.asyncio
async def test_create_task_with_title_exceeding_200_chars_returns_error(mock_mcp_context):
    """
    Test: create_task with title exceeding 200 chars returns error

    Verifies that create_task returns validation error for title exceeding 200 characters.
    """
    # Create a title with 201 characters
    long_title = "A" * 201

    # Execute
    result = await create_task_internal(
        ctx=mock_mcp_context,
        title=long_title
    )

    # Assert
    assert result["status"] == "error"
    assert "error" in result
    assert "Title exceeds 200 characters" in result["error"]


@pytest.mark.unit
@pytest.mark.asyncio
async def test_create_task_with_description_exceeding_2000_chars_returns_error(mock_mcp_context):
    """
    Test: create_task with description exceeding 2000 chars returns error

    Verifies that create_task returns validation error for description exceeding 2000 characters.
    """
    # Create a description with 2001 characters
    long_description = "B" * 2001

    # Execute
    result = await create_task_internal(
        ctx=mock_mcp_context,
        title="Valid title",
        description=long_description
    )

    # Assert
    assert result["status"] == "error"
    assert "error" in result
    assert "Description exceeds 2000 characters" in result["error"]


@pytest.mark.unit
@pytest.mark.asyncio
async def test_create_task_persists_user_id_from_mcp_context(mock_mcp_context, test_session):
    """
    Test: create_task persists user_id from MCPContext

    Verifies that create_task correctly uses user_id from MCPContext for data scoping.
    """
    # Execute
    result = await create_task_internal(
        ctx=mock_mcp_context,
        title="Test task for user scoping"
    )

    # Assert
    assert result["status"] == "success"

    # Verify task has correct user_id from context
    task_id = result["task"]["id"]
    task = get_task_by_id(test_session, task_id)
    assert task is not None
    assert task.user_id == mock_mcp_context.user_id

    # Verify task count for user
    task_count = count_tasks(test_session, mock_mcp_context.user_id)
    assert task_count == 1


@pytest.mark.unit
@pytest.mark.asyncio
async def test_create_task_with_max_valid_title_length(mock_mcp_context, test_session):
    """
    Test: create_task with maximum valid title length (200 chars)

    Verifies that create_task accepts title with exactly 200 characters.
    """
    # Create a title with exactly 200 characters
    max_title = "A" * 200

    # Execute
    result = await create_task_internal(
        ctx=mock_mcp_context,
        title=max_title
    )

    # Assert
    assert result["status"] == "success"
    assert result["task"]["title"] == max_title

    # Verify task persisted
    task_id = result["task"]["id"]
    task = get_task_by_id(test_session, task_id)
    assert task is not None
    assert len(task.title) == 200


@pytest.mark.unit
@pytest.mark.asyncio
async def test_create_task_with_max_valid_description_length(mock_mcp_context, test_session):
    """
    Test: create_task with maximum valid description length (2000 chars)

    Verifies that create_task accepts description with exactly 2000 characters.
    """
    # Create a description with exactly 2000 characters
    max_description = "B" * 2000

    # Execute
    result = await create_task_internal(
        ctx=mock_mcp_context,
        title="Valid title",
        description=max_description
    )

    # Assert
    assert result["status"] == "success"
    assert result["task"]["description"] == max_description

    # Verify task persisted
    task_id = result["task"]["id"]
    task = get_task_by_id(test_session, task_id)
    assert task is not None
    assert len(task.description) == 2000