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>
This commit is contained in:
parent
8db777ae8b
commit
e6327780aa
8 changed files with 1390 additions and 0 deletions
182
tests/test_fx.py
Normal file
182
tests/test_fx.py
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
"""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)
|
||||
Loading…
Add table
Add a link
Reference in a new issue