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