test/unittest_rqlrewrite.py
branchstable
changeset 9168 0fb4b67bde58
parent 8342 7a5271182ef0
child 9170 e6fe77dbcfdf
equal deleted inserted replaced
9167:c05652b108ce 9168:0fb4b67bde58
     1 # copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
     1 # copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
     2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
     2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
     3 #
     3 #
     4 # This file is part of CubicWeb.
     4 # This file is part of CubicWeb.
     5 #
     5 #
     6 # CubicWeb is free software: you can redistribute it and/or modify it under the
     6 # CubicWeb is free software: you can redistribute it and/or modify it under the
    21 from yams import BadSchemaDefinition
    21 from yams import BadSchemaDefinition
    22 from rql import parse, nodes, RQLHelper
    22 from rql import parse, nodes, RQLHelper
    23 
    23 
    24 from cubicweb import Unauthorized, rqlrewrite
    24 from cubicweb import Unauthorized, rqlrewrite
    25 from cubicweb.schema import RRQLExpression, ERQLExpression
    25 from cubicweb.schema import RRQLExpression, ERQLExpression
    26 from cubicweb.devtools import repotest, TestServerConfiguration
    26 from cubicweb.devtools import repotest, TestServerConfiguration, BaseApptestConfiguration
    27 
    27 
    28 
    28 
    29 def setUpModule(*args):
    29 def setUpModule(*args):
    30     global rqlhelper, schema
    30     global rqlhelper, schema
    31     config = TestServerConfiguration(RQLRewriteTC.datapath('rewrite'))
    31     config = TestServerConfiguration(RQLRewriteTC.datapath('rewrite'))
    44     global rqlhelper, schema
    44     global rqlhelper, schema
    45     del rqlhelper, schema
    45     del rqlhelper, schema
    46 
    46 
    47 def eid_func_map(eid):
    47 def eid_func_map(eid):
    48     return {1: 'CWUser',
    48     return {1: 'CWUser',
    49             2: 'Card'}[eid]
    49             2: 'Card',
       
    50             3: 'Affaire'}[eid]
    50 
    51 
    51 def rewrite(rqlst, snippets_map, kwargs, existingvars=None):
    52 def rewrite(rqlst, snippets_map, kwargs, existingvars=None):
    52     class FakeVReg:
    53     class FakeVReg:
    53         schema = schema
    54         schema = schema
    54         @staticmethod
    55         @staticmethod
   200                              'EXISTS(X created_by B), EXISTS(Y created_by B), '
   201                              'EXISTS(X created_by B), EXISTS(Y created_by B), '
   201                              'X is Card, Y is IN(Division, Note, Societe) '
   202                              'X is Card, Y is IN(Division, Note, Societe) '
   202                              'WITH LA BEING (Any LA WHERE (EXISTS(A created_by B, LA documented_by A)) OR (EXISTS(E created_by B, LA concerne E)), '
   203                              'WITH LA BEING (Any LA WHERE (EXISTS(A created_by B, LA documented_by A)) OR (EXISTS(E created_by B, LA concerne E)), '
   203                              'B eid %(D)s, LA is Affaire)')
   204                              'B eid %(D)s, LA is Affaire)')
   204 
   205 
       
   206 
       
   207     def test_ambiguous_optional_same_exprs(self):
       
   208         """See #3013535"""
       
   209         # see test of the same name in RewriteFullTC: original problem is
       
   210         # unreproducible here because it actually lies in
       
   211         # RQLRewriter.insert_local_checks
       
   212         rqlst = parse('Any A,AR,X,CD WHERE A concerne X?, A ref AR, A eid %(a)s, X creation_date CD')
       
   213         rewrite(rqlst, {('X', 'X'): ('X created_by U',),}, {'a': 3})
       
   214         self.assertEqual(rqlst.as_string(),
       
   215                          u'Any A,AR,X,CD WHERE A concerne X?, A ref AR, A eid %(a)s WITH X,CD BEING (Any X,CD WHERE X creation_date CD, EXISTS(X created_by B), B eid %(A)s, X is IN(Division, Note, Societe))')
       
   216 
   205     def test_optional_var_inlined(self):
   217     def test_optional_var_inlined(self):
   206         c1 = ('X require_permission P')
   218         c1 = ('X require_permission P')
   207         c2 = ('X inlined_card O, O require_permission P')
   219         c2 = ('X inlined_card O, O require_permission P')
   208         rqlst = parse('Any C,A,R WHERE A? inlined_card C, A ref R')
   220         rqlst = parse('Any C,A,R WHERE A? inlined_card C, A ref R')
   209         rewrite(rqlst, {('C', 'X'): (c1,),
   221         rewrite(rqlst, {('C', 'X'): (c1,),
   290         rqlst = parse('Card C WHERE C in_state STATE')
   302         rqlst = parse('Card C WHERE C in_state STATE')
   291         rewrite(rqlst, {('C', 'X'): (snippet,)}, {})
   303         rewrite(rqlst, {('C', 'X'): (snippet,)}, {})
   292         self.assertEqual(rqlst.as_string(),
   304         self.assertEqual(rqlst.as_string(),
   293                          "Any C WHERE C in_state STATE, C is Card, "
   305                          "Any C WHERE C in_state STATE, C is Card, "
   294                          "EXISTS(STATE name 'hop'), STATE is State")
   306                          "EXISTS(STATE name 'hop'), STATE is State")
       
   307 
   295     def test_relation_optimization_3_rhs(self):
   308     def test_relation_optimization_3_rhs(self):
   296         snippet = ('TW? subworkflow_exit X, TW name "hop"')
   309         snippet = ('TW? subworkflow_exit X, TW name "hop"')
   297         rqlst = parse('WorkflowTransition C WHERE C subworkflow_exit EXIT')
   310         rqlst = parse('WorkflowTransition C WHERE C subworkflow_exit EXIT')
   298         rewrite(rqlst, {('EXIT', 'X'): (snippet,)}, {})
   311         rewrite(rqlst, {('EXIT', 'X'): (snippet,)}, {})
   299         self.assertEqual(rqlst.as_string(),
   312         self.assertEqual(rqlst.as_string(),
   306         rqlst = parse('Card C WHERE C in_state STATE?')
   319         rqlst = parse('Card C WHERE C in_state STATE?')
   307         rewrite(rqlst, {('C', 'X'): (snippet,)}, {})
   320         rewrite(rqlst, {('C', 'X'): (snippet,)}, {})
   308         self.assertEqual(rqlst.as_string(),
   321         self.assertEqual(rqlst.as_string(),
   309                          "Any C WHERE C in_state STATE?, C is Card, "
   322                          "Any C WHERE C in_state STATE?, C is Card, "
   310                          "EXISTS(C in_state A, A name 'hop', A is State), STATE is State")
   323                          "EXISTS(C in_state A, A name 'hop', A is State), STATE is State")
       
   324 
   311     def test_relation_non_optimization_1_rhs(self):
   325     def test_relation_non_optimization_1_rhs(self):
   312         snippet = ('TW subworkflow_exit X, TW name "hop"')
   326         snippet = ('TW subworkflow_exit X, TW name "hop"')
   313         rqlst = parse('SubWorkflowExitPoint EXIT WHERE C? subworkflow_exit EXIT')
   327         rqlst = parse('SubWorkflowExitPoint EXIT WHERE C? subworkflow_exit EXIT')
   314         rewrite(rqlst, {('EXIT', 'X'): (snippet,)}, {})
   328         rewrite(rqlst, {('EXIT', 'X'): (snippet,)}, {})
   315         self.assertEqual(rqlst.as_string(),
   329         self.assertEqual(rqlst.as_string(),
   457         c_bad = ERQLExpression('X documented_by R, A in_state R')
   471         c_bad = ERQLExpression('X documented_by R, A in_state R')
   458 
   472 
   459         rqlst = parse('Any A, R WHERE A ref R, S is Affaire')
   473         rqlst = parse('Any A, R WHERE A ref R, S is Affaire')
   460         rewrite(rqlst, {('A', 'X'): (c_ok, c_bad)}, {})
   474         rewrite(rqlst, {('A', 'X'): (c_ok, c_bad)}, {})
   461 
   475 
       
   476 
       
   477 from cubicweb.devtools.testlib import CubicWebTC
       
   478 from logilab.common.decorators import classproperty
       
   479 
       
   480 class RewriteFullTC(CubicWebTC):
       
   481     @classproperty
       
   482     def config(cls):
       
   483         return BaseApptestConfiguration(apphome=cls.datapath('rewrite'))
       
   484 
       
   485     def process(self, rql, args=None):
       
   486         if args is None:
       
   487             args = {}
       
   488         querier = self.repo.querier
       
   489         union = querier.parse(rql)
       
   490         querier.solutions(self.session, union, args)
       
   491         querier._annotate(union)
       
   492         plan = querier.plan_factory(union, args, self.session)
       
   493         plan.preprocess(union)
       
   494         return union
       
   495 
       
   496     def test_ambiguous_optional_same_exprs(self):
       
   497         """See #3013535"""
       
   498         edef1 = self.schema['Societe']
       
   499         edef2 = self.schema['Division']
       
   500         edef3 = self.schema['Note']
       
   501         with self.temporary_permissions((edef1, {'read': (ERQLExpression('X owned_by U'),)}),
       
   502                                         (edef2, {'read': (ERQLExpression('X owned_by U'),)}),
       
   503                                         (edef3, {'read': (ERQLExpression('X owned_by U'),)})):
       
   504             union = self.process('Any A,AR,X,CD WHERE A concerne X?, A ref AR, X creation_date CD')
       
   505             self.assertEqual(union.as_string(), 'Any A,AR,X,CD WHERE A concerne X?, A ref AR, A is Affaire WITH X,CD BEING (Any X,CD WHERE X creation_date CD, EXISTS(X owned_by %(A)s), X is IN(Division, Note, Societe))')
       
   506 
       
   507 
   462 if __name__ == '__main__':
   508 if __name__ == '__main__':
   463     unittest_main()
   509     unittest_main()