from unittest.mock import patch from discgolf.models import DiscGolfCourse from discgolf.utils import _parse_udisc_datetime, import_udisc_csv from people.models import Person from scrobbles.models import Scrobble class TestParserHelpers: def test_parse_udisc_datetime(self): dt = _parse_udisc_datetime("Jun 15, 2026 10:00 AM") assert dt is not None assert dt.year == 2026 assert dt.month == 6 assert dt.day == 15 assert dt.hour == 10 assert dt.minute == 0 def test_parse_udisc_datetime_date_only(self): dt = _parse_udisc_datetime("Jun 15, 2026") assert dt is not None assert dt.year == 2026 class TestImportUdiscCSV: def test_import_singles_creates_course(self, user, udisc_singles_csv_file): import_udisc_csv(udisc_singles_csv_file, user.id) course = DiscGolfCourse.objects.filter(title="Maple Hill").first() assert course is not None assert course.layout_name == "Mountains" assert course.number_of_holes == 3 assert course.par_total == 9 assert course.par_per_hole == {"hole_1": 3, "hole_2": 3, "hole_3": 3} def test_import_singles_creates_scrobble(self, user, udisc_singles_csv_file): import_udisc_csv(udisc_singles_csv_file, user.id) assert Scrobble.objects.filter(source="uDisc").count() == 1 def test_import_singles_logdata(self, user, udisc_singles_csv_file): import_udisc_csv(udisc_singles_csv_file, user.id) scrobble = Scrobble.objects.filter(source="uDisc").first() log = scrobble.log assert log["course_name"] == "Maple Hill" assert log["par"] == 9 assert log["round_type"] == "Singles" assert "Alice" in log["scores"] assert "Bob" in log["scores"] assert log["scores"]["Alice"]["total"] == 9 assert log["scores"]["Bob"]["total"] == 12 def test_import_singles_creates_people(self, user, udisc_singles_csv_file): import_udisc_csv(udisc_singles_csv_file, user.id) assert Person.objects.filter(name="Alice").exists() assert Person.objects.filter(name="Bob").exists() def test_import_teams_creates_scrobble(self, user, udisc_teams_csv_file): import_udisc_csv(udisc_teams_csv_file, user.id) assert Scrobble.objects.filter(source="uDisc").count() == 1 def test_import_teams_logdata(self, user, udisc_teams_csv_file): import_udisc_csv(udisc_teams_csv_file, user.id) scrobble = Scrobble.objects.filter(source="uDisc").first() assert scrobble.log["round_type"] == "Teams" alice_bob = scrobble.log["scores"]["Alice+Bob"] assert "person_ids" in alice_bob assert len(alice_bob["person_ids"]) == 2 def test_import_creates_team_people(self, user, udisc_teams_csv_file): import_udisc_csv(udisc_teams_csv_file, user.id) assert Person.objects.filter(name="Alice").exists() assert Person.objects.filter(name="Bob").exists() assert Person.objects.filter(name="Charlie").exists() assert Person.objects.filter(name="Diana").exists() def test_import_teams_par_per_hole(self, user, udisc_teams_csv_file): import_udisc_csv(udisc_teams_csv_file, user.id) course = DiscGolfCourse.objects.get(title="Maple Hill") assert course.par_per_hole == {"hole_1": 3, "hole_2": 3, "hole_3": 3} def test_import_no_par_returns_empty(self, user, udisc_csv_no_par_file): result = import_udisc_csv(udisc_csv_no_par_file, user.id) assert result == [] def test_import_empty_csv(self, user, db): import tempfile with tempfile.NamedTemporaryFile( mode="w", suffix=".csv", delete=False, encoding="utf-8-sig" ) as f: f.write("PlayerName,CourseName,LayoutName,StartDate,Hole1,Total\n") path = f.name result = import_udisc_csv(path, user.id) assert result == [] def test_import_idempotent(self, user, udisc_singles_csv_file): import_udisc_csv(udisc_singles_csv_file, user.id) import_udisc_csv(udisc_singles_csv_file, user.id) assert DiscGolfCourse.objects.filter(title="Maple Hill").count() == 1 assert Scrobble.objects.filter(source="uDisc").count() == 2 def test_import_course_defaults_only_on_create( self, user, udisc_singles_csv_file ): import_udisc_csv(udisc_singles_csv_file, user.id) course = DiscGolfCourse.objects.get(title="Maple Hill") assert course.layout_name == "Mountains" course.layout_name = "Updated" course.save() import_udisc_csv(udisc_singles_csv_file, user.id) course.refresh_from_db() assert course.layout_name == "Updated" @patch("discgolf.utils.ScrobbleNtfyNotification") def test_import_sends_notification(self, mock_notification_class, user, udisc_singles_csv_file): import_udisc_csv(udisc_singles_csv_file, user.id) mock_notification_class.assert_called_once() mock_notification_class.return_value.send.assert_called_once() def test_import_hole_scores_per_player(self, user, udisc_singles_csv_file): import_udisc_csv(udisc_singles_csv_file, user.id) scrobble = Scrobble.objects.filter(source="uDisc").first() alice = scrobble.log["scores"]["Alice"] assert alice["hole_1"] == 4 assert alice["hole_2"] == 2 assert alice["hole_3"] == 3 bob = scrobble.log["scores"]["Bob"] assert bob["hole_1"] == 3 assert bob["hole_2"] == 4 assert bob["hole_3"] == 5 def test_import_record_error_on_bad_data(self, user, db): import tempfile content = """PlayerName,CourseName,LayoutName,StartDate,Hole1,Hole2,Hole3,Total Par,,Mountains,"Jun 15, 2026 10:00 AM",3,3,3,9 """ with tempfile.NamedTemporaryFile( mode="w", suffix=".csv", delete=False, encoding="utf-8-sig" ) as f: f.write(content) path = f.name errors = [] result = import_udisc_csv(path, user.id, record_error=errors.append) assert len(result) == 1 course = DiscGolfCourse.objects.first() assert course.title == ""