113 lines
4.3 KiB
Python
113 lines
4.3 KiB
Python
|
|
"""Tests for Visualizer metrics integration."""
|
||
|
|
|
||
|
|
import sys
|
||
|
|
import sqlite3
|
||
|
|
import tempfile
|
||
|
|
from pathlib import Path
|
||
|
|
from unittest.mock import patch
|
||
|
|
|
||
|
|
sys.path.append(str(Path(__file__).resolve().parents[1]))
|
||
|
|
|
||
|
|
from visualizer import Visualizer
|
||
|
|
from models import Book, BookSnapshot, OrderbookLevel, Metric
|
||
|
|
from repositories.sqlite_metrics_repository import SQLiteMetricsRepository
|
||
|
|
|
||
|
|
|
||
|
|
def test_visualizer_loads_metrics():
|
||
|
|
"""Test that visualizer can load stored metrics from database."""
|
||
|
|
with tempfile.NamedTemporaryFile(suffix=".db", delete=False) as tmp_file:
|
||
|
|
db_path = Path(tmp_file.name)
|
||
|
|
|
||
|
|
try:
|
||
|
|
# Create test database with metrics
|
||
|
|
metrics_repo = SQLiteMetricsRepository(db_path)
|
||
|
|
with metrics_repo.connect() as conn:
|
||
|
|
metrics_repo.create_metrics_table(conn)
|
||
|
|
|
||
|
|
# Insert test metrics
|
||
|
|
test_metrics = [
|
||
|
|
Metric(snapshot_id=1, timestamp=1000, obi=0.1, cvd=10.0, best_bid=50000.0, best_ask=50001.0),
|
||
|
|
Metric(snapshot_id=2, timestamp=1060, obi=0.2, cvd=15.0, best_bid=50002.0, best_ask=50003.0),
|
||
|
|
Metric(snapshot_id=3, timestamp=1120, obi=-0.1, cvd=12.0, best_bid=50004.0, best_ask=50005.0),
|
||
|
|
]
|
||
|
|
|
||
|
|
metrics_repo.insert_metrics_batch(conn, test_metrics)
|
||
|
|
conn.commit()
|
||
|
|
|
||
|
|
# Test visualizer
|
||
|
|
visualizer = Visualizer(window_seconds=60, max_bars=200)
|
||
|
|
visualizer.set_db_path(db_path)
|
||
|
|
|
||
|
|
# Load metrics directly to test the method
|
||
|
|
loaded_metrics = visualizer._load_stored_metrics(1000, 1120)
|
||
|
|
|
||
|
|
assert len(loaded_metrics) == 3
|
||
|
|
assert loaded_metrics[0].obi == 0.1
|
||
|
|
assert loaded_metrics[0].cvd == 10.0
|
||
|
|
assert loaded_metrics[1].obi == 0.2
|
||
|
|
assert loaded_metrics[2].obi == -0.1
|
||
|
|
|
||
|
|
finally:
|
||
|
|
db_path.unlink(missing_ok=True)
|
||
|
|
|
||
|
|
|
||
|
|
def test_visualizer_handles_no_database():
|
||
|
|
"""Test that visualizer handles gracefully when no database path is set."""
|
||
|
|
visualizer = Visualizer(window_seconds=60, max_bars=200)
|
||
|
|
|
||
|
|
# No database path set - should return empty list
|
||
|
|
metrics = visualizer._load_stored_metrics(1000, 2000)
|
||
|
|
assert metrics == []
|
||
|
|
|
||
|
|
|
||
|
|
def test_visualizer_handles_invalid_database():
|
||
|
|
"""Test that visualizer handles invalid database paths gracefully."""
|
||
|
|
visualizer = Visualizer(window_seconds=60, max_bars=200)
|
||
|
|
visualizer.set_db_path(Path("nonexistent.db"))
|
||
|
|
|
||
|
|
# Should handle error gracefully and return empty list
|
||
|
|
metrics = visualizer._load_stored_metrics(1000, 2000)
|
||
|
|
assert metrics == []
|
||
|
|
|
||
|
|
|
||
|
|
@patch('matplotlib.pyplot.subplots')
|
||
|
|
def test_visualizer_creates_four_subplots(mock_subplots):
|
||
|
|
"""Test that visualizer creates four subplots for OHLC, Volume, OBI, and CVD."""
|
||
|
|
# Mock the subplots creation
|
||
|
|
mock_fig = type('MockFig', (), {})()
|
||
|
|
mock_ax_ohlc = type('MockAx', (), {})()
|
||
|
|
mock_ax_volume = type('MockAx', (), {})()
|
||
|
|
mock_ax_obi = type('MockAx', (), {})()
|
||
|
|
mock_ax_cvd = type('MockAx', (), {})()
|
||
|
|
|
||
|
|
mock_subplots.return_value = (mock_fig, (mock_ax_ohlc, mock_ax_volume, mock_ax_obi, mock_ax_cvd))
|
||
|
|
|
||
|
|
# Create visualizer
|
||
|
|
visualizer = Visualizer(window_seconds=60, max_bars=200)
|
||
|
|
|
||
|
|
# Verify subplots were created correctly
|
||
|
|
mock_subplots.assert_called_once_with(4, 1, figsize=(12, 10), sharex=True)
|
||
|
|
assert visualizer.ax_ohlc == mock_ax_ohlc
|
||
|
|
assert visualizer.ax_volume == mock_ax_volume
|
||
|
|
assert visualizer.ax_obi == mock_ax_obi
|
||
|
|
assert visualizer.ax_cvd == mock_ax_cvd
|
||
|
|
|
||
|
|
|
||
|
|
def test_visualizer_update_from_book_with_empty_book():
|
||
|
|
"""Test that visualizer handles empty book gracefully."""
|
||
|
|
with patch('matplotlib.pyplot.subplots') as mock_subplots:
|
||
|
|
# Mock the subplots creation
|
||
|
|
mock_fig = type('MockFig', (), {'canvas': type('MockCanvas', (), {'draw_idle': lambda: None})()})()
|
||
|
|
mock_axes = [type('MockAx', (), {'clear': lambda: None})() for _ in range(4)]
|
||
|
|
mock_subplots.return_value = (mock_fig, tuple(mock_axes))
|
||
|
|
|
||
|
|
visualizer = Visualizer(window_seconds=60, max_bars=200)
|
||
|
|
|
||
|
|
# Test with empty book
|
||
|
|
book = Book()
|
||
|
|
|
||
|
|
# Should handle gracefully without errors
|
||
|
|
with patch('logging.warning') as mock_warning:
|
||
|
|
visualizer.update_from_book(book)
|
||
|
|
mock_warning.assert_called_once_with("Book has no snapshots to visualize")
|