No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

test_model.py 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. import unittest
  2. from unittest.mock import patch
  3. from EditorialModel.model import Model
  4. from EditorialModel.classes import EmClass
  5. from EditorialModel.types import EmType
  6. from EditorialModel.fields import EmField
  7. from EditorialModel.components import EmComponent
  8. from Lodel.utils.mlstring import MlString
  9. from EditorialModel.backend.json_backend import EmBackendJson
  10. from EditorialModel.backend.dummy_backend import EmBackendDummy
  11. from DataSource.dummy.migrationhandler import DummyMigrationHandler
  12. class TestModel(unittest.TestCase):
  13. def setUp(self):
  14. self.ed_mod = Model(EmBackendJson('EditorialModel/test/me.json'))
  15. def test_init(self):
  16. """ Instanciation test """
  17. model = Model(EmBackendJson('EditorialModel/test/me.json'))
  18. self.assertTrue(isinstance(model, Model))
  19. model = Model(EmBackendJson('EditorialModel/test/me.json'), migration_handler=DummyMigrationHandler())
  20. self.assertTrue(isinstance(model, Model))
  21. def test_bad_init(self):
  22. """ Test initialisation with bad arguments """
  23. for bad in [None, int, EmBackendDummy, DummyMigrationHandler, 'foobar']:
  24. with self.assertRaises(TypeError, msg="Tried to instanciate a Model with a bad backend"):
  25. Model(bad)
  26. for bad in [int, EmBackendDummy, DummyMigrationHandler, 'foobar']:
  27. with self.assertRaises(TypeError, msg="Tried to instanciate a Model with a migration_handler"):
  28. Model(EmBackendDummy(), bad)
  29. def test_components(self):
  30. """ Test components fetching """
  31. uid_l = list()
  32. for comp_class in [EmClass, EmType, EmField]:
  33. comp_l = self.ed_mod.components(comp_class)
  34. #Testing types of returned components
  35. for component in comp_l:
  36. self.assertTrue(isinstance(component, comp_class), "Model.components method doesn't return EmComponent of the right type. Asked for {} but got {}".format(type(comp_class), type(component)))
  37. uid_l.append(component.uid)
  38. #Testing that we have fetched all the components
  39. for uid in self.ed_mod._components['uids']:
  40. self.assertIn(uid, uid_l, "Component with uid %d was not fetched" % uid)
  41. #Testing components method without parameters
  42. uid_l = [comp.uid for comp in self.ed_mod.components()]
  43. for uid in self.ed_mod._components['uids']:
  44. self.assertIn(uid, uid_l, "Component with uid %d was not fetched using me.components()" % uid)
  45. self.assertFalse(self.ed_mod.components(EmComponent))
  46. self.assertFalse(self.ed_mod.components(int))
  47. def test_component(self):
  48. """ Test component fetching by uid """
  49. #assert that __hash__, __eq__ and components() are corrects
  50. for comp in self.ed_mod.components():
  51. self.assertEqual(comp, self.ed_mod.component(comp.uid))
  52. for baduid in [-1, 0xffffff, "hello"]:
  53. self.assertFalse(self.ed_mod.component(baduid))
  54. def test_sort_components(self):
  55. """ Test that Model.sort_components method actually sort components """
  56. # disordering an EmClass
  57. cl_l = self.ed_mod.components(EmClass)
  58. last_class = cl_l[0]
  59. last_class.rank = 10000
  60. self.ed_mod.sort_components(EmClass)
  61. self.assertEqual(self.ed_mod._components['EmClass'][-1].uid, last_class.uid, "The sort_components method doesn't really sort by rank")
  62. def test_new_uid(self):
  63. """ Test that model.new_uid return a new uniq uid """
  64. new_uid = self.ed_mod.new_uid()
  65. self.assertNotIn(new_uid, self.ed_mod._components['uids'].keys())
  66. def test_create_component_fails(self):
  67. """ Test the create_component method with invalid arguments """
  68. test_datas = {
  69. 'name': 'FooBar',
  70. 'classtype': 'entity',
  71. 'help_text': None,
  72. 'string': None,
  73. }
  74. #Invalid uid
  75. used_uid = self.ed_mod.components()[0].uid
  76. for bad_uid in [used_uid, -1, -1000, 'HelloWorld']:
  77. with self.assertRaises(ValueError, msg="The component was created but the given uid (%s) whas invalid (allready used, negative or WTF)" % bad_uid):
  78. self.ed_mod.create_component('EmClass', test_datas, uid=bad_uid)
  79. #Invalid component_type
  80. for bad_comp_name in ['EmComponent', 'EmFoobar', 'int', int]:
  81. with self.assertRaises(ValueError, msg="The create_component don't raise when an invalid classname (%s) is given as parameter" % bad_comp_name):
  82. self.ed_mod.create_component(bad_comp_name, test_datas)
  83. #Invalid rank
  84. for invalid_rank in [-1, 10000]:
  85. with self.assertRaises(ValueError, msg="A invalid rank (%s) was given" % invalid_rank):
  86. foodat = test_datas.copy()
  87. foodat['rank'] = invalid_rank
  88. self.ed_mod.create_component('EmClass', foodat)
  89. with self.assertRaises(TypeError, msg="A non integer rank was given"):
  90. foodat = test_datas.copy()
  91. foodat['rank'] = 'hello world'
  92. self.ed_mod.create_component('EmClass', foodat)
  93. #Invalid datas
  94. for invalid_datas in [dict(), [1, 2, 3, 4], ('hello', 'world')]:
  95. with self.assertRaises(TypeError, msg="Invalid datas was given in parameters"):
  96. self.ed_mod.create_component('EmClass', invalid_datas)
  97. def test_create_components(self):
  98. """ Test the create_component method mocking the EmComponent constructors """
  99. params = {
  100. 'EmClass': {
  101. 'cls': EmClass,
  102. 'cdats': {
  103. 'name': 'FooClass',
  104. 'classtype': 'entity',
  105. }
  106. },
  107. 'EmType': {
  108. 'cls': EmType,
  109. 'cdats': {
  110. 'name': 'FooType',
  111. 'class_id': self.ed_mod.components(EmClass)[0].uid,
  112. 'fields_list': [],
  113. }
  114. },
  115. 'EmField': {
  116. 'cls': EmField,
  117. 'cdats': {
  118. 'name': 'FooField',
  119. 'class_id': self.ed_mod.components(EmClass)[0].uid,
  120. 'fieldtype': 'char',
  121. 'max_length': 64,
  122. 'optional': True,
  123. 'internal': False,
  124. 'rel_field_id': None,
  125. 'icon': '0',
  126. 'nullable': False,
  127. 'uniq': True,
  128. }
  129. }
  130. }
  131. for cnt in params:
  132. tmpuid = self.ed_mod.new_uid()
  133. cdats = params[cnt]['cdats']
  134. cdats['string'] = MlString()
  135. cdats['help_text'] = MlString()
  136. with patch.object(params[cnt]['cls'], '__init__', return_value=None) as initmock:
  137. try:
  138. self.ed_mod.create_component(cnt, params[cnt]['cdats'])
  139. except AttributeError: # Raises because the component is a MagicMock
  140. pass
  141. cdats['uid'] = tmpuid
  142. cdats['model'] = self.ed_mod
  143. #Check that the component __init__ method was called with the good arguments
  144. initmock.assert_called_once_with(**cdats)
  145. def test_delete_component(self):
  146. """ Test the delete_component method """
  147. #Test that the delete_check() method is called
  148. for comp in self.ed_mod.components():
  149. with patch.object(comp.__class__, 'delete_check', return_value=False) as del_check_mock:
  150. ret = self.ed_mod.delete_component(comp.uid)
  151. del_check_mock.assert_called_once_with()
  152. #Check that when the delete_check() returns False de delete_component() too
  153. self.assertFalse(ret)
  154. #Using a new me for deletion test
  155. new_em = Model(EmBackendJson('EditorialModel/test/me.json'))
  156. for comp in new_em.components():
  157. cuid = comp.uid
  158. cname = new_em.name_from_emclass(comp.__class__)
  159. #Simulate that the delete_check() method returns True
  160. with patch.object(comp.__class__, 'delete_check', return_value=True) as del_check_mock:
  161. ret = new_em.delete_component(cuid)
  162. self.assertTrue(ret)
  163. self.assertNotIn(cuid, new_em._components['uids'])
  164. self.assertNotIn(comp, new_em._components[cname])
  165. def test_set_backend(self):
  166. """ Test the set_backend method """
  167. for backend in [EmBackendJson('EditorialModel/test/me.json'), EmBackendDummy()]:
  168. self.ed_mod.set_backend(backend)
  169. self.assertEqual(self.ed_mod.backend, backend)
  170. for bad_backend in [None, 'wow', int, EmBackendJson]:
  171. with self.assertRaises(TypeError, msg="But bad argument (%s %s) was given" % (type(bad_backend), bad_backend)):
  172. self.ed_mod.set_backend(bad_backend)
  173. def test_migrate_handler_order(self):
  174. """ Test that the migrate_handler() method create component in a good order """
  175. with patch.object(Model, 'create_component', return_value=None) as create_mock:
  176. try:
  177. self.ed_mod.migrate_handler(None)
  178. except AttributeError: # Raises because of the mock
  179. pass
  180. order_comp = ['EmClass', 'EmType', 'EmFieldGroup', 'EmField'] # Excpected creation order
  181. cur_comp = 0
  182. for mcall in create_mock.mock_calls:
  183. #Testing EmComponent order of creation
  184. while order_comp[cur_comp] != mcall[1][0]:
  185. cur_comp += 1
  186. if cur_comp >= len(order_comp):
  187. self.fail('The order of create_component() calls was not respected by migrate_handler() methods')
  188. #Testing uid
  189. comp = self.ed_mod.component(mcall[1][2])
  190. ctype = self.ed_mod.name_from_emclass(comp.__class__)
  191. self.assertEqual(mcall[1][0], ctype, "A component was created using a uid belonging to another component type")
  192. #Testing arguments of create_component
  193. comp_dump = comp.attr_dump()
  194. if 'fields_list' in comp_dump and comp_dump['fields_list']:
  195. del(comp_dump['fields_list'])
  196. if 'superiors_list' in comp_dump and comp_dump['superiors_list']:
  197. del(comp_dump['superiors_list'])
  198. self.assertEqual(mcall[1][1], comp_dump)
  199. def test_migrate_handler_relations(self):
  200. """ Test that the migrate_handler() method create Type relations correctly (selected fields and type hierarchy) """
  201. field_list_orig = []
  202. superiors_list_orig = dict()
  203. field_list_new = []
  204. superiors_list_new = dict()
  205. for emtype in self.ed_mod.components(EmType):
  206. for fluid in emtype.fields_list:
  207. field_list_orig.append(fluid)
  208. for nat, sup_l in emtype.superiors().items():
  209. superiors_list_orig[nat] = [sup.uid for sup in sup_l]
  210. with patch.object(DummyMigrationHandler, 'register_change', return_value=None) as mh_mock:
  211. self.ed_mod.migrate_handler(DummyMigrationHandler())
  212. #Getting cloned EM instance
  213. new_me = mh_mock.mock_calls[-1][1][0]
  214. for emtype in new_me.components(EmType):
  215. for fluid in emtype.fields_list:
  216. field_list_new.append(fluid)
  217. for nat, sup_l in emtype.superiors().items():
  218. superiors_list_new[nat] = [sup.uid for sup in sup_l]
  219. for fluid in field_list_orig:
  220. self.assertIn(fluid, field_list_orig, "Missing selected field (%d) when migrate_handler() is run" % fluid)
  221. for fluid in field_list_new:
  222. self.assertIn(fluid, field_list_new, "A field (%d) is selected when migrate_handler() is run but shouldn't be" % fluid)
  223. for nat, sup_l in superiors_list_orig.items():
  224. for supuid in sup_l:
  225. self.assertIn(supuid, superiors_list_new[nat], "Missing superiors (%d) when migrate_handler() is run" % supuid)
  226. for nat, sup_l in superiors_list_new.items():
  227. for supuid in sup_l:
  228. self.assertIn(supuid, superiors_list_orig[nat], "A superior (%d) is present when migrate_handler is called but shouldn't be" % supuid)
  229. def test_migrate_handler_hashes(self):
  230. """ Testing that the migrate_handler() method create an EM with the same hash as the original EM """
  231. with patch.object(DummyMigrationHandler, 'register_change', return_value=None) as mh_mock:
  232. self.ed_mod.migrate_handler(DummyMigrationHandler())
  233. #Getting the cloned EM instance
  234. last_call = mh_mock.mock_calls[-1]
  235. self.assertEqual(hash(last_call[1][0]), hash(self.ed_mod))
  236. def test_hash(self):
  237. """ Test that __hash__ and __eq__ work properly on models """
  238. me1 = Model(EmBackendJson('EditorialModel/test/me.json'))
  239. me2 = Model(EmBackendJson('EditorialModel/test/me.json'), migration_handler=DummyMigrationHandler())
  240. self.assertEqual(hash(me1), hash(me2), "When instanciate from the same backend & file but with another migration handler the hashes differs")
  241. self.assertTrue(me1.__eq__(me2))
  242. cl_l = me1.classes()
  243. cl_l[0].modify_rank(1)
  244. self.assertNotEqual(hash(me1), hash(me2), "After a class rank modification the hashes are the same")
  245. self.assertFalse(me1.__eq__(me2))
  246. cl_l = me2.classes()
  247. cl_l[0].modify_rank(1)
  248. self.assertEqual(hash(me1), hash(me2), "After doing sames modifications in the two models the hashes differs")
  249. self.assertTrue(me1.__eq__(me2))
  250. def test_compclass_getter(self):
  251. """ Test the Model methods that handles name <-> EmComponent conversion """
  252. for classname in ['EmField', 'EmClass', 'EmType']:
  253. cls = Model.emclass_from_name(classname)
  254. self.assertNotEqual(cls, False, "emclass_from_name return False when '%s' given as parameter" % classname)
  255. self.assertEqual(cls.__name__, classname)
  256. for classname in ['EmComponent', 'EmFoobar', int, EmClass]:
  257. self.assertFalse(Model.emclass_from_name(classname))
  258. for comp_cls in [EmClass, EmField, EmType]:
  259. self.assertEqual(Model.name_from_emclass(comp_cls), comp_cls.__name__)
  260. for comp in self.ed_mod.components(EmField):
  261. self.assertEqual(Model.name_from_emclass(comp.__class__), 'EmField')
  262. for cls in [EmComponent, int, str]:
  263. self.assertFalse(Model.name_from_emclass(cls))