File size: 3,843 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
"""
Contract Tests for mark_complete Tool

Validates that mark_complete tool adheres to its defined contract.
"""

import pytest
import json

from src.tools.mark_complete import mark_complete_internal, get_tool_definition
from tests.utils.task_helpers import create_test_task


@pytest.mark.contract
@pytest.mark.asyncio
async def test_mark_complete_input_schema_validation(mock_mcp_context, test_session):
    """
    Test: mark_complete input schema validation

    Verifies that mark_complete accepts inputs matching the defined schema.
    """
    # Get tool definition
    tool_def = get_tool_definition()

    # Verify tool definition structure
    assert tool_def["type"] == "function"
    assert "function" in tool_def
    assert tool_def["function"]["name"] == "mark_complete"

    # Verify parameters schema
    params = tool_def["function"]["parameters"]
    assert params["type"] == "object"
    assert "properties" in params
    assert "task_id" in params["properties"]
    assert params["required"] == ["task_id"]

    # Test valid input
    task = create_test_task(test_session, mock_mcp_context.user_id, title="Test")
    result = await mark_complete_internal(
        ctx=mock_mcp_context,
        task_id=task.id
    )
    assert result["status"] == "success"


@pytest.mark.contract
@pytest.mark.asyncio
async def test_mark_complete_output_schema_validation(mock_mcp_context, test_session):
    """
    Test: mark_complete output schema validation

    Verifies that mark_complete returns outputs matching the defined schema.
    """
    # Setup
    task = create_test_task(test_session, mock_mcp_context.user_id, title="Test Task")

    # Execute
    result = await mark_complete_internal(
        ctx=mock_mcp_context,
        task_id=task.id
    )

    # Verify output schema
    assert "status" in result
    assert result["status"] == "success"

    assert "task" in result
    task_data = result["task"]

    assert "id" in task_data
    assert isinstance(task_data["id"], int)

    assert "title" in task_data
    assert isinstance(task_data["title"], str)

    assert "completed" in task_data
    assert isinstance(task_data["completed"], bool)

    assert "updated_at" in task_data
    assert isinstance(task_data["updated_at"], str)


@pytest.mark.contract
@pytest.mark.asyncio
async def test_mark_complete_error_schema_validation(mock_mcp_context):
    """
    Test: mark_complete error schema validation

    Verifies that mark_complete returns errors matching the defined schema.
    """
    # Execute with non-existent task_id
    result = await mark_complete_internal(
        ctx=mock_mcp_context,
        task_id=99999
    )

    # Verify error schema
    assert "status" in result
    assert result["status"] == "error"

    assert "error" in result
    assert isinstance(result["error"], str)
    assert len(result["error"]) > 0


@pytest.mark.contract
def test_mark_complete_tool_definition_matches_contract():
    """
    Test: mark_complete tool definition matches contract

    Verifies that the tool definition matches the contract specification.
    """
    # Load contract from file
    import os
    contract_path = os.path.join(
        os.path.dirname(__file__),
        "../../../specs/001-mcp-server-tools/contracts/mark_complete.json"
    )

    with open(contract_path, "r") as f:
        contract = json.load(f)

    # Get tool definition
    tool_def = get_tool_definition()

    # Verify tool name matches
    assert tool_def["function"]["name"] == contract["tool_name"]

    # Verify input schema structure matches
    tool_params = tool_def["function"]["parameters"]
    contract_input = contract["input_schema"]

    assert tool_params["type"] == contract_input["type"]
    assert "task_id" in tool_params["properties"]
    assert tool_params["required"] == contract_input["required"]