from askbot.tests.utils import AskbotTestCase from askbot.search.state_manager import SearchState import askbot.conf from django.core import urlresolvers class SearchStateTests(AskbotTestCase): def _ss(self, query=None, tags=None): return SearchState( scope=None, sort=None, query=query, tags=tags, author=None, page=None, user_logged_in=False ) def test_no_selectors(self): ss = self._ss() self.assertEqual( 'scope:all/sort:activity-desc/page:1/', # search defaults ss.query_string() ) def test_buggy_selectors(self): ss = SearchState( scope='blah1', sort='blah2', query=None, tags=None, # INFO: URLs for the following selectors accept only digits! author=None, page='0', user_logged_in=False ) self.assertEqual( 'scope:all/sort:activity-desc/page:1/', # search defaults ss.query_string() ) def test_all_valid_selectors(self): ss = SearchState( scope='unanswered', sort='age-desc', query=' alfa', tags='miki, mini', author='12', page='2', user_logged_in=False ) self.assertEqual( 'scope:unanswered/sort:age-desc/tags:miki,mini/author:12/page:2/query:alfa/', ss.query_string() ) self.assertEqual( 'scope:unanswered/sort:age-desc/tags:miki,mini/author:12/page:2/query:alfa/', ss.deepcopy().query_string() ) def test_edge_cases_1(self): ss = SearchState( scope='followed', # this is not a valid choice for non-logger users sort='age-desc', query=' alfa', tags='miki, mini', author='12', page='2', user_logged_in=False ) self.assertEqual( 'scope:all/sort:age-desc/tags:miki,mini/author:12/page:2/query:alfa/', ss.query_string() ) self.assertEqual( 'scope:all/sort:age-desc/tags:miki,mini/author:12/page:2/query:alfa/', ss.deepcopy().query_string() ) ss = SearchState( scope='followed', sort='age-desc', query=' alfa', tags='miki, mini', author='12', page='2', user_logged_in=True ) self.assertEqual( 'scope:followed/sort:age-desc/tags:miki,mini/author:12/page:2/query:alfa/', ss.query_string() ) self.assertEqual( 'scope:followed/sort:age-desc/tags:miki,mini/author:12/page:2/query:alfa/', ss.deepcopy().query_string() ) def test_edge_cases_2(self): old_func = askbot.conf.should_show_sort_by_relevance askbot.conf.should_show_sort_by_relevance = lambda: True # monkey patch ss = SearchState( scope='all', sort='relevance-desc', query='hejho', tags='miki, mini', author='12', page='2', user_logged_in=False ) self.assertEqual( 'scope:all/sort:relevance-desc/tags:miki,mini/author:12/page:2/query:hejho/', ss.query_string() ) ss = SearchState( scope='all', sort='relevance-desc', # this is not a valid choice for empty queries query=None, tags='miki, mini', author='12', page='2', user_logged_in=False ) self.assertEqual( 'scope:all/sort:activity-desc/tags:miki,mini/author:12/page:2/', ss.query_string() ) askbot.conf.should_show_sort_by_relevance = lambda: False # monkey patch ss = SearchState( scope='all', sort='relevance-desc', # this is also invalid for db-s other than Postgresql query='hejho', tags='miki, mini', author='12', page='2', user_logged_in=False ) self.assertEqual( 'scope:all/sort:activity-desc/tags:miki,mini/author:12/page:2/query:hejho/', ss.query_string() ) askbot.conf.should_show_sort_by_relevance = old_func def test_query_escaping(self): ss = self._ss(query=' alfa miki maki +-%#?= lalala/: ') # query coming from URL is already unescaped qs = 'scope:all/sort:activity-desc/page:1/query:alfa%20miki%20maki%20+-%25%23%3F%3D%20lalala%2F%3A/' self.assertEqual(qs, ss.query_string()) self.assertEqual(qs, ss.deepcopy().query_string()) def test_tag_escaping(self): ss = self._ss(tags=' aA09_+.-#, miki ') # tag string coming from URL is already unescaped self.assertEqual( 'scope:all/sort:activity-desc/tags:aA09_+.-%23,miki/page:1/', ss.query_string() ) def test_extract_users(self): ss = self._ss(query='"@anna haha @"maria fernanda" @\'diego maradona\' hehe [user:karl marx] hoho user:\' george bush \'') self.assertEqual( sorted(ss.query_users), sorted(['anna', 'maria fernanda', 'diego maradona', 'karl marx', 'george bush']) ) self.assertEqual(sorted(ss.query_users), sorted(ss.deepcopy().query_users)) self.assertEqual(ss.stripped_query, '" haha hehe hoho') self.assertEqual(ss.stripped_query, ss.deepcopy().stripped_query) self.assertEqual( 'scope:all/sort:activity-desc/page:1/query:%22%40anna%20haha%20%40%22maria%20fernanda%22%20%40%27diego%20maradona%27%20hehe%20%5Buser%3Akarl%20%20marx%5D%20hoho%20%20user%3A%27%20george%20bush%20%20%27/', ss.query_string() ) def test_extract_tags(self): ss = self._ss(query='#tag1 [tag: tag2] some text [tag3] query') self.assertEqual(set(ss.query_tags), set(['tag1', 'tag2', 'tag3'])) self.assertEqual(ss.stripped_query, 'some text query') self.assertFalse(ss.deepcopy().query_tags is ss.query_tags) self.assertEqual(set(ss.deepcopy().query_tags), set(ss.query_tags)) self.assertTrue(ss.deepcopy().stripped_query is ss.stripped_query) self.assertEqual(ss.deepcopy().stripped_query, ss.stripped_query) def test_extract_title1(self): ss = self._ss(query='some text query [title: what is this?]') self.assertEqual(ss.query_title, 'what is this?') self.assertEqual(ss.stripped_query, 'some text query') def test_extract_title2(self): ss = self._ss(query='some text query title:"what is this?"') self.assertEqual(ss.query_title, 'what is this?') self.assertEqual(ss.stripped_query, 'some text query') def test_extract_title3(self): ss = self._ss(query='some text query title:\'what is this?\'') self.assertEqual(ss.query_title, 'what is this?') self.assertEqual(ss.stripped_query, 'some text query') def test_deep_copy_1(self): # deepcopy() is tested in other tests as well, but this is a dedicated test # just to make sure in one place that everything is ok: # 1. immutable properties (strings, ints) are just assigned to the copy # 2. lists are cloned so that change in the copy doesn't affect the original ss = SearchState( scope='unanswered', sort='votes-desc', query='hejho #tag1 [tag: tag2] @user @user2 title:"what is this?"', tags='miki, mini', author='12', page='2', user_logged_in=False ) ss2 = ss.deepcopy() self.assertEqual(ss.scope, 'unanswered') self.assertTrue(ss.scope is ss2.scope) self.assertEqual(ss.sort, 'votes-desc') self.assertTrue(ss.sort is ss2.sort) self.assertEqual(ss.query, 'hejho #tag1 [tag: tag2] @user @user2 title:"what is this?"') self.assertTrue(ss.query is ss2.query) self.assertFalse(ss.tags is ss2.tags) self.assertItemsEqual(ss.tags, ss2.tags) self.assertEqual(ss.author, 12) self.assertTrue(ss.author is ss2.author) self.assertEqual(ss.page, 2) self.assertTrue(ss.page is ss2.page) self.assertEqual(ss.stripped_query, 'hejho') self.assertTrue(ss.stripped_query is ss2.stripped_query) self.assertItemsEqual(ss.query_tags, ['tag1', 'tag2']) self.assertFalse(ss.query_tags is ss2.query_tags) self.assertItemsEqual(ss.query_users, ['user', 'user2']) self.assertFalse(ss.query_users is ss2.query_users) self.assertEqual(ss.query_title, 'what is this?') self.assertTrue(ss.query_title is ss2.query_title) self.assertEqual(ss._questions_url, urlresolvers.reverse('questions')) self.assertTrue(ss._questions_url is ss2._questions_url) def test_deep_copy_2(self): # Regression test: a special case of deepcopy() when `tags` list is empty, # there was a bug before where this empty list in original and copy pointed # to the same list object ss = SearchState.get_empty() ss2 = ss.deepcopy() self.assertFalse(ss.tags is ss2.tags) self.assertItemsEqual(ss.tags, ss2.tags) self.assertItemsEqual([], ss2.tags) def test_cannot_add_already_added_tag(self): ss = SearchState.get_empty().add_tag('double').add_tag('double') self.assertListEqual(['double'], ss.tags) def test_prevent_dupped_tags(self): ss = SearchState( scope=None, sort=None, query=None, tags='valid1,dupped,valid2,dupped', author=None, page=None, user_logged_in=False ) self.assertEqual( 'scope:all/sort:activity-desc/tags:valid1,dupped,valid2/page:1/', ss.query_string() )