"""Tests for the 18+ age gate on user registration.""" from datetime import date, timedelta import pytest from app.routers.auth import calculate_age class TestCalculateAge: """Unit tests for the calculate_age helper.""" def test_exactly_18(self): """A person born exactly 18 years ago today is 18.""" today = date(2025, 6, 15) dob = today.replace(year=today.year - 18) assert calculate_age(dob, today=today) == 18 def test_just_turned_18(self): """A person who turned 18 yesterday is 18.""" today = date(2025, 6, 15) dob = today.replace(year=today.year - 18) - timedelta(days=1) assert calculate_age(dob, today=today) == 18 def test_one_day_short_of_18(self): """A person born one day after their 18th birthday is 17.""" today = date(2025, 6, 15) dob = today.replace(year=today.year - 18) + timedelta(days=1) assert calculate_age(dob, today=today) == 17 def test_17_years_old(self): """A person who is 17 years old today is 17.""" today = date(2025, 6, 15) dob = date(2008, 6, 15) assert calculate_age(dob, today=today) == 17 def test_65_years_old(self): """A person who is 65 is correctly calculated.""" today = date(2025, 6, 15) dob = today.replace(year=today.year - 65) assert calculate_age(dob, today=today) == 65 def test_newborn(self): """A newborn is 0.""" today = date(2025, 6, 15) dob = today assert calculate_age(dob, today=today) == 0 def test_birthday_not_yet_this_year(self): """Person born Dec 31, 2000 — on Jan 1, 2025 they are still 24.""" dob = date(2000, 12, 31) assert calculate_age(dob, today=date(2025, 1, 1)) == 24 def test_birthday_today(self): """Person born Dec 31, 2000 — on Dec 31, 2024 they turn 24.""" dob = date(2000, 12, 31) assert calculate_age(dob, today=date(2024, 12, 31)) == 24 class TestRegisterRequestOver18Field: """Tests for RegisterRequest's over_18 field. Replaces TestRegisterRequestDateValidation -- date_of_birth and its field_validator were removed from RegisterRequest 2026-08-20 (interim simplification: a plain client-side over_18 confirmation instead of collecting/validating an actual date of birth; see calculate_age's own docstring in app/routers/auth.py for why that function is still here even though this endpoint no longer calls it). There's no date format left to validate, so the equivalent coverage is just: the field exists, is a real bool, and is required.""" def test_over_18_true_accepted(self): from app.routers.auth import RegisterRequest req = RegisterRequest(username="u", email="u@example.com", password="p", over_18=True) assert req.over_18 is True def test_over_18_false_accepted(self): """False is a valid value at the schema level -- the endpoint, not the schema, is what rejects it (see TestRegister::test_register_rejects_not_over_18 in test_auth_endpoints.py).""" from app.routers.auth import RegisterRequest req = RegisterRequest(username="u", email="u@example.com", password="p", over_18=False) assert req.over_18 is False def test_over_18_missing_rejected(self): """over_18 has no default -- omitting it entirely is a validation error.""" from app.routers.auth import RegisterRequest from pydantic import ValidationError with pytest.raises(ValidationError): RegisterRequest(username="u", email="u@example.com", password="p")