From fdc91c6892b5356842a25ea65c2926530244c7e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20C=2E=20Leit=C3=A3o?= Date: Wed, 11 Nov 2015 21:18:49 +0100 Subject: [PATCH] Major re-organization of tests. No new test. --- tests/xapian_tests/models.py | 24 ++ tests/xapian_tests/search_indexes.py | 129 +++++++ tests/xapian_tests/tests/test_backend.py | 394 ++++++++------------- tests/xapian_tests/tests/test_interface.py | 3 +- tests/xapian_tests/tests/test_query.py | 104 ++---- 5 files changed, 331 insertions(+), 323 deletions(-) diff --git a/tests/xapian_tests/models.py b/tests/xapian_tests/models.py index 36a5931..3757eae 100644 --- a/tests/xapian_tests/models.py +++ b/tests/xapian_tests/models.py @@ -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) diff --git a/tests/xapian_tests/search_indexes.py b/tests/xapian_tests/search_indexes.py index c4e7fac..9d1c023 100644 --- a/tests/xapian_tests/search_indexes.py +++ b/tests/xapian_tests/search_indexes.py @@ -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 diff --git a/tests/xapian_tests/tests/test_backend.py b/tests/xapian_tests/tests/test_backend.py index cfda3aa..338c577 100644 --- a/tests/xapian_tests/tests/test_backend.py +++ b/tests/xapian_tests/tests/test_backend.py @@ -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]) diff --git a/tests/xapian_tests/tests/test_interface.py b/tests/xapian_tests/tests/test_interface.py index 5164380..6fb2db4 100644 --- a/tests/xapian_tests/tests/test_interface.py +++ b/tests/xapian_tests/tests/test_interface.py @@ -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): diff --git a/tests/xapian_tests/tests/test_query.py b/tests/xapian_tests/tests/test_query.py index c1c097c..824bf95 100644 --- a/tests/xapian_tests/tests/test_query.py +++ b/tests/xapian_tests/tests/test_query.py @@ -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()') - 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(( 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(( 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(( 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(( 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): '( AND_NOT (Zhello OR hello)) AND ' '( 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((' '( AND_NOT (Zhello OR hello)) OR ' '( 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 ' '( 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): '( AND_NOT (ZXFOOhello OR XFOOhello)) AND ' '( 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(' '( 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(( 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(( 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.