Files

111 lines
4.0 KiB
Python
Raw Permalink Normal View History

import sys
from pathlib import Path
import json
import pytest
from unittest.mock import Mock, patch
from datetime import datetime, timedelta
# Add scripts to path
sys.path.insert(0, str(Path(__file__).parent.parent / "scripts"))
from alerts import check_alerts, load_alerts, save_alerts
@pytest.fixture
def mock_alerts_data():
return {
"_meta": {"version": 1, "supported_currencies": ["USD", "EUR"]},
"alerts": [
{
"ticker": "AAPL",
"target_price": 150.0,
"currency": "USD",
"note": "Buy Apple",
"triggered_count": 0,
"last_triggered": None
},
{
"ticker": "TSLA",
"target_price": 200.0,
"currency": "USD",
"note": "Buy Tesla",
"triggered_count": 5,
"last_triggered": "2026-01-26T10:00:00"
}
]
}
def test_check_alerts_trigger(mock_alerts_data, monkeypatch, tmp_path):
# Setup mock alerts file
alerts_file = tmp_path / "alerts.json"
monkeypatch.setattr("alerts.ALERTS_FILE", alerts_file)
alerts_file.write_text(json.dumps(mock_alerts_data))
# Mock market data: AAPL is under target, TSLA is over
mock_quotes = {
"AAPL": {"price": 145.0},
"TSLA": {"price": 210.0}
}
with patch("alerts.get_fetch_market_data") as mock_fmd_getter:
mock_fmd = Mock(return_value=mock_quotes)
mock_fmd_getter.return_value = mock_fmd
results = check_alerts()
assert len(results["triggered"]) == 1
assert results["triggered"][0]["ticker"] == "AAPL"
assert results["triggered"][0]["current_price"] == 145.0
assert len(results["watching"]) == 1
assert results["watching"][0]["ticker"] == "TSLA"
# Verify triggered count incremented for AAPL
updated_data = json.loads(alerts_file.read_text())
aapl_alert = next(a for a in updated_data["alerts"] if a["ticker"] == "AAPL")
assert aapl_alert["triggered_count"] == 1
assert aapl_alert["last_triggered"] is not None
def test_check_alerts_deduplication(mock_alerts_data, monkeypatch, tmp_path):
# If already triggered today, triggered_count should NOT increment
now = datetime.now()
mock_alerts_data["alerts"][0]["last_triggered"] = now.isoformat()
mock_alerts_data["alerts"][0]["triggered_count"] = 1
alerts_file = tmp_path / "alerts.json"
monkeypatch.setattr("alerts.ALERTS_FILE", alerts_file)
alerts_file.write_text(json.dumps(mock_alerts_data))
mock_quotes = {"AAPL": {"price": 140.0}, "TSLA": {"price": 250.0}}
with patch("alerts.get_fetch_market_data") as mock_fmd_getter:
mock_fmd = Mock(return_value=mock_quotes)
mock_fmd_getter.return_value = mock_fmd
check_alerts()
updated_data = json.loads(alerts_file.read_text())
aapl_alert = next(a for a in updated_data["alerts"] if a["ticker"] == "AAPL")
assert aapl_alert["triggered_count"] == 1 # Still 1, didn't increment because same day
def test_check_alerts_snooze(mock_alerts_data, monkeypatch, tmp_path):
# Snoozed alert should be ignored
future_date = datetime.now() + timedelta(days=1)
mock_alerts_data["alerts"][0]["snooze_until"] = future_date.isoformat()
alerts_file = tmp_path / "alerts.json"
monkeypatch.setattr("alerts.ALERTS_FILE", alerts_file)
alerts_file.write_text(json.dumps(mock_alerts_data))
mock_quotes = {"AAPL": {"price": 140.0}, "TSLA": {"price": 190.0}}
with patch("alerts.get_fetch_market_data") as mock_fmd_getter:
mock_fmd = Mock(return_value=mock_quotes)
mock_fmd_getter.return_value = mock_fmd
results = check_alerts()
# AAPL is snoozed, so only TSLA should be in triggered
assert len(results["triggered"]) == 1
assert results["triggered"][0]["ticker"] == "TSLA"
assert all(t["ticker"] != "AAPL" for t in results["triggered"])