330 lines
11 KiB
Python
330 lines
11 KiB
Python
"""Unit tests for FinnHub utilities."""
|
|
|
|
import json
|
|
import os
|
|
|
|
import pytest
|
|
|
|
from tradingagents.dataflows.finnhub_utils import get_data_in_range
|
|
|
|
|
|
class TestFinnhubUtils:
|
|
"""Test suite for FinnHub utility functions."""
|
|
|
|
def test_get_data_in_range_basic(self, temp_data_dir):
|
|
"""Test basic functionality of get_data_in_range."""
|
|
# Setup test data
|
|
ticker = "AAPL"
|
|
data_type = "news_data"
|
|
test_data = {
|
|
"2024-05-09": [{"headline": "Old news", "summary": "Before range"}],
|
|
"2024-05-10": [{"headline": "Good news", "summary": "In range"}],
|
|
"2024-05-11": [{"headline": "More news", "summary": "Also in range"}],
|
|
"2024-05-12": [{"headline": "Future news", "summary": "After range"}],
|
|
}
|
|
|
|
# Create data directory and file
|
|
data_dir = os.path.join(temp_data_dir, "finnhub_data", data_type)
|
|
os.makedirs(data_dir, exist_ok=True)
|
|
data_file = os.path.join(data_dir, f"{ticker}_data_formatted.json")
|
|
|
|
with open(data_file, "w") as f:
|
|
json.dump(test_data, f)
|
|
|
|
# Execute
|
|
result = get_data_in_range(
|
|
ticker=ticker,
|
|
start_date="2024-05-10",
|
|
end_date="2024-05-11",
|
|
data_type=data_type,
|
|
data_dir=temp_data_dir,
|
|
)
|
|
|
|
# Verify
|
|
assert len(result) == 2
|
|
assert "2024-05-10" in result
|
|
assert "2024-05-11" in result
|
|
assert "2024-05-09" not in result
|
|
assert "2024-05-12" not in result
|
|
assert result["2024-05-10"][0]["headline"] == "Good news"
|
|
assert result["2024-05-11"][0]["headline"] == "More news"
|
|
|
|
def test_get_data_in_range_with_period(self, temp_data_dir):
|
|
"""Test get_data_in_range with period parameter."""
|
|
ticker = "TSLA"
|
|
data_type = "fin_as_reported"
|
|
period = "quarterly"
|
|
test_data = {
|
|
"2024-03-31": [{"revenue": 21301000000, "period": "Q1"}],
|
|
"2024-06-30": [{"revenue": 24927000000, "period": "Q2"}],
|
|
}
|
|
|
|
# Create data directory and file
|
|
data_dir = os.path.join(temp_data_dir, "finnhub_data", data_type)
|
|
os.makedirs(data_dir, exist_ok=True)
|
|
data_file = os.path.join(data_dir, f"{ticker}_{period}_data_formatted.json")
|
|
|
|
with open(data_file, "w") as f:
|
|
json.dump(test_data, f)
|
|
|
|
# Execute
|
|
result = get_data_in_range(
|
|
ticker=ticker,
|
|
start_date="2024-03-01",
|
|
end_date="2024-06-30",
|
|
data_type=data_type,
|
|
data_dir=temp_data_dir,
|
|
period=period,
|
|
)
|
|
|
|
# Verify
|
|
assert len(result) == 2
|
|
assert "2024-03-31" in result
|
|
assert "2024-06-30" in result
|
|
assert result["2024-03-31"][0]["revenue"] == 21301000000
|
|
|
|
def test_get_data_in_range_filters_empty_values(self, temp_data_dir):
|
|
"""Test that empty values are filtered out."""
|
|
ticker = "NVDA"
|
|
data_type = "insider_trans"
|
|
test_data = {
|
|
"2024-05-10": [{"transaction": "buy", "shares": 1000}],
|
|
"2024-05-11": [], # Empty array should be filtered
|
|
"2024-05-12": [{"transaction": "sell", "shares": 500}],
|
|
}
|
|
|
|
# Create data directory and file
|
|
data_dir = os.path.join(temp_data_dir, "finnhub_data", data_type)
|
|
os.makedirs(data_dir, exist_ok=True)
|
|
data_file = os.path.join(data_dir, f"{ticker}_data_formatted.json")
|
|
|
|
with open(data_file, "w") as f:
|
|
json.dump(test_data, f)
|
|
|
|
# Execute
|
|
result = get_data_in_range(
|
|
ticker=ticker,
|
|
start_date="2024-05-10",
|
|
end_date="2024-05-12",
|
|
data_type=data_type,
|
|
data_dir=temp_data_dir,
|
|
)
|
|
|
|
# Verify - empty array should be filtered out
|
|
assert len(result) == 2
|
|
assert "2024-05-10" in result
|
|
assert "2024-05-11" not in result # Should be filtered out
|
|
assert "2024-05-12" in result
|
|
|
|
def test_get_data_in_range_date_boundary(self, temp_data_dir):
|
|
"""Test date boundary conditions."""
|
|
ticker = "MSFT"
|
|
data_type = "SEC_filings"
|
|
test_data = {
|
|
"2024-05-09": [{"filing": "10-Q"}],
|
|
"2024-05-10": [{"filing": "8-K"}], # Start date (inclusive)
|
|
"2024-05-11": [{"filing": "10-K"}],
|
|
"2024-05-12": [{"filing": "DEF 14A"}], # End date (inclusive)
|
|
"2024-05-13": [{"filing": "Schedule 13D"}],
|
|
}
|
|
|
|
# Create data directory and file
|
|
data_dir = os.path.join(temp_data_dir, "finnhub_data", data_type)
|
|
os.makedirs(data_dir, exist_ok=True)
|
|
data_file = os.path.join(data_dir, f"{ticker}_data_formatted.json")
|
|
|
|
with open(data_file, "w") as f:
|
|
json.dump(test_data, f)
|
|
|
|
# Execute
|
|
result = get_data_in_range(
|
|
ticker=ticker,
|
|
start_date="2024-05-10",
|
|
end_date="2024-05-12",
|
|
data_type=data_type,
|
|
data_dir=temp_data_dir,
|
|
)
|
|
|
|
# Verify - both boundary dates should be included
|
|
assert len(result) == 3
|
|
assert "2024-05-10" in result
|
|
assert "2024-05-11" in result
|
|
assert "2024-05-12" in result
|
|
assert "2024-05-09" not in result
|
|
assert "2024-05-13" not in result
|
|
|
|
def test_get_data_in_range_no_matching_data(self, temp_data_dir):
|
|
"""Test behavior when no data matches the date range."""
|
|
ticker = "AMZN"
|
|
data_type = "insider_senti"
|
|
test_data = {
|
|
"2024-04-01": [{"sentiment": "positive"}],
|
|
"2024-04-02": [{"sentiment": "neutral"}],
|
|
}
|
|
|
|
# Create data directory and file
|
|
data_dir = os.path.join(temp_data_dir, "finnhub_data", data_type)
|
|
os.makedirs(data_dir, exist_ok=True)
|
|
data_file = os.path.join(data_dir, f"{ticker}_data_formatted.json")
|
|
|
|
with open(data_file, "w") as f:
|
|
json.dump(test_data, f)
|
|
|
|
# Execute - request data from a different time range
|
|
result = get_data_in_range(
|
|
ticker=ticker,
|
|
start_date="2024-05-10",
|
|
end_date="2024-05-12",
|
|
data_type=data_type,
|
|
data_dir=temp_data_dir,
|
|
)
|
|
|
|
# Verify - should return empty dict
|
|
assert len(result) == 0
|
|
assert result == {}
|
|
|
|
def test_get_data_in_range_file_handling(self, temp_data_dir):
|
|
"""Test proper file path construction and handling."""
|
|
ticker = "GOOGL"
|
|
data_type = "news_data"
|
|
|
|
# Test without period
|
|
expected_path_no_period = os.path.join(
|
|
temp_data_dir,
|
|
"finnhub_data",
|
|
data_type,
|
|
f"{ticker}_data_formatted.json",
|
|
)
|
|
|
|
# Test with period
|
|
period = "annual"
|
|
expected_path_with_period = os.path.join(
|
|
temp_data_dir,
|
|
"finnhub_data",
|
|
data_type,
|
|
f"{ticker}_{period}_data_formatted.json",
|
|
)
|
|
|
|
# Create test data for both scenarios
|
|
test_data = {"2024-05-10": [{"test": "data"}]}
|
|
|
|
# Create directories
|
|
data_dir = os.path.join(temp_data_dir, "finnhub_data", data_type)
|
|
os.makedirs(data_dir, exist_ok=True)
|
|
|
|
# Create files
|
|
with open(expected_path_no_period, "w") as f:
|
|
json.dump(test_data, f)
|
|
with open(expected_path_with_period, "w") as f:
|
|
json.dump(test_data, f)
|
|
|
|
# Test without period
|
|
result1 = get_data_in_range(
|
|
ticker=ticker,
|
|
start_date="2024-05-10",
|
|
end_date="2024-05-10",
|
|
data_type=data_type,
|
|
data_dir=temp_data_dir,
|
|
)
|
|
assert len(result1) == 1
|
|
|
|
# Test with period
|
|
result2 = get_data_in_range(
|
|
ticker=ticker,
|
|
start_date="2024-05-10",
|
|
end_date="2024-05-10",
|
|
data_type=data_type,
|
|
data_dir=temp_data_dir,
|
|
period=period,
|
|
)
|
|
assert len(result2) == 1
|
|
|
|
@pytest.mark.parametrize(
|
|
("data_type", "period"),
|
|
[
|
|
("news_data", None),
|
|
("insider_trans", None),
|
|
("SEC_filings", None),
|
|
("insider_senti", None),
|
|
("fin_as_reported", "annual"),
|
|
("fin_as_reported", "quarterly"),
|
|
],
|
|
)
|
|
def test_get_data_in_range_various_data_types(
|
|
self,
|
|
temp_data_dir,
|
|
data_type,
|
|
period,
|
|
):
|
|
"""Test get_data_in_range with various data types."""
|
|
ticker = "TEST"
|
|
test_data = {
|
|
"2024-05-10": [{"test_field": "test_value"}],
|
|
}
|
|
|
|
# Create data directory and file
|
|
data_dir = os.path.join(temp_data_dir, "finnhub_data", data_type)
|
|
os.makedirs(data_dir, exist_ok=True)
|
|
|
|
filename = f"{ticker}_data_formatted.json"
|
|
if period:
|
|
filename = f"{ticker}_{period}_data_formatted.json"
|
|
|
|
data_file = os.path.join(data_dir, filename)
|
|
|
|
with open(data_file, "w") as f:
|
|
json.dump(test_data, f)
|
|
|
|
# Execute
|
|
result = get_data_in_range(
|
|
ticker=ticker,
|
|
start_date="2024-05-10",
|
|
end_date="2024-05-10",
|
|
data_type=data_type,
|
|
data_dir=temp_data_dir,
|
|
period=period,
|
|
)
|
|
|
|
# Verify
|
|
assert len(result) == 1
|
|
assert "2024-05-10" in result
|
|
assert result["2024-05-10"][0]["test_field"] == "test_value"
|
|
|
|
|
|
class TestFinnhubUtilsErrorHandling:
|
|
"""Test error handling in FinnHub utilities."""
|
|
|
|
def test_get_data_in_range_missing_file(self, temp_data_dir):
|
|
"""Test behavior when data file doesn't exist."""
|
|
with pytest.raises(FileNotFoundError):
|
|
get_data_in_range(
|
|
ticker="NONEXISTENT",
|
|
start_date="2024-05-10",
|
|
end_date="2024-05-11",
|
|
data_type="news_data",
|
|
data_dir=temp_data_dir,
|
|
)
|
|
|
|
def test_get_data_in_range_invalid_json(self, temp_data_dir):
|
|
"""Test behavior when JSON file is corrupted."""
|
|
ticker = "CORRUPT"
|
|
data_type = "news_data"
|
|
|
|
# Create data directory and corrupted file
|
|
data_dir = os.path.join(temp_data_dir, "finnhub_data", data_type)
|
|
os.makedirs(data_dir, exist_ok=True)
|
|
data_file = os.path.join(data_dir, f"{ticker}_data_formatted.json")
|
|
|
|
with open(data_file, "w") as f:
|
|
f.write("invalid json content")
|
|
|
|
# Should raise JSONDecodeError
|
|
with pytest.raises(json.JSONDecodeError):
|
|
get_data_in_range(
|
|
ticker=ticker,
|
|
start_date="2024-05-10",
|
|
end_date="2024-05-11",
|
|
data_type=data_type,
|
|
data_dir=temp_data_dir,
|
|
)
|