"""Test NormalizedDate.""" from datetime import date, datetime import pytest from sqlalchemy.engine import default from abacus_common_logic.models.normalized_date import NormalizedDate, to_date @pytest.fixture(scope='module') def sa_dialect(): """Return a SQLAlchemy dialect.""" return default.DefaultDialect() # to_date def test_to_date_none_and_empty(): """Test to_date with none or empty.""" assert to_date(None) is None assert to_date('') is None assert to_date(' ') is None def test_to_date_datetime(): """Test to_date with a datetime.""" dt = datetime(2025, 9, 29, 15, 30, 45) assert to_date(dt) == dt.date() def test_to_date_date(): """Test to_date with a date.""" d = date(2022, 12, 31) assert to_date(d) == d def test_to_date_epoch_seconds(): """Test to_date with seconds.""" for epoch in [0, 1_600_000_000, 1_600_000_000.0]: expected = datetime.fromtimestamp(epoch).date() assert to_date(epoch) == expected def test_to_date_bytes_utf8(): """Test to_date with bytes.""" assert to_date(b'2024-01-02') == date(2024, 1, 2) assert to_date(bytearray(b'2025-01-02')) == date(2025, 1, 2) def test_to_date_bytes_invalid_utf8_raises(): """Test to_date with invalid bytes.""" with pytest.raises(UnicodeDecodeError): to_date(b'\xff\xfe\xfa') # Invalid UTF-8 def test_to_date_iso_date_only(): """Test to_date with an iso date.""" assert to_date('2020-05-17') == date(2020, 5, 17) def test_to_date_iso_datetime_no_tz(): """Test to_date with an iso datetime.""" assert to_date('2020-05-17T23:59:59') == date(2020, 5, 17) def test_to_date_iso_datetime_with_z_suffix(): """Test to_date with an iso datetime and Z suffix.""" assert to_date('2020-05-17T23:59:59Z') == date(2020, 5, 17) def test_to_date_iso_datetime_with_offset(): """Test to_date with an iso datetime and timezone.""" assert to_date('2020-05-18T00:30:00+02:00') == date(2020, 5, 18) def test_to_date_fallback_formats(): """Test to_date fallback formats.""" expected = date(2025, 3, 5) assert to_date('2025/03/05') == expected # %Y/%m/%d assert to_date('03/05/2025') == expected # %m/%d/%Y assert to_date('05-03-2025') == expected # %d-%m-%Y def test_to_date_invalid_inputs_raise_typeerror(): """Test to_date with bad inputs.""" for bad_value in ['not-a-date', '2024-13-40', '05/35/2024', object()]: with pytest.raises(TypeError): to_date(bad_value) # NormalizedDate def test_normalized_date_metadata(): """Test NormalizedDate metadata.""" assert NormalizedDate.impl.__name__ == 'Date' def test_normalized_date_process_bind_param(sa_dialect): """Test NormalizedDate param normalization.""" nd = NormalizedDate() epoch_date = datetime.fromtimestamp(1_600_000_000).date() assert nd.process_bind_param(date(2021, 1, 2), dialect=sa_dialect) == date( 2021, 1, 2 ) assert nd.process_bind_param( datetime(2021, 1, 2, 12, 0, 0), dialect=sa_dialect ) == date(2021, 1, 2) assert nd.process_bind_param('2021-01-02', dialect=sa_dialect) == date(2021, 1, 2) assert nd.process_bind_param('2021-01-02T00:00:00Z', dialect=sa_dialect) == date( 2021, 1, 2 ) assert nd.process_bind_param('03/04/2021', dialect=sa_dialect) == date(2021, 3, 4) assert nd.process_bind_param(None, dialect=sa_dialect) is None assert nd.process_bind_param('', dialect=sa_dialect) is None assert nd.process_bind_param(1_600_000_000, dialect=sa_dialect) == epoch_date assert nd.process_bind_param(1_600_000_000.0, dialect=sa_dialect) == epoch_date assert nd.process_bind_param(b'2022-02-03', dialect=sa_dialect) == date(2022, 2, 3) def test_normalized_date_process_bind_param_invalid_raises(sa_dialect): """Test NormalizedDate invalid params.""" nd = NormalizedDate() with pytest.raises(TypeError): nd.process_bind_param('not-a-date', dialect=sa_dialect) def test_normalized_date_process_result_value(sa_dialect): """Test NormalizedDate result normalization.""" nd = NormalizedDate() assert nd.process_result_value(date(2021, 1, 2), dialect=sa_dialect) == date( 2021, 1, 2 ) assert nd.process_result_value( datetime(2021, 1, 2, 12, 0, 0), dialect=sa_dialect ) == date(2021, 1, 2) assert nd.process_result_value('2021-01-02', dialect=sa_dialect) == date(2021, 1, 2) assert nd.process_result_value( '2021-01-02T12:30:00+00:00', dialect=sa_dialect ) == date(2021, 1, 2) assert nd.process_result_value(None, dialect=sa_dialect) is None