@@ -262,3 +262,75 @@ def test_replace_all_emits_content_updated(self, window, qtbot):
262262 window ._replace_edit .setText ("goodbye" )
263263 with qtbot .waitSignal (window ._viewmodel .content_updated , timeout = 1000 ):
264264 window ._on_replace_all_clicked ()
265+
266+
267+ class TestTreeClickHandler :
268+ def test_file_click_loads_file (self , window , tmp_path , qtbot ):
269+ """Clicking a file path sets fileNameEdit and calls load_file — lines 233-234."""
270+ f = tmp_path / "click.txt"
271+ f .write_text ("click content" , encoding = "utf-8" )
272+ window ._fs_model .filePath = MagicMock (return_value = str (f ))
273+ window ._file_name_edit .setText (str (f ))
274+ with qtbot .waitSignal (window ._viewmodel .document_loaded , timeout = 1000 ):
275+ window ._on_tree_item_clicked (MagicMock ())
276+
277+ def test_directory_click_is_ignored (self , window , tmp_path ):
278+ """Clicking a directory does not call load_file — line 232 branch."""
279+ window ._fs_model .filePath = MagicMock (return_value = str (tmp_path ))
280+ emitted : list = []
281+ window ._viewmodel .document_loaded .connect (emitted .append )
282+ window ._on_tree_item_clicked (MagicMock ())
283+ assert emitted == []
284+
285+
286+ class TestActionOpenHandler :
287+ def test_chosen_file_is_loaded (self , window , tmp_path , monkeypatch , qtbot ):
288+ """QFileDialog returns path → file loaded — lines 304-306."""
289+ f = tmp_path / "opened.txt"
290+ f .write_text ("opened" , encoding = "utf-8" )
291+ monkeypatch .setattr (
292+ "src.views.main_window.QFileDialog.getOpenFileName" ,
293+ lambda * a , ** kw : (str (f ), "" ),
294+ )
295+ window ._file_name_edit .setText (str (f ))
296+ with qtbot .waitSignal (window ._viewmodel .document_loaded , timeout = 1000 ):
297+ window ._on_action_open ()
298+ assert window ._file_name_edit .text () == str (f )
299+
300+ def test_cancelled_dialog_is_no_op (self , window , monkeypatch ):
301+ """QFileDialog returns '' → nothing happens — lines 303-304 branch."""
302+ monkeypatch .setattr (
303+ "src.views.main_window.QFileDialog.getOpenFileName" ,
304+ lambda * a , ** kw : ("" , "" ),
305+ )
306+ emitted : list = []
307+ window ._viewmodel .document_loaded .connect (emitted .append )
308+ window ._on_action_open ()
309+ assert emitted == []
310+
311+
312+ class TestActionAboutHandler :
313+ def test_about_dialog_is_shown (self , window , monkeypatch ):
314+ """actionAbout → QMessageBox.about called — line 310."""
315+ calls : list = []
316+ monkeypatch .setattr (
317+ "src.views.main_window.QMessageBox.about" ,
318+ lambda * a : calls .append (a ),
319+ )
320+ window ._on_action_about ()
321+ assert len (calls ) == 1
322+ assert "0.2.0" in calls [0 ][2 ]
323+
324+
325+ class TestErrorHandler :
326+ def test_error_signal_shows_critical_dialog (self , window , monkeypatch , qtbot ):
327+ """error_occurred signal → QMessageBox.critical — line 366."""
328+ calls : list = []
329+ monkeypatch .setattr (
330+ "src.views.main_window.QMessageBox.critical" ,
331+ lambda * a , ** kw : calls .append (a ),
332+ )
333+ window ._viewmodel .error_occurred .emit ("something went wrong" )
334+ qtbot .wait (10 )
335+ assert len (calls ) == 1
336+ assert "something went wrong" in calls [0 ][2 ]
0 commit comments