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