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