TestGlobalStack.py 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714
  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 the user changes are being read properly from a global stack.
  255. @pytest.mark.parametrize("filename, user_changes_id", [
  256. ("Global.global.cfg", "empty"),
  257. ("Global.stack.cfg", "empty"),
  258. ("MachineLegacy.stack.cfg", "empty"),
  259. ("OnlyUser.global.cfg", "some_instance"), #This one does have a user profile.
  260. ("Complete.global.cfg", "some_user_changes")
  261. ])
  262. def test_deserializeUserChanges(filename, user_changes_id, container_registry, global_stack):
  263. serialized = readStack(filename)
  264. #Mock the loading of the instance containers.
  265. global_stack.findContainer = findSomeContainers
  266. original_container_registry = UM.Settings.ContainerStack._containerRegistry
  267. UM.Settings.ContainerStack._containerRegistry = container_registry #Always has all profiles you ask of.
  268. global_stack.deserialize(serialized)
  269. assert global_stack.userChanges.getId() == user_changes_id
  270. #Restore.
  271. UM.Settings.ContainerStack._containerRegistry = original_container_registry
  272. ## Tests whether the quality changes are being read properly from a global
  273. # stack.
  274. @pytest.mark.parametrize("filename, quality_changes_id", [
  275. ("Global.global.cfg", "empty"),
  276. ("Global.stack.cfg", "empty"),
  277. ("MachineLegacy.stack.cfg", "empty"),
  278. ("OnlyQualityChanges.global.cfg", "some_instance"),
  279. ("Complete.global.cfg", "some_quality_changes")
  280. ])
  281. def test_deserializeQualityChanges(filename, quality_changes_id, container_registry, global_stack):
  282. serialized = readStack(filename)
  283. #Mock the loading of the instance containers.
  284. global_stack.findContainer = findSomeContainers
  285. original_container_registry = UM.Settings.ContainerStack._containerRegistry
  286. UM.Settings.ContainerStack._containerRegistry = container_registry #Always has all the profiles you ask of.
  287. global_stack.deserialize(serialized)
  288. assert global_stack.qualityChanges.getId() == quality_changes_id
  289. #Restore.
  290. UM.Settings.ContainerStack._containerRegistry = original_container_registry
  291. ## Tests whether the quality profile is being read properly from a global
  292. # stack.
  293. @pytest.mark.parametrize("filename, quality_id", [
  294. ("Global.global.cfg", "empty"),
  295. ("Global.stack.cfg", "empty"),
  296. ("MachineLegacy.stack.cfg", "empty"),
  297. ("OnlyQuality.global.cfg", "some_instance"),
  298. ("Complete.global.cfg", "some_quality")
  299. ])
  300. def test_deserializeQuality(filename, quality_id, container_registry, global_stack):
  301. serialized = readStack(filename)
  302. #Mock the loading of the instance containers.
  303. global_stack.findContainer = findSomeContainers
  304. original_container_registry = UM.Settings.ContainerStack._containerRegistry
  305. UM.Settings.ContainerStack._containerRegistry = container_registry #Always has all the profiles you ask of.
  306. global_stack.deserialize(serialized)
  307. assert global_stack.quality.getId() == quality_id
  308. #Restore.
  309. UM.Settings.ContainerStack._containerRegistry = original_container_registry
  310. ## Tests whether the material profile is being read properly from a global
  311. # stack.
  312. @pytest.mark.parametrize("filename, material_id", [
  313. ("Global.global.cfg", "some_instance"),
  314. ("Global.stack.cfg", "some_instance"),
  315. ("MachineLegacy.stack.cfg", "some_instance"),
  316. ("OnlyDefinition.global.cfg", "empty"),
  317. ("OnlyMaterial.global.cfg", "some_instance"),
  318. ("Complete.global.cfg", "some_material")
  319. ])
  320. def test_deserializeMaterial(filename, material_id, container_registry, global_stack):
  321. serialized = readStack(filename)
  322. #Mock the loading of the instance containers.
  323. global_stack.findContainer = findSomeContainers
  324. original_container_registry = UM.Settings.ContainerStack._containerRegistry
  325. UM.Settings.ContainerStack._containerRegistry = container_registry #Always has all the profiles you ask of.
  326. global_stack.deserialize(serialized)
  327. assert global_stack.material.getId() == material_id
  328. #Restore.
  329. UM.Settings.ContainerStack._containerRegistry = original_container_registry
  330. ## Tests whether the variant profile is being read properly from a global
  331. # stack.
  332. @pytest.mark.parametrize("filename, variant_id", [
  333. ("Global.global.cfg", "empty"),
  334. ("Global.stack.cfg", "empty"),
  335. ("MachineLegacy.stack.cfg", "empty"),
  336. ("OnlyVariant.global.cfg", "some_instance"),
  337. ("Complete.global.cfg", "some_variant")
  338. ])
  339. def test_deserializeVariant(filename, variant_id, container_registry, global_stack):
  340. serialized = readStack(filename)
  341. #Mock the loading of the instance containers.
  342. global_stack.findContainer = findSomeContainers
  343. original_container_registry = UM.Settings.ContainerStack._containerRegistry
  344. UM.Settings.ContainerStack._containerRegistry = container_registry #Always has all the profiles you ask of.
  345. global_stack.deserialize(serialized)
  346. assert global_stack.variant.getId() == variant_id
  347. #Restore.
  348. UM.Settings.ContainerStack._containerRegistry = original_container_registry
  349. ## Tests whether the definition changes profile is being read properly from a
  350. # global stack.
  351. @pytest.mark.parametrize("filename, definition_changes_id", [
  352. ("Global.global.cfg", "empty"),
  353. ("Global.stack.cfg", "empty"),
  354. ("MachineLegacy.stack.cfg", "empty"),
  355. ("OnlyDefinitionChanges.global.cfg", "some_instance"),
  356. ("Complete.global.cfg", "some_material")
  357. ])
  358. def test_deserializeDefinitionChanges(filename, definition_changes_id, container_registry, global_stack):
  359. serialized = readStack(filename)
  360. global_stack = cura.Settings.GlobalStack.GlobalStack("TestStack")
  361. #Mock the loading of the instance containers.
  362. global_stack.findContainer = findSomeContainers
  363. original_container_registry = UM.Settings.ContainerStack._containerRegistry
  364. UM.Settings.ContainerStack._containerRegistry = container_registry #Always has all the profiles you ask of.
  365. global_stack.deserialize(serialized)
  366. assert global_stack.definitionChanges.getId() == definition_changes_id
  367. #Restore.
  368. UM.Settings.ContainerStack._containerRegistry = original_container_registry
  369. ## Tests whether the definition is being read properly from a global stack.
  370. @pytest.mark.parametrize("filename, definition_id", [
  371. ("Global.global.cfg", "some_definition"),
  372. ("Global.stack.cfg", "some_definition"),
  373. ("MachineLegacy.stack.cfg", "some_definition"),
  374. ("OnlyDefinition.global.cfg", "some_definition"),
  375. ("Complete.global.cfg", "some_definition")
  376. ])
  377. def test_deserializeDefinition(filename, definition_id, container_registry, global_stack):
  378. serialized = readStack(filename)
  379. #Mock the loading of the instance containers.
  380. global_stack.findContainer = findSomeContainers
  381. original_container_registry = UM.Settings.ContainerStack._containerRegistry
  382. UM.Settings.ContainerStack._containerRegistry = container_registry #Always has all the profiles you ask of.
  383. global_stack.deserialize(serialized)
  384. assert global_stack.definition.getId() == definition_id
  385. #Restore.
  386. UM.Settings.ContainerStack._containerRegistry = original_container_registry
  387. ## Tests that when a global stack is loaded with an unknown instance, it raises
  388. # an exception.
  389. def test_deserializeMissingContainer(global_stack):
  390. serialized = readStack("Global.global.cfg")
  391. with pytest.raises(Exception):
  392. global_stack.deserialize(serialized)
  393. try:
  394. global_stack.deserialize(serialized)
  395. except Exception as e:
  396. #Must be exactly Exception, not one of its subclasses, since that is what gets raised when a stack has an unknown container.
  397. #That's why we can't use pytest.raises.
  398. assert type(e) == Exception
  399. ## Tests whether getProperty properly applies the stack-like behaviour on its
  400. # containers.
  401. def test_getPropertyFallThrough(global_stack):
  402. #A few instance container mocks to put in the stack.
  403. mock_layer_heights = {} #For each container type, a mock container that defines layer height to something unique.
  404. mock_no_settings = {} #For each container type, a mock container that has no settings at all.
  405. container_indexes = cura.Settings.CuraContainerStack._ContainerIndexes #Cache.
  406. for type_id, type_name in container_indexes.IndexTypeMap.items():
  407. container = unittest.mock.MagicMock()
  408. 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.
  409. container.hasProperty = lambda key, property: key == "layer_height"
  410. container.getMetaDataEntry = unittest.mock.MagicMock(return_value = type_name)
  411. mock_layer_heights[type_id] = container
  412. container = unittest.mock.MagicMock()
  413. container.getProperty = unittest.mock.MagicMock(return_value = None) #Has no settings at all.
  414. container.hasProperty = unittest.mock.MagicMock(return_value = False)
  415. container.getMetaDataEntry = unittest.mock.MagicMock(return_value = type_name)
  416. mock_no_settings[type_id] = container
  417. global_stack.userChanges = mock_no_settings[container_indexes.UserChanges]
  418. global_stack.qualityChanges = mock_no_settings[container_indexes.QualityChanges]
  419. global_stack.quality = mock_no_settings[container_indexes.Quality]
  420. global_stack.material = mock_no_settings[container_indexes.Material]
  421. global_stack.variant = mock_no_settings[container_indexes.Variant]
  422. global_stack.definitionChanges = mock_no_settings[container_indexes.DefinitionChanges]
  423. with unittest.mock.patch("cura.Settings.CuraContainerStack.DefinitionContainer", unittest.mock.MagicMock): #To guard against the type checking.
  424. global_stack.definition = mock_layer_heights[container_indexes.Definition] #There's a layer height in here!
  425. assert global_stack.getProperty("layer_height", "value") == container_indexes.Definition
  426. global_stack.definitionChanges = mock_layer_heights[container_indexes.DefinitionChanges]
  427. assert global_stack.getProperty("layer_height", "value") == container_indexes.DefinitionChanges
  428. global_stack.variant = mock_layer_heights[container_indexes.Variant]
  429. assert global_stack.getProperty("layer_height", "value") == container_indexes.Variant
  430. global_stack.material = mock_layer_heights[container_indexes.Material]
  431. assert global_stack.getProperty("layer_height", "value") == container_indexes.Material
  432. global_stack.quality = mock_layer_heights[container_indexes.Quality]
  433. assert global_stack.getProperty("layer_height", "value") == container_indexes.Quality
  434. global_stack.qualityChanges = mock_layer_heights[container_indexes.QualityChanges]
  435. assert global_stack.getProperty("layer_height", "value") == container_indexes.QualityChanges
  436. global_stack.userChanges = mock_layer_heights[container_indexes.UserChanges]
  437. assert global_stack.getProperty("layer_height", "value") == container_indexes.UserChanges
  438. def test_getPropertyWithResolve(global_stack):
  439. #Define some containers for the stack.
  440. resolve = unittest.mock.MagicMock() #Sets just the resolve for bed temperature.
  441. resolve.getProperty = lambda key, property: 15 if (key == "material_bed_temperature" and property == "resolve") else None
  442. resolve_and_value = unittest.mock.MagicMock() #Sets the resolve and value for bed temperature.
  443. 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.
  444. value = unittest.mock.MagicMock() #Sets just the value for bed temperature.
  445. value.getProperty = lambda key, property: 10 if (key == "material_bed_temperature" and property == "value") else None
  446. empty = unittest.mock.MagicMock() #Sets no value or resolve.
  447. empty.getProperty = unittest.mock.MagicMock(return_value = None)
  448. with unittest.mock.patch("cura.Settings.CuraContainerStack.DefinitionContainer", unittest.mock.MagicMock): #To guard against the type checking.
  449. global_stack.definition = resolve_and_value
  450. assert global_stack.getProperty("material_bed_temperature", "value") == 7.5 #Resolve wins in the definition.
  451. global_stack.userChanges = resolve_and_value
  452. assert global_stack.getProperty("material_bed_temperature", "value") == 5 #Value wins in other places.
  453. global_stack.userChanges = value
  454. assert global_stack.getProperty("material_bed_temperature", "value") == 10 #Resolve in the definition doesn't influence the value in the user changes.
  455. global_stack.userChanges = resolve
  456. 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.
  457. global_stack.userChanges = empty
  458. global_stack.qualityChanges = resolve_and_value
  459. assert global_stack.getProperty("material_bed_temperature", "value") == 5 #Value still wins in lower places, except definition.
  460. global_stack.qualityChanges = empty
  461. global_stack.quality = resolve_and_value
  462. assert global_stack.getProperty("material_bed_temperature", "value") == 5
  463. global_stack.quality = empty
  464. global_stack.material = resolve_and_value
  465. assert global_stack.getProperty("material_bed_temperature", "value") == 5
  466. global_stack.material = empty
  467. global_stack.variant = resolve_and_value
  468. assert global_stack.getProperty("material_bed_temperature", "value") == 5
  469. global_stack.variant = empty
  470. global_stack.definitionChanges = resolve_and_value
  471. assert global_stack.getProperty("material_bed_temperature", "value") == 5
  472. ## Tests whether the hasUserValue returns true for settings that are changed in
  473. # the user-changes container.
  474. def test_hasUserValueUserChanges(global_stack):
  475. user_changes = MockContainer("test_user_changes", "user")
  476. def hasProperty(key, property):
  477. return key == "layer_height" and property == "value" # Only have the layer_height property set.
  478. user_changes.hasProperty = hasProperty
  479. global_stack.userChanges = user_changes
  480. assert not global_stack.hasUserValue("infill_sparse_density")
  481. assert global_stack.hasUserValue("layer_height")
  482. assert not global_stack.hasUserValue("")
  483. ## Tests whether the hasUserValue returns true for settings that are changed in
  484. # the quality-changes container.
  485. def test_hasUserValueQualityChanges(global_stack):
  486. quality_changes = MockContainer("test_quality_changes", "quality_changes")
  487. def hasProperty(key, property):
  488. return key == "layer_height" and property == "value" # Only have the layer_height property set.
  489. quality_changes.hasProperty = hasProperty
  490. global_stack.qualityChanges = quality_changes
  491. assert not global_stack.hasUserValue("infill_sparse_density")
  492. assert global_stack.hasUserValue("layer_height")
  493. assert not global_stack.hasUserValue("")
  494. ## Tests whether inserting a container is properly forbidden.
  495. def test_insertContainer(global_stack):
  496. with pytest.raises(InvalidOperationError):
  497. global_stack.insertContainer(0, unittest.mock.MagicMock())
  498. ## Tests whether removing a container is properly forbidden.
  499. def test_removeContainer(global_stack):
  500. with pytest.raises(InvalidOperationError):
  501. global_stack.removeContainer(unittest.mock.MagicMock())
  502. ## Tests setting definitions by specifying an ID of a definition that exists.
  503. def test_setDefinitionByIdExists(global_stack, container_registry):
  504. with unittest.mock.patch("cura.Settings.CuraContainerStack.DefinitionContainer", unittest.mock.MagicMock): #To guard against type checking the DefinitionContainer.
  505. global_stack.setDefinitionById("some_definition") #The container registry always has a container with the ID.
  506. ## Tests setting definitions by specifying an ID of a definition that doesn't
  507. # exist.
  508. def test_setDefinitionByIdDoesntExist(global_stack):
  509. with pytest.raises(InvalidContainerError):
  510. global_stack.setDefinitionById("some_definition") #Container registry is empty now.
  511. ## Tests setting definition changes by specifying an ID of a container that
  512. # exists.
  513. def test_setDefinitionChangesByIdExists(global_stack, container_registry):
  514. container_registry.typeMetaData = "definition_changes"
  515. global_stack.setDefinitionChangesById("some_definition_changes") #The container registry always has a container with the ID.
  516. ## Tests setting definition changes by specifying an ID of a container that
  517. # doesn't exist.
  518. def test_setDefinitionChangesByIdDoesntExist(global_stack):
  519. with pytest.raises(InvalidContainerError):
  520. global_stack.setDefinitionChangesById("some_definition_changes") #Container registry is empty now.
  521. ## Tests setting materials by specifying an ID of a material that exists.
  522. def test_setMaterialByIdExists(global_stack, container_registry):
  523. container_registry.typeMetaData = "material"
  524. global_stack.setMaterialById("some_material") #The container registry always has a container with the ID.
  525. ## Tests setting materials by specifying an ID of a material that doesn't
  526. # exist.
  527. def test_setMaterialByIdDoesntExist(global_stack):
  528. with pytest.raises(InvalidContainerError):
  529. global_stack.setMaterialById("some_material") #Container registry is empty now.
  530. ## Tests whether changing the next stack is properly forbidden.
  531. def test_setNextStack(global_stack):
  532. with pytest.raises(InvalidOperationError):
  533. global_stack.setNextStack(unittest.mock.MagicMock())
  534. ## Tests setting properties directly on the global stack.
  535. @pytest.mark.parametrize("key, property, value, output_value", [
  536. ("layer_height", "value", 0.1337, 0.1337),
  537. ("foo", "value", 100, 100),
  538. ("support_enabled", "value", True, True),
  539. ("layer_height", "default_value", 0.1337, 0.1337),
  540. ("layer_height", "is_bright_pink", "of course", "of course")
  541. ])
  542. def test_setPropertyUser(key, property, value, output_value, writable_global_stack):
  543. writable_global_stack.setProperty(key, property, value)
  544. assert writable_global_stack.userChanges.getProperty(key, property) == output_value
  545. ## Tests setting properties on specific containers on the global stack.
  546. @pytest.mark.parametrize("target_container", [
  547. "user",
  548. "quality_changes",
  549. "quality",
  550. "material",
  551. "variant",
  552. "definition_changes",
  553. ])
  554. def test_setPropertyOtherContainers(target_container, writable_global_stack):
  555. #Other parameters that don't need to be varied.
  556. key = "layer_height"
  557. property = "value"
  558. value = 0.1337
  559. output_value = 0.1337
  560. writable_global_stack.setProperty(key, property, value, target_container = target_container)
  561. containers = {
  562. "user": writable_global_stack.userChanges,
  563. "quality_changes": writable_global_stack.qualityChanges,
  564. "quality": writable_global_stack.quality,
  565. "material": writable_global_stack.material,
  566. "variant": writable_global_stack.variant,
  567. "definition_changes": writable_global_stack.definitionChanges,
  568. "definition": writable_global_stack.definition
  569. }
  570. assert containers[target_container].getProperty(key, property) == output_value
  571. ## Tests setting qualities by specifying an ID of a quality that exists.
  572. def test_setQualityByIdExists(global_stack, container_registry):
  573. container_registry.typeMetaData = "quality"
  574. global_stack.setQualityById("some_quality") #The container registry always has a container with the ID.
  575. ## Tests setting qualities by specifying an ID of a quality that doesn't exist.
  576. def test_setQualityByIdDoesntExist(global_stack):
  577. with pytest.raises(InvalidContainerError):
  578. global_stack.setQualityById("some_quality") #Container registry is empty now.
  579. ## Tests setting quality changes by specifying an ID of a quality change that
  580. # exists.
  581. def test_setQualityChangesByIdExists(global_stack, container_registry):
  582. container_registry.typeMetaData = "quality_changes"
  583. global_stack.setQualityChangesById("some_quality_changes") #The container registry always has a container with the ID.
  584. ## Tests setting quality changes by specifying an ID of a quality change that
  585. # doesn't exist.
  586. def test_setQualityChangesByIdDoesntExist(global_stack):
  587. with pytest.raises(InvalidContainerError):
  588. global_stack.setQualityChangesById("some_quality_changes") #Container registry is empty now.
  589. ## Tests setting variants by specifying an ID of a variant that exists.
  590. def test_setVariantByIdExists(global_stack, container_registry):
  591. container_registry.typeMetaData = "variant"
  592. global_stack.setVariantById("some_variant") #The container registry always has a container with the ID.
  593. ## Tests setting variants by specifying an ID of a variant that doesn't exist.
  594. def test_setVariantByIdDoesntExist(global_stack):
  595. with pytest.raises(InvalidContainerError):
  596. global_stack.setVariantById("some_variant") #Container registry is empty now.