Skip to content

Commit

Permalink
Improve unit test coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
francesco-ballarin committed Feb 14, 2024
1 parent 209c8c3 commit ea4eead
Show file tree
Hide file tree
Showing 4 changed files with 840 additions and 10 deletions.
46 changes: 36 additions & 10 deletions mathrace_interaction/mathrace_interaction/journal_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,22 +136,22 @@ def _reset_stream_to_position(self, position: int) -> None:
@abc.abstractmethod
def _read_race_definition_section(self, turing_dict: TuringDict) -> None:
"""Read the race definition section."""
pass
pass # pragma: no cover

@abc.abstractmethod
def _read_questions_definition_section(self, turing_dict: TuringDict) -> None:
"""Read the questions definition section."""
pass
pass # pragma: no cover

@abc.abstractmethod
def _read_teams_definition_section(self, turing_dict: TuringDict) -> None:
"""Read the teams definition section."""
pass
pass # pragma: no cover

@abc.abstractmethod
def _read_race_events_section(self, turing_dict: TuringDict) -> None:
"""Read all race events."""
pass
pass # pragma: no cover


class JournalReaderR5539(AbstractJournalReader):
Expand Down Expand Up @@ -365,12 +365,15 @@ def _process_race_definition_deadline_score_increase_entry(
def _read_questions_definition_section(self, turing_dict: TuringDict) -> None:
"""Read the questions definition section."""
# Define first a default configuration in which every question has a score of 20
if "default_score" not in turing_dict["mathrace_only"]:
turing_dict["mathrace_only"]["default_score"] = "20"
default_score = turing_dict["mathrace_only"]["default_score"]
questions: list[dict[str, str]] = list()
num_questions = int(turing_dict["num_problemi"])
for q in range(num_questions):
questions.append({
"problema": str(q + 1), "nome": f"Problema {q + 1}",
"risposta": str(int(True)), "punteggio": "20"
"risposta": str(int(True)), "punteggio": default_score
})
turing_dict["soluzioni"] = questions
# Update the default initialization based on values read from file
Expand Down Expand Up @@ -514,7 +517,7 @@ def _process_manual_bonus_event(self, timestamp_str: str, event_content: str, tu
"""Process a manual bonus event."""
event_datetime = self._convert_timestamp_to_datetime(timestamp_str, True, turing_dict)
turing_dict["mathrace_only"]["manual_bonuses"].append({
"orario": event_datetime, "motivazione": event_content})
"orario": event_datetime.isoformat(), "motivazione": event_content})

def _convert_timestamp_to_datetime(
self, timestamp_str: str, strict: bool, turing_dict: TuringDict
Expand Down Expand Up @@ -832,19 +835,20 @@ def _process_alternative_race_definition_num_questions_entry(
num_questions, default_score = num_questions_alternative.split(":")
else:
num_questions = num_questions_alternative
default_score = "20"
# Store the results in the dictionary
turing_dict["mathrace_only"]["num_questions_alternative"] = num_questions_alternative
turing_dict["num_problemi"] = num_questions
turing_dict["mathrace_only"]["default_score"] = num_questions_alternative
turing_dict["mathrace_only"]["default_score"] = default_score
# It is now possible to set the initial score, if it calculation was delayed when reading the first entry
initial_score = turing_dict["mathrace_only"]["initial_score"]
if initial_score == "N/A":
initial_score == str(int(num_questions) * 10)
turing_dict["mathrace_only"]["initial_score"] = str(int(num_questions) * 10)
else:
expected_score = int(num_questions) * 10
if int(initial_score) != expected_score:
raise RuntimeError(
f"Invalid line {line} in race definition: the expected score is {expected_score}, "
f"Invalid line {line} in alternative race definition: the expected score is {expected_score}, "
f"but the race definition contains {initial_score}. This is not compatible with turing, "
f"since it does not allow to change the initial score")

Expand Down Expand Up @@ -874,7 +878,7 @@ def _process_alternative_race_definition_total_time_deadline_score_increase_entr
"""Process the total time of the race in the race definition line."""
if "-" not in times:
raise RuntimeError(
f"Invalid line {line} in race definition: it does not contain the opreator -")
f"Invalid line {line} in race definition: it does not contain the operator -")
turing_dict["durata"], turing_dict["durata_blocco"] = times.split("-")


Expand Down Expand Up @@ -923,6 +927,28 @@ def _read_race_definition_section(self, turing_dict: TuringDict) -> None:
else:
self._process_bonus_or_superbonus_definition_line(line, turing_dict, mathrace_key, turing_key)

def _process_race_definition_bonus_cardinality_entry(
self, line: str, bonus_cardinality: str, turing_dict: TuringDict
) -> None:
"""
Process the bonus cardinality entry in the race definition line.
Earlier versions were hardcoding the value to 10. This is not true anymore in this version,
and the value can be any integer.
"""
turing_dict["mathrace_only"]["bonus_cardinality"] = bonus_cardinality

def _process_race_definition_superbonus_cardinality_entry(
self, line: str, superbonus_cardinality: str, turing_dict: TuringDict
) -> None:
"""
Process the superbonus cardinality entry in the race definition line.
Earlier versions were hardcoding the value to 6. This is not true anymore in this version,
and the value can be any integer.
"""
turing_dict["mathrace_only"]["superbonus_cardinality"] = superbonus_cardinality

def _process_bonus_or_superbonus_definition_line(
self, line: str, turing_dict: TuringDict, mathrace_key: str, turing_key: str
) -> None:
Expand Down
13 changes: 13 additions & 0 deletions mathrace_interaction/tests/unit/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import datetime
import io
import typing

import pytest

Expand Down Expand Up @@ -531,3 +532,15 @@ def turing_dict(race_name: str, race_date: datetime.datetime) -> TuringDict:

]
}

@pytest.fixture
def runtime_error_contains() -> typing.Callable[[typing.Callable[[], typing.Any], str], None]:
"""Check that a RuntimeError is raised and contains the expected text."""
def _(call: typing.Callable[[], typing.Any], expected_error_text: str) -> None:
"""Check that a RuntimeError is raised and contains the expected text (internal implementation)."""
with pytest.raises(RuntimeError) as excinfo:
call()
runtime_error_text = str(excinfo.value)
assert expected_error_text in runtime_error_text

return _
16 changes: 16 additions & 0 deletions mathrace_interaction/tests/unit/test_determine_journal_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,26 @@
"""Test mathrace_interaction.determine_journal_version."""

import io
import typing

from mathrace_interaction.determine_journal_version import determine_journal_version

RuntimeErrorContainsFixtureType: typing.TypeAlias = typing.Callable[[typing.Callable[[], typing.Any], str], None]


def test_determine_journal_version(journal: io.StringIO, journal_version: str) -> None:
"""Test that test_determine_journal_version correctly recognizes the version of sample journals."""
assert determine_journal_version(journal) == journal_version


def test_determine_journal_version_error_on_mixed_race_start_codes(
runtime_error_contains: RuntimeErrorContainsFixtureType
) -> None:
"""Test that test_determine_journal_version raises an error when multiple race start codes are present."""
wrong_journal = io.StringIO("""\
0 002 inizio gara
0 200 inizio gara
""")
runtime_error_contains(
lambda: determine_journal_version(wrong_journal),
"More than one race start event detected, with different event codes")
Loading

0 comments on commit ea4eead

Please sign in to comment.