TestGlobalStack.py 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638
  1. # Copyright (c) 2017 Ultimaker B.V.
  2. # Cura is released under the terms of the AGPLv3 or higher.
  3. import os.path #To find the test files.
  4. import pytest #This module contains unit tests.
  5. import unittest.mock #To monkeypatch some mocks in place of dependencies.
  6. import functools
  7. import cura.Settings.GlobalStack #The module we're testing.
  8. import cura.Settings.CuraContainerStack #To get the list of container types.
  9. from cura.Settings.Exceptions import TooManyExtrudersError, InvalidContainerError, InvalidOperationError #To test raising these errors.
  10. from UM.Settings.DefinitionContainer import DefinitionContainer #To test against the class DefinitionContainer.
  11. from UM.Settings.InstanceContainer import InstanceContainer #To test against the class InstanceContainer.
  12. import UM.Settings.ContainerRegistry
  13. import UM.Settings.ContainerStack
  14. class MockContainer:
  15. def __init__(self, container_id, type = "mock"):
  16. self._id = container_id
  17. self._type = type
  18. self._property_map = {}
  19. def getId(self):
  20. return self._id
  21. def getMetaDataEntry(self, entry, default = None):
  22. if entry == "type":
  23. return self._type
  24. return default
  25. def getProperty(self, key, property_name):
  26. if key not in self._property_map:
  27. return None
  28. if property_name not in self._property_map[key]:
  29. return None
  30. return self._property_map[key][property_name]
  31. def setProperty(self, key, property_name, value):
  32. if key not in self._property_map:
  33. self._property_map[key] = {}
  34. self._property_map[key][property_name] = value
  35. propertyChanged = unittest.mock.MagicMock()
  36. ## Fake container registry that always provides all containers you ask of.
  37. @pytest.yield_fixture()
  38. def container_registry():
  39. registry = unittest.mock.MagicMock()
  40. registry.typeMetaData = "registry_mock"
  41. def findInstanceContainers(registry, **kwargs):
  42. container_id = kwargs.get("id", "test_container")
  43. return [MockContainer(container_id, registry.typeMetaData)]
  44. registry.findInstanceContainers = functools.partial(findInstanceContainers, registry)
  45. def findContainers(registry, container_type = None, id = None):
  46. if not id:
  47. id = "test_container"
  48. return [MockContainer(id, registry.typeMetaData)]
  49. registry.findContainers = functools.partial(findContainers, registry)
  50. def getEmptyInstanceContainer():
  51. return MockContainer(container_id = "empty")
  52. registry.getEmptyInstanceContainer = getEmptyInstanceContainer
  53. UM.Settings.ContainerRegistry.ContainerRegistry._ContainerRegistry__instance = registry
  54. UM.Settings.ContainerStack._containerRegistry = registry
  55. yield registry
  56. UM.Settings.ContainerRegistry.ContainerRegistry._ContainerRegistry__instance = None
  57. UM.Settings.ContainerStack._containerRegistry = None
  58. #An empty global stack to test with.
  59. @pytest.fixture()
  60. def global_stack() -> cura.Settings.GlobalStack.GlobalStack:
  61. return cura.Settings.GlobalStack.GlobalStack("TestStack")
  62. @pytest.fixture()
  63. def writable_global_stack(global_stack):
  64. global_stack.userChanges = MockContainer("test_user_changes", "user")
  65. global_stack.qualityChanges = MockContainer("test_quality_changes", "quality_changes")
  66. global_stack.quality = MockContainer("test_quality", "quality")
  67. global_stack.material = MockContainer("test_material", "material")
  68. global_stack.variant = MockContainer("test_variant", "variant")
  69. global_stack.definitionChanges = MockContainer("test_definition_changes", "definition_changes")
  70. global_stack.definition = DefinitionContainerSubClass()
  71. return global_stack
  72. ## Place-in function for findContainer that finds only containers that start
  73. # with "some_".
  74. def findSomeContainers(container_id = "*", container_type = None, type = None, category = "*"):
  75. if container_id.startswith("some_"):
  76. return UM.Settings.ContainerRegistry._EmptyInstanceContainer(container_id)
  77. if container_type == DefinitionContainer:
  78. definition_mock = unittest.mock.MagicMock()
  79. definition_mock.getId = unittest.mock.MagicMock(return_value = "some_definition") #getId returns some_definition.
  80. return definition_mock
  81. ## Helper function to read the contents of a container stack in the test
  82. # stack folder.
  83. #
  84. # \param filename The name of the file in the "stacks" folder to read from.
  85. # \return The contents of that file.
  86. def readStack(filename):
  87. with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), "stacks", filename)) as file_handle:
  88. serialized = file_handle.read()
  89. return serialized
  90. ## Gets an instance container with a specified container type.
  91. #
  92. # \param container_type The type metadata for the instance container.
  93. # \return An instance container instance.
  94. def getInstanceContainer(container_type) -> InstanceContainer:
  95. container = InstanceContainer(container_id = "InstanceContainer")
  96. container.addMetaDataEntry("type", container_type)
  97. return container
  98. class DefinitionContainerSubClass(DefinitionContainer):
  99. def __init__(self):
  100. super().__init__(container_id = "SubDefinitionContainer")
  101. class InstanceContainerSubClass(InstanceContainer):
  102. def __init__(self, container_type):
  103. super().__init__(container_id = "SubInstanceContainer")
  104. self.addMetaDataEntry("type", container_type)
  105. #############################START OF TEST CASES################################
  106. ## Tests whether adding a container is properly forbidden.
  107. def test_addContainer(global_stack):
  108. with pytest.raises(InvalidOperationError):
  109. global_stack.addContainer(unittest.mock.MagicMock())
  110. ## Tests adding extruders to the global stack.
  111. def test_addExtruder(global_stack):
  112. mock_definition = unittest.mock.MagicMock()
  113. mock_definition.getProperty = lambda key, property: 2 if key == "machine_extruder_count" and property == "value" else None
  114. with unittest.mock.patch("cura.Settings.CuraContainerStack.DefinitionContainer", unittest.mock.MagicMock):
  115. global_stack.definition = mock_definition
  116. assert len(global_stack.extruders) == 0
  117. first_extruder = unittest.mock.MagicMock()
  118. with unittest.mock.patch("cura.Settings.CuraContainerStack.DefinitionContainer", unittest.mock.MagicMock):
  119. global_stack.addExtruder(first_extruder)
  120. assert len(global_stack.extruders) == 1
  121. assert global_stack.extruders[0] == first_extruder
  122. second_extruder = unittest.mock.MagicMock()
  123. with unittest.mock.patch("cura.Settings.CuraContainerStack.DefinitionContainer", unittest.mock.MagicMock):
  124. global_stack.addExtruder(second_extruder)
  125. assert len(global_stack.extruders) == 2
  126. assert global_stack.extruders[1] == second_extruder
  127. with unittest.mock.patch("cura.Settings.CuraContainerStack.DefinitionContainer", unittest.mock.MagicMock):
  128. with pytest.raises(TooManyExtrudersError): #Should be limited to 2 extruders because of machine_extruder_count.
  129. global_stack.addExtruder(unittest.mock.MagicMock())
  130. assert len(global_stack.extruders) == 2 #Didn't add the faulty extruder.
  131. #Tests setting user changes profiles to invalid containers.
  132. @pytest.mark.parametrize("container", [
  133. getInstanceContainer(container_type = "wrong container type"),
  134. getInstanceContainer(container_type = "material"), #Existing, but still wrong type.
  135. DefinitionContainer(container_id = "wrong class")
  136. ])
  137. def test_constrainUserChangesInvalid(container, global_stack):
  138. with pytest.raises(InvalidContainerError): #Invalid container, should raise an error.
  139. global_stack.userChanges = container
  140. #Tests setting user changes profiles.
  141. @pytest.mark.parametrize("container", [
  142. getInstanceContainer(container_type = "user"),
  143. InstanceContainerSubClass(container_type = "user")
  144. ])
  145. def test_constrainUserChangesValid(container, global_stack):
  146. global_stack.userChanges = container #Should not give an error.
  147. #Tests setting quality changes profiles to invalid containers.
  148. @pytest.mark.parametrize("container", [
  149. getInstanceContainer(container_type = "wrong container type"),
  150. getInstanceContainer(container_type = "material"), #Existing, but still wrong type.
  151. DefinitionContainer(container_id = "wrong class")
  152. ])
  153. def test_constrainQualityChangesInvalid(container, global_stack):
  154. with pytest.raises(InvalidContainerError): #Invalid container, should raise an error.
  155. global_stack.qualityChanges = container
  156. #Test setting quality changes profiles.
  157. @pytest.mark.parametrize("container", [
  158. getInstanceContainer(container_type = "quality_changes"),
  159. InstanceContainerSubClass(container_type = "quality_changes")
  160. ])
  161. def test_constrainQualityChangesValid(container, global_stack):
  162. global_stack.qualityChanges = container #Should not give an error.
  163. #Tests setting quality profiles to invalid containers.
  164. @pytest.mark.parametrize("container", [
  165. getInstanceContainer(container_type = "wrong container type"),
  166. getInstanceContainer(container_type = "material"), #Existing, but still wrong type.
  167. DefinitionContainer(container_id = "wrong class")
  168. ])
  169. def test_constrainQualityInvalid(container, global_stack):
  170. with pytest.raises(InvalidContainerError): #Invalid container, should raise an error.
  171. global_stack.quality = container
  172. #Test setting quality profiles.
  173. @pytest.mark.parametrize("container", [
  174. getInstanceContainer(container_type = "quality"),
  175. InstanceContainerSubClass(container_type = "quality")
  176. ])
  177. def test_constrainQualityValid(container, global_stack):
  178. global_stack.quality = container #Should not give an error.
  179. #Tests setting materials to invalid containers.
  180. @pytest.mark.parametrize("container", [
  181. getInstanceContainer(container_type = "wrong container type"),
  182. getInstanceContainer(container_type = "quality"), #Existing, but still wrong type.
  183. DefinitionContainer(container_id = "wrong class")
  184. ])
  185. def test_constrainMaterialInvalid(container, global_stack):
  186. with pytest.raises(InvalidContainerError): #Invalid container, should raise an error.
  187. global_stack.material = container
  188. #Test setting materials.
  189. @pytest.mark.parametrize("container", [
  190. getInstanceContainer(container_type = "material"),
  191. InstanceContainerSubClass(container_type = "material")
  192. ])
  193. def test_constrainMaterialValid(container, global_stack):
  194. global_stack.material = container #Should not give an error.
  195. #Tests setting variants to invalid containers.
  196. @pytest.mark.parametrize("container", [
  197. getInstanceContainer(container_type = "wrong container type"),
  198. getInstanceContainer(container_type = "material"), #Existing, but still wrong type.
  199. DefinitionContainer(container_id = "wrong class")
  200. ])
  201. def test_constrainVariantInvalid(container, global_stack):
  202. with pytest.raises(InvalidContainerError): #Invalid container, should raise an error.
  203. global_stack.variant = container
  204. #Test setting variants.
  205. @pytest.mark.parametrize("container", [
  206. getInstanceContainer(container_type = "variant"),
  207. InstanceContainerSubClass(container_type = "variant")
  208. ])
  209. def test_constrainVariantValid(container, global_stack):
  210. global_stack.variant = container #Should not give an error.
  211. #Tests setting definition changes profiles to invalid containers.
  212. @pytest.mark.parametrize("container", [
  213. getInstanceContainer(container_type = "wrong container type"),
  214. getInstanceContainer(container_type = "material"), #Existing, but still wrong type.
  215. DefinitionContainer(container_id = "wrong class")
  216. ])
  217. def test_constrainDefinitionChangesInvalid(container, global_stack):
  218. with pytest.raises(InvalidContainerError): #Invalid container, should raise an error.
  219. global_stack.definitionChanges = container
  220. #Test setting definition changes profiles.
  221. @pytest.mark.parametrize("container", [
  222. getInstanceContainer(container_type = "definition_changes"),
  223. InstanceContainerSubClass(container_type = "definition_changes")
  224. ])
  225. def test_constrainDefinitionChangesValid(container, global_stack):
  226. global_stack.definitionChanges = container #Should not give an error.
  227. #Tests setting definitions to invalid containers.
  228. @pytest.mark.parametrize("container", [
  229. getInstanceContainer(container_type = "wrong class"),
  230. getInstanceContainer(container_type = "material"), #Existing, but still wrong class.
  231. ])
  232. def test_constrainVariantInvalid(container, global_stack):
  233. with pytest.raises(InvalidContainerError): #Invalid container, should raise an error.
  234. global_stack.definition = container
  235. #Test setting definitions.
  236. @pytest.mark.parametrize("container", [
  237. DefinitionContainer(container_id = "DefinitionContainer"),
  238. DefinitionContainerSubClass()
  239. ])
  240. def test_constrainDefinitionValid(container, global_stack):
  241. global_stack.definition = container #Should not give an error.
  242. ## Tests whether deserialising completes the missing containers with empty
  243. # ones.
  244. @pytest.mark.skip #The test currently fails because the definition container doesn't have a category, which is wrong but we don't have time to refactor that right now.
  245. def test_deserializeCompletesEmptyContainers(global_stack: cura.Settings.GlobalStack):
  246. global_stack._containers = [DefinitionContainer(container_id = "definition")] #Set the internal state of this stack manually.
  247. with unittest.mock.patch("UM.Settings.ContainerStack.ContainerStack.deserialize", unittest.mock.MagicMock()): #Prevent calling super().deserialize.
  248. global_stack.deserialize("")
  249. assert len(global_stack.getContainers()) == len(cura.Settings.CuraContainerStack._ContainerIndexes.IndexTypeMap) #Needs a slot for every type.
  250. for container_type_index in cura.Settings.CuraContainerStack._ContainerIndexes.IndexTypeMap:
  251. if container_type_index == cura.Settings.CuraContainerStack._ContainerIndexes.Definition: #We're not checking the definition.
  252. continue
  253. assert global_stack.getContainer(container_type_index).getId() == "empty" #All others need to be empty.
  254. ## Tests whether an instance container with the wrong type gets removed when
  255. # deserialising.
  256. def test_deserializeRemovesWrongInstanceContainer(global_stack):
  257. global_stack._containers[cura.Settings.CuraContainerStack._ContainerIndexes.Quality] = getInstanceContainer(container_type = "wrong type")
  258. global_stack._containers[cura.Settings.CuraContainerStack._ContainerIndexes.Definition] = DefinitionContainer(container_id = "some definition")
  259. with unittest.mock.patch("UM.Settings.ContainerStack.ContainerStack.deserialize", unittest.mock.MagicMock()): #Prevent calling super().deserialize.
  260. global_stack.deserialize("")
  261. assert global_stack.quality == global_stack._empty_instance_container #Replaced with empty.
  262. ## Tests whether a container with the wrong class gets removed when
  263. # deserialising.
  264. def test_deserializeRemovesWrongContainerClass(global_stack):
  265. global_stack._containers[cura.Settings.CuraContainerStack._ContainerIndexes.Quality] = DefinitionContainer(container_id = "wrong class")
  266. global_stack._containers[cura.Settings.CuraContainerStack._ContainerIndexes.Definition] = DefinitionContainer(container_id = "some definition")
  267. with unittest.mock.patch("UM.Settings.ContainerStack.ContainerStack.deserialize", unittest.mock.MagicMock()): #Prevent calling super().deserialize.
  268. global_stack.deserialize("")
  269. assert global_stack.quality == global_stack._empty_instance_container #Replaced with empty.
  270. ## Tests whether an instance container in the definition spot results in an
  271. # error.
  272. def test_deserializeWrongDefinitionClass(global_stack):
  273. global_stack._containers[cura.Settings.CuraContainerStack._ContainerIndexes.Definition] = getInstanceContainer(container_type = "definition") #Correct type but wrong class.
  274. with unittest.mock.patch("UM.Settings.ContainerStack.ContainerStack.deserialize", unittest.mock.MagicMock()): #Prevent calling super().deserialize.
  275. with pytest.raises(UM.Settings.ContainerStack.InvalidContainerStackError): #Must raise an error that there is no definition container.
  276. global_stack.deserialize("")
  277. ## Tests whether an instance container with the wrong type is moved into the
  278. # correct slot by deserialising.
  279. def test_deserializeMoveInstanceContainer(global_stack):
  280. global_stack._containers[cura.Settings.CuraContainerStack._ContainerIndexes.Quality] = getInstanceContainer(container_type = "material") #Not in the correct spot.
  281. global_stack._containers[cura.Settings.CuraContainerStack._ContainerIndexes.Definition] = DefinitionContainer(container_id = "some definition")
  282. with unittest.mock.patch("UM.Settings.ContainerStack.ContainerStack.deserialize", unittest.mock.MagicMock()): #Prevent calling super().deserialize.
  283. global_stack.deserialize("")
  284. assert global_stack.quality.getId() == "empty"
  285. assert global_stack.material.getId() != "empty"
  286. ## Tests whether a definition container in the wrong spot is moved into the
  287. # correct spot by deserialising.
  288. @pytest.mark.skip
  289. def test_deserializeMoveDefinitionContainer(global_stack):
  290. global_stack._containers[cura.Settings.CuraContainerStack._ContainerIndexes.Material] = DefinitionContainer(container_id = "some definition") #Not in the correct spot.
  291. with unittest.mock.patch("UM.Settings.ContainerStack.ContainerStack.deserialize", unittest.mock.MagicMock()): #Prevent calling super().deserialize.
  292. global_stack.deserialize("")
  293. assert global_stack.material.getId() == "empty"
  294. assert global_stack.definition.getId() != "empty"
  295. UM.Settings.ContainerStack._containerRegistry = None
  296. ## Tests whether getProperty properly applies the stack-like behaviour on its
  297. # containers.
  298. def test_getPropertyFallThrough(global_stack):
  299. #A few instance container mocks to put in the stack.
  300. mock_layer_heights = {} #For each container type, a mock container that defines layer height to something unique.
  301. mock_no_settings = {} #For each container type, a mock container that has no settings at all.
  302. container_indexes = cura.Settings.CuraContainerStack._ContainerIndexes #Cache.
  303. for type_id, type_name in container_indexes.IndexTypeMap.items():
  304. container = unittest.mock.MagicMock()
  305. container.getProperty = lambda key, property, type_id = type_id: type_id if (key == "layer_height" and property == "value") else None #Returns the container type ID as layer height, in order to identify it.
  306. container.hasProperty = lambda key, property: key == "layer_height"
  307. container.getMetaDataEntry = unittest.mock.MagicMock(return_value = type_name)
  308. mock_layer_heights[type_id] = container
  309. container = unittest.mock.MagicMock()
  310. container.getProperty = unittest.mock.MagicMock(return_value = None) #Has no settings at all.
  311. container.hasProperty = unittest.mock.MagicMock(return_value = False)
  312. container.getMetaDataEntry = unittest.mock.MagicMock(return_value = type_name)
  313. mock_no_settings[type_id] = container
  314. global_stack.userChanges = mock_no_settings[container_indexes.UserChanges]
  315. global_stack.qualityChanges = mock_no_settings[container_indexes.QualityChanges]
  316. global_stack.quality = mock_no_settings[container_indexes.Quality]
  317. global_stack.material = mock_no_settings[container_indexes.Material]
  318. global_stack.variant = mock_no_settings[container_indexes.Variant]
  319. global_stack.definitionChanges = mock_no_settings[container_indexes.DefinitionChanges]
  320. with unittest.mock.patch("cura.Settings.CuraContainerStack.DefinitionContainer", unittest.mock.MagicMock): #To guard against the type checking.
  321. global_stack.definition = mock_layer_heights[container_indexes.Definition] #There's a layer height in here!
  322. assert global_stack.getProperty("layer_height", "value") == container_indexes.Definition
  323. global_stack.definitionChanges = mock_layer_heights[container_indexes.DefinitionChanges]
  324. assert global_stack.getProperty("layer_height", "value") == container_indexes.DefinitionChanges
  325. global_stack.variant = mock_layer_heights[container_indexes.Variant]
  326. assert global_stack.getProperty("layer_height", "value") == container_indexes.Variant
  327. global_stack.material = mock_layer_heights[container_indexes.Material]
  328. assert global_stack.getProperty("layer_height", "value") == container_indexes.Material
  329. global_stack.quality = mock_layer_heights[container_indexes.Quality]
  330. assert global_stack.getProperty("layer_height", "value") == container_indexes.Quality
  331. global_stack.qualityChanges = mock_layer_heights[container_indexes.QualityChanges]
  332. assert global_stack.getProperty("layer_height", "value") == container_indexes.QualityChanges
  333. global_stack.userChanges = mock_layer_heights[container_indexes.UserChanges]
  334. assert global_stack.getProperty("layer_height", "value") == container_indexes.UserChanges
  335. ## In definitions, test whether having no resolve allows us to find the value.
  336. def test_getPropertyNoResolveInDefinition(global_stack):
  337. value = unittest.mock.MagicMock() #Just sets the value for bed temperature.
  338. value.getProperty = lambda key, property: 10 if (key == "material_bed_temperature" and property == "value") else None
  339. with unittest.mock.patch("cura.Settings.CuraContainerStack.DefinitionContainer", unittest.mock.MagicMock): #To guard against the type checking.
  340. global_stack.definition = value
  341. assert global_stack.getProperty("material_bed_temperature", "value") == 10 #No resolve, so fall through to value.
  342. ## In definitions, when the value is asked and there is a resolve function, it
  343. # must get the resolve first.
  344. def test_getPropertyResolveInDefinition(global_stack):
  345. resolve_and_value = unittest.mock.MagicMock() #Sets the resolve and value for bed temperature.
  346. resolve_and_value.getProperty = lambda key, property: (7.5 if property == "resolve" else 5) if (key == "material_bed_temperature") else None #7.5 resolve, 5 value.
  347. with unittest.mock.patch("cura.Settings.CuraContainerStack.DefinitionContainer", unittest.mock.MagicMock): #To guard against the type checking.
  348. global_stack.definition = resolve_and_value
  349. assert global_stack.getProperty("material_bed_temperature", "value") == 7.5 #Resolve wins in the definition.
  350. ## In instance containers, when the value is asked and there is a resolve
  351. # function, it must get the value first.
  352. def test_getPropertyResolveInInstance(global_stack):
  353. container_indices = cura.Settings.CuraContainerStack._ContainerIndexes
  354. instance_containers = {}
  355. for container_type in container_indices.IndexTypeMap:
  356. instance_containers[container_type] = unittest.mock.MagicMock() #Sets the resolve and value for bed temperature.
  357. instance_containers[container_type].getProperty = lambda key, property: (7.5 if property == "resolve" else 5) if (key == "material_bed_temperature") else None #7.5 resolve, 5 value.
  358. instance_containers[container_type].getMetaDataEntry = unittest.mock.MagicMock(return_value = container_indices.IndexTypeMap[container_type]) #Make queries for the type return the desired type.
  359. instance_containers[container_indices.Definition].getProperty = lambda key, property: 10 if (key == "material_bed_temperature" and property == "value") else None #Definition only has value.
  360. with unittest.mock.patch("cura.Settings.CuraContainerStack.DefinitionContainer", unittest.mock.MagicMock): #To guard against the type checking.
  361. global_stack.definition = instance_containers[container_indices.Definition] #Stack must have a definition.
  362. #For all instance container slots, the value reigns over resolve.
  363. global_stack.definitionChanges = instance_containers[container_indices.DefinitionChanges]
  364. assert global_stack.getProperty("material_bed_temperature", "value") == 5
  365. global_stack.variant = instance_containers[container_indices.Variant]
  366. assert global_stack.getProperty("material_bed_temperature", "value") == 5
  367. global_stack.material = instance_containers[container_indices.Material]
  368. assert global_stack.getProperty("material_bed_temperature", "value") == 5
  369. global_stack.quality = instance_containers[container_indices.Quality]
  370. assert global_stack.getProperty("material_bed_temperature", "value") == 5
  371. global_stack.qualityChanges = instance_containers[container_indices.QualityChanges]
  372. assert global_stack.getProperty("material_bed_temperature", "value") == 5
  373. global_stack.userChanges = instance_containers[container_indices.UserChanges]
  374. assert global_stack.getProperty("material_bed_temperature", "value") == 5
  375. ## Tests whether the resolve property is properly obtained in all cases.
  376. @pytest.mark.skip
  377. def test_getPropertyWithResolve(global_stack):
  378. #Define some containers for the stack.
  379. resolve = unittest.mock.MagicMock() #Sets just the resolve for bed temperature.
  380. resolve.getProperty = lambda key, property: 15 if (key == "material_bed_temperature" and property == "resolve") else None
  381. resolve_and_value = unittest.mock.MagicMock() #Sets the resolve and value for bed temperature.
  382. resolve_and_value.getProperty = lambda key, property: (7.5 if property == "resolve" else 5) if (key == "material_bed_temperature") else None #7.5 resolve, 5 value.
  383. value = unittest.mock.MagicMock() #Sets just the value for bed temperature.
  384. value.getProperty = lambda key, property: 10 if (key == "material_bed_temperature" and property == "value") else None
  385. empty = unittest.mock.MagicMock() #Sets no value or resolve.
  386. empty.getProperty = unittest.mock.MagicMock(return_value = None)
  387. with unittest.mock.patch("cura.Settings.CuraContainerStack.DefinitionContainer", unittest.mock.MagicMock): #To guard against the type checking.
  388. global_stack.definition = resolve_and_value
  389. assert global_stack.getProperty("material_bed_temperature", "value") == 7.5 #Resolve wins in the definition.
  390. global_stack.userChanges = resolve_and_value
  391. assert global_stack.getProperty("material_bed_temperature", "value") == 5 #Value wins in other places.
  392. global_stack.userChanges = value
  393. assert global_stack.getProperty("material_bed_temperature", "value") == 10 #Resolve in the definition doesn't influence the value in the user changes.
  394. global_stack.userChanges = resolve
  395. assert global_stack.getProperty("material_bed_temperature", "value") == 15 #Falls through to definition for lack of values, but then asks the start of the stack for the resolve.
  396. global_stack.userChanges = empty
  397. global_stack.qualityChanges = resolve_and_value
  398. assert global_stack.getProperty("material_bed_temperature", "value") == 5 #Value still wins in lower places, except definition.
  399. global_stack.qualityChanges = empty
  400. global_stack.quality = resolve_and_value
  401. assert global_stack.getProperty("material_bed_temperature", "value") == 5
  402. global_stack.quality = empty
  403. global_stack.material = resolve_and_value
  404. assert global_stack.getProperty("material_bed_temperature", "value") == 5
  405. global_stack.material = empty
  406. global_stack.variant = resolve_and_value
  407. assert global_stack.getProperty("material_bed_temperature", "value") == 5
  408. global_stack.variant = empty
  409. global_stack.definitionChanges = resolve_and_value
  410. assert global_stack.getProperty("material_bed_temperature", "value") == 5
  411. ## Tests whether the hasUserValue returns true for settings that are changed in
  412. # the user-changes container.
  413. def test_hasUserValueUserChanges(global_stack):
  414. user_changes = MockContainer("test_user_changes", "user")
  415. def hasProperty(key, property):
  416. return key == "layer_height" and property == "value" # Only have the layer_height property set.
  417. user_changes.hasProperty = hasProperty
  418. global_stack.userChanges = user_changes
  419. assert not global_stack.hasUserValue("infill_sparse_density")
  420. assert global_stack.hasUserValue("layer_height")
  421. assert not global_stack.hasUserValue("")
  422. ## Tests whether the hasUserValue returns true for settings that are changed in
  423. # the quality-changes container.
  424. def test_hasUserValueQualityChanges(global_stack):
  425. quality_changes = MockContainer("test_quality_changes", "quality_changes")
  426. def hasProperty(key, property):
  427. return key == "layer_height" and property == "value" # Only have the layer_height property set.
  428. quality_changes.hasProperty = hasProperty
  429. global_stack.qualityChanges = quality_changes
  430. assert not global_stack.hasUserValue("infill_sparse_density")
  431. assert global_stack.hasUserValue("layer_height")
  432. assert not global_stack.hasUserValue("")
  433. ## Tests whether inserting a container is properly forbidden.
  434. def test_insertContainer(global_stack):
  435. with pytest.raises(InvalidOperationError):
  436. global_stack.insertContainer(0, unittest.mock.MagicMock())
  437. ## Tests whether removing a container is properly forbidden.
  438. def test_removeContainer(global_stack):
  439. with pytest.raises(InvalidOperationError):
  440. global_stack.removeContainer(unittest.mock.MagicMock())
  441. ## Tests setting definitions by specifying an ID of a definition that exists.
  442. def test_setDefinitionByIdExists(global_stack, container_registry):
  443. with unittest.mock.patch("cura.Settings.CuraContainerStack.DefinitionContainer", unittest.mock.MagicMock): #To guard against type checking the DefinitionContainer.
  444. global_stack.setDefinitionById("some_definition") #The container registry always has a container with the ID.
  445. ## Tests setting definitions by specifying an ID of a definition that doesn't
  446. # exist.
  447. def test_setDefinitionByIdDoesntExist(global_stack):
  448. with pytest.raises(InvalidContainerError):
  449. global_stack.setDefinitionById("some_definition") #Container registry is empty now.
  450. ## Tests setting definition changes by specifying an ID of a container that
  451. # exists.
  452. def test_setDefinitionChangesByIdExists(global_stack, container_registry):
  453. container_registry.typeMetaData = "definition_changes"
  454. global_stack.setDefinitionChangesById("some_definition_changes") #The container registry always has a container with the ID.
  455. ## Tests setting definition changes by specifying an ID of a container that
  456. # doesn't exist.
  457. def test_setDefinitionChangesByIdDoesntExist(global_stack):
  458. with pytest.raises(InvalidContainerError):
  459. global_stack.setDefinitionChangesById("some_definition_changes") #Container registry is empty now.
  460. ## Tests setting materials by specifying an ID of a material that exists.
  461. def test_setMaterialByIdExists(global_stack, container_registry):
  462. container_registry.typeMetaData = "material"
  463. global_stack.setMaterialById("some_material") #The container registry always has a container with the ID.
  464. ## Tests setting materials by specifying an ID of a material that doesn't
  465. # exist.
  466. def test_setMaterialByIdDoesntExist(global_stack):
  467. with pytest.raises(InvalidContainerError):
  468. global_stack.setMaterialById("some_material") #Container registry is empty now.
  469. ## Tests whether changing the next stack is properly forbidden.
  470. def test_setNextStack(global_stack):
  471. with pytest.raises(InvalidOperationError):
  472. global_stack.setNextStack(unittest.mock.MagicMock())
  473. ## Tests setting properties directly on the global stack.
  474. @pytest.mark.parametrize("key, property, value, output_value", [
  475. ("layer_height", "value", 0.1337, 0.1337),
  476. ("foo", "value", 100, 100),
  477. ("support_enabled", "value", True, True),
  478. ("layer_height", "default_value", 0.1337, 0.1337),
  479. ("layer_height", "is_bright_pink", "of course", "of course")
  480. ])
  481. def test_setPropertyUser(key, property, value, output_value, writable_global_stack):
  482. writable_global_stack.setProperty(key, property, value)
  483. assert writable_global_stack.userChanges.getProperty(key, property) == output_value
  484. ## Tests setting properties on specific containers on the global stack.
  485. @pytest.mark.parametrize("target_container", [
  486. "user",
  487. "quality_changes",
  488. "quality",
  489. "material",
  490. "variant",
  491. "definition_changes",
  492. ])
  493. def test_setPropertyOtherContainers(target_container, writable_global_stack):
  494. #Other parameters that don't need to be varied.
  495. key = "layer_height"
  496. property = "value"
  497. value = 0.1337
  498. output_value = 0.1337
  499. writable_global_stack.setProperty(key, property, value, target_container = target_container)
  500. containers = {
  501. "user": writable_global_stack.userChanges,
  502. "quality_changes": writable_global_stack.qualityChanges,
  503. "quality": writable_global_stack.quality,
  504. "material": writable_global_stack.material,
  505. "variant": writable_global_stack.variant,
  506. "definition_changes": writable_global_stack.definitionChanges,
  507. "definition": writable_global_stack.definition
  508. }
  509. assert containers[target_container].getProperty(key, property) == output_value
  510. ## Tests setting qualities by specifying an ID of a quality that exists.
  511. def test_setQualityByIdExists(global_stack, container_registry):
  512. container_registry.typeMetaData = "quality"
  513. global_stack.setQualityById("some_quality") #The container registry always has a container with the ID.
  514. ## Tests setting qualities by specifying an ID of a quality that doesn't exist.
  515. def test_setQualityByIdDoesntExist(global_stack):
  516. with pytest.raises(InvalidContainerError):
  517. global_stack.setQualityById("some_quality") #Container registry is empty now.
  518. ## Tests setting quality changes by specifying an ID of a quality change that
  519. # exists.
  520. def test_setQualityChangesByIdExists(global_stack, container_registry):
  521. container_registry.typeMetaData = "quality_changes"
  522. global_stack.setQualityChangesById("some_quality_changes") #The container registry always has a container with the ID.
  523. ## Tests setting quality changes by specifying an ID of a quality change that
  524. # doesn't exist.
  525. def test_setQualityChangesByIdDoesntExist(global_stack):
  526. with pytest.raises(InvalidContainerError):
  527. global_stack.setQualityChangesById("some_quality_changes") #Container registry is empty now.
  528. ## Tests setting variants by specifying an ID of a variant that exists.
  529. def test_setVariantByIdExists(global_stack, container_registry):
  530. container_registry.typeMetaData = "variant"
  531. global_stack.setVariantById("some_variant") #The container registry always has a container with the ID.
  532. ## Tests setting variants by specifying an ID of a variant that doesn't exist.
  533. def test_setVariantByIdDoesntExist(global_stack):
  534. with pytest.raises(InvalidContainerError):
  535. global_stack.setVariantById("some_variant") #Container registry is empty now.