]> source.dussan.org Git - redmine.git/commitdiff
Fixed: Custom values with a nil value cause error on (project|account)/show (#3705).
authorJean-Philippe Lang <jp_lang@yahoo.fr>
Sun, 20 Sep 2009 09:56:06 +0000 (09:56 +0000)
committerJean-Philippe Lang <jp_lang@yahoo.fr>
Sun, 20 Sep 2009 09:56:06 +0000 (09:56 +0000)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@2894 e93f8b46-1217-0410-a6f0-8f06a7374b81

app/views/account/show.rhtml
app/views/projects/show.rhtml
test/functional/account_controller_test.rb
test/functional/projects_controller_test.rb

index 24106ca010d86f6105c093ccad9a35b509e55e1c..8816f108eb514ed8048172c2d038892dc17e3a7a 100644 (file)
@@ -10,7 +10,7 @@
                <li><%=l(:field_mail)%>: <%= mail_to(h(@user.mail), nil, :encode => 'javascript') %></li>
        <% end %>
        <% for custom_value in @custom_values %>
-       <% if !custom_value.value.empty? %>
+       <% if !custom_value.value.blank? %>
     <li><%=h custom_value.custom_field.name%>: <%=h show_value(custom_value) %></li>
        <% end %>
        <% end %>
index 250e8512f4f682ec754b701fc594eefe33b99802..a83d98fe157f694f71819b9fbbb2f551ea9259eb 100644 (file)
@@ -9,7 +9,7 @@
            <%= @subprojects.collect{|p| link_to(h(p), :action => 'show', :id => p)}.join(", ") %></li>
   <% end %>
        <% @project.custom_values.each do |custom_value| %>
-       <% if !custom_value.value.empty? %>
+       <% if !custom_value.value.blank? %>
           <li><%= custom_value.custom_field.name%>: <%=h show_value(custom_value) %></li>
        <% end %>
        <% end %>
index 8184fa312392c7b4a823e8930303cc8e31f9a14f..e38ccb543c8d6c1300d12c19ad4b0242f0b031fa 100644 (file)
@@ -37,7 +37,19 @@ class AccountControllerTest < ActionController::TestCase
     assert_template 'show'
     assert_not_nil assigns(:user)
   end
+
+  def test_show_should_not_fail_when_custom_values_are_nil
+    user = User.find(2)
+
+    # Create a custom field to illustrate the issue
+    custom_field = CustomField.create!(:name => 'Testing', :field_format => 'text')
+    custom_value = user.custom_values.build(:custom_field => custom_field).save!
+
+    get :show, :id => 2
+    assert_response :success
+  end
   
+
   def test_show_inactive
     get :show, :id => 5
     assert_response 404
index 81b501ea50c57b0b15bf698e922427db5349c29a..812ae19a21d1544ba3541f3671a60b940d3e0000 100644 (file)
-# Redmine - project management software
-# Copyright (C) 2006-2008  Jean-Philippe Lang
-#
-# 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.
-# 
-# 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.
-# 
-# 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.
-
-require File.dirname(__FILE__) + '/../test_helper'
-require 'projects_controller'
-
-# Re-raise errors caught by the controller.
-class ProjectsController; def rescue_action(e) raise e end; end
-
-class ProjectsControllerTest < ActionController::TestCase
-  fixtures :projects, :versions, :users, :roles, :members, :member_roles, :issues, :journals, :journal_details,
-           :trackers, :projects_trackers, :issue_statuses, :enabled_modules, :enumerations, :boards, :messages,
-           :attachments
-
-  def setup
-    @controller = ProjectsController.new
-    @request    = ActionController::TestRequest.new
-    @response   = ActionController::TestResponse.new
-    @request.session[:user_id] = nil
-    Setting.default_language = 'en'
-  end
-  
-  def test_index_routing
-    assert_routing(
-      {:method => :get, :path => '/projects'},
-      :controller => 'projects', :action => 'index'
-    )
-  end
-  
-  def test_index
-    get :index
-    assert_response :success
-    assert_template 'index'
-    assert_not_nil assigns(:projects)
-    
-    assert_tag :ul, :child => {:tag => 'li',
-                               :descendant => {:tag => 'a', :content => 'eCookbook'},
-                               :child => { :tag => 'ul',
-                                           :descendant => { :tag => 'a',
-                                                            :content => 'Child of private child'
-                                                           }
-                                          }
-                               }
-                               
-    assert_no_tag :a, :content => /Private child of eCookbook/
-  end
-  
-  def test_index_atom_routing
-    assert_routing(
-      {:method => :get, :path => '/projects.atom'},
-      :controller => 'projects', :action => 'index', :format => 'atom'
-    )
-  end
-  
-  def test_index_atom
-    get :index, :format => 'atom'
-    assert_response :success
-    assert_template 'common/feed.atom.rxml'
-    assert_select 'feed>title', :text => 'Redmine: Latest projects'
-    assert_select 'feed>entry', :count => Project.count(:conditions => Project.visible_by(User.current))
-  end
-  
-  def test_add_routing
-    assert_routing(
-      {:method => :get, :path => '/projects/new'},
-      :controller => 'projects', :action => 'add'
-    )
-    assert_recognizes(
-      {:controller => 'projects', :action => 'add'},
-      {:method => :post, :path => '/projects/new'}
-    )
-    assert_recognizes(
-      {:controller => 'projects', :action => 'add'},
-      {:method => :post, :path => '/projects'}
-    )
-  end
-  
-  def test_get_add
-    @request.session[:user_id] = 1
-    get :add
-    assert_response :success
-    assert_template 'add'
-  end
-  
-  def test_get_add_by_non_admin
-    @request.session[:user_id] = 2
-    get :add
-    assert_response :success
-    assert_template 'add'
-  end
-  
-  def test_post_add
-    @request.session[:user_id] = 1
-    post :add, :project => { :name => "blog", 
-                             :description => "weblog",
-                             :identifier => "blog",
-                             :is_public => 1,
-                             :custom_field_values => { '3' => 'Beta' }
-                            }
-    assert_redirected_to '/projects/blog/settings'
-    
-    project = Project.find_by_name('blog')
-    assert_kind_of Project, project
-    assert_equal 'weblog', project.description 
-    assert_equal true, project.is_public?
-  end
-  
-  def test_post_add_by_non_admin
-    @request.session[:user_id] = 2
-    post :add, :project => { :name => "blog", 
-                             :description => "weblog",
-                             :identifier => "blog",
-                             :is_public => 1,
-                             :custom_field_values => { '3' => 'Beta' }
-                            }
-    assert_redirected_to '/projects/blog/settings'
-    
-    project = Project.find_by_name('blog')
-    assert_kind_of Project, project
-    assert_equal 'weblog', project.description 
-    assert_equal true, project.is_public?
-    
-    # User should be added as a project member
-    assert User.find(2).member_of?(project)
-    assert_equal 1, project.members.size
-  end
-  
-  def test_show_routing
-    assert_routing(
-      {:method => :get, :path => '/projects/test'},
-      :controller => 'projects', :action => 'show', :id => 'test'
-    )
-  end
-  
-  def test_show_by_id
-    get :show, :id => 1
-    assert_response :success
-    assert_template 'show'
-    assert_not_nil assigns(:project)
-  end
-
-  def test_show_by_identifier
-    get :show, :id => 'ecookbook'
-    assert_response :success
-    assert_template 'show'
-    assert_not_nil assigns(:project)
-    assert_equal Project.find_by_identifier('ecookbook'), assigns(:project)
-  end
-  
-  def test_private_subprojects_hidden
-    get :show, :id => 'ecookbook'
-    assert_response :success
-    assert_template 'show'
-    assert_no_tag :tag => 'a', :content => /Private child/
-  end
-
-  def test_private_subprojects_visible
-    @request.session[:user_id] = 2 # manager who is a member of the private subproject
-    get :show, :id => 'ecookbook'
-    assert_response :success
-    assert_template 'show'
-    assert_tag :tag => 'a', :content => /Private child/
-  end
-  
-  def test_settings_routing
-    assert_routing(
-      {:method => :get, :path => '/projects/4223/settings'},
-      :controller => 'projects', :action => 'settings', :id => '4223'
-    )
-    assert_routing(
-      {:method => :get, :path => '/projects/4223/settings/members'},
-      :controller => 'projects', :action => 'settings', :id => '4223', :tab => 'members'
-    )
-  end
-  
-  def test_settings
-    @request.session[:user_id] = 2 # manager
-    get :settings, :id => 1
-    assert_response :success
-    assert_template 'settings'
-  end
-  
-  def test_edit
-    @request.session[:user_id] = 2 # manager
-    post :edit, :id => 1, :project => {:name => 'Test changed name',
-                                       :issue_custom_field_ids => ['']}
-    assert_redirected_to 'projects/ecookbook/settings'
-    project = Project.find(1)
-    assert_equal 'Test changed name', project.name
-  end
-  
-  def test_add_version_routing
-    assert_routing(
-      {:method => :get, :path => 'projects/64/versions/new'},
-      :controller => 'projects', :action => 'add_version', :id => '64'
-    )
-    assert_routing(
-    #TODO: use PUT
-      {:method => :post, :path => 'projects/64/versions/new'},
-      :controller => 'projects', :action => 'add_version', :id => '64'
-    )
-  end
-  
-  def test_add_issue_category_routing
-    assert_routing(
-      {:method => :get, :path => 'projects/test/categories/new'},
-      :controller => 'projects', :action => 'add_issue_category', :id => 'test'
-    )
-    assert_routing(
-    #TODO: use PUT and update form
-      {:method => :post, :path => 'projects/64/categories/new'},
-      :controller => 'projects', :action => 'add_issue_category', :id => '64'
-    )
-  end
-  
-  def test_destroy_routing
-    assert_routing(
-      {:method => :get, :path => '/projects/567/destroy'},
-      :controller => 'projects', :action => 'destroy', :id => '567'
-    )
-    assert_routing(
-    #TODO: use DELETE and update form
-      {:method => :post, :path => 'projects/64/destroy'},
-      :controller => 'projects', :action => 'destroy', :id => '64'
-    )
-  end
-  
-  def test_get_destroy
-    @request.session[:user_id] = 1 # admin
-    get :destroy, :id => 1
-    assert_response :success
-    assert_template 'destroy'
-    assert_not_nil Project.find_by_id(1)
-  end
-
-  def test_post_destroy
-    @request.session[:user_id] = 1 # admin
-    post :destroy, :id => 1, :confirm => 1
-    assert_redirected_to 'admin/projects'
-    assert_nil Project.find_by_id(1)
-  end
-  
-  def test_add_file
-    set_tmp_attachments_directory
-    @request.session[:user_id] = 2
-    Setting.notified_events = ['file_added']
-    ActionMailer::Base.deliveries.clear
-    
-    assert_difference 'Attachment.count' do
-      post :add_file, :id => 1, :version_id => '',
-           :attachments => {'1' => {'file' => test_uploaded_file('testfile.txt', 'text/plain')}}
-    end
-    assert_redirected_to 'projects/ecookbook/files'
-    a = Attachment.find(:first, :order => 'created_on DESC')
-    assert_equal 'testfile.txt', a.filename
-    assert_equal Project.find(1), a.container
-
-    mail = ActionMailer::Base.deliveries.last
-    assert_kind_of TMail::Mail, mail
-    assert_equal "[eCookbook] New file", mail.subject
-    assert mail.body.include?('testfile.txt')
-  end
-  
-  def test_add_file_routing
-    assert_routing(
-      {:method => :get, :path => '/projects/33/files/new'},
-      :controller => 'projects', :action => 'add_file', :id => '33'
-    )
-    assert_routing(
-      {:method => :post, :path => '/projects/33/files/new'},
-      :controller => 'projects', :action => 'add_file', :id => '33'
-    )
-  end
-  
-  def test_add_version_file
-    set_tmp_attachments_directory
-    @request.session[:user_id] = 2
-    Setting.notified_events = ['file_added']
-    
-    assert_difference 'Attachment.count' do
-      post :add_file, :id => 1, :version_id => '2',
-           :attachments => {'1' => {'file' => test_uploaded_file('testfile.txt', 'text/plain')}}
-    end
-    assert_redirected_to 'projects/ecookbook/files'
-    a = Attachment.find(:first, :order => 'created_on DESC')
-    assert_equal 'testfile.txt', a.filename
-    assert_equal Version.find(2), a.container
-  end
-  
-  def test_list_files
-    get :list_files, :id => 1
-    assert_response :success
-    assert_template 'list_files'
-    assert_not_nil assigns(:containers)
-    
-    # file attached to the project
-    assert_tag :a, :content => 'project_file.zip',
-                   :attributes => { :href => '/attachments/download/8/project_file.zip' }
-    
-    # file attached to a project's version
-    assert_tag :a, :content => 'version_file.zip',
-                   :attributes => { :href => '/attachments/download/9/version_file.zip' }
-  end
-
-  def test_list_files_routing
-    assert_routing(
-      {:method => :get, :path => '/projects/33/files'},
-      :controller => 'projects', :action => 'list_files', :id => '33'
-    )
-  end
-  
-  def test_changelog_routing
-    assert_routing(
-      {:method => :get, :path => '/projects/44/changelog'},
-      :controller => 'projects', :action => 'changelog', :id => '44'
-    )
-  end
-  
-  def test_changelog
-    get :changelog, :id => 1
-    assert_response :success
-    assert_template 'changelog'
-    assert_not_nil assigns(:versions)
-  end
-  
-  def test_roadmap_routing
-    assert_routing(
-      {:method => :get, :path => 'projects/33/roadmap'},
-      :controller => 'projects', :action => 'roadmap', :id => '33'
-    )
-  end
-  
-  def test_roadmap
-    get :roadmap, :id => 1
-    assert_response :success
-    assert_template 'roadmap'
-    assert_not_nil assigns(:versions)
-    # Version with no date set appears
-    assert assigns(:versions).include?(Version.find(3))
-    # Completed version doesn't appear
-    assert !assigns(:versions).include?(Version.find(1))
-  end
-  
-  def test_roadmap_with_completed_versions
-    get :roadmap, :id => 1, :completed => 1
-    assert_response :success
-    assert_template 'roadmap'
-    assert_not_nil assigns(:versions)
-    # Version with no date set appears
-    assert assigns(:versions).include?(Version.find(3))
-    # Completed version appears
-    assert assigns(:versions).include?(Version.find(1))
-  end
-  
-  def test_project_activity_routing
-    assert_routing(
-      {:method => :get, :path => '/projects/1/activity'},
-       :controller => 'projects', :action => 'activity', :id => '1'
-    )
-  end
-  
-  def test_project_activity_atom_routing
-    assert_routing(
-      {:method => :get, :path => '/projects/1/activity.atom'},
-       :controller => 'projects', :action => 'activity', :id => '1', :format => 'atom'
-    )    
-  end
-  
-  def test_project_activity
-    get :activity, :id => 1, :with_subprojects => 0
-    assert_response :success
-    assert_template 'activity'
-    assert_not_nil assigns(:events_by_day)
-    
-    assert_tag :tag => "h3", 
-               :content => /#{2.days.ago.to_date.day}/,
-               :sibling => { :tag => "dl",
-                 :child => { :tag => "dt",
-                   :attributes => { :class => /issue-edit/ },
-                   :child => { :tag => "a",
-                     :content => /(#{IssueStatus.find(2).name})/,
-                   }
-                 }
-               }
-  end
-  
-  def test_previous_project_activity
-    get :activity, :id => 1, :from => 3.days.ago.to_date
-    assert_response :success
-    assert_template 'activity'
-    assert_not_nil assigns(:events_by_day)
-               
-    assert_tag :tag => "h3", 
-               :content => /#{3.day.ago.to_date.day}/,
-               :sibling => { :tag => "dl",
-                 :child => { :tag => "dt",
-                   :attributes => { :class => /issue/ },
-                   :child => { :tag => "a",
-                     :content => /#{Issue.find(1).subject}/,
-                   }
-                 }
-               }
-  end
-  
-  def test_global_activity_routing
-    assert_routing({:method => :get, :path => '/activity'}, :controller => 'projects', :action => 'activity', :id => nil)
-  end
-  
-  def test_global_activity
-    get :activity
-    assert_response :success
-    assert_template 'activity'
-    assert_not_nil assigns(:events_by_day)
-    
-    assert_tag :tag => "h3", 
-               :content => /#{5.day.ago.to_date.day}/,
-               :sibling => { :tag => "dl",
-                 :child => { :tag => "dt",
-                   :attributes => { :class => /issue/ },
-                   :child => { :tag => "a",
-                     :content => /#{Issue.find(5).subject}/,
-                   }
-                 }
-               }
-  end
-  
-  def test_user_activity
-    get :activity, :user_id => 2
-    assert_response :success
-    assert_template 'activity'
-    assert_not_nil assigns(:events_by_day)
-    
-    assert_tag :tag => "h3", 
-               :content => /#{3.day.ago.to_date.day}/,
-               :sibling => { :tag => "dl",
-                 :child => { :tag => "dt",
-                   :attributes => { :class => /issue/ },
-                   :child => { :tag => "a",
-                     :content => /#{Issue.find(1).subject}/,
-                   }
-                 }
-               }
-  end
-  
-  def test_global_activity_atom_routing
-    assert_routing({:method => :get, :path => '/activity.atom'}, :controller => 'projects', :action => 'activity', :id => nil, :format => 'atom')
-  end
-  
-  def test_activity_atom_feed
-    get :activity, :format => 'atom'
-    assert_response :success
-    assert_template 'common/feed.atom.rxml'
-  end
-  
-  def test_archive_routing
-    assert_routing(
-    #TODO: use PUT to project path and modify form
-      {:method => :post, :path => 'projects/64/archive'},
-      :controller => 'projects', :action => 'archive', :id => '64'
-    )
-  end
-  
-  def test_archive
-    @request.session[:user_id] = 1 # admin
-    post :archive, :id => 1
-    assert_redirected_to 'admin/projects'
-    assert !Project.find(1).active?
-  end
-  
-  def test_unarchive_routing
-    assert_routing(
-    #TODO: use PUT to project path and modify form
-      {:method => :post, :path => '/projects/567/unarchive'},
-      :controller => 'projects', :action => 'unarchive', :id => '567'
-    )
-  end
-  
-  def test_unarchive
-    @request.session[:user_id] = 1 # admin
-    Project.find(1).archive
-    post :unarchive, :id => 1
-    assert_redirected_to 'admin/projects'
-    assert Project.find(1).active?
-  end
-  
-  def test_project_breadcrumbs_should_be_limited_to_3_ancestors
-    CustomField.delete_all
-    parent = nil
-    6.times do |i|
-      p = Project.create!(:name => "Breadcrumbs #{i}", :identifier => "breadcrumbs-#{i}")
-      p.set_parent!(parent)
-      get :show, :id => p
-      assert_tag :h1, :parent => { :attributes => {:id => 'header'}},
-                      :children => { :count => [i, 3].min,
-                                     :only => { :tag => 'a' } }
-                                     
-      parent = p
-    end
-  end
-
-  def test_copy_with_project
-    @request.session[:user_id] = 1 # admin
-    get :copy, :id => 1
-    assert_response :success
-    assert_template 'copy'
-    assert assigns(:project)
-    assert_equal Project.find(1).description, assigns(:project).description
-    assert_nil assigns(:project).id
-  end
-
-  def test_copy_without_project
-    @request.session[:user_id] = 1 # admin
-    get :copy
-    assert_response :redirect
-    assert_redirected_to :controller => 'admin', :action => 'projects'
-  end
-
-  def test_jump_should_redirect_to_active_tab
-    get :show, :id => 1, :jump => 'issues'
-    assert_redirected_to 'projects/ecookbook/issues'
-  end
-  
-  def test_jump_should_not_redirect_to_inactive_tab
-    get :show, :id => 3, :jump => 'documents'
-    assert_response :success
-    assert_template 'show'
-  end
-  
-  def test_jump_should_not_redirect_to_unknown_tab
-    get :show, :id => 3, :jump => 'foobar'
-    assert_response :success
-    assert_template 'show'
-  end
-  
-  # A hook that is manually registered later
-  class ProjectBasedTemplate < Redmine::Hook::ViewListener
-    def view_layouts_base_html_head(context)
-      # Adds a project stylesheet
-      stylesheet_link_tag(context[:project].identifier) if context[:project]
-    end
-  end
-  # Don't use this hook now
-  Redmine::Hook.clear_listeners
-  
-  def test_hook_response
-    Redmine::Hook.add_listener(ProjectBasedTemplate)
-    get :show, :id => 1
-    assert_tag :tag => 'link', :attributes => {:href => '/stylesheets/ecookbook.css'},
-                               :parent => {:tag => 'head'}
-    
-    Redmine::Hook.clear_listeners
-  end
-end
+# Redmine - project management software\r
+# Copyright (C) 2006-2008  Jean-Philippe Lang\r
+#\r
+# This program is free software; you can redistribute it and/or\r
+# modify it under the terms of the GNU General Public License\r
+# as published by the Free Software Foundation; either version 2\r
+# of the License, or (at your option) any later version.\r
+# \r
+# This program is distributed in the hope that it will be useful,\r
+# but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+# GNU General Public License for more details.\r
+# \r
+# You should have received a copy of the GNU General Public License\r
+# along with this program; if not, write to the Free Software\r
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+\r
+require File.dirname(__FILE__) + '/../test_helper'\r
+require 'projects_controller'\r
+\r
+# Re-raise errors caught by the controller.\r
+class ProjectsController; def rescue_action(e) raise e end; end\r
+\r
+class ProjectsControllerTest < ActionController::TestCase\r
+  fixtures :projects, :versions, :users, :roles, :members, :member_roles, :issues, :journals, :journal_details,\r
+           :trackers, :projects_trackers, :issue_statuses, :enabled_modules, :enumerations, :boards, :messages,\r
+           :attachments\r
+\r
+  def setup\r
+    @controller = ProjectsController.new\r
+    @request    = ActionController::TestRequest.new\r
+    @response   = ActionController::TestResponse.new\r
+    @request.session[:user_id] = nil\r
+    Setting.default_language = 'en'\r
+  end\r
+  \r
+  def test_index_routing\r
+    assert_routing(\r
+      {:method => :get, :path => '/projects'},\r
+      :controller => 'projects', :action => 'index'\r
+    )\r
+  end\r
+  \r
+  def test_index\r
+    get :index\r
+    assert_response :success\r
+    assert_template 'index'\r
+    assert_not_nil assigns(:projects)\r
+    \r
+    assert_tag :ul, :child => {:tag => 'li',\r
+                               :descendant => {:tag => 'a', :content => 'eCookbook'},\r
+                               :child => { :tag => 'ul',\r
+                                           :descendant => { :tag => 'a',\r
+                                                            :content => 'Child of private child'\r
+                                                           }\r
+                                          }\r
+                               }\r
+                               \r
+    assert_no_tag :a, :content => /Private child of eCookbook/\r
+  end\r
+  \r
+  def test_index_atom_routing\r
+    assert_routing(\r
+      {:method => :get, :path => '/projects.atom'},\r
+      :controller => 'projects', :action => 'index', :format => 'atom'\r
+    )\r
+  end\r
+  \r
+  def test_index_atom\r
+    get :index, :format => 'atom'\r
+    assert_response :success\r
+    assert_template 'common/feed.atom.rxml'\r
+    assert_select 'feed>title', :text => 'Redmine: Latest projects'\r
+    assert_select 'feed>entry', :count => Project.count(:conditions => Project.visible_by(User.current))\r
+  end\r
+  \r
+  def test_add_routing\r
+    assert_routing(\r
+      {:method => :get, :path => '/projects/new'},\r
+      :controller => 'projects', :action => 'add'\r
+    )\r
+    assert_recognizes(\r
+      {:controller => 'projects', :action => 'add'},\r
+      {:method => :post, :path => '/projects/new'}\r
+    )\r
+    assert_recognizes(\r
+      {:controller => 'projects', :action => 'add'},\r
+      {:method => :post, :path => '/projects'}\r
+    )\r
+  end\r
+  \r
+  def test_get_add\r
+    @request.session[:user_id] = 1\r
+    get :add\r
+    assert_response :success\r
+    assert_template 'add'\r
+  end\r
+  \r
+  def test_get_add_by_non_admin\r
+    @request.session[:user_id] = 2\r
+    get :add\r
+    assert_response :success\r
+    assert_template 'add'\r
+  end\r
+  \r
+  def test_post_add\r
+    @request.session[:user_id] = 1\r
+    post :add, :project => { :name => "blog", \r
+                             :description => "weblog",\r
+                             :identifier => "blog",\r
+                             :is_public => 1,\r
+                             :custom_field_values => { '3' => 'Beta' }\r
+                            }\r
+    assert_redirected_to '/projects/blog/settings'\r
+    \r
+    project = Project.find_by_name('blog')\r
+    assert_kind_of Project, project\r
+    assert_equal 'weblog', project.description \r
+    assert_equal true, project.is_public?\r
+  end\r
+  \r
+  def test_post_add_by_non_admin\r
+    @request.session[:user_id] = 2\r
+    post :add, :project => { :name => "blog", \r
+                             :description => "weblog",\r
+                             :identifier => "blog",\r
+                             :is_public => 1,\r
+                             :custom_field_values => { '3' => 'Beta' }\r
+                            }\r
+    assert_redirected_to '/projects/blog/settings'\r
+    \r
+    project = Project.find_by_name('blog')\r
+    assert_kind_of Project, project\r
+    assert_equal 'weblog', project.description \r
+    assert_equal true, project.is_public?\r
+    \r
+    # User should be added as a project member\r
+    assert User.find(2).member_of?(project)\r
+    assert_equal 1, project.members.size\r
+  end\r
+  \r
+  def test_show_routing\r
+    assert_routing(\r
+      {:method => :get, :path => '/projects/test'},\r
+      :controller => 'projects', :action => 'show', :id => 'test'\r
+    )\r
+  end\r
+  \r
+  def test_show_by_id\r
+    get :show, :id => 1\r
+    assert_response :success\r
+    assert_template 'show'\r
+    assert_not_nil assigns(:project)\r
+  end\r
+\r
+  def test_show_by_identifier\r
+    get :show, :id => 'ecookbook'\r
+    assert_response :success\r
+    assert_template 'show'\r
+    assert_not_nil assigns(:project)\r
+    assert_equal Project.find_by_identifier('ecookbook'), assigns(:project)\r
+  end\r
+  \r
+  def test_show_should_not_fail_when_custom_values_are_nil\r
+    project = Project.find_by_identifier('ecookbook')\r
+    project.custom_values.first.update_attribute(:value, nil)\r
+    get :show, :id => 'ecookbook'\r
+    assert_response :success\r
+    assert_template 'show'\r
+    assert_not_nil assigns(:project)\r
+    assert_equal Project.find_by_identifier('ecookbook'), assigns(:project)\r
+  end\r
+  \r
+  def test_private_subprojects_hidden\r
+    get :show, :id => 'ecookbook'\r
+    assert_response :success\r
+    assert_template 'show'\r
+    assert_no_tag :tag => 'a', :content => /Private child/\r
+  end\r
+\r
+  def test_private_subprojects_visible\r
+    @request.session[:user_id] = 2 # manager who is a member of the private subproject\r
+    get :show, :id => 'ecookbook'\r
+    assert_response :success\r
+    assert_template 'show'\r
+    assert_tag :tag => 'a', :content => /Private child/\r
+  end\r
+  \r
+  def test_settings_routing\r
+    assert_routing(\r
+      {:method => :get, :path => '/projects/4223/settings'},\r
+      :controller => 'projects', :action => 'settings', :id => '4223'\r
+    )\r
+    assert_routing(\r
+      {:method => :get, :path => '/projects/4223/settings/members'},\r
+      :controller => 'projects', :action => 'settings', :id => '4223', :tab => 'members'\r
+    )\r
+  end\r
+  \r
+  def test_settings\r
+    @request.session[:user_id] = 2 # manager\r
+    get :settings, :id => 1\r
+    assert_response :success\r
+    assert_template 'settings'\r
+  end\r
+  \r
+  def test_edit\r
+    @request.session[:user_id] = 2 # manager\r
+    post :edit, :id => 1, :project => {:name => 'Test changed name',\r
+                                       :issue_custom_field_ids => ['']}\r
+    assert_redirected_to 'projects/ecookbook/settings'\r
+    project = Project.find(1)\r
+    assert_equal 'Test changed name', project.name\r
+  end\r
+  \r
+  def test_add_version_routing\r
+    assert_routing(\r
+      {:method => :get, :path => 'projects/64/versions/new'},\r
+      :controller => 'projects', :action => 'add_version', :id => '64'\r
+    )\r
+    assert_routing(\r
+    #TODO: use PUT\r
+      {:method => :post, :path => 'projects/64/versions/new'},\r
+      :controller => 'projects', :action => 'add_version', :id => '64'\r
+    )\r
+  end\r
+  \r
+  def test_add_issue_category_routing\r
+    assert_routing(\r
+      {:method => :get, :path => 'projects/test/categories/new'},\r
+      :controller => 'projects', :action => 'add_issue_category', :id => 'test'\r
+    )\r
+    assert_routing(\r
+    #TODO: use PUT and update form\r
+      {:method => :post, :path => 'projects/64/categories/new'},\r
+      :controller => 'projects', :action => 'add_issue_category', :id => '64'\r
+    )\r
+  end\r
+  \r
+  def test_destroy_routing\r
+    assert_routing(\r
+      {:method => :get, :path => '/projects/567/destroy'},\r
+      :controller => 'projects', :action => 'destroy', :id => '567'\r
+    )\r
+    assert_routing(\r
+    #TODO: use DELETE and update form\r
+      {:method => :post, :path => 'projects/64/destroy'},\r
+      :controller => 'projects', :action => 'destroy', :id => '64'\r
+    )\r
+  end\r
+  \r
+  def test_get_destroy\r
+    @request.session[:user_id] = 1 # admin\r
+    get :destroy, :id => 1\r
+    assert_response :success\r
+    assert_template 'destroy'\r
+    assert_not_nil Project.find_by_id(1)\r
+  end\r
+\r
+  def test_post_destroy\r
+    @request.session[:user_id] = 1 # admin\r
+    post :destroy, :id => 1, :confirm => 1\r
+    assert_redirected_to 'admin/projects'\r
+    assert_nil Project.find_by_id(1)\r
+  end\r
+  \r
+  def test_add_file\r
+    set_tmp_attachments_directory\r
+    @request.session[:user_id] = 2\r
+    Setting.notified_events = ['file_added']\r
+    ActionMailer::Base.deliveries.clear\r
+    \r
+    assert_difference 'Attachment.count' do\r
+      post :add_file, :id => 1, :version_id => '',\r
+           :attachments => {'1' => {'file' => test_uploaded_file('testfile.txt', 'text/plain')}}\r
+    end\r
+    assert_redirected_to 'projects/ecookbook/files'\r
+    a = Attachment.find(:first, :order => 'created_on DESC')\r
+    assert_equal 'testfile.txt', a.filename\r
+    assert_equal Project.find(1), a.container\r
+\r
+    mail = ActionMailer::Base.deliveries.last\r
+    assert_kind_of TMail::Mail, mail\r
+    assert_equal "[eCookbook] New file", mail.subject\r
+    assert mail.body.include?('testfile.txt')\r
+  end\r
+  \r
+  def test_add_file_routing\r
+    assert_routing(\r
+      {:method => :get, :path => '/projects/33/files/new'},\r
+      :controller => 'projects', :action => 'add_file', :id => '33'\r
+    )\r
+    assert_routing(\r
+      {:method => :post, :path => '/projects/33/files/new'},\r
+      :controller => 'projects', :action => 'add_file', :id => '33'\r
+    )\r
+  end\r
+  \r
+  def test_add_version_file\r
+    set_tmp_attachments_directory\r
+    @request.session[:user_id] = 2\r
+    Setting.notified_events = ['file_added']\r
+    \r
+    assert_difference 'Attachment.count' do\r
+      post :add_file, :id => 1, :version_id => '2',\r
+           :attachments => {'1' => {'file' => test_uploaded_file('testfile.txt', 'text/plain')}}\r
+    end\r
+    assert_redirected_to 'projects/ecookbook/files'\r
+    a = Attachment.find(:first, :order => 'created_on DESC')\r
+    assert_equal 'testfile.txt', a.filename\r
+    assert_equal Version.find(2), a.container\r
+  end\r
+  \r
+  def test_list_files\r
+    get :list_files, :id => 1\r
+    assert_response :success\r
+    assert_template 'list_files'\r
+    assert_not_nil assigns(:containers)\r
+    \r
+    # file attached to the project\r
+    assert_tag :a, :content => 'project_file.zip',\r
+                   :attributes => { :href => '/attachments/download/8/project_file.zip' }\r
+    \r
+    # file attached to a project's version\r
+    assert_tag :a, :content => 'version_file.zip',\r
+                   :attributes => { :href => '/attachments/download/9/version_file.zip' }\r
+  end\r
+\r
+  def test_list_files_routing\r
+    assert_routing(\r
+      {:method => :get, :path => '/projects/33/files'},\r
+      :controller => 'projects', :action => 'list_files', :id => '33'\r
+    )\r
+  end\r
+  \r
+  def test_changelog_routing\r
+    assert_routing(\r
+      {:method => :get, :path => '/projects/44/changelog'},\r
+      :controller => 'projects', :action => 'changelog', :id => '44'\r
+    )\r
+  end\r
+  \r
+  def test_changelog\r
+    get :changelog, :id => 1\r
+    assert_response :success\r
+    assert_template 'changelog'\r
+    assert_not_nil assigns(:versions)\r
+  end\r
+  \r
+  def test_roadmap_routing\r
+    assert_routing(\r
+      {:method => :get, :path => 'projects/33/roadmap'},\r
+      :controller => 'projects', :action => 'roadmap', :id => '33'\r
+    )\r
+  end\r
+  \r
+  def test_roadmap\r
+    get :roadmap, :id => 1\r
+    assert_response :success\r
+    assert_template 'roadmap'\r
+    assert_not_nil assigns(:versions)\r
+    # Version with no date set appears\r
+    assert assigns(:versions).include?(Version.find(3))\r
+    # Completed version doesn't appear\r
+    assert !assigns(:versions).include?(Version.find(1))\r
+  end\r
+  \r
+  def test_roadmap_with_completed_versions\r
+    get :roadmap, :id => 1, :completed => 1\r
+    assert_response :success\r
+    assert_template 'roadmap'\r
+    assert_not_nil assigns(:versions)\r
+    # Version with no date set appears\r
+    assert assigns(:versions).include?(Version.find(3))\r
+    # Completed version appears\r
+    assert assigns(:versions).include?(Version.find(1))\r
+  end\r
+  \r
+  def test_project_activity_routing\r
+    assert_routing(\r
+      {:method => :get, :path => '/projects/1/activity'},\r
+       :controller => 'projects', :action => 'activity', :id => '1'\r
+    )\r
+  end\r
+  \r
+  def test_project_activity_atom_routing\r
+    assert_routing(\r
+      {:method => :get, :path => '/projects/1/activity.atom'},\r
+       :controller => 'projects', :action => 'activity', :id => '1', :format => 'atom'\r
+    )    \r
+  end\r
+  \r
+  def test_project_activity\r
+    get :activity, :id => 1, :with_subprojects => 0\r
+    assert_response :success\r
+    assert_template 'activity'\r
+    assert_not_nil assigns(:events_by_day)\r
+    \r
+    assert_tag :tag => "h3", \r
+               :content => /#{2.days.ago.to_date.day}/,\r
+               :sibling => { :tag => "dl",\r
+                 :child => { :tag => "dt",\r
+                   :attributes => { :class => /issue-edit/ },\r
+                   :child => { :tag => "a",\r
+                     :content => /(#{IssueStatus.find(2).name})/,\r
+                   }\r
+                 }\r
+               }\r
+  end\r
+  \r
+  def test_previous_project_activity\r
+    get :activity, :id => 1, :from => 3.days.ago.to_date\r
+    assert_response :success\r
+    assert_template 'activity'\r
+    assert_not_nil assigns(:events_by_day)\r
+               \r
+    assert_tag :tag => "h3", \r
+               :content => /#{3.day.ago.to_date.day}/,\r
+               :sibling => { :tag => "dl",\r
+                 :child => { :tag => "dt",\r
+                   :attributes => { :class => /issue/ },\r
+                   :child => { :tag => "a",\r
+                     :content => /#{Issue.find(1).subject}/,\r
+                   }\r
+                 }\r
+               }\r
+  end\r
+  \r
+  def test_global_activity_routing\r
+    assert_routing({:method => :get, :path => '/activity'}, :controller => 'projects', :action => 'activity', :id => nil)\r
+  end\r
+  \r
+  def test_global_activity\r
+    get :activity\r
+    assert_response :success\r
+    assert_template 'activity'\r
+    assert_not_nil assigns(:events_by_day)\r
+    \r
+    assert_tag :tag => "h3", \r
+               :content => /#{5.day.ago.to_date.day}/,\r
+               :sibling => { :tag => "dl",\r
+                 :child => { :tag => "dt",\r
+                   :attributes => { :class => /issue/ },\r
+                   :child => { :tag => "a",\r
+                     :content => /#{Issue.find(5).subject}/,\r
+                   }\r
+                 }\r
+               }\r
+  end\r
+  \r
+  def test_user_activity\r
+    get :activity, :user_id => 2\r
+    assert_response :success\r
+    assert_template 'activity'\r
+    assert_not_nil assigns(:events_by_day)\r
+    \r
+    assert_tag :tag => "h3", \r
+               :content => /#{3.day.ago.to_date.day}/,\r
+               :sibling => { :tag => "dl",\r
+                 :child => { :tag => "dt",\r
+                   :attributes => { :class => /issue/ },\r
+                   :child => { :tag => "a",\r
+                     :content => /#{Issue.find(1).subject}/,\r
+                   }\r
+                 }\r
+               }\r
+  end\r
+  \r
+  def test_global_activity_atom_routing\r
+    assert_routing({:method => :get, :path => '/activity.atom'}, :controller => 'projects', :action => 'activity', :id => nil, :format => 'atom')\r
+  end\r
+  \r
+  def test_activity_atom_feed\r
+    get :activity, :format => 'atom'\r
+    assert_response :success\r
+    assert_template 'common/feed.atom.rxml'\r
+  end\r
+  \r
+  def test_archive_routing\r
+    assert_routing(\r
+    #TODO: use PUT to project path and modify form\r
+      {:method => :post, :path => 'projects/64/archive'},\r
+      :controller => 'projects', :action => 'archive', :id => '64'\r
+    )\r
+  end\r
+  \r
+  def test_archive\r
+    @request.session[:user_id] = 1 # admin\r
+    post :archive, :id => 1\r
+    assert_redirected_to 'admin/projects'\r
+    assert !Project.find(1).active?\r
+  end\r
+  \r
+  def test_unarchive_routing\r
+    assert_routing(\r
+    #TODO: use PUT to project path and modify form\r
+      {:method => :post, :path => '/projects/567/unarchive'},\r
+      :controller => 'projects', :action => 'unarchive', :id => '567'\r
+    )\r
+  end\r
+  \r
+  def test_unarchive\r
+    @request.session[:user_id] = 1 # admin\r
+    Project.find(1).archive\r
+    post :unarchive, :id => 1\r
+    assert_redirected_to 'admin/projects'\r
+    assert Project.find(1).active?\r
+  end\r
+  \r
+  def test_project_breadcrumbs_should_be_limited_to_3_ancestors\r
+    CustomField.delete_all\r
+    parent = nil\r
+    6.times do |i|\r
+      p = Project.create!(:name => "Breadcrumbs #{i}", :identifier => "breadcrumbs-#{i}")\r
+      p.set_parent!(parent)\r
+      get :show, :id => p\r
+      assert_tag :h1, :parent => { :attributes => {:id => 'header'}},\r
+                      :children => { :count => [i, 3].min,\r
+                                     :only => { :tag => 'a' } }\r
+                                     \r
+      parent = p\r
+    end\r
+  end\r
+\r
+  def test_copy_with_project\r
+    @request.session[:user_id] = 1 # admin\r
+    get :copy, :id => 1\r
+    assert_response :success\r
+    assert_template 'copy'\r
+    assert assigns(:project)\r
+    assert_equal Project.find(1).description, assigns(:project).description\r
+    assert_nil assigns(:project).id\r
+  end\r
+\r
+  def test_copy_without_project\r
+    @request.session[:user_id] = 1 # admin\r
+    get :copy\r
+    assert_response :redirect\r
+    assert_redirected_to :controller => 'admin', :action => 'projects'\r
+  end\r
+\r
+  def test_jump_should_redirect_to_active_tab\r
+    get :show, :id => 1, :jump => 'issues'\r
+    assert_redirected_to 'projects/ecookbook/issues'\r
+  end\r
+  \r
+  def test_jump_should_not_redirect_to_inactive_tab\r
+    get :show, :id => 3, :jump => 'documents'\r
+    assert_response :success\r
+    assert_template 'show'\r
+  end\r
+  \r
+  def test_jump_should_not_redirect_to_unknown_tab\r
+    get :show, :id => 3, :jump => 'foobar'\r
+    assert_response :success\r
+    assert_template 'show'\r
+  end\r
+  \r
+  # A hook that is manually registered later\r
+  class ProjectBasedTemplate < Redmine::Hook::ViewListener\r
+    def view_layouts_base_html_head(context)\r
+      # Adds a project stylesheet\r
+      stylesheet_link_tag(context[:project].identifier) if context[:project]\r
+    end\r
+  end\r
+  # Don't use this hook now\r
+  Redmine::Hook.clear_listeners\r
+  \r
+  def test_hook_response\r
+    Redmine::Hook.add_listener(ProjectBasedTemplate)\r
+    get :show, :id => 1\r
+    assert_tag :tag => 'link', :attributes => {:href => '/stylesheets/ecookbook.css'},\r
+                               :parent => {:tag => 'head'}\r
+    \r
+    Redmine::Hook.clear_listeners\r
+  end\r
+end\r