import pytest from datetime import date from werkzeug.exceptions import NotFound from models import db, ClassGroup, Student, Assessment from repositories.class_repository import ClassRepository class TestClassRepository: """Tests complets pour ClassRepository.""" def test_get_or_404_success(self, app): """Test de récupération par ID avec succès.""" with app.app_context(): repo = ClassRepository() # Créer une classe de test class_group = ClassGroup(name="6A", year="2023-2024") db.session.add(class_group) db.session.commit() # Test found = repo.get_or_404(class_group.id) assert found is not None assert found.name == "6A" assert found.year == "2023-2024" assert found.id == class_group.id def test_get_or_404_not_found(self, app): """Test de récupération par ID avec erreur 404.""" with app.app_context(): repo = ClassRepository() # Test avec un ID inexistant with pytest.raises(NotFound): repo.get_or_404(999) def test_find_by_name_success(self, app): """Test de recherche par nom avec succès.""" with app.app_context(): repo = ClassRepository() # Créer des classes de test class_group1 = ClassGroup(name="6A", year="2023-2024") class_group2 = ClassGroup(name="6B", year="2023-2024") db.session.add_all([class_group1, class_group2]) db.session.commit() # Test found = repo.find_by_name("6A") assert found is not None assert found.name == "6A" assert found.year == "2023-2024" # Test avec nom inexistant not_found = repo.find_by_name("6Z") assert not_found is None def test_exists_by_name_without_exclude(self, app): """Test d'existence par nom sans exclusion.""" with app.app_context(): repo = ClassRepository() # Créer une classe de test class_group = ClassGroup(name="6A", year="2023-2024") db.session.add(class_group) db.session.commit() # Test existence assert repo.exists_by_name("6A") is True assert repo.exists_by_name("6Z") is False def test_exists_by_name_with_exclude(self, app): """Test d'existence par nom avec exclusion d'un ID.""" with app.app_context(): repo = ClassRepository() # Créer des classes de test class_group1 = ClassGroup(name="6A", year="2023-2024") class_group2 = ClassGroup(name="6B", year="2023-2024") db.session.add_all([class_group1, class_group2]) db.session.commit() # Test sans exclusion assert repo.exists_by_name("6A") is True # Test avec exclusion de la classe même assert repo.exists_by_name("6A", exclude_id=class_group1.id) is False # Test avec exclusion d'une autre classe assert repo.exists_by_name("6A", exclude_id=class_group2.id) is True def test_find_all_ordered_year_name(self, app): """Test de recherche triée par année puis nom.""" with app.app_context(): repo = ClassRepository() # Créer des classes de test avec différentes années classes = [ ClassGroup(name="6B", year="2023-2024"), ClassGroup(name="6A", year="2023-2024"), ClassGroup(name="5B", year="2024-2025"), ClassGroup(name="5A", year="2024-2025"), ] db.session.add_all(classes) db.session.commit() # Test tri par année puis nom (défaut) ordered = repo.find_all_ordered() assert len(ordered) >= 4 # Extraire les classes créées pour ce test test_classes = [c for c in ordered if c.year in ["2023-2024", "2024-2025"]] # Vérifier l'ordre : année puis nom expected_order = [ ("2023-2024", "6A"), ("2023-2024", "6B"), ("2024-2025", "5A"), ("2024-2025", "5B"), ] actual_order = [(c.year, c.name) for c in test_classes] assert actual_order == expected_order def test_find_all_ordered_name(self, app): """Test de recherche triée par nom uniquement.""" with app.app_context(): repo = ClassRepository() # Créer des classes de test classes = [ ClassGroup(name="6C", year="2023-2024"), ClassGroup(name="6A", year="2024-2025"), ClassGroup(name="6B", year="2023-2024"), ] db.session.add_all(classes) db.session.commit() # Test tri par nom ordered = repo.find_all_ordered(order_by='name') # Extraire les classes créées pour ce test test_classes = [c for c in ordered if c.name in ["6A", "6B", "6C"]] # Vérifier l'ordre : nom seulement names = [c.name for c in test_classes] assert names == ["6A", "6B", "6C"] def test_find_all_ordered_year(self, app): """Test de recherche triée par année uniquement.""" with app.app_context(): repo = ClassRepository() # Créer des classes de test classes = [ ClassGroup(name="6C", year="2024-2025"), ClassGroup(name="6A", year="2023-2024"), ClassGroup(name="6B", year="2025-2026"), ] db.session.add_all(classes) db.session.commit() # Test tri par année ordered = repo.find_all_ordered(order_by='year') # Extraire les classes créées pour ce test test_classes = [c for c in ordered if c.name in ["6A", "6B", "6C"]] # Vérifier l'ordre : année seulement years = [c.year for c in test_classes] assert years == ["2023-2024", "2024-2025", "2025-2026"] def test_find_all_ordered_invalid_sort(self, app): """Test de recherche avec critère de tri invalide (utilise le défaut).""" with app.app_context(): repo = ClassRepository() # Créer des classes de test class_group = ClassGroup(name="6A", year="2023-2024") db.session.add(class_group) db.session.commit() # Test avec critère invalide (devrait utiliser tri par nom par défaut) ordered = repo.find_all_ordered(order_by='invalid') assert len(ordered) >= 1 def test_count_all(self, app): """Test de comptage total des classes.""" with app.app_context(): repo = ClassRepository() # Compter avant ajout initial_count = repo.count_all() # Créer des classes de test classes = [ ClassGroup(name="6A", year="2023-2024"), ClassGroup(name="6B", year="2023-2024"), ClassGroup(name="5A", year="2023-2024"), ] db.session.add_all(classes) db.session.commit() # Compter après ajout final_count = repo.count_all() assert final_count == initial_count + 3 def test_can_be_deleted_empty_class(self, app): """Test de vérification de suppression pour une classe vide.""" with app.app_context(): repo = ClassRepository() # Créer une classe vide class_group = ClassGroup(name="6A", year="2023-2024") db.session.add(class_group) db.session.commit() # Test can_delete, dependencies = repo.can_be_deleted(class_group.id) assert can_delete is True assert dependencies['students'] == 0 assert dependencies['assessments'] == 0 def test_can_be_deleted_with_students(self, app): """Test de vérification de suppression pour une classe avec étudiants.""" with app.app_context(): repo = ClassRepository() # Créer une classe avec étudiants class_group = ClassGroup(name="6A", year="2023-2024") db.session.add(class_group) db.session.commit() students = [ Student(first_name="Jean", last_name="Dupont", class_group_id=class_group.id), Student(first_name="Marie", last_name="Martin", class_group_id=class_group.id), ] db.session.add_all(students) db.session.commit() # Test can_delete, dependencies = repo.can_be_deleted(class_group.id) assert can_delete is False assert dependencies['students'] == 2 assert dependencies['assessments'] == 0 def test_can_be_deleted_with_assessments(self, app): """Test de vérification de suppression pour une classe avec évaluations.""" with app.app_context(): repo = ClassRepository() # Créer une classe avec évaluations class_group = ClassGroup(name="6A", year="2023-2024") db.session.add(class_group) db.session.commit() assessments = [ Assessment(title="Test 1", trimester=1, class_group_id=class_group.id, date=date(2023, 10, 15)), Assessment(title="Test 2", trimester=2, class_group_id=class_group.id, date=date(2023, 12, 15)), ] db.session.add_all(assessments) db.session.commit() # Test can_delete, dependencies = repo.can_be_deleted(class_group.id) assert can_delete is False assert dependencies['students'] == 0 assert dependencies['assessments'] == 2 def test_can_be_deleted_with_both(self, app): """Test de vérification de suppression pour une classe avec étudiants et évaluations.""" with app.app_context(): repo = ClassRepository() # Créer une classe avec étudiants et évaluations class_group = ClassGroup(name="6A", year="2023-2024") db.session.add(class_group) db.session.commit() student = Student(first_name="Jean", last_name="Dupont", class_group_id=class_group.id) assessment = Assessment(title="Test", trimester=1, class_group_id=class_group.id, date=date(2023, 10, 15)) db.session.add_all([student, assessment]) db.session.commit() # Test can_delete, dependencies = repo.can_be_deleted(class_group.id) assert can_delete is False assert dependencies['students'] == 1 assert dependencies['assessments'] == 1 def test_find_with_students_ordered_success(self, app): """Test de recherche avec étudiants triés.""" with app.app_context(): repo = ClassRepository() # Créer une classe avec étudiants class_group = ClassGroup(name="6A", year="2023-2024") db.session.add(class_group) db.session.commit() students = [ Student(first_name="Marie", last_name="Zidane", class_group_id=class_group.id), Student(first_name="Jean", last_name="Dupont", class_group_id=class_group.id), Student(first_name="Paul", last_name="Martin", class_group_id=class_group.id), ] db.session.add_all(students) db.session.commit() # Test found = repo.find_with_students_ordered(class_group.id) assert found is not None assert found.name == "6A" assert hasattr(found, '_students_ordered') # Vérifier le tri : Dupont, Martin, Zidane ordered_names = [f"{s.last_name}, {s.first_name}" for s in found._students_ordered] assert ordered_names == ["Dupont, Jean", "Martin, Paul", "Zidane, Marie"] def test_find_with_students_ordered_not_found(self, app): """Test de recherche avec étudiants triés pour classe inexistante.""" with app.app_context(): repo = ClassRepository() # Test avec ID inexistant found = repo.find_with_students_ordered(999) assert found is None def test_find_with_recent_assessments_success(self, app): """Test de recherche avec évaluations récentes.""" with app.app_context(): repo = ClassRepository() # Créer une classe avec évaluations class_group = ClassGroup(name="6A", year="2023-2024") db.session.add(class_group) db.session.commit() assessments = [ Assessment(title="Test 1", trimester=1, class_group_id=class_group.id, date=date(2023, 10, 1)), Assessment(title="Test 2", trimester=1, class_group_id=class_group.id, date=date(2023, 10, 15)), Assessment(title="Test 3", trimester=2, class_group_id=class_group.id, date=date(2023, 12, 1)), Assessment(title="Test 4", trimester=2, class_group_id=class_group.id, date=date(2023, 12, 15)), ] db.session.add_all(assessments) db.session.commit() # Test avec limite par défaut (5) found = repo.find_with_recent_assessments(class_group.id) assert found is not None assert found.name == "6A" assert hasattr(found, '_recent_assessments') assert len(found._recent_assessments) == 4 # Vérifier le tri par date décroissante dates = [a.date for a in found._recent_assessments] assert dates == sorted(dates, reverse=True) assert found._recent_assessments[0].title == "Test 4" # Plus récent def test_find_with_recent_assessments_with_limit(self, app): """Test de recherche avec évaluations récentes avec limite.""" with app.app_context(): repo = ClassRepository() # Créer une classe avec plusieurs évaluations class_group = ClassGroup(name="6A", year="2023-2024") db.session.add(class_group) db.session.commit() assessments = [] for i in range(7): assessment = Assessment( title=f"Test {i}", trimester=1, class_group_id=class_group.id, date=date(2023, 10, i + 1) ) assessments.append(assessment) db.session.add_all(assessments) db.session.commit() # Test avec limite de 3 found = repo.find_with_recent_assessments(class_group.id, limit=3) assert found is not None assert len(found._recent_assessments) == 3 # Les 3 plus récentes : Test 6, Test 5, Test 4 titles = [a.title for a in found._recent_assessments] assert titles == ["Test 6", "Test 5", "Test 4"] def test_find_with_recent_assessments_not_found(self, app): """Test de recherche avec évaluations récentes pour classe inexistante.""" with app.app_context(): repo = ClassRepository() # Test avec ID inexistant found = repo.find_with_recent_assessments(999) assert found is None def test_find_with_full_details_success(self, app): """Test de recherche avec tous les détails.""" with app.app_context(): repo = ClassRepository() # Créer une classe complète class_group = ClassGroup(name="6A", year="2023-2024") db.session.add(class_group) db.session.commit() # Ajouter étudiants et évaluations student = Student(first_name="Jean", last_name="Dupont", class_group_id=class_group.id) assessment = Assessment(title="Test", trimester=1, class_group_id=class_group.id, date=date(2023, 10, 15)) db.session.add_all([student, assessment]) db.session.commit() # Test found = repo.find_with_full_details(class_group.id) assert found is not None assert found.name == "6A" # Vérifier que les relations sont chargées (pas de requête supplémentaire) assert len(found.students) >= 1 assert len(found.assessments) >= 1 assert found.students[0].first_name == "Jean" assert found.assessments[0].title == "Test" def test_find_with_full_details_not_found(self, app): """Test de recherche avec tous les détails pour classe inexistante.""" with app.app_context(): repo = ClassRepository() # Test avec ID inexistant found = repo.find_with_full_details(999) assert found is None def test_get_students_count(self, app): """Test de comptage des étudiants d'une classe.""" with app.app_context(): repo = ClassRepository() # Créer une classe avec étudiants class_group = ClassGroup(name="6A", year="2023-2024") db.session.add(class_group) db.session.commit() # Compter avant ajout count_before = repo.get_students_count(class_group.id) assert count_before == 0 # Ajouter des étudiants students = [ Student(first_name="Jean", last_name="Dupont", class_group_id=class_group.id), Student(first_name="Marie", last_name="Martin", class_group_id=class_group.id), Student(first_name="Paul", last_name="Durand", class_group_id=class_group.id), ] db.session.add_all(students) db.session.commit() # Compter après ajout count_after = repo.get_students_count(class_group.id) assert count_after == 3 def test_get_assessments_count(self, app): """Test de comptage des évaluations d'une classe.""" with app.app_context(): repo = ClassRepository() # Créer une classe avec évaluations class_group = ClassGroup(name="6A", year="2023-2024") db.session.add(class_group) db.session.commit() # Compter avant ajout count_before = repo.get_assessments_count(class_group.id) assert count_before == 0 # Ajouter des évaluations assessments = [ Assessment(title="Test 1", trimester=1, class_group_id=class_group.id, date=date(2023, 10, 1)), Assessment(title="Test 2", trimester=2, class_group_id=class_group.id, date=date(2023, 12, 1)), ] db.session.add_all(assessments) db.session.commit() # Compter après ajout count_after = repo.get_assessments_count(class_group.id) assert count_after == 2 def test_find_for_form_choices(self, app): """Test de recherche pour les choix de formulaires.""" with app.app_context(): repo = ClassRepository() # Créer des classes de test classes = [ ClassGroup(name="6C", year="2023-2024"), ClassGroup(name="6A", year="2023-2024"), ClassGroup(name="6B", year="2023-2024"), ] db.session.add_all(classes) db.session.commit() # Test choices = repo.find_for_form_choices() # Extraire les classes créées pour ce test test_choices = [c for c in choices if c.name in ["6A", "6B", "6C"]] # Vérifier le tri par nom names = [c.name for c in test_choices] assert names == ["6A", "6B", "6C"] def test_inherited_methods(self, app): """Test des méthodes héritées du BaseRepository.""" with app.app_context(): repo = ClassRepository() # Test find_by_id class_group = ClassGroup(name="6A", year="2023-2024") saved = repo.save(class_group) repo.commit() found = repo.find_by_id(class_group.id) assert found is not None assert found.name == "6A" # Test find_all all_classes = repo.find_all() assert len(all_classes) >= 1 # Test delete repo.delete(class_group) repo.commit() found_after_delete = repo.find_by_id(class_group.id) assert found_after_delete is None