@@ -148,3 +148,65 @@ def test_replace_all_uses_current_text_when_provided(self, vm, qtbot):
148148 with qtbot .waitSignal (vm .content_updated , timeout = 1000 ) as blocker :
149149 vm .replace_all ("hello" , "goodbye" , current_text = "hello hello" )
150150 assert blocker .args [0 ] == "goodbye goodbye"
151+
152+
153+ class TestConvertToUtf8 :
154+ def test_saves_file_with_utf8_encoding (self , vm , mock_file_svc , qtbot ):
155+ """convert_to_utf8 must call save_file with encoding='utf-8'."""
156+ from src .models .text_document import TextDocument
157+ mock_file_svc .open_file .return_value = TextDocument (
158+ filepath = "/tmp/latin.txt" , content = "caf\u00e9 " , encoding = "ISO-8859-1"
159+ )
160+ vm .load_file ("/tmp/latin.txt" )
161+ vm .convert_to_utf8 ("café" )
162+ saved_doc = mock_file_svc .save_file .call_args [0 ][0 ]
163+ assert saved_doc .encoding == "utf-8"
164+ assert saved_doc .content == "café"
165+
166+ def test_emits_encoding_detected_utf8 (self , vm , mock_file_svc , qtbot ):
167+ """convert_to_utf8 must emit encoding_detected('utf-8')."""
168+ from src .models .text_document import TextDocument
169+ mock_file_svc .open_file .return_value = TextDocument (
170+ filepath = "/tmp/latin.txt" , content = "caf\u00e9 " , encoding = "ISO-8859-1"
171+ )
172+ vm .load_file ("/tmp/latin.txt" )
173+ with qtbot .waitSignal (vm .encoding_detected , timeout = 1000 ) as blocker :
174+ vm .convert_to_utf8 ("café" )
175+ assert blocker .args [0 ] == "utf-8"
176+
177+ def test_emits_file_saved (self , vm , mock_file_svc , qtbot ):
178+ """convert_to_utf8 must emit file_saved after a successful save."""
179+ from src .models .text_document import TextDocument
180+ mock_file_svc .open_file .return_value = TextDocument (
181+ filepath = "/tmp/latin.txt" , content = "caf\u00e9 " , encoding = "ISO-8859-1"
182+ )
183+ vm .load_file ("/tmp/latin.txt" )
184+ with qtbot .waitSignal (vm .file_saved , timeout = 1000 ) as blocker :
185+ vm .convert_to_utf8 ("café" )
186+ assert blocker .args [0 ] == "/tmp/latin.txt"
187+
188+ def test_no_op_when_already_utf8 (self , vm , mock_file_svc , qtbot ):
189+ """convert_to_utf8 must not save when encoding is already utf-8."""
190+ from src .models .text_document import TextDocument
191+ mock_file_svc .open_file .return_value = TextDocument (
192+ filepath = "/tmp/utf8.txt" , content = "hello" , encoding = "utf-8"
193+ )
194+ vm .load_file ("/tmp/utf8.txt" )
195+ vm .convert_to_utf8 ("hello" )
196+ mock_file_svc .save_file .assert_not_called ()
197+
198+ def test_no_op_when_no_document (self , vm , qtbot ):
199+ """convert_to_utf8 with no loaded document must be silent."""
200+ vm .convert_to_utf8 ("some text" ) # must not raise
201+
202+ def test_emits_error_on_save_failure (self , vm , mock_file_svc , qtbot ):
203+ """convert_to_utf8 must emit error_occurred when save_file raises."""
204+ from src .models .text_document import TextDocument
205+ mock_file_svc .open_file .return_value = TextDocument (
206+ filepath = "/tmp/latin.txt" , content = "caf\u00e9 " , encoding = "ISO-8859-1"
207+ )
208+ vm .load_file ("/tmp/latin.txt" )
209+ mock_file_svc .save_file .side_effect = PermissionError ("read-only" )
210+ with qtbot .waitSignal (vm .error_occurred , timeout = 1000 ) as blocker :
211+ vm .convert_to_utf8 ("café" )
212+ assert "Cannot convert" in blocker .args [0 ]
0 commit comments