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