"""
Tests for rubric-related MCP tools.
"""
import pytest
import json
from unittest.mock import AsyncMock, patch
from canvas_mcp.tools.rubrics import validate_rubric_criteria, preprocess_criteria_string
class TestRubricValidation:
"""Test rubric validation functions."""
def test_validate_valid_criteria(self):
"""Test validating valid rubric criteria."""
criteria_json = json.dumps({
"criterion_1": {
"description": "Quality",
"points": 10,
"ratings": []
}
})
result = validate_rubric_criteria(criteria_json)
assert "criterion_1" in result
assert result["criterion_1"]["points"] == 10
def test_validate_missing_description(self):
"""Test validation fails for missing description."""
criteria_json = json.dumps({
"criterion_1": {
"points": 10
}
})
with pytest.raises(ValueError, match="description"):
validate_rubric_criteria(criteria_json)
def test_validate_missing_points(self):
"""Test validation fails for missing points."""
criteria_json = json.dumps({
"criterion_1": {
"description": "Quality"
}
})
with pytest.raises(ValueError, match="points"):
validate_rubric_criteria(criteria_json)
def test_validate_negative_points(self):
"""Test validation fails for negative points."""
criteria_json = json.dumps({
"criterion_1": {
"description": "Quality",
"points": -5
}
})
with pytest.raises(ValueError, match="valid number|non-negative"):
validate_rubric_criteria(criteria_json)
def test_preprocess_criteria_string(self):
"""Test preprocessing criteria string."""
criteria = '{"criterion_1": {"description": "Test", "points": 10}}'
result = preprocess_criteria_string(criteria)
assert result == criteria
def test_preprocess_with_outer_quotes(self):
"""Test preprocessing with outer quotes."""
criteria = '"{\"criterion_1\": {\"description\": \"Test\", \"points\": 10}}"'
result = preprocess_criteria_string(criteria)
# Should remove outer quotes and unescape
assert result.startswith("{")
assert result.endswith("}")
class TestRubricTools:
"""Test rubric tool functions."""
@pytest.mark.asyncio
async def test_list_rubrics(self):
"""Test listing rubrics."""
mock_rubrics = [
{"id": 1, "title": "Rubric 1", "points_possible": 100},
{"id": 2, "title": "Rubric 2", "points_possible": 50}
]
with patch('canvas_mcp.core.client.fetch_all_paginated_results', new_callable=AsyncMock) as mock_fetch:
mock_fetch.return_value = mock_rubrics
from canvas_mcp.core.client import fetch_all_paginated_results
result = await fetch_all_paginated_results("/courses/12345/rubrics", {})
assert len(result) == 2
assert result[0]["title"] == "Rubric 1"
@pytest.mark.asyncio
async def test_get_rubric_details(self):
"""Test getting rubric details."""
mock_rubric = {
"id": 123,
"title": "Test Rubric",
"criteria": [
{"id": "crit1", "description": "Quality", "points": 40}
]
}
with patch('canvas_mcp.core.client.make_canvas_request', new_callable=AsyncMock) as mock_request:
mock_request.return_value = mock_rubric
from canvas_mcp.core.client import make_canvas_request
result = await make_canvas_request("get", "/courses/12345/rubrics/123")
assert result["title"] == "Test Rubric"
assert len(result["criteria"]) == 1
if __name__ == "__main__":
pytest.main([__file__, "-v"])