##// END OF EJS Templates
Fixed wrong assertion....
Jean-Philippe Lang -
r8520:08bb5e0c0ac0
parent child
Show More
@@ -1,898 +1,898
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,
21 fixtures :projects, :enabled_modules, :users, :members,
22 :member_roles, :roles, :trackers, :issue_statuses,
22 :member_roles, :roles, :trackers, :issue_statuses,
23 :issue_categories, :enumerations, :issues,
23 :issue_categories, :enumerations, :issues,
24 :watchers, :custom_fields, :custom_values, :versions,
24 :watchers, :custom_fields, :custom_values, :versions,
25 :queries,
25 :queries,
26 :projects_trackers
26 :projects_trackers
27
27
28 def test_custom_fields_for_all_projects_should_be_available_in_global_queries
28 def test_custom_fields_for_all_projects_should_be_available_in_global_queries
29 query = Query.new(:project => nil, :name => '_')
29 query = Query.new(:project => nil, :name => '_')
30 assert query.available_filters.has_key?('cf_1')
30 assert query.available_filters.has_key?('cf_1')
31 assert !query.available_filters.has_key?('cf_3')
31 assert !query.available_filters.has_key?('cf_3')
32 end
32 end
33
33
34 def test_system_shared_versions_should_be_available_in_global_queries
34 def test_system_shared_versions_should_be_available_in_global_queries
35 Version.find(2).update_attribute :sharing, 'system'
35 Version.find(2).update_attribute :sharing, 'system'
36 query = Query.new(:project => nil, :name => '_')
36 query = Query.new(:project => nil, :name => '_')
37 assert query.available_filters.has_key?('fixed_version_id')
37 assert query.available_filters.has_key?('fixed_version_id')
38 assert query.available_filters['fixed_version_id'][:values].detect {|v| v.last == '2'}
38 assert query.available_filters['fixed_version_id'][:values].detect {|v| v.last == '2'}
39 end
39 end
40
40
41 def test_project_filter_in_global_queries
41 def test_project_filter_in_global_queries
42 query = Query.new(:project => nil, :name => '_')
42 query = Query.new(:project => nil, :name => '_')
43 project_filter = query.available_filters["project_id"]
43 project_filter = query.available_filters["project_id"]
44 assert_not_nil project_filter
44 assert_not_nil project_filter
45 project_ids = project_filter[:values].map{|p| p[1]}
45 project_ids = project_filter[:values].map{|p| p[1]}
46 assert project_ids.include?("1") #public project
46 assert project_ids.include?("1") #public project
47 assert !project_ids.include?("2") #private project user cannot see
47 assert !project_ids.include?("2") #private project user cannot see
48 end
48 end
49
49
50 def find_issues_with_query(query)
50 def find_issues_with_query(query)
51 Issue.find :all,
51 Issue.find :all,
52 :include => [ :assigned_to, :status, :tracker, :project, :priority ],
52 :include => [ :assigned_to, :status, :tracker, :project, :priority ],
53 :conditions => query.statement
53 :conditions => query.statement
54 end
54 end
55
55
56 def assert_find_issues_with_query_is_successful(query)
56 def assert_find_issues_with_query_is_successful(query)
57 assert_nothing_raised do
57 assert_nothing_raised do
58 find_issues_with_query(query)
58 find_issues_with_query(query)
59 end
59 end
60 end
60 end
61
61
62 def assert_query_statement_includes(query, condition)
62 def assert_query_statement_includes(query, condition)
63 assert query.statement.include?(condition), "Query statement condition not found in: #{query.statement}"
63 assert query.statement.include?(condition), "Query statement condition not found in: #{query.statement}"
64 end
64 end
65
65
66 def assert_query_result(expected, query)
66 def assert_query_result(expected, query)
67 assert_nothing_raised do
67 assert_nothing_raised do
68 assert_equal expected.map(&:id).sort, query.issues.map(&:id).sort
68 assert_equal expected.map(&:id).sort, query.issues.map(&:id).sort
69 assert_equal expected.size, query.issue_count
69 assert_equal expected.size, query.issue_count
70 end
70 end
71 end
71 end
72
72
73 def test_query_should_allow_shared_versions_for_a_project_query
73 def test_query_should_allow_shared_versions_for_a_project_query
74 subproject_version = Version.find(4)
74 subproject_version = Version.find(4)
75 query = Query.new(:project => Project.find(1), :name => '_')
75 query = Query.new(:project => Project.find(1), :name => '_')
76 query.add_filter('fixed_version_id', '=', [subproject_version.id.to_s])
76 query.add_filter('fixed_version_id', '=', [subproject_version.id.to_s])
77
77
78 assert query.statement.include?("#{Issue.table_name}.fixed_version_id IN ('4')")
78 assert query.statement.include?("#{Issue.table_name}.fixed_version_id IN ('4')")
79 end
79 end
80
80
81 def test_query_with_multiple_custom_fields
81 def test_query_with_multiple_custom_fields
82 query = Query.find(1)
82 query = Query.find(1)
83 assert query.valid?
83 assert query.valid?
84 assert query.statement.include?("#{CustomValue.table_name}.value IN ('MySQL')")
84 assert query.statement.include?("#{CustomValue.table_name}.value IN ('MySQL')")
85 issues = find_issues_with_query(query)
85 issues = find_issues_with_query(query)
86 assert_equal 1, issues.length
86 assert_equal 1, issues.length
87 assert_equal Issue.find(3), issues.first
87 assert_equal Issue.find(3), issues.first
88 end
88 end
89
89
90 def test_operator_none
90 def test_operator_none
91 query = Query.new(:project => Project.find(1), :name => '_')
91 query = Query.new(:project => Project.find(1), :name => '_')
92 query.add_filter('fixed_version_id', '!*', [''])
92 query.add_filter('fixed_version_id', '!*', [''])
93 query.add_filter('cf_1', '!*', [''])
93 query.add_filter('cf_1', '!*', [''])
94 assert query.statement.include?("#{Issue.table_name}.fixed_version_id IS NULL")
94 assert query.statement.include?("#{Issue.table_name}.fixed_version_id IS NULL")
95 assert query.statement.include?("#{CustomValue.table_name}.value IS NULL OR #{CustomValue.table_name}.value = ''")
95 assert query.statement.include?("#{CustomValue.table_name}.value IS NULL OR #{CustomValue.table_name}.value = ''")
96 find_issues_with_query(query)
96 find_issues_with_query(query)
97 end
97 end
98
98
99 def test_operator_none_for_integer
99 def test_operator_none_for_integer
100 query = Query.new(:project => Project.find(1), :name => '_')
100 query = Query.new(:project => Project.find(1), :name => '_')
101 query.add_filter('estimated_hours', '!*', [''])
101 query.add_filter('estimated_hours', '!*', [''])
102 issues = find_issues_with_query(query)
102 issues = find_issues_with_query(query)
103 assert !issues.empty?
103 assert !issues.empty?
104 assert issues.all? {|i| !i.estimated_hours}
104 assert issues.all? {|i| !i.estimated_hours}
105 end
105 end
106
106
107 def test_operator_none_for_date
107 def test_operator_none_for_date
108 query = Query.new(:project => Project.find(1), :name => '_')
108 query = Query.new(:project => Project.find(1), :name => '_')
109 query.add_filter('start_date', '!*', [''])
109 query.add_filter('start_date', '!*', [''])
110 issues = find_issues_with_query(query)
110 issues = find_issues_with_query(query)
111 assert !issues.empty?
111 assert !issues.empty?
112 assert issues.all? {|i| i.start_date.nil?}
112 assert issues.all? {|i| i.start_date.nil?}
113 end
113 end
114
114
115 def test_operator_all
115 def test_operator_all
116 query = Query.new(:project => Project.find(1), :name => '_')
116 query = Query.new(:project => Project.find(1), :name => '_')
117 query.add_filter('fixed_version_id', '*', [''])
117 query.add_filter('fixed_version_id', '*', [''])
118 query.add_filter('cf_1', '*', [''])
118 query.add_filter('cf_1', '*', [''])
119 assert query.statement.include?("#{Issue.table_name}.fixed_version_id IS NOT NULL")
119 assert query.statement.include?("#{Issue.table_name}.fixed_version_id IS NOT NULL")
120 assert query.statement.include?("#{CustomValue.table_name}.value IS NOT NULL AND #{CustomValue.table_name}.value <> ''")
120 assert query.statement.include?("#{CustomValue.table_name}.value IS NOT NULL AND #{CustomValue.table_name}.value <> ''")
121 find_issues_with_query(query)
121 find_issues_with_query(query)
122 end
122 end
123
123
124 def test_operator_all_for_date
124 def test_operator_all_for_date
125 query = Query.new(:project => Project.find(1), :name => '_')
125 query = Query.new(:project => Project.find(1), :name => '_')
126 query.add_filter('start_date', '*', [''])
126 query.add_filter('start_date', '*', [''])
127 issues = find_issues_with_query(query)
127 issues = find_issues_with_query(query)
128 assert !issues.empty?
128 assert !issues.empty?
129 assert issues.all? {|i| i.start_date.present?}
129 assert issues.all? {|i| i.start_date.present?}
130 end
130 end
131
131
132 def test_numeric_filter_should_not_accept_non_numeric_values
132 def test_numeric_filter_should_not_accept_non_numeric_values
133 query = Query.new(:name => '_')
133 query = Query.new(:name => '_')
134 query.add_filter('estimated_hours', '=', ['a'])
134 query.add_filter('estimated_hours', '=', ['a'])
135
135
136 assert query.has_filter?('estimated_hours')
136 assert query.has_filter?('estimated_hours')
137 assert !query.valid?
137 assert !query.valid?
138 end
138 end
139
139
140 def test_operator_is_on_float
140 def test_operator_is_on_float
141 Issue.update_all("estimated_hours = 171.2", "id=2")
141 Issue.update_all("estimated_hours = 171.2", "id=2")
142
142
143 query = Query.new(:name => '_')
143 query = Query.new(:name => '_')
144 query.add_filter('estimated_hours', '=', ['171.20'])
144 query.add_filter('estimated_hours', '=', ['171.20'])
145 issues = find_issues_with_query(query)
145 issues = find_issues_with_query(query)
146 assert_equal 1, issues.size
146 assert_equal 1, issues.size
147 assert_equal 2, issues.first.id
147 assert_equal 2, issues.first.id
148 end
148 end
149
149
150 def test_operator_is_on_integer_custom_field
150 def test_operator_is_on_integer_custom_field
151 f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_for_all => true, :is_filter => true)
151 f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_for_all => true, :is_filter => true)
152 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => '7')
152 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => '7')
153 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '12')
153 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '12')
154 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
154 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
155
155
156 query = Query.new(:name => '_')
156 query = Query.new(:name => '_')
157 query.add_filter("cf_#{f.id}", '=', ['12'])
157 query.add_filter("cf_#{f.id}", '=', ['12'])
158 issues = find_issues_with_query(query)
158 issues = find_issues_with_query(query)
159 assert_equal 1, issues.size
159 assert_equal 1, issues.size
160 assert_equal 2, issues.first.id
160 assert_equal 2, issues.first.id
161 end
161 end
162
162
163 def test_operator_is_on_float_custom_field
163 def test_operator_is_on_float_custom_field
164 f = IssueCustomField.create!(:name => 'filter', :field_format => 'float', :is_filter => true, :is_for_all => true)
164 f = IssueCustomField.create!(:name => 'filter', :field_format => 'float', :is_filter => true, :is_for_all => true)
165 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => '7.3')
165 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => '7.3')
166 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '12.7')
166 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '12.7')
167 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
167 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
168
168
169 query = Query.new(:name => '_')
169 query = Query.new(:name => '_')
170 query.add_filter("cf_#{f.id}", '=', ['12.7'])
170 query.add_filter("cf_#{f.id}", '=', ['12.7'])
171 issues = find_issues_with_query(query)
171 issues = find_issues_with_query(query)
172 assert_equal 1, issues.size
172 assert_equal 1, issues.size
173 assert_equal 2, issues.first.id
173 assert_equal 2, issues.first.id
174 end
174 end
175
175
176 def test_operator_greater_than
176 def test_operator_greater_than
177 query = Query.new(:project => Project.find(1), :name => '_')
177 query = Query.new(:project => Project.find(1), :name => '_')
178 query.add_filter('done_ratio', '>=', ['40'])
178 query.add_filter('done_ratio', '>=', ['40'])
179 assert query.statement.include?("#{Issue.table_name}.done_ratio >= 40.0")
179 assert query.statement.include?("#{Issue.table_name}.done_ratio >= 40.0")
180 find_issues_with_query(query)
180 find_issues_with_query(query)
181 end
181 end
182
182
183 def test_operator_greater_than_a_float
183 def test_operator_greater_than_a_float
184 query = Query.new(:project => Project.find(1), :name => '_')
184 query = Query.new(:project => Project.find(1), :name => '_')
185 query.add_filter('estimated_hours', '>=', ['40.5'])
185 query.add_filter('estimated_hours', '>=', ['40.5'])
186 assert query.statement.include?("#{Issue.table_name}.estimated_hours >= 40.5")
186 assert query.statement.include?("#{Issue.table_name}.estimated_hours >= 40.5")
187 find_issues_with_query(query)
187 find_issues_with_query(query)
188 end
188 end
189
189
190 def test_operator_greater_than_on_int_custom_field
190 def test_operator_greater_than_on_int_custom_field
191 f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_filter => true, :is_for_all => true)
191 f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_filter => true, :is_for_all => true)
192 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => '7')
192 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => '7')
193 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '12')
193 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '12')
194 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
194 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
195
195
196 query = Query.new(:project => Project.find(1), :name => '_')
196 query = Query.new(:project => Project.find(1), :name => '_')
197 query.add_filter("cf_#{f.id}", '>=', ['8'])
197 query.add_filter("cf_#{f.id}", '>=', ['8'])
198 issues = find_issues_with_query(query)
198 issues = find_issues_with_query(query)
199 assert_equal 1, issues.size
199 assert_equal 1, issues.size
200 assert_equal 2, issues.first.id
200 assert_equal 2, issues.first.id
201 end
201 end
202
202
203 def test_operator_lesser_than
203 def test_operator_lesser_than
204 query = Query.new(:project => Project.find(1), :name => '_')
204 query = Query.new(:project => Project.find(1), :name => '_')
205 query.add_filter('done_ratio', '<=', ['30'])
205 query.add_filter('done_ratio', '<=', ['30'])
206 assert query.statement.include?("#{Issue.table_name}.done_ratio <= 30.0")
206 assert query.statement.include?("#{Issue.table_name}.done_ratio <= 30.0")
207 find_issues_with_query(query)
207 find_issues_with_query(query)
208 end
208 end
209
209
210 def test_operator_lesser_than_on_custom_field
210 def test_operator_lesser_than_on_custom_field
211 f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_filter => true, :is_for_all => true)
211 f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_filter => true, :is_for_all => true)
212 query = Query.new(:project => Project.find(1), :name => '_')
212 query = Query.new(:project => Project.find(1), :name => '_')
213 query.add_filter("cf_#{f.id}", '<=', ['30'])
213 query.add_filter("cf_#{f.id}", '<=', ['30'])
214 assert query.statement.include?("CAST(custom_values.value AS decimal(60,3)) <= 30.0")
214 assert query.statement.include?("CAST(custom_values.value AS decimal(60,3)) <= 30.0")
215 find_issues_with_query(query)
215 find_issues_with_query(query)
216 end
216 end
217
217
218 def test_operator_between
218 def test_operator_between
219 query = Query.new(:project => Project.find(1), :name => '_')
219 query = Query.new(:project => Project.find(1), :name => '_')
220 query.add_filter('done_ratio', '><', ['30', '40'])
220 query.add_filter('done_ratio', '><', ['30', '40'])
221 assert_include "#{Issue.table_name}.done_ratio BETWEEN 30.0 AND 40.0", query.statement
221 assert_include "#{Issue.table_name}.done_ratio BETWEEN 30.0 AND 40.0", query.statement
222 find_issues_with_query(query)
222 find_issues_with_query(query)
223 end
223 end
224
224
225 def test_operator_between_on_custom_field
225 def test_operator_between_on_custom_field
226 f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_filter => true, :is_for_all => true)
226 f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_filter => true, :is_for_all => true)
227 query = Query.new(:project => Project.find(1), :name => '_')
227 query = Query.new(:project => Project.find(1), :name => '_')
228 query.add_filter("cf_#{f.id}", '><', ['30', '40'])
228 query.add_filter("cf_#{f.id}", '><', ['30', '40'])
229 assert_include "CAST(custom_values.value AS decimal(60,3)) BETWEEN 30.0 AND 40.0", query.statement
229 assert_include "CAST(custom_values.value AS decimal(60,3)) BETWEEN 30.0 AND 40.0", query.statement
230 find_issues_with_query(query)
230 find_issues_with_query(query)
231 end
231 end
232
232
233 def test_date_filter_should_not_accept_non_date_values
233 def test_date_filter_should_not_accept_non_date_values
234 query = Query.new(:name => '_')
234 query = Query.new(:name => '_')
235 query.add_filter('created_on', '=', ['a'])
235 query.add_filter('created_on', '=', ['a'])
236
236
237 assert query.has_filter?('created_on')
237 assert query.has_filter?('created_on')
238 assert !query.valid?
238 assert !query.valid?
239 end
239 end
240
240
241 def test_date_filter_should_not_accept_invalid_date_values
241 def test_date_filter_should_not_accept_invalid_date_values
242 query = Query.new(:name => '_')
242 query = Query.new(:name => '_')
243 query.add_filter('created_on', '=', ['2011-01-34'])
243 query.add_filter('created_on', '=', ['2011-01-34'])
244
244
245 assert query.has_filter?('created_on')
245 assert query.has_filter?('created_on')
246 assert !query.valid?
246 assert !query.valid?
247 end
247 end
248
248
249 def test_relative_date_filter_should_not_accept_non_integer_values
249 def test_relative_date_filter_should_not_accept_non_integer_values
250 query = Query.new(:name => '_')
250 query = Query.new(:name => '_')
251 query.add_filter('created_on', '>t-', ['a'])
251 query.add_filter('created_on', '>t-', ['a'])
252
252
253 assert query.has_filter?('created_on')
253 assert query.has_filter?('created_on')
254 assert !query.valid?
254 assert !query.valid?
255 end
255 end
256
256
257 def test_operator_date_equals
257 def test_operator_date_equals
258 query = Query.new(:name => '_')
258 query = Query.new(:name => '_')
259 query.add_filter('due_date', '=', ['2011-07-10'])
259 query.add_filter('due_date', '=', ['2011-07-10'])
260 assert_match /issues\.due_date > '2011-07-09 23:59:59(\.9+)?' AND issues\.due_date <= '2011-07-10 23:59:59(\.9+)?/, query.statement
260 assert_match /issues\.due_date > '2011-07-09 23:59:59(\.9+)?' AND issues\.due_date <= '2011-07-10 23:59:59(\.9+)?/, query.statement
261 find_issues_with_query(query)
261 find_issues_with_query(query)
262 end
262 end
263
263
264 def test_operator_date_lesser_than
264 def test_operator_date_lesser_than
265 query = Query.new(:name => '_')
265 query = Query.new(:name => '_')
266 query.add_filter('due_date', '<=', ['2011-07-10'])
266 query.add_filter('due_date', '<=', ['2011-07-10'])
267 assert_match /issues\.due_date <= '2011-07-10 23:59:59(\.9+)?/, query.statement
267 assert_match /issues\.due_date <= '2011-07-10 23:59:59(\.9+)?/, query.statement
268 find_issues_with_query(query)
268 find_issues_with_query(query)
269 end
269 end
270
270
271 def test_operator_date_greater_than
271 def test_operator_date_greater_than
272 query = Query.new(:name => '_')
272 query = Query.new(:name => '_')
273 query.add_filter('due_date', '>=', ['2011-07-10'])
273 query.add_filter('due_date', '>=', ['2011-07-10'])
274 assert_match /issues\.due_date > '2011-07-09 23:59:59(\.9+)?'/, query.statement
274 assert_match /issues\.due_date > '2011-07-09 23:59:59(\.9+)?'/, query.statement
275 find_issues_with_query(query)
275 find_issues_with_query(query)
276 end
276 end
277
277
278 def test_operator_date_between
278 def test_operator_date_between
279 query = Query.new(:name => '_')
279 query = Query.new(:name => '_')
280 query.add_filter('due_date', '><', ['2011-06-23', '2011-07-10'])
280 query.add_filter('due_date', '><', ['2011-06-23', '2011-07-10'])
281 assert_match /issues\.due_date > '2011-06-22 23:59:59(\.9+)?' AND issues\.due_date <= '2011-07-10 23:59:59(\.9+)?/, query.statement
281 assert_match /issues\.due_date > '2011-06-22 23:59:59(\.9+)?' AND issues\.due_date <= '2011-07-10 23:59:59(\.9+)?/, query.statement
282 find_issues_with_query(query)
282 find_issues_with_query(query)
283 end
283 end
284
284
285 def test_operator_in_more_than
285 def test_operator_in_more_than
286 Issue.find(7).update_attribute(:due_date, (Date.today + 15))
286 Issue.find(7).update_attribute(:due_date, (Date.today + 15))
287 query = Query.new(:project => Project.find(1), :name => '_')
287 query = Query.new(:project => Project.find(1), :name => '_')
288 query.add_filter('due_date', '>t+', ['15'])
288 query.add_filter('due_date', '>t+', ['15'])
289 issues = find_issues_with_query(query)
289 issues = find_issues_with_query(query)
290 assert !issues.empty?
290 assert !issues.empty?
291 issues.each {|issue| assert(issue.due_date >= (Date.today + 15))}
291 issues.each {|issue| assert(issue.due_date >= (Date.today + 15))}
292 end
292 end
293
293
294 def test_operator_in_less_than
294 def test_operator_in_less_than
295 query = Query.new(:project => Project.find(1), :name => '_')
295 query = Query.new(:project => Project.find(1), :name => '_')
296 query.add_filter('due_date', '<t+', ['15'])
296 query.add_filter('due_date', '<t+', ['15'])
297 issues = find_issues_with_query(query)
297 issues = find_issues_with_query(query)
298 assert !issues.empty?
298 assert !issues.empty?
299 issues.each {|issue| assert(issue.due_date >= Date.today && issue.due_date <= (Date.today + 15))}
299 issues.each {|issue| assert(issue.due_date >= Date.today && issue.due_date <= (Date.today + 15))}
300 end
300 end
301
301
302 def test_operator_less_than_ago
302 def test_operator_less_than_ago
303 Issue.find(7).update_attribute(:due_date, (Date.today - 3))
303 Issue.find(7).update_attribute(:due_date, (Date.today - 3))
304 query = Query.new(:project => Project.find(1), :name => '_')
304 query = Query.new(:project => Project.find(1), :name => '_')
305 query.add_filter('due_date', '>t-', ['3'])
305 query.add_filter('due_date', '>t-', ['3'])
306 issues = find_issues_with_query(query)
306 issues = find_issues_with_query(query)
307 assert !issues.empty?
307 assert !issues.empty?
308 issues.each {|issue| assert(issue.due_date >= (Date.today - 3) && issue.due_date <= Date.today)}
308 issues.each {|issue| assert(issue.due_date >= (Date.today - 3) && issue.due_date <= Date.today)}
309 end
309 end
310
310
311 def test_operator_more_than_ago
311 def test_operator_more_than_ago
312 Issue.find(7).update_attribute(:due_date, (Date.today - 10))
312 Issue.find(7).update_attribute(:due_date, (Date.today - 10))
313 query = Query.new(:project => Project.find(1), :name => '_')
313 query = Query.new(:project => Project.find(1), :name => '_')
314 query.add_filter('due_date', '<t-', ['10'])
314 query.add_filter('due_date', '<t-', ['10'])
315 assert query.statement.include?("#{Issue.table_name}.due_date <=")
315 assert query.statement.include?("#{Issue.table_name}.due_date <=")
316 issues = find_issues_with_query(query)
316 issues = find_issues_with_query(query)
317 assert !issues.empty?
317 assert !issues.empty?
318 issues.each {|issue| assert(issue.due_date <= (Date.today - 10))}
318 issues.each {|issue| assert(issue.due_date <= (Date.today - 10))}
319 end
319 end
320
320
321 def test_operator_in
321 def test_operator_in
322 Issue.find(7).update_attribute(:due_date, (Date.today + 2))
322 Issue.find(7).update_attribute(:due_date, (Date.today + 2))
323 query = Query.new(:project => Project.find(1), :name => '_')
323 query = Query.new(:project => Project.find(1), :name => '_')
324 query.add_filter('due_date', 't+', ['2'])
324 query.add_filter('due_date', 't+', ['2'])
325 issues = find_issues_with_query(query)
325 issues = find_issues_with_query(query)
326 assert !issues.empty?
326 assert !issues.empty?
327 issues.each {|issue| assert_equal((Date.today + 2), issue.due_date)}
327 issues.each {|issue| assert_equal((Date.today + 2), issue.due_date)}
328 end
328 end
329
329
330 def test_operator_ago
330 def test_operator_ago
331 Issue.find(7).update_attribute(:due_date, (Date.today - 3))
331 Issue.find(7).update_attribute(:due_date, (Date.today - 3))
332 query = Query.new(:project => Project.find(1), :name => '_')
332 query = Query.new(:project => Project.find(1), :name => '_')
333 query.add_filter('due_date', 't-', ['3'])
333 query.add_filter('due_date', 't-', ['3'])
334 issues = find_issues_with_query(query)
334 issues = find_issues_with_query(query)
335 assert !issues.empty?
335 assert !issues.empty?
336 issues.each {|issue| assert_equal((Date.today - 3), issue.due_date)}
336 issues.each {|issue| assert_equal((Date.today - 3), issue.due_date)}
337 end
337 end
338
338
339 def test_operator_today
339 def test_operator_today
340 query = Query.new(:project => Project.find(1), :name => '_')
340 query = Query.new(:project => Project.find(1), :name => '_')
341 query.add_filter('due_date', 't', [''])
341 query.add_filter('due_date', 't', [''])
342 issues = find_issues_with_query(query)
342 issues = find_issues_with_query(query)
343 assert !issues.empty?
343 assert !issues.empty?
344 issues.each {|issue| assert_equal Date.today, issue.due_date}
344 issues.each {|issue| assert_equal Date.today, issue.due_date}
345 end
345 end
346
346
347 def test_operator_this_week_on_date
347 def test_operator_this_week_on_date
348 query = Query.new(:project => Project.find(1), :name => '_')
348 query = Query.new(:project => Project.find(1), :name => '_')
349 query.add_filter('due_date', 'w', [''])
349 query.add_filter('due_date', 'w', [''])
350 find_issues_with_query(query)
350 find_issues_with_query(query)
351 end
351 end
352
352
353 def test_operator_this_week_on_datetime
353 def test_operator_this_week_on_datetime
354 query = Query.new(:project => Project.find(1), :name => '_')
354 query = Query.new(:project => Project.find(1), :name => '_')
355 query.add_filter('created_on', 'w', [''])
355 query.add_filter('created_on', 'w', [''])
356 find_issues_with_query(query)
356 find_issues_with_query(query)
357 end
357 end
358
358
359 def test_operator_contains
359 def test_operator_contains
360 query = Query.new(:project => Project.find(1), :name => '_')
360 query = Query.new(:project => Project.find(1), :name => '_')
361 query.add_filter('subject', '~', ['uNable'])
361 query.add_filter('subject', '~', ['uNable'])
362 assert query.statement.include?("LOWER(#{Issue.table_name}.subject) LIKE '%unable%'")
362 assert query.statement.include?("LOWER(#{Issue.table_name}.subject) LIKE '%unable%'")
363 result = find_issues_with_query(query)
363 result = find_issues_with_query(query)
364 assert result.empty?
364 assert result.empty?
365 result.each {|issue| assert issue.subject.downcase.include?('unable') }
365 result.each {|issue| assert issue.subject.downcase.include?('unable') }
366 end
366 end
367
367
368 def test_range_for_this_week_with_week_starting_on_monday
368 def test_range_for_this_week_with_week_starting_on_monday
369 I18n.locale = :fr
369 I18n.locale = :fr
370 assert_equal '1', I18n.t(:general_first_day_of_week)
370 assert_equal '1', I18n.t(:general_first_day_of_week)
371
371
372 Date.stubs(:today).returns(Date.parse('2011-04-29'))
372 Date.stubs(:today).returns(Date.parse('2011-04-29'))
373
373
374 query = Query.new(:project => Project.find(1), :name => '_')
374 query = Query.new(:project => Project.find(1), :name => '_')
375 query.add_filter('due_date', 'w', [''])
375 query.add_filter('due_date', 'w', [''])
376 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}"
376 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}"
377 I18n.locale = :en
377 I18n.locale = :en
378 end
378 end
379
379
380 def test_range_for_this_week_with_week_starting_on_sunday
380 def test_range_for_this_week_with_week_starting_on_sunday
381 I18n.locale = :en
381 I18n.locale = :en
382 assert_equal '7', I18n.t(:general_first_day_of_week)
382 assert_equal '7', I18n.t(:general_first_day_of_week)
383
383
384 Date.stubs(:today).returns(Date.parse('2011-04-29'))
384 Date.stubs(:today).returns(Date.parse('2011-04-29'))
385
385
386 query = Query.new(:project => Project.find(1), :name => '_')
386 query = Query.new(:project => Project.find(1), :name => '_')
387 query.add_filter('due_date', 'w', [''])
387 query.add_filter('due_date', 'w', [''])
388 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}"
388 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}"
389 end
389 end
390
390
391 def test_operator_does_not_contains
391 def test_operator_does_not_contains
392 query = Query.new(:project => Project.find(1), :name => '_')
392 query = Query.new(:project => Project.find(1), :name => '_')
393 query.add_filter('subject', '!~', ['uNable'])
393 query.add_filter('subject', '!~', ['uNable'])
394 assert query.statement.include?("LOWER(#{Issue.table_name}.subject) NOT LIKE '%unable%'")
394 assert query.statement.include?("LOWER(#{Issue.table_name}.subject) NOT LIKE '%unable%'")
395 find_issues_with_query(query)
395 find_issues_with_query(query)
396 end
396 end
397
397
398 def test_filter_assigned_to_me
398 def test_filter_assigned_to_me
399 user = User.find(2)
399 user = User.find(2)
400 group = Group.find(10)
400 group = Group.find(10)
401 User.current = user
401 User.current = user
402 i1 = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to => user)
402 i1 = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to => user)
403 i2 = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to => group)
403 i2 = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to => group)
404 i3 = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to => Group.find(11))
404 i3 = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to => Group.find(11))
405 group.users << user
405 group.users << user
406
406
407 query = Query.new(:name => '_', :filters => { 'assigned_to_id' => {:operator => '=', :values => ['me']}})
407 query = Query.new(:name => '_', :filters => { 'assigned_to_id' => {:operator => '=', :values => ['me']}})
408 result = query.issues
408 result = query.issues
409 assert_equal Issue.visible.all(:conditions => {:assigned_to_id => ([2] + user.reload.group_ids)}).sort_by(&:id), result.sort_by(&:id)
409 assert_equal Issue.visible.all(:conditions => {:assigned_to_id => ([2] + user.reload.group_ids)}).sort_by(&:id), result.sort_by(&:id)
410
410
411 assert result.include?(i1)
411 assert result.include?(i1)
412 assert result.include?(i2)
412 assert result.include?(i2)
413 assert !result.include?(i3)
413 assert !result.include?(i3)
414 end
414 end
415
415
416 def test_user_custom_field_filtered_on_me
416 def test_user_custom_field_filtered_on_me
417 User.current = User.find(2)
417 User.current = User.find(2)
418 cf = IssueCustomField.create!(:field_format => 'user', :is_for_all => true, :is_filter => true, :name => 'User custom field', :tracker_ids => [1])
418 cf = IssueCustomField.create!(:field_format => 'user', :is_for_all => true, :is_filter => true, :name => 'User custom field', :tracker_ids => [1])
419 issue1 = Issue.create!(:project_id => 1, :tracker_id => 1, :custom_field_values => {cf.id.to_s => '2'}, :subject => 'Test', :author_id => 1)
419 issue1 = Issue.create!(:project_id => 1, :tracker_id => 1, :custom_field_values => {cf.id.to_s => '2'}, :subject => 'Test', :author_id => 1)
420 issue2 = Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {cf.id.to_s => '3'})
420 issue2 = Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {cf.id.to_s => '3'})
421
421
422 query = Query.new(:name => '_', :project => Project.find(1))
422 query = Query.new(:name => '_', :project => Project.find(1))
423 filter = query.available_filters["cf_#{cf.id}"]
423 filter = query.available_filters["cf_#{cf.id}"]
424 assert_not_nil filter
424 assert_not_nil filter
425 assert_include 'me', filter[:values].map{|v| v[1]}
425 assert_include 'me', filter[:values].map{|v| v[1]}
426
426
427 query.filters = { "cf_#{cf.id}" => {:operator => '=', :values => ['me']}}
427 query.filters = { "cf_#{cf.id}" => {:operator => '=', :values => ['me']}}
428 result = query.issues
428 result = query.issues
429 assert_equal 1, result.size
429 assert_equal 1, result.size
430 assert issue1, result.first
430 assert_equal issue1, result.first
431 end
431 end
432
432
433 def test_filter_my_projects
433 def test_filter_my_projects
434 User.current = User.find(2)
434 User.current = User.find(2)
435 query = Query.new(:name => '_')
435 query = Query.new(:name => '_')
436 filter = query.available_filters['project_id']
436 filter = query.available_filters['project_id']
437 assert_not_nil filter
437 assert_not_nil filter
438 assert_include 'mine', filter[:values].map{|v| v[1]}
438 assert_include 'mine', filter[:values].map{|v| v[1]}
439
439
440 query.filters = { 'project_id' => {:operator => '=', :values => ['mine']}}
440 query.filters = { 'project_id' => {:operator => '=', :values => ['mine']}}
441 result = query.issues
441 result = query.issues
442 assert_nil result.detect {|issue| !User.current.member_of?(issue.project)}
442 assert_nil result.detect {|issue| !User.current.member_of?(issue.project)}
443 end
443 end
444
444
445 def test_filter_watched_issues
445 def test_filter_watched_issues
446 User.current = User.find(1)
446 User.current = User.find(1)
447 query = Query.new(:name => '_', :filters => { 'watcher_id' => {:operator => '=', :values => ['me']}})
447 query = Query.new(:name => '_', :filters => { 'watcher_id' => {:operator => '=', :values => ['me']}})
448 result = find_issues_with_query(query)
448 result = find_issues_with_query(query)
449 assert_not_nil result
449 assert_not_nil result
450 assert !result.empty?
450 assert !result.empty?
451 assert_equal Issue.visible.watched_by(User.current).sort_by(&:id), result.sort_by(&:id)
451 assert_equal Issue.visible.watched_by(User.current).sort_by(&:id), result.sort_by(&:id)
452 User.current = nil
452 User.current = nil
453 end
453 end
454
454
455 def test_filter_unwatched_issues
455 def test_filter_unwatched_issues
456 User.current = User.find(1)
456 User.current = User.find(1)
457 query = Query.new(:name => '_', :filters => { 'watcher_id' => {:operator => '!', :values => ['me']}})
457 query = Query.new(:name => '_', :filters => { 'watcher_id' => {:operator => '!', :values => ['me']}})
458 result = find_issues_with_query(query)
458 result = find_issues_with_query(query)
459 assert_not_nil result
459 assert_not_nil result
460 assert !result.empty?
460 assert !result.empty?
461 assert_equal((Issue.visible - Issue.watched_by(User.current)).sort_by(&:id).size, result.sort_by(&:id).size)
461 assert_equal((Issue.visible - Issue.watched_by(User.current)).sort_by(&:id).size, result.sort_by(&:id).size)
462 User.current = nil
462 User.current = nil
463 end
463 end
464
464
465 def test_statement_should_be_nil_with_no_filters
465 def test_statement_should_be_nil_with_no_filters
466 q = Query.new(:name => '_')
466 q = Query.new(:name => '_')
467 q.filters = {}
467 q.filters = {}
468
468
469 assert q.valid?
469 assert q.valid?
470 assert_nil q.statement
470 assert_nil q.statement
471 end
471 end
472
472
473 def test_default_columns
473 def test_default_columns
474 q = Query.new
474 q = Query.new
475 assert !q.columns.empty?
475 assert !q.columns.empty?
476 end
476 end
477
477
478 def test_set_column_names
478 def test_set_column_names
479 q = Query.new
479 q = Query.new
480 q.column_names = ['tracker', :subject, '', 'unknonw_column']
480 q.column_names = ['tracker', :subject, '', 'unknonw_column']
481 assert_equal [:tracker, :subject], q.columns.collect {|c| c.name}
481 assert_equal [:tracker, :subject], q.columns.collect {|c| c.name}
482 c = q.columns.first
482 c = q.columns.first
483 assert q.has_column?(c)
483 assert q.has_column?(c)
484 end
484 end
485
485
486 def test_query_should_preload_spent_hours
486 def test_query_should_preload_spent_hours
487 q = Query.new(:name => '_', :column_names => [:subject, :spent_hours])
487 q = Query.new(:name => '_', :column_names => [:subject, :spent_hours])
488 assert q.has_column?(:spent_hours)
488 assert q.has_column?(:spent_hours)
489 issues = q.issues
489 issues = q.issues
490 assert_not_nil issues.first.instance_variable_get("@spent_hours")
490 assert_not_nil issues.first.instance_variable_get("@spent_hours")
491 end
491 end
492
492
493 def test_groupable_columns_should_include_custom_fields
493 def test_groupable_columns_should_include_custom_fields
494 q = Query.new
494 q = Query.new
495 assert q.groupable_columns.detect {|c| c.is_a? QueryCustomFieldColumn}
495 assert q.groupable_columns.detect {|c| c.is_a? QueryCustomFieldColumn}
496 end
496 end
497
497
498 def test_grouped_with_valid_column
498 def test_grouped_with_valid_column
499 q = Query.new(:group_by => 'status')
499 q = Query.new(:group_by => 'status')
500 assert q.grouped?
500 assert q.grouped?
501 assert_not_nil q.group_by_column
501 assert_not_nil q.group_by_column
502 assert_equal :status, q.group_by_column.name
502 assert_equal :status, q.group_by_column.name
503 assert_not_nil q.group_by_statement
503 assert_not_nil q.group_by_statement
504 assert_equal 'status', q.group_by_statement
504 assert_equal 'status', q.group_by_statement
505 end
505 end
506
506
507 def test_grouped_with_invalid_column
507 def test_grouped_with_invalid_column
508 q = Query.new(:group_by => 'foo')
508 q = Query.new(:group_by => 'foo')
509 assert !q.grouped?
509 assert !q.grouped?
510 assert_nil q.group_by_column
510 assert_nil q.group_by_column
511 assert_nil q.group_by_statement
511 assert_nil q.group_by_statement
512 end
512 end
513
513
514 def test_sortable_columns_should_sort_assignees_according_to_user_format_setting
514 def test_sortable_columns_should_sort_assignees_according_to_user_format_setting
515 with_settings :user_format => 'lastname_coma_firstname' do
515 with_settings :user_format => 'lastname_coma_firstname' do
516 q = Query.new
516 q = Query.new
517 assert q.sortable_columns.has_key?('assigned_to')
517 assert q.sortable_columns.has_key?('assigned_to')
518 assert_equal %w(users.lastname users.firstname users.id), q.sortable_columns['assigned_to']
518 assert_equal %w(users.lastname users.firstname users.id), q.sortable_columns['assigned_to']
519 end
519 end
520 end
520 end
521
521
522 def test_sortable_columns_should_sort_authors_according_to_user_format_setting
522 def test_sortable_columns_should_sort_authors_according_to_user_format_setting
523 with_settings :user_format => 'lastname_coma_firstname' do
523 with_settings :user_format => 'lastname_coma_firstname' do
524 q = Query.new
524 q = Query.new
525 assert q.sortable_columns.has_key?('author')
525 assert q.sortable_columns.has_key?('author')
526 assert_equal %w(authors.lastname authors.firstname authors.id), q.sortable_columns['author']
526 assert_equal %w(authors.lastname authors.firstname authors.id), q.sortable_columns['author']
527 end
527 end
528 end
528 end
529
529
530 def test_default_sort
530 def test_default_sort
531 q = Query.new
531 q = Query.new
532 assert_equal [], q.sort_criteria
532 assert_equal [], q.sort_criteria
533 end
533 end
534
534
535 def test_set_sort_criteria_with_hash
535 def test_set_sort_criteria_with_hash
536 q = Query.new
536 q = Query.new
537 q.sort_criteria = {'0' => ['priority', 'desc'], '2' => ['tracker']}
537 q.sort_criteria = {'0' => ['priority', 'desc'], '2' => ['tracker']}
538 assert_equal [['priority', 'desc'], ['tracker', 'asc']], q.sort_criteria
538 assert_equal [['priority', 'desc'], ['tracker', 'asc']], q.sort_criteria
539 end
539 end
540
540
541 def test_set_sort_criteria_with_array
541 def test_set_sort_criteria_with_array
542 q = Query.new
542 q = Query.new
543 q.sort_criteria = [['priority', 'desc'], 'tracker']
543 q.sort_criteria = [['priority', 'desc'], 'tracker']
544 assert_equal [['priority', 'desc'], ['tracker', 'asc']], q.sort_criteria
544 assert_equal [['priority', 'desc'], ['tracker', 'asc']], q.sort_criteria
545 end
545 end
546
546
547 def test_create_query_with_sort
547 def test_create_query_with_sort
548 q = Query.new(:name => 'Sorted')
548 q = Query.new(:name => 'Sorted')
549 q.sort_criteria = [['priority', 'desc'], 'tracker']
549 q.sort_criteria = [['priority', 'desc'], 'tracker']
550 assert q.save
550 assert q.save
551 q.reload
551 q.reload
552 assert_equal [['priority', 'desc'], ['tracker', 'asc']], q.sort_criteria
552 assert_equal [['priority', 'desc'], ['tracker', 'asc']], q.sort_criteria
553 end
553 end
554
554
555 def test_sort_by_string_custom_field_asc
555 def test_sort_by_string_custom_field_asc
556 q = Query.new
556 q = Query.new
557 c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'string' }
557 c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'string' }
558 assert c
558 assert c
559 assert c.sortable
559 assert c.sortable
560 issues = Issue.find :all,
560 issues = Issue.find :all,
561 :include => [ :assigned_to, :status, :tracker, :project, :priority ],
561 :include => [ :assigned_to, :status, :tracker, :project, :priority ],
562 :conditions => q.statement,
562 :conditions => q.statement,
563 :order => "#{c.sortable} ASC"
563 :order => "#{c.sortable} ASC"
564 values = issues.collect {|i| i.custom_value_for(c.custom_field).to_s}
564 values = issues.collect {|i| i.custom_value_for(c.custom_field).to_s}
565 assert !values.empty?
565 assert !values.empty?
566 assert_equal values.sort, values
566 assert_equal values.sort, values
567 end
567 end
568
568
569 def test_sort_by_string_custom_field_desc
569 def test_sort_by_string_custom_field_desc
570 q = Query.new
570 q = Query.new
571 c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'string' }
571 c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'string' }
572 assert c
572 assert c
573 assert c.sortable
573 assert c.sortable
574 issues = Issue.find :all,
574 issues = Issue.find :all,
575 :include => [ :assigned_to, :status, :tracker, :project, :priority ],
575 :include => [ :assigned_to, :status, :tracker, :project, :priority ],
576 :conditions => q.statement,
576 :conditions => q.statement,
577 :order => "#{c.sortable} DESC"
577 :order => "#{c.sortable} DESC"
578 values = issues.collect {|i| i.custom_value_for(c.custom_field).to_s}
578 values = issues.collect {|i| i.custom_value_for(c.custom_field).to_s}
579 assert !values.empty?
579 assert !values.empty?
580 assert_equal values.sort.reverse, values
580 assert_equal values.sort.reverse, values
581 end
581 end
582
582
583 def test_sort_by_float_custom_field_asc
583 def test_sort_by_float_custom_field_asc
584 q = Query.new
584 q = Query.new
585 c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'float' }
585 c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'float' }
586 assert c
586 assert c
587 assert c.sortable
587 assert c.sortable
588 issues = Issue.find :all,
588 issues = Issue.find :all,
589 :include => [ :assigned_to, :status, :tracker, :project, :priority ],
589 :include => [ :assigned_to, :status, :tracker, :project, :priority ],
590 :conditions => q.statement,
590 :conditions => q.statement,
591 :order => "#{c.sortable} ASC"
591 :order => "#{c.sortable} ASC"
592 values = issues.collect {|i| begin; Kernel.Float(i.custom_value_for(c.custom_field).to_s); rescue; nil; end}.compact
592 values = issues.collect {|i| begin; Kernel.Float(i.custom_value_for(c.custom_field).to_s); rescue; nil; end}.compact
593 assert !values.empty?
593 assert !values.empty?
594 assert_equal values.sort, values
594 assert_equal values.sort, values
595 end
595 end
596
596
597 def test_invalid_query_should_raise_query_statement_invalid_error
597 def test_invalid_query_should_raise_query_statement_invalid_error
598 q = Query.new
598 q = Query.new
599 assert_raise Query::StatementInvalid do
599 assert_raise Query::StatementInvalid do
600 q.issues(:conditions => "foo = 1")
600 q.issues(:conditions => "foo = 1")
601 end
601 end
602 end
602 end
603
603
604 def test_issue_count
604 def test_issue_count
605 q = Query.new(:name => '_')
605 q = Query.new(:name => '_')
606 issue_count = q.issue_count
606 issue_count = q.issue_count
607 assert_equal q.issues.size, issue_count
607 assert_equal q.issues.size, issue_count
608 end
608 end
609
609
610 def test_issue_count_with_archived_issues
610 def test_issue_count_with_archived_issues
611 p = Project.generate!( :status => Project::STATUS_ARCHIVED )
611 p = Project.generate!( :status => Project::STATUS_ARCHIVED )
612 i = Issue.generate!( :project => p, :tracker => p.trackers.first )
612 i = Issue.generate!( :project => p, :tracker => p.trackers.first )
613 assert !i.visible?
613 assert !i.visible?
614
614
615 test_issue_count
615 test_issue_count
616 end
616 end
617
617
618 def test_issue_count_by_association_group
618 def test_issue_count_by_association_group
619 q = Query.new(:name => '_', :group_by => 'assigned_to')
619 q = Query.new(:name => '_', :group_by => 'assigned_to')
620 count_by_group = q.issue_count_by_group
620 count_by_group = q.issue_count_by_group
621 assert_kind_of Hash, count_by_group
621 assert_kind_of Hash, count_by_group
622 assert_equal %w(NilClass User), count_by_group.keys.collect {|k| k.class.name}.uniq.sort
622 assert_equal %w(NilClass User), count_by_group.keys.collect {|k| k.class.name}.uniq.sort
623 assert_equal %w(Fixnum), count_by_group.values.collect {|k| k.class.name}.uniq
623 assert_equal %w(Fixnum), count_by_group.values.collect {|k| k.class.name}.uniq
624 assert count_by_group.has_key?(User.find(3))
624 assert count_by_group.has_key?(User.find(3))
625 end
625 end
626
626
627 def test_issue_count_by_list_custom_field_group
627 def test_issue_count_by_list_custom_field_group
628 q = Query.new(:name => '_', :group_by => 'cf_1')
628 q = Query.new(:name => '_', :group_by => 'cf_1')
629 count_by_group = q.issue_count_by_group
629 count_by_group = q.issue_count_by_group
630 assert_kind_of Hash, count_by_group
630 assert_kind_of Hash, count_by_group
631 assert_equal %w(NilClass String), count_by_group.keys.collect {|k| k.class.name}.uniq.sort
631 assert_equal %w(NilClass String), count_by_group.keys.collect {|k| k.class.name}.uniq.sort
632 assert_equal %w(Fixnum), count_by_group.values.collect {|k| k.class.name}.uniq
632 assert_equal %w(Fixnum), count_by_group.values.collect {|k| k.class.name}.uniq
633 assert count_by_group.has_key?('MySQL')
633 assert count_by_group.has_key?('MySQL')
634 end
634 end
635
635
636 def test_issue_count_by_date_custom_field_group
636 def test_issue_count_by_date_custom_field_group
637 q = Query.new(:name => '_', :group_by => 'cf_8')
637 q = Query.new(:name => '_', :group_by => 'cf_8')
638 count_by_group = q.issue_count_by_group
638 count_by_group = q.issue_count_by_group
639 assert_kind_of Hash, count_by_group
639 assert_kind_of Hash, count_by_group
640 assert_equal %w(Date NilClass), count_by_group.keys.collect {|k| k.class.name}.uniq.sort
640 assert_equal %w(Date NilClass), count_by_group.keys.collect {|k| k.class.name}.uniq.sort
641 assert_equal %w(Fixnum), count_by_group.values.collect {|k| k.class.name}.uniq
641 assert_equal %w(Fixnum), count_by_group.values.collect {|k| k.class.name}.uniq
642 end
642 end
643
643
644 def test_issue_ids
644 def test_issue_ids
645 q = Query.new(:name => '_')
645 q = Query.new(:name => '_')
646 order = "issues.subject, issues.id"
646 order = "issues.subject, issues.id"
647 issues = q.issues(:order => order)
647 issues = q.issues(:order => order)
648 assert_equal issues.map(&:id), q.issue_ids(:order => order)
648 assert_equal issues.map(&:id), q.issue_ids(:order => order)
649 end
649 end
650
650
651 def test_label_for
651 def test_label_for
652 q = Query.new
652 q = Query.new
653 assert_equal 'Assignee', q.label_for('assigned_to_id')
653 assert_equal 'Assignee', q.label_for('assigned_to_id')
654 end
654 end
655
655
656 def test_editable_by
656 def test_editable_by
657 admin = User.find(1)
657 admin = User.find(1)
658 manager = User.find(2)
658 manager = User.find(2)
659 developer = User.find(3)
659 developer = User.find(3)
660
660
661 # Public query on project 1
661 # Public query on project 1
662 q = Query.find(1)
662 q = Query.find(1)
663 assert q.editable_by?(admin)
663 assert q.editable_by?(admin)
664 assert q.editable_by?(manager)
664 assert q.editable_by?(manager)
665 assert !q.editable_by?(developer)
665 assert !q.editable_by?(developer)
666
666
667 # Private query on project 1
667 # Private query on project 1
668 q = Query.find(2)
668 q = Query.find(2)
669 assert q.editable_by?(admin)
669 assert q.editable_by?(admin)
670 assert !q.editable_by?(manager)
670 assert !q.editable_by?(manager)
671 assert q.editable_by?(developer)
671 assert q.editable_by?(developer)
672
672
673 # Private query for all projects
673 # Private query for all projects
674 q = Query.find(3)
674 q = Query.find(3)
675 assert q.editable_by?(admin)
675 assert q.editable_by?(admin)
676 assert !q.editable_by?(manager)
676 assert !q.editable_by?(manager)
677 assert q.editable_by?(developer)
677 assert q.editable_by?(developer)
678
678
679 # Public query for all projects
679 # Public query for all projects
680 q = Query.find(4)
680 q = Query.find(4)
681 assert q.editable_by?(admin)
681 assert q.editable_by?(admin)
682 assert !q.editable_by?(manager)
682 assert !q.editable_by?(manager)
683 assert !q.editable_by?(developer)
683 assert !q.editable_by?(developer)
684 end
684 end
685
685
686 def test_visible_scope
686 def test_visible_scope
687 query_ids = Query.visible(User.anonymous).map(&:id)
687 query_ids = Query.visible(User.anonymous).map(&:id)
688
688
689 assert query_ids.include?(1), 'public query on public project was not visible'
689 assert query_ids.include?(1), 'public query on public project was not visible'
690 assert query_ids.include?(4), 'public query for all projects was not visible'
690 assert query_ids.include?(4), 'public query for all projects was not visible'
691 assert !query_ids.include?(2), 'private query on public project was visible'
691 assert !query_ids.include?(2), 'private query on public project was visible'
692 assert !query_ids.include?(3), 'private query for all projects was visible'
692 assert !query_ids.include?(3), 'private query for all projects was visible'
693 assert !query_ids.include?(7), 'public query on private project was visible'
693 assert !query_ids.include?(7), 'public query on private project was visible'
694 end
694 end
695
695
696 context "#available_filters" do
696 context "#available_filters" do
697 setup do
697 setup do
698 @query = Query.new(:name => "_")
698 @query = Query.new(:name => "_")
699 end
699 end
700
700
701 should "include users of visible projects in cross-project view" do
701 should "include users of visible projects in cross-project view" do
702 users = @query.available_filters["assigned_to_id"]
702 users = @query.available_filters["assigned_to_id"]
703 assert_not_nil users
703 assert_not_nil users
704 assert users[:values].map{|u|u[1]}.include?("3")
704 assert users[:values].map{|u|u[1]}.include?("3")
705 end
705 end
706
706
707 should "include visible projects in cross-project view" do
707 should "include visible projects in cross-project view" do
708 projects = @query.available_filters["project_id"]
708 projects = @query.available_filters["project_id"]
709 assert_not_nil projects
709 assert_not_nil projects
710 assert projects[:values].map{|u|u[1]}.include?("1")
710 assert projects[:values].map{|u|u[1]}.include?("1")
711 end
711 end
712
712
713 context "'member_of_group' filter" do
713 context "'member_of_group' filter" do
714 should "be present" do
714 should "be present" do
715 assert @query.available_filters.keys.include?("member_of_group")
715 assert @query.available_filters.keys.include?("member_of_group")
716 end
716 end
717
717
718 should "be an optional list" do
718 should "be an optional list" do
719 assert_equal :list_optional, @query.available_filters["member_of_group"][:type]
719 assert_equal :list_optional, @query.available_filters["member_of_group"][:type]
720 end
720 end
721
721
722 should "have a list of the groups as values" do
722 should "have a list of the groups as values" do
723 Group.destroy_all # No fixtures
723 Group.destroy_all # No fixtures
724 group1 = Group.generate!.reload
724 group1 = Group.generate!.reload
725 group2 = Group.generate!.reload
725 group2 = Group.generate!.reload
726
726
727 expected_group_list = [
727 expected_group_list = [
728 [group1.name, group1.id.to_s],
728 [group1.name, group1.id.to_s],
729 [group2.name, group2.id.to_s]
729 [group2.name, group2.id.to_s]
730 ]
730 ]
731 assert_equal expected_group_list.sort, @query.available_filters["member_of_group"][:values].sort
731 assert_equal expected_group_list.sort, @query.available_filters["member_of_group"][:values].sort
732 end
732 end
733
733
734 end
734 end
735
735
736 context "'assigned_to_role' filter" do
736 context "'assigned_to_role' filter" do
737 should "be present" do
737 should "be present" do
738 assert @query.available_filters.keys.include?("assigned_to_role")
738 assert @query.available_filters.keys.include?("assigned_to_role")
739 end
739 end
740
740
741 should "be an optional list" do
741 should "be an optional list" do
742 assert_equal :list_optional, @query.available_filters["assigned_to_role"][:type]
742 assert_equal :list_optional, @query.available_filters["assigned_to_role"][:type]
743 end
743 end
744
744
745 should "have a list of the Roles as values" do
745 should "have a list of the Roles as values" do
746 assert @query.available_filters["assigned_to_role"][:values].include?(['Manager','1'])
746 assert @query.available_filters["assigned_to_role"][:values].include?(['Manager','1'])
747 assert @query.available_filters["assigned_to_role"][:values].include?(['Developer','2'])
747 assert @query.available_filters["assigned_to_role"][:values].include?(['Developer','2'])
748 assert @query.available_filters["assigned_to_role"][:values].include?(['Reporter','3'])
748 assert @query.available_filters["assigned_to_role"][:values].include?(['Reporter','3'])
749 end
749 end
750
750
751 should "not include the built in Roles as values" do
751 should "not include the built in Roles as values" do
752 assert ! @query.available_filters["assigned_to_role"][:values].include?(['Non member','4'])
752 assert ! @query.available_filters["assigned_to_role"][:values].include?(['Non member','4'])
753 assert ! @query.available_filters["assigned_to_role"][:values].include?(['Anonymous','5'])
753 assert ! @query.available_filters["assigned_to_role"][:values].include?(['Anonymous','5'])
754 end
754 end
755
755
756 end
756 end
757
757
758 end
758 end
759
759
760 context "#statement" do
760 context "#statement" do
761 context "with 'member_of_group' filter" do
761 context "with 'member_of_group' filter" do
762 setup do
762 setup do
763 Group.destroy_all # No fixtures
763 Group.destroy_all # No fixtures
764 @user_in_group = User.generate!
764 @user_in_group = User.generate!
765 @second_user_in_group = User.generate!
765 @second_user_in_group = User.generate!
766 @user_in_group2 = User.generate!
766 @user_in_group2 = User.generate!
767 @user_not_in_group = User.generate!
767 @user_not_in_group = User.generate!
768
768
769 @group = Group.generate!.reload
769 @group = Group.generate!.reload
770 @group.users << @user_in_group
770 @group.users << @user_in_group
771 @group.users << @second_user_in_group
771 @group.users << @second_user_in_group
772
772
773 @group2 = Group.generate!.reload
773 @group2 = Group.generate!.reload
774 @group2.users << @user_in_group2
774 @group2.users << @user_in_group2
775
775
776 end
776 end
777
777
778 should "search assigned to for users in the group" do
778 should "search assigned to for users in the group" do
779 @query = Query.new(:name => '_')
779 @query = Query.new(:name => '_')
780 @query.add_filter('member_of_group', '=', [@group.id.to_s])
780 @query.add_filter('member_of_group', '=', [@group.id.to_s])
781
781
782 assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IN ('#{@user_in_group.id}','#{@second_user_in_group.id}')"
782 assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IN ('#{@user_in_group.id}','#{@second_user_in_group.id}')"
783 assert_find_issues_with_query_is_successful @query
783 assert_find_issues_with_query_is_successful @query
784 end
784 end
785
785
786 should "search not assigned to any group member (none)" do
786 should "search not assigned to any group member (none)" do
787 @query = Query.new(:name => '_')
787 @query = Query.new(:name => '_')
788 @query.add_filter('member_of_group', '!*', [''])
788 @query.add_filter('member_of_group', '!*', [''])
789
789
790 # Users not in a group
790 # Users not in a group
791 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}')"
791 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}')"
792 assert_find_issues_with_query_is_successful @query
792 assert_find_issues_with_query_is_successful @query
793 end
793 end
794
794
795 should "search assigned to any group member (all)" do
795 should "search assigned to any group member (all)" do
796 @query = Query.new(:name => '_')
796 @query = Query.new(:name => '_')
797 @query.add_filter('member_of_group', '*', [''])
797 @query.add_filter('member_of_group', '*', [''])
798
798
799 # Only users in a group
799 # Only users in a group
800 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}')"
800 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}')"
801 assert_find_issues_with_query_is_successful @query
801 assert_find_issues_with_query_is_successful @query
802 end
802 end
803
803
804 should "return an empty set with = empty group" do
804 should "return an empty set with = empty group" do
805 @empty_group = Group.generate!
805 @empty_group = Group.generate!
806 @query = Query.new(:name => '_')
806 @query = Query.new(:name => '_')
807 @query.add_filter('member_of_group', '=', [@empty_group.id.to_s])
807 @query.add_filter('member_of_group', '=', [@empty_group.id.to_s])
808
808
809 assert_equal [], find_issues_with_query(@query)
809 assert_equal [], find_issues_with_query(@query)
810 end
810 end
811
811
812 should "return issues with ! empty group" do
812 should "return issues with ! empty group" do
813 @empty_group = Group.generate!
813 @empty_group = Group.generate!
814 @query = Query.new(:name => '_')
814 @query = Query.new(:name => '_')
815 @query.add_filter('member_of_group', '!', [@empty_group.id.to_s])
815 @query.add_filter('member_of_group', '!', [@empty_group.id.to_s])
816
816
817 assert_find_issues_with_query_is_successful @query
817 assert_find_issues_with_query_is_successful @query
818 end
818 end
819 end
819 end
820
820
821 context "with 'assigned_to_role' filter" do
821 context "with 'assigned_to_role' filter" do
822 setup do
822 setup do
823 @manager_role = Role.find_by_name('Manager')
823 @manager_role = Role.find_by_name('Manager')
824 @developer_role = Role.find_by_name('Developer')
824 @developer_role = Role.find_by_name('Developer')
825
825
826 @project = Project.generate!
826 @project = Project.generate!
827 @manager = User.generate!
827 @manager = User.generate!
828 @developer = User.generate!
828 @developer = User.generate!
829 @boss = User.generate!
829 @boss = User.generate!
830 @guest = User.generate!
830 @guest = User.generate!
831 User.add_to_project(@manager, @project, @manager_role)
831 User.add_to_project(@manager, @project, @manager_role)
832 User.add_to_project(@developer, @project, @developer_role)
832 User.add_to_project(@developer, @project, @developer_role)
833 User.add_to_project(@boss, @project, [@manager_role, @developer_role])
833 User.add_to_project(@boss, @project, [@manager_role, @developer_role])
834
834
835 @issue1 = Issue.generate_for_project!(@project, :assigned_to_id => @manager.id)
835 @issue1 = Issue.generate_for_project!(@project, :assigned_to_id => @manager.id)
836 @issue2 = Issue.generate_for_project!(@project, :assigned_to_id => @developer.id)
836 @issue2 = Issue.generate_for_project!(@project, :assigned_to_id => @developer.id)
837 @issue3 = Issue.generate_for_project!(@project, :assigned_to_id => @boss.id)
837 @issue3 = Issue.generate_for_project!(@project, :assigned_to_id => @boss.id)
838 @issue4 = Issue.generate_for_project!(@project, :assigned_to_id => @guest.id)
838 @issue4 = Issue.generate_for_project!(@project, :assigned_to_id => @guest.id)
839 @issue5 = Issue.generate_for_project!(@project)
839 @issue5 = Issue.generate_for_project!(@project)
840 end
840 end
841
841
842 should "search assigned to for users with the Role" do
842 should "search assigned to for users with the Role" do
843 @query = Query.new(:name => '_', :project => @project)
843 @query = Query.new(:name => '_', :project => @project)
844 @query.add_filter('assigned_to_role', '=', [@manager_role.id.to_s])
844 @query.add_filter('assigned_to_role', '=', [@manager_role.id.to_s])
845
845
846 assert_query_result [@issue1, @issue3], @query
846 assert_query_result [@issue1, @issue3], @query
847 end
847 end
848
848
849 should "search assigned to for users with the Role on the issue project" do
849 should "search assigned to for users with the Role on the issue project" do
850 other_project = Project.generate!
850 other_project = Project.generate!
851 User.add_to_project(@developer, other_project, @manager_role)
851 User.add_to_project(@developer, other_project, @manager_role)
852
852
853 @query = Query.new(:name => '_', :project => @project)
853 @query = Query.new(:name => '_', :project => @project)
854 @query.add_filter('assigned_to_role', '=', [@manager_role.id.to_s])
854 @query.add_filter('assigned_to_role', '=', [@manager_role.id.to_s])
855
855
856 assert_query_result [@issue1, @issue3], @query
856 assert_query_result [@issue1, @issue3], @query
857 end
857 end
858
858
859 should "return an empty set with empty role" do
859 should "return an empty set with empty role" do
860 @empty_role = Role.generate!
860 @empty_role = Role.generate!
861 @query = Query.new(:name => '_', :project => @project)
861 @query = Query.new(:name => '_', :project => @project)
862 @query.add_filter('assigned_to_role', '=', [@empty_role.id.to_s])
862 @query.add_filter('assigned_to_role', '=', [@empty_role.id.to_s])
863
863
864 assert_query_result [], @query
864 assert_query_result [], @query
865 end
865 end
866
866
867 should "search assigned to for users without the Role" do
867 should "search assigned to for users without the Role" do
868 @query = Query.new(:name => '_', :project => @project)
868 @query = Query.new(:name => '_', :project => @project)
869 @query.add_filter('assigned_to_role', '!', [@manager_role.id.to_s])
869 @query.add_filter('assigned_to_role', '!', [@manager_role.id.to_s])
870
870
871 assert_query_result [@issue2, @issue4, @issue5], @query
871 assert_query_result [@issue2, @issue4, @issue5], @query
872 end
872 end
873
873
874 should "search assigned to for users not assigned to any Role (none)" do
874 should "search assigned to for users not assigned to any Role (none)" do
875 @query = Query.new(:name => '_', :project => @project)
875 @query = Query.new(:name => '_', :project => @project)
876 @query.add_filter('assigned_to_role', '!*', [''])
876 @query.add_filter('assigned_to_role', '!*', [''])
877
877
878 assert_query_result [@issue4, @issue5], @query
878 assert_query_result [@issue4, @issue5], @query
879 end
879 end
880
880
881 should "search assigned to for users assigned to any Role (all)" do
881 should "search assigned to for users assigned to any Role (all)" do
882 @query = Query.new(:name => '_', :project => @project)
882 @query = Query.new(:name => '_', :project => @project)
883 @query.add_filter('assigned_to_role', '*', [''])
883 @query.add_filter('assigned_to_role', '*', [''])
884
884
885 assert_query_result [@issue1, @issue2, @issue3], @query
885 assert_query_result [@issue1, @issue2, @issue3], @query
886 end
886 end
887
887
888 should "return issues with ! empty role" do
888 should "return issues with ! empty role" do
889 @empty_role = Role.generate!
889 @empty_role = Role.generate!
890 @query = Query.new(:name => '_', :project => @project)
890 @query = Query.new(:name => '_', :project => @project)
891 @query.add_filter('assigned_to_role', '!', [@empty_role.id.to_s])
891 @query.add_filter('assigned_to_role', '!', [@empty_role.id.to_s])
892
892
893 assert_query_result [@issue1, @issue2, @issue3, @issue4, @issue5], @query
893 assert_query_result [@issue1, @issue2, @issue3, @issue4, @issue5], @query
894 end
894 end
895 end
895 end
896 end
896 end
897
897
898 end
898 end
General Comments 0
You need to be logged in to leave comments. Login now