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