FreeCAD

Форк
0
/
test_freecad_interface.py 
299 строк · 12.6 Кб
1
# SPDX-License-Identifier: LGPL-2.1-or-later
2
# ***************************************************************************
3
# *                                                                         *
4
# *   Copyright (c) 2023 FreeCAD Project Association                        *
5
# *                                                                         *
6
# *   This file is part of FreeCAD.                                         *
7
# *                                                                         *
8
# *   FreeCAD is free software: you can redistribute it and/or modify it    *
9
# *   under the terms of the GNU Lesser General Public License as           *
10
# *   published by the Free Software Foundation, either version 2.1 of the  *
11
# *   License, or (at your option) any later version.                       *
12
# *                                                                         *
13
# *   FreeCAD is distributed in the hope that it will be useful, but        *
14
# *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
15
# *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      *
16
# *   Lesser General Public License for more details.                       *
17
# *                                                                         *
18
# *   You should have received a copy of the GNU Lesser General Public      *
19
# *   License along with FreeCAD. If not, see                               *
20
# *   <https://www.gnu.org/licenses/>.                                      *
21
# *                                                                         *
22
# ***************************************************************************
23

24
"""Tests for the Addon Manager's FreeCAD interface classes."""
25

26
import json
27
import os
28
import sys
29
import tempfile
30
import unittest
31
from unittest.mock import patch, MagicMock
32

33
# pylint: disable=protected-access,import-outside-toplevel
34

35

36
class TestConsole(unittest.TestCase):
37
    """Tests for the Console"""
38

39
    def setUp(self) -> None:
40
        self.saved_freecad = None
41
        if "FreeCAD" in sys.modules:
42
            self.saved_freecad = sys.modules["FreeCAD"]
43
            sys.modules.pop("FreeCAD")
44
        if "addonmanager_freecad_interface" in sys.modules:
45
            sys.modules.pop("addonmanager_freecad_interface")
46
        sys.path.append("../../")
47

48
    def tearDown(self) -> None:
49
        if "FreeCAD" in sys.modules:
50
            sys.modules.pop("FreeCAD")
51
        if self.saved_freecad is not None:
52
            sys.modules["FreeCAD"] = self.saved_freecad
53

54
    def test_log_with_freecad(self):
55
        """Ensure that if FreeCAD exists, the appropriate function is called"""
56
        sys.modules["FreeCAD"] = unittest.mock.MagicMock()
57
        import addonmanager_freecad_interface as fc
58

59
        fc.Console.PrintLog("Test output")
60
        self.assertTrue(isinstance(fc.Console, unittest.mock.MagicMock))
61
        self.assertTrue(fc.Console.PrintLog.called)
62

63
    def test_log_no_freecad(self):
64
        """Test that if the FreeCAD import fails, the logger is set up correctly, and
65
        implements PrintLog"""
66
        sys.modules["FreeCAD"] = None
67
        with patch("addonmanager_freecad_interface.logging", new=MagicMock()) as mock_logging:
68
            import addonmanager_freecad_interface as fc
69

70
            fc.Console.PrintLog("Test output")
71
            self.assertTrue(isinstance(fc.Console, fc.ConsoleReplacement))
72
            self.assertTrue(mock_logging.log.called)
73

74
    def test_message_no_freecad(self):
75
        """Test that if the FreeCAD import fails the logger implements PrintMessage"""
76
        sys.modules["FreeCAD"] = None
77
        with patch("addonmanager_freecad_interface.logging", new=MagicMock()) as mock_logging:
78
            import addonmanager_freecad_interface as fc
79

80
            fc.Console.PrintMessage("Test output")
81
            self.assertTrue(mock_logging.info.called)
82

83
    def test_warning_no_freecad(self):
84
        """Test that if the FreeCAD import fails the logger implements PrintWarning"""
85
        sys.modules["FreeCAD"] = None
86
        with patch("addonmanager_freecad_interface.logging", new=MagicMock()) as mock_logging:
87
            import addonmanager_freecad_interface as fc
88

89
            fc.Console.PrintWarning("Test output")
90
            self.assertTrue(mock_logging.warning.called)
91

92
    def test_error_no_freecad(self):
93
        """Test that if the FreeCAD import fails the logger implements PrintError"""
94
        sys.modules["FreeCAD"] = None
95
        with patch("addonmanager_freecad_interface.logging", new=MagicMock()) as mock_logging:
96
            import addonmanager_freecad_interface as fc
97

98
            fc.Console.PrintError("Test output")
99
            self.assertTrue(mock_logging.error.called)
100

101

102
class TestParameters(unittest.TestCase):
103
    """Tests for the Parameters"""
104

105
    def setUp(self) -> None:
106
        self.saved_freecad = None
107
        if "FreeCAD" in sys.modules:
108
            self.saved_freecad = sys.modules["FreeCAD"]
109
            sys.modules.pop("FreeCAD")
110
        if "addonmanager_freecad_interface" in sys.modules:
111
            sys.modules.pop("addonmanager_freecad_interface")
112
        sys.path.append("../../")
113

114
    def tearDown(self) -> None:
115
        if "FreeCAD" in sys.modules:
116
            sys.modules.pop("FreeCAD")
117
        if self.saved_freecad is not None:
118
            sys.modules["FreeCAD"] = self.saved_freecad
119

120
    def test_param_get_with_freecad(self):
121
        """Ensure that if FreeCAD exists, the built-in FreeCAD function is called"""
122
        sys.modules["FreeCAD"] = unittest.mock.MagicMock()
123
        import addonmanager_freecad_interface as fc
124

125
        prefs = fc.ParamGet("some/fake/path")
126
        self.assertTrue(isinstance(prefs, unittest.mock.MagicMock))
127

128
    def test_param_get_no_freecad(self):
129
        """Test that if the FreeCAD import fails, param_get returns a ParametersReplacement"""
130
        sys.modules["FreeCAD"] = None
131
        import addonmanager_freecad_interface as fc
132

133
        prefs = fc.ParamGet("some/fake/path")
134
        self.assertTrue(isinstance(prefs, fc.ParametersReplacement))
135

136
    def test_replacement_getters_and_setters(self):
137
        """Test that ParameterReplacement's getters, setters, and deleters work"""
138
        sys.modules["FreeCAD"] = None
139
        import addonmanager_freecad_interface as fc
140

141
        prf = fc.ParamGet("some/fake/path")
142
        gs_types = [
143
            ("Bool", prf.GetBool, prf.SetBool, prf.RemBool, True, False),
144
            ("Int", prf.GetInt, prf.SetInt, prf.RemInt, 42, 0),
145
            ("Float", prf.GetFloat, prf.SetFloat, prf.RemFloat, 1.2, 3.4),
146
            ("String", prf.GetString, prf.SetString, prf.RemString, "test", "other"),
147
        ]
148
        for gs_type in gs_types:
149
            with self.subTest(msg=f"Testing {gs_type[0]}", gs_type=gs_type):
150
                getter = gs_type[1]
151
                setter = gs_type[2]
152
                deleter = gs_type[3]
153
                value_1 = gs_type[4]
154
                value_2 = gs_type[5]
155
                self.assertEqual(getter("test", value_1), value_1)
156
                self.assertEqual(getter("test", value_2), value_2)
157
                self.assertNotIn("test", prf.parameters)
158
                setter("test", value_1)
159
                self.assertIn("test", prf.parameters)
160
                self.assertEqual(getter("test", value_2), value_1)
161
                deleter("test")
162
                self.assertNotIn("test", prf.parameters)
163

164

165
class TestDataPaths(unittest.TestCase):
166
    """Tests for the data paths"""
167

168
    def setUp(self) -> None:
169
        self.saved_freecad = None
170
        if "FreeCAD" in sys.modules:
171
            self.saved_freecad = sys.modules["FreeCAD"]
172
            sys.modules.pop("FreeCAD")
173
        if "addonmanager_freecad_interface" in sys.modules:
174
            sys.modules.pop("addonmanager_freecad_interface")
175
        sys.path.append("../../")
176

177
    def tearDown(self) -> None:
178
        if "FreeCAD" in sys.modules:
179
            sys.modules.pop("FreeCAD")
180
        if self.saved_freecad is not None:
181
            sys.modules["FreeCAD"] = self.saved_freecad
182

183
    def test_init_with_freecad(self):
184
        """Ensure that if FreeCAD exists, the appropriate functions are called"""
185
        sys.modules["FreeCAD"] = unittest.mock.MagicMock()
186
        import addonmanager_freecad_interface as fc
187

188
        data_paths = fc.DataPaths()
189
        self.assertTrue(sys.modules["FreeCAD"].getUserAppDataDir.called)
190
        self.assertTrue(sys.modules["FreeCAD"].getUserMacroDir.called)
191
        self.assertTrue(sys.modules["FreeCAD"].getUserCachePath.called)
192
        self.assertIsNotNone(data_paths.mod_dir)
193
        self.assertIsNotNone(data_paths.cache_dir)
194
        self.assertIsNotNone(data_paths.macro_dir)
195

196
    def test_init_without_freecad(self):
197
        """Ensure that if FreeCAD does not exist, the appropriate functions are called"""
198
        sys.modules["FreeCAD"] = None
199
        import addonmanager_freecad_interface as fc
200

201
        data_paths = fc.DataPaths()
202
        self.assertIsNotNone(data_paths.mod_dir)
203
        self.assertIsNotNone(data_paths.cache_dir)
204
        self.assertIsNotNone(data_paths.macro_dir)
205
        self.assertNotEqual(data_paths.mod_dir, data_paths.cache_dir)
206
        self.assertNotEqual(data_paths.mod_dir, data_paths.macro_dir)
207
        self.assertNotEqual(data_paths.cache_dir, data_paths.macro_dir)
208

209

210
class TestPreferences(unittest.TestCase):
211
    """Tests for the preferences wrapper"""
212

213
    def setUp(self) -> None:
214
        sys.path.append("../../")
215
        import addonmanager_freecad_interface as fc
216

217
        self.fc = fc
218

219
    def tearDown(self) -> None:
220
        pass
221

222
    def test_load_preferences_defaults(self):
223
        """Preferences are loaded from a given file"""
224
        defaults = self.given_defaults()
225
        with tempfile.TemporaryDirectory() as temp_dir:
226
            json_file = os.path.join(temp_dir, "defaults.json")
227
            with open(json_file, "w", encoding="utf-8") as f:
228
                f.write(json.dumps(defaults))
229
            self.fc.Preferences._load_preferences_defaults(json_file)
230
            self.assertDictEqual(defaults, self.fc.Preferences.preferences_defaults)
231

232
    def test_in_memory_defaults(self):
233
        """Preferences are loaded from memory"""
234
        defaults = self.given_defaults()
235
        prefs = self.fc.Preferences(defaults)
236
        self.assertDictEqual(defaults, prefs.preferences_defaults)
237

238
    def test_get_good(self):
239
        """Get returns results when matching an existing preference"""
240
        defaults = self.given_defaults()
241
        prefs = self.fc.Preferences(defaults)
242
        self.assertEqual(prefs.get("TestBool"), defaults["TestBool"])
243
        self.assertEqual(prefs.get("TestInt"), defaults["TestInt"])
244
        self.assertEqual(prefs.get("TestFloat"), defaults["TestFloat"])
245
        self.assertEqual(prefs.get("TestString"), defaults["TestString"])
246

247
    def test_get_nonexistent(self):
248
        """Get raises an exception when asked for a non-existent preference"""
249
        defaults = self.given_defaults()
250
        prefs = self.fc.Preferences(defaults)
251
        with self.assertRaises(RuntimeError):
252
            prefs.get("No_such_thing")
253

254
    def test_get_bad_type(self):
255
        """Get raises an exception when getting an unsupported type"""
256
        defaults = self.given_defaults()
257
        defaults["TestArray"] = ["This", "Is", "Legal", "JSON"]
258
        prefs = self.fc.Preferences(defaults)
259
        with self.assertRaises(RuntimeError):
260
            prefs.get("TestArray")
261

262
    def test_set_good(self):
263
        """Set works when matching an existing preference"""
264
        defaults = self.given_defaults()
265
        prefs = self.fc.Preferences(defaults)
266
        prefs.set("TestBool", False)
267
        self.assertEqual(prefs.get("TestBool"), False)
268
        prefs.set("TestInt", 4321)
269
        self.assertEqual(prefs.get("TestInt"), 4321)
270
        prefs.set("TestFloat", 3.14159)
271
        self.assertEqual(prefs.get("TestFloat"), 3.14159)
272
        prefs.set("TestString", "Forty two")
273
        self.assertEqual(prefs.get("TestString"), "Forty two")
274

275
    def test_set_nonexistent(self):
276
        """Set raises an exception when asked for a non-existent preference"""
277
        defaults = self.given_defaults()
278
        prefs = self.fc.Preferences(defaults)
279
        with self.assertRaises(RuntimeError):
280
            prefs.get("No_such_thing")
281

282
    def test_set_bad_type(self):
283
        """Set raises an exception when setting an unsupported type"""
284
        defaults = self.given_defaults()
285
        defaults["TestArray"] = ["This", "Is", "Legal", "JSON"]
286
        prefs = self.fc.Preferences(defaults)
287
        with self.assertRaises(RuntimeError):
288
            prefs.get("TestArray")
289

290
    @staticmethod
291
    def given_defaults():
292
        """Get a dictionary of fake defaults for testing"""
293
        defaults = {
294
            "TestBool": True,
295
            "TestInt": 42,
296
            "TestFloat": 1.2,
297
            "TestString": "Test",
298
        }
299
        return defaults
300

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.