Files
AI-Trader/tests/unit/test_date_utils.py
Bill c3ea358a12 test: add comprehensive test suite for v0.3.0 on-demand price downloads
Add 64 new tests covering date utilities, price data management, and
on-demand download workflows with 100% coverage for date_utils and 85%
coverage for price_data_manager.

New test files:
- tests/unit/test_date_utils.py (22 tests)
  * Date range expansion and validation
  * Max simulation days configuration
  * Chronological ordering and boundary checks
  * 100% coverage of api/date_utils.py

- tests/unit/test_price_data_manager.py (33 tests)
  * Initialization and configuration
  * Symbol date retrieval and coverage detection
  * Priority-based download ordering
  * Rate limit and error handling
  * Data storage and coverage tracking
  * 85% coverage of api/price_data_manager.py

- tests/integration/test_on_demand_downloads.py (10 tests)
  * End-to-end download workflows
  * Rate limit handling with graceful degradation
  * Coverage tracking and gap detection
  * Data validation and filtering

Code improvements:
- Add DownloadError exception class for non-rate-limit failures
- Update all ValueError raises to DownloadError for consistency
- Add API key validation at download start
- Improve response validation to check for Meta Data

Test coverage:
- 64 tests passing (54 unit + 10 integration)
- api/date_utils.py: 100% coverage
- api/price_data_manager.py: 85% coverage
- Validates priority-first download strategy
- Confirms graceful rate limit handling
- Verifies database storage and retrieval

Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-31 17:13:03 -04:00

150 lines
5.3 KiB
Python

"""
Unit tests for api/date_utils.py
Tests date range expansion, validation, and utility functions.
"""
import pytest
from datetime import datetime, timedelta
from api.date_utils import (
expand_date_range,
validate_date_range,
get_max_simulation_days
)
class TestExpandDateRange:
"""Test expand_date_range function."""
def test_single_day(self):
"""Test single day range (start == end)."""
result = expand_date_range("2025-01-20", "2025-01-20")
assert result == ["2025-01-20"]
def test_multi_day_range(self):
"""Test multiple day range."""
result = expand_date_range("2025-01-20", "2025-01-22")
assert result == ["2025-01-20", "2025-01-21", "2025-01-22"]
def test_week_range(self):
"""Test week-long range."""
result = expand_date_range("2025-01-20", "2025-01-26")
assert len(result) == 7
assert result[0] == "2025-01-20"
assert result[-1] == "2025-01-26"
def test_chronological_order(self):
"""Test dates are in chronological order."""
result = expand_date_range("2025-01-20", "2025-01-25")
for i in range(len(result) - 1):
assert result[i] < result[i + 1]
def test_invalid_order(self):
"""Test error when start > end."""
with pytest.raises(ValueError, match="must be <= end_date"):
expand_date_range("2025-01-25", "2025-01-20")
def test_invalid_date_format(self):
"""Test error with invalid date format."""
with pytest.raises(ValueError):
expand_date_range("01-20-2025", "01-21-2025")
def test_month_boundary(self):
"""Test range spanning month boundary."""
result = expand_date_range("2025-01-30", "2025-02-02")
assert result == ["2025-01-30", "2025-01-31", "2025-02-01", "2025-02-02"]
def test_year_boundary(self):
"""Test range spanning year boundary."""
result = expand_date_range("2024-12-30", "2025-01-02")
assert len(result) == 4
assert "2024-12-31" in result
assert "2025-01-01" in result
class TestValidateDateRange:
"""Test validate_date_range function."""
def test_valid_single_day(self):
"""Test valid single day range."""
# Should not raise
validate_date_range("2025-01-20", "2025-01-20", max_days=30)
def test_valid_multi_day(self):
"""Test valid multi-day range."""
# Should not raise
validate_date_range("2025-01-20", "2025-01-25", max_days=30)
def test_max_days_boundary(self):
"""Test exactly at max days limit."""
# 30 days total (inclusive)
start = "2025-01-01"
end = "2025-01-30"
# Should not raise
validate_date_range(start, end, max_days=30)
def test_exceeds_max_days(self):
"""Test exceeds max days limit."""
start = "2025-01-01"
end = "2025-02-01" # 32 days
with pytest.raises(ValueError, match="Date range too large: 32 days"):
validate_date_range(start, end, max_days=30)
def test_invalid_order(self):
"""Test start > end."""
with pytest.raises(ValueError, match="must be <= end_date"):
validate_date_range("2025-01-25", "2025-01-20", max_days=30)
def test_future_date_rejected(self):
"""Test future dates are rejected."""
tomorrow = (datetime.now() + timedelta(days=1)).strftime("%Y-%m-%d")
next_week = (datetime.now() + timedelta(days=7)).strftime("%Y-%m-%d")
with pytest.raises(ValueError, match="cannot be in the future"):
validate_date_range(tomorrow, next_week, max_days=30)
def test_today_allowed(self):
"""Test today's date is allowed."""
today = datetime.now().strftime("%Y-%m-%d")
# Should not raise
validate_date_range(today, today, max_days=30)
def test_past_dates_allowed(self):
"""Test past dates are allowed."""
# Should not raise
validate_date_range("2020-01-01", "2020-01-10", max_days=30)
def test_invalid_date_format(self):
"""Test invalid date format raises error."""
with pytest.raises(ValueError, match="Invalid date format"):
validate_date_range("01-20-2025", "01-21-2025", max_days=30)
def test_custom_max_days(self):
"""Test custom max_days parameter."""
# Should raise with max_days=5
with pytest.raises(ValueError, match="Date range too large: 10 days"):
validate_date_range("2025-01-01", "2025-01-10", max_days=5)
class TestGetMaxSimulationDays:
"""Test get_max_simulation_days function."""
def test_default_value(self, monkeypatch):
"""Test default value when env var not set."""
monkeypatch.delenv("MAX_SIMULATION_DAYS", raising=False)
result = get_max_simulation_days()
assert result == 30
def test_env_var_override(self, monkeypatch):
"""Test environment variable override."""
monkeypatch.setenv("MAX_SIMULATION_DAYS", "60")
result = get_max_simulation_days()
assert result == 60
def test_env_var_string_to_int(self, monkeypatch):
"""Test env var is converted to int."""
monkeypatch.setenv("MAX_SIMULATION_DAYS", "100")
result = get_max_simulation_days()
assert isinstance(result, int)
assert result == 100