stocks / tests /test_utils.py
Arrechenash's picture
Initial Commit
3aed849
Raw
History Blame Contribute Delete
7.12 kB
"""
Tests for utility modules: paths, execution, reporting, stats_helpers.
"""
from pathlib import Path
from unittest.mock import patch
import pandas as pd
# =============================================================================
# Paths Tests
# =============================================================================
class TestPaths:
"""Tests for path utilities."""
def test_ensure_dir_creates_directory(self):
"""Test ensure_dir creates directory."""
from core.utils.paths import ensure_dir
with patch("os.makedirs") as mock_makedirs:
result = ensure_dir("/tmp/test_dir")
mock_makedirs.assert_called_once_with("/tmp/test_dir", exist_ok=True)
assert isinstance(result, Path)
def test_results_dir_constant(self):
"""Test RESULTS_DIR is defined."""
from core.utils.paths import RESULTS_DIR
assert isinstance(RESULTS_DIR, Path)
def test_data_dir_constant(self):
"""Test DATA_DIR is defined."""
from core.utils.paths import DATA_DIR
assert isinstance(DATA_DIR, Path)
def test_cache_dir_constant(self):
"""Test CACHE_DIR is defined."""
from core.utils.paths import CACHE_DIR
assert isinstance(CACHE_DIR, Path)
# =============================================================================
# Execution Tests
# =============================================================================
class TestExecution:
"""Tests for ParallelExecutor."""
def test_parallel_executor_init(self):
"""Test ParallelExecutor initialization."""
from core.utils.execution import ParallelExecutor
executor = ParallelExecutor(max_workers=4)
assert executor.max_workers == 4
def test_parallel_executor_empty_input(self):
"""Test ParallelExecutor with empty input."""
from core.utils.execution import ParallelExecutor
executor = ParallelExecutor(max_workers=2)
results = list(executor.map(lambda x: x, [], desc="test"))
assert results == []
# =============================================================================
# Reporting Tests
# =============================================================================
class TestReporting:
"""Tests for reporting utilities."""
def test_csv_column_map_exists(self):
"""Test CSV_COLUMN_MAP is defined."""
from core.utils.reporting import CSV_COLUMN_MAP
assert isinstance(CSV_COLUMN_MAP, dict)
assert len(CSV_COLUMN_MAP) > 0
def test_generate_report_basic(self):
"""Test generate_report creates summary without error."""
from core.utils.reporting import generate_report
mock_df = pd.DataFrame(
{
"symbol": ["AAPL", "GOOGL"],
"date": pd.to_datetime(["2026-04-15", "2026-04-15"]).date,
"entry": [150.0, 2800.0],
"exit": [155.0, 2850.0],
"profit": [500.0, 500.0],
"ret": [3.3, 1.8],
}
)
# Should not raise
generate_report(mock_df, initial_capital=10000)
# =============================================================================
# Stats Helpers Tests
# =============================================================================
class TestStatsHelpers:
"""Tests for statistical helper functions."""
def test_avg_vol10_calculation(self):
"""Test avg_vol10 calculation."""
from core.utils.stats_helpers import avg_vol10
df = pd.DataFrame(
{
"volume": [1000000, 1100000, 1200000, 1300000, 1400000, 1500000, 1600000, 1700000, 1800000, 1900000],
}
)
result = avg_vol10(df, 9)
expected = (1000000 + 1100000 + 1200000 + 1300000 + 1400000 + 1500000 + 1600000 + 1700000 + 1800000) / 9
assert result == expected
def test_avg_vol10_first_day(self):
"""Test avg_vol10 for first day."""
from core.utils.stats_helpers import avg_vol10
df = pd.DataFrame(
{
"volume": [1000000],
}
)
result = avg_vol10(df, 0)
assert result is None or result == 1000000
def test_gap_pct_calculation(self):
"""Test gap_pct calculation."""
from core.utils.stats_helpers import gap_pct
result = gap_pct(100.0, 105.0)
assert result == 5.0
def test_gap_pct_none_values(self):
"""Test gap_pct handles None values."""
from core.utils.stats_helpers import gap_pct
result = gap_pct(None, 105.0)
assert result is None
def test_gap_pct_zero_prev_close(self):
"""Test gap_pct handles zero prev close."""
from core.utils.stats_helpers import gap_pct
result = gap_pct(0, 105.0)
assert result is None
def test_bucket_gap_all_ranges(self):
"""Test bucket_gap for all ranges."""
from core.utils.stats_helpers import bucket_gap
assert bucket_gap(-10.0) == "gap_n5_p"
assert bucket_gap(-3.0) == "gap_n5_0"
assert bucket_gap(3.0) == "gap_0_5"
assert bucket_gap(7.0) == "gap_5_10"
assert bucket_gap(15.0) == "gap_10_p"
assert bucket_gap(None) is None
def test_bucket_range_all_ranges(self):
"""Test bucket_range for all ranges."""
from core.utils.stats_helpers import bucket_range
assert bucket_range(1.0) == "rng_0_2"
assert bucket_range(3.0) == "rng_2_5"
assert bucket_range(7.0) == "rng_5_10"
assert bucket_range(15.0) == "rng_10_p"
assert bucket_range(None) is None
def test_bucket_price_all_ranges(self):
"""Test bucket_price for all ranges."""
from core.utils.stats_helpers import bucket_price
assert bucket_price(3.0) == "prc_lt_5"
assert bucket_price(15.0) == "prc_5_20"
assert bucket_price(35.0) == "prc_20_50"
assert bucket_price(75.0) == "prc_50_100"
assert bucket_price(150.0) == "prc_gt_100"
assert bucket_price(None) is None
def test_bucket_rel_vol_all_ranges(self):
"""Test bucket_rel_vol for all ranges."""
from core.utils.stats_helpers import bucket_rel_vol
assert bucket_rel_vol(1.0) == "rvol_lt_2"
assert bucket_rel_vol(3.0) == "rvol_2_5"
assert bucket_rel_vol(7.0) == "rvol_5_10"
assert bucket_rel_vol(15.0) == "rvol_gt_10"
assert bucket_rel_vol(None) is None
def test_bucket_premium_pct_all_ranges(self):
"""Test bucket_premium_pct for all ranges."""
from core.utils.stats_helpers import bucket_premium_pct
assert bucket_premium_pct(40.0, 100.0) == "pm_pct_0_50"
assert bucket_premium_pct(60.0, 100.0) == "pm_pct_50_75"
assert bucket_premium_pct(80.0, 100.0) == "pm_pct_75_90"
assert bucket_premium_pct(95.0, 100.0) == "pm_pct_90_100"
assert bucket_premium_pct(110.0, 100.0) == "pm_pct_100_p"
assert bucket_premium_pct(None, 100.0) is None
assert bucket_premium_pct(50.0, 0) is None