""" Flaggturnering: GPS-flaggplanting + runde 2+ (migrasjon 069, 2026-08-14). Kaller de faktiske router-funksjonene i rounds.py direkte, samme mønster som test_concurrency_version_check.py -- ikke en gjenimplementering. Kun frittstående runder (rounds.py) dekkes her -- individual_tournaments.py sin org-speilende variant mangler conftest-hjelpere for tournament_round- familien og er i stedet manuelt browserverifisert (se CHANGELOG.md). """ import pytest from fastapi import HTTPException from app import db as app_db from app.auth import CurrentUser from app.routers.rounds import ( HoleUpdate, FlagPlantIn, FlagOverflowHoleIn, get_flag_map, get_flag_plant, list_flag_overflow_holes, plant_flag, unplant_flag, update_flag_overflow_hole, update_hole, ) from tests.conftest import create_hole, create_participant, create_round, create_user async def _setup_flag_round(holes_planned: int = 18, start_hole: int = 1): async with app_db.plain_connection() as conn: owner_id = await create_user() round_id = await create_round(conn, owner_id) await conn.execute( "UPDATE round SET play_format = 'flag', holes_planned = $2, start_hole = $3 WHERE id = $1", round_id, holes_planned, start_hole, ) participant_id = await create_participant( conn, round_id, user_id=owner_id, is_owner=True, course_handicap_snapshot=10, ) for n in range(1, 19): await create_hole(conn, participant_id, hole_number=n, par=4, stroke_index=n) return owner_id, round_id, participant_id async def _play_hole(round_id: str, participant_id: str, hole_number: int, score: int, user: CurrentUser): await update_hole(round_id, participant_id, hole_number, HoleUpdate(score=score, played=True), user=user) async def test_plant_flag_succeeds_on_first_unplayed_hole(pool): owner_id, round_id, participant_id = await _setup_flag_round() user = CurrentUser(user_id=owner_id) await _play_hole(round_id, participant_id, 1, 5, user) await _play_hole(round_id, participant_id, 2, 4, user) result = await plant_flag( round_id, participant_id, FlagPlantIn(lat=59.9, lng=10.7, hole_number=3, lap=1, on_green=False), user=user, ) assert result.lap == 1 assert result.hole_number == 3 assert result.on_green is False assert result.distance_to_pin_cm is None async def test_plant_flag_rejects_mismatched_hole(pool): owner_id, round_id, participant_id = await _setup_flag_round() user = CurrentUser(user_id=owner_id) await _play_hole(round_id, participant_id, 1, 5, user) # Faktisk posisjon er hull 2 (kun hull 1 spilt) -- forsøker å plante på hull 5. with pytest.raises(HTTPException) as exc_info: await plant_flag( round_id, participant_id, FlagPlantIn(lat=59.9, lng=10.7, hole_number=5, lap=1, on_green=False), user=user, ) assert exc_info.value.status_code == 400 assert exc_info.value.detail["code"] == "VALIDATION_FAILED" async def test_plant_flag_on_green_requires_distance(pool): owner_id, round_id, participant_id = await _setup_flag_round() user = CurrentUser(user_id=owner_id) with pytest.raises(HTTPException) as exc_info: await plant_flag( round_id, participant_id, FlagPlantIn(lat=59.9, lng=10.7, hole_number=1, lap=1, on_green=True), user=user, ) assert exc_info.value.status_code == 400 assert exc_info.value.detail["code"] == "VALIDATION_FAILED" async def test_plant_flag_on_green_with_distance_succeeds(pool): owner_id, round_id, participant_id = await _setup_flag_round() user = CurrentUser(user_id=owner_id) result = await plant_flag( round_id, participant_id, FlagPlantIn(lat=59.9, lng=10.7, hole_number=1, lap=1, on_green=True, distance_to_pin_cm=340), user=user, ) assert result.on_green is True assert result.distance_to_pin_cm == 340 async def test_replanting_overwrites_not_duplicates(pool): owner_id, round_id, participant_id = await _setup_flag_round() user = CurrentUser(user_id=owner_id) first = await plant_flag( round_id, participant_id, FlagPlantIn(lat=59.9, lng=10.7, hole_number=1, lap=1, on_green=False), user=user, ) await _play_hole(round_id, participant_id, 1, 5, user) second = await plant_flag( round_id, participant_id, FlagPlantIn(lat=60.0, lng=10.8, hole_number=2, lap=1, on_green=False), user=user, ) assert second.id != first.id current = await get_flag_plant(round_id, participant_id, user=user) assert current.hole_number == 2 async def test_unplant_removes_flag(pool): owner_id, round_id, participant_id = await _setup_flag_round() user = CurrentUser(user_id=owner_id) await plant_flag( round_id, participant_id, FlagPlantIn(lat=59.9, lng=10.7, hole_number=1, lap=1, on_green=False), user=user, ) await unplant_flag(round_id, participant_id, user=user) assert await get_flag_plant(round_id, participant_id, user=user) is None async def test_get_flag_plant_none_when_never_planted(pool): owner_id, round_id, participant_id = await _setup_flag_round() user = CurrentUser(user_id=owner_id) assert await get_flag_plant(round_id, participant_id, user=user) is None async def test_overflow_hole_rejected_before_lap_one_complete(pool): owner_id, round_id, participant_id = await _setup_flag_round() user = CurrentUser(user_id=owner_id) # Kun 5 av 18 hull spilt i lap 1 -- lap 2 skal avvises. for n in range(1, 6): await _play_hole(round_id, participant_id, n, 4, user) with pytest.raises(HTTPException) as exc_info: await update_flag_overflow_hole( round_id, participant_id, 2, 1, FlagOverflowHoleIn(score=4), user=user, ) assert exc_info.value.status_code == 400 assert exc_info.value.detail["code"] == "VALIDATION_FAILED" async def test_full_lap_two_flow(pool): owner_id, round_id, participant_id = await _setup_flag_round() user = CurrentUser(user_id=owner_id) for n in range(1, 19): await _play_hole(round_id, participant_id, n, 4, user) # Forsøk på å plante i lap 1 avvises nå -- spilleren har allerede # fullført alle 18 hull i lap 1, faktisk posisjon er lap 2, hull 1. with pytest.raises(HTTPException) as exc_info: await plant_flag( round_id, participant_id, FlagPlantIn(lat=59.9, lng=10.7, hole_number=1, lap=1, on_green=False), user=user, ) assert exc_info.value.status_code == 400 overflow_hole = await update_flag_overflow_hole( round_id, participant_id, 2, 1, FlagOverflowHoleIn(score=5), user=user, ) assert overflow_hole.lap == 2 assert overflow_hole.hole_number == 1 assert overflow_hole.score == 5 holes = await list_flag_overflow_holes(round_id, participant_id, user=user) assert len(holes) == 1 assert holes[0].hole_number == 1 # Nå kan flagget faktisk plantes riktig i lap 2, hull 2. lap2_plant = await plant_flag( round_id, participant_id, FlagPlantIn(lat=59.9, lng=10.7, hole_number=2, lap=2, on_green=False), user=user, ) assert lap2_plant.lap == 2 assert lap2_plant.hole_number == 2 async def test_flag_plant_respects_non_default_start_hole(pool): owner_id, round_id, participant_id = await _setup_flag_round(start_hole=10) user = CurrentUser(user_id=owner_id) # Spillerekkefølgen er 10,11,...,18,1,...,9 -- ingen hull spilt ennå, # så flagget skal kun kunne plantes på hull 10 (ikke fysisk hull 1). with pytest.raises(HTTPException) as exc_info: await plant_flag( round_id, participant_id, FlagPlantIn(lat=59.9, lng=10.7, hole_number=1, lap=1, on_green=False), user=user, ) assert exc_info.value.status_code == 400 result = await plant_flag( round_id, participant_id, FlagPlantIn(lat=59.9, lng=10.7, hole_number=10, lap=1, on_green=False), user=user, ) assert result.hole_number == 10 async def test_flag_map_shows_only_own_flag_when_switch_off(pool): owner_id, round_id, owner_participant_id = await _setup_flag_round() other_user_id = await create_user() async with app_db.plain_connection() as conn: other_participant_id = await create_participant(conn, round_id, user_id=other_user_id, is_owner=False) owner = CurrentUser(user_id=owner_id) other = CurrentUser(user_id=other_user_id) await plant_flag( round_id, owner_participant_id, FlagPlantIn(lat=59.9, lng=10.7, hole_number=1, lap=1, on_green=False), user=owner, ) await plant_flag( round_id, other_participant_id, FlagPlantIn(lat=60.0, lng=10.8, hole_number=1, lap=1, on_green=False), user=other, ) result = await get_flag_map(round_id, user=owner) assert result.visible_to_all is False assert [f.participant_id for f in result.flags] == [owner_participant_id] async def test_flag_map_shows_all_flags_when_switch_on(pool): owner_id, round_id, owner_participant_id = await _setup_flag_round() other_user_id = await create_user() async with app_db.plain_connection() as conn: other_participant_id = await create_participant(conn, round_id, user_id=other_user_id, is_owner=False) await conn.execute("UPDATE round SET flag_map_visible = true WHERE id = $1", round_id) owner = CurrentUser(user_id=owner_id) other = CurrentUser(user_id=other_user_id) await plant_flag( round_id, owner_participant_id, FlagPlantIn(lat=59.9, lng=10.7, hole_number=1, lap=1, on_green=False), user=owner, ) await plant_flag( round_id, other_participant_id, FlagPlantIn(lat=60.0, lng=10.8, hole_number=1, lap=1, on_green=False), user=other, ) result = await get_flag_map(round_id, user=other) assert result.visible_to_all is True assert {f.participant_id for f in result.flags} == {owner_participant_id, other_participant_id}