##// END OF EJS Templates
Fixes an assertion for postgresql (#7097)....
Jean-Philippe Lang -
r5483:93fabf23ae2e
parent child
Show More
@@ -1,607 +1,607
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 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 fixtures :projects, :enabled_modules, :users, :members, :member_roles, :roles, :trackers, :issue_statuses, :issue_categories, :enumerations, :issues, :watchers, :custom_fields, :custom_values, :versions, :queries
21 fixtures :projects, :enabled_modules, :users, :members, :member_roles, :roles, :trackers, :issue_statuses, :issue_categories, :enumerations, :issues, :watchers, :custom_fields, :custom_values, :versions, :queries
22
22
23 def test_custom_fields_for_all_projects_should_be_available_in_global_queries
23 def test_custom_fields_for_all_projects_should_be_available_in_global_queries
24 query = Query.new(:project => nil, :name => '_')
24 query = Query.new(:project => nil, :name => '_')
25 assert query.available_filters.has_key?('cf_1')
25 assert query.available_filters.has_key?('cf_1')
26 assert !query.available_filters.has_key?('cf_3')
26 assert !query.available_filters.has_key?('cf_3')
27 end
27 end
28
28
29 def test_system_shared_versions_should_be_available_in_global_queries
29 def test_system_shared_versions_should_be_available_in_global_queries
30 Version.find(2).update_attribute :sharing, 'system'
30 Version.find(2).update_attribute :sharing, 'system'
31 query = Query.new(:project => nil, :name => '_')
31 query = Query.new(:project => nil, :name => '_')
32 assert query.available_filters.has_key?('fixed_version_id')
32 assert query.available_filters.has_key?('fixed_version_id')
33 assert query.available_filters['fixed_version_id'][:values].detect {|v| v.last == '2'}
33 assert query.available_filters['fixed_version_id'][:values].detect {|v| v.last == '2'}
34 end
34 end
35
35
36 def test_project_filter_in_global_queries
36 def test_project_filter_in_global_queries
37 query = Query.new(:project => nil, :name => '_')
37 query = Query.new(:project => nil, :name => '_')
38 project_filter = query.available_filters["project_id"]
38 project_filter = query.available_filters["project_id"]
39 assert_not_nil project_filter
39 assert_not_nil project_filter
40 project_ids = project_filter[:values].map{|p| p[1]}
40 project_ids = project_filter[:values].map{|p| p[1]}
41 assert project_ids.include?("1") #public project
41 assert project_ids.include?("1") #public project
42 assert !project_ids.include?("2") #private project user cannot see
42 assert !project_ids.include?("2") #private project user cannot see
43 end
43 end
44
44
45 def find_issues_with_query(query)
45 def find_issues_with_query(query)
46 Issue.find :all,
46 Issue.find :all,
47 :include => [ :assigned_to, :status, :tracker, :project, :priority ],
47 :include => [ :assigned_to, :status, :tracker, :project, :priority ],
48 :conditions => query.statement
48 :conditions => query.statement
49 end
49 end
50
50
51 def assert_find_issues_with_query_is_successful(query)
51 def assert_find_issues_with_query_is_successful(query)
52 assert_nothing_raised do
52 assert_nothing_raised do
53 find_issues_with_query(query)
53 find_issues_with_query(query)
54 end
54 end
55 end
55 end
56
56
57 def assert_query_statement_includes(query, condition)
57 def assert_query_statement_includes(query, condition)
58 assert query.statement.include?(condition), "Query statement condition not found in: #{query.statement}"
58 assert query.statement.include?(condition), "Query statement condition not found in: #{query.statement}"
59 end
59 end
60
60
61 def test_query_should_allow_shared_versions_for_a_project_query
61 def test_query_should_allow_shared_versions_for_a_project_query
62 subproject_version = Version.find(4)
62 subproject_version = Version.find(4)
63 query = Query.new(:project => Project.find(1), :name => '_')
63 query = Query.new(:project => Project.find(1), :name => '_')
64 query.add_filter('fixed_version_id', '=', [subproject_version.id.to_s])
64 query.add_filter('fixed_version_id', '=', [subproject_version.id.to_s])
65
65
66 assert query.statement.include?("#{Issue.table_name}.fixed_version_id IN ('4')")
66 assert query.statement.include?("#{Issue.table_name}.fixed_version_id IN ('4')")
67 end
67 end
68
68
69 def test_query_with_multiple_custom_fields
69 def test_query_with_multiple_custom_fields
70 query = Query.find(1)
70 query = Query.find(1)
71 assert query.valid?
71 assert query.valid?
72 assert query.statement.include?("#{CustomValue.table_name}.value IN ('MySQL')")
72 assert query.statement.include?("#{CustomValue.table_name}.value IN ('MySQL')")
73 issues = find_issues_with_query(query)
73 issues = find_issues_with_query(query)
74 assert_equal 1, issues.length
74 assert_equal 1, issues.length
75 assert_equal Issue.find(3), issues.first
75 assert_equal Issue.find(3), issues.first
76 end
76 end
77
77
78 def test_operator_none
78 def test_operator_none
79 query = Query.new(:project => Project.find(1), :name => '_')
79 query = Query.new(:project => Project.find(1), :name => '_')
80 query.add_filter('fixed_version_id', '!*', [''])
80 query.add_filter('fixed_version_id', '!*', [''])
81 query.add_filter('cf_1', '!*', [''])
81 query.add_filter('cf_1', '!*', [''])
82 assert query.statement.include?("#{Issue.table_name}.fixed_version_id IS NULL")
82 assert query.statement.include?("#{Issue.table_name}.fixed_version_id IS NULL")
83 assert query.statement.include?("#{CustomValue.table_name}.value IS NULL OR #{CustomValue.table_name}.value = ''")
83 assert query.statement.include?("#{CustomValue.table_name}.value IS NULL OR #{CustomValue.table_name}.value = ''")
84 find_issues_with_query(query)
84 find_issues_with_query(query)
85 end
85 end
86
86
87 def test_operator_none_for_integer
87 def test_operator_none_for_integer
88 query = Query.new(:project => Project.find(1), :name => '_')
88 query = Query.new(:project => Project.find(1), :name => '_')
89 query.add_filter('estimated_hours', '!*', [''])
89 query.add_filter('estimated_hours', '!*', [''])
90 issues = find_issues_with_query(query)
90 issues = find_issues_with_query(query)
91 assert !issues.empty?
91 assert !issues.empty?
92 assert issues.all? {|i| !i.estimated_hours}
92 assert issues.all? {|i| !i.estimated_hours}
93 end
93 end
94
94
95 def test_operator_all
95 def test_operator_all
96 query = Query.new(:project => Project.find(1), :name => '_')
96 query = Query.new(:project => Project.find(1), :name => '_')
97 query.add_filter('fixed_version_id', '*', [''])
97 query.add_filter('fixed_version_id', '*', [''])
98 query.add_filter('cf_1', '*', [''])
98 query.add_filter('cf_1', '*', [''])
99 assert query.statement.include?("#{Issue.table_name}.fixed_version_id IS NOT NULL")
99 assert query.statement.include?("#{Issue.table_name}.fixed_version_id IS NOT NULL")
100 assert query.statement.include?("#{CustomValue.table_name}.value IS NOT NULL AND #{CustomValue.table_name}.value <> ''")
100 assert query.statement.include?("#{CustomValue.table_name}.value IS NOT NULL AND #{CustomValue.table_name}.value <> ''")
101 find_issues_with_query(query)
101 find_issues_with_query(query)
102 end
102 end
103
103
104 def test_operator_greater_than
104 def test_operator_greater_than
105 query = Query.new(:project => Project.find(1), :name => '_')
105 query = Query.new(:project => Project.find(1), :name => '_')
106 query.add_filter('done_ratio', '>=', ['40'])
106 query.add_filter('done_ratio', '>=', ['40'])
107 assert query.statement.include?("#{Issue.table_name}.done_ratio >= 40")
107 assert query.statement.include?("#{Issue.table_name}.done_ratio >= 40")
108 find_issues_with_query(query)
108 find_issues_with_query(query)
109 end
109 end
110
110
111 def test_operator_in_more_than
111 def test_operator_in_more_than
112 Issue.find(7).update_attribute(:due_date, (Date.today + 15))
112 Issue.find(7).update_attribute(:due_date, (Date.today + 15))
113 query = Query.new(:project => Project.find(1), :name => '_')
113 query = Query.new(:project => Project.find(1), :name => '_')
114 query.add_filter('due_date', '>t+', ['15'])
114 query.add_filter('due_date', '>t+', ['15'])
115 issues = find_issues_with_query(query)
115 issues = find_issues_with_query(query)
116 assert !issues.empty?
116 assert !issues.empty?
117 issues.each {|issue| assert(issue.due_date >= (Date.today + 15))}
117 issues.each {|issue| assert(issue.due_date >= (Date.today + 15))}
118 end
118 end
119
119
120 def test_operator_in_less_than
120 def test_operator_in_less_than
121 query = Query.new(:project => Project.find(1), :name => '_')
121 query = Query.new(:project => Project.find(1), :name => '_')
122 query.add_filter('due_date', '<t+', ['15'])
122 query.add_filter('due_date', '<t+', ['15'])
123 issues = find_issues_with_query(query)
123 issues = find_issues_with_query(query)
124 assert !issues.empty?
124 assert !issues.empty?
125 issues.each {|issue| assert(issue.due_date >= Date.today && issue.due_date <= (Date.today + 15))}
125 issues.each {|issue| assert(issue.due_date >= Date.today && issue.due_date <= (Date.today + 15))}
126 end
126 end
127
127
128 def test_operator_less_than_ago
128 def test_operator_less_than_ago
129 Issue.find(7).update_attribute(:due_date, (Date.today - 3))
129 Issue.find(7).update_attribute(:due_date, (Date.today - 3))
130 query = Query.new(:project => Project.find(1), :name => '_')
130 query = Query.new(:project => Project.find(1), :name => '_')
131 query.add_filter('due_date', '>t-', ['3'])
131 query.add_filter('due_date', '>t-', ['3'])
132 issues = find_issues_with_query(query)
132 issues = find_issues_with_query(query)
133 assert !issues.empty?
133 assert !issues.empty?
134 issues.each {|issue| assert(issue.due_date >= (Date.today - 3) && issue.due_date <= Date.today)}
134 issues.each {|issue| assert(issue.due_date >= (Date.today - 3) && issue.due_date <= Date.today)}
135 end
135 end
136
136
137 def test_operator_more_than_ago
137 def test_operator_more_than_ago
138 Issue.find(7).update_attribute(:due_date, (Date.today - 10))
138 Issue.find(7).update_attribute(:due_date, (Date.today - 10))
139 query = Query.new(:project => Project.find(1), :name => '_')
139 query = Query.new(:project => Project.find(1), :name => '_')
140 query.add_filter('due_date', '<t-', ['10'])
140 query.add_filter('due_date', '<t-', ['10'])
141 assert query.statement.include?("#{Issue.table_name}.due_date <=")
141 assert query.statement.include?("#{Issue.table_name}.due_date <=")
142 issues = find_issues_with_query(query)
142 issues = find_issues_with_query(query)
143 assert !issues.empty?
143 assert !issues.empty?
144 issues.each {|issue| assert(issue.due_date <= (Date.today - 10))}
144 issues.each {|issue| assert(issue.due_date <= (Date.today - 10))}
145 end
145 end
146
146
147 def test_operator_in
147 def test_operator_in
148 Issue.find(7).update_attribute(:due_date, (Date.today + 2))
148 Issue.find(7).update_attribute(:due_date, (Date.today + 2))
149 query = Query.new(:project => Project.find(1), :name => '_')
149 query = Query.new(:project => Project.find(1), :name => '_')
150 query.add_filter('due_date', 't+', ['2'])
150 query.add_filter('due_date', 't+', ['2'])
151 issues = find_issues_with_query(query)
151 issues = find_issues_with_query(query)
152 assert !issues.empty?
152 assert !issues.empty?
153 issues.each {|issue| assert_equal((Date.today + 2), issue.due_date)}
153 issues.each {|issue| assert_equal((Date.today + 2), issue.due_date)}
154 end
154 end
155
155
156 def test_operator_ago
156 def test_operator_ago
157 Issue.find(7).update_attribute(:due_date, (Date.today - 3))
157 Issue.find(7).update_attribute(:due_date, (Date.today - 3))
158 query = Query.new(:project => Project.find(1), :name => '_')
158 query = Query.new(:project => Project.find(1), :name => '_')
159 query.add_filter('due_date', 't-', ['3'])
159 query.add_filter('due_date', 't-', ['3'])
160 issues = find_issues_with_query(query)
160 issues = find_issues_with_query(query)
161 assert !issues.empty?
161 assert !issues.empty?
162 issues.each {|issue| assert_equal((Date.today - 3), issue.due_date)}
162 issues.each {|issue| assert_equal((Date.today - 3), issue.due_date)}
163 end
163 end
164
164
165 def test_operator_today
165 def test_operator_today
166 query = Query.new(:project => Project.find(1), :name => '_')
166 query = Query.new(:project => Project.find(1), :name => '_')
167 query.add_filter('due_date', 't', [''])
167 query.add_filter('due_date', 't', [''])
168 issues = find_issues_with_query(query)
168 issues = find_issues_with_query(query)
169 assert !issues.empty?
169 assert !issues.empty?
170 issues.each {|issue| assert_equal Date.today, issue.due_date}
170 issues.each {|issue| assert_equal Date.today, issue.due_date}
171 end
171 end
172
172
173 def test_operator_this_week_on_date
173 def test_operator_this_week_on_date
174 query = Query.new(:project => Project.find(1), :name => '_')
174 query = Query.new(:project => Project.find(1), :name => '_')
175 query.add_filter('due_date', 'w', [''])
175 query.add_filter('due_date', 'w', [''])
176 find_issues_with_query(query)
176 find_issues_with_query(query)
177 end
177 end
178
178
179 def test_operator_this_week_on_datetime
179 def test_operator_this_week_on_datetime
180 query = Query.new(:project => Project.find(1), :name => '_')
180 query = Query.new(:project => Project.find(1), :name => '_')
181 query.add_filter('created_on', 'w', [''])
181 query.add_filter('created_on', 'w', [''])
182 find_issues_with_query(query)
182 find_issues_with_query(query)
183 end
183 end
184
184
185 def test_operator_contains
185 def test_operator_contains
186 query = Query.new(:project => Project.find(1), :name => '_')
186 query = Query.new(:project => Project.find(1), :name => '_')
187 query.add_filter('subject', '~', ['uNable'])
187 query.add_filter('subject', '~', ['uNable'])
188 assert query.statement.include?("LOWER(#{Issue.table_name}.subject) LIKE '%unable%'")
188 assert query.statement.include?("LOWER(#{Issue.table_name}.subject) LIKE '%unable%'")
189 result = find_issues_with_query(query)
189 result = find_issues_with_query(query)
190 assert result.empty?
190 assert result.empty?
191 result.each {|issue| assert issue.subject.downcase.include?('unable') }
191 result.each {|issue| assert issue.subject.downcase.include?('unable') }
192 end
192 end
193
193
194 def test_range_for_this_week_with_week_starting_on_monday
194 def test_range_for_this_week_with_week_starting_on_monday
195 I18n.locale = :fr
195 I18n.locale = :fr
196 assert_equal '1', I18n.t(:general_first_day_of_week)
196 assert_equal '1', I18n.t(:general_first_day_of_week)
197
197
198 Date.stubs(:today).returns(Date.parse('2011-04-29'))
198 Date.stubs(:today).returns(Date.parse('2011-04-29'))
199
199
200 query = Query.new(:project => Project.find(1), :name => '_')
200 query = Query.new(:project => Project.find(1), :name => '_')
201 query.add_filter('due_date', 'w', [''])
201 query.add_filter('due_date', 'w', [''])
202 assert query.statement.include?("issues.due_date > '2011-04-24 23:59:59' AND issues.due_date <= '2011-05-01 23:59:59")
202 assert query.statement.match(/issues\.due_date > '2011-04-24 23:59:59(\.9+)?' AND issues\.due_date <= '2011-05-01 23:59:59(\.9+)?/), "range not found in #{query.statement}"
203 I18n.locale = :en
203 I18n.locale = :en
204 end
204 end
205
205
206 def test_range_for_this_week_with_week_starting_on_sunday
206 def test_range_for_this_week_with_week_starting_on_sunday
207 I18n.locale = :en
207 I18n.locale = :en
208 assert_equal '7', I18n.t(:general_first_day_of_week)
208 assert_equal '7', I18n.t(:general_first_day_of_week)
209
209
210 Date.stubs(:today).returns(Date.parse('2011-04-29'))
210 Date.stubs(:today).returns(Date.parse('2011-04-29'))
211
211
212 query = Query.new(:project => Project.find(1), :name => '_')
212 query = Query.new(:project => Project.find(1), :name => '_')
213 query.add_filter('due_date', 'w', [''])
213 query.add_filter('due_date', 'w', [''])
214 assert query.statement.include?("issues.due_date > '2011-04-23 23:59:59' AND issues.due_date <= '2011-04-30 23:59:59")
214 assert query.statement.match(/issues\.due_date > '2011-04-23 23:59:59(\.9+)?' AND issues\.due_date <= '2011-04-30 23:59:59(\.9+)?/), "range not found in #{query.statement}"
215 end
215 end
216
216
217 def test_operator_does_not_contains
217 def test_operator_does_not_contains
218 query = Query.new(:project => Project.find(1), :name => '_')
218 query = Query.new(:project => Project.find(1), :name => '_')
219 query.add_filter('subject', '!~', ['uNable'])
219 query.add_filter('subject', '!~', ['uNable'])
220 assert query.statement.include?("LOWER(#{Issue.table_name}.subject) NOT LIKE '%unable%'")
220 assert query.statement.include?("LOWER(#{Issue.table_name}.subject) NOT LIKE '%unable%'")
221 find_issues_with_query(query)
221 find_issues_with_query(query)
222 end
222 end
223
223
224 def test_filter_watched_issues
224 def test_filter_watched_issues
225 User.current = User.find(1)
225 User.current = User.find(1)
226 query = Query.new(:name => '_', :filters => { 'watcher_id' => {:operator => '=', :values => ['me']}})
226 query = Query.new(:name => '_', :filters => { 'watcher_id' => {:operator => '=', :values => ['me']}})
227 result = find_issues_with_query(query)
227 result = find_issues_with_query(query)
228 assert_not_nil result
228 assert_not_nil result
229 assert !result.empty?
229 assert !result.empty?
230 assert_equal Issue.visible.watched_by(User.current).sort_by(&:id), result.sort_by(&:id)
230 assert_equal Issue.visible.watched_by(User.current).sort_by(&:id), result.sort_by(&:id)
231 User.current = nil
231 User.current = nil
232 end
232 end
233
233
234 def test_filter_unwatched_issues
234 def test_filter_unwatched_issues
235 User.current = User.find(1)
235 User.current = User.find(1)
236 query = Query.new(:name => '_', :filters => { 'watcher_id' => {:operator => '!', :values => ['me']}})
236 query = Query.new(:name => '_', :filters => { 'watcher_id' => {:operator => '!', :values => ['me']}})
237 result = find_issues_with_query(query)
237 result = find_issues_with_query(query)
238 assert_not_nil result
238 assert_not_nil result
239 assert !result.empty?
239 assert !result.empty?
240 assert_equal((Issue.visible - Issue.watched_by(User.current)).sort_by(&:id).size, result.sort_by(&:id).size)
240 assert_equal((Issue.visible - Issue.watched_by(User.current)).sort_by(&:id).size, result.sort_by(&:id).size)
241 User.current = nil
241 User.current = nil
242 end
242 end
243
243
244 def test_statement_should_be_nil_with_no_filters
244 def test_statement_should_be_nil_with_no_filters
245 q = Query.new(:name => '_')
245 q = Query.new(:name => '_')
246 q.filters = {}
246 q.filters = {}
247
247
248 assert q.valid?
248 assert q.valid?
249 assert_nil q.statement
249 assert_nil q.statement
250 end
250 end
251
251
252 def test_default_columns
252 def test_default_columns
253 q = Query.new
253 q = Query.new
254 assert !q.columns.empty?
254 assert !q.columns.empty?
255 end
255 end
256
256
257 def test_set_column_names
257 def test_set_column_names
258 q = Query.new
258 q = Query.new
259 q.column_names = ['tracker', :subject, '', 'unknonw_column']
259 q.column_names = ['tracker', :subject, '', 'unknonw_column']
260 assert_equal [:tracker, :subject], q.columns.collect {|c| c.name}
260 assert_equal [:tracker, :subject], q.columns.collect {|c| c.name}
261 c = q.columns.first
261 c = q.columns.first
262 assert q.has_column?(c)
262 assert q.has_column?(c)
263 end
263 end
264
264
265 def test_groupable_columns_should_include_custom_fields
265 def test_groupable_columns_should_include_custom_fields
266 q = Query.new
266 q = Query.new
267 assert q.groupable_columns.detect {|c| c.is_a? QueryCustomFieldColumn}
267 assert q.groupable_columns.detect {|c| c.is_a? QueryCustomFieldColumn}
268 end
268 end
269
269
270 def test_grouped_with_valid_column
270 def test_grouped_with_valid_column
271 q = Query.new(:group_by => 'status')
271 q = Query.new(:group_by => 'status')
272 assert q.grouped?
272 assert q.grouped?
273 assert_not_nil q.group_by_column
273 assert_not_nil q.group_by_column
274 assert_equal :status, q.group_by_column.name
274 assert_equal :status, q.group_by_column.name
275 assert_not_nil q.group_by_statement
275 assert_not_nil q.group_by_statement
276 assert_equal 'status', q.group_by_statement
276 assert_equal 'status', q.group_by_statement
277 end
277 end
278
278
279 def test_grouped_with_invalid_column
279 def test_grouped_with_invalid_column
280 q = Query.new(:group_by => 'foo')
280 q = Query.new(:group_by => 'foo')
281 assert !q.grouped?
281 assert !q.grouped?
282 assert_nil q.group_by_column
282 assert_nil q.group_by_column
283 assert_nil q.group_by_statement
283 assert_nil q.group_by_statement
284 end
284 end
285
285
286 def test_default_sort
286 def test_default_sort
287 q = Query.new
287 q = Query.new
288 assert_equal [], q.sort_criteria
288 assert_equal [], q.sort_criteria
289 end
289 end
290
290
291 def test_set_sort_criteria_with_hash
291 def test_set_sort_criteria_with_hash
292 q = Query.new
292 q = Query.new
293 q.sort_criteria = {'0' => ['priority', 'desc'], '2' => ['tracker']}
293 q.sort_criteria = {'0' => ['priority', 'desc'], '2' => ['tracker']}
294 assert_equal [['priority', 'desc'], ['tracker', 'asc']], q.sort_criteria
294 assert_equal [['priority', 'desc'], ['tracker', 'asc']], q.sort_criteria
295 end
295 end
296
296
297 def test_set_sort_criteria_with_array
297 def test_set_sort_criteria_with_array
298 q = Query.new
298 q = Query.new
299 q.sort_criteria = [['priority', 'desc'], 'tracker']
299 q.sort_criteria = [['priority', 'desc'], 'tracker']
300 assert_equal [['priority', 'desc'], ['tracker', 'asc']], q.sort_criteria
300 assert_equal [['priority', 'desc'], ['tracker', 'asc']], q.sort_criteria
301 end
301 end
302
302
303 def test_create_query_with_sort
303 def test_create_query_with_sort
304 q = Query.new(:name => 'Sorted')
304 q = Query.new(:name => 'Sorted')
305 q.sort_criteria = [['priority', 'desc'], 'tracker']
305 q.sort_criteria = [['priority', 'desc'], 'tracker']
306 assert q.save
306 assert q.save
307 q.reload
307 q.reload
308 assert_equal [['priority', 'desc'], ['tracker', 'asc']], q.sort_criteria
308 assert_equal [['priority', 'desc'], ['tracker', 'asc']], q.sort_criteria
309 end
309 end
310
310
311 def test_sort_by_string_custom_field_asc
311 def test_sort_by_string_custom_field_asc
312 q = Query.new
312 q = Query.new
313 c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'string' }
313 c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'string' }
314 assert c
314 assert c
315 assert c.sortable
315 assert c.sortable
316 issues = Issue.find :all,
316 issues = Issue.find :all,
317 :include => [ :assigned_to, :status, :tracker, :project, :priority ],
317 :include => [ :assigned_to, :status, :tracker, :project, :priority ],
318 :conditions => q.statement,
318 :conditions => q.statement,
319 :order => "#{c.sortable} ASC"
319 :order => "#{c.sortable} ASC"
320 values = issues.collect {|i| i.custom_value_for(c.custom_field).to_s}
320 values = issues.collect {|i| i.custom_value_for(c.custom_field).to_s}
321 assert !values.empty?
321 assert !values.empty?
322 assert_equal values.sort, values
322 assert_equal values.sort, values
323 end
323 end
324
324
325 def test_sort_by_string_custom_field_desc
325 def test_sort_by_string_custom_field_desc
326 q = Query.new
326 q = Query.new
327 c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'string' }
327 c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'string' }
328 assert c
328 assert c
329 assert c.sortable
329 assert c.sortable
330 issues = Issue.find :all,
330 issues = Issue.find :all,
331 :include => [ :assigned_to, :status, :tracker, :project, :priority ],
331 :include => [ :assigned_to, :status, :tracker, :project, :priority ],
332 :conditions => q.statement,
332 :conditions => q.statement,
333 :order => "#{c.sortable} DESC"
333 :order => "#{c.sortable} DESC"
334 values = issues.collect {|i| i.custom_value_for(c.custom_field).to_s}
334 values = issues.collect {|i| i.custom_value_for(c.custom_field).to_s}
335 assert !values.empty?
335 assert !values.empty?
336 assert_equal values.sort.reverse, values
336 assert_equal values.sort.reverse, values
337 end
337 end
338
338
339 def test_sort_by_float_custom_field_asc
339 def test_sort_by_float_custom_field_asc
340 q = Query.new
340 q = Query.new
341 c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'float' }
341 c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'float' }
342 assert c
342 assert c
343 assert c.sortable
343 assert c.sortable
344 issues = Issue.find :all,
344 issues = Issue.find :all,
345 :include => [ :assigned_to, :status, :tracker, :project, :priority ],
345 :include => [ :assigned_to, :status, :tracker, :project, :priority ],
346 :conditions => q.statement,
346 :conditions => q.statement,
347 :order => "#{c.sortable} ASC"
347 :order => "#{c.sortable} ASC"
348 values = issues.collect {|i| begin; Kernel.Float(i.custom_value_for(c.custom_field).to_s); rescue; nil; end}.compact
348 values = issues.collect {|i| begin; Kernel.Float(i.custom_value_for(c.custom_field).to_s); rescue; nil; end}.compact
349 assert !values.empty?
349 assert !values.empty?
350 assert_equal values.sort, values
350 assert_equal values.sort, values
351 end
351 end
352
352
353 def test_invalid_query_should_raise_query_statement_invalid_error
353 def test_invalid_query_should_raise_query_statement_invalid_error
354 q = Query.new
354 q = Query.new
355 assert_raise Query::StatementInvalid do
355 assert_raise Query::StatementInvalid do
356 q.issues(:conditions => "foo = 1")
356 q.issues(:conditions => "foo = 1")
357 end
357 end
358 end
358 end
359
359
360 def test_issue_count_by_association_group
360 def test_issue_count_by_association_group
361 q = Query.new(:name => '_', :group_by => 'assigned_to')
361 q = Query.new(:name => '_', :group_by => 'assigned_to')
362 count_by_group = q.issue_count_by_group
362 count_by_group = q.issue_count_by_group
363 assert_kind_of Hash, count_by_group
363 assert_kind_of Hash, count_by_group
364 assert_equal %w(NilClass User), count_by_group.keys.collect {|k| k.class.name}.uniq.sort
364 assert_equal %w(NilClass User), count_by_group.keys.collect {|k| k.class.name}.uniq.sort
365 assert_equal %w(Fixnum), count_by_group.values.collect {|k| k.class.name}.uniq
365 assert_equal %w(Fixnum), count_by_group.values.collect {|k| k.class.name}.uniq
366 assert count_by_group.has_key?(User.find(3))
366 assert count_by_group.has_key?(User.find(3))
367 end
367 end
368
368
369 def test_issue_count_by_list_custom_field_group
369 def test_issue_count_by_list_custom_field_group
370 q = Query.new(:name => '_', :group_by => 'cf_1')
370 q = Query.new(:name => '_', :group_by => 'cf_1')
371 count_by_group = q.issue_count_by_group
371 count_by_group = q.issue_count_by_group
372 assert_kind_of Hash, count_by_group
372 assert_kind_of Hash, count_by_group
373 assert_equal %w(NilClass String), count_by_group.keys.collect {|k| k.class.name}.uniq.sort
373 assert_equal %w(NilClass String), count_by_group.keys.collect {|k| k.class.name}.uniq.sort
374 assert_equal %w(Fixnum), count_by_group.values.collect {|k| k.class.name}.uniq
374 assert_equal %w(Fixnum), count_by_group.values.collect {|k| k.class.name}.uniq
375 assert count_by_group.has_key?('MySQL')
375 assert count_by_group.has_key?('MySQL')
376 end
376 end
377
377
378 def test_issue_count_by_date_custom_field_group
378 def test_issue_count_by_date_custom_field_group
379 q = Query.new(:name => '_', :group_by => 'cf_8')
379 q = Query.new(:name => '_', :group_by => 'cf_8')
380 count_by_group = q.issue_count_by_group
380 count_by_group = q.issue_count_by_group
381 assert_kind_of Hash, count_by_group
381 assert_kind_of Hash, count_by_group
382 assert_equal %w(Date NilClass), count_by_group.keys.collect {|k| k.class.name}.uniq.sort
382 assert_equal %w(Date NilClass), count_by_group.keys.collect {|k| k.class.name}.uniq.sort
383 assert_equal %w(Fixnum), count_by_group.values.collect {|k| k.class.name}.uniq
383 assert_equal %w(Fixnum), count_by_group.values.collect {|k| k.class.name}.uniq
384 end
384 end
385
385
386 def test_label_for
386 def test_label_for
387 q = Query.new
387 q = Query.new
388 assert_equal 'assigned_to', q.label_for('assigned_to_id')
388 assert_equal 'assigned_to', q.label_for('assigned_to_id')
389 end
389 end
390
390
391 def test_editable_by
391 def test_editable_by
392 admin = User.find(1)
392 admin = User.find(1)
393 manager = User.find(2)
393 manager = User.find(2)
394 developer = User.find(3)
394 developer = User.find(3)
395
395
396 # Public query on project 1
396 # Public query on project 1
397 q = Query.find(1)
397 q = Query.find(1)
398 assert q.editable_by?(admin)
398 assert q.editable_by?(admin)
399 assert q.editable_by?(manager)
399 assert q.editable_by?(manager)
400 assert !q.editable_by?(developer)
400 assert !q.editable_by?(developer)
401
401
402 # Private query on project 1
402 # Private query on project 1
403 q = Query.find(2)
403 q = Query.find(2)
404 assert q.editable_by?(admin)
404 assert q.editable_by?(admin)
405 assert !q.editable_by?(manager)
405 assert !q.editable_by?(manager)
406 assert q.editable_by?(developer)
406 assert q.editable_by?(developer)
407
407
408 # Private query for all projects
408 # Private query for all projects
409 q = Query.find(3)
409 q = Query.find(3)
410 assert q.editable_by?(admin)
410 assert q.editable_by?(admin)
411 assert !q.editable_by?(manager)
411 assert !q.editable_by?(manager)
412 assert q.editable_by?(developer)
412 assert q.editable_by?(developer)
413
413
414 # Public query for all projects
414 # Public query for all projects
415 q = Query.find(4)
415 q = Query.find(4)
416 assert q.editable_by?(admin)
416 assert q.editable_by?(admin)
417 assert !q.editable_by?(manager)
417 assert !q.editable_by?(manager)
418 assert !q.editable_by?(developer)
418 assert !q.editable_by?(developer)
419 end
419 end
420
420
421 context "#available_filters" do
421 context "#available_filters" do
422 setup do
422 setup do
423 @query = Query.new(:name => "_")
423 @query = Query.new(:name => "_")
424 end
424 end
425
425
426 should "include users of visible projects in cross-project view" do
426 should "include users of visible projects in cross-project view" do
427 users = @query.available_filters["assigned_to_id"]
427 users = @query.available_filters["assigned_to_id"]
428 assert_not_nil users
428 assert_not_nil users
429 assert users[:values].map{|u|u[1]}.include?("3")
429 assert users[:values].map{|u|u[1]}.include?("3")
430 end
430 end
431
431
432 should "include visible projects in cross-project view" do
432 should "include visible projects in cross-project view" do
433 projects = @query.available_filters["project_id"]
433 projects = @query.available_filters["project_id"]
434 assert_not_nil projects
434 assert_not_nil projects
435 assert projects[:values].map{|u|u[1]}.include?("1")
435 assert projects[:values].map{|u|u[1]}.include?("1")
436 end
436 end
437
437
438 context "'member_of_group' filter" do
438 context "'member_of_group' filter" do
439 should "be present" do
439 should "be present" do
440 assert @query.available_filters.keys.include?("member_of_group")
440 assert @query.available_filters.keys.include?("member_of_group")
441 end
441 end
442
442
443 should "be an optional list" do
443 should "be an optional list" do
444 assert_equal :list_optional, @query.available_filters["member_of_group"][:type]
444 assert_equal :list_optional, @query.available_filters["member_of_group"][:type]
445 end
445 end
446
446
447 should "have a list of the groups as values" do
447 should "have a list of the groups as values" do
448 Group.destroy_all # No fixtures
448 Group.destroy_all # No fixtures
449 group1 = Group.generate!.reload
449 group1 = Group.generate!.reload
450 group2 = Group.generate!.reload
450 group2 = Group.generate!.reload
451
451
452 expected_group_list = [
452 expected_group_list = [
453 [group1.name, group1.id.to_s],
453 [group1.name, group1.id.to_s],
454 [group2.name, group2.id.to_s]
454 [group2.name, group2.id.to_s]
455 ]
455 ]
456 assert_equal expected_group_list.sort, @query.available_filters["member_of_group"][:values].sort
456 assert_equal expected_group_list.sort, @query.available_filters["member_of_group"][:values].sort
457 end
457 end
458
458
459 end
459 end
460
460
461 context "'assigned_to_role' filter" do
461 context "'assigned_to_role' filter" do
462 should "be present" do
462 should "be present" do
463 assert @query.available_filters.keys.include?("assigned_to_role")
463 assert @query.available_filters.keys.include?("assigned_to_role")
464 end
464 end
465
465
466 should "be an optional list" do
466 should "be an optional list" do
467 assert_equal :list_optional, @query.available_filters["assigned_to_role"][:type]
467 assert_equal :list_optional, @query.available_filters["assigned_to_role"][:type]
468 end
468 end
469
469
470 should "have a list of the Roles as values" do
470 should "have a list of the Roles as values" do
471 assert @query.available_filters["assigned_to_role"][:values].include?(['Manager','1'])
471 assert @query.available_filters["assigned_to_role"][:values].include?(['Manager','1'])
472 assert @query.available_filters["assigned_to_role"][:values].include?(['Developer','2'])
472 assert @query.available_filters["assigned_to_role"][:values].include?(['Developer','2'])
473 assert @query.available_filters["assigned_to_role"][:values].include?(['Reporter','3'])
473 assert @query.available_filters["assigned_to_role"][:values].include?(['Reporter','3'])
474 end
474 end
475
475
476 should "not include the built in Roles as values" do
476 should "not include the built in Roles as values" do
477 assert ! @query.available_filters["assigned_to_role"][:values].include?(['Non member','4'])
477 assert ! @query.available_filters["assigned_to_role"][:values].include?(['Non member','4'])
478 assert ! @query.available_filters["assigned_to_role"][:values].include?(['Anonymous','5'])
478 assert ! @query.available_filters["assigned_to_role"][:values].include?(['Anonymous','5'])
479 end
479 end
480
480
481 end
481 end
482
482
483 end
483 end
484
484
485 context "#statement" do
485 context "#statement" do
486 context "with 'member_of_group' filter" do
486 context "with 'member_of_group' filter" do
487 setup do
487 setup do
488 Group.destroy_all # No fixtures
488 Group.destroy_all # No fixtures
489 @user_in_group = User.generate!
489 @user_in_group = User.generate!
490 @second_user_in_group = User.generate!
490 @second_user_in_group = User.generate!
491 @user_in_group2 = User.generate!
491 @user_in_group2 = User.generate!
492 @user_not_in_group = User.generate!
492 @user_not_in_group = User.generate!
493
493
494 @group = Group.generate!.reload
494 @group = Group.generate!.reload
495 @group.users << @user_in_group
495 @group.users << @user_in_group
496 @group.users << @second_user_in_group
496 @group.users << @second_user_in_group
497
497
498 @group2 = Group.generate!.reload
498 @group2 = Group.generate!.reload
499 @group2.users << @user_in_group2
499 @group2.users << @user_in_group2
500
500
501 end
501 end
502
502
503 should "search assigned to for users in the group" do
503 should "search assigned to for users in the group" do
504 @query = Query.new(:name => '_')
504 @query = Query.new(:name => '_')
505 @query.add_filter('member_of_group', '=', [@group.id.to_s])
505 @query.add_filter('member_of_group', '=', [@group.id.to_s])
506
506
507 assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IN ('#{@user_in_group.id}','#{@second_user_in_group.id}')"
507 assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IN ('#{@user_in_group.id}','#{@second_user_in_group.id}')"
508 assert_find_issues_with_query_is_successful @query
508 assert_find_issues_with_query_is_successful @query
509 end
509 end
510
510
511 should "search not assigned to any group member (none)" do
511 should "search not assigned to any group member (none)" do
512 @query = Query.new(:name => '_')
512 @query = Query.new(:name => '_')
513 @query.add_filter('member_of_group', '!*', [''])
513 @query.add_filter('member_of_group', '!*', [''])
514
514
515 # Users not in a group
515 # Users not in a group
516 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}')"
516 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}')"
517 assert_find_issues_with_query_is_successful @query
517 assert_find_issues_with_query_is_successful @query
518 end
518 end
519
519
520 should "search assigned to any group member (all)" do
520 should "search assigned to any group member (all)" do
521 @query = Query.new(:name => '_')
521 @query = Query.new(:name => '_')
522 @query.add_filter('member_of_group', '*', [''])
522 @query.add_filter('member_of_group', '*', [''])
523
523
524 # Only users in a group
524 # Only users in a group
525 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}')"
525 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}')"
526 assert_find_issues_with_query_is_successful @query
526 assert_find_issues_with_query_is_successful @query
527 end
527 end
528
528
529 should "return an empty set with = empty group" do
529 should "return an empty set with = empty group" do
530 @empty_group = Group.generate!
530 @empty_group = Group.generate!
531 @query = Query.new(:name => '_')
531 @query = Query.new(:name => '_')
532 @query.add_filter('member_of_group', '=', [@empty_group.id.to_s])
532 @query.add_filter('member_of_group', '=', [@empty_group.id.to_s])
533
533
534 assert_equal [], find_issues_with_query(@query)
534 assert_equal [], find_issues_with_query(@query)
535 end
535 end
536
536
537 should "return issues with ! empty group" do
537 should "return issues with ! empty group" do
538 @empty_group = Group.generate!
538 @empty_group = Group.generate!
539 @query = Query.new(:name => '_')
539 @query = Query.new(:name => '_')
540 @query.add_filter('member_of_group', '!', [@empty_group.id.to_s])
540 @query.add_filter('member_of_group', '!', [@empty_group.id.to_s])
541
541
542 assert_find_issues_with_query_is_successful @query
542 assert_find_issues_with_query_is_successful @query
543 end
543 end
544 end
544 end
545
545
546 context "with 'assigned_to_role' filter" do
546 context "with 'assigned_to_role' filter" do
547 setup do
547 setup do
548 # No fixtures
548 # No fixtures
549 MemberRole.delete_all
549 MemberRole.delete_all
550 Member.delete_all
550 Member.delete_all
551 Role.delete_all
551 Role.delete_all
552
552
553 @manager_role = Role.generate!(:name => 'Manager')
553 @manager_role = Role.generate!(:name => 'Manager')
554 @developer_role = Role.generate!(:name => 'Developer')
554 @developer_role = Role.generate!(:name => 'Developer')
555
555
556 @project = Project.generate!
556 @project = Project.generate!
557 @manager = User.generate!
557 @manager = User.generate!
558 @developer = User.generate!
558 @developer = User.generate!
559 @boss = User.generate!
559 @boss = User.generate!
560 User.add_to_project(@manager, @project, @manager_role)
560 User.add_to_project(@manager, @project, @manager_role)
561 User.add_to_project(@developer, @project, @developer_role)
561 User.add_to_project(@developer, @project, @developer_role)
562 User.add_to_project(@boss, @project, [@manager_role, @developer_role])
562 User.add_to_project(@boss, @project, [@manager_role, @developer_role])
563 end
563 end
564
564
565 should "search assigned to for users with the Role" do
565 should "search assigned to for users with the Role" do
566 @query = Query.new(:name => '_')
566 @query = Query.new(:name => '_')
567 @query.add_filter('assigned_to_role', '=', [@manager_role.id.to_s])
567 @query.add_filter('assigned_to_role', '=', [@manager_role.id.to_s])
568
568
569 assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IN ('#{@manager.id}','#{@boss.id}')"
569 assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IN ('#{@manager.id}','#{@boss.id}')"
570 assert_find_issues_with_query_is_successful @query
570 assert_find_issues_with_query_is_successful @query
571 end
571 end
572
572
573 should "search assigned to for users not assigned to any Role (none)" do
573 should "search assigned to for users not assigned to any Role (none)" do
574 @query = Query.new(:name => '_')
574 @query = Query.new(:name => '_')
575 @query.add_filter('assigned_to_role', '!*', [''])
575 @query.add_filter('assigned_to_role', '!*', [''])
576
576
577 assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IS NULL OR #{Issue.table_name}.assigned_to_id NOT IN ('#{@manager.id}','#{@developer.id}','#{@boss.id}')"
577 assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IS NULL OR #{Issue.table_name}.assigned_to_id NOT IN ('#{@manager.id}','#{@developer.id}','#{@boss.id}')"
578 assert_find_issues_with_query_is_successful @query
578 assert_find_issues_with_query_is_successful @query
579 end
579 end
580
580
581 should "search assigned to for users assigned to any Role (all)" do
581 should "search assigned to for users assigned to any Role (all)" do
582 @query = Query.new(:name => '_')
582 @query = Query.new(:name => '_')
583 @query.add_filter('assigned_to_role', '*', [''])
583 @query.add_filter('assigned_to_role', '*', [''])
584
584
585 assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IN ('#{@manager.id}','#{@developer.id}','#{@boss.id}')"
585 assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IN ('#{@manager.id}','#{@developer.id}','#{@boss.id}')"
586 assert_find_issues_with_query_is_successful @query
586 assert_find_issues_with_query_is_successful @query
587 end
587 end
588
588
589 should "return an empty set with empty role" do
589 should "return an empty set with empty role" do
590 @empty_role = Role.generate!
590 @empty_role = Role.generate!
591 @query = Query.new(:name => '_')
591 @query = Query.new(:name => '_')
592 @query.add_filter('assigned_to_role', '=', [@empty_role.id.to_s])
592 @query.add_filter('assigned_to_role', '=', [@empty_role.id.to_s])
593
593
594 assert_equal [], find_issues_with_query(@query)
594 assert_equal [], find_issues_with_query(@query)
595 end
595 end
596
596
597 should "return issues with ! empty role" do
597 should "return issues with ! empty role" do
598 @empty_role = Role.generate!
598 @empty_role = Role.generate!
599 @query = Query.new(:name => '_')
599 @query = Query.new(:name => '_')
600 @query.add_filter('member_of_group', '!', [@empty_role.id.to_s])
600 @query.add_filter('member_of_group', '!', [@empty_role.id.to_s])
601
601
602 assert_find_issues_with_query_is_successful @query
602 assert_find_issues_with_query_is_successful @query
603 end
603 end
604 end
604 end
605 end
605 end
606
606
607 end
607 end
General Comments 0
You need to be logged in to leave comments. Login now