##// END OF EJS Templates
Set source encoding (#22405)....
Jean-Philippe Lang -
r14970:72e735761127
parent child
Show More
@@ -1,1709 +1,1711
1 # encoding: utf-8
2 #
1 3 # Redmine - project management software
2 4 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 5 #
4 6 # This program is free software; you can redistribute it and/or
5 7 # modify it under the terms of the GNU General Public License
6 8 # as published by the Free Software Foundation; either version 2
7 9 # of the License, or (at your option) any later version.
8 10 #
9 11 # This program is distributed in the hope that it will be useful,
10 12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 14 # GNU General Public License for more details.
13 15 #
14 16 # You should have received a copy of the GNU General Public License
15 17 # along with this program; if not, write to the Free Software
16 18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 19
18 20 require File.expand_path('../../test_helper', __FILE__)
19 21
20 22 class QueryTest < ActiveSupport::TestCase
21 23 include Redmine::I18n
22 24
23 25 fixtures :projects, :enabled_modules, :users, :members,
24 26 :member_roles, :roles, :trackers, :issue_statuses,
25 27 :issue_categories, :enumerations, :issues,
26 28 :watchers, :custom_fields, :custom_values, :versions,
27 29 :queries,
28 30 :projects_trackers,
29 31 :custom_fields_trackers,
30 32 :workflows
31 33
32 34 def setup
33 35 User.current = nil
34 36 end
35 37
36 38 def test_query_with_roles_visibility_should_validate_roles
37 39 set_language_if_valid 'en'
38 40 query = IssueQuery.new(:name => 'Query', :visibility => IssueQuery::VISIBILITY_ROLES)
39 41 assert !query.save
40 42 assert_include "Roles cannot be blank", query.errors.full_messages
41 43 query.role_ids = [1, 2]
42 44 assert query.save
43 45 end
44 46
45 47 def test_changing_roles_visibility_should_clear_roles
46 48 query = IssueQuery.create!(:name => 'Query', :visibility => IssueQuery::VISIBILITY_ROLES, :role_ids => [1, 2])
47 49 assert_equal 2, query.roles.count
48 50
49 51 query.visibility = IssueQuery::VISIBILITY_PUBLIC
50 52 query.save!
51 53 assert_equal 0, query.roles.count
52 54 end
53 55
54 56 def test_available_filters_should_be_ordered
55 57 set_language_if_valid 'en'
56 58 query = IssueQuery.new
57 59 assert_equal 0, query.available_filters.keys.index('status_id')
58 60 expected_order = [
59 61 "Status",
60 62 "Project",
61 63 "Tracker",
62 64 "Priority"
63 65 ]
64 66 assert_equal expected_order,
65 67 (query.available_filters.values.map{|v| v[:name]} & expected_order)
66 68 end
67 69
68 70 def test_available_filters_with_custom_fields_should_be_ordered
69 71 set_language_if_valid 'en'
70 72 UserCustomField.create!(
71 73 :name => 'order test', :field_format => 'string',
72 74 :is_for_all => true, :is_filter => true
73 75 )
74 76 query = IssueQuery.new
75 77 expected_order = [
76 78 "Searchable field",
77 79 "Database",
78 80 "Project's Development status",
79 81 "Author's order test",
80 82 "Assignee's order test"
81 83 ]
82 84 assert_equal expected_order,
83 85 (query.available_filters.values.map{|v| v[:name]} & expected_order)
84 86 end
85 87
86 88 def test_custom_fields_for_all_projects_should_be_available_in_global_queries
87 89 query = IssueQuery.new(:project => nil, :name => '_')
88 90 assert query.available_filters.has_key?('cf_1')
89 91 assert !query.available_filters.has_key?('cf_3')
90 92 end
91 93
92 94 def test_system_shared_versions_should_be_available_in_global_queries
93 95 Version.find(2).update_attribute :sharing, 'system'
94 96 query = IssueQuery.new(:project => nil, :name => '_')
95 97 assert query.available_filters.has_key?('fixed_version_id')
96 98 assert query.available_filters['fixed_version_id'][:values].detect {|v| v.last == '2'}
97 99 end
98 100
99 101 def test_project_filter_in_global_queries
100 102 query = IssueQuery.new(:project => nil, :name => '_')
101 103 project_filter = query.available_filters["project_id"]
102 104 assert_not_nil project_filter
103 105 project_ids = project_filter[:values].map{|p| p[1]}
104 106 assert project_ids.include?("1") #public project
105 107 assert !project_ids.include?("2") #private project user cannot see
106 108 end
107 109
108 110 def test_available_filters_should_not_include_fields_disabled_on_all_trackers
109 111 Tracker.all.each do |tracker|
110 112 tracker.core_fields = Tracker::CORE_FIELDS - ['start_date']
111 113 tracker.save!
112 114 end
113 115
114 116 query = IssueQuery.new(:name => '_')
115 117 assert_include 'due_date', query.available_filters
116 118 assert_not_include 'start_date', query.available_filters
117 119 end
118 120
119 121 def find_issues_with_query(query)
120 122 Issue.joins(:status, :tracker, :project, :priority).where(
121 123 query.statement
122 124 ).to_a
123 125 end
124 126
125 127 def assert_find_issues_with_query_is_successful(query)
126 128 assert_nothing_raised do
127 129 find_issues_with_query(query)
128 130 end
129 131 end
130 132
131 133 def assert_query_statement_includes(query, condition)
132 134 assert_include condition, query.statement
133 135 end
134 136
135 137 def assert_query_result(expected, query)
136 138 assert_nothing_raised do
137 139 assert_equal expected.map(&:id).sort, query.issues.map(&:id).sort
138 140 assert_equal expected.size, query.issue_count
139 141 end
140 142 end
141 143
142 144 def test_query_should_allow_shared_versions_for_a_project_query
143 145 subproject_version = Version.find(4)
144 146 query = IssueQuery.new(:project => Project.find(1), :name => '_')
145 147 query.add_filter('fixed_version_id', '=', [subproject_version.id.to_s])
146 148
147 149 assert query.statement.include?("#{Issue.table_name}.fixed_version_id IN ('4')")
148 150 end
149 151
150 152 def test_query_with_multiple_custom_fields
151 153 query = IssueQuery.find(1)
152 154 assert query.valid?
153 155 assert query.statement.include?("#{CustomValue.table_name}.value IN ('MySQL')")
154 156 issues = find_issues_with_query(query)
155 157 assert_equal 1, issues.length
156 158 assert_equal Issue.find(3), issues.first
157 159 end
158 160
159 161 def test_operator_none
160 162 query = IssueQuery.new(:project => Project.find(1), :name => '_')
161 163 query.add_filter('fixed_version_id', '!*', [''])
162 164 query.add_filter('cf_1', '!*', [''])
163 165 assert query.statement.include?("#{Issue.table_name}.fixed_version_id IS NULL")
164 166 assert query.statement.include?("#{CustomValue.table_name}.value IS NULL OR #{CustomValue.table_name}.value = ''")
165 167 find_issues_with_query(query)
166 168 end
167 169
168 170 def test_operator_none_for_integer
169 171 query = IssueQuery.new(:project => Project.find(1), :name => '_')
170 172 query.add_filter('estimated_hours', '!*', [''])
171 173 issues = find_issues_with_query(query)
172 174 assert !issues.empty?
173 175 assert issues.all? {|i| !i.estimated_hours}
174 176 end
175 177
176 178 def test_operator_none_for_date
177 179 query = IssueQuery.new(:project => Project.find(1), :name => '_')
178 180 query.add_filter('start_date', '!*', [''])
179 181 issues = find_issues_with_query(query)
180 182 assert !issues.empty?
181 183 assert issues.all? {|i| i.start_date.nil?}
182 184 end
183 185
184 186 def test_operator_none_for_string_custom_field
185 187 CustomField.find(2).update_attribute :default_value, ""
186 188 query = IssueQuery.new(:project => Project.find(1), :name => '_')
187 189 query.add_filter('cf_2', '!*', [''])
188 190 assert query.has_filter?('cf_2')
189 191 issues = find_issues_with_query(query)
190 192 assert !issues.empty?
191 193 assert issues.all? {|i| i.custom_field_value(2).blank?}
192 194 end
193 195
194 196 def test_operator_all
195 197 query = IssueQuery.new(:project => Project.find(1), :name => '_')
196 198 query.add_filter('fixed_version_id', '*', [''])
197 199 query.add_filter('cf_1', '*', [''])
198 200 assert query.statement.include?("#{Issue.table_name}.fixed_version_id IS NOT NULL")
199 201 assert query.statement.include?("#{CustomValue.table_name}.value IS NOT NULL AND #{CustomValue.table_name}.value <> ''")
200 202 find_issues_with_query(query)
201 203 end
202 204
203 205 def test_operator_all_for_date
204 206 query = IssueQuery.new(:project => Project.find(1), :name => '_')
205 207 query.add_filter('start_date', '*', [''])
206 208 issues = find_issues_with_query(query)
207 209 assert !issues.empty?
208 210 assert issues.all? {|i| i.start_date.present?}
209 211 end
210 212
211 213 def test_operator_all_for_string_custom_field
212 214 query = IssueQuery.new(:project => Project.find(1), :name => '_')
213 215 query.add_filter('cf_2', '*', [''])
214 216 assert query.has_filter?('cf_2')
215 217 issues = find_issues_with_query(query)
216 218 assert !issues.empty?
217 219 assert issues.all? {|i| i.custom_field_value(2).present?}
218 220 end
219 221
220 222 def test_numeric_filter_should_not_accept_non_numeric_values
221 223 query = IssueQuery.new(:name => '_')
222 224 query.add_filter('estimated_hours', '=', ['a'])
223 225
224 226 assert query.has_filter?('estimated_hours')
225 227 assert !query.valid?
226 228 end
227 229
228 230 def test_operator_is_on_float
229 231 Issue.where(:id => 2).update_all("estimated_hours = 171.2")
230 232 query = IssueQuery.new(:name => '_')
231 233 query.add_filter('estimated_hours', '=', ['171.20'])
232 234 issues = find_issues_with_query(query)
233 235 assert_equal 1, issues.size
234 236 assert_equal 2, issues.first.id
235 237 end
236 238
237 239 def test_operator_is_on_integer_custom_field
238 240 f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_for_all => true, :is_filter => true, :trackers => Tracker.all)
239 241 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => '7')
240 242 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '12')
241 243 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
242 244
243 245 query = IssueQuery.new(:name => '_')
244 246 query.add_filter("cf_#{f.id}", '=', ['12'])
245 247 issues = find_issues_with_query(query)
246 248 assert_equal 1, issues.size
247 249 assert_equal 2, issues.first.id
248 250 end
249 251
250 252 def test_operator_is_on_integer_custom_field_should_accept_negative_value
251 253 f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_for_all => true, :is_filter => true, :trackers => Tracker.all)
252 254 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => '7')
253 255 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '-12')
254 256 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
255 257
256 258 query = IssueQuery.new(:name => '_')
257 259 query.add_filter("cf_#{f.id}", '=', ['-12'])
258 260 assert query.valid?
259 261 issues = find_issues_with_query(query)
260 262 assert_equal 1, issues.size
261 263 assert_equal 2, issues.first.id
262 264 end
263 265
264 266 def test_operator_is_on_float_custom_field
265 267 f = IssueCustomField.create!(:name => 'filter', :field_format => 'float', :is_filter => true, :is_for_all => true, :trackers => Tracker.all)
266 268 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => '7.3')
267 269 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '12.7')
268 270 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
269 271
270 272 query = IssueQuery.new(:name => '_')
271 273 query.add_filter("cf_#{f.id}", '=', ['12.7'])
272 274 issues = find_issues_with_query(query)
273 275 assert_equal 1, issues.size
274 276 assert_equal 2, issues.first.id
275 277 end
276 278
277 279 def test_operator_is_on_float_custom_field_should_accept_negative_value
278 280 f = IssueCustomField.create!(:name => 'filter', :field_format => 'float', :is_filter => true, :is_for_all => true, :trackers => Tracker.all)
279 281 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => '7.3')
280 282 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '-12.7')
281 283 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
282 284
283 285 query = IssueQuery.new(:name => '_')
284 286 query.add_filter("cf_#{f.id}", '=', ['-12.7'])
285 287 assert query.valid?
286 288 issues = find_issues_with_query(query)
287 289 assert_equal 1, issues.size
288 290 assert_equal 2, issues.first.id
289 291 end
290 292
291 293 def test_operator_is_on_multi_list_custom_field
292 294 f = IssueCustomField.create!(:name => 'filter', :field_format => 'list', :is_filter => true, :is_for_all => true,
293 295 :possible_values => ['value1', 'value2', 'value3'], :multiple => true, :trackers => Tracker.all)
294 296 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => 'value1')
295 297 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => 'value2')
296 298 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => 'value1')
297 299
298 300 query = IssueQuery.new(:name => '_')
299 301 query.add_filter("cf_#{f.id}", '=', ['value1'])
300 302 issues = find_issues_with_query(query)
301 303 assert_equal [1, 3], issues.map(&:id).sort
302 304
303 305 query = IssueQuery.new(:name => '_')
304 306 query.add_filter("cf_#{f.id}", '=', ['value2'])
305 307 issues = find_issues_with_query(query)
306 308 assert_equal [1], issues.map(&:id).sort
307 309 end
308 310
309 311 def test_operator_is_not_on_multi_list_custom_field
310 312 f = IssueCustomField.create!(:name => 'filter', :field_format => 'list', :is_filter => true, :is_for_all => true,
311 313 :possible_values => ['value1', 'value2', 'value3'], :multiple => true, :trackers => Tracker.all)
312 314 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => 'value1')
313 315 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => 'value2')
314 316 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => 'value1')
315 317
316 318 query = IssueQuery.new(:name => '_')
317 319 query.add_filter("cf_#{f.id}", '!', ['value1'])
318 320 issues = find_issues_with_query(query)
319 321 assert !issues.map(&:id).include?(1)
320 322 assert !issues.map(&:id).include?(3)
321 323
322 324 query = IssueQuery.new(:name => '_')
323 325 query.add_filter("cf_#{f.id}", '!', ['value2'])
324 326 issues = find_issues_with_query(query)
325 327 assert !issues.map(&:id).include?(1)
326 328 assert issues.map(&:id).include?(3)
327 329 end
328 330
329 331 def test_operator_is_on_is_private_field
330 332 # is_private filter only available for those who can set issues private
331 333 User.current = User.find(2)
332 334
333 335 query = IssueQuery.new(:name => '_')
334 336 assert query.available_filters.key?('is_private')
335 337
336 338 query.add_filter("is_private", '=', ['1'])
337 339 issues = find_issues_with_query(query)
338 340 assert issues.any?
339 341 assert_nil issues.detect {|issue| !issue.is_private?}
340 342 ensure
341 343 User.current = nil
342 344 end
343 345
344 346 def test_operator_is_not_on_is_private_field
345 347 # is_private filter only available for those who can set issues private
346 348 User.current = User.find(2)
347 349
348 350 query = IssueQuery.new(:name => '_')
349 351 assert query.available_filters.key?('is_private')
350 352
351 353 query.add_filter("is_private", '!', ['1'])
352 354 issues = find_issues_with_query(query)
353 355 assert issues.any?
354 356 assert_nil issues.detect {|issue| issue.is_private?}
355 357 ensure
356 358 User.current = nil
357 359 end
358 360
359 361 def test_operator_greater_than
360 362 query = IssueQuery.new(:project => Project.find(1), :name => '_')
361 363 query.add_filter('done_ratio', '>=', ['40'])
362 364 assert query.statement.include?("#{Issue.table_name}.done_ratio >= 40.0")
363 365 find_issues_with_query(query)
364 366 end
365 367
366 368 def test_operator_greater_than_a_float
367 369 query = IssueQuery.new(:project => Project.find(1), :name => '_')
368 370 query.add_filter('estimated_hours', '>=', ['40.5'])
369 371 assert query.statement.include?("#{Issue.table_name}.estimated_hours >= 40.5")
370 372 find_issues_with_query(query)
371 373 end
372 374
373 375 def test_operator_greater_than_on_int_custom_field
374 376 f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_filter => true, :is_for_all => true, :trackers => Tracker.all)
375 377 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => '7')
376 378 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '12')
377 379 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
378 380
379 381 query = IssueQuery.new(:project => Project.find(1), :name => '_')
380 382 query.add_filter("cf_#{f.id}", '>=', ['8'])
381 383 issues = find_issues_with_query(query)
382 384 assert_equal 1, issues.size
383 385 assert_equal 2, issues.first.id
384 386 end
385 387
386 388 def test_operator_lesser_than
387 389 query = IssueQuery.new(:project => Project.find(1), :name => '_')
388 390 query.add_filter('done_ratio', '<=', ['30'])
389 391 assert query.statement.include?("#{Issue.table_name}.done_ratio <= 30.0")
390 392 find_issues_with_query(query)
391 393 end
392 394
393 395 def test_operator_lesser_than_on_custom_field
394 396 f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_filter => true, :is_for_all => true)
395 397 query = IssueQuery.new(:project => Project.find(1), :name => '_')
396 398 query.add_filter("cf_#{f.id}", '<=', ['30'])
397 399 assert_match /CAST.+ <= 30\.0/, query.statement
398 400 find_issues_with_query(query)
399 401 end
400 402
401 403 def test_operator_lesser_than_on_date_custom_field
402 404 f = IssueCustomField.create!(:name => 'filter', :field_format => 'date', :is_filter => true, :is_for_all => true, :trackers => Tracker.all)
403 405 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => '2013-04-11')
404 406 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '2013-05-14')
405 407 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
406 408
407 409 query = IssueQuery.new(:project => Project.find(1), :name => '_')
408 410 query.add_filter("cf_#{f.id}", '<=', ['2013-05-01'])
409 411 issue_ids = find_issues_with_query(query).map(&:id)
410 412 assert_include 1, issue_ids
411 413 assert_not_include 2, issue_ids
412 414 assert_not_include 3, issue_ids
413 415 end
414 416
415 417 def test_operator_between
416 418 query = IssueQuery.new(:project => Project.find(1), :name => '_')
417 419 query.add_filter('done_ratio', '><', ['30', '40'])
418 420 assert_include "#{Issue.table_name}.done_ratio BETWEEN 30.0 AND 40.0", query.statement
419 421 find_issues_with_query(query)
420 422 end
421 423
422 424 def test_operator_between_on_custom_field
423 425 f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_filter => true, :is_for_all => true)
424 426 query = IssueQuery.new(:project => Project.find(1), :name => '_')
425 427 query.add_filter("cf_#{f.id}", '><', ['30', '40'])
426 428 assert_match /CAST.+ BETWEEN 30.0 AND 40.0/, query.statement
427 429 find_issues_with_query(query)
428 430 end
429 431
430 432 def test_date_filter_should_not_accept_non_date_values
431 433 query = IssueQuery.new(:name => '_')
432 434 query.add_filter('created_on', '=', ['a'])
433 435
434 436 assert query.has_filter?('created_on')
435 437 assert !query.valid?
436 438 end
437 439
438 440 def test_date_filter_should_not_accept_invalid_date_values
439 441 query = IssueQuery.new(:name => '_')
440 442 query.add_filter('created_on', '=', ['2011-01-34'])
441 443
442 444 assert query.has_filter?('created_on')
443 445 assert !query.valid?
444 446 end
445 447
446 448 def test_relative_date_filter_should_not_accept_non_integer_values
447 449 query = IssueQuery.new(:name => '_')
448 450 query.add_filter('created_on', '>t-', ['a'])
449 451
450 452 assert query.has_filter?('created_on')
451 453 assert !query.valid?
452 454 end
453 455
454 456 def test_operator_date_equals
455 457 query = IssueQuery.new(:name => '_')
456 458 query.add_filter('due_date', '=', ['2011-07-10'])
457 459 assert_match /issues\.due_date > '#{quoted_date "2011-07-09"} 23:59:59(\.\d+)?' AND issues\.due_date <= '#{quoted_date "2011-07-10"} 23:59:59(\.\d+)?/,
458 460 query.statement
459 461 find_issues_with_query(query)
460 462 end
461 463
462 464 def test_operator_date_lesser_than
463 465 query = IssueQuery.new(:name => '_')
464 466 query.add_filter('due_date', '<=', ['2011-07-10'])
465 467 assert_match /issues\.due_date <= '#{quoted_date "2011-07-10"} 23:59:59(\.\d+)?/, query.statement
466 468 find_issues_with_query(query)
467 469 end
468 470
469 471 def test_operator_date_lesser_than_with_timestamp
470 472 query = IssueQuery.new(:name => '_')
471 473 query.add_filter('updated_on', '<=', ['2011-07-10T19:13:52'])
472 474 assert_match /issues\.updated_on <= '#{quoted_date "2011-07-10"} 19:13:52/, query.statement
473 475 find_issues_with_query(query)
474 476 end
475 477
476 478 def test_operator_date_greater_than
477 479 query = IssueQuery.new(:name => '_')
478 480 query.add_filter('due_date', '>=', ['2011-07-10'])
479 481 assert_match /issues\.due_date > '#{quoted_date "2011-07-09"} 23:59:59(\.\d+)?'/, query.statement
480 482 find_issues_with_query(query)
481 483 end
482 484
483 485 def test_operator_date_greater_than_with_timestamp
484 486 query = IssueQuery.new(:name => '_')
485 487 query.add_filter('updated_on', '>=', ['2011-07-10T19:13:52'])
486 488 assert_match /issues\.updated_on > '#{quoted_date "2011-07-10"} 19:13:51(\.0+)?'/, query.statement
487 489 find_issues_with_query(query)
488 490 end
489 491
490 492 def test_operator_date_between
491 493 query = IssueQuery.new(:name => '_')
492 494 query.add_filter('due_date', '><', ['2011-06-23', '2011-07-10'])
493 495 assert_match /issues\.due_date > '#{quoted_date "2011-06-22"} 23:59:59(\.\d+)?' AND issues\.due_date <= '#{quoted_date "2011-07-10"} 23:59:59(\.\d+)?'/,
494 496 query.statement
495 497 find_issues_with_query(query)
496 498 end
497 499
498 500 def test_operator_in_more_than
499 501 Issue.find(7).update_attribute(:due_date, (Date.today + 15))
500 502 query = IssueQuery.new(:project => Project.find(1), :name => '_')
501 503 query.add_filter('due_date', '>t+', ['15'])
502 504 issues = find_issues_with_query(query)
503 505 assert !issues.empty?
504 506 issues.each {|issue| assert(issue.due_date >= (Date.today + 15))}
505 507 end
506 508
507 509 def test_operator_in_less_than
508 510 query = IssueQuery.new(:project => Project.find(1), :name => '_')
509 511 query.add_filter('due_date', '<t+', ['15'])
510 512 issues = find_issues_with_query(query)
511 513 assert !issues.empty?
512 514 issues.each {|issue| assert(issue.due_date <= (Date.today + 15))}
513 515 end
514 516
515 517 def test_operator_in_the_next_days
516 518 query = IssueQuery.new(:project => Project.find(1), :name => '_')
517 519 query.add_filter('due_date', '><t+', ['15'])
518 520 issues = find_issues_with_query(query)
519 521 assert !issues.empty?
520 522 issues.each {|issue| assert(issue.due_date >= Date.today && issue.due_date <= (Date.today + 15))}
521 523 end
522 524
523 525 def test_operator_less_than_ago
524 526 Issue.find(7).update_attribute(:due_date, (Date.today - 3))
525 527 query = IssueQuery.new(:project => Project.find(1), :name => '_')
526 528 query.add_filter('due_date', '>t-', ['3'])
527 529 issues = find_issues_with_query(query)
528 530 assert !issues.empty?
529 531 issues.each {|issue| assert(issue.due_date >= (Date.today - 3))}
530 532 end
531 533
532 534 def test_operator_in_the_past_days
533 535 Issue.find(7).update_attribute(:due_date, (Date.today - 3))
534 536 query = IssueQuery.new(:project => Project.find(1), :name => '_')
535 537 query.add_filter('due_date', '><t-', ['3'])
536 538 issues = find_issues_with_query(query)
537 539 assert !issues.empty?
538 540 issues.each {|issue| assert(issue.due_date >= (Date.today - 3) && issue.due_date <= Date.today)}
539 541 end
540 542
541 543 def test_operator_more_than_ago
542 544 Issue.find(7).update_attribute(:due_date, (Date.today - 10))
543 545 query = IssueQuery.new(:project => Project.find(1), :name => '_')
544 546 query.add_filter('due_date', '<t-', ['10'])
545 547 assert query.statement.include?("#{Issue.table_name}.due_date <=")
546 548 issues = find_issues_with_query(query)
547 549 assert !issues.empty?
548 550 issues.each {|issue| assert(issue.due_date <= (Date.today - 10))}
549 551 end
550 552
551 553 def test_operator_in
552 554 Issue.find(7).update_attribute(:due_date, (Date.today + 2))
553 555 query = IssueQuery.new(:project => Project.find(1), :name => '_')
554 556 query.add_filter('due_date', 't+', ['2'])
555 557 issues = find_issues_with_query(query)
556 558 assert !issues.empty?
557 559 issues.each {|issue| assert_equal((Date.today + 2), issue.due_date)}
558 560 end
559 561
560 562 def test_operator_ago
561 563 Issue.find(7).update_attribute(:due_date, (Date.today - 3))
562 564 query = IssueQuery.new(:project => Project.find(1), :name => '_')
563 565 query.add_filter('due_date', 't-', ['3'])
564 566 issues = find_issues_with_query(query)
565 567 assert !issues.empty?
566 568 issues.each {|issue| assert_equal((Date.today - 3), issue.due_date)}
567 569 end
568 570
569 571 def test_operator_today
570 572 query = IssueQuery.new(:project => Project.find(1), :name => '_')
571 573 query.add_filter('due_date', 't', [''])
572 574 issues = find_issues_with_query(query)
573 575 assert !issues.empty?
574 576 issues.each {|issue| assert_equal Date.today, issue.due_date}
575 577 end
576 578
577 579 def test_operator_date_periods
578 580 %w(t ld w lw l2w m lm y).each do |operator|
579 581 query = IssueQuery.new(:name => '_')
580 582 query.add_filter('due_date', operator, [''])
581 583 assert query.valid?
582 584 assert query.issues
583 585 end
584 586 end
585 587
586 588 def test_operator_datetime_periods
587 589 %w(t ld w lw l2w m lm y).each do |operator|
588 590 query = IssueQuery.new(:name => '_')
589 591 query.add_filter('created_on', operator, [''])
590 592 assert query.valid?
591 593 assert query.issues
592 594 end
593 595 end
594 596
595 597 def test_operator_contains
596 598 issue = Issue.generate!(:subject => 'AbCdEfG')
597 599
598 600 query = IssueQuery.new(:name => '_')
599 601 query.add_filter('subject', '~', ['cdeF'])
600 602 result = find_issues_with_query(query)
601 603 assert_include issue, result
602 604 result.each {|issue| assert issue.subject.downcase.include?('cdef') }
603 605 end
604 606
605 607 def test_operator_contains_with_utf8_string
606 608 issue = Issue.generate!(:subject => 'Subject contains Kiểm')
607 609
608 610 query = IssueQuery.new(:name => '_')
609 611 query.add_filter('subject', '~', ['Kiểm'])
610 612 result = find_issues_with_query(query)
611 613 assert_include issue, result
612 614 assert_equal 1, result.size
613 615 end
614 616
615 617 def test_operator_does_not_contain
616 618 issue = Issue.generate!(:subject => 'AbCdEfG')
617 619
618 620 query = IssueQuery.new(:name => '_')
619 621 query.add_filter('subject', '!~', ['cdeF'])
620 622 result = find_issues_with_query(query)
621 623 assert_not_include issue, result
622 624 end
623 625
624 626 def test_range_for_this_week_with_week_starting_on_monday
625 627 I18n.locale = :fr
626 628 assert_equal '1', I18n.t(:general_first_day_of_week)
627 629
628 630 Date.stubs(:today).returns(Date.parse('2011-04-29'))
629 631
630 632 query = IssueQuery.new(:project => Project.find(1), :name => '_')
631 633 query.add_filter('due_date', 'w', [''])
632 634 assert_match /issues\.due_date > '#{quoted_date "2011-04-24"} 23:59:59(\.\d+)?' AND issues\.due_date <= '#{quoted_date "2011-05-01"} 23:59:59(\.\d+)?/,
633 635 query.statement
634 636 I18n.locale = :en
635 637 end
636 638
637 639 def test_range_for_this_week_with_week_starting_on_sunday
638 640 I18n.locale = :en
639 641 assert_equal '7', I18n.t(:general_first_day_of_week)
640 642
641 643 Date.stubs(:today).returns(Date.parse('2011-04-29'))
642 644
643 645 query = IssueQuery.new(:project => Project.find(1), :name => '_')
644 646 query.add_filter('due_date', 'w', [''])
645 647 assert_match /issues\.due_date > '#{quoted_date "2011-04-23"} 23:59:59(\.\d+)?' AND issues\.due_date <= '#{quoted_date "2011-04-30"} 23:59:59(\.\d+)?/,
646 648 query.statement
647 649 end
648 650
649 651 def test_filter_assigned_to_me
650 652 user = User.find(2)
651 653 group = Group.find(10)
652 654 User.current = user
653 655 i1 = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to => user)
654 656 i2 = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to => group)
655 657 i3 = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to => Group.find(11))
656 658 group.users << user
657 659
658 660 query = IssueQuery.new(:name => '_', :filters => { 'assigned_to_id' => {:operator => '=', :values => ['me']}})
659 661 result = query.issues
660 662 assert_equal Issue.visible.where(:assigned_to_id => ([2] + user.reload.group_ids)).sort_by(&:id), result.sort_by(&:id)
661 663
662 664 assert result.include?(i1)
663 665 assert result.include?(i2)
664 666 assert !result.include?(i3)
665 667 end
666 668
667 669 def test_user_custom_field_filtered_on_me
668 670 User.current = User.find(2)
669 671 cf = IssueCustomField.create!(:field_format => 'user', :is_for_all => true, :is_filter => true, :name => 'User custom field', :tracker_ids => [1])
670 672 issue1 = Issue.create!(:project_id => 1, :tracker_id => 1, :custom_field_values => {cf.id.to_s => '2'}, :subject => 'Test', :author_id => 1)
671 673 issue2 = Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {cf.id.to_s => '3'})
672 674
673 675 query = IssueQuery.new(:name => '_', :project => Project.find(1))
674 676 filter = query.available_filters["cf_#{cf.id}"]
675 677 assert_not_nil filter
676 678 assert_include 'me', filter[:values].map{|v| v[1]}
677 679
678 680 query.filters = { "cf_#{cf.id}" => {:operator => '=', :values => ['me']}}
679 681 result = query.issues
680 682 assert_equal 1, result.size
681 683 assert_equal issue1, result.first
682 684 end
683 685
684 686 def test_filter_on_me_by_anonymous_user
685 687 User.current = nil
686 688 query = IssueQuery.new(:name => '_', :filters => { 'assigned_to_id' => {:operator => '=', :values => ['me']}})
687 689 assert_equal [], query.issues
688 690 end
689 691
690 692 def test_filter_my_projects
691 693 User.current = User.find(2)
692 694 query = IssueQuery.new(:name => '_')
693 695 filter = query.available_filters['project_id']
694 696 assert_not_nil filter
695 697 assert_include 'mine', filter[:values].map{|v| v[1]}
696 698
697 699 query.filters = { 'project_id' => {:operator => '=', :values => ['mine']}}
698 700 result = query.issues
699 701 assert_nil result.detect {|issue| !User.current.member_of?(issue.project)}
700 702 end
701 703
702 704 def test_filter_watched_issues
703 705 User.current = User.find(1)
704 706 query = IssueQuery.new(:name => '_', :filters => { 'watcher_id' => {:operator => '=', :values => ['me']}})
705 707 result = find_issues_with_query(query)
706 708 assert_not_nil result
707 709 assert !result.empty?
708 710 assert_equal Issue.visible.watched_by(User.current).sort_by(&:id), result.sort_by(&:id)
709 711 User.current = nil
710 712 end
711 713
712 714 def test_filter_unwatched_issues
713 715 User.current = User.find(1)
714 716 query = IssueQuery.new(:name => '_', :filters => { 'watcher_id' => {:operator => '!', :values => ['me']}})
715 717 result = find_issues_with_query(query)
716 718 assert_not_nil result
717 719 assert !result.empty?
718 720 assert_equal((Issue.visible - Issue.watched_by(User.current)).sort_by(&:id).size, result.sort_by(&:id).size)
719 721 User.current = nil
720 722 end
721 723
722 724 def test_filter_on_custom_field_should_ignore_projects_with_field_disabled
723 725 field = IssueCustomField.generate!(:trackers => Tracker.all, :project_ids => [1, 3, 4], :is_for_all => false, :is_filter => true)
724 726 Issue.generate!(:project_id => 3, :tracker_id => 2, :custom_field_values => {field.id.to_s => 'Foo'})
725 727 Issue.generate!(:project_id => 4, :tracker_id => 2, :custom_field_values => {field.id.to_s => 'Foo'})
726 728
727 729 query = IssueQuery.new(:name => '_', :project => Project.find(1))
728 730 query.filters = {"cf_#{field.id}" => {:operator => '=', :values => ['Foo']}}
729 731 assert_equal 2, find_issues_with_query(query).size
730 732
731 733 field.project_ids = [1, 3] # Disable the field for project 4
732 734 field.save!
733 735 assert_equal 1, find_issues_with_query(query).size
734 736 end
735 737
736 738 def test_filter_on_custom_field_should_ignore_trackers_with_field_disabled
737 739 field = IssueCustomField.generate!(:tracker_ids => [1, 2], :is_for_all => true, :is_filter => true)
738 740 Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {field.id.to_s => 'Foo'})
739 741 Issue.generate!(:project_id => 1, :tracker_id => 2, :custom_field_values => {field.id.to_s => 'Foo'})
740 742
741 743 query = IssueQuery.new(:name => '_', :project => Project.find(1))
742 744 query.filters = {"cf_#{field.id}" => {:operator => '=', :values => ['Foo']}}
743 745 assert_equal 2, find_issues_with_query(query).size
744 746
745 747 field.tracker_ids = [1] # Disable the field for tracker 2
746 748 field.save!
747 749 assert_equal 1, find_issues_with_query(query).size
748 750 end
749 751
750 752 def test_filter_on_project_custom_field
751 753 field = ProjectCustomField.create!(:name => 'Client', :is_filter => true, :field_format => 'string')
752 754 CustomValue.create!(:custom_field => field, :customized => Project.find(3), :value => 'Foo')
753 755 CustomValue.create!(:custom_field => field, :customized => Project.find(5), :value => 'Foo')
754 756
755 757 query = IssueQuery.new(:name => '_')
756 758 filter_name = "project.cf_#{field.id}"
757 759 assert_include filter_name, query.available_filters.keys
758 760 query.filters = {filter_name => {:operator => '=', :values => ['Foo']}}
759 761 assert_equal [3, 5], find_issues_with_query(query).map(&:project_id).uniq.sort
760 762 end
761 763
762 764 def test_filter_on_author_custom_field
763 765 field = UserCustomField.create!(:name => 'Client', :is_filter => true, :field_format => 'string')
764 766 CustomValue.create!(:custom_field => field, :customized => User.find(3), :value => 'Foo')
765 767
766 768 query = IssueQuery.new(:name => '_')
767 769 filter_name = "author.cf_#{field.id}"
768 770 assert_include filter_name, query.available_filters.keys
769 771 query.filters = {filter_name => {:operator => '=', :values => ['Foo']}}
770 772 assert_equal [3], find_issues_with_query(query).map(&:author_id).uniq.sort
771 773 end
772 774
773 775 def test_filter_on_assigned_to_custom_field
774 776 field = UserCustomField.create!(:name => 'Client', :is_filter => true, :field_format => 'string')
775 777 CustomValue.create!(:custom_field => field, :customized => User.find(3), :value => 'Foo')
776 778
777 779 query = IssueQuery.new(:name => '_')
778 780 filter_name = "assigned_to.cf_#{field.id}"
779 781 assert_include filter_name, query.available_filters.keys
780 782 query.filters = {filter_name => {:operator => '=', :values => ['Foo']}}
781 783 assert_equal [3], find_issues_with_query(query).map(&:assigned_to_id).uniq.sort
782 784 end
783 785
784 786 def test_filter_on_fixed_version_custom_field
785 787 field = VersionCustomField.create!(:name => 'Client', :is_filter => true, :field_format => 'string')
786 788 CustomValue.create!(:custom_field => field, :customized => Version.find(2), :value => 'Foo')
787 789
788 790 query = IssueQuery.new(:name => '_')
789 791 filter_name = "fixed_version.cf_#{field.id}"
790 792 assert_include filter_name, query.available_filters.keys
791 793 query.filters = {filter_name => {:operator => '=', :values => ['Foo']}}
792 794 assert_equal [2], find_issues_with_query(query).map(&:fixed_version_id).uniq.sort
793 795 end
794 796
795 797 def test_filter_on_relations_with_a_specific_issue
796 798 IssueRelation.delete_all
797 799 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Issue.find(2))
798 800 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(3), :issue_to => Issue.find(1))
799 801
800 802 query = IssueQuery.new(:name => '_')
801 803 query.filters = {"relates" => {:operator => '=', :values => ['1']}}
802 804 assert_equal [2, 3], find_issues_with_query(query).map(&:id).sort
803 805
804 806 query = IssueQuery.new(:name => '_')
805 807 query.filters = {"relates" => {:operator => '=', :values => ['2']}}
806 808 assert_equal [1], find_issues_with_query(query).map(&:id).sort
807 809 end
808 810
809 811 def test_filter_on_relations_with_any_issues_in_a_project
810 812 IssueRelation.delete_all
811 813 with_settings :cross_project_issue_relations => '1' do
812 814 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Project.find(2).issues.first)
813 815 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(2), :issue_to => Project.find(2).issues.first)
814 816 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Project.find(3).issues.first)
815 817 end
816 818
817 819 query = IssueQuery.new(:name => '_')
818 820 query.filters = {"relates" => {:operator => '=p', :values => ['2']}}
819 821 assert_equal [1, 2], find_issues_with_query(query).map(&:id).sort
820 822
821 823 query = IssueQuery.new(:name => '_')
822 824 query.filters = {"relates" => {:operator => '=p', :values => ['3']}}
823 825 assert_equal [1], find_issues_with_query(query).map(&:id).sort
824 826
825 827 query = IssueQuery.new(:name => '_')
826 828 query.filters = {"relates" => {:operator => '=p', :values => ['4']}}
827 829 assert_equal [], find_issues_with_query(query).map(&:id).sort
828 830 end
829 831
830 832 def test_filter_on_relations_with_any_issues_not_in_a_project
831 833 IssueRelation.delete_all
832 834 with_settings :cross_project_issue_relations => '1' do
833 835 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Project.find(2).issues.first)
834 836 #IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(2), :issue_to => Project.find(1).issues.first)
835 837 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Project.find(3).issues.first)
836 838 end
837 839
838 840 query = IssueQuery.new(:name => '_')
839 841 query.filters = {"relates" => {:operator => '=!p', :values => ['1']}}
840 842 assert_equal [1], find_issues_with_query(query).map(&:id).sort
841 843 end
842 844
843 845 def test_filter_on_relations_with_no_issues_in_a_project
844 846 IssueRelation.delete_all
845 847 with_settings :cross_project_issue_relations => '1' do
846 848 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Project.find(2).issues.first)
847 849 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(2), :issue_to => Project.find(3).issues.first)
848 850 IssueRelation.create!(:relation_type => "relates", :issue_to => Project.find(2).issues.first, :issue_from => Issue.find(3))
849 851 end
850 852
851 853 query = IssueQuery.new(:name => '_')
852 854 query.filters = {"relates" => {:operator => '!p', :values => ['2']}}
853 855 ids = find_issues_with_query(query).map(&:id).sort
854 856 assert_include 2, ids
855 857 assert_not_include 1, ids
856 858 assert_not_include 3, ids
857 859 end
858 860
859 861 def test_filter_on_relations_with_any_open_issues
860 862 IssueRelation.delete_all
861 863 # Issue 1 is blocked by 8, which is closed
862 864 IssueRelation.create!(:relation_type => "blocked", :issue_from => Issue.find(1), :issue_to => Issue.find(8))
863 865 # Issue 2 is blocked by 3, which is open
864 866 IssueRelation.create!(:relation_type => "blocked", :issue_from => Issue.find(2), :issue_to => Issue.find(3))
865 867
866 868 query = IssueQuery.new(:name => '_')
867 869 query.filters = {"blocked" => {:operator => "*o", :values => ['']}}
868 870 ids = find_issues_with_query(query).map(&:id)
869 871 assert_equal [], ids & [1]
870 872 assert_include 2, ids
871 873 end
872 874
873 875 def test_filter_on_relations_with_no_open_issues
874 876 IssueRelation.delete_all
875 877 # Issue 1 is blocked by 8, which is closed
876 878 IssueRelation.create!(:relation_type => "blocked", :issue_from => Issue.find(1), :issue_to => Issue.find(8))
877 879 # Issue 2 is blocked by 3, which is open
878 880 IssueRelation.create!(:relation_type => "blocked", :issue_from => Issue.find(2), :issue_to => Issue.find(3))
879 881
880 882 query = IssueQuery.new(:name => '_')
881 883 query.filters = {"blocked" => {:operator => "!o", :values => ['']}}
882 884 ids = find_issues_with_query(query).map(&:id)
883 885 assert_equal [], ids & [2]
884 886 assert_include 1, ids
885 887 end
886 888
887 889 def test_filter_on_relations_with_no_issues
888 890 IssueRelation.delete_all
889 891 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Issue.find(2))
890 892 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(3), :issue_to => Issue.find(1))
891 893
892 894 query = IssueQuery.new(:name => '_')
893 895 query.filters = {"relates" => {:operator => '!*', :values => ['']}}
894 896 ids = find_issues_with_query(query).map(&:id)
895 897 assert_equal [], ids & [1, 2, 3]
896 898 assert_include 4, ids
897 899 end
898 900
899 901 def test_filter_on_relations_with_any_issues
900 902 IssueRelation.delete_all
901 903 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Issue.find(2))
902 904 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(3), :issue_to => Issue.find(1))
903 905
904 906 query = IssueQuery.new(:name => '_')
905 907 query.filters = {"relates" => {:operator => '*', :values => ['']}}
906 908 assert_equal [1, 2, 3], find_issues_with_query(query).map(&:id).sort
907 909 end
908 910
909 911 def test_filter_on_relations_should_not_ignore_other_filter
910 912 issue = Issue.generate!
911 913 issue1 = Issue.generate!(:status_id => 1)
912 914 issue2 = Issue.generate!(:status_id => 2)
913 915 IssueRelation.create!(:relation_type => "relates", :issue_from => issue, :issue_to => issue1)
914 916 IssueRelation.create!(:relation_type => "relates", :issue_from => issue, :issue_to => issue2)
915 917
916 918 query = IssueQuery.new(:name => '_')
917 919 query.filters = {
918 920 "status_id" => {:operator => '=', :values => ['1']},
919 921 "relates" => {:operator => '=', :values => [issue.id.to_s]}
920 922 }
921 923 assert_equal [issue1], find_issues_with_query(query)
922 924 end
923 925
924 926 def test_filter_on_parent
925 927 Issue.delete_all
926 928 parent = Issue.generate_with_descendants!
927 929
928 930
929 931 query = IssueQuery.new(:name => '_')
930 932 query.filters = {"parent_id" => {:operator => '=', :values => [parent.id.to_s]}}
931 933 assert_equal parent.children.map(&:id).sort, find_issues_with_query(query).map(&:id).sort
932 934
933 935 query.filters = {"parent_id" => {:operator => '~', :values => [parent.id.to_s]}}
934 936 assert_equal parent.descendants.map(&:id).sort, find_issues_with_query(query).map(&:id).sort
935 937
936 938 query.filters = {"parent_id" => {:operator => '*', :values => ['']}}
937 939 assert_equal parent.descendants.map(&:id).sort, find_issues_with_query(query).map(&:id).sort
938 940
939 941 query.filters = {"parent_id" => {:operator => '!*', :values => ['']}}
940 942 assert_equal [parent.id], find_issues_with_query(query).map(&:id).sort
941 943 end
942 944
943 945 def test_filter_on_invalid_parent_should_return_no_results
944 946 query = IssueQuery.new(:name => '_')
945 947 query.filters = {"parent_id" => {:operator => '=', :values => '99999999999'}}
946 948 assert_equal [], find_issues_with_query(query).map(&:id).sort
947 949
948 950 query.filters = {"parent_id" => {:operator => '~', :values => '99999999999'}}
949 951 assert_equal [], find_issues_with_query(query)
950 952 end
951 953
952 954 def test_filter_on_child
953 955 Issue.delete_all
954 956 parent = Issue.generate_with_descendants!
955 957 child, leaf = parent.children.sort_by(&:id)
956 958 grandchild = child.children.first
957 959
958 960
959 961 query = IssueQuery.new(:name => '_')
960 962 query.filters = {"child_id" => {:operator => '=', :values => [grandchild.id.to_s]}}
961 963 assert_equal [child.id], find_issues_with_query(query).map(&:id).sort
962 964
963 965 query.filters = {"child_id" => {:operator => '~', :values => [grandchild.id.to_s]}}
964 966 assert_equal [parent, child].map(&:id).sort, find_issues_with_query(query).map(&:id).sort
965 967
966 968 query.filters = {"child_id" => {:operator => '*', :values => ['']}}
967 969 assert_equal [parent, child].map(&:id).sort, find_issues_with_query(query).map(&:id).sort
968 970
969 971 query.filters = {"child_id" => {:operator => '!*', :values => ['']}}
970 972 assert_equal [grandchild, leaf].map(&:id).sort, find_issues_with_query(query).map(&:id).sort
971 973 end
972 974
973 975 def test_filter_on_invalid_child_should_return_no_results
974 976 query = IssueQuery.new(:name => '_')
975 977 query.filters = {"child_id" => {:operator => '=', :values => '99999999999'}}
976 978 assert_equal [], find_issues_with_query(query)
977 979
978 980 query.filters = {"child_id" => {:operator => '~', :values => '99999999999'}}
979 981 assert_equal [].map(&:id).sort, find_issues_with_query(query)
980 982 end
981 983
982 984 def test_statement_should_be_nil_with_no_filters
983 985 q = IssueQuery.new(:name => '_')
984 986 q.filters = {}
985 987
986 988 assert q.valid?
987 989 assert_nil q.statement
988 990 end
989 991
990 992 def test_available_filters_as_json_should_include_missing_assigned_to_id_values
991 993 user = User.generate!
992 994 with_current_user User.find(1) do
993 995 q = IssueQuery.new
994 996 q.filters = {"assigned_to_id" => {:operator => '=', :values => user.id.to_s}}
995 997
996 998 filters = q.available_filters_as_json
997 999 assert_include [user.name, user.id.to_s], filters['assigned_to_id']['values']
998 1000 end
999 1001 end
1000 1002
1001 1003 def test_available_filters_as_json_should_include_missing_author_id_values
1002 1004 user = User.generate!
1003 1005 with_current_user User.find(1) do
1004 1006 q = IssueQuery.new
1005 1007 q.filters = {"author_id" => {:operator => '=', :values => user.id.to_s}}
1006 1008
1007 1009 filters = q.available_filters_as_json
1008 1010 assert_include [user.name, user.id.to_s], filters['author_id']['values']
1009 1011 end
1010 1012 end
1011 1013
1012 1014 def test_default_columns
1013 1015 q = IssueQuery.new
1014 1016 assert q.columns.any?
1015 1017 assert q.inline_columns.any?
1016 1018 assert q.block_columns.empty?
1017 1019 end
1018 1020
1019 1021 def test_set_column_names
1020 1022 q = IssueQuery.new
1021 1023 q.column_names = ['tracker', :subject, '', 'unknonw_column']
1022 1024 assert_equal [:id, :tracker, :subject], q.columns.collect {|c| c.name}
1023 1025 end
1024 1026
1025 1027 def test_has_column_should_accept_a_column_name
1026 1028 q = IssueQuery.new
1027 1029 q.column_names = ['tracker', :subject]
1028 1030 assert q.has_column?(:tracker)
1029 1031 assert !q.has_column?(:category)
1030 1032 end
1031 1033
1032 1034 def test_has_column_should_accept_a_column
1033 1035 q = IssueQuery.new
1034 1036 q.column_names = ['tracker', :subject]
1035 1037
1036 1038 tracker_column = q.available_columns.detect {|c| c.name==:tracker}
1037 1039 assert_kind_of QueryColumn, tracker_column
1038 1040 category_column = q.available_columns.detect {|c| c.name==:category}
1039 1041 assert_kind_of QueryColumn, category_column
1040 1042
1041 1043 assert q.has_column?(tracker_column)
1042 1044 assert !q.has_column?(category_column)
1043 1045 end
1044 1046
1045 1047 def test_inline_and_block_columns
1046 1048 q = IssueQuery.new
1047 1049 q.column_names = ['subject', 'description', 'tracker']
1048 1050
1049 1051 assert_equal [:id, :subject, :tracker], q.inline_columns.map(&:name)
1050 1052 assert_equal [:description], q.block_columns.map(&:name)
1051 1053 end
1052 1054
1053 1055 def test_custom_field_columns_should_be_inline
1054 1056 q = IssueQuery.new
1055 1057 columns = q.available_columns.select {|column| column.is_a? QueryCustomFieldColumn}
1056 1058 assert columns.any?
1057 1059 assert_nil columns.detect {|column| !column.inline?}
1058 1060 end
1059 1061
1060 1062 def test_query_should_preload_spent_hours
1061 1063 q = IssueQuery.new(:name => '_', :column_names => [:subject, :spent_hours])
1062 1064 assert q.has_column?(:spent_hours)
1063 1065 issues = q.issues
1064 1066 assert_not_nil issues.first.instance_variable_get("@spent_hours")
1065 1067 end
1066 1068
1067 1069 def test_groupable_columns_should_include_custom_fields
1068 1070 q = IssueQuery.new
1069 1071 column = q.groupable_columns.detect {|c| c.name == :cf_1}
1070 1072 assert_not_nil column
1071 1073 assert_kind_of QueryCustomFieldColumn, column
1072 1074 end
1073 1075
1074 1076 def test_groupable_columns_should_not_include_multi_custom_fields
1075 1077 field = CustomField.find(1)
1076 1078 field.update_attribute :multiple, true
1077 1079
1078 1080 q = IssueQuery.new
1079 1081 column = q.groupable_columns.detect {|c| c.name == :cf_1}
1080 1082 assert_nil column
1081 1083 end
1082 1084
1083 1085 def test_groupable_columns_should_include_user_custom_fields
1084 1086 cf = IssueCustomField.create!(:name => 'User', :is_for_all => true, :tracker_ids => [1], :field_format => 'user')
1085 1087
1086 1088 q = IssueQuery.new
1087 1089 assert q.groupable_columns.detect {|c| c.name == "cf_#{cf.id}".to_sym}
1088 1090 end
1089 1091
1090 1092 def test_groupable_columns_should_include_version_custom_fields
1091 1093 cf = IssueCustomField.create!(:name => 'User', :is_for_all => true, :tracker_ids => [1], :field_format => 'version')
1092 1094
1093 1095 q = IssueQuery.new
1094 1096 assert q.groupable_columns.detect {|c| c.name == "cf_#{cf.id}".to_sym}
1095 1097 end
1096 1098
1097 1099 def test_grouped_with_valid_column
1098 1100 q = IssueQuery.new(:group_by => 'status')
1099 1101 assert q.grouped?
1100 1102 assert_not_nil q.group_by_column
1101 1103 assert_equal :status, q.group_by_column.name
1102 1104 assert_not_nil q.group_by_statement
1103 1105 assert_equal 'status', q.group_by_statement
1104 1106 end
1105 1107
1106 1108 def test_grouped_with_invalid_column
1107 1109 q = IssueQuery.new(:group_by => 'foo')
1108 1110 assert !q.grouped?
1109 1111 assert_nil q.group_by_column
1110 1112 assert_nil q.group_by_statement
1111 1113 end
1112 1114
1113 1115 def test_sortable_columns_should_sort_assignees_according_to_user_format_setting
1114 1116 with_settings :user_format => 'lastname_comma_firstname' do
1115 1117 q = IssueQuery.new
1116 1118 assert q.sortable_columns.has_key?('assigned_to')
1117 1119 assert_equal %w(users.lastname users.firstname users.id), q.sortable_columns['assigned_to']
1118 1120 end
1119 1121 end
1120 1122
1121 1123 def test_sortable_columns_should_sort_authors_according_to_user_format_setting
1122 1124 with_settings :user_format => 'lastname_comma_firstname' do
1123 1125 q = IssueQuery.new
1124 1126 assert q.sortable_columns.has_key?('author')
1125 1127 assert_equal %w(authors.lastname authors.firstname authors.id), q.sortable_columns['author']
1126 1128 end
1127 1129 end
1128 1130
1129 1131 def test_sortable_columns_should_include_custom_field
1130 1132 q = IssueQuery.new
1131 1133 assert q.sortable_columns['cf_1']
1132 1134 end
1133 1135
1134 1136 def test_sortable_columns_should_not_include_multi_custom_field
1135 1137 field = CustomField.find(1)
1136 1138 field.update_attribute :multiple, true
1137 1139
1138 1140 q = IssueQuery.new
1139 1141 assert !q.sortable_columns['cf_1']
1140 1142 end
1141 1143
1142 1144 def test_default_sort
1143 1145 q = IssueQuery.new
1144 1146 assert_equal [], q.sort_criteria
1145 1147 end
1146 1148
1147 1149 def test_set_sort_criteria_with_hash
1148 1150 q = IssueQuery.new
1149 1151 q.sort_criteria = {'0' => ['priority', 'desc'], '2' => ['tracker']}
1150 1152 assert_equal [['priority', 'desc'], ['tracker', 'asc']], q.sort_criteria
1151 1153 end
1152 1154
1153 1155 def test_set_sort_criteria_with_array
1154 1156 q = IssueQuery.new
1155 1157 q.sort_criteria = [['priority', 'desc'], 'tracker']
1156 1158 assert_equal [['priority', 'desc'], ['tracker', 'asc']], q.sort_criteria
1157 1159 end
1158 1160
1159 1161 def test_create_query_with_sort
1160 1162 q = IssueQuery.new(:name => 'Sorted')
1161 1163 q.sort_criteria = [['priority', 'desc'], 'tracker']
1162 1164 assert q.save
1163 1165 q.reload
1164 1166 assert_equal [['priority', 'desc'], ['tracker', 'asc']], q.sort_criteria
1165 1167 end
1166 1168
1167 1169 def test_sort_by_string_custom_field_asc
1168 1170 q = IssueQuery.new
1169 1171 c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'string' }
1170 1172 assert c
1171 1173 assert c.sortable
1172 1174 issues = q.issues(:order => "#{c.sortable} ASC")
1173 1175 values = issues.collect {|i| i.custom_value_for(c.custom_field).to_s}
1174 1176 assert !values.empty?
1175 1177 assert_equal values.sort, values
1176 1178 end
1177 1179
1178 1180 def test_sort_by_string_custom_field_desc
1179 1181 q = IssueQuery.new
1180 1182 c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'string' }
1181 1183 assert c
1182 1184 assert c.sortable
1183 1185 issues = q.issues(:order => "#{c.sortable} DESC")
1184 1186 values = issues.collect {|i| i.custom_value_for(c.custom_field).to_s}
1185 1187 assert !values.empty?
1186 1188 assert_equal values.sort.reverse, values
1187 1189 end
1188 1190
1189 1191 def test_sort_by_float_custom_field_asc
1190 1192 q = IssueQuery.new
1191 1193 c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'float' }
1192 1194 assert c
1193 1195 assert c.sortable
1194 1196 issues = q.issues(:order => "#{c.sortable} ASC")
1195 1197 values = issues.collect {|i| begin; Kernel.Float(i.custom_value_for(c.custom_field).to_s); rescue; nil; end}.compact
1196 1198 assert !values.empty?
1197 1199 assert_equal values.sort, values
1198 1200 end
1199 1201
1200 1202 def test_set_totalable_names
1201 1203 q = IssueQuery.new
1202 1204 q.totalable_names = ['estimated_hours', :spent_hours, '']
1203 1205 assert_equal [:estimated_hours, :spent_hours], q.totalable_columns.map(&:name)
1204 1206 end
1205 1207
1206 1208 def test_totalable_columns_should_default_to_settings
1207 1209 with_settings :issue_list_default_totals => ['estimated_hours'] do
1208 1210 q = IssueQuery.new
1209 1211 assert_equal [:estimated_hours], q.totalable_columns.map(&:name)
1210 1212 end
1211 1213 end
1212 1214
1213 1215 def test_available_totalable_columns_should_include_estimated_hours
1214 1216 q = IssueQuery.new
1215 1217 assert_include :estimated_hours, q.available_totalable_columns.map(&:name)
1216 1218 end
1217 1219
1218 1220 def test_available_totalable_columns_should_include_spent_hours
1219 1221 User.current = User.find(1)
1220 1222
1221 1223 q = IssueQuery.new
1222 1224 assert_include :spent_hours, q.available_totalable_columns.map(&:name)
1223 1225 end
1224 1226
1225 1227 def test_available_totalable_columns_should_include_int_custom_field
1226 1228 field = IssueCustomField.generate!(:field_format => 'int', :is_for_all => true)
1227 1229 q = IssueQuery.new
1228 1230 assert_include "cf_#{field.id}".to_sym, q.available_totalable_columns.map(&:name)
1229 1231 end
1230 1232
1231 1233 def test_available_totalable_columns_should_include_float_custom_field
1232 1234 field = IssueCustomField.generate!(:field_format => 'float', :is_for_all => true)
1233 1235 q = IssueQuery.new
1234 1236 assert_include "cf_#{field.id}".to_sym, q.available_totalable_columns.map(&:name)
1235 1237 end
1236 1238
1237 1239 def test_total_for_estimated_hours
1238 1240 Issue.delete_all
1239 1241 Issue.generate!(:estimated_hours => 5.5)
1240 1242 Issue.generate!(:estimated_hours => 1.1)
1241 1243 Issue.generate!
1242 1244
1243 1245 q = IssueQuery.new
1244 1246 assert_equal 6.6, q.total_for(:estimated_hours)
1245 1247 end
1246 1248
1247 1249 def test_total_by_group_for_estimated_hours
1248 1250 Issue.delete_all
1249 1251 Issue.generate!(:estimated_hours => 5.5, :assigned_to_id => 2)
1250 1252 Issue.generate!(:estimated_hours => 1.1, :assigned_to_id => 3)
1251 1253 Issue.generate!(:estimated_hours => 3.5)
1252 1254
1253 1255 q = IssueQuery.new(:group_by => 'assigned_to')
1254 1256 assert_equal(
1255 1257 {nil => 3.5, User.find(2) => 5.5, User.find(3) => 1.1},
1256 1258 q.total_by_group_for(:estimated_hours)
1257 1259 )
1258 1260 end
1259 1261
1260 1262 def test_total_for_spent_hours
1261 1263 TimeEntry.delete_all
1262 1264 TimeEntry.generate!(:hours => 5.5)
1263 1265 TimeEntry.generate!(:hours => 1.1)
1264 1266
1265 1267 q = IssueQuery.new
1266 1268 assert_equal 6.6, q.total_for(:spent_hours)
1267 1269 end
1268 1270
1269 1271 def test_total_by_group_for_spent_hours
1270 1272 TimeEntry.delete_all
1271 1273 TimeEntry.generate!(:hours => 5.5, :issue_id => 1)
1272 1274 TimeEntry.generate!(:hours => 1.1, :issue_id => 2)
1273 1275 Issue.where(:id => 1).update_all(:assigned_to_id => 2)
1274 1276 Issue.where(:id => 2).update_all(:assigned_to_id => 3)
1275 1277
1276 1278 q = IssueQuery.new(:group_by => 'assigned_to')
1277 1279 assert_equal(
1278 1280 {User.find(2) => 5.5, User.find(3) => 1.1},
1279 1281 q.total_by_group_for(:spent_hours)
1280 1282 )
1281 1283 end
1282 1284
1283 1285 def test_total_by_project_group_for_spent_hours
1284 1286 TimeEntry.delete_all
1285 1287 TimeEntry.generate!(:hours => 5.5, :issue_id => 1)
1286 1288 TimeEntry.generate!(:hours => 1.1, :issue_id => 2)
1287 1289 Issue.where(:id => 1).update_all(:assigned_to_id => 2)
1288 1290 Issue.where(:id => 2).update_all(:assigned_to_id => 3)
1289 1291
1290 1292 q = IssueQuery.new(:group_by => 'project')
1291 1293 assert_equal(
1292 1294 {Project.find(1) => 6.6},
1293 1295 q.total_by_group_for(:spent_hours)
1294 1296 )
1295 1297 end
1296 1298
1297 1299 def test_total_for_int_custom_field
1298 1300 field = IssueCustomField.generate!(:field_format => 'int', :is_for_all => true)
1299 1301 CustomValue.create!(:customized => Issue.find(1), :custom_field => field, :value => '2')
1300 1302 CustomValue.create!(:customized => Issue.find(2), :custom_field => field, :value => '7')
1301 1303 CustomValue.create!(:customized => Issue.find(3), :custom_field => field, :value => '')
1302 1304
1303 1305 q = IssueQuery.new
1304 1306 assert_equal 9, q.total_for("cf_#{field.id}")
1305 1307 end
1306 1308
1307 1309 def test_total_by_group_for_int_custom_field
1308 1310 field = IssueCustomField.generate!(:field_format => 'int', :is_for_all => true)
1309 1311 CustomValue.create!(:customized => Issue.find(1), :custom_field => field, :value => '2')
1310 1312 CustomValue.create!(:customized => Issue.find(2), :custom_field => field, :value => '7')
1311 1313 Issue.where(:id => 1).update_all(:assigned_to_id => 2)
1312 1314 Issue.where(:id => 2).update_all(:assigned_to_id => 3)
1313 1315
1314 1316 q = IssueQuery.new(:group_by => 'assigned_to')
1315 1317 assert_equal(
1316 1318 {User.find(2) => 2, User.find(3) => 7},
1317 1319 q.total_by_group_for("cf_#{field.id}")
1318 1320 )
1319 1321 end
1320 1322
1321 1323 def test_total_for_float_custom_field
1322 1324 field = IssueCustomField.generate!(:field_format => 'float', :is_for_all => true)
1323 1325 CustomValue.create!(:customized => Issue.find(1), :custom_field => field, :value => '2.3')
1324 1326 CustomValue.create!(:customized => Issue.find(2), :custom_field => field, :value => '7')
1325 1327 CustomValue.create!(:customized => Issue.find(3), :custom_field => field, :value => '')
1326 1328
1327 1329 q = IssueQuery.new
1328 1330 assert_equal 9.3, q.total_for("cf_#{field.id}")
1329 1331 end
1330 1332
1331 1333 def test_invalid_query_should_raise_query_statement_invalid_error
1332 1334 q = IssueQuery.new
1333 1335 assert_raise Query::StatementInvalid do
1334 1336 q.issues(:conditions => "foo = 1")
1335 1337 end
1336 1338 end
1337 1339
1338 1340 def test_issue_count
1339 1341 q = IssueQuery.new(:name => '_')
1340 1342 issue_count = q.issue_count
1341 1343 assert_equal q.issues.size, issue_count
1342 1344 end
1343 1345
1344 1346 def test_issue_count_with_archived_issues
1345 1347 p = Project.generate! do |project|
1346 1348 project.status = Project::STATUS_ARCHIVED
1347 1349 end
1348 1350 i = Issue.generate!( :project => p, :tracker => p.trackers.first )
1349 1351 assert !i.visible?
1350 1352
1351 1353 test_issue_count
1352 1354 end
1353 1355
1354 1356 def test_issue_count_by_association_group
1355 1357 q = IssueQuery.new(:name => '_', :group_by => 'assigned_to')
1356 1358 count_by_group = q.issue_count_by_group
1357 1359 assert_kind_of Hash, count_by_group
1358 1360 assert_equal %w(NilClass User), count_by_group.keys.collect {|k| k.class.name}.uniq.sort
1359 1361 assert_equal %w(Fixnum), count_by_group.values.collect {|k| k.class.name}.uniq
1360 1362 assert count_by_group.has_key?(User.find(3))
1361 1363 end
1362 1364
1363 1365 def test_issue_count_by_list_custom_field_group
1364 1366 q = IssueQuery.new(:name => '_', :group_by => 'cf_1')
1365 1367 count_by_group = q.issue_count_by_group
1366 1368 assert_kind_of Hash, count_by_group
1367 1369 assert_equal %w(NilClass String), count_by_group.keys.collect {|k| k.class.name}.uniq.sort
1368 1370 assert_equal %w(Fixnum), count_by_group.values.collect {|k| k.class.name}.uniq
1369 1371 assert count_by_group.has_key?('MySQL')
1370 1372 end
1371 1373
1372 1374 def test_issue_count_by_date_custom_field_group
1373 1375 q = IssueQuery.new(:name => '_', :group_by => 'cf_8')
1374 1376 count_by_group = q.issue_count_by_group
1375 1377 assert_kind_of Hash, count_by_group
1376 1378 assert_equal %w(Date NilClass), count_by_group.keys.collect {|k| k.class.name}.uniq.sort
1377 1379 assert_equal %w(Fixnum), count_by_group.values.collect {|k| k.class.name}.uniq
1378 1380 end
1379 1381
1380 1382 def test_issue_count_with_nil_group_only
1381 1383 Issue.update_all("assigned_to_id = NULL")
1382 1384
1383 1385 q = IssueQuery.new(:name => '_', :group_by => 'assigned_to')
1384 1386 count_by_group = q.issue_count_by_group
1385 1387 assert_kind_of Hash, count_by_group
1386 1388 assert_equal 1, count_by_group.keys.size
1387 1389 assert_nil count_by_group.keys.first
1388 1390 end
1389 1391
1390 1392 def test_issue_ids
1391 1393 q = IssueQuery.new(:name => '_')
1392 1394 order = "issues.subject, issues.id"
1393 1395 issues = q.issues(:order => order)
1394 1396 assert_equal issues.map(&:id), q.issue_ids(:order => order)
1395 1397 end
1396 1398
1397 1399 def test_label_for
1398 1400 set_language_if_valid 'en'
1399 1401 q = IssueQuery.new
1400 1402 assert_equal 'Assignee', q.label_for('assigned_to_id')
1401 1403 end
1402 1404
1403 1405 def test_label_for_fr
1404 1406 set_language_if_valid 'fr'
1405 1407 q = IssueQuery.new
1406 1408 assert_equal "Assign\xc3\xa9 \xc3\xa0".force_encoding('UTF-8'), q.label_for('assigned_to_id')
1407 1409 end
1408 1410
1409 1411 def test_editable_by
1410 1412 admin = User.find(1)
1411 1413 manager = User.find(2)
1412 1414 developer = User.find(3)
1413 1415
1414 1416 # Public query on project 1
1415 1417 q = IssueQuery.find(1)
1416 1418 assert q.editable_by?(admin)
1417 1419 assert q.editable_by?(manager)
1418 1420 assert !q.editable_by?(developer)
1419 1421
1420 1422 # Private query on project 1
1421 1423 q = IssueQuery.find(2)
1422 1424 assert q.editable_by?(admin)
1423 1425 assert !q.editable_by?(manager)
1424 1426 assert q.editable_by?(developer)
1425 1427
1426 1428 # Private query for all projects
1427 1429 q = IssueQuery.find(3)
1428 1430 assert q.editable_by?(admin)
1429 1431 assert !q.editable_by?(manager)
1430 1432 assert q.editable_by?(developer)
1431 1433
1432 1434 # Public query for all projects
1433 1435 q = IssueQuery.find(4)
1434 1436 assert q.editable_by?(admin)
1435 1437 assert !q.editable_by?(manager)
1436 1438 assert !q.editable_by?(developer)
1437 1439 end
1438 1440
1439 1441 def test_visible_scope
1440 1442 query_ids = IssueQuery.visible(User.anonymous).map(&:id)
1441 1443
1442 1444 assert query_ids.include?(1), 'public query on public project was not visible'
1443 1445 assert query_ids.include?(4), 'public query for all projects was not visible'
1444 1446 assert !query_ids.include?(2), 'private query on public project was visible'
1445 1447 assert !query_ids.include?(3), 'private query for all projects was visible'
1446 1448 assert !query_ids.include?(7), 'public query on private project was visible'
1447 1449 end
1448 1450
1449 1451 def test_query_with_public_visibility_should_be_visible_to_anyone
1450 1452 q = IssueQuery.create!(:name => 'Query', :visibility => IssueQuery::VISIBILITY_PUBLIC)
1451 1453
1452 1454 assert q.visible?(User.anonymous)
1453 1455 assert IssueQuery.visible(User.anonymous).find_by_id(q.id)
1454 1456
1455 1457 assert q.visible?(User.find(7))
1456 1458 assert IssueQuery.visible(User.find(7)).find_by_id(q.id)
1457 1459
1458 1460 assert q.visible?(User.find(2))
1459 1461 assert IssueQuery.visible(User.find(2)).find_by_id(q.id)
1460 1462
1461 1463 assert q.visible?(User.find(1))
1462 1464 assert IssueQuery.visible(User.find(1)).find_by_id(q.id)
1463 1465 end
1464 1466
1465 1467 def test_query_with_roles_visibility_should_be_visible_to_user_with_role
1466 1468 q = IssueQuery.create!(:name => 'Query', :visibility => IssueQuery::VISIBILITY_ROLES, :role_ids => [1,2])
1467 1469
1468 1470 assert !q.visible?(User.anonymous)
1469 1471 assert_nil IssueQuery.visible(User.anonymous).find_by_id(q.id)
1470 1472
1471 1473 assert !q.visible?(User.find(7))
1472 1474 assert_nil IssueQuery.visible(User.find(7)).find_by_id(q.id)
1473 1475
1474 1476 assert q.visible?(User.find(2))
1475 1477 assert IssueQuery.visible(User.find(2)).find_by_id(q.id)
1476 1478
1477 1479 assert q.visible?(User.find(1))
1478 1480 assert IssueQuery.visible(User.find(1)).find_by_id(q.id)
1479 1481 end
1480 1482
1481 1483 def test_query_with_private_visibility_should_be_visible_to_owner
1482 1484 q = IssueQuery.create!(:name => 'Query', :visibility => IssueQuery::VISIBILITY_PRIVATE, :user => User.find(7))
1483 1485
1484 1486 assert !q.visible?(User.anonymous)
1485 1487 assert_nil IssueQuery.visible(User.anonymous).find_by_id(q.id)
1486 1488
1487 1489 assert q.visible?(User.find(7))
1488 1490 assert IssueQuery.visible(User.find(7)).find_by_id(q.id)
1489 1491
1490 1492 assert !q.visible?(User.find(2))
1491 1493 assert_nil IssueQuery.visible(User.find(2)).find_by_id(q.id)
1492 1494
1493 1495 assert q.visible?(User.find(1))
1494 1496 assert_nil IssueQuery.visible(User.find(1)).find_by_id(q.id)
1495 1497 end
1496 1498
1497 1499 test "#available_filters should include users of visible projects in cross-project view" do
1498 1500 users = IssueQuery.new.available_filters["assigned_to_id"]
1499 1501 assert_not_nil users
1500 1502 assert users[:values].map{|u|u[1]}.include?("3")
1501 1503 end
1502 1504
1503 1505 test "#available_filters should include users of subprojects" do
1504 1506 user1 = User.generate!
1505 1507 user2 = User.generate!
1506 1508 project = Project.find(1)
1507 1509 Member.create!(:principal => user1, :project => project.children.visible.first, :role_ids => [1])
1508 1510
1509 1511 users = IssueQuery.new(:project => project).available_filters["assigned_to_id"]
1510 1512 assert_not_nil users
1511 1513 assert users[:values].map{|u|u[1]}.include?(user1.id.to_s)
1512 1514 assert !users[:values].map{|u|u[1]}.include?(user2.id.to_s)
1513 1515 end
1514 1516
1515 1517 test "#available_filters should include visible projects in cross-project view" do
1516 1518 projects = IssueQuery.new.available_filters["project_id"]
1517 1519 assert_not_nil projects
1518 1520 assert projects[:values].map{|u|u[1]}.include?("1")
1519 1521 end
1520 1522
1521 1523 test "#available_filters should include 'member_of_group' filter" do
1522 1524 query = IssueQuery.new
1523 1525 assert query.available_filters.keys.include?("member_of_group")
1524 1526 assert_equal :list_optional, query.available_filters["member_of_group"][:type]
1525 1527 assert query.available_filters["member_of_group"][:values].present?
1526 1528 assert_equal Group.givable.sort.map {|g| [g.name, g.id.to_s]},
1527 1529 query.available_filters["member_of_group"][:values].sort
1528 1530 end
1529 1531
1530 1532 test "#available_filters should include 'assigned_to_role' filter" do
1531 1533 query = IssueQuery.new
1532 1534 assert query.available_filters.keys.include?("assigned_to_role")
1533 1535 assert_equal :list_optional, query.available_filters["assigned_to_role"][:type]
1534 1536
1535 1537 assert query.available_filters["assigned_to_role"][:values].include?(['Manager','1'])
1536 1538 assert query.available_filters["assigned_to_role"][:values].include?(['Developer','2'])
1537 1539 assert query.available_filters["assigned_to_role"][:values].include?(['Reporter','3'])
1538 1540
1539 1541 assert ! query.available_filters["assigned_to_role"][:values].include?(['Non member','4'])
1540 1542 assert ! query.available_filters["assigned_to_role"][:values].include?(['Anonymous','5'])
1541 1543 end
1542 1544
1543 1545 def test_available_filters_should_include_custom_field_according_to_user_visibility
1544 1546 visible_field = IssueCustomField.generate!(:is_for_all => true, :is_filter => true, :visible => true)
1545 1547 hidden_field = IssueCustomField.generate!(:is_for_all => true, :is_filter => true, :visible => false, :role_ids => [1])
1546 1548
1547 1549 with_current_user User.find(3) do
1548 1550 query = IssueQuery.new
1549 1551 assert_include "cf_#{visible_field.id}", query.available_filters.keys
1550 1552 assert_not_include "cf_#{hidden_field.id}", query.available_filters.keys
1551 1553 end
1552 1554 end
1553 1555
1554 1556 def test_available_columns_should_include_custom_field_according_to_user_visibility
1555 1557 visible_field = IssueCustomField.generate!(:is_for_all => true, :is_filter => true, :visible => true)
1556 1558 hidden_field = IssueCustomField.generate!(:is_for_all => true, :is_filter => true, :visible => false, :role_ids => [1])
1557 1559
1558 1560 with_current_user User.find(3) do
1559 1561 query = IssueQuery.new
1560 1562 assert_include :"cf_#{visible_field.id}", query.available_columns.map(&:name)
1561 1563 assert_not_include :"cf_#{hidden_field.id}", query.available_columns.map(&:name)
1562 1564 end
1563 1565 end
1564 1566
1565 1567 def setup_member_of_group
1566 1568 Group.destroy_all # No fixtures
1567 1569 @user_in_group = User.generate!
1568 1570 @second_user_in_group = User.generate!
1569 1571 @user_in_group2 = User.generate!
1570 1572 @user_not_in_group = User.generate!
1571 1573
1572 1574 @group = Group.generate!.reload
1573 1575 @group.users << @user_in_group
1574 1576 @group.users << @second_user_in_group
1575 1577
1576 1578 @group2 = Group.generate!.reload
1577 1579 @group2.users << @user_in_group2
1578 1580
1579 1581 @query = IssueQuery.new(:name => '_')
1580 1582 end
1581 1583
1582 1584 test "member_of_group filter should search assigned to for users in the group" do
1583 1585 setup_member_of_group
1584 1586 @query.add_filter('member_of_group', '=', [@group.id.to_s])
1585 1587
1586 1588 assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IN ('#{@user_in_group.id}','#{@second_user_in_group.id}','#{@group.id}')"
1587 1589 assert_find_issues_with_query_is_successful @query
1588 1590 end
1589 1591
1590 1592 test "member_of_group filter should search not assigned to any group member (none)" do
1591 1593 setup_member_of_group
1592 1594 @query.add_filter('member_of_group', '!*', [''])
1593 1595
1594 1596 # Users not in a group
1595 1597 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}')"
1596 1598 assert_find_issues_with_query_is_successful @query
1597 1599 end
1598 1600
1599 1601 test "member_of_group filter should search assigned to any group member (all)" do
1600 1602 setup_member_of_group
1601 1603 @query.add_filter('member_of_group', '*', [''])
1602 1604
1603 1605 # Only users in a group
1604 1606 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}')"
1605 1607 assert_find_issues_with_query_is_successful @query
1606 1608 end
1607 1609
1608 1610 test "member_of_group filter should return an empty set with = empty group" do
1609 1611 setup_member_of_group
1610 1612 @empty_group = Group.generate!
1611 1613 @query.add_filter('member_of_group', '=', [@empty_group.id.to_s])
1612 1614
1613 1615 assert_equal [], find_issues_with_query(@query)
1614 1616 end
1615 1617
1616 1618 test "member_of_group filter should return issues with ! empty group" do
1617 1619 setup_member_of_group
1618 1620 @empty_group = Group.generate!
1619 1621 @query.add_filter('member_of_group', '!', [@empty_group.id.to_s])
1620 1622
1621 1623 assert_find_issues_with_query_is_successful @query
1622 1624 end
1623 1625
1624 1626 def setup_assigned_to_role
1625 1627 @manager_role = Role.find_by_name('Manager')
1626 1628 @developer_role = Role.find_by_name('Developer')
1627 1629
1628 1630 @project = Project.generate!
1629 1631 @manager = User.generate!
1630 1632 @developer = User.generate!
1631 1633 @boss = User.generate!
1632 1634 @guest = User.generate!
1633 1635 User.add_to_project(@manager, @project, @manager_role)
1634 1636 User.add_to_project(@developer, @project, @developer_role)
1635 1637 User.add_to_project(@boss, @project, [@manager_role, @developer_role])
1636 1638
1637 1639 @issue1 = Issue.generate!(:project => @project, :assigned_to_id => @manager.id)
1638 1640 @issue2 = Issue.generate!(:project => @project, :assigned_to_id => @developer.id)
1639 1641 @issue3 = Issue.generate!(:project => @project, :assigned_to_id => @boss.id)
1640 1642 @issue4 = Issue.generate!(:project => @project, :assigned_to_id => @guest.id)
1641 1643 @issue5 = Issue.generate!(:project => @project)
1642 1644
1643 1645 @query = IssueQuery.new(:name => '_', :project => @project)
1644 1646 end
1645 1647
1646 1648 test "assigned_to_role filter should search assigned to for users with the Role" do
1647 1649 setup_assigned_to_role
1648 1650 @query.add_filter('assigned_to_role', '=', [@manager_role.id.to_s])
1649 1651
1650 1652 assert_query_result [@issue1, @issue3], @query
1651 1653 end
1652 1654
1653 1655 test "assigned_to_role filter should search assigned to for users with the Role on the issue project" do
1654 1656 setup_assigned_to_role
1655 1657 other_project = Project.generate!
1656 1658 User.add_to_project(@developer, other_project, @manager_role)
1657 1659 @query.add_filter('assigned_to_role', '=', [@manager_role.id.to_s])
1658 1660
1659 1661 assert_query_result [@issue1, @issue3], @query
1660 1662 end
1661 1663
1662 1664 test "assigned_to_role filter should return an empty set with empty role" do
1663 1665 setup_assigned_to_role
1664 1666 @empty_role = Role.generate!
1665 1667 @query.add_filter('assigned_to_role', '=', [@empty_role.id.to_s])
1666 1668
1667 1669 assert_query_result [], @query
1668 1670 end
1669 1671
1670 1672 test "assigned_to_role filter should search assigned to for users without the Role" do
1671 1673 setup_assigned_to_role
1672 1674 @query.add_filter('assigned_to_role', '!', [@manager_role.id.to_s])
1673 1675
1674 1676 assert_query_result [@issue2, @issue4, @issue5], @query
1675 1677 end
1676 1678
1677 1679 test "assigned_to_role filter should search assigned to for users not assigned to any Role (none)" do
1678 1680 setup_assigned_to_role
1679 1681 @query.add_filter('assigned_to_role', '!*', [''])
1680 1682
1681 1683 assert_query_result [@issue4, @issue5], @query
1682 1684 end
1683 1685
1684 1686 test "assigned_to_role filter should search assigned to for users assigned to any Role (all)" do
1685 1687 setup_assigned_to_role
1686 1688 @query.add_filter('assigned_to_role', '*', [''])
1687 1689
1688 1690 assert_query_result [@issue1, @issue2, @issue3], @query
1689 1691 end
1690 1692
1691 1693 test "assigned_to_role filter should return issues with ! empty role" do
1692 1694 setup_assigned_to_role
1693 1695 @empty_role = Role.generate!
1694 1696 @query.add_filter('assigned_to_role', '!', [@empty_role.id.to_s])
1695 1697
1696 1698 assert_query_result [@issue1, @issue2, @issue3, @issue4, @issue5], @query
1697 1699 end
1698 1700
1699 1701 def test_query_column_should_accept_a_symbol_as_caption
1700 1702 set_language_if_valid 'en'
1701 1703 c = QueryColumn.new('foo', :caption => :general_text_Yes)
1702 1704 assert_equal 'Yes', c.caption
1703 1705 end
1704 1706
1705 1707 def test_query_column_should_accept_a_proc_as_caption
1706 1708 c = QueryColumn.new('foo', :caption => lambda {'Foo'})
1707 1709 assert_equal 'Foo', c.caption
1708 1710 end
1709 1711 end
General Comments 0
You need to be logged in to leave comments. Login now