| 
 | 1 | +import winreg  | 
 | 2 | +from unittest import mock  | 
 | 3 | + | 
 | 4 | +import pytest  | 
 | 5 | + | 
 | 6 | +from manage import arputils  | 
 | 7 | +from manage.pathutils import Path  | 
 | 8 | + | 
 | 9 | + | 
 | 10 | +def test_size_empty_directory(tmp_path):  | 
 | 11 | +    result = arputils._size(tmp_path)  | 
 | 12 | +    assert result == 0  | 
 | 13 | + | 
 | 14 | + | 
 | 15 | +def test_size_with_files(tmp_path):  | 
 | 16 | +    (tmp_path / "file1.txt").write_bytes(b"x" * 1024)  | 
 | 17 | +    (tmp_path / "file2.txt").write_bytes(b"y" * 2048)  | 
 | 18 | +      | 
 | 19 | +    result = arputils._size(tmp_path)  | 
 | 20 | +    assert result == 3  | 
 | 21 | + | 
 | 22 | + | 
 | 23 | +def test_size_ignores_oserror(tmp_path):  | 
 | 24 | +    (tmp_path / "file.txt").write_bytes(b"test")  | 
 | 25 | +      | 
 | 26 | +    with mock.patch("manage.arputils.rglob") as mock_rglob:  | 
 | 27 | +        mock_file = mock.Mock()  | 
 | 28 | +        mock_file.lstat.side_effect = OSError("Access denied")  | 
 | 29 | +        mock_rglob.return_value = [mock_file]  | 
 | 30 | +          | 
 | 31 | +        result = arputils._size(tmp_path)  | 
 | 32 | +        assert result == 0  | 
 | 33 | + | 
 | 34 | + | 
 | 35 | +def test_set_int_value():  | 
 | 36 | +    mock_key = mock.Mock()  | 
 | 37 | +      | 
 | 38 | +    with mock.patch("winreg.SetValueEx") as mock_set:  | 
 | 39 | +        arputils._set_value(mock_key, "TestInt", 42)  | 
 | 40 | +        mock_set.assert_called_once_with(  | 
 | 41 | +            mock_key, "TestInt", None, winreg.REG_DWORD, 42  | 
 | 42 | +        )  | 
 | 43 | + | 
 | 44 | + | 
 | 45 | +def test_set_string_value():  | 
 | 46 | +    mock_key = mock.Mock()  | 
 | 47 | +      | 
 | 48 | +    with mock.patch("winreg.SetValueEx") as mock_set:  | 
 | 49 | +        arputils._set_value(mock_key, "TestStr", "hello")  | 
 | 50 | +        mock_set.assert_called_once_with(  | 
 | 51 | +            mock_key, "TestStr", None, winreg.REG_SZ, "hello"  | 
 | 52 | +        )  | 
 | 53 | + | 
 | 54 | + | 
 | 55 | +def test_set_path_value_converts_to_string():  | 
 | 56 | +    mock_key = mock.Mock()  | 
 | 57 | +    test_path = Path("C:/test/path")  | 
 | 58 | +      | 
 | 59 | +    with mock.patch("winreg.SetValueEx") as mock_set:  | 
 | 60 | +        arputils._set_value(mock_key, "TestPath", test_path)  | 
 | 61 | +        mock_set.assert_called_once()  | 
 | 62 | +        assert isinstance(mock_set.call_args[0][4], str)  | 
 | 63 | + | 
 | 64 | + | 
 | 65 | +def test_self_cmd_uses_cache():  | 
 | 66 | +    arputils._self_cmd_cache = Path("C:/cached/pymanager.exe")  | 
 | 67 | +      | 
 | 68 | +    result = arputils._self_cmd()  | 
 | 69 | +    assert result == Path("C:/cached/pymanager.exe")  | 
 | 70 | +      | 
 | 71 | +    arputils._self_cmd_cache = None  | 
 | 72 | + | 
 | 73 | + | 
 | 74 | +def test_self_cmd_raises_when_not_found(monkeypatch, tmp_path):  | 
 | 75 | +    arputils._self_cmd_cache = None  | 
 | 76 | +      | 
 | 77 | +    monkeypatch.setenv("LocalAppData", str(tmp_path))  | 
 | 78 | +      | 
 | 79 | +    windows_apps = tmp_path / "Microsoft" / "WindowsApps"  | 
 | 80 | +    windows_apps.mkdir(parents=True)  | 
 | 81 | +      | 
 | 82 | +    with mock.patch.dict("sys.modules", {"_winapi": None}):  | 
 | 83 | +        with pytest.raises(FileNotFoundError, match="Cannot determine uninstall command"):  | 
 | 84 | +            arputils._self_cmd()  | 
 | 85 | +      | 
 | 86 | +    arputils._self_cmd_cache = None  | 
 | 87 | + | 
 | 88 | + | 
 | 89 | +def test_iter_keys_with_none():  | 
 | 90 | +    result = list(arputils._iter_keys(None))  | 
 | 91 | +    assert result == []  | 
 | 92 | + | 
 | 93 | + | 
 | 94 | +def test_iter_keys_stops_on_oserror():  | 
 | 95 | +    mock_key = mock.Mock()  | 
 | 96 | +      | 
 | 97 | +    with mock.patch("winreg.EnumKey") as mock_enum:  | 
 | 98 | +        mock_enum.side_effect = ["key1", OSError()]  | 
 | 99 | +          | 
 | 100 | +        result = list(arputils._iter_keys(mock_key))  | 
 | 101 | +        assert result == ["key1"]  | 
 | 102 | + | 
 | 103 | + | 
 | 104 | +def test_delete_key_retries_on_permission_error():  | 
 | 105 | +    mock_key = mock.Mock()  | 
 | 106 | +      | 
 | 107 | +    with mock.patch("winreg.DeleteKey") as mock_delete:  | 
 | 108 | +        with mock.patch("time.sleep"):  | 
 | 109 | +            mock_delete.side_effect = [  | 
 | 110 | +                PermissionError(),  | 
 | 111 | +                PermissionError(),  | 
 | 112 | +                None  | 
 | 113 | +            ]  | 
 | 114 | +              | 
 | 115 | +            arputils._delete_key(mock_key, "test_key")  | 
 | 116 | +              | 
 | 117 | +            assert mock_delete.call_count == 3  | 
 | 118 | + | 
 | 119 | + | 
 | 120 | +def test_delete_key_ignores_filenotfound():  | 
 | 121 | +    mock_key = mock.Mock()  | 
 | 122 | +      | 
 | 123 | +    with mock.patch("winreg.DeleteKey") as mock_delete:  | 
 | 124 | +        mock_delete.side_effect = FileNotFoundError()  | 
 | 125 | +          | 
 | 126 | +        arputils._delete_key(mock_key, "test_key")  | 
0 commit comments