TestExtruderStack.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  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 stack files.
  4. import pytest #This module contains automated tests.
  5. import unittest.mock #For the mocking and monkeypatching functionality.
  6. import UM.Settings.ContainerRegistry #To create empty instance containers.
  7. import UM.Settings.ContainerStack #To set the container registry the container stacks use.
  8. from UM.Settings.DefinitionContainer import DefinitionContainer #To check against the class of DefinitionContainer.
  9. from UM.Settings.InstanceContainer import InstanceContainer #To check against the class of InstanceContainer.
  10. import cura.Settings.ExtruderStack #The module we're testing.
  11. from cura.Settings.Exceptions import InvalidContainerError, InvalidOperationError #To check whether the correct exceptions are raised.
  12. ## Fake container registry that always provides all containers you ask of.
  13. @pytest.fixture()
  14. def container_registry():
  15. registry = unittest.mock.MagicMock()
  16. def findContainers(id = None):
  17. if not id:
  18. return [UM.Settings.ContainerRegistry._EmptyInstanceContainer("test_container")]
  19. else:
  20. return [UM.Settings.ContainerRegistry._EmptyInstanceContainer(id)]
  21. registry.findContainers = findContainers
  22. return registry
  23. ## An empty extruder stack to test with.
  24. @pytest.fixture()
  25. def extruder_stack() -> cura.Settings.ExtruderStack.ExtruderStack:
  26. return cura.Settings.ExtruderStack.ExtruderStack("TestStack")
  27. ## Place-in function for findContainer that finds only containers that start
  28. # with "some_".
  29. def findSomeContainers(container_id = "*", container_type = None, type = None, category = "*"):
  30. if container_id.startswith("some_"):
  31. return UM.Settings.ContainerRegistry._EmptyInstanceContainer(container_id)
  32. if container_type == DefinitionContainer:
  33. definition_mock = unittest.mock.MagicMock()
  34. definition_mock.getId = unittest.mock.MagicMock(return_value = "some_definition") #getId returns some_definition.
  35. return definition_mock
  36. ## Helper function to read the contents of a container stack in the test
  37. # stack folder.
  38. #
  39. # \param filename The name of the file in the "stacks" folder to read from.
  40. # \return The contents of that file.
  41. def readStack(filename):
  42. with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), "stacks", filename)) as file_handle:
  43. serialized = file_handle.read()
  44. return serialized
  45. class DefinitionContainerSubClass(DefinitionContainer):
  46. def __init__(self):
  47. super().__init__(container_id = "SubDefinitionContainer")
  48. class InstanceContainerSubClass(InstanceContainer):
  49. def __init__(self):
  50. super().__init__(container_id = "SubInstanceContainer")
  51. #############################START OF TEST CASES################################
  52. ## Tests whether adding a container is properly forbidden.
  53. def test_addContainer(extruder_stack):
  54. with pytest.raises(InvalidOperationError):
  55. extruder_stack.addContainer(unittest.mock.MagicMock())
  56. ## Tests whether the container types are properly enforced on the stack.
  57. #
  58. # When setting a field to have a different type of stack than intended, we
  59. # should get an exception.
  60. @pytest.mark.parametrize("definition_container, instance_container", [
  61. (DefinitionContainer(container_id = "TestDefinitionContainer"), InstanceContainer(container_id = "TestInstanceContainer")),
  62. (DefinitionContainerSubClass(), InstanceContainerSubClass())
  63. ])
  64. def test_constrainContainerTypes(definition_container, instance_container, extruder_stack):
  65. with pytest.raises(InvalidContainerError): #Putting a definition container in the user changes is not allowed.
  66. extruder_stack.userChanges = definition_container
  67. extruder_stack.userChanges = instance_container #Putting an instance container in the user changes is allowed.
  68. with pytest.raises(InvalidContainerError):
  69. extruder_stack.qualityChanges = definition_container
  70. extruder_stack.qualityChanges = instance_container
  71. with pytest.raises(InvalidContainerError):
  72. extruder_stack.quality = definition_container
  73. extruder_stack.quality = instance_container
  74. with pytest.raises(InvalidContainerError):
  75. extruder_stack.material = definition_container
  76. extruder_stack.material = instance_container
  77. with pytest.raises(InvalidContainerError):
  78. extruder_stack.variant = definition_container
  79. extruder_stack.variant = instance_container
  80. with pytest.raises(InvalidContainerError): #Putting an instance container in the definition is not allowed.
  81. extruder_stack.definition = instance_container
  82. extruder_stack.definition = definition_container #Putting a definition container in the definition is allowed.
  83. ## Tests whether definitions are being read properly from an extruder stack.
  84. @pytest.mark.parametrize("filename, definition_id", [
  85. ("Left.extruder.cfg", "empty"),
  86. ("ExtruderLegacy.stack.cfg", "empty"),
  87. ("OnlyDefinition.extruder.cfg", "empty"),
  88. ("Complete.extruder.cfg", "some_definition")
  89. ])
  90. def test_deserializeDefinition(filename, definition_id, container_registry, extruder_stack):
  91. serialized = readStack(filename)
  92. #Mock the loading of the instance containers.
  93. extruder_stack.findContainer = findSomeContainers
  94. original_container_registry = UM.Settings.ContainerStack._containerRegistry
  95. UM.Settings.ContainerStack._containerRegistry = container_registry #Always has all profiles you ask of.
  96. extruder_stack.deserialize(serialized)
  97. assert extruder_stack.definition.getId() == definition_id
  98. #Restore.
  99. UM.Settings.ContainerStack._containerRegistry = original_container_registry
  100. ## Tests whether materials are being read properly from an extruder stack.
  101. @pytest.mark.parametrize("filename, material_id", [
  102. ("Left.extruder.cfg", "some_instance"),
  103. ("ExtruderLegacy.stack.cfg", "some_instance"),
  104. ("OnlyMaterial.extruder.cfg", "some_instance"),
  105. ("OnlyDefinition.extruder.cfg", "empty"),
  106. ("Complete.extruder.cfg", "some_material")
  107. ])
  108. def test_deserializeMaterial(filename, material_id, container_registry, extruder_stack):
  109. serialized = readStack(filename)
  110. #Mock the loading of the instance containers.
  111. extruder_stack.findContainer = findSomeContainers
  112. original_container_registry = UM.Settings.ContainerStack._containerRegistry
  113. UM.Settings.ContainerStack._containerRegistry = container_registry #Always has all profiles you ask of.
  114. extruder_stack.deserialize(serialized)
  115. assert extruder_stack.material.getId() == material_id
  116. #Restore.
  117. UM.Settings.ContainerStack._containerRegistry = original_container_registry
  118. ## Tests that when an extruder is loaded with an unknown instance, it raises an
  119. # exception.
  120. def test_deserializeMissingContainer(extruder_stack):
  121. serialized = readStack("Left.extruder.cfg")
  122. with pytest.raises(Exception):
  123. extruder_stack.deserialize(serialized)
  124. try:
  125. extruder_stack.deserialize(serialized)
  126. except Exception as e:
  127. #Must be exactly Exception, not one of its subclasses, since that is what gets raised when a stack has an unknown container.
  128. #That's why we can't use pytest.raises.
  129. assert type(e) == Exception
  130. ## Tests whether qualities are being read properly from an extruder stack.
  131. @pytest.mark.parametrize("filename, quality_id", [
  132. ("Left.extruder.cfg", "empty"),
  133. ("ExtruderLegacy.stack.cfg", "empty"),
  134. ("OnlyQuality.extruder.cfg", "some_instance"),
  135. ("Complete.extruder.cfg", "some_quality")
  136. ])
  137. def test_deserializeQuality(filename, quality_id, container_registry, extruder_stack):
  138. serialized = readStack(filename)
  139. #Mock the loading of the instance containers.
  140. extruder_stack.findContainer = findSomeContainers
  141. original_container_registry = UM.Settings.ContainerStack._containerRegistry
  142. UM.Settings.ContainerStack._containerRegistry = container_registry #Always has all profiles you ask of.
  143. extruder_stack.deserialize(serialized)
  144. assert extruder_stack.quality.getId() == quality_id
  145. #Restore.
  146. UM.Settings.ContainerStack._containerRegistry = original_container_registry
  147. ## Tests whether quality changes are being read properly from an extruder
  148. # stack.
  149. @pytest.mark.parametrize("filename, quality_changes_id", [
  150. ("Left.extruder.cfg", "empty"),
  151. ("ExtruderLegacy.stack.cfg", "empty"),
  152. ("OnlyQualityChanges.extruder.cfg", "some_instance"),
  153. ("Complete.extruder.cfg", "some_quality_changes")
  154. ])
  155. def test_deserializeQualityChanges(filename, quality_changes_id, container_registry, extruder_stack):
  156. serialized = readStack(filename)
  157. #Mock the loading of the instance containers.
  158. extruder_stack.findContainer = findSomeContainers
  159. original_container_registry = UM.Settings.ContainerStack._containerRegistry
  160. UM.Settings.ContainerStack._containerRegistry = container_registry #Always has all profiles you ask of.
  161. extruder_stack.deserialize(serialized)
  162. assert extruder_stack.qualityChanges.getId() == quality_changes_id
  163. #Restore.
  164. UM.Settings.ContainerStack._containerRegistry = original_container_registry
  165. ## Tests whether user changes are being read properly from an extruder stack.
  166. @pytest.mark.parametrize("filename, user_changes_id", [
  167. ("Left.extruder.cfg", "empty"),
  168. ("ExtruderLegacy.stack.cfg", "empty"),
  169. ("OnlyUser.extruder.cfg", "some_instance"),
  170. ("Complete.extruder.cfg", "some_user_changes")
  171. ])
  172. def test_deserializeUserChanges(filename, user_changes_id, container_registry, extruder_stack):
  173. serialized = readStack(filename)
  174. #Mock the loading of the instance containers.
  175. extruder_stack.findContainer = findSomeContainers
  176. original_container_registry = UM.Settings.ContainerStack._containerRegistry
  177. UM.Settings.ContainerStack._containerRegistry = container_registry #Always has all profiles you ask of.
  178. extruder_stack.deserialize(serialized)
  179. assert extruder_stack.userChanges.getId() == user_changes_id
  180. #Restore.
  181. UM.Settings.ContainerStack._containerRegistry = original_container_registry
  182. ## Tests whether variants are being read properly from an extruder stack.
  183. @pytest.mark.parametrize("filename, variant_id", [
  184. ("Left.extruder.cfg", "empty"),
  185. ("ExtruderLegacy.stack.cfg", "empty"),
  186. ("OnlyVariant.extruder.cfg", "some_instance"),
  187. ("Complete.extruder.cfg", "some_variant")
  188. ])
  189. def test_deserializeVariant(filename, variant_id, container_registry, extruder_stack):
  190. serialized = readStack(filename)
  191. #Mock the loading of the instance containers.
  192. extruder_stack.findContainer = findSomeContainers
  193. original_container_registry = UM.Settings.ContainerStack._containerRegistry
  194. UM.Settings.ContainerStack._containerRegistry = container_registry #Always has all profiles you ask of.
  195. extruder_stack.deserialize(serialized)
  196. assert extruder_stack.variant.getId() == variant_id
  197. #Restore.
  198. UM.Settings.ContainerStack._containerRegistry = original_container_registry
  199. ## Tests whether getProperty properly applies the stack-like behaviour on its
  200. # containers.
  201. def test_getPropertyFallThrough(extruder_stack):
  202. #A few instance container mocks to put in the stack.
  203. layer_height_5 = unittest.mock.MagicMock() #Sets layer height to 5.
  204. layer_height_5.getProperty = lambda key, property: 5 if (key == "layer_height" and property == "value") else None
  205. layer_height_5.hasProperty = lambda key: key == "layer_height"
  206. layer_height_10 = unittest.mock.MagicMock() #Sets layer height to 10.
  207. layer_height_10.getProperty = lambda key, property: 10 if (key == "layer_height" and property == "value") else None
  208. layer_height_10.hasProperty = lambda key: key == "layer_height"
  209. no_layer_height = unittest.mock.MagicMock() #No settings at all.
  210. no_layer_height.getProperty = lambda key, property: None
  211. no_layer_height.hasProperty = lambda key: False
  212. extruder_stack.userChanges = no_layer_height
  213. extruder_stack.qualityChanges = no_layer_height
  214. extruder_stack.quality = no_layer_height
  215. extruder_stack.material = no_layer_height
  216. extruder_stack.variant = no_layer_height
  217. extruder_stack.definition = layer_height_5 #Here it is!
  218. assert extruder_stack.getProperty("layer_height", "value") == 5
  219. extruder_stack.variant = layer_height_10
  220. assert extruder_stack.getProperty("layer_height", "value") == 10
  221. extruder_stack.material = layer_height_5
  222. assert extruder_stack.getProperty("layer_height", "value") == 5
  223. extruder_stack.quality = layer_height_10
  224. assert extruder_stack.getProperty("layer_height", "value") == 10
  225. extruder_stack.qualityChanges = layer_height_5
  226. assert extruder_stack.getProperty("layer_height", "value") == 5
  227. extruder_stack.userChanges = layer_height_10
  228. assert extruder_stack.getProperty("layer_height", "value") == 10
  229. ## Tests whether inserting a container is properly forbidden.
  230. def test_insertContainer(extruder_stack):
  231. with pytest.raises(InvalidOperationError):
  232. extruder_stack.insertContainer(0, unittest.mock.MagicMock())
  233. ## Tests whether removing a container is properly forbidden.
  234. def test_removeContainer(extruder_stack):
  235. with pytest.raises(InvalidOperationError):
  236. extruder_stack.removeContainer(unittest.mock.MagicMock())