unittest_magicsearch.py 10.8 KB
Newer Older
Adrien Di Mascio's avatar
Adrien Di Mascio committed
1
# -*- coding: utf-8 -*-
2
3
4
5
6
7
8
"""Unit tests for magic_search service

:organization: Logilab
:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
"""
Adrien Di Mascio's avatar
Adrien Di Mascio committed
9
10
11
12
13
14
15
16
17
18
19

import sys

from logilab.common.testlib import TestCase, unittest_main

from rql import BadRQLQuery, RQLSyntaxError

from cubicweb.devtools.apptest import EnvBasedTC, TestEnvironment


translations = {
20
    u'CWUser' : u"Utilisateur",
Adrien Di Mascio's avatar
Adrien Di Mascio committed
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#    u'Workcase' : u"Affaire",
    u'EmailAddress' : u"Adresse",
#    u'Division' : u"Division",
#    u'Comment' : u"Commentaire",
    u'name' : u"nom",
    u'alias' : u"nom",
    u'surname' : u"nom",
    u'firstname' : u"prénom",
    u'state' : u"état",
#    u'subject' : u"sujet",
    u'address' : u"adresse",
    u'use_email' : u"adel",
    }
def _translate(msgid):
    return translations.get(msgid, msgid)


from cubicweb.web.views.magicsearch import translate_rql_tree, QSPreProcessor, QueryTranslator

class QueryTranslatorTC(EnvBasedTC):
    """test suite for QueryTranslatorTC"""
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
42

Adrien Di Mascio's avatar
Adrien Di Mascio committed
43
44
45
46
    def setUp(self):
        super(QueryTranslatorTC, self).setUp()
        self.req = self.env.create_request()
        self.vreg.config.translations = {'en': _translate}
47
        proc = self.vreg.select('components', 'magicsearch', self.req)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
        self.proc = [p for p in proc.processors if isinstance(p, QueryTranslator)][0]

    def test_basic_translations(self):
        """tests basic translations (no ambiguities)"""
        rql = "Any C WHERE C is Adresse, P adel C, C adresse 'Logilab'"
        rql, = self.proc.preprocess_query(rql, self.req)
        self.assertEquals(rql, "Any C WHERE C is EmailAddress, P use_email C, C address 'Logilab'")

    def test_ambiguous_translations(self):
        """tests possibly ambiguous translations"""
        rql = "Any P WHERE P adel C, C is EmailAddress, C nom 'Logilab'"
        rql, = self.proc.preprocess_query(rql, self.req)
        self.assertEquals(rql, "Any P WHERE P use_email C, C is EmailAddress, C alias 'Logilab'")
        rql = "Any P WHERE P is Utilisateur, P adel C, P nom 'Smith'"
        rql, = self.proc.preprocess_query(rql, self.req)
63
        self.assertEquals(rql, "Any P WHERE P is CWUser, P use_email C, P surname 'Smith'")
Adrien Di Mascio's avatar
Adrien Di Mascio committed
64
65
66
67
68
69
70
71


class QSPreProcessorTC(EnvBasedTC):
    """test suite for QSPreProcessor"""
    def setUp(self):
        super(QSPreProcessorTC, self).setUp()
        self.vreg.config.translations = {'en': _translate}
        self.req = self.request()
72
        proc = self.vreg.select('components', 'magicsearch', self.req)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
        self.proc = [p for p in proc.processors if isinstance(p, QSPreProcessor)][0]
        self.proc.req = self.req

    def test_entity_translation(self):
        """tests QSPreProcessor._get_entity_name()"""
        translate = self.proc._get_entity_type
        self.assertEquals(translate(u'EmailAddress'), "EmailAddress")
        self.assertEquals(translate(u'emailaddress'), "EmailAddress")
        self.assertEquals(translate(u'Adresse'), "EmailAddress")
        self.assertEquals(translate(u'adresse'), "EmailAddress")
        self.assertRaises(BadRQLQuery, translate, 'whatever')

    def test_attribute_translation(self):
        """tests QSPreProcessor._get_attribute_name"""
        translate = self.proc._get_attribute_name
88
        eschema = self.schema.eschema('CWUser')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
89
90
91
        self.assertEquals(translate(u'prénom', eschema), "firstname")
        self.assertEquals(translate(u'nom', eschema), 'surname')
        #self.assert_(translate(u'nom') in ('name', 'surname'))
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
92
        eschema = self.schema.eschema('EmailAddress')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
93
94
95
96
97
98
99
100
101
102
103
        self.assertEquals(translate(u'adresse', eschema), "address")
        self.assertEquals(translate(u'nom', eschema), 'alias')
        # should fail if the name is not an attribute for the given entity schema
        self.assertRaises(BadRQLQuery, translate, 'whatever', eschema)
        self.assertRaises(BadRQLQuery, translate, 'prénom', eschema)

    def test_one_word_query(self):
        """tests the 'one word shortcut queries'"""
        transform = self.proc._one_word_query
        self.assertEquals(transform('123'),
                          ('Any X WHERE X eid %(x)s', {'x': 123}, 'x'))
104
        self.assertEquals(transform('CWUser'),
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
105
                          ('CWUser C',))
Adrien Di Mascio's avatar
Adrien Di Mascio committed
106
        self.assertEquals(transform('Utilisateur'),
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
107
                          ('CWUser C',))
Adrien Di Mascio's avatar
Adrien Di Mascio committed
108
109
110
111
112
113
114
115
116
        self.assertEquals(transform('Adresse'),
                          ('EmailAddress E',))
        self.assertEquals(transform('adresse'),
                          ('EmailAddress E',))
        self.assertRaises(BadRQLQuery, transform, 'Workcases')

    def test_two_words_query(self):
        """tests the 'two words shortcut queries'"""
        transform = self.proc._two_words_query
117
118
119
        self.assertEquals(transform('CWUser', 'E'),
                          ("CWUser E",))
        self.assertEquals(transform('CWUser', 'Smith'),
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
120
                          ('CWUser C WHERE C has_text %(text)s', {'text': 'Smith'}))
Adrien Di Mascio's avatar
Adrien Di Mascio committed
121
        self.assertEquals(transform('utilisateur', 'Smith'),
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
122
                          ('CWUser C WHERE C has_text %(text)s', {'text': 'Smith'}))
Adrien Di Mascio's avatar
Adrien Di Mascio committed
123
124
125
126
127
        self.assertEquals(transform(u'adresse', 'Logilab'),
                          ('EmailAddress E WHERE E has_text %(text)s', {'text': 'Logilab'}))
        self.assertEquals(transform(u'adresse', 'Logi%'),
                          ('EmailAddress E WHERE E alias LIKE %(text)s', {'text': 'Logi%'}))
        self.assertRaises(BadRQLQuery, transform, "pers", "taratata")
128
        #self.assertEquals(transform('CWUser', '%mi'), 'CWUser E WHERE P surname LIKE "%mi"')
Adrien Di Mascio's avatar
Adrien Di Mascio committed
129
130
131
132
133

    def test_three_words_query(self):
        """tests the 'three words shortcut queries'"""
        transform = self.proc._three_words_query
        self.assertEquals(transform('utilisateur', u'prénom', 'cubicweb'),
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
134
                          ('CWUser C WHERE C firstname %(text)s', {'text': 'cubicweb'}))
Adrien Di Mascio's avatar
Adrien Di Mascio committed
135
        self.assertEquals(transform('utilisateur', 'nom', 'cubicweb'),
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
136
                          ('CWUser C WHERE C surname %(text)s', {'text': 'cubicweb'}))
Adrien Di Mascio's avatar
Adrien Di Mascio committed
137
138
139
        self.assertEquals(transform(u'adresse', 'nom', 'cubicweb'),
                          ('EmailAddress E WHERE E alias %(text)s', {'text': 'cubicweb'}))
        self.assertEquals(transform('EmailAddress', 'nom', 'cubicweb'),
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
140
                          ('EmailAddress E WHERE E alias %(text)s', {'text': 'cubicweb'}))
Adrien Di Mascio's avatar
Adrien Di Mascio committed
141
        self.assertEquals(transform('utilisateur', u'prénom', 'cubicweb%'),
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
142
                          ('CWUser C WHERE C firstname LIKE %(text)s', {'text': 'cubicweb%'}))
Adrien Di Mascio's avatar
Adrien Di Mascio committed
143
        # expanded shortcuts
144
        self.assertEquals(transform('CWUser', 'use_email', 'Logilab'),
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
145
                          ('CWUser C WHERE C use_email C1, C1 has_text %(text)s', {'text': 'Logilab'}))
146
        self.assertEquals(transform('CWUser', 'use_email', '%Logilab'),
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
147
                          ('CWUser C WHERE C use_email C1, C1 alias LIKE %(text)s', {'text': '%Logilab'}))
Adrien Di Mascio's avatar
Adrien Di Mascio committed
148
        self.assertRaises(BadRQLQuery, transform, 'word1', 'word2', 'word3')
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
149

Adrien Di Mascio's avatar
Adrien Di Mascio committed
150
151
152
153
154
155
156
157
158
    def test_multiple_words_query(self):
        """tests multiple_words_query()"""
        self.assertEquals(self.proc._multiple_words_query(['a', 'b', 'c', 'd', 'e']),
                          ('a b c d e',))

    def test_quoted_queries(self):
        """tests how quoted queries are handled"""
        queries = [
            (u'Adresse "My own EmailAddress"', ('EmailAddress E WHERE E has_text %(text)s', {'text': u'My own EmailAddress'})),
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
159
160
161
            (u'Utilisateur prénom "Jean Paul"', ('CWUser C WHERE C firstname %(text)s', {'text': 'Jean Paul'})),
            (u'Utilisateur firstname "Jean Paul"', ('CWUser C WHERE C firstname %(text)s', {'text': 'Jean Paul'})),
            (u'CWUser firstname "Jean Paul"', ('CWUser C WHERE C firstname %(text)s', {'text': 'Jean Paul'})),
Adrien Di Mascio's avatar
Adrien Di Mascio committed
162
163
164
165
166
167
            ]
        transform = self.proc._quoted_words_query
        for query, expected in queries:
            self.assertEquals(transform(query), expected)
        self.assertRaises(BadRQLQuery, transform, "unquoted rql")
        self.assertRaises(BadRQLQuery, transform, 'pers "Jean Paul"')
168
        self.assertRaises(BadRQLQuery, transform, 'CWUser firstname other "Jean Paul"')
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
169

Adrien Di Mascio's avatar
Adrien Di Mascio committed
170
171
172
    def test_process_query(self):
        """tests how queries are processed"""
        queries = [
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
173
            (u'Utilisateur', (u"CWUser C",)),
174
            (u'Utilisateur P', (u"CWUser P",)),
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
175
176
            (u'Utilisateur cubicweb', (u'CWUser C WHERE C has_text %(text)s', {'text': u'cubicweb'})),
            (u'CWUser prénom cubicweb', (u'CWUser C WHERE C firstname %(text)s', {'text': 'cubicweb'},)),
Adrien Di Mascio's avatar
Adrien Di Mascio committed
177
178
179
180
            (u'Any X WHERE X is Something', (u"Any X WHERE X is Something",)),
            ]
        for query, expected in queries:
            self.assertEquals(self.proc.preprocess_query(query, self.req), expected)
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
181

Adrien Di Mascio's avatar
Adrien Di Mascio committed
182
183
184


## Processor Chains tests ############################################
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
185

Adrien Di Mascio's avatar
Adrien Di Mascio committed
186
187
188
189
190
191
192
193

class ProcessorChainTC(EnvBasedTC):
    """test suite for magic_search's processor chains"""

    def setUp(self):
        super(ProcessorChainTC, self).setUp()
        self.vreg.config.translations = {'en': _translate}
        self.req = self.request()
194
        self.proc = self.vreg.select('components', 'magicsearch', self.req)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
195
196
197
198
199
200
201
202
203

    def test_main_preprocessor_chain(self):
        """tests QUERY_PROCESSOR"""
        queries = [
            (u'foo',
             ("Any X WHERE X has_text %(text)s", {'text': u'foo'})),
            # XXX this sounds like a language translator test...
            # and it fail
            (u'Utilisateur Smith',
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
204
             ('CWUser C WHERE C has_text %(text)s', {'text': u'Smith'})),
Adrien Di Mascio's avatar
Adrien Di Mascio committed
205
            (u'utilisateur nom Smith',
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
206
             ('CWUser C WHERE C surname %(text)s', {'text': u'Smith'})),
Adrien Di Mascio's avatar
Adrien Di Mascio committed
207
            (u'Any P WHERE P is Utilisateur, P nom "Smith"',
208
             ('Any P WHERE P is CWUser, P surname "Smith"', None)),
Adrien Di Mascio's avatar
Adrien Di Mascio committed
209
210
211
212
213
214
215
216
217
218
219
220
221
            ]
        for query, expected in queries:
            rset = self.proc.process_query(query, self.req)
            self.assertEquals((rset.rql, rset.args), expected)

    def test_iso88591_fulltext(self):
        """we must be able to type accentuated characters in the search field"""
        rset = self.proc.process_query(u'écrire', self.req)
        self.assertEquals(rset.rql, "Any X WHERE X has_text %(text)s")
        self.assertEquals(rset.args, {'text': u'écrire'})

    def test_explicit_component(self):
        self.assertRaises(RQLSyntaxError,
222
                          self.proc.process_query, u'rql: CWUser E WHERE E noattr "Smith",', self.req)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
223
        self.assertRaises(BadRQLQuery,
224
                          self.proc.process_query, u'rql: CWUser E WHERE E noattr "Smith"', self.req)
Adrien Di Mascio's avatar
Adrien Di Mascio committed
225
226
227
        rset = self.proc.process_query(u'text: utilisateur Smith', self.req)
        self.assertEquals(rset.rql, 'Any X WHERE X has_text %(text)s')
        self.assertEquals(rset.args, {'text': u'utilisateur Smith'})
sylvain.thenault@logilab.fr's avatar
sylvain.thenault@logilab.fr committed
228

Adrien Di Mascio's avatar
Adrien Di Mascio committed
229
230
if __name__ == '__main__':
    unittest_main()