""" Tests unitaires pour le GradingCalculator. """ import pytest from domain.services.grading_calculator import ( GradingCalculator, NotesStrategy, ScoreStrategy, GradingStrategyFactory, ) class TestNotesStrategy: """Tests pour la stratégie de notation par points.""" def test_calculate_integer(self): strategy = NotesStrategy() assert strategy.calculate_score("15", 20) == 15.0 def test_calculate_decimal_point(self): strategy = NotesStrategy() assert strategy.calculate_score("15.5", 20) == 15.5 def test_calculate_decimal_comma(self): strategy = NotesStrategy() assert strategy.calculate_score("15,5", 20) == 15.5 def test_calculate_zero(self): strategy = NotesStrategy() assert strategy.calculate_score("0", 20) == 0.0 def test_calculate_invalid(self): strategy = NotesStrategy() assert strategy.calculate_score("invalid", 20) == 0.0 def test_grading_type(self): strategy = NotesStrategy() assert strategy.get_grading_type() == "notes" class TestScoreStrategy: """Tests pour la stratégie de notation par compétences.""" def test_calculate_score_0(self): strategy = ScoreStrategy() # 0/3 * 6 = 0 assert strategy.calculate_score("0", 6) == 0.0 def test_calculate_score_1(self): strategy = ScoreStrategy() # 1/3 * 6 = 2 assert strategy.calculate_score("1", 6) == 2.0 def test_calculate_score_2(self): strategy = ScoreStrategy() # 2/3 * 6 = 4 assert strategy.calculate_score("2", 6) == 4.0 def test_calculate_score_3(self): strategy = ScoreStrategy() # 3/3 * 6 = 6 assert strategy.calculate_score("3", 6) == 6.0 def test_calculate_score_3_with_max_3(self): strategy = ScoreStrategy() # 3/3 * 3 = 3 assert strategy.calculate_score("3", 3) == 3.0 def test_calculate_score_2_with_max_3(self): strategy = ScoreStrategy() # 2/3 * 3 = 2 assert strategy.calculate_score("2", 3) == 2.0 def test_calculate_invalid_score(self): strategy = ScoreStrategy() assert strategy.calculate_score("4", 6) == 0.0 def test_calculate_negative_score(self): strategy = ScoreStrategy() assert strategy.calculate_score("-1", 6) == 0.0 def test_calculate_non_numeric(self): strategy = ScoreStrategy() assert strategy.calculate_score("abc", 6) == 0.0 def test_grading_type(self): strategy = ScoreStrategy() assert strategy.get_grading_type() == "score" class TestGradingStrategyFactory: """Tests pour la factory de stratégies.""" def test_create_notes_strategy(self): strategy = GradingStrategyFactory.create("notes") assert isinstance(strategy, NotesStrategy) def test_create_score_strategy(self): strategy = GradingStrategyFactory.create("score") assert isinstance(strategy, ScoreStrategy) def test_create_unknown_raises(self): with pytest.raises(ValueError, match="Type de notation non supporté"): GradingStrategyFactory.create("unknown") class TestGradingCalculator: """Tests pour le calculateur unifié.""" def test_calculate_notes_score(self): calc = GradingCalculator() assert calc.calculate_score("15.5", "notes", 20) == 15.5 def test_calculate_competence_score(self): calc = GradingCalculator() # 2/3 * 3 = 2 assert calc.calculate_score("2", "score", 3) == 2.0 def test_special_value_dot(self): calc = GradingCalculator() # "." = pas de réponse = 0 assert calc.calculate_score(".", "notes", 20) == 0.0 def test_special_value_d(self): calc = GradingCalculator() # "d" = dispensé = None assert calc.calculate_score("d", "notes", 20) is None def test_special_value_a(self): calc = GradingCalculator() # "a" = absent = 0 assert calc.calculate_score("a", "notes", 20) == 0.0 def test_empty_value(self): calc = GradingCalculator() assert calc.calculate_score("", "notes", 20) is None def test_whitespace_value(self): calc = GradingCalculator() assert calc.calculate_score(" ", "notes", 20) is None def test_is_special_value_dot(self): calc = GradingCalculator() assert calc.is_special_value(".") is True def test_is_special_value_d(self): calc = GradingCalculator() assert calc.is_special_value("d") is True def test_is_special_value_a(self): calc = GradingCalculator() assert calc.is_special_value("a") is True def test_is_special_value_number(self): calc = GradingCalculator() assert calc.is_special_value("15") is False def test_is_counted_in_total_dot(self): calc = GradingCalculator() # "." compte dans le total (comme 0) assert calc.is_counted_in_total(".") is True def test_is_counted_in_total_d(self): calc = GradingCalculator() # "d" ne compte pas (dispensé) assert calc.is_counted_in_total("d") is False def test_is_counted_in_total_a(self): calc = GradingCalculator() # "a" compte dans le total (comme 0) assert calc.is_counted_in_total("a") is True def test_is_counted_in_total_normal(self): calc = GradingCalculator() assert calc.is_counted_in_total("15") is True def test_is_counted_in_total_empty(self): calc = GradingCalculator() assert calc.is_counted_in_total("") is False class TestGradingCalculatorValidation: """Tests pour la validation des notes.""" def test_validate_notes_integer(self): calc = GradingCalculator() assert calc.validate_grade_value("15", "notes") is True def test_validate_notes_decimal(self): calc = GradingCalculator() assert calc.validate_grade_value("15.5", "notes") is True def test_validate_notes_comma(self): calc = GradingCalculator() assert calc.validate_grade_value("15,5", "notes") is True def test_validate_notes_negative(self): calc = GradingCalculator() assert calc.validate_grade_value("-5", "notes") is False def test_validate_notes_exceeds_max(self): calc = GradingCalculator() assert calc.validate_grade_value("25", "notes", max_points=20) is False def test_validate_notes_within_max(self): calc = GradingCalculator() assert calc.validate_grade_value("18", "notes", max_points=20) is True def test_validate_score_valid(self): calc = GradingCalculator() for score in ["0", "1", "2", "3"]: assert calc.validate_grade_value(score, "score") is True def test_validate_score_invalid(self): calc = GradingCalculator() assert calc.validate_grade_value("4", "score") is False assert calc.validate_grade_value("-1", "score") is False assert calc.validate_grade_value("abc", "score") is False def test_validate_special_values(self): calc = GradingCalculator() assert calc.validate_grade_value(".", "notes") is True assert calc.validate_grade_value("d", "score") is True assert calc.validate_grade_value("a", "notes") is True def test_validate_empty(self): calc = GradingCalculator() assert calc.validate_grade_value("", "notes") is True assert calc.validate_grade_value(" ", "score") is True class TestGradingCalculatorCustomConfig: """Tests avec configuration personnalisée.""" def test_custom_special_values(self): custom_config = { "x": { "label": "Excusé", "value": 0, "counts": False } } calc = GradingCalculator(special_values=custom_config) assert calc.is_special_value("x") is True assert calc.calculate_score("x", "notes", 20) == 0.0 assert calc.is_counted_in_total("x") is False # Les valeurs par défaut ne sont plus disponibles assert calc.is_special_value(".") is False