"""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")