agenda/tests/test_fx.py
Edward Betts e6327780aa Add comprehensive test coverage for 8 modules
Increases overall test coverage from 53% to 56% by adding tests for:
- accommodation.py (60% → 100%)
- birthday.py (24% → 100%)
- calendar.py (19% → 100%)
- carnival.py (33% → 100%)
- domains.py (75% → 100%)
- events_yaml.py (50% → 96%)
- fx.py (14% → 21% for tested functions)
- sun.py (55% → 100%)

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-20 11:39:49 +02:00

182 lines
5.8 KiB
Python

"""Tests for foreign exchange functionality."""
import json
import os
import tempfile
from decimal import Decimal
from unittest.mock import Mock, patch
import pytest
from agenda.fx import read_cached_rates
class TestReadCachedRates:
"""Test the read_cached_rates function."""
def test_read_cached_rates_none_filename(self) -> None:
"""Test with None filename returns empty dict."""
result = read_cached_rates(None, ["USD", "EUR"])
assert result == {}
def test_read_cached_rates_valid_file(self) -> None:
"""Test reading valid cached rates file."""
currencies = ["USD", "EUR", "JPY"]
data = {
"quotes": {
"GBPUSD": 1.25,
"GBPEUR": 1.15,
"GBPJPY": 150.0,
"GBPCAD": 1.70 # Not requested
}
}
with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f:
json.dump(data, f)
filepath = f.name
try:
result = read_cached_rates(filepath, currencies)
assert len(result) == 3
assert result["USD"] == Decimal("1.25")
assert result["EUR"] == Decimal("1.15")
assert result["JPY"] == Decimal("150.0")
assert "CAD" not in result # Not requested
finally:
os.unlink(filepath)
def test_read_cached_rates_missing_currencies(self) -> None:
"""Test with some currencies missing from data."""
currencies = ["USD", "EUR", "CHF"] # CHF not in data
data = {
"quotes": {
"GBPUSD": 1.25,
"GBPEUR": 1.15
# GBPCHF missing
}
}
with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f:
json.dump(data, f)
filepath = f.name
try:
result = read_cached_rates(filepath, currencies)
assert len(result) == 2
assert result["USD"] == Decimal("1.25")
assert result["EUR"] == Decimal("1.15")
assert "CHF" not in result # Missing from data
finally:
os.unlink(filepath)
def test_read_cached_rates_empty_currencies_list(self) -> None:
"""Test with empty currencies list."""
data = {
"quotes": {
"GBPUSD": 1.25,
"GBPEUR": 1.15
}
}
with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f:
json.dump(data, f)
filepath = f.name
try:
result = read_cached_rates(filepath, [])
assert result == {}
finally:
os.unlink(filepath)
def test_read_cached_rates_no_quotes_key(self) -> None:
"""Test with data missing quotes key."""
currencies = ["USD", "EUR"]
data = {"other_key": "value"} # No quotes key
with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f:
json.dump(data, f)
filepath = f.name
try:
with pytest.raises(KeyError):
read_cached_rates(filepath, currencies)
finally:
os.unlink(filepath)
def test_read_cached_rates_file_not_found(self) -> None:
"""Test error handling when file doesn't exist."""
with pytest.raises(FileNotFoundError):
read_cached_rates("/nonexistent/file.json", ["USD"])
def test_read_cached_rates_invalid_json(self) -> None:
"""Test error handling with invalid JSON."""
with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f:
f.write("invalid json content")
filepath = f.name
try:
with pytest.raises(json.JSONDecodeError):
read_cached_rates(filepath, ["USD"])
finally:
os.unlink(filepath)
def test_read_cached_rates_decimal_precision(self) -> None:
"""Test that rates are returned as Decimal with proper precision."""
currencies = ["USD"]
data = {
"quotes": {
"GBPUSD": 1.234567890123456789 # High precision
}
}
with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f:
json.dump(data, f)
filepath = f.name
try:
result = read_cached_rates(filepath, currencies)
assert isinstance(result["USD"], Decimal)
# Should preserve reasonable precision from the JSON
# Python's JSON precision may be limited to float precision
expected = Decimal("1.234567890123456789")
assert abs(result["USD"] - expected) < Decimal("0.0000000000000001")
finally:
os.unlink(filepath)
def test_read_cached_rates_various_currency_codes(self) -> None:
"""Test with various currency codes."""
currencies = ["USD", "EUR", "JPY", "CHF", "CAD", "AUD"]
data = {
"quotes": {
"GBPUSD": 1.25,
"GBPEUR": 1.15,
"GBPJPY": 150.0,
"GBPCHF": 1.12,
"GBPCAD": 1.70,
"GBPAUD": 1.85
}
}
with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f:
json.dump(data, f)
filepath = f.name
try:
result = read_cached_rates(filepath, currencies)
assert len(result) == 6
for currency in currencies:
assert currency in result
assert isinstance(result[currency], Decimal)
finally:
os.unlink(filepath)