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 13KB

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