import pytest from datetime import datetime, timezone, timedelta from planetarytime import Body, EpochType, PlanetaryTime from planetarytime.exceptions import DatetimePrecedesEpochError, EpochUnavailableError from planetarytime.epoch import get_epoch_date def test_from_earth_at_epoch_is_year_zero_sol_zero() -> None: epoch_dt = get_epoch_date(Body.MARS, EpochType.DISCOVERY) pt = PlanetaryTime.from_earth(epoch_dt, Body.MARS, EpochType.DISCOVERY) assert pt.year == 0 assert pt.sol == 0 assert pt.hour == 0 assert pt.minute == 0 assert pt.second == 0 def test_from_earth_one_sol_later() -> None: epoch_dt = get_epoch_date(Body.MARS, EpochType.DISCOVERY) one_sol_later = epoch_dt + timedelta(hours=Body.MARS.hours_per_sol) pt = PlanetaryTime.from_earth(one_sol_later, Body.MARS, EpochType.DISCOVERY) assert pt.year == 0 assert pt.sol == 1 assert pt.hour == 0 def test_from_earth_one_year_later() -> None: epoch_dt = get_epoch_date(Body.MARS, EpochType.DISCOVERY) one_year_seconds = Body.MARS.sols_per_year * Body.MARS.hours_per_sol * 3600 one_year_later = epoch_dt + timedelta(seconds=one_year_seconds) pt = PlanetaryTime.from_earth(one_year_later, Body.MARS, EpochType.DISCOVERY) assert pt.year == 1 assert pt.sol == 0 assert pt.hour == 0 def test_from_earth_one_hour_later() -> None: epoch_dt = get_epoch_date(Body.MARS, EpochType.DISCOVERY) one_hour_later = epoch_dt + timedelta(hours=1) pt = PlanetaryTime.from_earth(one_hour_later, Body.MARS, EpochType.DISCOVERY) assert pt.year == 0 assert pt.sol == 0 assert pt.hour == 1 assert pt.minute == 0 def test_from_earth_naive_datetime_treated_as_utc() -> None: epoch_dt = get_epoch_date(Body.MARS, EpochType.DISCOVERY) naive = epoch_dt.replace(tzinfo=None) pt = PlanetaryTime.from_earth(naive, Body.MARS, EpochType.DISCOVERY) assert pt.year == 0 assert pt.sol == 0 def test_from_earth_before_epoch_raises() -> None: epoch_dt = get_epoch_date(Body.MARS, EpochType.DISCOVERY) before_epoch = epoch_dt - timedelta(days=1) with pytest.raises(DatetimePrecedesEpochError): PlanetaryTime.from_earth(before_epoch, Body.MARS, EpochType.DISCOVERY) def test_contact_epoch_unavailable_raises() -> None: with pytest.raises(EpochUnavailableError): PlanetaryTime.from_earth(datetime(2024, 1, 1, tzinfo=timezone.utc), Body.JUPITER, EpochType.CONTACT) def test_str_contains_body_name_and_sol() -> None: epoch_dt = get_epoch_date(Body.MARS, EpochType.DISCOVERY) pt = PlanetaryTime.from_earth(epoch_dt, Body.MARS, EpochType.DISCOVERY) assert "Mars" in str(pt) assert "Sol" in str(pt) assert "Year" in str(pt) def test_repr_contains_year_and_sol() -> None: epoch_dt = get_epoch_date(Body.MARS, EpochType.DISCOVERY) pt = PlanetaryTime.from_earth(epoch_dt, Body.MARS, EpochType.DISCOVERY) r = repr(pt) assert "PlanetaryTime(" in r assert "year=" in r assert "sol=" in r