Skip to main content
Glama
test_path_generator.py18.2 kB
""" Unit tests for the path generator implementations. """ import pytest from unittest.mock import patch, MagicMock, AsyncMock, call from api.models import Resource, MCP, Node from core.path_generator.category_based_subtopic_generator import CategoryBasedSubtopicGenerator from core.path_generator.default_quiz_generator import DefaultQuizGenerator from core.path_generator.tree_based_node_structure import TreeBasedNodeStructure from core.path_generator.default_path_generator import DefaultPathGenerator from core.path_generator.path_generator_factory import PathGeneratorFactory class TestCategoryBasedSubtopicGenerator: """Tests for the CategoryBasedSubtopicGenerator implementation.""" def test_generate_subtopics(self): """Test the generate_subtopics method.""" # Mock the category service mock_category_service = MagicMock() mock_category_service.get_subtopics_for_category.return_value = [ "Introduction to Python", "Python Basics", "Python Functions", "Python Classes" ] with patch("core.path_generator.category_based_subtopic_generator.category_service", mock_category_service): generator = CategoryBasedSubtopicGenerator() subtopics = generator.generate_subtopics("Python", 10, "technology") # Check results assert len(subtopics) == 10 assert "Introduction to Python" in subtopics # Check that category service was called mock_category_service.get_subtopics_for_category.assert_called_once_with("Python", 10, "technology") class TestDefaultQuizGenerator: """Tests for the DefaultQuizGenerator implementation.""" def test_generate_quiz(self): """Test the generate_quiz method.""" generator = DefaultQuizGenerator() # Create test resources resources = [ Resource( id="r1", title="Python Programming", url="https://example.com/python", type="article", description="Learn Python programming", duration=None, readTime=15, difficulty="beginner", thumbnail=None ), Resource( id="r2", title="Python Functions", url="https://example.com/functions", type="video", description="Understanding Python functions", duration=10, readTime=None, difficulty="intermediate", thumbnail=None ) ] # Generate a quiz quiz = generator.generate_quiz("Python", "Python Basics", resources) # Check results assert quiz is not None assert len(quiz.questions) >= 3 assert quiz.passingScore == 70 # Check that questions have all required fields for question in quiz.questions: assert question.id is not None assert question.text is not None assert len(question.options) == 4 assert 0 <= question.correctOptionIndex < 4 class TestTreeBasedNodeStructure: """Tests for the TreeBasedNodeStructure implementation.""" @pytest.mark.asyncio async def test_create_node_structure(self): """Test the create_node_structure method.""" # Mock the quiz generator mock_quiz_generator = MagicMock() # Mock the youtube service mock_youtube = MagicMock() mock_youtube.search_videos_for_topic = AsyncMock(return_value=[ Resource( id="v1", title="Python Video", url="https://youtube.com/watch?v=123", type="video", description="Python tutorial video", duration=10, readTime=None, difficulty="beginner", thumbnail=None ) ]) with patch("core.path_generator.tree_based_node_structure.youtube", mock_youtube): service = TreeBasedNodeStructure(mock_quiz_generator) # Create test resources resources = [ Resource( id="r1", title="Python Programming", url="https://example.com/python", type="article", description="Learn Python programming", duration=None, readTime=15, difficulty="beginner", thumbnail=None ), Resource( id="r2", title="Python Functions", url="https://example.com/functions", type="video", description="Understanding Python functions", duration=10, readTime=None, difficulty="intermediate", thumbnail=None ) ] # Create test subtopics subtopics = [ "Introduction to Python", "Python Basics", "Python Functions", "Python Classes", "Python Modules", "Python Packages", "Python Libraries", "Python Frameworks", "Python Web Development", "Python Data Science" ] # Create node structure nodes, node_ids = await service.create_node_structure( topic="Python", subtopics=subtopics, resources=resources, min_nodes=5, max_nodes=10, min_width=2, max_width=3, min_height=2, max_height=4, language="en" ) # Check results assert len(nodes) >= 5 assert len(nodes) <= 10 assert len(node_ids) == len(nodes) # Check that root node exists root_id = node_ids[0] assert root_id in nodes assert nodes[root_id].title.startswith("Introduction to") # Check that all nodes have resources for node_id, node in nodes.items(): assert node.resources is not None # Check that youtube service was called assert mock_youtube.search_videos_for_topic.call_count > 0 def test_distribute_quizzes(self): """Test the distribute_quizzes method.""" # Mock the quiz generator mock_quiz_generator = MagicMock() service = TreeBasedNodeStructure(mock_quiz_generator) # Create test nodes nodes = { "n1": Node( id="n1", title="Introduction to Python", description="Get started with Python", type="lesson", resources=[], prerequisites=[], visualPosition={"x": 0, "y": 0, "level": 0} ), "n2": Node( id="n2", title="Python Basics", description="Learn Python basics", type="lesson", resources=[], prerequisites=["n1"], visualPosition={"x": 0, "y": 200, "level": 1} ), "n3": Node( id="n3", title="Python Functions", description="Learn Python functions", type="lesson", resources=[], prerequisites=["n2"], visualPosition={"x": 0, "y": 400, "level": 2} ), "n4": Node( id="n4", title="Python Classes", description="Learn Python classes", type="lesson", resources=[], prerequisites=["n2"], visualPosition={"x": 200, "y": 400, "level": 2} ) } # Create test resources resources = [ Resource( id="r1", title="Python Programming", url="https://example.com/python", type="article", description="Learn Python programming", duration=None, readTime=15, difficulty="beginner", thumbnail=None ) ] # Distribute quizzes updated_nodes = service.distribute_quizzes( nodes=nodes, node_ids=["n1", "n2", "n3", "n4"], topic="Python", resources=resources, target_percentage=0.5 ) # Check results assert len(updated_nodes) == 4 # Count nodes with quizzes quiz_count = sum(1 for node in updated_nodes.values() if node.quiz is not None) # A implementação atual distribui pelo menos 1 quiz, não necessariamente 50% assert quiz_count >= 1 # Check that quiz generator was called assert mock_quiz_generator.generate_quiz.call_count >= 1 class TestDefaultPathGenerator: """Tests for the DefaultPathGenerator implementation.""" @pytest.mark.asyncio async def test_generate_learning_path(self): """Test the generate_learning_path method.""" # Mock the subtopic generator mock_subtopic_generator = MagicMock() mock_subtopic_generator.generate_subtopics.return_value = [ "Introduction to Python", "Python Basics", "Python Functions", "Python Classes" ] # Mock the node structure service mock_node_structure = MagicMock() mock_node_structure.create_node_structure = AsyncMock(return_value=( { "n1": Node( id="n1", title="Introduction to Python", description="Get started with Python", type="lesson", resources=[], prerequisites=[], visualPosition={"x": 0, "y": 0, "level": 0} ), "n2": Node( id="n2", title="Python Basics", description="Learn Python basics", type="lesson", resources=[], prerequisites=["n1"], visualPosition={"x": 0, "y": 200, "level": 1} ) }, ["n1", "n2"] )) mock_node_structure.distribute_quizzes.return_value = { "n1": Node( id="n1", title="Introduction to Python", description="Get started with Python", type="lesson", resources=[], prerequisites=[], visualPosition={"x": 0, "y": 0, "level": 0} ), "n2": Node( id="n2", title="Python Basics", description="Learn Python basics", type="lesson", resources=[], prerequisites=["n1"], visualPosition={"x": 0, "y": 200, "level": 1} ) } # Mock the category service mock_category_service = MagicMock() mock_category_service.detect_category.return_value = "technology" # Mock the cache mock_cache = MagicMock() mock_cache.get.return_value = None with patch("core.path_generator.default_path_generator.category_service", mock_category_service), \ patch("core.path_generator.default_path_generator.cache", mock_cache): generator = DefaultPathGenerator(mock_subtopic_generator, mock_node_structure) # Create test resources resources = [ Resource( id="r1", title="Python Programming", url="https://example.com/python", type="article", description="Learn Python programming", duration=None, readTime=15, difficulty="beginner", thumbnail=None ) ] # Generate learning path mcp = await generator.generate_learning_path( topic="Python", resources=resources, min_nodes=2, max_nodes=5, min_width=2, max_width=3, min_height=2, max_height=4, language="en" ) # Check results assert isinstance(mcp, MCP) assert mcp.topic == "Python" assert mcp.category == "technology" assert len(mcp.nodes) == 2 assert mcp.totalHours > 0 assert len(mcp.tags) > 0 # Check that subtopic generator was called mock_subtopic_generator.generate_subtopics.assert_called_once() # Check that node structure service was called mock_node_structure.create_node_structure.assert_called_once() mock_node_structure.distribute_quizzes.assert_called_once() # Check that category service was called at least once with "Python" assert mock_category_service.detect_category.call_count >= 1 assert call("Python") in mock_category_service.detect_category.call_args_list # Check that cache was used mock_cache.get.assert_called_once() mock_cache.setex.assert_called_once() def test_estimate_total_hours(self): """Test the estimate_total_hours method.""" generator = DefaultPathGenerator(MagicMock(), MagicMock()) # Create test resources resources = [ Resource( id="r1", title="Python Programming", url="https://example.com/python", type="article", description="Learn Python programming", duration=None, readTime=15, difficulty="beginner", thumbnail=None ), Resource( id="r2", title="Python Functions", url="https://example.com/functions", type="video", description="Understanding Python functions", duration=10, readTime=None, difficulty="intermediate", thumbnail=None ), Resource( id="r3", title="Python Classes", url="https://example.com/classes", type="tutorial", description="Learn Python classes", duration=None, readTime=None, difficulty="advanced", thumbnail=None ) ] # Estimate total hours total_hours = generator.estimate_total_hours(resources) # Check results assert total_hours > 0 assert isinstance(total_hours, int) def test_generate_tags(self): """Test the generate_tags method.""" generator = DefaultPathGenerator(MagicMock(), MagicMock()) # Mock the category service mock_category_service = MagicMock() mock_category_service.detect_category.return_value = "technology" with patch("core.path_generator.default_path_generator.category_service", mock_category_service): # Create test resources resources = [ Resource( id="r1", title="Python Programming", url="https://example.com/python", type="article", description="Learn Python programming", duration=None, readTime=15, difficulty="beginner", thumbnail=None ), Resource( id="r2", title="Python Functions", url="https://example.com/functions", type="video", description="Understanding Python functions", duration=10, readTime=None, difficulty="intermediate", thumbnail=None ) ] # Generate tags tags = generator.generate_tags("Python", resources) # Check results assert len(tags) > 0 assert "python" in tags assert "technology" in tags # Check that category service was called at least once with "Python" assert mock_category_service.detect_category.call_count >= 1 assert call("Python") in mock_category_service.detect_category.call_args_list class TestPathGeneratorFactory: """Tests for the PathGeneratorFactory.""" def test_create_path_generator(self): """Test the create_path_generator method.""" # Clear existing instances PathGeneratorFactory._instances = {} # Create generator generator = PathGeneratorFactory.create_path_generator("default") # Check type assert isinstance(generator, DefaultPathGenerator) # Check singleton pattern assert PathGeneratorFactory.create_path_generator("default") is generator

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/cabrit0/mcp_server_reuneMacacada'

If you have feedback or need assistance with the MCP directory API, please join our Discord server