##// END OF EJS Templates
Misc tests....
Jean-Philippe Lang -
r13349:ee173b64b831
parent child
Show More
@@ -1,1425 +1,1448
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2014 Jean-Philippe Lang
2 # Copyright (C) 2006-2014 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class QueryTest < ActiveSupport::TestCase
20 class QueryTest < ActiveSupport::TestCase
21 include Redmine::I18n
21 include Redmine::I18n
22
22
23 fixtures :projects, :enabled_modules, :users, :members,
23 fixtures :projects, :enabled_modules, :users, :members,
24 :member_roles, :roles, :trackers, :issue_statuses,
24 :member_roles, :roles, :trackers, :issue_statuses,
25 :issue_categories, :enumerations, :issues,
25 :issue_categories, :enumerations, :issues,
26 :watchers, :custom_fields, :custom_values, :versions,
26 :watchers, :custom_fields, :custom_values, :versions,
27 :queries,
27 :queries,
28 :projects_trackers,
28 :projects_trackers,
29 :custom_fields_trackers,
29 :custom_fields_trackers,
30 :workflows
30 :workflows
31
31
32 def test_query_with_roles_visibility_should_validate_roles
32 def test_query_with_roles_visibility_should_validate_roles
33 set_language_if_valid 'en'
33 set_language_if_valid 'en'
34 query = IssueQuery.new(:name => 'Query', :visibility => IssueQuery::VISIBILITY_ROLES)
34 query = IssueQuery.new(:name => 'Query', :visibility => IssueQuery::VISIBILITY_ROLES)
35 assert !query.save
35 assert !query.save
36 assert_include "Roles can't be blank", query.errors.full_messages
36 assert_include "Roles can't be blank", query.errors.full_messages
37 query.role_ids = [1, 2]
37 query.role_ids = [1, 2]
38 assert query.save
38 assert query.save
39 end
39 end
40
40
41 def test_changing_roles_visibility_should_clear_roles
41 def test_changing_roles_visibility_should_clear_roles
42 query = IssueQuery.create!(:name => 'Query', :visibility => IssueQuery::VISIBILITY_ROLES, :role_ids => [1, 2])
42 query = IssueQuery.create!(:name => 'Query', :visibility => IssueQuery::VISIBILITY_ROLES, :role_ids => [1, 2])
43 assert_equal 2, query.roles.count
43 assert_equal 2, query.roles.count
44
44
45 query.visibility = IssueQuery::VISIBILITY_PUBLIC
45 query.visibility = IssueQuery::VISIBILITY_PUBLIC
46 query.save!
46 query.save!
47 assert_equal 0, query.roles.count
47 assert_equal 0, query.roles.count
48 end
48 end
49
49
50 def test_available_filters_should_be_ordered
50 def test_available_filters_should_be_ordered
51 set_language_if_valid 'en'
51 set_language_if_valid 'en'
52 query = IssueQuery.new
52 query = IssueQuery.new
53 assert_equal 0, query.available_filters.keys.index('status_id')
53 assert_equal 0, query.available_filters.keys.index('status_id')
54 expected_order = [
54 expected_order = [
55 "Status",
55 "Status",
56 "Project",
56 "Project",
57 "Tracker",
57 "Tracker",
58 "Priority"
58 "Priority"
59 ]
59 ]
60 assert_equal expected_order,
60 assert_equal expected_order,
61 (query.available_filters.values.map{|v| v[:name]} & expected_order)
61 (query.available_filters.values.map{|v| v[:name]} & expected_order)
62 end
62 end
63
63
64 def test_available_filters_with_custom_fields_should_be_ordered
64 def test_available_filters_with_custom_fields_should_be_ordered
65 set_language_if_valid 'en'
65 set_language_if_valid 'en'
66 UserCustomField.create!(
66 UserCustomField.create!(
67 :name => 'order test', :field_format => 'string',
67 :name => 'order test', :field_format => 'string',
68 :is_for_all => true, :is_filter => true
68 :is_for_all => true, :is_filter => true
69 )
69 )
70 query = IssueQuery.new
70 query = IssueQuery.new
71 expected_order = [
71 expected_order = [
72 "Searchable field",
72 "Searchable field",
73 "Database",
73 "Database",
74 "Project's Development status",
74 "Project's Development status",
75 "Author's order test",
75 "Author's order test",
76 "Assignee's order test"
76 "Assignee's order test"
77 ]
77 ]
78 assert_equal expected_order,
78 assert_equal expected_order,
79 (query.available_filters.values.map{|v| v[:name]} & expected_order)
79 (query.available_filters.values.map{|v| v[:name]} & expected_order)
80 end
80 end
81
81
82 def test_custom_fields_for_all_projects_should_be_available_in_global_queries
82 def test_custom_fields_for_all_projects_should_be_available_in_global_queries
83 query = IssueQuery.new(:project => nil, :name => '_')
83 query = IssueQuery.new(:project => nil, :name => '_')
84 assert query.available_filters.has_key?('cf_1')
84 assert query.available_filters.has_key?('cf_1')
85 assert !query.available_filters.has_key?('cf_3')
85 assert !query.available_filters.has_key?('cf_3')
86 end
86 end
87
87
88 def test_system_shared_versions_should_be_available_in_global_queries
88 def test_system_shared_versions_should_be_available_in_global_queries
89 Version.find(2).update_attribute :sharing, 'system'
89 Version.find(2).update_attribute :sharing, 'system'
90 query = IssueQuery.new(:project => nil, :name => '_')
90 query = IssueQuery.new(:project => nil, :name => '_')
91 assert query.available_filters.has_key?('fixed_version_id')
91 assert query.available_filters.has_key?('fixed_version_id')
92 assert query.available_filters['fixed_version_id'][:values].detect {|v| v.last == '2'}
92 assert query.available_filters['fixed_version_id'][:values].detect {|v| v.last == '2'}
93 end
93 end
94
94
95 def test_project_filter_in_global_queries
95 def test_project_filter_in_global_queries
96 query = IssueQuery.new(:project => nil, :name => '_')
96 query = IssueQuery.new(:project => nil, :name => '_')
97 project_filter = query.available_filters["project_id"]
97 project_filter = query.available_filters["project_id"]
98 assert_not_nil project_filter
98 assert_not_nil project_filter
99 project_ids = project_filter[:values].map{|p| p[1]}
99 project_ids = project_filter[:values].map{|p| p[1]}
100 assert project_ids.include?("1") #public project
100 assert project_ids.include?("1") #public project
101 assert !project_ids.include?("2") #private project user cannot see
101 assert !project_ids.include?("2") #private project user cannot see
102 end
102 end
103
103
104 def test_available_filters_should_not_include_fields_disabled_on_all_trackers
105 Tracker.all.each do |tracker|
106 tracker.core_fields = Tracker::CORE_FIELDS - ['start_date']
107 tracker.save!
108 end
109
110 query = IssueQuery.new(:name => '_')
111 assert_include 'due_date', query.available_filters
112 assert_not_include 'start_date', query.available_filters
113 end
114
104 def find_issues_with_query(query)
115 def find_issues_with_query(query)
105 Issue.joins(:status, :tracker, :project, :priority).where(
116 Issue.joins(:status, :tracker, :project, :priority).where(
106 query.statement
117 query.statement
107 ).to_a
118 ).to_a
108 end
119 end
109
120
110 def assert_find_issues_with_query_is_successful(query)
121 def assert_find_issues_with_query_is_successful(query)
111 assert_nothing_raised do
122 assert_nothing_raised do
112 find_issues_with_query(query)
123 find_issues_with_query(query)
113 end
124 end
114 end
125 end
115
126
116 def assert_query_statement_includes(query, condition)
127 def assert_query_statement_includes(query, condition)
117 assert_include condition, query.statement
128 assert_include condition, query.statement
118 end
129 end
119
130
120 def assert_query_result(expected, query)
131 def assert_query_result(expected, query)
121 assert_nothing_raised do
132 assert_nothing_raised do
122 assert_equal expected.map(&:id).sort, query.issues.map(&:id).sort
133 assert_equal expected.map(&:id).sort, query.issues.map(&:id).sort
123 assert_equal expected.size, query.issue_count
134 assert_equal expected.size, query.issue_count
124 end
135 end
125 end
136 end
126
137
127 def test_query_should_allow_shared_versions_for_a_project_query
138 def test_query_should_allow_shared_versions_for_a_project_query
128 subproject_version = Version.find(4)
139 subproject_version = Version.find(4)
129 query = IssueQuery.new(:project => Project.find(1), :name => '_')
140 query = IssueQuery.new(:project => Project.find(1), :name => '_')
130 query.add_filter('fixed_version_id', '=', [subproject_version.id.to_s])
141 query.add_filter('fixed_version_id', '=', [subproject_version.id.to_s])
131
142
132 assert query.statement.include?("#{Issue.table_name}.fixed_version_id IN ('4')")
143 assert query.statement.include?("#{Issue.table_name}.fixed_version_id IN ('4')")
133 end
144 end
134
145
135 def test_query_with_multiple_custom_fields
146 def test_query_with_multiple_custom_fields
136 query = IssueQuery.find(1)
147 query = IssueQuery.find(1)
137 assert query.valid?
148 assert query.valid?
138 assert query.statement.include?("#{CustomValue.table_name}.value IN ('MySQL')")
149 assert query.statement.include?("#{CustomValue.table_name}.value IN ('MySQL')")
139 issues = find_issues_with_query(query)
150 issues = find_issues_with_query(query)
140 assert_equal 1, issues.length
151 assert_equal 1, issues.length
141 assert_equal Issue.find(3), issues.first
152 assert_equal Issue.find(3), issues.first
142 end
153 end
143
154
144 def test_operator_none
155 def test_operator_none
145 query = IssueQuery.new(:project => Project.find(1), :name => '_')
156 query = IssueQuery.new(:project => Project.find(1), :name => '_')
146 query.add_filter('fixed_version_id', '!*', [''])
157 query.add_filter('fixed_version_id', '!*', [''])
147 query.add_filter('cf_1', '!*', [''])
158 query.add_filter('cf_1', '!*', [''])
148 assert query.statement.include?("#{Issue.table_name}.fixed_version_id IS NULL")
159 assert query.statement.include?("#{Issue.table_name}.fixed_version_id IS NULL")
149 assert query.statement.include?("#{CustomValue.table_name}.value IS NULL OR #{CustomValue.table_name}.value = ''")
160 assert query.statement.include?("#{CustomValue.table_name}.value IS NULL OR #{CustomValue.table_name}.value = ''")
150 find_issues_with_query(query)
161 find_issues_with_query(query)
151 end
162 end
152
163
153 def test_operator_none_for_integer
164 def test_operator_none_for_integer
154 query = IssueQuery.new(:project => Project.find(1), :name => '_')
165 query = IssueQuery.new(:project => Project.find(1), :name => '_')
155 query.add_filter('estimated_hours', '!*', [''])
166 query.add_filter('estimated_hours', '!*', [''])
156 issues = find_issues_with_query(query)
167 issues = find_issues_with_query(query)
157 assert !issues.empty?
168 assert !issues.empty?
158 assert issues.all? {|i| !i.estimated_hours}
169 assert issues.all? {|i| !i.estimated_hours}
159 end
170 end
160
171
161 def test_operator_none_for_date
172 def test_operator_none_for_date
162 query = IssueQuery.new(:project => Project.find(1), :name => '_')
173 query = IssueQuery.new(:project => Project.find(1), :name => '_')
163 query.add_filter('start_date', '!*', [''])
174 query.add_filter('start_date', '!*', [''])
164 issues = find_issues_with_query(query)
175 issues = find_issues_with_query(query)
165 assert !issues.empty?
176 assert !issues.empty?
166 assert issues.all? {|i| i.start_date.nil?}
177 assert issues.all? {|i| i.start_date.nil?}
167 end
178 end
168
179
169 def test_operator_none_for_string_custom_field
180 def test_operator_none_for_string_custom_field
170 query = IssueQuery.new(:project => Project.find(1), :name => '_')
181 query = IssueQuery.new(:project => Project.find(1), :name => '_')
171 query.add_filter('cf_2', '!*', [''])
182 query.add_filter('cf_2', '!*', [''])
172 assert query.has_filter?('cf_2')
183 assert query.has_filter?('cf_2')
173 issues = find_issues_with_query(query)
184 issues = find_issues_with_query(query)
174 assert !issues.empty?
185 assert !issues.empty?
175 assert issues.all? {|i| i.custom_field_value(2).blank?}
186 assert issues.all? {|i| i.custom_field_value(2).blank?}
176 end
187 end
177
188
178 def test_operator_all
189 def test_operator_all
179 query = IssueQuery.new(:project => Project.find(1), :name => '_')
190 query = IssueQuery.new(:project => Project.find(1), :name => '_')
180 query.add_filter('fixed_version_id', '*', [''])
191 query.add_filter('fixed_version_id', '*', [''])
181 query.add_filter('cf_1', '*', [''])
192 query.add_filter('cf_1', '*', [''])
182 assert query.statement.include?("#{Issue.table_name}.fixed_version_id IS NOT NULL")
193 assert query.statement.include?("#{Issue.table_name}.fixed_version_id IS NOT NULL")
183 assert query.statement.include?("#{CustomValue.table_name}.value IS NOT NULL AND #{CustomValue.table_name}.value <> ''")
194 assert query.statement.include?("#{CustomValue.table_name}.value IS NOT NULL AND #{CustomValue.table_name}.value <> ''")
184 find_issues_with_query(query)
195 find_issues_with_query(query)
185 end
196 end
186
197
187 def test_operator_all_for_date
198 def test_operator_all_for_date
188 query = IssueQuery.new(:project => Project.find(1), :name => '_')
199 query = IssueQuery.new(:project => Project.find(1), :name => '_')
189 query.add_filter('start_date', '*', [''])
200 query.add_filter('start_date', '*', [''])
190 issues = find_issues_with_query(query)
201 issues = find_issues_with_query(query)
191 assert !issues.empty?
202 assert !issues.empty?
192 assert issues.all? {|i| i.start_date.present?}
203 assert issues.all? {|i| i.start_date.present?}
193 end
204 end
194
205
195 def test_operator_all_for_string_custom_field
206 def test_operator_all_for_string_custom_field
196 query = IssueQuery.new(:project => Project.find(1), :name => '_')
207 query = IssueQuery.new(:project => Project.find(1), :name => '_')
197 query.add_filter('cf_2', '*', [''])
208 query.add_filter('cf_2', '*', [''])
198 assert query.has_filter?('cf_2')
209 assert query.has_filter?('cf_2')
199 issues = find_issues_with_query(query)
210 issues = find_issues_with_query(query)
200 assert !issues.empty?
211 assert !issues.empty?
201 assert issues.all? {|i| i.custom_field_value(2).present?}
212 assert issues.all? {|i| i.custom_field_value(2).present?}
202 end
213 end
203
214
204 def test_numeric_filter_should_not_accept_non_numeric_values
215 def test_numeric_filter_should_not_accept_non_numeric_values
205 query = IssueQuery.new(:name => '_')
216 query = IssueQuery.new(:name => '_')
206 query.add_filter('estimated_hours', '=', ['a'])
217 query.add_filter('estimated_hours', '=', ['a'])
207
218
208 assert query.has_filter?('estimated_hours')
219 assert query.has_filter?('estimated_hours')
209 assert !query.valid?
220 assert !query.valid?
210 end
221 end
211
222
212 def test_operator_is_on_float
223 def test_operator_is_on_float
213 Issue.where(:id => 2).update_all("estimated_hours = 171.2")
224 Issue.where(:id => 2).update_all("estimated_hours = 171.2")
214 query = IssueQuery.new(:name => '_')
225 query = IssueQuery.new(:name => '_')
215 query.add_filter('estimated_hours', '=', ['171.20'])
226 query.add_filter('estimated_hours', '=', ['171.20'])
216 issues = find_issues_with_query(query)
227 issues = find_issues_with_query(query)
217 assert_equal 1, issues.size
228 assert_equal 1, issues.size
218 assert_equal 2, issues.first.id
229 assert_equal 2, issues.first.id
219 end
230 end
220
231
221 def test_operator_is_on_integer_custom_field
232 def test_operator_is_on_integer_custom_field
222 f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_for_all => true, :is_filter => true, :trackers => Tracker.all)
233 f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_for_all => true, :is_filter => true, :trackers => Tracker.all)
223 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => '7')
234 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => '7')
224 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '12')
235 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '12')
225 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
236 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
226
237
227 query = IssueQuery.new(:name => '_')
238 query = IssueQuery.new(:name => '_')
228 query.add_filter("cf_#{f.id}", '=', ['12'])
239 query.add_filter("cf_#{f.id}", '=', ['12'])
229 issues = find_issues_with_query(query)
240 issues = find_issues_with_query(query)
230 assert_equal 1, issues.size
241 assert_equal 1, issues.size
231 assert_equal 2, issues.first.id
242 assert_equal 2, issues.first.id
232 end
243 end
233
244
234 def test_operator_is_on_integer_custom_field_should_accept_negative_value
245 def test_operator_is_on_integer_custom_field_should_accept_negative_value
235 f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_for_all => true, :is_filter => true, :trackers => Tracker.all)
246 f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_for_all => true, :is_filter => true, :trackers => Tracker.all)
236 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => '7')
247 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => '7')
237 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '-12')
248 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '-12')
238 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
249 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
239
250
240 query = IssueQuery.new(:name => '_')
251 query = IssueQuery.new(:name => '_')
241 query.add_filter("cf_#{f.id}", '=', ['-12'])
252 query.add_filter("cf_#{f.id}", '=', ['-12'])
242 assert query.valid?
253 assert query.valid?
243 issues = find_issues_with_query(query)
254 issues = find_issues_with_query(query)
244 assert_equal 1, issues.size
255 assert_equal 1, issues.size
245 assert_equal 2, issues.first.id
256 assert_equal 2, issues.first.id
246 end
257 end
247
258
248 def test_operator_is_on_float_custom_field
259 def test_operator_is_on_float_custom_field
249 f = IssueCustomField.create!(:name => 'filter', :field_format => 'float', :is_filter => true, :is_for_all => true, :trackers => Tracker.all)
260 f = IssueCustomField.create!(:name => 'filter', :field_format => 'float', :is_filter => true, :is_for_all => true, :trackers => Tracker.all)
250 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => '7.3')
261 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => '7.3')
251 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '12.7')
262 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '12.7')
252 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
263 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
253
264
254 query = IssueQuery.new(:name => '_')
265 query = IssueQuery.new(:name => '_')
255 query.add_filter("cf_#{f.id}", '=', ['12.7'])
266 query.add_filter("cf_#{f.id}", '=', ['12.7'])
256 issues = find_issues_with_query(query)
267 issues = find_issues_with_query(query)
257 assert_equal 1, issues.size
268 assert_equal 1, issues.size
258 assert_equal 2, issues.first.id
269 assert_equal 2, issues.first.id
259 end
270 end
260
271
261 def test_operator_is_on_float_custom_field_should_accept_negative_value
272 def test_operator_is_on_float_custom_field_should_accept_negative_value
262 f = IssueCustomField.create!(:name => 'filter', :field_format => 'float', :is_filter => true, :is_for_all => true, :trackers => Tracker.all)
273 f = IssueCustomField.create!(:name => 'filter', :field_format => 'float', :is_filter => true, :is_for_all => true, :trackers => Tracker.all)
263 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => '7.3')
274 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => '7.3')
264 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '-12.7')
275 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '-12.7')
265 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
276 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
266
277
267 query = IssueQuery.new(:name => '_')
278 query = IssueQuery.new(:name => '_')
268 query.add_filter("cf_#{f.id}", '=', ['-12.7'])
279 query.add_filter("cf_#{f.id}", '=', ['-12.7'])
269 assert query.valid?
280 assert query.valid?
270 issues = find_issues_with_query(query)
281 issues = find_issues_with_query(query)
271 assert_equal 1, issues.size
282 assert_equal 1, issues.size
272 assert_equal 2, issues.first.id
283 assert_equal 2, issues.first.id
273 end
284 end
274
285
275 def test_operator_is_on_multi_list_custom_field
286 def test_operator_is_on_multi_list_custom_field
276 f = IssueCustomField.create!(:name => 'filter', :field_format => 'list', :is_filter => true, :is_for_all => true,
287 f = IssueCustomField.create!(:name => 'filter', :field_format => 'list', :is_filter => true, :is_for_all => true,
277 :possible_values => ['value1', 'value2', 'value3'], :multiple => true, :trackers => Tracker.all)
288 :possible_values => ['value1', 'value2', 'value3'], :multiple => true, :trackers => Tracker.all)
278 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => 'value1')
289 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => 'value1')
279 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => 'value2')
290 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => 'value2')
280 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => 'value1')
291 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => 'value1')
281
292
282 query = IssueQuery.new(:name => '_')
293 query = IssueQuery.new(:name => '_')
283 query.add_filter("cf_#{f.id}", '=', ['value1'])
294 query.add_filter("cf_#{f.id}", '=', ['value1'])
284 issues = find_issues_with_query(query)
295 issues = find_issues_with_query(query)
285 assert_equal [1, 3], issues.map(&:id).sort
296 assert_equal [1, 3], issues.map(&:id).sort
286
297
287 query = IssueQuery.new(:name => '_')
298 query = IssueQuery.new(:name => '_')
288 query.add_filter("cf_#{f.id}", '=', ['value2'])
299 query.add_filter("cf_#{f.id}", '=', ['value2'])
289 issues = find_issues_with_query(query)
300 issues = find_issues_with_query(query)
290 assert_equal [1], issues.map(&:id).sort
301 assert_equal [1], issues.map(&:id).sort
291 end
302 end
292
303
293 def test_operator_is_not_on_multi_list_custom_field
304 def test_operator_is_not_on_multi_list_custom_field
294 f = IssueCustomField.create!(:name => 'filter', :field_format => 'list', :is_filter => true, :is_for_all => true,
305 f = IssueCustomField.create!(:name => 'filter', :field_format => 'list', :is_filter => true, :is_for_all => true,
295 :possible_values => ['value1', 'value2', 'value3'], :multiple => true, :trackers => Tracker.all)
306 :possible_values => ['value1', 'value2', 'value3'], :multiple => true, :trackers => Tracker.all)
296 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => 'value1')
307 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => 'value1')
297 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => 'value2')
308 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => 'value2')
298 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => 'value1')
309 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => 'value1')
299
310
300 query = IssueQuery.new(:name => '_')
311 query = IssueQuery.new(:name => '_')
301 query.add_filter("cf_#{f.id}", '!', ['value1'])
312 query.add_filter("cf_#{f.id}", '!', ['value1'])
302 issues = find_issues_with_query(query)
313 issues = find_issues_with_query(query)
303 assert !issues.map(&:id).include?(1)
314 assert !issues.map(&:id).include?(1)
304 assert !issues.map(&:id).include?(3)
315 assert !issues.map(&:id).include?(3)
305
316
306 query = IssueQuery.new(:name => '_')
317 query = IssueQuery.new(:name => '_')
307 query.add_filter("cf_#{f.id}", '!', ['value2'])
318 query.add_filter("cf_#{f.id}", '!', ['value2'])
308 issues = find_issues_with_query(query)
319 issues = find_issues_with_query(query)
309 assert !issues.map(&:id).include?(1)
320 assert !issues.map(&:id).include?(1)
310 assert issues.map(&:id).include?(3)
321 assert issues.map(&:id).include?(3)
311 end
322 end
312
323
313 def test_operator_is_on_is_private_field
324 def test_operator_is_on_is_private_field
314 # is_private filter only available for those who can set issues private
325 # is_private filter only available for those who can set issues private
315 User.current = User.find(2)
326 User.current = User.find(2)
316
327
317 query = IssueQuery.new(:name => '_')
328 query = IssueQuery.new(:name => '_')
318 assert query.available_filters.key?('is_private')
329 assert query.available_filters.key?('is_private')
319
330
320 query.add_filter("is_private", '=', ['1'])
331 query.add_filter("is_private", '=', ['1'])
321 issues = find_issues_with_query(query)
332 issues = find_issues_with_query(query)
322 assert issues.any?
333 assert issues.any?
323 assert_nil issues.detect {|issue| !issue.is_private?}
334 assert_nil issues.detect {|issue| !issue.is_private?}
324 ensure
335 ensure
325 User.current = nil
336 User.current = nil
326 end
337 end
327
338
328 def test_operator_is_not_on_is_private_field
339 def test_operator_is_not_on_is_private_field
329 # is_private filter only available for those who can set issues private
340 # is_private filter only available for those who can set issues private
330 User.current = User.find(2)
341 User.current = User.find(2)
331
342
332 query = IssueQuery.new(:name => '_')
343 query = IssueQuery.new(:name => '_')
333 assert query.available_filters.key?('is_private')
344 assert query.available_filters.key?('is_private')
334
345
335 query.add_filter("is_private", '!', ['1'])
346 query.add_filter("is_private", '!', ['1'])
336 issues = find_issues_with_query(query)
347 issues = find_issues_with_query(query)
337 assert issues.any?
348 assert issues.any?
338 assert_nil issues.detect {|issue| issue.is_private?}
349 assert_nil issues.detect {|issue| issue.is_private?}
339 ensure
350 ensure
340 User.current = nil
351 User.current = nil
341 end
352 end
342
353
343 def test_operator_greater_than
354 def test_operator_greater_than
344 query = IssueQuery.new(:project => Project.find(1), :name => '_')
355 query = IssueQuery.new(:project => Project.find(1), :name => '_')
345 query.add_filter('done_ratio', '>=', ['40'])
356 query.add_filter('done_ratio', '>=', ['40'])
346 assert query.statement.include?("#{Issue.table_name}.done_ratio >= 40.0")
357 assert query.statement.include?("#{Issue.table_name}.done_ratio >= 40.0")
347 find_issues_with_query(query)
358 find_issues_with_query(query)
348 end
359 end
349
360
350 def test_operator_greater_than_a_float
361 def test_operator_greater_than_a_float
351 query = IssueQuery.new(:project => Project.find(1), :name => '_')
362 query = IssueQuery.new(:project => Project.find(1), :name => '_')
352 query.add_filter('estimated_hours', '>=', ['40.5'])
363 query.add_filter('estimated_hours', '>=', ['40.5'])
353 assert query.statement.include?("#{Issue.table_name}.estimated_hours >= 40.5")
364 assert query.statement.include?("#{Issue.table_name}.estimated_hours >= 40.5")
354 find_issues_with_query(query)
365 find_issues_with_query(query)
355 end
366 end
356
367
357 def test_operator_greater_than_on_int_custom_field
368 def test_operator_greater_than_on_int_custom_field
358 f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_filter => true, :is_for_all => true, :trackers => Tracker.all)
369 f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_filter => true, :is_for_all => true, :trackers => Tracker.all)
359 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => '7')
370 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => '7')
360 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '12')
371 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '12')
361 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
372 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
362
373
363 query = IssueQuery.new(:project => Project.find(1), :name => '_')
374 query = IssueQuery.new(:project => Project.find(1), :name => '_')
364 query.add_filter("cf_#{f.id}", '>=', ['8'])
375 query.add_filter("cf_#{f.id}", '>=', ['8'])
365 issues = find_issues_with_query(query)
376 issues = find_issues_with_query(query)
366 assert_equal 1, issues.size
377 assert_equal 1, issues.size
367 assert_equal 2, issues.first.id
378 assert_equal 2, issues.first.id
368 end
379 end
369
380
370 def test_operator_lesser_than
381 def test_operator_lesser_than
371 query = IssueQuery.new(:project => Project.find(1), :name => '_')
382 query = IssueQuery.new(:project => Project.find(1), :name => '_')
372 query.add_filter('done_ratio', '<=', ['30'])
383 query.add_filter('done_ratio', '<=', ['30'])
373 assert query.statement.include?("#{Issue.table_name}.done_ratio <= 30.0")
384 assert query.statement.include?("#{Issue.table_name}.done_ratio <= 30.0")
374 find_issues_with_query(query)
385 find_issues_with_query(query)
375 end
386 end
376
387
377 def test_operator_lesser_than_on_custom_field
388 def test_operator_lesser_than_on_custom_field
378 f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_filter => true, :is_for_all => true)
389 f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_filter => true, :is_for_all => true)
379 query = IssueQuery.new(:project => Project.find(1), :name => '_')
390 query = IssueQuery.new(:project => Project.find(1), :name => '_')
380 query.add_filter("cf_#{f.id}", '<=', ['30'])
391 query.add_filter("cf_#{f.id}", '<=', ['30'])
381 assert_match /CAST.+ <= 30\.0/, query.statement
392 assert_match /CAST.+ <= 30\.0/, query.statement
382 find_issues_with_query(query)
393 find_issues_with_query(query)
383 end
394 end
384
395
385 def test_operator_lesser_than_on_date_custom_field
396 def test_operator_lesser_than_on_date_custom_field
386 f = IssueCustomField.create!(:name => 'filter', :field_format => 'date', :is_filter => true, :is_for_all => true, :trackers => Tracker.all)
397 f = IssueCustomField.create!(:name => 'filter', :field_format => 'date', :is_filter => true, :is_for_all => true, :trackers => Tracker.all)
387 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => '2013-04-11')
398 CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => '2013-04-11')
388 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '2013-05-14')
399 CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '2013-05-14')
389 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
400 CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
390
401
391 query = IssueQuery.new(:project => Project.find(1), :name => '_')
402 query = IssueQuery.new(:project => Project.find(1), :name => '_')
392 query.add_filter("cf_#{f.id}", '<=', ['2013-05-01'])
403 query.add_filter("cf_#{f.id}", '<=', ['2013-05-01'])
393 issue_ids = find_issues_with_query(query).map(&:id)
404 issue_ids = find_issues_with_query(query).map(&:id)
394 assert_include 1, issue_ids
405 assert_include 1, issue_ids
395 assert_not_include 2, issue_ids
406 assert_not_include 2, issue_ids
396 assert_not_include 3, issue_ids
407 assert_not_include 3, issue_ids
397 end
408 end
398
409
399 def test_operator_between
410 def test_operator_between
400 query = IssueQuery.new(:project => Project.find(1), :name => '_')
411 query = IssueQuery.new(:project => Project.find(1), :name => '_')
401 query.add_filter('done_ratio', '><', ['30', '40'])
412 query.add_filter('done_ratio', '><', ['30', '40'])
402 assert_include "#{Issue.table_name}.done_ratio BETWEEN 30.0 AND 40.0", query.statement
413 assert_include "#{Issue.table_name}.done_ratio BETWEEN 30.0 AND 40.0", query.statement
403 find_issues_with_query(query)
414 find_issues_with_query(query)
404 end
415 end
405
416
406 def test_operator_between_on_custom_field
417 def test_operator_between_on_custom_field
407 f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_filter => true, :is_for_all => true)
418 f = IssueCustomField.create!(:name => 'filter', :field_format => 'int', :is_filter => true, :is_for_all => true)
408 query = IssueQuery.new(:project => Project.find(1), :name => '_')
419 query = IssueQuery.new(:project => Project.find(1), :name => '_')
409 query.add_filter("cf_#{f.id}", '><', ['30', '40'])
420 query.add_filter("cf_#{f.id}", '><', ['30', '40'])
410 assert_match /CAST.+ BETWEEN 30.0 AND 40.0/, query.statement
421 assert_match /CAST.+ BETWEEN 30.0 AND 40.0/, query.statement
411 find_issues_with_query(query)
422 find_issues_with_query(query)
412 end
423 end
413
424
414 def test_date_filter_should_not_accept_non_date_values
425 def test_date_filter_should_not_accept_non_date_values
415 query = IssueQuery.new(:name => '_')
426 query = IssueQuery.new(:name => '_')
416 query.add_filter('created_on', '=', ['a'])
427 query.add_filter('created_on', '=', ['a'])
417
428
418 assert query.has_filter?('created_on')
429 assert query.has_filter?('created_on')
419 assert !query.valid?
430 assert !query.valid?
420 end
431 end
421
432
422 def test_date_filter_should_not_accept_invalid_date_values
433 def test_date_filter_should_not_accept_invalid_date_values
423 query = IssueQuery.new(:name => '_')
434 query = IssueQuery.new(:name => '_')
424 query.add_filter('created_on', '=', ['2011-01-34'])
435 query.add_filter('created_on', '=', ['2011-01-34'])
425
436
426 assert query.has_filter?('created_on')
437 assert query.has_filter?('created_on')
427 assert !query.valid?
438 assert !query.valid?
428 end
439 end
429
440
430 def test_relative_date_filter_should_not_accept_non_integer_values
441 def test_relative_date_filter_should_not_accept_non_integer_values
431 query = IssueQuery.new(:name => '_')
442 query = IssueQuery.new(:name => '_')
432 query.add_filter('created_on', '>t-', ['a'])
443 query.add_filter('created_on', '>t-', ['a'])
433
444
434 assert query.has_filter?('created_on')
445 assert query.has_filter?('created_on')
435 assert !query.valid?
446 assert !query.valid?
436 end
447 end
437
448
438 def test_operator_date_equals
449 def test_operator_date_equals
439 query = IssueQuery.new(:name => '_')
450 query = IssueQuery.new(:name => '_')
440 query.add_filter('due_date', '=', ['2011-07-10'])
451 query.add_filter('due_date', '=', ['2011-07-10'])
441 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
452 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
442 find_issues_with_query(query)
453 find_issues_with_query(query)
443 end
454 end
444
455
445 def test_operator_date_lesser_than
456 def test_operator_date_lesser_than
446 query = IssueQuery.new(:name => '_')
457 query = IssueQuery.new(:name => '_')
447 query.add_filter('due_date', '<=', ['2011-07-10'])
458 query.add_filter('due_date', '<=', ['2011-07-10'])
448 assert_match /issues\.due_date <= '2011-07-10 23:59:59(\.9+)?/, query.statement
459 assert_match /issues\.due_date <= '2011-07-10 23:59:59(\.9+)?/, query.statement
449 find_issues_with_query(query)
460 find_issues_with_query(query)
450 end
461 end
451
462
452 def test_operator_date_lesser_than_with_timestamp
463 def test_operator_date_lesser_than_with_timestamp
453 query = IssueQuery.new(:name => '_')
464 query = IssueQuery.new(:name => '_')
454 query.add_filter('updated_on', '<=', ['2011-07-10T19:13:52'])
465 query.add_filter('updated_on', '<=', ['2011-07-10T19:13:52'])
455 assert_match /issues\.updated_on <= '2011-07-10 19:13:52/, query.statement
466 assert_match /issues\.updated_on <= '2011-07-10 19:13:52/, query.statement
456 find_issues_with_query(query)
467 find_issues_with_query(query)
457 end
468 end
458
469
459 def test_operator_date_greater_than
470 def test_operator_date_greater_than
460 query = IssueQuery.new(:name => '_')
471 query = IssueQuery.new(:name => '_')
461 query.add_filter('due_date', '>=', ['2011-07-10'])
472 query.add_filter('due_date', '>=', ['2011-07-10'])
462 assert_match /issues\.due_date > '2011-07-09 23:59:59(\.9+)?'/, query.statement
473 assert_match /issues\.due_date > '2011-07-09 23:59:59(\.9+)?'/, query.statement
463 find_issues_with_query(query)
474 find_issues_with_query(query)
464 end
475 end
465
476
466 def test_operator_date_greater_than_with_timestamp
477 def test_operator_date_greater_than_with_timestamp
467 query = IssueQuery.new(:name => '_')
478 query = IssueQuery.new(:name => '_')
468 query.add_filter('updated_on', '>=', ['2011-07-10T19:13:52'])
479 query.add_filter('updated_on', '>=', ['2011-07-10T19:13:52'])
469 assert_match /issues\.updated_on > '2011-07-10 19:13:51(\.0+)?'/, query.statement
480 assert_match /issues\.updated_on > '2011-07-10 19:13:51(\.0+)?'/, query.statement
470 find_issues_with_query(query)
481 find_issues_with_query(query)
471 end
482 end
472
483
473 def test_operator_date_between
484 def test_operator_date_between
474 query = IssueQuery.new(:name => '_')
485 query = IssueQuery.new(:name => '_')
475 query.add_filter('due_date', '><', ['2011-06-23', '2011-07-10'])
486 query.add_filter('due_date', '><', ['2011-06-23', '2011-07-10'])
476 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
487 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
477 find_issues_with_query(query)
488 find_issues_with_query(query)
478 end
489 end
479
490
480 def test_operator_in_more_than
491 def test_operator_in_more_than
481 Issue.find(7).update_attribute(:due_date, (Date.today + 15))
492 Issue.find(7).update_attribute(:due_date, (Date.today + 15))
482 query = IssueQuery.new(:project => Project.find(1), :name => '_')
493 query = IssueQuery.new(:project => Project.find(1), :name => '_')
483 query.add_filter('due_date', '>t+', ['15'])
494 query.add_filter('due_date', '>t+', ['15'])
484 issues = find_issues_with_query(query)
495 issues = find_issues_with_query(query)
485 assert !issues.empty?
496 assert !issues.empty?
486 issues.each {|issue| assert(issue.due_date >= (Date.today + 15))}
497 issues.each {|issue| assert(issue.due_date >= (Date.today + 15))}
487 end
498 end
488
499
489 def test_operator_in_less_than
500 def test_operator_in_less_than
490 query = IssueQuery.new(:project => Project.find(1), :name => '_')
501 query = IssueQuery.new(:project => Project.find(1), :name => '_')
491 query.add_filter('due_date', '<t+', ['15'])
502 query.add_filter('due_date', '<t+', ['15'])
492 issues = find_issues_with_query(query)
503 issues = find_issues_with_query(query)
493 assert !issues.empty?
504 assert !issues.empty?
494 issues.each {|issue| assert(issue.due_date <= (Date.today + 15))}
505 issues.each {|issue| assert(issue.due_date <= (Date.today + 15))}
495 end
506 end
496
507
497 def test_operator_in_the_next_days
508 def test_operator_in_the_next_days
498 query = IssueQuery.new(:project => Project.find(1), :name => '_')
509 query = IssueQuery.new(:project => Project.find(1), :name => '_')
499 query.add_filter('due_date', '><t+', ['15'])
510 query.add_filter('due_date', '><t+', ['15'])
500 issues = find_issues_with_query(query)
511 issues = find_issues_with_query(query)
501 assert !issues.empty?
512 assert !issues.empty?
502 issues.each {|issue| assert(issue.due_date >= Date.today && issue.due_date <= (Date.today + 15))}
513 issues.each {|issue| assert(issue.due_date >= Date.today && issue.due_date <= (Date.today + 15))}
503 end
514 end
504
515
505 def test_operator_less_than_ago
516 def test_operator_less_than_ago
506 Issue.find(7).update_attribute(:due_date, (Date.today - 3))
517 Issue.find(7).update_attribute(:due_date, (Date.today - 3))
507 query = IssueQuery.new(:project => Project.find(1), :name => '_')
518 query = IssueQuery.new(:project => Project.find(1), :name => '_')
508 query.add_filter('due_date', '>t-', ['3'])
519 query.add_filter('due_date', '>t-', ['3'])
509 issues = find_issues_with_query(query)
520 issues = find_issues_with_query(query)
510 assert !issues.empty?
521 assert !issues.empty?
511 issues.each {|issue| assert(issue.due_date >= (Date.today - 3))}
522 issues.each {|issue| assert(issue.due_date >= (Date.today - 3))}
512 end
523 end
513
524
514 def test_operator_in_the_past_days
525 def test_operator_in_the_past_days
515 Issue.find(7).update_attribute(:due_date, (Date.today - 3))
526 Issue.find(7).update_attribute(:due_date, (Date.today - 3))
516 query = IssueQuery.new(:project => Project.find(1), :name => '_')
527 query = IssueQuery.new(:project => Project.find(1), :name => '_')
517 query.add_filter('due_date', '><t-', ['3'])
528 query.add_filter('due_date', '><t-', ['3'])
518 issues = find_issues_with_query(query)
529 issues = find_issues_with_query(query)
519 assert !issues.empty?
530 assert !issues.empty?
520 issues.each {|issue| assert(issue.due_date >= (Date.today - 3) && issue.due_date <= Date.today)}
531 issues.each {|issue| assert(issue.due_date >= (Date.today - 3) && issue.due_date <= Date.today)}
521 end
532 end
522
533
523 def test_operator_more_than_ago
534 def test_operator_more_than_ago
524 Issue.find(7).update_attribute(:due_date, (Date.today - 10))
535 Issue.find(7).update_attribute(:due_date, (Date.today - 10))
525 query = IssueQuery.new(:project => Project.find(1), :name => '_')
536 query = IssueQuery.new(:project => Project.find(1), :name => '_')
526 query.add_filter('due_date', '<t-', ['10'])
537 query.add_filter('due_date', '<t-', ['10'])
527 assert query.statement.include?("#{Issue.table_name}.due_date <=")
538 assert query.statement.include?("#{Issue.table_name}.due_date <=")
528 issues = find_issues_with_query(query)
539 issues = find_issues_with_query(query)
529 assert !issues.empty?
540 assert !issues.empty?
530 issues.each {|issue| assert(issue.due_date <= (Date.today - 10))}
541 issues.each {|issue| assert(issue.due_date <= (Date.today - 10))}
531 end
542 end
532
543
533 def test_operator_in
544 def test_operator_in
534 Issue.find(7).update_attribute(:due_date, (Date.today + 2))
545 Issue.find(7).update_attribute(:due_date, (Date.today + 2))
535 query = IssueQuery.new(:project => Project.find(1), :name => '_')
546 query = IssueQuery.new(:project => Project.find(1), :name => '_')
536 query.add_filter('due_date', 't+', ['2'])
547 query.add_filter('due_date', 't+', ['2'])
537 issues = find_issues_with_query(query)
548 issues = find_issues_with_query(query)
538 assert !issues.empty?
549 assert !issues.empty?
539 issues.each {|issue| assert_equal((Date.today + 2), issue.due_date)}
550 issues.each {|issue| assert_equal((Date.today + 2), issue.due_date)}
540 end
551 end
541
552
542 def test_operator_ago
553 def test_operator_ago
543 Issue.find(7).update_attribute(:due_date, (Date.today - 3))
554 Issue.find(7).update_attribute(:due_date, (Date.today - 3))
544 query = IssueQuery.new(:project => Project.find(1), :name => '_')
555 query = IssueQuery.new(:project => Project.find(1), :name => '_')
545 query.add_filter('due_date', 't-', ['3'])
556 query.add_filter('due_date', 't-', ['3'])
546 issues = find_issues_with_query(query)
557 issues = find_issues_with_query(query)
547 assert !issues.empty?
558 assert !issues.empty?
548 issues.each {|issue| assert_equal((Date.today - 3), issue.due_date)}
559 issues.each {|issue| assert_equal((Date.today - 3), issue.due_date)}
549 end
560 end
550
561
551 def test_operator_today
562 def test_operator_today
552 query = IssueQuery.new(:project => Project.find(1), :name => '_')
563 query = IssueQuery.new(:project => Project.find(1), :name => '_')
553 query.add_filter('due_date', 't', [''])
564 query.add_filter('due_date', 't', [''])
554 issues = find_issues_with_query(query)
565 issues = find_issues_with_query(query)
555 assert !issues.empty?
566 assert !issues.empty?
556 issues.each {|issue| assert_equal Date.today, issue.due_date}
567 issues.each {|issue| assert_equal Date.today, issue.due_date}
557 end
568 end
558
569
559 def test_operator_this_week_on_date
570 def test_operator_date_periods
560 query = IssueQuery.new(:project => Project.find(1), :name => '_')
571 %w(t ld w lw l2w m lm y).each do |operator|
561 query.add_filter('due_date', 'w', [''])
572 query = IssueQuery.new(:name => '_')
562 find_issues_with_query(query)
573 query.add_filter('due_date', operator, [''])
574 assert query.valid?
575 assert query.issues
576 end
563 end
577 end
564
578
565 def test_operator_this_week_on_datetime
579 def test_operator_datetime_periods
566 query = IssueQuery.new(:project => Project.find(1), :name => '_')
580 %w(t ld w lw l2w m lm y).each do |operator|
567 query.add_filter('created_on', 'w', [''])
581 query = IssueQuery.new(:name => '_')
568 find_issues_with_query(query)
582 query.add_filter('created_on', operator, [''])
583 assert query.valid?
584 assert query.issues
585 end
569 end
586 end
570
587
571 def test_operator_contains
588 def test_operator_contains
572 query = IssueQuery.new(:project => Project.find(1), :name => '_')
589 query = IssueQuery.new(:project => Project.find(1), :name => '_')
573 query.add_filter('subject', '~', ['uNable'])
590 query.add_filter('subject', '~', ['uNable'])
574 assert query.statement.include?("LOWER(#{Issue.table_name}.subject) LIKE '%unable%'")
591 assert query.statement.include?("LOWER(#{Issue.table_name}.subject) LIKE '%unable%'")
575 result = find_issues_with_query(query)
592 result = find_issues_with_query(query)
576 assert result.empty?
593 assert result.empty?
577 result.each {|issue| assert issue.subject.downcase.include?('unable') }
594 result.each {|issue| assert issue.subject.downcase.include?('unable') }
578 end
595 end
579
596
580 def test_range_for_this_week_with_week_starting_on_monday
597 def test_range_for_this_week_with_week_starting_on_monday
581 I18n.locale = :fr
598 I18n.locale = :fr
582 assert_equal '1', I18n.t(:general_first_day_of_week)
599 assert_equal '1', I18n.t(:general_first_day_of_week)
583
600
584 Date.stubs(:today).returns(Date.parse('2011-04-29'))
601 Date.stubs(:today).returns(Date.parse('2011-04-29'))
585
602
586 query = IssueQuery.new(:project => Project.find(1), :name => '_')
603 query = IssueQuery.new(:project => Project.find(1), :name => '_')
587 query.add_filter('due_date', 'w', [''])
604 query.add_filter('due_date', 'w', [''])
588 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}"
605 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}"
589 I18n.locale = :en
606 I18n.locale = :en
590 end
607 end
591
608
592 def test_range_for_this_week_with_week_starting_on_sunday
609 def test_range_for_this_week_with_week_starting_on_sunday
593 I18n.locale = :en
610 I18n.locale = :en
594 assert_equal '7', I18n.t(:general_first_day_of_week)
611 assert_equal '7', I18n.t(:general_first_day_of_week)
595
612
596 Date.stubs(:today).returns(Date.parse('2011-04-29'))
613 Date.stubs(:today).returns(Date.parse('2011-04-29'))
597
614
598 query = IssueQuery.new(:project => Project.find(1), :name => '_')
615 query = IssueQuery.new(:project => Project.find(1), :name => '_')
599 query.add_filter('due_date', 'w', [''])
616 query.add_filter('due_date', 'w', [''])
600 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}"
617 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}"
601 end
618 end
602
619
603 def test_operator_does_not_contains
620 def test_operator_does_not_contains
604 query = IssueQuery.new(:project => Project.find(1), :name => '_')
621 query = IssueQuery.new(:project => Project.find(1), :name => '_')
605 query.add_filter('subject', '!~', ['uNable'])
622 query.add_filter('subject', '!~', ['uNable'])
606 assert query.statement.include?("LOWER(#{Issue.table_name}.subject) NOT LIKE '%unable%'")
623 assert query.statement.include?("LOWER(#{Issue.table_name}.subject) NOT LIKE '%unable%'")
607 find_issues_with_query(query)
624 find_issues_with_query(query)
608 end
625 end
609
626
610 def test_filter_assigned_to_me
627 def test_filter_assigned_to_me
611 user = User.find(2)
628 user = User.find(2)
612 group = Group.find(10)
629 group = Group.find(10)
613 User.current = user
630 User.current = user
614 i1 = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to => user)
631 i1 = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to => user)
615 i2 = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to => group)
632 i2 = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to => group)
616 i3 = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to => Group.find(11))
633 i3 = Issue.generate!(:project_id => 1, :tracker_id => 1, :assigned_to => Group.find(11))
617 group.users << user
634 group.users << user
618
635
619 query = IssueQuery.new(:name => '_', :filters => { 'assigned_to_id' => {:operator => '=', :values => ['me']}})
636 query = IssueQuery.new(:name => '_', :filters => { 'assigned_to_id' => {:operator => '=', :values => ['me']}})
620 result = query.issues
637 result = query.issues
621 assert_equal Issue.visible.where(:assigned_to_id => ([2] + user.reload.group_ids)).sort_by(&:id), result.sort_by(&:id)
638 assert_equal Issue.visible.where(:assigned_to_id => ([2] + user.reload.group_ids)).sort_by(&:id), result.sort_by(&:id)
622
639
623 assert result.include?(i1)
640 assert result.include?(i1)
624 assert result.include?(i2)
641 assert result.include?(i2)
625 assert !result.include?(i3)
642 assert !result.include?(i3)
626 end
643 end
627
644
628 def test_user_custom_field_filtered_on_me
645 def test_user_custom_field_filtered_on_me
629 User.current = User.find(2)
646 User.current = User.find(2)
630 cf = IssueCustomField.create!(:field_format => 'user', :is_for_all => true, :is_filter => true, :name => 'User custom field', :tracker_ids => [1])
647 cf = IssueCustomField.create!(:field_format => 'user', :is_for_all => true, :is_filter => true, :name => 'User custom field', :tracker_ids => [1])
631 issue1 = Issue.create!(:project_id => 1, :tracker_id => 1, :custom_field_values => {cf.id.to_s => '2'}, :subject => 'Test', :author_id => 1)
648 issue1 = Issue.create!(:project_id => 1, :tracker_id => 1, :custom_field_values => {cf.id.to_s => '2'}, :subject => 'Test', :author_id => 1)
632 issue2 = Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {cf.id.to_s => '3'})
649 issue2 = Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {cf.id.to_s => '3'})
633
650
634 query = IssueQuery.new(:name => '_', :project => Project.find(1))
651 query = IssueQuery.new(:name => '_', :project => Project.find(1))
635 filter = query.available_filters["cf_#{cf.id}"]
652 filter = query.available_filters["cf_#{cf.id}"]
636 assert_not_nil filter
653 assert_not_nil filter
637 assert_include 'me', filter[:values].map{|v| v[1]}
654 assert_include 'me', filter[:values].map{|v| v[1]}
638
655
639 query.filters = { "cf_#{cf.id}" => {:operator => '=', :values => ['me']}}
656 query.filters = { "cf_#{cf.id}" => {:operator => '=', :values => ['me']}}
640 result = query.issues
657 result = query.issues
641 assert_equal 1, result.size
658 assert_equal 1, result.size
642 assert_equal issue1, result.first
659 assert_equal issue1, result.first
643 end
660 end
644
661
662 def test_filter_on_me_by_anonymous_user
663 User.current = nil
664 query = IssueQuery.new(:name => '_', :filters => { 'assigned_to_id' => {:operator => '=', :values => ['me']}})
665 assert_equal [], query.issues
666 end
667
645 def test_filter_my_projects
668 def test_filter_my_projects
646 User.current = User.find(2)
669 User.current = User.find(2)
647 query = IssueQuery.new(:name => '_')
670 query = IssueQuery.new(:name => '_')
648 filter = query.available_filters['project_id']
671 filter = query.available_filters['project_id']
649 assert_not_nil filter
672 assert_not_nil filter
650 assert_include 'mine', filter[:values].map{|v| v[1]}
673 assert_include 'mine', filter[:values].map{|v| v[1]}
651
674
652 query.filters = { 'project_id' => {:operator => '=', :values => ['mine']}}
675 query.filters = { 'project_id' => {:operator => '=', :values => ['mine']}}
653 result = query.issues
676 result = query.issues
654 assert_nil result.detect {|issue| !User.current.member_of?(issue.project)}
677 assert_nil result.detect {|issue| !User.current.member_of?(issue.project)}
655 end
678 end
656
679
657 def test_filter_watched_issues
680 def test_filter_watched_issues
658 User.current = User.find(1)
681 User.current = User.find(1)
659 query = IssueQuery.new(:name => '_', :filters => { 'watcher_id' => {:operator => '=', :values => ['me']}})
682 query = IssueQuery.new(:name => '_', :filters => { 'watcher_id' => {:operator => '=', :values => ['me']}})
660 result = find_issues_with_query(query)
683 result = find_issues_with_query(query)
661 assert_not_nil result
684 assert_not_nil result
662 assert !result.empty?
685 assert !result.empty?
663 assert_equal Issue.visible.watched_by(User.current).sort_by(&:id), result.sort_by(&:id)
686 assert_equal Issue.visible.watched_by(User.current).sort_by(&:id), result.sort_by(&:id)
664 User.current = nil
687 User.current = nil
665 end
688 end
666
689
667 def test_filter_unwatched_issues
690 def test_filter_unwatched_issues
668 User.current = User.find(1)
691 User.current = User.find(1)
669 query = IssueQuery.new(:name => '_', :filters => { 'watcher_id' => {:operator => '!', :values => ['me']}})
692 query = IssueQuery.new(:name => '_', :filters => { 'watcher_id' => {:operator => '!', :values => ['me']}})
670 result = find_issues_with_query(query)
693 result = find_issues_with_query(query)
671 assert_not_nil result
694 assert_not_nil result
672 assert !result.empty?
695 assert !result.empty?
673 assert_equal((Issue.visible - Issue.watched_by(User.current)).sort_by(&:id).size, result.sort_by(&:id).size)
696 assert_equal((Issue.visible - Issue.watched_by(User.current)).sort_by(&:id).size, result.sort_by(&:id).size)
674 User.current = nil
697 User.current = nil
675 end
698 end
676
699
677 def test_filter_on_custom_field_should_ignore_projects_with_field_disabled
700 def test_filter_on_custom_field_should_ignore_projects_with_field_disabled
678 field = IssueCustomField.generate!(:trackers => Tracker.all, :project_ids => [1, 3, 4], :is_filter => true)
701 field = IssueCustomField.generate!(:trackers => Tracker.all, :project_ids => [1, 3, 4], :is_filter => true)
679 Issue.generate!(:project_id => 3, :tracker_id => 2, :custom_field_values => {field.id.to_s => 'Foo'})
702 Issue.generate!(:project_id => 3, :tracker_id => 2, :custom_field_values => {field.id.to_s => 'Foo'})
680 Issue.generate!(:project_id => 4, :tracker_id => 2, :custom_field_values => {field.id.to_s => 'Foo'})
703 Issue.generate!(:project_id => 4, :tracker_id => 2, :custom_field_values => {field.id.to_s => 'Foo'})
681
704
682 query = IssueQuery.new(:name => '_', :project => Project.find(1))
705 query = IssueQuery.new(:name => '_', :project => Project.find(1))
683 query.filters = {"cf_#{field.id}" => {:operator => '=', :values => ['Foo']}}
706 query.filters = {"cf_#{field.id}" => {:operator => '=', :values => ['Foo']}}
684 assert_equal 2, find_issues_with_query(query).size
707 assert_equal 2, find_issues_with_query(query).size
685
708
686 field.project_ids = [1, 3] # Disable the field for project 4
709 field.project_ids = [1, 3] # Disable the field for project 4
687 field.save!
710 field.save!
688 assert_equal 1, find_issues_with_query(query).size
711 assert_equal 1, find_issues_with_query(query).size
689 end
712 end
690
713
691 def test_filter_on_custom_field_should_ignore_trackers_with_field_disabled
714 def test_filter_on_custom_field_should_ignore_trackers_with_field_disabled
692 field = IssueCustomField.generate!(:tracker_ids => [1, 2], :is_for_all => true, :is_filter => true)
715 field = IssueCustomField.generate!(:tracker_ids => [1, 2], :is_for_all => true, :is_filter => true)
693 Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {field.id.to_s => 'Foo'})
716 Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {field.id.to_s => 'Foo'})
694 Issue.generate!(:project_id => 1, :tracker_id => 2, :custom_field_values => {field.id.to_s => 'Foo'})
717 Issue.generate!(:project_id => 1, :tracker_id => 2, :custom_field_values => {field.id.to_s => 'Foo'})
695
718
696 query = IssueQuery.new(:name => '_', :project => Project.find(1))
719 query = IssueQuery.new(:name => '_', :project => Project.find(1))
697 query.filters = {"cf_#{field.id}" => {:operator => '=', :values => ['Foo']}}
720 query.filters = {"cf_#{field.id}" => {:operator => '=', :values => ['Foo']}}
698 assert_equal 2, find_issues_with_query(query).size
721 assert_equal 2, find_issues_with_query(query).size
699
722
700 field.tracker_ids = [1] # Disable the field for tracker 2
723 field.tracker_ids = [1] # Disable the field for tracker 2
701 field.save!
724 field.save!
702 assert_equal 1, find_issues_with_query(query).size
725 assert_equal 1, find_issues_with_query(query).size
703 end
726 end
704
727
705 def test_filter_on_project_custom_field
728 def test_filter_on_project_custom_field
706 field = ProjectCustomField.create!(:name => 'Client', :is_filter => true, :field_format => 'string')
729 field = ProjectCustomField.create!(:name => 'Client', :is_filter => true, :field_format => 'string')
707 CustomValue.create!(:custom_field => field, :customized => Project.find(3), :value => 'Foo')
730 CustomValue.create!(:custom_field => field, :customized => Project.find(3), :value => 'Foo')
708 CustomValue.create!(:custom_field => field, :customized => Project.find(5), :value => 'Foo')
731 CustomValue.create!(:custom_field => field, :customized => Project.find(5), :value => 'Foo')
709
732
710 query = IssueQuery.new(:name => '_')
733 query = IssueQuery.new(:name => '_')
711 filter_name = "project.cf_#{field.id}"
734 filter_name = "project.cf_#{field.id}"
712 assert_include filter_name, query.available_filters.keys
735 assert_include filter_name, query.available_filters.keys
713 query.filters = {filter_name => {:operator => '=', :values => ['Foo']}}
736 query.filters = {filter_name => {:operator => '=', :values => ['Foo']}}
714 assert_equal [3, 5], find_issues_with_query(query).map(&:project_id).uniq.sort
737 assert_equal [3, 5], find_issues_with_query(query).map(&:project_id).uniq.sort
715 end
738 end
716
739
717 def test_filter_on_author_custom_field
740 def test_filter_on_author_custom_field
718 field = UserCustomField.create!(:name => 'Client', :is_filter => true, :field_format => 'string')
741 field = UserCustomField.create!(:name => 'Client', :is_filter => true, :field_format => 'string')
719 CustomValue.create!(:custom_field => field, :customized => User.find(3), :value => 'Foo')
742 CustomValue.create!(:custom_field => field, :customized => User.find(3), :value => 'Foo')
720
743
721 query = IssueQuery.new(:name => '_')
744 query = IssueQuery.new(:name => '_')
722 filter_name = "author.cf_#{field.id}"
745 filter_name = "author.cf_#{field.id}"
723 assert_include filter_name, query.available_filters.keys
746 assert_include filter_name, query.available_filters.keys
724 query.filters = {filter_name => {:operator => '=', :values => ['Foo']}}
747 query.filters = {filter_name => {:operator => '=', :values => ['Foo']}}
725 assert_equal [3], find_issues_with_query(query).map(&:author_id).uniq.sort
748 assert_equal [3], find_issues_with_query(query).map(&:author_id).uniq.sort
726 end
749 end
727
750
728 def test_filter_on_assigned_to_custom_field
751 def test_filter_on_assigned_to_custom_field
729 field = UserCustomField.create!(:name => 'Client', :is_filter => true, :field_format => 'string')
752 field = UserCustomField.create!(:name => 'Client', :is_filter => true, :field_format => 'string')
730 CustomValue.create!(:custom_field => field, :customized => User.find(3), :value => 'Foo')
753 CustomValue.create!(:custom_field => field, :customized => User.find(3), :value => 'Foo')
731
754
732 query = IssueQuery.new(:name => '_')
755 query = IssueQuery.new(:name => '_')
733 filter_name = "assigned_to.cf_#{field.id}"
756 filter_name = "assigned_to.cf_#{field.id}"
734 assert_include filter_name, query.available_filters.keys
757 assert_include filter_name, query.available_filters.keys
735 query.filters = {filter_name => {:operator => '=', :values => ['Foo']}}
758 query.filters = {filter_name => {:operator => '=', :values => ['Foo']}}
736 assert_equal [3], find_issues_with_query(query).map(&:assigned_to_id).uniq.sort
759 assert_equal [3], find_issues_with_query(query).map(&:assigned_to_id).uniq.sort
737 end
760 end
738
761
739 def test_filter_on_fixed_version_custom_field
762 def test_filter_on_fixed_version_custom_field
740 field = VersionCustomField.create!(:name => 'Client', :is_filter => true, :field_format => 'string')
763 field = VersionCustomField.create!(:name => 'Client', :is_filter => true, :field_format => 'string')
741 CustomValue.create!(:custom_field => field, :customized => Version.find(2), :value => 'Foo')
764 CustomValue.create!(:custom_field => field, :customized => Version.find(2), :value => 'Foo')
742
765
743 query = IssueQuery.new(:name => '_')
766 query = IssueQuery.new(:name => '_')
744 filter_name = "fixed_version.cf_#{field.id}"
767 filter_name = "fixed_version.cf_#{field.id}"
745 assert_include filter_name, query.available_filters.keys
768 assert_include filter_name, query.available_filters.keys
746 query.filters = {filter_name => {:operator => '=', :values => ['Foo']}}
769 query.filters = {filter_name => {:operator => '=', :values => ['Foo']}}
747 assert_equal [2], find_issues_with_query(query).map(&:fixed_version_id).uniq.sort
770 assert_equal [2], find_issues_with_query(query).map(&:fixed_version_id).uniq.sort
748 end
771 end
749
772
750 def test_filter_on_relations_with_a_specific_issue
773 def test_filter_on_relations_with_a_specific_issue
751 IssueRelation.delete_all
774 IssueRelation.delete_all
752 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Issue.find(2))
775 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Issue.find(2))
753 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(3), :issue_to => Issue.find(1))
776 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(3), :issue_to => Issue.find(1))
754
777
755 query = IssueQuery.new(:name => '_')
778 query = IssueQuery.new(:name => '_')
756 query.filters = {"relates" => {:operator => '=', :values => ['1']}}
779 query.filters = {"relates" => {:operator => '=', :values => ['1']}}
757 assert_equal [2, 3], find_issues_with_query(query).map(&:id).sort
780 assert_equal [2, 3], find_issues_with_query(query).map(&:id).sort
758
781
759 query = IssueQuery.new(:name => '_')
782 query = IssueQuery.new(:name => '_')
760 query.filters = {"relates" => {:operator => '=', :values => ['2']}}
783 query.filters = {"relates" => {:operator => '=', :values => ['2']}}
761 assert_equal [1], find_issues_with_query(query).map(&:id).sort
784 assert_equal [1], find_issues_with_query(query).map(&:id).sort
762 end
785 end
763
786
764 def test_filter_on_relations_with_any_issues_in_a_project
787 def test_filter_on_relations_with_any_issues_in_a_project
765 IssueRelation.delete_all
788 IssueRelation.delete_all
766 with_settings :cross_project_issue_relations => '1' do
789 with_settings :cross_project_issue_relations => '1' do
767 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Project.find(2).issues.first)
790 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Project.find(2).issues.first)
768 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(2), :issue_to => Project.find(2).issues.first)
791 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(2), :issue_to => Project.find(2).issues.first)
769 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Project.find(3).issues.first)
792 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Project.find(3).issues.first)
770 end
793 end
771
794
772 query = IssueQuery.new(:name => '_')
795 query = IssueQuery.new(:name => '_')
773 query.filters = {"relates" => {:operator => '=p', :values => ['2']}}
796 query.filters = {"relates" => {:operator => '=p', :values => ['2']}}
774 assert_equal [1, 2], find_issues_with_query(query).map(&:id).sort
797 assert_equal [1, 2], find_issues_with_query(query).map(&:id).sort
775
798
776 query = IssueQuery.new(:name => '_')
799 query = IssueQuery.new(:name => '_')
777 query.filters = {"relates" => {:operator => '=p', :values => ['3']}}
800 query.filters = {"relates" => {:operator => '=p', :values => ['3']}}
778 assert_equal [1], find_issues_with_query(query).map(&:id).sort
801 assert_equal [1], find_issues_with_query(query).map(&:id).sort
779
802
780 query = IssueQuery.new(:name => '_')
803 query = IssueQuery.new(:name => '_')
781 query.filters = {"relates" => {:operator => '=p', :values => ['4']}}
804 query.filters = {"relates" => {:operator => '=p', :values => ['4']}}
782 assert_equal [], find_issues_with_query(query).map(&:id).sort
805 assert_equal [], find_issues_with_query(query).map(&:id).sort
783 end
806 end
784
807
785 def test_filter_on_relations_with_any_issues_not_in_a_project
808 def test_filter_on_relations_with_any_issues_not_in_a_project
786 IssueRelation.delete_all
809 IssueRelation.delete_all
787 with_settings :cross_project_issue_relations => '1' do
810 with_settings :cross_project_issue_relations => '1' do
788 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Project.find(2).issues.first)
811 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Project.find(2).issues.first)
789 #IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(2), :issue_to => Project.find(1).issues.first)
812 #IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(2), :issue_to => Project.find(1).issues.first)
790 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Project.find(3).issues.first)
813 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Project.find(3).issues.first)
791 end
814 end
792
815
793 query = IssueQuery.new(:name => '_')
816 query = IssueQuery.new(:name => '_')
794 query.filters = {"relates" => {:operator => '=!p', :values => ['1']}}
817 query.filters = {"relates" => {:operator => '=!p', :values => ['1']}}
795 assert_equal [1], find_issues_with_query(query).map(&:id).sort
818 assert_equal [1], find_issues_with_query(query).map(&:id).sort
796 end
819 end
797
820
798 def test_filter_on_relations_with_no_issues_in_a_project
821 def test_filter_on_relations_with_no_issues_in_a_project
799 IssueRelation.delete_all
822 IssueRelation.delete_all
800 with_settings :cross_project_issue_relations => '1' do
823 with_settings :cross_project_issue_relations => '1' do
801 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Project.find(2).issues.first)
824 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Project.find(2).issues.first)
802 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(2), :issue_to => Project.find(3).issues.first)
825 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(2), :issue_to => Project.find(3).issues.first)
803 IssueRelation.create!(:relation_type => "relates", :issue_to => Project.find(2).issues.first, :issue_from => Issue.find(3))
826 IssueRelation.create!(:relation_type => "relates", :issue_to => Project.find(2).issues.first, :issue_from => Issue.find(3))
804 end
827 end
805
828
806 query = IssueQuery.new(:name => '_')
829 query = IssueQuery.new(:name => '_')
807 query.filters = {"relates" => {:operator => '!p', :values => ['2']}}
830 query.filters = {"relates" => {:operator => '!p', :values => ['2']}}
808 ids = find_issues_with_query(query).map(&:id).sort
831 ids = find_issues_with_query(query).map(&:id).sort
809 assert_include 2, ids
832 assert_include 2, ids
810 assert_not_include 1, ids
833 assert_not_include 1, ids
811 assert_not_include 3, ids
834 assert_not_include 3, ids
812 end
835 end
813
836
814 def test_filter_on_relations_with_no_issues
837 def test_filter_on_relations_with_no_issues
815 IssueRelation.delete_all
838 IssueRelation.delete_all
816 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Issue.find(2))
839 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Issue.find(2))
817 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(3), :issue_to => Issue.find(1))
840 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(3), :issue_to => Issue.find(1))
818
841
819 query = IssueQuery.new(:name => '_')
842 query = IssueQuery.new(:name => '_')
820 query.filters = {"relates" => {:operator => '!*', :values => ['']}}
843 query.filters = {"relates" => {:operator => '!*', :values => ['']}}
821 ids = find_issues_with_query(query).map(&:id)
844 ids = find_issues_with_query(query).map(&:id)
822 assert_equal [], ids & [1, 2, 3]
845 assert_equal [], ids & [1, 2, 3]
823 assert_include 4, ids
846 assert_include 4, ids
824 end
847 end
825
848
826 def test_filter_on_relations_with_any_issues
849 def test_filter_on_relations_with_any_issues
827 IssueRelation.delete_all
850 IssueRelation.delete_all
828 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Issue.find(2))
851 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Issue.find(2))
829 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(3), :issue_to => Issue.find(1))
852 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(3), :issue_to => Issue.find(1))
830
853
831 query = IssueQuery.new(:name => '_')
854 query = IssueQuery.new(:name => '_')
832 query.filters = {"relates" => {:operator => '*', :values => ['']}}
855 query.filters = {"relates" => {:operator => '*', :values => ['']}}
833 assert_equal [1, 2, 3], find_issues_with_query(query).map(&:id).sort
856 assert_equal [1, 2, 3], find_issues_with_query(query).map(&:id).sort
834 end
857 end
835
858
836 def test_filter_on_relations_should_not_ignore_other_filter
859 def test_filter_on_relations_should_not_ignore_other_filter
837 issue = Issue.generate!
860 issue = Issue.generate!
838 issue1 = Issue.generate!(:status_id => 1)
861 issue1 = Issue.generate!(:status_id => 1)
839 issue2 = Issue.generate!(:status_id => 2)
862 issue2 = Issue.generate!(:status_id => 2)
840 IssueRelation.create!(:relation_type => "relates", :issue_from => issue, :issue_to => issue1)
863 IssueRelation.create!(:relation_type => "relates", :issue_from => issue, :issue_to => issue1)
841 IssueRelation.create!(:relation_type => "relates", :issue_from => issue, :issue_to => issue2)
864 IssueRelation.create!(:relation_type => "relates", :issue_from => issue, :issue_to => issue2)
842
865
843 query = IssueQuery.new(:name => '_')
866 query = IssueQuery.new(:name => '_')
844 query.filters = {
867 query.filters = {
845 "status_id" => {:operator => '=', :values => ['1']},
868 "status_id" => {:operator => '=', :values => ['1']},
846 "relates" => {:operator => '=', :values => [issue.id.to_s]}
869 "relates" => {:operator => '=', :values => [issue.id.to_s]}
847 }
870 }
848 assert_equal [issue1], find_issues_with_query(query)
871 assert_equal [issue1], find_issues_with_query(query)
849 end
872 end
850
873
851 def test_statement_should_be_nil_with_no_filters
874 def test_statement_should_be_nil_with_no_filters
852 q = IssueQuery.new(:name => '_')
875 q = IssueQuery.new(:name => '_')
853 q.filters = {}
876 q.filters = {}
854
877
855 assert q.valid?
878 assert q.valid?
856 assert_nil q.statement
879 assert_nil q.statement
857 end
880 end
858
881
859 def test_default_columns
882 def test_default_columns
860 q = IssueQuery.new
883 q = IssueQuery.new
861 assert q.columns.any?
884 assert q.columns.any?
862 assert q.inline_columns.any?
885 assert q.inline_columns.any?
863 assert q.block_columns.empty?
886 assert q.block_columns.empty?
864 end
887 end
865
888
866 def test_set_column_names
889 def test_set_column_names
867 q = IssueQuery.new
890 q = IssueQuery.new
868 q.column_names = ['tracker', :subject, '', 'unknonw_column']
891 q.column_names = ['tracker', :subject, '', 'unknonw_column']
869 assert_equal [:id, :tracker, :subject], q.columns.collect {|c| c.name}
892 assert_equal [:id, :tracker, :subject], q.columns.collect {|c| c.name}
870 end
893 end
871
894
872 def test_has_column_should_accept_a_column_name
895 def test_has_column_should_accept_a_column_name
873 q = IssueQuery.new
896 q = IssueQuery.new
874 q.column_names = ['tracker', :subject]
897 q.column_names = ['tracker', :subject]
875 assert q.has_column?(:tracker)
898 assert q.has_column?(:tracker)
876 assert !q.has_column?(:category)
899 assert !q.has_column?(:category)
877 end
900 end
878
901
879 def test_has_column_should_accept_a_column
902 def test_has_column_should_accept_a_column
880 q = IssueQuery.new
903 q = IssueQuery.new
881 q.column_names = ['tracker', :subject]
904 q.column_names = ['tracker', :subject]
882
905
883 tracker_column = q.available_columns.detect {|c| c.name==:tracker}
906 tracker_column = q.available_columns.detect {|c| c.name==:tracker}
884 assert_kind_of QueryColumn, tracker_column
907 assert_kind_of QueryColumn, tracker_column
885 category_column = q.available_columns.detect {|c| c.name==:category}
908 category_column = q.available_columns.detect {|c| c.name==:category}
886 assert_kind_of QueryColumn, category_column
909 assert_kind_of QueryColumn, category_column
887
910
888 assert q.has_column?(tracker_column)
911 assert q.has_column?(tracker_column)
889 assert !q.has_column?(category_column)
912 assert !q.has_column?(category_column)
890 end
913 end
891
914
892 def test_inline_and_block_columns
915 def test_inline_and_block_columns
893 q = IssueQuery.new
916 q = IssueQuery.new
894 q.column_names = ['subject', 'description', 'tracker']
917 q.column_names = ['subject', 'description', 'tracker']
895
918
896 assert_equal [:id, :subject, :tracker], q.inline_columns.map(&:name)
919 assert_equal [:id, :subject, :tracker], q.inline_columns.map(&:name)
897 assert_equal [:description], q.block_columns.map(&:name)
920 assert_equal [:description], q.block_columns.map(&:name)
898 end
921 end
899
922
900 def test_custom_field_columns_should_be_inline
923 def test_custom_field_columns_should_be_inline
901 q = IssueQuery.new
924 q = IssueQuery.new
902 columns = q.available_columns.select {|column| column.is_a? QueryCustomFieldColumn}
925 columns = q.available_columns.select {|column| column.is_a? QueryCustomFieldColumn}
903 assert columns.any?
926 assert columns.any?
904 assert_nil columns.detect {|column| !column.inline?}
927 assert_nil columns.detect {|column| !column.inline?}
905 end
928 end
906
929
907 def test_query_should_preload_spent_hours
930 def test_query_should_preload_spent_hours
908 q = IssueQuery.new(:name => '_', :column_names => [:subject, :spent_hours])
931 q = IssueQuery.new(:name => '_', :column_names => [:subject, :spent_hours])
909 assert q.has_column?(:spent_hours)
932 assert q.has_column?(:spent_hours)
910 issues = q.issues
933 issues = q.issues
911 assert_not_nil issues.first.instance_variable_get("@spent_hours")
934 assert_not_nil issues.first.instance_variable_get("@spent_hours")
912 end
935 end
913
936
914 def test_groupable_columns_should_include_custom_fields
937 def test_groupable_columns_should_include_custom_fields
915 q = IssueQuery.new
938 q = IssueQuery.new
916 column = q.groupable_columns.detect {|c| c.name == :cf_1}
939 column = q.groupable_columns.detect {|c| c.name == :cf_1}
917 assert_not_nil column
940 assert_not_nil column
918 assert_kind_of QueryCustomFieldColumn, column
941 assert_kind_of QueryCustomFieldColumn, column
919 end
942 end
920
943
921 def test_groupable_columns_should_not_include_multi_custom_fields
944 def test_groupable_columns_should_not_include_multi_custom_fields
922 field = CustomField.find(1)
945 field = CustomField.find(1)
923 field.update_attribute :multiple, true
946 field.update_attribute :multiple, true
924
947
925 q = IssueQuery.new
948 q = IssueQuery.new
926 column = q.groupable_columns.detect {|c| c.name == :cf_1}
949 column = q.groupable_columns.detect {|c| c.name == :cf_1}
927 assert_nil column
950 assert_nil column
928 end
951 end
929
952
930 def test_groupable_columns_should_include_user_custom_fields
953 def test_groupable_columns_should_include_user_custom_fields
931 cf = IssueCustomField.create!(:name => 'User', :is_for_all => true, :tracker_ids => [1], :field_format => 'user')
954 cf = IssueCustomField.create!(:name => 'User', :is_for_all => true, :tracker_ids => [1], :field_format => 'user')
932
955
933 q = IssueQuery.new
956 q = IssueQuery.new
934 assert q.groupable_columns.detect {|c| c.name == "cf_#{cf.id}".to_sym}
957 assert q.groupable_columns.detect {|c| c.name == "cf_#{cf.id}".to_sym}
935 end
958 end
936
959
937 def test_groupable_columns_should_include_version_custom_fields
960 def test_groupable_columns_should_include_version_custom_fields
938 cf = IssueCustomField.create!(:name => 'User', :is_for_all => true, :tracker_ids => [1], :field_format => 'version')
961 cf = IssueCustomField.create!(:name => 'User', :is_for_all => true, :tracker_ids => [1], :field_format => 'version')
939
962
940 q = IssueQuery.new
963 q = IssueQuery.new
941 assert q.groupable_columns.detect {|c| c.name == "cf_#{cf.id}".to_sym}
964 assert q.groupable_columns.detect {|c| c.name == "cf_#{cf.id}".to_sym}
942 end
965 end
943
966
944 def test_grouped_with_valid_column
967 def test_grouped_with_valid_column
945 q = IssueQuery.new(:group_by => 'status')
968 q = IssueQuery.new(:group_by => 'status')
946 assert q.grouped?
969 assert q.grouped?
947 assert_not_nil q.group_by_column
970 assert_not_nil q.group_by_column
948 assert_equal :status, q.group_by_column.name
971 assert_equal :status, q.group_by_column.name
949 assert_not_nil q.group_by_statement
972 assert_not_nil q.group_by_statement
950 assert_equal 'status', q.group_by_statement
973 assert_equal 'status', q.group_by_statement
951 end
974 end
952
975
953 def test_grouped_with_invalid_column
976 def test_grouped_with_invalid_column
954 q = IssueQuery.new(:group_by => 'foo')
977 q = IssueQuery.new(:group_by => 'foo')
955 assert !q.grouped?
978 assert !q.grouped?
956 assert_nil q.group_by_column
979 assert_nil q.group_by_column
957 assert_nil q.group_by_statement
980 assert_nil q.group_by_statement
958 end
981 end
959
982
960 def test_sortable_columns_should_sort_assignees_according_to_user_format_setting
983 def test_sortable_columns_should_sort_assignees_according_to_user_format_setting
961 with_settings :user_format => 'lastname_coma_firstname' do
984 with_settings :user_format => 'lastname_coma_firstname' do
962 q = IssueQuery.new
985 q = IssueQuery.new
963 assert q.sortable_columns.has_key?('assigned_to')
986 assert q.sortable_columns.has_key?('assigned_to')
964 assert_equal %w(users.lastname users.firstname users.id), q.sortable_columns['assigned_to']
987 assert_equal %w(users.lastname users.firstname users.id), q.sortable_columns['assigned_to']
965 end
988 end
966 end
989 end
967
990
968 def test_sortable_columns_should_sort_authors_according_to_user_format_setting
991 def test_sortable_columns_should_sort_authors_according_to_user_format_setting
969 with_settings :user_format => 'lastname_coma_firstname' do
992 with_settings :user_format => 'lastname_coma_firstname' do
970 q = IssueQuery.new
993 q = IssueQuery.new
971 assert q.sortable_columns.has_key?('author')
994 assert q.sortable_columns.has_key?('author')
972 assert_equal %w(authors.lastname authors.firstname authors.id), q.sortable_columns['author']
995 assert_equal %w(authors.lastname authors.firstname authors.id), q.sortable_columns['author']
973 end
996 end
974 end
997 end
975
998
976 def test_sortable_columns_should_include_custom_field
999 def test_sortable_columns_should_include_custom_field
977 q = IssueQuery.new
1000 q = IssueQuery.new
978 assert q.sortable_columns['cf_1']
1001 assert q.sortable_columns['cf_1']
979 end
1002 end
980
1003
981 def test_sortable_columns_should_not_include_multi_custom_field
1004 def test_sortable_columns_should_not_include_multi_custom_field
982 field = CustomField.find(1)
1005 field = CustomField.find(1)
983 field.update_attribute :multiple, true
1006 field.update_attribute :multiple, true
984
1007
985 q = IssueQuery.new
1008 q = IssueQuery.new
986 assert !q.sortable_columns['cf_1']
1009 assert !q.sortable_columns['cf_1']
987 end
1010 end
988
1011
989 def test_default_sort
1012 def test_default_sort
990 q = IssueQuery.new
1013 q = IssueQuery.new
991 assert_equal [], q.sort_criteria
1014 assert_equal [], q.sort_criteria
992 end
1015 end
993
1016
994 def test_set_sort_criteria_with_hash
1017 def test_set_sort_criteria_with_hash
995 q = IssueQuery.new
1018 q = IssueQuery.new
996 q.sort_criteria = {'0' => ['priority', 'desc'], '2' => ['tracker']}
1019 q.sort_criteria = {'0' => ['priority', 'desc'], '2' => ['tracker']}
997 assert_equal [['priority', 'desc'], ['tracker', 'asc']], q.sort_criteria
1020 assert_equal [['priority', 'desc'], ['tracker', 'asc']], q.sort_criteria
998 end
1021 end
999
1022
1000 def test_set_sort_criteria_with_array
1023 def test_set_sort_criteria_with_array
1001 q = IssueQuery.new
1024 q = IssueQuery.new
1002 q.sort_criteria = [['priority', 'desc'], 'tracker']
1025 q.sort_criteria = [['priority', 'desc'], 'tracker']
1003 assert_equal [['priority', 'desc'], ['tracker', 'asc']], q.sort_criteria
1026 assert_equal [['priority', 'desc'], ['tracker', 'asc']], q.sort_criteria
1004 end
1027 end
1005
1028
1006 def test_create_query_with_sort
1029 def test_create_query_with_sort
1007 q = IssueQuery.new(:name => 'Sorted')
1030 q = IssueQuery.new(:name => 'Sorted')
1008 q.sort_criteria = [['priority', 'desc'], 'tracker']
1031 q.sort_criteria = [['priority', 'desc'], 'tracker']
1009 assert q.save
1032 assert q.save
1010 q.reload
1033 q.reload
1011 assert_equal [['priority', 'desc'], ['tracker', 'asc']], q.sort_criteria
1034 assert_equal [['priority', 'desc'], ['tracker', 'asc']], q.sort_criteria
1012 end
1035 end
1013
1036
1014 def test_sort_by_string_custom_field_asc
1037 def test_sort_by_string_custom_field_asc
1015 q = IssueQuery.new
1038 q = IssueQuery.new
1016 c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'string' }
1039 c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'string' }
1017 assert c
1040 assert c
1018 assert c.sortable
1041 assert c.sortable
1019 issues = q.issues(:order => "#{c.sortable} ASC")
1042 issues = q.issues(:order => "#{c.sortable} ASC")
1020 values = issues.collect {|i| i.custom_value_for(c.custom_field).to_s}
1043 values = issues.collect {|i| i.custom_value_for(c.custom_field).to_s}
1021 assert !values.empty?
1044 assert !values.empty?
1022 assert_equal values.sort, values
1045 assert_equal values.sort, values
1023 end
1046 end
1024
1047
1025 def test_sort_by_string_custom_field_desc
1048 def test_sort_by_string_custom_field_desc
1026 q = IssueQuery.new
1049 q = IssueQuery.new
1027 c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'string' }
1050 c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'string' }
1028 assert c
1051 assert c
1029 assert c.sortable
1052 assert c.sortable
1030 issues = q.issues(:order => "#{c.sortable} DESC")
1053 issues = q.issues(:order => "#{c.sortable} DESC")
1031 values = issues.collect {|i| i.custom_value_for(c.custom_field).to_s}
1054 values = issues.collect {|i| i.custom_value_for(c.custom_field).to_s}
1032 assert !values.empty?
1055 assert !values.empty?
1033 assert_equal values.sort.reverse, values
1056 assert_equal values.sort.reverse, values
1034 end
1057 end
1035
1058
1036 def test_sort_by_float_custom_field_asc
1059 def test_sort_by_float_custom_field_asc
1037 q = IssueQuery.new
1060 q = IssueQuery.new
1038 c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'float' }
1061 c = q.available_columns.find {|col| col.is_a?(QueryCustomFieldColumn) && col.custom_field.field_format == 'float' }
1039 assert c
1062 assert c
1040 assert c.sortable
1063 assert c.sortable
1041 issues = q.issues(:order => "#{c.sortable} ASC")
1064 issues = q.issues(:order => "#{c.sortable} ASC")
1042 values = issues.collect {|i| begin; Kernel.Float(i.custom_value_for(c.custom_field).to_s); rescue; nil; end}.compact
1065 values = issues.collect {|i| begin; Kernel.Float(i.custom_value_for(c.custom_field).to_s); rescue; nil; end}.compact
1043 assert !values.empty?
1066 assert !values.empty?
1044 assert_equal values.sort, values
1067 assert_equal values.sort, values
1045 end
1068 end
1046
1069
1047 def test_invalid_query_should_raise_query_statement_invalid_error
1070 def test_invalid_query_should_raise_query_statement_invalid_error
1048 q = IssueQuery.new
1071 q = IssueQuery.new
1049 assert_raise Query::StatementInvalid do
1072 assert_raise Query::StatementInvalid do
1050 q.issues(:conditions => "foo = 1")
1073 q.issues(:conditions => "foo = 1")
1051 end
1074 end
1052 end
1075 end
1053
1076
1054 def test_issue_count
1077 def test_issue_count
1055 q = IssueQuery.new(:name => '_')
1078 q = IssueQuery.new(:name => '_')
1056 issue_count = q.issue_count
1079 issue_count = q.issue_count
1057 assert_equal q.issues.size, issue_count
1080 assert_equal q.issues.size, issue_count
1058 end
1081 end
1059
1082
1060 def test_issue_count_with_archived_issues
1083 def test_issue_count_with_archived_issues
1061 p = Project.generate! do |project|
1084 p = Project.generate! do |project|
1062 project.status = Project::STATUS_ARCHIVED
1085 project.status = Project::STATUS_ARCHIVED
1063 end
1086 end
1064 i = Issue.generate!( :project => p, :tracker => p.trackers.first )
1087 i = Issue.generate!( :project => p, :tracker => p.trackers.first )
1065 assert !i.visible?
1088 assert !i.visible?
1066
1089
1067 test_issue_count
1090 test_issue_count
1068 end
1091 end
1069
1092
1070 def test_issue_count_by_association_group
1093 def test_issue_count_by_association_group
1071 q = IssueQuery.new(:name => '_', :group_by => 'assigned_to')
1094 q = IssueQuery.new(:name => '_', :group_by => 'assigned_to')
1072 count_by_group = q.issue_count_by_group
1095 count_by_group = q.issue_count_by_group
1073 assert_kind_of Hash, count_by_group
1096 assert_kind_of Hash, count_by_group
1074 assert_equal %w(NilClass User), count_by_group.keys.collect {|k| k.class.name}.uniq.sort
1097 assert_equal %w(NilClass User), count_by_group.keys.collect {|k| k.class.name}.uniq.sort
1075 assert_equal %w(Fixnum), count_by_group.values.collect {|k| k.class.name}.uniq
1098 assert_equal %w(Fixnum), count_by_group.values.collect {|k| k.class.name}.uniq
1076 assert count_by_group.has_key?(User.find(3))
1099 assert count_by_group.has_key?(User.find(3))
1077 end
1100 end
1078
1101
1079 def test_issue_count_by_list_custom_field_group
1102 def test_issue_count_by_list_custom_field_group
1080 q = IssueQuery.new(:name => '_', :group_by => 'cf_1')
1103 q = IssueQuery.new(:name => '_', :group_by => 'cf_1')
1081 count_by_group = q.issue_count_by_group
1104 count_by_group = q.issue_count_by_group
1082 assert_kind_of Hash, count_by_group
1105 assert_kind_of Hash, count_by_group
1083 assert_equal %w(NilClass String), count_by_group.keys.collect {|k| k.class.name}.uniq.sort
1106 assert_equal %w(NilClass String), count_by_group.keys.collect {|k| k.class.name}.uniq.sort
1084 assert_equal %w(Fixnum), count_by_group.values.collect {|k| k.class.name}.uniq
1107 assert_equal %w(Fixnum), count_by_group.values.collect {|k| k.class.name}.uniq
1085 assert count_by_group.has_key?('MySQL')
1108 assert count_by_group.has_key?('MySQL')
1086 end
1109 end
1087
1110
1088 def test_issue_count_by_date_custom_field_group
1111 def test_issue_count_by_date_custom_field_group
1089 q = IssueQuery.new(:name => '_', :group_by => 'cf_8')
1112 q = IssueQuery.new(:name => '_', :group_by => 'cf_8')
1090 count_by_group = q.issue_count_by_group
1113 count_by_group = q.issue_count_by_group
1091 assert_kind_of Hash, count_by_group
1114 assert_kind_of Hash, count_by_group
1092 assert_equal %w(Date NilClass), count_by_group.keys.collect {|k| k.class.name}.uniq.sort
1115 assert_equal %w(Date NilClass), count_by_group.keys.collect {|k| k.class.name}.uniq.sort
1093 assert_equal %w(Fixnum), count_by_group.values.collect {|k| k.class.name}.uniq
1116 assert_equal %w(Fixnum), count_by_group.values.collect {|k| k.class.name}.uniq
1094 end
1117 end
1095
1118
1096 def test_issue_count_with_nil_group_only
1119 def test_issue_count_with_nil_group_only
1097 Issue.update_all("assigned_to_id = NULL")
1120 Issue.update_all("assigned_to_id = NULL")
1098
1121
1099 q = IssueQuery.new(:name => '_', :group_by => 'assigned_to')
1122 q = IssueQuery.new(:name => '_', :group_by => 'assigned_to')
1100 count_by_group = q.issue_count_by_group
1123 count_by_group = q.issue_count_by_group
1101 assert_kind_of Hash, count_by_group
1124 assert_kind_of Hash, count_by_group
1102 assert_equal 1, count_by_group.keys.size
1125 assert_equal 1, count_by_group.keys.size
1103 assert_nil count_by_group.keys.first
1126 assert_nil count_by_group.keys.first
1104 end
1127 end
1105
1128
1106 def test_issue_ids
1129 def test_issue_ids
1107 q = IssueQuery.new(:name => '_')
1130 q = IssueQuery.new(:name => '_')
1108 order = "issues.subject, issues.id"
1131 order = "issues.subject, issues.id"
1109 issues = q.issues(:order => order)
1132 issues = q.issues(:order => order)
1110 assert_equal issues.map(&:id), q.issue_ids(:order => order)
1133 assert_equal issues.map(&:id), q.issue_ids(:order => order)
1111 end
1134 end
1112
1135
1113 def test_label_for
1136 def test_label_for
1114 set_language_if_valid 'en'
1137 set_language_if_valid 'en'
1115 q = IssueQuery.new
1138 q = IssueQuery.new
1116 assert_equal 'Assignee', q.label_for('assigned_to_id')
1139 assert_equal 'Assignee', q.label_for('assigned_to_id')
1117 end
1140 end
1118
1141
1119 def test_label_for_fr
1142 def test_label_for_fr
1120 set_language_if_valid 'fr'
1143 set_language_if_valid 'fr'
1121 q = IssueQuery.new
1144 q = IssueQuery.new
1122 assert_equal "Assign\xc3\xa9 \xc3\xa0".force_encoding('UTF-8'), q.label_for('assigned_to_id')
1145 assert_equal "Assign\xc3\xa9 \xc3\xa0".force_encoding('UTF-8'), q.label_for('assigned_to_id')
1123 end
1146 end
1124
1147
1125 def test_editable_by
1148 def test_editable_by
1126 admin = User.find(1)
1149 admin = User.find(1)
1127 manager = User.find(2)
1150 manager = User.find(2)
1128 developer = User.find(3)
1151 developer = User.find(3)
1129
1152
1130 # Public query on project 1
1153 # Public query on project 1
1131 q = IssueQuery.find(1)
1154 q = IssueQuery.find(1)
1132 assert q.editable_by?(admin)
1155 assert q.editable_by?(admin)
1133 assert q.editable_by?(manager)
1156 assert q.editable_by?(manager)
1134 assert !q.editable_by?(developer)
1157 assert !q.editable_by?(developer)
1135
1158
1136 # Private query on project 1
1159 # Private query on project 1
1137 q = IssueQuery.find(2)
1160 q = IssueQuery.find(2)
1138 assert q.editable_by?(admin)
1161 assert q.editable_by?(admin)
1139 assert !q.editable_by?(manager)
1162 assert !q.editable_by?(manager)
1140 assert q.editable_by?(developer)
1163 assert q.editable_by?(developer)
1141
1164
1142 # Private query for all projects
1165 # Private query for all projects
1143 q = IssueQuery.find(3)
1166 q = IssueQuery.find(3)
1144 assert q.editable_by?(admin)
1167 assert q.editable_by?(admin)
1145 assert !q.editable_by?(manager)
1168 assert !q.editable_by?(manager)
1146 assert q.editable_by?(developer)
1169 assert q.editable_by?(developer)
1147
1170
1148 # Public query for all projects
1171 # Public query for all projects
1149 q = IssueQuery.find(4)
1172 q = IssueQuery.find(4)
1150 assert q.editable_by?(admin)
1173 assert q.editable_by?(admin)
1151 assert !q.editable_by?(manager)
1174 assert !q.editable_by?(manager)
1152 assert !q.editable_by?(developer)
1175 assert !q.editable_by?(developer)
1153 end
1176 end
1154
1177
1155 def test_visible_scope
1178 def test_visible_scope
1156 query_ids = IssueQuery.visible(User.anonymous).map(&:id)
1179 query_ids = IssueQuery.visible(User.anonymous).map(&:id)
1157
1180
1158 assert query_ids.include?(1), 'public query on public project was not visible'
1181 assert query_ids.include?(1), 'public query on public project was not visible'
1159 assert query_ids.include?(4), 'public query for all projects was not visible'
1182 assert query_ids.include?(4), 'public query for all projects was not visible'
1160 assert !query_ids.include?(2), 'private query on public project was visible'
1183 assert !query_ids.include?(2), 'private query on public project was visible'
1161 assert !query_ids.include?(3), 'private query for all projects was visible'
1184 assert !query_ids.include?(3), 'private query for all projects was visible'
1162 assert !query_ids.include?(7), 'public query on private project was visible'
1185 assert !query_ids.include?(7), 'public query on private project was visible'
1163 end
1186 end
1164
1187
1165 def test_query_with_public_visibility_should_be_visible_to_anyone
1188 def test_query_with_public_visibility_should_be_visible_to_anyone
1166 q = IssueQuery.create!(:name => 'Query', :visibility => IssueQuery::VISIBILITY_PUBLIC)
1189 q = IssueQuery.create!(:name => 'Query', :visibility => IssueQuery::VISIBILITY_PUBLIC)
1167
1190
1168 assert q.visible?(User.anonymous)
1191 assert q.visible?(User.anonymous)
1169 assert IssueQuery.visible(User.anonymous).find_by_id(q.id)
1192 assert IssueQuery.visible(User.anonymous).find_by_id(q.id)
1170
1193
1171 assert q.visible?(User.find(7))
1194 assert q.visible?(User.find(7))
1172 assert IssueQuery.visible(User.find(7)).find_by_id(q.id)
1195 assert IssueQuery.visible(User.find(7)).find_by_id(q.id)
1173
1196
1174 assert q.visible?(User.find(2))
1197 assert q.visible?(User.find(2))
1175 assert IssueQuery.visible(User.find(2)).find_by_id(q.id)
1198 assert IssueQuery.visible(User.find(2)).find_by_id(q.id)
1176
1199
1177 assert q.visible?(User.find(1))
1200 assert q.visible?(User.find(1))
1178 assert IssueQuery.visible(User.find(1)).find_by_id(q.id)
1201 assert IssueQuery.visible(User.find(1)).find_by_id(q.id)
1179 end
1202 end
1180
1203
1181 def test_query_with_roles_visibility_should_be_visible_to_user_with_role
1204 def test_query_with_roles_visibility_should_be_visible_to_user_with_role
1182 q = IssueQuery.create!(:name => 'Query', :visibility => IssueQuery::VISIBILITY_ROLES, :role_ids => [1,2])
1205 q = IssueQuery.create!(:name => 'Query', :visibility => IssueQuery::VISIBILITY_ROLES, :role_ids => [1,2])
1183
1206
1184 assert !q.visible?(User.anonymous)
1207 assert !q.visible?(User.anonymous)
1185 assert_nil IssueQuery.visible(User.anonymous).find_by_id(q.id)
1208 assert_nil IssueQuery.visible(User.anonymous).find_by_id(q.id)
1186
1209
1187 assert !q.visible?(User.find(7))
1210 assert !q.visible?(User.find(7))
1188 assert_nil IssueQuery.visible(User.find(7)).find_by_id(q.id)
1211 assert_nil IssueQuery.visible(User.find(7)).find_by_id(q.id)
1189
1212
1190 assert q.visible?(User.find(2))
1213 assert q.visible?(User.find(2))
1191 assert IssueQuery.visible(User.find(2)).find_by_id(q.id)
1214 assert IssueQuery.visible(User.find(2)).find_by_id(q.id)
1192
1215
1193 assert q.visible?(User.find(1))
1216 assert q.visible?(User.find(1))
1194 assert IssueQuery.visible(User.find(1)).find_by_id(q.id)
1217 assert IssueQuery.visible(User.find(1)).find_by_id(q.id)
1195 end
1218 end
1196
1219
1197 def test_query_with_private_visibility_should_be_visible_to_owner
1220 def test_query_with_private_visibility_should_be_visible_to_owner
1198 q = IssueQuery.create!(:name => 'Query', :visibility => IssueQuery::VISIBILITY_PRIVATE, :user => User.find(7))
1221 q = IssueQuery.create!(:name => 'Query', :visibility => IssueQuery::VISIBILITY_PRIVATE, :user => User.find(7))
1199
1222
1200 assert !q.visible?(User.anonymous)
1223 assert !q.visible?(User.anonymous)
1201 assert_nil IssueQuery.visible(User.anonymous).find_by_id(q.id)
1224 assert_nil IssueQuery.visible(User.anonymous).find_by_id(q.id)
1202
1225
1203 assert q.visible?(User.find(7))
1226 assert q.visible?(User.find(7))
1204 assert IssueQuery.visible(User.find(7)).find_by_id(q.id)
1227 assert IssueQuery.visible(User.find(7)).find_by_id(q.id)
1205
1228
1206 assert !q.visible?(User.find(2))
1229 assert !q.visible?(User.find(2))
1207 assert_nil IssueQuery.visible(User.find(2)).find_by_id(q.id)
1230 assert_nil IssueQuery.visible(User.find(2)).find_by_id(q.id)
1208
1231
1209 assert q.visible?(User.find(1))
1232 assert q.visible?(User.find(1))
1210 assert_nil IssueQuery.visible(User.find(1)).find_by_id(q.id)
1233 assert_nil IssueQuery.visible(User.find(1)).find_by_id(q.id)
1211 end
1234 end
1212
1235
1213 test "#available_filters should include users of visible projects in cross-project view" do
1236 test "#available_filters should include users of visible projects in cross-project view" do
1214 users = IssueQuery.new.available_filters["assigned_to_id"]
1237 users = IssueQuery.new.available_filters["assigned_to_id"]
1215 assert_not_nil users
1238 assert_not_nil users
1216 assert users[:values].map{|u|u[1]}.include?("3")
1239 assert users[:values].map{|u|u[1]}.include?("3")
1217 end
1240 end
1218
1241
1219 test "#available_filters should include users of subprojects" do
1242 test "#available_filters should include users of subprojects" do
1220 user1 = User.generate!
1243 user1 = User.generate!
1221 user2 = User.generate!
1244 user2 = User.generate!
1222 project = Project.find(1)
1245 project = Project.find(1)
1223 Member.create!(:principal => user1, :project => project.children.visible.first, :role_ids => [1])
1246 Member.create!(:principal => user1, :project => project.children.visible.first, :role_ids => [1])
1224
1247
1225 users = IssueQuery.new(:project => project).available_filters["assigned_to_id"]
1248 users = IssueQuery.new(:project => project).available_filters["assigned_to_id"]
1226 assert_not_nil users
1249 assert_not_nil users
1227 assert users[:values].map{|u|u[1]}.include?(user1.id.to_s)
1250 assert users[:values].map{|u|u[1]}.include?(user1.id.to_s)
1228 assert !users[:values].map{|u|u[1]}.include?(user2.id.to_s)
1251 assert !users[:values].map{|u|u[1]}.include?(user2.id.to_s)
1229 end
1252 end
1230
1253
1231 test "#available_filters should include visible projects in cross-project view" do
1254 test "#available_filters should include visible projects in cross-project view" do
1232 projects = IssueQuery.new.available_filters["project_id"]
1255 projects = IssueQuery.new.available_filters["project_id"]
1233 assert_not_nil projects
1256 assert_not_nil projects
1234 assert projects[:values].map{|u|u[1]}.include?("1")
1257 assert projects[:values].map{|u|u[1]}.include?("1")
1235 end
1258 end
1236
1259
1237 test "#available_filters should include 'member_of_group' filter" do
1260 test "#available_filters should include 'member_of_group' filter" do
1238 query = IssueQuery.new
1261 query = IssueQuery.new
1239 assert query.available_filters.keys.include?("member_of_group")
1262 assert query.available_filters.keys.include?("member_of_group")
1240 assert_equal :list_optional, query.available_filters["member_of_group"][:type]
1263 assert_equal :list_optional, query.available_filters["member_of_group"][:type]
1241 assert query.available_filters["member_of_group"][:values].present?
1264 assert query.available_filters["member_of_group"][:values].present?
1242 assert_equal Group.givable.sort.map {|g| [g.name, g.id.to_s]},
1265 assert_equal Group.givable.sort.map {|g| [g.name, g.id.to_s]},
1243 query.available_filters["member_of_group"][:values].sort
1266 query.available_filters["member_of_group"][:values].sort
1244 end
1267 end
1245
1268
1246 test "#available_filters should include 'assigned_to_role' filter" do
1269 test "#available_filters should include 'assigned_to_role' filter" do
1247 query = IssueQuery.new
1270 query = IssueQuery.new
1248 assert query.available_filters.keys.include?("assigned_to_role")
1271 assert query.available_filters.keys.include?("assigned_to_role")
1249 assert_equal :list_optional, query.available_filters["assigned_to_role"][:type]
1272 assert_equal :list_optional, query.available_filters["assigned_to_role"][:type]
1250
1273
1251 assert query.available_filters["assigned_to_role"][:values].include?(['Manager','1'])
1274 assert query.available_filters["assigned_to_role"][:values].include?(['Manager','1'])
1252 assert query.available_filters["assigned_to_role"][:values].include?(['Developer','2'])
1275 assert query.available_filters["assigned_to_role"][:values].include?(['Developer','2'])
1253 assert query.available_filters["assigned_to_role"][:values].include?(['Reporter','3'])
1276 assert query.available_filters["assigned_to_role"][:values].include?(['Reporter','3'])
1254
1277
1255 assert ! query.available_filters["assigned_to_role"][:values].include?(['Non member','4'])
1278 assert ! query.available_filters["assigned_to_role"][:values].include?(['Non member','4'])
1256 assert ! query.available_filters["assigned_to_role"][:values].include?(['Anonymous','5'])
1279 assert ! query.available_filters["assigned_to_role"][:values].include?(['Anonymous','5'])
1257 end
1280 end
1258
1281
1259 def test_available_filters_should_include_custom_field_according_to_user_visibility
1282 def test_available_filters_should_include_custom_field_according_to_user_visibility
1260 visible_field = IssueCustomField.generate!(:is_for_all => true, :is_filter => true, :visible => true)
1283 visible_field = IssueCustomField.generate!(:is_for_all => true, :is_filter => true, :visible => true)
1261 hidden_field = IssueCustomField.generate!(:is_for_all => true, :is_filter => true, :visible => false, :role_ids => [1])
1284 hidden_field = IssueCustomField.generate!(:is_for_all => true, :is_filter => true, :visible => false, :role_ids => [1])
1262
1285
1263 with_current_user User.find(3) do
1286 with_current_user User.find(3) do
1264 query = IssueQuery.new
1287 query = IssueQuery.new
1265 assert_include "cf_#{visible_field.id}", query.available_filters.keys
1288 assert_include "cf_#{visible_field.id}", query.available_filters.keys
1266 assert_not_include "cf_#{hidden_field.id}", query.available_filters.keys
1289 assert_not_include "cf_#{hidden_field.id}", query.available_filters.keys
1267 end
1290 end
1268 end
1291 end
1269
1292
1270 def test_available_columns_should_include_custom_field_according_to_user_visibility
1293 def test_available_columns_should_include_custom_field_according_to_user_visibility
1271 visible_field = IssueCustomField.generate!(:is_for_all => true, :is_filter => true, :visible => true)
1294 visible_field = IssueCustomField.generate!(:is_for_all => true, :is_filter => true, :visible => true)
1272 hidden_field = IssueCustomField.generate!(:is_for_all => true, :is_filter => true, :visible => false, :role_ids => [1])
1295 hidden_field = IssueCustomField.generate!(:is_for_all => true, :is_filter => true, :visible => false, :role_ids => [1])
1273
1296
1274 with_current_user User.find(3) do
1297 with_current_user User.find(3) do
1275 query = IssueQuery.new
1298 query = IssueQuery.new
1276 assert_include :"cf_#{visible_field.id}", query.available_columns.map(&:name)
1299 assert_include :"cf_#{visible_field.id}", query.available_columns.map(&:name)
1277 assert_not_include :"cf_#{hidden_field.id}", query.available_columns.map(&:name)
1300 assert_not_include :"cf_#{hidden_field.id}", query.available_columns.map(&:name)
1278 end
1301 end
1279 end
1302 end
1280
1303
1281 def setup_member_of_group
1304 def setup_member_of_group
1282 Group.destroy_all # No fixtures
1305 Group.destroy_all # No fixtures
1283 @user_in_group = User.generate!
1306 @user_in_group = User.generate!
1284 @second_user_in_group = User.generate!
1307 @second_user_in_group = User.generate!
1285 @user_in_group2 = User.generate!
1308 @user_in_group2 = User.generate!
1286 @user_not_in_group = User.generate!
1309 @user_not_in_group = User.generate!
1287
1310
1288 @group = Group.generate!.reload
1311 @group = Group.generate!.reload
1289 @group.users << @user_in_group
1312 @group.users << @user_in_group
1290 @group.users << @second_user_in_group
1313 @group.users << @second_user_in_group
1291
1314
1292 @group2 = Group.generate!.reload
1315 @group2 = Group.generate!.reload
1293 @group2.users << @user_in_group2
1316 @group2.users << @user_in_group2
1294
1317
1295 @query = IssueQuery.new(:name => '_')
1318 @query = IssueQuery.new(:name => '_')
1296 end
1319 end
1297
1320
1298 test "member_of_group filter should search assigned to for users in the group" do
1321 test "member_of_group filter should search assigned to for users in the group" do
1299 setup_member_of_group
1322 setup_member_of_group
1300 @query.add_filter('member_of_group', '=', [@group.id.to_s])
1323 @query.add_filter('member_of_group', '=', [@group.id.to_s])
1301
1324
1302 assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IN ('#{@user_in_group.id}','#{@second_user_in_group.id}','#{@group.id}')"
1325 assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IN ('#{@user_in_group.id}','#{@second_user_in_group.id}','#{@group.id}')"
1303 assert_find_issues_with_query_is_successful @query
1326 assert_find_issues_with_query_is_successful @query
1304 end
1327 end
1305
1328
1306 test "member_of_group filter should search not assigned to any group member (none)" do
1329 test "member_of_group filter should search not assigned to any group member (none)" do
1307 setup_member_of_group
1330 setup_member_of_group
1308 @query.add_filter('member_of_group', '!*', [''])
1331 @query.add_filter('member_of_group', '!*', [''])
1309
1332
1310 # Users not in a group
1333 # Users not in a group
1311 assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IS NULL OR #{Issue.table_name}.assigned_to_id NOT IN ('#{@user_in_group.id}','#{@second_user_in_group.id}','#{@user_in_group2.id}','#{@group.id}','#{@group2.id}')"
1334 assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IS NULL OR #{Issue.table_name}.assigned_to_id NOT IN ('#{@user_in_group.id}','#{@second_user_in_group.id}','#{@user_in_group2.id}','#{@group.id}','#{@group2.id}')"
1312 assert_find_issues_with_query_is_successful @query
1335 assert_find_issues_with_query_is_successful @query
1313 end
1336 end
1314
1337
1315 test "member_of_group filter should search assigned to any group member (all)" do
1338 test "member_of_group filter should search assigned to any group member (all)" do
1316 setup_member_of_group
1339 setup_member_of_group
1317 @query.add_filter('member_of_group', '*', [''])
1340 @query.add_filter('member_of_group', '*', [''])
1318
1341
1319 # Only users in a group
1342 # Only users in a group
1320 assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IN ('#{@user_in_group.id}','#{@second_user_in_group.id}','#{@user_in_group2.id}','#{@group.id}','#{@group2.id}')"
1343 assert_query_statement_includes @query, "#{Issue.table_name}.assigned_to_id IN ('#{@user_in_group.id}','#{@second_user_in_group.id}','#{@user_in_group2.id}','#{@group.id}','#{@group2.id}')"
1321 assert_find_issues_with_query_is_successful @query
1344 assert_find_issues_with_query_is_successful @query
1322 end
1345 end
1323
1346
1324 test "member_of_group filter should return an empty set with = empty group" do
1347 test "member_of_group filter should return an empty set with = empty group" do
1325 setup_member_of_group
1348 setup_member_of_group
1326 @empty_group = Group.generate!
1349 @empty_group = Group.generate!
1327 @query.add_filter('member_of_group', '=', [@empty_group.id.to_s])
1350 @query.add_filter('member_of_group', '=', [@empty_group.id.to_s])
1328
1351
1329 assert_equal [], find_issues_with_query(@query)
1352 assert_equal [], find_issues_with_query(@query)
1330 end
1353 end
1331
1354
1332 test "member_of_group filter should return issues with ! empty group" do
1355 test "member_of_group filter should return issues with ! empty group" do
1333 setup_member_of_group
1356 setup_member_of_group
1334 @empty_group = Group.generate!
1357 @empty_group = Group.generate!
1335 @query.add_filter('member_of_group', '!', [@empty_group.id.to_s])
1358 @query.add_filter('member_of_group', '!', [@empty_group.id.to_s])
1336
1359
1337 assert_find_issues_with_query_is_successful @query
1360 assert_find_issues_with_query_is_successful @query
1338 end
1361 end
1339
1362
1340 def setup_assigned_to_role
1363 def setup_assigned_to_role
1341 @manager_role = Role.find_by_name('Manager')
1364 @manager_role = Role.find_by_name('Manager')
1342 @developer_role = Role.find_by_name('Developer')
1365 @developer_role = Role.find_by_name('Developer')
1343
1366
1344 @project = Project.generate!
1367 @project = Project.generate!
1345 @manager = User.generate!
1368 @manager = User.generate!
1346 @developer = User.generate!
1369 @developer = User.generate!
1347 @boss = User.generate!
1370 @boss = User.generate!
1348 @guest = User.generate!
1371 @guest = User.generate!
1349 User.add_to_project(@manager, @project, @manager_role)
1372 User.add_to_project(@manager, @project, @manager_role)
1350 User.add_to_project(@developer, @project, @developer_role)
1373 User.add_to_project(@developer, @project, @developer_role)
1351 User.add_to_project(@boss, @project, [@manager_role, @developer_role])
1374 User.add_to_project(@boss, @project, [@manager_role, @developer_role])
1352
1375
1353 @issue1 = Issue.generate!(:project => @project, :assigned_to_id => @manager.id)
1376 @issue1 = Issue.generate!(:project => @project, :assigned_to_id => @manager.id)
1354 @issue2 = Issue.generate!(:project => @project, :assigned_to_id => @developer.id)
1377 @issue2 = Issue.generate!(:project => @project, :assigned_to_id => @developer.id)
1355 @issue3 = Issue.generate!(:project => @project, :assigned_to_id => @boss.id)
1378 @issue3 = Issue.generate!(:project => @project, :assigned_to_id => @boss.id)
1356 @issue4 = Issue.generate!(:project => @project, :assigned_to_id => @guest.id)
1379 @issue4 = Issue.generate!(:project => @project, :assigned_to_id => @guest.id)
1357 @issue5 = Issue.generate!(:project => @project)
1380 @issue5 = Issue.generate!(:project => @project)
1358
1381
1359 @query = IssueQuery.new(:name => '_', :project => @project)
1382 @query = IssueQuery.new(:name => '_', :project => @project)
1360 end
1383 end
1361
1384
1362 test "assigned_to_role filter should search assigned to for users with the Role" do
1385 test "assigned_to_role filter should search assigned to for users with the Role" do
1363 setup_assigned_to_role
1386 setup_assigned_to_role
1364 @query.add_filter('assigned_to_role', '=', [@manager_role.id.to_s])
1387 @query.add_filter('assigned_to_role', '=', [@manager_role.id.to_s])
1365
1388
1366 assert_query_result [@issue1, @issue3], @query
1389 assert_query_result [@issue1, @issue3], @query
1367 end
1390 end
1368
1391
1369 test "assigned_to_role filter should search assigned to for users with the Role on the issue project" do
1392 test "assigned_to_role filter should search assigned to for users with the Role on the issue project" do
1370 setup_assigned_to_role
1393 setup_assigned_to_role
1371 other_project = Project.generate!
1394 other_project = Project.generate!
1372 User.add_to_project(@developer, other_project, @manager_role)
1395 User.add_to_project(@developer, other_project, @manager_role)
1373 @query.add_filter('assigned_to_role', '=', [@manager_role.id.to_s])
1396 @query.add_filter('assigned_to_role', '=', [@manager_role.id.to_s])
1374
1397
1375 assert_query_result [@issue1, @issue3], @query
1398 assert_query_result [@issue1, @issue3], @query
1376 end
1399 end
1377
1400
1378 test "assigned_to_role filter should return an empty set with empty role" do
1401 test "assigned_to_role filter should return an empty set with empty role" do
1379 setup_assigned_to_role
1402 setup_assigned_to_role
1380 @empty_role = Role.generate!
1403 @empty_role = Role.generate!
1381 @query.add_filter('assigned_to_role', '=', [@empty_role.id.to_s])
1404 @query.add_filter('assigned_to_role', '=', [@empty_role.id.to_s])
1382
1405
1383 assert_query_result [], @query
1406 assert_query_result [], @query
1384 end
1407 end
1385
1408
1386 test "assigned_to_role filter should search assigned to for users without the Role" do
1409 test "assigned_to_role filter should search assigned to for users without the Role" do
1387 setup_assigned_to_role
1410 setup_assigned_to_role
1388 @query.add_filter('assigned_to_role', '!', [@manager_role.id.to_s])
1411 @query.add_filter('assigned_to_role', '!', [@manager_role.id.to_s])
1389
1412
1390 assert_query_result [@issue2, @issue4, @issue5], @query
1413 assert_query_result [@issue2, @issue4, @issue5], @query
1391 end
1414 end
1392
1415
1393 test "assigned_to_role filter should search assigned to for users not assigned to any Role (none)" do
1416 test "assigned_to_role filter should search assigned to for users not assigned to any Role (none)" do
1394 setup_assigned_to_role
1417 setup_assigned_to_role
1395 @query.add_filter('assigned_to_role', '!*', [''])
1418 @query.add_filter('assigned_to_role', '!*', [''])
1396
1419
1397 assert_query_result [@issue4, @issue5], @query
1420 assert_query_result [@issue4, @issue5], @query
1398 end
1421 end
1399
1422
1400 test "assigned_to_role filter should search assigned to for users assigned to any Role (all)" do
1423 test "assigned_to_role filter should search assigned to for users assigned to any Role (all)" do
1401 setup_assigned_to_role
1424 setup_assigned_to_role
1402 @query.add_filter('assigned_to_role', '*', [''])
1425 @query.add_filter('assigned_to_role', '*', [''])
1403
1426
1404 assert_query_result [@issue1, @issue2, @issue3], @query
1427 assert_query_result [@issue1, @issue2, @issue3], @query
1405 end
1428 end
1406
1429
1407 test "assigned_to_role filter should return issues with ! empty role" do
1430 test "assigned_to_role filter should return issues with ! empty role" do
1408 setup_assigned_to_role
1431 setup_assigned_to_role
1409 @empty_role = Role.generate!
1432 @empty_role = Role.generate!
1410 @query.add_filter('assigned_to_role', '!', [@empty_role.id.to_s])
1433 @query.add_filter('assigned_to_role', '!', [@empty_role.id.to_s])
1411
1434
1412 assert_query_result [@issue1, @issue2, @issue3, @issue4, @issue5], @query
1435 assert_query_result [@issue1, @issue2, @issue3, @issue4, @issue5], @query
1413 end
1436 end
1414
1437
1415 def test_query_column_should_accept_a_symbol_as_caption
1438 def test_query_column_should_accept_a_symbol_as_caption
1416 set_language_if_valid 'en'
1439 set_language_if_valid 'en'
1417 c = QueryColumn.new('foo', :caption => :general_text_Yes)
1440 c = QueryColumn.new('foo', :caption => :general_text_Yes)
1418 assert_equal 'Yes', c.caption
1441 assert_equal 'Yes', c.caption
1419 end
1442 end
1420
1443
1421 def test_query_column_should_accept_a_proc_as_caption
1444 def test_query_column_should_accept_a_proc_as_caption
1422 c = QueryColumn.new('foo', :caption => lambda {'Foo'})
1445 c = QueryColumn.new('foo', :caption => lambda {'Foo'})
1423 assert_equal 'Foo', c.caption
1446 assert_equal 'Foo', c.caption
1424 end
1447 end
1425 end
1448 end
@@ -1,462 +1,468
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2014 Jean-Philippe Lang
2 # Copyright (C) 2006-2014 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 RepositoryTest < ActiveSupport::TestCase
20 class RepositoryTest < ActiveSupport::TestCase
21 fixtures :projects,
21 fixtures :projects,
22 :trackers,
22 :trackers,
23 :projects_trackers,
23 :projects_trackers,
24 :enabled_modules,
24 :enabled_modules,
25 :repositories,
25 :repositories,
26 :issues,
26 :issues,
27 :issue_statuses,
27 :issue_statuses,
28 :issue_categories,
28 :issue_categories,
29 :changesets,
29 :changesets,
30 :changes,
30 :changes,
31 :users,
31 :users,
32 :members,
32 :members,
33 :member_roles,
33 :member_roles,
34 :roles,
34 :roles,
35 :enumerations
35 :enumerations
36
36
37 include Redmine::I18n
37 include Redmine::I18n
38
38
39 def setup
39 def setup
40 @repository = Project.find(1).repository
40 @repository = Project.find(1).repository
41 end
41 end
42
42
43 def test_blank_log_encoding_error_message
43 def test_blank_log_encoding_error_message
44 set_language_if_valid 'en'
44 set_language_if_valid 'en'
45 repo = Repository::Bazaar.new(
45 repo = Repository::Bazaar.new(
46 :project => Project.find(3),
46 :project => Project.find(3),
47 :url => "/test",
47 :url => "/test",
48 :log_encoding => ''
48 :log_encoding => ''
49 )
49 )
50 assert !repo.save
50 assert !repo.save
51 assert_include "Commit messages encoding can't be blank",
51 assert_include "Commit messages encoding can't be blank",
52 repo.errors.full_messages
52 repo.errors.full_messages
53 end
53 end
54
54
55 def test_blank_log_encoding_error_message_fr
55 def test_blank_log_encoding_error_message_fr
56 set_language_if_valid 'fr'
56 set_language_if_valid 'fr'
57 str = "Encodage des messages de commit doit \xc3\xaatre renseign\xc3\xa9(e)".force_encoding('UTF-8')
57 str = "Encodage des messages de commit doit \xc3\xaatre renseign\xc3\xa9(e)".force_encoding('UTF-8')
58 repo = Repository::Bazaar.new(
58 repo = Repository::Bazaar.new(
59 :project => Project.find(3),
59 :project => Project.find(3),
60 :url => "/test"
60 :url => "/test"
61 )
61 )
62 assert !repo.save
62 assert !repo.save
63 assert_include str, repo.errors.full_messages
63 assert_include str, repo.errors.full_messages
64 end
64 end
65
65
66 def test_create
66 def test_create
67 repository = Repository::Subversion.new(:project => Project.find(3))
67 repository = Repository::Subversion.new(:project => Project.find(3))
68 assert !repository.save
68 assert !repository.save
69
69
70 repository.url = "svn://localhost"
70 repository.url = "svn://localhost"
71 assert repository.save
71 assert repository.save
72 repository.reload
72 repository.reload
73
73
74 project = Project.find(3)
74 project = Project.find(3)
75 assert_equal repository, project.repository
75 assert_equal repository, project.repository
76 end
76 end
77
77
78 def test_first_repository_should_be_set_as_default
78 def test_first_repository_should_be_set_as_default
79 repository1 = Repository::Subversion.new(
79 repository1 = Repository::Subversion.new(
80 :project => Project.find(3),
80 :project => Project.find(3),
81 :identifier => 'svn1',
81 :identifier => 'svn1',
82 :url => 'file:///svn1'
82 :url => 'file:///svn1'
83 )
83 )
84 assert repository1.save
84 assert repository1.save
85 assert repository1.is_default?
85 assert repository1.is_default?
86
86
87 repository2 = Repository::Subversion.new(
87 repository2 = Repository::Subversion.new(
88 :project => Project.find(3),
88 :project => Project.find(3),
89 :identifier => 'svn2',
89 :identifier => 'svn2',
90 :url => 'file:///svn2'
90 :url => 'file:///svn2'
91 )
91 )
92 assert repository2.save
92 assert repository2.save
93 assert !repository2.is_default?
93 assert !repository2.is_default?
94
94
95 assert_equal repository1, Project.find(3).repository
95 assert_equal repository1, Project.find(3).repository
96 assert_equal [repository1, repository2], Project.find(3).repositories.sort
96 assert_equal [repository1, repository2], Project.find(3).repositories.sort
97 end
97 end
98
98
99 def test_default_repository_should_be_one
99 def test_default_repository_should_be_one
100 assert_equal 0, Project.find(3).repositories.count
100 assert_equal 0, Project.find(3).repositories.count
101 repository1 = Repository::Subversion.new(
101 repository1 = Repository::Subversion.new(
102 :project => Project.find(3),
102 :project => Project.find(3),
103 :identifier => 'svn1',
103 :identifier => 'svn1',
104 :url => 'file:///svn1'
104 :url => 'file:///svn1'
105 )
105 )
106 assert repository1.save
106 assert repository1.save
107 assert repository1.is_default?
107 assert repository1.is_default?
108
108
109 repository2 = Repository::Subversion.new(
109 repository2 = Repository::Subversion.new(
110 :project => Project.find(3),
110 :project => Project.find(3),
111 :identifier => 'svn2',
111 :identifier => 'svn2',
112 :url => 'file:///svn2',
112 :url => 'file:///svn2',
113 :is_default => true
113 :is_default => true
114 )
114 )
115 assert repository2.save
115 assert repository2.save
116 assert repository2.is_default?
116 assert repository2.is_default?
117 repository1.reload
117 repository1.reload
118 assert !repository1.is_default?
118 assert !repository1.is_default?
119
119
120 assert_equal repository2, Project.find(3).repository
120 assert_equal repository2, Project.find(3).repository
121 assert_equal [repository2, repository1], Project.find(3).repositories.sort
121 assert_equal [repository2, repository1], Project.find(3).repositories.sort
122 end
122 end
123
123
124 def test_identifier_should_accept_letters_digits_dashes_and_underscores
124 def test_identifier_should_accept_letters_digits_dashes_and_underscores
125 r = Repository::Subversion.new(
125 r = Repository::Subversion.new(
126 :project_id => 3,
126 :project_id => 3,
127 :identifier => 'svn-123_45',
127 :identifier => 'svn-123_45',
128 :url => 'file:///svn'
128 :url => 'file:///svn'
129 )
129 )
130 assert r.save
130 assert r.save
131 end
131 end
132
132
133 def test_identifier_should_not_be_frozen_for_a_new_repository
133 def test_identifier_should_not_be_frozen_for_a_new_repository
134 assert_equal false, Repository.new.identifier_frozen?
134 assert_equal false, Repository.new.identifier_frozen?
135 end
135 end
136
136
137 def test_identifier_should_not_be_frozen_for_a_saved_repository_with_blank_identifier
137 def test_identifier_should_not_be_frozen_for_a_saved_repository_with_blank_identifier
138 Repository.where(:id => 10).update_all(["identifier = ''"])
138 Repository.where(:id => 10).update_all(["identifier = ''"])
139 assert_equal false, Repository.find(10).identifier_frozen?
139 assert_equal false, Repository.find(10).identifier_frozen?
140 end
140 end
141
141
142 def test_identifier_should_be_frozen_for_a_saved_repository_with_valid_identifier
142 def test_identifier_should_be_frozen_for_a_saved_repository_with_valid_identifier
143 Repository.where(:id => 10).update_all(["identifier = 'abc123'"])
143 Repository.where(:id => 10).update_all(["identifier = 'abc123'"])
144 assert_equal true, Repository.find(10).identifier_frozen?
144 assert_equal true, Repository.find(10).identifier_frozen?
145 end
145 end
146
146
147 def test_identifier_should_not_accept_change_if_frozen
147 def test_identifier_should_not_accept_change_if_frozen
148 r = Repository.new(:identifier => 'foo')
148 r = Repository.new(:identifier => 'foo')
149 r.stubs(:identifier_frozen?).returns(true)
149 r.stubs(:identifier_frozen?).returns(true)
150
150
151 r.identifier = 'bar'
151 r.identifier = 'bar'
152 assert_equal 'foo', r.identifier
152 assert_equal 'foo', r.identifier
153 end
153 end
154
154
155 def test_identifier_should_accept_change_if_not_frozen
155 def test_identifier_should_accept_change_if_not_frozen
156 r = Repository.new(:identifier => 'foo')
156 r = Repository.new(:identifier => 'foo')
157 r.stubs(:identifier_frozen?).returns(false)
157 r.stubs(:identifier_frozen?).returns(false)
158
158
159 r.identifier = 'bar'
159 r.identifier = 'bar'
160 assert_equal 'bar', r.identifier
160 assert_equal 'bar', r.identifier
161 end
161 end
162
162
163 def test_destroy
163 def test_destroy
164 repository = Repository.find(10)
164 repository = Repository.find(10)
165 changesets = repository.changesets.count
165 changesets = repository.changesets.count
166 changes = repository.filechanges.count
166 changes = repository.filechanges.count
167
167
168 assert_difference 'Changeset.count', -changesets do
168 assert_difference 'Changeset.count', -changesets do
169 assert_difference 'Change.count', -changes do
169 assert_difference 'Change.count', -changes do
170 Repository.find(10).destroy
170 Repository.find(10).destroy
171 end
171 end
172 end
172 end
173 end
173 end
174
174
175 def test_destroy_should_delete_parents_associations
175 def test_destroy_should_delete_parents_associations
176 changeset = Changeset.find(102)
176 changeset = Changeset.find(102)
177 changeset.parents = Changeset.where(:id => [100, 101]).to_a
177 changeset.parents = Changeset.where(:id => [100, 101]).to_a
178 assert_difference 'Changeset.connection.select_all("select * from changeset_parents").count', -2 do
178 assert_difference 'Changeset.connection.select_all("select * from changeset_parents").count', -2 do
179 Repository.find(10).destroy
179 Repository.find(10).destroy
180 end
180 end
181 end
181 end
182
182
183 def test_destroy_should_delete_issues_associations
183 def test_destroy_should_delete_issues_associations
184 changeset = Changeset.find(102)
184 changeset = Changeset.find(102)
185 changeset.issues = Issue.where(:id => [1, 2]).to_a
185 changeset.issues = Issue.where(:id => [1, 2]).to_a
186 assert_difference 'Changeset.connection.select_all("select * from changesets_issues").count', -2 do
186 assert_difference 'Changeset.connection.select_all("select * from changesets_issues").count', -2 do
187 Repository.find(10).destroy
187 Repository.find(10).destroy
188 end
188 end
189 end
189 end
190
190
191 def test_should_not_create_with_disabled_scm
191 def test_should_not_create_with_disabled_scm
192 # disable Subversion
192 # disable Subversion
193 with_settings :enabled_scm => ['Darcs', 'Git'] do
193 with_settings :enabled_scm => ['Darcs', 'Git'] do
194 repository = Repository::Subversion.new(
194 repository = Repository::Subversion.new(
195 :project => Project.find(3), :url => "svn://localhost")
195 :project => Project.find(3), :url => "svn://localhost")
196 assert !repository.save
196 assert !repository.save
197 assert_include I18n.translate('activerecord.errors.messages.invalid'),
197 assert_include I18n.translate('activerecord.errors.messages.invalid'),
198 repository.errors[:type]
198 repository.errors[:type]
199 end
199 end
200 end
200 end
201
201
202 def test_scan_changesets_for_issue_ids
202 def test_scan_changesets_for_issue_ids
203 Setting.default_language = 'en'
203 Setting.default_language = 'en'
204 Setting.commit_ref_keywords = 'refs , references, IssueID'
204 Setting.commit_ref_keywords = 'refs , references, IssueID'
205 Setting.commit_update_keywords = [
205 Setting.commit_update_keywords = [
206 {'keywords' => 'fixes , closes',
206 {'keywords' => 'fixes , closes',
207 'status_id' => IssueStatus.where(:is_closed => true).first.id,
207 'status_id' => IssueStatus.where(:is_closed => true).first.id,
208 'done_ratio' => '90'}
208 'done_ratio' => '90'}
209 ]
209 ]
210 Setting.default_language = 'en'
210 Setting.default_language = 'en'
211 ActionMailer::Base.deliveries.clear
211 ActionMailer::Base.deliveries.clear
212
212
213 # make sure issue 1 is not already closed
213 # make sure issue 1 is not already closed
214 fixed_issue = Issue.find(1)
214 fixed_issue = Issue.find(1)
215 assert !fixed_issue.closed?
215 assert !fixed_issue.closed?
216 old_status = fixed_issue.status
216 old_status = fixed_issue.status
217
217
218 with_settings :notified_events => %w(issue_added issue_updated) do
218 with_settings :notified_events => %w(issue_added issue_updated) do
219 Repository.scan_changesets_for_issue_ids
219 Repository.scan_changesets_for_issue_ids
220 end
220 end
221 assert_equal [101, 102], Issue.find(3).changeset_ids
221 assert_equal [101, 102], Issue.find(3).changeset_ids
222
222
223 # fixed issues
223 # fixed issues
224 fixed_issue.reload
224 fixed_issue.reload
225 assert fixed_issue.closed?
225 assert fixed_issue.closed?
226 assert_equal 90, fixed_issue.done_ratio
226 assert_equal 90, fixed_issue.done_ratio
227 assert_equal [101], fixed_issue.changeset_ids
227 assert_equal [101], fixed_issue.changeset_ids
228
228
229 # issue change
229 # issue change
230 journal = fixed_issue.journals.reorder('created_on desc').first
230 journal = fixed_issue.journals.reorder('created_on desc').first
231 assert_equal User.find_by_login('dlopper'), journal.user
231 assert_equal User.find_by_login('dlopper'), journal.user
232 assert_equal 'Applied in changeset r2.', journal.notes
232 assert_equal 'Applied in changeset r2.', journal.notes
233
233
234 # 2 email notifications
234 # 2 email notifications
235 assert_equal 2, ActionMailer::Base.deliveries.size
235 assert_equal 2, ActionMailer::Base.deliveries.size
236 mail = ActionMailer::Base.deliveries.first
236 mail = ActionMailer::Base.deliveries.first
237 assert_not_nil mail
237 assert_not_nil mail
238 assert mail.subject.starts_with?(
238 assert mail.subject.starts_with?(
239 "[#{fixed_issue.project.name} - #{fixed_issue.tracker.name} ##{fixed_issue.id}]")
239 "[#{fixed_issue.project.name} - #{fixed_issue.tracker.name} ##{fixed_issue.id}]")
240 assert_mail_body_match(
240 assert_mail_body_match(
241 "Status changed from #{old_status} to #{fixed_issue.status}", mail)
241 "Status changed from #{old_status} to #{fixed_issue.status}", mail)
242
242
243 # ignoring commits referencing an issue of another project
243 # ignoring commits referencing an issue of another project
244 assert_equal [], Issue.find(4).changesets
244 assert_equal [], Issue.find(4).changesets
245 end
245 end
246
246
247 def test_for_changeset_comments_strip
247 def test_for_changeset_comments_strip
248 repository = Repository::Mercurial.create(
248 repository = Repository::Mercurial.create(
249 :project => Project.find( 4 ),
249 :project => Project.find( 4 ),
250 :url => '/foo/bar/baz' )
250 :url => '/foo/bar/baz' )
251 comment = <<-COMMENT
251 comment = <<-COMMENT
252 This is a loooooooooooooooooooooooooooong comment
252 This is a loooooooooooooooooooooooooooong comment
253
253
254
254
255 COMMENT
255 COMMENT
256 changeset = Changeset.new(
256 changeset = Changeset.new(
257 :comments => comment, :commit_date => Time.now,
257 :comments => comment, :commit_date => Time.now,
258 :revision => 0, :scmid => 'f39b7922fb3c',
258 :revision => 0, :scmid => 'f39b7922fb3c',
259 :committer => 'foo <foo@example.com>',
259 :committer => 'foo <foo@example.com>',
260 :committed_on => Time.now, :repository => repository )
260 :committed_on => Time.now, :repository => repository )
261 assert( changeset.save )
261 assert( changeset.save )
262 assert_not_equal( comment, changeset.comments )
262 assert_not_equal( comment, changeset.comments )
263 assert_equal( 'This is a loooooooooooooooooooooooooooong comment',
263 assert_equal( 'This is a loooooooooooooooooooooooooooong comment',
264 changeset.comments )
264 changeset.comments )
265 end
265 end
266
266
267 def test_for_urls_strip_cvs
267 def test_for_urls_strip_cvs
268 repository = Repository::Cvs.create(
268 repository = Repository::Cvs.create(
269 :project => Project.find(4),
269 :project => Project.find(4),
270 :url => ' :pserver:login:password@host:/path/to/the/repository',
270 :url => ' :pserver:login:password@host:/path/to/the/repository',
271 :root_url => 'foo ',
271 :root_url => 'foo ',
272 :log_encoding => 'UTF-8')
272 :log_encoding => 'UTF-8')
273 assert repository.save
273 assert repository.save
274 repository.reload
274 repository.reload
275 assert_equal ':pserver:login:password@host:/path/to/the/repository',
275 assert_equal ':pserver:login:password@host:/path/to/the/repository',
276 repository.url
276 repository.url
277 assert_equal 'foo', repository.root_url
277 assert_equal 'foo', repository.root_url
278 end
278 end
279
279
280 def test_for_urls_strip_subversion
280 def test_for_urls_strip_subversion
281 repository = Repository::Subversion.create(
281 repository = Repository::Subversion.create(
282 :project => Project.find(4),
282 :project => Project.find(4),
283 :url => ' file:///dummy ')
283 :url => ' file:///dummy ')
284 assert repository.save
284 assert repository.save
285 repository.reload
285 repository.reload
286 assert_equal 'file:///dummy', repository.url
286 assert_equal 'file:///dummy', repository.url
287 end
287 end
288
288
289 def test_for_urls_strip_git
289 def test_for_urls_strip_git
290 repository = Repository::Git.create(
290 repository = Repository::Git.create(
291 :project => Project.find(4),
291 :project => Project.find(4),
292 :url => ' c:\dummy ')
292 :url => ' c:\dummy ')
293 assert repository.save
293 assert repository.save
294 repository.reload
294 repository.reload
295 assert_equal 'c:\dummy', repository.url
295 assert_equal 'c:\dummy', repository.url
296 end
296 end
297
297
298 def test_manual_user_mapping
298 def test_manual_user_mapping
299 assert_no_difference "Changeset.where('user_id <> 2').count" do
299 assert_no_difference "Changeset.where('user_id <> 2').count" do
300 c = Changeset.create!(
300 c = Changeset.create!(
301 :repository => @repository,
301 :repository => @repository,
302 :committer => 'foo',
302 :committer => 'foo',
303 :committed_on => Time.now,
303 :committed_on => Time.now,
304 :revision => 100,
304 :revision => 100,
305 :comments => 'Committed by foo.'
305 :comments => 'Committed by foo.'
306 )
306 )
307 assert_nil c.user
307 assert_nil c.user
308 @repository.committer_ids = {'foo' => '2'}
308 @repository.committer_ids = {'foo' => '2'}
309 assert_equal User.find(2), c.reload.user
309 assert_equal User.find(2), c.reload.user
310 # committer is now mapped
310 # committer is now mapped
311 c = Changeset.create!(
311 c = Changeset.create!(
312 :repository => @repository,
312 :repository => @repository,
313 :committer => 'foo',
313 :committer => 'foo',
314 :committed_on => Time.now,
314 :committed_on => Time.now,
315 :revision => 101,
315 :revision => 101,
316 :comments => 'Another commit by foo.'
316 :comments => 'Another commit by foo.'
317 )
317 )
318 assert_equal User.find(2), c.user
318 assert_equal User.find(2), c.user
319 end
319 end
320 end
320 end
321
321
322 def test_auto_user_mapping_by_username
322 def test_auto_user_mapping_by_username
323 c = Changeset.create!(
323 c = Changeset.create!(
324 :repository => @repository,
324 :repository => @repository,
325 :committer => 'jsmith',
325 :committer => 'jsmith',
326 :committed_on => Time.now,
326 :committed_on => Time.now,
327 :revision => 100,
327 :revision => 100,
328 :comments => 'Committed by john.'
328 :comments => 'Committed by john.'
329 )
329 )
330 assert_equal User.find(2), c.user
330 assert_equal User.find(2), c.user
331 end
331 end
332
332
333 def test_auto_user_mapping_by_email
333 def test_auto_user_mapping_by_email
334 c = Changeset.create!(
334 c = Changeset.create!(
335 :repository => @repository,
335 :repository => @repository,
336 :committer => 'john <jsmith@somenet.foo>',
336 :committer => 'john <jsmith@somenet.foo>',
337 :committed_on => Time.now,
337 :committed_on => Time.now,
338 :revision => 100,
338 :revision => 100,
339 :comments => 'Committed by john.'
339 :comments => 'Committed by john.'
340 )
340 )
341 assert_equal User.find(2), c.user
341 assert_equal User.find(2), c.user
342 end
342 end
343
343
344 def test_filesystem_avaialbe
344 def test_filesystem_avaialbe
345 klass = Repository::Filesystem
345 klass = Repository::Filesystem
346 assert klass.scm_adapter_class
346 assert klass.scm_adapter_class
347 assert_equal true, klass.scm_available
347 assert_equal true, klass.scm_available
348 end
348 end
349
349
350 def test_extra_info_should_not_return_non_hash_value
350 def test_extra_info_should_not_return_non_hash_value
351 repo = Repository.new
351 repo = Repository.new
352 repo.extra_info = "foo"
352 repo.extra_info = "foo"
353 assert_nil repo.extra_info
353 assert_nil repo.extra_info
354 end
354 end
355
355
356 def test_merge_extra_info
356 def test_merge_extra_info
357 repo = Repository::Subversion.new(:project => Project.find(3))
357 repo = Repository::Subversion.new(:project => Project.find(3))
358 assert !repo.save
358 assert !repo.save
359 repo.url = "svn://localhost"
359 repo.url = "svn://localhost"
360 assert repo.save
360 assert repo.save
361 repo.reload
361 repo.reload
362 project = Project.find(3)
362 project = Project.find(3)
363 assert_equal repo, project.repository
363 assert_equal repo, project.repository
364 assert_nil repo.extra_info
364 assert_nil repo.extra_info
365 h1 = {"test_1" => {"test_11" => "test_value_11"}}
365 h1 = {"test_1" => {"test_11" => "test_value_11"}}
366 repo.merge_extra_info(h1)
366 repo.merge_extra_info(h1)
367 assert_equal h1, repo.extra_info
367 assert_equal h1, repo.extra_info
368 h2 = {"test_2" => {
368 h2 = {"test_2" => {
369 "test_21" => "test_value_21",
369 "test_21" => "test_value_21",
370 "test_22" => "test_value_22",
370 "test_22" => "test_value_22",
371 }}
371 }}
372 repo.merge_extra_info(h2)
372 repo.merge_extra_info(h2)
373 assert_equal (h = {"test_11" => "test_value_11"}),
373 assert_equal (h = {"test_11" => "test_value_11"}),
374 repo.extra_info["test_1"]
374 repo.extra_info["test_1"]
375 assert_equal "test_value_21",
375 assert_equal "test_value_21",
376 repo.extra_info["test_2"]["test_21"]
376 repo.extra_info["test_2"]["test_21"]
377 h3 = {"test_2" => {
377 h3 = {"test_2" => {
378 "test_23" => "test_value_23",
378 "test_23" => "test_value_23",
379 "test_24" => "test_value_24",
379 "test_24" => "test_value_24",
380 }}
380 }}
381 repo.merge_extra_info(h3)
381 repo.merge_extra_info(h3)
382 assert_equal (h = {"test_11" => "test_value_11"}),
382 assert_equal (h = {"test_11" => "test_value_11"}),
383 repo.extra_info["test_1"]
383 repo.extra_info["test_1"]
384 assert_nil repo.extra_info["test_2"]["test_21"]
384 assert_nil repo.extra_info["test_2"]["test_21"]
385 assert_equal "test_value_23",
385 assert_equal "test_value_23",
386 repo.extra_info["test_2"]["test_23"]
386 repo.extra_info["test_2"]["test_23"]
387 end
387 end
388
388
389 def test_sort_should_not_raise_an_error_with_nil_identifiers
389 def test_sort_should_not_raise_an_error_with_nil_identifiers
390 r1 = Repository.new
390 r1 = Repository.new
391 r2 = Repository.new
391 r2 = Repository.new
392
392
393 assert_nothing_raised do
393 assert_nothing_raised do
394 [r1, r2].sort
394 [r1, r2].sort
395 end
395 end
396 end
396 end
397
397
398 def test_stats_by_author_reflect_changesets_and_changes
398 def test_stats_by_author_reflect_changesets_and_changes
399 repository = Repository.find(10)
399 repository = Repository.find(10)
400
400
401 expected = {"Dave Lopper"=>{:commits_count=>10, :changes_count=>3}}
401 expected = {"Dave Lopper"=>{:commits_count=>10, :changes_count=>3}}
402 assert_equal expected, repository.stats_by_author
402 assert_equal expected, repository.stats_by_author
403
403
404 set = Changeset.create!(
404 set = Changeset.create!(
405 :repository => repository,
405 :repository => repository,
406 :committer => 'dlopper',
406 :committer => 'dlopper',
407 :committed_on => Time.now,
407 :committed_on => Time.now,
408 :revision => 101,
408 :revision => 101,
409 :comments => 'Another commit by foo.'
409 :comments => 'Another commit by foo.'
410 )
410 )
411 Change.create!(:changeset => set, :action => 'A', :path => '/path/to/file1')
411 Change.create!(:changeset => set, :action => 'A', :path => '/path/to/file1')
412 Change.create!(:changeset => set, :action => 'A', :path => '/path/to/file2')
412 Change.create!(:changeset => set, :action => 'A', :path => '/path/to/file2')
413 expected = {"Dave Lopper"=>{:commits_count=>11, :changes_count=>5}}
413 expected = {"Dave Lopper"=>{:commits_count=>11, :changes_count=>5}}
414 assert_equal expected, repository.stats_by_author
414 assert_equal expected, repository.stats_by_author
415 end
415 end
416
416
417 def test_stats_by_author_honnor_committers
417 def test_stats_by_author_honnor_committers
418 # in fact it is really tested above, but let's have a dedicated test
418 # in fact it is really tested above, but let's have a dedicated test
419 # to ensure things are dynamically linked to Users
419 # to ensure things are dynamically linked to Users
420 User.find_by_login("dlopper").update_attribute(:firstname, "Dave's")
420 User.find_by_login("dlopper").update_attribute(:firstname, "Dave's")
421 repository = Repository.find(10)
421 repository = Repository.find(10)
422 expected = {"Dave's Lopper"=>{:commits_count=>10, :changes_count=>3}}
422 expected = {"Dave's Lopper"=>{:commits_count=>10, :changes_count=>3}}
423 assert_equal expected, repository.stats_by_author
423 assert_equal expected, repository.stats_by_author
424 end
424 end
425
425
426 def test_stats_by_author_doesnt_drop_unmapped_users
426 def test_stats_by_author_doesnt_drop_unmapped_users
427 repository = Repository.find(10)
427 repository = Repository.find(10)
428 Changeset.create!(
428 Changeset.create!(
429 :repository => repository,
429 :repository => repository,
430 :committer => 'unnamed <foo@bar.net>',
430 :committer => 'unnamed <foo@bar.net>',
431 :committed_on => Time.now,
431 :committed_on => Time.now,
432 :revision => 101,
432 :revision => 101,
433 :comments => 'Another commit by foo.'
433 :comments => 'Another commit by foo.'
434 )
434 )
435
435
436 assert repository.stats_by_author.has_key?("unnamed <foo@bar.net>")
436 assert repository.stats_by_author.has_key?("unnamed <foo@bar.net>")
437 end
437 end
438
438
439 def test_stats_by_author_merge_correctly
439 def test_stats_by_author_merge_correctly
440 # as we honnor users->committer map and it's not injective,
440 # as we honnor users->committer map and it's not injective,
441 # we must be sure merges happen correctly and stats are not
441 # we must be sure merges happen correctly and stats are not
442 # wiped out when two source counts map to the same user.
442 # wiped out when two source counts map to the same user.
443 #
443 #
444 # Here we have Changeset's with committer="dlopper" and others
444 # Here we have Changeset's with committer="dlopper" and others
445 # with committer="dlopper <dlopper@somefoo.net>"
445 # with committer="dlopper <dlopper@somefoo.net>"
446 repository = Repository.find(10)
446 repository = Repository.find(10)
447
447
448 expected = {"Dave Lopper"=>{:commits_count=>10, :changes_count=>3}}
448 expected = {"Dave Lopper"=>{:commits_count=>10, :changes_count=>3}}
449 assert_equal expected, repository.stats_by_author
449 assert_equal expected, repository.stats_by_author
450
450
451 set = Changeset.create!(
451 set = Changeset.create!(
452 :repository => repository,
452 :repository => repository,
453 :committer => 'dlopper <dlopper@somefoo.net>',
453 :committer => 'dlopper <dlopper@somefoo.net>',
454 :committed_on => Time.now,
454 :committed_on => Time.now,
455 :revision => 101,
455 :revision => 101,
456 :comments => 'Another commit by foo.'
456 :comments => 'Another commit by foo.'
457 )
457 )
458
458
459 expected = {"Dave Lopper"=>{:commits_count=>11, :changes_count=>3}}
459 expected = {"Dave Lopper"=>{:commits_count=>11, :changes_count=>3}}
460 assert_equal expected, repository.stats_by_author
460 assert_equal expected, repository.stats_by_author
461 end
461 end
462
463 def test_fetch_changesets
464 # 2 repositories in fixtures
465 Repository::Subversion.any_instance.expects(:fetch_changesets).twice.returns(true)
466 Repository.fetch_changesets
467 end
462 end
468 end
General Comments 0
You need to be logged in to leave comments. Login now