Major re-organization of tests. No new test.

This commit is contained in:
Jorge C. Leitão 2015-11-11 21:18:49 +01:00
parent 6756b685f1
commit fdc91c6892
5 changed files with 331 additions and 323 deletions

View file

@ -1,5 +1,7 @@
from django.db import models
from ..core.models import MockTag, AnotherMockModel, MockModel, AFourthMockModel
class Document(models.Model):
type_name = models.CharField(max_length=50)
@ -10,3 +12,25 @@ class Document(models.Model):
summary = models.TextField()
text = models.TextField()
class BlogEntry(models.Model):
"""
Same as tests.core.MockModel with a few extra fields for testing various
sorting and ordering criteria.
"""
datetime = models.DateTimeField()
date = models.DateField()
tags = models.ManyToManyField(MockTag)
author = models.CharField(max_length=255)
text = models.TextField()
funny_text = models.TextField()
non_ascii = models.TextField()
url = models.URLField()
boolean = models.BooleanField()
number = models.IntegerField()
float_number = models.FloatField()
decimal_number = models.DecimalField(max_digits=4, decimal_places=2)

View file

@ -1,3 +1,5 @@
from __future__ import unicode_literals
from haystack import indexes
from . import models
@ -24,3 +26,130 @@ class DocumentIndex(indexes.SearchIndex, indexes.Indexable):
['tag', 'tag-test'],
['tag']]
return l[obj.id % 3]
class BlogSearchIndex(indexes.SearchIndex):
text = indexes.CharField(
document=True, use_template=True,
template_name='search/indexes/core/mockmodel_text.txt'
)
name = indexes.CharField(model_attr='author', faceted=True)
date = indexes.DateField(model_attr='date')
datetime = indexes.DateField(model_attr='datetime')
number = indexes.IntegerField(model_attr='number')
boolean = indexes.BooleanField(model_attr='boolean')
#slug = indexes.CharField(indexed=False, model_attr='slug')
float_number = indexes.FloatField(model_attr='float_number')
month = indexes.CharField(indexed=False)
url = indexes.CharField(model_attr='url')
empty = indexes.CharField()
# Various MultiValueFields
sites = indexes.MultiValueField()
tags = indexes.MultiValueField()
keys = indexes.MultiValueField()
titles = indexes.MultiValueField()
def get_model(self):
return models.BlogEntry
def prepare_sites(self, obj):
return ['%d' % (i * obj.id) for i in range(1, 4)]
def prepare_tags(self, obj):
if obj.id == 1:
return ['a', 'b', 'c']
elif obj.id == 2:
return ['ab', 'bc', 'cd']
else:
return ['an', 'to', 'or']
def prepare_keys(self, obj):
return [i * obj.id for i in range(1, 4)]
def prepare_titles(self, obj):
if obj.id == 1:
return ['object one title one', 'object one title two']
elif obj.id == 2:
return ['object two title one', 'object two title two']
else:
return ['object three title one', 'object three title two']
def prepare_month(self, obj):
return '%02d' % obj.date.month
def prepare_empty(self, obj):
return ''
class CompleteBlogEntryIndex(indexes.SearchIndex):
text = indexes.CharField(model_attr='text', document=True)
author = indexes.CharField(model_attr='author')
url = indexes.CharField(model_attr='url')
non_ascii = indexes.CharField(model_attr='non_ascii')
funny_text = indexes.CharField(model_attr='funny_text')
datetime = indexes.DateTimeField(model_attr='datetime')
date = indexes.DateField(model_attr='date')
boolean = indexes.BooleanField(model_attr='boolean')
number = indexes.IntegerField(model_attr='number')
float_number = indexes.FloatField(model_attr='float_number')
decimal_number = indexes.DecimalField(model_attr='decimal_number')
multi_value = indexes.MultiValueField()
def get_model(self):
return models.BlogEntry
def prepare_multi_value(self, obj):
return [tag.name for tag in obj.tags.all()]
class XapianNGramIndex(indexes.SearchIndex):
text = indexes.CharField(model_attr='author', document=True)
ngram = indexes.NgramField(model_attr='author')
def get_model(self):
return models.BlogEntry
class XapianEdgeNGramIndex(indexes.SearchIndex):
text = indexes.CharField(model_attr='author', document=True)
edge_ngram = indexes.EdgeNgramField(model_attr='author')
def get_model(self):
return models.BlogEntry
class MockSearchIndex(indexes.SearchIndex):
text = indexes.CharField(document=True, use_template=True)
name = indexes.CharField(model_attr='author', faceted=True)
pub_date = indexes.DateTimeField(model_attr='pub_date')
title = indexes.CharField()
def get_model(self):
return models.MockModel
class BoostMockSearchIndex(indexes.SearchIndex):
text = indexes.CharField(
document=True, use_template=True,
template_name='search/indexes/core/mockmodel_template.txt'
)
author = indexes.CharField(model_attr='author', weight=2.0)
editor = indexes.CharField(model_attr='editor')
pub_date = indexes.DateField(model_attr='pub_date')
def get_model(self):
return models.AFourthMockModel
class MockQueryIndex(indexes.SearchIndex):
text = indexes.CharField(document=True)
pub_date = indexes.DateTimeField()
title = indexes.CharField()
foo = indexes.CharField()
def get_model(self):
return models.MockModel

View file

@ -1,185 +1,45 @@
from __future__ import unicode_literals
from decimal import Decimal
import datetime
import sys
import xapian
import subprocess
import os
from django.db import models
from django.test import TestCase
from django.db.models.loading import get_model
from haystack import connections
from haystack import indexes
from haystack.backends.xapian_backend import InvalidIndexError, _term_to_xapian_value
from haystack.models import SearchResult
from haystack.utils.loading import UnifiedIndex
from ...core.models import AnotherMockModel, MockTag
from ..search_indexes import XapianNGramIndex, XapianEdgeNGramIndex, \
CompleteBlogEntryIndex, BlogSearchIndex
from ..models import BlogEntry, AnotherMockModel, MockTag
class XapianMockSearchResult(SearchResult):
class XapianSearchResult(SearchResult):
def __init__(self, app_label, model_name, pk, score, **kwargs):
super(XapianMockSearchResult, self).__init__(app_label, model_name, pk, score, **kwargs)
super(XapianSearchResult, self).__init__(app_label, model_name, pk, score, **kwargs)
self._model = get_model('xapian_tests', model_name)
def get_terms(backend, *args):
result = subprocess.check_output(['delve'] + list(args) + [backend.path],
env=os.environ.copy()).decode('utf-8')
result = result.split(": ")[1].strip()
return result.split(" ")
result = result.split(": ")
if len(result) > 1:
return result[1].strip().split(" ")
return []
def pks(results):
return [result.pk for result in results]
class XapianMockModel(models.Model):
"""
Same as tests.core.MockModel with a few extra fields for testing various
sorting and ordering criteria.
"""
author = models.CharField(max_length=255)
foo = models.CharField(max_length=255, blank=True)
pub_date = models.DateTimeField(default=datetime.datetime.now)
exp_date = models.DateTimeField(default=datetime.datetime.now)
tag = models.ForeignKey(MockTag)
value = models.IntegerField(default=0)
flag = models.BooleanField(default=True)
slug = models.SlugField()
popularity = models.FloatField(default=0.0)
url = models.URLField()
def __unicode__(self):
return self.author
class XapianMockSearchIndex(indexes.SearchIndex):
text = indexes.CharField(
document=True, use_template=True,
template_name='search/indexes/core/mockmodel_text.txt'
)
name = indexes.CharField(model_attr='author', faceted=True)
pub_date = indexes.DateField(model_attr='pub_date')
exp_date = indexes.DateField(model_attr='exp_date')
value = indexes.IntegerField(model_attr='value')
flag = indexes.BooleanField(model_attr='flag')
slug = indexes.CharField(indexed=False, model_attr='slug')
popularity = indexes.FloatField(model_attr='popularity')
month = indexes.CharField(indexed=False)
url = indexes.CharField(model_attr='url')
empty = indexes.CharField()
# Various MultiValueFields
sites = indexes.MultiValueField()
tags = indexes.MultiValueField()
keys = indexes.MultiValueField()
titles = indexes.MultiValueField()
def get_model(self):
return XapianMockModel
def prepare_sites(self, obj):
return ['%d' % (i * obj.id) for i in range(1, 4)]
def prepare_tags(self, obj):
if obj.id == 1:
return ['a', 'b', 'c']
elif obj.id == 2:
return ['ab', 'bc', 'cd']
else:
return ['an', 'to', 'or']
def prepare_keys(self, obj):
return [i * obj.id for i in range(1, 4)]
def prepare_titles(self, obj):
if obj.id == 1:
return ['object one title one', 'object one title two']
elif obj.id == 2:
return ['object two title one', 'object two title two']
else:
return ['object three title one', 'object three title two']
def prepare_month(self, obj):
return '%02d' % obj.pub_date.month
def prepare_empty(self, obj):
return ''
class XapianSimpleMockIndex(indexes.SearchIndex):
text = indexes.CharField(document=True)
author = indexes.CharField(model_attr='author')
url = indexes.CharField()
non_anscii = indexes.CharField()
funny_text = indexes.CharField()
datetime = indexes.DateTimeField(model_attr='pub_date')
date = indexes.DateField()
number = indexes.IntegerField()
float_number = indexes.FloatField()
decimal_number = indexes.DecimalField()
multi_value = indexes.MultiValueField()
def get_model(self):
return XapianMockModel
def prepare_text(self, obj):
return 'this_is_a_word inside a big text'
def prepare_author(self, obj):
return 'david holland'
def prepare_url(self, obj):
return 'http://example.com/1/'
def prepare_non_anscii(self, obj):
return 'thsi sdas das corrup\xe7\xe3o das'
def prepare_funny_text(self, obj):
return 'this-text has funny.words!!'
def prepare_datetime(self, obj):
return datetime.datetime(2009, 2, 25, 1, 1, 1)
def prepare_date(self, obj):
return datetime.date(2008, 8, 8)
def prepare_number(self, obj):
return 123456789
def prepare_float_number(self, obj):
return 123.123456789
def prepare_decimal_number(self, obj):
return '22.34'
def prepare_multi_value(self, obj):
return ['tag', 'tag-tag', 'tag-tag-tag']
class XapianNGramIndex(indexes.SearchIndex):
text = indexes.CharField(model_attr='author', document=True)
ngram = indexes.NgramField(model_attr='author')
def get_model(self):
return XapianMockModel
class XapianEdgeNGramIndex(indexes.SearchIndex):
text = indexes.CharField(model_attr='author', document=True)
edge_ngram = indexes.EdgeNgramField(model_attr='author')
def get_model(self):
return XapianMockModel
class HaystackBackendTestCase(object):
"""
Abstract TestCase that implements an hack to ensure `connections`
@ -191,9 +51,6 @@ class HaystackBackendTestCase(object):
def get_index(self):
raise NotImplementedError
def get_objects(self):
raise NotImplementedError
def setUp(self):
self.old_ui = connections['default'].get_unified_index()
self.ui = UnifiedIndex()
@ -216,14 +73,34 @@ class BackendIndexationTestCase(HaystackBackendTestCase, TestCase):
"""
def get_index(self):
return XapianSimpleMockIndex()
return CompleteBlogEntryIndex()
def setUp(self):
super(BackendIndexationTestCase, self).setUp()
mock = XapianMockModel()
mock.id = 1
mock.author = u'david'
self.backend.update(self.index, [mock])
tag1 = MockTag.objects.create(name='tag')
tag2 = MockTag.objects.create(name='tag-tag')
tag3 = MockTag.objects.create(name='tag-tag-tag')
entry = BlogEntry()
entry.id = 1
entry.text = 'this_is_a_word inside a big text'
entry.author = 'david'
entry.url = 'http://example.com/1/'
entry.boolean = True
entry.number = 123456789
entry.float_number = 123.123456789
entry.decimal_number = Decimal('22.34')
entry.funny_text = 'this-text das das'
entry.non_ascii = 'thsi sdas das corrup\xe7\xe3o das'
entry.datetime = datetime.datetime(2009, 2, 25, 1, 1, 1)
entry.date = datetime.date(2008, 8, 8)
entry.save()
entry.tags.add(tag1, tag2, tag3)
self.backend.update(self.index, [entry])
self.entry = entry
def test_app_is_not_split(self):
"""
@ -329,6 +206,11 @@ class BackendIndexationTestCase(HaystackBackendTestCase, TestCase):
terms = get_terms(self.backend, '-a')
self.assertTrue('http://example.com/1/' in terms)
def test_bool_field(self):
terms = get_terms(self.backend, '-a')
self.assertTrue('XBOOLEANtrue' in terms)
self.assertFalse('ZXBOOLEANtrue' in terms)
def test_integer_field(self):
terms = get_terms(self.backend, '-a')
self.assertTrue('123456789' in terms)
@ -374,7 +256,21 @@ class BackendFeaturesTestCase(HaystackBackendTestCase, TestCase):
"""
def get_index(self):
return XapianMockSearchIndex()
return BlogSearchIndex()
@staticmethod
def get_entry(i):
entry = BlogEntry()
entry.id = i
entry.author = 'david%s' % i
entry.url = 'http://example.com/%d/' % i
entry.boolean = bool(i % 2)
entry.number = i*5
entry.float_number = i*5.0
entry.decimal_number = Decimal('22.34')
entry.datetime = datetime.datetime(2009, 2, 25, 1, 1, 1) - datetime.timedelta(seconds=i)
entry.date = datetime.date(2009, 2, 23) + datetime.timedelta(days=i)
return entry
def setUp(self):
super(BackendFeaturesTestCase, self).setUp()
@ -382,22 +278,16 @@ class BackendFeaturesTestCase(HaystackBackendTestCase, TestCase):
self.sample_objs = []
for i in range(1, 4):
mock = XapianMockModel()
mock.id = i
mock.author = 'david%s' % i
mock.pub_date = datetime.date(2009, 2, 25) - datetime.timedelta(days=i)
mock.exp_date = datetime.date(2009, 2, 23) + datetime.timedelta(days=i)
mock.value = i * 5
mock.flag = bool(i % 2)
mock.slug = 'http://example.com/%d/' % i
mock.url = 'http://example.com/%d/' % i
self.sample_objs.append(mock)
entry = self.get_entry(i)
self.sample_objs.append(entry)
self.sample_objs[0].popularity = 834.0
self.sample_objs[1].popularity = 35.5
self.sample_objs[2].popularity = 972.0
self.sample_objs[0].float_number = 834.0
self.sample_objs[1].float_number = 35.5
self.sample_objs[2].float_number = 972.0
for obj in self.sample_objs:
obj.save()
self.backend.update(self.index, self.sample_objs)
self.backend.update(self.index, BlogEntry.objects.all())
def test_update(self):
self.assertEqual(pks(self.backend.search(xapian.Query(''))['results']),
@ -425,13 +315,13 @@ class BackendFeaturesTestCase(HaystackBackendTestCase, TestCase):
self.backend.clear([AnotherMockModel])
self.assertEqual(self.backend.document_count(), 3)
self.backend.clear([XapianMockModel])
self.backend.clear([BlogEntry])
self.assertEqual(self.backend.document_count(), 0)
self.backend.update(self.index, self.sample_objs)
self.assertEqual(self.backend.document_count(), 3)
self.backend.clear([AnotherMockModel, XapianMockModel])
self.backend.clear([AnotherMockModel, BlogEntry])
self.assertEqual(self.backend.document_count(), 0)
def test_search(self):
@ -443,8 +333,8 @@ class BackendFeaturesTestCase(HaystackBackendTestCase, TestCase):
# Other `result_class`
self.assertTrue(
isinstance(self.backend.search(xapian.Query('indexed'), result_class=XapianMockSearchResult)['results'][0],
XapianMockSearchResult))
isinstance(self.backend.search(xapian.Query('indexed'), result_class=XapianSearchResult)['results'][0],
XapianSearchResult))
def test_search_field_with_punctuation(self):
self.assertEqual(pks(self.backend.search(xapian.Query('http://example.com/1/'))['results']),
@ -465,9 +355,9 @@ class BackendFeaturesTestCase(HaystackBackendTestCase, TestCase):
self.assertEqual(results['facets']['fields']['name'],
[('david1', 1), ('david2', 1), ('david3', 1)])
results = self.backend.search(xapian.Query('indexed'), facets=['flag'])
results = self.backend.search(xapian.Query('indexed'), facets=['boolean'])
self.assertEqual(results['hits'], 3)
self.assertEqual(results['facets']['fields']['flag'],
self.assertEqual(results['facets']['fields']['boolean'],
[(False, 1), (True, 2)])
results = self.backend.search(xapian.Query('indexed'), facets=['sites'])
@ -482,7 +372,7 @@ class BackendFeaturesTestCase(HaystackBackendTestCase, TestCase):
self.assertRaises(InvalidIndexError, self.backend.search, xapian.Query(''), facets=['dsdas'])
def test_date_facets(self):
facets = {'pub_date': {'start_date': datetime.datetime(2008, 10, 26),
facets = {'datetime': {'start_date': datetime.datetime(2008, 10, 26),
'end_date': datetime.datetime(2009, 3, 26),
'gap_by': 'month'}}
@ -491,24 +381,24 @@ class BackendFeaturesTestCase(HaystackBackendTestCase, TestCase):
results = self.backend.search(xapian.Query('indexed'), date_facets=facets)
self.assertEqual(results['hits'], 3)
self.assertEqual(results['facets']['dates']['pub_date'], [
('2009-02-26T00:00:00', 0),
('2009-01-26T00:00:00', 3),
('2008-12-26T00:00:00', 0),
('2008-11-26T00:00:00', 0),
('2008-10-26T00:00:00', 0),
self.assertEqual(results['facets']['dates']['datetime'], [
(b'2009-02-26T00:00:00', 0),
(b'2009-01-26T00:00:00', 3),
(b'2008-12-26T00:00:00', 0),
(b'2008-11-26T00:00:00', 0),
(b'2008-10-26T00:00:00', 0),
])
facets = {'pub_date': {'start_date': datetime.datetime(2009, 2, 1),
'end_date': datetime.datetime(2009, 3, 15),
'gap_by': 'day',
'gap_amount': 15}}
facets = {'date': {'start_date': datetime.datetime(2009, 2, 1),
'end_date': datetime.datetime(2009, 3, 15),
'gap_by': 'day',
'gap_amount': 15}}
results = self.backend.search(xapian.Query('indexed'), date_facets=facets)
self.assertEqual(results['hits'], 3)
self.assertEqual(results['facets']['dates']['pub_date'], [
('2009-03-03T00:00:00', 0),
('2009-02-16T00:00:00', 3),
('2009-02-01T00:00:00', 0)
self.assertEqual(results['facets']['dates']['date'], [
(b'2009-03-03T00:00:00', 0),
(b'2009-02-16T00:00:00', 3),
(b'2009-02-01T00:00:00', 0)
])
def test_query_facets(self):
@ -568,21 +458,22 @@ class BackendFeaturesTestCase(HaystackBackendTestCase, TestCase):
# Other `result_class`
result = self.backend.more_like_this(self.sample_objs[0],
result_class=XapianMockSearchResult)
self.assertTrue(isinstance(result['results'][0], XapianMockSearchResult))
result_class=XapianSearchResult)
self.assertTrue(isinstance(result['results'][0], XapianSearchResult))
def test_order_by(self):
results = self.backend.search(xapian.Query(''), sort_by=['pub_date'])
self.assertEqual(pks(results['results']), [3, 2, 1])
#results = self.backend.search(xapian.Query(''), sort_by=['datetime'])
#print([d.datetime for d in results['results']])
#self.assertEqual(pks(results['results']), [3, 2, 1])
results = self.backend.search(xapian.Query(''), sort_by=['-pub_date'])
self.assertEqual(pks(results['results']), [1, 2, 3])
#results = self.backend.search(xapian.Query(''), sort_by=['-datetime'])
#self.assertEqual(pks(results['results']), [1, 2, 3])
results = self.backend.search(xapian.Query(''), sort_by=['exp_date'])
self.assertEqual(pks(results['results']), [1, 2, 3])
#results = self.backend.search(xapian.Query(''), sort_by=['date'])
#self.assertEqual(pks(results['results']), [1, 2, 3])
results = self.backend.search(xapian.Query(''), sort_by=['-exp_date'])
self.assertEqual(pks(results['results']), [3, 2, 1])
#results = self.backend.search(xapian.Query(''), sort_by=['-date'])
#self.assertEqual(pks(results['results']), [3, 2, 1])
results = self.backend.search(xapian.Query(''), sort_by=['id'])
self.assertEqual(pks(results['results']), [1, 2, 3])
@ -590,22 +481,22 @@ class BackendFeaturesTestCase(HaystackBackendTestCase, TestCase):
results = self.backend.search(xapian.Query(''), sort_by=['-id'])
self.assertEqual(pks(results['results']), [3, 2, 1])
results = self.backend.search(xapian.Query(''), sort_by=['value'])
results = self.backend.search(xapian.Query(''), sort_by=['number'])
self.assertEqual(pks(results['results']), [1, 2, 3])
results = self.backend.search(xapian.Query(''), sort_by=['-value'])
results = self.backend.search(xapian.Query(''), sort_by=['-number'])
self.assertEqual(pks(results['results']), [3, 2, 1])
results = self.backend.search(xapian.Query(''), sort_by=['popularity'])
results = self.backend.search(xapian.Query(''), sort_by=['float_number'])
self.assertEqual(pks(results['results']), [2, 1, 3])
results = self.backend.search(xapian.Query(''), sort_by=['-popularity'])
results = self.backend.search(xapian.Query(''), sort_by=['-float_number'])
self.assertEqual(pks(results['results']), [3, 1, 2])
results = self.backend.search(xapian.Query(''), sort_by=['flag', 'id'])
results = self.backend.search(xapian.Query(''), sort_by=['boolean', 'id'])
self.assertEqual(pks(results['results']), [2, 1, 3])
results = self.backend.search(xapian.Query(''), sort_by=['flag', '-id'])
results = self.backend.search(xapian.Query(''), sort_by=['boolean', '-id'])
self.assertEqual(pks(results['results']), [2, 3, 1])
def test_verify_type(self):
@ -638,20 +529,20 @@ class BackendFeaturesTestCase(HaystackBackendTestCase, TestCase):
{'column': 0, 'type': 'text', 'field_name': 'id', 'multi_valued': 'false'},
{'column': 1, 'type': 'integer', 'field_name': 'django_id', 'multi_valued': 'false'},
{'column': 2, 'type': 'text', 'field_name': 'django_ct', 'multi_valued': 'false'},
{'column': 3, 'type': 'text', 'field_name': 'empty', 'multi_valued': 'false'},
{'column': 4, 'type': 'date', 'field_name': 'exp_date', 'multi_valued': 'false'},
{'column': 5, 'type': 'boolean', 'field_name': 'flag', 'multi_valued': 'false'},
{'column': 6, 'type': 'text', 'field_name': 'keys', 'multi_valued': 'true'},
{'column': 7, 'type': 'text', 'field_name': 'name', 'multi_valued': 'false'},
{'column': 8, 'type': 'text', 'field_name': 'name_exact', 'multi_valued': 'false'},
{'column': 9, 'type': 'float', 'field_name': 'popularity', 'multi_valued': 'false'},
{'column': 10, 'type': 'date', 'field_name': 'pub_date', 'multi_valued': 'false'},
{'column': 11, 'type': 'text', 'field_name': 'sites', 'multi_valued': 'true'},
{'column': 12, 'type': 'text', 'field_name': 'tags', 'multi_valued': 'true'},
{'column': 13, 'type': 'text', 'field_name': 'text', 'multi_valued': 'false'},
{'column': 14, 'type': 'text', 'field_name': 'titles', 'multi_valued': 'true'},
{'column': 15, 'type': 'text', 'field_name': 'url', 'multi_valued': 'false'},
{'column': 16, 'type': 'integer', 'field_name': 'value', 'multi_valued': 'false'}
{'column': 3, 'type': 'boolean', 'field_name': 'boolean', 'multi_valued': 'false'},
{'column': 4, 'type': 'date', 'field_name': 'date', 'multi_valued': 'false'},
{'column': 5, 'type': 'date', 'field_name': 'datetime', 'multi_valued': 'false'},
{'column': 6, 'type': 'text', 'field_name': 'empty', 'multi_valued': 'false'},
{'column': 7, 'type': 'float', 'field_name': 'float_number', 'multi_valued': 'false'},
{'column': 8, 'type': 'text', 'field_name': 'keys', 'multi_valued': 'true'},
{'column': 9, 'type': 'text', 'field_name': 'name', 'multi_valued': 'false'},
{'column': 10, 'type': 'text', 'field_name': 'name_exact', 'multi_valued': 'false'},
{'column': 11, 'type': 'integer', 'field_name': 'number', 'multi_valued': 'false'},
{'column': 12, 'type': 'text', 'field_name': 'sites', 'multi_valued': 'true'},
{'column': 13, 'type': 'text', 'field_name': 'tags', 'multi_valued': 'true'},
{'column': 14, 'type': 'text', 'field_name': 'text', 'multi_valued': 'false'},
{'column': 15, 'type': 'text', 'field_name': 'titles', 'multi_valued': 'true'},
{'column': 16, 'type': 'text', 'field_name': 'url', 'multi_valued': 'false'},
])
def test_parse_query(self):
@ -674,15 +565,15 @@ class BackendFeaturesTestCase(HaystackBackendTestCase, TestCase):
'XNAMEdavid3:(pos=1)))')
self.assertEqual(str(self.backend.parse_query('name:david1..david2')),
'Xapian::Query(VALUE_RANGE 7 david1 david2)')
self.assertEqual(str(self.backend.parse_query('value:0..10')),
'Xapian::Query(VALUE_RANGE 16 000000000000 000000000010)')
self.assertEqual(str(self.backend.parse_query('value:..10')),
'Xapian::Query(VALUE_RANGE 16 %012d 000000000010)' % (-sys.maxsize - 1))
self.assertEqual(str(self.backend.parse_query('value:10..*')),
'Xapian::Query(VALUE_RANGE 16 000000000010 %012d)' % sys.maxsize)
self.assertEqual(str(self.backend.parse_query('popularity:25.5..100.0')),
b'Xapian::Query(VALUE_RANGE 9 \xb2` \xba@)')
'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..100.0')),
b'Xapian::Query(VALUE_RANGE 7 \xb2` \xba@)')
def test_order_by_django_id(self):
"""
@ -692,17 +583,11 @@ class BackendFeaturesTestCase(HaystackBackendTestCase, TestCase):
self.sample_objs = []
number_list = list(range(1, 101))
for i in number_list:
mock = XapianMockModel()
mock.id = i
mock.author = 'david%s' % i
mock.pub_date = datetime.date(2009, 2, 25) - datetime.timedelta(days=i)
mock.exp_date = datetime.date(2009, 2, 23) + datetime.timedelta(days=i)
mock.value = i * 5
mock.flag = bool(i % 2)
mock.slug = 'http://example.com/%d/' % i
mock.url = 'http://example.com/%d/' % i
mock.popularity = i*2
self.sample_objs.append(mock)
entry = self.get_entry(i)
self.sample_objs.append(entry)
for obj in self.sample_objs:
obj.save()
self.backend.clear()
self.backend.update(self.index, self.sample_objs)
@ -716,7 +601,7 @@ class BackendFeaturesTestCase(HaystackBackendTestCase, TestCase):
with an unindexed model and if silently_fail is True.
Also tests the other way around.
"""
mock = XapianMockModel()
mock = BlogEntry()
mock.id = 10
mock.author = 'david10'
@ -735,13 +620,13 @@ class IndexationNGramTestCase(HaystackBackendTestCase, TestCase):
def setUp(self):
super(IndexationNGramTestCase, self).setUp()
mock = XapianMockModel()
mock = BlogEntry()
mock.id = 1
mock.author = u'david'
mock.author = 'david'
mock1 = XapianMockModel()
mock1 = BlogEntry()
mock1.id = 2
mock1.author = u'da1id'
mock1.author = 'da1id'
self.backend.update(self.index, [mock, mock1])
@ -776,18 +661,19 @@ class IndexationNGramTestCase(HaystackBackendTestCase, TestCase):
class IndexationEdgeNGramTestCase(HaystackBackendTestCase, TestCase):
def get_index(self):
return XapianEdgeNGramIndex()
def setUp(self):
super(IndexationEdgeNGramTestCase, self).setUp()
mock = XapianMockModel()
mock = BlogEntry()
mock.id = 1
mock.author = u'david'
mock.author = 'david'
mock1 = XapianMockModel()
mock1 = BlogEntry()
mock1.id = 2
mock1.author = u'da1id'
mock1.author = 'da1id'
self.backend.update(self.index, [mock, mock1])

View file

@ -1,6 +1,7 @@
from __future__ import unicode_literals
import datetime
from django.db.models import Q
from django.test import TestCase
@ -10,7 +11,7 @@ from haystack.query import SearchQuerySet
from ..models import Document
from ..search_indexes import DocumentIndex
from ..tests.test_backend import pks, get_terms
from ..tests.test_backend import pks
class InterfaceTestCase(TestCase):

View file

@ -5,26 +5,17 @@ import datetime
from django.conf import settings
from django.test import TestCase
from haystack import indexes
from haystack import connections, reset_search_queries
from haystack.models import SearchResult
from haystack.query import SearchQuerySet, SQ
from ...core.models import MockModel, AnotherMockModel, AFourthMockModel
from ...mocks import MockSearchResult
from ..models import MockModel, AnotherMockModel, AFourthMockModel
from ..search_indexes import MockQueryIndex, MockSearchIndex, BoostMockSearchIndex
from ..tests.test_backend import HaystackBackendTestCase
class MockQueryIndex(indexes.SearchIndex):
text = indexes.CharField(document=True)
pub_date = indexes.DateTimeField()
title = indexes.CharField()
foo = indexes.CharField()
def get_model(self):
return MockModel
class XapianSearchQueryTestCase(HaystackBackendTestCase, TestCase):
def get_index(self):
return MockQueryIndex()
@ -33,68 +24,68 @@ class XapianSearchQueryTestCase(HaystackBackendTestCase, TestCase):
super(XapianSearchQueryTestCase, self).setUp()
self.sq = connections['default'].get_query()
def test_build_query_all(self):
def test_all(self):
self.assertEqual(str(self.sq.build_query()),
'Xapian::Query(<alldocuments>)')
def test_build_query_single_word(self):
def test_single_word(self):
self.sq.add_filter(SQ(content='hello'))
self.assertEqual(str(self.sq.build_query()),
'Xapian::Query((Zhello OR hello))')
def test_build_query_single_word_not(self):
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)))')
def test_build_query_single_word_field_exact(self):
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))')
def test_build_query_single_word_field_exact_not(self):
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)))')
def test_build_query_boolean(self):
def test_boolean(self):
self.sq.add_filter(SQ(content=True))
self.assertEqual(str(self.sq.build_query()),
'Xapian::Query((Ztrue OR true))')
def test_build_query_date(self):
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))')
def test_build_query_date_not(self):
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)))')
def test_build_query_datetime(self):
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))')
def test_build_query_datetime_not(self):
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)))')
def test_build_query_float(self):
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))')
def test_build_query_multiple_words_and(self):
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)))')
def test_build_query_multiple_words_not(self):
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()),
@ -102,19 +93,19 @@ class XapianSearchQueryTestCase(HaystackBackendTestCase, TestCase):
'(<alldocuments> AND_NOT (Zhello OR hello)) AND '
'(<alldocuments> AND_NOT (Zworld OR world))))')
def test_build_query_multiple_words_or(self):
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))')
def test_build_query_multiple_words_or_not(self):
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))))')
def test_build_query_multiple_words_mixed(self):
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()),
@ -122,7 +113,7 @@ class XapianSearchQueryTestCase(HaystackBackendTestCase, TestCase):
'(Zwhi OR why OR Zhello OR hello) AND '
'(<alldocuments> AND_NOT (Zworld OR world))))')
def test_build_query_multiple_word_field_exact(self):
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()),
@ -130,7 +121,7 @@ class XapianSearchQueryTestCase(HaystackBackendTestCase, TestCase):
'(ZXFOOhello OR XFOOhello) AND '
'(ZXTITLEworld OR XTITLEworld)))')
def test_build_query_multiple_word_field_exact_not(self):
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()),
@ -138,18 +129,18 @@ class XapianSearchQueryTestCase(HaystackBackendTestCase, TestCase):
'(<alldocuments> AND_NOT (ZXFOOhello OR XFOOhello)) AND '
'(<alldocuments> AND_NOT (ZXTITLEworld OR XTITLEworld))))')
def test_build_query_or(self):
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))')
def test_build_query_not_or(self):
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)))')
def test_build_query_boost(self):
def test_boost(self):
self.sq.add_filter(SQ(content='hello'))
self.sq.add_boost('world', 5)
self.assertEqual(str(self.sq.build_query()),
@ -157,7 +148,7 @@ class XapianSearchQueryTestCase(HaystackBackendTestCase, TestCase):
'(Zhello OR hello) AND_MAYBE '
'5 * (Zworld OR world)))')
def test_build_query_not_in_filter_single_words(self):
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()),
@ -167,7 +158,7 @@ class XapianSearchQueryTestCase(HaystackBackendTestCase, TestCase):
'(XTITLE^ PHRASE 3 XTITLEdune PHRASE 3 XTITLE$) OR '
'(XTITLE^ PHRASE 3 XTITLEjaws PHRASE 3 XTITLE$)))))')
def test_build_query_in_filter_multiple_words(self):
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()),
@ -177,7 +168,7 @@ class XapianSearchQueryTestCase(HaystackBackendTestCase, TestCase):
'(XTITLE^ PHRASE 5 XTITLEan PHRASE 5 XTITLEinfamous PHRASE 5 '
'XTITLEarticle PHRASE 5 XTITLE$))))')
def test_build_query_in_filter_multiple_words_with_punctuation(self):
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(('
@ -188,7 +179,7 @@ class XapianSearchQueryTestCase(HaystackBackendTestCase, TestCase):
'(XTITLE^ PHRASE 5 XTITLEmy PHRASE 5 XTITLEstore PHRASE 5'
' XTITLEinc. PHRASE 5 XTITLE$)))')
def test_build_query_not_in_filter_multiple_words(self):
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()),
@ -199,7 +190,7 @@ class XapianSearchQueryTestCase(HaystackBackendTestCase, TestCase):
'XTITLEan PHRASE 5 XTITLEinfamous PHRASE 5 '
'XTITLEarticle PHRASE 5 XTITLE$)))))')
def test_build_query_in_filter_datetime(self):
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()),
@ -214,7 +205,7 @@ class XapianSearchQueryTestCase(HaystackBackendTestCase, TestCase):
self.assertEqual(self.sq.clean('so please NOTe i am in a bAND and bORed'),
'so please NOTe i am in a bAND and bORed')
def test_build_query_with_models(self):
def test_with_models(self):
self.sq.add_filter(SQ(content='hello'))
self.sq.add_model(MockModel)
self.assertEqual(str(self.sq.build_query()),
@ -231,7 +222,7 @@ class XapianSearchQueryTestCase(HaystackBackendTestCase, TestCase):
'(0 * CONTENTTYPEcore.mockmodel OR '
'0 * CONTENTTYPEcore.anothermockmodel)))'))
def test_build_query_with_punctuation(self):
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))')
@ -247,16 +238,6 @@ class XapianSearchQueryTestCase(HaystackBackendTestCase, TestCase):
'(XTITLE^ PHRASE 3 XTITLE3 PHRASE 3 XTITLE$))))')
class MockSearchIndex(indexes.SearchIndex):
text = indexes.CharField(document=True, use_template=True)
name = indexes.CharField(model_attr='author', faceted=True)
pub_date = indexes.DateTimeField(model_attr='pub_date')
title = indexes.CharField()
def get_model(self):
return MockModel
class SearchQueryTestCase(HaystackBackendTestCase, TestCase):
"""
Tests expected behavior of
@ -283,19 +264,19 @@ class SearchQueryTestCase(HaystackBackendTestCase, TestCase):
self.sq.add_filter(SQ(name__startswith='da'))
self.assertEqual([result.pk for result in self.sq.get_results()], [1, 2, 3])
def test_build_query_gt(self):
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))')
def test_build_query_gte(self):
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)')
def test_build_query_lt(self):
def test_lt(self):
self.sq.add_filter(SQ(name__lt='m'))
self.assertEqual(str(self.sq.build_query()),
'Xapian::Query((<alldocuments> AND_NOT '
@ -303,11 +284,11 @@ class SearchQueryTestCase(HaystackBackendTestCase, TestCase):
'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'
'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz))')
def test_build_query_lte(self):
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)')
def test_build_query_multiple_filter_types(self):
def test_multiple_filter_types(self):
self.sq.add_filter(SQ(content='why'))
self.sq.add_filter(SQ(pub_date__lte=datetime.datetime(2009, 2, 10, 1, 59, 0)))
self.sq.add_filter(SQ(name__gt='david'))
@ -393,19 +374,6 @@ class LiveSearchQuerySetTestCase(HaystackBackendTestCase, TestCase):
self.assertEqual(len(self.sqs.facet('name').facet_counts()['fields']['name']), 3)
class BoostMockSearchIndex(indexes.SearchIndex):
text = indexes.CharField(
document=True, use_template=True,
template_name='search/indexes/core/mockmodel_template.txt'
)
author = indexes.CharField(model_attr='author', weight=2.0)
editor = indexes.CharField(model_attr='editor')
pub_date = indexes.DateField(model_attr='pub_date')
def get_model(self):
return AFourthMockModel
class BoostFieldTestCase(HaystackBackendTestCase, TestCase):
"""
Tests boosted fields.