issues_controller_test.rb 61.2 KB
Newer Older
1
# Redmine - project management software
2
# Copyright (C) 2006-2011  Jean-Philippe Lang
3 4 5 6 7
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
8
#
9 10 11 12
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
13
#
14 15 16 17
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

18
require File.expand_path('../../test_helper', __FILE__)
19 20
require 'issues_controller'

edavis10's avatar
edavis10 committed
21
class IssuesControllerTest < ActionController::TestCase
22 23 24 25
  fixtures :projects,
           :users,
           :roles,
           :members,
26
           :member_roles,
27 28
           :issues,
           :issue_statuses,
29
           :versions,
30
           :trackers,
31
           :projects_trackers,
32 33 34
           :issue_categories,
           :enabled_modules,
           :enumerations,
35
           :attachments,
36 37 38
           :workflows,
           :custom_fields,
           :custom_values,
jplang's avatar
jplang committed
39
           :custom_fields_projects,
40
           :custom_fields_trackers,
41 42
           :time_entries,
           :journals,
edavis10's avatar
edavis10 committed
43 44
           :journal_details,
           :queries
45

46 47 48 49 50 51
  def setup
    @controller = IssuesController.new
    @request    = ActionController::TestRequest.new
    @response   = ActionController::TestResponse.new
    User.current = nil
  end
52

53
  def test_index
54
    Setting.default_language = 'en'
55

56 57
    get :index
    assert_response :success
58
    assert_template 'index'
59 60
    assert_not_nil assigns(:issues)
    assert_nil assigns(:project)
61 62 63 64 65
    assert_tag :tag => 'a', :content => /Can't print recipes/
    assert_tag :tag => 'a', :content => /Subproject issue/
    # private projects hidden
    assert_no_tag :tag => 'a', :content => /Issue of a private subproject/
    assert_no_tag :tag => 'a', :content => /Issue on project 2/
66 67
    # project column
    assert_tag :tag => 'th', :content => /Project/
68
  end
69

70 71
  def test_index_should_not_list_issues_when_module_disabled
    EnabledModule.delete_all("name = 'issue_tracking' AND project_id = 1")
72 73
    get :index
    assert_response :success
74
    assert_template 'index'
75 76 77 78 79
    assert_not_nil assigns(:issues)
    assert_nil assigns(:project)
    assert_no_tag :tag => 'a', :content => /Can't print recipes/
    assert_tag :tag => 'a', :content => /Subproject issue/
  end
jplang's avatar
jplang committed
80 81 82 83 84 85 86

  def test_index_should_list_visible_issues_only
    get :index, :per_page => 100
    assert_response :success
    assert_not_nil assigns(:issues)
    assert_nil assigns(:issues).detect {|issue| !issue.visible?}
  end
87

88
  def test_index_with_project
89
    Setting.display_subprojects_issues = 0
90 91
    get :index, :project_id => 1
    assert_response :success
92
    assert_template 'index'
93
    assert_not_nil assigns(:issues)
94 95 96
    assert_tag :tag => 'a', :content => /Can't print recipes/
    assert_no_tag :tag => 'a', :content => /Subproject issue/
  end
97

98 99 100 101
  def test_index_with_project_and_subprojects
    Setting.display_subprojects_issues = 1
    get :index, :project_id => 1
    assert_response :success
102
    assert_template 'index'
103 104 105 106 107
    assert_not_nil assigns(:issues)
    assert_tag :tag => 'a', :content => /Can't print recipes/
    assert_tag :tag => 'a', :content => /Subproject issue/
    assert_no_tag :tag => 'a', :content => /Issue of a private subproject/
  end
108

109 110 111 112 113
  def test_index_with_project_and_subprojects_should_show_private_subprojects
    @request.session[:user_id] = 2
    Setting.display_subprojects_issues = 1
    get :index, :project_id => 1
    assert_response :success
114
    assert_template 'index'
115 116 117 118
    assert_not_nil assigns(:issues)
    assert_tag :tag => 'a', :content => /Can't print recipes/
    assert_tag :tag => 'a', :content => /Subproject issue/
    assert_tag :tag => 'a', :content => /Issue of a private subproject/
119
  end
120

121
  def test_index_with_project_and_default_filter
122 123
    get :index, :project_id => 1, :set_filter => 1
    assert_response :success
124
    assert_template 'index'
125
    assert_not_nil assigns(:issues)
126

127 128 129 130 131
    query = assigns(:query)
    assert_not_nil query
    # default filter
    assert_equal({'status_id' => {:operator => 'o', :values => ['']}}, query.filters)
  end
132

133
  def test_index_with_project_and_filter
134
    get :index, :project_id => 1, :set_filter => 1,
jplang's avatar
jplang committed
135 136
      :f => ['tracker_id'],
      :op => {'tracker_id' => '='},
137
      :v => {'tracker_id' => ['1']}
138
    assert_response :success
139
    assert_template 'index'
140
    assert_not_nil assigns(:issues)
141

142 143 144 145
    query = assigns(:query)
    assert_not_nil query
    assert_equal({'tracker_id' => {:operator => '=', :values => ['1']}}, query.filters)
  end
146

147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
  def test_index_with_short_filters

    to_test = {
      'status_id' => {
        'o' => { :op => 'o', :values => [''] },
        'c' => { :op => 'c', :values => [''] },
        '7' => { :op => '=', :values => ['7'] },
        '7|3|4' => { :op => '=', :values => ['7', '3', '4'] },
        '=7' => { :op => '=', :values => ['7'] },
        '!3' => { :op => '!', :values => ['3'] },
        '!7|3|4' => { :op => '!', :values => ['7', '3', '4'] }},
      'subject' => {
        'This is a subject' => { :op => '=', :values => ['This is a subject'] },
        'o' => { :op => '=', :values => ['o'] },
        '~This is part of a subject' => { :op => '~', :values => ['This is part of a subject'] },
        '!~This is part of a subject' => { :op => '!~', :values => ['This is part of a subject'] }},
      'start_date' => {
        '2011-10-12' => { :op => '=', :values => ['2011-10-12'] },
        '=2011-10-12' => { :op => '=', :values => ['2011-10-12'] },
        '>=2011-10-12' => { :op => '>=', :values => ['2011-10-12'] },
        '<=2011-10-12' => { :op => '<=', :values => ['2011-10-12'] },
        '><2011-10-01|2011-10-30' => { :op => '><', :values => ['2011-10-01', '2011-10-30'] },
        '<t+2' => { :op => '<t+', :values => ['2'] },
        '>t+2' => { :op => '>t+', :values => ['2'] },
        't+2' => { :op => 't+', :values => ['2'] },
        't' => { :op => 't', :values => [''] },
        'w' => { :op => 'w', :values => [''] },
        '>t-2' => { :op => '>t-', :values => ['2'] },
        '<t-2' => { :op => '<t-', :values => ['2'] },
        't-2' => { :op => 't-', :values => ['2'] }},
      'created_on' => {
        '>=2011-10-12' => { :op => '>=', :values => ['2011-10-12'] },
        '<t+2' => { :op => '=', :values => ['<t+2'] },
        '>t+2' => { :op => '=', :values => ['>t+2'] },
        't+2' => { :op => 't', :values => ['+2'] }},
      'cf_1' => {
        'c' => { :op => '=', :values => ['c'] },
        '!c' => { :op => '!', :values => ['c'] },
        '!*' => { :op => '!*', :values => [''] },
        '*' => { :op => '*', :values => [''] }},
      'estimated_hours' => {
        '=13.4' => { :op => '=', :values => ['13.4'] },
        '>=45' => { :op => '>=', :values => ['45'] },
        '<=125' => { :op => '<=', :values => ['125'] },
        '><10.5|20.5' => { :op => '><', :values => ['10.5', '20.5'] },
        '!*' => { :op => '!*', :values => [''] },
        '*' => { :op => '*', :values => [''] }}
    }

    default_filter = { 'status_id' => {:operator => 'o', :values => [''] }}

    to_test.each do |field, expression_and_expected|
      expression_and_expected.each do |filter_expression, expected|
200
puts field + ' / ' + filter_expression + ' => ' + expected.inspect
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
        get :index, :set_filter => 1, field => filter_expression

        assert_response :success
        assert_template 'index'
        assert_not_nil assigns(:issues)

        query = assigns(:query)
        assert_not_nil query
        assert query.has_filter?(field)
        assert_equal(default_filter.merge({field => {:operator => expected[:op], :values => expected[:values]}}), query.filters)
      end
    end

  end

216 217 218
  def test_index_with_project_and_empty_filters
    get :index, :project_id => 1, :set_filter => 1, :fields => ['']
    assert_response :success
219
    assert_template 'index'
220
    assert_not_nil assigns(:issues)
221

222 223 224 225
    query = assigns(:query)
    assert_not_nil query
    # no filter
    assert_equal({}, query.filters)
226
  end
227

jplang's avatar
jplang committed
228 229 230
  def test_index_with_query
    get :index, :project_id => 1, :query_id => 5
    assert_response :success
231
    assert_template 'index'
jplang's avatar
jplang committed
232 233 234
    assert_not_nil assigns(:issues)
    assert_nil assigns(:issue_count_by_group)
  end
235

236
  def test_index_with_query_grouped_by_tracker
jplang's avatar
jplang committed
237 238
    get :index, :project_id => 1, :query_id => 6
    assert_response :success
239
    assert_template 'index'
jplang's avatar
jplang committed
240
    assert_not_nil assigns(:issues)
241
    assert_not_nil assigns(:issue_count_by_group)
242
  end
243

244 245 246
  def test_index_with_query_grouped_by_list_custom_field
    get :index, :project_id => 1, :query_id => 9
    assert_response :success
247
    assert_template 'index'
248
    assert_not_nil assigns(:issues)
249
    assert_not_nil assigns(:issue_count_by_group)
jplang's avatar
jplang committed
250
  end
251

252 253 254
  def test_private_query_should_not_be_available_to_other_users
    q = Query.create!(:name => "private", :user => User.find(2), :is_public => false, :project => nil)
    @request.session[:user_id] = 3
255

256 257 258
    get :index, :query_id => q.id
    assert_response 403
  end
259

260 261 262
  def test_private_query_should_be_available_to_its_user
    q = Query.create!(:name => "private", :user => User.find(2), :is_public => false, :project => nil)
    @request.session[:user_id] = 2
263

264 265 266
    get :index, :query_id => q.id
    assert_response :success
  end
267

268 269 270
  def test_public_query_should_be_available_to_other_users
    q = Query.create!(:name => "private", :user => User.find(2), :is_public => true, :project => nil)
    @request.session[:user_id] = 3
271

272 273 274
    get :index, :query_id => q.id
    assert_response :success
  end
275

jplang's avatar
jplang committed
276 277 278 279
  def test_index_sort_by_field_not_included_in_columns
    Setting.issue_list_default_columns = %w(subject author)
    get :index, :sort => 'tracker'
  end
280

281
  def test_index_csv_with_project
282
    Setting.default_language = 'en'
283

284 285 286 287
    get :index, :format => 'csv'
    assert_response :success
    assert_not_nil assigns(:issues)
    assert_equal 'text/csv', @response.content_type
288
    assert @response.body.starts_with?("#,")
289 290 291 292 293 294

    get :index, :project_id => 1, :format => 'csv'
    assert_response :success
    assert_not_nil assigns(:issues)
    assert_equal 'text/csv', @response.content_type
  end
295

296 297 298 299 300
  def test_index_pdf
    get :index, :format => 'pdf'
    assert_response :success
    assert_not_nil assigns(:issues)
    assert_equal 'application/pdf', @response.content_type
301

302 303 304 305
    get :index, :project_id => 1, :format => 'pdf'
    assert_response :success
    assert_not_nil assigns(:issues)
    assert_equal 'application/pdf', @response.content_type
306

jplang's avatar
jplang committed
307 308 309 310
    get :index, :project_id => 1, :query_id => 6, :format => 'pdf'
    assert_response :success
    assert_not_nil assigns(:issues)
    assert_equal 'application/pdf', @response.content_type
311
  end
312

313 314 315 316 317 318 319
  def test_index_pdf_with_query_grouped_by_list_custom_field
    get :index, :project_id => 1, :query_id => 9, :format => 'pdf'
    assert_response :success
    assert_not_nil assigns(:issues)
    assert_not_nil assigns(:issue_count_by_group)
    assert_equal 'application/pdf', @response.content_type
  end
320

321
  def test_index_sort
jplang's avatar
jplang committed
322
    get :index, :sort => 'tracker,id:desc'
323
    assert_response :success
324

jplang's avatar
jplang committed
325 326 327
    sort_params = @request.session['issues_index_sort']
    assert sort_params.is_a?(String)
    assert_equal 'tracker,id:desc', sort_params
328

jplang's avatar
jplang committed
329 330 331 332
    issues = assigns(:issues)
    assert_not_nil issues
    assert !issues.empty?
    assert_equal issues.sort {|a,b| a.tracker == b.tracker ? b.id <=> a.id : a.tracker <=> b.tracker }.collect(&:id), issues.collect(&:id)
333
  end
334

335 336
  def test_index_with_columns
    columns = ['tracker', 'subject', 'assigned_to']
337
    get :index, :set_filter => 1, :c => columns
338
    assert_response :success
339

340 341 342 343
    # query should use specified columns
    query = assigns(:query)
    assert_kind_of Query, query
    assert_equal columns, query.column_names.map(&:to_s)
344

345 346 347 348
    # columns should be stored in session
    assert_kind_of Hash, session[:query]
    assert_kind_of Array, session[:query][:column_names]
    assert_equal columns, session[:query][:column_names].map(&:to_s)
349 350 351 352 353 354

    # ensure only these columns are kept in the selected columns list
    assert_tag :tag => 'select', :attributes => { :id => 'selected_columns' },
                                 :children => { :count => 3 }
    assert_no_tag :tag => 'option', :attributes => { :value => 'project' },
                                    :parent => { :tag => 'select', :attributes => { :id => "selected_columns" } }
355
  end
356

357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
  def test_index_without_project_should_implicitly_add_project_column_to_default_columns
    Setting.issue_list_default_columns = ['tracker', 'subject', 'assigned_to']
    get :index, :set_filter => 1

    # query should use specified columns
    query = assigns(:query)
    assert_kind_of Query, query
    assert_equal [:project, :tracker, :subject, :assigned_to], query.columns.map(&:name)
  end

  def test_index_without_project_and_explicit_default_columns_should_not_add_project_column
    Setting.issue_list_default_columns = ['tracker', 'subject', 'assigned_to']
    columns = ['tracker', 'subject', 'assigned_to']
    get :index, :set_filter => 1, :c => columns

    # query should use specified columns
    query = assigns(:query)
    assert_kind_of Query, query
    assert_equal columns.map(&:to_sym), query.columns.map(&:name)
  end

378 379 380 381
  def test_index_with_custom_field_column
    columns = %w(tracker subject cf_2)
    get :index, :set_filter => 1, :c => columns
    assert_response :success
382

383 384 385 386
    # query should use specified columns
    query = assigns(:query)
    assert_kind_of Query, query
    assert_equal columns, query.column_names.map(&:to_s)
387

388 389 390 391
    assert_tag :td,
      :attributes => {:class => 'cf_2 string'},
      :ancestor => {:tag => 'table', :attributes => {:class => /issues/}}
  end
392

393 394 395 396 397 398
  def test_index_send_html_if_query_is_invalid
    get :index, :f => ['start_date'], :op => {:start_date => '='}
    assert_equal 'text/html', @response.content_type
    assert_template 'index'
  end

399 400 401 402 403 404
  def test_index_send_nothing_if_query_is_invalid
    get :index, :f => ['start_date'], :op => {:start_date => '='}, :format => 'csv'
    assert_equal 'text/csv', @response.content_type
    assert @response.body.blank?
  end

405
  def test_show_by_anonymous
406 407
    get :show, :id => 1
    assert_response :success
408
    assert_template 'show'
409
    assert_not_nil assigns(:issue)
410
    assert_equal Issue.find(1), assigns(:issue)
411

412 413 414
    # anonymous role is allowed to add a note
    assert_tag :tag => 'form',
               :descendant => { :tag => 'fieldset',
415
                                :child => { :tag => 'legend',
416
                                            :content => /Notes/ } }
417
  end
418

419 420 421 422
  def test_show_by_manager
    @request.session[:user_id] = 2
    get :show, :id => 1
    assert_response :success
423

424 425
    assert_tag :tag => 'a',
      :content => /Quote/
426

427 428
    assert_tag :tag => 'form',
               :descendant => { :tag => 'fieldset',
429
                                :child => { :tag => 'legend',
430 431
                                            :content => /Change properties/ } },
               :descendant => { :tag => 'fieldset',
432
                                :child => { :tag => 'legend',
433 434
                                            :content => /Log time/ } },
               :descendant => { :tag => 'fieldset',
435
                                :child => { :tag => 'legend',
436 437
                                            :content => /Notes/ } }
  end
438

439 440 441 442 443 444 445 446 447
  def test_update_form_should_not_display_inactive_enumerations
    @request.session[:user_id] = 2
    get :show, :id => 1
    assert_response :success

    assert ! IssuePriority.find(15).active?
    assert_no_tag :option, :attributes => {:value => '15'},
                           :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} }
  end
448

449 450 451
  def test_update_form_should_allow_attachment_upload
    @request.session[:user_id] = 2
    get :show, :id => 1
452

453 454 455 456 457 458 459
    assert_tag :tag => 'form',
      :attributes => {:id => 'issue-form', :method => 'post', :enctype => 'multipart/form-data'},
      :descendant => {
        :tag => 'input',
        :attributes => {:type => 'file', :name => 'attachments[1][file]'}
      }
  end
460

jplang's avatar
jplang committed
461 462 463 464 465
  def test_show_should_deny_anonymous_access_without_permission
    Role.anonymous.remove_permission!(:view_issues)
    get :show, :id => 1
    assert_response :redirect
  end
466

jplang's avatar
jplang committed
467 468 469 470 471
  def test_show_should_deny_anonymous_access_to_private_issue
    Issue.update_all(["is_private = ?", true], "id = 1")
    get :show, :id => 1
    assert_response :redirect
  end
472

jplang's avatar
jplang committed
473 474 475 476 477 478
  def test_show_should_deny_non_member_access_without_permission
    Role.non_member.remove_permission!(:view_issues)
    @request.session[:user_id] = 9
    get :show, :id => 1
    assert_response 403
  end
479

jplang's avatar
jplang committed
480 481 482 483 484 485
  def test_show_should_deny_non_member_access_to_private_issue
    Issue.update_all(["is_private = ?", true], "id = 1")
    @request.session[:user_id] = 9
    get :show, :id => 1
    assert_response 403
  end
486

jplang's avatar
jplang committed
487 488 489 490 491 492
  def test_show_should_deny_member_access_without_permission
    Role.find(1).remove_permission!(:view_issues)
    @request.session[:user_id] = 2
    get :show, :id => 1
    assert_response 403
  end
493

jplang's avatar
jplang committed
494 495 496 497 498 499
  def test_show_should_deny_member_access_to_private_issue_without_permission
    Issue.update_all(["is_private = ?", true], "id = 1")
    @request.session[:user_id] = 3
    get :show, :id => 1
    assert_response 403
  end
500

jplang's avatar
jplang committed
501 502 503 504 505 506
  def test_show_should_allow_author_access_to_private_issue
    Issue.update_all(["is_private = ?, author_id = 3", true], "id = 1")
    @request.session[:user_id] = 3
    get :show, :id => 1
    assert_response :success
  end
507

jplang's avatar
jplang committed
508 509 510 511 512 513
  def test_show_should_allow_assignee_access_to_private_issue
    Issue.update_all(["is_private = ?, assigned_to_id = 3", true], "id = 1")
    @request.session[:user_id] = 3
    get :show, :id => 1
    assert_response :success
  end
514

jplang's avatar
jplang committed
515 516 517 518 519 520 521
  def test_show_should_allow_member_access_to_private_issue_with_permission
    Issue.update_all(["is_private = ?", true], "id = 1")
    User.find(3).roles_for_project(Project.find(1)).first.update_attribute :issues_visibility, 'all'
    @request.session[:user_id] = 3
    get :show, :id => 1
    assert_response :success
  end
522

523 524 525 526 527
  def test_show_should_not_disclose_relations_to_invisible_issues
    Setting.cross_project_issue_relations = '1'
    IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => 'relates')
    # Relation to a private project issue
    IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(4), :relation_type => 'relates')
528

529 530
    get :show, :id => 1
    assert_response :success
531

532 533 534 535 536
    assert_tag :div, :attributes => { :id => 'relations' },
                     :descendant => { :tag => 'a', :content => /#2$/ }
    assert_no_tag :div, :attributes => { :id => 'relations' },
                        :descendant => { :tag => 'a', :content => /#4$/ }
  end
537

538 539 540
  def test_show_atom
    get :show, :id => 2, :format => 'atom'
    assert_response :success
541
    assert_template 'journals/index'
542
    # Inline image
543
    assert_select 'content', :text => Regexp.new(Regexp.quote('http://test.host/attachments/download/10'))
544
  end
545

jplang's avatar
jplang committed
546
  def test_show_export_to_pdf
547
    get :show, :id => 3, :format => 'pdf'
jplang's avatar
jplang committed
548 549 550 551 552 553
    assert_response :success
    assert_equal 'application/pdf', @response.content_type
    assert @response.body.starts_with?('%PDF')
    assert_not_nil assigns(:issue)
  end

554 555 556 557 558
  def test_get_new
    @request.session[:user_id] = 2
    get :new, :project_id => 1, :tracker_id => 1
    assert_response :success
    assert_template 'new'
559

560
    assert_tag :tag => 'input', :attributes => { :name => 'issue[custom_field_values][2]',
561
                                                 :value => 'Default string' }
562 563 564 565 566

    # Be sure we don't display inactive IssuePriorities
    assert ! IssuePriority.find(15).active?
    assert_no_tag :option, :attributes => {:value => '15'},
                           :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} }
567
  end
568

569 570 571
  def test_get_new_form_should_allow_attachment_upload
    @request.session[:user_id] = 2
    get :new, :project_id => 1, :tracker_id => 1
572

573 574 575 576 577 578 579
    assert_tag :tag => 'form',
      :attributes => {:id => 'issue-form', :method => 'post', :enctype => 'multipart/form-data'},
      :descendant => {
        :tag => 'input',
        :attributes => {:type => 'file', :name => 'attachments[1][file]'}
      }
  end
580 581 582 583 584 585

  def test_get_new_without_tracker_id
    @request.session[:user_id] = 2
    get :new, :project_id => 1
    assert_response :success
    assert_template 'new'
586

587 588 589 590
    issue = assigns(:issue)
    assert_not_nil issue
    assert_equal Project.find(1).trackers.first, issue.tracker
  end
591

592 593 594
  def test_get_new_with_no_default_status_should_display_an_error
    @request.session[:user_id] = 2
    IssueStatus.delete_all
595

596 597
    get :new, :project_id => 1
    assert_response 500
598
    assert_error_tag :content => /No default issue/
599
  end
600

601 602 603
  def test_get_new_with_no_tracker_should_display_an_error
    @request.session[:user_id] = 2
    Tracker.delete_all
604

605 606
    get :new, :project_id => 1
    assert_response 500
607
    assert_error_tag :content => /No tracker/
608
  end
609

610 611
  def test_update_new_form
    @request.session[:user_id] = 2
612
    xhr :post, :new, :project_id => 1,
613
                     :issue => {:tracker_id => 2,
614 615 616 617
                                :subject => 'This is the test_new issue',
                                :description => 'This is the description',
                                :priority_id => 5}
    assert_response :success
618
    assert_template 'attributes'
619

620 621 622 623 624 625
    issue = assigns(:issue)
    assert_kind_of Issue, issue
    assert_equal 1, issue.project_id
    assert_equal 2, issue.tracker_id
    assert_equal 'This is the test_new issue', issue.subject
  end
626

627
  def test_post_create
628
    @request.session[:user_id] = 2
edavis10's avatar
edavis10 committed
629
    assert_difference 'Issue.count' do
630
      post :create, :project_id => 1,
edavis10's avatar
edavis10 committed
631
                 :issue => {:tracker_id => 3,
632
                            :status_id => 2,
edavis10's avatar
edavis10 committed
633 634 635
                            :subject => 'This is the test_new issue',
                            :description => 'This is the description',
                            :priority_id => 5,
636
                            :start_date => '2010-11-07',
edavis10's avatar
edavis10 committed
637 638 639 640
                            :estimated_hours => '',
                            :custom_field_values => {'2' => 'Value for field 2'}}
    end
    assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
641

642 643 644
    issue = Issue.find_by_subject('This is the test_new issue')
    assert_not_nil issue
    assert_equal 2, issue.author_id
645
    assert_equal 3, issue.tracker_id
646
    assert_equal 2, issue.status_id
647
    assert_equal Date.parse('2010-11-07'), issue.start_date
648
    assert_nil issue.estimated_hours
649
    v = issue.custom_values.find(:first, :conditions => {:custom_field_id => 2})
650 651
    assert_not_nil v
    assert_equal 'Value for field 2', v.value
652
  end
653

654 655 656 657 658 659 660 661
  def test_post_new_with_group_assignment
    group = Group.find(11)
    project = Project.find(1)
    project.members << Member.new(:principal => group, :roles => [Role.first])

    with_settings :issue_group_assignment => '1' do
      @request.session[:user_id] = 2
      assert_difference 'Issue.count' do
662
        post :create, :project_id => project.id,
663 664 665 666 667 668 669
                      :issue => {:tracker_id => 3,
                                 :status_id => 1,
                                 :subject => 'This is the test_new_with_group_assignment issue',
                                 :assigned_to_id => group.id}
      end
    end
    assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
670

671 672 673 674
    issue = Issue.find_by_subject('This is the test_new_with_group_assignment issue')
    assert_not_nil issue
    assert_equal group, issue.assigned_to
  end
675

676 677 678
  def test_post_create_without_start_date
    @request.session[:user_id] = 2
    assert_difference 'Issue.count' do
679
      post :create, :project_id => 1,
680 681 682 683 684 685 686 687 688 689
                 :issue => {:tracker_id => 3,
                            :status_id => 2,
                            :subject => 'This is the test_new issue',
                            :description => 'This is the description',
                            :priority_id => 5,
                            :start_date => '',
                            :estimated_hours => '',
                            :custom_field_values => {'2' => 'Value for field 2'}}
    end
    assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
690

691 692 693 694
    issue = Issue.find_by_subject('This is the test_new issue')
    assert_not_nil issue
    assert_nil issue.start_date
  end
695

696
  def test_post_create_and_continue
697
    @request.session[:user_id] = 2
698 699 700 701 702
    assert_difference 'Issue.count' do
      post :create, :project_id => 1,
        :issue => {:tracker_id => 3, :subject => 'This is first issue', :priority_id => 5},
        :continue => ''
    end
703

704 705 706 707
    issue = Issue.first(:order => 'id DESC')
    assert_redirected_to :controller => 'issues', :action => 'new', :project_id => 'ecookbook', :issue => {:tracker_id => 3}
    assert_not_nil flash[:notice], "flash was not set"
    assert flash[:notice].include?("<a href='/issues/#{issue.id}'>##{issue.id}</a>"), "issue link not found in flash: #{flash[:notice]}"
708
  end
709

710
  def test_post_create_without_custom_fields_param
711
    @request.session[:user_id] = 2
edavis10's avatar
edavis10 committed
712
    assert_difference 'Issue.count' do
713
      post :create, :project_id => 1,
edavis10's avatar
edavis10 committed
714 715 716 717 718 719
                 :issue => {:tracker_id => 1,
                            :subject => 'This is the test_new issue',
                            :description => 'This is the description',
                            :priority_id => 5}
    end
    assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
720
  end
721

722
  def test_post_create_with_required_custom_field_and_without_custom_fields_param
723 724 725 726
    field = IssueCustomField.find_by_name('Database')
    field.update_attribute(:is_required, true)

    @request.session[:user_id] = 2
727
    post :create, :project_id => 1,
728 729 730 731 732 733 734 735
               :issue => {:tracker_id => 1,
                          :subject => 'This is the test_new issue',
                          :description => 'This is the description',
                          :priority_id => 5}
    assert_response :success
    assert_template 'new'
    issue = assigns(:issue)
    assert_not_nil issue
736
    assert_equal I18n.translate('activerecord.errors.messages.invalid'), issue.errors.on(:custom_values)
737
  end
738

739
  def test_post_create_with_watchers
740 741
    @request.session[:user_id] = 2
    ActionMailer::Base.deliveries.clear
742

743
    assert_difference 'Watcher.count', 2 do
744
      post :create, :project_id => 1,
745 746 747 748 749 750 751
                 :issue => {:tracker_id => 1,
                            :subject => 'This is a new issue with watchers',
                            :description => 'This is the description',
                            :priority_id => 5,
                            :watcher_user_ids => ['2', '3']}
    end
    issue = Issue.find_by_subject('This is a new issue with watchers')
jplang's avatar
jplang committed
752 753
    assert_not_nil issue
    assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
754

755 756 757 758 759 760 761 762
    # Watchers added
    assert_equal [2, 3], issue.watcher_user_ids.sort
    assert issue.watched_by?(User.find(3))
    # Watchers notified
    mail = ActionMailer::Base.deliveries.last
    assert_kind_of TMail::Mail, mail
    assert [mail.bcc, mail.cc].flatten.include?(User.find(3).mail)
  end
763

764
  def test_post_create_subissue
jplang's avatar
jplang committed
765
    @request.session[:user_id] = 2
766

jplang's avatar
jplang committed
767
    assert_difference 'Issue.count' do
768
      post :create, :project_id => 1,
jplang's avatar
jplang committed
769 770 771 772 773 774 775 776
                 :issue => {:tracker_id => 1,
                            :subject => 'This is a child issue',
                            :parent_issue_id => 2}
    end
    issue = Issue.find_by_subject('This is a child issue')
    assert_not_nil issue
    assert_equal Issue.find(2), issue.parent
  end
777 778 779

  def test_post_create_subissue_with_non_numeric_parent_id
    @request.session[:user_id] = 2
780

781
    assert_difference 'Issue.count' do
782
      post :create, :project_id => 1,
783 784 785 786 787 788 789 790
                 :issue => {:tracker_id => 1,
                            :subject => 'This is a child issue',
                            :parent_issue_id => 'ABC'}
    end
    issue = Issue.find_by_subject('This is a child issue')
    assert_not_nil issue
    assert_nil issue.parent
  end
791

792 793 794 795 796 797 798 799 800 801 802 803
  def test_post_create_private
    @request.session[:user_id] = 2

    assert_difference 'Issue.count' do
      post :create, :project_id => 1,
                 :issue => {:tracker_id => 1,
                            :subject => 'This is a private issue',
                            :is_private => '1'}
    end
    issue = Issue.first(:order => 'id DESC')
    assert issue.is_private?
  end
804

805 806 807 808
  def test_post_create_private_with_set_own_issues_private_permission
    role = Role.find(1)
    role.remove_permission! :set_issues_private
    role.add_permission! :set_own_issues_private
809

810 811 812 813 814 815 816 817 818 819 820
    @request.session[:user_id] = 2

    assert_difference 'Issue.count' do
      post :create, :project_id => 1,
                 :issue => {:tracker_id => 1,
                            :subject => 'This is a private issue',
                            :is_private => '1'}
    end
    issue = Issue.first(:order => 'id DESC')
    assert issue.is_private?
  end
821

822
  def test_post_create_should_send_a_notification
823 824
    ActionMailer::Base.deliveries.clear
    @request.session[:user_id] = 2
edavis10's avatar
edavis10 committed
825
    assert_difference 'Issue.count' do
826
      post :create, :project_id => 1,
edavis10's avatar
edavis10 committed
827 828 829 830 831 832 833 834
                 :issue => {:tracker_id => 3,
                            :subject => 'This is the test_new issue',
                            :description => 'This is the description',
                            :priority_id => 5,
                            :estimated_hours => '',
                            :custom_field_values => {'2' => 'Value for field 2'}}
    end
    assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
835

836 837
    assert_equal 1, ActionMailer::Base.deliveries.size
  end
838

839
  def test_post_create_should_preserve_fields_values_on_validation_failure
840
    @request.session[:user_id] = 2
841
    post :create, :project_id => 1,
842
               :issue => {:tracker_id => 1,
843 844 845
                          # empty subject
                          :subject => '',
                          :description => 'This is a description',
846 847 848 849
                          :priority_id => 6,
                          :custom_field_values => {'1' => 'Oracle', '2' => 'Value for field 2'}}
    assert_response :success
    assert_template 'new'
850

851 852
    assert_tag :textarea, :attributes => { :name => 'issue[description]' },
                          :content => 'This is a description'
853 854 855
    assert_tag :select, :attributes => { :name => 'issue[priority_id]' },
                        :child => { :tag => 'option', :attributes => { :selected => 'selected',
                                                                       :value => '6' },
856
                                                      :content => 'High' }
857 858 859 860
    # Custom fields
    assert_tag :select, :attributes => { :name => 'issue[custom_field_values][1]' },
                        :child => { :tag => 'option', :attributes => { :selected => 'selected',
                                                                       :value => 'Oracle' },
861
                                                      :content => 'Oracle' }
862 863 864
    assert_tag :input, :attributes => { :name => 'issue[custom_field_values][2]',
                                        :value => 'Value for field 2'}
  end
865

866
  def test_post_create_should_ignore_non_safe_attributes
867 868
    @request.session[:user_id] = 2
    assert_nothing_raised do
869
      post :create, :project_id => 1, :issue => { :tracker => "A param can not be a Tracker" }
870 871
    end
  end
872

873 874 875
  def test_post_create_with_attachment
    set_tmp_attachments_directory
    @request.session[:user_id] = 2
876

877 878
    assert_difference 'Issue.count' do
      assert_difference 'Attachment.count' do
879
        post :create, :project_id => 1,
880 881 882 883
          :issue => { :tracker_id => '1', :subject => 'With attachment' },
          :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
      end
    end
884

885 886
    issue = Issue.first(:order => 'id DESC')
    attachment = Attachment.first(:order => 'id DESC')
887

888 889 890 891 892 893 894 895 896 897
    assert_equal issue, attachment.container
    assert_equal 2, attachment.author_id
    assert_equal 'testfile.txt', attachment.filename
    assert_equal 'text/plain', attachment.content_type
    assert_equal 'test file', attachment.description
    assert_equal 59, attachment.filesize
    assert File.exists?(attachment.diskfile)
    assert_equal 59, File.size(attachment.diskfile)
  end

898 899 900
  context "without workflow privilege" do
    setup do
      Workflow.delete_all(["role_id = ?", Role.anonymous.id])
901
      Role.anonymous.add_permission! :add_issues, :add_issue_notes
902
    end
903

904 905 906 907 908 909 910 911 912 913
    context "#new" do
      should "propose default status only" do
        get :new, :project_id => 1
        assert_response :success
        assert_template 'new'
        assert_tag :tag => 'select',
          :attributes => {:name => 'issue[status_id]'},
          :children => {:count => 1},
          :child => {:tag => 'option', :attributes => {:value => IssueStatus.default.id.to_s}}
      end
914

915 916
      should "accept default status" do
        assert_difference 'Issue.count' do
917
          post :create, :project_id => 1,
918 919 920 921 922 923 924
                     :issue => {:tracker_id => 1,
                                :subject => 'This is an issue',
                                :status_id => 1}
        end
        issue = Issue.last(:order => 'id')
        assert_equal IssueStatus.default, issue.status
      end
925

926 927
      should "ignore unauthorized status" do
        assert_difference 'Issue.count' do
928
          post :create, :project_id => 1,
929 930 931 932 933 934 935 936
                     :issue => {:tracker_id => 1,
                                :subject => 'This is an issue',
                                :status_id => 3}
        end
        issue = Issue.last(:order => 'id')
        assert_equal IssueStatus.default, issue.status
      end
    end
937

938 939 940 941 942 943 944
    context "#update" do
      should "ignore status change" do
        assert_difference 'Journal.count' do
          put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 3}
        end
        assert_equal 1, Issue.find(1).status_id
      end
945

946 947 948 949 950 951 952 953 954 955
      should "ignore attributes changes" do
        assert_difference 'Journal.count' do
          put :update, :id => 1, :notes => 'just trying', :issue => {:subject => 'changed', :assigned_to_id => 2}
        end
        issue = Issue.find(1)
        assert_equal "Can't print recipes", issue.subject
        assert_nil issue.assigned_to
      end
    end
  end
956

957 958 959 960 961 962 963
  context "with workflow privilege" do
    setup do
      Workflow.delete_all(["role_id = ?", Role.anonymous.id])
      Workflow.create!(:role => Role.anonymous, :tracker_id => 1, :old_status_id => 1, :new_status_id => 3)
      Workflow.create!(:role => Role.anonymous, :tracker_id => 1, :old_status_id => 1, :new_status_id => 4)
      Role.anonymous.add_permission! :add_issues, :add_issue_notes
    end
964

965 966 967 968 969 970 971
    context "#update" do
      should "accept authorized status" do
        assert_difference 'Journal.count' do
          put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 3}
        end
        assert_equal 3, Issue.find(1).status_id
      end
972

973 974 975 976 977 978
      should "ignore unauthorized status" do
        assert_difference 'Journal.count' do
          put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 2}
        end
        assert_equal 1, Issue.find(1).status_id
      end
979

980 981 982 983 984 985 986
      should "accept authorized attributes changes" do
        assert_difference 'Journal.count' do
          put :update, :id => 1, :notes => 'just trying', :issue => {:assigned_to_id => 2}
        end
        issue = Issue.find(1)
        assert_equal 2, issue.assigned_to_id
      end
987

988 989 990 991 992 993 994 995
      should "ignore unauthorized attributes changes" do
        assert_difference 'Journal.count' do
          put :update, :id => 1, :notes => 'just trying', :issue => {:subject => 'changed'}
        end
        issue = Issue.find(1)
        assert_equal "Can't print recipes", issue.subject
      end
    end
996

997 998 999 1000 1001 1002 1003 1004 1005 1006 1007
    context "and :edit_issues permission" do
      setup do
        Role.anonymous.add_permission! :add_issues, :edit_issues
      end

      should "accept authorized status" do
        assert_difference 'Journal.count' do
          put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 3}
        end
        assert_equal 3, Issue.find(1).status_id
      end
1008

1009 1010 1011 1012 1013 1014
      should "ignore unauthorized status" do
        assert_difference 'Journal.count' do
          put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 2}
        end
        assert_equal 1, Issue.find(1).status_id
      end
1015

1016 1017 1018 1019 1020 1021 1022 1023 1024
      should "accept authorized attributes changes" do
        assert_difference 'Journal.count' do
          put :update, :id => 1, :notes => 'just trying', :issue => {:subject => 'changed', :assigned_to_id => 2}
        end
        issue = Issue.find(1)
        assert_equal "changed", issue.subject
        assert_equal 2, issue.assigned_to_id
      end
    end
1025
  end
1026

1027 1028 1029 1030 1031 1032 1033 1034
  def test_copy_issue
    @request.session[:user_id] = 2
    get :new, :project_id => 1, :copy_from => 1
    assert_template 'new'
    assert_not_nil assigns(:issue)
    orig = Issue.find(1)
    assert_equal orig.subject, assigns(:issue).subject
  end
1035

1036 1037 1038 1039 1040 1041 1042
  def test_get_edit
    @request.session[:user_id] = 2
    get :edit, :id => 1
    assert_response :success
    assert_template 'edit'
    assert_not_nil assigns(:issue)
    assert_equal Issue.find(1), assigns(:issue)
1043 1044 1045 1046 1047

    # Be sure we don't display inactive IssuePriorities
    assert ! IssuePriority.find(15).active?
    assert_no_tag :option, :attributes => {:value => '15'},
                           :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} }
1048
  end
1049

1050 1051
  def test_get_edit_with_params
    @request.session[:user_id] = 2
1052 1053
    get :edit, :id => 1, :issue => { :status_id => 5, :priority_id => 7 },
        :time_entry => { :hours => '2.5', :comments => 'test_get_edit_with_params', :activity_id => TimeEntryActivity.first.id }