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