from datetime import datetime import pytest from sqlalchemy import text def test_location_record_endpoint_writes_row(location_client) -> None: client, engine = location_client response = client.post( "/location/record", json={ "person": "tianyu", "latitude": "1.23", "longitude": "4.56", "altitude": "7.89", }, ) assert response.status_code == 200 assert response.text == "" with engine.connect() as conn: row = conn.execute( text( "SELECT person, datetime, latitude, longitude, altitude " "FROM location ORDER BY datetime DESC LIMIT 1" ) ).one() assert row.person == "tianyu" assert row.latitude == pytest.approx(1.23) assert row.longitude == pytest.approx(4.56) assert row.altitude == pytest.approx(7.89) datetime.fromisoformat(row.datetime.replace("Z", "+00:00")) def test_location_record_endpoint_rejects_unknown_fields(location_client) -> None: client, _ = location_client response = client.post( "/location/record", json={ "person": "tianyu", "latitude": "1.23", "longitude": "4.56", "extra": "not-allowed", }, ) assert response.status_code == 400 assert response.text == "bad request" assert "extra" not in response.text assert "ValidationError" not in response.text def test_location_record_endpoint_rejects_missing_latitude(location_client) -> None: client, _ = location_client response = client.post( "/location/record", json={ "person": "tianyu", "longitude": "4.56", }, ) assert response.status_code == 400 assert response.text == "bad request" assert "latitude" not in response.text def test_location_record_endpoint_rejects_missing_longitude(location_client) -> None: client, _ = location_client response = client.post( "/location/record", json={ "person": "tianyu", "latitude": "1.23", }, ) assert response.status_code == 400 assert response.text == "bad request" assert "longitude" not in response.text def test_location_record_endpoint_rejects_invalid_latitude(location_client) -> None: client, _ = location_client response = client.post( "/location/record", json={ "person": "tianyu", "latitude": "bad-lat", "longitude": "4.56", }, ) assert response.status_code == 400 assert response.text == "bad request" assert "bad-lat" not in response.text assert "latitude" not in response.text def test_location_record_endpoint_rejects_invalid_longitude(location_client) -> None: client, _ = location_client response = client.post( "/location/record", json={ "person": "tianyu", "latitude": "1.23", "longitude": "bad-long", }, ) assert response.status_code == 400 assert response.text == "bad request" assert "bad-long" not in response.text assert "longitude" not in response.text def test_location_record_endpoint_defaults_missing_altitude_to_zero(location_client) -> None: client, engine = location_client response = client.post( "/location/record", json={ "person": "tianyu", "latitude": "1.23", "longitude": "4.56", }, ) assert response.status_code == 200 with engine.connect() as conn: row = conn.execute( text( "SELECT latitude, longitude, altitude " "FROM location ORDER BY datetime DESC LIMIT 1" ) ).one() assert row.latitude == pytest.approx(1.23) assert row.longitude == pytest.approx(4.56) assert row.altitude == pytest.approx(0.0) def test_location_record_endpoint_defaults_invalid_altitude_to_zero(location_client) -> None: client, engine = location_client response = client.post( "/location/record", json={ "person": "tianyu", "latitude": "1.23", "longitude": "4.56", "altitude": "bad-alt", }, ) assert response.status_code == 200 with engine.connect() as conn: row = conn.execute( text( "SELECT latitude, longitude, altitude " "FROM location ORDER BY datetime DESC LIMIT 1" ) ).one() assert row.latitude == pytest.approx(1.23) assert row.longitude == pytest.approx(4.56) assert row.altitude == pytest.approx(0.0)