Fixed tests for Xapian 1.3.

Changes were mostly on how the query parser parsed a query.
Probabily we should not test that anyway, but for now
it is passing in 1.3.3
This commit is contained in:
Jorge C. Leitão 2015-11-14 08:37:32 +01:00
parent 4fc3d749c8
commit 63cfcc1d73
3 changed files with 194 additions and 162 deletions

View File

@ -1,5 +1,5 @@
import os
from settings import *
from .settings import *
INSTALLED_APPS = [
'test_haystack.core',

View File

@ -9,6 +9,7 @@ import os
from django.test import TestCase
from django.db.models.loading import get_model
from django.utils.encoding import force_text
from haystack import connections
from haystack.backends.xapian_backend import InvalidIndexError, _term_to_xapian_value
@ -20,6 +21,9 @@ from ..search_indexes import XapianNGramIndex, XapianEdgeNGramIndex, \
from ..models import BlogEntry, AnotherMockModel, MockTag
XAPIAN_VERSION = [int(x) for x in xapian.__version__.split('.')]
class XapianSearchResult(SearchResult):
def __init__(self, app_label, model_name, pk, score, **kwargs):
super(XapianSearchResult, self).__init__(app_label, model_name, pk, score, **kwargs)
@ -27,7 +31,18 @@ class XapianSearchResult(SearchResult):
def get_terms(backend, *args):
result = subprocess.check_output(['delve'] + list(args) + [backend.path],
if XAPIAN_VERSION[1] <= 2:
# old versions use "delve".
executable = 'delve'
else:
# new versions use 'xapian-delve'
executable = 'xapian-delve'
# dev versions (odd minor) use a suffix
if XAPIAN_VERSION[1] % 2 != 0:
executable = executable+'-%d.%d' % tuple(XAPIAN_VERSION[0:2])
result = subprocess.check_output([executable] + list(args) + [backend.path],
env=os.environ.copy()).decode('utf-8')
result = result.split(": ")
if len(result) > 1:
@ -63,6 +78,22 @@ class HaystackBackendTestCase(object):
self.backend.clear()
connections['default']._index = self.old_ui
def assertExpectedQuery(self, query, string_or_list, xapian12string=''):
if isinstance(string_or_list, list):
strings = string_or_list
else:
strings = [string_or_list]
expected = ['Query(%s)' % string for string in strings]
if XAPIAN_VERSION[1] <= 2:
if xapian12string:
expected = ['Xapian::Query(%s)' % xapian12string]
else:
expected = ['Xapian::Query(%s)' % string for string in strings]
self.assertIn(str(query), expected)
class BackendIndexationTestCase(HaystackBackendTestCase, TestCase):
"""
@ -362,8 +393,8 @@ class BackendFeaturesTestCase(HaystackBackendTestCase, TestCase):
results = self.backend.search(xapian.Query('indexed'), facets=['sites'])
self.assertEqual(results['hits'], 3)
self.assertEqual(results['facets']['fields']['sites'],
[('1', 1), ('3', 2), ('2', 2), ('4', 1), ('6', 2), ('9', 1)])
self.assertEqual(set(results['facets']['fields']['sites']),
set([('1', 1), ('3', 2), ('2', 2), ('4', 1), ('6', 2), ('9', 1)]))
results = self.backend.search(xapian.Query('indexed'),
facets=['number'])
@ -541,7 +572,7 @@ class BackendFeaturesTestCase(HaystackBackendTestCase, TestCase):
self.assertEqual(_term_to_xapian_value([1, 2, 3], 'text'), '[1, 2, 3]')
self.assertEqual(_term_to_xapian_value((1, 2, 3), 'text'), '(1, 2, 3)')
self.assertEqual(_term_to_xapian_value({'a': 1, 'c': 3, 'b': 2}, 'text'),
"{u'a': 1, u'c': 3, u'b': 2}")
force_text({'a': 1, 'c': 3, 'b': 2}))
self.assertEqual(_term_to_xapian_value(datetime.datetime(2009, 5, 9, 16, 14), 'datetime'),
'20090509161400')
self.assertEqual(_term_to_xapian_value(datetime.datetime(2009, 5, 9, 0, 0), 'date'),
@ -576,17 +607,20 @@ class BackendFeaturesTestCase(HaystackBackendTestCase, TestCase):
])
def test_parse_query(self):
self.assertEqual(str(self.backend.parse_query('indexed')),
'Xapian::Query(Zindex:(pos=1))')
self.assertEqual(str(self.backend.parse_query('name:david')),
'Xapian::Query(ZXNAMEdavid:(pos=1))')
self.assertExpectedQuery(self.backend.parse_query('indexed'), 'Zindex@1',
xapian12string='Zindex:(pos=1)')
self.assertExpectedQuery(self.backend.parse_query('name:david'),
'ZXNAMEdavid@1', xapian12string='ZXNAMEdavid:(pos=1)')
if xapian.minor_version() >= 2:
self.assertEqual(str(self.backend.parse_query('name:da*')),
'Xapian::Query(('
'XNAMEdavid1:(pos=1) SYNONYM '
'XNAMEdavid2:(pos=1) SYNONYM '
'XNAMEdavid3:(pos=1)))')
# todo: why `SYNONYM WILDCARD OR XNAMEda`?
self.assertExpectedQuery(
self.backend.parse_query('name:da*'),
'(SYNONYM WILDCARD OR XNAMEda)',
xapian12string='(XNAMEdavid1:(pos=1) SYNONYM '
'XNAMEdavid2:(pos=1) SYNONYM '
'XNAMEdavid3:(pos=1))')
else:
self.assertEqual(str(self.backend.parse_query('name:da*')),
'Xapian::Query(('
@ -594,20 +628,19 @@ class BackendFeaturesTestCase(HaystackBackendTestCase, TestCase):
'XNAMEdavid2:(pos=1) OR '
'XNAMEdavid3:(pos=1)))')
self.assertEqual(str(self.backend.parse_query('name:david1..david2')),
'Xapian::Query(VALUE_RANGE 9 david1 david2)')
self.assertEqual(str(self.backend.parse_query('number:0..10')),
'Xapian::Query(VALUE_RANGE 11 000000000000 000000000010)')
self.assertEqual(str(self.backend.parse_query('number:..10')),
'Xapian::Query(VALUE_RANGE 11 %012d 000000000010)' % (-sys.maxsize - 1))
self.assertEqual(str(self.backend.parse_query('number:10..*')),
'Xapian::Query(VALUE_RANGE 11 000000000010 %012d)' % sys.maxsize)
self.assertEqual(str(self.backend.parse_query('float_number:25.5..*')),
b'Xapian::Query(VALUE_RANGE 7 \xb2` \xff\xff\xff\xff\xff\xff\xff\xff\xff)')
self.assertEqual(str(self.backend.parse_query('float_number:..25.5')),
b'Xapian::Query(VALUE_RANGE 7 \xb2`)')
self.assertEqual(str(self.backend.parse_query('float_number:25.5..100.0')),
b'Xapian::Query(VALUE_RANGE 7 \xb2` \xba@)')
def test_parse_query_range(self):
self.assertExpectedQuery(self.backend.parse_query('name:david1..david2'),
'0 * VALUE_RANGE 9 david1 david2',
xapian12string='VALUE_RANGE 9 david1 david2')
self.assertExpectedQuery(self.backend.parse_query('number:0..10'),
'0 * VALUE_RANGE 11 000000000000 000000000010',
xapian12string='VALUE_RANGE 11 000000000000 000000000010')
self.assertExpectedQuery(self.backend.parse_query('number:..10'),
'0 * VALUE_RANGE 11 %012d 000000000010' % (-sys.maxsize - 1),
xapian12string='VALUE_RANGE 11 %012d 000000000010' % (-sys.maxsize - 1))
self.assertExpectedQuery(self.backend.parse_query('number:10..*'),
'0 * VALUE_RANGE 11 000000000010 %012d' % sys.maxsize,
xapian12string='VALUE_RANGE 11 000000000010 %012d' % sys.maxsize)
def test_order_by_django_id(self):
"""

View File

@ -29,177 +29,177 @@ class XapianSearchQueryTestCase(HaystackBackendTestCase, TestCase):
self.sq = connections['default'].get_query()
def test_all(self):
self.assertEqual(str(self.sq.build_query()),
'Xapian::Query(<alldocuments>)')
self.assertExpectedQuery(self.sq.build_query(), '<alldocuments>')
def test_single_word(self):
self.sq.add_filter(SQ(content='hello'))
self.assertEqual(str(self.sq.build_query()),
'Xapian::Query((Zhello OR hello))')
self.assertExpectedQuery(self.sq.build_query(), '(Zhello OR hello)')
def test_single_word_not(self):
self.sq.add_filter(~SQ(content='hello'))
self.assertEqual(str(self.sq.build_query()),
'Xapian::Query((<alldocuments> AND_NOT (Zhello OR hello)))')
self.assertExpectedQuery(self.sq.build_query(),
'(<alldocuments> AND_NOT (Zhello OR hello))')
def test_single_word_field_exact(self):
self.sq.add_filter(SQ(foo='hello'))
self.assertEqual(str(self.sq.build_query()),
'Xapian::Query((ZXFOOhello OR XFOOhello))')
self.assertExpectedQuery(self.sq.build_query(),
'(ZXFOOhello OR XFOOhello)')
def test_single_word_field_exact_not(self):
self.sq.add_filter(~SQ(foo='hello'))
self.assertEqual(str(self.sq.build_query()),
'Xapian::Query((<alldocuments> AND_NOT (ZXFOOhello OR XFOOhello)))')
self.assertExpectedQuery(self.sq.build_query(),
'(<alldocuments> AND_NOT '
'(ZXFOOhello OR XFOOhello))')
def test_boolean(self):
self.sq.add_filter(SQ(content=True))
self.assertEqual(str(self.sq.build_query()),
'Xapian::Query((Ztrue OR true))')
self.assertExpectedQuery(self.sq.build_query(), '(Ztrue OR true)')
def test_date(self):
self.sq.add_filter(SQ(content=datetime.date(2009, 5, 8)))
self.assertEqual(str(self.sq.build_query()),
'Xapian::Query((Z2009-05-08 OR 2009-05-08))')
self.assertExpectedQuery(self.sq.build_query(),
'(Z2009-05-08 OR 2009-05-08)')
def test_date_not(self):
self.sq.add_filter(~SQ(content=datetime.date(2009, 5, 8)))
self.assertEqual(str(self.sq.build_query()),
'Xapian::Query((<alldocuments> AND_NOT (Z2009-05-08 OR 2009-05-08)))')
self.assertExpectedQuery(self.sq.build_query(),
'(<alldocuments> AND_NOT '
'(Z2009-05-08 OR 2009-05-08))')
def test_datetime(self):
self.sq.add_filter(SQ(content=datetime.datetime(2009, 5, 8, 11, 28)))
self.assertEqual(str(self.sq.build_query()),
'Xapian::Query((Z2009-05-08 OR 2009-05-08 OR Z11:28:00 OR 11:28:00))')
self.assertExpectedQuery(self.sq.build_query(),
'((Z2009-05-08 OR 2009-05-08) OR'
' (Z11:28:00 OR 11:28:00))',
xapian12string='(Z2009-05-08 OR 2009-05-08 OR'
' Z11:28:00 OR 11:28:00)')
def test_datetime_not(self):
self.sq.add_filter(~SQ(content=datetime.datetime(2009, 5, 8, 11, 28)))
self.assertEqual(str(self.sq.build_query()),
'Xapian::Query((<alldocuments> AND_NOT '
'(Z2009-05-08 OR 2009-05-08 OR Z11:28:00 OR 11:28:00)))')
self.assertExpectedQuery(self.sq.build_query(),
'(<alldocuments> AND_NOT ((Z2009-05-08 OR 2009-05-08) OR (Z11:28:00 OR 11:28:00)))',
xapian12string='(<alldocuments> AND_NOT '
'(Z2009-05-08 OR 2009-05-08 OR'
' Z11:28:00 OR 11:28:00))')
def test_float(self):
self.sq.add_filter(SQ(content=25.52))
self.assertEqual(str(self.sq.build_query()),
'Xapian::Query((Z25.52 OR 25.52))')
self.assertExpectedQuery(self.sq.build_query(), '(Z25.52 OR 25.52)')
def test_multiple_words_and(self):
self.sq.add_filter(SQ(content='hello'))
self.sq.add_filter(SQ(content='world'))
self.assertEqual(str(self.sq.build_query()),
'Xapian::Query(((Zhello OR hello) AND (Zworld OR world)))')
self.assertExpectedQuery(self.sq.build_query(),
'((Zhello OR hello) AND (Zworld OR world))')
def test_multiple_words_not(self):
self.sq.add_filter(~SQ(content='hello'))
self.sq.add_filter(~SQ(content='world'))
self.assertEqual(str(self.sq.build_query()),
'Xapian::Query(('
'(<alldocuments> AND_NOT (Zhello OR hello)) AND '
'(<alldocuments> AND_NOT (Zworld OR world))))')
self.assertExpectedQuery(self.sq.build_query(),
'((<alldocuments> AND_NOT (Zhello OR hello)) AND'
' (<alldocuments> AND_NOT (Zworld OR world)))')
def test_multiple_words_or(self):
self.sq.add_filter(SQ(content='hello') | SQ(content='world'))
self.assertEqual(str(self.sq.build_query()),
'Xapian::Query((Zhello OR hello OR Zworld OR world))')
self.assertExpectedQuery(
self.sq.build_query(),
'((Zhello OR hello) OR (Zworld OR world))',
xapian12string='(Zhello OR hello OR Zworld OR world)')
def test_multiple_words_or_not(self):
self.sq.add_filter(~SQ(content='hello') | ~SQ(content='world'))
self.assertEqual(str(self.sq.build_query()),
'Xapian::Query(('
'(<alldocuments> AND_NOT (Zhello OR hello)) OR '
'(<alldocuments> AND_NOT (Zworld OR world))))')
self.assertExpectedQuery(self.sq.build_query(),
'((<alldocuments> AND_NOT (Zhello OR hello)) OR'
' (<alldocuments> AND_NOT (Zworld OR world)))')
def test_multiple_words_mixed(self):
self.sq.add_filter(SQ(content='why') | SQ(content='hello'))
self.sq.add_filter(~SQ(content='world'))
self.assertEqual(str(self.sq.build_query()),
'Xapian::Query(('
'(Zwhi OR why OR Zhello OR hello) AND '
'(<alldocuments> AND_NOT (Zworld OR world))))')
self.assertExpectedQuery(
self.sq.build_query(),
'(((Zwhi OR why) OR (Zhello OR hello)) AND '
'(<alldocuments> AND_NOT (Zworld OR world)))',
xapian12string='((Zwhi OR why OR Zhello OR hello) AND'
' (<alldocuments> AND_NOT (Zworld OR world)))',)
def test_multiple_word_field_exact(self):
self.sq.add_filter(SQ(foo='hello'))
self.sq.add_filter(SQ(title='world'))
self.assertEqual(str(self.sq.build_query()),
'Xapian::Query(('
'(ZXFOOhello OR XFOOhello) AND '
'(ZXTITLEworld OR XTITLEworld)))')
self.assertExpectedQuery(self.sq.build_query(),
'((ZXFOOhello OR XFOOhello) AND'
' (ZXTITLEworld OR XTITLEworld))')
def test_multiple_word_field_exact_not(self):
self.sq.add_filter(~SQ(foo='hello'))
self.sq.add_filter(~SQ(title='world'))
self.assertEqual(str(self.sq.build_query()),
'Xapian::Query(('
'(<alldocuments> AND_NOT (ZXFOOhello OR XFOOhello)) AND '
'(<alldocuments> AND_NOT (ZXTITLEworld OR XTITLEworld))))')
self.assertExpectedQuery(self.sq.build_query(),
'((<alldocuments> AND_NOT (ZXFOOhello OR XFOOhello)) AND'
' (<alldocuments> AND_NOT (ZXTITLEworld OR XTITLEworld)))')
def test_or(self):
self.sq.add_filter(SQ(content='hello world'))
self.assertEqual(str(self.sq.build_query()),
'Xapian::Query((Zhello OR hello OR Zworld OR world))')
self.assertExpectedQuery(
self.sq.build_query(), '((Zhello OR hello) OR (Zworld OR world))',
xapian12string='(Zhello OR hello OR Zworld OR world)')
def test_not_or(self):
self.sq.add_filter(~SQ(content='hello world'))
self.assertEqual(str(self.sq.build_query()),
'Xapian::Query('
'(<alldocuments> AND_NOT (Zhello OR hello OR Zworld OR world)))')
self.assertExpectedQuery(
self.sq.build_query(),
'(<alldocuments> AND_NOT ((Zhello OR hello) OR (Zworld OR world)))',
xapian12string='(<alldocuments> AND_NOT (Zhello OR hello OR Zworld OR world))')
def test_boost(self):
self.sq.add_filter(SQ(content='hello'))
self.sq.add_boost('world', 5)
self.assertEqual(str(self.sq.build_query()),
'Xapian::Query(('
'(Zhello OR hello) AND_MAYBE '
'5 * (Zworld OR world)))')
self.assertExpectedQuery(self.sq.build_query(),
'((Zhello OR hello) AND_MAYBE'
' 5 * (Zworld OR world))')
def test_not_in_filter_single_words(self):
self.sq.add_filter(SQ(content='why'))
self.sq.add_filter(~SQ(title__in=["Dune", "Jaws"]))
self.assertEqual(str(self.sq.build_query()),
'Xapian::Query('
'((Zwhi OR why) AND '
'(<alldocuments> AND_NOT ('
'(XTITLE^ PHRASE 3 XTITLEdune PHRASE 3 XTITLE$) OR '
'(XTITLE^ PHRASE 3 XTITLEjaws PHRASE 3 XTITLE$)))))')
self.assertExpectedQuery(self.sq.build_query(),
'((Zwhi OR why) AND '
'(<alldocuments> AND_NOT ('
'(XTITLE^ PHRASE 3 XTITLEdune PHRASE 3 XTITLE$) OR '
'(XTITLE^ PHRASE 3 XTITLEjaws PHRASE 3 XTITLE$))))')
def test_in_filter_multiple_words(self):
self.sq.add_filter(SQ(content='why'))
self.sq.add_filter(SQ(title__in=["A Famous Paper", "An Infamous Article"]))
self.assertEqual(str(self.sq.build_query()),
'Xapian::Query(('
'(Zwhi OR why) AND ((XTITLE^ PHRASE 5 XTITLEa PHRASE 5 '
'XTITLEfamous PHRASE 5 XTITLEpaper PHRASE 5 XTITLE$) OR '
'(XTITLE^ PHRASE 5 XTITLEan PHRASE 5 XTITLEinfamous PHRASE 5 '
'XTITLEarticle PHRASE 5 XTITLE$))))')
self.assertExpectedQuery(self.sq.build_query(),
'((Zwhi OR why) AND ((XTITLE^ PHRASE 5 XTITLEa PHRASE 5 '
'XTITLEfamous PHRASE 5 XTITLEpaper PHRASE 5 XTITLE$) OR '
'(XTITLE^ PHRASE 5 XTITLEan PHRASE 5 XTITLEinfamous PHRASE 5 '
'XTITLEarticle PHRASE 5 XTITLE$)))')
def test_in_filter_multiple_words_with_punctuation(self):
self.sq.add_filter(SQ(title__in=["A Famous Paper", "An Infamous Article", "My Store Inc."]))
self.assertEqual(str(self.sq.build_query()),
'Xapian::Query(('
'(XTITLE^ PHRASE 5 XTITLEa PHRASE 5 XTITLEfamous PHRASE 5'
' XTITLEpaper PHRASE 5 XTITLE$) OR '
'(XTITLE^ PHRASE 5 XTITLEan PHRASE 5 XTITLEinfamous PHRASE 5'
' XTITLEarticle PHRASE 5 XTITLE$) OR '
'(XTITLE^ PHRASE 5 XTITLEmy PHRASE 5 XTITLEstore PHRASE 5'
' XTITLEinc. PHRASE 5 XTITLE$)))')
self.assertExpectedQuery(self.sq.build_query(),
'((XTITLE^ PHRASE 5 XTITLEa PHRASE 5 XTITLEfamous PHRASE 5'
' XTITLEpaper PHRASE 5 XTITLE$) OR '
'(XTITLE^ PHRASE 5 XTITLEan PHRASE 5 XTITLEinfamous PHRASE 5'
' XTITLEarticle PHRASE 5 XTITLE$) OR '
'(XTITLE^ PHRASE 5 XTITLEmy PHRASE 5 XTITLEstore PHRASE 5'
' XTITLEinc. PHRASE 5 XTITLE$))')
def test_not_in_filter_multiple_words(self):
self.sq.add_filter(SQ(content='why'))
self.sq.add_filter(~SQ(title__in=["A Famous Paper", "An Infamous Article"]))
self.assertEqual(str(self.sq.build_query()),
'Xapian::Query(('
'(Zwhi OR why) AND (<alldocuments> AND_NOT '
'((XTITLE^ PHRASE 5 XTITLEa PHRASE 5 XTITLEfamous PHRASE 5 '
'XTITLEpaper PHRASE 5 XTITLE$) OR (XTITLE^ PHRASE 5 '
'XTITLEan PHRASE 5 XTITLEinfamous PHRASE 5 '
'XTITLEarticle PHRASE 5 XTITLE$)))))')
self.assertExpectedQuery(self.sq.build_query(),
'((Zwhi OR why) AND (<alldocuments> AND_NOT '
'((XTITLE^ PHRASE 5 XTITLEa PHRASE 5 XTITLEfamous PHRASE 5 '
'XTITLEpaper PHRASE 5 XTITLE$) OR (XTITLE^ PHRASE 5 '
'XTITLEan PHRASE 5 XTITLEinfamous PHRASE 5 '
'XTITLEarticle PHRASE 5 XTITLE$))))')
def test_in_filter_datetime(self):
self.sq.add_filter(SQ(content='why'))
self.sq.add_filter(SQ(pub_date__in=[datetime.datetime(2009, 7, 6, 1, 56, 21)]))
self.assertEqual(str(self.sq.build_query()),
'Xapian::Query(((Zwhi OR why) AND '
'(XPUB_DATE2009-07-06 AND_MAYBE XPUB_DATE01:56:21)))')
self.assertExpectedQuery(self.sq.build_query(),
'((Zwhi OR why) AND '
'(XPUB_DATE2009-07-06 AND_MAYBE XPUB_DATE01:56:21))')
def test_clean(self):
self.assertEqual(self.sq.clean('hello world'), 'hello world')
@ -212,34 +212,35 @@ class XapianSearchQueryTestCase(HaystackBackendTestCase, TestCase):
def test_with_models(self):
self.sq.add_filter(SQ(content='hello'))
self.sq.add_model(MockModel)
self.assertEqual(str(self.sq.build_query()),
'Xapian::Query(((Zhello OR hello) AND '
'0 * CONTENTTYPEcore.mockmodel))')
self.assertExpectedQuery(self.sq.build_query(),
'((Zhello OR hello) AND '
'0 * CONTENTTYPEcore.mockmodel)')
self.sq.add_model(AnotherMockModel)
self.assertTrue(str(self.sq.build_query()) in (
'Xapian::Query(((Zhello OR hello) AND '
'(0 * CONTENTTYPEcore.anothermockmodel OR '
'0 * CONTENTTYPEcore.mockmodel)))',
'Xapian::Query(((Zhello OR hello) AND '
'(0 * CONTENTTYPEcore.mockmodel OR '
'0 * CONTENTTYPEcore.anothermockmodel)))'))
self.assertExpectedQuery(self.sq.build_query(),
['((Zhello OR hello) AND '
'(0 * CONTENTTYPEcore.mockmodel OR'
' 0 * CONTENTTYPEcore.anothermockmodel))',
'((Zhello OR hello) AND '
'(0 * CONTENTTYPEcore.anothermockmodel OR'
' 0 * CONTENTTYPEcore.mockmodel))'])
def test_with_punctuation(self):
self.sq.add_filter(SQ(content='http://www.example.com'))
self.assertEqual(str(self.sq.build_query()), 'Xapian::Query((Zhttp://www.example.com OR '
'http://www.example.com))')
self.assertExpectedQuery(self.sq.build_query(),
'(Zhttp://www.example.com OR'
' http://www.example.com)')
def test_in_filter_values_list(self):
self.sq.add_filter(SQ(content='why'))
self.sq.add_filter(SQ(title__in=MockModel.objects.values_list('id', flat=True)))
self.assertEqual(str(self.sq.build_query()),
'Xapian::Query('
'((Zwhi OR why) AND ('
'(XTITLE^ PHRASE 3 XTITLE1 PHRASE 3 XTITLE$) OR '
'(XTITLE^ PHRASE 3 XTITLE2 PHRASE 3 XTITLE$) OR '
'(XTITLE^ PHRASE 3 XTITLE3 PHRASE 3 XTITLE$))))')
self.sq.add_filter(SQ(title__in=MockModel.objects.values_list('id',
flat=True)))
self.assertExpectedQuery(self.sq.build_query(),
'((Zwhi OR why) AND ('
'(XTITLE^ PHRASE 3 XTITLE1 PHRASE 3 XTITLE$) OR '
'(XTITLE^ PHRASE 3 XTITLE2 PHRASE 3 XTITLE$) OR '
'(XTITLE^ PHRASE 3 XTITLE3 PHRASE 3 XTITLE$)))')
class SearchQueryTestCase(HaystackBackendTestCase, TestCase):
@ -270,27 +271,27 @@ class SearchQueryTestCase(HaystackBackendTestCase, TestCase):
def test_gt(self):
self.sq.add_filter(SQ(name__gt='m'))
self.assertEqual(str(self.sq.build_query()),
'Xapian::Query((<alldocuments> AND_NOT VALUE_RANGE 3 a m))')
self.assertExpectedQuery(self.sq.build_query(),
'(<alldocuments> AND_NOT VALUE_RANGE 3 a m)')
def test_gte(self):
self.sq.add_filter(SQ(name__gte='m'))
self.assertEqual(str(self.sq.build_query()),
'Xapian::Query(VALUE_RANGE 3 m zzzzzzzzzzzzzzzzzzzzzzzzzzzz'
'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'
'zzzzzzzzzzzzzz)')
self.assertExpectedQuery(self.sq.build_query(),
'VALUE_RANGE 3 m zzzzzzzzzzzzzzzzzzzzzzzzzzzz'
'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'
'zzzzzzzzzzzzzzzzzzzzzzzzzzzz')
def test_lt(self):
self.sq.add_filter(SQ(name__lt='m'))
self.assertEqual(str(self.sq.build_query()),
'Xapian::Query((<alldocuments> AND_NOT '
'VALUE_RANGE 3 m zzzzzzzzzzzzzzzzzzzzzz'
'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'
'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz))')
self.assertExpectedQuery(self.sq.build_query(),
'(<alldocuments> AND_NOT VALUE_RANGE 3 m '
'zzzzzzzzzzzzzzzzzzzzzzzzzzzz'
'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'
'zzzzzzzzzzzzzzzzzzzzzzzzzzzz)')
def test_lte(self):
self.sq.add_filter(SQ(name__lte='m'))
self.assertEqual(str(self.sq.build_query()), 'Xapian::Query(VALUE_RANGE 3 a m)')
self.assertExpectedQuery(self.sq.build_query(), 'VALUE_RANGE 3 a m')
def test_multiple_filter_types(self):
self.sq.add_filter(SQ(content='why'))
@ -298,13 +299,14 @@ class SearchQueryTestCase(HaystackBackendTestCase, TestCase):
self.sq.add_filter(SQ(name__gt='david'))
self.sq.add_filter(SQ(title__gte='B'))
self.sq.add_filter(SQ(django_id__in=[1, 2, 3]))
self.assertEqual(str(self.sq.build_query()),
'Xapian::Query(((Zwhi OR why) AND '
'VALUE_RANGE 5 00010101000000 20090210015900 AND '
'(<alldocuments> AND_NOT VALUE_RANGE 3 a david) AND '
'VALUE_RANGE 7 b zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'
'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz AND '
'(QQ000000000001 OR QQ000000000002 OR QQ000000000003)))')
self.assertExpectedQuery(self.sq.build_query(),
'((Zwhi OR why) AND'
' VALUE_RANGE 5 00010101000000 20090210015900 AND'
' (<alldocuments> AND_NOT VALUE_RANGE 3 a david)'
' AND VALUE_RANGE 7 b zzzzzzzzzzzzzzzzzzzzzzzzzzz'
'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'
'zzzzzzzzzzzzzzzzzzzzzzzzz AND'
' (QQ000000000001 OR QQ000000000002 OR QQ000000000003))')
def test_log_query(self):
reset_search_queries()
@ -323,8 +325,8 @@ class SearchQueryTestCase(HaystackBackendTestCase, TestCase):
self.sq.add_filter(SQ(name='bar'))
len(self.sq.get_results())
self.assertEqual(len(connections['default'].queries), 1)
self.assertEqual(str(connections['default'].queries[0]['query_string']),
'Xapian::Query((ZXNAMEbar OR XNAMEbar))')
self.assertExpectedQuery(connections['default'].queries[0]['query_string'],
'(ZXNAMEbar OR XNAMEbar)')
# And again, for good measure.
self.sq = connections['default'].get_query()
@ -332,14 +334,11 @@ class SearchQueryTestCase(HaystackBackendTestCase, TestCase):
self.sq.add_filter(SQ(text='moof'))
len(self.sq.get_results())
self.assertEqual(len(connections['default'].queries), 2)
self.assertEqual(str(connections['default'].queries[0]['query_string']),
'Xapian::Query(('
'ZXNAMEbar OR '
'XNAMEbar))')
self.assertEqual(str(connections['default'].queries[1]['query_string']),
'Xapian::Query(('
'(ZXNAMEbar OR XNAMEbar) AND '
'(ZXTEXTmoof OR XTEXTmoof)))')
self.assertExpectedQuery(connections['default'].queries[0]['query_string'],
'(ZXNAMEbar OR XNAMEbar)')
self.assertExpectedQuery(connections['default'].queries[1]['query_string'],
'((ZXNAMEbar OR XNAMEbar) AND'
' (ZXTEXTmoof OR XTEXTmoof))')
# Restore.
settings.DEBUG = old_debug