##// END OF EJS Templates
move filter order tests from helper to model....
Toshi MARUYAMA -
r11618:f2a609c3589c
parent child
Show More
@@ -1,69 +1,38
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2013 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.expand_path('../../../test_helper', __FILE__)
19 19
20 20 class QueriesHelperTest < ActionView::TestCase
21 21 include QueriesHelper
22 include Redmine::I18n
23 22
24 23 fixtures :projects, :enabled_modules, :users, :members,
25 24 :member_roles, :roles, :trackers, :issue_statuses,
26 25 :issue_categories, :enumerations, :issues,
27 26 :watchers, :custom_fields, :custom_values, :versions,
28 27 :queries,
29 28 :projects_trackers,
30 29 :custom_fields_trackers
31 30
32 def test_filters_options_should_be_ordered
33 set_language_if_valid 'en'
31 def test_filters_options_has_empty_item
34 32 query = IssueQuery.new
35 33 filter_count = query.available_filters.size
36 34 fo = filters_options(query)
37 35 assert_equal filter_count + 1, fo.size
38 36 assert_equal [], fo[0]
39
40 expected_order = [
41 "Status",
42 "Project",
43 "Tracker",
44 "Priority"
45 ]
46 assert_equal expected_order, (fo.map(&:first) & expected_order)
47 end
48
49 def test_filters_options_should_be_ordered_with_custom_fields
50 set_language_if_valid 'en'
51 UserCustomField.create!(
52 :name => 'order test', :field_format => 'string',
53 :is_for_all => true, :is_filter => true
54 )
55 query = IssueQuery.new
56 filter_count = query.available_filters.size
57 fo = filters_options(query)
58 assert_equal filter_count + 1, fo.size
59
60 expected_order = [
61 "Searchable field",
62 "Database",
63 "Project's Development status",
64 "Author's order test",
65 "Assignee's order test"
66 ]
67 assert_equal expected_order, (fo.map(&:first) & expected_order)
68 37 end
69 38 end
@@ -1,1234 +1,1261
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2013 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.expand_path('../../test_helper', __FILE__)
19 19
20 20 class QueryTest < ActiveSupport::TestCase
21 21 include Redmine::I18n
22 22
23 23 fixtures :projects, :enabled_modules, :users, :members,
24 24 :member_roles, :roles, :trackers, :issue_statuses,
25 25 :issue_categories, :enumerations, :issues,
26 26 :watchers, :custom_fields, :custom_values, :versions,
27 27 :queries,
28 28 :projects_trackers,
29 29 :custom_fields_trackers
30 30
31 31 def test_available_filters_should_be_ordered
32 set_language_if_valid 'en'
32 33 query = IssueQuery.new
33 34 assert_equal 0, query.available_filters.keys.index('status_id')
35 expected_order = [
36 "Status",
37 "Project",
38 "Tracker",
39 "Priority"
40 ]
41 assert_equal expected_order,
42 (query.available_filters.values.map{|v| v[:name]} & expected_order)
43 end
44
45 def test_available_filters_with_custom_fields_should_be_ordered
46 set_language_if_valid 'en'
47 UserCustomField.create!(
48 :name => 'order test', :field_format => 'string',
49 :is_for_all => true, :is_filter => true
50 )
51 query = IssueQuery.new
52 expected_order = [
53 "Searchable field",
54 "Database",
55 "Project's Development status",
56 "Author's order test",
57 "Assignee's order test"
58 ]
59 assert_equal expected_order,
60 (query.available_filters.values.map{|v| v[:name]} & expected_order)
34 61 end
35 62
36 63 def test_custom_fields_for_all_projects_should_be_available_in_global_queries
37 64 query = IssueQuery.new(:project => nil, :name => '_')
38 65 assert query.available_filters.has_key?('cf_1')
39 66 assert !query.available_filters.has_key?('cf_3')
40 67 end
41 68
42 69 def test_system_shared_versions_should_be_available_in_global_queries
43 70 Version.find(2).update_attribute :sharing, 'system'
44 71 query = IssueQuery.new(:project => nil, :name => '_')
45 72 assert query.available_filters.has_key?('fixed_version_id')
46 73 assert query.available_filters['fixed_version_id'][:values].detect {|v| v.last == '2'}
47 74 end
48 75
49 76 def test_project_filter_in_global_queries
50 77 query = IssueQuery.new(:project => nil, :name => '_')
51 78 project_filter = query.available_filters["project_id"]
52 79 assert_not_nil project_filter
53 80 project_ids = project_filter[:values].map{|p| p[1]}
54 81 assert project_ids.include?("1") #public project
55 82 assert !project_ids.include?("2") #private project user cannot see
56 83 end
57 84
58 85 def find_issues_with_query(query)
59 86 Issue.includes([:assigned_to, :status, :tracker, :project, :priority]).where(
60 87 query.statement
61 88 ).all
62 89 end
63 90
64 91 def assert_find_issues_with_query_is_successful(query)
65 92 assert_nothing_raised do
66 93 find_issues_with_query(query)
67 94 end
68 95 end
69 96
70 97 def assert_query_statement_includes(query, condition)
71 98 assert_include condition, query.statement
72 99 end
73 100
74 101 def assert_query_result(expected, query)
75 102 assert_nothing_raised do
76 103 assert_equal expected.map(&:id).sort, query.issues.map(&:id).sort
77 104 assert_equal expected.size, query.issue_count
78 105 end
79 106 end
80 107
81 108 def test_query_should_allow_shared_versions_for_a_project_query
82 109 subproject_version = Version.find(4)
83 110 query = IssueQuery.new(:project => Project.find(1), :name => '_')
84 111 query.add_filter('fixed_version_id', '=', [subproject_version.id.to_s])
85 112
86 113 assert query.statement.include?("#{Issue.table_name}.fixed_version_id IN ('4')")
87 114 end
88 115
89 116 def test_query_with_multiple_custom_fields
90 117 query = IssueQuery.find(1)
91 118 assert query.valid?
92 119 assert query.statement.include?("#{CustomValue.table_name}.value IN ('MySQL')")
93 120 issues = find_issues_with_query(query)
94 121 assert_equal 1, issues.length
95 122 assert_equal Issue.find(3), issues.first
96 123 end
97 124
98 125 def test_operator_none
99 126 query = IssueQuery.new(:project => Project.find(1), :name => '_')
100 127 query.add_filter('fixed_version_id', '!*', [''])
101 128 query.add_filter('cf_1', '!*', [''])
102 129 assert query.statement.include?("#{Issue.table_name}.fixed_version_id IS NULL")
103 130 assert query.statement.include?("#{CustomValue.table_name}.value IS NULL OR #{CustomValue.table_name}.value = ''")
104 131 find_issues_with_query(query)
105 132 end
106 133
107 134 def test_operator_none_for_integer
108 135 query = IssueQuery.new(:project => Project.find(1), :name => '_')
109 136 query.add_filter('estimated_hours', '!*', [''])
110 137 issues = find_issues_with_query(query)
111 138 assert !issues.empty?
112 139 assert issues.all? {|i| !i.estimated_hours}
113 140 end
114 141
115 142 def test_operator_none_for_date
116 143 query = IssueQuery.new(:project => Project.find(1), :name => '_')
117 144 query.add_filter('start_date', '!*', [''])
118 145 issues = find_issues_with_query(query)
119 146 assert !issues.empty?
120 147 assert issues.all? {|i| i.start_date.nil?}
121 148 end
122 149
123 150 def test_operator_none_for_string_custom_field
124 151 query = IssueQuery.new(:project => Project.find(1), :name => '_')
125 152 query.add_filter('cf_2', '!*', [''])
126 153 assert query.has_filter?('cf_2')
127 154 issues = find_issues_with_query(query)
128 155 assert !issues.empty?
129 156 assert issues.all? {|i| i.custom_field_value(2).blank?}
130 157 end
131 158
132 159 def test_operator_all
133 160 query = IssueQuery.new(:project => Project.find(1), :name => '_')
134 161 query.add_filter('fixed_version_id', '*', [''])
135 162 query.add_filter('cf_1', '*', [''])
136 163 assert query.statement.include?("#{Issue.table_name}.fixed_version_id IS NOT NULL")
137 164 assert query.statement.include?("#{CustomValue.table_name}.value IS NOT NULL AND #{CustomValue.table_name}.value <> ''")
138 165 find_issues_with_query(query)
139 166 end
140 167
141 168 def test_operator_all_for_date
142 169 query = IssueQuery.new(:project => Project.find(1), :name => '_')
143 170 query.add_filter('start_date', '*', [''])
144 171 issues = find_issues_with_query(query)
145 172 assert !issues.empty?
146 173 assert issues.all? {|i| i.start_date.present?}
147 174 end
148 175
149 176 def test_operator_all_for_string_custom_field
150 177 query = IssueQuery.new(:project => Project.find(1), :name => '_')
151 178 query.add_filter('cf_2', '*', [''])
152 179 assert query.has_filter?('cf_2')
153 180 issues = find_issues_with_query(query)
154 181 assert !issues.empty?
155 182 assert issues.all? {|i| i.custom_field_value(2).present?}
156 183 end
157 184
158 185 def test_numeric_filter_should_not_accept_non_numeric_values
159 186 query = IssueQuery.new(:name => '_')
160 187 query.add_filter('estimated_hours', '=', ['a'])
161 188
162 189 assert query.has_filter?('estimated_hours')
163 190 assert !query.valid?
164 191 end
165 192
166 193 def test_operator_is_on_float
167 194 Issue.update_all("estimated_hours = 171.2", "id=2")
168 195
169 196 query = IssueQuery.new(:name => '_')
170 197 query.add_filter('estimated_hours', '=', ['171.20'])
171 198 issues = find_issues_with_query(query)
172 199 assert_equal 1, issues.size
173 200 assert_equal 2, issues.first.id
174 201 end
175 202
176 203 def test_operator_is_on_integer_custom_field
177 204 f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_for_all => true, :is_filter => true)
178 205 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => '7')
179 206 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '12')
180 207 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
181 208
182 209 query = IssueQuery.new(:name => '_')
183 210 query.add_filter("cf_#{f.id}", '=', ['12'])
184 211 issues = find_issues_with_query(query)
185 212 assert_equal 1, issues.size
186 213 assert_equal 2, issues.first.id
187 214 end
188 215
189 216 def test_operator_is_on_integer_custom_field_should_accept_negative_value
190 217 f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_for_all => true, :is_filter => true)
191 218 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => '7')
192 219 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '-12')
193 220 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
194 221
195 222 query = IssueQuery.new(:name => '_')
196 223 query.add_filter("cf_#{f.id}", '=', ['-12'])
197 224 assert query.valid?
198 225 issues = find_issues_with_query(query)
199 226 assert_equal 1, issues.size
200 227 assert_equal 2, issues.first.id
201 228 end
202 229
203 230 def test_operator_is_on_float_custom_field
204 231 f = IssueCustomField.create!(:name => 'filter', :field_format => 'float', :is_filter => true, :is_for_all => true)
205 232 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => '7.3')
206 233 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '12.7')
207 234 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
208 235
209 236 query = IssueQuery.new(:name => '_')
210 237 query.add_filter("cf_#{f.id}", '=', ['12.7'])
211 238 issues = find_issues_with_query(query)
212 239 assert_equal 1, issues.size
213 240 assert_equal 2, issues.first.id
214 241 end
215 242
216 243 def test_operator_is_on_float_custom_field_should_accept_negative_value
217 244 f = IssueCustomField.create!(:name => 'filter', :field_format => 'float', :is_filter => true, :is_for_all => true)
218 245 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => '7.3')
219 246 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '-12.7')
220 247 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
221 248
222 249 query = IssueQuery.new(:name => '_')
223 250 query.add_filter("cf_#{f.id}", '=', ['-12.7'])
224 251 assert query.valid?
225 252 issues = find_issues_with_query(query)
226 253 assert_equal 1, issues.size
227 254 assert_equal 2, issues.first.id
228 255 end
229 256
230 257 def test_operator_is_on_multi_list_custom_field
231 258 f = IssueCustomField.create!(:name => 'filter', :field_format => 'list', :is_filter => true, :is_for_all => true,
232 259 :possible_values => ['value1', 'value2', 'value3'], :multiple => true)
233 260 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => 'value1')
234 261 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => 'value2')
235 262 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => 'value1')
236 263
237 264 query = IssueQuery.new(:name => '_')
238 265 query.add_filter("cf_#{f.id}", '=', ['value1'])
239 266 issues = find_issues_with_query(query)
240 267 assert_equal [1, 3], issues.map(&:id).sort
241 268
242 269 query = IssueQuery.new(:name => '_')
243 270 query.add_filter("cf_#{f.id}", '=', ['value2'])
244 271 issues = find_issues_with_query(query)
245 272 assert_equal [1], issues.map(&:id).sort
246 273 end
247 274
248 275 def test_operator_is_not_on_multi_list_custom_field
249 276 f = IssueCustomField.create!(:name => 'filter', :field_format => 'list', :is_filter => true, :is_for_all => true,
250 277 :possible_values => ['value1', 'value2', 'value3'], :multiple => true)
251 278 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => 'value1')
252 279 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => 'value2')
253 280 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => 'value1')
254 281
255 282 query = IssueQuery.new(:name => '_')
256 283 query.add_filter("cf_#{f.id}", '!', ['value1'])
257 284 issues = find_issues_with_query(query)
258 285 assert !issues.map(&:id).include?(1)
259 286 assert !issues.map(&:id).include?(3)
260 287
261 288 query = IssueQuery.new(:name => '_')
262 289 query.add_filter("cf_#{f.id}", '!', ['value2'])
263 290 issues = find_issues_with_query(query)
264 291 assert !issues.map(&:id).include?(1)
265 292 assert issues.map(&:id).include?(3)
266 293 end
267 294
268 295 def test_operator_is_on_is_private_field
269 296 # is_private filter only available for those who can set issues private
270 297 User.current = User.find(2)
271 298
272 299 query = IssueQuery.new(:name => '_')
273 300 assert query.available_filters.key?('is_private')
274 301
275 302 query.add_filter("is_private", '=', ['1'])
276 303 issues = find_issues_with_query(query)
277 304 assert issues.any?
278 305 assert_nil issues.detect {|issue| !issue.is_private?}
279 306 ensure
280 307 User.current = nil
281 308 end
282 309
283 310 def test_operator_is_not_on_is_private_field
284 311 # is_private filter only available for those who can set issues private
285 312 User.current = User.find(2)
286 313
287 314 query = IssueQuery.new(:name => '_')
288 315 assert query.available_filters.key?('is_private')
289 316
290 317 query.add_filter("is_private", '!', ['1'])
291 318 issues = find_issues_with_query(query)
292 319 assert issues.any?
293 320 assert_nil issues.detect {|issue| issue.is_private?}
294 321 ensure
295 322 User.current = nil
296 323 end
297 324
298 325 def test_operator_greater_than
299 326 query = IssueQuery.new(:project => Project.find(1), :name => '_')
300 327 query.add_filter('done_ratio', '>=', ['40'])
301 328 assert query.statement.include?("#{Issue.table_name}.done_ratio >= 40.0")
302 329 find_issues_with_query(query)
303 330 end
304 331
305 332 def test_operator_greater_than_a_float
306 333 query = IssueQuery.new(:project => Project.find(1), :name => '_')
307 334 query.add_filter('estimated_hours', '>=', ['40.5'])
308 335 assert query.statement.include?("#{Issue.table_name}.estimated_hours >= 40.5")
309 336 find_issues_with_query(query)
310 337 end
311 338
312 339 def test_operator_greater_than_on_int_custom_field
313 340 f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_filter => true, :is_for_all => true)
314 341 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => '7')
315 342 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '12')
316 343 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
317 344
318 345 query = IssueQuery.new(:project => Project.find(1), :name => '_')
319 346 query.add_filter("cf_#{f.id}", '>=', ['8'])
320 347 issues = find_issues_with_query(query)
321 348 assert_equal 1, issues.size
322 349 assert_equal 2, issues.first.id
323 350 end
324 351
325 352 def test_operator_lesser_than
326 353 query = IssueQuery.new(:project => Project.find(1), :name => '_')
327 354 query.add_filter('done_ratio', '<=', ['30'])
328 355 assert query.statement.include?("#{Issue.table_name}.done_ratio <= 30.0")
329 356 find_issues_with_query(query)
330 357 end
331 358
332 359 def test_operator_lesser_than_on_custom_field
333 360 f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_filter => true, :is_for_all => true)
334 361 query = IssueQuery.new(:project => Project.find(1), :name => '_')
335 362 query.add_filter("cf_#{f.id}", '<=', ['30'])
336 363 assert_match /CAST.+ <= 30\.0/, query.statement
337 364 find_issues_with_query(query)
338 365 end
339 366
340 367 def test_operator_between
341 368 query = IssueQuery.new(:project => Project.find(1), :name => '_')
342 369 query.add_filter('done_ratio', '><', ['30', '40'])
343 370 assert_include "#{Issue.table_name}.done_ratio BETWEEN 30.0 AND 40.0", query.statement
344 371 find_issues_with_query(query)
345 372 end
346 373
347 374 def test_operator_between_on_custom_field
348 375 f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_filter => true, :is_for_all => true)
349 376 query = IssueQuery.new(:project => Project.find(1), :name => '_')
350 377 query.add_filter("cf_#{f.id}", '><', ['30', '40'])
351 378 assert_match /CAST.+ BETWEEN 30.0 AND 40.0/, query.statement
352 379 find_issues_with_query(query)
353 380 end
354 381
355 382 def test_date_filter_should_not_accept_non_date_values
356 383 query = IssueQuery.new(:name => '_')
357 384 query.add_filter('created_on', '=', ['a'])
358 385
359 386 assert query.has_filter?('created_on')
360 387 assert !query.valid?
361 388 end
362 389
363 390 def test_date_filter_should_not_accept_invalid_date_values
364 391 query = IssueQuery.new(:name => '_')
365 392 query.add_filter('created_on', '=', ['2011-01-34'])
366 393
367 394 assert query.has_filter?('created_on')
368 395 assert !query.valid?
369 396 end
370 397
371 398 def test_relative_date_filter_should_not_accept_non_integer_values
372 399 query = IssueQuery.new(:name => '_')
373 400 query.add_filter('created_on', '>t-', ['a'])
374 401
375 402 assert query.has_filter?('created_on')
376 403 assert !query.valid?
377 404 end
378 405
379 406 def test_operator_date_equals
380 407 query = IssueQuery.new(:name => '_')
381 408 query.add_filter('due_date', '=', ['2011-07-10'])
382 409 assert_match /issues\.due_date > '2011-07-09 23:59:59(\.9+)?' AND issues\.due_date <= '2011-07-10 23:59:59(\.9+)?/, query.statement
383 410 find_issues_with_query(query)
384 411 end
385 412
386 413 def test_operator_date_lesser_than
387 414 query = IssueQuery.new(:name => '_')
388 415 query.add_filter('due_date', '<=', ['2011-07-10'])
389 416 assert_match /issues\.due_date <= '2011-07-10 23:59:59(\.9+)?/, query.statement
390 417 find_issues_with_query(query)
391 418 end
392 419
393 420 def test_operator_date_greater_than
394 421 query = IssueQuery.new(:name => '_')
395 422 query.add_filter('due_date', '>=', ['2011-07-10'])
396 423 assert_match /issues\.due_date > '2011-07-09 23:59:59(\.9+)?'/, query.statement
397 424 find_issues_with_query(query)
398 425 end
399 426
400 427 def test_operator_date_between
401 428 query = IssueQuery.new(:name => '_')
402 429 query.add_filter('due_date', '><', ['2011-06-23', '2011-07-10'])
403 430 assert_match /issues\.due_date > '2011-06-22 23:59:59(\.9+)?' AND issues\.due_date <= '2011-07-10 23:59:59(\.9+)?/, query.statement
404 431 find_issues_with_query(query)
405 432 end
406 433
407 434 def test_operator_in_more_than
408 435 Issue.find(7).update_attribute(:due_date, (Date.today + 15))
409 436 query = IssueQuery.new(:project => Project.find(1), :name => '_')
410 437 query.add_filter('due_date', '>t+', ['15'])
411 438 issues = find_issues_with_query(query)
412 439 assert !issues.empty?
413 440 issues.each {|issue| assert(issue.due_date >= (Date.today + 15))}
414 441 end
415 442
416 443 def test_operator_in_less_than
417 444 query = IssueQuery.new(:project => Project.find(1), :name => '_')
418 445 query.add_filter('due_date', '<t+', ['15'])
419 446 issues = find_issues_with_query(query)
420 447 assert !issues.empty?
421 448 issues.each {|issue| assert(issue.due_date <= (Date.today + 15))}
422 449 end
423 450
424 451 def test_operator_in_the_next_days
425 452 query = IssueQuery.new(:project => Project.find(1), :name => '_')
426 453 query.add_filter('due_date', '><t+', ['15'])
427 454 issues = find_issues_with_query(query)
428 455 assert !issues.empty?
429 456 issues.each {|issue| assert(issue.due_date >= Date.today && issue.due_date <= (Date.today + 15))}
430 457 end
431 458
432 459 def test_operator_less_than_ago
433 460 Issue.find(7).update_attribute(:due_date, (Date.today - 3))
434 461 query = IssueQuery.new(:project => Project.find(1), :name => '_')
435 462 query.add_filter('due_date', '>t-', ['3'])
436 463 issues = find_issues_with_query(query)
437 464 assert !issues.empty?
438 465 issues.each {|issue| assert(issue.due_date >= (Date.today - 3))}
439 466 end
440 467
441 468 def test_operator_in_the_past_days
442 469 Issue.find(7).update_attribute(:due_date, (Date.today - 3))
443 470 query = IssueQuery.new(:project => Project.find(1), :name => '_')
444 471 query.add_filter('due_date', '><t-', ['3'])
445 472 issues = find_issues_with_query(query)
446 473 assert !issues.empty?
447 474 issues.each {|issue| assert(issue.due_date >= (Date.today - 3) && issue.due_date <= Date.today)}
448 475 end
449 476
450 477 def test_operator_more_than_ago
451 478 Issue.find(7).update_attribute(:due_date, (Date.today - 10))
452 479 query = IssueQuery.new(:project => Project.find(1), :name => '_')
453 480 query.add_filter('due_date', '<t-', ['10'])
454 481 assert query.statement.include?("#{Issue.table_name}.due_date <=")
455 482 issues = find_issues_with_query(query)
456 483 assert !issues.empty?
457 484 issues.each {|issue| assert(issue.due_date <= (Date.today - 10))}
458 485 end
459 486
460 487 def test_operator_in
461 488 Issue.find(7).update_attribute(:due_date, (Date.today + 2))
462 489 query = IssueQuery.new(:project => Project.find(1), :name => '_')
463 490 query.add_filter('due_date', 't+', ['2'])
464 491 issues = find_issues_with_query(query)
465 492 assert !issues.empty?
466 493 issues.each {|issue| assert_equal((Date.today + 2), issue.due_date)}
467 494 end
468 495
469 496 def test_operator_ago
470 497 Issue.find(7).update_attribute(:due_date, (Date.today - 3))
471 498 query = IssueQuery.new(:project => Project.find(1), :name => '_')
472 499 query.add_filter('due_date', 't-', ['3'])
473 500 issues = find_issues_with_query(query)
474 501 assert !issues.empty?
475 502 issues.each {|issue| assert_equal((Date.today - 3), issue.due_date)}
476 503 end
477 504
478 505 def test_operator_today
479 506 query = IssueQuery.new(:project => Project.find(1), :name => '_')
480 507 query.add_filter('due_date', 't', [''])
481 508 issues = find_issues_with_query(query)
482 509 assert !issues.empty?
483 510 issues.each {|issue| assert_equal Date.today, issue.due_date}
484 511 end
485 512
486 513 def test_operator_this_week_on_date
487 514 query = IssueQuery.new(:project => Project.find(1), :name => '_')
488 515 query.add_filter('due_date', 'w', [''])
489 516 find_issues_with_query(query)
490 517 end
491 518
492 519 def test_operator_this_week_on_datetime
493 520 query = IssueQuery.new(:project => Project.find(1), :name => '_')
494 521 query.add_filter('created_on', 'w', [''])
495 522 find_issues_with_query(query)
496 523 end
497 524
498 525 def test_operator_contains
499 526 query = IssueQuery.new(:project => Project.find(1), :name => '_')
500 527 query.add_filter('subject', '~', ['uNable'])
501 528 assert query.statement.include?("LOWER(#{Issue.table_name}.subject) LIKE '%unable%'")
502 529 result = find_issues_with_query(query)
503 530 assert result.empty?
504 531 result.each {|issue| assert issue.subject.downcase.include?('unable') }
505 532 end
506 533
507 534 def test_range_for_this_week_with_week_starting_on_monday
508 535 I18n.locale = :fr
509 536 assert_equal '1', I18n.t(:general_first_day_of_week)
510 537
511 538 Date.stubs(:today).returns(Date.parse('2011-04-29'))
512 539
513 540 query = IssueQuery.new(:project => Project.find(1), :name => '_')
514 541 query.add_filter('due_date', 'w', [''])
515 542 assert query.statement.match(/issues\.due_date > '2011-04-24 23:59:59(\.9+)?' AND issues\.due_date <= '2011-05-01 23:59:59(\.9+)?/), "range not found in #{query.statement}"
516 543 I18n.locale = :en
517 544 end
518 545
519 546 def test_range_for_this_week_with_week_starting_on_sunday
520 547 I18n.locale = :en
521 548 assert_equal '7', I18n.t(:general_first_day_of_week)
522 549
523 550 Date.stubs(:today).returns(Date.parse('2011-04-29'))
524 551
525 552 query = IssueQuery.new(:project => Project.find(1), :name => '_')
526 553 query.add_filter('due_date', 'w', [''])
527 554 assert query.statement.match(/issues\.due_date > '2011-04-23 23:59:59(\.9+)?' AND issues\.due_date <= '2011-04-30 23:59:59(\.9+)?/), "range not found in #{query.statement}"
528 555 end
529 556
530 557 def test_operator_does_not_contains
531 558 query = IssueQuery.new(:project => Project.find(1), :name => '_')
532 559 query.add_filter('subject', '!~', ['uNable'])
533 560 assert query.statement.include?("LOWER(#{Issue.table_name}.subject) NOT LIKE '%unable%'")
534 561 find_issues_with_query(query)
535 562 end
536 563
537 564 def test_filter_assigned_to_me
538 565 user = User.find(2)
539 566 group = Group.find(10)
540 567 User.current = user
541 568 i1 = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to => user)
542 569 i2 = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to => group)
543 570 i3 = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to => Group.find(11))
544 571 group.users << user
545 572
546 573 query = IssueQuery.new(:name => '_', :filters => { 'assigned_to_id' => {:operator => '=', :values => ['me']}})
547 574 result = query.issues
548 575 assert_equal Issue.visible.all(:conditions => {:assigned_to_id => ([2] + user.reload.group_ids)}).sort_by(&:id), result.sort_by(&:id)
549 576
550 577 assert result.include?(i1)
551 578 assert result.include?(i2)
552 579 assert !result.include?(i3)
553 580 end
554 581
555 582 def test_user_custom_field_filtered_on_me
556 583 User.current = User.find(2)
557 584 cf = IssueCustomField.create!(:field_format => 'user', :is_for_all => true, :is_filter => true, :name => 'User custom field', :tracker_ids => [1])
558 585 issue1 = Issue.create!(:project_id => 1, :tracker_id => 1, :custom_field_values => {cf.id.to_s => '2'}, :subject => 'Test', :author_id => 1)
559 586 issue2 = Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {cf.id.to_s => '3'})
560 587
561 588 query = IssueQuery.new(:name => '_', :project => Project.find(1))
562 589 filter = query.available_filters["cf_#{cf.id}"]
563 590 assert_not_nil filter
564 591 assert_include 'me', filter[:values].map{|v| v[1]}
565 592
566 593 query.filters = { "cf_#{cf.id}" => {:operator => '=', :values => ['me']}}
567 594 result = query.issues
568 595 assert_equal 1, result.size
569 596 assert_equal issue1, result.first
570 597 end
571 598
572 599 def test_filter_my_projects
573 600 User.current = User.find(2)
574 601 query = IssueQuery.new(:name => '_')
575 602 filter = query.available_filters['project_id']
576 603 assert_not_nil filter
577 604 assert_include 'mine', filter[:values].map{|v| v[1]}
578 605
579 606 query.filters = { 'project_id' => {:operator => '=', :values => ['mine']}}
580 607 result = query.issues
581 608 assert_nil result.detect {|issue| !User.current.member_of?(issue.project)}
582 609 end
583 610
584 611 def test_filter_watched_issues
585 612 User.current = User.find(1)
586 613 query = IssueQuery.new(:name => '_', :filters => { 'watcher_id' => {:operator => '=', :values => ['me']}})
587 614 result = find_issues_with_query(query)
588 615 assert_not_nil result
589 616 assert !result.empty?
590 617 assert_equal Issue.visible.watched_by(User.current).sort_by(&:id), result.sort_by(&:id)
591 618 User.current = nil
592 619 end
593 620
594 621 def test_filter_unwatched_issues
595 622 User.current = User.find(1)
596 623 query = IssueQuery.new(:name => '_', :filters => { 'watcher_id' => {:operator => '!', :values => ['me']}})
597 624 result = find_issues_with_query(query)
598 625 assert_not_nil result
599 626 assert !result.empty?
600 627 assert_equal((Issue.visible - Issue.watched_by(User.current)).sort_by(&:id).size, result.sort_by(&:id).size)
601 628 User.current = nil
602 629 end
603 630
604 631 def test_filter_on_project_custom_field
605 632 field = ProjectCustomField.create!(:name => 'Client', :is_filter => true, :field_format => 'string')
606 633 CustomValue.create!(:custom_field => field, :customized => Project.find(3), :value => 'Foo')
607 634 CustomValue.create!(:custom_field => field, :customized => Project.find(5), :value => 'Foo')
608 635
609 636 query = IssueQuery.new(:name => '_')
610 637 filter_name = "project.cf_#{field.id}"
611 638 assert_include filter_name, query.available_filters.keys
612 639 query.filters = {filter_name => {:operator => '=', :values => ['Foo']}}
613 640 assert_equal [3, 5], find_issues_with_query(query).map(&:project_id).uniq.sort
614 641 end
615 642
616 643 def test_filter_on_author_custom_field
617 644 field = UserCustomField.create!(:name => 'Client', :is_filter => true, :field_format => 'string')
618 645 CustomValue.create!(:custom_field => field, :customized => User.find(3), :value => 'Foo')
619 646
620 647 query = IssueQuery.new(:name => '_')
621 648 filter_name = "author.cf_#{field.id}"
622 649 assert_include filter_name, query.available_filters.keys
623 650 query.filters = {filter_name => {:operator => '=', :values => ['Foo']}}
624 651 assert_equal [3], find_issues_with_query(query).map(&:author_id).uniq.sort
625 652 end
626 653
627 654 def test_filter_on_assigned_to_custom_field
628 655 field = UserCustomField.create!(:name => 'Client', :is_filter => true, :field_format => 'string')
629 656 CustomValue.create!(:custom_field => field, :customized => User.find(3), :value => 'Foo')
630 657
631 658 query = IssueQuery.new(:name => '_')
632 659 filter_name = "assigned_to.cf_#{field.id}"
633 660 assert_include filter_name, query.available_filters.keys
634 661 query.filters = {filter_name => {:operator => '=', :values => ['Foo']}}
635 662 assert_equal [3], find_issues_with_query(query).map(&:assigned_to_id).uniq.sort
636 663 end
637 664
638 665 def test_filter_on_fixed_version_custom_field
639 666 field = VersionCustomField.create!(:name => 'Client', :is_filter => true, :field_format => 'string')
640 667 CustomValue.create!(:custom_field => field, :customized => Version.find(2), :value => 'Foo')
641 668
642 669 query = IssueQuery.new(:name => '_')
643 670 filter_name = "fixed_version.cf_#{field.id}"
644 671 assert_include filter_name, query.available_filters.keys
645 672 query.filters = {filter_name => {:operator => '=', :values => ['Foo']}}
646 673 assert_equal [2], find_issues_with_query(query).map(&:fixed_version_id).uniq.sort
647 674 end
648 675
649 676 def test_filter_on_relations_with_a_specific_issue
650 677 IssueRelation.delete_all
651 678 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Issue.find(2))
652 679 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(3), :issue_to => Issue.find(1))
653 680
654 681 query = IssueQuery.new(:name => '_')
655 682 query.filters = {"relates" => {:operator => '=', :values => ['1']}}
656 683 assert_equal [2, 3], find_issues_with_query(query).map(&:id).sort
657 684
658 685 query = IssueQuery.new(:name => '_')
659 686 query.filters = {"relates" => {:operator => '=', :values => ['2']}}
660 687 assert_equal [1], find_issues_with_query(query).map(&:id).sort
661 688 end
662 689
663 690 def test_filter_on_relations_with_any_issues_in_a_project
664 691 IssueRelation.delete_all
665 692 with_settings :cross_project_issue_relations => '1' do
666 693 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Project.find(2).issues.first)
667 694 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(2), :issue_to => Project.find(2).issues.first)
668 695 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Project.find(3).issues.first)
669 696 end
670 697
671 698 query = IssueQuery.new(:name => '_')
672 699 query.filters = {"relates" => {:operator => '=p', :values => ['2']}}
673 700 assert_equal [1, 2], find_issues_with_query(query).map(&:id).sort
674 701
675 702 query = IssueQuery.new(:name => '_')
676 703 query.filters = {"relates" => {:operator => '=p', :values => ['3']}}
677 704 assert_equal [1], find_issues_with_query(query).map(&:id).sort
678 705
679 706 query = IssueQuery.new(:name => '_')
680 707 query.filters = {"relates" => {:operator => '=p', :values => ['4']}}
681 708 assert_equal [], find_issues_with_query(query).map(&:id).sort
682 709 end
683 710
684 711 def test_filter_on_relations_with_any_issues_not_in_a_project
685 712 IssueRelation.delete_all
686 713 with_settings :cross_project_issue_relations => '1' do
687 714 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Project.find(2).issues.first)
688 715 #IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(2), :issue_to => Project.find(1).issues.first)
689 716 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Project.find(3).issues.first)
690 717 end
691 718
692 719 query = IssueQuery.new(:name => '_')
693 720 query.filters = {"relates" => {:operator => '=!p', :values => ['1']}}
694 721 assert_equal [1], find_issues_with_query(query).map(&:id).sort
695 722 end
696 723
697 724 def test_filter_on_relations_with_no_issues_in_a_project
698 725 IssueRelation.delete_all
699 726 with_settings :cross_project_issue_relations => '1' do
700 727 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Project.find(2).issues.first)
701 728 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(2), :issue_to => Project.find(3).issues.first)
702 729 IssueRelation.create!(:relation_type => "relates", :issue_to => Project.find(2).issues.first, :issue_from => Issue.find(3))
703 730 end
704 731
705 732 query = IssueQuery.new(:name => '_')
706 733 query.filters = {"relates" => {:operator => '!p', :values => ['2']}}
707 734 ids = find_issues_with_query(query).map(&:id).sort
708 735 assert_include 2, ids
709 736 assert_not_include 1, ids
710 737 assert_not_include 3, ids
711 738 end
712 739
713 740 def test_filter_on_relations_with_no_issues
714 741 IssueRelation.delete_all
715 742 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Issue.find(2))
716 743 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(3), :issue_to => Issue.find(1))
717 744
718 745 query = IssueQuery.new(:name => '_')
719 746 query.filters = {"relates" => {:operator => '!*', :values => ['']}}
720 747 ids = find_issues_with_query(query).map(&:id)
721 748 assert_equal [], ids & [1, 2, 3]
722 749 assert_include 4, ids
723 750 end
724 751
725 752 def test_filter_on_relations_with_any_issues
726 753 IssueRelation.delete_all
727 754 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Issue.find(2))
728 755 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(3), :issue_to => Issue.find(1))
729 756
730 757 query = IssueQuery.new(:name => '_')
731 758 query.filters = {"relates" => {:operator => '*', :values => ['']}}
732 759 assert_equal [1, 2, 3], find_issues_with_query(query).map(&:id).sort
733 760 end
734 761
735 762 def test_statement_should_be_nil_with_no_filters
736 763 q = IssueQuery.new(:name => '_')
737 764 q.filters = {}
738 765
739 766 assert q.valid?
740 767 assert_nil q.statement
741 768 end
742 769
743 770 def test_default_columns
744 771 q = IssueQuery.new
745 772 assert q.columns.any?
746 773 assert q.inline_columns.any?
747 774 assert q.block_columns.empty?
748 775 end
749 776
750 777 def test_set_column_names
751 778 q = IssueQuery.new
752 779 q.column_names = ['tracker', :subject, '', 'unknonw_column']
753 780 assert_equal [:id, :tracker, :subject], q.columns.collect {|c| c.name}
754 781 end
755 782
756 783 def test_has_column_should_accept_a_column_name
757 784 q = IssueQuery.new
758 785 q.column_names = ['tracker', :subject]
759 786 assert q.has_column?(:tracker)
760 787 assert !q.has_column?(:category)
761 788 end
762 789
763 790 def test_has_column_should_accept_a_column
764 791 q = IssueQuery.new
765 792 q.column_names = ['tracker', :subject]
766 793
767 794 tracker_column = q.available_columns.detect {|c| c.name==:tracker}
768 795 assert_kind_of QueryColumn, tracker_column
769 796 category_column = q.available_columns.detect {|c| c.name==:category}
770 797 assert_kind_of QueryColumn, category_column
771 798
772 799 assert q.has_column?(tracker_column)
773 800 assert !q.has_column?(category_column)
774 801 end
775 802
776 803 def test_inline_and_block_columns
777 804 q = IssueQuery.new
778 805 q.column_names = ['subject', 'description', 'tracker']
779 806
780 807 assert_equal [:id, :subject, :tracker], q.inline_columns.map(&:name)
781 808 assert_equal [:description], q.block_columns.map(&:name)
782 809 end
783 810
784 811 def test_custom_field_columns_should_be_inline
785 812 q = IssueQuery.new
786 813 columns = q.available_columns.select {|column| column.is_a? QueryCustomFieldColumn}
787 814 assert columns.any?
788 815 assert_nil columns.detect {|column| !column.inline?}
789 816 end
790 817
791 818 def test_query_should_preload_spent_hours
792 819 q = IssueQuery.new(:name => '_', :column_names => [:subject, :spent_hours])
793 820 assert q.has_column?(:spent_hours)
794 821 issues = q.issues
795 822 assert_not_nil issues.first.instance_variable_get("@spent_hours")
796 823 end
797 824
798 825 def test_groupable_columns_should_include_custom_fields
799 826 q = IssueQuery.new
800 827 column = q.groupable_columns.detect {|c| c.name == :cf_1}
801 828 assert_not_nil column
802 829 assert_kind_of QueryCustomFieldColumn, column
803 830 end
804 831
805 832 def test_groupable_columns_should_not_include_multi_custom_fields
806 833 field = CustomField.find(1)
807 834 field.update_attribute :multiple, true
808 835
809 836 q = IssueQuery.new
810 837 column = q.groupable_columns.detect {|c| c.name == :cf_1}
811 838 assert_nil column
812 839 end
813 840
814 841 def test_groupable_columns_should_include_user_custom_fields
815 842 cf = IssueCustomField.create!(:name => 'User', :is_for_all => true, :tracker_ids => [1], :field_format => 'user')
816 843
817 844 q = IssueQuery.new
818 845 assert q.groupable_columns.detect {|c| c.name == "cf_#{cf.id}".to_sym}
819 846 end
820 847
821 848 def test_groupable_columns_should_include_version_custom_fields
822 849 cf = IssueCustomField.create!(:name => 'User', :is_for_all => true, :tracker_ids => [1], :field_format => 'version')
823 850
824 851 q = IssueQuery.new
825 852 assert q.groupable_columns.detect {|c| c.name == "cf_#{cf.id}".to_sym}
826 853 end
827 854
828 855 def test_grouped_with_valid_column
829 856 q = IssueQuery.new(:group_by => 'status')
830 857 assert q.grouped?
831 858 assert_not_nil q.group_by_column
832 859 assert_equal :status, q.group_by_column.name
833 860 assert_not_nil q.group_by_statement
834 861 assert_equal 'status', q.group_by_statement
835 862 end
836 863
837 864 def test_grouped_with_invalid_column
838 865 q = IssueQuery.new(:group_by => 'foo')
839 866 assert !q.grouped?
840 867 assert_nil q.group_by_column
841 868 assert_nil q.group_by_statement
842 869 end
843 870
844 871 def test_sortable_columns_should_sort_assignees_according_to_user_format_setting
845 872 with_settings :user_format => 'lastname_coma_firstname' do
846 873 q = IssueQuery.new
847 874 assert q.sortable_columns.has_key?('assigned_to')
848 875 assert_equal %w(users.lastname users.firstname users.id), q.sortable_columns['assigned_to']
849 876 end
850 877 end
851 878
852 879 def test_sortable_columns_should_sort_authors_according_to_user_format_setting
853 880 with_settings :user_format => 'lastname_coma_firstname' do
854 881 q = IssueQuery.new
855 882 assert q.sortable_columns.has_key?('author')
856 883 assert_equal %w(authors.lastname authors.firstname authors.id), q.sortable_columns['author']
857 884 end
858 885 end
859 886
860 887 def test_sortable_columns_should_include_custom_field
861 888 q = IssueQuery.new
862 889 assert q.sortable_columns['cf_1']
863 890 end
864 891
865 892 def test_sortable_columns_should_not_include_multi_custom_field
866 893 field = CustomField.find(1)
867 894 field.update_attribute :multiple, true
868 895
869 896 q = IssueQuery.new
870 897 assert !q.sortable_columns['cf_1']
871 898 end
872 899
873 900 def test_default_sort
874 901 q = IssueQuery.new
875 902 assert_equal [], q.sort_criteria
876 903 end
877 904
878 905 def test_set_sort_criteria_with_hash
879 906 q = IssueQuery.new
880 907 q.sort_criteria = {'0' => ['priority', 'desc'], '2' => ['tracker']}
881 908 assert_equal [['priority', 'desc'], ['tracker', 'asc']], q.sort_criteria
882 909 end
883 910
884 911 def test_set_sort_criteria_with_array
885 912 q = IssueQuery.new
886 913 q.sort_criteria = [['priority', 'desc'], 'tracker']
887 914 assert_equal [['priority', 'desc'], ['tracker', 'asc']], q.sort_criteria
888 915 end
889 916
890 917 def test_create_query_with_sort
891 918 q = IssueQuery.new(:name => 'Sorted')
892 919 q.sort_criteria = [['priority', 'desc'], 'tracker']
893 920 assert q.save
894 921 q.reload
895 922 assert_equal [['priority', 'desc'], ['tracker', 'asc']], q.sort_criteria
896 923 end
897 924
898 925 def test_sort_by_string_custom_field_asc
899 926 q = IssueQuery.new
900 927 c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'string' }
901 928 assert c
902 929 assert c.sortable
903 930 issues = q.issues(:order => "#{c.sortable} ASC")
904 931 values = issues.collect {|i| i.custom_value_for(c.custom_field).to_s}
905 932 assert !values.empty?
906 933 assert_equal values.sort, values
907 934 end
908 935
909 936 def test_sort_by_string_custom_field_desc
910 937 q = IssueQuery.new
911 938 c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'string' }
912 939 assert c
913 940 assert c.sortable
914 941 issues = q.issues(:order => "#{c.sortable} DESC")
915 942 values = issues.collect {|i| i.custom_value_for(c.custom_field).to_s}
916 943 assert !values.empty?
917 944 assert_equal values.sort.reverse, values
918 945 end
919 946
920 947 def test_sort_by_float_custom_field_asc
921 948 q = IssueQuery.new
922 949 c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'float' }
923 950 assert c
924 951 assert c.sortable
925 952 issues = q.issues(:order => "#{c.sortable} ASC")
926 953 values = issues.collect {|i| begin; Kernel.Float(i.custom_value_for(c.custom_field).to_s); rescue; nil; end}.compact
927 954 assert !values.empty?
928 955 assert_equal values.sort, values
929 956 end
930 957
931 958 def test_invalid_query_should_raise_query_statement_invalid_error
932 959 q = IssueQuery.new
933 960 assert_raise Query::StatementInvalid do
934 961 q.issues(:conditions => "foo = 1")
935 962 end
936 963 end
937 964
938 965 def test_issue_count
939 966 q = IssueQuery.new(:name => '_')
940 967 issue_count = q.issue_count
941 968 assert_equal q.issues.size, issue_count
942 969 end
943 970
944 971 def test_issue_count_with_archived_issues
945 972 p = Project.generate! do |project|
946 973 project.status = Project::STATUS_ARCHIVED
947 974 end
948 975 i = Issue.generate!( :project => p, :tracker => p.trackers.first )
949 976 assert !i.visible?
950 977
951 978 test_issue_count
952 979 end
953 980
954 981 def test_issue_count_by_association_group
955 982 q = IssueQuery.new(:name => '_', :group_by => 'assigned_to')
956 983 count_by_group = q.issue_count_by_group
957 984 assert_kind_of Hash, count_by_group
958 985 assert_equal %w(NilClass User), count_by_group.keys.collect {|k| k.class.name}.uniq.sort
959 986 assert_equal %w(Fixnum), count_by_group.values.collect {|k| k.class.name}.uniq
960 987 assert count_by_group.has_key?(User.find(3))
961 988 end
962 989
963 990 def test_issue_count_by_list_custom_field_group
964 991 q = IssueQuery.new(:name => '_', :group_by => 'cf_1')
965 992 count_by_group = q.issue_count_by_group
966 993 assert_kind_of Hash, count_by_group
967 994 assert_equal %w(NilClass String), count_by_group.keys.collect {|k| k.class.name}.uniq.sort
968 995 assert_equal %w(Fixnum), count_by_group.values.collect {|k| k.class.name}.uniq
969 996 assert count_by_group.has_key?('MySQL')
970 997 end
971 998
972 999 def test_issue_count_by_date_custom_field_group
973 1000 q = IssueQuery.new(:name => '_', :group_by => 'cf_8')
974 1001 count_by_group = q.issue_count_by_group
975 1002 assert_kind_of Hash, count_by_group
976 1003 assert_equal %w(Date NilClass), count_by_group.keys.collect {|k| k.class.name}.uniq.sort
977 1004 assert_equal %w(Fixnum), count_by_group.values.collect {|k| k.class.name}.uniq
978 1005 end
979 1006
980 1007 def test_issue_count_with_nil_group_only
981 1008 Issue.update_all("assigned_to_id = NULL")
982 1009
983 1010 q = IssueQuery.new(:name => '_', :group_by => 'assigned_to')
984 1011 count_by_group = q.issue_count_by_group
985 1012 assert_kind_of Hash, count_by_group
986 1013 assert_equal 1, count_by_group.keys.size
987 1014 assert_nil count_by_group.keys.first
988 1015 end
989 1016
990 1017 def test_issue_ids
991 1018 q = IssueQuery.new(:name => '_')
992 1019 order = "issues.subject, issues.id"
993 1020 issues = q.issues(:order => order)
994 1021 assert_equal issues.map(&:id), q.issue_ids(:order => order)
995 1022 end
996 1023
997 1024 def test_label_for
998 1025 set_language_if_valid 'en'
999 1026 q = IssueQuery.new
1000 1027 assert_equal 'Assignee', q.label_for('assigned_to_id')
1001 1028 end
1002 1029
1003 1030 def test_label_for_fr
1004 1031 set_language_if_valid 'fr'
1005 1032 q = IssueQuery.new
1006 1033 s = "Assign\xc3\xa9 \xc3\xa0"
1007 1034 s.force_encoding('UTF-8') if s.respond_to?(:force_encoding)
1008 1035 assert_equal s, q.label_for('assigned_to_id')
1009 1036 end
1010 1037
1011 1038 def test_editable_by
1012 1039 admin = User.find(1)
1013 1040 manager = User.find(2)
1014 1041 developer = User.find(3)
1015 1042
1016 1043 # Public query on project 1
1017 1044 q = IssueQuery.find(1)
1018 1045 assert q.editable_by?(admin)
1019 1046 assert q.editable_by?(manager)
1020 1047 assert !q.editable_by?(developer)
1021 1048
1022 1049 # Private query on project 1
1023 1050 q = IssueQuery.find(2)
1024 1051 assert q.editable_by?(admin)
1025 1052 assert !q.editable_by?(manager)
1026 1053 assert q.editable_by?(developer)
1027 1054
1028 1055 # Private query for all projects
1029 1056 q = IssueQuery.find(3)
1030 1057 assert q.editable_by?(admin)
1031 1058 assert !q.editable_by?(manager)
1032 1059 assert q.editable_by?(developer)
1033 1060
1034 1061 # Public query for all projects
1035 1062 q = IssueQuery.find(4)
1036 1063 assert q.editable_by?(admin)
1037 1064 assert !q.editable_by?(manager)
1038 1065 assert !q.editable_by?(developer)
1039 1066 end
1040 1067
1041 1068 def test_visible_scope
1042 1069 query_ids = IssueQuery.visible(User.anonymous).map(&:id)
1043 1070
1044 1071 assert query_ids.include?(1), 'public query on public project was not visible'
1045 1072 assert query_ids.include?(4), 'public query for all projects was not visible'
1046 1073 assert !query_ids.include?(2), 'private query on public project was visible'
1047 1074 assert !query_ids.include?(3), 'private query for all projects was visible'
1048 1075 assert !query_ids.include?(7), 'public query on private project was visible'
1049 1076 end
1050 1077
1051 1078 test "#available_filters should include users of visible projects in cross-project view" do
1052 1079 users = IssueQuery.new.available_filters["assigned_to_id"]
1053 1080 assert_not_nil users
1054 1081 assert users[:values].map{|u|u[1]}.include?("3")
1055 1082 end
1056 1083
1057 1084 test "#available_filters should include users of subprojects" do
1058 1085 user1 = User.generate!
1059 1086 user2 = User.generate!
1060 1087 project = Project.find(1)
1061 1088 Member.create!(:principal => user1, :project => project.children.visible.first, :role_ids => [1])
1062 1089
1063 1090 users = IssueQuery.new(:project => project).available_filters["assigned_to_id"]
1064 1091 assert_not_nil users
1065 1092 assert users[:values].map{|u|u[1]}.include?(user1.id.to_s)
1066 1093 assert !users[:values].map{|u|u[1]}.include?(user2.id.to_s)
1067 1094 end
1068 1095
1069 1096 test "#available_filters should include visible projects in cross-project view" do
1070 1097 projects = IssueQuery.new.available_filters["project_id"]
1071 1098 assert_not_nil projects
1072 1099 assert projects[:values].map{|u|u[1]}.include?("1")
1073 1100 end
1074 1101
1075 1102 test "#available_filters should include 'member_of_group' filter" do
1076 1103 query = IssueQuery.new
1077 1104 assert query.available_filters.keys.include?("member_of_group")
1078 1105 assert_equal :list_optional, query.available_filters["member_of_group"][:type]
1079 1106 assert query.available_filters["member_of_group"][:values].present?
1080 1107 assert_equal Group.all.sort.map {|g| [g.name, g.id.to_s]},
1081 1108 query.available_filters["member_of_group"][:values].sort
1082 1109 end
1083 1110
1084 1111 test "#available_filters should include 'assigned_to_role' filter" do
1085 1112 query = IssueQuery.new
1086 1113 assert query.available_filters.keys.include?("assigned_to_role")
1087 1114 assert_equal :list_optional, query.available_filters["assigned_to_role"][:type]
1088 1115
1089 1116 assert query.available_filters["assigned_to_role"][:values].include?(['Manager','1'])
1090 1117 assert query.available_filters["assigned_to_role"][:values].include?(['Developer','2'])
1091 1118 assert query.available_filters["assigned_to_role"][:values].include?(['Reporter','3'])
1092 1119
1093 1120 assert ! query.available_filters["assigned_to_role"][:values].include?(['Non member','4'])
1094 1121 assert ! query.available_filters["assigned_to_role"][:values].include?(['Anonymous','5'])
1095 1122 end
1096 1123
1097 1124 context "#statement" do
1098 1125 context "with 'member_of_group' filter" do
1099 1126 setup do
1100 1127 Group.destroy_all # No fixtures
1101 1128 @user_in_group = User.generate!
1102 1129 @second_user_in_group = User.generate!
1103 1130 @user_in_group2 = User.generate!
1104 1131 @user_not_in_group = User.generate!
1105 1132
1106 1133 @group = Group.generate!.reload
1107 1134 @group.users << @user_in_group
1108 1135 @group.users << @second_user_in_group
1109 1136
1110 1137 @group2 = Group.generate!.reload
1111 1138 @group2.users << @user_in_group2
1112 1139
1113 1140 end
1114 1141
1115 1142 should "search assigned to for users in the group" do
1116 1143 @query = IssueQuery.new(:name => '_')
1117 1144 @query.add_filter('member_of_group', '=', [@group.id.to_s])
1118 1145
1119 1146 assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IN ('#{@user_in_group.id}','#{@second_user_in_group.id}','#{@group.id}')"
1120 1147 assert_find_issues_with_query_is_successful @query
1121 1148 end
1122 1149
1123 1150 should "search not assigned to any group member (none)" do
1124 1151 @query = IssueQuery.new(:name => '_')
1125 1152 @query.add_filter('member_of_group', '!*', [''])
1126 1153
1127 1154 # Users not in a group
1128 1155 assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IS NULL OR #{Issue.table_name}.assigned_to_id NOT IN ('#{@user_in_group.id}','#{@second_user_in_group.id}','#{@user_in_group2.id}','#{@group.id}','#{@group2.id}')"
1129 1156 assert_find_issues_with_query_is_successful @query
1130 1157 end
1131 1158
1132 1159 should "search assigned to any group member (all)" do
1133 1160 @query = IssueQuery.new(:name => '_')
1134 1161 @query.add_filter('member_of_group', '*', [''])
1135 1162
1136 1163 # Only users in a group
1137 1164 assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IN ('#{@user_in_group.id}','#{@second_user_in_group.id}','#{@user_in_group2.id}','#{@group.id}','#{@group2.id}')"
1138 1165 assert_find_issues_with_query_is_successful @query
1139 1166 end
1140 1167
1141 1168 should "return an empty set with = empty group" do
1142 1169 @empty_group = Group.generate!
1143 1170 @query = IssueQuery.new(:name => '_')
1144 1171 @query.add_filter('member_of_group', '=', [@empty_group.id.to_s])
1145 1172
1146 1173 assert_equal [], find_issues_with_query(@query)
1147 1174 end
1148 1175
1149 1176 should "return issues with ! empty group" do
1150 1177 @empty_group = Group.generate!
1151 1178 @query = IssueQuery.new(:name => '_')
1152 1179 @query.add_filter('member_of_group', '!', [@empty_group.id.to_s])
1153 1180
1154 1181 assert_find_issues_with_query_is_successful @query
1155 1182 end
1156 1183 end
1157 1184
1158 1185 context "with 'assigned_to_role' filter" do
1159 1186 setup do
1160 1187 @manager_role = Role.find_by_name('Manager')
1161 1188 @developer_role = Role.find_by_name('Developer')
1162 1189
1163 1190 @project = Project.generate!
1164 1191 @manager = User.generate!
1165 1192 @developer = User.generate!
1166 1193 @boss = User.generate!
1167 1194 @guest = User.generate!
1168 1195 User.add_to_project(@manager, @project, @manager_role)
1169 1196 User.add_to_project(@developer, @project, @developer_role)
1170 1197 User.add_to_project(@boss, @project, [@manager_role, @developer_role])
1171 1198
1172 1199 @issue1 = Issue.generate!(:project => @project, :assigned_to_id => @manager.id)
1173 1200 @issue2 = Issue.generate!(:project => @project, :assigned_to_id => @developer.id)
1174 1201 @issue3 = Issue.generate!(:project => @project, :assigned_to_id => @boss.id)
1175 1202 @issue4 = Issue.generate!(:project => @project, :assigned_to_id => @guest.id)
1176 1203 @issue5 = Issue.generate!(:project => @project)
1177 1204 end
1178 1205
1179 1206 should "search assigned to for users with the Role" do
1180 1207 @query = IssueQuery.new(:name => '_', :project => @project)
1181 1208 @query.add_filter('assigned_to_role', '=', [@manager_role.id.to_s])
1182 1209
1183 1210 assert_query_result [@issue1, @issue3], @query
1184 1211 end
1185 1212
1186 1213 should "search assigned to for users with the Role on the issue project" do
1187 1214 other_project = Project.generate!
1188 1215 User.add_to_project(@developer, other_project, @manager_role)
1189 1216
1190 1217 @query = IssueQuery.new(:name => '_', :project => @project)
1191 1218 @query.add_filter('assigned_to_role', '=', [@manager_role.id.to_s])
1192 1219
1193 1220 assert_query_result [@issue1, @issue3], @query
1194 1221 end
1195 1222
1196 1223 should "return an empty set with empty role" do
1197 1224 @empty_role = Role.generate!
1198 1225 @query = IssueQuery.new(:name => '_', :project => @project)
1199 1226 @query.add_filter('assigned_to_role', '=', [@empty_role.id.to_s])
1200 1227
1201 1228 assert_query_result [], @query
1202 1229 end
1203 1230
1204 1231 should "search assigned to for users without the Role" do
1205 1232 @query = IssueQuery.new(:name => '_', :project => @project)
1206 1233 @query.add_filter('assigned_to_role', '!', [@manager_role.id.to_s])
1207 1234
1208 1235 assert_query_result [@issue2, @issue4, @issue5], @query
1209 1236 end
1210 1237
1211 1238 should "search assigned to for users not assigned to any Role (none)" do
1212 1239 @query = IssueQuery.new(:name => '_', :project => @project)
1213 1240 @query.add_filter('assigned_to_role', '!*', [''])
1214 1241
1215 1242 assert_query_result [@issue4, @issue5], @query
1216 1243 end
1217 1244
1218 1245 should "search assigned to for users assigned to any Role (all)" do
1219 1246 @query = IssueQuery.new(:name => '_', :project => @project)
1220 1247 @query.add_filter('assigned_to_role', '*', [''])
1221 1248
1222 1249 assert_query_result [@issue1, @issue2, @issue3], @query
1223 1250 end
1224 1251
1225 1252 should "return issues with ! empty role" do
1226 1253 @empty_role = Role.generate!
1227 1254 @query = IssueQuery.new(:name => '_', :project => @project)
1228 1255 @query.add_filter('assigned_to_role', '!', [@empty_role.id.to_s])
1229 1256
1230 1257 assert_query_result [@issue1, @issue2, @issue3, @issue4, @issue5], @query
1231 1258 end
1232 1259 end
1233 1260 end
1234 1261 end
General Comments 0
You need to be logged in to leave comments. Login now