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_lecrud.py 8.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. """
  2. Tests for _LeObject and LeObject
  3. """
  4. import unittest
  5. from unittest import TestCase
  6. from unittest.mock import patch
  7. import EditorialModel
  8. import leapi
  9. import leapi.test.utils
  10. from leapi.lecrud import _LeCrud
  11. ## @brief Test LeCrud methods
  12. # @note those tests need the full dynamically generated code
  13. class LeCrudTestCase(TestCase):
  14. @classmethod
  15. def setUpClass(cls):
  16. """ Write the generated code in a temporary directory and import it """
  17. cls.tmpdir = leapi.test.utils.tmp_load_factory_code()
  18. @classmethod
  19. def tearDownClass(cls):
  20. """ Remove the temporary directory created at class setup """
  21. leapi.test.utils.cleanup(cls.tmpdir)
  22. def test_split_query_filter(self):
  23. """ Tests the _split_filter() classmethod """
  24. import dyncode
  25. query_results = {
  26. 'Hello = world' : ('Hello', '=', 'world'),
  27. 'hello <= "world"': ('hello', '<=', '"world"'),
  28. '_he42_ll-o >= \'world"': ('_he42_ll-o', '>=', '\'world"'),
  29. 'foo in ["foo", 42, \'bar\']': ('foo', ' in ', '["foo", 42, \'bar\']'),
  30. ' bar42 < 42': ('bar42', '<', '42'),
  31. ' _hidden > 1337': ('_hidden', '>', '1337'),
  32. '_42 not in foobar': ('_42', ' not in ', 'foobar'),
  33. 'hello in foo':('hello', ' in ', 'foo'),
  34. "\t\t\thello\t\t\nin\nfoo\t\t\n\t":('hello', ' in ', 'foo'),
  35. "hello \nnot\tin \nfoo":('hello', ' not in ', 'foo'),
  36. 'hello != bar':('hello', '!=', 'bar'),
  37. 'hello = "world>= <= != in not in"': ('hello', '=', '"world>= <= != in not in"'),
  38. 'superior.parent = 13': ('superior.parent', '=', '13'),
  39. }
  40. for query, result in query_results.items():
  41. res = dyncode.LeCrud._split_filter(query)
  42. self.assertEqual(res, result, "When parsing the query : '%s' the returned value is different from the expected '%s'"%(query, result))
  43. def test_invalid_split_query_filter(self):
  44. """ Testing the _split_filter() method with invalid queries """
  45. import dyncode
  46. invalid_queries = [
  47. '42 = 42',
  48. '4hello = foo',
  49. 'foo == bar',
  50. 'hello >> world',
  51. 'hello = ',
  52. ' = world',
  53. '=',
  54. '42',
  55. '"hello" = world',
  56. 'foo.bar = 15',
  57. ]
  58. for query in invalid_queries:
  59. with self.assertRaises(ValueError, msg='But the query was not valid : "%s"'%query):
  60. dyncode.LeCrud._split_filter(query)
  61. def test_field_is_relational(self):
  62. """ Testing the test to check if a field is relational """
  63. from dyncode import LeCrud
  64. test_fields = {
  65. 'superior.parent': True,
  66. 'subordinate.parent': True,
  67. 'foofoo.foo': False,
  68. }
  69. for field, eres in test_fields.items():
  70. self.assertEqual(LeCrud._field_is_relational(field), eres)
  71. def test_check_datas(self):
  72. """ testing the check_datas* methods """
  73. from dyncode import Publication, Numero, LeObject
  74. datas = { 'titre':'foobar' }
  75. Numero.check_datas_value(datas, False, False)
  76. Numero.check_datas_value(datas, True, False)
  77. with self.assertRaises(leapi.lecrud.LeApiDataCheckError):
  78. Numero.check_datas_value({}, True)
  79. def test_prepare_filters(self):
  80. """ Testing the _prepare_filters() method """
  81. from dyncode import Publication, Numero, LeObject, Personnes
  82. #Simple filters
  83. filters = [
  84. 'lodel_id = 1',
  85. 'superior.parent > 2'
  86. ]
  87. filt, rfilt = Numero._prepare_filters(filters)
  88. self.assertEqual(filt, [('lodel_id', '=', '1')])
  89. self.assertEqual(rfilt, [((leapi.leobject.REL_SUP,'parent'), '>', '2')])
  90. #All fields, no relationnal and class given
  91. filters = []
  92. res_filt = []
  93. for field in Numero._fields:
  94. filters.append('%s=1'%field)
  95. res_filt.append((field, '=', '1'))
  96. filt, rfilt = Publication._prepare_filters(filters)
  97. self.assertEqual(rfilt, [])
  98. self.assertEqual(filt, res_filt)
  99. #Mixed type filters (tuple and string)
  100. filters = [
  101. ('lodel_id', '<=', '0'),
  102. 'subordinate.parent = 2',
  103. ]
  104. filt, rfilt = Numero._prepare_filters(filters)
  105. self.assertEqual(filt, [('lodel_id', '<=', '0')])
  106. self.assertEqual(rfilt, [((leapi.leobject.REL_SUB,'parent'), '=', '2')])
  107. def test_prepare_filters_invalid(self):
  108. """ Testing the _prepare_filters() method """
  109. from dyncode import LeCrud, Publication, Numero, Personnes, LeObject
  110. #Numero fields filters but no letype nor leclass given
  111. filters = []
  112. res_filt = []
  113. for field in Numero._fields:
  114. filters.append('%s=1'%field)
  115. res_filt.append((field, '=', '1'))
  116. with self.assertRaises(leapi.lecrud.LeApiDataCheckError):
  117. LeObject._prepare_filters(filters)
  118. #simply invalid filters
  119. filters = ['hello world !']
  120. with self.assertRaises(ValueError):
  121. Personnes._prepare_filters(filters)
  122. #
  123. # Tests mocking the datasource
  124. @patch('leapi.datasources.dummy.DummyDatasource.insert')
  125. def test_insert(self, dsmock):
  126. from dyncode import Publication, Numero, LeObject, Personne, Article
  127. ndatas = [
  128. (Numero, {'titre' : 'FooBar'}),
  129. (Numero, {'titre':'hello'}),
  130. (Personne, {'nom':'world', 'prenom':'hello'}),
  131. (Article, {'titre': 'Ar Boof', 'soustitre': 'Wow!'}),
  132. ]
  133. for lecclass, ndats in ndatas:
  134. lecclass.insert(ndats)
  135. dsmock.assert_called_once_with(lecclass, **ndats)
  136. dsmock.reset_mock()
  137. lecclass.insert(ndats)
  138. dsmock.assert_called_once_with(lecclass, **ndats)
  139. dsmock.reset_mock()
  140. ## @todo try failing on inserting from LeClass child or LeObject
  141. @patch('leapi.datasources.dummy.DummyDatasource.insert')
  142. def test_insert_fails(self, dsmock):
  143. from dyncode import Publication, Numero, LeObject, Personne, Article
  144. ndatas = [
  145. (Numero, dict()),
  146. (Numero, {'titre':'hello', 'lodel_id':42}),
  147. (Numero, {'tititre': 'hehello'}),
  148. (Personne, {'titre':'hello'}),
  149. (Article, {'titre': 'hello'}),
  150. ]
  151. for lecclass, ndats in ndatas:
  152. with self.assertRaises(leapi.lecrud.LeApiDataCheckError, msg="But trying to insert %s as %s"%(ndats, lecclass.__name__)):
  153. lecclass.insert(ndats)
  154. assert not dsmock.called
  155. pass
  156. ## @todo test invalid get
  157. @patch('leapi.datasources.dummy.DummyDatasource.select')
  158. def test_get(self, dsmock):
  159. from dyncode import Publication, Numero, LeObject, Textes
  160. args = [
  161. (
  162. Numero,
  163. ['lodel_id', 'superior.parent'],
  164. ['titre != "foobar"'],
  165. ['lodel_id', (leapi.leobject.REL_SUP, 'parent')],
  166. [('titre','!=', '"foobar"')],
  167. []
  168. ),
  169. (
  170. Numero,
  171. ['lodel_id', 'titre', 'superior.parent', 'subordinate.translation'],
  172. ['superior.parent in [1,2,3,4,5]'],
  173. ['lodel_id', 'titre', (leapi.leobject.REL_SUP,'parent'), (leapi.leobject.REL_SUB, 'translation')],
  174. [],
  175. [( (leapi.leobject.REL_SUP, 'parent'), ' in ', '[1,2,3,4,5]')]
  176. ),
  177. (
  178. Numero,
  179. [],
  180. [],
  181. Numero._fields,
  182. [],
  183. []
  184. ),
  185. (
  186. Textes,
  187. ['lodel_id', 'titre', 'soustitre', 'superior.parent'],
  188. ['titre != "foobar"'],
  189. ['lodel_id', 'titre', 'soustitre', (leapi.leobject.REL_SUP, 'parent')],
  190. [('titre','!=', '"foobar"')],
  191. [],
  192. ),
  193. (
  194. LeObject,
  195. ['lodel_id'],
  196. [],
  197. ['lodel_id'],
  198. [],
  199. [],
  200. ),
  201. ]
  202. for callcls, field_list, filters, fl_ds, filters_ds, rfilters_ds in args:
  203. callcls.get(filters, field_list)
  204. dsmock.assert_called_with(callcls, fl_ds, filters_ds, rfilters_ds)
  205. dsmock.reset_mock()