annotate test/unit/query_test.rb @ 1477:f2ad2199b49a bibplugin_integration

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