|
1 # copyright 2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
|
2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr |
|
3 # |
|
4 # This file is part of CubicWeb. |
|
5 # |
|
6 # CubicWeb is free software: you can redistribute it and/or modify it under the |
|
7 # terms of the GNU Lesser General Public License as published by the Free |
|
8 # Software Foundation, either version 2.1 of the License, or (at your option) |
|
9 # any later version. |
|
10 # |
|
11 # CubicWeb is distributed in the hope that it will be useful, but WITHOUT |
|
12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
|
13 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
|
14 # details. |
|
15 # |
|
16 # You should have received a copy of the GNU Lesser General Public License along |
|
17 # with CubicWeb. If not, see <http://www.gnu.org/licenses/>. |
|
18 """unit tests for computed attributes/relations hooks""" |
|
19 |
|
20 from unittest import TestCase |
|
21 |
|
22 from yams.buildobjs import EntityType, String, Int, SubjectRelation |
|
23 |
|
24 from cubicweb.devtools.testlib import CubicWebTC |
|
25 from cubicweb.schema import build_schema_from_namespace |
|
26 |
|
27 |
|
28 class FormulaDependenciesMatrixTC(TestCase): |
|
29 |
|
30 def simple_schema(self): |
|
31 THISYEAR = 2014 |
|
32 |
|
33 class Person(EntityType): |
|
34 name = String() |
|
35 salary = Int() |
|
36 birth_year = Int(required=True) |
|
37 works_for = SubjectRelation('Company') |
|
38 age = Int(formula='Any %d - D WHERE X birth_year D' % THISYEAR) |
|
39 |
|
40 class Company(EntityType): |
|
41 name = String() |
|
42 total_salary = Int(formula='Any SUM(SA) GROUPBY X WHERE P works_for X, P salary SA') |
|
43 |
|
44 schema = build_schema_from_namespace(vars().items()) |
|
45 return schema |
|
46 |
|
47 def setUp(self): |
|
48 from cubicweb.hooks.synccomputed import _FormulaDependenciesMatrix |
|
49 self.schema = self.simple_schema() |
|
50 self.dependencies = _FormulaDependenciesMatrix(self.schema) |
|
51 |
|
52 def test_computed_attributes_by_etype(self): |
|
53 comp_by_etype = self.dependencies.computed_attribute_by_etype |
|
54 self.assertEqual(len(comp_by_etype), 2) |
|
55 values = comp_by_etype['Person'] |
|
56 self.assertEqual(len(values), 1) |
|
57 self.assertEqual(values[0].rtype, 'age') |
|
58 values = comp_by_etype['Company'] |
|
59 self.assertEqual(len(values), 1) |
|
60 self.assertEqual(values[0].rtype, 'total_salary') |
|
61 |
|
62 def test_computed_attribute_by_relation(self): |
|
63 comp_by_rdef = self.dependencies.computed_attribute_by_relation |
|
64 self.assertEqual(len(comp_by_rdef), 1) |
|
65 key, values = iter(comp_by_rdef.iteritems()).next() |
|
66 self.assertEqual(key.rtype, 'works_for') |
|
67 self.assertEqual(len(values), 1) |
|
68 self.assertEqual(values[0].rtype, 'total_salary') |
|
69 |
|
70 def test_computed_attribute_by_etype_attrs(self): |
|
71 comp_by_attr = self.dependencies.computed_attribute_by_etype_attrs |
|
72 self.assertEqual(len(comp_by_attr), 1) |
|
73 values = comp_by_attr['Person'] |
|
74 self.assertEqual(len(values), 2) |
|
75 values = set((rdef.formula, tuple(v)) |
|
76 for rdef, v in values.iteritems()) |
|
77 self.assertEquals(values, |
|
78 set((('Any 2014 - D WHERE X birth_year D', tuple(('birth_year',))), |
|
79 ('Any SUM(SA) GROUPBY X WHERE P works_for X, P salary SA', tuple(('salary',))))) |
|
80 ) |
|
81 |
|
82 |
|
83 class ComputedAttributeTC(CubicWebTC): |
|
84 appid = 'data-computed' |
|
85 |
|
86 def setup_entities(self, req): |
|
87 self.societe = req.create_entity('Societe', nom=u'Foo') |
|
88 req.create_entity('Person', name=u'Titi', salaire=1000, |
|
89 travaille=self.societe, birth_year=2001) |
|
90 self.tata = req.create_entity('Person', name=u'Tata', salaire=2000, |
|
91 travaille=self.societe, birth_year=1990) |
|
92 |
|
93 |
|
94 def test_update_on_add_remove_relation(self): |
|
95 """check the rewriting of a computed attribute""" |
|
96 with self.admin_access.web_request() as req: |
|
97 self.setup_entities(req) |
|
98 req.cnx.commit() |
|
99 rset = req.execute('Any S WHERE X salaire_total S, X nom "Foo"') |
|
100 self.assertEqual(rset[0][0], 3000) |
|
101 # Add relation. |
|
102 toto = req.create_entity('Person', name=u'Toto', salaire=1500, |
|
103 travaille=self.societe, birth_year=1988) |
|
104 req.cnx.commit() |
|
105 rset = req.execute('Any S WHERE X salaire_total S, X nom "Foo"') |
|
106 self.assertEqual(rset[0][0], 4500) |
|
107 # Delete relation. |
|
108 toto.cw_set(travaille=None) |
|
109 req.cnx.commit() |
|
110 rset = req.execute('Any S WHERE X salaire_total S, X nom "Foo"') |
|
111 self.assertEqual(rset[0][0], 3000) |
|
112 |
|
113 def test_recompute_on_attribute_update(self): |
|
114 """check the modification of an attribute triggers the update of the |
|
115 computed attributes that depend on it""" |
|
116 with self.admin_access.web_request() as req: |
|
117 self.setup_entities(req) |
|
118 req.cnx.commit() |
|
119 rset = req.execute('Any S WHERE X salaire_total S, X nom "Foo"') |
|
120 self.assertEqual(rset[0][0], 3000) |
|
121 # Update attribute. |
|
122 self.tata.cw_set(salaire=1000) |
|
123 req.cnx.commit() |
|
124 rset = req.execute('Any S WHERE X salaire_total S, X nom "Foo"') |
|
125 self.assertEqual(rset[0][0], 2000) |
|
126 |
|
127 def test_init_on_entity_creation(self): |
|
128 """check the computed attribute is initialized on entity creation""" |
|
129 with self.admin_access.web_request() as req: |
|
130 p = req.create_entity('Person', name=u'Tata', salaire=2000, |
|
131 birth_year=1990) |
|
132 req.cnx.commit() |
|
133 rset = req.execute('Any A, X WHERE X age A, X name "Tata"') |
|
134 self.assertEqual(rset[0][0], 2014 - 1990) |
|
135 |
|
136 |
|
137 if __name__ == '__main__': |
|
138 from logilab.common.testlib import unittest_main |
|
139 unittest_main() |