Spaces:
Running
Running
Download backend/tests/test_answer_utils.py from banu4prasad/Gateprep: direct link, hf CLI and curl.
- Browser
- Download file 5.87 kB
-
https://huggingface.co/spaces/banu4prasad/Gateprep/resolve/main/backend/tests/test_answer_utils.py
- Command line
-
hf download hf://spaces/banu4prasad/Gateprep/backend/tests/test_answer_utils.py
-
curl -L -o test_answer_utils.py https://huggingface.co/spaces/banu4prasad/Gateprep/resolve/main/backend/tests/test_answer_utils.py
5.87 kB
| import math | |
| import pytest | |
| from enum import Enum | |
| from app.services.answer_utils import ( | |
| normalize_question_type, | |
| parse_float, | |
| parse_nat_range, | |
| split_answer_tokens, | |
| is_valid_nat_answer, | |
| normalize_choice_answer, | |
| validate_msq_answer, | |
| validate_mcq_answer, | |
| validate_nat_answer, | |
| validate_answer_for_type, | |
| ) | |
| class DummyEnum(Enum): | |
| MCQ = "MCQ" | |
| NAT = "QuestionType.NAT" | |
| def test_normalize_question_type(): | |
| assert normalize_question_type(" MCQ ") == "mcq" | |
| assert normalize_question_type("NAT") == "nat" | |
| assert normalize_question_type("QuestionType.MSQ") == "msq" | |
| assert normalize_question_type(DummyEnum.MCQ) == "mcq" | |
| assert normalize_question_type(DummyEnum.NAT) == "nat" | |
| assert normalize_question_type(None) == "" | |
| assert normalize_question_type("") == "" | |
| def test_parse_float(): | |
| assert parse_float("1.23") == 1.23 | |
| assert parse_float("-0.5") == -0.5 | |
| assert parse_float("1e-5") == 1e-5 | |
| assert parse_float(42) == 42.0 | |
| # Invalid strings | |
| assert parse_float("abc") is None | |
| assert parse_float("1.2.3") is None | |
| assert parse_float("") is None | |
| assert parse_float(None) is None | |
| # Non-finite values | |
| assert parse_float(float("inf")) is None | |
| assert parse_float(float("-inf")) is None | |
| assert parse_float(float("nan")) is None | |
| def test_parse_nat_range(): | |
| assert parse_nat_range("1-2") == (1.0, 2.0) | |
| assert parse_nat_range("1.5 : 2.5") == (1.5, 2.5) | |
| assert parse_nat_range(" 10 to 20 ") == (10.0, 20.0) | |
| assert parse_nat_range("-2--1") == (-2.0, -1.0) | |
| assert parse_nat_range("-5 : -3.5") == (-5.0, -3.5) | |
| # Invalid ranges (lo > hi) | |
| assert parse_nat_range("2-1") is None | |
| assert parse_nat_range("5 to 3") is None | |
| # Invalid formats | |
| assert parse_nat_range("1-2-3") is None | |
| assert parse_nat_range("abc-def") is None | |
| assert parse_nat_range("1") is None | |
| assert parse_nat_range(None) is None | |
| def test_split_answer_tokens(): | |
| assert split_answer_tokens("A, B, C") == ["A", "B", "C"] | |
| assert split_answer_tokens("A ; B / C") == ["A", "B", "C"] | |
| assert split_answer_tokens(" word1 , word2 ") == ["word1", "word2"] | |
| assert split_answer_tokens("A") == ["A"] | |
| assert split_answer_tokens("") == [] | |
| assert split_answer_tokens(" ") == [] | |
| assert split_answer_tokens(None) == [] | |
| assert split_answer_tokens(",;/") == [] | |
| def test_is_valid_nat_answer(): | |
| assert is_valid_nat_answer("1.5") is True | |
| assert is_valid_nat_answer("1.5:2.5") is True | |
| assert is_valid_nat_answer("-10 to -5") is True | |
| assert is_valid_nat_answer("1.5, 2.5:3.5, 4") is True | |
| assert is_valid_nat_answer("abc") is False | |
| assert is_valid_nat_answer("1.5, abc") is False | |
| assert is_valid_nat_answer("") is False | |
| assert is_valid_nat_answer(None) is False | |
| assert is_valid_nat_answer("2-1") is False # Invalid range (lo > hi) | |
| assert is_valid_nat_answer("1.5-2.5-3.5") is False | |
| def test_normalize_choice_answer(): | |
| assert normalize_choice_answer("a, b, c") == "A,B,C" | |
| assert normalize_choice_answer(" a ; B / c ") == "A,B,C" | |
| assert normalize_choice_answer("option1") == "OPTION1" | |
| assert normalize_choice_answer(" ") == "" | |
| assert normalize_choice_answer(None) == "" | |
| from app.models.models import Question | |
| from app.services.scoring import evaluate_answer | |
| def test_nat_colon_range_scores_boundary_values(): | |
| question = Question( | |
| question_type="nat", | |
| question_text="Probability", | |
| options=[], | |
| correct_answer="0.44:0.45", | |
| marks=2.0, | |
| negative_marks=0.0, | |
| ) | |
| for selected in ("0.44", "0.445", "0.45"): | |
| assert evaluate_answer(question, selected) == (True, 2.0) | |
| assert evaluate_answer(question, "0.46") == (False, 0.0) | |
| def test_nat_hyphen_negative_range_still_works(): | |
| assert parse_nat_range("-2--1") == (-2.0, -1.0) | |
| assert is_valid_nat_answer("-2--1") is True | |
| def test_validate_mcq_answer(): | |
| assert validate_mcq_answer("A") == "A" | |
| assert validate_mcq_answer("C") == "C" | |
| with pytest.raises(ValueError, match="MCQ correct_answer must be one of A, B, C, or D"): | |
| validate_mcq_answer("E") | |
| with pytest.raises(ValueError, match="MCQ correct_answer must be one of A, B, C, or D"): | |
| validate_mcq_answer("A,B") | |
| def test_validate_msq_answer(): | |
| # Happy paths | |
| assert validate_msq_answer("A, B") == ("A,B", 0.0) | |
| assert validate_msq_answer(" a ; C / d ") == ("A,C,D", 0.0) | |
| assert validate_msq_answer("A") == ("A", 0.0) | |
| # Duplicates are removed (order preserved) | |
| assert validate_msq_answer("A, B, A, C, b") == ("A,B,C", 0.0) | |
| # Error cases | |
| with pytest.raises(ValueError, match="MSQ correct_answer must contain option letters like A,C"): | |
| validate_msq_answer("") | |
| with pytest.raises(ValueError, match="MSQ correct_answer must contain option letters like A,C"): | |
| validate_msq_answer("A, E") | |
| with pytest.raises(ValueError, match="MSQ correct_answer must contain option letters like A,C"): | |
| validate_msq_answer("1, 2") | |
| def test_validate_nat_answer(): | |
| assert validate_nat_answer("1.5:2.5") == 0.0 | |
| assert validate_nat_answer("42") == 0.0 | |
| with pytest.raises(ValueError, match="NAT correct_answer must be a number or range like 41.5-42.5 or 41.5:42.5"): | |
| validate_nat_answer("abc") | |
| def test_validate_answer_for_type(): | |
| # MCQ | |
| ans, neg, clear = validate_answer_for_type("mcq", "B") | |
| assert ans == "B" | |
| assert neg is None | |
| assert clear is False | |
| # MSQ | |
| ans, neg, clear = validate_answer_for_type("msq", "A, C") | |
| assert ans == "A,C" | |
| assert neg == 0.0 | |
| assert clear is False | |
| # NAT | |
| ans, neg, clear = validate_answer_for_type("nat", "1.5:2.5") | |
| assert ans == "1.5:2.5" | |
| assert neg == 0.0 | |
| assert clear is True | |