1+ import pytest
2+ from jumper_extension .perfmonitor_magics import perfmonitorMagics , load_ipython_extension , unload_ipython_extension
3+ from unittest .mock import Mock , patch
4+ import pandas as pd
5+
6+ def test_initialization_and_basic_operations (ipython , mock_cpu_only ):
7+ """Test initialization, start/stop, and basic operations"""
8+ magics = perfmonitorMagics (ipython )
9+ assert magics .monitor is None
10+ assert not magics .print_perfreports
11+
12+ # Test start/stop cycle with valid interval parsing
13+ magics .perfmonitor_start ("0.5" )
14+ assert magics .monitor .interval == 0.5
15+ magics .perfmonitor_stop ("" )
16+
17+ # Test already running
18+ magics .perfmonitor_start ("" )
19+ magics .perfmonitor_start ("" ) # Already running
20+ magics .perfmonitor_stop ("" )
21+
22+ # Test invalid interval (no monitor running)
23+ magics .perfmonitor_start ("invalid" ) # Invalid interval
24+
25+ def test_no_monitor_error_cases (ipython , mock_cpu_only ):
26+ """Test all commands that require active monitor"""
27+ magics = perfmonitorMagics (ipython )
28+ magics .perfmonitor_stop ("" )
29+ magics .perfmonitor_resources ("" )
30+ magics .perfmonitor_plot ("" )
31+ magics .perfmonitor_perfreport ("" )
32+ magics .perfmonitor_export_perfdata ("" )
33+
34+ def test_resources_and_gpu (ipython , mock_cpu_gpu ):
35+ """Test resources display with GPU"""
36+ magics = perfmonitorMagics (ipython )
37+ magics .perfmonitor_start ("" )
38+ magics .perfmonitor_resources ("" )
39+ magics .perfmonitor_stop ("" )
40+
41+ def test_cell_operations (ipython , mock_cpu_only ):
42+ """Test cell history and reports"""
43+ magics = perfmonitorMagics (ipython )
44+
45+ # Test cell history tracking and command
46+ cell_info = type ('Info' , (), {'raw_cell' : 'test' })()
47+ magics .pre_run_cell (cell_info )
48+ result = type ('Result' , (), {'result' : None })()
49+ magics .post_run_cell (result )
50+
51+ with patch .object (magics .cell_history , 'print' ):
52+ perfmonitorMagics .cell_history (magics , "" )
53+
54+ # Test auto-reports
55+ magics .perfmonitor_start ("" )
56+ magics .perfmonitor_enable_perfreports ("" )
57+ with patch .object (magics , '_perfreport' ):
58+ magics .post_run_cell (result )
59+ magics .perfmonitor_disable_perfreports ("" )
60+ magics .perfmonitor_stop ("" )
61+
62+ def test_parse_cell_number (ipython , mock_cpu_only ):
63+ """Test all cell number parsing scenarios"""
64+ magics = perfmonitorMagics (ipython )
65+ assert magics ._parse_cell_number ("" ) is None
66+ assert magics ._parse_cell_number ("invalid" ) is False
67+ assert magics ._parse_cell_number ("999" ) is False
68+
69+ # Add valid cell for testing
70+ cell_info = type ('Info' , (), {'raw_cell' : 'test' })()
71+ magics .pre_run_cell (cell_info )
72+ result = type ('Result' , (), {'result' : None })()
73+ magics .post_run_cell (result )
74+ assert magics ._parse_cell_number ("0" ) is not None
75+
76+ def test_plot_scenarios (ipython , mock_cpu_only ):
77+ """Test plotting with various data scenarios"""
78+ magics = perfmonitorMagics (ipython )
79+ magics .perfmonitor_start ("" )
80+
81+ # Test invalid cell
82+ magics .perfmonitor_plot ("invalid" )
83+
84+ # Test empty data
85+ with patch .object (magics .monitor .data , 'to_dataframe' , return_value = pd .DataFrame (columns = ['time' ])):
86+ magics .perfmonitor_plot ("" )
87+
88+ # Test with data
89+ df = pd .DataFrame ({'time' : [1.0 , 2.0 ], 'cpu_util_avg' : [50.0 , 60.0 ]})
90+ with patch .object (magics .monitor .data , 'to_dataframe' , return_value = df ), \
91+ patch .object (magics .visualizer , 'plot' ), \
92+ patch .object (magics .monitor , 'start_time' , 0.0 ):
93+ magics .perfmonitor_plot ("" )
94+
95+ # Test with cell filter
96+ with patch ('time.time' , side_effect = [1.0 , 2.0 ]):
97+ cell_info = type ('Info' , (), {'raw_cell' : 'test' })()
98+ magics .pre_run_cell (cell_info )
99+ magics .post_run_cell (type ('Result' , (), {'result' : None })())
100+
101+ with patch .object (magics .monitor .data , 'to_dataframe' , return_value = df ), \
102+ patch .object (magics .visualizer , 'plot' ), \
103+ patch .object (magics .monitor , 'start_time' , 0.0 ):
104+ magics .perfmonitor_plot ("0" )
105+
106+ magics .perfmonitor_stop ("" )
107+
108+ def test_perfreport_scenarios (ipython , mock_cpu_only ):
109+ """Test performance reporting scenarios"""
110+ magics = perfmonitorMagics (ipython )
111+
112+ # Test no monitor
113+ magics ._perfreport ()
114+
115+ magics .perfmonitor_start ("" )
116+
117+ # Test invalid cell for perfreport command
118+ magics .perfmonitor_perfreport ("invalid" )
119+
120+ # Add cell to history
121+ with patch ('time.time' , side_effect = [1.0 , 2.0 ]):
122+ cell_info = type ('Info' , (), {'raw_cell' : 'test' })()
123+ magics .pre_run_cell (cell_info )
124+ magics .post_run_cell (type ('Result' , (), {'result' : None })())
125+
126+ # Test empty data
127+ with patch .object (magics .monitor .data , 'to_dataframe' , return_value = pd .DataFrame (columns = ['time' ])):
128+ magics ._perfreport ()
129+
130+ # Test with full data
131+ df = pd .DataFrame ({
132+ 'time' : [1.0 , 2.0 ], 'cpu_util_avg' : [50.0 , 60.0 ], 'memory_usage_gb' : [4.0 , 4.5 ],
133+ 'gpu_util_avg' : [30.0 , 40.0 ], 'gpu_mem_avg' : [2.0 , 2.5 ]
134+ })
135+ with patch .object (magics .monitor .data , 'to_dataframe' , return_value = df ):
136+ magics ._perfreport ()
137+ magics ._perfreport ((1.0 , 2.0 )) # Custom cell marks
138+ magics .perfmonitor_perfreport ("0" ) # Via command
139+
140+ # Test with missing columns
141+ df_partial = pd .DataFrame ({'time' : [1.0 , 2.0 ], 'cpu_util_avg' : [50.0 , 60.0 ], 'memory_usage_gb' : [4.0 , 4.5 ]})
142+ with patch .object (magics .monitor .data , 'to_dataframe' , return_value = df_partial ):
143+ magics ._perfreport ()
144+
145+ magics .perfmonitor_stop ("" )
146+
147+ def test_export_and_help (ipython , mock_cpu_only ):
148+ """Test export functions and help"""
149+ magics = perfmonitorMagics (ipython )
150+
151+ # Test exports without monitor
152+ magics .perfmonitor_export_perfdata ("" )
153+
154+ # Test exports with monitor
155+ magics .perfmonitor_start ("" )
156+ with patch .object (magics .monitor .data , 'export' ):
157+ magics .perfmonitor_export_perfdata ("" )
158+ magics .perfmonitor_export_perfdata ("custom.csv" )
159+ magics .perfmonitor_stop ("" )
160+
161+ # Test cell history export
162+ with patch .object (magics .cell_history , 'export' ):
163+ magics .perfmonitor_export_cell_history ("" )
164+ magics .perfmonitor_export_cell_history ("custom.json" )
165+
166+ # Test help
167+ magics .perfmonitor_help ("" )
168+
169+ def test_extension_lifecycle (ipython , mock_cpu_only ):
170+ """Test IPython extension load/unload"""
171+ with patch .object (ipython .events , 'register' ), patch .object (ipython , 'register_magics' ):
172+ load_ipython_extension (ipython )
173+
174+ # Test unload with monitor
175+ from jumper_extension .perfmonitor_magics import _perfmonitor_magics
176+ _perfmonitor_magics .perfmonitor_start ("" )
177+ with patch .object (ipython .events , 'unregister' ):
178+ unload_ipython_extension (ipython )
179+
180+ # Test unload without magics
181+ from jumper_extension import perfmonitor_magics
182+ perfmonitor_magics ._perfmonitor_magics = None
183+ unload_ipython_extension (ipython )
0 commit comments