127 lines
3.0 KiB
Python
127 lines
3.0 KiB
Python
"""Tests for datetime formula functions (R1)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from agentkit.bitable.formula.functions.datetime import (
|
|
DATETIME_FUNCTIONS,
|
|
_date,
|
|
_dateadd,
|
|
_datedif,
|
|
_day,
|
|
_eomonth,
|
|
_hour,
|
|
_minute,
|
|
_month,
|
|
_networkdays,
|
|
_now,
|
|
_second,
|
|
_today,
|
|
_weekday,
|
|
_year,
|
|
)
|
|
|
|
|
|
def test_registry_has_15_functions() -> None:
|
|
assert len(DATETIME_FUNCTIONS) == 15
|
|
assert "DATE" in DATETIME_FUNCTIONS
|
|
assert "NETWORKDAYS" in DATETIME_FUNCTIONS
|
|
|
|
|
|
def test_date_constructor() -> None:
|
|
result = _date(2026, 7, 6)
|
|
assert result == "2026-07-06T00:00:00"
|
|
|
|
|
|
def test_year_month_day() -> None:
|
|
d = _date(2026, 7, 6)
|
|
assert _year(d) == 2026
|
|
assert _month(d) == 7
|
|
assert _day(d) == 6
|
|
|
|
|
|
def test_hour_minute_second() -> None:
|
|
dt = "2026-07-06T14:30:45"
|
|
assert _hour(dt) == 14
|
|
assert _minute(dt) == 30
|
|
assert _second(dt) == 45
|
|
|
|
|
|
def test_weekday() -> None:
|
|
# 2026-07-06 is a Monday → ISO weekday 1
|
|
assert _weekday("2026-07-06") == 1
|
|
# 2026-07-12 is a Sunday → ISO weekday 7
|
|
assert _weekday("2026-07-12") == 7
|
|
|
|
|
|
def test_datedif_days() -> None:
|
|
assert _datedif("2026-07-01", "2026-07-06", "days") == 5
|
|
|
|
|
|
def test_datedif_months() -> None:
|
|
assert _datedif("2026-01-15", "2026-07-15", "months") == 6
|
|
|
|
|
|
def test_datedif_years() -> None:
|
|
assert _datedif("2020-01-01", "2026-01-01", "years") == 6
|
|
|
|
|
|
def test_dateadd_days() -> None:
|
|
assert _dateadd("2026-07-06", 5, "days") == "2026-07-11T00:00:00"
|
|
|
|
|
|
def test_dateadd_months() -> None:
|
|
assert _dateadd("2026-01-15", 1, "months") == "2026-02-15T00:00:00"
|
|
|
|
|
|
def test_dateadd_months_clamps_day() -> None:
|
|
# Jan 31 + 1 month → Feb 28 (2026 is not a leap year)
|
|
assert _dateadd("2026-01-31", 1, "months") == "2026-02-28T00:00:00"
|
|
|
|
|
|
def test_networkdays() -> None:
|
|
# 2026-07-06 (Mon) to 2026-07-10 (Fri) = 5 working days
|
|
assert _networkdays("2026-07-06", "2026-07-10") == 5
|
|
|
|
|
|
def test_networkdays_includes_weekend() -> None:
|
|
# 2026-07-06 (Mon) to 2026-07-12 (Sun) = 5 working days (weekend excluded)
|
|
assert _networkdays("2026-07-06", "2026-07-12") == 5
|
|
|
|
|
|
def test_networkdays_reversed_args() -> None:
|
|
# Should swap if start > end
|
|
assert _networkdays("2026-07-10", "2026-07-06") == 5
|
|
|
|
|
|
def test_eomonth() -> None:
|
|
# End of July 2026
|
|
assert _eomonth("2026-07-06", 0) == "2026-07-31T00:00:00"
|
|
|
|
|
|
def test_eomonth_next_month() -> None:
|
|
# End of August 2026
|
|
assert _eomonth("2026-07-06", 1) == "2026-08-31T00:00:00"
|
|
|
|
|
|
def test_today_returns_iso_string() -> None:
|
|
result = _today()
|
|
assert isinstance(result, str)
|
|
assert "T00:00:00" in result
|
|
|
|
|
|
def test_now_returns_iso_string() -> None:
|
|
result = _now()
|
|
assert isinstance(result, str)
|
|
assert "T" in result
|
|
|
|
|
|
def test_none_input_returns_none_for_accessors() -> None:
|
|
assert _year(None) is None
|
|
assert _month(None) is None
|
|
assert _day(None) is None
|
|
|
|
|
|
def test_empty_string_returns_none_for_accessors() -> None:
|
|
assert _year("") is None
|
|
assert _datedif("", "2026-07-06") is None
|