From 43360aace04f53bc58af552ecc3239b3cebf9396 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 31 May 2019 13:07:03 +0200 Subject: [PATCH 1/5] Add tests for ExportQualityProfile --- cura/Settings/CuraContainerRegistry.py | 12 +++--- tests/Settings/TestCuraContainerRegistry.py | 43 ++++++++++++++++++++- 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/cura/Settings/CuraContainerRegistry.py b/cura/Settings/CuraContainerRegistry.py index dd7ed625d6..483150a75c 100644 --- a/cura/Settings/CuraContainerRegistry.py +++ b/cura/Settings/CuraContainerRegistry.py @@ -103,13 +103,14 @@ class CuraContainerRegistry(ContainerRegistry): # \param instance_ids \type{list} the IDs of the profiles to export. # \param file_name \type{str} the full path and filename to export to. # \param file_type \type{str} the file type with the format " (*.)" - def exportQualityProfile(self, container_list, file_name, file_type): + # \return True if the export succeeded, false otherwise. + def exportQualityProfile(self, container_list, file_name, file_type) -> bool: # Parse the fileType to deduce what plugin can save the file format. # fileType has the format " (*.)" split = file_type.rfind(" (*.") # Find where the description ends and the extension starts. if split < 0: # Not found. Invalid format. Logger.log("e", "Invalid file format identifier %s", file_type) - return + return False description = file_type[:split] extension = file_type[split + 4:-1] # Leave out the " (*." and ")". if not file_name.endswith("." + extension): # Auto-fill the extension if the user did not provide any. @@ -121,7 +122,7 @@ class CuraContainerRegistry(ContainerRegistry): result = QMessageBox.question(None, catalog.i18nc("@title:window", "File Already Exists"), catalog.i18nc("@label Don't translate the XML tag !", "The file {0} already exists. Are you sure you want to overwrite it?").format(file_name)) if result == QMessageBox.No: - return + return False profile_writer = self._findProfileWriter(extension, description) try: @@ -132,17 +133,18 @@ class CuraContainerRegistry(ContainerRegistry): lifetime = 0, title = catalog.i18nc("@info:title", "Error")) m.show() - return + return False if not success: Logger.log("w", "Failed to export profile to %s: Writer plugin reported failure.", file_name) m = Message(catalog.i18nc("@info:status Don't translate the XML tag !", "Failed to export profile to {0}: Writer plugin reported failure.", file_name), lifetime = 0, title = catalog.i18nc("@info:title", "Error")) m.show() - return + return False m = Message(catalog.i18nc("@info:status Don't translate the XML tag !", "Exported profile to {0}", file_name), title = catalog.i18nc("@info:title", "Export succeeded")) m.show() + return True ## Gets the plugin object matching the criteria # \param extension diff --git a/tests/Settings/TestCuraContainerRegistry.py b/tests/Settings/TestCuraContainerRegistry.py index 1308e3d4df..4df096797c 100644 --- a/tests/Settings/TestCuraContainerRegistry.py +++ b/tests/Settings/TestCuraContainerRegistry.py @@ -159,6 +159,7 @@ test_loadMetaDataValidation_data = [ } ] + @pytest.mark.parametrize("parameters", test_loadMetaDataValidation_data) def test_loadMetadataValidation(container_registry, definition_container, parameters): from cura.CuraApplication import CuraApplication @@ -178,4 +179,44 @@ def test_loadMetadataValidation(container_registry, definition_container, parame assert parameters["id"] in container_registry.metadata assert container_registry.metadata[parameters["id"]] == parameters["metadata"] else: - assert parameters["id"] not in container_registry.metadata \ No newline at end of file + assert parameters["id"] not in container_registry.metadata + + +class TestExportQualityProfile: + # This class is just there to provide some grouping for the tests. + def test_exportQualityProfileInvalidFileType(self, container_registry): + # With an invalid file_type, we should get a false for success. + assert not container_registry.exportQualityProfile([], "zomg", "invalid") + + + def test_exportQualityProfileFailedWriter(self, container_registry): + # Create a writer that always fails. + mocked_writer = unittest.mock.MagicMock(name = "mocked_writer") + mocked_writer.write = unittest.mock.MagicMock(return_value = False) + container_registry._findProfileWriter = unittest.mock.MagicMock("findProfileWriter", return_value = mocked_writer) + + # Ensure that it actually fails if the writer did. + with unittest.mock.patch("UM.Application.Application.getInstance"): + assert not container_registry.exportQualityProfile([], "zomg", "test files (*.tst)") + + + def test_exportQualityProfileExceptionWriter(self, container_registry): + # Create a writer that always fails. + mocked_writer = unittest.mock.MagicMock(name = "mocked_writer") + mocked_writer.write = unittest.mock.MagicMock(return_value = True, side_effect = Exception("Failed :(")) + container_registry._findProfileWriter = unittest.mock.MagicMock("findProfileWriter", return_value = mocked_writer) + + # Ensure that it actually fails if the writer did. + with unittest.mock.patch("UM.Application.Application.getInstance"): + assert not container_registry.exportQualityProfile([], "zomg", "test files (*.tst)") + + + def test_exportQualityProfileSuccessWriter(self, container_registry): + # Create a writer that always fails. + mocked_writer = unittest.mock.MagicMock(name="mocked_writer") + mocked_writer.write = unittest.mock.MagicMock(return_value=True) + container_registry._findProfileWriter = unittest.mock.MagicMock("findProfileWriter", return_value=mocked_writer) + + # Ensure that it actually fails if the writer did. + with unittest.mock.patch("UM.Application.Application.getInstance"): + assert container_registry.exportQualityProfile([], "zomg", "test files (*.tst)") \ No newline at end of file From 1d4fe56a21926cb8f010cd2b53364024b156d743 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 31 May 2019 13:18:14 +0200 Subject: [PATCH 2/5] Add tests for _findProfileWriter --- tests/Settings/TestCuraContainerRegistry.py | 25 +++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/tests/Settings/TestCuraContainerRegistry.py b/tests/Settings/TestCuraContainerRegistry.py index 4df096797c..2c4816afed 100644 --- a/tests/Settings/TestCuraContainerRegistry.py +++ b/tests/Settings/TestCuraContainerRegistry.py @@ -188,7 +188,6 @@ class TestExportQualityProfile: # With an invalid file_type, we should get a false for success. assert not container_registry.exportQualityProfile([], "zomg", "invalid") - def test_exportQualityProfileFailedWriter(self, container_registry): # Create a writer that always fails. mocked_writer = unittest.mock.MagicMock(name = "mocked_writer") @@ -199,7 +198,6 @@ class TestExportQualityProfile: with unittest.mock.patch("UM.Application.Application.getInstance"): assert not container_registry.exportQualityProfile([], "zomg", "test files (*.tst)") - def test_exportQualityProfileExceptionWriter(self, container_registry): # Create a writer that always fails. mocked_writer = unittest.mock.MagicMock(name = "mocked_writer") @@ -210,7 +208,6 @@ class TestExportQualityProfile: with unittest.mock.patch("UM.Application.Application.getInstance"): assert not container_registry.exportQualityProfile([], "zomg", "test files (*.tst)") - def test_exportQualityProfileSuccessWriter(self, container_registry): # Create a writer that always fails. mocked_writer = unittest.mock.MagicMock(name="mocked_writer") @@ -219,4 +216,24 @@ class TestExportQualityProfile: # Ensure that it actually fails if the writer did. with unittest.mock.patch("UM.Application.Application.getInstance"): - assert container_registry.exportQualityProfile([], "zomg", "test files (*.tst)") \ No newline at end of file + assert container_registry.exportQualityProfile([], "zomg", "test files (*.tst)") + + +def test__findProfileWriterNoPlugins(container_registry): + # Mock it so that no IO plugins are found. + container_registry._getIOPlugins = unittest.mock.MagicMock(return_value = []) + mocked_plugin_registry = unittest.mock.MagicMock(name = "plugin registry") + + with unittest.mock.patch("UM.PluginRegistry.PluginRegistry.getInstance", mocked_plugin_registry): + # Since there are no writers, don't return any + assert container_registry._findProfileWriter(".zomg", "dunno") is None + + +def test__findProfileWriter(container_registry): + # Mock it so that no IO plugins are found. + container_registry._getIOPlugins = unittest.mock.MagicMock(return_value = [("writer_id", {"profile_writer": [{"extension": ".zomg", "description": "dunno"}]})]) + mocked_plugin_registry = unittest.mock.MagicMock(name = "plugin registry") + + with unittest.mock.patch("UM.PluginRegistry.PluginRegistry.getInstance", mocked_plugin_registry): + # In this case it's getting a mocked object (from the mocked_plugin_registry) + assert container_registry._findProfileWriter(".zomg", "dunno") is not None From 14d5fa55294c805f722c04f9ace5af8462e29431 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 31 May 2019 13:59:54 +0200 Subject: [PATCH 3/5] Add a bunch of tests for importing profiles --- cura/Settings/CuraContainerRegistry.py | 6 +- tests/Settings/TestCuraContainerRegistry.py | 71 +++++++++++++++++++-- 2 files changed, 70 insertions(+), 7 deletions(-) diff --git a/cura/Settings/CuraContainerRegistry.py b/cura/Settings/CuraContainerRegistry.py index 483150a75c..6e354a4c79 100644 --- a/cura/Settings/CuraContainerRegistry.py +++ b/cura/Settings/CuraContainerRegistry.py @@ -171,9 +171,6 @@ class CuraContainerRegistry(ContainerRegistry): if not file_name: return { "status": "error", "message": catalog.i18nc("@info:status Don't translate the XML tags !", "Failed to import profile from {0}: {1}", file_name, "Invalid path")} - plugin_registry = PluginRegistry.getInstance() - extension = file_name.split(".")[-1] - global_stack = Application.getInstance().getGlobalContainerStack() if not global_stack: return {"status": "error", "message": catalog.i18nc("@info:status Don't translate the XML tags !", "Can't import profile from {0} before a printer is added.", file_name)} @@ -182,6 +179,9 @@ class CuraContainerRegistry(ContainerRegistry): for position in sorted(global_stack.extruders): machine_extruders.append(global_stack.extruders[position]) + plugin_registry = PluginRegistry.getInstance() + extension = file_name.split(".")[-1] + for plugin_id, meta_data in self._getIOPlugins("profile_reader"): if meta_data["profile_reader"][0]["extension"] != extension: continue diff --git a/tests/Settings/TestCuraContainerRegistry.py b/tests/Settings/TestCuraContainerRegistry.py index 2c4816afed..06f3f581ba 100644 --- a/tests/Settings/TestCuraContainerRegistry.py +++ b/tests/Settings/TestCuraContainerRegistry.py @@ -6,6 +6,7 @@ import pytest #To parameterize tests. import unittest.mock #To mock and monkeypatch stuff. from UM.Settings.DefinitionContainer import DefinitionContainer +from cura.ReaderWriters.ProfileReader import NoProfileException from cura.Settings.ExtruderStack import ExtruderStack #Testing for returning the correct types of stacks. from cura.Settings.GlobalStack import GlobalStack #Testing for returning the correct types of stacks. import UM.Settings.InstanceContainer #Creating instance containers to register. @@ -222,9 +223,8 @@ class TestExportQualityProfile: def test__findProfileWriterNoPlugins(container_registry): # Mock it so that no IO plugins are found. container_registry._getIOPlugins = unittest.mock.MagicMock(return_value = []) - mocked_plugin_registry = unittest.mock.MagicMock(name = "plugin registry") - with unittest.mock.patch("UM.PluginRegistry.PluginRegistry.getInstance", mocked_plugin_registry): + with unittest.mock.patch("UM.PluginRegistry.PluginRegistry.getInstance"): # Since there are no writers, don't return any assert container_registry._findProfileWriter(".zomg", "dunno") is None @@ -232,8 +232,71 @@ def test__findProfileWriterNoPlugins(container_registry): def test__findProfileWriter(container_registry): # Mock it so that no IO plugins are found. container_registry._getIOPlugins = unittest.mock.MagicMock(return_value = [("writer_id", {"profile_writer": [{"extension": ".zomg", "description": "dunno"}]})]) - mocked_plugin_registry = unittest.mock.MagicMock(name = "plugin registry") - with unittest.mock.patch("UM.PluginRegistry.PluginRegistry.getInstance", mocked_plugin_registry): + with unittest.mock.patch("UM.PluginRegistry.PluginRegistry.getInstance"): # In this case it's getting a mocked object (from the mocked_plugin_registry) assert container_registry._findProfileWriter(".zomg", "dunno") is not None + + +def test_importProfileEmptyFileName(container_registry): + result = container_registry.importProfile("") + assert result["status"] == "error" + + +mocked_application = unittest.mock.MagicMock(name = "application") +mocked_plugin_registry = unittest.mock.MagicMock(name="mocked_plugin_registry") + +@unittest.mock.patch("UM.Application.Application.getInstance", unittest.mock.MagicMock(return_value = mocked_application)) +@unittest.mock.patch("UM.PluginRegistry.PluginRegistry.getInstance", unittest.mock.MagicMock(return_value = mocked_plugin_registry)) +class TestImportProfile: + mocked_global_stack = unittest.mock.MagicMock(name="global stack") + mocked_global_stack.extruders = {0: unittest.mock.MagicMock(name="extruder stack")} + mocked_global_stack.getId = unittest.mock.MagicMock(return_value="blarg") + mocked_profile_reader = unittest.mock.MagicMock() + + mocked_plugin_registry.getPluginObject = unittest.mock.MagicMock(return_value=mocked_profile_reader) + + def test_importProfileWithoutGlobalStack(self, container_registry): + mocked_application.getGlobalContainerStack = unittest.mock.MagicMock(return_value = None) + result = container_registry.importProfile("non_empty") + assert result["status"] == "error" + + def test_importProfileNoProfileException(self, container_registry): + container_registry._getIOPlugins = unittest.mock.MagicMock(return_value=[("reader_id", {"profile_reader": [{"extension": "zomg", "description": "dunno"}]})]) + mocked_application.getGlobalContainerStack = unittest.mock.MagicMock(return_value=self.mocked_global_stack) + self.mocked_profile_reader.read = unittest.mock.MagicMock(side_effect = NoProfileException) + result = container_registry.importProfile("test.zomg") + # It's not an error, but we also didn't find any profile to read. + assert result["status"] == "ok" + + def test_importProfileGenericException(self, container_registry): + container_registry._getIOPlugins = unittest.mock.MagicMock(return_value=[("reader_id", {"profile_reader": [{"extension": "zomg", "description": "dunno"}]})]) + mocked_application.getGlobalContainerStack = unittest.mock.MagicMock(return_value=self.mocked_global_stack) + self.mocked_profile_reader.read = unittest.mock.MagicMock(side_effect = Exception) + result = container_registry.importProfile("test.zomg") + assert result["status"] == "error" + + def test_importProfileNoDefinitionFound(self, container_registry): + container_registry._getIOPlugins = unittest.mock.MagicMock(return_value=[("reader_id", {"profile_reader": [{"extension": "zomg", "description": "dunno"}]})]) + mocked_application.getGlobalContainerStack = unittest.mock.MagicMock(return_value=self.mocked_global_stack) + container_registry.findDefinitionContainers = unittest.mock.MagicMock(return_value = []) + mocked_profile = unittest.mock.MagicMock(name = "Mocked_global_profile") + self.mocked_profile_reader.read = unittest.mock.MagicMock(return_value = [mocked_profile]) + + result = container_registry.importProfile("test.zomg") + assert result["status"] == "error" + + def test_importProfileSuccess(self, container_registry): + container_registry._getIOPlugins = unittest.mock.MagicMock(return_value=[("reader_id", {"profile_reader": [{"extension": "zomg", "description": "dunno"}]})]) + mocked_application.getGlobalContainerStack = unittest.mock.MagicMock(return_value=self.mocked_global_stack) + + mocked_definition = unittest.mock.MagicMock(name = "definition") + + container_registry.findDefinitionContainers = unittest.mock.MagicMock(return_value = [mocked_definition]) + mocked_profile = unittest.mock.MagicMock(name = "Mocked_global_profile") + + self.mocked_profile_reader.read = unittest.mock.MagicMock(return_value = [mocked_profile]) + with unittest.mock.patch.object(container_registry, "createUniqueName", return_value="derp"): + with unittest.mock.patch.object(container_registry, "_configureProfile", return_value=None): + result = container_registry.importProfile("test.zomg") + assert result["status"] == "ok" \ No newline at end of file From 92dc99a4d50aee67395ca8fe10172cbc4bea6fe2 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 31 May 2019 14:54:34 +0200 Subject: [PATCH 4/5] Add a number of tests for settingInheritanceManager --- .../Settings/TestSettingInheritanceManager.py | 137 ++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 tests/Settings/TestSettingInheritanceManager.py diff --git a/tests/Settings/TestSettingInheritanceManager.py b/tests/Settings/TestSettingInheritanceManager.py new file mode 100644 index 0000000000..3589d8b91f --- /dev/null +++ b/tests/Settings/TestSettingInheritanceManager.py @@ -0,0 +1,137 @@ +from unittest.mock import patch, MagicMock + +import pytest + +from UM.Settings.SettingFunction import SettingFunction +from UM.Settings.SettingInstance import InstanceState +from cura.Settings.SettingInheritanceManager import SettingInheritanceManager + +setting_function = SettingFunction("") +setting_function.getUsedSettingKeys = MagicMock(return_value = ["omg", "zomg"]) + +setting_property_dict = {"setting_1": {}, + "setting_2": {"state": InstanceState.User, "enabled": False}, + "setting_3": {"state": InstanceState.User, "enabled": True}, + "setting_4": {"state": InstanceState.User, "enabled": True, "value": 12}, + "setting_5": {"state": InstanceState.User, "enabled": True, "value": setting_function}} + + +def getPropertySideEffect(*args, **kwargs): + properties = setting_property_dict.get(args[0]) + if properties: + return properties.get(args[1]) + + +@pytest.fixture +def setting_inheritance_manager(): + with patch("UM.Application.Application.getInstance"): + with patch("cura.Settings.ExtruderManager.ExtruderManager.getInstance"): + return SettingInheritanceManager() + +@pytest.fixture +def mocked_stack(): + mocked_stack = MagicMock() + mocked_stack.getProperty = MagicMock(side_effect=getPropertySideEffect) + mocked_stack.getNextStack = MagicMock(return_value = None) + mocked_stack.getAllKeys = MagicMock(return_value = ["omg", "zomg", "blarg"]) + return mocked_stack + +def test_getChildrenKeysWithOverrideNoGlobalStack(setting_inheritance_manager): + setting_inheritance_manager._global_container_stack = None + assert setting_inheritance_manager.getChildrenKeysWithOverride("derp") == [] + + +def test_getChildrenKeysWithOverrideEmptyDefinitions(setting_inheritance_manager): + mocked_global_container = MagicMock() + mocked_global_container.definition.findDefinitions = MagicMock(return_value = []) + setting_inheritance_manager._global_container_stack = mocked_global_container + assert setting_inheritance_manager.getChildrenKeysWithOverride("derp") == [] + + +def test_getChildrenKeysWithOverride(setting_inheritance_manager): + mocked_global_container = MagicMock() + mocked_definition = MagicMock() + mocked_definition.getAllKeys = MagicMock(return_value = ["omg", "zomg", "blarg"]) + mocked_global_container.definition.findDefinitions = MagicMock(return_value=[mocked_definition]) + setting_inheritance_manager._global_container_stack = mocked_global_container + + setting_inheritance_manager._settings_with_inheritance_warning = ["omg", "zomg"] + + assert setting_inheritance_manager.getChildrenKeysWithOverride("derp") == ["omg", "zomg"] + + +def test_manualRemoveOverrideWrongSetting(setting_inheritance_manager): + setting_inheritance_manager._settings_with_inheritance_warning = ["omg", "zomg"] + assert setting_inheritance_manager.settingsWithInheritanceWarning == ["omg", "zomg"] + + # Shouldn't do anything + setting_inheritance_manager.manualRemoveOverride("BLARG") + assert setting_inheritance_manager.settingsWithInheritanceWarning == ["omg", "zomg"] + + +def test_manualRemoveOverrideExistingSetting(setting_inheritance_manager): + setting_inheritance_manager._settings_with_inheritance_warning = ["omg", "zomg"] + assert setting_inheritance_manager.settingsWithInheritanceWarning == ["omg", "zomg"] + + # Shouldn't do anything + setting_inheritance_manager.manualRemoveOverride("omg") + assert setting_inheritance_manager.settingsWithInheritanceWarning == ["zomg"] + + +def test_getOverridesForExtruderNoGlobalStack(setting_inheritance_manager): + setting_inheritance_manager._global_container_stack = None + assert setting_inheritance_manager.getOverridesForExtruder("derp", 0) == [] + + +def test_settingIsOverwritingInheritanceNoUserState(setting_inheritance_manager, mocked_stack): + # Setting 1 doesn't have a user state, so it cant have an override + assert not setting_inheritance_manager._settingIsOverwritingInheritance("setting_1", mocked_stack) + + +def test_settingIsOverwritingInheritanceNotEnabled(setting_inheritance_manager, mocked_stack): + # Setting 2 doesn't have a enabled, so it cant have an override + assert not setting_inheritance_manager._settingIsOverwritingInheritance("setting_2", mocked_stack) + + +def test_settingIsOverwritingInheritanceNoContainers(setting_inheritance_manager, mocked_stack): + mocked_stack.getContainers = MagicMock(return_value = []) + # All the properties are correct, but there are no containers :( + assert not setting_inheritance_manager._settingIsOverwritingInheritance("setting_3", mocked_stack) + + +def test_settingIsOverwritingInheritanceNoneValue(setting_inheritance_manager, mocked_stack): + mocked_container = MagicMock() + mocked_container.getProperty = MagicMock(side_effect=getPropertySideEffect) + mocked_stack.getContainers = MagicMock(return_value = [mocked_container]) + + # Setting 3 doesn't have a value, so even though the container is there, it's value is None + assert not setting_inheritance_manager._settingIsOverwritingInheritance("setting_3", mocked_stack) + + +def test_settingIsOverwritingInheritanceNoSettingFunction(setting_inheritance_manager, mocked_stack): + mocked_container = MagicMock() + mocked_container.getProperty = MagicMock(side_effect=getPropertySideEffect) + mocked_stack.getContainers = MagicMock(return_value=[mocked_container]) + + # Setting 4 does have a value, but it's not a settingFunction + assert not setting_inheritance_manager._settingIsOverwritingInheritance("setting_4", mocked_stack) + + +def test_settingIsOverwritingInheritanceSingleSettingFunction(setting_inheritance_manager, mocked_stack): + mocked_container = MagicMock() + mocked_container.getProperty = MagicMock(side_effect=getPropertySideEffect) + mocked_stack.getContainers = MagicMock(return_value=[mocked_container]) + setting_inheritance_manager._active_container_stack = mocked_stack + # Setting 5 does have a value, but we only have one container filled + assert not setting_inheritance_manager._settingIsOverwritingInheritance("setting_5", mocked_stack) + + +def test_settingIsOverwritingInheritance(setting_inheritance_manager, mocked_stack): + mocked_container = MagicMock() + mocked_second_container = MagicMock() + mocked_second_container.getProperty = MagicMock(return_value = 12) + mocked_container.getProperty = MagicMock(side_effect=getPropertySideEffect) + mocked_stack.getContainers = MagicMock(return_value=[mocked_second_container, mocked_container]) + setting_inheritance_manager._active_container_stack = mocked_stack + + assert setting_inheritance_manager._settingIsOverwritingInheritance("setting_5", mocked_stack) \ No newline at end of file From 475b91d0d107950f82a9f7a95bfc5e95df3cbd9f Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 31 May 2019 15:28:58 +0200 Subject: [PATCH 5/5] Add tests for CuraSceneController --- tests/TestCuraSceneController.py | 79 ++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 tests/TestCuraSceneController.py diff --git a/tests/TestCuraSceneController.py b/tests/TestCuraSceneController.py new file mode 100644 index 0000000000..ffffa8ac2a --- /dev/null +++ b/tests/TestCuraSceneController.py @@ -0,0 +1,79 @@ +from unittest.mock import MagicMock, patch + +import pytest + +from UM.Scene.SceneNode import SceneNode +from cura.Machines.Models.MultiBuildPlateModel import MultiBuildPlateModel +from cura.Scene.CuraSceneController import CuraSceneController +from cura.UI.ObjectsModel import ObjectsModel + + +@pytest.fixture +def objects_model() -> ObjectsModel: + return MagicMock(spec=ObjectsModel) + +@pytest.fixture +def multi_build_plate_model() -> MultiBuildPlateModel: + return MagicMock(spec=MultiBuildPlateModel) + +@pytest.fixture +def mocked_application(): + mocked_application = MagicMock() + mocked_controller = MagicMock() + mocked_scene = MagicMock() + mocked_application.getController = MagicMock(return_value=mocked_controller) + mocked_controller.getScene = MagicMock(return_value=mocked_scene) + return mocked_application + + +def test_setActiveBuildPlate(objects_model, multi_build_plate_model): + with patch("UM.Application.Application.getInstance"): + controller = CuraSceneController(objects_model, multi_build_plate_model) + controller.setActiveBuildPlate(12) + multi_build_plate_model.setActiveBuildPlate.assert_called_once_with(12) + objects_model.setActiveBuildPlate.assert_called_once_with(12) + + # Doing it again shouldn't cause another change to be passed along + controller.setActiveBuildPlate(12) + multi_build_plate_model.setActiveBuildPlate.assert_called_once_with(12) + objects_model.setActiveBuildPlate.assert_called_once_with(12) + + +def test_calcMaxBuildPlateEmptyScene(objects_model, multi_build_plate_model, mocked_application): + mocked_root = MagicMock() + mocked_root.callDecoration = MagicMock(return_value=0) + mocked_application.getController().getScene().getRoot = MagicMock(return_value=mocked_root) + with patch("UM.Application.Application.getInstance", MagicMock(return_value=mocked_application)): + controller = CuraSceneController(objects_model, multi_build_plate_model) + assert controller._calcMaxBuildPlate() == 0 + + +def test_calcMaxBuildPlateFilledScene(objects_model, multi_build_plate_model, mocked_application): + mocked_root = MagicMock() + mocked_root.callDecoration = MagicMock(return_value = 0) + mocked_child = MagicMock() + mocked_child.callDecoration = MagicMock(return_value = 2) + mocked_root.getAllChildren = MagicMock(return_value = [mocked_child]) + mocked_application.getController().getScene().getRoot = MagicMock(return_value=mocked_root) + with patch("UM.Application.Application.getInstance", MagicMock(return_value=mocked_application)): + controller = CuraSceneController(objects_model, multi_build_plate_model) + assert controller._calcMaxBuildPlate() == 2 + + +def test_updateMaxBuildPlate(objects_model, multi_build_plate_model): + with patch("UM.Application.Application.getInstance"): + controller = CuraSceneController(objects_model, multi_build_plate_model) + controller._calcMaxBuildPlate = MagicMock(return_value = 12) + controller.updateMaxBuildPlate(SceneNode()) + + # Check if that went well. + multi_build_plate_model.setMaxBuildPlate.assert_called_once_with(12) + + # Move to a different active build plate + controller.setActiveBuildPlate(5) + + # And check what happens if we move down again! + controller._calcMaxBuildPlate = MagicMock(return_value=2) + controller.updateMaxBuildPlate(SceneNode()) + assert controller._active_build_plate == 0 # We don't have any items anywere, so default to 0 +