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