""" Rangefinder-koordinater for offisielle (TeeOff-koblede) baner (migrasjon 079, ADR-081). To lag med tester: 1. `get_target_points()`/`resolve_match_course_key()` -- de delte byggeklossene direkte, uavhengig av hvilket av de tre kallestedene som bruker dem. 2. Integrasjon mot alle tre endepunktene (frittstående runde, individuell org-turnering, lag-matchplay) + den nye skrive-veien for offisielle baners koordinater i courses.py. """ from fastapi import HTTPException import pytest from app.auth import CurrentUser from app.hole_history import resolve_match_course_key from app.target_points import get_target_points from app.routers.courses import CoursePointIn, list_course_coordinates, replace_course_coordinates from app.routers.individual_tournaments import get_tournament_round_hole_target_points from app.routers.rounds import get_round_hole_target_points from app.routers.scoring import get_match_hole_target_points from tests.conftest import ( add_membership, create_course, create_match, create_org, create_org_hole, create_participant, create_player, create_round, create_session, create_team, create_team_roster, create_tee, create_tournament, create_tournament_participant, create_tournament_round, create_tournament_round_participant, create_user, ) import app.db as app_db # --------------------------------------------------------------------------- # 1. get_target_points() / resolve_match_course_key() # --------------------------------------------------------------------------- async def test_get_target_points_returns_empty_for_none_key(pool): async with app_db.plain_connection() as conn: points = await get_target_points(conn, None, 1) assert points == [] async def test_get_target_points_teeoff_branch(pool): async with app_db.plain_connection() as conn: await conn.execute( """ INSERT INTO teeoff_course_coordinate (external_course_ref, hole_number, poi_type, location, side_fairway, latitude, longitude) VALUES ('slug:99', 5, 'green', 'middle', 'center', 59.1, 10.4) """ ) points = await get_target_points(conn, ("teeoff", "slug", "99"), 5) other_hole = await get_target_points(conn, ("teeoff", "slug", "99"), 6) assert len(points) == 1 assert points[0].poi_type == "green" assert points[0].latitude == 59.1 assert other_hole == [] async def test_get_target_points_golfapi_branch(pool): async with app_db.plain_connection() as conn: await conn.execute( """ INSERT INTO golfapi_course (course_id, club_id, club_name, course_name, num_holes, num_coordinates) VALUES ('gapi-1', 'club-1', 'Testklubb', 'Bane', 18, 1) """ ) await conn.execute( """ INSERT INTO golfapi_course_coordinate (golfapi_course_id, hole_number, poi_type, location, side_fairway, latitude, longitude) VALUES ('gapi-1', 3, 'water', 'front', 'left', 59.2, 10.5) """ ) points = await get_target_points(conn, ("golfapi", "gapi-1"), 3) assert len(points) == 1 assert points[0].poi_type == "water" async def test_resolve_match_course_key_custom_course_returns_none(pool): user_id = await create_user() org_id = await create_org() await add_membership(org_id, user_id, role="member") tournament_id = await create_tournament(org_id) course_id = await create_course(org_id) # source defaults to 'custom' team_a = await create_team(org_id, tournament_id) team_b = await create_team(org_id, tournament_id) session_id = await create_session(org_id, tournament_id, course_id) match_id = await create_match(org_id, session_id, team_a, team_b) async with app_db.org_connection(org_id) as conn: key = await resolve_match_course_key(conn, match_id) assert key is None async def test_resolve_match_course_key_official_course(pool): org_id = await create_org() tournament_id = await create_tournament(org_id) course_id = await create_course(org_id) async with app_db.org_connection(org_id) as conn: await conn.execute( "UPDATE course SET source = 'official', external_course_ref = 'slug-x:42' WHERE id = $1", course_id, ) team_a = await create_team(org_id, tournament_id) team_b = await create_team(org_id, tournament_id) session_id = await create_session(org_id, tournament_id, course_id) match_id = await create_match(org_id, session_id, team_a, team_b) async with app_db.org_connection(org_id) as conn: key = await resolve_match_course_key(conn, match_id) assert key == ("teeoff", "slug-x", "42") async def test_resolve_match_course_key_international_course(pool): org_id = await create_org() tournament_id = await create_tournament(org_id) course_id = await create_course(org_id) async with app_db.org_connection(org_id) as conn: await conn.execute( "UPDATE course SET source = 'international', external_course_ref = 'gapi-77' WHERE id = $1", course_id, ) team_a = await create_team(org_id, tournament_id) team_b = await create_team(org_id, tournament_id) session_id = await create_session(org_id, tournament_id, course_id) match_id = await create_match(org_id, session_id, team_a, team_b) async with app_db.org_connection(org_id) as conn: key = await resolve_match_course_key(conn, match_id) assert key == ("golfapi", "gapi-77") async def test_resolve_match_course_key_nonexistent_match_returns_none(pool): org_id = await create_org() async with app_db.org_connection(org_id) as conn: key = await resolve_match_course_key(conn, "00000000-0000-0000-0000-000000000000") assert key is None # --------------------------------------------------------------------------- # 2. Integrasjon: de tre GET-endepunktene + skrive-veien i courses.py. # --------------------------------------------------------------------------- async def test_round_target_points_teeoff_round_now_returns_points(pool): """Regresjonsbevis for refaktoreringen: FØR migrasjon 079 returnerte dette endepunktet [] for EN HVER teeoff-sourcet frittstående runde, uansett koordinatdata. Nå slår den opp via samme bane-bro som hole_history.py.""" user_id = await create_user() async with app_db.plain_connection() as conn: round_id = await create_round(conn, user_id) # teeoff/test-facility/test-course await create_participant(conn, round_id, user_id=user_id, is_owner=True) await conn.execute( """ INSERT INTO teeoff_course_coordinate (external_course_ref, hole_number, poi_type, location, side_fairway, latitude, longitude) VALUES ('test-facility:test-course', 4, 'tee_front', 'middle', 'center', 59.0, 10.0) """ ) points = await get_round_hole_target_points(round_id, 4, user=CurrentUser(user_id=user_id)) assert len(points) == 1 assert points[0].poi_type == "tee_front" empty = await get_round_hole_target_points(round_id, 5, user=CurrentUser(user_id=user_id)) assert empty == [] async def test_tournament_round_target_points_official_course(pool): user_id = await create_user() org_id = await create_org() await add_membership(org_id, user_id, role="member") tournament_id = await create_tournament(org_id) course_id = await create_course(org_id) async with app_db.org_connection(org_id) as conn: await conn.execute( "UPDATE course SET source = 'official', external_course_ref = 'tourn-slug:7' WHERE id = $1", course_id, ) await conn.execute( """ INSERT INTO teeoff_course_coordinate (external_course_ref, hole_number, poi_type, location, side_fairway, latitude, longitude) VALUES ('tourn-slug:7', 9, 'rock', 'front', 'center', 59.3, 10.6) """ ) for n in range(1, 19): await create_org_hole(org_id, course_id, hole_number=n) tournament_round_id = await create_tournament_round(org_id, tournament_id, course_id) points = await get_tournament_round_hole_target_points( tournament_id, tournament_round_id, 9, organization_id=org_id, ) assert len(points) == 1 assert points[0].poi_type == "rock" with pytest.raises(HTTPException) as exc_info: await get_tournament_round_hole_target_points( "00000000-0000-0000-0000-000000000000", tournament_round_id, 9, organization_id=org_id, ) assert exc_info.value.status_code == 404 async def test_match_target_points_official_course_and_access_control(pool): member_id = await create_user() outsider_id = await create_user() org_id = await create_org() await add_membership(org_id, member_id, role="member") tournament_id = await create_tournament(org_id) course_id = await create_course(org_id) async with app_db.org_connection(org_id) as conn: await conn.execute( "UPDATE course SET source = 'official', external_course_ref = 'match-slug:3' WHERE id = $1", course_id, ) await conn.execute( """ INSERT INTO teeoff_course_coordinate (external_course_ref, hole_number, poi_type, location, side_fairway, latitude, longitude) VALUES ('match-slug:3', 2, 'water', 'back', 'right', 59.4, 10.7) """ ) team_a = await create_team(org_id, tournament_id) team_b = await create_team(org_id, tournament_id) session_id = await create_session(org_id, tournament_id, course_id) match_id = await create_match(org_id, session_id, team_a, team_b) points = await get_match_hole_target_points( match_id, 2, organization_id=org_id, user=CurrentUser(user_id=member_id), ) assert len(points) == 1 assert points[0].poi_type == "water" with pytest.raises(HTTPException) as exc_info: await get_match_hole_target_points( match_id, 2, organization_id=org_id, user=CurrentUser(user_id=outsider_id), ) assert exc_info.value.status_code == 403 async def test_course_coordinates_write_path_requires_official_and_fully_replaces(pool): org_id = await create_org() course_id = await create_course(org_id) # 'custom' by default # 400 på ikke-offisiell bane. with pytest.raises(HTTPException) as exc_info: await replace_course_coordinates( course_id, [CoursePointIn(hole_number=1, poi_type="green", location="middle", side_fairway="center", latitude=59.0, longitude=10.0)], organization_id=org_id, ) assert exc_info.value.status_code == 400 # GET returnerer stille tom liste for ikke-offisiell bane (ikke feil). assert await list_course_coordinates(course_id, organization_id=org_id) == [] async with app_db.org_connection(org_id) as conn: await conn.execute( "UPDATE course SET source = 'official', external_course_ref = 'write-slug:1' WHERE id = $1", course_id, ) first_set = [ CoursePointIn(hole_number=1, poi_type="green", location="front", side_fairway="center", latitude=59.0, longitude=10.0), CoursePointIn(hole_number=1, poi_type="water", location="back", side_fairway="left", latitude=59.01, longitude=10.01), ] result = await replace_course_coordinates(course_id, first_set, organization_id=org_id) assert len(result) == 2 # Ny PUT ERSTATTER hele settet -- ikke et tillegg. second_set = [ CoursePointIn(hole_number=2, poi_type="rock", location="middle", side_fairway="right", latitude=59.02, longitude=10.02), ] result = await replace_course_coordinates(course_id, second_set, organization_id=org_id) assert len(result) == 1 assert result[0].hole_number == 2 assert result[0].poi_type == "rock" read_back = await list_course_coordinates(course_id, organization_id=org_id) assert len(read_back) == 1 assert read_back[0].poi_type == "rock"