blob: ac5a00b044f70c00a9e94d0d68293fb094ead6e4 [file] [log] [blame]
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +01001# Copyright 2016 The Chromium Authors
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
Copybara854996b2021-09-07 19:36:02 +00004
5"""Tests for the ast2sort module."""
6from __future__ import print_function
7from __future__ import division
8from __future__ import absolute_import
9
10import unittest
11
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +010012from mrproto import tracker_pb2
Copybara854996b2021-09-07 19:36:02 +000013from search import ast2sort
14from search import query2ast
15
16
17BUILTIN_ISSUE_FIELDS = query2ast.BUILTIN_ISSUE_FIELDS
18ANY_FIELD = query2ast.BUILTIN_ISSUE_FIELDS['any_field']
19
20
21class AST2SortTest(unittest.TestCase):
22
23 def setUp(self):
24 self.harmonized_labels = [
25 (101, 0, 'Hot'), (102, 1, 'Cold'), (103, None, 'Odd')]
26 self.harmonized_statuses = [
27 (201, 0, 'New'), (202, 1, 'Assigned'), (203, None, 'OnHold')]
28 self.harmonized_fields = []
29 self.fmt = lambda string, **kwords: string
30
31 def testBuildSortClauses_EmptySortDirectives(self):
32 left_joins, order_by = ast2sort.BuildSortClauses(
33 [], self.harmonized_labels, self.harmonized_statuses,
34 self.harmonized_fields)
35 self.assertEqual([], left_joins)
36 self.assertEqual([], order_by)
37
38 def testBuildSortClauses_Normal(self):
39 left_joins, order_by = ast2sort.BuildSortClauses(
40 ['stars', 'status', 'pri', 'reporter', 'id'], self.harmonized_labels,
41 self.harmonized_statuses, self.harmonized_fields)
42 expected_left_joins = [
43 ('User AS Sort3 ON Issue.reporter_id = Sort3.user_id', [])]
44 expected_order_by = [
45 ('Issue.star_count ASC', []),
46 ('FIELD(IF(ISNULL(Issue.status_id), Issue.derived_status_id, '
47 'Issue.status_id), %s,%s) DESC', [201, 202]),
48 ('FIELD(IF(ISNULL(Issue.status_id), Issue.derived_status_id, '
49 'Issue.status_id), %s) DESC', [203]),
50 ('ISNULL(Sort3.email) ASC', []),
51 ('Sort3.email ASC', []),
52 ('Issue.local_id ASC', [])]
53 self.assertEqual(expected_left_joins, left_joins)
54 self.assertEqual(expected_order_by, order_by)
55
56 def testProcessProjectSD(self):
57 left_joins, order_by = ast2sort._ProcessProjectSD(self.fmt)
58 self.assertEqual([], left_joins)
59 self.assertEqual(
60 [('Issue.project_id {sort_dir}', [])],
61 order_by)
62
63 def testProcessReporterSD(self):
64 left_joins, order_by = ast2sort._ProcessReporterSD(self.fmt)
65 self.assertEqual(
66 [('User AS {alias} ON Issue.reporter_id = {alias}.user_id', [])],
67 left_joins)
68 self.assertEqual(
69 [('ISNULL({alias}.email) {sort_dir}', []),
70 ('{alias}.email {sort_dir}', [])],
71 order_by)
72
73 def testProcessOwnerSD(self):
74 left_joins, order_by = ast2sort._ProcessOwnerSD(self.fmt)
75 self.assertEqual(
76 [('User AS {alias}_exp ON Issue.owner_id = {alias}_exp.user_id', []),
77 ('User AS {alias}_der ON '
78 'Issue.derived_owner_id = {alias}_der.user_id', [])],
79 left_joins)
80 self.assertEqual(
81 [('(ISNULL({alias}_exp.email) AND ISNULL({alias}_der.email)) '
82 '{sort_dir}', []),
83 ('CONCAT({alias}_exp.email, {alias}_der.email) {sort_dir}', [])],
84 order_by)
85
86 def testProcessCcSD(self):
87 left_joins, order_by = ast2sort._ProcessCcSD(self.fmt)
88 self.assertEqual(
89 [('Issue2Cc AS {alias} ON Issue.id = {alias}.issue_id '
90 'LEFT JOIN User AS {alias}_user '
91 'ON {alias}.cc_id = {alias}_user.user_id', [])],
92 left_joins)
93 self.assertEqual(
94 [('ISNULL({alias}_user.email) {sort_dir}', []),
95 ('{alias}_user.email {sort_dir}', [])],
96 order_by)
97
98 def testProcessComponentSD(self):
99 left_joins, order_by = ast2sort._ProcessComponentSD(self.fmt)
100 self.assertEqual(
101 [('Issue2Component AS {alias} ON Issue.id = {alias}.issue_id '
102 'LEFT JOIN ComponentDef AS {alias}_component '
103 'ON {alias}.component_id = {alias}_component.id', [])],
104 left_joins)
105 self.assertEqual(
106 [('ISNULL({alias}_component.path) {sort_dir}', []),
107 ('{alias}_component.path {sort_dir}', [])],
108 order_by)
109
110 def testProcessSummarySD(self):
111 left_joins, order_by = ast2sort._ProcessSummarySD(self.fmt)
112 self.assertEqual(
113 [('IssueSummary AS {alias} ON Issue.id = {alias}.issue_id', [])],
114 left_joins)
115 self.assertEqual(
116 [('{alias}.summary {sort_dir}', [])],
117 order_by)
118
119 def testProcessStatusSD(self):
120 pass # TODO(jrobbins): fill in this test case
121
122 def testProcessBlockedSD(self):
123 left_joins, order_by = ast2sort._ProcessBlockedSD(self.fmt)
124 self.assertEqual(
125 [('IssueRelation AS {alias} ON Issue.id = {alias}.issue_id '
126 'AND {alias}.kind = %s', ['blockedon'])],
127 left_joins)
128 self.assertEqual(
129 [('ISNULL({alias}.dst_issue_id) {sort_dir}', [])],
130 order_by)
131
132 def testProcessBlockedOnSD(self):
133 left_joins, order_by = ast2sort._ProcessBlockedOnSD(self.fmt)
134 self.assertEqual(
135 [('IssueRelation AS {alias} ON Issue.id = {alias}.issue_id '
136 'AND {alias}.kind = %s', ['blockedon'])],
137 left_joins)
138 self.assertEqual(
139 [('ISNULL({alias}.dst_issue_id) {sort_dir}', []),
140 ('{alias}.dst_issue_id {sort_dir}', [])],
141 order_by)
142
143 def testProcessBlockingSD(self):
144 left_joins, order_by = ast2sort._ProcessBlockingSD(self.fmt)
145 self.assertEqual(
146 [('IssueRelation AS {alias} ON Issue.id = {alias}.dst_issue_id '
147 'AND {alias}.kind = %s', ['blockedon'])],
148 left_joins)
149 self.assertEqual(
150 [('ISNULL({alias}.issue_id) {sort_dir}', []),
151 ('{alias}.issue_id {sort_dir}', [])],
152 order_by)
153
154 def testProcessMergedIntoSD(self):
155 left_joins, order_by = ast2sort._ProcessMergedIntoSD(self.fmt)
156 self.assertEqual(
157 [('IssueRelation AS {alias} ON Issue.id = {alias}.issue_id '
158 'AND {alias}.kind = %s', ['mergedinto'])],
159 left_joins)
160 self.assertEqual(
161 [('ISNULL({alias}.dst_issue_id) {sort_dir}', []),
162 ('{alias}.dst_issue_id {sort_dir}', [])],
163 order_by)
164
165 def testProcessCustomAndLabelSD(self):
166 pass # TODO(jrobbins): fill in this test case
167
168 def testProcessCustomAndLabelSD_PhaseField(self):
169 harmonized_labels = []
170 bear_fd = tracker_pb2.FieldDef(
171 field_id=1, field_name='DropBear', project_id=789,
172 field_type=tracker_pb2.FieldTypes.INT_TYPE)
173 bear2_fd = tracker_pb2.FieldDef(
174 field_id=2, field_name='DropBear', project_id=788,
175 field_type=tracker_pb2.FieldTypes.STR_TYPE)
176 koala_fd = tracker_pb2.FieldDef(
177 field_id=3, field_name='koala', project_id=789,
178 field_type=tracker_pb2.FieldTypes.INT_TYPE)
179 bear_app_fd = tracker_pb2.FieldDef(
180 field_id=4, field_name='dropbear', project_id=789,
181 field_type=tracker_pb2.FieldTypes.APPROVAL_TYPE)
182 harmonized_fields = [bear_fd, bear2_fd, koala_fd, bear_app_fd]
183 phase_name = 'stable'
184 alias = 'Sort0'
185 sort_dir = 'DESC'
186 sd = 'stable.dropbear'
187 left_joins, order_by = ast2sort._ProcessCustomAndLabelSD(
188 sd, harmonized_labels, harmonized_fields, alias, sort_dir,
189 self.fmt)
190
191 expected_joins = []
192 expected_order = []
193 int_left_joins, int_order_by = ast2sort._CustomFieldSortClauses(
194 [bear_fd, bear2_fd], tracker_pb2.FieldTypes.INT_TYPE, 'int_value',
195 alias, sort_dir, phase_name=phase_name)
196 str_left_joins, str_order_by = ast2sort._CustomFieldSortClauses(
197 [bear_fd, bear2_fd], tracker_pb2.FieldTypes.STR_TYPE, 'str_value',
198 alias, sort_dir, phase_name=phase_name)
199 user_left_joins, user_order_by = ast2sort._CustomFieldSortClauses(
200 [bear_fd, bear2_fd], tracker_pb2.FieldTypes.USER_TYPE, 'user_id',
201 alias, sort_dir, phase_name=phase_name)
202 label_left_joinss, label_order_by = ast2sort._LabelSortClauses(
203 sd, harmonized_labels, self.fmt)
204 expected_joins.extend(
205 int_left_joins + str_left_joins + user_left_joins + label_left_joinss)
206 expected_order.extend(
207 int_order_by + str_order_by + user_order_by + label_order_by)
208 self.assertEqual(left_joins, expected_joins)
209 self.assertEqual(order_by, expected_order)
210
211 def testApprovalFieldSortClauses_Status(self):
212 approval_fd_list = [
213 tracker_pb2.FieldDef(field_id=2, project_id=789,
214 field_type=tracker_pb2.FieldTypes.APPROVAL_TYPE),
215 tracker_pb2.FieldDef(field_id=4, project_id=788,
216 field_type=tracker_pb2.FieldTypes.APPROVAL_TYPE)
217 ]
218 left_joins, order_by = ast2sort._ApprovalFieldSortClauses(
219 approval_fd_list, '-status', self.fmt)
220
221 self.assertEqual(
222 [('{tbl_name} AS {alias}_approval '
223 'ON Issue.id = {alias}_approval.issue_id '
224 'AND {alias}_approval.approval_id IN ({approval_ids_ph})', [2, 4])],
225 left_joins)
226
227 self.assertEqual(
228 [('FIELD({alias}_approval.status, {approval_status_ph}) {rev_sort_dir}',
229 ast2sort.APPROVAL_STATUS_SORT_ORDER)],
230 order_by)
231
232 def testApprovalFieldSortClauses_Approver(self):
233 approval_fd_list = [
234 tracker_pb2.FieldDef(field_id=2, project_id=789,
235 field_type=tracker_pb2.FieldTypes.APPROVAL_TYPE),
236 tracker_pb2.FieldDef(field_id=4, project_id=788,
237 field_type=tracker_pb2.FieldTypes.APPROVAL_TYPE)
238 ]
239 left_joins, order_by = ast2sort._ApprovalFieldSortClauses(
240 approval_fd_list, '-approver', self.fmt)
241
242 self.assertEqual(
243 [('{tbl_name} AS {alias}_approval '
244 'ON Issue.id = {alias}_approval.issue_id '
245 'AND {alias}_approval.approval_id IN ({approval_ids_ph})', [2, 4]),
246 ('User AS {alias}_approval_user '
247 'ON {alias}_approval.approver_id = {alias}_approval_user.user_id',
248 [])],
249 left_joins)
250
251 self.assertEqual(
252 [('ISNULL({alias}_approval_user.email) {sort_dir}', []),
253 ('{alias}_approval_user.email {sort_dir}', [])],
254 order_by)
255
256 def testLabelSortClauses_NoSuchLabels(self):
257 sd = 'somethingelse'
258 harmonized_labels = [
259 (101, 0, 'Type-Defect'),
260 (102, 1, 'Type-Enhancement'),
261 (103, 2, 'Type-Task'),
262 (104, 0, 'Priority-High'),
263 (199, None, 'Type-Laundry'),
264 ]
265 left_joins, order_by = ast2sort._LabelSortClauses(
266 sd, harmonized_labels, self.fmt)
267 self.assertEqual([], left_joins)
268 self.assertEqual([], order_by)
269
270 def testLabelSortClauses_Normal(self):
271 sd = 'type'
272 harmonized_labels = [
273 (101, 0, 'Type-Defect'),
274 (102, 1, 'Type-Enhancement'),
275 (103, 2, 'Type-Task'),
276 (104, 0, 'Priority-High'),
277 (199, None, 'Type-Laundry'),
278 ]
279 left_joins, order_by = ast2sort._LabelSortClauses(
280 sd, harmonized_labels, self.fmt)
281 self.assertEqual(1, len(left_joins))
282 self.assertEqual(
283 ('Issue2Label AS {alias} ON Issue.id = {alias}.issue_id AND '
284 '{alias}.label_id IN ({all_label_ph})',
285 [101, 102, 103, 199]),
286 left_joins[0])
287 self.assertEqual(2, len(order_by))
288 self.assertEqual(
289 ('FIELD({alias}.label_id, {wk_label_ph}) {rev_sort_dir}',
290 [101, 102, 103]),
291 order_by[0])
292 self.assertEqual(
293 ('FIELD({alias}.label_id, {odd_label_ph}) {rev_sort_dir}',
294 [199]),
295 order_by[1])
296
297 def testCustomFieldSortClauses_Normal(self):
298 fd_list = [
299 tracker_pb2.FieldDef(field_id=1, project_id=789,
300 field_type=tracker_pb2.FieldTypes.INT_TYPE),
301 tracker_pb2.FieldDef(field_id=2, project_id=788,
302 field_type=tracker_pb2.FieldTypes.STR_TYPE),
303 ]
304 left_joins, order_by = ast2sort._CustomFieldSortClauses(
305 fd_list, tracker_pb2.FieldTypes.INT_TYPE, 'int_value', 'Sort0', 'DESC')
306
307 self.assertEqual(
308 left_joins, [
309 ('Issue2FieldValue AS Sort0_int_value '
310 'ON Issue.id = Sort0_int_value.issue_id '
311 'AND Sort0_int_value.field_id IN (%s)', [1]),
312 ])
313 self.assertEqual(
314 order_by, [
315 ('ISNULL(Sort0_int_value.int_value) DESC', []),
316 ('Sort0_int_value.int_value DESC', []),
317 ])
318
319 def testCustomFieldSortClauses_PhaseUser(self):
320 fd_list = [
321 tracker_pb2.FieldDef(field_id=1, project_id=789,
322 field_type=tracker_pb2.FieldTypes.INT_TYPE),
323 tracker_pb2.FieldDef(field_id=2, project_id=788,
324 field_type=tracker_pb2.FieldTypes.STR_TYPE),
325 tracker_pb2.FieldDef(field_id=3, project_id=788,
326 field_type=tracker_pb2.FieldTypes.USER_TYPE),
327 ]
328 left_joins, order_by = ast2sort._CustomFieldSortClauses(
329 fd_list, tracker_pb2.FieldTypes.USER_TYPE, 'user_id', 'Sort0', 'DESC',
330 phase_name='Stable')
331
332 self.assertEqual(
333 left_joins, [
334 ('Issue2FieldValue AS Sort0_user_id '
335 'ON Issue.id = Sort0_user_id.issue_id '
336 'AND Sort0_user_id.field_id IN (%s)', [3]),
337 ('IssuePhaseDef AS Sort0_user_id_phase '
338 'ON Sort0_user_id.phase_id = Sort0_user_id_phase.id '
339 'AND LOWER(Sort0_user_id_phase.name) = LOWER(%s)', ['Stable']),
340 ('User AS Sort0_user_id_user '
341 'ON Sort0_user_id.user_id = Sort0_user_id_user.user_id', []),
342 ])
343 self.assertEqual(
344 order_by, [
345 ('ISNULL(Sort0_user_id_user.email) DESC', []),
346 ('Sort0_user_id_user.email DESC', []),
347 ])
348
349 def testOneSortDirective_NativeSortable(self):
350 left_joins, order_by = ast2sort._OneSortDirective(
351 1, 'opened', self.harmonized_labels, self.harmonized_statuses,
352 self.harmonized_fields)
353 self.assertEqual([], left_joins)
354 self.assertEqual([('Issue.opened ASC', [])], order_by)
355
356 left_joins, order_by = ast2sort._OneSortDirective(
357 1, 'stars', self.harmonized_labels, self.harmonized_statuses,
358 self.harmonized_fields)
359 self.assertEqual([], left_joins)
360 self.assertEqual([('Issue.star_count ASC', [])], order_by)
361
362 left_joins, order_by = ast2sort._OneSortDirective(
363 1, '-stars', self.harmonized_labels, self.harmonized_statuses,
364 self.harmonized_fields)
365 self.assertEqual([], left_joins)
366 self.assertEqual([('Issue.star_count DESC', [])], order_by)
367
368 left_joins, order_by = ast2sort._OneSortDirective(
369 1, 'componentmodified', self.harmonized_labels,
370 self.harmonized_statuses, self.harmonized_fields)
371 self.assertEqual([], left_joins)
372 self.assertEqual([('Issue.component_modified ASC', [])], order_by)