| Index: appengine/monorail/search/test/query2ast_test.py
|
| diff --git a/appengine/monorail/search/test/query2ast_test.py b/appengine/monorail/search/test/query2ast_test.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..e25768ee9b0b31ddcf6dfcfab9d2ecc5c44bee8c
|
| --- /dev/null
|
| +++ b/appengine/monorail/search/test/query2ast_test.py
|
| @@ -0,0 +1,546 @@
|
| +# Copyright 2016 The Chromium Authors. All rights reserved.
|
| +# Use of this source code is govered by a BSD-style
|
| +# license that can be found in the LICENSE file or at
|
| +# https://developers.google.com/open-source/licenses/bsd
|
| +
|
| +"""Tests for the query2ast module."""
|
| +
|
| +import datetime
|
| +import time
|
| +import unittest
|
| +
|
| +from proto import ast_pb2
|
| +from search import query2ast
|
| +from services import fulltext_helpers
|
| +from tracker import tracker_bizobj
|
| +
|
| +BOOL = query2ast.BOOL
|
| +DATE = query2ast.DATE
|
| +NUM = query2ast.NUM
|
| +TXT = query2ast.TXT
|
| +
|
| +BUILTIN_ISSUE_FIELDS = query2ast.BUILTIN_ISSUE_FIELDS
|
| +ANY_FIELD = query2ast.BUILTIN_ISSUE_FIELDS['any_field']
|
| +
|
| +EQ = query2ast.EQ
|
| +NE = query2ast.NE
|
| +LT = query2ast.LT
|
| +GT = query2ast.GT
|
| +LE = query2ast.LE
|
| +GE = query2ast.GE
|
| +TEXT_HAS = query2ast.TEXT_HAS
|
| +NOT_TEXT_HAS = query2ast.NOT_TEXT_HAS
|
| +TEXT_MATCHES = query2ast.TEXT_MATCHES
|
| +NOT_TEXT_MATCHES = query2ast.NOT_TEXT_MATCHES
|
| +IS_DEFINED = query2ast.IS_DEFINED
|
| +IS_NOT_DEFINED = query2ast.IS_NOT_DEFINED
|
| +KEY_HAS = query2ast.KEY_HAS
|
| +
|
| +MakeCond = ast_pb2.MakeCond
|
| +
|
| +
|
| +class QueryParsingUnitTest(unittest.TestCase):
|
| +
|
| + default_config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
|
| +
|
| + @unittest.skip('TODO(jrobbins): fully support OR')
|
| + def skip_testParseUserQuery_OrClause(self):
|
| + # ParseUserQuery extends _ParseORQuery with specialized
|
| + # handling of "OR" operators in a user query
|
| +
|
| + # an "OR" query, which should look like two separate simple querys
|
| + # joined together by a pipe.
|
| + ast = query2ast.ParseUserQuery(
|
| + 'ham OR fancy', '', BUILTIN_ISSUE_FIELDS, self.default_config)
|
| + conj1 = ast.conjunctions[0]
|
| + conj2 = ast.conjunctions[1]
|
| + self.assertEqual([MakeCond(TEXT_HAS, [ANY_FIELD], ['ham'], [])],
|
| + conj1.conds)
|
| + self.assertEqual([MakeCond(TEXT_HAS, [ANY_FIELD], ['fancy'], [])],
|
| + conj2.conds)
|
| +
|
| + def testParseUserQuery_Words(self):
|
| + # an "ORTerm" is actually anything appearing on either side of an
|
| + # "OR" operator. So this could be thought of as "simple" query parsing.
|
| +
|
| + # a simple query with no spaces
|
| + ast = query2ast.ParseUserQuery(
|
| + 'hamfancy', '', BUILTIN_ISSUE_FIELDS, self.default_config)
|
| + fulltext_cond = ast.conjunctions[0].conds[0]
|
| + self.assertEqual(
|
| + MakeCond(TEXT_HAS, [ANY_FIELD], ['hamfancy'], []), fulltext_cond)
|
| +
|
| + # negative word
|
| + ast = query2ast.ParseUserQuery(
|
| + '-hamfancy', '', BUILTIN_ISSUE_FIELDS, self.default_config)
|
| + fulltext_cond = ast.conjunctions[0].conds[0]
|
| + self.assertEqual(
|
| + # note: not NOT_TEXT_HAS.
|
| + MakeCond(NOT_TEXT_HAS, [ANY_FIELD], ['hamfancy'], []),
|
| + fulltext_cond)
|
| +
|
| + # an explicit "AND" query in the "featured" context
|
| + warnings = []
|
| + query2ast.ParseUserQuery(
|
| + 'ham AND fancy', 'label:featured', BUILTIN_ISSUE_FIELDS,
|
| + self.default_config, warnings=warnings)
|
| + self.assertEqual(
|
| + ['The only supported boolean operator is OR (all capitals).'],
|
| + warnings)
|
| +
|
| + # an implicit "AND" query
|
| + ast = query2ast.ParseUserQuery(
|
| + 'ham fancy', '-label:deprecated', BUILTIN_ISSUE_FIELDS,
|
| + self.default_config)
|
| + scope_cond1, ft_cond1, ft_cond2 = ast.conjunctions[0].conds
|
| + self.assertEqual(
|
| + MakeCond(NOT_TEXT_HAS, [BUILTIN_ISSUE_FIELDS['label']],
|
| + ['deprecated'], []),
|
| + scope_cond1)
|
| + self.assertEqual(
|
| + MakeCond(TEXT_HAS, [ANY_FIELD], ['ham'], []), ft_cond1)
|
| + self.assertEqual(
|
| + MakeCond(TEXT_HAS, [ANY_FIELD], ['fancy'], []), ft_cond2)
|
| +
|
| + # Use word with special prefix.
|
| + word_with_special_prefix = '%stest' % fulltext_helpers.NON_OP_PREFIXES[0]
|
| + ast = query2ast.ParseUserQuery(
|
| + word_with_special_prefix, '', BUILTIN_ISSUE_FIELDS, self.default_config)
|
| + fulltext_cond = ast.conjunctions[0].conds[0]
|
| + self.assertEqual(
|
| + MakeCond(TEXT_HAS, [ANY_FIELD], [word_with_special_prefix], []),
|
| + fulltext_cond)
|
| +
|
| + # mix positive and negative words
|
| + ast = query2ast.ParseUserQuery(
|
| + 'ham -fancy', '-label:deprecated', BUILTIN_ISSUE_FIELDS,
|
| + self.default_config)
|
| + scope_cond1, ft_cond1, ft_cond2 = ast.conjunctions[0].conds
|
| + self.assertEqual(
|
| + MakeCond(NOT_TEXT_HAS, [BUILTIN_ISSUE_FIELDS['label']],
|
| + ['deprecated'], []),
|
| + scope_cond1)
|
| + self.assertEqual(
|
| + MakeCond(TEXT_HAS, [ANY_FIELD], ['ham'], []), ft_cond1)
|
| + self.assertEqual(
|
| + MakeCond(NOT_TEXT_HAS, [ANY_FIELD], ['fancy'], []), ft_cond2)
|
| +
|
| + # converts terms to lower case
|
| + ast = query2ast.ParseUserQuery(
|
| + 'AmDude', '-label:deprecated', BUILTIN_ISSUE_FIELDS,
|
| + self.default_config)
|
| + scope_cond1, fulltext_cond = ast.conjunctions[0].conds
|
| + self.assertEqual(
|
| + MakeCond(NOT_TEXT_HAS, [BUILTIN_ISSUE_FIELDS['label']],
|
| + ['deprecated'], []),
|
| + scope_cond1)
|
| + self.assertEqual(
|
| + MakeCond(TEXT_HAS, [ANY_FIELD], ['amdude'], []), fulltext_cond)
|
| +
|
| + def testParseUserQuery_Phrases(self):
|
| + # positive phrases
|
| + ast = query2ast.ParseUserQuery(
|
| + '"one two"', '-label:deprecated', BUILTIN_ISSUE_FIELDS,
|
| + self.default_config)
|
| + scope_cond1, fulltext_cond = ast.conjunctions[0].conds
|
| + self.assertEqual(
|
| + MakeCond(NOT_TEXT_HAS, [BUILTIN_ISSUE_FIELDS['label']],
|
| + ['deprecated'], []),
|
| + scope_cond1)
|
| + self.assertEqual(
|
| + MakeCond(TEXT_HAS, [ANY_FIELD], ['"one two"'], []), fulltext_cond)
|
| +
|
| + # negative phrases
|
| + ast = query2ast.ParseUserQuery(
|
| + '-"one two"', '-label:deprecated', BUILTIN_ISSUE_FIELDS,
|
| + self.default_config)
|
| + scope_cond1, fulltext_cond = ast.conjunctions[0].conds
|
| + self.assertEqual(
|
| + MakeCond(NOT_TEXT_HAS, [BUILTIN_ISSUE_FIELDS['label']],
|
| + ['deprecated'], []),
|
| + scope_cond1)
|
| + self.assertEqual(
|
| + MakeCond(NOT_TEXT_HAS, [ANY_FIELD], ['"one two"'], []), fulltext_cond)
|
| +
|
| + # multiple phrases
|
| + ast = query2ast.ParseUserQuery(
|
| + '-"a b" "x y"', '-label:deprecated', BUILTIN_ISSUE_FIELDS,
|
| + self.default_config)
|
| + scope_cond1, ft_cond1, ft_cond2 = ast.conjunctions[0].conds
|
| + self.assertEqual(
|
| + MakeCond(NOT_TEXT_HAS, [BUILTIN_ISSUE_FIELDS['label']],
|
| + ['deprecated'], []),
|
| + scope_cond1)
|
| + self.assertEqual(
|
| + MakeCond(NOT_TEXT_HAS, [ANY_FIELD], ['"a b"'], []), ft_cond1)
|
| + self.assertEqual(
|
| + MakeCond(TEXT_HAS, [ANY_FIELD], ['"x y"'], []), ft_cond2)
|
| +
|
| + def testParseUserQuery_CodeSyntaxThatWeNeedToCopeWith(self):
|
| + # positive phrases
|
| + ast = query2ast.ParseUserQuery(
|
| + 'Base::Tuple', '', BUILTIN_ISSUE_FIELDS,
|
| + self.default_config)
|
| + cond = ast.conjunctions[0].conds[0]
|
| + self.assertEqual(
|
| + MakeCond(TEXT_HAS, [ANY_FIELD],
|
| + ['"base::tuple"'], []),
|
| + cond)
|
| +
|
| + def testParseUserQuery_HasOperator(self):
|
| + # Search for issues with at least one attachment
|
| + ast = query2ast.ParseUserQuery(
|
| + 'has:attachment', '', BUILTIN_ISSUE_FIELDS, self.default_config)
|
| + cond1 = ast.conjunctions[0].conds[0]
|
| + self.assertEqual(
|
| + MakeCond(IS_DEFINED, [BUILTIN_ISSUE_FIELDS['attachment']], [], []),
|
| + cond1)
|
| +
|
| + ast = query2ast.ParseUserQuery(
|
| + '-has:attachment', '', BUILTIN_ISSUE_FIELDS, self.default_config)
|
| + cond1 = ast.conjunctions[0].conds[0]
|
| + self.assertEqual(
|
| + MakeCond(IS_NOT_DEFINED, [BUILTIN_ISSUE_FIELDS['attachment']], [], []),
|
| + cond1)
|
| +
|
| + ast = query2ast.ParseUserQuery(
|
| + 'has=attachment', '', BUILTIN_ISSUE_FIELDS, self.default_config)
|
| + cond1 = ast.conjunctions[0].conds[0]
|
| + self.assertEqual(
|
| + MakeCond(IS_DEFINED, [BUILTIN_ISSUE_FIELDS['attachment']], [], []),
|
| + cond1)
|
| +
|
| + ast = query2ast.ParseUserQuery(
|
| + '-has=attachment', '', BUILTIN_ISSUE_FIELDS, self.default_config)
|
| + cond1 = ast.conjunctions[0].conds[0]
|
| + self.assertEqual(
|
| + MakeCond(IS_NOT_DEFINED, [BUILTIN_ISSUE_FIELDS['attachment']], [], []),
|
| + cond1)
|
| +
|
| + # Search for numeric fields for searches with 'has' prefix
|
| + ast = query2ast.ParseUserQuery(
|
| + 'has:attachments', '', BUILTIN_ISSUE_FIELDS, self.default_config)
|
| + cond1 = ast.conjunctions[0].conds[0]
|
| + self.assertEqual(
|
| + MakeCond(IS_DEFINED, [BUILTIN_ISSUE_FIELDS['attachments']], [], []),
|
| + cond1)
|
| +
|
| + ast = query2ast.ParseUserQuery(
|
| + '-has:attachments', '', BUILTIN_ISSUE_FIELDS, self.default_config)
|
| + cond1 = ast.conjunctions[0].conds[0]
|
| + self.assertEqual(
|
| + MakeCond(IS_NOT_DEFINED, [BUILTIN_ISSUE_FIELDS['attachments']],
|
| + [], []),
|
| + cond1)
|
| +
|
| + def testParseUserQuery_Components(self):
|
| + """Parse user queries for components"""
|
| + ast = query2ast.ParseUserQuery(
|
| + 'component:UI', '', BUILTIN_ISSUE_FIELDS, self.default_config)
|
| + cond1 = ast.conjunctions[0].conds[0]
|
| + self.assertEqual(
|
| + MakeCond(TEXT_HAS, [BUILTIN_ISSUE_FIELDS['component']],
|
| + ['ui'], []),
|
| + cond1)
|
| +
|
| + ast = query2ast.ParseUserQuery(
|
| + 'Component:UI>AboutBox', '', BUILTIN_ISSUE_FIELDS, self.default_config)
|
| + cond1 = ast.conjunctions[0].conds[0]
|
| + self.assertEqual(
|
| + MakeCond(TEXT_HAS, [BUILTIN_ISSUE_FIELDS['component']],
|
| + ['ui>aboutbox'], []),
|
| + cond1)
|
| +
|
| + def testParseUserQuery_OwnersReportersAndCc(self):
|
| + """Parse user queries for owner:, reporter: and cc:."""
|
| + ast = query2ast.ParseUserQuery(
|
| + 'owner:user', '', BUILTIN_ISSUE_FIELDS, self.default_config)
|
| + cond1 = ast.conjunctions[0].conds[0]
|
| + self.assertEqual(
|
| + MakeCond(TEXT_HAS, [BUILTIN_ISSUE_FIELDS['owner']],
|
| + ['user'], []),
|
| + cond1)
|
| +
|
| + ast = query2ast.ParseUserQuery(
|
| + 'owner:user@example.com', '', BUILTIN_ISSUE_FIELDS, self.default_config)
|
| + cond1 = ast.conjunctions[0].conds[0]
|
| + self.assertEqual(
|
| + MakeCond(TEXT_HAS, [BUILTIN_ISSUE_FIELDS['owner']],
|
| + ['user@example.com'], []),
|
| + cond1)
|
| +
|
| + ast = query2ast.ParseUserQuery(
|
| + 'owner=user@example.com', '', BUILTIN_ISSUE_FIELDS, self.default_config)
|
| + cond1 = ast.conjunctions[0].conds[0]
|
| + self.assertEqual(
|
| + MakeCond(EQ, [BUILTIN_ISSUE_FIELDS['owner']],
|
| + ['user@example.com'], []),
|
| + cond1)
|
| +
|
| + ast = query2ast.ParseUserQuery(
|
| + '-reporter=user@example.com', '', BUILTIN_ISSUE_FIELDS,
|
| + self.default_config)
|
| + cond1 = ast.conjunctions[0].conds[0]
|
| + self.assertEqual(
|
| + MakeCond(NE, [BUILTIN_ISSUE_FIELDS['reporter']],
|
| + ['user@example.com'], []),
|
| + cond1)
|
| +
|
| + ast = query2ast.ParseUserQuery(
|
| + 'cc=user@example.com,user2@example.com', '', BUILTIN_ISSUE_FIELDS,
|
| + self.default_config)
|
| + cond1 = ast.conjunctions[0].conds[0]
|
| + self.assertEqual(
|
| + MakeCond(EQ, [BUILTIN_ISSUE_FIELDS['cc']],
|
| + ['user@example.com', 'user2@example.com'], []),
|
| + cond1)
|
| +
|
| + ast = query2ast.ParseUserQuery(
|
| + 'cc:user,user2', '', BUILTIN_ISSUE_FIELDS, self.default_config)
|
| + cond1 = ast.conjunctions[0].conds[0]
|
| + self.assertEqual(
|
| + MakeCond(TEXT_HAS, [BUILTIN_ISSUE_FIELDS['cc']],
|
| + ['user', 'user2'], []),
|
| + cond1)
|
| +
|
| + def testParseUserQuery_SearchWithinFields(self):
|
| + # Search for issues with certain filenames
|
| + ast = query2ast.ParseUserQuery(
|
| + 'attachment:filename', '', BUILTIN_ISSUE_FIELDS, self.default_config)
|
| + cond1 = ast.conjunctions[0].conds[0]
|
| + self.assertEqual(
|
| + MakeCond(TEXT_HAS, [BUILTIN_ISSUE_FIELDS['attachment']],
|
| + ['filename'], []),
|
| + cond1)
|
| +
|
| + ast = query2ast.ParseUserQuery(
|
| + '-attachment:filename', '', BUILTIN_ISSUE_FIELDS,
|
| + self.default_config)
|
| + cond1 = ast.conjunctions[0].conds[0]
|
| + self.assertEqual(
|
| + MakeCond(NOT_TEXT_HAS, [BUILTIN_ISSUE_FIELDS['attachment']],
|
| + ['filename'], []),
|
| + cond1)
|
| +
|
| + # Search for issues with a certain number of attachments
|
| + ast = query2ast.ParseUserQuery(
|
| + 'attachments:2', '', BUILTIN_ISSUE_FIELDS, self.default_config)
|
| + cond1 = ast.conjunctions[0].conds[0]
|
| + self.assertEqual(
|
| + MakeCond(TEXT_HAS, [BUILTIN_ISSUE_FIELDS['attachments']],
|
| + ['2'], [2]),
|
| + cond1)
|
| +
|
| + # Searches with '=' syntax
|
| + ast = query2ast.ParseUserQuery(
|
| + 'attachment=filename', '', BUILTIN_ISSUE_FIELDS, self.default_config)
|
| + cond1 = ast.conjunctions[0].conds[0]
|
| + self.assertEqual(
|
| + MakeCond(EQ, [BUILTIN_ISSUE_FIELDS['attachment']],
|
| + ['filename'], []),
|
| + cond1)
|
| +
|
| + ast = query2ast.ParseUserQuery(
|
| + '-attachment=filename', '', BUILTIN_ISSUE_FIELDS, self.default_config)
|
| + cond1 = ast.conjunctions[0].conds[0]
|
| + self.assertEqual(
|
| + MakeCond(NE, [BUILTIN_ISSUE_FIELDS['attachment']],
|
| + ['filename'], []),
|
| + cond1)
|
| +
|
| + ast = query2ast.ParseUserQuery(
|
| + 'milestone=2009', '', BUILTIN_ISSUE_FIELDS, self.default_config)
|
| + cond1 = ast.conjunctions[0].conds[0]
|
| + self.assertEqual(
|
| + MakeCond(EQ, [BUILTIN_ISSUE_FIELDS['label']], ['milestone-2009'], []),
|
| + cond1)
|
| +
|
| + ast = query2ast.ParseUserQuery(
|
| + '-milestone=2009', '', BUILTIN_ISSUE_FIELDS, self.default_config)
|
| + cond1 = ast.conjunctions[0].conds[0]
|
| + self.assertEqual(
|
| + MakeCond(NE, [BUILTIN_ISSUE_FIELDS['label']], ['milestone-2009'], []),
|
| + cond1)
|
| +
|
| + ast = query2ast.ParseUserQuery(
|
| + 'milestone=2009-Q1', '', BUILTIN_ISSUE_FIELDS, self.default_config)
|
| + cond1 = ast.conjunctions[0].conds[0]
|
| + self.assertEqual(
|
| + MakeCond(EQ, [BUILTIN_ISSUE_FIELDS['label']],
|
| + ['milestone-2009-q1'], []),
|
| + cond1)
|
| +
|
| + ast = query2ast.ParseUserQuery(
|
| + '-milestone=2009-Q1', '', BUILTIN_ISSUE_FIELDS,
|
| + self.default_config)
|
| + cond1 = ast.conjunctions[0].conds[0]
|
| + self.assertEqual(
|
| + MakeCond(NE, [BUILTIN_ISSUE_FIELDS['label']],
|
| + ['milestone-2009-q1'], []),
|
| + cond1)
|
| +
|
| + # Searches with ':' syntax
|
| + ast = query2ast.ParseUserQuery(
|
| + 'summary:foo', '', BUILTIN_ISSUE_FIELDS, self.default_config)
|
| + cond1 = ast.conjunctions[0].conds[0]
|
| + self.assertEqual(
|
| + MakeCond(TEXT_HAS,
|
| + [BUILTIN_ISSUE_FIELDS['summary']], ['foo'], []),
|
| + cond1)
|
| +
|
| + ast = query2ast.ParseUserQuery(
|
| + 'summary:"greetings programs"', '', BUILTIN_ISSUE_FIELDS,
|
| + self.default_config)
|
| + cond1 = ast.conjunctions[0].conds[0]
|
| + self.assertEqual(
|
| + MakeCond(TEXT_HAS,
|
| + [BUILTIN_ISSUE_FIELDS['summary']], ['greetings programs'], []),
|
| + cond1)
|
| +
|
| + ast = query2ast.ParseUserQuery(
|
| + 'summary:"Ӓ"', '', BUILTIN_ISSUE_FIELDS,
|
| + self.default_config)
|
| + cond1 = ast.conjunctions[0].conds[0]
|
| + self.assertEqual(
|
| + MakeCond(TEXT_HAS,
|
| + [BUILTIN_ISSUE_FIELDS['summary']], ['Ӓ'], []),
|
| + cond1)
|
| +
|
| + ast = query2ast.ParseUserQuery(
|
| + 'priority:high', '', BUILTIN_ISSUE_FIELDS, self.default_config)
|
| + cond1 = ast.conjunctions[0].conds[0]
|
| + self.assertEqual(
|
| + MakeCond(KEY_HAS,
|
| + [BUILTIN_ISSUE_FIELDS['label']], ['priority-high'], []),
|
| + cond1)
|
| +
|
| + ast = query2ast.ParseUserQuery(
|
| + 'type:security', '', BUILTIN_ISSUE_FIELDS, self.default_config)
|
| + cond1 = ast.conjunctions[0].conds[0]
|
| + self.assertEqual(
|
| + MakeCond(KEY_HAS,
|
| + [BUILTIN_ISSUE_FIELDS['label']], ['type-security'], []),
|
| + cond1)
|
| +
|
| + ast = query2ast.ParseUserQuery(
|
| + 'label:priority-high', '', BUILTIN_ISSUE_FIELDS, self.default_config)
|
| + cond1 = ast.conjunctions[0].conds[0]
|
| + self.assertEqual(
|
| + MakeCond(TEXT_HAS,
|
| + [BUILTIN_ISSUE_FIELDS['label']], ['priority-high'], []),
|
| + cond1)
|
| +
|
| + def testParseUserQuery_QuickOr(self):
|
| + # quick-or searches
|
| + ast = query2ast.ParseUserQuery(
|
| + 'milestone:2008,2009,2010', '', BUILTIN_ISSUE_FIELDS,
|
| + self.default_config)
|
| + cond1 = ast.conjunctions[0].conds[0]
|
| + self.assertEqual(
|
| + MakeCond(KEY_HAS, [BUILTIN_ISSUE_FIELDS['label']],
|
| + ['milestone-2008', 'milestone-2009', 'milestone-2010'], []),
|
| + cond1)
|
| +
|
| + ast = query2ast.ParseUserQuery(
|
| + 'label:milestone-2008,milestone-2009,milestone-2010', '',
|
| + BUILTIN_ISSUE_FIELDS, self.default_config)
|
| + cond1 = ast.conjunctions[0].conds[0]
|
| + self.assertEqual(
|
| + MakeCond(TEXT_HAS, [BUILTIN_ISSUE_FIELDS['label']],
|
| + ['milestone-2008', 'milestone-2009', 'milestone-2010'], []),
|
| + cond1)
|
| +
|
| + ast = query2ast.ParseUserQuery(
|
| + 'milestone=2008,2009,2010', '', BUILTIN_ISSUE_FIELDS,
|
| + self.default_config)
|
| + cond1 = ast.conjunctions[0].conds[0]
|
| + self.assertEqual(
|
| + MakeCond(EQ, [BUILTIN_ISSUE_FIELDS['label']],
|
| + ['milestone-2008', 'milestone-2009', 'milestone-2010'], []),
|
| + cond1)
|
| +
|
| + def testParseUserQuery_Dates(self):
|
| + # query with a daterange
|
| + ast = query2ast.ParseUserQuery(
|
| + 'modified>=2009-5-12', '', BUILTIN_ISSUE_FIELDS,
|
| + self.default_config)
|
| + cond1 = ast.conjunctions[0].conds[0]
|
| + ts1 = int(time.mktime(datetime.datetime(2009, 5, 12).timetuple()))
|
| + self.assertEqual(
|
| + MakeCond(GE, [BUILTIN_ISSUE_FIELDS['modified']], [], [ts1]), cond1)
|
| +
|
| + # query with multiple dateranges
|
| + ast = query2ast.ParseUserQuery(
|
| + 'modified>=2009-5-12 opened<2008/1/1', '',
|
| + BUILTIN_ISSUE_FIELDS, self.default_config)
|
| + cond1, cond2 = ast.conjunctions[0].conds
|
| + ts1 = int(time.mktime(datetime.datetime(2009, 5, 12).timetuple()))
|
| + self.assertEqual(
|
| + MakeCond(GE, [BUILTIN_ISSUE_FIELDS['modified']], [], [ts1]), cond1)
|
| + ts2 = int(time.mktime(datetime.datetime(2008, 1, 1).timetuple()))
|
| + self.assertEqual(
|
| + MakeCond(LT, [BUILTIN_ISSUE_FIELDS['opened']], [], [ts2]), cond2)
|
| +
|
| + # query with multiple dateranges plus a search term
|
| + ast = query2ast.ParseUserQuery(
|
| + 'one two modified>=2009-5-12 opened<2008/1/1', '',
|
| + BUILTIN_ISSUE_FIELDS, self.default_config)
|
| + ft_cond1, ft_cond2, cond1, cond2 = ast.conjunctions[0].conds
|
| + ts1 = int(time.mktime(datetime.datetime(2009, 5, 12).timetuple()))
|
| + self.assertEqual(
|
| + MakeCond(TEXT_HAS, [ANY_FIELD], ['one'], []), ft_cond1)
|
| + self.assertEqual(
|
| + MakeCond(TEXT_HAS, [ANY_FIELD], ['two'], []), ft_cond2)
|
| + self.assertEqual(
|
| + MakeCond(GE, [BUILTIN_ISSUE_FIELDS['modified']], [], [ts1]), cond1)
|
| + ts2 = int(time.mktime(datetime.datetime(2008, 1, 1).timetuple()))
|
| + self.assertEqual(
|
| + MakeCond(LT, [BUILTIN_ISSUE_FIELDS['opened']], [], [ts2]), cond2)
|
| +
|
| + # query with a date field compared to "today"
|
| + ast = query2ast.ParseUserQuery(
|
| + 'modified<today', '', BUILTIN_ISSUE_FIELDS,
|
| + self.default_config)
|
| + cond1 = ast.conjunctions[0].conds[0]
|
| + ts1 = query2ast._CalculatePastDate(0)
|
| + self.assertEqual(MakeCond(LT, [BUILTIN_ISSUE_FIELDS['modified']],
|
| + [], [ts1]),
|
| + cond1)
|
| +
|
| + # query with a daterange using today-N alias
|
| + ast = query2ast.ParseUserQuery(
|
| + 'modified>=today-13', '', BUILTIN_ISSUE_FIELDS,
|
| + self.default_config)
|
| + cond1 = ast.conjunctions[0].conds[0]
|
| + ts1 = query2ast._CalculatePastDate(13)
|
| + self.assertEqual(MakeCond(GE, [BUILTIN_ISSUE_FIELDS['modified']],
|
| + [], [ts1]),
|
| + cond1)
|
| +
|
| + ast = query2ast.ParseUserQuery(
|
| + 'modified>today-13', '', BUILTIN_ISSUE_FIELDS, self.default_config)
|
| + cond1 = ast.conjunctions[0].conds[0]
|
| + ts1 = query2ast._CalculatePastDate(13)
|
| + self.assertEqual(MakeCond(GT, [BUILTIN_ISSUE_FIELDS['modified']],
|
| + [], [ts1]),
|
| + cond1)
|
| +
|
| + # query with multiple old date query terms.
|
| + ast = query2ast.ParseUserQuery(
|
| + 'modified-after:2009-5-12 opened-before:2008/1/1 '
|
| + 'closed-after:2007-2-1', '',
|
| + BUILTIN_ISSUE_FIELDS, self.default_config)
|
| + cond1, cond2, cond3 = ast.conjunctions[0].conds
|
| + ts1 = int(time.mktime(datetime.datetime(2009, 5, 12).timetuple()))
|
| + self.assertEqual(
|
| + MakeCond(GT, [BUILTIN_ISSUE_FIELDS['modified']], [], [ts1]), cond1)
|
| + ts2 = int(time.mktime(datetime.datetime(2008, 1, 1).timetuple()))
|
| + self.assertEqual(
|
| + MakeCond(LT, [BUILTIN_ISSUE_FIELDS['opened']], [], [ts2]), cond2)
|
| + ts3 = int(time.mktime(datetime.datetime(2007, 2, 1).timetuple()))
|
| + self.assertEqual(
|
| + MakeCond(GT, [BUILTIN_ISSUE_FIELDS['closed']], [], [ts3]), cond3)
|
| +
|
| +
|
| +if __name__ == '__main__':
|
| + unittest.main()
|
|
|