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