Spaces:
Sleeping
Sleeping
| """ | |
| Tests for the gamification system in SkillSprout | |
| """ | |
| import pytest | |
| from unittest.mock import Mock, patch | |
| import sys | |
| import os | |
| # Add parent directory to path | |
| sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) | |
| from space_app import ( | |
| GamificationManager, Achievement, UserStats, EnhancedUserProgress | |
| ) | |
| class TestAchievement: | |
| """Test cases for Achievement data class""" | |
| def test_achievement_creation(self): | |
| """Test creating an achievement""" | |
| achievement = Achievement( | |
| id="test_achievement", | |
| name="Test Achievement", | |
| description="A test achievement", | |
| icon="๐", | |
| unlocked=False, | |
| unlock_condition="Complete 1 lesson" | |
| ) | |
| assert achievement.id == "test_achievement" | |
| assert achievement.name == "Test Achievement" | |
| assert achievement.unlocked is False | |
| assert achievement.icon == "๐" | |
| def test_achievement_defaults(self): | |
| """Test achievement with default values""" | |
| achievement = Achievement( | |
| id="simple", | |
| name="Simple", | |
| description="Simple achievement", | |
| icon="โญ" | |
| ) | |
| assert achievement.unlocked is False | |
| assert achievement.unlock_condition == "" | |
| class TestUserStats: | |
| """Test cases for UserStats class""" | |
| def test_user_stats_creation(self): | |
| """Test creating user stats""" | |
| stats = UserStats(user_id="test_user") | |
| assert stats.user_id == "test_user" | |
| assert stats.total_points == 0 | |
| assert stats.level == 1 | |
| assert stats.achievements == [] | |
| assert stats.streak_days == 0 | |
| assert stats.total_lessons == 0 | |
| assert stats.total_quizzes == 0 | |
| assert stats.correct_answers == 0 | |
| def test_add_points_no_level_up(self): | |
| """Test adding points without level up""" | |
| stats = UserStats(user_id="test_user") | |
| # Act | |
| stats.add_points(50) | |
| # Assert | |
| assert stats.total_points == 50 | |
| assert stats.level == 1 # Should still be level 1 | |
| def test_add_points_level_up(self): | |
| """Test adding points that triggers level up""" | |
| stats = UserStats(user_id="test_user") | |
| # Act | |
| stats.add_points(150) # Should trigger level up | |
| # Assert | |
| assert stats.total_points == 150 | |
| assert stats.level == 2 | |
| def test_add_points_multiple_levels(self): | |
| """Test adding points that triggers multiple level ups""" | |
| stats = UserStats(user_id="test_user") | |
| # Act | |
| stats.add_points(450) # Should reach level 5 | |
| # Assert | |
| assert stats.total_points == 450 | |
| assert stats.level == 5 | |
| def test_add_points_max_level(self): | |
| """Test that level doesn't exceed maximum""" | |
| stats = UserStats(user_id="test_user") | |
| # Act | |
| stats.add_points(2000) # Way more than needed for max level | |
| # Assert | |
| assert stats.level == 10 # Should cap at level 10 | |
| def test_get_accuracy_no_quizzes(self): | |
| """Test accuracy calculation with no quizzes""" | |
| stats = UserStats(user_id="test_user") | |
| # Act & Assert | |
| assert stats.get_accuracy() == 0.0 | |
| def test_get_accuracy_with_quizzes(self): | |
| """Test accuracy calculation with quiz data""" | |
| stats = UserStats(user_id="test_user") | |
| stats.total_quizzes = 10 | |
| stats.correct_answers = 8 | |
| # Act | |
| accuracy = stats.get_accuracy() | |
| # Assert | |
| assert accuracy == 80.0 | |
| class TestEnhancedUserProgress: | |
| """Test cases for EnhancedUserProgress class""" | |
| def test_enhanced_progress_creation(self): | |
| """Test creating enhanced user progress""" | |
| progress = EnhancedUserProgress( | |
| user_id="test_user", | |
| skill="Python Programming" | |
| ) | |
| assert progress.user_id == "test_user" | |
| assert progress.skill == "Python Programming" | |
| assert progress.lessons_completed == 0 | |
| assert progress.quiz_scores == [] | |
| assert progress.time_spent == [] | |
| assert progress.mastery_level == 0.0 | |
| class TestGamificationManager: | |
| """Test cases for GamificationManager class""" | |
| def gamification_manager(self): | |
| """Create a GamificationManager instance for testing""" | |
| return GamificationManager() | |
| def test_gamification_manager_initialization(self, gamification_manager): | |
| """Test GamificationManager initialization""" | |
| assert len(gamification_manager.user_stats) == 0 | |
| assert len(gamification_manager.achievements) > 0 | |
| # Check that all required achievements exist | |
| required_achievements = [ | |
| "first_steps", "quiz_master", "persistent", "scholar", | |
| "expert", "polyglot", "perfectionist", "speed", | |
| "consistent", "explorer" | |
| ] | |
| for achievement_id in required_achievements: | |
| assert achievement_id in gamification_manager.achievements | |
| def test_get_user_stats_new_user(self, gamification_manager): | |
| """Test getting stats for a new user""" | |
| # Act | |
| stats = gamification_manager.get_user_stats("new_user") | |
| # Assert | |
| assert isinstance(stats, UserStats) | |
| assert stats.user_id == "new_user" | |
| assert stats.total_points == 0 | |
| assert stats.level == 1 | |
| def test_get_user_stats_existing_user(self, gamification_manager): | |
| """Test getting stats for existing user""" | |
| # Arrange | |
| user_id = "existing_user" | |
| stats1 = gamification_manager.get_user_stats(user_id) | |
| stats1.total_points = 100 | |
| # Act | |
| stats2 = gamification_manager.get_user_stats(user_id) | |
| # Assert | |
| assert stats2.total_points == 100 | |
| assert stats1 is stats2 # Should be same object | |
| def test_check_achievements_first_steps(self, gamification_manager): | |
| """Test unlocking first steps achievement""" | |
| # Arrange | |
| user_id = "test_user" | |
| progress = EnhancedUserProgress(user_id=user_id, skill="Python") | |
| # Set up conditions for first steps achievement | |
| stats = gamification_manager.get_user_stats(user_id) | |
| stats.total_lessons = 1 | |
| # Act | |
| newly_unlocked = gamification_manager.check_achievements(user_id, progress) | |
| # Assert | |
| assert len(newly_unlocked) > 0 | |
| achievement_ids = [a.id for a in newly_unlocked] | |
| assert "first_steps" in achievement_ids | |
| assert "first_steps" in stats.achievements | |
| def test_check_achievements_quiz_master(self, gamification_manager): | |
| """Test unlocking quiz master achievement""" | |
| # Arrange | |
| user_id = "quiz_master_user" | |
| progress = EnhancedUserProgress(user_id=user_id, skill="Python") | |
| progress.quiz_scores = [100, 80, 100] # Has perfect score | |
| # Act | |
| newly_unlocked = gamification_manager.check_achievements(user_id, progress) | |
| # Assert | |
| achievement_ids = [a.id for a in newly_unlocked] | |
| assert "quiz_master" in achievement_ids | |
| def test_check_achievements_persistent(self, gamification_manager): | |
| """Test unlocking persistent learner achievement""" | |
| # Arrange | |
| user_id = "persistent_user" | |
| progress = EnhancedUserProgress(user_id=user_id, skill="Python") | |
| stats = gamification_manager.get_user_stats(user_id) | |
| stats.total_lessons = 5 | |
| # Act | |
| newly_unlocked = gamification_manager.check_achievements(user_id, progress) | |
| # Assert | |
| achievement_ids = [a.id for a in newly_unlocked] | |
| assert "persistent" in achievement_ids | |
| def test_check_achievements_no_new_unlocks(self, gamification_manager): | |
| """Test checking achievements when none should be unlocked""" | |
| # Arrange | |
| user_id = "minimal_user" | |
| progress = EnhancedUserProgress(user_id=user_id, skill="Python") | |
| # User has minimal progress, shouldn't unlock anything | |
| # Act | |
| newly_unlocked = gamification_manager.check_achievements(user_id, progress) | |
| # Assert | |
| assert len(newly_unlocked) == 0 | |
| def test_check_achievements_already_unlocked(self, gamification_manager): | |
| """Test that already unlocked achievements aren't returned again""" | |
| # Arrange | |
| user_id = "repeat_user" | |
| progress = EnhancedUserProgress(user_id=user_id, skill="Python") | |
| stats = gamification_manager.get_user_stats(user_id) | |
| stats.total_lessons = 1 | |
| stats.achievements = ["first_steps"] # Already unlocked | |
| # Act | |
| newly_unlocked = gamification_manager.check_achievements(user_id, progress) | |
| # Assert | |
| achievement_ids = [a.id for a in newly_unlocked] | |
| assert "first_steps" not in achievement_ids | |
| def test_check_achievements_points_awarded(self, gamification_manager): | |
| """Test that bonus points are awarded for achievements""" | |
| # Arrange | |
| user_id = "points_user" | |
| progress = EnhancedUserProgress(user_id=user_id, skill="Python") | |
| stats = gamification_manager.get_user_stats(user_id) | |
| initial_points = stats.total_points | |
| stats.total_lessons = 1 # Will unlock first_steps | |
| # Act | |
| newly_unlocked = gamification_manager.check_achievements(user_id, progress) | |
| # Assert | |
| assert len(newly_unlocked) > 0 | |
| assert stats.total_points > initial_points # Should have bonus points | |
| def test_achievement_perfectionist(self, gamification_manager): | |
| """Test perfectionist achievement (5 perfect scores)""" | |
| # Arrange | |
| user_id = "perfectionist_user" | |
| progress = EnhancedUserProgress(user_id=user_id, skill="Python") | |
| progress.quiz_scores = [100, 100, 100, 100, 100, 90] # 5 perfect scores | |
| # Act | |
| newly_unlocked = gamification_manager.check_achievements(user_id, progress) | |
| # Assert | |
| achievement_ids = [a.id for a in newly_unlocked] | |
| assert "perfectionist" in achievement_ids | |
| def test_achievement_consistent(self, gamification_manager): | |
| """Test consistent achievement (7-day streak)""" | |
| # Arrange | |
| user_id = "consistent_user" | |
| progress = EnhancedUserProgress(user_id=user_id, skill="Python") | |
| stats = gamification_manager.get_user_stats(user_id) | |
| stats.streak_days = 7 | |
| # Act | |
| newly_unlocked = gamification_manager.check_achievements(user_id, progress) | |
| # Assert | |
| achievement_ids = [a.id for a in newly_unlocked] | |
| assert "consistent" in achievement_ids | |
| class TestGamificationIntegration: | |
| """Integration tests for gamification with other systems""" | |
| def test_gamification_with_lesson_completion(self): | |
| """Test gamification integration when completing lessons""" | |
| # This would test the integration between the main app and gamification | |
| # Requires importing the enhanced app components | |
| pass | |
| def test_gamification_with_quiz_submission(self): | |
| """Test gamification integration when submitting quizzes""" | |
| pass | |
| class TestAchievementConditions: | |
| """Test specific achievement unlock conditions""" | |
| def sample_progress(self): | |
| """Create sample progress data for testing""" | |
| return EnhancedUserProgress( | |
| user_id="test_user", | |
| skill="Python Programming", | |
| lessons_completed=0, | |
| quiz_scores=[], | |
| time_spent=[], | |
| mastery_level=0.0 | |
| ) | |
| def test_scholar_achievement_condition(self, gamification_manager, enhanced_user_progress): | |
| """Test scholar achievement (10 lessons)""" | |
| # Arrange | |
| stats = gamification_manager.get_user_stats("test_user") | |
| stats.total_lessons = 10 | |
| # Act | |
| newly_unlocked = gamification_manager.check_achievements("test_user", enhanced_user_progress) | |
| # Assert | |
| achievement_ids = [a.id for a in newly_unlocked] | |
| assert "scholar" in achievement_ids | |
| def test_expert_achievement_condition(self, gamification_manager, enhanced_user_progress): | |
| """Test expert achievement (20 lessons)""" | |
| # Arrange | |
| stats = gamification_manager.get_user_stats("test_user") | |
| stats.total_lessons = 20 | |
| # Act | |
| newly_unlocked = gamification_manager.check_achievements("test_user", enhanced_user_progress) | |
| # Assert | |
| achievement_ids = [a.id for a in newly_unlocked] | |
| assert "expert" in achievement_ids | |
| assert "scholar" in achievement_ids # Should also unlock scholar | |
| assert "persistent" in achievement_ids # Should also unlock persistent | |